diff --git a/custom_components/houseplan/frontend/houseplan-assets.json b/custom_components/houseplan/frontend/houseplan-assets.json index 416262a0..66cc11a1 100644 --- a/custom_components/houseplan/frontend/houseplan-assets.json +++ b/custom_components/houseplan/frontend/houseplan-assets.json @@ -1,312 +1,312 @@ { "schema": 1, - "fingerprint": "c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f", + "fingerprint": "54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32", "entry": "houseplan-card.js", "panelEntry": "houseplan-panel.js", "initialViewFiles": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js", + "houseplan-assets/houseplan-card-9fMSy3y3.js", "houseplan-card.js" ], - "initialViewGzipBytes": 289829, + "initialViewGzipBytes": 289852, "initialPanelFiles": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js", + "houseplan-assets/houseplan-card-9fMSy3y3.js", "houseplan-panel.js" ], - "initialPanelGzipBytes": 291350, + "initialPanelGzipBytes": 291374, "initialPanelOnlyFiles": [ "houseplan-panel.js" ], - "initialPanelOnlyGzipBytes": 2323, + "initialPanelOnlyGzipBytes": 2325, "lazyFiles": [ - "houseplan-assets/backdrop-pick-CtZfmF4H.js", - "houseplan-assets/de-AkOtg0jq.js", - "houseplan-assets/editor-_VTHnoKH.js", - "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "houseplan-assets/fr-Ds3OdruH.js", - "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js", - "houseplan-assets/houseplan-editor-runtime-BlocE3XU.js", - "houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js", - "houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js", - "houseplan-assets/iso-scene-render-BfrsUAJf.js", - "houseplan-assets/live-interaction-runtime-CCfHOfT8.js", - "houseplan-assets/pdf-export-Bslsp3h0.js", - "houseplan-assets/summary-panel-runtime-loaded-BGIJeXIz.js", - "houseplan-assets/zigbee-topology-D0gydI7H.js", - "houseplan-assets/zigbee-topology-runtime-BXasXMdL.js" + "houseplan-assets/backdrop-pick-BJOCHJxe.js", + "houseplan-assets/de-DVCIKwC0.js", + "houseplan-assets/editor-C694OxAO.js", + "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "houseplan-assets/fr-DHxhbm5E.js", + "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js", + "houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js", + "houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js", + "houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js", + "houseplan-assets/iso-scene-render-fYqz_-Ot.js", + "houseplan-assets/live-interaction-runtime-XyTIhKAA.js", + "houseplan-assets/pdf-export-D3vmqIY6.js", + "houseplan-assets/summary-panel-runtime-loaded-CX2cplA1.js", + "houseplan-assets/zigbee-topology-CI6PJorK.js", + "houseplan-assets/zigbee-topology-runtime-d-S2Abll.js" ], - "lazyGzipBytes": 459663, + "lazyGzipBytes": 459551, "lazyEditorFiles": [ - "houseplan-assets/backdrop-pick-CtZfmF4H.js", - "houseplan-assets/editor-_VTHnoKH.js", - "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js", - "houseplan-assets/houseplan-editor-runtime-BlocE3XU.js", - "houseplan-assets/zigbee-topology-D0gydI7H.js" + "houseplan-assets/backdrop-pick-BJOCHJxe.js", + "houseplan-assets/editor-C694OxAO.js", + "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js", + "houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js", + "houseplan-assets/zigbee-topology-CI6PJorK.js" ], - "lazyEditorGzipBytes": 243125, + "lazyEditorGzipBytes": 242989, "lazyOnboardingFiles": [ - "houseplan-assets/backdrop-pick-CtZfmF4H.js", - "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js" + "houseplan-assets/backdrop-pick-BJOCHJxe.js", + "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js" ], - "lazyOnboardingGzipBytes": 33646, + "lazyOnboardingGzipBytes": 33577, "lazyLocaleFiles": [ - "houseplan-assets/de-AkOtg0jq.js", - "houseplan-assets/fr-Ds3OdruH.js" + "houseplan-assets/de-DVCIKwC0.js", + "houseplan-assets/fr-DHxhbm5E.js" ], - "lazyLocaleGzipBytes": 55372, + "lazyLocaleGzipBytes": 55383, "lazyIsometricFiles": [ - "houseplan-assets/iso-scene-render-BfrsUAJf.js" + "houseplan-assets/iso-scene-render-fYqz_-Ot.js" ], - "lazyIsometricGzipBytes": 17644, + "lazyIsometricGzipBytes": 17643, "lazyFurnitureArtFiles": [ - "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js" + "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js" ], - "lazyFurnitureArtGzipBytes": 16945, + "lazyFurnitureArtGzipBytes": 16942, "lazyPdfFiles": [ - "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js", - "houseplan-assets/pdf-export-Bslsp3h0.js" + "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js", + "houseplan-assets/pdf-export-D3vmqIY6.js" ], - "lazyPdfGzipBytes": 126819, + "lazyPdfGzipBytes": 126817, "files": [ { - "path": "houseplan-assets/backdrop-pick-CtZfmF4H.js", - "sha256": "0318781a07d46ab4852f6ab7b0fdc44c180a1b0271935e031f9a9f885de62991", - "rawBytes": 74764, - "gzipBytes": 24114, + "path": "houseplan-assets/backdrop-pick-BJOCHJxe.js", + "sha256": "c24f2896a89f71e0a4147184f93b0e69e0c22eb705b772e644e9fc131ff879f4", + "rawBytes": 74375, + "gzipBytes": 24031, "isEntry": false, "imports": [ - "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/de-AkOtg0jq.js", - "sha256": "21cadc32b989295b913052353b5c8049b844474028e72162f8564698c0bdb9db", + "path": "houseplan-assets/de-DVCIKwC0.js", + "sha256": "6f716933e452260c6e7c0c40d7193e750b6fc443f162cca5cb814c734142dde5", "rawBytes": 92513, - "gzipBytes": 27927, + "gzipBytes": 27933, "isEntry": false, "imports": [], "dynamicImports": [] }, { - "path": "houseplan-assets/editor-_VTHnoKH.js", - "sha256": "881257f965ba340ab8367a3a0ffbfaf7e4509a38997c7b3b33281ff27b700907", + "path": "houseplan-assets/editor-C694OxAO.js", + "sha256": "f95242b8000cddf2fe1856a5518883c00a27a90c2983f228003db0189dffc1b4", "rawBytes": 3833, "gzipBytes": 1583, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "sha256": "5068cd6f5bd37792a593096b142ea5e9b729b0f85a1cf4d3c5722f714ff64eb2", - "rawBytes": 23495, - "gzipBytes": 4704, + "path": "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "sha256": "44a654e7c905948ab4bb363514532c13e67e3e54eee37e4af0ec8447f706fbc1", + "rawBytes": 23544, + "gzipBytes": 4716, "isEntry": false, "imports": [], "dynamicImports": [] }, { - "path": "houseplan-assets/fr-Ds3OdruH.js", - "sha256": "395585192b0478200785d46cb37805871bd0726088ca776e0f95150af595633c", + "path": "houseplan-assets/fr-DHxhbm5E.js", + "sha256": "f603ade3217ebe9959225379598608583ec29ab654dc257f57ae894d85ca448f", "rawBytes": 94824, - "gzipBytes": 27445, + "gzipBytes": 27450, "isEntry": false, "imports": [], "dynamicImports": [] }, { - "path": "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js", - "sha256": "2f193022979145fe8544c3c498fb8f1e9b3690fa6500fcd70a6c4f34c8a13860", + "path": "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js", + "sha256": "86d1074252f182c84d47285560a5b22c26724e21f21d03fbac4583973a9c11a7", "rawBytes": 52033, - "gzipBytes": 16945, + "gzipBytes": 16942, "isEntry": false, "imports": [], "dynamicImports": [] }, { - "path": "houseplan-assets/houseplan-card-BWAph8ZF.js", - "sha256": "ded6a4cd113062c60ed2086560b03f1cdba08884b0454c85f7140f5f51b284cb", + "path": "houseplan-assets/houseplan-card-9fMSy3y3.js", + "sha256": "e475fbae1c25540d2e349d4441bc963a4ff4181b8659fd491309dd1e578f716a", "rawBytes": 1027208, - "gzipBytes": 289027, + "gzipBytes": 289049, "isEntry": false, "imports": [], "dynamicImports": [ - "houseplan-assets/de-AkOtg0jq.js", - "houseplan-assets/editor-_VTHnoKH.js", - "houseplan-assets/fr-Ds3OdruH.js", - "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js", - "houseplan-assets/houseplan-editor-runtime-BlocE3XU.js", - "houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js", - "houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js", - "houseplan-assets/iso-scene-render-BfrsUAJf.js", - "houseplan-assets/live-interaction-runtime-CCfHOfT8.js", - "houseplan-assets/pdf-export-Bslsp3h0.js", - "houseplan-assets/summary-panel-runtime-loaded-BGIJeXIz.js" + "houseplan-assets/de-DVCIKwC0.js", + "houseplan-assets/editor-C694OxAO.js", + "houseplan-assets/fr-DHxhbm5E.js", + "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js", + "houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js", + "houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js", + "houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js", + "houseplan-assets/iso-scene-render-fYqz_-Ot.js", + "houseplan-assets/live-interaction-runtime-XyTIhKAA.js", + "houseplan-assets/pdf-export-D3vmqIY6.js", + "houseplan-assets/summary-panel-runtime-loaded-CX2cplA1.js" ] }, { - "path": "houseplan-assets/houseplan-editor-runtime-BlocE3XU.js", - "sha256": "1af11a5d027eec8d8a0793eae9be1713b6387d3a15c239e83f8623f87877f8a1", - "rawBytes": 677599, - "gzipBytes": 188352, + "path": "houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js", + "sha256": "e84feb1cf320be8297982134d45a5adceaec5a50f95aaa884e6e53cae2664edd", + "rawBytes": 677390, + "gzipBytes": 188290, "isEntry": false, "imports": [ - "houseplan-assets/backdrop-pick-CtZfmF4H.js", - "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js", - "houseplan-assets/houseplan-card-BWAph8ZF.js", - "houseplan-assets/zigbee-topology-D0gydI7H.js" + "houseplan-assets/backdrop-pick-BJOCHJxe.js", + "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js", + "houseplan-assets/houseplan-card-9fMSy3y3.js", + "houseplan-assets/zigbee-topology-CI6PJorK.js" ], "dynamicImports": [ - "houseplan-assets/zigbee-topology-runtime-BXasXMdL.js" + "houseplan-assets/zigbee-topology-runtime-d-S2Abll.js" ] }, { - "path": "houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js", - "sha256": "a30a515e61b632b90005e296b23d5cc52d3266c91ce29760fbb7358180956d1c", + "path": "houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js", + "sha256": "64367a8743ea22c4a9a350456878b7006ba01a346cc89eabb786e3c1d944ad3a", "rawBytes": 15667, - "gzipBytes": 4828, + "gzipBytes": 4830, "isEntry": false, "imports": [ - "houseplan-assets/backdrop-pick-CtZfmF4H.js", - "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/backdrop-pick-BJOCHJxe.js", + "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js", - "sha256": "780e78bbb5e04de2042497fdea47f44c31f8abeef03ad7cae3aeaf0e776f0db5", + "path": "houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js", + "sha256": "b2fa73ad0fc3353630e380abe1f63f483113c7bfc5f1e634150c2f0e12b4e0cf", "rawBytes": 10759, - "gzipBytes": 3684, + "gzipBytes": 3686, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js", - "houseplan-assets/zigbee-topology-D0gydI7H.js", - "houseplan-assets/zigbee-topology-runtime-BXasXMdL.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js", + "houseplan-assets/zigbee-topology-CI6PJorK.js", + "houseplan-assets/zigbee-topology-runtime-d-S2Abll.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/iso-scene-render-BfrsUAJf.js", - "sha256": "2806544f1906569d9613087eea4ca3b7017d0394147d6913f9e9998b8b4b456b", + "path": "houseplan-assets/iso-scene-render-fYqz_-Ot.js", + "sha256": "009a9217d1c522a5c2b6f9d5ea3450e2a77aafe52096d9c1d19902a18c6632f9", "rawBytes": 51983, - "gzipBytes": 17644, + "gzipBytes": 17643, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/live-interaction-runtime-CCfHOfT8.js", - "sha256": "5b905320a37ded5bfb1b52a4095e6a5821644d4ce0031d2ba2374b1418be2239", + "path": "houseplan-assets/live-interaction-runtime-XyTIhKAA.js", + "sha256": "0fd38fd067699ea97f11565db7c4ae86c1bcc867041e7e3377408f40e741f03f", "rawBytes": 8216, - "gzipBytes": 3205, + "gzipBytes": 3209, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/pdf-export-Bslsp3h0.js", - "sha256": "c7fc552565f6551b70366350399fbbe9bb849a588be6c293e6fb17602dabd0ae", + "path": "houseplan-assets/pdf-export-D3vmqIY6.js", + "sha256": "4c60cf0b34a17777c60c4849f1ee42841fb74b69466366adcf94cf97eec9ad2e", "rawBytes": 236247, - "gzipBytes": 109874, + "gzipBytes": 109875, "isEntry": false, "imports": [ - "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js", - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js", + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/summary-panel-editor-1TWzLmMH.js", - "sha256": "b6fad5dd728b4b6cfa4b4d54989a2d9d9dd9f37aba52301332a0bf3a4e69a66b", - "rawBytes": 14862, - "gzipBytes": 3424, + "path": "houseplan-assets/summary-panel-editor-CNT_mev4.js", + "sha256": "ef5dcf22a38fb5df834dcce277de7967303b8025167527483aab726dd30f3a2c", + "rawBytes": 14867, + "gzipBytes": 3427, "isEntry": false, "imports": [ - "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "houseplan-assets/houseplan-card-BWAph8ZF.js", - "houseplan-assets/summary-panel-runtime-loaded-BGIJeXIz.js" + "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "houseplan-assets/houseplan-card-9fMSy3y3.js", + "houseplan-assets/summary-panel-runtime-loaded-CX2cplA1.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/summary-panel-metrics-CsJSnPHD.js", - "sha256": "a9c4d54e9e1d168a3dd48fd8f09d8470eafa3b9dbc825fe6f9dda5bcb34a7029", + "path": "houseplan-assets/summary-panel-metrics-BhoEMuKv.js", + "sha256": "0b4f1816c4069cc62f20dccaeeeceb82c139dee339782833e594e46aa768fe06", "rawBytes": 2611, - "gzipBytes": 1306, + "gzipBytes": 1308, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/summary-panel-runtime-loaded-BGIJeXIz.js", - "sha256": "e3042c31f4e963a6c91fec76b05b1900e79360f60c246d8ce32291dd71201840", + "path": "houseplan-assets/summary-panel-runtime-loaded-CX2cplA1.js", + "sha256": "95e65a1d327f9d2f90796b9ae7754e0d8a64c15e44a82cefe329dca8f6115689", "rawBytes": 72733, - "gzipBytes": 20171, + "gzipBytes": 20172, "isEntry": false, "imports": [ - "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [ - "houseplan-assets/summary-panel-editor-1TWzLmMH.js", - "houseplan-assets/summary-panel-metrics-CsJSnPHD.js" + "houseplan-assets/summary-panel-editor-CNT_mev4.js", + "houseplan-assets/summary-panel-metrics-BhoEMuKv.js" ] }, { - "path": "houseplan-assets/zigbee-topology-D0gydI7H.js", - "sha256": "abe70ae6d783881bc6e8bdaac98a7372d1263f206103bf7110348f83f4a8dc2a", + "path": "houseplan-assets/zigbee-topology-CI6PJorK.js", + "sha256": "6e503b93a48deeda46368588fd4eebf7215aa4a2928e1162747da8b3ffe4b67a", "rawBytes": 18962, "gzipBytes": 7427, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/zigbee-topology-runtime-BXasXMdL.js", - "sha256": "c7dd23a95592651b462f8ef86d073b4aa98b6fad4ce3395b5bbeb0679bf0c76d", + "path": "houseplan-assets/zigbee-topology-runtime-d-S2Abll.js", + "sha256": "f6aad0abbf74532abc1c705d1268cce95048e7dbdc81a52a776a996c8b70f969", "rawBytes": 3942, - "gzipBytes": 1760, + "gzipBytes": 1764, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js", - "houseplan-assets/zigbee-topology-D0gydI7H.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js", + "houseplan-assets/zigbee-topology-CI6PJorK.js" ], "dynamicImports": [] }, { "path": "houseplan-card.js", - "sha256": "d5d8d4cbc7b0a71e4c6ba3f4cffb2fd412a9f8ce922200659ce96ee8f70d0bc0", + "sha256": "c796620c6d67c8fb18479291279eb410302ad541ed2b3679d59b780f74e8935b", "rawBytes": 1205, - "gzipBytes": 802, + "gzipBytes": 803, "isEntry": true, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { "path": "houseplan-panel.js", - "sha256": "a34d397053df4099bce9aca317cfa95619c4e031796d77a1da09c15aab69a132", + "sha256": "c134452d829194d8d630e5859f8142d345e15348a706d7a83d5d9328b0df3faa", "rawBytes": 6165, - "gzipBytes": 2323, + "gzipBytes": 2325, "isEntry": true, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] } diff --git a/custom_components/houseplan/frontend/houseplan-assets/backdrop-pick-CtZfmF4H.js b/custom_components/houseplan/frontend/houseplan-assets/backdrop-pick-BJOCHJxe.js similarity index 62% rename from custom_components/houseplan/frontend/houseplan-assets/backdrop-pick-CtZfmF4H.js rename to custom_components/houseplan/frontend/houseplan-assets/backdrop-pick-BJOCHJxe.js index e2b1aa41..38cf624d 100644 --- a/custom_components/houseplan/frontend/houseplan-assets/backdrop-pick-CtZfmF4H.js +++ b/custom_components/houseplan/frontend/houseplan-assets/backdrop-pick-BJOCHJxe.js @@ -1,7 +1,7 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{A as e,c as a,s as t,l as i,cG as n,d as s,dC as r,dD as o,cF as l,dE as c,cL as d,cK as p,dF as h,bn as u,bm as m,bo as _,ar as g,ay as b,az as f,dG as v}from"./houseplan-card-BWAph8ZF.js";import{c as w,f as y,C as k}from"./form-kit.styles-DcvCvE8g.js";const $=w+y(k,{withSwitch:!1}),x=new WeakSet;let S=null;function M(e){const a=e.renderRoot;if(!a||x.has(a))return;const t=a.ownerDocument??globalThis.document,i=t?.defaultView?.CSSStyleSheet;if(i&&"adoptedStyleSheets"in a)return S||(S=new i,S.replaceSync($)),a.adoptedStyleSheets=[...a.adoptedStyleSheets,S],void x.add(a);if(a.querySelector("style[data-hp-form-kit]"))return void x.add(a);const n=t.createElement("style");n.dataset.hpFormKit="true",n.textContent=$,a.appendChild(n),x.add(a)}function C({title:t,help:i,body:n,id:s}){return a`
+globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{A as e,c as a,s as t,l as i,cG as n,ao as s,dC as r,dD as o,cF as l,dE as c,cL as d,cK as p,dF as h,bn as u,bm as m,bo as _,ar as g,ay as b,az as f,dG as v}from"./houseplan-card-9fMSy3y3.js";import{c as w,f as y,C as k}from"./form-kit.styles-CKUQLdmn.js";const $=w+y(k,{withSwitch:!1}),x=new WeakSet;let S=null;function M(e){const a=e.renderRoot;if(!a||x.has(a))return;const t=a.ownerDocument??globalThis.document,i=t?.defaultView?.CSSStyleSheet;if(i&&"adoptedStyleSheets"in a)return S||(S=new i,S.replaceSync($)),a.adoptedStyleSheets=[...a.adoptedStyleSheets,S],void x.add(a);if(a.querySelector("style[data-hp-form-kit]"))return void x.add(a);const n=t.createElement("style");n.dataset.hpFormKit="true",n.textContent=$,a.appendChild(n),x.add(a)}function C({title:t,help:i,body:n,id:s}){return a`
${t?a`

${t}

${i??e}
`:e}
${n}
-
`}function z({title:t,help:i}){return a`

${t}

${i??e}
`}function L({label:t,htmlFor:i,help:n,control:s,hint:r,error:o}){return a`
+
`}function L({title:t,help:i}){return a`

${t}

${i??e}
`}function z({label:t,htmlFor:i,help:n,control:s,hint:r,error:o}){return a`
${i?a``:t}${n??e} ${s} ${o?a``:r?a`

${r}

`:e} @@ -70,7 +70,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc `}function N({min:e,max:t,value:i,unit:n,ariaLabel:s,disabled:r,slider:o,onInput:l,id:c}){return a`
${o} ${I({id:c,value:String(i),unit:n,min:e,max:t,step:1,ariaLabel:s,disabled:r,onInput:a=>{const i=Number(a);Number.isFinite(i)&&l(Math.min(t,Math.max(e,i)))}})} -
`}function O(e,t){return a``}function W(e,t,{disabled:i=!1}={}){return a``}function G({text:t,action:i}){return a`${t??""}${i??e}`}function U({title:t,tag:i,body:n}){return a`
+
`}function O(e,t){return a``}function W(e,t,{disabled:i=!1}={}){return a``}function U({text:t,action:i}){return a`${t??""}${i??e}`}function G({title:t,tag:i,body:n}){return a`

${t}

${i?a`${i}`:e}
${n}
`}function V({open:t,current:i,placeholder:n,ariaLabel:s,filter:r,filterPlaceholder:o,candidates:l,selected:c,emptyText:d,onToggle:p,onFilter:h,onPick:u,id:m,toolbar:_,disabled:g=!1}){return a`
@@ -92,7 +92,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc `):a`

${d}

`}
`:e} - `}const j=new WeakMap;function Z(e,a,t){const i=j.get(e)??new Map;i.set(a,t),j.set(e,i)}function K(e,a){j.get(e)?.delete(a)}function Q(e,a,t){const i=j.get(e)?.get(a);return void 0===i||i!==t}function Y(e,a=new Set){const t=Object.entries(e).filter(([e])=>!a.has(e)).sort(([e],[a])=>ea?1:0);return JSON.stringify(t)}var J={"space.title_hint":"Shown in the space tabs.","space.scale_hint":"Scale of the plan.","space.scale_changed":"Changing the scale recalculates the dimensions of the whole space when you save. Points on the plan stay where they are.","space.plan.help":"Use an image as a background to draw over. Rooms and devices stay editable on top of it. Switching to drawing by hand keeps the uploaded image available to use again.","space.plan.help.aria":"Help: floor plan","space.source_draw_hint":"Outline rooms in the plan editor.","space.source_file_hint":"Add an image to draw over.","space.plan_kept":"Your uploaded image is kept. Switch back to use it again.","space.show_borders_hint":"Show patterned outlines around the walls.","space.show_borders.help":"When off, patterned wall outlines and zero-thickness wall lines are hidden. Plain, light wall bands stay visible, so rooms remain separated. Doors, windows, room fills and lighting keep working.","space.show_borders.help.aria":"Help: room borders","space.layers_label":"Visible layers","space.layers.help":"Hiding changes only what you see on the plan. Decorative elements remain available in the background editor. Doors and windows stay in the plan editor, while their sensors, sunlight and lamp glow keep working.","space.layers.help.aria":"Help: visible layers","space.layer_decor":"Decorative layer","space.layer_openings":"Doors, windows & gates","space.fill_lqi_hint":"Uses average room LQI: low at 40 or below, high at 180 or above. Colors and opacity follow the general palette.","space.fill_light_hint":"Uses separate colors for any light on, all lights off, and no light sources. Colors and opacity follow the general palette.","space.temp_range":"Comfort range","space.temp_min":"Minimum","space.temp_max":"Maximum","space.temp_range_hint":"Below the minimum: cold. Within the range: comfort. Above the maximum: hot. Without a temperature reading, light-source glow can still add base shading.","space.show_names_hint":"Display room names and their selected values.","space.show_names.help":"Hiding room names also hides their values without clearing your selections. Room-card positions stay where you placed them.","space.show_names.help.aria":"Help: room names","space.card_values":"Values on the card","space.label_lqi_short":"Zigbee signal","space.values_hidden":"Values are saved but hidden.","space.values_hidden_action":"Show room names","space.card_font_hint":"Scales every room card in this space.","space.card_font.help":"100% is the default size. This scales every room card in this space while keeping individual card sizes and positions. Changes apply when you save.","space.card_font.help.aria":"Help: room-card font size","space.sun_inherit_short":"Use general settings","space.north_general":"Use general settings · {v}","space.north_custom":"Custom direction","space.north_deg":"North direction","space.compass_aria":"Compass: north at {v}","space.glow_enabled_hint":"Show a soft glow around lights that are on.","space.glow_enabled.help":"Lamp glow and sunlight are independent. Hiding opening symbols does not stop either effect. Window glass still lets sunlight in when the window is closed.","space.glow_enabled.help.aria":"Help: light-source glow","space.error_title":"Enter a name for the space.","space.error_plan":"Add a floor-plan image or switch to drawing by hand.","space.error_temp_range":"The maximum must be higher than the minimum.","space.error_north":"Enter a whole number between 0° and 359°.","btn.reset_100":"Reset to 100%","dialog.unsaved":"Unsaved changes","dialog.review_fields":"Review {n} field(s)","dialog.discard_title":"Discard your changes?","dialog.discard_message":"Your changes haven’t been saved.","dialog.discard_confirm":"Discard changes","dialog.discard_keep":"Keep editing","gs.show_room_tooltip_hint":"Hover a room on the plan to see its summary.","gs.radar_show_live_hint":"Hides or shows all live radar targets. This does not start or stop observation recording.","gs.bg_custom_hint":"Custom background color.","gs.bg_theme_hint":"Using the theme background.","gs.sun_rays_hint":"Draw sun rays through window openings.","gs.error_glow_radius":"Enter a radius greater than zero.","gs.error_north":"Enter a whole number between 0° and 359°.","gs.opacity_of":"{name} opacity","room.fill_inherit_hint":"Use the fill mode set for the whole space.","room.fill_following":"Following the space: {mode}.","room.fill_mode_label":"Fill mode","room.temp_min_label":"Minimum","room.temp_max_label":"Maximum","room.sizes_hint":"On top of the space-wide card size ({v}%).","room.error_temp_range":"Enter numbers for the comfort bounds.","room.error_name":"Enter a name or choose an area.","marker.name_hint":"Shown on the plan.","marker.binding.help":"A bound marker shows the live state of a Home Assistant device or entity and can act on it. A virtual device is a plain marker with no binding.","marker.binding.help.aria":"Help: binding to a Home Assistant device","marker.binding_virtual_hint":"A virtual device is a plain marker with no binding.","marker.room_hint_auto":"Placed by the device’s Home Assistant area.","marker.room_hint_override":"Overrides the placement by device area.","marker.light_role_seg_auto":"Auto","marker.light_role_seg_always":"Always","marker.light_role_seg_never":"Never","marker.glow_radius_empty_hint":"Empty: uses the general radius ({v}).","marker.icon.help":"Empty means automatic: the icon comes from the icon rules for this device. Pick one to override, or pin the automatic choice.","marker.icon.help.aria":"Help: marker icon","marker.icon_custom_hint":"Custom icon for this marker.","marker.display.help":"How the marker face reacts to state and activity. The value modes replace the icon with a Home Assistant value.","marker.display.help.aria":"Help: display mode","marker.size.help":"Scales and rotates only this marker on the plan. The tap area grows with the icon.","marker.size.help.aria":"Help: icon size and rotation","marker.size_short":"Size","marker.error_binding":"Choose a device or entity to bind.","marker.error_glow_radius":"Enter a radius greater than 0, or leave it empty.","room.fill_seg_lqi":"Zigbee","room.fill_seg_custom":"Custom"};const X={en:J,ru:{"space.title_hint":"Показывается на вкладках пространств.","space.scale_hint":"Масштаб плана.","space.scale_changed":"Смена масштаба пересчитает размеры всего пространства при сохранении. Точки на плане останутся на месте.","space.plan.help":"Изображение под планом, поверх которого рисуют. Комнаты и устройства остаются редактируемыми. При переходе на рисование вручную загруженное изображение сохраняется и доступно снова.","space.plan.help.aria":"Справка: подложка плана","space.source_draw_hint":"Обвести комнаты в редакторе плана.","space.source_file_hint":"Добавить картинку и рисовать поверх неё.","space.plan_kept":"Загруженное изображение сохранено. Переключитесь обратно, чтобы снова использовать его.","space.show_borders_hint":"Показывать узорную обводку стен.","space.show_borders.help":"Когда выключено, узорная обводка стен и линии стен нулевой толщины скрыты. Светлые полосы стен остаются видны, комнаты не сливаются. Двери, окна, заливки комнат и освещение продолжают работать.","space.show_borders.help.aria":"Справка: границы комнат","space.layers_label":"Видимые слои","space.layers.help":"Скрытие меняет только то, что видно на плане. Декоративные элементы остаются в редакторе подложки. Двери и окна остаются в редакторе плана, а их датчики, солнечный свет и свечение ламп продолжают работать.","space.layers.help.aria":"Справка: видимые слои","space.layer_decor":"Декоративный слой","space.layer_openings":"Двери, окна и ворота","space.fill_lqi_hint":"По среднему LQI комнаты: слабый — 40 и ниже, сильный — 180 и выше. Цвета и прозрачность — из общей палитры.","space.fill_light_hint":"Отдельные цвета для «горит хотя бы одна», «все выключены» и «источников нет». Цвета и прозрачность — из общей палитры.","space.temp_range":"Комфортный диапазон","space.temp_min":"Минимум","space.temp_max":"Максимум","space.temp_range_hint":"Ниже минимума — холодно. В диапазоне — комфорт. Выше максимума — жарко. Без показаний температуры свечение источников света всё равно даёт базовую заливку.","space.show_names_hint":"Названия комнат и выбранные значения на плане.","space.show_names.help":"Скрытие названий скрывает и значения, не сбрасывая выбор. Положение карточек комнат сохраняется.","space.show_names.help.aria":"Справка: названия комнат","space.card_values":"Значения на карточке","space.label_lqi_short":"Сигнал Zigbee","space.values_hidden":"Значения сохранены, но скрыты.","space.values_hidden_action":"Показать названия комнат","space.card_font_hint":"Масштабирует каждую карточку комнаты в этом пространстве.","space.card_font.help":"100 % — размер по умолчанию. Масштабирует все карточки комнат пространства, сохраняя индивидуальные размеры и положение. Применяется при сохранении.","space.card_font.help.aria":"Справка: размер шрифта карточек","space.sun_inherit_short":"Как в общих","space.north_general":"Как в общих · {v}","space.north_custom":"Своё направление","space.north_deg":"Направление на север","space.compass_aria":"Компас: север {v}","space.glow_enabled_hint":"Мягкое свечение вокруг включённых ламп.","space.glow_enabled.help":"Свечение ламп и солнечный свет независимы. Скрытие символов проёмов не отключает ни то, ни другое. Стекло окна пропускает солнце и при закрытом окне.","space.glow_enabled.help.aria":"Справка: свечение источников света","space.error_title":"Введите название пространства.","space.error_plan":"Добавьте изображение плана или переключитесь на рисование вручную.","space.error_temp_range":"Максимум должен быть больше минимума.","space.error_north":"Введите целое число от 0° до 359°.","btn.reset_100":"Сбросить до 100%","dialog.unsaved":"Есть несохранённые изменения","dialog.review_fields":"Проверьте поля: {n}","dialog.discard_title":"Отменить изменения?","dialog.discard_message":"Изменения не сохранены.","dialog.discard_confirm":"Отменить изменения","dialog.discard_keep":"Продолжить редактирование","gs.show_room_tooltip_hint":"Наведите на комнату на плане, чтобы увидеть сводку.","gs.radar_show_live_hint":"Показывает или скрывает все живые цели радаров. Запись наблюдения не запускается и не останавливается.","gs.bg_custom_hint":"Свой цвет фона.","gs.bg_theme_hint":"Используется фон темы.","gs.sun_rays_hint":"Рисовать солнечные лучи через оконные проёмы.","gs.error_glow_radius":"Введите радиус больше нуля.","gs.error_north":"Введите целое число от 0° до 359°.","gs.opacity_of":"Прозрачность: {name}","room.fill_inherit_hint":"Использовать режим заливки всего пространства.","room.fill_following":"Как у пространства: {mode}.","room.fill_mode_label":"Режим заливки","room.temp_min_label":"Минимум","room.temp_max_label":"Максимум","room.sizes_hint":"Поверх размера карточек всего пространства ({v}%).","room.error_temp_range":"Введите числа для границ комфорта.","room.error_name":"Введите название или выберите зону.","marker.name_hint":"Показывается на плане.","marker.binding.help":"Привязанный маркер показывает живое состояние устройства или сущности Home Assistant и может им управлять. Виртуальное устройство — просто маркер без привязки.","marker.binding.help.aria":"Справка: привязка к устройству Home Assistant","marker.binding_virtual_hint":"Виртуальное устройство — просто маркер без привязки.","marker.room_hint_auto":"Размещается по зоне устройства в Home Assistant.","marker.room_hint_override":"Переопределяет размещение по зоне устройства.","marker.light_role_seg_auto":"Авто","marker.light_role_seg_always":"Всегда","marker.light_role_seg_never":"Никогда","marker.glow_radius_empty_hint":"Пусто: общий радиус ({v}).","marker.icon.help":"Пусто — автоматически: иконка берётся из правил иконок для этого устройства. Выберите свою, чтобы переопределить, или закрепите автоматическую.","marker.icon.help.aria":"Справка: иконка маркера","marker.icon_custom_hint":"Своя иконка для этого маркера.","marker.display.help":"Как лицо маркера реагирует на состояние и активность. Режимы значения заменяют иконку значением из Home Assistant.","marker.display.help.aria":"Справка: режим отображения","marker.size.help":"Масштабирует и поворачивает только этот маркер на плане. Область нажатия растёт вместе с иконкой.","marker.size.help.aria":"Справка: размер и поворот иконки","marker.size_short":"Размер","marker.error_binding":"Выберите устройство или сущность для привязки.","marker.error_glow_radius":"Введите радиус больше 0 или оставьте поле пустым.","room.fill_seg_lqi":"Zigbee","room.fill_seg_custom":"Свой цвет"},de:{"space.title_hint":"Wird in den Bereichs-Tabs angezeigt.","space.scale_hint":"Maßstab des Plans.","space.scale_changed":"Eine Änderung des Maßstabs berechnet beim Speichern die Maße des gesamten Bereichs neu. Punkte auf dem Plan bleiben, wo sie sind.","space.plan.help":"Ein Bild als Hintergrund, über das gezeichnet wird. Räume und Geräte bleiben darüber bearbeitbar. Beim Wechsel zum Zeichnen von Hand bleibt das hochgeladene Bild erhalten.","space.plan.help.aria":"Hilfe: Grundriss","space.source_draw_hint":"Räume im Plan-Editor umreißen.","space.source_file_hint":"Ein Bild hinzufügen und darüber zeichnen.","space.plan_kept":"Das hochgeladene Bild bleibt erhalten. Wechseln Sie zurück, um es wieder zu nutzen.","space.show_borders_hint":"Gemusterte Umrisse um die Wände anzeigen.","space.show_borders.help":"Ausgeschaltet werden gemusterte Wandumrisse und Linien von Wänden ohne Dicke ausgeblendet. Helle Wandbänder bleiben sichtbar, Räume bleiben getrennt. Türen, Fenster, Raumfüllungen und Beleuchtung funktionieren weiter.","space.show_borders.help.aria":"Hilfe: Raumgrenzen","space.layers_label":"Sichtbare Ebenen","space.layers.help":"Ausblenden ändert nur, was auf dem Plan zu sehen ist. Dekorative Elemente bleiben im Hintergrund-Editor verfügbar. Türen und Fenster bleiben im Plan-Editor; ihre Sensoren, Sonnenlicht und Lampenschein funktionieren weiter.","space.layers.help.aria":"Hilfe: sichtbare Ebenen","space.layer_decor":"Dekorative Ebene","space.layer_openings":"Türen, Fenster & Tore","space.fill_lqi_hint":"Nach mittlerem LQI des Raums: schwach bei 40 oder weniger, stark bei 180 oder mehr. Farben und Deckkraft folgen der allgemeinen Palette.","space.fill_light_hint":"Eigene Farben für „mindestens eine Lampe an“, „alle aus“ und „keine Lichtquellen“. Farben und Deckkraft folgen der allgemeinen Palette.","space.temp_range":"Komfortbereich","space.temp_min":"Minimum","space.temp_max":"Maximum","space.temp_range_hint":"Unter dem Minimum: kalt. Im Bereich: Komfort. Über dem Maximum: heiß. Ohne Temperaturwert kann der Lampenschein weiterhin eine Grundschattierung geben.","space.show_names_hint":"Raumnamen und ausgewählte Werte anzeigen.","space.show_names.help":"Das Ausblenden der Raumnamen blendet auch ihre Werte aus, ohne die Auswahl zu löschen. Die Positionen der Raumkarten bleiben erhalten.","space.show_names.help.aria":"Hilfe: Raumnamen","space.card_values":"Werte auf der Karte","space.label_lqi_short":"Zigbee-Signal","space.values_hidden":"Werte sind gespeichert, aber ausgeblendet.","space.values_hidden_action":"Raumnamen anzeigen","space.card_font_hint":"Skaliert jede Raumkarte in diesem Bereich.","space.card_font.help":"100 % ist die Standardgröße. Skaliert alle Raumkarten dieses Bereichs, individuelle Größen und Positionen bleiben erhalten. Gilt nach dem Speichern.","space.card_font.help.aria":"Hilfe: Schriftgröße der Raumkarten","space.sun_inherit_short":"Wie allgemein","space.north_general":"Wie allgemein · {v}","space.north_custom":"Eigene Richtung","space.north_deg":"Nordrichtung","space.compass_aria":"Kompass: Norden bei {v}","space.glow_enabled_hint":"Sanftes Leuchten um eingeschaltete Lampen.","space.glow_enabled.help":"Lampenschein und Sonnenlicht sind unabhängig. Das Ausblenden von Öffnungssymbolen stoppt keinen der Effekte. Fensterglas lässt Sonnenlicht auch bei geschlossenem Fenster durch.","space.glow_enabled.help.aria":"Hilfe: Leuchten der Lichtquellen","space.error_title":"Geben Sie einen Namen für den Bereich ein.","space.error_plan":"Fügen Sie ein Grundrissbild hinzu oder wechseln Sie zum Zeichnen von Hand.","space.error_temp_range":"Das Maximum muss über dem Minimum liegen.","space.error_north":"Geben Sie eine ganze Zahl zwischen 0° und 359° ein.","btn.reset_100":"Auf 100 % zurücksetzen","dialog.unsaved":"Ungespeicherte Änderungen","dialog.review_fields":"{n} Feld(er) prüfen","dialog.discard_title":"Änderungen verwerfen?","dialog.discard_message":"Ihre Änderungen wurden nicht gespeichert.","dialog.discard_confirm":"Änderungen verwerfen","dialog.discard_keep":"Weiter bearbeiten","gs.show_room_tooltip_hint":"Zeigen Sie auf einen Raum im Plan, um seine Übersicht zu sehen.","gs.radar_show_live_hint":"Blendet alle Live-Radarziele ein oder aus. Die Beobachtungsaufzeichnung wird dadurch nicht gestartet oder gestoppt.","gs.bg_custom_hint":"Eigene Hintergrundfarbe.","gs.bg_theme_hint":"Hintergrund des Themes wird verwendet.","gs.sun_rays_hint":"Sonnenstrahlen durch Fensteröffnungen zeichnen.","gs.error_glow_radius":"Geben Sie einen Radius größer als null ein.","gs.error_north":"Geben Sie eine ganze Zahl zwischen 0° und 359° ein.","gs.opacity_of":"Deckkraft: {name}","room.fill_inherit_hint":"Den Füllmodus des gesamten Bereichs verwenden.","room.fill_following":"Wie der Bereich: {mode}.","room.fill_mode_label":"Füllmodus","room.temp_min_label":"Minimum","room.temp_max_label":"Maximum","room.sizes_hint":"Zusätzlich zur bereichsweiten Kartengröße ({v} %).","room.error_temp_range":"Geben Sie Zahlen für die Komfortgrenzen ein.","room.error_name":"Geben Sie einen Namen ein oder wählen Sie einen Bereich.","marker.name_hint":"Wird auf dem Plan angezeigt.","marker.binding.help":"Ein verknüpfter Marker zeigt den Live-Zustand eines Home-Assistant-Geräts oder einer Entität und kann darauf wirken. Ein virtuelles Gerät ist ein einfacher Marker ohne Verknüpfung.","marker.binding.help.aria":"Hilfe: Verknüpfung mit einem Home-Assistant-Gerät","marker.binding_virtual_hint":"Ein virtuelles Gerät ist ein einfacher Marker ohne Verknüpfung.","marker.room_hint_auto":"Platzierung nach dem Home-Assistant-Bereich des Geräts.","marker.room_hint_override":"Überschreibt die Platzierung nach Gerätebereich.","marker.light_role_seg_auto":"Auto","marker.light_role_seg_always":"Immer","marker.light_role_seg_never":"Nie","marker.glow_radius_empty_hint":"Leer: allgemeiner Radius ({v}).","marker.icon.help":"Leer bedeutet automatisch: Das Symbol kommt aus den Symbolregeln für dieses Gerät. Wählen Sie eines zum Überschreiben oder heften Sie die automatische Wahl an.","marker.icon.help.aria":"Hilfe: Marker-Symbol","marker.icon_custom_hint":"Eigenes Symbol für diesen Marker.","marker.display.help":"Wie das Marker-Gesicht auf Zustand und Aktivität reagiert. Die Wert-Modi ersetzen das Symbol durch einen Home-Assistant-Wert.","marker.display.help.aria":"Hilfe: Anzeigemodus","marker.size.help":"Skaliert und dreht nur diesen Marker auf dem Plan. Die Tippfläche wächst mit dem Symbol.","marker.size.help.aria":"Hilfe: Symbolgröße und Drehung","marker.size_short":"Größe","marker.error_binding":"Wählen Sie ein Gerät oder eine Entität zum Verknüpfen.","marker.error_glow_radius":"Geben Sie einen Radius größer als 0 ein oder lassen Sie das Feld leer.","room.fill_seg_lqi":"Zigbee","room.fill_seg_custom":"Eigene"},fr:{"space.title_hint":"Affiché dans les onglets des espaces.","space.scale_hint":"Échelle du plan.","space.scale_changed":"Changer l’échelle recalcule les dimensions de tout l’espace à l’enregistrement. Les points du plan restent en place.","space.plan.help":"Une image en arrière-plan sur laquelle dessiner. Les pièces et les appareils restent modifiables par-dessus. Passer au dessin à la main conserve l’image téléversée pour la réutiliser.","space.plan.help.aria":"Aide : fond de plan","space.source_draw_hint":"Tracer les pièces dans l’éditeur de plan.","space.source_file_hint":"Ajouter une image et dessiner par-dessus.","space.plan_kept":"Votre image téléversée est conservée. Revenez en arrière pour la réutiliser.","space.show_borders_hint":"Afficher les contours hachurés autour des murs.","space.show_borders.help":"Désactivé, les contours hachurés des murs et les lignes des murs sans épaisseur sont masqués. Les bandes claires des murs restent visibles, les pièces restent séparées. Portes, fenêtres, remplissages et éclairage continuent de fonctionner.","space.show_borders.help.aria":"Aide : bordures des pièces","space.layers_label":"Calques visibles","space.layers.help":"Masquer ne change que ce qui est visible sur le plan. Les éléments décoratifs restent disponibles dans l’éditeur de fond. Portes et fenêtres restent dans l’éditeur de plan ; leurs capteurs, la lumière du soleil et la lueur des lampes continuent de fonctionner.","space.layers.help.aria":"Aide : calques visibles","space.layer_decor":"Calque décoratif","space.layer_openings":"Portes, fenêtres et portails","space.fill_lqi_hint":"Selon le LQI moyen de la pièce : faible à 40 ou moins, fort à 180 ou plus. Couleurs et opacité suivent la palette générale.","space.fill_light_hint":"Couleurs distinctes pour « au moins une lampe allumée », « toutes éteintes » et « aucune source ». Couleurs et opacité suivent la palette générale.","space.temp_range":"Plage de confort","space.temp_min":"Minimum","space.temp_max":"Maximum","space.temp_range_hint":"Sous le minimum : froid. Dans la plage : confort. Au-dessus du maximum : chaud. Sans mesure de température, la lueur des sources lumineuses peut encore donner un ombrage de base.","space.show_names_hint":"Afficher les noms des pièces et les valeurs choisies.","space.show_names.help":"Masquer les noms masque aussi leurs valeurs sans effacer vos choix. La position des cartes des pièces est conservée.","space.show_names.help.aria":"Aide : noms des pièces","space.card_values":"Valeurs sur la carte","space.label_lqi_short":"Signal Zigbee","space.values_hidden":"Les valeurs sont enregistrées mais masquées.","space.values_hidden_action":"Afficher les noms des pièces","space.card_font_hint":"Met à l’échelle chaque carte de pièce de cet espace.","space.card_font.help":"100 % est la taille par défaut. Met à l’échelle toutes les cartes de pièces de cet espace en conservant tailles et positions individuelles. Appliqué à l’enregistrement.","space.card_font.help.aria":"Aide : taille de police des cartes","space.sun_inherit_short":"Comme les réglages généraux","space.north_general":"Comme les réglages généraux · {v}","space.north_custom":"Direction personnalisée","space.north_deg":"Direction du nord","space.compass_aria":"Boussole : nord à {v}","space.glow_enabled_hint":"Lueur douce autour des lampes allumées.","space.glow_enabled.help":"La lueur des lampes et la lumière du soleil sont indépendantes. Masquer les symboles d’ouvertures n’arrête aucun des deux effets. Le vitrage laisse passer le soleil même fenêtre fermée.","space.glow_enabled.help.aria":"Aide : lueur des sources lumineuses","space.error_title":"Saisissez un nom pour l’espace.","space.error_plan":"Ajoutez une image du plan ou passez au dessin à la main.","space.error_temp_range":"Le maximum doit être supérieur au minimum.","space.error_north":"Saisissez un nombre entier entre 0° et 359°.","btn.reset_100":"Réinitialiser à 100 %","dialog.unsaved":"Modifications non enregistrées","dialog.review_fields":"Vérifiez {n} champ(s)","dialog.discard_title":"Abandonner vos modifications ?","dialog.discard_message":"Vos modifications n’ont pas été enregistrées.","dialog.discard_confirm":"Abandonner","dialog.discard_keep":"Continuer la modification","gs.show_room_tooltip_hint":"Survolez une pièce sur le plan pour voir son résumé.","gs.radar_show_live_hint":"Affiche ou masque toutes les cibles radar en direct. Cela ne démarre ni n’arrête l’enregistrement d’observation.","gs.bg_custom_hint":"Couleur de fond personnalisée.","gs.bg_theme_hint":"Fond du thème utilisé.","gs.sun_rays_hint":"Tracer les rayons du soleil à travers les ouvertures des fenêtres.","gs.error_glow_radius":"Saisissez un rayon supérieur à zéro.","gs.error_north":"Saisissez un nombre entier entre 0° et 359°.","gs.opacity_of":"Opacité : {name}","room.fill_inherit_hint":"Utiliser le mode de remplissage de tout l’espace.","room.fill_following":"Comme l’espace : {mode}.","room.fill_mode_label":"Mode de remplissage","room.temp_min_label":"Minimum","room.temp_max_label":"Maximum","room.sizes_hint":"En plus de la taille des cartes de l’espace ({v} %).","room.error_temp_range":"Saisissez des nombres pour les bornes de confort.","room.error_name":"Saisissez un nom ou choisissez une zone.","marker.name_hint":"Affiché sur le plan.","marker.binding.help":"Un marqueur lié affiche l’état en direct d’un appareil ou d’une entité Home Assistant et peut agir dessus. Un appareil virtuel est un simple marqueur sans liaison.","marker.binding.help.aria":"Aide : liaison à un appareil Home Assistant","marker.binding_virtual_hint":"Un appareil virtuel est un simple marqueur sans liaison.","marker.room_hint_auto":"Placé selon la zone Home Assistant de l’appareil.","marker.room_hint_override":"Remplace le placement par zone de l’appareil.","marker.light_role_seg_auto":"Auto","marker.light_role_seg_always":"Toujours","marker.light_role_seg_never":"Jamais","marker.glow_radius_empty_hint":"Vide : rayon général ({v}).","marker.icon.help":"Vide signifie automatique : l’icône vient des règles d’icônes de cet appareil. Choisissez-en une pour remplacer, ou épinglez le choix automatique.","marker.icon.help.aria":"Aide : icône du marqueur","marker.icon_custom_hint":"Icône personnalisée pour ce marqueur.","marker.display.help":"Comment la face du marqueur réagit à l’état et à l’activité. Les modes valeur remplacent l’icône par une valeur Home Assistant.","marker.display.help.aria":"Aide : mode d’affichage","marker.size.help":"Redimensionne et fait pivoter uniquement ce marqueur sur le plan. La zone de toucher grandit avec l’icône.","marker.size.help.aria":"Aide : taille et rotation de l’icône","marker.size_short":"Taille","marker.error_binding":"Choisissez un appareil ou une entité à lier.","marker.error_glow_radius":"Saisissez un rayon supérieur à 0 ou laissez le champ vide.","room.fill_seg_lqi":"Zigbee","room.fill_seg_custom":"Perso"}};function ee(e,a){const t=X[e]?.[a]??J[a];return"string"==typeof t&&t.trim().length>0}function ae(e,a,i){return t(X[e]?.[a]??J[a]??a,i)}function te(t){const n=i(t.hass,t._config?.language);return{st:(e,a)=>ae(n,e,a),shelp:t=>{const i=`${t}.aria`;return ee(n,t)&&ee(n,i)?a``:e}}}const ie=new Set(["busy","pickSaved","saved","savedBusy","savedAspect","cellCmInput","cellCmTouched","displayTouched","deleteBlockers","copy"]);function ne(e){return Y({...e,planFile:e.planFile?e.planFile.name:null},ie)}function se(e,a){Z(e,"space",ne(a))}const re=.1,oe=1e3,le=(e,a)=>{e.host._spaceDialog=a};function ce(t){M(t.host);const{host:i}=t,n=i._spaceDialog,s=i._t.bind(i),{st:r}=te(i),o=e=>`${t.idPrefix}-${e}`,l=function(e,a){const t=[];return e.title.trim()||t.push({field:`${a}-title`,message:"space.error_title"}),"file"!==e.source||e.planFile||e.planUrl||t.push({field:`${a}-plan`,message:"space.error_plan"}),"temp"!==e.fillMode||Number.isFinite(e.tempMin)&&Number.isFinite(e.tempMax)&&e.tempMin=0&&e.northDeg<=359||t.push({field:`${a}-north-deg`,message:"space.error_north"}),t}(n,t.idPrefix),c=e=>l.find(a=>a.field===e),d=function(e,a){return Q(e,"space",ne(a))}(i,n),p=d&&0===l.length&&!n.busy,h=i._importTotal>0&&"create"===n.mode?s("import.progress",{i:i._importTotal-i._importQueue.length,n:i._importTotal}):"",u=()=>{!function(e){K(e,"space")}(i),i._spaceDialog=null,i._importQueue=[],i._importTotal=0},m=async e=>{if(!d||n.busy)return void u();const a=e.currentTarget;await i._confirmDanger({key:"discard-space-dialog",kind:"warning",title:r("dialog.discard_title"),message:r("dialog.discard_message"),objectName:n.title.trim()||void 0,confirmLabel:r("dialog.discard_confirm"),cancelLabel:r("dialog.discard_keep")})?u():a?.rejectClose?.()};return{title:`${"create"===n.mode?s("space.new"):s("space.header")}${h?` · ${h}`:""}`,badge:"edit"===n.mode?n.title.trim():"",requestClose:m,body:a`
+
`}const j=new WeakMap;function Z(e,a,t){const i=j.get(e)??new Map;i.set(a,t),j.set(e,i)}function K(e,a){j.get(e)?.delete(a)}function Q(e,a,t){const i=j.get(e)?.get(a);return void 0===i||i!==t}function Y(e,a=new Set){const t=Object.entries(e).filter(([e])=>!a.has(e)).sort(([e],[a])=>ea?1:0);return JSON.stringify(t)}var J={"space.title_hint":"Shown in the space tabs.","space.scale_hint":"Scale of the plan.","space.scale_changed":"Changing the scale recalculates the dimensions of the whole space when you save. Points on the plan stay where they are.","space.plan.help":"Use an image as a background to draw over. Rooms and devices stay editable on top of it. Switching to drawing by hand keeps the uploaded image available to use again.","space.plan.help.aria":"Help: floor plan","space.source_draw_hint":"Outline rooms in the plan editor.","space.source_file_hint":"Add an image to draw over.","space.plan_kept":"Your uploaded image is kept. Switch back to use it again.","space.show_borders_hint":"Show patterned outlines around the walls.","space.show_borders.help":"When off, patterned wall outlines and zero-thickness wall lines are hidden. Plain, light wall bands stay visible, so rooms remain separated. Doors, windows, room fills and lighting keep working.","space.show_borders.help.aria":"Help: room borders","space.layers_label":"Visible layers","space.layers.help":"Hiding changes only what you see on the plan. Decorative elements remain available in the background editor. Doors and windows stay in the plan editor, while their sensors, sunlight and lamp glow keep working.","space.layers.help.aria":"Help: visible layers","space.layer_decor":"Decorative layer","space.layer_openings":"Doors, windows & gates","space.fill_lqi_hint":"Uses average room LQI: low at 40 or below, high at 180 or above. Colors and opacity follow the general palette.","space.fill_light_hint":"Uses separate colors for any light on, all lights off, and no light sources. Colors and opacity follow the general palette.","space.temp_range":"Comfort range","space.temp_min":"Minimum","space.temp_max":"Maximum","space.temp_range_hint":"Below the minimum: cold. Within the range: comfort. Above the maximum: hot. Without a temperature reading, light-source glow can still add base shading.","space.show_names_hint":"Display room names and their selected values.","space.show_names.help":"Hiding room names also hides their values without clearing your selections. Room-card positions stay where you placed them.","space.show_names.help.aria":"Help: room names","space.card_values":"Values on the card","space.label_lqi_short":"Zigbee signal","space.values_hidden":"Values are saved but hidden.","space.values_hidden_action":"Show room names","space.card_font_hint":"Scales every room card in this space.","space.card_font.help":"100% is the default size. This scales every room card in this space while keeping individual card sizes and positions. Changes apply when you save.","space.card_font.help.aria":"Help: room-card font size","space.sun_inherit_short":"Use general settings","space.north_general":"Use general settings · {v}","space.north_custom":"Custom direction","space.north_deg":"North direction","space.compass_aria":"Compass: north at {v}","space.glow_enabled_hint":"Show a soft glow around lights that are on.","space.glow_enabled.help":"Lamp glow and sunlight are independent. Hiding opening symbols does not stop either effect. Window glass still lets sunlight in when the window is closed.","space.glow_enabled.help.aria":"Help: light-source glow","space.error_title":"Enter a name for the space.","space.error_plan":"Add a floor-plan image or switch to drawing by hand.","space.error_temp_range":"The maximum must be higher than the minimum.","space.error_north":"Enter a whole number between 0° and 359°.","btn.reset_100":"Reset to 100%","dialog.unsaved":"Unsaved changes","dialog.review_fields":"Review {n} field(s)","dialog.discard_title":"Discard your changes?","dialog.discard_message":"Your changes haven’t been saved.","dialog.discard_confirm":"Discard changes","dialog.discard_keep":"Keep editing","gs.show_room_tooltip_hint":"Hover a room on the plan to see its summary.","gs.radar_show_live_hint":"Hides or shows all live radar targets. This does not start or stop observation recording.","gs.bg_custom_hint":"Custom background color.","gs.bg_theme_hint":"Using the theme background.","gs.sun_rays_hint":"Draw sun rays through window openings.","gs.error_glow_radius":"Enter a radius greater than zero.","gs.error_north":"Enter a whole number between 0° and 359°.","gs.opacity_of":"{name} opacity","room.fill_inherit_hint":"Use the fill mode set for the whole space.","room.fill_following":"Following the space: {mode}.","room.fill_mode_label":"Fill mode","room.temp_min_label":"Minimum","room.temp_max_label":"Maximum","room.sizes_hint":"On top of the space-wide card size ({v}%).","room.error_temp_range":"Enter numbers for the comfort bounds.","room.error_name":"Enter a name or choose an area.","marker.name_hint":"Shown on the plan.","marker.binding.help":"A bound marker shows the live state of a Home Assistant device or entity and can act on it. A virtual device is a plain marker with no binding.","marker.binding.help.aria":"Help: binding to a Home Assistant device","marker.binding_virtual_hint":"A virtual device is a plain marker with no binding.","marker.room_hint_auto":"Placed by the device’s Home Assistant area.","marker.room_hint_override":"Overrides the placement by device area.","marker.light_role_seg_auto":"Auto","marker.light_role_seg_always":"Always","marker.light_role_seg_never":"Never","marker.glow_radius_empty_hint":"Empty: uses the general radius ({v}).","marker.icon.help":"Empty means automatic: the icon comes from the icon rules for this device. Pick one to override, or pin the automatic choice.","marker.icon.help.aria":"Help: marker icon","marker.icon_custom_hint":"Custom icon for this marker.","marker.display.help":"How the marker face reacts to state and activity. The value modes replace the icon with a Home Assistant value.","marker.display.help.aria":"Help: display mode","marker.size.help":"Scales and rotates only this marker on the plan. The tap area grows with the icon.","marker.size.help.aria":"Help: icon size and rotation","marker.size_short":"Size","marker.error_binding":"Choose a device or entity to bind.","room.fill_seg_lqi":"Zigbee","room.fill_seg_custom":"Custom"};const X={en:J,ru:{"space.title_hint":"Показывается на вкладках пространств.","space.scale_hint":"Масштаб плана.","space.scale_changed":"Смена масштаба пересчитает размеры всего пространства при сохранении. Точки на плане останутся на месте.","space.plan.help":"Изображение под планом, поверх которого рисуют. Комнаты и устройства остаются редактируемыми. При переходе на рисование вручную загруженное изображение сохраняется и доступно снова.","space.plan.help.aria":"Справка: подложка плана","space.source_draw_hint":"Обвести комнаты в редакторе плана.","space.source_file_hint":"Добавить картинку и рисовать поверх неё.","space.plan_kept":"Загруженное изображение сохранено. Переключитесь обратно, чтобы снова использовать его.","space.show_borders_hint":"Показывать узорную обводку стен.","space.show_borders.help":"Когда выключено, узорная обводка стен и линии стен нулевой толщины скрыты. Светлые полосы стен остаются видны, комнаты не сливаются. Двери, окна, заливки комнат и освещение продолжают работать.","space.show_borders.help.aria":"Справка: границы комнат","space.layers_label":"Видимые слои","space.layers.help":"Скрытие меняет только то, что видно на плане. Декоративные элементы остаются в редакторе подложки. Двери и окна остаются в редакторе плана, а их датчики, солнечный свет и свечение ламп продолжают работать.","space.layers.help.aria":"Справка: видимые слои","space.layer_decor":"Декоративный слой","space.layer_openings":"Двери, окна и ворота","space.fill_lqi_hint":"По среднему LQI комнаты: слабый — 40 и ниже, сильный — 180 и выше. Цвета и прозрачность — из общей палитры.","space.fill_light_hint":"Отдельные цвета для «горит хотя бы одна», «все выключены» и «источников нет». Цвета и прозрачность — из общей палитры.","space.temp_range":"Комфортный диапазон","space.temp_min":"Минимум","space.temp_max":"Максимум","space.temp_range_hint":"Ниже минимума — холодно. В диапазоне — комфорт. Выше максимума — жарко. Без показаний температуры свечение источников света всё равно даёт базовую заливку.","space.show_names_hint":"Названия комнат и выбранные значения на плане.","space.show_names.help":"Скрытие названий скрывает и значения, не сбрасывая выбор. Положение карточек комнат сохраняется.","space.show_names.help.aria":"Справка: названия комнат","space.card_values":"Значения на карточке","space.label_lqi_short":"Сигнал Zigbee","space.values_hidden":"Значения сохранены, но скрыты.","space.values_hidden_action":"Показать названия комнат","space.card_font_hint":"Масштабирует каждую карточку комнаты в этом пространстве.","space.card_font.help":"100 % — размер по умолчанию. Масштабирует все карточки комнат пространства, сохраняя индивидуальные размеры и положение. Применяется при сохранении.","space.card_font.help.aria":"Справка: размер шрифта карточек","space.sun_inherit_short":"Как в общих","space.north_general":"Как в общих · {v}","space.north_custom":"Своё направление","space.north_deg":"Направление на север","space.compass_aria":"Компас: север {v}","space.glow_enabled_hint":"Мягкое свечение вокруг включённых ламп.","space.glow_enabled.help":"Свечение ламп и солнечный свет независимы. Скрытие символов проёмов не отключает ни то, ни другое. Стекло окна пропускает солнце и при закрытом окне.","space.glow_enabled.help.aria":"Справка: свечение источников света","space.error_title":"Введите название пространства.","space.error_plan":"Добавьте изображение плана или переключитесь на рисование вручную.","space.error_temp_range":"Максимум должен быть больше минимума.","space.error_north":"Введите целое число от 0° до 359°.","btn.reset_100":"Сбросить до 100%","dialog.unsaved":"Есть несохранённые изменения","dialog.review_fields":"Проверьте поля: {n}","dialog.discard_title":"Отменить изменения?","dialog.discard_message":"Изменения не сохранены.","dialog.discard_confirm":"Отменить изменения","dialog.discard_keep":"Продолжить редактирование","gs.show_room_tooltip_hint":"Наведите на комнату на плане, чтобы увидеть сводку.","gs.radar_show_live_hint":"Показывает или скрывает все живые цели радаров. Запись наблюдения не запускается и не останавливается.","gs.bg_custom_hint":"Свой цвет фона.","gs.bg_theme_hint":"Используется фон темы.","gs.sun_rays_hint":"Рисовать солнечные лучи через оконные проёмы.","gs.error_glow_radius":"Введите радиус больше нуля.","gs.error_north":"Введите целое число от 0° до 359°.","gs.opacity_of":"Прозрачность: {name}","room.fill_inherit_hint":"Использовать режим заливки всего пространства.","room.fill_following":"Как у пространства: {mode}.","room.fill_mode_label":"Режим заливки","room.temp_min_label":"Минимум","room.temp_max_label":"Максимум","room.sizes_hint":"Поверх размера карточек всего пространства ({v}%).","room.error_temp_range":"Введите числа для границ комфорта.","room.error_name":"Введите название или выберите зону.","marker.name_hint":"Показывается на плане.","marker.binding.help":"Привязанный маркер показывает живое состояние устройства или сущности Home Assistant и может им управлять. Виртуальное устройство — просто маркер без привязки.","marker.binding.help.aria":"Справка: привязка к устройству Home Assistant","marker.binding_virtual_hint":"Виртуальное устройство — просто маркер без привязки.","marker.room_hint_auto":"Размещается по зоне устройства в Home Assistant.","marker.room_hint_override":"Переопределяет размещение по зоне устройства.","marker.light_role_seg_auto":"Авто","marker.light_role_seg_always":"Всегда","marker.light_role_seg_never":"Никогда","marker.glow_radius_empty_hint":"Пусто: общий радиус ({v}).","marker.icon.help":"Пусто — автоматически: иконка берётся из правил иконок для этого устройства. Выберите свою, чтобы переопределить, или закрепите автоматическую.","marker.icon.help.aria":"Справка: иконка маркера","marker.icon_custom_hint":"Своя иконка для этого маркера.","marker.display.help":"Как лицо маркера реагирует на состояние и активность. Режимы значения заменяют иконку значением из Home Assistant.","marker.display.help.aria":"Справка: режим отображения","marker.size.help":"Масштабирует и поворачивает только этот маркер на плане. Область нажатия растёт вместе с иконкой.","marker.size.help.aria":"Справка: размер и поворот иконки","marker.size_short":"Размер","marker.error_binding":"Выберите устройство или сущность для привязки.","room.fill_seg_lqi":"Zigbee","room.fill_seg_custom":"Свой цвет"},de:{"space.title_hint":"Wird in den Bereichs-Tabs angezeigt.","space.scale_hint":"Maßstab des Plans.","space.scale_changed":"Eine Änderung des Maßstabs berechnet beim Speichern die Maße des gesamten Bereichs neu. Punkte auf dem Plan bleiben, wo sie sind.","space.plan.help":"Ein Bild als Hintergrund, über das gezeichnet wird. Räume und Geräte bleiben darüber bearbeitbar. Beim Wechsel zum Zeichnen von Hand bleibt das hochgeladene Bild erhalten.","space.plan.help.aria":"Hilfe: Grundriss","space.source_draw_hint":"Räume im Plan-Editor umreißen.","space.source_file_hint":"Ein Bild hinzufügen und darüber zeichnen.","space.plan_kept":"Das hochgeladene Bild bleibt erhalten. Wechseln Sie zurück, um es wieder zu nutzen.","space.show_borders_hint":"Gemusterte Umrisse um die Wände anzeigen.","space.show_borders.help":"Ausgeschaltet werden gemusterte Wandumrisse und Linien von Wänden ohne Dicke ausgeblendet. Helle Wandbänder bleiben sichtbar, Räume bleiben getrennt. Türen, Fenster, Raumfüllungen und Beleuchtung funktionieren weiter.","space.show_borders.help.aria":"Hilfe: Raumgrenzen","space.layers_label":"Sichtbare Ebenen","space.layers.help":"Ausblenden ändert nur, was auf dem Plan zu sehen ist. Dekorative Elemente bleiben im Hintergrund-Editor verfügbar. Türen und Fenster bleiben im Plan-Editor; ihre Sensoren, Sonnenlicht und Lampenschein funktionieren weiter.","space.layers.help.aria":"Hilfe: sichtbare Ebenen","space.layer_decor":"Dekorative Ebene","space.layer_openings":"Türen, Fenster & Tore","space.fill_lqi_hint":"Nach mittlerem LQI des Raums: schwach bei 40 oder weniger, stark bei 180 oder mehr. Farben und Deckkraft folgen der allgemeinen Palette.","space.fill_light_hint":"Eigene Farben für „mindestens eine Lampe an“, „alle aus“ und „keine Lichtquellen“. Farben und Deckkraft folgen der allgemeinen Palette.","space.temp_range":"Komfortbereich","space.temp_min":"Minimum","space.temp_max":"Maximum","space.temp_range_hint":"Unter dem Minimum: kalt. Im Bereich: Komfort. Über dem Maximum: heiß. Ohne Temperaturwert kann der Lampenschein weiterhin eine Grundschattierung geben.","space.show_names_hint":"Raumnamen und ausgewählte Werte anzeigen.","space.show_names.help":"Das Ausblenden der Raumnamen blendet auch ihre Werte aus, ohne die Auswahl zu löschen. Die Positionen der Raumkarten bleiben erhalten.","space.show_names.help.aria":"Hilfe: Raumnamen","space.card_values":"Werte auf der Karte","space.label_lqi_short":"Zigbee-Signal","space.values_hidden":"Werte sind gespeichert, aber ausgeblendet.","space.values_hidden_action":"Raumnamen anzeigen","space.card_font_hint":"Skaliert jede Raumkarte in diesem Bereich.","space.card_font.help":"100 % ist die Standardgröße. Skaliert alle Raumkarten dieses Bereichs, individuelle Größen und Positionen bleiben erhalten. Gilt nach dem Speichern.","space.card_font.help.aria":"Hilfe: Schriftgröße der Raumkarten","space.sun_inherit_short":"Wie allgemein","space.north_general":"Wie allgemein · {v}","space.north_custom":"Eigene Richtung","space.north_deg":"Nordrichtung","space.compass_aria":"Kompass: Norden bei {v}","space.glow_enabled_hint":"Sanftes Leuchten um eingeschaltete Lampen.","space.glow_enabled.help":"Lampenschein und Sonnenlicht sind unabhängig. Das Ausblenden von Öffnungssymbolen stoppt keinen der Effekte. Fensterglas lässt Sonnenlicht auch bei geschlossenem Fenster durch.","space.glow_enabled.help.aria":"Hilfe: Leuchten der Lichtquellen","space.error_title":"Geben Sie einen Namen für den Bereich ein.","space.error_plan":"Fügen Sie ein Grundrissbild hinzu oder wechseln Sie zum Zeichnen von Hand.","space.error_temp_range":"Das Maximum muss über dem Minimum liegen.","space.error_north":"Geben Sie eine ganze Zahl zwischen 0° und 359° ein.","btn.reset_100":"Auf 100 % zurücksetzen","dialog.unsaved":"Ungespeicherte Änderungen","dialog.review_fields":"{n} Feld(er) prüfen","dialog.discard_title":"Änderungen verwerfen?","dialog.discard_message":"Ihre Änderungen wurden nicht gespeichert.","dialog.discard_confirm":"Änderungen verwerfen","dialog.discard_keep":"Weiter bearbeiten","gs.show_room_tooltip_hint":"Zeigen Sie auf einen Raum im Plan, um seine Übersicht zu sehen.","gs.radar_show_live_hint":"Blendet alle Live-Radarziele ein oder aus. Die Beobachtungsaufzeichnung wird dadurch nicht gestartet oder gestoppt.","gs.bg_custom_hint":"Eigene Hintergrundfarbe.","gs.bg_theme_hint":"Hintergrund des Themes wird verwendet.","gs.sun_rays_hint":"Sonnenstrahlen durch Fensteröffnungen zeichnen.","gs.error_glow_radius":"Geben Sie einen Radius größer als null ein.","gs.error_north":"Geben Sie eine ganze Zahl zwischen 0° und 359° ein.","gs.opacity_of":"Deckkraft: {name}","room.fill_inherit_hint":"Den Füllmodus des gesamten Bereichs verwenden.","room.fill_following":"Wie der Bereich: {mode}.","room.fill_mode_label":"Füllmodus","room.temp_min_label":"Minimum","room.temp_max_label":"Maximum","room.sizes_hint":"Zusätzlich zur bereichsweiten Kartengröße ({v} %).","room.error_temp_range":"Geben Sie Zahlen für die Komfortgrenzen ein.","room.error_name":"Geben Sie einen Namen ein oder wählen Sie einen Bereich.","marker.name_hint":"Wird auf dem Plan angezeigt.","marker.binding.help":"Ein verknüpfter Marker zeigt den Live-Zustand eines Home-Assistant-Geräts oder einer Entität und kann darauf wirken. Ein virtuelles Gerät ist ein einfacher Marker ohne Verknüpfung.","marker.binding.help.aria":"Hilfe: Verknüpfung mit einem Home-Assistant-Gerät","marker.binding_virtual_hint":"Ein virtuelles Gerät ist ein einfacher Marker ohne Verknüpfung.","marker.room_hint_auto":"Platzierung nach dem Home-Assistant-Bereich des Geräts.","marker.room_hint_override":"Überschreibt die Platzierung nach Gerätebereich.","marker.light_role_seg_auto":"Auto","marker.light_role_seg_always":"Immer","marker.light_role_seg_never":"Nie","marker.glow_radius_empty_hint":"Leer: allgemeiner Radius ({v}).","marker.icon.help":"Leer bedeutet automatisch: Das Symbol kommt aus den Symbolregeln für dieses Gerät. Wählen Sie eines zum Überschreiben oder heften Sie die automatische Wahl an.","marker.icon.help.aria":"Hilfe: Marker-Symbol","marker.icon_custom_hint":"Eigenes Symbol für diesen Marker.","marker.display.help":"Wie das Marker-Gesicht auf Zustand und Aktivität reagiert. Die Wert-Modi ersetzen das Symbol durch einen Home-Assistant-Wert.","marker.display.help.aria":"Hilfe: Anzeigemodus","marker.size.help":"Skaliert und dreht nur diesen Marker auf dem Plan. Die Tippfläche wächst mit dem Symbol.","marker.size.help.aria":"Hilfe: Symbolgröße und Drehung","marker.size_short":"Größe","marker.error_binding":"Wählen Sie ein Gerät oder eine Entität zum Verknüpfen.","room.fill_seg_lqi":"Zigbee","room.fill_seg_custom":"Eigene"},fr:{"space.title_hint":"Affiché dans les onglets des espaces.","space.scale_hint":"Échelle du plan.","space.scale_changed":"Changer l’échelle recalcule les dimensions de tout l’espace à l’enregistrement. Les points du plan restent en place.","space.plan.help":"Une image en arrière-plan sur laquelle dessiner. Les pièces et les appareils restent modifiables par-dessus. Passer au dessin à la main conserve l’image téléversée pour la réutiliser.","space.plan.help.aria":"Aide : fond de plan","space.source_draw_hint":"Tracer les pièces dans l’éditeur de plan.","space.source_file_hint":"Ajouter une image et dessiner par-dessus.","space.plan_kept":"Votre image téléversée est conservée. Revenez en arrière pour la réutiliser.","space.show_borders_hint":"Afficher les contours hachurés autour des murs.","space.show_borders.help":"Désactivé, les contours hachurés des murs et les lignes des murs sans épaisseur sont masqués. Les bandes claires des murs restent visibles, les pièces restent séparées. Portes, fenêtres, remplissages et éclairage continuent de fonctionner.","space.show_borders.help.aria":"Aide : bordures des pièces","space.layers_label":"Calques visibles","space.layers.help":"Masquer ne change que ce qui est visible sur le plan. Les éléments décoratifs restent disponibles dans l’éditeur de fond. Portes et fenêtres restent dans l’éditeur de plan ; leurs capteurs, la lumière du soleil et la lueur des lampes continuent de fonctionner.","space.layers.help.aria":"Aide : calques visibles","space.layer_decor":"Calque décoratif","space.layer_openings":"Portes, fenêtres et portails","space.fill_lqi_hint":"Selon le LQI moyen de la pièce : faible à 40 ou moins, fort à 180 ou plus. Couleurs et opacité suivent la palette générale.","space.fill_light_hint":"Couleurs distinctes pour « au moins une lampe allumée », « toutes éteintes » et « aucune source ». Couleurs et opacité suivent la palette générale.","space.temp_range":"Plage de confort","space.temp_min":"Minimum","space.temp_max":"Maximum","space.temp_range_hint":"Sous le minimum : froid. Dans la plage : confort. Au-dessus du maximum : chaud. Sans mesure de température, la lueur des sources lumineuses peut encore donner un ombrage de base.","space.show_names_hint":"Afficher les noms des pièces et les valeurs choisies.","space.show_names.help":"Masquer les noms masque aussi leurs valeurs sans effacer vos choix. La position des cartes des pièces est conservée.","space.show_names.help.aria":"Aide : noms des pièces","space.card_values":"Valeurs sur la carte","space.label_lqi_short":"Signal Zigbee","space.values_hidden":"Les valeurs sont enregistrées mais masquées.","space.values_hidden_action":"Afficher les noms des pièces","space.card_font_hint":"Met à l’échelle chaque carte de pièce de cet espace.","space.card_font.help":"100 % est la taille par défaut. Met à l’échelle toutes les cartes de pièces de cet espace en conservant tailles et positions individuelles. Appliqué à l’enregistrement.","space.card_font.help.aria":"Aide : taille de police des cartes","space.sun_inherit_short":"Comme les réglages généraux","space.north_general":"Comme les réglages généraux · {v}","space.north_custom":"Direction personnalisée","space.north_deg":"Direction du nord","space.compass_aria":"Boussole : nord à {v}","space.glow_enabled_hint":"Lueur douce autour des lampes allumées.","space.glow_enabled.help":"La lueur des lampes et la lumière du soleil sont indépendantes. Masquer les symboles d’ouvertures n’arrête aucun des deux effets. Le vitrage laisse passer le soleil même fenêtre fermée.","space.glow_enabled.help.aria":"Aide : lueur des sources lumineuses","space.error_title":"Saisissez un nom pour l’espace.","space.error_plan":"Ajoutez une image du plan ou passez au dessin à la main.","space.error_temp_range":"Le maximum doit être supérieur au minimum.","space.error_north":"Saisissez un nombre entier entre 0° et 359°.","btn.reset_100":"Réinitialiser à 100 %","dialog.unsaved":"Modifications non enregistrées","dialog.review_fields":"Vérifiez {n} champ(s)","dialog.discard_title":"Abandonner vos modifications ?","dialog.discard_message":"Vos modifications n’ont pas été enregistrées.","dialog.discard_confirm":"Abandonner","dialog.discard_keep":"Continuer la modification","gs.show_room_tooltip_hint":"Survolez une pièce sur le plan pour voir son résumé.","gs.radar_show_live_hint":"Affiche ou masque toutes les cibles radar en direct. Cela ne démarre ni n’arrête l’enregistrement d’observation.","gs.bg_custom_hint":"Couleur de fond personnalisée.","gs.bg_theme_hint":"Fond du thème utilisé.","gs.sun_rays_hint":"Tracer les rayons du soleil à travers les ouvertures des fenêtres.","gs.error_glow_radius":"Saisissez un rayon supérieur à zéro.","gs.error_north":"Saisissez un nombre entier entre 0° et 359°.","gs.opacity_of":"Opacité : {name}","room.fill_inherit_hint":"Utiliser le mode de remplissage de tout l’espace.","room.fill_following":"Comme l’espace : {mode}.","room.fill_mode_label":"Mode de remplissage","room.temp_min_label":"Minimum","room.temp_max_label":"Maximum","room.sizes_hint":"En plus de la taille des cartes de l’espace ({v} %).","room.error_temp_range":"Saisissez des nombres pour les bornes de confort.","room.error_name":"Saisissez un nom ou choisissez une zone.","marker.name_hint":"Affiché sur le plan.","marker.binding.help":"Un marqueur lié affiche l’état en direct d’un appareil ou d’une entité Home Assistant et peut agir dessus. Un appareil virtuel est un simple marqueur sans liaison.","marker.binding.help.aria":"Aide : liaison à un appareil Home Assistant","marker.binding_virtual_hint":"Un appareil virtuel est un simple marqueur sans liaison.","marker.room_hint_auto":"Placé selon la zone Home Assistant de l’appareil.","marker.room_hint_override":"Remplace le placement par zone de l’appareil.","marker.light_role_seg_auto":"Auto","marker.light_role_seg_always":"Toujours","marker.light_role_seg_never":"Jamais","marker.glow_radius_empty_hint":"Vide : rayon général ({v}).","marker.icon.help":"Vide signifie automatique : l’icône vient des règles d’icônes de cet appareil. Choisissez-en une pour remplacer, ou épinglez le choix automatique.","marker.icon.help.aria":"Aide : icône du marqueur","marker.icon_custom_hint":"Icône personnalisée pour ce marqueur.","marker.display.help":"Comment la face du marqueur réagit à l’état et à l’activité. Les modes valeur remplacent l’icône par une valeur Home Assistant.","marker.display.help.aria":"Aide : mode d’affichage","marker.size.help":"Redimensionne et fait pivoter uniquement ce marqueur sur le plan. La zone de toucher grandit avec l’icône.","marker.size.help.aria":"Aide : taille et rotation de l’icône","marker.size_short":"Taille","marker.error_binding":"Choisissez un appareil ou une entité à lier.","room.fill_seg_lqi":"Zigbee","room.fill_seg_custom":"Perso"}};function ee(e,a){const t=X[e]?.[a]??J[a];return"string"==typeof t&&t.trim().length>0}function ae(e,a,i){return t(X[e]?.[a]??J[a]??a,i)}function te(t){const n=i(t.hass,t._config?.language);return{st:(e,a)=>ae(n,e,a),shelp:t=>{const i=`${t}.aria`;return ee(n,t)&&ee(n,i)?a``:e}}}const ie=new Set(["busy","pickSaved","saved","savedBusy","savedAspect","cellCmInput","cellCmTouched","displayTouched","deleteBlockers","copy"]);function ne(e){return Y({...e,planFile:e.planFile?e.planFile.name:null},ie)}function se(e,a){Z(e,"space",ne(a))}const re=.1,oe=1e3,le=(e,a)=>{e.host._spaceDialog=a};function ce(t){M(t.host);const{host:i}=t,n=i._spaceDialog,s=i._t.bind(i),{st:r}=te(i),o=e=>`${t.idPrefix}-${e}`,l=function(e,a){const t=[];return e.title.trim()||t.push({field:`${a}-title`,message:"space.error_title"}),"file"!==e.source||e.planFile||e.planUrl||t.push({field:`${a}-plan`,message:"space.error_plan"}),"temp"!==e.fillMode||Number.isFinite(e.tempMin)&&Number.isFinite(e.tempMax)&&e.tempMin=0&&e.northDeg<=359||t.push({field:`${a}-north-deg`,message:"space.error_north"}),t}(n,t.idPrefix),c=e=>l.find(a=>a.field===e),d=function(e,a){return Q(e,"space",ne(a))}(i,n),p=d&&0===l.length&&!n.busy,h=i._importTotal>0&&"create"===n.mode?s("import.progress",{i:i._importTotal-i._importQueue.length,n:i._importTotal}):"",u=()=>{!function(e){K(e,"space")}(i),i._spaceDialog=null,i._importQueue=[],i._importTotal=0},m=async e=>{if(!d||n.busy)return void u();const a=e.currentTarget;await i._confirmDanger({key:"discard-space-dialog",kind:"warning",title:r("dialog.discard_title"),message:r("dialog.discard_message"),objectName:n.title.trim()||void 0,confirmLabel:r("dialog.discard_confirm"),cancelLabel:r("dialog.discard_keep")})?u():a?.rejectClose?.()};return{title:`${"create"===n.mode?s("space.new"):s("space.header")}${h?` · ${h}`:""}`,badge:"edit"===n.mode?n.title.trim():"",requestClose:m,body:a`
${de(t,n,o,c)} ${he(t,n,o,c)} ${ue(t,n,o)} @@ -109,7 +109,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${s("btn.delete")}
`:e} - ${G(l.length?{action:W(r("dialog.review_fields",{n:String(l.length)}),()=>{const e=l[0];if(!e)return;const a=i.renderRoot.querySelector(`#${e.field}`);a?.scrollIntoView({block:"center"}),a?.focus()})}:{text:d?r("dialog.unsaved"):""})} + ${U(l.length?{action:W(r("dialog.review_fields",{n:String(l.length)}),()=>{const e=l[0];if(!e)return;const a=i.renderRoot.querySelector(`#${e.field}`);a?.scrollIntoView({block:"center"}),a?.focus()})}:{text:d?r("dialog.unsaved"):""})}
${i._importTotal>0&&"create"===n.mode?a``:e} @@ -119,12 +119,12 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
`}}function de(t,i,l,c){const{host:d}=t,p=d._t.bind(d),{st:h,shelp:u}=te(d),m="edit"===i.mode&&i.spaceId?d._serverCfg?.spaces.find(e=>e.id===i.spaceId):void 0,_=m&&Number(m.cell_cm)>0?Number(m.cell_cm):null,g=null!==_&&Math.abs(i.cellCm-_)>1e-9,b=c(l("title")),f=c(l("plan"));return C({id:"basics",title:p("space.card_basics"),body:a` - ${P([L({label:p("space.title_label"),htmlFor:l("title"),hint:h("space.title_hint"),error:b?h(b.message):void 0,control:a`le(t,{...i,title:e.target.value})} />`}),L({label:p("space.scale_label"),htmlFor:l("cell-cm"),help:t.help("space.cell_cm.help"),hint:h("space.scale_hint"),control:I({id:l("cell-cm"),wide:!0,value:i.cellCmInput??n(i.cellCm,d._imperial),unit:p(d._imperial?"space.scale_unit_imperial":"space.scale_unit"),min:Number(n(.1,d._imperial)),max:Number(n(oe,d._imperial)),step:.1,onInput:e=>{const a=s(e),n=null==a?null:r(a,d._imperial);le(t,{...i,cellCmInput:e,cellCmTouched:!0,cellCm:null!=n&&n>0?Math.max(.1,Math.min(oe,n)):i.cellCm})}})})],{narrow:!0})} + @input=${e=>le(t,{...i,title:e.target.value})} />`}),z({label:p("space.scale_label"),htmlFor:l("cell-cm"),help:t.help("space.cell_cm.help"),hint:h("space.scale_hint"),control:I({id:l("cell-cm"),wide:!0,value:i.cellCmInput??n(i.cellCm,d._imperial),unit:p(d._imperial?"space.scale_unit_imperial":"space.scale_unit"),min:Number(n(.1,d._imperial)),max:Number(n(oe,d._imperial)),step:.1,onInput:e=>{const a=s(e),n=null==a?null:r(a,d._imperial);le(t,{...i,cellCmInput:e,cellCmTouched:!0,cellCm:null!=n&&n>0?Math.max(.1,Math.min(oe,n)):i.cellCm})}})})],{narrow:!0})} ${g?B({kind:"warning",text:h("space.scale_changed")}):e} - ${z({title:p("space.plan_label"),help:u("space.plan.help")})} + ${L({title:p("space.plan_label"),help:u("space.plan.help")})}
${v="plansrc",w=i.source,y=[{value:"draw",title:p("space.source_draw"),caption:h("space.source_draw_hint")},{value:"file",title:p("space.source_file"),caption:h("space.source_file_hint")}],k=e=>le(t,o(i,e)),$=p("space.plan_label"),a`
${y.map(e=>a`
`})}
`}function Rr(e,t="hp-paperg"){return W`${e.map(e=>"path"in e?W``:"poly"in e?W``:W``)}`}const Cr={color:"#607d8b",opacity:1,widthCm:3.6,fill:!1,fillColor:"#607d8b",fillOpacity:.25},Tr=(e,t=1)=>{const i=Number(e);return Number.isFinite(i)?Math.min(1,Math.max(0,i)):t},Dr=e=>{let t=Number(e);return Number.isFinite(t)?(t=(t%360+360)%360,t>180?t-360:t):0};function Ar(e,t,i){return Dr(t)?[e.x,e.y]:i([e.x,e.y])}function Pr(e,t,i,n){const r=Math.abs(i[0]-t[0]),o=Math.abs(i[1]-t[1]);return"line"===e?Math.hypot(r,o)>=n:r>=n&&o>=n}const Fr=(e,t,i)=>{const n=Number(e),r=Number.isFinite(t)&&t>0?t:5;return Number.isFinite(n)&&n>0?n/r*i:0},zr=(e,t,i)=>{const n=Number(e),r=Number.isFinite(t)&&t>0?t:5;return Number.isFinite(n)&&i>0?n/i*r:0},Ir=(e,t,i,n=Cr.widthCm)=>{const r=Number(e?.width_cm);if(Number.isFinite(r)&&r>0)return r;const o=Number(e?.width);return Number.isFinite(o)&&o>0?zr(o,t,i):n};function Or(e){const t=Cr;return e.color===t.color&&e.opacity===t.opacity&&e.widthCm===t.widthCm&&e.fill===t.fill&&e.fillColor===t.fillColor&&e.fillOpacity===t.fillOpacity?null:{color:e.color,opacity:Tr(e.opacity),width_cm:Math.max(.1,Math.min(100,Number(e.widthCm)||.1)),fill:!!e.fill,fill_color:e.fillColor,fill_opacity:Tr(e.fillOpacity,.25)}}function Er(e,t){return{color:e.color,opacity:Tr(e.opacity),width_cm:Math.max(.1,Math.min(100,Number(e.widthCm)||.1)),...t?{fill:e.fill,fill_color:e.fillColor,fill_opacity:Tr(e.fillOpacity,.25)}:{}}}function Nr(e){const t=e.x+e.w/2,i=e.y+e.h/2,n=Dr(e.angle)*Math.PI/180,r=Math.cos(n),o=Math.sin(n),s=(e,n)=>{const s=e-t,a=n-i;return[t+s*r-a*o,i+s*o+a*r]};return[s(e.x,e.y),s(e.x+e.w,e.y),s(e.x+e.w,e.y+e.h),s(e.x,e.y+e.h)]}function Hr(e){const t=Nr(e),i=(e,t)=>[(e[0]+t[0])/2,(e[1]+t[1])/2],n=[(t[0][0]+t[2][0])/2,(t[0][1]+t[2][1])/2];return{points:[...t,i(t[0],t[1]),i(t[1],t[2]),i(t[2],t[3]),i(t[3],t[0]),n],segments:t.map((e,i)=>({a:e,b:t[(i+1)%4]}))}}function Lr(e,t,i,n,r,o,s,a){const l=Dr(e.angle)*Math.PI/180,c=Math.cos(l),h=Math.sin(l),d=-Math.sin(l),u=Math.cos(l),p=e.x+e.w/2,_=e.y+e.h/2,m=t>0?-e.w/2:e.w/2,g=i>0?-e.h/2:e.h/2,f=p+m*c+g*d,v=_+m*h+g*u,y=n-f,b=r-v;let w=(y*c+b*h)*(t>0?1:-1),k=(y*d+b*u)*(i>0?1:-1),x=null;if(o){const t=w/Math.max(e.w,a),i=k/Math.max(e.h,a);x=Math.max(a/Math.max(e.w,a),a/Math.max(e.h,a),t,i),w=e.w*x,k=e.h*x}if(s>0)if(o){const t=Math.max(1,Math.round(e.w/s)),i=Math.max(1,Math.round(e.h/s));if(Math.abs(e.w-t*s)<1e-6&&Math.abs(e.h-i*s)<1e-6){const n=(e,t)=>{let i=Math.abs(e),n=Math.abs(t);for(;n;)[i,n]=[n,i%n];return Math.max(1,i)},r=1/n(t,i),o=Math.max(a/e.w,a/e.h),s=Math.max(o,Math.round((x??1)/r)*r);w=e.w*s,k=e.h*s}else{e.w>=e.h?(w=Math.round(w/s)*s,k=w*(e.h/Math.max(e.w,a))):(k=Math.round(k/s)*s,w=k*(e.w/Math.max(e.h,a)))}}else w=Math.round(w/s)*s,k=Math.round(k/s)*s;w=Math.max(a,w),k=Math.max(a,k);return{x:f+(t>0?w/2:-w/2)*c+(i>0?k/2:-k/2)*d-w/2,y:v+(t>0?w/2:-w/2)*h+(i>0?k/2:-k/2)*u-k/2,w:w,h:k,angle:Dr(e.angle)||void 0}}const Br=(e,t,i)=>{const n=i[0]-t[0],r=i[1]-t[1],o=n*n+r*r;if(o<1e-12)return[...t];const s=Math.max(0,Math.min(1,((e[0]-t[0])*n+(e[1]-t[1])*r)/o));return[t[0]+n*s,t[1]+r*s]};function qr(e,t,i,n){const r=n(e);let o=null;for(const r of t.points){const t=n(r),s=Math.hypot(t[0]-e[0],t[1]-e[1]);s<=i&&(!o||se.points),segments:e.flatMap(e=>e.segments)}}const Wr=Math.tan(.25*Math.PI/180);function Ur(e,t){const i=Math.abs(Number(t[0])-Number(e[0])),n=Math.abs(Number(t[1])-Number(e[1]));if(!([i,n].every(Number.isFinite)&&i>0&&n>0))return null;const r=i>=n?"horizontal":"vertical",o=Math.max(i,n),s=Math.min(i,n);return s/o>Wr?null:{axis:r,major:o,minor:s,angleDegrees:180*Math.atan2(s,o)/Math.PI}}function Gr(e,t){const i=Ur(e,t);return i?"horizontal"===i.axis?[Number(t[0]),Number(e[1])]:[Number(e[0]),Number(t[1])]:[Number(t[0]),Number(t[1])]}const Vr=e=>`${e[0]},${e[1]}`,Kr=(e,t)=>e[0]===t[0]&&e[1]===t[1],Yr=(e,t)=>{const i=Vr(e),n=Vr(t);return i{let t=0;for(let i=0;i{if(e.length<3)return!1;for(let t=0;t1e-12},Jr=(e,t)=>Kr(e,t.from)?[...t.to]:[...e],Qr=(e,t)=>e.map(e=>Array.isArray(e?.poly)?{...e,poly:e.poly.map(e=>Jr(e,t))}:e),eo=(e,t,i)=>{const n=e.flatMap((e,t)=>ni(e)?.some(e=>Kr(e,i.from))?[t]:[]);if(!n.length)return!1;for(const i of n){const n=ni(e[i]),r=ni(t[i]);if(!n||!r)continue;if(!Zr(r))return!1;const o=Math.sign(Xr(n)),s=Math.sign(Xr(r));if(o&&s&&o!==s)return!1}const r=new Set;for(const e of n){const i=ni(t[e]);if(i)for(let n=0;n{let i=0;for(const n of e){const e=ni(n);if(e)for(let n=0;n{const{a:i,b:n,axis:r}=e,o="horizontal"===r?{from:n,to:[n[0],i[1]]}:{from:n,to:[i[0],n[1]]},s="horizontal"===r?{from:i,to:[i[0],n[1]]}:{from:i,to:[n[0],i[1]]};return[{move:o,preservedDegree:to(t,i)},{move:s,preservedDegree:to(t,n)}].sort((e,t)=>t.preservedDegree-e.preservedDegree||Vr(e.move.to).localeCompare(Vr(t.move.to))||Vr(e.move.from).localeCompare(Vr(t.move.from))).map(e=>e.move)};function no(e){const t=JSON.parse(JSON.stringify(e||{}));let i=Array.isArray(t.rooms)?t.rooms:[];const n=new Map;for(const e of i){const t=ni(e);if(t)for(let e=0;ee.key.localeCompare(t.key))){let t=null;for(const n of io(e,i)){const e=a.get(Vr(n.from));if(e&&e!==Vr(n.to))continue;const r=Qr(i,n);if(eo(i,r,n)){t=n,i=r;break}}t?(a.set(Vr(t.from),Vr(t.to)),r++,s=Math.max(s,Math.hypot(t.to[0]-t.from[0],t.to[1]-t.from[1]))):o++}t.rooms=i;for(const e of t.partitions||[]){if(!Array.isArray(e?.a)||!Array.isArray(e?.b))continue;const i=Ur(e.a,e.b);if(!i)continue;const n={key:String(e.id||Yr(e.a,e.b)),a:[...e.a],b:[...e.b],axis:i.axis};let a=null;for(const i of io(n,[{poly:[e.a,e.b]}])){const n=Jr(e.a,i),r=Jr(e.b,i),o=Math.hypot(r[0]-n[0],r[1]-n[1]);if(!(o>0))continue;const s=(t.openings||[]).filter(t=>"partition"===t?.host?.kind&&t.host.id===e.id).every(e=>{const t=Number(e.host.t),i=Number(e.length);return Number.isFinite(t)&&t>=0&&t<=1&&Number.isFinite(i)&&i>0&&t*o-i/2>=-1e-12&&t*o+i/2<=o+1e-12});if(s){a=i,e.a=n,e.b=r;break}}a?(r++,s=Math.max(s,Math.hypot(a.to[0]-a.from[0],a.to[1]-a.from[1]))):o++}return{space:t,report:{wallsStraightened:r,wallsStraightenSkipped:o,maxStraightenShift:s},changed:r>0}}const ro=["rect","ellipse","furniture","image"],oo=10**9,so=240,ao=1e-4;function lo(e){if(Array.isArray(e))return e.map(e=>lo(e));if(null!==e&&"object"==typeof e){const t={};for(const[i,n]of Object.entries(e))t[i]=lo(n);return t}return e}function co(e){if("number"!=typeof e||!Number.isFinite(e))return e;const t=(e<0||Object.is(e,-0)?-1:1)*(Math.floor(Math.abs(e)*oo+.5)/oo);return 0===t?0:t}function ho(e){if("number"!=typeof e||!Number.isFinite(e))return e;const t=e*so,i=Math.round(t);if(Math.abs(t-i)null!==po(e)):[]}function mo(e){return"string"==typeof e&&ro.includes(e)}function go(e,t){for(const i of t)Object.prototype.hasOwnProperty.call(e,i)&&(e[i]=co(e[i]))}function fo(e,t){for(const i of t)Object.prototype.hasOwnProperty.call(e,i)&&(e[i]=ho(e[i]))}function vo(e){if(Array.isArray(e))for(let t=0;t{for(const r of n){const n=t[r];"number"==typeof n&&Number.isFinite(n)&&i(n,e)}},n=t=>{if(Array.isArray(t))for(let n=0;n{if(Array.isArray(e))for(const t of e)n(t)};for(const i of _o(e.rooms))t(i,["x","y","w","h"]),r(i.poly);for(const t of _o(e.walls))n(t.a),n(t.b);for(const t of _o(e.wall_segments))n(t.a),n(t.b);for(const i of _o(e.openings))t(i,["x","y"]);for(const i of _o(e.decor))"line"===i.kind?t(i,["x1","y1","x2","y2"]):mo(i.kind)?t(i,["x","y","w","h"]):"text"===i.kind&&t(i,["x","y"]);for(const t of _o(e.room_drafts))r(t.points);for(const t of _o(e.partitions))n(t.a),n(t.b);for(const t of _o(e.wall_columns))n(t.center);for(const t of _o(e.open_spans))n(t.a),n(t.b)}const r=po(t);if(!r)return;const o=new Map;if(n)for(const e of _o(n.spaces))null!=e.id&&o.set(String(e.id),e);for(const e of Object.values(r)){const t=po(e);if(!t)continue;const n=null!=t.s&&o.get(String(t.s))||null;for(const e of["x","y"]){const r=t[e];"number"==typeof r&&Number.isFinite(r)&&i(r,n)}}}function wo(e){const t=Number(e?.cell_cm);return t>0?t:5}function ko(e,t={}){const i={canonicalized:0,far:0,maxShift:0,maxShiftCm:0,spaces:[],bySpace:new Map},n=_o(po(e)?.spaces);let r=5;for(const e of n)r=Math.max(r,wo(e));bo(e,t,(e,t)=>{const n=e*so,o=Math.abs(n-Math.round(n)),s=ho(e),a=o>0&&o=ao))return;const l=a&&"number"==typeof s?Math.abs(s-e):0;if(a?i.canonicalized++:i.far++,i.maxShift=Math.max(i.maxShift,l),i.maxShiftCm=Math.max(i.maxShiftCm,l*so*(t?wo(t):r)),!t?.id||!a)return;const c=String(t.id);let h=i.bySpace.get(c);h||(h={spaceId:c,space:String(t.title||c),canonicalized:0,far:0,maxShift:0,maxShiftCm:0},i.bySpace.set(c,h)),h.canonicalized++,h.maxShift=Math.max(h.maxShift,l),h.maxShiftCm=Math.max(h.maxShiftCm,l*so*wo(t))}),i.bySpace.size&&bo(e,t,(e,t)=>{if(!t?.id)return;const n=i.bySpace.get(String(t.id));if(!n)return;const r=e*so;Math.abs(r-Math.round(r))>=ao&&n.far++}),i.spaces=[...i.bySpace.values()];const{bySpace:o,...s}=i;return s}function xo(e){return function(e){const t=e,i=po(t);i&&fo(i,["x","y"]);return t}(lo(e))}function So(e){const t=e,i=po(t);if(!i)return t;for(const e of Object.values(i)){const t=po(e);t&&fo(t,["x","y"])}return t}function $o(e){return Mo(lo(e))}function Mo(e){const t=e,i=po(t);if(!i)return t;for(const e of _o(i.spaces)){go(e,["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"]);for(const t of _o(e.rooms))fo(t,["x","y","w","h"]),yo(t.poly);for(const t of _o(e.walls))vo(t.a),vo(t.b);for(const t of _o(e.wall_segments))vo(t.a),vo(t.b);for(const t of _o(e.openings)){fo(t,["x","y"]),go(t,["angle","length"]);const e=po(t.host);e&&go(e,["t"])}for(const t of _o(e.decor))"line"===t.kind?fo(t,["x1","y1","x2","y2"]):mo(t.kind)?(fo(t,["x","y","w","h"]),go(t,["angle"])):"text"===t.kind&&(fo(t,["x","y"]),go(t,["scale","angle"]));for(const t of _o(e.room_drafts))yo(t.points);for(const t of _o(e.partitions))vo(t.a),vo(t.b);for(const t of _o(e.wall_columns))vo(t.center),"square"===t.shape&&go(t,["angle"]);for(const t of _o(e.open_spans))vo(t.a),vo(t.b)}for(const e of _o(i.markers))go(e,["angle"]);return t}const Ro=15,Co=8;function To(e,t,i,n,r){const o=i[0]-e[0],s=i[1]-e[1],a=Math.hypot(o,s);if(!(a>0)||a<=r+1e-9)return null;const l=o/a,c=s/a,h=t=>{const n=(t[0]-e[0])*l+(t[1]-e[1])*c,o=(r-n)/(a-n);return!Number.isFinite(o)||o<-1e-9||o>1+1e-9?null:[t[0]+(i[0]-t[0])*o,t[1]+(i[1]-t[1])*o]},d=h(t),u=h(n);return d&&u?[[e[0],e[1]],t,d,u,n]:null}const Do=Math.sin(.25*Math.PI/180);function Ao(e,t){return Number.isFinite(e)&&e>0&&Number.isFinite(t)&&t>0&&e*t<3}function Po(e){const t=Number(e)>0?Number(e):5;if(5===t)return 8;const i=5/t*8;return Math.min(80,Math.max(.5,i))}function Fo(e,t){return Number.isFinite(e)&&e>0&&Number.isFinite(t)&&t>0&&e*t<2}function zo(e){return Number.isFinite(e)?Math.max(1,Math.min(100,e)):1}function Io(e,t){return!Number.isFinite(e)||e<0?"":String(t?Math.round(e/2.54*100)/100:Math.round(100*e)/100)}function Oo(e,t,i){if(!Number.isFinite(e)||e<=0)return 0;const n=Number(t)>0?Number(t):5;return zo(e)/n*i}function Eo(e,t){return t>0&&Number.isFinite(e)?Math.round(e/t)*t:e}function No(e){return Math.max(1e-6*Math.abs(e),1e-9)}function Ho(e,t){if(!(t>0&&Number.isFinite(e)))return e;const i=Eo(e,t);return Math.abs(i-e)<=No(t)?i:e}function Lo(e,t){let i=t[0]-e[0],n=t[1]-e[1];const r=Math.hypot(i,n);return r<1e-12?[1,0]:(i/=r,n/=r,(i<-1e-12||Math.abs(i)<=1e-12&&n<0)&&(i=-i,n=-n),[i,n])}function Bo(e,t,i){const n=[Ho(e[0],i),Ho(e[1],i)],r=[Ho(t[0],i),Ho(t[1],i)],o=Eo((n[0]+r[0])/2,i),s=Eo((n[1]+r[1])/2,i),[a,l]=Lo(n,r);let c=Math.atan2(l,a);c<0&&(c+=Math.PI);const h=Math.round(1800*c)/1800,d=i>0&&i<.01?6:i<1?4:2;return`${o.toFixed(d)},${s.toFixed(d)}@${h.toFixed(4)}`}function qo(e,t,i,n){return 1===n?Bo(e,t,i):Bo([e[0]/n,e[1]/n],[t[0]/n,t[1]/n],i)}function jo(e,t){if(!Array.isArray(e.a)||!Array.isArray(e.b)||e.a.length<2||e.b.length<2)return null;const i=[Number(e.a[0]),Number(e.a[1]),Number(e.b[0]),Number(e.b[1])];if(!i.every(Number.isFinite))return null;const n=t>0?t:1;return[[i[0]*n,i[1]*n],[i[2]*n,i[3]*n]]}function Wo(e,t,i,n,r){const o=r>0?r:1;return{key:qo(e,t,n,o),cm:zo(i),a:[e[0]/o,e[1]/o],b:[t[0]/o,t[1]/o]}}function Uo(e,t){const i=t>0?t:1,n=[];for(const t of e){const e=t.key.lastIndexOf("@");if(e<0)continue;const[r,o]=t.key.slice(0,e).split(",").map(Number),s=Number(t.key.slice(e+1));[r,o,s].every(Number.isFinite)&&n.push({w:t,x:r*i,y:o*i,ang:s})}return n}function Go(e,t){const[i,n]=Lo(e,t);let r=Math.atan2(n,i);return r<0&&(r+=Math.PI),r}function Vo(e,t){let i=Math.abs(e-t);return i>Math.PI/2&&(i=Math.PI-i),i<.02}function Ko(e,t,i,n,r=1){if(!e?.length)return null;const o=qo(t,i,n,r),s=e.find(e=>e.key===o);if(s)return s;const a=r>0?r:1,l=No(n)*a,c=(e,t)=>Math.abs(e[0]-t[0])<=l&&Math.abs(e[1]-t[1])<=l;for(const n of e){const e=jo(n,a);if(e&&(c(e[0],t)&&c(e[1],i)||c(e[0],i)&&c(e[1],t)))return n}const h=(t[0]+i[0])/2,d=(t[1]+i[1])/2,u=Go(t,i),p=Math.max(.5*n,1e-9)*a;for(const t of Uo(e,a))if(Vo(t.ang,u)&&Math.hypot(t.x-h,t.y-d)<=p)return t.w;return null}function Yo(e,t,i,n,r=1){const o=Ko(e,t,i,n,r);if(o&&o.cm>0)return zo(o.cm);const s=function(e,t,i,n,r){if(!e?.length)return null;const o=r>0?r:1,s=Math.hypot(i[0]-t[0],i[1]-t[1]);if(s<1e-12)return null;const a=Go(t,i),l=Math.max(.5*n,1e-9)*o;let c=null;for(const n of e){if(!(n.cm>0))continue;const e=jo(n,o);if(!e)continue;const r=Math.hypot(e[1][0]-e[0][0],e[1][1]-e[0][1]);if(r<1e-12||!Vo(Go(e[0],e[1]),a))continue;if(Ns(t[0],t[1],e[0][0],e[0][1],e[1][0],e[1][1])>l||Ns(i[0],i[1],e[0][0],e[0][1],e[1][0],e[1][1])>l)continue;if(r+l(o.has(e.key)||(e=>{const t=jo(e,n);if(!t)return!1;const[i,o]=t,a=o[0]-i[0],c=o[1]-i[1],h=Math.hypot(a,c);if(h<=l)return!1;if(!s.some(e=>{const t=[e[0],e[1]],n=[e[2],e[3]];return Vo(Go(i,o),Go(t,n))&&Ns(i[0],i[1],t[0],t[1],n[0],n[1])<=l&&Ns(o[0],o[1],t[0],t[1],n[0],n[1])<=l}))return!1;const d=(r||[]).some(e=>{const t=[e[0],e[1]],n=[e[2],e[3]];if(!Vo(Go(i,o),Go(t,n)))return!1;const r=e=>Math.abs((e[0]-i[0])*c-(e[1]-i[1])*a)/h;if(r(t)>l||r(n)>l)return!1;const s=h*h,d=((t[0]-i[0])*a+(t[1]-i[1])*c)/s,u=((n[0]-i[0])*a+(n[1]-i[1])*c)/s;return Math.min(1,Math.max(d,u))-Math.max(0,Math.min(d,u))>l/h});return!d})(e))&&e.cm>=1&&e.cm<=100)}function Zo(e,t,i,n=8){const[r,o]=Lo(e,t);let s=Math.atan2(o,r);s<0&&(s+=Math.PI);let a=i*Math.PI/180%Math.PI;a<0&&(a+=Math.PI);let l=Math.abs(s-a);return l>Math.PI/2&&(l=Math.PI-l),l<=n*Math.PI/180}function Jo(e,t,i,n,r=1,o="affine",s){if(!e?.length)return[];if(t.length!==i.length)return"fixed-topology"===o&&s?.(),e.slice();const a=r>0?r:1,l=Math.max(.5*n,1e-9)*a,c=Math.max(n*a*1e-6,1e-9),h=[],d=new Map,u=new Map,p=(e,t,i)=>{const n=e.get(t)||new Set;n.add(i),e.set(t,n)};for(let e=0;e[e[0]+(t[0]-e[0])*i,e[1]+(t[1]-e[1])*i],m=(e,t)=>Math.hypot(e[0]-t[0],e[1]-t[1])<=c,g=(e,t)=>{if("fixed-topology"===o){const i=t.na[0]-t.oa[0],n=t.na[1]-t.oa[1],r=t.nb[0]-t.ob[0],o=t.nb[1]-t.ob[1];return Math.hypot(i-r,n-o)<=c?[e[0]+i,e[1]+n]:m(e,t.oa)?[...t.na]:m(e,t.ob)?[...t.nb]:[...e]}const i=Math.max(0,Math.min(1,((e[0]-t.oa[0])*t.dx+(e[1]-t.oa[1])*t.dy)/t.len2));return _(t.na,t.nb,i)},f=(e,t)=>{const[i,n]=Lo(e,t);return(t[0]-e[0])*i+(t[1]-e[1])*n>=0?[[...e],[...t]]:[[...t],[...e]]},v=[],y=[],b=(e,t,i)=>{if(Math.hypot(t[0]-e[0],t[1]-e[1])<=c)return;const[r,o]=f(e,t),s=zo(i);if(y.some(e=>e.entry.cm===s&&m(e.span[0],r)&&m(e.span[1],o)))return;const l=Wo(r,o,s,n,a);v.push(l),y.push({entry:l,span:[r,o]})};for(const t of e){const e=jo(t,a);if(e){const[i,n]=f(e[0],e[1]),r=n[0]-i[0],s=n[1]-i[1],a=r*r+s*s,d=Math.sqrt(a);if(d<=c){v.push({...t,cm:zo(t.cm)});continue}const u=[];for(const e of h){if(!Vo(Go(i,n),Go(e.oa,e.ob)))continue;const t=e=>Math.abs((e[0]-i[0])*s-(e[1]-i[1])*r)/d;if(t(e.oa)>l||t(e.ob)>l)continue;const o=((e.oa[0]-i[0])*r+(e.oa[1]-i[1])*s)/a,h=((e.ob[0]-i[0])*r+(e.ob[1]-i[1])*s)/a,p=Math.max(0,Math.min(o,h)),_=Math.min(1,Math.max(o,h));(_-p)*d>c&&u.push({lo:p,hi:_,move:e})}if(!u.length){"fixed-topology"===o?v.push({...t}):b(i,n,t.cm);continue}const p=[0,1,...u.flatMap(({lo:e,hi:t})=>[e,t])].sort((e,t)=>e-t).filter((e,t,i)=>0===t||Math.abs(e-i[t-1])*d>c),y=[];for(let e=0;e+1a>=e.lo-1e-12&&a<=e.hi+1e-12);if(!l.length){y.push([o,s]);continue}const h=[g(o,l[0].move),g(s,l[0].move)],f=l.slice(1).some(e=>{const t=g(o,e.move),i=g(s,e.move);return!m(h[0],t)||!m(h[1],i)});y.push(f?[o,s]:h)}const w=(e,t)=>{const i=e[1][0]-e[0][0],n=e[1][1]-e[0][1],r=t[1][0]-t[0][0],o=t[1][1]-t[0][1],s=Math.hypot(i,n);return!(s<=c||i*r+n*o<=0)&&Math.abs(i*o-n*r)/s<=c},k=[];for(const e of y){const t=k[k.length-1];t&&m(t[1],e[0])&&w(t,e)?t[1]=e[1]:k.push([[...e[0]],[...e[1]]])}if("fixed-topology"===o&&1===k.length){const[i,n]=k[0];if(m(i,e[0])&&m(n,e[1])||m(i,e[1])&&m(n,e[0])){v.push({...t});continue}}for(const[e,i]of k)b(e,i,t.cm);continue}if("fixed-topology"===o){const e=u.get(t.key);if(1===e?.size){const i=[...e][0];v.push(i===t.key?{...t}:{...t,key:i});continue}const i=[Uo([t],a)[0]];1!==a&&i.push(Uo([t],1)[0]);const n=i.filter(Boolean).some(e=>h.some(t=>{if(!Vo(e.ang,Go(t.oa,t.ob)))return!1;const i=((e.x-t.oa[0])*t.dx+(e.y-t.oa[1])*t.dy)/t.len2;return i>=-1e-6&&i<=1.000001&&Ns(e.x,e.y,t.oa[0],t.oa[1],t.ob[0],t.ob[1])<=l}));((e?.size||0)>1||n)&&s?.(),v.push({...t});continue}let i="";const r=d.get(t.key);if(1===r?.size&&(i=[...r][0]),!i){const e=Uo([t],a)[0];if(e){const t=new Set;for(const i of h){if(!Vo(e.ang,Go(i.oa,i.ob)))continue;const r=((e.x-i.oa[0])*i.dx+(e.y-i.oa[1])*i.dy)/i.len2;if(r<-1e-6||r>1.000001)continue;if(Ns(e.x,e.y,i.oa[0],i.oa[1],i.ob[0],i.ob[1])>l)continue;const o=g([e.x,e.y],i),[s,c]=Lo(i.na,i.nb),h=Math.max(n*a,1e-6);t.add(qo([o[0]-s*h,o[1]-c*h],[o[0]+s*h,o[1]+c*h],n,a))}1===t.size&&(i=[...t][0])}}v.push({...t,key:i||t.key,cm:zo(t.cm)})}return v}function Qo(e,t,i,n,r=1,o="affine"){return Jo(e,t,i,n,r,o)}function es(e,t,i,n,r=1,o="fixed-topology"){let s=!1;const a=Jo(e,t,i,n,r,o,()=>{s=!0});return{walls:s?(e||[]).map(e=>({...e})):a,rejected:s}}function ts(e,t,i,n=1,r=[]){const o=n>0?n:1,s=Math.abs(i),a=Math.max(s*o*ao,1e-9),l=(r||[]).flatMap(e=>{const t=jo(e,o);return t?t.map(e=>[...e]):[]}),c=e=>e.every((e,t)=>(e=>{if(!(s>0))return!0;const t=e/o/s;return Math.abs(t-Math.round(t))Math.abs(e-i[t])<=a)),h=[],d=e=>JSON.stringify([e.key,e.cm,e.a,e.b]);for(const i of e||[]){const e=jo(i,o);if(!e)continue;const[n,r]=e;if(![n[0],n[1],r[0],r[1]].every(Number.isFinite)||!c(n)||!c(r)){h.push(d(i));continue}const s=r[0]-n[0],l=r[1]-n[1],u=Math.hypot(s,l);if(u<=a){h.push(d(i));continue}const p=s/u,_=l/u,m=[];for(const e of t){const[t,i]=e;if(![t?.[0],t?.[1],i?.[0],i?.[1]].every(Number.isFinite))continue;const r=e=>Math.abs((e[0]-n[0])*_-(e[1]-n[1])*p);if(r(t)>a||r(i)>a)continue;const o=(t[0]-n[0])*p+(t[1]-n[1])*_,s=(i[0]-n[0])*p+(i[1]-n[1])*_,l=Math.max(0,Math.min(o,s)),c=Math.min(u,Math.max(o,s));c-l>a&&m.push([l,c])}m.sort((e,t)=>e[0]-t[0]||e[1]-t[1]);let g=0;for(const[e,t]of m){if(e>g+a)break;if(g=Math.max(g,t),g>=u-a)break}ge.key!==s);return null==n||n<1?a:[...a,Wo(t,i,n,r,o)]}function ns(e,t,i,n,r,o=[],s=1){let a=e?e.slice():[];for(const e of function(e,t,i,n,r=1,o=[]){const s=Ss(e,t,i,n,r,o);if(!s)return[];const a=[];for(let e=0;e0||(c=is(c,t,i,n,r,s)))}return c}function os(e){const{a:t,b:i,halfDepth:n}=e;if(!Array.isArray(t)||!Array.isArray(i)||t.length<2||i.length<2||![t[0],t[1],i[0],i[1]].every(Number.isFinite))return null;const r=i[0]-t[0],o=i[1]-t[1],s=Math.hypot(r,o);if(!(s>1e-9&&n>0&&Number.isFinite(n)))return null;const a=-o/s*n,l=r/s*n;return[[t[0]+a,t[1]+l],[i[0]+a,i[1]+l],[i[0]-a,i[1]-l],[t[0]-a,t[1]-l]]}function ss(e,t,i){return Math.hypot(e[0]-t[0],e[1]-t[1])<=i}function as(e,t,i){const n=t.b[0]-t.a[0],r=t.b[1]-t.a[1],o=n*n+r*r;if(!(o>i*i))return!1;const s=((e[0]-t.a[0])*n+(e[1]-t.a[1])*r)/o;if(!(s>0&&s<1))return!1;const a=[t.a[0]+n*s,t.a[1]+r*s];return Math.hypot(e[0]-a[0],e[1]-a[1])<=i}function ls(e,t,i,n){const r=Math.hypot(t,i);if(!(r>1e-9&&n>0))return;const o=[t/r,i/r],s=e.find(e=>Math.abs(e.u[0]*o[1]-e.u[1]*o[0])<1e-9&&e.u[0]*o[0]+e.u[1]*o[1]>1-1e-9);s?s.halfDepth=Math.max(s.halfDepth,n):e.push({u:o,halfDepth:n})}function cs(e,t){try{const i=Gt(Bs(e),Bs(t));let n=null,r=0;for(const e of i||[]){const t=e?.[0]||[],i=Math.abs(ms(t));t.length>=4&&i>r&&(r=i,n=t.slice(0,-1).map(e=>[e[0],e[1]]))}return n}catch{return null}}function hs(e,t=1e-6){const i=(e||[]).map((e,t)=>({segment:e,index:t})).filter(({segment:e})=>e&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&e.a.every(Number.isFinite)&&e.b.every(Number.isFinite)&&Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>1e-9);if(i.length<2)return[];const n=Math.max(Number.isFinite(t)?t:0,1e-9),r=i.flatMap(({segment:e})=>[e.a,e.b]).map(e=>[e[0],e[1]]).sort((e,t)=>e[0]-t[0]||e[1]-t[1]),o=[];for(const e of r)o.some(t=>ss(t,e,n))||o.push(e);const s=[];for(const e of o){const t=[];let r=!1;for(const{segment:o,index:s}of i){const i=Math.hypot(o.b[0]-o.a[0],o.b[1]-o.a[1]);ss(e,o.a,n)?t.push({u:[(o.b[0]-o.a[0])/i,(o.b[1]-o.a[1])/i],halfDepth:o.halfDepth,length:i,index:s}):ss(e,o.b,n)?t.push({u:[(o.a[0]-o.b[0])/i,(o.a[1]-o.b[1])/i],halfDepth:o.halfDepth,length:i,index:s}):as(e,o,n)&&(r=!0)}if(r||2!==t.length)continue;const[o,a]=t,l=o.u[0]*a.u[1]-o.u[1]*a.u[0];if(Math.abs(l)<1e-9)continue;const c=l<0?1:-1,h=[-o.u[1],o.u[0]],d=[-a.u[1],a.u[0]],u=[e[0]+h[0]*o.halfDepth*c,e[1]+h[1]*o.halfDepth*c],p=[e[0]-d[0]*a.halfDepth*c,e[1]-d[1]*a.halfDepth*c];if(!vs(u,o.u,p,a.u))continue;const _=[[o,a,p,[d[0]*-c,d[1]*-c]],[a,o,u,[h[0]*c,h[1]*c]]];for(const[t,,i,r]of _){const o=Math.min(2*t.halfDepth,t.length),a=[-t.u[1]*t.halfDepth,t.u[0]*t.halfDepth],l=[[e[0]+a[0],e[1]+a[1]],[e[0]+t.u[0]*o+a[0],e[1]+t.u[1]*o+a[1]],[e[0]+t.u[0]*o-a[0],e[1]+t.u[1]*o-a[1]],[e[0]-a[0],e[1]-a[1]]],c=e=>(e[0]-i[0])*r[0]+(e[1]-i[1])*r[1],h=[];for(let e=0;e=-1e-12&&h.push(t),n>1e-12&&r<-1e-12||n<-1e-12&&r>1e-12){const e=n/(n-r);h.push([t[0]+(i[0]-t[0])*e,t[1]+(i[1]-t[1])*e])}}h.length>=3&&Math.abs(ms(h))>n*n&&s.push({segmentIndex:t.index,wedge:h})}}return s}function ds(e,t=1e-6){const i=(e||[]).filter(e=>e&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&e.a.every(Number.isFinite)&&e.b.every(Number.isFinite)&&Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>1e-9);if(i.length<2)return[];const n=Math.max(Number.isFinite(t)?t:0,1e-9),r=i.flatMap(e=>[e.a,e.b]).map(e=>[e[0],e[1]]).sort((e,t)=>e[0]-t[0]||e[1]-t[1]),o=[];for(const e of r)o.some(t=>ss(t,e,n))||o.push(e);const s=[],a=i.map((e,t)=>({roomId:"",a:[e.a[0],e.a[1]],b:[e.b[0],e.b[1]],key:`join-${t}`,kind:"outer",cm:0,open:!1,half:e.halfDepth})),l=Ts(a,n);for(const e of Ds(l).fans)s.push(e);const c=e=>!!As(l,e);for(const e of o){if(c(e))continue;const t=[];for(const r of i)ss(e,r.a,n)?ls(t,r.b[0]-r.a[0],r.b[1]-r.a[1],r.halfDepth):ss(e,r.b,n)?ls(t,r.a[0]-r.b[0],r.a[1]-r.b[1],r.halfDepth):as(e,r,n)&&(ls(t,r.a[0]-e[0],r.a[1]-e[1],r.halfDepth),ls(t,r.b[0]-e[0],r.b[1]-e[1],r.halfDepth));if(!(t.length<2)){t.sort((e,t)=>Math.atan2(e.u[1],e.u[0])-Math.atan2(t.u[1],t.u[0])||e.halfDepth-t.halfDepth);for(let i=0;in*n&&s.push(m)}}}return s}function us(e,t,i,n){if(!(t>0)||!e||e.length<2)return"";if(i&&e.length>=3){let i=e;const r=e[e.length-1];if(e.length>=4&&Math.hypot(e[0][0]-r[0],e[0][1]-r[1])<1e-9&&(i=e.slice(0,-1)),i.length>=3){const e=i.map((e,i)=>n?.[i]||t),r=aa(i,e),o=ws(i,e);if(r&&o)return`${ks(r)} ${ks(xs(o))}`}}const r=[];for(let i=0;i=1e-9&&a>0&&r.push({a:o,b:s,halfDepth:a})}const o=r.map(os);for(const{segmentIndex:e,wedge:t}of hs(r)){const i=o[e];if(!i)continue;const n=cs(i,t);n&&(o[e]=n)}const s=[...o.filter(e=>!!e),...ds(r)],a=function(e){let t=null;try{for(const i of e){if(i.length<3)continue;const e=Bs(i);t=t?Wt(t,e):[e]}return t}catch{return null}}(s);return a?Qs(a):s.map(e=>ks(e)).join(" ")}function ps(e,t,i,n,r=1){if(!i.length)return!1;const o=_s(n,r),s=(e[0]+t[0])/2,a=(e[1]+t[1])/2,[l,c]=Lo(e,t);for(const e of i){const[t,i]=Lo([e[0],e[1]],[e[2],e[3]]);if(!(Math.abs(l*i-c*t)>.05)&&Ns(s,a,e[0],e[1],e[2],e[3])<=o)return!0}return!1}function _s(e,t){return Math.max(e*(t>0?t:1)*.04,1e-9)}function ms(e){let t=0;for(let i=0;ie[1]!=l>e[1]&&e[0]<(a-o)*(e[1]-s)/(l-s+0)+o&&(i=!i)}return i}([c[0]+.001*a,c[1]+.001*l],e)||(a=-a,l=-l),[a,l]}function fs(e,t){const i=e[0]*t[1]-e[1]*t[0],n=e[0]*t[0]+e[1]*t[1];return Math.abs(i)<1e-9&&n>0}function vs(e,t,i,n){const r=t[0]*n[1]-t[1]*n[0];if(Math.abs(r)<1e-12)return null;const o=[i[0]-e[0],i[1]-e[1]],s=(o[0]*n[1]-o[1]*n[0])/r;return[e[0]+s*t[0],e[1]+s*t[1]]}function ys(e,t,i){const n=e?.length||0;if(n<3||!Array.isArray(i)||i.length!==n)return 0;const r=(Math.trunc(t)%n+n)%n,o=e[r],s=e[(r+1)%n],a=s[0]-o[0],l=s[1]-o[1],c=Math.hypot(a,l);if(!(c>0))return 0;const h=Math.max(0,Number(i[r])||0);if(!(h>0))return c;const d=[a/c,l/c],u=gs(e,r),p=[o[0]+u[0]*h,o[1]+u[1]*h],_=t=>{const r=Math.max(0,Number(i[t])||0);if(!(r>0))return null;const s=e[t],a=e[(t+1)%n],l=a[0]-s[0],c=a[1]-s[1],h=Math.hypot(l,c);if(!(h>0))return null;const u=gs(e,t),_=vs(p,d,[s[0]+u[0]*r,s[1]+u[1]*r],[l/h,c/h]);return _?(_[0]-o[0])*d[0]+(_[1]-o[1])*d[1]:null},m=_((r-1+n)%n)??0,g=(_((r+1)%n)??c)-m;return g>0?g:0}function bs(e,t,i,n,r,o,s,a=1){const l=(e||[]).find(e=>e?.id===t),c=ni(l);if(!c||c.length<3)return null;const h=Fs(e,t,i,n,r,o,s,a);if(!h)return c.map(()=>0);const d=4*_s(r,a);return c.map((e,t)=>{const i=c[(t+1)%c.length],n=[(e[0]+i[0])/2,(e[1]+i[1])/2];for(let e=0;e!(e>0)))return e.map(e=>[e[0],e[1]]);const r=[];for(let o=0;o0||u>0)){r.push([e[o][0],e[o][1]]);continue}if(d>0!=u>0){const t=e[o],i=d>0?[t[0]+p*d,t[1]+_*d]:[t[0],t[1]],n=u>0?[t[0]+m*u,t[1]+g*u]:[t[0],t[1]];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}if(fs(w,k)){const t=e[o],i=[t[0]+p*d,t[1]+_*d],n=[t[0]+m*u,t[1]+g*u];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}const $=vs(x,w,S,k),M=Math.max(d,u,1e-9),R=As(i,e[o])?.limit??4*M;if($){const i=Math.hypot($[0]-e[o][0],$[1]-e[o][1]);if(Number.isFinite(i)&&i<=R){r.push($);continue}if(ta(e,t,o)){r.push($);continue}}d>0&&r.push([e[o][0]+p*d,e[o][1]+_*d]),u>0&&r.push([e[o][0]+m*u,e[o][1]+g*u]),d>0||u>0||r.push([e[o][0],e[o][1]])}return r.length>=3?r:null}function ks(e,t=!0){if(!e.length)return"";let i=`M ${e[0][0]} ${e[0][1]}`;for(let t=1;te?.id===t),a=ni(s);if(!a||a.length<3)return null;const l=_s(n,r),c=[];for(const i of e||[]){if(!i||i.id===t)continue;const e=ni(i);if(e)for(const t of Fn(a,e,l))c.push([t[0],t[1]],[t[2],t[3]])}for(const e of i||[])c.push([e[0],e[1]],[e[2],e[3]]);for(const e of o||[]){const t=jo(e,r);t&&c.push(t[0],t[1])}const h=[],d=[];for(let e=0;el)continue;const s=((e[0]-t[0])*(i[0]-t[0])+(e[1]-t[1])*(i[1]-t[1]))/(n*n);s<=r||s>=1-r||(o.some(e=>Math.abs(e-s)*n<=2*l)||o.push(s))}o.sort((e,t)=>e-t);for(const n of o)h.push([t[0]+(i[0]-t[0])*n,t[1]+(i[1]-t[1])*n]),d.push(e)}return{poly:h,parent:d,orig:a}}function $s(e,t,i,n){const r=t.poly.length,o=new Array(r).fill(0);if(!e?.length)return o;const s=new Set,a=[];for(let l=0;l0?(o[l]=zo(c.cm),s.add(c.key)):a.push(l)}if(!a.length)return o;const l=n>0?n:1,c=Math.max(.5*i,1e-9)*l,h=Uo(e,l).filter(e=>e.w.cm>0);for(let e=a.length-1;e>=0;e--){const i=a[e],n=t.poly[i],s=t.poly[(i+1)%r],d=Go(n,s);let u=null;for(const e of h){const t=jo(e.w,l);if(!t||!Vo(Go(t[0],t[1]),d))continue;if(Ns(n[0],n[1],t[0][0],t[0][1],t[1][0],t[1][1])>c||Ns(s[0],s[1],t[0][0],t[0][1],t[1][0],t[1][1])>c)continue;const i=Math.hypot(s[0]-n[0],s[1]-n[1]),r=Math.hypot(t[1][0]-t[0][0],t[1][1]-t[0][1]),o=Math.max(0,r-i);(!u||oc||Ns(r[0],r[1],t[0][0],t[0][1],t[1][0],t[1][1])>c)continue;i=!0,o=Math.max(0,Math.hypot(t[1][0]-t[0][0],t[1][1]-t[0][1])-_)}else{if(Ns(e.x,e.y,n[0],n[1],r[0],r[1])>c)continue;o=Math.hypot(e.x-d,e.y-u)}(!p||i&&!p.exact||i===p.exact&&o0?i:1,o=(e||[]).filter(e=>e&&!e.open&&null!==e.kind&&Number.isFinite(e.half)&&e.half>0&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&[e.a[0],e.a[1],e.b[0],e.b[1]].every(Number.isFinite)&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>n).sort((e,t)=>e.key.localeCompare(t.key)||e.a[0]-t.a[0]||e.a[1]-t.a[1]||e.b[0]-t.b[0]||e.b[1]-t.b[1]||e.half-t.half),s=new Map;for(const e of o){const t=s.get(e.key);t?e.half>t.half&&s.set(e.key,{...t,half:e.half}):s.set(e.key,e)}const a=[...s.values()].flatMap(e=>[{point:[e.a[0],e.a[1]],other:e.b,halfDepth:e.half,kind:e.kind,key:e.key},{point:[e.b[0],e.b[1]],other:e.a,halfDepth:e.half,kind:e.kind,key:e.key}]).sort((e,t)=>e.point[0]-t.point[0]||e.point[1]-t.point[1]||e.other[0]-t.other[0]||e.other[1]-t.other[1]||e.halfDepth-t.halfDepth),l=new Map;for(const e of a){const[t,i]=Ms(e.point,n),r=Rs(t,i),o=l.get(r)||[];o.push(e),l.set(r,o)}const c=[],h=new Map;for(const e of a){const t=Cs(h,e.point,n).filter(t=>Math.hypot(t.point[0]-e.point[0],t.point[1]-e.point[1])<=n).sort((t,i)=>Math.hypot(t.point[0]-e.point[0],t.point[1]-e.point[1])-Math.hypot(i.point[0]-e.point[0],i.point[1]-e.point[1])||t.point[0]-i.point[0]||t.point[1]-i.point[1]);let i=t[0];if(!i){i={point:[...e.point],rays:[]},c.push(i);const[t,r]=Ms(i.point,n),o=Rs(t,r),s=h.get(o)||[];s.push(i),h.set(o,s)}const r=e.other[0]-e.point[0],o=e.other[1]-e.point[1],s=Math.hypot(r,o);if(!(s>n))continue;const a=[r/s,o/s];let l=Math.atan2(a[1],a[0]);l<0&&(l+=2*Math.PI),i.rays.push({u:a,halfDepth:e.halfDepth,length:s,angle:l})}const d=[],u=e=>{const t=1e-9*Math.max(1,r),i=e.filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Number.isFinite(e.length)&&e.length>n);return i.filter((e,n)=>!i.some((i,r)=>r!==n&&i.halfDepth>=e.halfDepth-t&&i.length>=e.length-t&&(i.halfDepth>e.halfDepth+t||i.length>e.length+t||re.length-t.length||e.halfDepth-t.halfDepth).map(e=>({...e}))};for(const e of c){const t=e.rays.sort((e,t)=>e.angle-t.angle||e.length-t.length||e.halfDepth-t.halfDepth),i=[];for(const e of t){const t=i[i.length-1];t&&Math.abs(e.angle-t.angle)<=1e-9?t.supports.push({halfDepth:e.halfDepth,length:e.length}):i.push({u:[...e.u],angle:e.angle,supports:[{halfDepth:e.halfDepth,length:e.length}]})}if(i.length>1&&2*Math.PI-i[i.length-1].angle+i[0].angle<=1e-9){const e=i.pop();i[0].supports.push(...e.supports)}if(i.length<3)continue;const r=i.map(t=>{const i=u(t.supports),r=new Set,o=[];for(const s of i){const i=[e.point[0]+t.u[0]*s.length,e.point[1]+t.u[1]*s.length];for(const t of Cs(l,i,n)){if("shared"!==t.kind||Math.hypot(t.point[0]-i[0],t.point[1]-i[1])>n)continue;const s=t.other[0]-t.point[0],a=t.other[1]-t.point[1],l=Math.hypot(s,a);if(!(l>n))continue;const c=s/l,h=a/l;if(Math.hypot(t.other[0]-e.point[0],t.other[1]-e.point[1])<=n)continue;const d=`${t.key}|${t.point[0]}|${t.point[1]}|${t.other[0]}|${t.other[1]}|${t.halfDepth}`;r.has(d)||(r.add(d),o.push({start:[t.point[0],t.point[1]],u:[c,h],length:l,halfDepth:t.halfDepth}))}}return o.sort((e,t)=>e.start[0]-t.start[0]||e.start[1]-t.start[1]||e.u[0]-t.u[0]||e.u[1]-t.u[1]||e.length-t.length||e.halfDepth-t.halfDepth),{u:[...t.u],halfDepth:Math.max(...i.map(e=>e.halfDepth)),length:Math.max(...i.map(e=>e.length)),supports:i,continuations:o}}).filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Number.isFinite(e.length)&&e.length>n);if(r.length<3)continue;const o=Math.max(...r.map(e=>e.halfDepth));o>0&&Number.isFinite(o)&&d.push({point:[...e.point],rays:r,halfDepth:o,limit:1.25*o})}d.sort((e,t)=>e.point[0]-t.point[0]||e.point[1]-t.point[1]);const p=new Map;for(const e of d){const[t,i]=Ms(e.point,n),r=Rs(t,i),o=p.get(r)||[];o.push(e),p.set(r,o)}return{epsilon:n,coordinateScale:r,nodes:d,index:p}}function Ds(e){const t={fans:[],supports:[]};if(!e?.nodes?.length)return t;const i=Math.max(e.epsilon,1e-9)**2;for(const n of e.nodes){const e=n.rays.filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0).map(e=>({...e,thickLength:Math.max(...e.supports.filter(t=>t.halfDepth>=e.halfDepth-1e-12).map(e=>e.length),0),angle:(()=>{const t=Math.atan2(e.u[1],e.u[0]);return t<0?t+2*Math.PI:t})()})).sort((e,t)=>e.angle-t.angle);if(e.length<2)continue;const r=n.point;for(const i of e)for(const e of i.supports){if(!(e.halfDepth>0&&e.length>0))continue;const n=-i.u[1]*e.halfDepth,o=i.u[0]*e.halfDepth,s=[r[0]+i.u[0]*e.length,r[1]+i.u[1]*e.length];t.supports.push([[r[0]+n,r[1]+o],[s[0]+n,s[1]+o],[s[0]-n,s[1]-o],[r[0]-n,r[1]-o]])}for(let n=0;n{const e=s.angle-o.angle;return e>0?e:e+2*Math.PI})();if(a<1e-9)continue;const l=a>Math.PI+1e-9,c=4*Math.max(o.halfDepth,s.halfDepth),h=[r[0]-o.u[1]*o.halfDepth,r[1]+o.u[0]*o.halfDepth],d=[r[0]+s.u[1]*s.halfDepth,r[1]-s.u[0]*s.halfDepth],u=o.u[0]*s.u[1]-o.u[1]*s.u[0],p=e=>{let t=Math.atan2(e[1]-r[1],e[0]-r[0])-o.angle;for(;t<0;)t+=2*Math.PI;return t<=a+1e-9};let _=null;if(Math.abs(u)>1e-9){const e=((d[0]-h[0])*s.u[1]-(d[1]-h[1])*s.u[0])/u,t=((d[0]-h[0])*o.u[1]-(d[1]-h[1])*o.u[0])/u,i=[h[0]+o.u[0]*e,h[1]+o.u[1]*e];(l?e<=1e-9&&t<=1e-9:e>1e-9&&e<=o.thickLength&&t<=s.thickLength)&&Math.hypot(i[0]-r[0],i[1]-r[1])<=c&&p(i)&&(_=i)}const m=e=>{Math.abs(ms(e))>i&&t.fans.push(e)};if(_){const e=1.5*Math.max(o.halfDepth,s.halfDepth);m(To([r[0],r[1]],h,_,d,e)??[[r[0],r[1]],h,_,d]);continue}if(l){m([[r[0],r[1]],h,d]);continue}const g=(e,t)=>Math.min(t,Math.sqrt(Math.max(c**2-e**2,0)),2*Math.max(o.halfDepth,s.halfDepth)),f=[h[0]+o.u[0]*g(o.halfDepth,o.thickLength),h[1]+o.u[1]*g(o.halfDepth,o.thickLength)],v=[d[0]+s.u[0]*g(s.halfDepth,s.thickLength),d[1]+s.u[1]*g(s.halfDepth,s.thickLength)];m([[r[0],r[1]],h,f,v,d])}}return t}function As(e,t){return!e||!Array.isArray(t)||t.length<2||!t.slice(0,2).every(Number.isFinite)?null:Cs(e.index,t,e.epsilon).filter(i=>Math.hypot(i.point[0]-t[0],i.point[1]-t[1])<=e.epsilon).sort((e,i)=>Math.hypot(e.point[0]-t[0],e.point[1]-t[1])-Math.hypot(i.point[0]-t[0],i.point[1]-t[1])||e.point[0]-i.point[0]||e.point[1]-i.point[1])[0]||null}function Ps(e,t,i,n,r,o,s){return Ts(zs(e,t,i,n,r,o,s),4*_s(n,s),s)}function Fs(e,t,i,n,r,o,s,a=1){const l=Ss(e,t,n,r,a,i);if(!l)return null;const c=function(e,t,i){const n=(e||[]).find(e=>e?.id===t),r=ni(n);if(!r)return[];const o=[];for(const n of e||[]){if(!n||n.id===t)continue;const e=ni(n);if(e)for(const t of Fn(r,e,i))o.push(t)}return o}(e,t,_s(r,a)),h=function(e,t,i,n,r){const o=_s(n,r),s=[];for(let a=0;aNs(h,d,e[0],e[1],e[2],e[3])<=o);s.push(u?"shared":"outer")}return s}(l.poly,c,n,r,a),d=$s(i,l,r,a),u=d.map((e,t)=>h[t]&&e>0?Oo(e,o,s)/2:0);return{...l,kinds:h,cms:d,offsets:u}}function zs(e,t,i,n,r,o,s=1){const a=[];for(const l of e||[]){if(!l?.id)continue;const c=Fs(e,l.id,t,i,n,r,o,s);if(c)for(let e=0;e0&&(a=is(a,e.a,e.b,e.cm,n,s));return a}function Os(e,t,i,n,r,o,s=1){if(!t?.length)return[];const a=zs(e,t,i,n,r,o,s),l=new Map;for(const e of a){if(e.open||!e.kind||!e.roomId)continue;const t=l.get(e.key)||new Set;t.add(e.roomId),l.set(e.key,t)}const c=e=>{const t=[...l.get(e)||[]].sort();return 1!==t.length&&2!==t.length?`ambiguous:${e}`:`${1===t.length?"outer":"shared"}:${t.join("|")}`},h=[],d=new Set;for(const e of a)!e.open&&e.cm>0&&!d.has(e.key)&&(d.add(e.key),h.push({...e,ownerSignature:c(e.key)}));const u=[];for(const a of e||[]){if(!a?.id)continue;const l=Fs(e,a.id,t,i,n,r,o,s);if(l)for(let e=0;e0)||null===l.kinds[i]){e++;continue}const o=c(qo(l.poly[i],l.poly[(i+1)%l.poly.length],n,s));let a=e;for(;a+10&&u.push({a:[d[0],d[1]],b:[p[0],p[1]],key:qo(d,p,n,s),cm:r,len:_,ownerSignature:o}),e=a+1}}}u.sort((e,t)=>t.len-e.len||e.key.localeCompare(t.key));const p=[],_=new Set,m=new Set,g=4*_s(n,s);for(const e of u){const t=h.filter(t=>!m.has(t.key)&&t.cm===e.cm&&t.ownerSignature===e.ownerSignature&&Vo(Go(t.a,t.b),Go(e.a,e.b))&&Ns(t.a[0],t.a[1],e.a[0],e.a[1],e.b[0],e.b[1])<=g&&Ns(t.b[0],t.b[1],e.a[0],e.a[1],e.b[0],e.b[1])<=g);if(t.length){for(const e of t)m.add(e.key);_.has(e.key)||(_.add(e.key),p.push(Wo(e.a,e.b,e.cm,n,s)))}}for(const e of h)m.has(e.key)||_.has(e.key)||(_.add(e.key),p.push(Wo(e.a,e.b,e.cm,n,s)));return p}function Es(e,t,i,n,r,o,s,a=1){const l=_s(r,a),c=(n[0]+n[2])/2,h=(n[1]+n[3])/2,d=Go([n[0],n[1]],[n[2],n[3]]);let u=null;for(const n of zs(e,t,i,r,o,s,a)){if(!Vo(Go(n.a,n.b),d))continue;const e=Ns(c,h,n.a[0],n.a[1],n.b[0],n.b[1]);e>4*l||(!u||e[e[0],e[1]]),o=Math.abs(ms(r));r.length>=3&&o>i&&(t=r,i=o)}return t}function Ls(e,t,i,n,r,o,s,a=1,l,c){const h=(e||[]).find(e=>e?.id===t),d=ni(h);if(!d||d.length<3)return null;if(!i?.length)return d.map(e=>[e[0],e[1]]);const u=Fs(e,t,i,n,r,o,s,a);if(!u||!u.offsets.some(e=>e>0))return d.map(e=>[e[0],e[1]]);const p=c||Ps(e,i,n,r,o,s,a),_=ws(u.poly,u.offsets,p);if(!_)return d.map(e=>[e[0],e[1]]);if(!p.nodes.length)return _;const m=void 0===l?ia(e,i,n,[],r,o,s,a):null,g=l??("ok"===m?.status||"degraded-extra"===m?.status?m.roomGeom:void 0);if(g)try{const e=Hs(Gt(Bs(u.poly),g));if(e)return e}catch{}return function(e,t){try{return Hs(Ut(Bs(e),Bs(t)))}catch{return null}}(_,u.poly)||d.map(e=>[e[0],e[1]])}function Bs(e){const t=e.map(e=>[e[0],e[1]]);return t.push([e[0][0],e[0][1]]),[t]}function qs(e){return!(!Array.isArray(e)||!e.length)&&e.every(e=>Array.isArray(e)&&e.length&&e.every(e=>Array.isArray(e)&&e.length>=4&&e.every(e=>Array.isArray(e)&&e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1])))&&Math.abs(Ci(e[0]))>1e-9)}function js(e,t,i,n){const r=n?new Set(n):null;let o=null;for(let n=0;nt.epsilon))continue;const l=Ks([[e.point[0]+a[0]*n.halfDepth,e.point[1]+a[1]*n.halfDepth],[e.point[0]+s.u[0]*r+a[0]*n.halfDepth,e.point[1]+s.u[1]*r+a[1]*n.halfDepth],[e.point[0]+s.u[0]*r-a[0]*n.halfDepth,e.point[1]+s.u[1]*r-a[1]*n.halfDepth],[e.point[0]-a[0]*n.halfDepth,e.point[1]-a[1]*n.halfDepth]],t.coordinateScale);if(!l)continue;const c=Bs(l);o=o?Wt(o,c):c}}return o}function Ws(e,t,i){let n=null;for(const r of e.rays)for(const e of r.continuations){const r=[-e.u[1],e.u[0]],o=[e.start[0]+e.u[0]*e.length,e.start[1]+e.u[1]*e.length],s=Ks([[e.start[0]+r[0]*e.halfDepth,e.start[1]+r[1]*e.halfDepth],[o[0]+r[0]*e.halfDepth,o[1]+r[1]*e.halfDepth],[o[0]-r[0]*e.halfDepth,o[1]-r[1]*e.halfDepth],[e.start[0]-r[0]*e.halfDepth,e.start[1]-r[1]*e.halfDepth]],t.coordinateScale);if(!s)continue;const a=Ut(Bs(s),i);Array.isArray(a)&&0!==a.length&&(n=n?Wt(n,a):a)}return n}function Us(e,t,i=2*(4*e.halfDepth+2*t.epsilon)){const n=function(e,t=Do){const i=new Set,n=Number.isFinite(t)&&t>=0?t:Do;for(let t=0;te-t)}(e);return n.length?js(e,t,i,n):null}function Gs(e,t,i,n,r){const o=function(e){let t=null;for(const i of e){const e=Bs(i);try{t=t?Wt(t,e):e}catch{}}return t}(function(e,t,i=!1){if(!e)return[];const n=[];for(const r of e.nodes)for(let o=0;o1e-9)||h>=Math.PI-1e-9)continue;const d=[-s.u[1],s.u[0]],u=[-a.u[1],a.u[0]],p=[r.point[0]+d[0]*s.halfDepth,r.point[1]+d[1]*s.halfDepth],_=[r.point[0]-u[0]*a.halfDepth,r.point[1]-u[1]*a.halfDepth],m=vs(p,s.u,_,a.u);if(!m)continue;const g=Math.hypot(m[0]-r.point[0],m[1]-r.point[1]);if(!Number.isFinite(g)||g<=r.limit)continue;const f=t?Math.sqrt(Math.max(0,r.limit*r.limit-s.halfDepth*s.halfDepth)):0,v=t?Math.sqrt(Math.max(0,r.limit*r.limit-a.halfDepth*a.halfDepth)):0,y=Ks([[p[0]+s.u[0]*f,p[1]+s.u[1]*f],[_[0]+a.u[0]*v,_[1]+a.u[1]*v],m],e.coordinateScale);if(y&&n.push(y),i){const t=m[0]-r.point[0],i=m[1]-r.point[1],o=Math.hypot(t,i),s=g-r.limit;if(o>e.epsilon&&s>e.epsilon){const a=Math.min(Math.max(8*e.epsilon,.05*r.halfDepth),.25*s),l=t/o,c=i/o,h=-c,d=l,u=Ks([[m[0]-l*a+h*a,m[1]-c*a+d*a],[m[0]-l*a-h*a,m[1]-c*a-d*a],[m[0]+l*a,m[1]+c*a]],e.coordinateScale);u&&n.push(u)}}}return n}({...t,nodes:[e]},i,n));return o&&r?Gt(o,r):o}function Vs(e,t,i,n){if(!e||!t.nodes.length)return e;let r=null;try{r=function(e){let t=null;for(const i of e.nodes){const n=Us(i,e);n&&(t=t?Wt(t,n):n)}return t}(t)}catch{return e}let o=e;for(const e of t.nodes){const s=4*e.halfDepth+2*t.epsilon,a=2*s,l=[[e.point[0]-s,e.point[1]-s],[e.point[0]+s,e.point[1]-s],[e.point[0]+s,e.point[1]+s],[e.point[0]-s,e.point[1]+s]];try{let s=o;const c=Gs(e,t,!1,!0,r);c&&(s=Gt(s,c));let h=js(e,t,a);const d=Gs(e,t,!0,!0,r);d&&(h=Gt(h,d)),r&&(h=Wt(h,r));const u=.02*Math.min(...e.rays.map(e=>e.halfDepth));if(h=Wt(h,Bs([[e.point[0]-u,e.point[1]-u],[e.point[0]+u,e.point[1]-u],[e.point[0]+u,e.point[1]+u],[e.point[0]-u,e.point[1]+u]])),!h)continue;let p=Ut(h,Bs(l));n?p=Ut(p,n):i&&(p=Ut(p,i));const _=Bs(l),m=Gt(s,_),g=i?Gt(Ut(s,_),i):null,f=Ws(e,t,_);o=Wt(m,...g?[g]:[],...f?[f]:[],p)}catch{}}if(r)try{let e=r;n?e=Ut(e,n):i&&(e=Ut(e,i)),o=Wt(o,e)}catch{}return o}function Ks(e,t=1){if(!Array.isArray(e)||e.length<3)return null;const i=Number.isFinite(t)&&t>0?t:1,n=1e-12*Math.max(1,i),r=[];for(const t of e){if(!Array.isArray(t)||t.length<2)return null;const e=Number(t[0]),i=Number(t[1]);if(!Number.isFinite(e)||!Number.isFinite(i))return null;const o=Math.round(e/n)*n,s=Math.round(i/n)*n;if(!Number.isFinite(o)||!Number.isFinite(s))return null;r.push([Object.is(o,-0)?0:o,Object.is(s,-0)?0:s])}return Math.abs(ms(r))>n*n?r:null}function Ys(e,t,i,n){if(Ns(e[0],e[1],t[0],t[1],i[0],i[1])>n)return!1;const r=i[0]-t[0],o=i[1]-t[1],s=(e[0]-t[0])*r+(e[1]-t[1])*o,a=r*r+o*o,l=n*Math.sqrt(a);return s>=-l&&s<=a+l}function Xs(e,t,i){const n=[],r=[];for(let o=0;oi*i))continue;const d=i/Math.sqrt(h),u=[0,1];for(const e of t)for(const t of[e.a,e.b]){if(!Ys(t,s,a,i))continue;const e=((t[0]-s[0])*l+(t[1]-s[1])*c)/h;e>d&&e<1-d&&u.push(e)}u.sort((e,t)=>e-t);const p=u.filter((e,t)=>0===t||Math.abs(e-u[t-1])>d);for(let e=0;e=3&&r.length===n.length?{poly:n,offsets:r}:null}function Zs(e,t,i,n,r,o,s,a){const l=(e||[]).map(ni).filter(e=>!!e&&e.length>=3);if(!l.length)return null;let c=Wt(Bs(l[0]));for(let e=1;e"outer"===e.kind&&e.half>0),u=4*_s(n,s),p=a||Ts(h,u,s);let _=null;for(const e of function(e){const t=[];for(const i of Array.isArray(e)?e:[])if(Array.isArray(i))for(const e of i){if(!Array.isArray(e)||e.length<4)continue;const i=e.slice(0,-1).map(e=>[e[0],e[1]]);i.length>=3&&t.push(i)}return t}(c)){const t=Xs(e,d,u);if(!t||!t.offsets.some(e=>e>0))continue;const i=aa(t.poly,t.offsets,p),n=ws(t.poly,t.offsets,p);if(!i||!n)continue;const r=Gt(Bs(i),Bs(n));_=_?Wt(_,r):r}return{centre:c,shell:_||[]}}function Js(e,t,i,n,r,o,s=1){try{const a=Zs(e,t,i,n,r,o,s,Ps(e,t,i,n,r,o,s));if(!a)return[];return a.shell?.length?Wt(a.centre,a.shell):a.centre}catch{return null}}function Qs(e){if(!e)return"";let t="";for(const i of e)if(Array.isArray(i))for(const e of i){if(!Array.isArray(e)||e.length<4)continue;const i=e.slice(0,e.length-1);i.length<3||(t+=(t?" ":"")+ks(i.map(e=>[e[0],e[1]])))}return t}const ea=15;function ta(e,t,i){const n=e?.length||0;if(n<3||t?.length!==n)return!1;const r=e[(i-1+n)%n],o=e[i],s=e[(i+1)%n],a=[r[0]-o[0],r[1]-o[1]],l=[s[0]-o[0],s[1]-o[1]],c=Math.hypot(a[0],a[1]),h=Math.hypot(l[0],l[1]);if(!(c>1e-9&&h>1e-9))return!1;const d=Math.max(-1,Math.min(1,(a[0]*l[0]+a[1]*l[1])/(c*h))),u=Math.acos(d);if(!(u>1e-9))return!1;if(u>=ea*Math.PI/180)return!1;const p=Math.max(0,t[(i-1+n)%n]),_=Math.max(0,t[i]);if(!(p>0||_>0))return!1;const m=Math.sin(u);if(!(m>1e-12))return!1;const g=(_+p*d)/m,f=(p+_*d)/m;return Number.isFinite(g)&&Number.isFinite(f)&&g>0&&f>0&&ge>0))continue;for(const e of l.offsets)e>0&&(u=Math.max(u,2*e));const c=aa(l.poly,l.offsets,d),p=ws(l.poly,l.offsets,d);c&&h.push({outset:c,inset:p})}for(const e of l){const t=e.map(e=>e[0]),i=e.map(e=>e[1]);if(t.length){const n=Math.min(Math.max(...t)-Math.min(...t),Math.max(...i)-Math.min(...i)),r=Math.min(...e.map((t,i)=>{const n=e[(i+1)%e.length];return Math.hypot(n[0]-t[0],n[1]-t[1])}));u=Math.max(u,e.length>16?n:r)}}const p=function(e,t,i,n,r,o,s,a){if(!t?.length||!i?.length)return[];const l=4*_s(n,s),c=new Map;for(const a of zs(e,t,i,n,r,o,s))!a.open&&a.half>0&&!c.has(a.key)&&c.set(a.key,a);const h=[...c.values()];if(h.length<2)return[];const d=a||Ts(h,l),u=[];for(const e of i)for(const t of[[e[0],e[1]],[e[2],e[3]]])u.some(e=>Math.hypot(e[0]-t[0],e[1]-t[1])<=l)||u.push(t);const p=[],_=(e,t)=>{let i=0,n=0;if(Math.hypot(e.a[0]-t[0],e.a[1]-t[1])<=l)i=e.b[0]-e.a[0],n=e.b[1]-e.a[1];else{if(!(Math.hypot(e.b[0]-t[0],e.b[1]-t[1])<=l))return null;i=e.a[0]-e.b[0],n=e.a[1]-e.b[1]}const r=Math.hypot(i,n);return r>l?[i/r,n/r]:null};for(const e of u){const t=h.map(t=>({iv:t,u:_(t,e)})).filter(e=>!!e.u);for(let i=0;i0?[e.slice(),u,m,_]:[e.slice(),_,m,u];else{if(!f)continue;{const t=[-r.u[1],r.u[0]],i=[-o.u[1],o.u[0]],n=s<0?1:-1,a=[e[0]+t[0]*r.iv.half*n,e[1]+t[1]*r.iv.half*n],l=[e[0]-i[0]*o.iv.half*n,e[1]-i[1]*o.iv.half*n];y=s>0?[e.slice(),a,l]:[e.slice(),l,a]}}Math.abs(ms(y))>l*l&&p.push(y)}}return p}(e,t,i,r,o,s,a,d),_=n.length?la(e,t,i,r,o,s,a):null;let m="exterior";try{const v=Zs(e,t,i,r,o,s,a,d);m="paper";const y=v?v.shell?.length?Wt(v.centre,v.shell):v.centre:[],b=e=>{const t=Bs(e.outset);if(!e.inset)return t;const i=Bs(e.inset);return Gt(t,i)};m="room-rings";let w=null;for(const e of h)try{const t=b(e);w=w?Wt(w,t):t}catch{}if(m="edge-bodies",v)for(const n of oa(e,t,i,r,o,s,a))try{const e=Ut(Bs(n.quad),v.centre);w=w?Wt(w,e):e}catch{}m="junctions",w=function(e,t,i=1,n=Wt){let r=e;for(const e of t||[]){const t=Ks(e,i);if(t)try{const e=Bs(t);r=r?n(r,e):e}catch{}}return r}(w,p,a),m="facade-clip",w&&v&&(w=Ut(w,v.centre)),m="exterior-shell";const k=[];let x=0;if(v?.shell?.length)if(w)try{const e=Wt(w,v.shell);if(!qs(e))throw new Error("invalid shell union");w=e}catch{if(!qs(w)||!qs(v.shell))throw new Error("invalid shell");k.push({id:"exterior-shell",geom:v.shell}),x++}else w=v.shell;if(m="multi-wall-trim",w&&d.nodes.length){const e=e=>e.rays.some(e=>e.supports.some(e=>e.length<2*e.halfDepth)),t=d.nodes.filter(e);if(t.length){w=Vs(w,{...d,nodes:t},v?.centre,y)}}if(m="junction-corners",d.nodes.length){const n=Ds(d),l=function(e,t,i,n,r,o,s,a){try{const l=Zs(e,t,i,n,r,o,s,{epsilon:a.epsilon,coordinateScale:a.coordinateScale,nodes:[],index:new Map});return l?l.shell?.length?Wt(l.centre,l.shell):l.centre:null}catch{return null}}(e,t,i,r,o,s,a,d);for(const e of n.fans)try{let t=[Bs(e)];if(l&&(t=Ut(t,l)),!t?.length)continue;w=w?Wt(w,t):t}catch{}g=w,f=Math.max(d.epsilon,1e-9)**2,w=Array.isArray(g)?g.map(e=>{if(!Array.isArray(e)||!e.length)return e;const[t,...i]=e;return Math.abs(ms(t||[]))<=f?null:[t,...i.filter(e=>Math.abs(ms(e||[]))>f)]}).filter(e=>!!e):g}const S=w||[],$=[...qs(S)?[{id:"room-primary",geom:S}]:[],...k.map((e,t)=>({id:`room-isolated-${t}`,geom:e.geom}))];m="openings";for(const e of n){if(!(e.length>0))continue;const t=da(_,e,!0);if(!t.negative&&!t.positive)continue;const i=e.angle*Math.PI/180,n=Math.cos(i),o=Math.sin(i),s=-o,l=n,c=e.length/2,h=1.25*Math.max(u,r*a),d=[[e.x-n*c-s*h,e.y-o*c-l*h],[e.x+n*c-s*h,e.y+o*c-l*h],[e.x+n*c+s*h,e.y+o*c+l*h],[e.x-n*c+s*h,e.y-o*c+l*h]];w&&(w=Gt(w,Bs(d)));for(const e of k)e.geom=Gt(e.geom,Bs(d))}m="extras";const M=[];let R=0;const C=c.mergeExtra||((e,t)=>e?Wt(e,t):t);for(let e=0;ee.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]))||Math.abs(Ci(t))<=1e-9){R++;continue}const i=[Bs(t)];try{const t=C(w,i,e);if(!qs(t))throw new Error("invalid extra union");w=t}catch{R++,qs(i)&&M.push({id:`extra-${e}`,geom:i})}}M.push(...k),M.sort((e,t)=>Qs(e.geom).localeCompare(Qs(t.geom)));const T=w||[];return{status:R||x?"degraded-extra":"ok",geom:T,components:[...qs(T)?[{id:"primary",geom:T}]:[],...M.map((e,t)=>({...e,id:`isolated-${t}`}))],roomGeom:S,roomComponents:$,paperGeom:y,depthUnits:u,openingPadUnits:1.25*Math.max(u,r*a),openingIndex:_,multiWallNodes:d,degradedExtraCount:R+x}}catch{return c.onCoreFailure?.(m),{status:"failed-core",geom:[],components:[],roomGeom:[],paperGeom:[],roomComponents:[],depthUnits:u,openingIndex:null,multiWallNodes:d,degradedExtraCount:0}}var g,f}function na(e,t,i,n=[],r,o,s,a=1,l=[],c={}){if(!t?.length&&!l.length)return null;return ra(ia(e,t,i,n,r,o,s,a,l,c))}function ra(e){if("failed-core"===e.status||"not-applicable"===e.status)return null;const t=e.components.map(e=>({id:e.id,d:Qs(e.geom),fillRule:"evenodd"})).filter(e=>!!e.d),i=t[0]?.d||"",n=Qs(e.paperGeom);if(t.length){const r={status:e.status,d:i,paths:t,components:e.components,roomGeom:e.roomGeom,multiWallNodes:e.multiWallNodes,paperD:n,depthUnits:e.depthUnits,fillRule:"evenodd"};return Object.defineProperties(r,{roomComponents:{value:e.roomComponents||[],enumerable:!1},openingIndex:{value:e.openingIndex,enumerable:!1},openingPadUnits:{value:e.openingPadUnits,enumerable:!1}}),r}return null}function oa(e,t,i,n,r,o,s=1){if(!t?.length)return[];const a=new Set,l=[];for(const c of e||[]){if(!c?.id)continue;const h=Fs(e,c.id,t,i,n,r,o,s);if(!h)continue;const d=h.poly;for(let e=0;e0))continue;const p=qo(t,i,n,s);if(a.has(p))continue;a.add(p);const _=Oo(u,r,o),[m,g]=gs(d,e),f=-m,v=-g,y=_/2,b=[[t[0]+f*y,t[1]+v*y],[i[0]+f*y,i[1]+v*y],[i[0]+m*y,i[1]+g*y],[t[0]+m*y,t[1]+g*y]];l.push({key:p,kind:c,cm:u,quad:b,a:[t[0],t[1]],b:[i[0],i[1]],depthUnits:_})}}return l}function sa(e,t=[]){let i=ks(e.quad);const[n,r]=Lo(e.a,e.b),o=n,s=r,a=-s,l=o;for(const n of t){if(!Zo(e.a,e.b,n.angle))continue;if(Ns(n.x,n.y,e.a[0],e.a[1],e.b[0],e.b[1])>Math.max(.55*e.depthUnits,.001))continue;const t=n.length/2,r=e.depthUnits,c=n.x,h=n.y;i+=` ${ks(xs([[c-o*t-a*r,h-s*t-l*r],[c+o*t-a*r,h+s*t-l*r],[c+o*t+a*r,h+s*t+l*r],[c-o*t+a*r,h-s*t+l*r]]))}`}return i}function aa(e,t,i){const n=e?.length||0;if(n<3||t.length!==n)return null;if(t.every(e=>!(e>0)))return e.map(e=>[e[0],e[1]]);xs(e),t.slice().reverse();const r=[];for(let o=0;o0||l>0)){r.push([e[o][0],e[o][1]]);continue}if(a>0!=l>0){const t=e[o],i=a>0?[t[0]-c*a,t[1]-h*a]:[t[0],t[1]],n=l>0?[t[0]-d*l,t[1]-u*l]:[t[0],t[1]];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}if(fs(w,k)){const t=e[o],i=[t[0]-c*a,t[1]-h*a],n=[t[0]-d*l,t[1]-u*l];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}const $=vs(x,w,S,k),M=Math.max(a,l,1e-9),R=As(i,e[o])?.limit??4*M;if($){const i=Math.hypot($[0]-e[o][0],$[1]-e[o][1]);if(Number.isFinite(i)&&i<=R){r.push($);continue}if(ta(e,t,o)){r.push([e[o][0],e[o][1]]);continue}}a>0&&r.push([e[o][0]-c*a,e[o][1]-h*a]),l>0&&r.push([e[o][0]-d*l,e[o][1]-u*l])}return r.length>=3?r:null}function la(e,t,i,n,r,o,s=1){const a=[];for(const l of e||[]){if(!l?.id)continue;const c=Fs(e,l.id,t,i,n,r,o,s);if(!c)continue;const h=Math.abs(Ci(c.poly));for(let e=0;e[Math.max(t,e.x0),Math.min(i,e.x1)]).filter(e=>e[1]-e[0]>n).sort((e,t)=>e[0]-t[0]||e[1]-t[1]);if(!r.length)return{coverage:0,full:!1};let o=r[0][0],s=r[0][1],a=0,l=o<=t+n;for(let e=1;e=i-n,{coverage:a,full:l}}function ha(e,t){return Number(t.full)-Number(e.full)||e.faceDistance-t.faceDistance||e.area-t.area||e.roomId.localeCompare(t.roomId)}function da(e,t,i=!1){const n=Number(t?.x),r=Number(t?.y),o=Number(t?.angle),s=Number(t?.length);if(!([n,r,o,s].every(Number.isFinite)&&s>0))return{negative:null,positive:null};const a=o*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=-c,d=l,u=s/2,p=Math.max(1e-9,e.adjacencyEps),_=new Map;let m=0;for(const t of e.edges){if(i&&!(t.half>0))continue;if(!Zo(t.a,t.b,o))continue;const[e,s]=Lo(t.a,t.b);if(Math.abs((n-t.a[0])*s-(r-t.a[1])*e)>p)continue;const a=(t.a[0]-n)*l+(t.a[1]-r)*c,g=(t.b[0]-n)*l+(t.b[1]-r)*c,f=Math.max(-u,Math.min(a,g)),v=Math.min(u,Math.max(a,g));if(v-f<=p)continue;const y=t.inward[0]*h+t.inward[1]*d>=0?1:-1,b=((t.a[0]+t.b[0])/2-n)*h+((t.a[1]+t.b[1])/2-r)*d,w=Math.abs(b+y*t.half),k=`${y}|${t.roomId}`,x={x0:f,x1:v,half:t.half,cm:t.cm,key:t.key,axis:[e,s]},S=_.get(k);S?(S.pieces.push(x),S.faceDistance=Math.min(S.faceDistance,w)):_.set(k,{roomId:t.roomId,side:y,order:m++,pieces:[x],faceDistance:w,area:t.area,coverage:0,full:!1})}for(const e of _.values()){const t=ca(e.pieces,-u,u,p);e.coverage=t.coverage,e.full=t.full}const g=e=>{const t=[..._.values()].filter(t=>t.side===e&&t.coverage>p);return t.sort(ha),t[0]||null};return{negative:g(-1),positive:g(1)}}function ua(e,t,i,n,r,o,s=1,a=[]){return pa(la(e,i,a,n,r,o,s),t)}function pa(e,t){const i=da(e,t),n=[i.negative,i.positive].filter(e=>!!e);if(!n.length)return{ox:0,oy:0,cm:0,side:-1};const r=i.negative&&i.positive?-1:n[0].side,o=t.flip_v?-r:r,s=(-1===o?i.negative:i.positive)||n[0],a=[...s.pieces].sort((e,t)=>(e.x0<=0&&e.x1>=0?0:Math.min(Math.abs(e.x0),Math.abs(e.x1)))-(t.x0<=0&&t.x1>=0?0:Math.min(Math.abs(t.x0),Math.abs(t.x1)))||t.x1-t.x0-(e.x1-e.x0)||e.key.localeCompare(t.key))[0];if(!(a.half>0&&a.cm>0))return{ox:0,oy:0,cm:0,side:o};const l=t.angle*Math.PI/180,c=-Math.sin(l),h=Math.cos(l);return{ox:c*o*a.half,oy:h*o*a.half,cm:a.cm,side:o}}function _a(e,t){const i=1e-9,n=t.filter(e=>Number.isFinite(e.x0)&&Number.isFinite(e.x1)&&Number.isFinite(e.half)&&e.x1>e.x0&&e.half>0);if(!n.length)return"";const r=n.flatMap(e=>[e.x0,e.x1]).sort((e,t)=>e-t),o=[];for(const e of r){const t=o[o.length-1];(void 0===t||e>t+i)&&o.push(e)}const s=[];for(let e=0;e+1t+i))continue;const a=(t+r)/2,l=n.reduce((e,t)=>a>=t.x0-i&&a<=t.x1+i?Math.max(e,t.half):e,0);if(!(l>0))continue;const c=s[s.length-1];c&&t<=c.x1+i&&Math.abs(l-c.half)<=i?c.x1=r:s.push({x0:t,x1:r,half:l})}const a=[];for(const e of s){const t=a[a.length-1],n=t?.[t.length-1];n&&e.x0<=n.x1+i?(e.x0=n.x1,t.push(e)):a.push([e])}return a.map(t=>{const i=t[0],n=t[t.length-1],r=Math.min(.25*Math.min(...t.map(e=>e.half)),.75),o=-e*r,s=[];if(1===e){s.push(`M ${i.x0} ${o} L ${n.x1} ${o}`);for(let e=t.length-1;e>=0;e--){const i=t[e];s.push(`L ${i.x1} ${i.half} L ${i.x0} ${i.half}`)}}else{s.push(`M ${n.x1} ${o} L ${i.x0} ${o}`);for(const e of t)s.push(`L ${e.x0} ${-e.half} L ${e.x1} ${-e.half}`)}return s.push("Z"),s.join(" ")}).join(" ")}function ma(e,t,i,n){if(!n)return i;const r=e.angle*Math.PI/180,o=Math.cos(r),s=Math.sin(r),a=[],l=1e-9;for(const r of i){const[i,c]=r.axis,h=o*i+s*c;if(Math.abs(h)<=l)continue;const d=e.x*i+e.y*c,u=d+h*r.x0,p=d+h*r.x1,_=Math.min(u,p),m=Math.max(u,p),g=`${r.key}|${t}`,f=n.get(g)||[];let v=[[_,m]];for(const[e,t]of f){const i=[];for(const[n,r]of v)t<=n+l||e>=r-l?i.push([n,r]):(e>n+l&&i.push([n,Math.min(r,e)]),te[0]-t[0]||e[1]-t[1]),b=[];for(const e of y){const t=b[b.length-1];t&&e[0]<=t[1]+l?t[1]=Math.max(t[1],e[1]):b.push([e[0],e[1]])}n.set(g,b)}return a}function ga(e,t){const i=new Map;return t.map(t=>function(e,t,i){const n=da(e,t,!0),r=n.negative,o=n.positive;if(!r&&!o)return null;let s;if(r&&o)s=[{candidate:r,side:-1},{candidate:o,side:1}];else{const e=r||o;s=[{candidate:e,side:-1},{candidate:e,side:1}]}const a=s.map(({candidate:e,side:n})=>({candidate:e,side:n,pieces:ma(t,n,e.pieces,i)})),l=a.map(({candidate:e,side:t,pieces:i})=>({side:t,roomId:e.roomId,d:_a(t,i)})),c=a.flatMap(({pieces:e})=>e);if(!c.length)return null;const h=Math.max(...c.map(e=>e.half));return{faces:l,minY:-h,maxY:h,wallKey:[...new Set(c.map(e=>e.key))].sort().join("|")}}(e,t,i))}const fa=150,va=1e-6;function ya(e){return Number.isFinite(e)?Math.max(1,Math.min(fa,e)):1}function ba(e){return((Number.isFinite(Number(e))?Number(e):0)%90+90)%90}const wa=e=>{const t=e.map(e=>[e[0],e[1]]);return!t.length||t[0][0]===t[t.length-1][0]&&t[0][1]===t[t.length-1][1]||t.push([...t[0]]),[t]},ka=(e,t)=>e[0]===t[0]&&e[1]===t[1];function xa(e,t=1e-6){const i=Number.isFinite(t)&&t>0?t:va,n=[];for(const t of e||[]){if(!Array.isArray(t)||t.length<2)return null;const e=Number(t[0]),r=Number(t[1]);if(!Number.isFinite(e)||!Number.isFinite(r))return null;const o=Math.round(e/i)*i,s=Math.round(r/i)*i;if(!Number.isFinite(o)||!Number.isFinite(s))return null;const a=[Object.is(o,-0)?0:o,Object.is(s,-0)?0:s];n.length&&ka(n[n.length-1],a)||n.push(a)}return n.length>1&&ka(n[0],n[n.length-1])&&n.pop(),n.length<3||new Set(n.map(e=>`${e[0]},${e[1]}`)).size<3?null:Ci(n)>i*i?n:null}function Sa(e){const t=[];for(const i of e||[])for(const e of i||[]){const i=(e||[]).filter(e=>Array.isArray(e)&&e.length>=2);i.length<4||t.push(`M ${i.slice(0,-1).map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`)}return t.join(" ")}function $a(e,t,i,n,r){return os({a:e,b:t,halfDepth:Oo(i,n,r)/2})}function Ma(e,t,i){const n=Number(t)>0?Number(t):5,r=ya(e.cm)/n*i,o=e.center[0],s=e.center[1];if("circle"===e.shape){const e=r/2;return Array.from({length:96},(t,i)=>{const n=i/96*Math.PI*2;return[o+Math.cos(n)*e,s+Math.sin(n)*e]})}const a=r/2,l=ba(e.angle)*Math.PI/180,c=Math.cos(l),h=Math.sin(l);return[[-a,-a],[a,-a],[a,a],[-a,a]].map(([e,t])=>[o+e*c-t*h,s+e*h+t*c])}function Ra(e,t){const i=Number.isFinite(t)?Math.max(0,Math.min(1,t)):0,n=(e.a[0]+e.b[0])/2,r=(e.a[1]+e.b[1])/2,o=(e.b[0]-e.a[0])*i/2,s=(e.b[1]-e.a[1])*i/2;return{...e,a:[n-o,r-s],b:[n+o,r+s]}}function Ca(e,t,i=1e-9){if(!t.length)return[e];let n=[wa(e)];try{for(const e of t){const t=e.b[0]-e.a[0],r=e.b[1]-e.a[1],o=Math.hypot(t,r);if(!(o>i))continue;const s=t/o,a=r/o,l=-a,c=s,h=1.25*Math.max(Number(e.depth)||0,4*i),d=Math.max(2*i,1e-9*o),u=[[e.a[0]-s*d-l*h,e.a[1]-a*d-c*h],[e.b[0]+s*d-l*h,e.b[1]+a*d-c*h],[e.b[0]+s*d+l*h,e.b[1]+a*d+c*h],[e.a[0]-s*d+l*h,e.a[1]-a*d+c*h]];n=Gt(n,wa(u))}return Na(n)}catch{return[e]}}function Ta(e,t){try{const i=Gt([[...e.map(e=>[e[0],e[1]]),[e[0][0],e[0][1]]]],[[...t.map(e=>[e[0],e[1]]),[t[0][0],t[0][1]]]]);let n=null,r=0;for(const e of i||[]){const t=e?.[0]||[],i=Math.abs(Ci(t));t.length>=4&&i>r&&(r=i,n=t.slice(0,-1).map(e=>[e[0],e[1]]))}return n}catch{return null}}function Da(e,t,i,n=Math.max(2e-4*i,1e-9),r=[]){const o=[],s=new Map;for(const e of r){const t=s.get(e.hostId)||[];t.push(e),s.set(e.hostId,t)}const a=[],l=[],c=[];for(const n of e.partitions||[]){const e={a:n.a,b:n.b,halfDepth:Oo(n.cm,t,i)/2};if(!(e.halfDepth>0))continue;const r=os(e);r&&(o.push(e),a.push(r),c.push({id:n.id,body:r}))}const h=o;for(const{segmentIndex:e,wedge:t}of hs(h,n)){const i={list:a,at:e},n=Ta(i.list[i.at],t);n&&(i.list[i.at]=n,c[i.at].body=n)}for(const e of c)l.push(...Ca(e.body,s.get(e.id)||[],n));const d=(e.wall_columns||[]).map(e=>Ma(e,t,i)),u=ds(o,n).flatMap(e=>Ca(e,r,n));return{partitions:a,columns:d,patches:u,all:[...l,...u,...d]}}function Aa(e){try{const t=e.map(e=>xa(e)).filter(e=>!!e).map(e=>wa(e));return t.length?Wt(t[0],...t.slice(1)):null}catch{return null}}const Pa=e=>`M ${e.map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`;function Fa(e){const t=[];for(const i of e||[]){if(Oa([i])<=1e-6)continue;const e=[];for(const t of i||[]){const i=(t||[]).filter(e=>Array.isArray(e)&&e.length>=2);i.length<4||e.push(Pa(i.slice(0,-1)))}e.length&&t.push(e.join(" "))}return t}function za(e,t,i={}){const n=Aa(e.filter(e=>e.length>=3)),r=t.some(e=>!xa(e))?null:Aa(t);if(!n)return[];if(r)try{return Fa(Ut(n,r))}catch{}return function(e,t,i){let n=null;for(let r=0;r=4&&t.push(e.slice(0,-1).map(e=>[e[0],e[1]]));return t}function Na(e){const t=[];for(const i of e||[]){const e=i?.[0];e?.length>=4&&t.push(e.slice(0,-1).map(e=>[e[0],e[1]]))}return t}function Ha(e,t){let i=!1;for(let n=0,r=t.length-1;ne[1]!=l>e[1]&&e[0]<(a-o)*(e[1]-s)/(l-s||1e-12)+o&&(i=!i)}return i}function La(e,t){for(const i of t||[]){const t=i?.[0];if(!t?.length||!Ha(e,t))continue;let n=!1;for(let t=1;ti)return!1;if(Math.abs(ya(e.cm)-ya(t.cm))>1e-6)return!1;if(e.shape!==t.shape)return!0;if("circle"===e.shape||"circle"===t.shape)return!0;const n=Math.abs(ba(e.angle)-ba(t.angle));return Math.min(n,90-n)<=1e-6}const qa=2.54;function ja(e){const t="number"==typeof e?e:NaN;return!Number.isFinite(t)||t<=0||5===t?1:5/t}function Wa(e,t){return e*ja(t)}function Ua(e){return e?qa:1}function Ga(e,t){if(!t)return String(e);const i=e/qa;return String(Math.round(1e6*i)/1e6)}function Va(e,t){return t?e*qa:e}const Ka=1e3;function Ya(e,t){const i=Number(e),n=Number.isFinite(i)&&i>0?i:1,r=n>=1?t:t*n,o=n>=1?t/n:t;return{x:(t-r)/2,y:(t-o)/2,w:r,h:o}}const Xa=.01,Za=100;function Ja(e,t=1e3){const i=Ya(e?.plan_aspect,t),n=Number(e?.plan_scale),r=Number.isFinite(n)&&n>0?Math.min(Za,Math.max(Xa,n)):1,o=Number(e?.plan_scale_x),s=Number(e?.plan_scale_y),a=Number.isFinite(o)&&o>0?Math.min(Za,Math.max(Xa,o)):r,l=Number.isFinite(s)&&s>0?Math.min(Za,Math.max(Xa,s)):r,c=Number(e?.plan_x),h=Number(e?.plan_y),d=Dr(e?.plan_angle);return{x:i.x+(Number.isFinite(c)?cl(c):0)*t,y:i.y+(Number.isFinite(h)?cl(h):0)*t,w:i.w*a,h:i.h*l,...d?{angle:d}:{}}}function Qa(e){if(null==e.x||null==e.y)return{x:e.x,y:e.y,w:e.w,h:e.h};const t=Number(e.w)||0,i=Number(e.h)||0;return{x:t<0?e.x+t:e.x,y:i<0?e.y+i:e.y,w:Math.abs(t),h:Math.abs(i)}}function el(e){return e&&Array.isArray(e.spaces)?e.spaces.map(e=>{const t=Ka,i=function(e){return Array.isArray(e)&&4===e.length&&e.every(e=>Number.isFinite(e))&&e[2]>1e-6&&e[3]>1e-6?e:[0,0,1,1]}(e.view_box);return{id:e.id,title:e.title,cellCm:Number.isFinite(Number(e.cell_cm))&&Number(e.cell_cm)>0?Number(e.cell_cm):5,vb:[i[0]*Ka,i[1]*t,i[2]*Ka,i[3]*t],bg:e.plan_url?{href:Hn(e.plan_url),...Ja(e,Ka)}:null,rooms:(e.rooms||[]).map(e=>{const i={...e,...Qa(e)};return{id:i.id,name:i.name,area:i.area??null,open_to:i.open_to||void 0,settings:i.settings||void 0,x:null!=i.x?i.x*Ka:void 0,y:null!=i.y?i.y*t:void 0,w:null!=i.w?i.w*Ka:void 0,h:null!=i.h?i.h*t:void 0,poly:i.poly?i.poly.map(e=>[e[0]*Ka,e[1]*t]):void 0,wall_ids:Array.isArray(i.wall_ids)?[...i.wall_ids]:void 0}}),wall_segments:(e.wall_segments||[]).map(e=>({...e,id:String(e.id),a:[Number(e.a?.[0])*Ka,Number(e.a?.[1])*t],b:[Number(e.b?.[0])*Ka,Number(e.b?.[1])*t],cm:Number(e.cm)})),partitions:(e.partitions||[]).map(e=>({id:e.id,a:[e.a[0]*Ka,e.a[1]*t],b:[e.b[0]*Ka,e.b[1]*t],cm:Number(e.cm)})),wall_columns:(e.wall_columns||[]).map(e=>({id:e.id,shape:"circle"===e.shape?"circle":"square",center:[e.center[0]*Ka,e.center[1]*t],cm:Number(e.cm),..."circle"===e.shape?{}:{angle:ba(e.angle)}}))}}):[]}const tl=5e3,il=tl*Ka,nl=240,rl=Ka/nl,ol=1/nl;function sl(e){if(!Number.isFinite(e))return e;const t=Math.round(e*nl/Ka)*Ka/nl;return Math.abs(t-e)<=1e-9*rl?e:t}function al(e){return{x:sl(e.x),y:sl(e.y)}}function ll(e){return Number.isFinite(e)?Math.min(il,Math.max(-il,e)):0}function cl(e){return Number.isFinite(e)?Math.min(tl,Math.max(-tl,e)):0}const hl=1/3,dl=200;function ul(e){return"house"===e?"house":"content"}function pl(e){let t=1/0,i=1/0,n=-1/0,r=-1/0;for(const o of e){const e=Number(o[0]),s=Number(o[1]);Number.isFinite(e)&&Number.isFinite(s)&&(en&&(n=e),s>r&&(r=s))}return t>n?null:{minX:t,minY:i,maxX:n,maxY:r}}function _l(e){const t=[],i=e=>{if(Array.isArray(e))if(e.length>=2&&Number.isFinite(Number(e[0]))&&Number.isFinite(Number(e[1])))t.push([Number(e[0]),Number(e[1])]);else for(const t of e)i(t)};return i(e),pl(t)}function ml(e,t){const i=Number.isFinite(t)&&t>0?t:0;return{minX:e.minX-i,minY:e.minY-i,maxX:e.maxX+i,maxY:e.maxY+i}}function gl(e){return e.poly&&e.poly.length?pl(e.poly):null==e.x||null==e.y?null:pl([[e.x,e.y],[e.x+(e.w||0),e.y+(e.h||0)]])}function fl(e,t=1e3,i=1e3){const n=Number(e.x)*t,r=Number(e.y)*i,o=Number(e.w)*t,s=Number(e.h)*i;return![n,r,o,s].every(Number.isFinite)||o<=0||s<=0?null:pl(Nr({x:n,y:r,w:o,h:s,angle:Dr(e.angle)||void 0}))}function vl(e,t){const i=[];for(const t of e.rooms||[]){const e=gl(t);e&&i.push(e)}if(e.bg){const t=pl(Nr(e.bg));t&&i.push(t)}for(const e of t||[])if(Array.isArray(e)){const t=pl([e]);t&&i.push(t)}else i.push(e);return i}const yl=e=>{if(!e.length)return 0;const t=[...e].sort((e,t)=>e-t),i=t.length>>1;return t.length%2?t[i]:(t[i-1]+t[i])/2},bl=e=>{let t=1/0,i=1/0,n=-1/0,r=-1/0;for(const o of e)o.minXn&&(n=o.maxX),o.maxY>r&&(r=o.maxY);return t>n||i>r?null:{x:t,y:i,w:n-t,h:r-i}};function wl(e,t){let{x:i,y:n,w:r,h:o}=e;r<30&&(i=i+r/2-100,r=dl),o<30&&(n=n+o/2-100,o=dl);const s="number"==typeof t?{top:t,right:t,bottom:t,left:t}:t,a=Math.max(r,o),l=a*s.top,c=a*s.right,h=a*s.bottom,d=a*s.left;return{x:i-d,y:n-l,w:r+d+c,h:o+l+h}}function kl(e,t={}){const i=t.pad??.05,n=t.k??10,r=t.minSpread??50,o=e.filter(e=>Number.isFinite(e.minX)&&Number.isFinite(e.minY)&&Number.isFinite(e.maxX)&&Number.isFinite(e.maxY)&&Math.abs(e.minX)<=il&&Math.abs(e.maxX)<=il&&Math.abs(e.minY)<=il&&Math.abs(e.maxY)<=il);if(!o.length)return{core:null,all:null,outliers:0};const s=bl(o);if(o.length<4){const e=wl(s,i);return{core:e,all:e,outliers:0}}const a=o.map(e=>(e.minX+e.maxX)/2),l=o.map(e=>(e.minY+e.maxY)/2),c=yl(a),h=yl(l),d=o.map((e,t)=>Math.max(Math.abs(a[t]-c),Math.abs(l[t]-h))),u=Math.max(((e,t)=>e.length?e[Math.min(e.length-1,Math.max(0,Math.round(t*(e.length-1))))]:0)([...d].sort((e,t)=>e-t),.75),r),p=d.map(e=>e>n*u),_=p.filter(Boolean).length,m=_&&_<=o.length*hl?o.filter((e,t)=>!p[t]):o;return{core:wl(bl(m)||s,i),all:wl(s,i),outliers:m===o?0:_}}function xl(e){return kl(e,{pad:0}).all}function Sl(e,t,i=.05){const n=kl(vl(e,t),{pad:i});if(n.core)return n.core;const r=e.vb&&4===e.vb.length&&e.vb[2]>0&&e.vb[3]>0?e.vb:[0,0,Ka,Ka];return{x:r[0],y:r[1],w:r[2],h:r[3]}}function $l(e){const t=Sl(e);return{x:t.x+t.w/2,y:t.y+t.h/2}}function Ml(e){const t=[];for(const i of e.rooms||[]){const e=gl(i);e&&t.push(e)}const i=kl(t,{pad:0}).core,n=Ka*ja(e.cellCm??5);return i?Math.max(n,Math.min(il,Math.max(i.w,i.h))):n}function Rl(e,t,i,n=1){const r=Number(i),o=Number.isFinite(n)&&n>0?n:1;return!Number.isFinite(r)||r<=0?e*o:e*Ml(t)*o/r}const Cl=[1,2,5,10,20,50,100,200,500,1e3];function Tl(e,t,i=7){if(!(e>0&&t>0&&Number.isFinite(t)))return null;const n=Cl.find(n=>e*n*t>=i);if(void 0===n)return null;const r=Cl.find(e=>e>=5*n)??5*n;return{fine:n,coarse:r}}function Dl(e){if(e.poly&&e.poly.length){const t=e.poly.map(e=>e[0]),i=e.poly.map(e=>e[1]),n=Math.min(...t),r=Math.min(...i);return{x:n,y:r,w:Math.max(...t)-n,h:Math.max(...i)-r}}return{x:e.x??0,y:e.y??0,w:e.w??0,h:e.h??0}}function Al(e,t,i,n,r,o=new Set){const s=t[e.id];return!o.has(e.id)&&s&&s.s===e.space?{x:s.x*Ka,y:s.y*Ka}:n[e.id]?n[e.id]:al($l(r))}function Pl(e,t,i,n){const r=i["rl_"+(e.id||"")];if(r&&r.s===t)return{x:r.x*Ka,y:r.y*Ka};const o=function(e){if(e.poly){const t=e.poly.length;return[e.poly.reduce((e,t)=>e+t[0],0)/t,e.poly.reduce((e,t)=>e+t[1],0)/t]}return[e.x+e.w/2,e.y+.1*Math.min(e.w,e.h)]}(e);return al({x:o[0],y:o[1]})}function Fl(e,t){for(const i of e?.spaces??[])for(const e of i?.decor??[])if("furniture"===e?.kind&&"string"==typeof e.symbol&&t(e.symbol))return!0;return!1}let zl=0;const Il=new Set;const Ol=new class{constructor(e){this.options=e,this._art=null,this._failed=!1,this._terminal=!1,this._inFlight=null,this._hosts=new Set,this._settled=[]}state(){return this._art?"ready":this._failed?"fallback":"pending"}get terminal(){return this._terminal}art(e,t){if(this._art)return this._art[e];t&&!this._failed&&this._hosts.add(t)}adopt(e,t){return!!this._art||(t!==this.options.expectedFingerprint?((this.options.warn??console.warn)("[houseplan] furniture artwork from another build ignored",{fingerprint:t}),!1):(this._install(e),!0))}ensure(){return"pending"!==this.state()?Promise.resolve():(this._inFlight||(this._inFlight=this._loadWithRetry().finally(()=>{this._inFlight=null})),this._inFlight)}onSettled(e){"pending"===this.state()?this._settled.push(e):Promise.resolve().then(e)}async _loadWithRetry(){let e=new Error("furniture artwork did not load");for(const t of[0,1])try{const i=await this.options.load(t);if(i.FURNITURE_ART_FINGERPRINT!==this.options.expectedFingerprint){this._terminal=!0,e=new Error(`furniture artwork fingerprint mismatch: expected ${this.options.expectedFingerprint}, got ${i.FURNITURE_ART_FINGERPRINT}`);break}if(this._art)return;return void this._install(i.GENERATED_FURNITURE_ART)}catch(t){e=t}this._art||(this._failed=!0,(this.options.warn??console.warn)("[houseplan] furniture artwork unavailable",e),this.options.loadFailed?.(this._terminal),this._flush())}_install(e){this._art=e,this._failed=!1,this._flush()}_flush(){const e=[...this._hosts];this._hosts.clear();for(const t of e)t.isConnected&&t.requestUpdate();const t=this._settled.splice(0);for(const e of t)e()}}({expectedFingerprint:"c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f",load:async e=>0===e?await import("./furniture-plan-art.generated-Ck1wv9qF.js"):await import((()=>{const e=new URL("./furniture-plan-art.generated-Ck1wv9qF.js",import.meta.url);return e.searchParams.set("hp_retry","art-"+ ++zl),e.href})()),loadFailed:e=>{for(const t of Il)t(e)}}),El=["furniture","appliance","sanitary","other"],Nl=[{id:"coffee_table",group:"furniture",category:"coffee_table",w:120,h:60},{id:"coffee_table_round",group:"furniture",category:"coffee_table",w:80,h:80},{id:"coffee_table_oval",group:"furniture",category:"coffee_table",w:120,h:60},{id:"coffee_table_rounded",group:"furniture",category:"coffee_table",w:120,h:60},{id:"table_dining",group:"furniture",category:"dining_table",w:160,h:90},{id:"table_round",group:"furniture",category:"dining_table",w:110,h:110},{id:"table_dining_oval",group:"furniture",category:"dining_table",w:180,h:100},{id:"table_dining_rounded",group:"furniture",category:"dining_table",w:160,h:90},{id:"desk",group:"furniture",category:"work_table",w:140,h:70},{id:"desk_corner",group:"furniture",category:"work_table",w:160,h:160},{id:"chair",group:"furniture",category:"chair",w:50,h:50},{id:"chair_bar",group:"furniture",category:"chair",w:45,h:48},{id:"armchair",group:"furniture",category:"armchair",w:90,h:90},{id:"armchair_office",group:"furniture",category:"armchair",w:65,h:65},{id:"sofa",group:"furniture",category:"sofa",w:180,h:90},{id:"sofa_three_seat",group:"furniture",category:"sofa",w:240,h:90},{id:"sofa_corner_right",group:"furniture",category:"sofa",w:260,h:170},{id:"bed_single",group:"furniture",category:"bed",w:90,h:200},{id:"bed_double",group:"furniture",category:"bed",w:160,h:200},{id:"nightstand",group:"furniture",category:"nightstand",w:50,h:40},{id:"cabinet_tv",group:"furniture",category:"nightstand",w:140,h:45},{id:"cabinet_shoe",group:"furniture",category:"nightstand",w:80,h:35},{id:"cabinet_sink",group:"furniture",category:"nightstand",w:80,h:50},{id:"bookshelf",group:"furniture",category:"wardrobe",w:100,h:35},{id:"wall_unit",group:"furniture",category:"wardrobe",w:240,h:45},{id:"wardrobe",group:"furniture",category:"wardrobe",w:180,h:60},{id:"kitchen_floor",group:"furniture",category:"kitchen_cabinet",w:60,h:60},{id:"kitchen_floor_corner",group:"furniture",category:"kitchen_cabinet",w:90,h:90},{id:"kitchen_wall",group:"furniture",category:"kitchen_cabinet",w:60,h:35},{id:"kitchen_wall_corner",group:"furniture",category:"kitchen_cabinet",w:60,h:60},{id:"shelf_floor",group:"furniture",category:"shelving",w:100,h:35},{id:"shelf_wall",group:"furniture",category:"shelving",w:100,h:25},{id:"cooktop_two",group:"appliance",category:"cooktop",w:30,h:50},{id:"stove",group:"appliance",category:"cooktop",w:60,h:60},{id:"tv",group:"appliance",category:"tv",w:120,h:28},{id:"tv_wall",group:"appliance",category:"tv",w:120,h:15},{id:"toilet",group:"sanitary",category:"toilet",w:40,h:70},{id:"toilet_built_in",group:"sanitary",category:"toilet",w:40,h:55},{id:"bathtub",group:"sanitary",category:"bathtub",w:170,h:75},{id:"bathtub_corner",group:"sanitary",category:"bathtub",w:140,h:140},{id:"bidet",group:"sanitary",category:"bidet",w:40,h:60},{id:"bidet_built_in",group:"sanitary",category:"bidet",w:40,h:50},{id:"kitchen_sink",group:"sanitary",category:"kitchen_sink",w:60,h:50},{id:"kitchen_sink_double",group:"sanitary",category:"kitchen_sink",w:90,h:50},{id:"fridge",group:"appliance",category:"fridge",w:60,h:65},{id:"dishwasher",group:"appliance",category:"dishwasher",w:60,h:60},{id:"washer",group:"appliance",category:"washer",w:60,h:60},{id:"dryer",group:"appliance",category:"dryer",w:60,h:60},{id:"ac",group:"appliance",category:"air_conditioner",w:90,h:25},{id:"water_heater",group:"appliance",category:"boiler",w:45,h:45},{id:"shower",group:"sanitary",category:"shower",w:90,h:90},{id:"sink",group:"sanitary",category:"sink",w:60,h:45},{id:"stairs",group:"other",category:"stairs",w:100,h:280},{id:"fireplace",group:"other",category:"fireplace",w:120,h:40},{id:"plant",group:"other",category:"plant",w:40,h:40},{id:"rug",group:"other",category:"rug",w:200,h:140},{id:"computer",group:"appliance",category:"computer",w:120,h:60},{id:"hood",group:"appliance",category:"hood",w:60,h:50},{id:"oven",group:"appliance",category:"oven",w:60,h:60},{id:"cactus",group:"other",category:"plant",w:70,h:120}].map(e=>({id:e.id,group:e.group,category:e.category,w:e.w,h:e.h})),Hl=new Map(Nl.map(e=>[e.id,e]));function Ll(e){return e&&Hl.get(e)||null}function Bl(e){return Hl.has(e)}function ql(e){return Nl.filter(t=>t.group===e)}function jl(e){const t=Ll(e);return t?{w:t.w,h:t.h}:{w:60,h:60}}function Wl(e,t,i=rl,n=1e3){const r=Number(t)>0?Number(t):5;return(Number(e)||0)/r*i/n}const Ul=5e-4,Gl=tl;function Vl(e){return Number.isFinite(e)?Math.max(Ul,Math.min(Gl,e)):Ul}function Kl(e){return Number.isFinite(e)?Math.max(1,Math.min(1e4,e)):1}function Yl(e,t){return Ll(e)?Ol.art(e,t)??null:null}function Xl(e,t,i=1){const n=Number(e),r=Number(i),o=Number.isFinite(n)&&n>0?n:Number.isFinite(r)&&r>0?r:1,s=Number(t),a=o*(Number.isFinite(s)&&s>0?s:1);return Number.isFinite(a)&&a>0?a:o}function Zl(e,t,i,n,r){const o=e+i/2,s=t+n/2,a=(Number(r)||0)*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=(e,t)=>{const i=e-o,n=t-s;return[o+i*l-n*c,s+i*c+n*l]};return[h(e,t),h(e+i,t),h(e+i,t+n),h(e,t+n)]}function Jl(e,t,i,n,r,o,s){const a=Number.isFinite(s)&&s>0?s:1e-6,l=(Number(e.angle)||0)*Math.PI/180,c=Math.cos(l),h=Math.sin(l),d=-Math.sin(l),u=Math.cos(l),p=e.x+e.w/2,_=e.y+e.h/2,m=t>0?-e.w/2:t<0?e.w/2:0,g=i>0?-e.h/2:i<0?e.h/2:0,f=p+m*c+g*d,v=_+m*h+g*u,y=n-f,b=r-v,w=t?(y*c+b*h)*(t>0?1:-1):e.w,k=i?(y*d+b*u)*(i>0?1:-1):e.h;let x=t?Math.abs(w):e.w,S=i?Math.abs(k):e.h;if(o&&t&&i){const t=x/Math.max(e.w,a),i=S/Math.max(e.h,a),n=Math.abs(t-1)>=Math.abs(i-1)?t:i,r=Math.max(a/e.w,a/e.h),o=Math.max(r,Number.isFinite(n)?n:r);x=e.w*o,S=e.h*o}x=Math.max(a,Number.isFinite(x)?x:a),S=Math.max(a,Number.isFinite(S)?S:a);const $=!!t&&w<0,M=!!i&&k<0,R=t?(t>0?1:-1)*($?-1:1):0,C=i?(i>0?1:-1)*(M?-1:1):0,T=f+R*(x/2)*c+C*(S/2)*d,D=v+R*(x/2)*h+C*(S/2)*u,A=!!e.flip_h!==$,P=!!e.flip_v!==M;return{x:T-x/2,y:D-S/2,w:x,h:S,...Number(e.angle)?{angle:Number(e.angle)}:{},...A?{flip_h:!0}:{},...P?{flip_v:!0}:{}}}function Ql(e,t,i,n){let r=Number(e)+(Number(i)-Number(t));if([r,t,i].every(Number.isFinite)||(r=0),n){const e=r/45;r=45*(e<0?-Math.round(Math.abs(e)):Math.round(e))}return r=(r%360+360)%360,r>180?r-360:r}function ec(e,t,i,n,r){const o=e.x*t,s=e.y*i,a=e.w*t,l=e.h*i,c=o+a/2,h=s+l/2,d=o+(e.flip_h?a:0),u=s+(e.flip_v?l:0),p=(e.flip_h?-1:1)*a/n,_=(e.flip_v?-1:1)*l/r,m=Number(e.angle)||0;return(m?`rotate(${m} ${c} ${h}) `:"")+`translate(${d} ${u}) scale(${p} ${_})`}function tc(e,t,i,n=.1){if("string"==typeof e&&!e.trim())return null;const r=Number(e);if(!Number.isFinite(r)||0===r)return null;const o=r*(t?30.48:100),s=Math.abs(o);return si?null:o}function ic(e,t,i){const n=Math.abs(Number(e))/(i?30.48:100),r=Number(n.toFixed(6));return String(t?-r:r)}const nc=15e3,rc=2e3,oc=new WeakMap;function sc(e,t){let i=oc.get(e);if(!i){const t=new Set;i={hiddenAt:"hidden"===e.visibilityState?Date.now():0,token:0,subscribers:t,onVisibility:()=>{const t=oc.get(e);if(!t)return;const i=Date.now();if("hidden"===e.visibilityState){t.hiddenAt||(t.hiddenAt=i);const e={kind:"hidden",token:t.token,at:i,hiddenFor:0,long:!1};for(const i of[...t.subscribers])i(e);return}const n=t.hiddenAt?Math.max(0,i-t.hiddenAt):0;t.hiddenAt=0,t.token++;const r={kind:"visible",token:t.token,at:i,hiddenFor:n,long:n>=nc};for(const e of[...t.subscribers])e(r)},onPageShow:t=>{const i=oc.get(e);if(!i)return;const n=Date.now();i.token++;const r={kind:"pageshow",token:i.token,at:n,hiddenFor:0,long:!!t.persisted,persisted:!!t.persisted};for(const e of[...i.subscribers])e(r)}},oc.set(e,i),e.addEventListener("visibilitychange",i.onVisibility),e.defaultView?.addEventListener("pageshow",i.onPageShow)}return i.subscribers.add(t),()=>{const i=oc.get(e);i&&(i.subscribers.delete(t),i.subscribers.size||(e.removeEventListener("visibilitychange",i.onVisibility),e.defaultView?.removeEventListener("pageshow",i.onPageShow),oc.delete(e)))}}const ac={now:()=>Date.now(),setTimeout:(e,t)=>window.setTimeout(e,t),clearTimeout:e=>window.clearTimeout(e),requestAnimationFrame:e=>window.requestAnimationFrame(e),cancelAnimationFrame:e=>window.cancelAnimationFrame(e)};class lc{constructor(e,t=ac){this.onChange=e,this.clock=t,this._state="steady",this._token=0,this._frameFingerprint="",this._hasCompleteFrame=!1,this._overlayPhase="none",this._recoveryReason=null,this._overlayTimer=0,this._overlayRaf=0,this._overlayOpaqueAt=0,this._barrierRafs=new Set,this._trace=[],this._disposed=!1}get state(){return this._state}get token(){return this._token}get frameFingerprint(){return this._frameFingerprint}get hasCompleteFrame(){return this._hasCompleteFrame}get overlayPhase(){return this._overlayPhase}get overlayVisible(){return"none"!==this._overlayPhase}get overlayBlocksInteraction(){return this.overlayVisible}get recoveryReason(){return this._recoveryReason}get trace(){return this._trace.map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}note(e,t={}){this.record(e,void 0,t)}record(e,t,i={}){this._trace.push({at:this.clock.now(),token:this._token,event:e,state:this._state,...t?{reason:t}:{},...i}),this._trace.length>80&&this._trace.splice(0,this._trace.length-80)}changed(){this._disposed||this.onChange()}adoptCompleteFrame(e){e&&(this._hasCompleteFrame=!0,this._frameFingerprint=e,this._state="steady",this._recoveryReason=null,this.clearOverlay(),this.record("frame-adopted"),this.changed())}markCompleteFrame(e){e&&(this._hasCompleteFrame=!0,this._frameFingerprint=e,this._state="steady",this._recoveryReason=null,this.clearOverlay(),this.record("frame-complete"),this.changed())}refreshCompleteFrame(e){!this._disposed&&this._hasCompleteFrame&&"steady"===this._state&&e&&e!==this._frameFingerprint&&(this._frameFingerprint=e,this.record("frame-refreshed"))}visibility(e){return"hidden"===e.kind?(this.record("visibility-hidden"),this._token):e.long||"visible"!==e.kind&&"pageshow"!==e.kind?this.beginCandidate("pageshow"===e.kind?"pageshow":"long-resume"):(this.record("pageshow"===e.kind?"pageshow-noop":"visibility-visible-quick"),this._token)}beginCandidate(e,t="plan"){return this._token++,this._recoveryReason=t,this._hasCompleteFrame?(this._state="connection"===t?"offline-stale":"holding",this.clearOverlay()):this.overlayVisible?this._state="overlay-visible":(this._state="overlay-pending",this.scheduleOverlay(t)),this.record("candidate-start",e),this.changed(),this._token}connectionLost(){return this.beginCandidate("connection-lost","connection")}candidateReady(e){return!this._disposed&&e===this._token&&(this._state="candidate-ready",this.record("candidate-ready"),this.changed(),!0)}async commitAfterPaint(e,t){if(this._disposed||e!==this._token)return!1;let i=!0;const n=(async()=>{for(await t.updateComplete();i&&!this._disposed&&e===this._token;)if(t.stageValid()&&t.assetsReady()){if(await this.nextFrame(),e!==this._token||!t.stageValid()||!t.assetsReady())continue;if(await this.nextFrame(),e===this._token&&t.stageValid()&&t.assetsReady())return!0}else await this.nextFrame();return!1})();let r=0;const o=new Promise(e=>{r=this.clock.setTimeout(()=>e({ready:!1,timedOut:!0}),rc)}),s=await Promise.race([n.then(e=>({ready:e,timedOut:!1})),o]);return i=!1,this.clock.clearTimeout(r),!this._disposed&&e===this._token&&(!(!s.ready&&!s.timedOut)&&(s.ready?(this._hasCompleteFrame=!0,this._frameFingerprint=t.frameFingerprint(),this.record("paint-barrier"),this.finishOverlayAfterCommit(),!0):(this.record("paint-barrier-timeout"),this._hasCompleteFrame?(this._state="connection"===this._recoveryReason?"offline-stale":"steady",this.clearOverlay()):(this._state="recovery-error","opaque"!==this._overlayPhase&&this.showOverlayNow()),this.changed(),!1)))}retry(e=this._recoveryReason||"plan"){return this.beginCandidate("retry",e)}nextFrame(){return new Promise(e=>{const t=this.clock.requestAnimationFrame(()=>{this._barrierRafs.delete(t),e()});this._barrierRafs.add(t)})}scheduleOverlay(e){this.clearOverlayTimer(),this._recoveryReason=e,this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._hasCompleteFrame||"overlay-pending"!==this._state&&"candidate-ready"!==this._state||(this._state="overlay-visible",this._overlayPhase="entering",this.record("overlay-enter"),this.changed(),this._overlayRaf=this.clock.requestAnimationFrame(()=>{this._overlayRaf=0,"entering"===this._overlayPhase&&(this._overlayPhase="fading-in",this.changed(),this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,"fading-in"===this._overlayPhase&&(this._overlayPhase="opaque",this._overlayOpaqueAt=this.clock.now(),this.record("overlay-opaque"),this.changed())},150))}))},150)}showOverlayNow(){this.clearOverlayTimer(),this._overlayPhase="opaque",this._overlayOpaqueAt=this.clock.now(),this.record("overlay-error")}finishOverlayAfterCommit(){if(this.clearOverlayTimer(),"none"===this._overlayPhase||"entering"===this._overlayPhase||"fading-in"===this._overlayPhase)return this.clearOverlay(),this._state="steady",this._recoveryReason=null,this.record("candidate-committed"),void this.changed();const e=Math.max(0,this._overlayOpaqueAt+250-this.clock.now());this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._overlayPhase="leaving",this.record("overlay-leave"),this.changed(),this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._overlayPhase="none",this._state="steady",this._recoveryReason=null,this.record("candidate-committed"),this.changed()},180)},e)}clearOverlayTimer(){this._overlayTimer&&this.clock.clearTimeout(this._overlayTimer),this._overlayTimer=0}clearOverlay(){this.clearOverlayTimer(),this._overlayRaf&&this.clock.cancelAnimationFrame(this._overlayRaf),this._overlayRaf=0,this._overlayPhase="none",this._overlayOpaqueAt=0}dispose(){this._disposed=!0,this._token++,this.clearOverlay();for(const e of this._barrierRafs)this.clock.cancelAnimationFrame(e);this._barrierRafs.clear()}}function cc(e){let t=2166136261,i=2654435769;const n=new WeakSet,r=e=>{for(let n=0;n>>0)+(i>>>2)}},o=e=>{if(null===e)return void r("n");const t=typeof e;if("string"===t)return void r(`s${e.length}:${e}`);if("number"===t)return void r(`d${Number.isNaN(e)?"NaN":String(e)}`);if("boolean"===t)return void r(e?"t":"f");if("undefined"===t)return void r("u");if("object"!==t)return void r(`${t}:${String(e)}`);const i=e;if(n.has(i))r("[cycle]");else{if(n.add(i),Array.isArray(e)){r("[");for(const t of e)o(t);return r("]"),void n.delete(i)}r("{");for(const t of Object.keys(e).sort())r(t),o(e[t]);r("}"),n.delete(i)}};return o(e),`${(t>>>0).toString(16).padStart(8,"0")}${(i>>>0).toString(16).padStart(8,"0")}`}function hc(e){return cc(e)}const dc=new WeakMap;class uc{constructor(e,t=()=>Date.now()){this.onUpdate=e,this.now=t,this.fallbackAuthority={},this.referenceOwner={},this.referenced=new Set,this.queued=new Set,this.disposed=!1,this.sharedUpdate=()=>{this.disposed||this.onUpdate()}}bind(e){const t=((e,t)=>{const i=e?.connection||e?.callWS||t;return!i||"object"!=typeof i&&"function"!=typeof i?t:i})(e,this.fallbackAuthority);return this.shared&&this.authority===t||(this.shared&&(this.shared.listeners.delete(this.sharedUpdate),this.shared.references.delete(this.referenceOwner)),this.authority=t,this.shared=(e=>{let t=dc.get(e);return t||(t={signed:{},queued:new Set,inFlight:new Map,retry:new Map,listeners:new Set,settlers:new Set,references:new Map},dc.set(e,t)),t})(t),this.disposed||(this.shared.listeners.add(this.sharedUpdate),this.shared.references.set(this.referenceOwner,new Set(this.referenced)))),this.shared}start(e,t){this.disposed=!1,this.referenced=new Set(t());const i=this.bind(e());i.listeners.add(this.sharedUpdate),i.references.set(this.referenceOwner,new Set(this.referenced)),this.stopTimer(),this.resignTimer=setInterval(()=>this.resign(e(),t()),288e5)}dispose(){if(this.disposed=!0,this.stopTimer(),clearTimeout(this.batchTimer),this.shared){this.shared.listeners.delete(this.sharedUpdate),this.shared.references.delete(this.referenceOwner);for(const e of this.queued)this.shared.queued.delete(e)}this.queued.clear()}invalidate(e){const t=this.bind(e);clearTimeout(this.batchTimer),this.queued.clear(),t.queued.clear(),t.inFlight.clear(),t.retry.clear(),t.signed={}}stopTimer(){void 0!==this.resignTimer&&clearInterval(this.resignTimer),this.resignTimer=void 0}display(e,t){const i=Hn(t);if(!i.startsWith("/api/houseplan/content/"))return i;const n=this.bind(e);this.referenced.add(i),n.references.set(this.referenceOwner,new Set(this.referenced));const r=n.signed[i],o=r?this.now()-r.at:1/0;return o{const t=[...this.queued];this.queued.clear();for(const e of t)i.queued.delete(e);this.sign(e,t)},30))}sign(e,t){if(!t.length||!e?.callWS)return;const i=this.bind(e);for(const n of function(e,t){const i=Math.max(1,Math.floor(t)),n=[];for(let t=0;t{const n=i.inFlight.get(e);return!(void 0!==n&&t-n<15e3)&&(i.inFlight.set(e,t),!0)});r.length&&e.callWS({type:"houseplan/content/sign",paths:r}).then(e=>{const t=this.now();let n=0,o=!1;for(const s of r){const r=e?.urls?.[s];if("string"==typeof r&&r){const e=i.signed[s];e?.loaded&&e.url!==r?(e.pending={url:r,at:t},this.preloadReplacement(i,s,r,t)):(i.signed[s]={url:r,at:t,loaded:e?.url===r&&!!e.loaded},o=!0),i.retry.delete(s),n++}else this.backOff(i,s)}if(n&&(this.trimShared(i),o))for(const e of[...i.listeners])e()}).catch(()=>{for(const e of r)this.backOff(i,e)}).finally(()=>{for(const e of r)i.inFlight.get(e)===t&&i.inFlight.delete(e);for(const e of[...i.settlers])e()})}}preloadReplacement(e,t,i,n){const r=()=>{const r=e.signed[t];if(r?.pending?.url===i){e.signed[t]={url:i,at:n,loaded:!0},e.retry.delete(t),this.trimShared(e);for(const t of[...e.listeners])t()}},o=()=>{const n=e.signed[t];n?.pending?.url===i&&(delete n.pending,this.backOff(e,t))};if("undefined"==typeof Image)return void r();const s=new Image;s.onload=()=>{("function"==typeof s.decode?s.decode():Promise.resolve()).then(r).catch(o)},s.onerror=o,s.src=i}preloadCurrentImage(e,t,i){if(i.loaded)return Promise.resolve(!0);if(i.preload)return i.preload;if("undefined"==typeof Image)return i.loaded=!0,Promise.resolve(!0);const n=i.url;return i.preload=new Promise(r=>{const o=new Image;let s=!1;const a=o=>{if(s)return;s=!0,clearTimeout(l);const a=e.signed[t];if(a===i&&delete a.preload,o&&a===i&&a.url===n){a.loaded=!0;for(const t of[...e.listeners])t();r(!0)}else o||a!==i||this.backOff(e,t),r(!1)};o.onload=()=>{("function"==typeof o.decode?o.decode():Promise.resolve()).then(()=>a(!0)).catch(()=>a(!1))},o.onerror=()=>a(!1);const l=setTimeout(()=>a(!1),rc);o.src=n}),i.preload}prepareImage(e,t){const i=Hn(t);if(!i.startsWith("/api/houseplan/content/"))return Promise.resolve(!0);const n=this.bind(e),r=()=>{const t=n.signed[i];if(t&&this.now()-t.atthis.now()&&!n.inFlight.has(i)&&!n.queued.has(i)?Promise.resolve(!1):null},o=r();return o?(s=o,new Promise(e=>{let t=!1;const i=i=>{t||(t=!0,clearTimeout(n),e(i))},n=setTimeout(()=>i(!1),rc);s.then(i).catch(()=>i(!1))})):new Promise(e=>{let t=!1,i=null;const o=i=>{t||(t=!0,clearTimeout(a),n.settlers.delete(s),e(i))},s=()=>{t||i||(i=r(),i&&i.then(o).catch(()=>o(!1)))},a=setTimeout(()=>o(!1),rc);n.settlers.add(s),s()});var s}backOff(e,t){const i=e.retry.get(t)?.delay||0,n=Math.min(6e4,i?2*i:2e3);e.retry.set(t,{notBefore:this.now()+n,delay:n})}trimShared(e){const t=Object.entries(e.signed);if(t.length<=512)return;const i=new Set(e.inFlight.keys());for(const t of e.references.values())for(const e of t)i.add(e);for(const[e,n]of t)(n.pending||n.preload)&&i.add(e);t.sort((e,t)=>t[1].at-e[1].at);const n=t.filter(([e])=>i.has(e));for(const e of t){if(n.length>=512)break;i.has(e[0])||n.push(e)}e.signed=Object.fromEntries(n)}resign(e,t){const i=this.bind(e);this.referenced=new Set(t),i.references.set(this.referenceOwner,new Set(this.referenced));const n=this.now(),r=new Set;for(const e of i.references.values())for(const t of e)r.add(t);const o={};for(const[e,t]of Object.entries(i.signed))r.has(e)&&n-t.at!!o[e]&&!o[e].pending))}markLoaded(e,t,i){const n=Hn(t);if(!n.startsWith("/api/houseplan/content/"))return;const r=this.bind(e).signed[n];if(r&&(!i||r.url===i)&&!r.loaded){r.loaded=!0;for(const t of[...this.bind(e).listeners])t()}}isReady(e,t){const i=Hn(t);if(!i.startsWith("/api/houseplan/content/"))return!0;const n=this.bind(e).signed[i];return!!n&&this.now()-n.at=2&&(this._sequenceMultitouch=!0,this._postGestureClickBlocked=!0))}pointerTerminal(e,t){if("touch"!==t)return!1;const i=this._sequenceMultitouch;return this._activeTouchPointers.delete(e),0===this._activeTouchPointers.size&&(this._sequenceMultitouch=!1),i}reset(){this._activeTouchPointers.clear(),this._sequenceMultitouch=!1,this._postGestureClickBlocked=!1}}const _c=1e-7,mc=(e,t)=>{const i=e.x-t.x,n=e.y-t.y;return i*i+n*n};function gc(e){const t=Math.max(0,e.floorRadius);return{left:Math.min(e.painted.left,e.center.x-t),top:Math.min(e.painted.top,e.center.y-t),right:Math.max(e.painted.right,e.center.x+t),bottom:Math.max(e.painted.bottom,e.center.y+t)}}function fc(e,t){let i=null,n=Number.POSITIVE_INFINITY;for(const r of e){const e=mc(t,r.center);(efunction(e,t){const i=Math.max(0,t.right-t.left),n=Math.max(0,t.bottom-t.top);if(i<=0||n<=0)return!1;const r=Math.min(i,n)/2,o=Math.max(t.left+r,Math.min(t.right-r,e.x)),s=Math.max(t.top+r,Math.min(t.bottom-r,e.y));return mc(e,{x:o,y:s})<=r*r+_c}(t,e.painted));if(i.length)return fc(i,t);return fc(e.filter(e=>{const i=Math.max(0,e.floorRadius);return mc(t,e.center)<=i*i+_c}),t)}class yc{constructor(e,t=44){this.cellSize=t,this.buckets=new Map;const i=Number.isFinite(t)&&t>0?t:44;this.cellSize=i;for(const t of e){const e=gc(t),n=Math.floor(e.left/i),r=Math.floor(e.right/i),o=Math.floor(e.top/i),s=Math.floor(e.bottom/i);for(let e=n;e<=r;e++)for(let i=o;i<=s;i++){const n=`${e}:${i}`,r=this.buckets.get(n);r?r.push(t):this.buckets.set(n,[t])}}}resolve(e){const t=`${Math.floor(e.x/this.cellSize)}:${Math.floor(e.y/this.cellSize)}`;return vc(this.buckets.get(t)||[],e)}}class bc{constructor(){this.active=new Map,this.released=new Map}begin(e,t){this.released.delete(e),this.active.set(e,t)}owner(e){return this.active.get(e)||null}release(e){const t=this.active.get(e)||null;if(!t)return this.released.get(e)||null;for(this.active.delete(e),this.released.set(e,t);this.released.size>16;){const e=this.released.keys().next().value;if(void 0===e)break;this.released.delete(e)}return t}consumeClick(e){const t=this.released.get(e)||null;return this.released.delete(e),t}cancel(e){const t=this.active.get(e)||null;return this.active.delete(e),t}clear(){this.active.clear(),this.released.clear()}}class wc{constructor(){this.index=null,this.pointers=new bc,this.hoverId=null,this.hoverElement=null}invalidate(){this.index=null}reset(e){this.invalidate(),this.pointers.clear(),this.hover(e,null)}clearPointers(){this.pointers.clear()}cancel(e){return this.pointers.cancel(e)}release(e){return this.pointers.release(e)}indexFor(e){if(this.index)return this.index;const t=[];for(const i of e.querySelectorAll('.devlayer > .dev[data-hp="device"][data-id]')){const e=i.querySelector(".device-shell-frame"),n=i.getBoundingClientRect(),r=e?.getBoundingClientRect();!i.dataset.id||!i.isConnected||!r||n.width<=0||n.height<=0||r.width<=0||r.height<=0||t.push({id:i.dataset.id,center:{x:n.left+n.width/2,y:n.top+n.height/2},painted:{left:r.left,top:r.top,right:r.right,bottom:r.bottom},floorRadius:Math.max(22,Math.min(r.width,r.height)/2)})}return this.index=new yc(t),this.index}at(e,t,i,n,r){const o=this.indexFor(e).resolve({x:n,y:r})?.id;return o&&t.find(e=>e.id===o&&e.space===i)||null}byId(e,t,i){return i&&e.find(e=>e.id===i&&e.space===t)||null}begin(e,t,i,n,r){const o=this.at(e,t,i,n.clientX,n.clientY)||r;return this.pointers.begin(n.pointerId,o.id),o}pointer(e,t,i,n,r){const o=n.pointerId;return(Number.isFinite(o)?this.byId(t,i,this.pointers.owner(o)):null)||this.at(e,t,i,n.clientX,n.clientY)||r}click(e,t,i,n,r){if(!(n instanceof PointerEvent))return r;const o=n,s=Number.isFinite(o.pointerId)?this.pointers.consumeClick(o.pointerId):null;return this.byId(t,i,s)||this.at(e,t,i,o.clientX,o.clientY)||r}hover(e,t){this.hoverId===t&&this.hoverElement?.isConnected||(this.hoverElement?.removeAttribute("data-hp-device-hover"),this.hoverId=t,this.hoverElement=t&&[...e.querySelectorAll('.devlayer > .dev[data-hp="device"][data-id]')].find(e=>e.dataset.id===t)||null,this.hoverElement?.setAttribute("data-hp-device-hover",""))}}function kc(e,t){if(t)return e.find(e=>e.id===t)}function xc(e,t){return{id:e,title:t,plan_url:null,view_box:[0,0,1,1],rooms:[],wall_segments:[]}}function Sc(e="file"){const t="draw"===e;return{source:e,showBorders:t,showNames:t,displayTouched:!1}}function $c(e,t){if(e.displayTouched)return{...e,source:t};const i="draw"===t;return{...e,source:t,showBorders:i,showNames:i}}function Mc(e,t,i){return{...e,[t]:i,displayTouched:!0}}function Rc(e){const t=String(e??"").trim().replace(",",".");if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(t))return null;const i=Number(t);return Number.isFinite(i)?i:null}function Cc(e,t){const i=e=>{if(""===String(e??"").trim())return{valid:!0,value:null};const t=Rc(e);return{valid:null!==t,value:t}},n=i(e),r=i(t);return n.valid&&r.valid?null!==n.value&&null!==r.value&&n.value>r.value?{valid:!0,min:r.value,max:n.value}:{valid:!0,min:n.value,max:r.value}:{valid:!1,min:n.value,max:r.value}}function Tc(e,t,i,n,r,o){const s=Cc(n,r);return pn(e,t,o&&s.valid?{settings:{...i.settings||{},temp_min:s.min,temp_max:s.max}}:i)}function Dc(e){const t=e=>"number"==typeof e&&Number.isFinite(e)?String(e):"";return[t(e?.temp_min),t(e?.temp_max)]}function Ac(e,t,i){const n=Cc(t,i);return!!n.valid&&(null===n.min?delete e.temp_min:e.temp_min=n.min,null===n.max?delete e.temp_max:e.temp_max=n.max,!0)}var Pc="M11,18H13V16H11V18M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,6A4,4 0 0,0 8,10H10A2,2 0 0,1 12,8A2,2 0 0,1 14,10C14,12 11,11.75 11,15H13C13,12.75 16,12.5 16,10A4,4 0 0,0 12,6Z";function Fc(e,t,i){return[e[0]*t+e[1]*i+e[2],e[3]*t+e[4]*i+e[5]]}function zc(e,t){let i=0;for(const[n,r]of t){const t=Fc(e,n[0],n[1]);i=Math.max(i,Math.hypot(t[0]-r[0],t[1]-r[1]))}return i}const Ic=e=>{if(null==e||""===e)return null;const t=Number(e);return Number.isFinite(t)?t:null},Oc=e=>{const t=e,i=Ic(Array.isArray(t)?t[0]:t?.x),n=Ic(Array.isArray(t)?t[1]:t?.y);return null==i||null==n?null:[i,n]};function Ec(e){if(!Array.isArray(e))return null;const t=[];for(const i of e){const e=Oc(i);if(!e)return null;t.push(e)}if(t.length>1){const e=t[0],i=t[t.length-1];e[0]===i[0]&&e[1]===i[1]&&t.pop()}if(t.length<3)return null;let i=0,n=0,r=0;for(let e=0;ee+t[0],0)/t.length,t.reduce((e,t)=>e+t[1],0)/t.length]:[n/(3*i),r/(3*i)]}function Nc(e){if(!Array.isArray(e))return null;const t=[];for(const i of e){const e=Oc(i);if(!e)return null;t.push(e)}if(t.length>1){const e=t[0],i=t[t.length-1];e[0]===i[0]&&e[1]===i[1]&&t.pop()}const i=Ec(t);if(!i)return null;const n=t.map(e=>e[0]),r=t.map(e=>e[1]);return{centroid:i,bbox:[Math.min(...n),Math.min(...r),Math.max(...n),Math.max(...r)]}}function Hc(e){let t=e;if(t&&"object"==typeof t&&!Array.isArray(t)){const e=t;t=e.path??e.points??t}if(!Array.isArray(t)||!t.length)return[];let i=(t.some(e=>(e=>Array.isArray(e)?e.length>=2&&!Array.isArray(e[0])&&("object"!=typeof e[0]||null==e[0]):!!e&&"object"==typeof e&&("x"in e||"y"in e))(e))?[t]:t.filter(Array.isArray)).map(e=>e.map(Oc).filter(e=>null!=e)).filter(e=>e.length>=2);i.length>64&&(i=i.slice(-64));const n=i.reduce((e,t)=>e+t.length,0);if(n<=4e3)return i.map(e=>e.slice());const r=4e3-2*i.length,o=i.map(e=>e.length-2),s=o.reduce((e,t)=>e+t,0),a=o.map(e=>r*e/s),l=a.map(Math.floor);let c=r-l.reduce((e,t)=>e+t,0);const h=a.map((e,t)=>({index:t,fraction:e-Math.floor(e)})).sort((e,t)=>t.fraction-e.fraction||e.index-t.index);for(let e=0;efunction(e,t){if(t>=e.length)return e.slice();if(t<=2)return[e[0],e[e.length-1]];const i=[];for(let n=0;ne.slice()),i=t[t.length-1];return i?(i.length>2?i.pop():t.pop(),t):[]}const qc=e=>Number.isFinite(e[0])&&Number.isFinite(e[1]),jc=(e,t)=>e[0]===t[0]&&e[1]===t[1];function Wc(e){if(!e)return null;const t=e.vacuum_position||e.robot_position||null,i=t&&null!=Ic(t.x)&&null!=Ic(t.y)?{x:Ic(t.x),y:Ic(t.y),a:Ic(t.a??t.angle??t.theta)}:null,n=Hc(e.path?.path??e.path?.points??e.path),r=[],o=e.rooms,s=Array.isArray(o)?o.map((e,t)=>[String(e?.id??t),e]):o&&"object"==typeof o?Object.entries(o):[];for(const[e,t]of s){if(!t||"object"!=typeof t)continue;const i=String(t.name??t.label??"").trim(),n=[[Ic(t.cx),Ic(t.cy)],[Ic(t.center?.x),Ic(t.center?.y)],[Ic(t.x),Ic(t.y)]].find(([e,t])=>null!=e&&null!=t);let o=n?.[0]??null,s=n?.[1]??null;const a=Nc(t.outline),l=Ic(t.x0),c=Ic(t.y0),h=Ic(t.x1),d=Ic(t.y1),u=(null!=l&&null!=c&&null!=h&&null!=d?[Math.min(l,h),Math.min(c,d),Math.max(l,h),Math.max(c,d)]:null)||a?.bbox||null;if(null!=o&&null!=s||!a||([o,s]=a.centroid),null!=o&&null!=s||!u||(o=(u[0]+u[2])/2,s=(u[1]+u[3])/2),i&&null!=o&&null!=s){const t={id:e,name:i,cx:o,cy:s};u&&([t.x0,t.y0,t.x1,t.y1]=u),r.push(t)}}const a=function(e){return String(e.map_name??e.current_map??e.map_index??e.selected_map??"default")}(e);return i||r.length||n.length?{pos:i,path:n,rooms:r,mapId:a}:null}function Uc(e,t,i){return![e,t,i].every(Number.isFinite)||e<0||t<=0||i<=0?Number.POSITIVE_INFINITY:e/t*i}const Gc=40;function Vc(e,t,i){if(!e||!t)return null;const n=t.attributes||{},r=e.split(".")[0]||"",o=null!=i?.platform?String(i.platform):null,s=!!Oc(n.vacuum_position??n.robot_position),a=!(!n.rooms||"object"!=typeof n.rooms),l=Hc(n.path?.path??n.path?.points??n.path).length>0,c=[n.map_name,n.current_map,n.map_index,n.selected_map].some(e=>null!=e),h="xiaomi_cloud_map_extractor"===o,d=a||l||c;let u=null;if(s?u="compatible":h?u="known_xcme_incomplete":d?u="partial":"camera"===r&&(u="camera"),!u)return null;const p=s?"camera"===r?300:200:h?100:d?50:0;return{entityId:e,name:String(n.friendly_name||e),platform:o,category:u,hasPosition:s,hasRooms:a,hasPath:l,hasMapId:c,score:p}}const Kc=e=>e.toLowerCase().replace(/[\s_\-.,]+/g,"");function Yc(e,t){const i=new Set(t.map(Kc).filter(Boolean)),n=new Set;for(const t of e){const e=Kc(t.name||"");e&&i.has(e)&&n.add(e)}return n.size}function Xc(e,t){const i=new Map(t.map(e=>[Kc(e.name),e])),n=[],r=[];for(const t of e){const e=i.get(Kc(t.name));e&&(n.push([[t.cx,t.cy],[e.cx,e.cy]]),r.push(t.name))}if(n.length<3)return null;const o=function(e){if(e.length<3)return null;let t=0,i=0,n=0,r=0,o=0,s=0,a=0,l=0,c=0,h=0,d=0,u=0;for(const[[p,_],[m,g]]of e){if(![p,_,m,g].every(Number.isFinite))return null;t+=p*p,i+=p*_,n+=p,r+=_*_,o+=_,s+=1,a+=p*m,l+=_*m,c+=m,h+=p*g,d+=_*g,u+=g}const p=[t,i,n,i,r,o,n,o,s],_=e=>{const[t,i,n,r,o,s,a,l,c]=p,h=t*(o*c-s*l)-i*(r*c-s*a)+n*(r*l-o*a);if(!Number.isFinite(h)||Math.abs(h)<1e-9)return null;const d=[(o*c-s*l)/h,(n*l-i*c)/h,(i*s-n*o)/h,(s*a-r*c)/h,(t*c-n*a)/h,(n*r-t*s)/h,(r*l-o*a)/h,(i*a-t*l)/h,(t*o-i*r)/h];return[d[0]*e[0]+d[1]*e[1]+d[2]*e[2],d[3]*e[0]+d[4]*e[1]+d[5]*e[2],d[6]*e[0]+d[7]*e[1]+d[8]*e[2]]},m=_([a,l,c]),g=_([h,d,u]);if(!m||!g)return null;const f=[m[0],m[1],m[2],g[0],g[1],g[2]];return f.every(Number.isFinite)?f:null}(n);return o?{matrix:o,matched:r,residual:zc(o,n)}:null}function Zc(e,t,i){const n=e[e.length-1];if(n&&n[0]===t[0]&&n[1]===t[1])return e;if(e.push(t),e.length<=600)return e;let r=function(e,t){if(e.length<3)return e.slice();const i=new Uint8Array(e.length);i[0]=i[e.length-1]=1;const n=[[0,e.length-1]];for(;n.length;){const[r,o]=n.pop(),[s,a]=e[r],[l,c]=e[o],h=l-s,d=c-a,u=Math.hypot(h,d)||1e-9;let p=0,_=-1;for(let t=r+1;tp&&(p=i,_=t)}_>0&&p>t&&(i[_]=1,n.push([r,_],[_,o]))}const r=[];for(let t=0;t600&&(r=r.filter((e,t)=>t%2==0||t===r.length-1)),r}function Jc(e){return"cleaning"===e||"returning"===e||"on"===e}const Qc={0:[1,0],90:[0,1],180:[-1,0],270:[0,-1]};function eh(e){const[t,i]=Qc[e.rot]||[1,0],n=e.mir?-1:1;return[e.s*t*n,-e.s*i,e.ox,e.s*i*n,e.s*t,e.oy]}function th(e){const t=e[0]*e[4]-e[1]*e[3];if(!Number.isFinite(t)||Math.abs(t)<1e-12)return null;const i=t<0,n=Math.sqrt(Math.abs(t));let r=180*Math.atan2(-e[1],e[4])/Math.PI;return r=(90*Math.round(r/90)%360+360)%360,{ox:e[2],oy:e[5],s:n,rot:r,mir:i}}function ih(e,t){const i=[],n=[];for(const t of e)null!=t.x0?(i.push(t.x0,t.x1),n.push(t.y0,t.y1)):(i.push(t.cx),n.push(t.cy));if(!i.length)return{ox:t[0]+t[2]/2,oy:t[1]+t[3]/2,s:t[2]/1e4,rot:0,mir:!0};const r=Math.min(...i),o=Math.max(...i),s=Math.min(...n),a=Math.max(...n),l=Math.max(o-r,a-s)||1,c={ox:0,oy:0,s:.6*Math.min(t[2],t[3])/l,rot:0,mir:!0},h=eh(c),[d,u]=Fc(h,(r+o)/2,(s+a)/2);return c.ox=t[0]+t[2]/2-d,c.oy=t[1]+t[3]/2-u,c}function nh(e,t,i,n){const[r,o]=Fc(eh(t),i,n),s=eh({...e,ox:0,oy:0}),[a,l]=Fc(s,i,n);return{...e,ox:r-a,oy:o-l}}function rh(e){const t=e?.trail_mode;return"never"===t||"cleaning"===t||"always"===t?t:!1===e?.trail?"never":"cleaning"}const oh=e=>"number"==typeof e&&Number.isFinite(e);function sh(e){return Array.isArray(e)&&6===e.length&&e.every(oh)?[e[0],e[1],e[2],e[3],e[4],e[5]]:null}function ah(e,t,i){return"legacy:"+e+" "+t+" "+i}function lh(e,t,i,n){const r=t?.map_routes;if(Array.isArray(r))return r.filter(e=>e&&"string"==typeof e.id&&e.id).map(e=>({id:e.id,source:String(e.source??""),map_id:String(e.map_id??""),space:String(e.space??""),calibration:sh(e.calibration)}));const o="string"==typeof t?.source&&t.source?t.source:n||"";if(!o)return[];const s=t?.calibration;if(!s||"object"!=typeof s)return[];const a=[];for(const t of Object.keys(s)){const n=sh(s[t]);n&&a.push({id:ah(e,o,t),source:o,map_id:t,space:i,calibration:n})}return a}const ch=(e,t)=>e instanceof Map?e.get(t):e?.[t];function hh(e){const t=[];let i=!1,n="",r="";for(const o of e.routes){const s=ch(e.observed,o.source);void 0!==s&&(i=!0,n||(n=o.source,r=s),s===o.map_id&&t.push(o))}if(t.length>1)return{kind:"ambiguous",routeIds:t.map(e=>e.id).sort()};if(1===t.length){const i=t[0];if(e.spaceIds&&!e.spaceIds.has(i.space))return{kind:"missing_space",route:i};const n=sh(i.calibration);return n?{kind:"ready",route:{...i,calibration:n}}:{kind:"needs_calibration",route:i}}if(i)return{kind:"unmapped",source:n,mapId:r};const o=e.observed instanceof Map?[...e.observed.entries()]:Object.entries(e.observed||{});if(o.length){const e=o.slice().sort((e,t)=>e[0].localeCompare(t[0]))[0];return{kind:"unmapped",source:e[0],mapId:e[1]}}return{kind:"none"}}function dh(e,t,i){const n=new Set;for(const t of e)t.source&&n.add(t.source);for(const e of t)e&&n.add(e);const r={};for(const e of[...n].sort()){const t=i(e);void 0!==t&&(r[e]=t)}return r}function uh(e,t,i){if(!e)return null;const n="string"==typeof e.route_id?e.route_id:"";if(n)return t.find(e=>e.id===n)||null;const r=function(e,t,i){if(!e||"string"!=typeof e.map_id)return{kind:"orphan_run"};const n=e.map_id,r="string"==typeof i?i:"";let o=t.filter(e=>e.map_id===n);return r&&(o=o.filter(e=>e.source===r)),1===o.length?{kind:"adopted",route:o[0]}:0===o.length?{kind:"orphan_run"}:{kind:"ambiguous_run",routeIds:o.map(e=>e.id).sort()}}(e,t,i);return"adopted"===r.kind?r.route:null}function ph(e){const t="ready"===e.resolution.kind?e.resolution.route:null,i=t&&t.space===e.renderSpace?sh(t.calibration):null,n=uh(e.serverCurrent,e.routes,e.rootSource),r=!!t&&!!n&&n.id===t.id,o=uh(e.serverPrevious,e.routes,e.rootSource);return{live:i,currentRunMatches:r,previous:!!o&&o.space===e.renderSpace&&(e.explicitRoutes||!!t&&o.id===t.id)?sh(o.calibration):null}}const _h={availability:"available",status:"alarm",activity:"none"},mh=new Set(["motion","vibration","sound"]),gh=new Set(["occupancy","presence"]),fh=new Set(["door","window","garage_door","opening"]),vh=new Set(["running","power"]),yh=new Set(["smoke","gas","carbon_monoxide","moisture","safety","tamper","problem"]);const bh=new Set(["running","working","washing","rinsing","spinning","drying","heating","cooling","cleaning","cooking","playing","recording","pumping","irrigating","humidifying","dehumidifying","fan","preheating","defrosting"]),wh=new Set([...bh,"start","started","run","active","in_progress","wash","rinse","spin","dry"]),kh=new Set(["off","idle","paused","standby","docked","finished","complete","completed","stopped","ready","sleeping","stop","end","done","inactive"]),xh=new Set(["heat","cool","heat_cool","auto","dry","fan_only"]),Sh=e=>""===e||"unknown"===e||"unavailable"===e||"__missing__"===e,$h=e=>String(e??"").trim().toLowerCase(),Mh=e=>$h(e).replace(/[\s-]+/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,""),Rh=new Map([["run_state",0],["job_state",0],["operation_state",0],["activity_state",0],["machine_state",1],["running_state",1],["status",2],["device_status",2],["machine_status",2]]),Ch=new Set(["wifi","connection","signal","battery"]);function Th(e,t){const i=e?.entities?.[t]||{};if("config"===i.entity_category)return null;const n=String(t||"").split(".").slice(1).join("."),r=[i.translation_key,i.original_name,i.name],o=[...r,n];r.some(e=>$h(e))||o.push(e?.states?.[t]?.attributes?.friendly_name);const s=o.map(Mh).filter(Boolean);if(s.some(e=>e.split("_").some(e=>Ch.has(e))))return null;let a=null;for(const e of s)for(const[t,i]of Rh)(e===t||e.endsWith(`_${t}`))&&(a=null==a?i:Math.min(a,i));return a}const Dh=(e,t)=>null!=Th(e,t);function Ah(e,t){if(!t.startsWith("switch."))return!1;const i=e?.entities?.[t]||{},n=e?.states?.[t],r=t.slice(7).toLowerCase();if(/(?:^|_)(?:main_)?power$/.test(r))return!0;if([i.translation_key,i.original_name,i.name].map($h).some(e=>["power","main power","power switch","питание"].includes(e)))return!0;const o=$h(n?.attributes?.friendly_name);return/(?:^|[\s._-])(?:main[\s._-]+)?power$/.test(o)||/(?:^|[\s._-])питание$/.test(o)}function Ph(e){for(const t of["hvac_action","action","current_operation","run_state","job_state","operation","activity"]){const i=$h(e?.[t]);if(bh.has(i)||kh.has(i))return i}return""}function Fh(e,t){const i=e?.states?.[t],n=i?$h(i.state):"__missing__",r=String(t||"").split(".")[0],o=$h(i?.attributes?.device_class),s={eid:t,state:n,availability:Sh(n)?"unavailable":"available",status:"neutral",activity:"none",edge:"none"};if("unavailable"===s.availability)return s;if(function(e,t,i){return"alarm_control_panel"===e?"triggered"===i:"on"===i&&Yn(e,t)}(r,o,n))return{...s,status:"alarm"};if("binary_sensor"===r)return mh.has(o)?{...s,edge:"rising"}:gh.has(o)?{...s,activity:"on"===n?"presence":"none"}:fh.has(o)?{...s,status:"on"===n?"open":"neutral",edge:"rising"}:"moving"===o?{...s,activity:"on"===n?"transition":"none"}:vh.has(o)&&"on"===n?{...s,status:"working",activity:"running"}:s;if("cover"===r)return{...s,activity:"opening"===n||"closing"===n?"transition":"none",edge:"terminal_transition"};if("lock"===r)return{...s,status:"unlocked"===n||"open"===n?"open":"neutral",activity:"locking"===n||"unlocking"===n?"transition":"none",edge:"terminal_transition"};if("valve"===r)return{...s,status:["open","opening","closing"].includes(n)?"open":"neutral",activity:"opening"===n||"closing"===n?"transition":"none",edge:"terminal_transition"};if("climate"===r){const e=Ph(i.attributes),t=Array.isArray(i.attributes?.hvac_modes)?i.attributes.hvac_modes.map($h):[],r=!kh.has(n)&&(xh.has(n)||bh.has(n)||t.includes(n));return(e?bh.has(e):r)?{...s,status:"working",activity:"running"}:s}if(["light","switch","fan","humidifier"].includes(r))return"on"===n?{...s,status:"working",activity:"running"}:s;if("media_player"===r)return"off"===n?{...s,availability:"unavailable"}:s;if("vacuum"===r)return"cleaning"===n?{...s,status:"working",activity:"running"}:"returning"===n?{...s,status:"working",activity:"transition"}:s;if("script"===r)return"on"===n?{...s,status:"working",activity:"running"}:s;if("automation"===r)return s;if("button"===r||"event"===r)return{...s,edge:"change"};const a=Ph(i.attributes);return bh.has(a)||bh.has(n)&&!kh.has(n)?{...s,status:"working",activity:"running"}:s}function zh(e,t,i){const n=i.filter(t=>t.startsWith("switch.")&&!e?.entities?.[t]?.entity_category),r=t.find(t=>Ah(e,t));if(!(n.length>1&&!!r))return t.map(t=>Fh(e,t));const o=t.find(t=>t!==r&&Dh(e,t)),s=Fh(e,r);return"unavailable"===s.availability||"off"===s.state?t.map(t=>({eid:t,state:e?.states?.[t]?$h(e.states[t].state):"__missing__",availability:"unavailable",status:"neutral",activity:"none",edge:"none"})):t.map(t=>{if(t===o)return function(e,t){const i=e?.states?.[t],n=i?$h(i.state):"__missing__",r={eid:t,state:n,availability:Sh(n)?"unavailable":"available",status:"neutral",activity:"none",edge:"none"};if("unavailable"===r.availability)return r;const o=Ph(i?.attributes);return bh.has(o)||wh.has(n)&&!kh.has(n)?{...r,status:"working",activity:"running"}:r}(e,t);return{...t===r?s:Fh(e,t),status:"neutral",activity:"none",edge:"none"}})}function Ih(e){if(!e.length)return{availability:"available",status:"neutral",activity:"none"};const t=e.filter(e=>"available"===e.availability);if(!t.length)return{availability:"unavailable",status:"neutral",activity:"none"};if(t.some(e=>"alarm"===e.status))return _h;const i=t.some(e=>"working"===e.status)?"working":t.some(e=>"open"===e.status)?"open":"neutral",n=t.some(e=>"transition"===e.activity)?"transition":t.some(e=>"presence"===e.activity)?"presence":t.some(e=>"running"===e.activity)?"running":"none";return{availability:"available",status:i,activity:n}}function Oh(e,t){if(!(e=>!!e&&!Sh(e))(e)||"unavailable"===t.availability||e===t.state)return null;if("rising"===t.edge)return"off"===e&&"on"===t.state?"event":null;if("change"===t.edge)return"event";if("terminal_transition"===t.edge){const i=new Set([e,t.state]);if(i.has("closed")&&i.has("open")||i.has("locked")&&i.has("unlocked"))return"transition"}return null}const Eh=(e,t=0)=>{const i=Number(e);return Number.isInteger(i)&&i>=0?i:t},Nh=(e,t)=>{const i={rev:0,configRev:Eh(t),off:new Set};if(null==e)return{snapshot:i,valid:!1};const n=e.off;return!Number.isInteger(e.rev)||Number(e.rev)<0||!Number.isInteger(e.config_rev)||Number(e.config_rev)<0||!Array.isArray(n)||n.some(e=>"string"!=typeof e||!e)?{snapshot:i,valid:!1}:{snapshot:{rev:Number(e.rev),configRev:Number(e.config_rev),off:new Set(n)},valid:!0}};function Hh(e,t=0){return Nh(e,t).snapshot}function Lh(e,t,i,n){const r=Nh(t,i);return n&&r.valid&&r.snapshot.configRev===i?e.configRev===i&&r.snapshot.rev{try{const[i,n]=await Promise.all([e.callWS({type:"config/device_registry/list"}),e.callWS({type:"config/entity_registry/list"})]),r=Zh(i,"id"),o=Zh(n,"entity_id");if(!r||!o)throw new Error("invalid_registry_response");t.devices=r,t.entities=o,t.authoritative=!0,t.access="full",t.lastSuccess=Date.now(),t.error=void 0}catch(e){t.authoritative=!1,t.access="limited",t.error=function(e){if(e&&"object"==typeof e){const t=e;return String(t.message||t.code||t.error||"registry_unavailable")}return String(e||"registry_unavailable")}(e)}finally{t.revision++,t.loading=void 0,function(e){for(const t of[...e.listeners])try{t()}catch{}}(t)}})()),t.loading}function Qh(e,t){void 0===t.reloadTimer&&(t.reloadTimer=globalThis.setTimeout(()=>{t.reloadTimer=void 0,Jh(e,t)},80))}async function ed(e,t){if(t.subscribing||t.unsubDevice&&t.unsubEntity)return t.subscribing;const i=e?.connection?.subscribeEvents;return"function"==typeof i?(t.subscribing=(async()=>{try{t.unsubDevice||(t.unsubDevice=await i.call(e.connection,()=>Qh(e,t),"device_registry_updated")),t.unsubEntity||(t.unsubEntity=await i.call(e.connection,()=>Qh(e,t),"entity_registry_updated"))}catch{}finally{0===t.refs&&(t.unsubDevice?.(),t.unsubEntity?.(),t.unsubDevice=void 0,t.unsubEntity=void 0),t.subscribing=void 0}})(),t.subscribing):void 0}function td(e,t){const i=Xh(e);if(!i)return()=>{};const n=0===i.refs;i.refs++,i.listeners.add(t),("pending"===i.access||n)&&Jh(e,i),ed(e,i);let r=!1;return()=>{r||(r=!0,i.listeners.delete(t),i.refs=Math.max(0,i.refs-1),i.refs>0||(i.unsubDevice?.(),i.unsubEntity?.(),i.unsubDevice=void 0,i.unsubEntity=void 0,void 0!==i.reloadTimer&&globalThis.clearTimeout(i.reloadTimer),i.reloadTimer=void 0))}}function id(e){const t=Xh(e);t&&(Qh(e,t),ed(e,t))}function nd(e){const t=Xh(e);if(!t)return{revision:0,authoritative:!1,access:"limited",devices:e?.devices||{},entities:e?.entities||{},lastSuccess:0,error:"registry_unavailable"};let i=e?.devices||{},n=e?.entities||{};if(t.authoritative){const r=t.liveDevices!==i||t.liveEntities!==n,o=void 0!==t.liveDevices||void 0!==t.liveEntities;if(r&&(t.liveDevices=i,t.liveEntities=n,t.projectedRevision=void 0,o&&Qh(e,t)),t.projectedRevision!==t.revision||!t.projectedDevices||!t.projectedEntities){const e={...t.devices},r={...t.entities};for(const[t,n]of Object.entries(i))Object.prototype.hasOwnProperty.call(e,t)||(e[t]=n);for(const[e,t]of Object.entries(n))Object.prototype.hasOwnProperty.call(r,e)||(r[e]=t);t.projectedDevices=e,t.projectedEntities=r,t.projectedRevision=t.revision}i=t.projectedDevices,n=t.projectedEntities}return{revision:t.revision,authoritative:t.authoritative,access:t.access,devices:i,entities:n,lastSuccess:t.lastSuccess,error:t.error}}function rd(e){if(!e||"object"!=typeof e&&"function"!=typeof e)return 0;let t=Gh.get(e);return t||(t=Vh++,Gh.set(e,t)),t}function od(e,t=nd(e)){return[t.revision,t.access,rd(t.devices),rd(t.entities)].join(":")}function sd(e){return!!e&&null==e.disabled_by}function ad(e,t=nd(e)){const i={},n={},r={};for(const[e,n]of Object.entries(t.devices||{}))sd(n)&&(i[e]=n);for(const[e,i]of Object.entries(t.entities||{})){if(!sd(i))continue;const r=i.device_id?t.devices?.[i.device_id]:null;t.authoritative&&i.device_id&&!r||(r&&!sd(r)||(n[e]=i))}for(const[i,n]of Object.entries(e?.states||{})){const e=t.entities?.[i];if(e&&!sd(e))continue;const o=e?.device_id?t.devices?.[e.device_id]:null;t.authoritative&&e?.device_id&&!o||(o&&!sd(o)||(r[i]=n))}return{...e,devices:i,entities:n,states:r}}function ld(e,t=nd(e)){return{...e,devices:t.devices||{},entities:t.entities||{}}}function cd(e,t){const i=[];for(const[n,r]of Object.entries(e||{}))r?.device_id===t&&i.push(n);return i}function hd(){if(Yh)return Yh;if("undefined"==typeof localStorage)return{};try{const e=JSON.parse(localStorage.getItem(Kh)||"{}");if(!e||"object"!=typeof e||Array.isArray(e))return{};const t=Date.now(),i={};for(const[n,r]of Object.entries(e))!r||"active"!==r.kind&&"ha_disabled"!==r.kind||!Number.isFinite(r.ts)||t-r.ts>7776e6||(i[n]=r);return Yh=i,Yh}catch{return{}}}function dd(e,t,i=nd(e)){if(!t||"virtual"===t)return{kind:"active",enabledEntityIds:[],allEntityIds:[]};const n=t.indexOf(":");if(n<1)return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]};const r=t.slice(0,n),o=t.slice(n+1);if("device"!==r&&"entity"!==r||!o)return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]};const s=i.devices||{},a=i.entities||{};if(i.authoritative){if("device"===r){const e=s[o];if(!e)return{kind:"orphaned",reason:"device_missing",enabledEntityIds:[],allEntityIds:[]};const t=cd(a,o);if(!sd(e))return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:t};const i=t.filter(e=>sd(a[e]));return t.length&&!i.length?{kind:"ha_disabled",reason:"all_entities",enabledEntityIds:[],allEntityIds:t}:{kind:"active",enabledEntityIds:i,allEntityIds:t}}const t=a[o];return t&&!sd(t)?{kind:"ha_disabled",reason:"entity",enabledEntityIds:[],allEntityIds:[o]}:t?.device_id&&!s[t.device_id]?{kind:"orphaned",reason:"device_missing",enabledEntityIds:[],allEntityIds:[o]}:t?.device_id&&!sd(s[t.device_id])?{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:[o]}:t||e?.states?.[o]?{kind:"active",enabledEntityIds:[o],allEntityIds:[o]}:{kind:"orphaned",reason:"entity_missing",enabledEntityIds:[],allEntityIds:[]}}const l=function(e){return hd()[e]||null}(t);if("device"===r){const t=s[o],i=cd(a,o);if(null!=t?.disabled_by)return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:i};const n=i.filter(e=>{const t=a[e];return null==t?.disabled_by&&(!t.device_id||null==s[t.device_id]?.disabled_by)});if(i.length&&!n.length&&i.every(e=>null!=a[e]?.disabled_by))return{kind:"ha_disabled",reason:"all_entities",enabledEntityIds:[],allEntityIds:i};if("ha_disabled"===l?.kind)return{kind:"ha_disabled",reason:l.reason||"device",enabledEntityIds:[],allEntityIds:i};if(t||n.some(t=>!!e?.states?.[t]))return{kind:"active",enabledEntityIds:n,allEntityIds:i}}else{const t=a[o];if(null!=t?.disabled_by)return{kind:"ha_disabled",reason:"entity",enabledEntityIds:[],allEntityIds:[o]};if(t?.device_id&&null!=s[t.device_id]?.disabled_by)return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:[o]};if("ha_disabled"===l?.kind)return{kind:"ha_disabled",reason:l.reason||"entity",enabledEntityIds:[],allEntityIds:[o]};if(t||e?.states?.[o])return{kind:"active",enabledEntityIds:[o],allEntityIds:[o]}}return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]}}function ud(e){const t=nd(e);return{access:t.access,authoritative:t.authoritative,revision:t.revision,lastSuccess:t.lastSuccess,error:t.error}}function pd(e){const t={};for(const[i,n]of Object.entries(e.entities)){if(!n?.device_id||!sd(n))continue;const r=e.devices?.[n.device_id];r&&!sd(r)||(t[n.device_id]=t[n.device_id]||[]).push(i)}return t}function _d(e,t){const i=new Map;for(const n of e){if(!0===n?.removed)continue;const e=n?.binding||"";if(!e.startsWith("entity:"))continue;const r=e.slice(7);if(!r)continue;const o=t?.entities?.[r]?.device_id;if(!o)continue;const s=i.get(o)||new Set;s.add(r),i.set(o,s)}return{byDevice:i}}function md(e,t,i,n){const r=n.byDevice.get(t);return r?.size?{partial:!0,entityIds:i.filter(t=>!r.has(t)&&!e?.entities?.[t]?.hidden)}:{partial:!1,entityIds:[...i]}}function gd(e,t,i){if(t.identifiers?.[0]?.[0])return t.identifiers[0][0];for(const t of i){const i=e.entities[t]?.platform;if(i)return i}return""}function fd(e,t){if(/_device_temperature$/.test(t))return!1;if(e.entities?.[t]?.entity_category)return!1;const i=e.states[t];if(!i)return/_temperature$/.test(t);const n=i.attributes||{};return"temperature"===n.device_class||/°C|°F/.test(n.unit_of_measurement||"")||/_temperature$/.test(t)}const vd=["vacuum","lawn_mower","climate","media_player","light","cover","lock","valve","alarm_control_panel","water_heater","fan","humidifier","siren","camera","remote"],yd=e=>[...e.filter(e=>!e.reg?.hidden),...e.filter(e=>!!e.reg?.hidden)];function bd(e,t){const i=t.map(t=>({eid:t,reg:e?.entities?.[t]})).filter(e=>!!e.reg);if(!i.length)return[];const n=i.filter(e=>!e.reg.entity_category),r=n.length?n:i;for(const e of vd){const t=r.filter(t=>t.eid.startsWith(e+"."));if(t.length)return yd(t).map(e=>e.eid)}const o=r.filter(t=>function(e,t){if(!t.startsWith("binary_sensor."))return!1;const i=$h(e?.states?.[t]?.attributes?.device_class||e?.entities?.[t]?.device_class||e?.entities?.[t]?.original_device_class);return mh.has(i)||gh.has(i)||fh.has(i)||vh.has(i)||"moving"===i||yh.has(i)}(e,t.eid));if(o.length)return yd(o).map(e=>e.eid);const s=r.filter(e=>e.eid.startsWith("switch."));if(s.length){const t=yd(s),n=t.find(t=>Ah(e,t.eid));if(s.length>1&&n){const t=i.filter(t=>t.eid!==n.eid&&"config"!==t.reg?.entity_category&&null!=Th(e,t.eid)),r=t.filter(e=>!e.reg?.entity_category),o=r.length?r:t;for(const t of[0,1,2]){const i=yd(o.filter(i=>Th(e,i.eid)===t));if(i.length)return[i[0].eid,n.eid]}}return[(n||t[0]).eid]}const a=[];for(const e of je)a.push(...yd(r.filter(t=>t.eid.startsWith(e+"."))));return a.push(...yd(r.filter(e=>!je.includes(e.eid.split(".")[0])))),a.map(e=>e.eid)}function wd(e,t,i){const n=t.map(t=>({eid:t,reg:e.entities[t],st:e.states[t]})).filter(e=>e.reg),r=[n.filter(e=>!e.reg.hidden&&!e.reg.entity_category),n.filter(e=>!e.reg.entity_category),n.filter(e=>!e.reg.hidden),n];if("mdi:thermometer"===i||"mdi:air-filter"===i)for(const t of r){const i=t.find(t=>fd(e,t.eid));if(i)return i.eid}const o=bd(e,t);return o.find(Pn)||o[0]}function kd(e,t,i=[]){return[...new Set(xd(e,t,i))].filter(e=>Pn(e))}function xd(e,t,i=[]){const n=e?.startsWith("entity:")?new Set([e.slice(7)]):new Set(i);return(t||[]).filter(e=>"string"==typeof e&&!n.has(e))}function Sd(e,t){if("string"==typeof t)return e.area===t;const i=e.marker?.room_id;return i?!!t.id&&i===t.id:!!t.area&&e.area===t.area}function $d(e){const t=e.marker?.binding?.startsWith("entity:")?e.marker.binding.slice(7):null,i=e.entities.filter(Pn),n=e.primary&&Pn(e.primary)?e.primary:null;return[...new Set([t,n,...i].filter(e=>!!e&&Pn(e)))]}function Md(e){const t=$d(e),i=e.marker?.light_entity;return i&&t.includes(i)?i:t[0]||null}function Rd(e,t){if(!1===t.marker?.is_light)return[];if(!0===t.marker?.is_light){return[{eid:Md(t),via:"forced"}]}const i=t.primary||bd(e,t.entities)[0];return i&&!i.startsWith("light.")?[]:t.entities.filter(t=>t.startsWith("light.")&&!!e.states?.[t]).map(e=>({eid:e,via:"light"}))}const Cd=new WeakMap,Td=new WeakMap;function Dd(e){return e.map(e=>[e.id||"",!0===e.hidden?1:0,e.primary||"",[...e.entities].join(","),void 0===e.controls?"":[...e.controls].join(","),e.marker?.id||"",e.marker?.binding||"",e.marker?.is_light,e.marker?.tap_action||"",!0===e.marker?.removed?1:0,e.marker?.light_entity||"",null==e.marker?.controls?"":[...e.marker.controls].join(",")].join("")).join("")}function Ad(e){const t=Dd(e),i=Cd.get(e);if(i?.fingerprint===t)return i;const n=e.filter(e=>!e.hidden),r=new Map,o=new Map;for(const t of e){o.set(t,xd(t.marker?.binding,t.marker?.controls??t.controls,t.entities));const e=t.hidden||!0!==t.marker?.is_light?null:t.marker?.id||t.id;e&&r.set(String(e),t)}const s=new Map;for(const t of e){const e=o.get(t)||[],i=new Set(void 0===t.controls?e.filter(Pn):t.controls.filter(Pn)),n=Md(t),a=i.size?[...i]:n?[n]:[];for(const i of e){if(!i.startsWith("marker:"))continue;const e=i.slice(7);if(!e||e===String(t.marker?.id||t.id||""))continue;if(!r.has(e))continue;const n=s.get(e)||{markerId:e,controllers:[],driverEids:[]};n.controllers.push({device:t,driverEids:[...a]}),n.driverEids=[...new Set([...n.driverEids,...a])],s.set(e,n)}}const a={fingerprint:t,visible:n,markerById:r,persistedByDevice:o,incomingByMarker:s};return Cd.set(e,a),a}function Pd(e){return Ad(e).incomingByMarker}function Fd(e,t){const i=kd(t.marker?.binding,t.controls??t.marker?.controls,t.entities),n=xd(t.marker?.binding,t.marker?.controls??t.controls,t.entities);return(null!=t.marker?.is_light||!i.length&&!n.some(e=>e.startsWith("marker:")))&&Rd(e,t).length>0}function zd(e,t){return Rd(e,t).some(e=>!!e.eid)}function Id(e,t,i,n){const r="always"===e||"auto"===e&&t,o=r&&!i;return{sourceExists:r,fromSourceEnabled:r&&i,manualEnabled:r,radiusEnabled:r,passive:o,effectiveMode:o&&"auto"===n?"fixed":n}}function Od(e,t){const i=kd(t.marker?.binding,t.controls??t.marker?.controls,t.entities).map(e=>({eid:e,via:"controls"})),n=Fd(e,t)?Rd(e,t):[];for(const e of n)e.eid&&i.some(t=>t.eid===e.eid)||i.push(e);return i}function Ed(e,t,i,n){if(null!=i)return Ed(e,t,null,n).filter(e=>Sd(e.device,i));const r=Dd(t),o=function(e,t){const i=new Set;for(const e of t){for(const t of e.entities)i.add(t);for(const t of e.controls||e.marker?.controls||[])"string"!=typeof t||t.startsWith("marker:")||i.add(t)}return[...i].sort().map(t=>`${t}:${e?.states?.[t]?.state??""}`).join("|")}(e,t),s=Bh(n),a=Td.get(t);if(a?.graphFingerprint===r&&a.stateFingerprint===o&&a.virtualLightFingerprint===s&&a.registry===e?.entities)return a.sources;const{visible:l,markerById:c,persistedByDevice:h,incomingByMarker:d}=Ad(t),u=null==i?l:l.filter(e=>Sd(e,i)),p=new Map,_=new Map;for(const t of u){const i=Od(e,t).filter(e=>"controls"!==e.via);for(const n of i){const i=!0===t.marker?.is_light?String(t.marker?.id||t.id||""):"",r=i?`marker:${i}`:`entity:${n.eid}`,o=n.eid?[n.eid]:[],s={key:r,eid:n.eid||"",stateEids:o,serviceEids:o,device:t,via:n.via,castsGlow:!0,passive:!n.eid,on:!n.eid||"on"===e.states?.[n.eid]?.state};p.set(t,[...p.get(t)||[],s]),n.eid&&_.set(n.eid,s)}}const m=new Map;for(const e of t){const t=h.get(e)||[],i=new Set(void 0===e.controls?t.filter(Pn):e.controls);m.set(e,i)}for(const t of p.values())for(const i of t){if(!i.passive)continue;const t=i.key.slice(7),r=d.get(t);i.on=!r||r.driverEids.some(t=>"on"===e.states?.[t]?.state),!r&&qh(i.device.marker)&&(i.on=jh(i.device.marker,n))}const g=new Map,f=e=>{const t=g.get(e.key);(!t||e.castsGlow&&!t.castsGlow)&&g.set(e.key,e)};for(const t of l){const n=h.get(t)||[],r=null==i||Sd(t,i);for(const i of n){if(i.startsWith("marker:")){const e=c.get(i.slice(7)),t=e?p.get(e):null;if(t)for(const e of t)f(e);continue}if(!Pn(i)||!m.get(t)?.has(i))continue;const n=_.get(i);n?f(n):r&&f({key:`entity:${i}`,eid:i,stateEids:[i],serviceEids:[i],device:t,via:"controls",castsGlow:!1,passive:!1,on:"on"===e.states?.[i]?.state})}for(const e of p.get(t)||[])f(e)}const v=[...g.values()];return Td.set(t,{graphFingerprint:r,stateFingerprint:o,virtualLightFingerprint:s,registry:e?.entities,sources:v}),v}function Nd(e){const t=e.filter(e=>e.castsGlow);return t.find(e=>e.on)||t[0]||null}function Hd(e){return e.length?e.some(e=>e.on)?"on":"off":"none"}function Ld(e,t){const i=[];for(const n of t){const t=e.states[n];if(!t)continue;const r=(t.attributes?.unit_of_measurement||"").toLowerCase();if(/_(linkquality|lqi)$/.test(n)||"lqi"===r){const e=parseFloat(t.state);isNaN(e)||i.push(e);continue}const o=t.attributes?.linkquality??t.attributes?.lqi;if(null!=o){const e=parseFloat(o);isNaN(e)||i.push(e)}}return Ii(i)}function Bd(e,t){for(const i of t){if(!fd(e,i))continue;const t=e.states[i];if(!t)continue;const n=parseFloat(t.state);if(!isNaN(n))return Math.round(10*n)/10}return null}function qd(e,t){for(const i of t){if(!i.startsWith("climate."))continue;const t=e.states[i];if(!t||"unavailable"===t.state||"unknown"===t.state)continue;const n=parseFloat(t.attributes?.current_temperature);if(Number.isFinite(n))return Math.round(10*n)/10}return null}function jd(e,t){if(e.entities?.[t]?.entity_category)return!1;const i=e.states[t];if(!i)return/_humidity$/.test(t);const n=i.attributes||{};return"humidity"===n.device_class||"%"===n.unit_of_measurement&&/_humidity$/.test(t)||/_humidity$/.test(t)}function Wd(e,t){for(const i of t){if(!jd(e,i))continue;const t=e.states[i];if(!t)continue;const n=parseFloat(t.state);if(!isNaN(n))return Math.round(n)}return null}function Ud(e,t){if(!t)return[];const i=[];for(const[t,n]of Object.entries(e.entities)){if(!t.startsWith("light.")||n.hidden||!sd(n))continue;let r=null;if("group"===n.platform)r=n.area_id||null;else{if(!n.device_id)continue;{const t=e.devices[n.device_id];if(!sd(t))continue;if("Group"!==t?.model)continue;r=t.area_id||n.area_id||null}}if(!r)continue;const o=e.states[t];i.push({eid:t,name:n.name||o?.attributes?.friendly_name||t,area:r})}return i}function Gd(e,t,i,n,r){const o=qe(t,i,r);if(o!==Be)return o;const s=[];for(const t of n){const i=e.states[t]?.attributes?.device_class;i&&s.push(i)}return function(e){for(const t of e){const e=Le[t];if(e)return e}return null}(s)??Be}function Vd(e,t){return e.map(e=>{if(!Array.isArray(e.controls))return e;const i=e.controls.filter(e=>!("string"==typeof e&&e.startsWith("marker:")&&t.has(e.slice(7))));return i.length===e.controls.length?e:{...e,controls:i.length?i:null}})}function Kd(e,t,i){if(!t||!i||t===i)return[...e];const n=`marker:${t}`,r=`marker:${i}`;return e.map(e=>{const t=Array.isArray(e.controls)?e.controls.map(e=>e===n?r:e):e.controls,i="derived_marker_state"===e.value_badge?.source?.kind&&e.value_badge.source.ref===n?{...e.value_badge,source:{...e.value_badge.source,ref:r}}:e.value_badge,o="derived_marker_state"===e.value_source?.kind&&e.value_source.ref===n?{...e.value_source,ref:r}:e.value_source;return t===e.controls&&i===e.value_badge&&o===e.value_source?e:{...e,controls:t,...void 0!==i?{value_badge:i}:{},...void 0!==o?{value_source:o}:{}}})}function Yd(e,t,i){if(!t||t===i)return!0;const n=new Map;for(const t of e)n.set(t.id,(t.controls||[]).filter(e=>"string"==typeof e&&e.startsWith("marker:")).map(e=>e.slice(7)));const r=new Set,o=[i];for(;o.length;){const e=o.pop();if(e===t)return!0;r.has(e)||(r.add(e),o.push(...n.get(e)||[]))}return!1}function Xd(e,t,i,n){const r=new Set([t]),o=e.filter(e=>{const o=e.id===t||!n&&e.binding===i;return o&&r.add(e.id),!o});return{markers:n?o:[...o,{id:t,binding:i,removed:!0,hidden:!0}],cleanupIds:r}}function Zd(e){const t=new Set,i=new Set,n=new Set;for(const r of e||[]){const e=String(r.binding||"").indexOf(":");if(e<1)continue;const o=r.binding.slice(0,e),s=r.binding.slice(e+1);s&&(!0===r?.removed?"device"===o?t.add(s):"entity"===o&&i.add(s):"entity"===o&&n.add(s))}return{devices:t,entities:i,liveEntities:n}}function Jd(e,t,i){if(i.liveEntities.has(t))return!1;if(i.entities.has(t))return!0;const n=e?.entities?.[t]?.device_id;return!!n&&i.devices.has(n)}function Qd(e,t,i,n,r){const o=kd(t.binding,t.controls,e.entities).filter(e=>!Jd(i,e,n)).filter(e=>"active"===dd(i,"entity:"+e,r).kind);e.marker=t,e.controls=o,e.userHidden=!0===t.hidden,e.hidden=e.userHidden||"ha_disabled"===e.bindingStatus?.kind,t.name&&(e.name=t.name),t.icon&&(e.icon=t.icon),null!=t.model&&(e.model=t.model),e.link=t.link??null,e.description=t.description??null,e.pdfs=t.pdfs||[],e.tapAction=t.tap_action??null}function eu(e){const t=e.hass,i=e.registry||nd(t),n=ad(t,i),r=ld(t,i),{areaToSpace:o,markers:s,settings:a,excluded:l,iconRules:c}=e,h=!1!==a.group_lights,d=Zd(s),u=Ud(n,h).filter(e=>!Jd(n,e.eid,d)),p=new Set(u.map(e=>e.area)),_=pd(n),m=_d(s,r),g=new Set(s.map(e=>e.binding)),f=[];for(const e of Object.values(n.devices)){const r=e.area_id;if(!r||!o[r])continue;if("service"===e.entry_type)continue;if(g.has("device:"+e.id))continue;if("active"!==dd(t,"device:"+e.id,i).kind)continue;const s=md(n,e.id,_[e.id]||[],m);if(s.partial&&!s.entityIds.length)continue;const a=s.entityIds,d=gd(n,e,a);let u=l.has(d)||"Group"===e.model||/scene/i.test(e.model||"")||/bridge/i.test((e.model||"")+(e.name||""))||"myheat"===d&&!!e.via_device_id;if(!u&&h&&p.has(r)){const t=(e.name_by_user||e.name||"").trim();"mdi:lightbulb"===Gd(n,t,e.model,a,c)&&(u=!0)}u&&f.push("device:"+e.id)}return f}function tu(e,t,i,n){if("string"==typeof e.room_id&&e.room_id.length>0&&null===e.area)return{area:"",space:e.space||n};const r=e.area||t||"";return{area:r,space:r&&i[r]||e.space||n}}function iu(e){const t=e.hass,i=e.registry||nd(t),n=ad(t,i),r=ld(t,i),{areaToSpace:o,markers:s,settings:a,excluded:l,showAll:c,firstSpaceId:h,loc:d,iconRules:u}=e,p=!1!==a.group_lights,_=Zd(s),m=Ud(n,p).filter(e=>!Jd(n,e.eid,_)),g=new Set(m.map(e=>e.area)),f=pd(n),v=function(e){const t={};for(const[i,n]of Object.entries(e.entities||{}))n?.device_id&&(t[n.device_id]=t[n.device_id]||[]).push(i);return t}(r),y=_d(s,r),b=new Set;for(const e of s){const[t,i]=e.binding.split(":");"device"!==t&&"entity"!==t||!i||b.add(e.binding)}const w=(e,t)=>s.find(i=>i.binding===e+":"+t),k={},x=[];for(const e of Object.values(n.devices)){const r=e.area_id;if(!r||!o[r])continue;if("service"===e.entry_type)continue;if(b.has("device:"+e.id))continue;const s=dd(t,"device:"+e.id,i);if("active"!==s.kind)continue;const h=w("device",e.id);if(h&&h.hidden&&!a.filter_seeded)continue;const _=md(n,e.id,f[e.id]||[],y);if(_.partial&&!_.entityIds.length)continue;const m=_.entityIds,v=_.partial?{kind:"active",enabledEntityIds:m,allEntityIds:m}:s,S=gd(n,e,m),$=!a.filter_seeded;if($&&!c){if(l.has(S))continue;if("Group"===e.model)continue;if(/scene/i.test(e.model||""))continue;if(/bridge/i.test((e.model||"")+(e.name||"")))continue;if("myheat"===S&&e.via_device_id)continue}const M=(e.name_by_user||e.name||d("device.unnamed")).trim(),R=M+"|"+r;let C=Gd(n,M,e.model,m,u);if(m.some(e=>e.startsWith("lock."))&&(C="mdi:lock"),$&&!c&&p&&"mdi:lightbulb"===C&&g.has(r))continue;k[R]=(k[R]||0)+1;const T=k[R]>1?M+" "+k[R]:M,D={id:e.id,name:T,model:e.model||"",area:r,space:o[r],icon:C,entities:m,allEntities:v.allEntityIds,bindingStatus:v,bindingKind:"device",bindingRef:e.id,pdfs:[]};D.primary=wd(n,m,C),"mdi:thermometer"!==C&&"mdi:air-filter"!==C||(D.temp=Bd(n,m)),D.primary&&jd(n,D.primary)&&(D.hum=Wd(n,m)),x.push(D)}for(const e of m)o[e.area]&&(b.has("entity:"+e.eid)||x.push({id:"lg_"+e.eid,name:e.name,model:d("device.light_group"),area:e.area,space:o[e.area],icon:"mdi:lightbulb-group",entities:[e.eid],allEntities:[e.eid],bindingStatus:{kind:"active",enabledEntityIds:[e.eid],allEntityIds:[e.eid]},primary:e.eid,bindingKind:"entity",bindingRef:e.eid,pdfs:[]}));for(const e of s){if(e.removed)continue;const[s,l]=e.binding.split(":"),c="device"===s||"entity"===s?dd(t,e.binding,i):null;if(!e.hidden||a.filter_seeded||"ha_disabled"===c?.kind)if("device"===s){const t=c;if("unverified"===t.kind)continue;const s=r.devices[l],{area:a,space:p}=tu(e,s?.area_id,o,h),m="active"===t.kind?t.enabledEntityIds:[];let g=s?Gd(n,s.name_by_user||s.name||"",s.model,m,u):"mdi:help-circle";m.some(e=>e.startsWith("lock."))&&(g="mdi:lock");const f={id:e.id,name:s?.name_by_user||s?.name||d("device.fallback"),model:s?.model||"",area:a,space:p,icon:g,entities:m,allEntities:t.allEntityIds.length?t.allEntityIds:s&&v[s.id]||[],bindingStatus:t,bindingKind:"device",bindingRef:l};f.primary=wd(n,m,g),"mdi:thermometer"!==g&&"mdi:air-filter"!==g||(f.temp=Bd(n,m)),f.primary&&jd(n,f.primary)&&(f.hum=Wd(n,m)),Qd(f,e,r,_,i),x.push(f)}else if("entity"===s){if(Jd(r,l,_))continue;const t=c;if("unverified"===t.kind)continue;const s=r.entities[l],a=s?.area_id||s?.device_id&&r.devices[s.device_id]?.area_id||"",{area:d,space:p}=tu(e,a,o,h),m=n.states[l],g=s?.name||m?.attributes?.friendly_name||l;let f=Gd(n,g,"",[l],u);l.startsWith("lock.")&&(f="mdi:lock");const v={id:e.id,name:g,model:"",area:d,space:p,icon:f,entities:"active"===t.kind?[l]:[],allEntities:[l],bindingStatus:t,primary:"active"===t.kind?l:void 0,bindingKind:"entity",bindingRef:l};"mdi:thermometer"!==f&&"mdi:air-filter"!==f||!v.entities.length||(v.temp=Bd(n,v.entities)),v.entities.length&&jd(n,l)&&(v.hum=Wd(n,v.entities)),Qd(v,e,r,_,i),x.push(v)}else{const t=e.area||"",n=e.space||t&&o[t]||h,s={id:e.id,name:e.name||d("device.virtual"),model:e.model||"",area:t,space:n,icon:e.icon||"mdi:map-marker",entities:[],allEntities:[],bindingStatus:{kind:"active",enabledEntityIds:[],allEntityIds:[]},bindingKind:"virtual",virtual:!0};Qd(s,e,r,_,i),x.push(s)}}return x}function nu(e){const{marker:t,siblingMarkers:i=[],...n}=e;return iu({...n,markers:[...i.filter(e=>e.id!==t.id),t]}).find(e=>e.id===t.id)||null}function ru(e,t,i,n){if(!t)return null;if(function(e,t,i){if(!t)return!1;const n=t.indexOf(":");if(n<1)return!1;const r=t.slice(0,n),o=t.slice(n+1),s=Zd(i);return"device"===r?s.devices.has(o):"entity"===r&&Jd(e,o,s)}(e,t,n))return null;const r=t.indexOf(":");if(r<0)return null;const o=t.slice(0,r),s=t.slice(r+1);if(!s)return null;if("entity"===o){const t=parseFloat(e.states[s]?.state);return Number.isFinite(t)?"temp"===i?Math.round(10*t)/10:Math.round(t):null}if("device"===o){const t=Object.entries(e.entities).filter(([,e])=>e.device_id===s).map(([e])=>e);return"temp"===i?Bd(e,t):Wd(e,t)}return null}const ou=new RegExp(["water","voda","coolant","flow_?temp","return_?temp","target","setpoint","chip","cpu","processor","board","core_temp","device_temp","batter","akkum","freezer","fridge","oven","kettle","boiler"].join("|"),"i");function su(e,t){return t.area?t.area:e&&t.id?`@room/${encodeURIComponent(e)}/${encodeURIComponent(t.id)}`:null}function au(e){return null==e.area&&e.space&&e.room_id?su(e.space,{id:e.room_id,area:null}):e.area||null}function lu(e){const t=e?.exclude_integrations;return t?new Set(t):Ie}function cu(e,t,i,n=Ie){const r=new Map;if(!e?.entities)return r;const o=Zd(i),s=new Set,a=new Map,l=new Map;for(const e of i||[]){if(e?.removed)continue;const t=(e.binding||"").indexOf(":");if(t<=0)continue;const i=e.binding.slice(0,t),n=e.binding.slice(t+1);if(!n)continue;!0===e.use_climate_temp&&s.add(n);const r=au(e);r&&("entity"!==i||a.has(n)?"device"!==i||l.has(n)||l.set(n,r):a.set(n,r))}const c=new Map;for(const[t,i]of Object.entries(e.entities)){if(i.device_id&&o.devices.has(i.device_id)&&!o.liveEntities.has(t)||!i.device_id&&o.entities.has(t)&&!o.liveEntities.has(t))continue;const r=i.device_id?e.devices?.[i.device_id]:null;if(!sd(i)||r&&!sd(r))continue;const h=a.get(t)||(i.device_id?l.get(i.device_id):null)||i.area_id||r?.area_id||null;if(!h)continue;if(i.entity_category)continue;if(!(s.size>0&&t.startsWith("climate.")&&(s.has(t)||i.device_id&&s.has(i.device_id)))){if(n.has(i.platform))continue;if(ou.test(t))continue}let d=c.get(h);d||(d=new Map,c.set(h,d));const u=i.device_id||t;let p=d.get(u);if(!p){const n=e.states?.[t];p={name:(r?r.name_by_user||r.name:i.name||n?.attributes?.friendly_name||t)||t,model:r?.model,ents:[]},d.set(u,p)}p.ents.push(t)}for(const[i,n]of c){const o=[],a=[];for(const[i,r]of n){const n=Gd(e,r.name,r.model,r.ents,t),l="mdi:thermometer"===n||"mdi:air-filter"===n;if(l){const t=Bd(e,r.ents);null!=t&&o.push(t)}if(s.size>0&&(s.has(i)||r.ents.some(e=>s.has(e)))){const t=qd(e,r.ents);null!=t&&o.push(t)}if(l||"mdi:water-percent"===n){const t=Wd(e,r.ents);null!=t&&a.push(t)}}(o.length||a.length)&&r.set(i,{temp:o.length?Math.round(o.reduce((e,t)=>e+t,0)/o.length*10)/10:null,hum:a.length?Math.round(a.reduce((e,t)=>e+t,0)/a.length):null})}return r}function hu(e,t,i){const n=[];for(const r of t){if(r.area!==i||r.virtual)continue;const t=Ld(e,r.entities);null!=t&&n.push(t)}return Ii(n)}const du={offStates:["off"],unknownUsesToggle:!0},uu={light:du,switch:du,fan:du,humidifier:du,input_boolean:du,automation:du,remote:du,group:du,climate:{...du,featureMasks:{turn_on:256,turn_off:128,toggle:384}},media_player:{...du,featureMasks:{turn_on:128,turn_off:256,toggle:384}},siren:{...du,featureMasks:{turn_on:1,turn_off:2,toggle:3}},vacuum:{...du,featureMasks:{turn_on:1,turn_off:2,toggle:3}},water_heater:{...du,featureMasks:{turn_on:8,turn_off:8,toggle:8}},camera:{...du,featureMasks:{turn_on:1,turn_off:1,toggle:1}}};function pu(e){return e.slice(0,e.indexOf("."))}function _u(e,t,i){if(!e?.services||"object"!=typeof e.services)return!1;const n=e.services?.[t];return!!n&&Object.prototype.hasOwnProperty.call(n,i)}function mu(e,t,i){return _u(e,t,i)?{domain:t,service:i}:_u(e,"homeassistant",i)?{domain:"homeassistant",service:i}:null}function gu(e,t){return e?.entities?.[t]||null}function fu(e,t,i){const n=e?.states?.[i],r=gu(t,i);return n?.attributes?.friendly_name||r?.name||r?.original_name||i}function vu(e,t){const i=gu(e,t);if(null!=i?.disabled_by)return!0;const n=i?.device_id?e?.devices?.[i.device_id]:null;return null!=n?.disabled_by}function yu(e,t){const i=e?.attributes?.supported_features;if(null==i||""===i)return!1;const n=Number(i);return Number.isFinite(n)&&(n&t)===t}function bu(e,t,i){const n=pu(i);if("lock"===n||"alarm_control_panel"===n)return!0;if("cover"!==n)return!1;const r=e?.states?.[i],o=gu(t,i),s=String(r?.attributes?.device_class||o?.device_class||o?.original_device_class||"");return Gi.has(s)}function wu(e,t,i,n,r){return{ref:i,entityId:n,name:n?fu(e,t,n):null,reason:r}}function ku(e,t,i,n,r,o=null){return{target:null,skipped:wu(e,t,i,n,r),semantics:o,nextEffect:null,command:null}}function xu(e,t,i,n,r=i){const o=pu(i);if("cover"!==o&&"valve"!==o)return function(e,t,i,n,r=i){const o=pu(i),s=e?.states?.[i];if(vu(t,i))return ku(e,t,r,i,"ha-disabled","power");if(bu(e,t,i))return ku(e,t,r,i,"secure");if(!s)return ku(e,t,r,i,"missing","power");if("unavailable"===s.state)return ku(e,t,r,i,"unavailable","power");const a=uu[o];if(!a)return ku(e,t,r,i,"unsupported");let l,c;if("unknown"===s.state||""===s.state){if(!a.unknownUsesToggle)return ku(e,t,r,i,"unsupported","power");l="toggle",c="toggle"}else a.offStates.includes(String(s.state))?(l="turn-on",c="turn_on"):(l="turn-off",c="turn_off");const h=a.featureMasks?.[c];if(h&&!yu(s,h))return ku(e,t,r,i,"unsupported","power");const d=mu(e,o,c);return d?{target:{entityId:i,name:fu(e,t,i),state:String(s.state||""),via:n},skipped:null,semantics:"power",nextEffect:l,command:{...d,data:{entity_id:i}}}:ku(e,t,r,i,"unsupported","power")}(e,t,i,n,r);if(vu(t,i))return ku(e,t,r,i,"ha-disabled",o);if(bu(e,t,i))return ku(e,t,r,i,"secure",o);const s=e?.states?.[i];if(!s)return ku(e,t,r,i,"missing",o);if("unavailable"===s.state)return ku(e,t,r,i,"unavailable",o);const a=function(e,t,i){const n=String(i?.state||""),r="closed"===n?{service:`open_${t}`,effect:"open",feature:1}:"open"===n?{service:`close_${t}`,effect:"close",feature:2}:"opening"===n||"closing"===n?{service:`stop_${t}`,effect:"stop",feature:8}:null;return r&&yu(i,r.feature)&&_u(e,t,r.service)?r:yu(i,3)&&_u(e,t,"toggle")?{service:"toggle",effect:"toggle"}:null}(e,o,s);if(!a)return ku(e,t,r,i,"unsupported",o);return{target:{entityId:i,name:fu(e,t,i),state:String(s.state||""),via:n},skipped:null,semantics:o,nextEffect:a.effect,command:{domain:o,service:a.service,data:{entity_id:i}}}}function Su(e){return"entity"===e.bindingKind?e.bindingRef&&Pn(e.bindingRef)?[e.bindingRef]:[]:"virtual"===e.bindingKind?[]:$d(e)}function $u(e){const t=e.marker?.toggle_entity;return t&&Su(e).includes(t)?t:null}function Mu(e,t,i){const n=function(e,t){if("entity"===e.bindingKind&&e.bindingRef){const t=e.marker?.light_entity?Md(e):null;return[...new Set([t,e.bindingRef].filter(e=>!!e))]}const i=e.entities.length?e.entities:e.allEntities||[],n=e.marker?.light_entity||e.primary&&Pn(e.primary)?Md(e):null;return[...new Set([n,...bd(t,i)].filter(e=>!!e))]}(i,t);if(!n.length)return null;const r="entity"===i.bindingKind?"binding":"device-role";if("binding"===r)return xu(e,t,n[0],r);let o=null,s=null;for(const i of n){const n=xu(e,t,i,r);if(n.command)return n;const a=n.skipped?.reason;if("missing"===a||"unavailable"===a||"secure"===a)return n;"ha-disabled"!==a?o||=n:s||=n}return o||s}function Ru(e){const t=e.skipped?.reason;return"missing"===t?"unavailable":t||"unsupported"}function Cu(e,t){return{origin:e,kind:"none",semantics:null,targets:[],skippedTargets:[],noneReason:t,nextEffect:null,command:null}}function Tu(e,t){return"cover"===e||"toggle"===e?"toggle":"more-info"===e||"run"===e||"info"===e||"none"===e?e:(null==e||""===e)&&"light"===t?"toggle":"info"}function Du(e,t){return{origin:e,kind:"single",semantics:t.semantics,targets:t.target?[t.target]:[],skippedTargets:t.skipped?[t.skipped]:[],noneReason:t.command?null:Ru(t),nextEffect:t.nextEffect,command:t.command}}function Au(e,t,i,n=[]){const r=new Map,o=[],s=new Set,a=e=>{const t=`${e.ref}\n${e.entityId||""}\n${e.reason}`;s.has(t)||(s.add(t),o.push(e))};for(const e of n)a(e);for(const n of i){const i=xu(e,t,n.entityId,n.via,n.ref);i.target?r.set(n.entityId,r.get(n.entityId)||i.target):i.skipped&&a(i.skipped)}const l=[...r.values()];if(!l.length)return{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:l,skippedTargets:o,noneReason:o.length&&o.every(e=>"secure"===e.reason)?"secure":"configured-targets-missing",nextEffect:null,command:null};const c=l.some(e=>"on"===e.state)?"turn_off":"turn_on",h=mu(e,"homeassistant",c);return h?{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:l,skippedTargets:o,noneReason:null,nextEffect:"turn_on"===c?"turn-on":"turn-off",command:{...h,data:{entity_id:l.map(e=>e.entityId)}}}:{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:[],skippedTargets:[...o,...l.map(i=>wu(e,t,i.entityId,i.entityId,"unsupported"))],noneReason:"unsupported",nextEffect:null,command:null}}function Pu(e){return String(e.marker?.id||e.id||"")}function Fu(e){const{hass:t,device:i}=e,n=e.registryHass||t,r=function(e){return"toggle"===e.tapAction?"explicit-toggle":"cover"===e.tapAction?"legacy-cover":!e.tapAction&&e.primary?.startsWith("light.")?"default-light":null}(i);if(!r)return null;const o=i.marker;if("explicit-toggle"===r&&qh(o)){const t=String(o?.id||i.id||""),n=Pd(e.devices).get(t);if(n)return function(e,t){const i=e.registryHass||e.hass;return Au(e.hass,i,t.driverEids.map(e=>({entityId:e,via:"control-marker-driver",ref:`marker:${t.markerId}`})))}(e,n);const s=jh(o,e.virtualLights);return{origin:r,kind:"single",semantics:"power",targets:[{entityId:"",name:i.name,state:s?"on":"off",via:"virtual-light"}],skippedTargets:[],noneReason:null,nextEffect:s?"turn-off":"turn-on",command:null,operation:{kind:"virtual-light",markerId:o.id}}}if("explicit-toggle"===r){if(xd(i.marker?.binding,i.marker?.controls??i.controls,i.entities).length)return function(e,t=null){const{hass:i,device:n,devices:r}=e,o=e.registryHass||i,s=xd(n.marker?.binding,n.marker?.controls??n.controls,n.entities),a=e.lightSources||Ed(i,r,null,e.virtualLights),l=new Map;for(const e of a){if(!e.key.startsWith("marker:"))continue;const t=l.get(e.key)||[];t.push(e),l.set(e.key,t)}const c=Pd(r),h=new Map;for(const e of r){const t=String(e.marker?.id||e.id||"");t&&h.set(t,e)}const d=[],u=[];t&&d.push({entityId:t,via:"entity"===n.bindingKind?"binding":"device-role",ref:t});for(const e of s){if(!e.startsWith("marker:")){Pn(e)?d.push({entityId:e,via:"control-entity",ref:e}):u.push(wu(i,o,e,e.includes(".")?e:null,"unsupported"));continue}const t=l.get(e)||[];if(!t.length){const t=h.get(e.slice(7));if("ha_disabled"===t?.bindingStatus?.kind){const n=t.bindingStatus.allEntityIds[0]||null;u.push({ref:e,entityId:n,name:t.name||(n?fu(i,o,n):null),reason:"ha-disabled"})}else u.push(wu(i,o,e,null,"missing"));continue}const r=[...new Set(t.flatMap(e=>e.serviceEids))];if(r.length){for(const t of r)d.push({entityId:t,via:"control-entity",ref:e});continue}const s=t.some(e=>e.passive),a=e.slice(7),p=Pu(n),_=c.get(a)?.controllers.find(e=>Pu(e.device)===p);if(s&&_?.driverEids.length)for(const t of _.driverEids)d.push({entityId:t,via:"control-marker-driver",ref:e});else u.push(wu(i,o,e,null,s?"missing":"unsupported"))}return Au(i,o,d,u)}(e,$u(i))}if("legacy-cover"===r){const e=i.entities.find(e=>e.startsWith("cover."))||i.allEntities?.find(e=>e.startsWith("cover."));return e?Du(r,xu(t,n,e,"device-role")):Cu(r,"no-actionable-entity")}const s=$u(i),a=s?xu(t,n,s,"entity"===i.bindingKind?"binding":"device-role"):Mu(t,n,i);return a?Du(r,a):Cu(r,i.virtual||"virtual"===i.bindingKind?"no-actionable-entity":"no-binding")}function zu(e){if(!e)return[];const t=Array.isArray(e.data.entity_id)?e.data.entity_id:[e.data.entity_id];return[...new Set(t)].sort()}function Iu(e){return e?e.operation?e.operation:e.command?{kind:"ha-service",command:e.command}:null:null}const Ou=new Set(["missing","ha-disabled","unavailable"]);function Eu(e,t){const i=Iu(e),n=Iu(t);return!(!i||!n||i.kind!==n.kind)&&("virtual-light"===i.kind&&"virtual-light"===n.kind?i.markerId===n.markerId:"ha-service"===i.kind&&"ha-service"===n.kind&&function(e,t){const i=zu(e),n=zu(t);return i.length===n.length&&i.every((e,t)=>e===n[t])}(i.command,n.command))}function Nu(e,t){const i=e.targets[0]||e.skippedTargets[0],n=[];return"group"===e.kind?e.targets.length&&n.push(t.group(e.targets)):i&&n.push(t.single(i)),e.nextEffect&&e.targets.length&&n.push("group"===e.kind?t.groupCurrentNext(e.targets,e.nextEffect):t.currentNext(e.targets[0],e.nextEffect)),e.skippedTargets.length&&n.push(t.skipped(e.skippedTargets)),!e.command&&e.noneReason&&n.push(t.none(e.noneReason)),n}function Hu(e,t){return e.catch(()=>{}).then(t)}const Lu=e=>{const t=e?.config;return t&&Array.isArray(t.spaces)?t:null},Bu=(e,t)=>"number"==typeof e&&Number.isFinite(e)?e:t;class qu{constructor(e){this.onBodyReplaced=e,this.config=null,this.configRev=0,this.configFingerprint="",this.layout={},this.layoutRev=0,this.layoutFingerprint=""}setConfig(e){const t=this.config;e!==t&&(this.config=e,this.onBodyReplaced?.("_serverCfg",t))}setLayout(e){const t=this.layout;e!==t&&(this.layout=e,this.onBodyReplaced?.("_layout",t))}currentConfigFingerprint(){return this.configFingerprint||cc(this.config)}currentLayoutFingerprint(){return this.layoutFingerprint||cc(this.layout)}adoptResponses(e,t,i,n){const r=Lu(e),o=cc(r),s=o!==this.currentConfigFingerprint();s&&(i(),this.setConfig(r),this.configFingerprint=o),this.configRev=e?.rev??this.configRev;let a=!1;if(void 0!==t){const e=t?.layout??{},i=cc(e);a=i!==this.currentLayoutFingerprint(),a&&(n(),this.setLayout(e),this.layoutFingerprint=i),this.layoutRev=t?.rev??this.layoutRev}return{configChanged:s,layoutChanged:a}}adoptMergedLayout(e,t,i){const n=cc(e),r=n!==cc(this.layout);return r&&(i?.(),this.setLayout(e)),this.layoutFingerprint=n,this.layoutRev=t?.rev??this.layoutRev,r}stageConfigCandidate(e){const t=cc(e);t!==cc(this.config)&&this.setConfig(e),this.configFingerprint=t}acceptConfigWrite(e,t){this.configFingerprint=cc(e),this.configRev=Bu(t?.rev,this.configRev+1)}acceptPairWrite(e,t,i){this.setConfig(e),this.configFingerprint=cc(e),this.setLayout(t),this.layoutFingerprint=cc(t),this.configRev=Bu(i?.config_rev,this.configRev+1),this.layoutRev=Bu(i?.layout_rev,this.layoutRev+1)}noteLayoutRevision(e){"number"==typeof e&&e>this.layoutRev&&(this.layoutRev=e)}stageLocalConfig(e){this.setConfig(e)}stageLocalLayout(e){this.setLayout(e)}seedIdentity(e){Object.assign(this,e)}refreshConfigFingerprint(){this.configFingerprint=cc(this.config)}refreshLayoutFingerprint(){this.layoutFingerprint=cc(this.layout)}beginOptimistic(e,t){return function(e,t,i,n,r){return{previous:JSON.parse(JSON.stringify(e)),previousFingerprint:i,revision:n,attempted:t,attemptedFingerprint:r(t)}}(e,t,this.configFingerprint,this.configRev,cc)}rollbackOptimistic(e){const t=this.config;return!(!t||this.configRev!==e.revision||cc(t)!==e.attemptedFingerprint)&&(this.setConfig(e.previous),this.configFingerprint=e.previousFingerprint,!0)}restoreCached(e){const t=e?.config;return!(!t||!Array.isArray(t.spaces))&&(this.setConfig(t),this.configRev=e?.rev||0,this.configFingerprint=e?.config_fingerprint||cc(t),this.setLayout(e?.layout||{}),this.layoutRev=e?.layout_rev||0,this.layoutFingerprint=e?.layout_fingerprint||cc(this.layout),!0)}snapshot(e){return this.config?(this.refreshConfigFingerprint(),this.refreshLayoutFingerprint(),{config:this.config,rev:this.configRev,config_fingerprint:this.configFingerprint,layout:this.layout,layout_rev:this.layoutRev,layout_fingerprint:this.layoutFingerprint,virtual_lights:e}):null}}async function ju(e,t){const i=t.isCurrent??(()=>!0);if(!i())return{status:"superseded"};const{cfgResp:n,layResp:r}=t,o=e._adoption,s=Lu(n),a=null!=n&&cc(s)!==o.currentConfigFingerprint()||null!=r&&cc(r.layout??{})!==o.currentLayoutFingerprint();if(a){const t=await e._signer.prepareImage(e.hass,e._candidateBackdrop(s));if(!i())return{status:"superseded"};if(!t)return e._continuity.note("asset-failed"),e._scheduleLoadRetry(!0),{status:"asset-wait"}}if(!i())return{status:"superseded"};a&&e._continuity.hasCompleteFrame&&"steady"===e._continuity.state&&e._beginContinuityCandidate(t.reason,!0),t.beforeAdopt?.();const l=e._space;return function(e,t,i){const n=e._adoption,r=!!n.config,{configChanged:o,layoutChanged:s}=n.adoptResponses(t??{},i,()=>{e._geometryHistory.clear(),e._devicePositionHistory.clear(),e._cancelDeviceDrag(),e._pendingPhysicalWrites.clear(),e._clearRoomFocus(!0),e._cancelCameraTransition(!1),r&&e._clearGeometryGesture()},()=>{e._cancelCameraTransition(!1),e._devicePositionHistory.clear(),e._cancelDeviceDrag()});if(o&&e._seedDecorStyle(n.config),t&&("virtual_lights"in t||"config"in t)){const i=Lh(e._virtualLights,t.virtual_lights,n.configRev,"virtual_lights"in t);Bh(i)!==Bh(e._virtualLights)&&(e._virtualLights=i,e._capturedSnapshotVirtual="")}e._canOptimizeUndo=!(!t?.can_optimize_undo&&!i?.can_optimize_undo),e._adoptConfigCapabilities(t),e._undoKind=t?.undo_kind||i?.undo_kind||null,"boolean"==typeof t?.can_write&&(e._serverCanWrite=t.can_write),o&&e._continuity.note("config-candidate",{configRev:n.configRev}),s&&e._continuity.note("layout-candidate",{layoutRev:n.layoutRev})}(e,n,r),"reload"===t.profile&&(e._syncDecorAssets(s).catch(()=>{}),e._adoptInitialSpace(e._model,!0),e._resumePendingNavMode(),e._cacheSnapshot()),t.afterAdopt?.(),{status:"adopted",spaceChanged:e._space!==l}}const Wu=(e,t)=>e.connection===t.connection&&e.userId===t.userId&&e.route===t.route,Uu=e=>"number"==typeof e&&Number.isFinite(e)?e:null;class Gu{constructor(){this.sequence=0,this.currentSequence=0,this.lifecycle=0,this.observedHighWater=null,this.context=null}observeContext(e){this.context?Wu(this.context,e)||(this.context={...e},this.invalidateLifecycle()):this.context={...e}}invalidateLifecycle(){this.lifecycle+=1,this.currentSequence=++this.sequence,this.observedHighWater=null}observeRevision(e,t,i){this.observeContext(i);const n=Uu(e);if(null===n)return null;const r=Uu(t)??Number.NEGATIVE_INFINITY;return n<=Math.max(r,this.observedHighWater??Number.NEGATIVE_INFINITY)?null:(this.observedHighWater=n,Object.freeze({sequence:this.currentSequence,lifecycle:this.lifecycle,context:{...i},observedRevision:n}))}isReservationCurrent(e,t,i){this.observeContext(t);const n=Uu(i)??Number.NEGATIVE_INFINITY;return e.sequence===this.currentSequence&&e.lifecycle===this.lifecycle&&Wu(e.context,t)&&e.observedRevision===this.observedHighWater&&e.observedRevision>n}begin(e){this.observeContext(e.context),e.force&&this.invalidateLifecycle();const t=++this.sequence;return this.currentSequence=t,Object.freeze({sequence:t,lifecycle:this.lifecycle,force:e.force,context:{...e.context},baselineRevision:e.baselineRevision,baselineFingerprint:e.baselineFingerprint})}isCurrent(e){this.observeContext(e.context);const t=e.claim;return e.connected&&(t.force||!e.writePending)&&t.sequence===this.currentSequence&&t.lifecycle===this.lifecycle&&Wu(t.context,e.context)&&t.baselineRevision===e.baselineRevision&&t.baselineFingerprint===e.baselineFingerprint}}const Vu=e=>{const t=e.hass,i=t?.user?.id;return{connection:t?.connection??null,userId:"string"==typeof i?i:null,route:location.pathname}};async function Ku(e,t=!1,i){let n=null;const r=e._configReloadAuthority;if(!t){if(void 0!==i&&(n=r.observeRevision(i,e._cfgRev,Vu(e)),!n))return;if(e._saveConfigDebounced.pending()&&e._saveConfigDebounced.flush(),e._cfgWriting)return clearTimeout(e._reloadRetry),void(e._reloadRetry=window.setTimeout(()=>{n&&!r.isReservationCurrent(n,Vu(e),e._cfgRev)||Ku(e,!1)},400))}const o=r.begin({force:t,context:Vu(e),baselineRevision:e._cfgRev,baselineFingerprint:e._adoption.currentConfigFingerprint()}),s=()=>((e,t)=>e._configReloadAuthority.isCurrent({claim:t,context:Vu(e),connected:e.isConnected,baselineRevision:e._cfgRev,baselineFingerprint:e._adoption.currentConfigFingerprint(),writePending:e._saveConfigDebounced.pending()||e._cfgWriting}))(e,o);let a=!1;try{const t=await e._getAuthoritativeConfig();if(!s())return;const i=await e._adoptAuthoritative({cfgResp:t,reason:"config-reload",profile:"reload",isCurrent:s,afterAdopt:()=>{e._regSignature="",e._maybeRebuildDevices()}});if("superseded"===i.status)return;if(a=!0,"adopted"!==i.status)return;i.spaceChanged&&e._restoreZoom(),e.requestUpdate()}catch(t){if(!s())return;a=!0,e._showToast(e._t("toast.cfg_reload_failed",{err:e._errText(t)}))}finally{(a||s())&&(e._continuityDataReady=!0,e.requestUpdate())}}const Yu=e=>!!e&&e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]);function Xu(e,t=5,i=5){return Oo(e.cm,t,i)/2}function Zu(e,t,i=1,n=5,r=5,o=0){const s=e.host;if(!s||"partition"!==s.kind||"string"!=typeof s.id||!s.id)return{resolved:null,reason:"invalid-host"};const a=t.find(e=>e.id===s.id);if(!a)return{resolved:null,reason:"missing-partition"};if(!Yu(a.a)||!Yu(a.b)||!Number.isFinite(s.t)||s.t<0||s.t>1)return{resolved:null,reason:"invalid-position"};const l=a.b[0]-a.a[0],c=a.b[1]-a.a[1],h=Math.hypot(l,c),d=Number(e.length)*i;if(!(h>1e-9&&d>0&&Number.isFinite(d)))return{resolved:null,reason:"invalid-length"};const u=s.t*h;if(u-d/2h-o+1e-9)return{resolved:null,reason:"does-not-fit"};const p=l/h,_=c/h;let m=180*Math.atan2(c,l)/Math.PI;return m>=90?m-=180:m<-90&&(m+=180),{reason:null,resolved:{opening:e,host:s,partition:a,center:[a.a[0]+l*s.t,a.a[1]+c*s.t],angle:m,length:d,depth:Oo(a.cm,n,r),t:s.t,axis:{a:[a.a[0],a.a[1]],b:[a.b[0],a.b[1]],ux:p,uy:_,length:h}}}}function Ju(e,t,i=1,n=5,r=5){return Zu(e,t,i,n,r,0)}function Qu(e,t,i=1,n=5,r=5){const o=e.host,s="partition"===o?.kind?t.find(e=>e.id===o.id):void 0;if(!s)return Ju(e,t,i,n,r);const a=Zu(e,t,i,n,r,Xu(s,n,r));return"does-not-fit"===a.reason?{resolved:null,reason:"does-not-fit-jamb"}:a}function ep(e,t){return!e||(e.length!==t.length||e.host?.kind!==t.host?.kind||e.host?.id!==t.host?.id||e.host?.t!==t.host?.t)}function tp(e){const{center:t,length:i,axis:n,host:r}=e,o=i/2;return{hostId:r.id,a:[t[0]-n.ux*o,t[1]-n.uy*o],b:[t[0]+n.ux*o,t[1]+n.uy*o],depth:e.depth}}function ip(e,t=!1){const i=t?1:-1,n=e.depth/2;return{ox:-e.axis.uy*i*n,oy:e.axis.ux*i*n,cm:e.partition.cm,side:i}}function np(e,t,i){return e.flatMap(e=>!Yu(e.a)||!Yu(e.b)||Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])<=1e-9?[]:[{roomId:"",a:[e.a[0],e.a[1]],b:[e.b[0],e.b[1]],key:`partition:${e.id}`,kind:"outer",cm:e.cm,open:!1,half:Oo(e.cm,t,i)/2,partitionHost:{kind:"partition",id:e.id}}])}function rp(e,t,i){const{center:n,length:r,axis:o}=e,s=r/2,a=t.flatMap(e=>{if(!e.kind||e.open)return[];const t=e.b[0]-e.a[0],r=e.b[1]-e.a[1],a=Math.hypot(t,r);if(!(a>i))return[];const l=t/a,c=r/a;if(Math.abs(o.ux*c-o.uy*l)>1e-6)return[];if(Math.abs((n[0]-e.a[0])*c-(n[1]-e.a[1])*l)>i)return[];const h=e=>(e[0]-n[0])*o.ux+(e[1]-n[1])*o.uy,d=h(e.a),u=h(e.b),p=Math.max(-s,Math.min(d,u)),_=Math.min(s,Math.max(d,u));return _>=p-i?[[p,_]]:[]});if(!a.length)return!1;a.sort((e,t)=>e[0]-t[0]||e[1]-t[1]);let l=-s;for(const[e,t]of a){if(e>l+i)return!1;if(l=Math.max(l,t),l>=s-i)return!0}return!1}function op(e,t,i=1e-9){const n=e.length/(2*e.axis.length),r=e.t-n,o=e.t+n;return t.some(t=>{if(t.host.id!==e.host.id||t.opening.id===e.opening.id)return!1;const n=t.length/(2*t.axis.length);return Math.max(r,t.t-n)ha-icon{align-self:start;color:var(--hp-accent);}.version-recovery-copy{min-width:0;display:flex;flex-direction:column;gap:var(--sp-2);font-size:var(--fs-m);line-height:1.35;}.version-recovery-copy>span{color:var(--hp-muted);}.version-recovery-versions{display:flex;flex-wrap:wrap;gap:var(--sp-2) var(--sp-5);}.version-recovery-versions span,.version-recovery-versions b{overflow-wrap:anywhere;}.version-recovery-reload{min-height:44px;white-space:normal;}@keyframes hp-version-recovery-in{from{opacity:0;}to{opacity:1;}}@keyframes hp-version-recovery-out{from{opacity:1;}to{opacity:0;}}@media (max-width:520px){.version-recovery-card{grid-template-columns:auto minmax(0,1fr);}.version-recovery-reload{grid-column:1 / -1;width:100%;}}@keyframes fixedfloor-spin{to{transform:rotate(360deg);}}.spacer{flex:1;}.bootveil{position:absolute;inset:0;z-index:40;display:flex;align-items:center;justify-content:center;background:var(--hp-bg,#16212e);opacity:1;transition:opacity 0.15s ease;pointer-events:none;}.bootveil.off{opacity:0;}.bootveil .boothouse{position:static;width:56px;height:56px;fill:var(--hp-accent);opacity:0.85;animation:hp-boot-pulse 1.3s ease-in-out infinite;}@keyframes hp-boot-pulse{0%,100%{opacity:0.3;transform:scale(0.94);}50%{opacity:0.9;transform:scale(1);}}@media (prefers-reduced-motion:reduce){.bootveil .boothouse{animation:none;opacity:0.7;}.version-recovery.phase-visible,.version-recovery.phase-leaving{animation:none;}}@keyframes hp-pulse-short{0%{transform:scale(1);opacity:0.55;}70%{opacity:0.22;}100%{transform:scale(var(--ripple-scale,1.5));opacity:0;}}@keyframes hp-pulse-short-b{0%{transform:scale(1);opacity:0.55;}70%{opacity:0.22;}100%{transform:scale(var(--ripple-scale,1.5));opacity:0;}}@keyframes hp-pulse-continuous{0%{transform:scale(1);opacity:0.55;}65%{opacity:0.18;}100%{transform:scale(var(--ripple-scale,1.5));opacity:0;}}@keyframes hp-pulse-alarm{0%{transform:scale(1);opacity:0.72;}100%{transform:scale(1.5);opacity:0;}}@keyframes hp-slide-left{0%{transform:translateX(4%);opacity:0.72;}100%{transform:translateX(0);opacity:1;}}@keyframes hp-slide-right{0%{transform:translateX(-4%);opacity:0.72;}100%{transform:translateX(0);opacity:1;}}@keyframes hp-sunfade-in{from{opacity:0;}to{opacity:1;}}@keyframes hp-sunfade-out{from{opacity:1;}to{opacity:0;}}.sr-only{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0,0,0,0) !important;white-space:nowrap !important;border:0 !important;}.toast{position:fixed;pointer-events:none;left:50%;bottom:22px;transform:translateX(-50%);background:var(--hp-bg);border:1px solid var(--hp-accent);color:var(--hp-txt);padding:var(--sp-4) var(--sp-6);border-radius:var(--rad-l);font-size:var(--fs-m);box-shadow:var(--shadow-2);z-index:120;max-width:90vw;}`,o`.fixedfloor-loading{animation:fixedfloor-spin 1.1s linear infinite;}.fixedfloor-error p{max-width:42rem;margin:0;overflow-wrap:anywhere;}@media (prefers-reduced-motion:reduce){.fixedfloor-loading{animation:none;}.radar-target{transition:none;}}.stage.noplan{background:#ffffff;}.stage.mode-plan,.stage.mode-devices,.stage.mode-decor{background:#ffffff;}.stage{position:relative;width:100%;container-type:inline-size;overflow:hidden;touch-action:none;background:var(--ha-card-background,var(--card-background-color,#111));}.zoomwrap{position:absolute;inset:0;z-index:1;}.stage.mode-transition,.stage.mode-transition .zoomwrap{transition:none !important;}.stage.mode-transition .hp-view-only-layer,.stage.mode-transition .hp-editor-only-layer{pointer-events:none;will-change:opacity;}.stage.mode-transition .hp-paper{fill:var(--hp-mode-paper) !important;}.hp-day-cycle-env{position:absolute;inset:0;z-index:0;overflow:hidden;pointer-events:none;isolation:isolate;}.hp-day-cycle-bg{position:absolute;inset:0;opacity:0;overflow:hidden;transition:opacity 1100ms cubic-bezier(.22,.61,.36,1);}.hp-day-cycle-bg.active{opacity:1;}.hp-day-cycle-sun{position:absolute;left:var(--hp-day-cycle-sun-x);top:var(--hp-day-cycle-sun-y);width:clamp(140px,25cqw,250px);height:clamp(140px,25cqw,250px);transform:translate(-50%,-50%);border-radius:50%;filter:blur(10px);opacity:var(--hp-day-cycle-sun-opacity);transition:left 1100ms cubic-bezier(.22,.61,.36,1),top 1100ms cubic-bezier(.22,.61,.36,1),opacity 1100ms cubic-bezier(.22,.61,.36,1);}.stage.mode-transition .hp-day-cycle-env{transition:none;}.stage.daycycle .hp-paperg,.stage.daycycle.hp-safe-daycycle-outline .hp-paper-outline-svg,.hp-static-stage.daycycle .hp-paper-outline-svg{filter:drop-shadow(0 0 1px var(--hp-day-cycle-outline-near)) drop-shadow(0 0 5px var(--hp-day-cycle-outline-mid)) drop-shadow(0 0 10px var(--hp-day-cycle-outline-far));will-change:filter;transition:filter 1100ms cubic-bezier(.22,.61,.36,1);}.stage.daycycle.hp-safe-daycycle-outline .hp-paperg{filter:none;will-change:auto;transition:none;}.hp-static-stage.daycycle .hp-paperg{filter:none;will-change:auto;transition:none;}.stage.daycycle.hp-safe-daycycle-outline .hp-paper-outline-svg{transition:none;}.stage.daycycle.hp-safe-daycycle-outline .plan-svg{will-change:transform;}@media (prefers-reduced-motion:reduce){.hp-day-cycle-bg,.hp-day-cycle-sun,.stage.daycycle .hp-paperg,.stage.daycycle.hp-safe-daycycle-outline .hp-paper-outline-svg,.hp-static-stage.daycycle .hp-paper-outline-svg{transition:none;}}.sunlayer{pointer-events:none;}.compass{touch-action:none;cursor:grab;user-select:none;}.compass:active{cursor:grabbing;}.stage.hpboot .zoomwrap,.stage.hpboot .zoombadge{visibility:hidden;}.stage.hpsettle{transition:height 0.25s ease;}@media (prefers-reduced-motion:reduce){.stage.hpsettle{transition:none;}}.zoomctl{display:inline-flex;gap:var(--sp-1);background:rgba(127,127,127,0.12);border-radius:var(--rad-m);padding:var(--sp-1);}.zoomctl .zb{border:none;padding:var(--sp-3) var(--sp-4);}.zoomctl .zb[disabled]{opacity:0.4;pointer-events:none;}.projection-toggle{min-width:44px;min-height:44px;justify-content:center;padding:var(--sp-3);}.header-action{min-width:44px;min-height:44px;justify-content:center;padding:var(--sp-3);}.homearrow{position:absolute;z-index:12;transform:translate(-50%,-50%);width:40px;height:40px;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;background:var(--card-background-color,var(--hp-bg));color:var(--hp-accent);border:1px solid var(--hp-accent);opacity:0.9;padding:0;}.homearrow ha-icon{--mdc-icon-size:22px;line-height:1;}.zoombadge{position:absolute;z-index:12;left:var(--sp-4);bottom:var(--sp-4);background:var(--card-background-color,var(--hp-bg));opacity:0.92;color:var(--hp-txt);border:1px solid var(--hp-accent);border-radius:var(--rad-m);padding:var(--sp-1) var(--sp-4);font-size:var(--fs-s);font-weight:600;pointer-events:none;}.zoomwrap>svg{position:absolute;inset:0;width:100%;height:100%;display:block;}.plan-svg{z-index:1;}.hp-paper-outline-svg{z-index:0;overflow:visible;pointer-events:none;visibility:hidden;}.stage.hp-safe-daycycle-outline .hp-paper-outline-svg{visibility:visible;}.hp-static-stage .hp-paper-outline-svg{visibility:visible;}.iso-underlay-svg{z-index:0;overflow:visible;}.iso-shadows-svg{z-index:3;overflow:visible;}.iso-walls-svg{z-index:4;overflow:visible;}.iso-overlays-svg{z-index:5;overflow:visible;}.iso-underlay-svg,.iso-shadows-svg,.iso-walls-svg,.iso-overlays-svg,.iso-underlay,.iso-shadows,.iso-walls,.iso-openings{pointer-events:none;}.iso-side-hi{stop-color:#b9bdbe;}.iso-side-lo{stop-color:#969c9f;}.iso-top-hi{stop-color:#fafaf7;}.iso-top-lo{stop-color:#e2e4e2;}.iso-wall-side{fill:url(#hp-iso-wall-side) #a8acae;stroke:#92989b;stroke-width:0.7;vector-effect:non-scaling-stroke;}.iso-wall-top{fill:url(#hp-iso-wall-top) #f3f3f1;stroke:#d7d9d8;stroke-width:0.8;vector-effect:non-scaling-stroke;}.iso-material-texture{fill:url(#hp-iso-wall-texture);stroke:none;opacity:0.12;pointer-events:none;}.iso-floor-texture{fill:url(#hp-iso-floor-texture);opacity:0.1;}.iso-texture-mark{fill:rgba(36,43,47,0.34);}.iso-texture-line{fill:none;stroke:rgba(36,43,47,0.24);stroke-width:0.55;}.iso-floor-side{fill:#858b8d;stroke:#71787b;stroke-width:0.7;vector-effect:non-scaling-stroke;}.iso-opening-panel{fill:#d7d9d7;fill-opacity:0.96;stroke:#7f878b;stroke-width:0.9;vector-effect:non-scaling-stroke;}.iso-opening-panel.iso-window{fill:#dfeff4;fill-opacity:0.72;stroke:#8aa7b1;}.iso-opening-panel.iso-material-reveal{fill:#c7cbca;stroke:#8b9294;}.iso-opening-panel.iso-material-matte-leaf{fill:#a6abad;stroke:none;}.iso-opening-panel.iso-opening-leaf-edge,.iso-opening-panel.iso-opening-leaf-top{fill:#8d9497;}.iso-opening-panel.iso-material-light-frame,.iso-opening-panel.iso-material-light-sill{fill:#fffef8;fill-opacity:0.94;stroke:#b3b5ae;}.iso-opening-panel.iso-material-light-window,.iso-opening-panel.iso-material-glass-side{fill:#c9e4f3;fill-opacity:0.88;stroke:#8fb4c7;}.iso-opening-panel.iso-material-glass-top{fill:#e3f2fa;fill-opacity:0.96;stroke:#9fc4d5;}.iso-ambient-shadow{fill:rgba(15,21,25,0.22);filter:url(#hp-iso-ambient-shadow);}.stage.theme-dark .iso-side-hi{stop-color:#4c555a;}.stage.theme-dark .iso-side-lo{stop-color:#343c40;}.stage.theme-dark .iso-top-hi{stop-color:#687176;}.stage.theme-dark .iso-top-lo{stop-color:#50585d;}.stage.theme-dark .iso-wall-side{stroke:#30373b;}.stage.theme-dark .iso-wall-top{stroke:#7b858a;}.stage.theme-dark .iso-floor-side{fill:#2d3438;stroke:#20272a;}.stage.theme-dark .iso-opening-panel{fill:#626b70;stroke:#899399;}.stage.theme-dark .iso-opening-panel.iso-window{fill:#75919b;stroke:#abc6ce;}.stage.theme-dark .iso-opening-panel.iso-material-reveal{fill:#454e52;stroke:#727d82;}.stage.theme-dark .iso-opening-panel.iso-material-matte-leaf{fill:#626a6e;stroke:none;}.stage.theme-dark .iso-opening-panel.iso-opening-leaf-edge,.stage.theme-dark .iso-opening-panel.iso-opening-leaf-top{fill:#4b5458;}.stage.theme-dark .iso-opening-panel.iso-material-light-frame,.stage.theme-dark .iso-opening-panel.iso-material-light-sill{fill:#e8e7df;stroke:#a9aca7;}.stage.theme-dark .iso-opening-panel.iso-material-light-window,.stage.theme-dark .iso-opening-panel.iso-material-glass-side{fill:#8fbfd5;stroke:#bad9e6;}.stage.theme-dark .iso-opening-panel.iso-material-glass-top{fill:#c9e6f2;stroke:#d9eef6;}.stage.theme-dark .iso-ambient-shadow{fill:rgba(0,0,0,0.34);}.stage.theme-dark .iso-texture-mark{fill:rgba(255,255,255,0.24);}.stage.theme-dark .iso-texture-line{stroke:rgba(255,255,255,0.18);}@media (prefers-color-scheme:dark){.stage:not(.theme-light) .iso-side-hi{stop-color:#4c555a;}.stage:not(.theme-light) .iso-side-lo{stop-color:#343c40;}.stage:not(.theme-light) .iso-top-hi{stop-color:#687176;}.stage:not(.theme-light) .iso-top-lo{stop-color:#50585d;}.stage:not(.theme-light) .iso-wall-side{stroke:#30373b;}.stage:not(.theme-light) .iso-wall-top{stroke:#7b858a;}.stage:not(.theme-light) .iso-floor-side{fill:#2d3438;stroke:#20272a;}.stage:not(.theme-light) .iso-opening-panel{fill:#626b70;stroke:#899399;}.stage:not(.theme-light) .iso-opening-panel.iso-window{fill:#75919b;stroke:#abc6ce;}.stage:not(.theme-light) .iso-opening-panel.iso-material-reveal{fill:#454e52;stroke:#727d82;}.stage:not(.theme-light) .iso-opening-panel.iso-material-matte-leaf{fill:#626a6e;stroke:none;}.stage:not(.theme-light) .iso-opening-panel.iso-opening-leaf-edge,.stage:not(.theme-light) .iso-opening-panel.iso-opening-leaf-top{fill:#4b5458;}.stage:not(.theme-light) .iso-opening-panel.iso-material-light-frame,.stage:not(.theme-light) .iso-opening-panel.iso-material-light-sill{fill:#e8e7df;stroke:#a9aca7;}.stage:not(.theme-light) .iso-opening-panel.iso-material-light-window,.stage:not(.theme-light) .iso-opening-panel.iso-material-glass-side{fill:#8fbfd5;stroke:#bad9e6;}.stage:not(.theme-light) .iso-opening-panel.iso-material-glass-top{fill:#c9e6f2;stroke:#d9eef6;}.stage:not(.theme-light) .iso-ambient-shadow{fill:rgba(0,0,0,0.34);}.stage:not(.theme-light) .iso-texture-mark{fill:rgba(255,255,255,0.24);}.stage:not(.theme-light) .iso-texture-line{stroke:rgba(255,255,255,0.18);}}@media (forced-colors:active){.iso-wall-side,.iso-wall-top,.iso-floor-side,.iso-opening-panel{fill:Canvas;stroke:CanvasText;forced-color-adjust:auto;}.iso-ambient-shadow,.iso-material-texture{display:none;}}@supports not (filter:blur(1px)){.iso-ambient-shadow,.iso-material-texture{display:none;}}.hp-paper{fill:var(--ha-card-background,var(--card-background-color,#111));stroke:none;}.stage.noplan .hp-paper,.stage.mode-plan .hp-paper,.stage.mode-devices .hp-paper,.stage.mode-decor .hp-paper{fill:#ffffff;}.room{transition:0.12s;cursor:default;stroke-linejoin:round;stroke-linecap:round;}.stage.mode-view .room{cursor:pointer;}.room.overlay{fill:transparent;stroke:transparent;stroke-width:calc(2px * var(--hp-cell-visual-scale,1));}:host([data-pointer-hover]) .stage.mode-view .room.overlay:not(.styled):hover{stroke:var(--hp-accent);stroke-opacity:1;}.room.yard{fill:rgba(75,140,90,0.14);stroke:#4b8c5a;stroke-width:calc(2px * var(--hp-cell-visual-scale,1));}:host([data-pointer-hover]) .stage.mode-view .room.yard:not(.styled):hover{stroke:var(--hp-accent);stroke-opacity:1;}.room.styled{stroke:var(--room-stroke,transparent);stroke-opacity:var(--room-stroke-op,0);stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));fill:var(--room-fill,transparent);fill-opacity:var(--room-fill-op,0);}.glow-base-layer,.glow-base-tunnels,.glow-pools-frame,.glow-pools,.glow-spot{pointer-events:none;}.glow-pools-frame,.glow-pools,.glow-spot{isolation:isolate;}.glow-pools.blend-screen .glow-spot{mix-blend-mode:screen;}.glow-spot{opacity:1;transition:opacity 500ms ease;}.glow-spot.is-entering,.glow-spot.is-leaving{opacity:0;}@media (prefers-reduced-motion:reduce){.glow-spot{transition:none;}}:host([data-pointer-hover]) .stage.mode-view .room.styled:hover{stroke:var(--hp-accent);stroke-opacity:1;}.op-leaf{transition:transform 0.6s ease;}.op-arc{stroke-width:calc(1.5px * var(--hp-cell-visual-scale,1));transition:stroke-dashoffset 0.6s ease;}.op-outline{fill:none;stroke:var(--hp-accent);stroke-width:calc(1.5px * var(--hp-cell-visual-scale,1));opacity:0;transition:opacity 0.15s;pointer-events:none;}:host([data-pointer-hover]) .stage.markup g.opening:hover .op-outline{opacity:0.9;}.op-hit{fill:transparent;pointer-events:none;cursor:default;}.stage.markup .op-hit{pointer-events:auto;cursor:grab;touch-action:none;}.stage.markup .op-hit:active{cursor:grabbing;}.stage.markup .opening.orphan{pointer-events:auto;cursor:pointer;color:var(--error-color,#db4437);}.stage.markup .opening.orphan circle{fill:var(--hp-bg);stroke:currentColor;stroke-width:calc(2px * var(--hp-cell-visual-scale,1));}.stage.markup .opening.orphan text{fill:currentColor;font-weight:800;font-size:calc(12px * var(--hp-cell-visual-scale,1));pointer-events:none;}.stage.markup.tool-resize .op-hit{pointer-events:none;cursor:default;}.stage.mode-view .oplock{pointer-events:auto;cursor:pointer;}.stage.projection-iso.mode-view .oplock::before{content:'';position:absolute;left:50%;top:50%;width:max(44px,100%);height:max(44px,100%);transform:translate(-50%,-50%);border-radius:50%;pointer-events:auto;}@media (prefers-reduced-motion:reduce){.op-leaf,.op-arc{transition:none;}}.roomlabel{pointer-events:none;position:absolute;transform:translate(-50%,-50%);font-size:calc(var(--rl-icon-size,var(--icon-size,2.5cqw)) * 0.5 * var(--rl-scale,1) * var(--rl-font,1) * var(--rl-space,1));font-weight:700;letter-spacing:0.04em;white-space:nowrap;cursor:grab;user-select:none;z-index:1;display:flex;flex-direction:column;align-items:center;gap:0.15em;text-align:center;}.rlname{display:inline-flex;align-items:center;gap:0.25em;font-size:calc(1em * var(--rl-name,1));}.zoomwrap.slide-left{animation:hp-slide-left 0.18s cubic-bezier(0.2,0.7,0.2,1);}.zoomwrap.slide-right{animation:hp-slide-right 0.18s cubic-bezier(0.2,0.7,0.2,1);}@media (prefers-reduced-motion:reduce){.zoomwrap.slide-left,.zoomwrap.slide-right{animation:none;}}.rlgearbtn{--gear-h:calc(var(--icon-size,2.5cqw) * 0.77);position:absolute;transform:translate(-50%,-50%);display:inline-flex;align-items:center;gap:0.35em;height:var(--gear-h);padding:0 calc(var(--gear-h) * 0.38);border:0;border-radius:999px;background:var(--hp-accent);color:var(--text-primary-color,#fff);font:inherit;font-size:calc(var(--gear-h) * 0.42);font-weight:600;line-height:1;white-space:nowrap;cursor:pointer;pointer-events:auto;opacity:0.92;box-shadow:var(--shadow-1);z-index:2;}.rlgearbtn{transition:opacity 0.15s,filter 0.15s;}:host([data-pointer-hover]) .rlgearbtn:hover{opacity:1;filter:brightness(1.18);}.rlgearbtn ha-icon{--mdc-icon-size:calc(var(--gear-h) * 0.55);display:inline-flex;}.rlgear{--mdc-icon-size:0.9em;display:inline-flex;margin-right:0.2em;opacity:0.6;cursor:pointer;pointer-events:auto;}:host([data-pointer-hover]) .rlgear:hover{opacity:1;}.rlgo{--mdc-icon-size:0.85em;display:inline-flex;opacity:0.55;}.stage.mode-view .rlgo{pointer-events:auto;cursor:pointer;}:host([data-pointer-hover]) .stage.mode-view .rlgo:hover{opacity:1;}.roomlabel .rlmetrics{position:absolute;top:calc(100% + 0.15em);left:50%;transform:translateX(-50%);white-space:nowrap;display:flex;align-items:center;gap:0.55em;font-size:calc(0.75em * var(--rl-meta,1));font-weight:600;letter-spacing:0.02em;opacity:0.9;}.roomlabel .rlm{display:inline-flex;align-items:center;gap:0.12em;}.roomlabel .rlm ha-icon{--mdc-icon-size:1.05em;display:inline-flex;}.roomlabel .rlm.lit{opacity:1;}.rlhandle{display:none;position:absolute;width:9px;height:9px;border-radius:2px;background:var(--hp-accent);border:1px solid var(--card-background-color,#fff);z-index:2;}.rlhandle.tl{left:-6px;top:-6px;cursor:nwse-resize;}.rlhandle.br{right:-6px;bottom:-6px;cursor:nwse-resize;}.rlhandle.tr{right:-6px;top:-6px;cursor:nesw-resize;}.rlhandle.bl{left:-6px;bottom:-6px;cursor:nesw-resize;}:host([data-pointer-hover]) .stage.markup .roomlabel:hover .rlhandle{display:block;}.stage.markup .roomlabel{pointer-events:auto;}.stage.mode-view .roomlabel{pointer-events:auto;cursor:pointer;border-radius:0.2em;}.stage.projection-iso.mode-view .roomlabel{box-sizing:border-box;min-width:44px;min-height:44px;justify-content:center;text-shadow:none;filter:none;-webkit-text-stroke:0 transparent;color:#303936 !important;}.stage.projection-iso.mode-view .dev,.stage.projection-iso.mode-view .oplock{z-index:2;}.stage.projection-iso.theme-dark.mode-view .roomlabel{color:#f2f0e8 !important;}@media (prefers-color-scheme:dark){.stage.projection-iso:not(.theme-light).mode-view .roomlabel{color:#f2f0e8 !important;}}.stage.mode-view .roomlabel:focus-visible{outline:2px solid var(--hp-accent);outline-offset:4px;}.roomlabel:active{cursor:grabbing;}.measurelayer{position:absolute;inset:0;pointer-events:none;}.alignline{stroke:var(--hp-accent);stroke-width:calc(1.2px * var(--hp-cell-visual-scale,1));stroke-dasharray:calc(4px * var(--hp-cell-visual-scale,1)) calc(4px * var(--hp-cell-visual-scale,1));pointer-events:none;opacity:0.9;}.aligndot{fill:var(--hp-accent);pointer-events:none;}.measurelabel.on45{color:#4bd28f;border-color:#4bd28f;}.measurelabel{position:absolute;transform:translate(12px,-150%);font-size:var(--fs-s);font-weight:600;padding:1px var(--sp-3);border-radius:var(--rad-s);background:rgba(0,0,0,0.72);color:#fff;white-space:nowrap;pointer-events:none;user-select:none;z-index:3;}.measurelabel.opdimension{transform:translate(calc(-50% + var(--op-label-shift-x,0px)),calc(-50% + var(--op-label-shift-y,-12px)));border:1px solid var(--hp-open,#ff9800);}.decorlayer .dshape{pointer-events:none;}.stage.mode-decor .decorlayer .dshape{pointer-events:visiblePainted;cursor:pointer;}.stage.mode-decor.dtool-select .decorlayer .dshape{cursor:move;}.stage.mode-decor.dtool-line .decorlayer .dshape,.stage.mode-decor.dtool-rect .decorlayer .dshape,.stage.mode-decor.dtool-ellipse .decorlayer .dshape,.stage.mode-decor.dtool-text .decorlayer .dshape,.stage.mode-decor.dtool-furniture .decorlayer .dshape,.stage.mode-decor.dtool-image .decorlayer .dshape,.stage.mode-decor.dtool-backdrop .decorlayer .dshape{pointer-events:none;}.stage.mode-decor.dtool-furniture,.stage.mode-decor.dtool-image{cursor:copy;}.stage.mode-decor.dtool-select .decorlayer .dimage,.stage.mode-decor.dtool-erase .decorlayer .dimage,.stage.mode-decor.dtool-select .decorlayer .dimage-missing,.stage.mode-decor.dtool-erase .decorlayer .dimage-missing{pointer-events:bounding-box;}.decorlayer .dimage-missing rect{fill:rgba(127,127,127,0.12);stroke:var(--hp-accent);stroke-dasharray:8 5;vector-effect:non-scaling-stroke;}.decorlayer .dimage-missing path{fill:none;stroke:var(--hp-accent);vector-effect:non-scaling-stroke;}.decorlayer .decor-image-placement-preview{opacity:0.65;}.stage.mode-decor.dtool-text .decorlayer .dshape.dtext,.stage.mode-decor.dtool-select .decorlayer .dshape.dtext,.stage.mode-decor.dtool-erase .decorlayer .dshape.dtext{pointer-events:visiblePainted;pointer-events:bounding-box;}.stage.mode-decor.dtool-text .decorlayer .dshape.dtext{cursor:text;}.decorlayer .derasehit{fill:none;stroke:transparent;stroke-width:16px;stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke;pointer-events:none;}.stage.mode-decor.dtool-erase .decorlayer .derasehit{pointer-events:stroke;}.decorlayer .dselecthit{fill:none;stroke:transparent;stroke-width:16px;stroke-linecap:round;vector-effect:non-scaling-stroke;pointer-events:none;}.stage.mode-decor.dtool-select .decorlayer .dselecthit{pointer-events:stroke;cursor:move;}.stage.mode-decor .decorlayer .dshape.dfurniturehit{fill:none;stroke:transparent;pointer-events:none;}.stage.mode-decor.dtool-select .decorlayer .dshape.dfurniturehit{pointer-events:stroke;cursor:move;}.decorlayer .dsel{filter:drop-shadow(0 0 3px var(--hp-accent));}.decorlayer .ddraft{stroke-dasharray:calc(6px * var(--hp-cell-visual-scale,1)) calc(5px * var(--hp-cell-visual-scale,1));pointer-events:none;}.decorlayer .furniture-placement-preview{opacity:0.55;pointer-events:none;}.decorlayer text{font-weight:600;user-select:none;dominant-baseline:middle;text-anchor:middle;}.stage.mode-decor{outline:2px solid #26a69a;outline-offset:-2px;}.bdframe .bdbox{fill:none;stroke:var(--hp-accent);stroke-width:2;stroke-dasharray:10 7;vector-effect:non-scaling-stroke;pointer-events:none;opacity:0.9;}.bdframe .bdhandle{fill:transparent;stroke:none;pointer-events:all;touch-action:none;}.bdframe .bdknob{fill:var(--hp-accent);stroke:#fff;stroke-width:1;vector-effect:non-scaling-stroke;pointer-events:none;}:host([data-pointer-hover]) .bdframe .bdhandle:hover + .bdknob{fill:#fff;stroke:var(--hp-accent);}.bdframe .bd-nwse{cursor:nwse-resize;}.bdframe .bd-nesw{cursor:nesw-resize;}.stage.mode-decor.bdgrab{cursor:grab;}.stage.mode-decor.bdgrabbing,.stage.mode-decor.bdgrabbing .bdframe .bdhandle{cursor:grabbing;}.measurelabel.bdmeasure{transform:translate(-50%,-50%);border:1px solid var(--hp-accent);}.dtframe .dtbox{fill:none;stroke:var(--hp-accent);stroke-width:1.5;stroke-dasharray:7 5;vector-effect:non-scaling-stroke;pointer-events:none;opacity:0.85;}.dtframe .dtstem,.bdframe .dtstem{stroke:var(--hp-accent);stroke-width:1.5;vector-effect:non-scaling-stroke;pointer-events:none;opacity:0.85;}.dtframe .dthandle{fill:transparent;stroke:none;pointer-events:all;touch-action:none;}.dtframe .dtknob{fill:var(--hp-accent);stroke:#fff;stroke-width:1;vector-effect:non-scaling-stroke;pointer-events:none;}:host([data-pointer-hover]) .dtframe .dthandle:hover + .dtknob{fill:#fff;stroke:var(--hp-accent);}.dtframe .dt-nwse{cursor:nwse-resize;}.dtframe .dt-nesw{cursor:nesw-resize;}.dtframe .dtrot{cursor:grab;}.dtframe .dt-ew{cursor:ew-resize;}.dtframe .dt-ns{cursor:ns-resize;}.dtfurnitureframe .dtrot{cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M18.4 7.2A8 8 0 1 0 20 12' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'/%3E%3Cpath d='m15.5 3.8 3.2 3.5-4.6.8' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 12 12,grab;}.dtfurnitureframe .dtrot:active{cursor:grabbing;}.dtframe .dtendpoint{cursor:crosshair;}.bdframe .dtrot{cursor:grab;}.dtarea{resize:vertical;min-height:3.4em;font:inherit;line-height:1.35;}.stage.mode-decor.dtool-line,.stage.mode-decor.dtool-rect,.stage.mode-decor.dtool-ellipse,.stage.mode-decor.dtool-text{cursor:crosshair;}.stage.mode-decor.dtool-erase,.stage.mode-decor.dtool-erase .decorlayer .dshape{cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg transform='rotate(-45 12 12)'%3E%3Crect x='7' y='2' width='10' height='18' rx='2' fill='%23fff' stroke='%23111' stroke-width='1.5'/%3E%3Cpath d='M7 13h10v5a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2z' fill='%23ff9f43' stroke='%23111' stroke-width='1.5'/%3E%3C/g%3E%3C/svg%3E") 5 22,pointer;}.stage.mode-decor .room{pointer-events:none;}.stage.mode-decor .devlayer,.stage.mode-decor .devlayer *,.stage.mode-decor .dev::before{pointer-events:none;}.stage .room,.stage .devlayer,.stage .opening,.stage .room-outline,.stage .wallbodies,.stage .opening-tunnels,.stage .glow-base-layer,.stage .glow-pools-frame,.stage .zero-walls{opacity:var(--hp-mode-architecture-opacity,1);}.opening-preview{opacity:0.5;pointer-events:none;}.opening-preview[data-kind="passage"]{opacity:1;}.passage-preview-cut{fill:var(--wall-fill,#ffffff);fill-opacity:0.35;stroke:none;pointer-events:none;}.passage-preview-boundary{stroke:var(--hp-open,#ff9800);stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));pointer-events:none;}.opening-preview .op-leaf,.opening-preview .op-arc{transition:none;}.opening-preview-dot{fill:var(--hp-open,#ff9800);pointer-events:none;}.opening-dimensions,.opening-dimension{pointer-events:none;}.opening-dimension-line,.opening-dimension-tick{fill:none;stroke:var(--hp-open,#ff9800);stroke-width:1.5;vector-effect:non-scaling-stroke;pointer-events:none;}.opening-dimension-tick{stroke-width:2;}.stage.edit .room{pointer-events:none;}.stage.markup{cursor:crosshair;}.stage.markup.tool-merge,.stage.markup.tool-split.pickstage,.stage.markup.tool-delroom{cursor:pointer;}.stage.markup.tool-wallthick{cursor:default;}.stage.markup.tool-wallthick.wallhot{cursor:pointer;}.wallbody-fill{fill:var(--wall-fill,#ffffff);fill-opacity:var(--wall-fill-op,1);fill-rule:evenodd;stroke:none;pointer-events:none;}.wallbody{fill:url(#hp-wall-hatch);fill-rule:evenodd;stroke:var(--room-stroke,var(--hp-muted));stroke-width:calc(0.6px * var(--hp-cell-visual-scale,1));pointer-events:none;}.wallbody.solid{fill:none;}.wallthick-hover{fill:var(--accent-color,#03a9f4);fill-opacity:0.38;stroke:var(--accent-color,#03a9f4);stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));stroke-linejoin:round;stroke-linecap:round;pointer-events:none;}.wallthick-hover.isopen{fill:var(--error-color,#f44336);stroke:var(--error-color,#f44336);}.zero-wall{stroke:var(--zero-wall-stroke,var(--hp-muted));stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));stroke-dasharray:calc(7px * var(--hp-cell-visual-scale,1)) calc(7px * var(--hp-cell-visual-scale,1));stroke-linecap:butt;pointer-events:none;opacity:0.9;}.zero-walls.solid .zero-wall{stroke-dasharray:none;}.room.noedge{stroke-opacity:0 !important;}.room-outline{fill:none;stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));stroke-linejoin:round;stroke-linecap:round;pointer-events:none;}.room-outline.outlined{stroke:rgba(62,166,255,0.55);stroke-opacity:1;}.room-hover-fill{fill:#000;fill-opacity:0.22;pointer-events:none;}.room-hover-halo{fill:none;stroke:var(--hp-accent);stroke-opacity:0.28;stroke-width:calc(8px * var(--hp-cell-visual-scale,1));stroke-linejoin:round;stroke-linecap:round;pointer-events:none;}.room-hover-outline{fill:none;stroke:var(--hp-accent);stroke-width:calc(3px * var(--hp-cell-visual-scale,1));stroke-linejoin:round;stroke-linecap:round;pointer-events:none;}.stage.markup .room{pointer-events:none;}.stage.markup .devlayer .dev{display:none;}.stage.mode-plan{outline:2px solid #ffc14d;outline-offset:-2px;}.stage.mode-devices{outline:2px solid var(--hp-accent);outline-offset:-2px;}.room.outlined{stroke:rgba(62,166,255,0.55);fill:rgba(62,166,255,0.06);}.room.picked{stroke:#ffc14d;stroke-width:calc(3px * var(--hp-cell-visual-scale,1));fill:rgba(255,193,77,0.25);}.griddot{fill:var(--hp-accent);opacity:0.35;stroke:rgba(0,0,0,0.35);stroke-width:0.4;}.griddot.major{opacity:0.5;stroke-width:0;}.seg{stroke:var(--hp-accent);stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));stroke-linecap:round;stroke-linejoin:round;}.pathline{stroke:#ffc14d;stroke-width:calc(3px * var(--hp-cell-visual-scale,1));fill:none;stroke-linecap:round;stroke-linejoin:round;}.preview{stroke:#ffc14d;stroke-width:calc(2px * var(--hp-cell-visual-scale,1));stroke-dasharray:calc(6px * var(--hp-cell-visual-scale,1)) calc(5px * var(--hp-cell-visual-scale,1));opacity:0.7;}.active-axis{stroke:#ffc14d;stroke-width:2;stroke-linecap:round;vector-effect:non-scaling-stroke;pointer-events:none;}.active-vertex{fill:#ffc14d;stroke:#171006;stroke-width:2;vector-effect:non-scaling-stroke;pointer-events:none;}.wall-repair-preview{stroke:#d93025;stroke-width:4;stroke-linecap:round;stroke-dasharray:5 4;vector-effect:non-scaling-stroke;pointer-events:none;}.drawwall-preview-fill{fill:var(--wall-fill,#ffffff);fill-opacity:calc(var(--wall-fill-op,1) * 0.55);fill-rule:evenodd;stroke:none;pointer-events:none;}.drawwall-preview{fill:url(#hp-wall-hatch);fill-opacity:0.55;fill-rule:evenodd;stroke:var(--accent-color,#03a9f4);stroke-width:calc(0.5px * var(--hp-cell-visual-scale,1));stroke-opacity:0.7;pointer-events:none;}.drawwall-zero-preview{fill:none;stroke:var(--accent-color,#03a9f4);stroke-width:calc(3px * var(--hp-cell-visual-scale,1));stroke-linecap:butt;stroke-linejoin:round;opacity:0.72;pointer-events:none;}.drawwall-zero-preview.dashed{stroke-dasharray:calc(7px * var(--hp-cell-visual-scale,1)) calc(7px * var(--hp-cell-visual-scale,1));}.vertex{fill:#ffc14d;stroke:#4a2800;stroke-width:calc(1px * var(--hp-cell-visual-scale,1));}.vertex.first{fill:#4bd28f;stroke:#04121f;}.plan-snap-overlay,.plan-snap-overlay *,.hidden-wall-diagnostic,.hidden-wall-diagnostic *{pointer-events:none;}.plan-snap-line,.hidden-wall-line{fill:none;stroke:color-mix(in srgb,var(--hp-accent) 82%,white 18%);stroke-width:1;stroke-linecap:round;opacity:0.92;}.plan-snap-node,.hidden-wall-node{fill:var(--ha-card-background,var(--card-background-color,#fff));stroke:color-mix(in srgb,var(--hp-accent) 88%,#07131c 12%);stroke-width:1;vector-effect:non-scaling-stroke;}.plan-snap-node.active{fill:#ffc14d;stroke:#171006;stroke-width:2;}.plan-snap-node.active.dynamic{fill:#4bd28f;stroke:#04121f;}.plan-snap-node.conflict{fill:#fff;stroke:#d93025;stroke-width:3;}@media (prefers-color-scheme:dark){.plan-snap-line{stroke:color-mix(in srgb,var(--hp-accent) 72%,white 28%);}.hidden-wall-line{stroke:color-mix(in srgb,var(--hp-accent) 72%,white 28%);}.plan-snap-node,.hidden-wall-node{fill:#17242c;stroke:#9bdcf5;}.plan-snap-node.active{fill:#ffc14d;stroke:#fff4d6;}.plan-snap-node.active.dynamic{fill:#4bd28f;stroke:#eafff4;}}@media (forced-colors:active){.plan-snap-line,.hidden-wall-line{stroke:CanvasText;opacity:1;forced-color-adjust:auto;}.plan-snap-node,.hidden-wall-node{fill:Canvas;stroke:CanvasText;forced-color-adjust:auto;}.plan-snap-node.active,.plan-snap-node.active.dynamic{fill:Highlight;stroke:HighlightText;forced-color-adjust:auto;}}.sunlayer{animation:hp-sunfade-in 2s linear both;}.sunlayer.out{animation:hp-sunfade-out 2s linear both;}@media (prefers-reduced-motion:reduce){.sunlayer,.sunlayer.out{animation:none;}.sunlayer.out{opacity:0;}}.devlayer{position:absolute;inset:0;pointer-events:none;z-index:6;}.radar-target{position:absolute;width:8px;height:8px;box-sizing:border-box;transform:translate(-50%,-50%);border-radius:50%;background:var(--success-color,#43a047);border:2px solid var(--primary-text-color,#1f1f1f);box-shadow:0 0 0 1px color-mix(in srgb,var(--card-background-color,#fff) 80%,transparent);pointer-events:none;z-index:0;}.radar-target.smooth{transition:left 200ms linear,top 200ms linear;}.radar-ranges{position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none;z-index:0;}.radar-ranges path,.radar-ranges polyline{fill:none;stroke:var(--success-color,#43a047);stroke-width:2px;stroke-dasharray:5 4;vector-effect:non-scaling-stroke;opacity:0.72;}.radar-ranges .radar-zone{fill:color-mix(in srgb,var(--success-color,#43a047) 8%,transparent);stroke:var(--success-color,#43a047);stroke-width:2px;vector-effect:non-scaling-stroke;opacity:0.8;}.stage.mode-devices .dev{cursor:grab;}.stage.mode-devices .dev:active{cursor:grabbing;}.physical-hit{fill:transparent;stroke:transparent;pointer-events:none;cursor:grab;}.stage.tool-select .physical-hit{pointer-events:all;}.physical-hit:active{cursor:grabbing;}line.physical-hit{cursor:pointer;}.physical-hit.selected{fill:rgba(255,193,77,0.24);stroke:transparent;}line.physical-hit.selected{stroke:transparent;}.physical-drag{fill:rgba(255,193,77,0.38);stroke:#ffc14d;stroke-width:2.5;vector-effect:non-scaling-stroke;pointer-events:none;}.physical-chrome{pointer-events:none;}.physical-chrome .frame,.physical-chrome .stem{fill:none;stroke:#ffc14d;stroke-width:2;vector-effect:non-scaling-stroke;}.physical-chrome .frame{fill:rgba(255,193,77,0.22);}.physical-chrome polyline.frame{fill:none;}.physical-chrome .move-dot{fill:#ffc14d;stroke:#24262d;stroke-width:1.5;vector-effect:non-scaling-stroke;}.physical-chrome .rotate-handle{fill:#24262d;stroke:#ffc14d;stroke-width:2.5;vector-effect:non-scaling-stroke;pointer-events:all;cursor:crosshair;}.drawwall.invalid input{border-color:var(--error-color,#db4437);}.drawwall .rangehint{margin-inline-start:4px;font-size:0.78em;opacity:0.72;}.drawwall.invalid .rangehint{color:var(--error-color,#db4437);opacity:1;}.stage.markup.tool-partition,.stage.markup.tool-column{cursor:crosshair;}.rszhandle{fill:transparent;stroke:none;pointer-events:all;cursor:grab;touch-action:none;}.rszhandle:active{cursor:grabbing;}.rszhandle.disabled,.rszhandle.disabled:active{cursor:not-allowed;}.rszicon{pointer-events:none;}.rszicon path{fill:none;stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke;}.rszhalo{stroke:var(--hp-bg);stroke-width:6;}.rszink{stroke:var(--hp-accent);stroke-width:2;}:host([data-pointer-hover]) .rszhandle:hover + .rszicon .rszink{stroke-width:3;}.rszicon.disabled{opacity:0.38;}:host([data-pointer-hover]) .rszhandle.disabled:hover + .rszicon .rszink{stroke-width:2;}.rszmeasurelayer,.rszmeasurelayer *{pointer-events:none;}.rszmeasurehalo,.rszmeasureink,.rszleader{fill:none;stroke-linecap:round;vector-effect:non-scaling-stroke;}.rszmeasurehalo{stroke:var(--hp-bg);stroke-width:7px;opacity:0.9;}.rszmeasureink{stroke:var(--hp-accent);stroke-width:3px;}.rszleader{stroke:var(--hp-accent);stroke-width:2px;opacity:0.95;}.measurelabel.dmeasure{transform:translate(-50%,-160%);}.measurelabel.rszarea{transform:translate(calc(-50% + var(--rsz-label-x,0px)),calc(-50% + var(--rsz-label-y,0px)));background:rgba(0,0,0,0.6);border:1px solid var(--hp-accent);}.measurelabel.furnmeasure{transform:translate(-50%,-50%);border:1px solid var(--hp-accent);}.alignmsg{margin:0 0 8px;font-size:13px;line-height:1.45;}`,o`.dev ha-icon{position:relative;z-index:1;}.device-pulse{position:absolute;left:50%;top:50%;width:var(--dev-size);height:var(--dev-size);transform:translate(-50%,-50%);pointer-events:none;z-index:0;}.device-pulse i{position:absolute;inset:0;border-radius:50%;border:2px solid var(--ripple-color,var(--hp-accent));opacity:0;}.device-pulse.short i{animation:hp-pulse-short 1.1s cubic-bezier(.22,.61,.36,1) 1 forwards;}.device-pulse.short i:nth-child(2){animation-delay:1.1s;}.device-pulse.short i:nth-child(3){animation-delay:2.2s;}.device-pulse.short.gen2 i{animation-name:hp-pulse-short-b;}.device-pulse.continuous i:nth-child(n + 2),.device-pulse.alarm i:nth-child(n + 3){display:none;}.device-pulse.continuous i:first-child{animation:hp-pulse-continuous 3.6s cubic-bezier(.45,.05,.55,.95) infinite;}.device-pulse.alarm i{border-width:3px;border-color:#F0410C;animation:hp-pulse-alarm 2.4s cubic-bezier(.22,.61,.36,1) infinite;}.device-pulse.alarm i:nth-child(2){animation-delay:1.2s;}.activity-dot{position:absolute;right:8%;bottom:8%;width:18%;height:18%;min-width:4px;min-height:4px;border-radius:50%;background:var(--ripple-color,var(--hp-accent));border:1px solid color-mix(in srgb,var(--hp-bg) 82%,transparent);pointer-events:none;z-index:3;}.kioskdots{position:absolute;left:50%;bottom:var(--sp-5);transform:translateX(-50%);display:flex;gap:var(--sp-4);z-index:5;pointer-events:none;}.kdot{width:9px;height:9px;border-radius:50%;background:var(--hp-muted);opacity:0.55;}.kdot.on{background:var(--hp-accent);opacity:1;}.dev.valonly{width:var(--dev-size,var(--icon-size,2.5cqw));}.dev.valonly .device-core{width:max-content;min-width:var(--dev-size,var(--icon-size,2.5cqw));padding-inline:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.16);border-radius:calc(var(--dev-size,var(--icon-size,2.5cqw)) / 2);}.dev .valtext{overflow:visible;font-size:calc(var(--dev-size,var(--icon-size,2.5cqw)) * var(--value-font-scale,.45));font-weight:600;white-space:nowrap;}@media (prefers-reduced-motion:reduce){.device-pulse{display:none;}}.dev .newdot{position:absolute;top:calc(var(--dev-size,var(--icon-size,2.5cqw)) * -0.12);right:calc(var(--dev-size,var(--icon-size,2.5cqw)) * -0.12);width:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.34);height:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.34);border-radius:50%;background:#f0301f;border:2px solid var(--card-background-color,var(--hp-bg));pointer-events:none;z-index:2;}.dev{position:absolute;--dev-size:calc(var(--device-base-size,2.25cqw) * var(--dev-scale,1));--device-shell-size:calc(var(--dev-size) * 1.26875);--device-shell-inset:calc(var(--dev-size) * 0.134375);--device-shell-stroke-ratio:0.01875;--device-shell-border-width:max(1px,calc(var(--dev-size) * var(--device-shell-stroke-ratio)));--device-core-bg:var(--card-background-color,#fff);--device-core-fg:var(--primary-text-color,#252525);--device-core-bg:light-dark(#fff,#252525);--device-core-fg:light-dark(#252525,#fff);--device-face-bg:var(--device-core-bg);--device-face-fg:var(--device-core-fg);--device-shell-base-stroke:light-dark(#BCBCBC,rgb(37 37 37 / 75%));--device-shell-stroke:var(--device-shell-base-stroke);--device-shell-shadow:0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .05) rgb(37 40 45 / 12%),0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%);--device-core-inset-shadow:0 0 0 0 transparent;--device-ring-color:transparent;--device-ring-width:0px;width:var(--dev-size);height:var(--dev-size);margin:calc(var(--dev-size) / -2) 0 0 calc(var(--dev-size) / -2);border:0;background:transparent;display:block;color:var(--device-core-fg);cursor:pointer;pointer-events:none;transition:opacity 0.2s;box-shadow:none;outline:none;z-index:auto;}.dev.theme-light{--device-core-bg:#fff;--device-core-fg:#000;--device-shell-base-stroke:#BCBCBC;--device-shell-stroke:var(--device-shell-base-stroke);--device-shell-shadow:0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .05) rgb(37 40 45 / 12%),0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%);--device-core-inset-shadow:0 0 0 0 transparent;}.dev.theme-dark{--device-core-bg:#252525;--device-core-fg:#fff;--device-shell-base-stroke:rgb(37 37 37 / 75%);--device-shell-stroke:var(--device-shell-base-stroke);--device-shell-shadow:0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .0375) rgb(37 40 45 / 12%),0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%);--device-core-inset-shadow:inset 0 calc(var(--dev-size) * 0.0125) calc(var(--dev-size) * 0.0125) rgb(255 255 255 / 70%);}.dev::before{content:'';position:absolute;left:50%;top:50%;width:max(44px,var(--device-shell-size));height:max(44px,var(--device-shell-size));transform:translate(-50%,-50%);border-radius:50%;pointer-events:auto;z-index:1;}.device-shell{position:absolute;box-sizing:border-box;display:flex;align-items:center;gap:calc(var(--dev-size) * 0.1);padding:0;min-width:var(--dev-size);min-height:var(--dev-size);border:0;background:transparent;box-shadow:none;transition:opacity .2s;pointer-events:none;z-index:2;}.device-shell-frame{position:absolute;z-index:0;box-sizing:border-box;inset:calc(var(--device-shell-inset) / -1);border:var(--device-shell-border-width) solid var(--device-shell-stroke);border-radius:9999px;background:transparent;box-shadow:var(--device-shell-shadow);transition:border-color .15s,opacity .2s;pointer-events:auto;backdrop-filter:none;}.device-shell:not(.with-values){left:0;top:0;}.device-shell:not(.with-values):not(.text-shell) .device-shell-frame{border-radius:50%;}.device-shell.with-values.pos-right{left:0;top:50%;transform:translateY(-50%);}.device-shell.with-values.pos-left{right:0;top:50%;transform:translateY(-50%);flex-direction:row-reverse;}.device-shell.with-values.pos-bottom{left:50%;top:0;transform:translateX(-50%);flex-direction:column;}.device-shell.with-values.pos-top{left:50%;bottom:0;transform:translateX(-50%);flex-direction:column-reverse;}.device-core{position:relative;z-index:1;box-sizing:border-box;flex:0 0 auto;width:var(--dev-size);height:var(--dev-size);display:flex;align-items:center;justify-content:center;border-radius:50%;background:var(--device-face-bg);color:var(--device-face-fg);box-shadow:var(--device-core-inset-shadow),0 0 0 var(--device-ring-width) var(--device-ring-color);line-height:0;transition:background .15s,color .15s,opacity .2s;pointer-events:none;}.device-sections{display:flex;flex-direction:column;align-items:stretch;justify-content:center;gap:calc(var(--dev-size) * .08);min-width:0;pointer-events:none;}.device-shell.pos-top .device-sections,.device-shell.pos-bottom .device-sections{flex-direction:row;}.dev ha-icon{--mdc-icon-size:calc(var(--dev-size,var(--device-base-size,2.25cqw)) * 0.55);display:flex;align-items:center;justify-content:center;line-height:0;}.dev.on{--device-face-bg:#F0A00C;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:#F0A00C;}.dev.theme-light.on{--device-face-fg:#fff;}.dev.theme-dark.on{--device-face-fg:#252525;--device-shell-stroke-ratio:.0375;}.dev.open{--device-face-bg:var(--hp-open);--device-face-fg:light-dark(#fff,#252525);}.dev.theme-light.open{--device-face-fg:#fff;}.dev.theme-dark.open{--device-face-fg:#252525;}.dev.lock-locked{--device-face-bg:#66D17A;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:#66D17A;}.dev.theme-light.lock-locked{--device-face-fg:#fff;}.dev.theme-dark.lock-locked{--device-face-fg:#252525;--device-shell-stroke-ratio:.025;}.dev.lock-unlocked{--device-face-bg:#F0410C;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:#F0410C;}.dev.theme-light.lock-unlocked{--device-face-fg:#fff;}.dev.theme-dark.lock-unlocked{--device-face-fg:#252525;--device-shell-stroke-ratio:.025;}:host([data-pointer-hover]) .dev:not(.unavail)[data-hp-device-hover]{--device-face-bg:#0C82F0;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:var(--device-shell-base-stroke);}:host([data-pointer-hover]) .dev.theme-light:not(.unavail)[data-hp-device-hover]{--device-face-fg:#fff;}:host([data-pointer-hover]) .dev.theme-dark:not(.unavail)[data-hp-device-hover]{--device-face-fg:#252525;}:host([data-pointer-hover]) .dev[data-hp-device-hover],.dev:focus-visible{z-index:5;}.dev[data-hp-zigbee-topology-endpoint]{z-index:8;}:host([data-pointer-hover]) .dev[data-hp-zigbee-topology-endpoint][data-hp-device-hover]{z-index:8;}.dev.unavail{opacity:0.35;--device-face-bg:#B5BAC1;--device-shell-stroke:var(--device-shell-base-stroke);}.dev.virtual .device-shell-frame{border-style:dashed;}.dev.ghost{opacity:0.6;color:var(--hp-accent);}.dev.ghost .device-shell-frame{border-style:dashed;border-color:var(--hp-accent);box-shadow:none;}.dev.ghost .device-core{background:rgba(62,166,255,0.22);background:color-mix(in srgb,var(--hp-accent) 30%,var(--card-background-color,#1c2530));color:var(--hp-accent);}.dev.ghost.ha-disabled{opacity:0.62;color:var(--secondary-text-color,#9aa0aa);}.dev.ghost.ha-disabled .device-shell-frame{border-color:var(--secondary-text-color,#9aa0aa);}.dev.ghost.ha-disabled .device-core{background:rgba(120,124,134,0.2);background:color-mix(in srgb,var(--secondary-text-color,#9aa0aa) 24%,var(--card-background-color,#1c2530));color:var(--secondary-text-color,#9aa0aa);}.dev .habadge{position:absolute;right:-18%;bottom:-18%;display:grid;place-items:center;width:46%;height:46%;min-width:12px;min-height:12px;border-radius:50%;background:var(--card-background-color,#242832);border:1px solid currentColor;}.dev .habadge ha-icon{width:72%;height:72%;}.dev.sel{--device-ring-color:#F0A00C;--device-ring-width:calc(var(--dev-size) * 0.0375);}.dev:focus-visible{--device-ring-color:#0C82F0;--device-ring-width:calc(var(--dev-size) * 0.0375);}.dev:not(.on):not(.open):not(.alarm):not(.lock-locked):not(.lock-unlocked):not(.unavail):focus-visible{--device-face-fg:#0C82F0;}.dev.alarm,:host([data-pointer-hover]) .dev.alarm[data-hp-device-hover],.dev.alarm:focus-visible{--device-face-bg:#F0410C;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:#F0410C;}.dev.theme-light.alarm{--device-face-fg:#fff;}.dev.theme-dark.alarm{--device-face-fg:#252525;--device-shell-stroke-ratio:.025;}.dev .value-badge{position:relative;z-index:2;box-sizing:border-box;width:max-content;min-width:calc(var(--dev-size,var(--icon-size,2.5cqw)) * .7875);height:calc(var(--dev-size,var(--icon-size,2.5cqw)) * .7875);display:flex;align-items:center;justify-content:center;overflow:visible;background:var(--device-core-bg);border:0;border-radius:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.39375);padding:0 calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.14);font-size:calc(var(--dev-size,var(--icon-size,2.5cqw)) * var(--value-font-scale,.45));font-weight:600;line-height:1;color:var(--device-core-fg);white-space:nowrap;pointer-events:none;}.dev .value-badge.unavailable,.dev .value-badge.missing{opacity:0.66;}.dev .lqi{position:absolute;top:calc(50% + var(--device-shell-size) / 2 + var(--dev-size) * .05);left:50%;transform:translateX(-50%);margin-top:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.05);font-size:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.38);font-weight:600;line-height:1;text-shadow:0 0 3px rgba(0,0,0,0.9),0 0 2px rgba(0,0,0,0.9);white-space:nowrap;pointer-events:none;}.dev .lqi.below-value-badge{margin-top:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.8875);}.temprange{display:inline-flex;align-items:center;gap:var(--sp-3);margin-left:auto;color:var(--hp-muted);font-size:var(--fs-s);}.vacwarn{position:absolute;top:-12%;right:-12%;width:calc(var(--device-base-size,2.25cqw) * 0.42);height:calc(var(--device-base-size,2.25cqw) * 0.42);border-radius:50%;display:flex;align-items:center;justify-content:center;background:light-dark(#fff,#252525);border:1px solid #E5A100;color:#E5A100;z-index:7;pointer-events:none;}.vacwarn ha-icon{--mdc-icon-size:calc(var(--device-base-size,2.25cqw) * 0.32);color:inherit;}.vacpuck{position:absolute;--puck-size:calc(var(--device-base-size,2.25cqw) * 0.8);width:var(--puck-size);height:var(--puck-size);border-radius:50%;transform:translate(-50%,-50%);--vac-core-bg:light-dark(#fff,#252525);--vac-core-fg:light-dark(#252525,#fff);background:var(--vac-core-bg);border:1px solid #BCBCBC;box-shadow:0 1px 2px rgb(37 40 45 / 12%),0 4px 8px -1.07px rgb(37 40 45 / 18%);color:var(--vac-core-fg);display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:6;transition:left 1.2s linear,top 1.2s linear;animation:vacpulse 2.2s ease-out infinite;}.vacpuck.theme-light{--vac-core-bg:#fff;--vac-core-fg:#252525;}.vacpuck.theme-dark{--vac-core-bg:#252525;--vac-core-fg:#fff;}.vacpuck.jump{transition:none;}.vacpuck.stale{opacity:0.45;animation:none;}.vacpuck ha-icon{--mdc-icon-size:calc(var(--puck-size) * 0.68);color:var(--vac-core-fg);display:flex;align-items:center;justify-content:center;line-height:0;width:var(--mdc-icon-size);height:var(--mdc-icon-size);}@keyframes vacpulse{0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--hp-accent) 45%,transparent);}70%{box-shadow:0 0 0 12px transparent;}100%{box-shadow:0 0 0 0 transparent;}}@media (prefers-reduced-motion:reduce){.vacpuck{animation:none;}}.vactrail{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:5;overflow:visible;}.vactrail polyline,.vactrail path{fill:none;stroke-linejoin:round;stroke-linecap:round;vector-effect:non-scaling-stroke;}.vactrail g.prev{opacity:0.4;}.vactrail .case{stroke:rgba(0,0,0,0.4);stroke-width:2.25;}.vactrail .core{stroke:rgba(255,255,255,0.82);stroke-width:0.9;}.devicepreview-empty{min-height:82px;margin:4px 0 14px;padding:var(--sp-4);display:flex;align-items:center;justify-content:center;gap:var(--sp-3);border:1px dashed var(--hp-line);border-radius:var(--rad-m);color:var(--hp-muted);text-align:center;}`,o`.hdr{position:sticky;top:var(--header-height,56px);z-index:20;background:var(--card-background-color,var(--hp-bg));border-radius:var(--ha-card-border-radius,12px) var(--ha-card-border-radius,12px) 0 0;}.tabs{display:flex;gap:var(--sp-2);background:rgba(127,127,127,0.12);padding:var(--sp-2);border-radius:var(--rad-l);flex-wrap:wrap;}.tab{border:0;background:transparent;color:var(--hp-muted);display:inline-flex;align-items:center;padding:var(--sp-3) var(--sp-5);border-radius:var(--rad-m);font-size:var(--fs-m);font-weight:600;cursor:pointer;transition:0.15s;font-family:inherit;}:host([data-pointer-hover]) .tab:hover{color:var(--hp-txt);}.tab.active{background:var(--hp-accent);color:var(--text-primary-color,#fff);}.farhint{position:absolute;left:50%;transform:translateX(-50%);bottom:var(--sp-4);z-index:12;display:flex;align-items:center;gap:var(--sp-2);max-width:calc(100% - var(--sp-8));background:var(--card-background-color,var(--hp-bg));opacity:0.94;color:var(--hp-txt);border:1px solid var(--divider-color,#33404d);border-radius:var(--rad-m);padding:var(--sp-1) var(--sp-3);font-size:var(--fs-s);}.farhint ha-icon{--mdc-icon-size:18px;color:var(--hp-warn,#e2a03f);flex:none;}.farhint span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.dropbtn{display:flex;align-items:center;gap:var(--sp-4);width:100%;text-align:left;border:1px solid var(--hp-muted);border-radius:var(--rad-m);background:transparent;color:var(--hp-txt);padding:var(--sp-4) 10px;cursor:pointer;font-family:inherit;font-size:var(--fs-m);margin-top:var(--sp-3);}.dropbtn .ref{color:var(--hp-muted);font-size:var(--fs-s);margin-left:auto;}.dropbtn ha-icon{--mdc-icon-size:18px;margin-left:var(--sp-2);}.dropbtn.open{border-color:var(--hp-accent);}.droppanel{border:1px solid var(--hp-accent);border-top:none;border-radius:0 0 var(--rad-m) var(--rad-m);padding:var(--sp-3);margin-top:-4px;}.hdr.kioskhide{display:none;}.decorbar .dcolor{width:30px;height:26px;padding:0;border:none;background:none;cursor:pointer;}.decorbar .dwidth{font-family:inherit;font-size:var(--fs-s);border-radius:var(--rad-s);background:var(--hp-bg2,transparent);color:var(--hp-txt);border:1px solid var(--hp-muted);padding:var(--sp-2) var(--sp-3);}.decorbar .bdhint{font-size:var(--fs-s);color:var(--hp-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.decorbar .dfill{display:inline-flex;align-items:center;gap:var(--sp-2);font-size:var(--fs-s);cursor:pointer;}.decorbar .dfill input[type="checkbox"]{width:16px;height:16px;flex:none;margin:0;padding:0;}.decorbar hp-color-opacity{flex:0 0 auto;}.modes{display:inline-flex;gap:var(--sp-1);background:rgba(127,127,127,0.12);border-radius:var(--rad-l);padding:var(--sp-2);}.modetab{display:inline-flex;align-items:center;gap:var(--sp-3);border:0;background:transparent;color:var(--hp-muted);padding:var(--sp-3) 10px;border-radius:var(--rad-m);font-size:var(--fs-m);font-weight:600;cursor:pointer;font-family:inherit;transition:background-color 0.14s ease,color 0.14s ease,transform 0.14s ease;}.modetab:active{transform:scale(0.97);}.modetab ha-icon{--mdc-icon-size:15px;}.tab[data-reorderable]{cursor:grab;}.tab.dragging{cursor:grabbing;opacity:0.55;}.tab.drop-before{box-shadow:inset 2px 0 0 0 var(--primary-color,#03a9f4);}.tab.drop-after{box-shadow:inset -2px 0 0 0 var(--primary-color,#03a9f4);}.modetab .closex{--mdc-icon-size:13px;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;min-width:24px;min-height:24px;margin:-5.5px -5.5px -5.5px -3.5px;opacity:0.75;cursor:pointer;border-radius:var(--rad-s);}:host([data-pointer-hover]) .modetab .closex:hover{opacity:1;}.editbar .barclose{box-sizing:border-box;width:40px;height:40px;padding:0;margin:0;min-width:40px;min-height:40px;justify-content:center;gap:0;line-height:0;}.editbar .barclose ha-icon{flex:none;margin:0;}.modetab.active{background:var(--hp-accent);color:var(--text-primary-color,#fff);}@media (max-width:720px){.modetab .ml{display:none;}}.editbar{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:stretch;border-bottom:1px solid var(--hp-line);font-size:var(--fs-m);}.editbar-tools{display:flex;align-items:center;gap:10px;padding:var(--sp-4) var(--sp-5);flex-wrap:wrap;min-width:0;outline:none;}.editbar-end{display:flex;align-items:center;padding:var(--sp-4) var(--sp-5);border-inline-start:1px solid var(--hp-line);background:var(--card-background-color,var(--hp-bg));position:relative;z-index:2;}.tab .tabedit{--mdc-icon-size:13px;display:inline-flex;align-items:center;margin-left:var(--sp-3);opacity:0.4;}:host([data-pointer-hover]) .tab:hover .tabedit{opacity:0.9;}.tab.tabadd{padding:var(--sp-3) var(--sp-4);}.tab.tabadd ha-icon{--mdc-icon-size:15px;}.rhint{font-size:var(--fs-s);color:var(--hp-muted);margin-bottom:var(--sp-3);}.editorchrome{display:block;height:0;opacity:0;visibility:hidden;overflow:hidden;}.editorchrome:not(.open){pointer-events:none;}.editorchrome.open{height:auto;opacity:1;visibility:visible;overflow:visible;}.editorchrome.transitioning{overflow:hidden;will-change:height;pointer-events:none;}.editorchrome.transitioning .barclose{pointer-events:auto;}.editorchrome-inner{min-height:0;transform-origin:top center;}.editorchrome.transitioning .editorchrome-inner{will-change:opacity;}@media (prefers-reduced-motion:reduce){.modetab{transition:none;}}.editbar .warn{color:#ffc14d;}.editbar .sname{font-weight:600;}.editbar input{width:74px;background:transparent;border:1px solid var(--hp-line);color:var(--hp-txt);border-radius:var(--rad-s);padding:var(--sp-3) var(--sp-4);font-size:var(--fs-m);}.editbar label,.editbar .hint{color:var(--hp-muted);font-size:var(--fs-s);}.editbar .drawwall{display:inline-flex;align-items:center;gap:var(--sp-3);white-space:nowrap;}.editbar .wallsgroup{display:inline-flex;align-items:center;gap:10px;white-space:nowrap;}.editbar .drawwall input{width:4.2em;}.editbar .drawwall .opl{color:var(--hp-muted);font-size:var(--fs-s);}.menuwrap{position:fixed;inset:0;z-index:80;}.menu{position:fixed;background:var(--hp-bg);border:1px solid var(--hp-accent);border-radius:var(--rad-l);box-shadow:var(--shadow-2);min-width:210px;max-width:300px;overflow:hidden;transform:translate(0,8px);}.menu .hd{padding:var(--sp-4) var(--sp-5);font-weight:600;font-size:var(--fs-m);border-bottom:1px solid var(--hp-line);display:flex;align-items:center;gap:var(--sp-3);}.menu .hd ha-icon,.menu .it.all ha-icon{color:var(--hp-accent);--mdc-icon-size:16px;}.menu .it{padding:var(--sp-4) var(--sp-5);font-size:var(--fs-m);cursor:pointer;display:flex;align-items:center;gap:var(--sp-4);}.menu .it ha-icon{--mdc-icon-size:16px;color:var(--hp-muted);}:host([data-pointer-hover]) .menu .it:hover{background:rgba(127,127,127,0.15);}.menu .it.all{color:var(--hp-accent);font-weight:600;}.tip{position:fixed;pointer-events:none;background:var(--hp-bg);border:1px solid var(--hp-accent);color:var(--hp-txt);padding:var(--sp-3) 10px;border-radius:var(--rad-m);font-size:var(--fs-m);box-shadow:var(--shadow-2);z-index:60;max-width:260px;}.tip .m{color:var(--hp-muted);font-size:var(--fs-s);display:block;}`,o`.head{display:flex;align-items:center;gap:10px;padding:10px var(--sp-5);border-bottom:1px solid var(--hp-line);flex-wrap:wrap;}.title{font-size:var(--fs-l);font-weight:600;display:flex;align-items:center;gap:var(--sp-3);white-space:nowrap;}.title ha-icon{color:var(--hp-accent);--mdc-icon-size:18px;}@media (max-width:1100px){.head .count{display:none;}}@media (max-width:620px){.head{gap:var(--sp-3);padding:var(--sp-4) 10px;}.head .title{font-size:var(--fs-m);}}.count{font-size:var(--fs-s);color:var(--hp-muted);}.btn{display:inline-flex;align-items:center;gap:var(--sp-3);border:1px solid var(--hp-line);background:transparent;color:var(--hp-txt);padding:var(--sp-3) 10px;border-radius:var(--rad-m);cursor:pointer;transition:0.15s;font-family:inherit;font-size:var(--fs-m);}.btn ha-icon{--mdc-icon-size:17px;}:host([data-pointer-hover]) .btn:hover{border-color:var(--hp-accent);}.btn.on{background:var(--hp-accent);color:var(--text-primary-color,#fff);border-color:var(--hp-accent);}.btn.ghost{border:none;}.btn[disabled]{opacity:0.5;pointer-events:none;}.recoveryoverlay{position:absolute;inset:0;z-index:75;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--sp-4);padding:var(--sp-6);box-sizing:border-box;background:linear-gradient(var(--ha-card-background,var(--card-background-color,#111)),var(--ha-card-background,var(--card-background-color,#111))),#111;color:var(--primary-text-color,#fff);text-align:center;pointer-events:auto;transition:opacity 0.15s ease;}.recoveryoverlay.phase-entering,.recoveryoverlay.phase-leaving{opacity:0;}.recoveryoverlay.phase-fading-in,.recoveryoverlay.phase-opaque{opacity:1;}.recoveryoverlay ha-icon{--mdc-icon-size:44px;color:var(--hp-accent);}.editorloading{position:absolute;z-index:74;left:50%;top:50%;display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-5);border:1px solid color-mix(in srgb,var(--hp-accent) 45%,transparent);border-radius:999px;background:color-mix(in srgb,var(--ha-card-background,var(--card-background-color,#111)) 92%,transparent);color:var(--primary-text-color);box-shadow:0 6px 22px rgb(0 0 0 / 18%);transform:translate(-50%,-50%);pointer-events:none;animation:editor-loading-in 0.15s ease both;}.editorloading ha-icon{--mdc-icon-size:22px;color:var(--hp-accent);animation:editor-loading-spin 0.9s linear infinite;}@keyframes editor-loading-in{from{opacity:0;transform:translate(-50%,calc(-50% + 4px));}to{opacity:1;transform:translate(-50%,-50%);}}@keyframes editor-loading-spin{to{transform:rotate(360deg);}}@media (prefers-reduced-motion:reduce){.recoveryoverlay,.editorloading,.editorloading ha-icon{transition:none;animation:none;}}.oplock{--oplock-size:calc(var(--icon-size,2.5cqw) * 0.62);--oplock-core-size:calc(var(--oplock-size) / 1.26875);--oplock-stroke-ratio:0.01875;--oplock-stroke-width:max(1px,calc(var(--oplock-core-size) * var(--oplock-stroke-ratio)));--oplock-core-bg:light-dark(#fff,#252525);--oplock-core-fg:light-dark(#252525,#fff);--oplock-shell-stroke:light-dark(#BCBCBC,rgb(37 37 37 / 75%));--oplock-shell-shadow:0 calc(var(--oplock-core-size) * .025) calc(var(--oplock-core-size) * .05) rgb(37 40 45 / 12%),0 calc(var(--oplock-core-size) * .1) calc(var(--oplock-core-size) * .175) calc(var(--oplock-core-size) * -.025) rgb(37 40 45 / 18%);--oplock-core-shadow:0 0 0 0 transparent;pointer-events:none;position:absolute;transform:translate(-50%,-50%);width:var(--oplock-size);height:var(--oplock-size);display:grid;place-items:center;border:0;background:transparent;z-index:1;}.oplock.theme-light{--oplock-core-bg:#fff;--oplock-core-fg:#252525;--oplock-shell-stroke:#BCBCBC;}.oplock.theme-dark{--oplock-core-bg:#252525;--oplock-core-fg:#fff;--oplock-shell-stroke:rgb(37 37 37 / 75%);--oplock-core-shadow:inset 0 calc(var(--oplock-core-size) * .0125) calc(var(--oplock-core-size) * .0125) rgb(255 255 255 / 70%);}.oplock-shell{box-sizing:border-box;width:100%;height:100%;border:var(--oplock-stroke-width) solid var(--oplock-shell-stroke);border-radius:50%;background:transparent;box-shadow:var(--oplock-shell-shadow);display:grid;place-items:center;pointer-events:none;backdrop-filter:none;}.oplock-core{width:var(--oplock-core-size);height:var(--oplock-core-size);border-radius:50%;background:var(--oplock-core-bg);color:var(--oplock-core-fg);box-shadow:var(--oplock-core-shadow);display:grid;place-items:center;pointer-events:none;}.oplock ha-icon{--mdc-icon-size:calc(var(--oplock-core-size) * 0.55);display:flex;line-height:0;}.oplock.locked{--oplock-core-bg:#66D17A;--oplock-core-fg:light-dark(#fff,#252525);--oplock-shell-stroke:#66D17A;}.oplock.theme-light.locked{--oplock-core-fg:#fff;}.oplock.theme-dark.locked{--oplock-core-fg:#252525;--oplock-stroke-ratio:.025;}.oplock.unlocked{--oplock-core-bg:#F0410C;--oplock-core-fg:light-dark(#fff,#252525);--oplock-shell-stroke:#F0410C;}.oplock.theme-light.unlocked{--oplock-core-fg:#fff;}.oplock.theme-dark.unlocked{--oplock-core-fg:#252525;--oplock-stroke-ratio:.025;}.oplock.unknown{--oplock-core-fg:var(--hp-muted);}.btn.lockact{width:100%;justify-content:center;display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-4);}.btn.lockact.warn{color:var(--error-color,#d33);border-color:var(--error-color,#d33);}.oprow{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-3) 0;}.oprow b{margin-left:auto;}.oprow.ok b{color:#66d17a;}.oprow.warn b{color:var(--hp-open);}.ctrlstates{display:flex;flex-direction:column;gap:var(--sp-2);}.ctrlstate{display:inline-flex;align-items:center;gap:var(--sp-3);color:var(--hp-muted);}.ctrlstate.on{color:var(--hp-txt);}.ctrlstate ha-icon{--mdc-icon-size:15px;}.cardpreview{display:flex;flex-direction:column;align-items:center;gap:var(--sp-2);margin:var(--sp-4) 0 var(--sp-1);padding:10px;border:1px dashed var(--hp-muted);border-radius:var(--rad-m);}.cardpreview .cpname{font-weight:700;letter-spacing:0.04em;}.cardpreview .cpmeta{display:inline-flex;align-items:center;gap:0.3em;font-weight:600;opacity:0.85;}.cardpreview .cpmeta ha-icon{--mdc-icon-size:1.05em;}hp-dialog .dfill{display:inline-flex;align-items:center;gap:var(--sp-3);cursor:pointer;}.wallthick-dlg{position:absolute;z-index:40;min-width:200px;transform:translate(-50%,8px);padding:10px 12px;border-radius:10px;background:var(--card-background-color,#fff);box-shadow:0 8px 28px rgba(0,0,0,.22);display:flex;flex-direction:column;gap:8px;pointer-events:auto;}.wallthick-dlg .row{display:flex;align-items:center;gap:8px;}.wallthick-dlg input[type="number"]{width:5.5em;padding:4px 6px;border:1px solid var(--divider-color,#ccc);border-radius:6px;background:var(--input-fill,transparent);color:var(--primary-text-color);}.areasel,.namein{background:var(--hp-bg);border:1px solid var(--hp-line);color:var(--hp-txt);border-radius:var(--rad-s);padding:var(--sp-3) var(--sp-4);font-size:var(--fs-m);font-family:inherit;}.namein{width:130px;}.habindingbanner{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);margin-bottom:var(--sp-4);border:1px solid var(--warning-color,#ff9800);border-radius:var(--rad-m);background:color-mix(in srgb,var(--warning-color,#ff9800) 12%,transparent);color:var(--primary-text-color,#f1f3f6);}.habindingbanner>span{flex:1;min-width:0;}.habindingbanner>ha-icon{color:var(--warning-color,#ff9800);flex:0 0 auto;}.habindingbanner.limited{border-color:var(--secondary-text-color,#9aa0aa);background:color-mix(in srgb,var(--secondary-text-color,#9aa0aa) 10%,transparent);}.habindingbanner.limited>ha-icon{color:var(--secondary-text-color,#9aa0aa);}.srcrow{display:flex;align-items:center;gap:var(--sp-4);font-size:var(--fs-m);cursor:pointer;padding:var(--sp-1) 0;}.dispsection{margin-top:var(--sp-5) !important;padding-top:var(--sp-4);border-top:1px solid var(--hp-line);font-weight:600;color:var(--hp-txt) !important;}.colorrow{display:flex;align-items:center;gap:var(--sp-4);}.colorrow input[type='range']{flex:1;}.colorrow .tempin{width:70px;flex:none;}hp-dialog .body .temprange .tempin{width:56px;flex:none;padding:var(--sp-2) var(--sp-3);}hp-dialog .body .colorrow .tempin{width:72px;flex:none;}.srcrow{flex-wrap:nowrap;}.srcrow ha-switch{flex:none;}.colorrow ha-slider{flex:1;min-width:0;}.srcrow>span:first-of-type{white-space:nowrap;}.colorrow .opl{color:var(--hp-muted);font-size:var(--fs-s);}.colorrow .opv{font-size:var(--fs-s);min-width:34px;text-align:right;}.markerlightgroup{min-width:0;margin:var(--sp-5) 0 0;padding:var(--sp-4);border:1px solid var(--hp-line);border-radius:var(--rad-m);}.markerlightgroup legend{display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-1);padding:0 var(--sp-2);color:var(--hp-txt);font-weight:600;}.markerlightgroup legend>span{min-width:0;overflow-wrap:anywhere;}.markerlightgroup[disabled]>:not(legend){opacity:.62;}.radargroup{display:grid;gap:var(--sp-2);}.radargroup>p{margin:0;}.radargroup>label:not(.srcrow){margin-top:var(--sp-2);}.radarcoordinates{align-items:flex-end;flex-wrap:wrap;}.radarcoordinates>label{display:grid;flex:1 1 92px;gap:var(--sp-1);min-width:0;margin:0;}hp-dialog .body .radarcoordinates .tempin{box-sizing:border-box;width:100%;}.radarinspection{display:grid;gap:6px;padding:10px 12px;border-radius:10px;background:color-mix(in srgb,var(--primary-color) 7%,transparent);}.radarinspection code{overflow-wrap:anywhere;font-size:12px;}.radarsetup{display:grid;gap:10px;margin-top:10px;padding:12px;border:1px solid var(--hp-accent);border-radius:var(--rad-m);background:color-mix(in srgb,var(--secondary-background-color) 88%,transparent);}.radarsetup-head{display:flex;align-items:center;gap:8px;}.radarsetup-head strong{flex:1;}.radarsetup>svg{width:min(100%,460px);aspect-ratio:1;justify-self:center;border-radius:var(--rad-m);background:var(--primary-background-color);touch-action:none;cursor:crosshair;}.radarsetup .room{fill:color-mix(in srgb,var(--hp-accent) 8%,transparent);stroke:var(--divider-color);stroke-width:3;vector-effect:non-scaling-stroke;}.radarsetup .heading{stroke:var(--hp-accent);stroke-width:4;vector-effect:non-scaling-stroke;}.radarsetup .trail{fill:none;stroke:var(--success-color,#43a047);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke;opacity:.55;}.radarsetup g circle{fill:var(--hp-bg);stroke:var(--hp-accent);stroke-width:3;vector-effect:non-scaling-stroke;}.radarsetup g.pending circle{stroke-dasharray:5 4;}.radarsetup g text{fill:var(--hp-txt);font-size:22px;font-weight:700;text-anchor:middle;dominant-baseline:middle;pointer-events:none;}.help-inline-label{display:inline-flex;align-items:center;flex-wrap:wrap;gap:var(--sp-1);}hp-dialog .body .help-inline-label>label{min-width:0;margin-top:0;overflow-wrap:anywhere;}.markerlightgroup .srcrow>span:first-of-type{min-width:0;white-space:normal;overflow-wrap:anywhere;}.planrow{display:flex;align-items:center;gap:10px;}.savedplans{display:flex;flex-direction:column;gap:var(--sp-3);max-height:240px;overflow:auto;margin:var(--sp-3) 0 var(--sp-1);padding:var(--sp-3);border:1px solid var(--hp-line);border-radius:var(--rad-m);background:var(--hp-bg2,rgba(255,255,255,0.03));flex:0 0 auto;min-height:2.6em;}.savedplan{display:flex;align-items:center;gap:10px;}.savedplan.cur{outline:1px solid var(--hp-accent);border-radius:var(--rad-s);}.savedplan img{width:56px;height:40px;object-fit:contain;border:1px solid var(--hp-line);border-radius:var(--rad-s);background:#fff;flex:none;}.savedmeta{display:flex;flex-direction:column;min-width:0;flex:1;}.savedmeta b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.savedmeta .muted{font-size:var(--fs-s);}.savedplan .btn.danger ha-icon{color:#f25a4a;}.savedplan .btn[disabled]{opacity:0.4;pointer-events:none;}.planprev{max-width:120px;max-height:70px;border:1px solid var(--hp-line);border-radius:var(--rad-s);background:#fff;}.planname{font-size:var(--fs-m);max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.planname.muted{color:var(--hp-muted);}.filebtn{cursor:pointer;}.btn.danger{border-color:#b3402a;color:#ff7a5c;}hp-dialog .row .spacer{flex:1;}hp-dialog .body{max-height:66vh;overflow-y:auto;}hp-dialog[form-shell] .body{max-height:none;overflow:visible;padding:16px;box-sizing:border-box;}@media (max-width:480px){hp-dialog[form-shell] .body{padding:12px;}}hp-confirm{display:contents;}hp-dialog .danger-confirm-body{display:flex;flex-direction:column;gap:var(--sp-4);}hp-dialog .danger-confirm-body p{margin:0;line-height:1.45;}hp-dialog .danger-confirm-object{overflow-wrap:anywhere;font-size:var(--fs-l);line-height:1.3;}.curbind{display:flex;align-items:center;gap:var(--sp-3);font-size:var(--fs-m);color:var(--hp-txt);flex-wrap:wrap;}.curbind .ref{color:var(--hp-muted);font-size:var(--fs-s);}.vacbox .vacbtns{display:flex;gap:var(--sp-4);margin:var(--sp-3) 0;flex-wrap:wrap;}.vacdiag{display:grid;gap:4px;margin-bottom:var(--sp-3);}.vacdiag>div{display:flex;justify-content:space-between;gap:var(--sp-5);}.vacdiag>div>span{color:var(--secondary-text-color);}.vacdiag>div>b{text-align:right;overflow-wrap:anywhere;}.vacroute-missing-group{margin-top:var(--sp-4);padding-top:var(--sp-4);border-top:1px solid var(--hp-line);}.vacroute-group-title{margin:0 0 var(--sp-3);color:var(--secondary-text-color);font-size:var(--fs-m);font-weight:600;}.vacroute-missing-group .vacroute-list{margin-top:0;}.vacpicker{margin:var(--sp-3) 0;}.vacsource-warning{display:grid;gap:8px;}.vacsource-warning .btn{justify-self:start;}.vacpicker>summary{display:inline-flex;width:auto;list-style:none;cursor:pointer;}.vacpicker>summary::-webkit-details-marker{display:none;}.vacsource-list{display:grid;gap:6px;margin-top:8px;}.vacsource-list details{padding:6px 0 0;}.vacsource-list details>summary{cursor:pointer;font-weight:600;}.vacsource{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;min-width:0;padding:9px 10px;border:1px solid var(--divider-color);border-radius:10px;color:var(--primary-text-color);background:var(--secondary-background-color);text-align:left;cursor:pointer;}.vacsource.on{border-color:var(--accent-color);box-shadow:inset 3px 0 var(--accent-color);}.vacsource>span:first-child{min-width:0;display:grid;gap:2px;}.vacsource small{color:var(--secondary-text-color);overflow-wrap:anywhere;}.vacsource-meta{color:var(--secondary-text-color);text-align:right;font-size:0.82em;}.vacxcme pre{margin:8px 0 0;white-space:pre-wrap;user-select:text;}.vacfit{position:absolute;inset:0;width:100%;height:100%;z-index:12;overflow:visible;touch-action:none;cursor:grab;pointer-events:auto;}.vacfit:active{cursor:grabbing;}.vacfit polygon{fill:color-mix(in srgb,var(--hp-accent) 16%,transparent);stroke:var(--hp-accent);stroke-width:2;vector-effect:non-scaling-stroke;stroke-dasharray:6 4;}.vacfit text{fill:var(--hp-accent);font-size:26px;text-anchor:middle;dominant-baseline:middle;pointer-events:none;user-select:none;}.furnpalette{display:flex;flex-direction:column;max-height:38vh;border-top:1px solid var(--hp-border,rgba(255,255,255,0.12));background:var(--card-background-color,var(--hp-bg));font-size:0.85em;}.furnhd{display:flex;align-items:center;gap:6px;padding:4px 8px;font-weight:600;opacity:0.9;}.furnhd .spacer{flex:1;}.furnbody{overflow:auto;padding:0 8px 6px;}.furngroup{margin:6px 0 3px;font-size:0.85em;text-transform:uppercase;letter-spacing:0.04em;opacity:0.6;}.furnrow{display:flex;flex-wrap:wrap;gap:4px;}.furnback{min-height:34px;gap:5px;margin:2px 0 4px;}.furnitem{display:flex;flex-direction:column;align-items:center;gap:2px;width:74px;padding:4px 2px;border:1px solid transparent;border-radius:8px;background:rgba(127,127,127,0.08);color:inherit;font:inherit;font-size:0.8em;line-height:1.15;text-align:center;cursor:pointer;}:host([data-pointer-hover]) .furnitem:hover{background:rgba(127,127,127,0.18);}.furnitem.on{border-color:var(--hp-accent);background:rgba(38,166,154,0.18);}.furnprev{width:40px;height:40px;color:var(--primary-text-color,currentColor);}.furncategory{width:92px;min-height:76px;}.furncatprev{width:48px;height:48px;}.furnvariants .furnitem{min-height:74px;}.furnsize{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:6px 8px;border-top:1px solid var(--hp-border,rgba(255,255,255,0.12));}.furnsize label{display:flex;align-items:baseline;gap:3px;opacity:0.8;}.furnsize .furnunit{opacity:0.6;font-size:0.85em;}.furnsize input{width:5.5em;padding:3px 5px;}.furnhint{opacity:0.6;}.imageupload{display:inline-flex;gap:6px;margin:4px 0 8px;cursor:pointer;}.imageupload.disabled{opacity:0.55;pointer-events:none;}.imageupload input{display:none;}.imageassets{align-items:stretch;}.imageempty{padding:12px 6px;}.imageasset{position:relative;}.imageasset .furnitem{width:104px;min-height:92px;}.imageasset img{width:64px;height:54px;object-fit:contain;border-radius:4px;background:repeating-conic-gradient(#ddd 0 25%,#fff 0 50%) 50% / 12px 12px;}.imageasset .furnitem span{max-width:96px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.imageasset .furnitem small{opacity:0.65;font-size:0.72em;}.imageassetdelete{position:absolute;top:0;right:0;min-width:30px;width:30px;min-height:30px;padding:3px;}.imagepropertypreview{display:flex;align-items:center;gap:10px;min-width:0;}.imagepropertypreview img{width:72px;height:54px;object-fit:contain;border-radius:4px;background:repeating-conic-gradient(#ddd 0 25%,#fff 0 50%) 50% / 12px 12px;}.imagepropertypreview span{overflow-wrap:anywhere;}.vacfitdot{fill:var(--hp-accent);pointer-events:none;}.vacfithandle{fill:transparent;stroke:none;cursor:nwse-resize;}.vacfitknob{fill:var(--hp-bg);stroke:var(--hp-accent);stroke-width:2;vector-effect:non-scaling-stroke;pointer-events:none;}.vaccalbar{position:fixed;left:50%;bottom:24px;transform:translateX(-50%);display:flex;gap:var(--sp-5);align-items:center;background:var(--hp-bg);color:var(--hp-txt);border:1px solid var(--hp-accent);border-radius:var(--rad-l);padding:10px var(--sp-5);z-index:60;box-shadow:var(--shadow-2);}.candlist{max-height:160px;overflow-y:auto;border-top:1px solid var(--hp-line);flex:0 0 auto;min-height:2.6em;}.cand{display:flex;justify-content:space-between;gap:var(--sp-4);padding:var(--sp-3) var(--sp-4);cursor:pointer;border-radius:var(--rad-s);font-size:var(--fs-m);}:host([data-pointer-hover]) .cand:hover{background:rgba(127,127,127,0.15);}.cand.sel{background:var(--hp-accent);color:var(--text-primary-color,#fff);}.cand .cs{color:var(--hp-muted);font-size:var(--fs-s);white-space:nowrap;}.opening-entity-candidate{width:100%;border:0;background:transparent;color:inherit;font:inherit;text-align:left;}.opening-entity-candidate.sel{background:var(--hp-accent);color:var(--text-primary-color,#fff);}.opening-entity-empty{cursor:default;}.cand.sel .cs{color:var(--text-primary-color,#fff);opacity:0.85;}.cand.muted{color:var(--hp-muted);cursor:default;}.entlist{display:flex;flex-direction:column;gap:var(--sp-2);margin-bottom:10px;}.entrow{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-3) var(--sp-4);border-radius:var(--rad-m);background:var(--secondary-background-color,rgba(128,128,128,0.12));}.entrow ha-icon{--mdc-icon-size:20px;color:var(--hp-muted);}.entrow.on ha-icon{color:var(--hp-accent);}.entrow .en{flex:1;font-size:var(--fs-m);}.entrow .ev{font-size:var(--fs-m);color:var(--hp-muted);}.entbtn{min-width:74px;min-height:32px;padding:var(--sp-2) var(--sp-5);border:1px solid var(--hp-muted);border-radius:999px;background:transparent;color:var(--hp-txt);font:inherit;font-size:var(--fs-m);cursor:pointer;}.entbtn.on{background:var(--hp-accent);border-color:var(--hp-accent);color:var(--text-primary-color,#fff);font-weight:600;}.inforow{display:flex;gap:10px;font-size:var(--fs-m);margin:var(--sp-2) 0;}.inforow .k{color:var(--hp-muted);min-width:84px;}.inforow a{color:var(--hp-accent);word-break:break-all;}.infodesc{font-size:var(--fs-m);white-space:pre-wrap;margin-top:var(--sp-3);}.infodesc.muted{color:var(--hp-muted);}.pdflist{display:flex;flex-direction:column;gap:var(--sp-2);}.pdf{display:inline-flex;align-items:center;gap:var(--sp-2);color:var(--hp-accent);text-decoration:none;}ha-icon-picker{display:block;}.floorrow{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-3) var(--sp-2);font-size:var(--fs-m);cursor:pointer;}.floorrow .floorlvl{color:var(--hp-muted);font-size:var(--fs-s);border:1px solid var(--hp-line);border-radius:var(--rad-s);padding:0 var(--sp-3);}.rtest{display:flex;align-items:center;gap:var(--sp-4);margin-bottom:var(--sp-4);}.rtest .namein{flex:1;}.rtest ha-icon{color:var(--hp-accent);}.rtesticon{font-size:var(--fs-s);color:var(--hp-muted);}.rrow{display:flex;align-items:center;gap:var(--sp-3);margin:var(--sp-1) 0;}.rrow .rpat{flex:2;}.rrow .ricon{flex:1.4;}.rrow .rpat.bad{border-color:#ff7a5c;}.rrow .rprev{--mdc-icon-size:18px;color:var(--hp-txt);min-width:18px;}.rrow .ract{--mdc-icon-size:16px;color:var(--hp-muted);cursor:pointer;}:host([data-pointer-hover]) .rrow .ract:hover{color:var(--hp-txt);}:host([data-pointer-hover]) .rrow .ract.del:hover{color:#ff7a5c;}.optimize-live{display:grid;justify-items:start;gap:var(--sp-2);margin-bottom:var(--sp-3);}.optimize-live .alignmsg,.optimize-live .rhint{margin-bottom:0;}.optimize-cleanup{min-height:44px;}.optimize-selected{color:var(--hp-txt);}.optimize-details{margin-top:var(--sp-3);color:var(--hp-muted);font-size:var(--fs-s);overflow-wrap:anywhere;}.optimize-details>summary{width:fit-content;color:var(--hp-txt);cursor:pointer;font-weight:600;}.optimize-details>summary:focus-visible{outline:2px solid var(--hp-accent);outline-offset:3px;border-radius:var(--rad-s);}.optimize-details ul{margin:var(--sp-3) 0;padding-inline-start:22px;}.optimize-details li + li{margin-top:var(--sp-1);}.btn.alignall{width:100%;justify-content:center;}.backupactions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-3);}.backupactions .btn{justify-content:center;min-width:0;}.backupupload{display:inline-flex;min-width:0;}.backupupload>.btn{width:100%;justify-content:center;}.backupupload input{display:none;}.backupbody{min-width:0;}.backupplanonly{margin-inline-start:var(--sp-4) !important;align-items:flex-start !important;}.backupplanonly>span:first-of-type{display:grid;gap:2px;white-space:normal;}.backupplanonly small{color:var(--secondary-text-color);line-height:1.35;}.backupplanonlystatus{color:var(--hp-accent) !important;font-weight:700;}.backupfile,.backupsummary,.backupcontent{display:flex;flex-direction:column;min-width:0;gap:var(--sp-1);}.backupfile b,.backupcontent span{overflow-wrap:anywhere;}.backupfile span,.backupsummary span,.backupcontent span{color:var(--hp-muted);font-size:var(--fs-s);}.backupcounts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-2) var(--sp-4);font-size:var(--fs-s);}.backupwarn,.backuperror{border-radius:var(--rad-s);padding:var(--sp-3);font-size:var(--fs-s);line-height:1.45;overflow-wrap:anywhere;}.backupwarn{background:color-mix(in srgb,var(--hp-accent) 12%,transparent);}.backuperror{background:rgba(179,64,42,.16);color:#ff7a5c;}.backupdetails{border:1px solid var(--hp-line);border-radius:var(--rad-s);padding:var(--sp-2) var(--sp-3);font-size:var(--fs-s);}.backupdetails summary{cursor:pointer;font-weight:700;}.backupdetails>div{display:grid;gap:var(--sp-1);padding-block-start:var(--sp-2);}.backupdetails code{overflow-wrap:anywhere;color:var(--hp-muted);}.backupchoices{display:flex;flex-direction:column;gap:var(--sp-2);border:1px solid var(--hp-line);border-radius:var(--rad-s);min-width:0;}.backupchoices label{margin:0 !important;display:flex;gap:var(--sp-2);}.backupconfirm{align-items:flex-start !important;}.backupconfirm>span:first-of-type{min-width:0;white-space:normal;overflow-wrap:anywhere;}@media (max-width:520px){.backupactions,.backupcounts{grid-template-columns:1fr;}}.aboutver{font-size:var(--fs-s);color:var(--hp-muted);margin:var(--sp-2) 0 var(--sp-3);}.aboutlink{display:flex;align-items:center;gap:var(--sp-3);width:fit-content;color:var(--hp-accent);text-decoration:none;font-size:var(--fs-m);padding:var(--sp-1) 0;}:host([data-pointer-hover]) .aboutlink:hover{text-decoration:underline;}.aboutlink ha-icon{--mdc-icon-size:18px;line-height:1;}hp-dialog .supportbody{min-width:0;overflow-x:hidden;gap:var(--sp-5);}.supportsection{display:grid;min-width:0;gap:var(--sp-2);}.supportsection + .supportsection{padding-top:var(--sp-4);border-top:1px solid var(--hp-line);}.supportsection h3{margin:0;color:var(--hp-txt);font-size:var(--fs-m);}.supportlinks,.supportactions{display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-2) var(--sp-4);min-width:0;}.supportform>label:not(.srcrow){margin-top:var(--sp-2);color:var(--hp-muted);font-size:var(--fs-s);}.supportmessage,.supportraw{width:100%;min-width:0;box-sizing:border-box;resize:vertical;border:1px solid var(--hp-line);border-radius:var(--rad-s);padding:var(--sp-3);color:var(--hp-txt);background:color-mix(in srgb,var(--card-background-color,var(--hp-bg)) 92%,var(--hp-txt));font:inherit;}.supportmessage{min-height:120px;background:var(--hp-bg);}.supportraw{min-height:220px;margin-top:var(--sp-2);resize:none;white-space:pre;overflow:auto;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;}.supportattach{min-width:0;align-items:flex-start;margin:var(--sp-2) 0 0 !important;}.supportattach>span:first-of-type{min-width:0;white-space:normal;overflow-wrap:anywhere;}.supportwarning,.supportstatus,.supportupdate{display:flex;align-items:flex-start;gap:var(--sp-2);min-width:0;margin:0;padding:var(--sp-3);border-radius:var(--rad-s);background:color-mix(in srgb,var(--hp-accent) 14%,transparent);overflow-wrap:anywhere;font-size:var(--fs-s);line-height:1.45;}.supportwarning ha-icon,.supportstatus ha-icon,.supportupdate ha-icon{flex:none;color:var(--hp-accent);--mdc-icon-size:20px;}.supportpreview,.supportmanual,.supporterror,.supportsuccess{display:grid;min-width:0;gap:var(--sp-2);padding:var(--sp-3);border:1px solid var(--hp-line);border-radius:var(--rad-s);}.supportsummary{font-weight:600;overflow-wrap:anywhere;}.supporthash{display:grid;min-width:0;gap:var(--sp-1);color:var(--hp-muted);font-size:var(--fs-s);}.supporthash code{overflow-wrap:anywhere;color:var(--hp-txt);}.supportpreview details{min-width:0;}.supportpreview summary{cursor:pointer;color:var(--hp-accent);}.supportprivacy{margin:0 !important;line-height:1.45;}.supporterror{background:color-mix(in srgb,var(--error-color,#db4437) 12%,transparent);border-color:color-mix(in srgb,var(--error-color,#db4437) 45%,var(--hp-line));}.supportsuccess{background:color-mix(in srgb,var(--success-color,#43a047) 12%,transparent);border-color:color-mix(in srgb,var(--success-color,#43a047) 45%,var(--hp-line));}.supportfooter{flex-wrap:wrap;}@media (max-width:520px){hp-dialog .supportbody{padding-inline:var(--sp-4);}hp-dialog .supportfooter{padding-inline:var(--sp-4);}.supportactions .btn,.supportactions .aboutlink{max-width:100%;}}hp-dialog .body{padding:var(--sp-5) var(--sp-6);display:flex;flex-direction:column;gap:var(--sp-3);}hp-dialog .tapconfirm-body{min-width:0;overflow-x:hidden;}hp-dialog .tapconfirm-body p{max-width:100%;min-width:0;margin:0;overflow-wrap:anywhere;white-space:normal;}hp-dialog .tapconfirm-line{color:var(--hp-muted);}hp-dialog .body label{font-size:var(--fs-s);color:var(--hp-muted);margin-top:var(--sp-3);}hp-dialog .body .namein,hp-dialog .body .areasel{width:100%;box-sizing:border-box;}hp-dialog .row{display:flex;justify-content:flex-end;gap:var(--sp-4);width:100%;min-width:0;box-sizing:border-box;padding:var(--sp-5) var(--sp-6);border-top:1px solid var(--hp-line);}hp-dialog>.row[slot='footer'] button{min-height:44px;}hp-dialog .row.dialog-action-footer{align-items:center;justify-content:flex-start;flex-wrap:wrap;row-gap:var(--sp-4);}hp-dialog .dialog-action-group{display:flex;flex:0 1 auto;flex-wrap:wrap;align-items:center;gap:var(--sp-4);max-width:100%;min-width:0;}hp-dialog .dialog-action-group .btn{flex:0 0 auto;min-height:44px;}hp-dialog .dialog-action-danger{margin-right:auto;}hp-dialog .dialog-action-commit{margin-left:auto;justify-content:flex-end;}hp-dialog .row.infofooter{align-items:center;justify-content:flex-start;flex-wrap:wrap;gap:var(--sp-3);}hp-dialog .row.infofooter .btn{flex-shrink:0;}hp-dialog .row.infofooter .infofooter-close{margin-left:auto;}@media (max-width:480px){hp-dialog .row.infofooter{padding:var(--sp-4) var(--sp-5);}}.device-inbox{display:flex;flex-direction:column;gap:var(--sp-4);padding:var(--sp-5) var(--sp-6);min-width:0;}.device-inbox-dialog{--hp-dialog-wide-width:920px;}.device-inbox-head{display:grid;grid-template-columns:minmax(180px,1fr) auto;align-items:center;gap:var(--sp-4);}.device-inbox-search{width:100%;min-width:0;box-sizing:border-box;border:1px solid var(--hp-line);border-radius:var(--rad-m);background:transparent;color:var(--hp-txt);font:inherit;padding:11px 14px;}.device-inbox-tabs{display:flex;gap:var(--sp-2);overflow-x:auto;scrollbar-width:thin;padding-bottom:var(--sp-1);}.device-inbox-tabs button{flex:0 0 auto;border:1px solid var(--hp-line);border-radius:999px;background:transparent;color:var(--hp-txt);font:inherit;padding:8px 12px;cursor:pointer;}.device-inbox-tabs button.on{border-color:var(--hp-accent);background:color-mix(in srgb,var(--hp-accent) 18%,transparent);}.device-inbox-tabs button span{color:var(--hp-muted);margin-inline-start:4px;}.device-inbox-discovery{margin:8px 0;padding:8px 10px;border:1px solid var(--divider-color,#e0e0e0);border-radius:8px;}.device-inbox-discovery summary{cursor:pointer;font-weight:600;}.device-inbox-discovery .srcrow{display:flex;gap:6px;align-items:center;margin:8px 0;}.device-inbox-excluded{display:flex;flex-wrap:wrap;gap:6px;align-items:center;}.device-inbox-excluded>span{font-weight:500;}.device-inbox-chips{display:flex;flex-wrap:wrap;gap:4px;}.device-inbox-chips .chip{display:inline-flex;align-items:center;gap:2px;padding:1px 6px;border-radius:10px;background:var(--secondary-background-color,#f0f0f0);font-size:12px;}.device-inbox-chips .chip button{border:none;background:none;cursor:pointer;padding:0 2px;color:var(--secondary-text-color,#666);}.device-inbox-excluded input[type="text"]{flex:1 1 140px;min-width:120px;padding:4px 6px;border:1px solid var(--divider-color,#e0e0e0);border-radius:6px;background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);}.device-inbox-preview{margin:8px 0 4px;font-size:13px;opacity:0.85;}.device-inbox-filters{display:flex;flex-wrap:wrap;gap:var(--sp-4) var(--sp-6);color:var(--hp-muted);}.device-inbox-filters label{display:inline-flex;align-items:center;gap:var(--sp-2);cursor:pointer;}.device-inbox-filter-help{display:inline-flex;align-items:center;gap:var(--sp-1);min-width:0;}.device-inbox-results{display:grid;gap:var(--sp-3);min-width:0;}.device-inbox-row{display:grid;grid-template-columns:42px minmax(180px,1fr) minmax(180px,auto);align-items:center;gap:var(--sp-4);min-width:0;border:1px solid var(--hp-line);border-radius:var(--rad-m);padding:var(--sp-4);background:color-mix(in srgb,var(--hp-txt) 3%,transparent);}.device-inbox-icon{--mdc-icon-size:28px;color:var(--hp-txt);justify-self:center;}.device-inbox-copy{min-width:0;}.device-inbox-name{display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-2);}.device-inbox-new{border-radius:999px;background:var(--hp-accent);color:var(--text-primary-color,#fff);font-size:var(--fs-s);padding:2px 7px;}.device-inbox-meta,.device-inbox-reason,.device-inbox-copy code{display:block;color:var(--hp-muted);font-size:var(--fs-s);overflow-wrap:anywhere;white-space:normal;}.device-inbox-status{color:var(--error-color,#db4437);margin-inline-start:var(--sp-2);}.device-inbox-actions{display:flex;justify-content:flex-end;align-items:center;flex-wrap:wrap;gap:var(--sp-2);}.device-inbox-actions .btn{min-height:36px;padding:7px 10px;}.device-inbox-menu{position:relative;}.device-inbox-menu summary{list-style:none;cursor:pointer;}.device-inbox-menu summary::-webkit-details-marker{display:none;}.device-inbox-menu-items{position:absolute;z-index:2;inset-inline-end:0;top:calc(100% + var(--sp-1));display:grid;gap:var(--sp-1);min-width:180px;padding:var(--sp-2);border:1px solid var(--hp-line);border-radius:var(--rad-m);background:var(--hp-panel,var(--card-background-color,#fff));box-shadow:0 8px 24px rgba(0,0,0,.22);}.device-inbox-menu-items .btn{justify-content:flex-start;width:100%;}.device-inbox-empty{color:var(--hp-muted);text-align:center;padding:var(--sp-8);}.device-inbox-more{align-self:center;}@media (max-width:680px){.device-inbox{padding:var(--sp-4);}.device-inbox-head{grid-template-columns:minmax(0,1fr);}.device-inbox-head .btn{justify-self:stretch;}.device-inbox-tabs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));overflow-x:visible;}.device-inbox-tabs button{min-width:0;overflow-wrap:anywhere;}.device-inbox-row{grid-template-columns:36px minmax(0,1fr);}.device-inbox-actions{grid-column:1 / -1;justify-content:flex-start;}}`];var lp={"editor.context_actions":"Actions: {object}","editor.tool_options":"Tool options: {tool}","editor.palette":"Palette: {tool}","editor.open_group":"Tool group: {group}","editor.group_active":"{group} — active: {item}","editor.disabled_action":"{action} is unavailable: {reason}","editor.loading":"Loading…","editor.loading_aria":"The plan editor is loading","editor.load_failed":"Could not load the editor.","editor.refresh_advice":"Refresh the page and try again.","editor.retry_advice":"Check your connection and press again.","version_mismatch.title":"House Plan versions do not match","version_mismatch.body":"If Home Assistant is still restarting, let it finish, then reload this page.","version_mismatch.frontend":"Card","version_mismatch.backend":"Integration","version_mismatch.reload":"Reload page","color_picker.title":"Color picker","color_picker.hue":"Hue","color_picker.saturation":"Saturation","color_picker.value":"Brightness","color_picker.hex":"Hex color","color_picker.invalid_hex":"Enter a 3- or 6-digit hex color","color_picker.confirm":"OK","btn.properties":"Properties","btn.keep_as_walls":"Keep as walls","btn.delete_room_keep_walls":"Delete room, keep walls","btn.delete_room_with_walls":"Delete room and walls","title.markup_select":"Select and edit walls and columns","title.markup_column":"Column: click a grid point to place a square column","markup.partition":"Partition","markup.column":"Column","markup.hint_column":"click a grid point to place a square column","history.wall_segment":"Add wall segment","history.column_add":"Add column","history.physical_edit":"Change physical object","history.physical_delete":"Delete physical object","history.physical_move":"Move physical object","history.wall_face_batch":"Create rooms from walls","toast.column_duplicate":"A column with the same centre and outer size already exists","physical.partition_properties":"Partition properties","physical.column_properties":"Column properties","physical.shape":"Shape","physical.square":"Square","physical.circle":"Circle","physical.diameter":"Diameter","physical.side":"Side","physical.rotation":"Rotation angle","physical.length":"Length","physical.allowed_range":"Allowed: {min}–{max} {unit}","physical.column_size_title":"Outer side of the square column placed by the click (1–150 cm).","card.title":"House plan","count.devices":"{n} dev.","empty.no_spaces":"No spaces yet.","nav.spaces":"House Plan spaces","empty.add_first":"Add the first space and upload a floor plan.","empty.read_only":"No spaces are configured. Ask an administrator to add one.","empty.install":'Install the House Plan integration and add it in "Devices & services".',"btn.add_space":"Add space","btn.cancel":"Cancel","btn.save":"Save","btn.close":"Close","btn.delete":"Delete","btn.copy":"Copy","btn.edit":"Edit","btn.open_in_ha":"Open in HA","btn.reset":"Reset","btn.attach":"Attach…","btn.upload":"Upload…","btn.replace":"Replace…","title.zoom_in":"Zoom in","title.zoom_out":"Zoom out","title.zoom_fit":"Fit all","title.configure_space":"Configure space","title.add_space":"Add space","title.markup_add":"Walls: draw a continuous chain; each accepted segment is saved independently. Shift locks to 45°","title.markup_merge":"Merge: click one room, then the neighbour it shares a wall with","title.markup_split":"Split a room: click the room, then two points on its walls","title.markup_delroom":"Delete room: click inside a room and confirm","markup.add":"Walls","markup.merge":"Merge","markup.split":"Split","markup.resize":"Resize","title.markup_resize":"Resize rooms: drag an available horizontal or vertical wall handle","markup.hint_resize":"drag an available wall handle · the wall stops at the first unsafe position · Esc cancels · Ctrl+Z — undo","resize.disabled.diagonal":"This wall is angled; Resize supports only horizontal and vertical walls","resize.disabled.side-angle":"An adjoining wall is angled; Resize requires both adjoining walls to meet this wall at right angles","resize.disabled.duplicate-physical-wall":"A separate partition or column overlaps this wall; remove or move it before resizing","resize.disabled.partial-shared":"A neighbouring room uses only part of this wall, so it cannot be moved safely as one shared wall","resize.disabled.unequal-shared":"The neighbouring room uses different endpoints or wall length, so the walls cannot move together safely","resize.disabled.multiple-rooms":"Moving this wall would affect more than two rooms","resize.disabled.thickness-conflict":"The wall thickness cannot be preserved safely","resize.disabled.opening-conflict":"An opening on this wall cannot be moved safely","resize.disabled.invalid-geometry":"This wall cannot be resized without changing the plan structure","resize.limit_stopped":"Wall stopped: the next step would break a junction limit","resize.commit_failed":"Resize was cancelled because the final plan did not pass the geometry check","resize.preview_failed":"Resize stopped at the last safe position because the plan geometry could not be preserved","markup.opening":"Opening","markup.delete_room":"Delete room","history.undo":"Undo","history.redo":"Redo","history.undo_named":"Undo: {name} (Ctrl+Z)","history.redo_named":"Redo: {name} (Ctrl+Shift+Z / Ctrl+Y)","history.undo_empty":"Nothing to undo","history.redo_empty":"Nothing to redo","history.undone":"Undone: {name}","history.redone":"Redone: {name}","history.add_room":"Create room","history.split_room":"Split room","history.merge_rooms":"Merge rooms","history.resize_room":"Resize room","history.wall_thickness":"Change wall thickness","history.add_opening":"Add door or window opening","history.edit_opening":"Edit opening","history.move_opening":"Move opening","history.delete_opening":"Delete opening","history.delete_room_keep_walls":"Delete room, keep walls","history.delete_room_with_walls":"Delete room and walls","history.decor_add":"Add decor object","history.decor_edit":"Edit decor object","history.decor_move":"Move decor object","history.decor_transform":"Transform decor object","history.decor_delete":"Delete decor object","history.backdrop_transform":"Transform plan backdrop","history.device_move":"Move {name}","history.device_stale":"Device position history is no longer applicable and was cleared","opening.new":"New opening","opening.edit":"Opening","opening.door":"Door","opening.window":"Window","opening.gate":"Gate","opening.passage":"Open passage","opening.passage_binding_warning":"Saving will remove the open/close sensor and lock.","opening.invalid_passage_fields":"The open passage on plan “{room}” has unsupported settings: {fields}.","opening.type_label":"Type","opening.length_label":"Length, cm","opening.contact_label":"Open/close sensor","opening.lock_label":"Lock","opening.none":"— none —","opening.search_ph":"Search: name or entity id…","opening.invert":"Invert open/closed","opening.flip_h":"Hinge on the other jamb","opening.flip_v":"Opens to the other side","opening.open":"Open","opening.closed":"Closed","opening.locked":"Locked","opening.unlocked":"Unlocked","opening.state_unknown":"unavailable","opening.no_entities":"No sensors bound — a static symbol on the plan.","toast.opening_no_wall":"Click next to a room wall or independent wall","opening.host_partition":"Independent wall","opening.partition_orphan":"The independent wall for this opening no longer exists","opening.partition_jamb_margin":"Leave at least {distance} between the opening and the end of the wall","opening.rebind_partition":"Attach to another independent wall","confirm.delete_partition_openings_title":"Delete wall and openings?","confirm.delete_partition_openings_body":"This wall contains {count} opening(s). They will be deleted together.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.hint_points":"points: {n} · Shift — 45° steps · Esc — finish chain · Ctrl+Z — undo a point · closing an area offers a room","markup.hint_start":"click a grid dot to start a wall chain","tip.lqi":"average zigbee signal:","tip.area":"area: {value}","info.device_header":"Device on the plan","info.model":"Model","info.state":"State","info.link":"Link","info.manuals":"Manuals","info.none":"No additional information","marker.new_device":"New device","marker.name_label":"Name","marker.name_ph":"Name","marker.binding_label":"Bind to an HA device","marker.binding_disabled":"disabled in Home Assistant","marker.virtual_option":"Virtual device (no binding)","marker.search_ph":"Search device / group…","marker.nothing_found":"nothing found","marker.room_label":"Room","marker.room_choose":"— select a room —","marker.room_auto":"— by device area (auto) —","marker.icon_label":"Icon","marker.icon_ph":"mdi:… (empty = auto)","marker.display_label":"Display","display.badge":"Icon + state","display.icon_ripple":"Icon + state and activity","display.static_icon":"Always static icon","display.value_static_icon":"Value + static icon","marker.display_hint_badge":"The icon and dynamic plate show device state without the ordinary activity pulse. Red alarms remain visible.","marker.display_hint_icon_ripple":"The icon, dynamic plate and pulse show a short pulse for events and a continuous pulse for work, motion or presence. Red alarms have separate priority.","marker.display_hint_value":"A selected or automatically resolved Home Assistant value replaces the icon while the plate continues to show state. Red alarms remain visible.","marker.display_hint_static_icon":"The theme-aware shell and icon always stay the same. State, activity, unavailability and alarms do not change the face.","marker.display_hint_value_static_icon":"The marker shows the selected value while the shell stays theme-aware. State, activity, unavailability and alarms do not change the marker colour.","marker.static_alarm_warning":"This device can report alarms. Static display hides the marker's visual alarm indication.","marker.preview.title":"Display preview","marker.preview.actual":"Now","marker.preview.example":"Example","marker.preview.integration":"Provided by","marker.preview.source":"Display source","marker.preview.current_state":"Current state","marker.preview.result":"On the plan","marker.preview.details":"Source details","marker.preview.select_source":"Choose a Home Assistant device or entity to see its actual display.","marker.preview.unknown_provider":"Unknown integration","marker.preview.virtual_provider":"House Plan · virtual device","marker.preview.no_source":"No active source","marker.preview.no_state":"No current state","marker.preview.mixed_states":"Several different states","marker.preview.multiple_sources":"{n} sources","marker.preview.more_sources":"+{n} more","marker.preview.scaled":"The preview is scaled to {n}% to fit. The saved size is unchanged.","marker.preview.demo_short":"Show short activity","marker.preview.demo_continuous":"Show continuous activity","marker.preview.stop_continuous":"Stop continuous activity","marker.preview.demo_short_notice":"Short activity example; the actual device state is unchanged.","marker.preview.demo_continuous_notice":"Continuous activity example; the actual device state is unchanged.","marker.preview.demo_already_visible":"The current state already shows a real activity or alarm effect.","marker.preview.reduced_motion":"System reduced-motion is enabled, so ordinary activity is shown as a dot.","marker.preview.reason.neutral":"Neutral dark plate","marker.preview.reason.working":"Yellow plate: the device is working now","marker.preview.reason.working_activity":"Yellow plate and activity effect: the device is working now","marker.preview.reason.open":"Orange plate: physically open or unlocked","marker.preview.reason.cover_icon_state":"Neutral plate; the cover entity controls the displayed state and icon","marker.preview.reason.presence":"Activity effect while presence is detected","marker.preview.reason.event":"Short activity effect after a detected event","marker.preview.reason.transition":"Activity effect while the device is moving or changing state","marker.preview.reason.media_neutral":"Media devices stay on a neutral dark plate while available","marker.preview.reason.unavailable":"Subdued neutral plate: unavailable or off","marker.preview.reason.alarm":"Red alarm plate; alarm indication is always shown","marker.preview.reason.live_states_disabled":"Live-state styling is disabled for this card","marker.preview.reason.value_no_state":"No usable state value; the icon is shown instead","marker.preview.reason.value_ambiguous_sources":"Several possible value sources; the icon is shown instead","marker.preview.reason.value_non_scalar":"The source did not return a simple value; the icon is shown instead","marker.preview.reason.value_virtual":"A virtual device has no Home Assistant value; the icon is shown instead","marker.preview.reason.vacuum_live_plan_only":"Live vacuum position and trail are available only on the full plan","marker.preview.reason.hidden_design_preview":"The device is hidden on the plan; this design preview remains visible","marker.preview.reason.composite_power_source":"State comes from the device Power entity; auxiliary switches are ignored","marker.preview.reason.activity_display_disabled":"The selected display mode does not show ordinary activity effects","marker.preview.reason.ha_disabled":"The Home Assistant binding is disabled and will be hidden on the plan","marker.preview.reason.orphaned":"The saved Home Assistant binding can no longer be found","marker.preview.reason.static_icon":"Static mode: device state does not change the icon","marker.preview.reason.value_static_icon":"Static mode with a value: device state does not change the marker colour","marker.activity_color":"Activity pulse color","marker.ripple_size":"Activity pulse size","marker.activity_alarm_note":"Color and size affect ordinary activity only and do not change red alarms.","marker.pulse_a11y_alarm":"Alarm","marker.pulse_a11y_event":"Recent event","marker.pulse_a11y_presence":"Presence detected","marker.pulse_a11y_transition":"Changing state","marker.pulse_a11y_running":"Working","marker.state_a11y_neutral":"Default state","marker.state_a11y_working":"Working","marker.state_a11y_open":"Open","marker.state_a11y_locked":"Locked","marker.state_a11y_unlocked":"Unlocked","marker.state_a11y_alarm":"Alarm","marker.state_a11y_unavailable":"Unavailable","marker.lqi_a11y_low":"LQI {value}, low signal","marker.lqi_a11y_mid":"LQI {value}, medium signal","marker.lqi_a11y_high":"LQI {value}, high signal","marker.size_label":"Icon size and rotation","marker.angle_label":"Rotate","marker.model_label":"Model","marker.model_ph":"e.g. Aqara T&H","marker.link_label":"Link","marker.desc_label":"Description","marker.desc_ph":"Notes, specs…","marker.manuals_label":"Manuals (PDF etc.)","marker.sub_device":"device","marker.sub_z2m_group":" · Z2M group","marker.sub_group":"group","marker.sub_helper":"helper","space.new":"New space","space.copy_title":"Copy space","space.copy_name":"New space name","space.copy_fallback":"Space","space.copy_create":"Create copy","space.copy_optimize_title":"Optimize before copying?","space.copy_optimize_body":"Before creating “{name}”, House Plan must optimize the entire plan, including other spaces. Continue?","space.copy_optimize_confirm":"Optimize and copy","space.copy_error_changed":"The plan changed while confirmation was open. Review it and try again.","space.copy_error_source_missing":"The source space no longer exists. Reopen its settings and try again.","space.copy_error_source_invalid":"House Plan could not validate every wall in this space. Fix the source space and try again.","space.copy_error_spaces_limit":"House Plan already has the maximum number of spaces.","space.copy_error_partitions_limit":"This space has too many walls to copy.","space.copy_error_openings_limit":"This space has too many openings to copy.","space.copy_error_decor_limit":"This space has too many background objects to copy.","space.copy_error_columns_limit":"This space has too many columns to copy.","space.copy_error_opening_host":"One of the openings is no longer attached to a wall. Fix or delete it before copying.","space.copy_error_geometry":"The copy would create unsafe wall geometry. Fix the source space and try again.","space.copy_error_optimize_geometry":"Copy stopped because optimizing the entire plan is unsafe for one of the spaces.","space.header":"Space","space.title_label":"Space name","space.title_ph":"e.g. Garage","space.plan_label":"Floor plan","space.no_plan":"no plan image","space.plan_alt":"plan","room.new":"New room","room.name_label":"Display name","room.name_ph":"e.g. Terrace","room.area_label":"Home Assistant area","room.no_area_option":"— no area —","room.default_name":"Room","device.unnamed":"unnamed","device.light_group":"light group","device.fallback":"device","device.virtual":"virtual device","confirm.delete_room_title":'Delete room "{name}"?',"confirm.delete_room_body":"Choose whether the room's exclusive physical walls should remain. Walls shared with another room are always kept.","confirm.remove_marker_title":"Delete device from the plan?","confirm.remove_marker_body":"The device will disappear completely and stop contributing to plan data. You can add it again later.","confirm.erase_decor":"Erase the {kind} object? You can undo this action from the editor history.","confirm.delete_space_title":"Delete space?","confirm.delete_space_body":"The space, all its rooms and all its plan markup will be deleted.","confirm.delete_space_vac_routes":"Robot map assignments will also be removed: {count}.","space.delete_blocked":"This space is still used by {n} device(s). Move them to another space or delete them first.","toast.pos_save_failed":"Failed to save position: {err}","toast.no_entity":"The device has no suitable entity","toast.ha_disabled_action":"A Home Assistant object that is disabled cannot be used on the plan.","toast.ha_disabled_show_device":"A device disabled in Home Assistant cannot be shown on the plan. Enable it in Home Assistant first.","toast.ha_disabled_show_entity":"An entity disabled in Home Assistant cannot be shown on the plan. Enable it in Home Assistant first.","toast.ha_disabled_add":"A disabled Home Assistant object cannot be added to the plan. Enable it in Home Assistant first.","toast.ha_binding_unverified":"The object status could not be verified through the Home Assistant registry. Display and actions are temporarily unavailable.","toast.markup_needs_server":"Markup is available after the config is moved to the server","toast.space_order_changed":"Order changed. If any card pins its floor by number, check those panels.","toast.conflict":"Config was changed in another window — data refreshed, repeat your last action","toast.cfg_save_failed":"Failed to save config: {err}","toast.room_overlap":"The outline overlaps room “{name}” — rooms must not overlap","toast.contour_cannot_close":"The outline cannot close because it is degenerate or intersects itself","toast.merge_not_adjacent":"Only rooms that share a wall can be merged","toast.rooms_merged":"Rooms merged into “{name}”","toast.split_pick_wall":"Start the cut on the room’s wall","toast.split_bad_cut":"The cut must run wall to wall inside the room, without crossing walls or itself","merge.header":"Merge rooms","merge.hint":"The merged room keeps one name and one area. The other area is released — its devices leave the plan until another room claims it.","merge.keep":"Keep","merge.no_area":"no area","toast.room_saved":"Room saved ({n}). Devices added: {added}. Outline the next one or exit markup.","toast.room_saved_no_area":"Room saved ({n}, no area). Outline the next one or exit markup.","toast.marker_needs_server":"Device editing is available after the config is moved to the server","toast.virtual_name_required":"Enter a name for the virtual device","toast.marker_saved":"Device saved","toast.marker_removed":"Device deleted from the plan","toast.integration_missing":"The House Plan integration is not installed — management unavailable","toast.plan_formats":"Supported formats: SVG, PNG, JPG, WebP","toast.plan_required":"Upload a floor plan — it is required","toast.space_added_onboard":"Space added. Outline the rooms: click grid dots and close the contour.","toast.space_added":"Space added","toast.space_copied":"Space “{name}” created","toast.space_saved":"Space saved","toast.space_deleted":"Space deleted","toast.delete_failed":"Delete failed: {err}","toast.error":"Error: {err}","toast.toggle_target_unavailable":"Target “{name}” is unavailable — no action was performed","toast.toggle_targets_unavailable":"Targets are unavailable: {names}. No action was performed","toast.file_failed":'File "{name}" was not uploaded: {err}',"toast.files_attached":"Files attached: {n}","err.unknown":"unknown error","err.code":"code {code}","err.too_large":"file larger than {mb} MB","err.bad_ext":"unsupported type (PDF/image expected)","err.unauthorized":"administrator rights required","editor.title":"Title","editor.default_floor":"Initial space","editor.default_floor_missing":"Initial space “{id}” no longer exists. Choose another space.","editor.floor":"Fixed space","editor.floor_none":"— not fixed —","editor.floor_index":"YAML index {index} (preserved)","fixed_floor.loading":"Loading the fixed space…","fixed_floor.invalid_title":"The fixed space is unavailable","fixed_floor.invalid_body":"Check floor in the card configuration. The configured value is: {value}","editor.icon_size":"Icon size, % of plan width","editor.show_temperature":"Show temperature","editor.live_states":"Live states (on/off, open…)","editor.light_pools":"Light pools and wall shadows","editor.show_signal":"Show zigbee signal (LQI)","editor.language":"Interface language","editor.lang_auto":"Auto (HA profile)","title.icon_rules":"Icon rules: which MDI icon devices get by name","rules.title":"Icon rules","rules.hint":"Rules are checked top-down against “device name + model” (case-insensitive regex); the first match wins. When nothing matches, the entity device class decides, then the generic chip icon.","rules.pattern_ph":"regex, e.g. plug|socket","rules.icon_ph":"mdi:power-socket-de","rules.add":"Add rule","rules.reset":"Reset to defaults","rules.test_ph":"Try a device name…","rules.invalid":"invalid regex","rules.saved":"Icon rules saved","btn.up":"Up","btn.down":"Down","tap.info":"Device card","tap.more_info":"HA more-info dialog","tap.toggle":"Toggle state","marker.tap_label":"Tap action for this device","tap.toggle_note":"The resolved state is shown below. Secure devices are never toggled from the plan.","import.title":"Create spaces from HA floors","import.hint":"Your Home Assistant already knows these floors. Pick the ones to turn into plan spaces — you will upload a floor-plan image for each one next. Rooms are then outlined by hand on the plan.","import.start":"Create {n} space(s)","import.manual":"Start from scratch","import.progress":"Floor {i} of {n}","import.done":"Spaces created. Outline the rooms: click grid dots and close the contour.","btn.skip":"Skip","space.scale_label":"Scale (grid cell size)","space.cell_cm.help":"Links the grid to real dimensions: lengths, areas, wall thickness, opening sizes and glow radius depend on it. Changing it after drawing changes the calculated dimensions of the whole space without moving its points on the plan.","space.cell_cm.help.aria":"Help: space scale","space.scale_unit":"cm per cell","space.scale_unit_imperial":"in per cell","space.display_section":"Appearance","space.show_borders":"Always show room borders","space.zero_wall_style":"Zero-thickness walls","space.zero_wall_style.help":"Dashed zero-thickness walls pass Glow and sun rays, while solid ones block them as zero-area barriers. The choice affects every such wall in the space even when its line is hidden in View.","space.zero_wall_style.help.aria":"Help: zero-thickness wall style","space.zero_wall_dashed":"Dashed","space.zero_wall_solid":"Solid","space.show_names":"Show room names","space.room_color":"Border & name color","space.opacity":"Opacity","space.fill_label":"Room fill","space.fill_mode.help":"“Custom colour” is styling, while “Light”, “Temperature” and “LQI” use current Home Assistant data; Glow is enabled separately.","space.fill_mode.help.aria":"Help: room fill mode","fill.none":"None","fill.lqi":"Zigbee signal","fill.light":"Lights","fill.custom":"Custom color","space.custom_fill":"Fill color","space.source_file":"Use a floor-plan image","space.source_draw":"Draw it myself","fill.temp":"Temperature","tip.temp_avg":"average temperature:","tip.hum_avg":"average humidity:","space_card.button":"Open the space plan","space_card.not_found":"Space “{id}” not found","space_card.loading":"Loading…","continuity.restore_plan":"Restoring floor plan…","continuity.restore_connection":"Restoring device connection…","continuity.retry":"Try again","editor.space":"Space","editor.framing":"Framing","editor.fit_content":"All visible content","editor.fit_house":"Tight to house geometry","editor.show_button":"Show button","editor.button_label":"Button label","editor.button_target":"Target dashboard path","marker.sub_entity":"entity","title.general_settings":"General settings","title.export_pdf":"Save as PDF","pdf.title":"Save as PDF","pdf.dimensions":"Show dimensions and areas","pdf.decor":"Show furniture and other decor","pdf.room_names":"Show room names","pdf.backdrop":"Show backdrop","pdf.save":"Save","pdf.saving":"Creating…","pdf.failed":"Could not create the PDF.","pdf.too_large":"The images exceed the 25 MB PDF limit.","pdf.asset_failed":"A backdrop or decor image could not be loaded.","pdf.scale":"Scale 1:{n}","pdf.north":"North","gs.title":"General settings","gs.light_group":"Lights","gs.light_on":"Lights on","gs.light_off":"All lights off","gs.temp_group":"Temperature","gs.temp_cold":"Cold","gs.temp_ok":"Comfortable","gs.temp_hot":"Hot","gs.lqi_group":"Zigbee signal","gs.lqi_low":"Weak signal","gs.lqi_high":"Strong signal","gs.reset":"Reset to defaults","gs.saved":"General settings saved","gs.radar_show_live":"Show live presence on the plan","radar.title":"Presence on the plan","radar.help":"Connect this marker to exact Home Assistant radar entities, place the sensor and choose its coordinate profile. Live positions are clipped to the selected room.","radar.help.aria":"Help: presence radar settings","radar.enabled":"Use this presence radar","radar.show_live":"Show live targets","radar.configure":"Configure radar","radar.configure_on_plan":"Configure on plan","radar.change_installation":"Change installation","radar.no_contour":"This room has no boundary. Radar points will not be clipped.","radar.discard_setup_title":"Discard radar setup?","radar.discard_setup":"The unsaved radar setup will be lost.","radar.step_place_mount":"Mark the physical sensor position","radar.step_place_heading":"Mark a point straight ahead of the sensor","radar.step_reference":"Mark reference position {n}, then start measurement","radar.step_check_reference":"Mark an independent check position","radar.start_measure":"Start measurement","radar.countdown":"Stand at the mark in {seconds} s","radar.capturing":"Stand still and alone while measuring…","radar.fit_ready":"Calibration is ready","radar.check_third":"Check at another position","radar.check_complete":"Independent check completed","radar.error_distance":"Position difference: {distance}","radar.ambiguous_target":"More than one target was reported. Repeat the measurement alone.","radar.insufficient_samples":"Not enough current coordinates. Retry or use manual setup.","radar.bad_references":"Choose separated references in different directions from the sensor.","radar.ambiguous_sources":"The measurements allow two equally plausible directions. Choose reference points that distinguish left from right.","radar.bad_fit":"Measurements do not match. Check units, mounting point and references.","radar.desktop_hint":"Use a computer for precise setup. Editing on touch devices is best effort.","radar.detected":"House Plan recognized radar metadata for this device. Review the exact sources before saving.","radar.detected_ld2450":"House Plan found an ESPHome LD2450 coordinate set. Review the exact X/Y sources before saving.","radar.additional_actions":"Additional actions","radar.declare":"This is a presence radar","radar.profile":"Data profile","radar.profile_esphome_ld2450_v1":"ESPHome LD2450 (X/Y targets)","radar.profile_cartesian_v1":"Cartesian targets (X/Y)","radar.profile_polar_v1":"Polar target (distance/angle)","radar.profile_range_v1":"Distance only","radar.profile_zones_v1":"Zone states","radar.profile_presence_v1":"Presence only","radar.room":"Radar room","radar.room_choose":"Choose a room","radar.target":"Target {n}","radar.axis_x":"X coordinate entity","radar.axis_y":"Y coordinate entity","radar.add_target":"Add target slot","radar.range_channel":"Range channel {n}","radar.add_range":"Add range channel","radar.presence_gate":"Presence gate entity","radar.swap_axes":"Swap X and Y axes","radar.axis_x_sign":"X direction","radar.axis_y_sign":"Y direction","radar.distance_source":"Distance entity","radar.angle_source":"Angle entity","radar.angle_unit":"Angle unit","radar.degrees":"Degrees","radar.radians":"Radians","radar.angle_zero":"Zero-angle direction","radar.angle_forward":"Forward","radar.angle_right":"Right","radar.angle_clockwise":"Angles increase clockwise","radar.zone_source":"Zone entity","radar.occupancy_source":"Presence entity","radar.count_source":"Target count entity","radar.availability_source":"Availability entity","radar.source_choose":"Choose an entity","radar.source_optional":"Optional","radar.source_missing":"currently unavailable","radar.saved_unsupported":"This saved radar setup is unsupported or incomplete. It remains inactive; remove it or update House Plan before configuring it again.","radar.occupancy":"Presence (on/off)","radar.count":"Count","radar.mount":"Position and direction","radar.mount_hint":"This is the physical sensor position. Moving its decorative marker does not change it.","radar.heading":"Direction, °","radar.range_cm":"Range, cm","radar.fov_deg":"Field of view, °","radar.unit":"Source unit","radar.mirror":"Mirror the left/right axis","radar.remove":"Remove radar settings","radar.invalid":"Complete the radar room, sources and position before saving.","radar.check_sources":"Check live data","radar.checking":"Checking…","radar.health":"Connection status","radar.live_summary":"Current targets: {targets}; range arcs: {ranges}","radar.health_ok":"Current data received","radar.health_off":"No targets detected","radar.health_stale":"Some coordinate data is out of date","radar.health_partial":"Some sources are current; others are out of date","radar.health_restricted":"Access to one or more sources is restricted","radar.health_incomplete":"The current radar report is incomplete","radar.health_position_unavailable":"Presence reported; current position unavailable","radar.health_unavailable":"Sensor data unavailable","radar.health_needs_setup":"Installation needs setup","radar.health_inconsistent":"The sources report conflicting values","radar.health_unknown":"Current state is unknown","radar.health_disabled":"Radar is disabled","radar.error_invalid_radar":"Check the radar settings.","radar.error_invalid_selection":"Select an existing room and valid sources.","radar.error_source_restricted":"You do not have access to all selected sources.","radar.error_rate_limited":"Too many requests. Try again shortly.","radar.error_not_ready":"Radar processing is not ready.","radar.error_conflict":"The plan changed. Reopen the radar setup and try again.","radar.error_source_unavailable":"One or more selected radar sources are unavailable.","radar.error_unsupported_capability":"This radar capability is not supported by the installed integration.","radar.report_age":"{seconds} s ago","space.show_lqi":"Zigbee signal next to devices","gs.light_none":"No light sources","mode.plan":"Plan editor","mode.devices":"Device editor","display.value":"Value + state","marker.subarea":"no area, manual","device.new":"New device — open its editor to dismiss","opening.unlock_action":"Unlock","opening.lock_action":"Lock","opening.lock_pending":"Working…","title.close_editor":"Close editor (back to view)","title.add_device":"Add a device to the plan","devbar.add":"Add","devbar.rules":"Icon rules","device_inbox.button":"Devices","device_inbox.title":"Devices on the plan","device_inbox.search":"Search devices, entities and integrations…","device_inbox.add_virtual":"Add virtual device","device_inbox.tab_on_plan":"On plan","device_inbox.tab_available":"Available","device_inbox.tab_hidden":"Hidden","device_inbox.tab_readd":"Available again","device_inbox.only_new":"New only","device_inbox.show_entities":"Show entities","device_inbox.show_hidden":"Show hidden on plan","device_inbox.show_hidden.help":"Temporarily shows hidden and disabled markers as editor-only ghosts on the plan. Saved device visibility does not change.","device_inbox.show_hidden.help.aria":"Help: show hidden devices on the plan","device_inbox.new":"New","device_inbox.find":"Find on plan","device_inbox.edit":"Edit","device_inbox.hide":"Hide","device_inbox.show":"Show","device_inbox.add":"Add","device_inbox.readd":"Add again","device_inbox.hide_available":"Hide from list","device_inbox.show_more":"Show more","device_inbox.more_actions":"More actions","device_inbox.find_hidden_hint":"Enable “Show hidden on plan” first","device_inbox.show_disabled":"Activate this binding in Home Assistant before showing it","device_inbox.empty_on_plan":"No matching devices are on the plan yet.","device_inbox.empty_available":"No devices are available to add.","device_inbox.empty_hidden":"There are no hidden devices.","device_inbox.empty_readd":"No removed devices are available to add again.","device_inbox.reason_visible_auto":"Discovered automatically","device_inbox.reason_visible_explicit":"Added explicitly","device_inbox.reason_manual_hidden":"Hidden by user","device_inbox.reason_automatic_hidden":"Hidden automatically","device_inbox.reason_service_entry":"Service-only registry entry","device_inbox.reason_excluded_integration":"Integration “{integration}” excluded by discovery filters","device_inbox.reason_excluded_domain":"Non-spatial entity type","device_inbox.reason_grouped_light":"Represented by a room light group","device_inbox.reason_represented_by_parent":"Represented by its parent device","device_inbox.reason_removed":"Previously removed from the plan","device_inbox.reason_available":"Available to add to the plan","device_inbox.reason_no_bound_room":"HA area is not linked to a plan room","device_inbox.status_ha_disabled":"Disabled in Home Assistant","device_inbox.status_orphaned":"Binding is no longer present in Home Assistant","device_inbox.status_unverified":"Home Assistant registry is temporarily unavailable","device_inbox.saved":"Device list updated","device_inbox.filters_excluded":"Excluded integrations","device_inbox.filters_group_lights":"Group room lights into one marker","device_inbox.filters_preview_appear":"will appear: {count}","device_inbox.filters_preview_hide":"will disappear: {count}","device_inbox.filters_preview_lights":"lights affected: {count}","device_inbox.filters_reset":"Restore recommended","device_inbox.filters_save":"Save filters","device_inbox.filters_search_ph":"Add an integration…","device_inbox.filters_title":"Discovery filters","space.roomcard_section":"Room cards","space.label_temp":"Temperature","space.label_hum":"Humidity","space.label_lqi":"Average Zigbee signal","space.label_light":"Lights on/off","roomcard.light_on":"On","roomcard.light_off":"Off","roomcard.light_partial":"{on} of {total}","toast.split_pick_inside":"Intermediate cut points must be inside the room","mode.decor":"Background editor","decor.select":"Select","decor.line":"Line","decor.rect":"Rectangle","decor.ellipse":"Oval","decor.text":"Text","decor.erase":"Erase","decor.erase_confirm_title":"Erase object?","decor.color":"Color","decor.width":"Line width","decor.line_style":"Line style","decor.line_style_solid":"Solid","decor.line_style_dashed":"Dashed","decor.fill":"Fill","decor.fill_color":"Fill color","decor.length":"Length","decor.size":"Size","decor.flip_h":"Flip horizontally","decor.flip_v":"Flip vertically","decor.angle":"Rotation angle, °","decor.text_size":"Text size","decor.backdrop_properties":"Plan backdrop properties","decor.text_title":"Text label","decor.object_title":"Edit {kind}","decor.text_label":"Text","decor.live_group":"Insert HA variable","decor.live_entity":"Entity","decor.live_entity_ph":"choose an entity","decor.live_attr":"Value","decor.live_attr_ph":"choose state or attribute","decor.live_state":"State","decor.backdrop":"Backdrop image","decor.backdrop_hint":"Drag to move; pull a corner to resize; use the top handle to rotate. Shift changes proportions or frees the angle.","decor.backdrop_reset":"Reset the picture","decor.backdrop_reset_done":"The picture is back at its original place and size","marker.icon_auto":"Auto: {icon} (by icon rules; pick one to override)","marker.icon_pin_auto":"Pin","mode.plan_tip":"Plan editor — the geometry of the home: draw and split/merge rooms, bind them to HA areas, place doors, windows and gates, move room cards, set the scale","mode.devices_tip":"Device editor — everything about icons: drag to position, click to edit binding/icon/display, add virtual devices, icon rules","mode.decor_tip":"Background editor — purely visual decor under the plan: lines, rectangles, ovals and text labels that never react to clicks","space.glow_enabled":"Light-source glow","gs.glow_group":"Light-source glow","gs.glow_base":"House darkness","gs.glow_light":"Default light color / intensity","gs.wall_fill":"Wall fill","gs.glow_radius":"Glow radius","gs.glow_radius.help":"Sets the default glow radius in metres or feet; a device-specific radius overrides it.","gs.glow_radius.help.aria":"Help: default glow radius","gs.unit_m":"m","gs.unit_ft":"ft","marker.controls_label":"Controls other light sources","marker.controls.help":"With the “Toggle state” action, the listed sources toggle together with this marker. Their glow stays at their own markers, and the link alone does not turn the controlling marker into a light source.","marker.controls.help.aria":"Help: controlling other light sources","marker.controls_filter":"Search lights and switches…","info.controls":"Controls","marker.glow_radius_label":"Glow radius","marker.glow_radius.help":"Sets the glow radius in metres or feet; an empty value uses the radius from general settings.","marker.glow_radius.help.aria":"Help: glow radius","markup.wallthick":"Thickness","markup.select":"Select","title.markup_wallthick":"Thickness — click a wall to set its thickness from 0 to 100 cm.","markup.hint_wallthick":"click a wall · Esc closes without applying","wallthick.field":"Thickness","wallthick.unit_cm":"cm","wallthick.unit_in":"in","wallthick.apply_room":"Apply to all walls of this room","markup.draw_wall_title":"Thickness of each new wall segment (0–100 cm). Shared walls keep the existing value.","room.queue_progress":"Room {current} of {total}","toast.wall_rooms_saved":"Created rooms: {n}","toast.wall_chain_saved":"Wall chain saved","toast.wallthick_pick":"Click a wall","toast.wallthick_set":"Wall thickness set","toast.wallthick_cleared":"Wall thickness removed","toast.physical_range":"Enter a value from {min} to {max} {unit}","toast.zero_wall_opening_conflict":"Remove the opening on this wall segment first.","toast.zero_wall_ambiguous":"The wall segment is ambiguous. Simplify or adjust the junction.","toast.zero_wall_migration_blocked":"The space was not converted: {reason}. No data was changed.","toast.physical_angle":"Enter a rotation angle from 0° up to, but not including, 90°","toast.physical_limit":"The space has reached the limit for this type of geometry","toast.geometry_unsafe":"Change canceled: wall geometry could not be built safely.","junction.limit_angle":"The angle between walls is too sharp: {actual}°, minimum {limit}°.","junction.limit_valence":"Too many walls meet in one node: {actual}, maximum {limit}.","junction.limit_length":"The wall segment is too short: {actual} cm, minimum {limit} cm.","junction.limit_distance":"Walls and nodes are too close: {actual} cm, minimum {limit} cm.","junction.limit_clearance":"No room interior is left: {actual} cm², minimum {limit} cm².","junction.limit_check_failed":"The junction check could not run — the change was not saved","toast.wall_model_migration_blocked":"The wall model could not be updated: {reason}. The plan was not changed. Run “Optimize plans”; if the error repeats, fix the conflicting wall geometry.","toast.wall_model_client_outdated":"Update the card and reload the page before editing the plan.","wall_model.reason.invalid-room":"invalid room contour","wall_model.reason.zero-length":"zero-length wall segment","wall_model.reason.third-owner":"wall shared by more than two rooms","wall_model.reason.duplicate-id":"conflicting wall identifiers","wall_model.reason.thickness-conflict":"conflicting wall thickness values","wall_model.reason.opening-host":"opening cannot be assigned to one wall","toast.delete_room_pick":"Click inside the room you want to delete","toast.plan_snap_ambiguous":"Zoom in to choose the wall node","toast.wall_repair_ambiguous":"The room outline has more than one possible connection. Zoom in and connect it explicitly.","toast.wall_repair_too_large":"The gap is larger than 2 cm. Connect the walls before creating the room.","toast.wall_repair_changed":"The wall geometry changed. Try creating the room again.","toast.opening_on_zero_wall":"Openings cannot sit on a zero-thickness wall","marker.from_ha_option":"Pick from the HA list","marker.show_entities":"Show entities","marker.show_entities_tip":"Adds not only devices to the list, but all their entities too","marker.pick_ph":"Choose a device…","room.open_area":"Open the HA area","room.fit_action":"Fit room {name}","view.volumetric":"Volumetric view","view.flat":"Flat view","kiosk.title":"This screen's sizes","kiosk.hint":"Stored on this device only — every wall tablet or TV can have its own comfortable sizes.","kiosk.icon_scale":"Device icon size","kiosk.font_scale":"Room card text size","editor.kiosk":"Wall device (kiosk) mode","editor.cycle":"Auto-switch spaces every N seconds (kiosk, 0 = off)","room.settings_title":"Room settings","room.fill_label":"Fill in THIS room","fill.inherit":"As the space","room.custom_fill_space":"Space color","room.custom_fill_own":"Room color","room.temp_range_label":"Comfort range","room.temp_range_min":"Lower comfort-temperature bound","room.temp_range_max":"Upper comfort-temperature bound","room.temp_range_reset":"As the space","room.temp_range.help":"This range applies only to this room. Empty fields inherit the corresponding space bounds; if the bounds are reversed, House Plan uses the smaller value as the lower bound and the larger value as the upper bound.","room.temp_range.help.aria":"About the room comfort range","room.temp_src_label":"Temperature source","room.hum_src_label":"Humidity source","room.src_average":"Average of the room’s sensors","room.src_pick":"Specific device or entity","room.src_ph":"Choose a source…","toast.room_updated":"Room updated","space.card_font":"Room-card font size","room.sizes_section":"Font sizes","room.group_basics":"Basics","room.group_basics.help":"The area links the room to a Home Assistant area, which is where its sensors come from. Without one the room stays geometry.","room.group_basics.help.aria":"Help: room name and area","room.group_fill":"Fill","room.group_fill.help":"This room’s fill overrides the space one; a custom colour is kept for this room only.","room.group_fill.help.aria":"Help: room fill","room.group_sources":"Sensor sources","room.group_sources.help":"By default the room averages its own sensors. A selected sensor replaces that average everywhere: tooltip, card, fill.","room.group_sources.help.aria":"Help: temperature and humidity sources","room.sizes_section.help":"These scales apply to this room only and multiply the shared card scale from the space settings.","room.sizes_section.help.aria":"Help: room font sizes","room.name_scale":"Room name size","room.label_scale":"Metrics size","preview.room_name":"Living room","toast.cfg_reload_failed":"Could not reload the plan from the server: {err}","toast.locale_load_failed":"Could not load the language pack. English is used until the page reloads.","toast.furniture_art_load_failed":"Could not load the furniture drawings. Reload the page to show them.","room.settings_short":"Room settings","room.unnamed":"Unnamed room","marker.use_climate_temp":"Include the device temperature in the room","marker.use_climate_temp_tip":"Adds an air conditioner or thermostat current_temperature to the room average. Configure the external value badge separately below.","marker.value_badge_title":"Value badge","marker.value_badge.help":"Shows one selected value next to the icon. It does not affect room metrics, light, Glow or the tap action.","marker.value_badge.help.aria":"Help: device value badge","marker.value_badge_enabled":"Show a value badge","marker.value_badge_source":"Value","marker.value_badge_source.help":"Choose a specific state, supported attribute, or derived value of this device.","marker.value_badge_source.help.aria":"Help: value badge source","marker.value_badge_position":"Position","marker.value_badge_position.help":"The chosen side stays fixed and does not flip automatically at a plan edge.","marker.value_badge_position.help.aria":"Help: value badge position","marker.value_badge_right":"Right","marker.value_badge_bottom":"Below","marker.value_badge_left":"Left","marker.value_badge_top":"Above","marker.value_badge_empty":"This device has no available values","marker.value_badge_static":"A static icon does not show live values. The setting is preserved.","marker.value_badge_missing":"Source unavailable","marker.value_badge_missing_hint":"The saved source is currently unavailable. Keep it, disable the badge, or choose another value.","marker.value_badge_duplicate":"The same value is already shown inside the icon.","marker.value_badge_state":"State · {name}","marker.value_badge_marker_state":"Light-source state · {name}","marker.value_badge_lqi":"Average Zigbee signal quality","marker.value_badge_attr_current_temperature":"Current temperature · {name}","marker.value_badge_attr_temperature":"Target temperature · {name}","marker.value_badge_attr_current_humidity":"Current humidity · {name}","marker.value_badge_attr_humidity":"Humidity · {name}","marker.value_badge_attr_current_position":"Position · {name}","marker.value_badge_attr_percentage":"Speed · {name}","marker.value_badge_attr_brightness":"Brightness · {name}","marker.value_badge_attr_volume_level":"Volume · {name}","marker.value_badge_attr_battery_level":"Battery · {name}","marker.value_badge_attr_fan_speed":"Fan speed · {name}","marker.value_source":"Value source","marker.value_source.help":"Choose the value that replaces the icon. The tap action does not change.","marker.value_source.help.aria":"Help: value face source","marker.value_source_auto":"Automatic (as before)","marker.value_source_missing_hint":"The saved source is currently unavailable. The face shows — until it recovers or you choose another value.","marker.light_role_label":"Is this device a light source?","marker.light_role.help":"“Auto” uses the bound device's resolved role, “Always” forces its own source and “Never” excludes it; linked lights above remain independent.","marker.light_role.help.aria":"Help: whether this device is a light source","marker.light_role_auto_yes":"Auto (light source)","marker.light_role_auto_no":"Auto (not a light source)","marker.light_entity_label":"Leading light entity","marker.light_entity.help":"For a composite device, choose the entity whose state, colour and brightness represent this plan source. The automatic fallback remains compatible with older plans.","marker.light_entity.help.aria":"Help: leading light entity","marker.light_entity_auto":"Automatic ({entity})","marker.light_entity_none":"no controllable entity","marker.light_entity_missing":"The saved entity {entity} is unavailable. House Plan temporarily uses {fallback}; the saved choice will be restored if it returns.","marker.toggle_entity_label":"Entity to toggle","marker.toggle_entity.help":"For a composite device, choose the exact own light or switch operated by a tap. Automatic keeps the previous target rules and is independent from the leading light entity.","marker.toggle_entity.help.aria":"Help: entity to toggle","marker.toggle_entity_auto":"Automatic ({entity})","marker.toggle_entity_none":"no own controllable entity","marker.toggle_entity_missing":"The saved entity {entity} is no longer among this marker’s selectable channels. House Plan temporarily uses {fallback}; the saved choice will be restored if it returns.","marker.glow_color_label":"Glow colour and brightness","marker.glow_mode.help":"Use live source values, override only its colour, or fix both colour and brightness. The minimum is 1%; to disable the source, choose “Never”.","marker.glow_mode.help.aria":"Help: glow colour and brightness","marker.glow_mode_auto":"From source","marker.glow_mode_color":"Set colour","marker.glow_mode_fixed":"Colour and brightness","marker.glow_color":"Glow colour","marker.glow_brightness":"Brightness","marker.glow_disabled_never":"Glow settings are unavailable because this marker is explicitly not a light source.","marker.glow_disabled_auto":"Auto mode found no spatial light source for this marker.","marker.glow_disabled_no_entity":"No active controllable Home Assistant entity is available for this spatial source.","marker.glow_passive_hint":"This source has no own Home Assistant data. Set its colour and brightness manually; its radius remains available.","marker.control_broken":"Saved source is missing or no longer marked as a light","marker.control_missing_label":"Missing plan light","marker.control_passive":"passive source","toast.marker_control_cycle":"This link would create a circular chain of light controls.","toast.marker_binding_required":"Choose a Home Assistant device before linking another light source.","confirm.unlock_title":"Unlock?","confirm.unlock_body":"House Plan will send an unlock command to this lock.","toast.files_migrate_failed":"Attachments could not be moved to the new binding, links keep pointing at the old files: {err}","space.pick_saved":"Already uploaded","space.pick_saved_hint":"Plans stored on the server, including ones you detached earlier","space.no_saved":"No plans stored on the server yet.","space.loading":"Loading…","space.used_by":"in use: {list}","space.in_use":"A space still uses this plan — detach it first","btn.use":"Use","confirm.delete_plan_title":"Delete plan file?","confirm.delete_plan_body":"The file will be deleted from the server. This action cannot be undone.","toast.plans_list_failed":"Could not list the stored plans: {err}","toast.plan_delete_failed":"Could not delete the plan: {err}","marker.hide":"Hide","marker.hide_tip":'The device will disappear from the plan after saving but will still count toward the room signal. Restore it through the "Devices" catalog in the device editor.',"marker.show":"Show","marker.show_tip":"The device will appear on the plan again after saving.","marker.hidden_ghost":"Device hidden by the user","marker.ha_disabled_device":"The device is disabled in Home Assistant and hidden from the plan.","marker.ha_disabled_entity":"The entity is disabled in Home Assistant and hidden from the plan.","marker.ha_disabled_all_entities":"The device has no active Home Assistant entities, so it is hidden from the plan.","marker.ha_registry_limited":"The full Home Assistant registry is unavailable to this user. The unverified object cannot be shown or used for now.","marker.delete_tip":"Completely delete the device from the plan and every aggregate. You can add it again later.","tap.run":"Run automation/script/scene","tap.none":"Do nothing","marker.run_target_label":"What to run","marker.run_search_ph":"Search: automation, script or scene…","marker.run_target_gone":"Target {id} not found — pick again","marker.tap_confirm":"Ask for confirmation","marker.tap_confirm_tip":"Show a confirmation dialog before acting — a guard against accidental taps.","marker.toggle_hint_single":"Target: {name} ({id}).","marker.virtual_light_target":"Virtual light: {name}.","marker.virtual_light_current":"Manual state: {state} → {effect}.","marker.virtual_light_state_on":"on","marker.virtual_light_state_off":"off","marker.toggle_hint_group":"Will toggle {count} source(s): {names}.","marker.toggle_hint_current":"Now: {state} → {effect}.","marker.toggle_hint_group_current":"Currently on: {on} of {count} → {effect}.","marker.toggle_hint_skipped":"Will be skipped ({count}): {targets}.","marker.toggle_effect_turn_on":"will turn on","marker.toggle_effect_turn_off":"will turn off","marker.toggle_effect_open":"will open","marker.toggle_effect_close":"will close","marker.toggle_effect_stop":"will stop","marker.toggle_effect_toggle":"state will toggle","marker.toggle_skip_missing":"not found","marker.toggle_skip_ha_disabled":"disabled in HA","marker.toggle_skip_unavailable":"unavailable","marker.toggle_skip_unsupported":"toggle is unsupported","marker.toggle_skip_secure":"blocked for security","marker.toggle_none_no_binding":"This device has no binding, so there is no state to toggle. Tapping will do nothing.","marker.toggle_none_no_actionable_entity":"This device has no state that can be toggled. Tapping will do nothing.","marker.toggle_none_configured_targets_missing":"The configured targets are unavailable. The device's own entity will not be substituted for them.","marker.toggle_none_ha_disabled":"The target is disabled in Home Assistant and cannot be used on the plan.","marker.toggle_none_unavailable":"The target is currently unavailable. Tapping will do nothing.","marker.toggle_none_unsupported":"Home Assistant exposes no safe toggle operation for this entity. Tapping will do nothing.","marker.toggle_none_secure":"Toggling locks, alarms and secure gates from the plan is blocked for security.","run.automation":"automation","run.script":"script","run.scene":"scene","confirm.tap_run":'Run "{name}"?',"confirm.tap_toggle":'Toggle "{name}"?',"confirm.current_state":"Current state: {state}","confirm.expected_state":"After switching: {state}","confirm.group_current":"on {on} of {total}","confirm.group_all_on":"all are on","confirm.group_all_off":"all are off","confirm.unavailable_targets":"Unavailable: {count}","confirm.expected_by_ha":"Home Assistant will determine the state","confirm.state_on":"On","confirm.state_off":"Off","confirm.state_open":"Open","confirm.state_closed":"Closed","confirm.state_opening":"Opening","confirm.state_closing":"Closing","confirm.state_stopped":"Stopped","confirm.state_unknown":"Unknown","toast.run_started":"Started: {name}","toast.run_target_missing":"Run target not found — check the device settings","toast.run_target_required":"Pick an automation, script or scene","toast.tap_target_changed":"The action target changed. Try again.","toast.virtual_light_toggle_failed":"Could not toggle the virtual light: {err}","toast.value_badge_source_required":"Choose a value for the badge","btn.run":"Run","vac.section":"Robot vacuum: live position","vac.autocal":"Set up automatically","vac.live":"Live position on the plan","vac.trail":"Show the robot's path","vac.autocal_no_rooms":"The integration reports no room list — open “Fit manually”","vac.route_warn_unmapped":"The robot is cleaning a map that is not assigned to any floor","vac.route_warn_needs_calibration":"The map is assigned to a floor but not calibrated","vac.route_warn_ambiguous":"Two maps are indistinguishable — no floor was chosen","vac.route_warn_missing_space":"The space of this map was deleted","vac.autocal_no_match":"Room names did not match (need ≥3 in common) — open “Fit manually”","vac.autocal_done":"Done: bound via {rooms} rooms. Start a cleanup and check","vac.cal_need_pos":"The robot is not reporting coordinates — start a cleanup and pause it","vac.cal_done":"Calibration saved. Start a cleanup and check","vac.cal_cancelled":"Calibration cancelled","vac.fit":"Fit manually","vac.fit_hint":"Drag the robot map into place, stretch by the corners","vac.fit_rotate":"Rotate 90°","vac.fit_mirror":"Mirror","vac.trail_never":"Never","vac.trail_cleaning":"While cleaning","vac.trail_always":"Always","gs.bg_color":"Background around the plan","gs.bg_default":"Theme default","gs.bg_mode":"Plan background","gs.bg_mode.help":"“Follows the Sun” uses sun.sun, falling back to the browser's local clock; Static always shows the selected colour.","gs.bg_mode.help.aria":"Help: general plan background","gs.bg_static":"Static color","gs.bg_daynight":"Follows the Sun","gs.sun_group":"Sun","gs.sun_missing":"The sun.sun entity was not found — the background follows your local clock; window rays are unavailable.","gs.north":"North on the plan","gs.north.help":"The angle is measured clockwise from the plan's upward vertical; north is required for window rays, not for the “Follows the Sun” background.","gs.north.help.aria":"Help: general north direction","gs.north_ph":"not set","gs.north_clear":"Clear","gs.north_letter":"N","gs.sun_rays":"Sunlight through windows","gs.sun_ray_origin":"Sun rays","gs.sun_ray_origin.inner":"From the inner window corners","gs.sun_ray_origin.outer":"From the outer window corners","gs.about_version":"Houseplan Card v{v}","gs.about_github":"GitHub · docs & issues","gs.about_telegram":"Telegram chat","support.title":"Help & feedback","space.bg_color":"Background around the plan","space.bg_inherit":"Inherit general","space.bg_mode":"Plan background","space.bg_mode.help":"Inherit the general background or override this space with a static colour or “Follows the Sun”.","space.bg_mode.help.aria":"Help: space background","space.north":"North on the plan","space.north.help":"Overrides general north for this space; the angle is measured clockwise from the plan's upward vertical and is used by window rays.","space.north.help.aria":"Help: north for this space","space.sun_rays":"Sunlight through windows","space.sun_inherit":"General settings","space.sun_on":"On","space.sun_off":"Off","canvas.far_objects":"{n} object(s) far from the plan","canvas.show_far":"Show","canvas.home_tip":"The plan is over there — click to fit it","gs.grid_group":"Plan maintenance","gs.align_all":"Optimize plans","gs.align_title":"Optimize plans","gs.align_none":"All plans already use the current optimized data model.","gs.optimize_no_automatic_changes":"There are no automatic changes to apply. Review the items below.","gs.align_count":"{n} of {total} elements will move, by at most {cm} cm.","gs.align_where":"The largest shift is in “{s}”.","gs.align_turned":"Openings whose angle is corrected: {n}.","gs.align_preflight_failed":"Could not safely verify the geometry of the following spaces: {spaces}{more}.","gs.align_preflight_hint":"Plans were not changed. Copy the diagnostics with the button below and attach them to the bug report together with a space export.","gs.preflight_reason_prepare-exception":"Could not prepare the space geometry (exception while building the model)","gs.preflight_reason_wall-null":"The wall body did not build (the union came back empty)","gs.preflight_reason_wall-degraded-extra":"The wall body degraded with extra geometry","gs.preflight_reason_wall-failed-core":"The wall body core failed to assemble","gs.preflight_reason_wall-exception":"Wall construction threw an exception","gs.preflight_reason_floor-null":"The floor outline did not build","gs.preflight_reason_floor-exception":"Floor construction threw an exception","gs.preflight_copy":"Copy diagnostics","gs.preflight_copied":"Diagnostics copied","gs.preflight_update_hint":"The card and integration versions differ — update House Plan and retry.","gs.align_preflight_space":"Space {n}","gs.align_preflight_more":", and {n} more","gs.optimize_changes":"Model migrations: {m}; spaces updated: {c}; noisy coordinate values removed: {p}; merged real-wall fragments: {w}; merged zero-thickness wall fragments: {s}; independent walls: {i}.","gs.zero_walls_migrated":"Virtual wall spans converted: {n}.","gs.wall_segments_migrated":"Wall segments stabilised: {n}.","gs.room_drafts_migrated":"Unfinished contours converted to ordinary walls: {drafts}; wall segments: {segments}.","gs.optimize_lattice_summary":"Noisy coordinate values canonicalized: {n}; maximum movement: {cm} cm.","gs.optimize_lattice_space":"{space}: coordinate values canonicalized: {n}; off-grid values left unchanged: {far}.","gs.optimize_coincident_partitions":"Hidden independent wall sections absorbed into room walls: {n}.","gs.optimize_openings_rehosted":"Openings reattached to room walls: {n}.","gs.optimize_walls_straightened":"Walls straightened: {n}; maximum movement: {cm} cm.","gs.optimize_walls_straightened_where":"Largest wall correction: {s}.","gs.optimize_walls_straighten_skipped":"Near-axis walls left unchanged because they could not be repaired safely: {n}.","gs.optimize_glow_migration":"Legacy Glow: {spaces} spaces → no data fill + independent Glow; {rooms} rooms → inherited data fill + independent Glow.","gs.optimize_references":"References repaired: spaces — {spaces}; rooms — {rooms}; positions — {positions}; devices detached from missing spaces — {detached}.","gs.optimize_reference_more":", and {n} more","gs.optimize_orphans_removed":"Forgotten records removed: {total} — room labels: {rooms}; devices: {devices}; group markers: {groups}. They belonged to spaces deleted earlier.","gs.optimize_live_positions":"Old positions in deleted spaces belong to existing objects: {n}{names}. They will be kept.","gs.optimize_live_positions_remove":"Old positions in deleted spaces belong to existing objects: {n}{names}. They are selected for removal.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Remove old positions","gs.optimize_live_keep":"Keep old positions","gs.optimize_live_selected":"Old positions will be removed after Optimize is applied.","gs.optimize_unverified":"Could not safely verify positions: {n}. They were left unchanged.","gs.optimize_registry_limited":"Full administrator access to the Home Assistant registries is required for a safe check.","gs.optimize_vacuum_warning":"Vacuum room mappings that still need review: {n}.","gs.optimize_details":"Details","gs.optimize_details_more":"And {n} more records.","gs.optimize_detail_removed":"will be removed","gs.optimize_detail_live":"will be kept","gs.optimize_detail_unverified":"not verified","gs.optimize_detail_room_label":"room label","gs.optimize_detail_device":"device","gs.optimize_detail_group":"group marker","gs.optimize_detail_unknown":"unknown owner","gs.optimize_detail_item":"{status}: {kind} {id}; old space {space}","gs.align_warn":"Elements deliberately placed between grid nodes will move. One undo is available after the operation, only until the next plan edit.","gs.align_run":"Optimize","gs.align_done":"Plans optimized: {n} elements moved, {m} records maintained, {r} references repaired","gs.optimize_undo":"Undo last optimization","gs.optimize_undone":"The last optimization was undone","decor.furniture":"Furniture","decor.image":"Image","decor.image_title":"Custom images","decor.image_upload":"Upload image","decor.image_replace":"Replace image","decor.image_uploading":"Uploading…","decor.image_asset":"Image file","decor.image_pick_hint":"Upload an image or choose one already used in House Plan.","decor.image_place_hint":"Click on the plan to place the image.","decor.image_none":"No uploaded images yet.","decor.image_unavailable":"Image unavailable","decor.image_used":"Used in {n} objects","decor.image_upload_failed":"Could not upload the image: {err}","decor.image_error_capacity":"The custom image storage limit has been reached.","decor.image_in_use":"Remove every placed copy before deleting this image.","decor.image_delete_title":"Delete image file?","decor.image_delete_message":"Delete “{name}” from House Plan? This cannot be undone.","furn.title":"Furniture library","furn.symbol":"Symbol","furn.group_furniture":"Furniture","furn.group_appliance":"Appliances","furn.group_sanitary":"Plumbing","furn.group_other":"Other","furn.width":"Width","furn.depth":"Depth","furn.back_to_categories":"All categories","furn.pick_hint":"Choose a category, then a symbol.","furn.place_hint":"Click on the plan — the piece lands against the nearest wall. Shift places it free.","furn.cat_air_conditioner":"Air conditioners","furn.cat_armchair":"Armchairs","furn.cat_bathtub":"Bathtubs","furn.cat_bed":"Beds","furn.cat_bidet":"Bidets","furn.cat_boiler":"Water heaters","furn.cat_chair":"Chairs","furn.cat_coffee_table":"Coffee tables","furn.cat_computer":"Computer","furn.cat_cooktop":"Cooktops","furn.cat_dining_table":"Dining tables","furn.cat_dishwasher":"Dishwashers","furn.cat_dryer":"Dryers","furn.cat_fireplace":"Fireplaces","furn.cat_fridge":"Refrigerators","furn.cat_hood":"Cooker hood","furn.cat_kitchen_cabinet":"Kitchen cabinets","furn.cat_kitchen_sink":"Kitchen sinks","furn.cat_nightstand":"Cabinets","furn.cat_oven":"Oven","furn.cat_plant":"Plants","furn.cat_rug":"Rugs","furn.cat_shelving":"Shelving","furn.cat_shower":"Showers","furn.cat_sink":"Sinks","furn.cat_sofa":"Sofas","furn.cat_stairs":"Stairs","furn.cat_toilet":"Toilets","furn.cat_tv":"Televisions","furn.cat_wardrobe":"Wardrobes","furn.cat_washer":"Washing machines","furn.cat_work_table":"Desks","furn.sym_cactus":"Cactus","furn.sym_computer":"Computer","furn.sym_hood":"Cooker hood","furn.sym_oven":"Oven","furn.sym_sofa":"Two-seat sofa","furn.sym_sofa_three_seat":"Three-seat sofa","furn.sym_sofa_corner_right":"Right sectional sofa","furn.sym_armchair":"Soft armchair","furn.sym_armchair_office":"Office chair","furn.sym_coffee_table":"Rectangular coffee table","furn.sym_coffee_table_round":"Round coffee table","furn.sym_coffee_table_oval":"Oval coffee table","furn.sym_coffee_table_rounded":"Rounded coffee table","furn.sym_table_dining":"Rectangular dining table","furn.sym_table_round":"Round table","furn.sym_table_dining_oval":"Oval dining table","furn.sym_table_dining_rounded":"Rounded dining table","furn.sym_chair":"Chair","furn.sym_chair_bar":"Bar stool","furn.sym_desk":"Rectangular desk","furn.sym_desk_corner":"Corner desk","furn.sym_bed_double":"Double bed","furn.sym_bed_single":"Single bed","furn.sym_nightstand":"Bedside table","furn.sym_cabinet_tv":"TV cabinet","furn.sym_cabinet_shoe":"Shoe cabinet","furn.sym_cabinet_sink":"Sink cabinet","furn.sym_wardrobe":"Wardrobe","furn.sym_bookshelf":"Bookcase","furn.sym_wall_unit":"Wall unit","furn.sym_kitchen_floor":"Kitchen floor module","furn.sym_kitchen_floor_corner":"Kitchen floor corner module","furn.sym_kitchen_wall":"Kitchen wall module","furn.sym_kitchen_wall_corner":"Kitchen wall corner module","furn.sym_shelf_floor":"Floor shelving unit","furn.sym_shelf_wall":"Wall shelf","furn.sym_fridge":"Fridge","furn.sym_stove":"Four-burner cooktop","furn.sym_cooktop_two":"Two-burner cooktop","furn.sym_dishwasher":"Dishwasher","furn.sym_washer":"Washing machine","furn.sym_dryer":"Tumble dryer","furn.sym_tv":"TV on stand","furn.sym_tv_wall":"Wall-mounted TV","furn.sym_ac":"Air conditioner","furn.sym_water_heater":"Water heater","furn.sym_toilet":"Floor-standing toilet","furn.sym_toilet_built_in":"Built-in toilet","furn.sym_bathtub":"Rectangular bathtub","furn.sym_bathtub_corner":"Corner bathtub","furn.sym_shower":"Shower","furn.sym_sink":"Washbasin","furn.sym_kitchen_sink":"Single kitchen sink","furn.sym_kitchen_sink_double":"Double kitchen sink","furn.sym_bidet":"Floor-standing bidet","furn.sym_bidet_built_in":"Built-in bidet","furn.sym_stairs":"Stairs","furn.sym_fireplace":"Fireplace","furn.sym_plant":"Plant","furn.sym_rug":"Rug","common.yes":"Yes","common.no":"No","vac.diag_source":"Source","vac.diag_platform":"Integration","vac.diag_status":"Status","vac.diag_position":"Position","vac.diag_rooms":"Rooms","vac.diag_rooms_value":"{total} · {matched} names match · {readiness}","vac.autocal_ready":"auto-calibration available","vac.autocal_not_ready":"need 3 matching names","vac.diag_path":"Integration path","vac.diag_map":"Map ID","vac.source_none":"not selected","vac.source_status_ok":"Ready","vac.source_status_missing":"Missing","vac.source_status_disabled":"Disabled in Home Assistant","vac.source_status_unavailable":"Unavailable","vac.source_status_unverified":"Cannot verify with current permissions","vac.source_status_unsupported":"No position data","vac.source_status_none":"No source","vac.source_banner_missing":"The saved source no longer exists. It was not replaced automatically; choose another source or restore it in Home Assistant.","vac.source_banner_disabled":"The saved source is disabled in Home Assistant. Enable it there or choose another source.","vac.source_banner_unverified":"Current Home Assistant permissions cannot verify this saved source. It remains pinned and will not be replaced automatically.","vac.choose_source":"Choose source","vac.source_auto":"Automatic","vac.source_auto_hint":"Use a compatible entity from this device","vac.all_cameras":"All cameras","vac.all_cameras_warn":"A camera may not provide robot data. Choose one only if it is your vacuum map.","vac.all_cameras_empty":"No other camera entities found.","vac.platform_unknown":"unknown integration","vac.cap_position":"position","vac.cap_rooms_short":"rooms","vac.cap_path":"path","vac.cap_map":"map ID","vac.cap_none":"no robot data detected","vac.xcme_hint":"Enable these Xiaomi Cloud Map Extractor attributes:","vac.documentation":"Documentation","vac.residual_title":"Check automatic calibration","vac.residual_message":"The matched rooms disagree by up to {error}. Apply this approximate calibration, refine it manually, or cancel without changing the saved setup.","vac.apply_proposal":"Apply","gs.backup_group":"Backup and transfer","backup.export_open":"Export","backup.import_open":"Import","backup.export_title":"Export House Plan","backup.import_title":"Import House Plan","backup.export_hint":"Choose whether the backup should contain the whole House Plan configuration or only the current space.","backup.full":"Full backup","backup.current_space":"Current space","backup.current_space_title":"Current space: {title}","backup.no_current_space":"No current space","backup.plan_only":"Plan only","backup.plan_only_hint":"Keep rooms, walls, openings, decor and room-label positions without devices or Home Assistant bindings.","backup.plan_only_preview":"This file contains the plan only","backup.privacy_warning":"The archive keeps names, Home Assistant identifiers and exact coordinates. Internal plans and attachments are referenced, not embedded; runtime states and vacuum trails are not included.","backup.download":"Download JSON","backup.export_done":"Backup downloaded","backup.reading":"Checking the backup…","backup.revalidated":"The plan changed after this preview. The summary was refreshed; review it and confirm again.","backup.error.support_invalid_message":"Check the support message and try again.","backup.error.support_package_too_large":"The anonymized support package exceeds the 8 MiB limit.","backup.error.support_preview_expired":"The support attachment preview expired or is no longer available.","backup.error.support_rate_limited":"Too many support reports or previews were requested. Try again later.","backup.error.support_rejected":"The report did not pass support service validation.","backup.error.support_unavailable":"The private support service is temporarily unavailable.","backup.error.unauthorized":"You do not have permission to export or import this plan.","backup.error.not_ready":"House Plan is not ready yet. Try again in a moment.","backup.error.too_large":"The backup exceeds the 8 MiB limit.","backup.error.invalid_json":"The selected file is not valid JSON.","backup.error.invalid_format":"The selected file is not a House Plan backup.","backup.error.invalid_image":"The image is damaged or does not match its format.","backup.error.unsupported_export_version":"This backup format is not supported by the installed version.","backup.error.unsupported_image":"Use a supported PNG, JPEG, WebP or SVG image.","backup.error.future_model":"The backup was created by a newer House Plan data model.","backup.error.invalid_config":"The backup contains an invalid House Plan configuration.","backup.error.wall_model_migration_blocked":"The backup wall model could not be upgraded safely. Optimize the source plan first, then export it again.","backup.error.invalid_layout":"The backup contains invalid object positions.","backup.error.invalid_content":"The backup contains invalid or inconsistent content references.","backup.error.space_not_found":"The selected space no longer exists.","backup.error.capacity_exceeded":"Adding this backup would exceed the plan limits.","backup.error.preview_expired":"The preview expired. Select the backup file again.","backup.error.preview_owner_mismatch":"This preview belongs to another Home Assistant user.","backup.error.conflict":"The plan changed after the preview. Review the refreshed summary.","backup.error.content_confirmation_required":"Confirm that unavailable local content may be detached.","backup.error.commit_failed":"The backup could not be applied safely. The previous plan was restored or is pending recovery.","backup.error.missing_plan":"A referenced plan file disappeared after the preview. Review the backup again.","backup.error.missing_content":"A referenced local attachment disappeared after the preview. Review the backup again.","backup.error.marker_control_missing":"A linked plan light is missing from the backup.","backup.error.marker_control_not_light":"A linked plan target is no longer marked as a light source.","backup.error.marker_control_self":"A light source cannot control itself.","backup.error.marker_control_cycle":"The backup contains a circular chain of light controls.","backup.error.duplicate_marker_control":"The backup contains a duplicate plan-light link.","backup.error.no_backup":"There is no import or optimization snapshot to restore.","backup.error.in_use":"The item is still in use","backup.error.invalid_data":"The request carries invalid data","backup.error.invalid_light_entity":"The leading light must be a light.* or switch.* entity","backup.error.invalid_marker_control":"Invalid marker control reference","backup.error.invalid_name":"The name is invalid","backup.error.invalid_partition_opening_host":"The opening must keep its partition host","backup.error.invalid_partition_opening_jamb_margin":"The opening leaves no physical jamb at the wall end","backup.error.invalid_passage_fields":"An open passage cannot carry door-only settings","backup.error.invalid_space_id":"Unknown space","backup.error.invalid_toggle_entity":"The toggle entity must be light.* or switch.*","backup.error.invalid_value_badge":"Invalid value badge settings","backup.error.invalid_value_badge_attribute":"Invalid value badge attribute","backup.error.invalid_value_badge_position":"Invalid value badge position","backup.error.invalid_value_badge_source":"Invalid value badge source","backup.error.invalid_vacuum_map_route":"Check how the robot's maps are assigned to spaces.","backup.error.invalid_value_source":"Invalid value source","backup.error.invalid_value_source_attribute":"Invalid value source attribute","backup.error.io_error":"A file operation failed on the server","backup.error.not_toggleable":"This device cannot be toggled","backup.error.nothing_to_repair":"Nothing to repair","backup.error.space_in_use":"The space is still referenced","backup.error.value_badge_source_required":"The value badge needs a source","backup.error.wall_model_client_outdated":"The plan was updated elsewhere — reload the page","backup.same_source":"Created on this Home Assistant instance","backup.foreign_source":"Created on another Home Assistant instance","backup.created":"Created: {value}","backup.versions":"Card {card}; integration {integration}; data model {model}","backup.count_spaces":"Spaces: {n}","backup.count_rooms":"Rooms: {n}","backup.count_walls":"Walls: {n}","backup.count_openings":"Openings: {n}","backup.count_decor":"Decor objects: {n}","backup.count_markers":"Devices: {n}","backup.count_layout":"Positions: {n}","backup.bindings":"Bindings — devices: {device}, entities: {entity}, virtual: {virtual}; positions without a space: {legacy}","backup.binding_status":"Target status — active: {active}, disabled: {disabled}, missing: {missing}","backup.missing_areas":"Areas missing on the target: {areas}","backup.dropped_marker_links":"Plan-light links outside this transferred space were omitted: {n}.","backup.room_drafts_migrated":"Legacy unfinished contours converted to ordinary walls: {drafts}; wall segments: {segments}.","backup.repaired_target_refs":"Existing references restored by this space import: {n}.","backup.preserved_unresolved_refs":"References that could not be restored unambiguously were preserved: {n}.","backup.preserved_unresolved_hint":"No data was guessed or deleted. After the import, run Optimize plans to inspect the remaining references.","backup.import_details":"Import reference details","backup.import_detail.incoming_remapped":"References updated inside the imported copy: {n}","backup.import_detail.target_repaired":"Existing references restored: {n}","backup.import_detail.preserved_unresolved":"Unresolved references preserved: {n}","backup.import_detail.collisions":"Destination conflicts preserved safely: {n}","backup.import_detail.dropped_links":"Incoming links omitted by transfer rules: {n}","backup.import_detail.bounded_lineages":"Overly nested identifiers left bounded: {n}","backup.replace_warning":"This replaces the current configuration and layout. Uploaded files are never deleted. One undo remains available until the next plan edit.","backup.foreign_bookkeeping":"Instance-specific known/new-device bookkeeping will not be imported.","backup.final_name":"New space name","backup.target_settings":"The target instance's global settings remain unchanged.","backup.duplicates":"Bindings already present: {n}","backup.skip":"Skip duplicate devices","backup.virtual_copy":"Add safe static virtual copies","backup.content":"Referenced content","backup.decor_images_summary":"Custom images: {objects} objects, {assets} files; missing files: {missing}.","backup.content_available":"available locally","backup.content_external":"external link","backup.content_detach_required":"will be detached","backup.confirm_detach":"I understand that unavailable internal plans and attachments will be detached from the imported configuration.","backup.confirm_missing_images":"I understand that missing custom images will remain as repair placeholders and other unavailable local files will be detached.","backup.replace":"Replace","backup.add":"Add space","backup.space_done":"Space imported: {rooms} rooms, {markers} devices, {refs} existing references restored","backup.full_done":"Backup restored: {spaces} spaces, {rooms} rooms, {markers} devices","backup.undo_import":"Undo last full import","backup.import_undone":"Full import undone","backdrop.large_title":"Large image","backdrop.large_body":"This image is {w}×{h} ({fileMb} MB file) and needs about {decodedMb} MB of memory to display. On tablets this can crash the page.","backdrop.unknown_body":"The image dimensions could not be read — the file may be damaged. Continuing may crash the page on tablets.","backdrop.reduced_dimensions":"Reduced copy: {w}×{h} px.","backdrop.use_downscaled":"Upload a reduced copy","backdrop.reducing":"Reducing…","backdrop.keep_original":"Keep the original","backdrop.too_large_title":"Image is too large","backdrop.too_large_body":"This image exceeds what browsers can display ({w}×{h}, limit {limit} px per side). Please reduce it in a desktop editor and upload again.","backdrop.downscale_failed":"Could not create the reduced copy. The original plan was not changed.","gs.card_display":"Display","gs.card_zigbee":"Zigbee links","gs.card_fills":"Room fill colors","gs.card_plan":"Plan","gs.card_data":"Data","gs.card_fills.help.aria":"About room fill colors","gs.backup_group.help.aria":"About backup and transfer","gs.grid_group.help.aria":"About plan maintenance","gs.backup_group.help":"Download a portable JSON backup or preview and import a backup made by House Plan.","gs.grid_group.help":"Updates data models, aligns plan elements to the grid and merges redundant wall fragments. An exact report is shown before anything is stored.","gs.card_fills.help":"Fill colors apply to every space; each color has its own opacity. Which fill mode a space uses is set in that space's dialog.","space.card_basics":"Basics","space.card_sun":"Sun & light","marker.card_basics":"Basics","marker.card_tap":"Tap action","marker.card_light":"Light and glow","marker.card_appearance":"Appearance","marker.card_details":"Details"};const cp=new WeakSet,hp=new WeakSet;function dp(e,t,i){const n=i?t.state(i):"ready";return i&&"pending"===n?(hp.has(e)||(e.inert=!0,e.setAttribute("aria-busy","true"),hp.add(e)),t.ensure(i).then(()=>{e.isConnected&&e.requestUpdate()}),cp.has(e)?"warm":"cold"):(hp.delete(e)&&(e.inert=!1,e.removeAttribute("aria-busy")),i&&(e.setAttribute("lang","fallback"===n?"en":i),cp.add(e)),"ready")}function up(){return j``}const pp=[{code:"en",nativeLabel:"English",dictionary:lp},{code:"ru",nativeLabel:"Русский",dictionary:{"editor.context_actions":"Действия: {object}","editor.tool_options":"Параметры инструмента: {tool}","editor.palette":"Палитра: {tool}","editor.open_group":"Группа инструментов: {group}","editor.group_active":"{group} — активно: {item}","editor.disabled_action":"{action} недоступно: {reason}","editor.loading":"Загрузка…","editor.loading_aria":"Редактор плана загружается","editor.load_failed":"Не удалось загрузить редактор.","editor.refresh_advice":"Обновите страницу и повторите попытку.","editor.retry_advice":"Проверьте сеть и нажмите ещё раз.","version_mismatch.title":"Версии House Plan не совпадают","version_mismatch.body":"Если Home Assistant ещё перезапускается, дождитесь завершения, затем перезагрузите эту страницу.","version_mismatch.frontend":"Карточка","version_mismatch.backend":"Интеграция","version_mismatch.reload":"Перезагрузить страницу","color_picker.title":"Выбор цвета","color_picker.hue":"Оттенок","color_picker.saturation":"Насыщенность","color_picker.value":"Яркость","color_picker.hex":"Цвет HEX","color_picker.invalid_hex":"Введите цвет HEX из 3 или 6 цифр","color_picker.confirm":"ОК","btn.properties":"Свойства","btn.keep_as_walls":"Оставить стенами","btn.delete_room_keep_walls":"Удалить комнату, оставить стены","btn.delete_room_with_walls":"Удалить комнату и стены","title.markup_select":"Выбор и редактирование стен и колонн","title.markup_column":"Колонна: кликните точку сетки для квадратной колонны","markup.partition":"Перегородка","markup.column":"Колонна","markup.hint_column":"кликните точку сетки, чтобы поставить квадратную колонну","history.wall_segment":"Добавление отрезка стены","history.column_add":"Добавление колонны","history.physical_edit":"Изменение физического объекта","history.physical_delete":"Удаление физического объекта","history.physical_move":"Перемещение физического объекта","history.wall_face_batch":"Создание комнат из стен","toast.column_duplicate":"Колонна с тем же центром и внешним размером уже существует","physical.partition_properties":"Свойства перегородки","physical.column_properties":"Свойства колонны","physical.shape":"Форма","physical.square":"Квадрат","physical.circle":"Круг","physical.diameter":"Диаметр","physical.side":"Сторона","physical.rotation":"Угол поворота","physical.length":"Длина","physical.allowed_range":"Допустимо: {min}–{max} {unit}","physical.column_size_title":"Внешняя сторона квадратной колонны, создаваемой кликом (1–150 см).","card.title":"План дома","count.devices":"{n} устр.","empty.no_spaces":"Пространств пока нет.","nav.spaces":"Пространства House Plan","empty.add_first":"Добавьте первое пространство и загрузите план этажа.","empty.read_only":"Пространства не настроены. Попросите администратора добавить первое.","empty.install":"Установите интеграцию House Plan и добавьте запись в «Устройства и службы».","btn.add_space":"Добавить пространство","btn.cancel":"Отмена","btn.save":"Сохранить","btn.close":"Закрыть","btn.delete":"Удалить","btn.copy":"Копировать","btn.edit":"Редактировать","btn.open_in_ha":"Открыть в HA","btn.reset":"Сброс","btn.attach":"Прикрепить…","btn.upload":"Загрузить…","btn.replace":"Заменить…","title.zoom_in":"Приблизить","title.zoom_out":"Отдалить","title.zoom_fit":"Вписать всё","title.configure_space":"Настроить пространство","title.add_space":"Добавить пространство","title.markup_add":"Стены: рисуйте непрерывную цепочку; каждый принятый отрезок сохраняется отдельно. Shift фиксирует 45°","title.markup_merge":"Объединить: клик по одной комнате, затем по соседней с общей стеной","title.markup_split":"Разделить комнату: клик по комнате, затем две точки на её стенах","title.markup_delroom":"Удалить комнату: кликните внутри комнаты и подтвердите удаление","markup.add":"Стены","markup.merge":"Объединить","markup.split":"Разделить","markup.resize":"Размер","title.markup_resize":"Изменение размера комнат: тяните доступную ручку горизонтальной или вертикальной стены","markup.hint_resize":"тяните доступную ручку стены · стена упирается в первую небезопасную позицию · Esc — отмена · Ctrl+Z — отмена шага","resize.disabled.diagonal":"Стена расположена под углом: Resize поддерживает только горизонтальные и вертикальные стены","resize.disabled.side-angle":"Примыкающая стена расположена под углом: для Resize обе примыкающие стены должны образовывать прямой угол","resize.disabled.duplicate-physical-wall":"Стену перекрывает отдельная перегородка или колонна; удалите или переместите её перед изменением размера","resize.disabled.partial-shared":"Соседняя комната использует только часть этой стены, поэтому её нельзя безопасно двигать как одну общую стену","resize.disabled.unequal-shared":"У соседней комнаты другие конечные точки или длина стены, поэтому стены нельзя безопасно двигать вместе","resize.disabled.multiple-rooms":"Перемещение затронуло бы больше двух комнат","resize.disabled.thickness-conflict":"Толщину стены нельзя безопасно сохранить","resize.disabled.opening-conflict":"Проём на этой стене нельзя безопасно переместить","resize.disabled.invalid-geometry":"Эту стену нельзя переместить без изменения структуры плана","resize.limit_stopped":"Стена остановлена: дальше нарушается ограничение стыков","resize.commit_failed":"Изменение размера отменено: итоговый план не прошёл проверку геометрии","resize.preview_failed":"Стена остановлена в последней безопасной позиции: геометрию плана нельзя сохранить без потерь","markup.opening":"Проём","markup.delete_room":"Удалить комнату","history.undo":"Отменить","history.redo":"Повторить","history.undo_named":"Отменить: {name} (Ctrl+Z)","history.redo_named":"Повторить: {name} (Ctrl+Shift+Z / Ctrl+Y)","history.undo_empty":"Нет операций для отмены","history.redo_empty":"Нет операций для повтора","history.undone":"Отменено: {name}","history.redone":"Повторено: {name}","history.add_room":"Создание комнаты","history.split_room":"Разделение комнаты","history.merge_rooms":"Объединение комнат","history.resize_room":"Изменение размера комнаты","history.wall_thickness":"Изменение толщины стены","history.add_opening":"Добавление дверного или оконного проёма","history.edit_opening":"Изменение проёма","history.move_opening":"Перемещение проёма","history.delete_opening":"Удаление проёма","history.delete_room_keep_walls":"Удаление комнаты с сохранением стен","history.delete_room_with_walls":"Удаление комнаты и её стен","history.decor_add":"Добавление объекта декора","history.decor_edit":"Изменение объекта декора","history.decor_move":"Перемещение объекта декора","history.decor_transform":"Трансформация объекта декора","history.decor_delete":"Удаление объекта декора","history.backdrop_transform":"Трансформация подложки плана","history.device_move":"Перемещение: {name}","history.device_stale":"История позиций больше неприменима и была очищена","opening.new":"Новый проём","opening.edit":"Проём","opening.door":"Дверь","opening.window":"Окно","opening.gate":"Ворота","opening.passage":"Открытый проём","opening.passage_binding_warning":"При сохранении датчик открытия и замок будут удалены.","opening.invalid_passage_fields":"У открытого проёма на плане «{room}» есть недопустимые параметры: {fields}.","opening.type_label":"Тип","opening.length_label":"Длина, см","opening.contact_label":"Датчик открытия","opening.lock_label":"Замок","opening.none":"— нет —","opening.search_ph":"Поиск: имя или entity_id…","opening.invert":"Инвертировать открыто/закрыто","opening.flip_h":"Петли с другой стороны","opening.flip_v":"Открывается в другую сторону","opening.open":"Открыто","opening.closed":"Закрыто","opening.locked":"Заперто","opening.unlocked":"Не заперто","opening.state_unknown":"недоступно","opening.no_entities":"Датчики не привязаны — статичный символ на плане.","toast.opening_no_wall":"Кликните рядом со стеной комнаты или независимой стеной","opening.host_partition":"Независимая стена","opening.partition_orphan":"Независимая стена этого проёма больше не существует","opening.partition_jamb_margin":"Оставьте от края проёма до торца стены минимум {distance}","opening.rebind_partition":"Привязать к другой независимой стене","confirm.delete_partition_openings_title":"Удалить стену и проёмы?","confirm.delete_partition_openings_body":"В стене есть проёмы: {count}. Они будут удалены вместе со стеной.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.hint_points":"точек: {n} · Shift — шаг 45° · Esc — завершить цепочку · Ctrl+Z — убрать точку · при замыкании будет предложена комната","markup.hint_start":"кликните точку сетки, чтобы начать цепочку стен","tip.lqi":"средний сигнал zigbee:","tip.area":"площадь: {value}","info.device_header":"Устройство на плане","info.model":"Модель","info.state":"Состояние","info.link":"Ссылка","info.manuals":"Инструкции","info.none":"Нет дополнительной информации","marker.new_device":"Новое устройство","marker.name_label":"Название","marker.name_ph":"Название","marker.binding_label":"Привязка к устройству HA","marker.binding_disabled":"деактивировано в Home Assistant","marker.virtual_option":"Виртуальное устройство (без привязки)","marker.search_ph":"Поиск устройства / группы…","marker.nothing_found":"ничего не найдено","marker.room_label":"Комната","marker.room_choose":"— выберите комнату —","marker.room_auto":"— по зоне устройства (авто) —","marker.icon_label":"Иконка","marker.icon_ph":"mdi:… (пусто = авто)","marker.display_label":"Отображение","display.badge":"Значок + состояние","display.icon_ripple":"Значок + состояние и активность","display.static_icon":"Всегда статичный значок","display.value_static_icon":"Значение + статичный значок","marker.display_hint_badge":"Значок и динамическая подложка показывают состояние устройства без обычной пульсации активности. Красная тревога сохраняется.","marker.display_hint_icon_ripple":"Значок, динамическая подложка и пульсация: короткая — для событий, постоянная — для работы, движения или присутствия. Красная тревога имеет отдельный приоритет.","marker.display_hint_value":"Значок заменяется выбранным или автоматически найденным значением Home Assistant; подложка продолжает показывать состояние. Красная тревога сохраняется.","marker.display_hint_static_icon":"Подложка в цветах темы и значок всегда остаются одинаковыми. Состояния, активность, недоступность и тревоги не меняют отображение.","marker.display_hint_value_static_icon":"Маркер показывает выбранное значение, а подложка остаётся в цветах темы. Состояния, активность, недоступность и тревоги не меняют цвет маркера.","marker.static_alarm_warning":"Это устройство может сообщать о тревогах. Статичный режим скрывает визуальную тревогу маркера.","marker.preview.title":"Предпросмотр отображения","marker.preview.actual":"Сейчас","marker.preview.example":"Пример","marker.preview.integration":"Интеграция","marker.preview.source":"Источник отображения","marker.preview.current_state":"Текущее состояние","marker.preview.result":"На плане","marker.preview.details":"Подробнее об источниках","marker.preview.select_source":"Выберите устройство или сущность Home Assistant, чтобы увидеть фактическое отображение.","marker.preview.unknown_provider":"Интеграция неизвестна","marker.preview.virtual_provider":"House Plan · виртуальное устройство","marker.preview.no_source":"Нет активного источника","marker.preview.no_state":"Нет текущего состояния","marker.preview.mixed_states":"Несколько разных состояний","marker.preview.multiple_sources":"Источников: {n}","marker.preview.more_sources":"ещё {n}","marker.preview.scaled":"Предпросмотр уменьшен до {n}%, чтобы поместиться. Сохранённый размер не изменится.","marker.preview.demo_short":"Показать краткую активность","marker.preview.demo_continuous":"Показать постоянную активность","marker.preview.stop_continuous":"Остановить постоянную активность","marker.preview.demo_short_notice":"Пример краткой активности; фактическое состояние устройства не меняется.","marker.preview.demo_continuous_notice":"Пример постоянной активности; фактическое состояние устройства не меняется.","marker.preview.demo_already_visible":"Текущее состояние уже показывает реальную активность или тревогу.","marker.preview.reduced_motion":"В системе включено уменьшение движения, поэтому обычная активность показана точкой.","marker.preview.reason.neutral":"Нейтральная тёмная подложка","marker.preview.reason.working":"Жёлтая подложка: устройство сейчас работает","marker.preview.reason.working_activity":"Жёлтая подложка и эффект активности: устройство сейчас работает","marker.preview.reason.open":"Оранжевая подложка: физически открыто или разблокировано","marker.preview.reason.cover_icon_state":"Нейтральная подложка; состояние и значок определяет сущность шторы или заслонки","marker.preview.reason.presence":"Эффект активности, пока обнаружено присутствие","marker.preview.reason.event":"Короткий эффект активности после события","marker.preview.reason.transition":"Эффект активности во время движения или смены состояния","marker.preview.reason.media_neutral":"Медиаустройство остаётся на нейтральной тёмной подложке, пока доступно","marker.preview.reason.unavailable":"Приглушённая нейтральная подложка: отключено или недоступно","marker.preview.reason.alarm":"Красная тревожная подложка; тревога отображается всегда","marker.preview.reason.live_states_disabled":"Оформление по живым состояниям отключено в настройках карточки","marker.preview.reason.value_no_state":"Нет подходящего значения состояния — вместо него показан значок","marker.preview.reason.value_ambiguous_sources":"Подходит несколько источников значения — вместо него показан значок","marker.preview.reason.value_non_scalar":"Источник вернул не простое значение — вместо него показан значок","marker.preview.reason.value_virtual":"У виртуального устройства нет значения HA — вместо него показан значок","marker.preview.reason.vacuum_live_plan_only":"Живая позиция и след пылесоса доступны только на полном плане","marker.preview.reason.hidden_design_preview":"Устройство скрыто на плане, но его оформление видно в предпросмотре","marker.preview.reason.composite_power_source":"Состояние берётся из сущности питания устройства; вспомогательные переключатели не учитываются","marker.preview.reason.activity_display_disabled":"Выбранный режим отображения не показывает обычные эффекты активности","marker.preview.reason.ha_disabled":"Привязка отключена в Home Assistant, поэтому устройство будет скрыто на плане","marker.preview.reason.orphaned":"Сохранённая привязка Home Assistant больше не найдена","marker.preview.reason.static_icon":"Статичный режим: состояние устройства не меняет значок","marker.preview.reason.value_static_icon":"Статичный режим со значением: состояние устройства не меняет цвет маркера","marker.activity_color":"Цвет пульсации активности","marker.ripple_size":"Размер пульсации активности","marker.activity_alarm_note":"Цвет и размер относятся только к обычной активности и не влияют на красную тревогу.","marker.pulse_a11y_alarm":"Тревога","marker.pulse_a11y_event":"Недавнее событие","marker.pulse_a11y_presence":"Обнаружено присутствие","marker.pulse_a11y_transition":"Изменение состояния","marker.pulse_a11y_running":"Работает","marker.state_a11y_neutral":"Обычное состояние","marker.state_a11y_working":"Работает","marker.state_a11y_open":"Открыто","marker.state_a11y_locked":"Заблокировано","marker.state_a11y_unlocked":"Разблокировано","marker.state_a11y_alarm":"Тревога","marker.state_a11y_unavailable":"Недоступно","marker.lqi_a11y_low":"LQI {value}, слабый сигнал","marker.lqi_a11y_mid":"LQI {value}, средний сигнал","marker.lqi_a11y_high":"LQI {value}, сильный сигнал","marker.size_label":"Размер и поворот иконки","marker.angle_label":"Поворот","marker.model_label":"Модель","marker.model_ph":"напр. Aqara T&H","marker.link_label":"Ссылка","marker.desc_label":"Описание","marker.desc_ph":"Заметки, характеристики…","marker.manuals_label":"Инструкции (PDF и т.п.)","marker.sub_device":"устройство","marker.sub_z2m_group":" · Z2M-группа","marker.sub_group":"группа","marker.sub_helper":"хелпер","space.new":"Новое пространство","space.copy_title":"Копирование пространства","space.copy_name":"Название нового пространства","space.copy_fallback":"Пространство","space.copy_create":"Создать копию","space.copy_optimize_title":"Оптимизировать перед копированием?","space.copy_optimize_body":"Перед созданием «{name}» House Plan должен оптимизировать весь план, включая другие пространства. Продолжить?","space.copy_optimize_confirm":"Оптимизировать и скопировать","space.copy_error_changed":"План изменился, пока было открыто подтверждение. Проверьте его и повторите попытку.","space.copy_error_source_missing":"Исходного пространства больше нет. Снова откройте его настройки и повторите попытку.","space.copy_error_source_invalid":"House Plan не смог проверить все стены этого пространства. Исправьте исходное пространство и повторите попытку.","space.copy_error_spaces_limit":"В House Plan уже создано максимальное число пространств.","space.copy_error_partitions_limit":"В этом пространстве слишком много стен для копирования.","space.copy_error_openings_limit":"В этом пространстве слишком много проёмов для копирования.","space.copy_error_decor_limit":"В этом пространстве слишком много элементов подложки для копирования.","space.copy_error_columns_limit":"В этом пространстве слишком много колонн для копирования.","space.copy_error_opening_host":"Один из проёмов больше не привязан к стене. Исправьте или удалите его перед копированием.","space.copy_error_geometry":"Копия создаст небезопасную геометрию стен. Исправьте исходное пространство и повторите попытку.","space.copy_error_optimize_geometry":"Копирование остановлено: оптимизация всего плана небезопасна для одного из пространств.","space.header":"Пространство","space.title_label":"Название пространства","space.title_ph":"Например: Гараж","space.plan_label":"Подложка","space.no_plan":"нет подложки","space.plan_alt":"план","room.new":"Новая комната","room.name_label":"Отображаемое имя","room.name_ph":"Например: Терраса","room.area_label":"Зона Home Assistant","room.no_area_option":"— без зоны —","room.default_name":"Комната","device.unnamed":"без имени","device.light_group":"группа света","device.fallback":"устройство","device.virtual":"виртуальное устройство","confirm.delete_room_title":"Удалить комнату «{name}»?","confirm.delete_room_body":"Выберите, нужно ли оставить физические стены, принадлежащие только этой комнате. Общие с другой комнатой стены сохраняются всегда.","confirm.remove_marker_title":"Удалить устройство с плана?","confirm.remove_marker_body":"Устройство исчезнет полностью и перестанет участвовать в данных плана. Позже его можно будет добавить заново.","confirm.erase_decor":"Стереть объект «{kind}»? Действие можно отменить из истории редактора.","confirm.delete_space_title":"Удалить пространство?","confirm.delete_space_body":"Пространство, все его комнаты и вся разметка плана будут удалены.","confirm.delete_space_vac_routes":"Также будет снято сопоставление карт роботов: {count}.","space.delete_blocked":"Это пространство всё ещё используется устройствами: {n}. Сначала перенесите их в другое пространство или удалите.","toast.pos_save_failed":"Не удалось сохранить позицию: {err}","toast.no_entity":"У устройства нет подходящей сущности","toast.ha_disabled_action":"Деактивированный объект Home Assistant нельзя использовать на плане.","toast.ha_disabled_show_device":"Деактивированное в Home Assistant устройство нельзя показать на плане. Сначала активируйте его в Home Assistant.","toast.ha_disabled_show_entity":"Деактивированную в Home Assistant сущность нельзя показать на плане. Сначала активируйте её в Home Assistant.","toast.ha_disabled_add":"Деактивированный объект Home Assistant нельзя добавить на план. Сначала активируйте его в Home Assistant.","toast.ha_binding_unverified":"Статус объекта не удалось подтвердить по реестру Home Assistant. Отображение и действия временно недоступны.","toast.markup_needs_server":"Разметка доступна после переноса конфига на сервер","toast.space_order_changed":"Порядок изменён. Если где-то этаж карточки задан номером, проверьте такие панели.","toast.conflict":"Конфиг изменён в другом окне — данные обновлены, повторите последнее действие","toast.cfg_save_failed":"Не удалось сохранить конфиг: {err}","toast.room_overlap":"Контур накладывается на комнату «{name}» — комнаты не должны накладываться","toast.contour_cannot_close":"Контур нельзя замкнуть: он вырожден или пересекает сам себя","toast.merge_not_adjacent":"Объединять можно только комнаты с общей стеной","toast.rooms_merged":"Комнаты объединены в «{name}»","toast.split_pick_wall":"Начните разрез на стене комнаты","toast.split_bad_cut":"Разрез — от стены до стены внутри комнаты, без пересечения стен и самого себя","merge.header":"Объединение комнат","merge.hint":"У объединённой комнаты одно имя и одна зона. Вторая зона освобождается — её устройства уйдут с плана, пока их не заберёт другая комната.","merge.keep":"Оставить","merge.no_area":"без зоны","toast.room_saved":"Комната сохранена ({n}). Устройств добавлено: {added}. Обведите следующую или выйдите из разметки.","toast.room_saved_no_area":"Комната сохранена ({n}, без зоны). Обведите следующую или выйдите из разметки.","toast.marker_needs_server":"Редактирование устройств доступно после переноса конфига на сервер","toast.virtual_name_required":"Укажите имя виртуального устройства","toast.marker_saved":"Устройство сохранено","toast.marker_removed":"Устройство удалено с плана","toast.integration_missing":"Интеграция House Plan не установлена — управление недоступно","toast.plan_formats":"Поддерживаются SVG, PNG, JPG, WebP","toast.plan_required":"Загрузите подложку — план этажа обязателен","toast.space_added_onboard":"Пространство добавлено. Обведите комнаты: кликайте по точкам сетки и замкните контур.","toast.space_added":"Пространство добавлено","toast.space_copied":"Пространство «{name}» создано","toast.space_saved":"Пространство сохранено","toast.space_deleted":"Пространство удалено","toast.delete_failed":"Ошибка удаления: {err}","toast.error":"Ошибка: {err}","toast.toggle_target_unavailable":"Цель «{name}» недоступна — действие не выполнено","toast.toggle_targets_unavailable":"Цели недоступны: {names}. Действие не выполнено","toast.file_failed":"Файл «{name}» не загружен: {err}","toast.files_attached":"Прикреплено файлов: {n}","err.unknown":"неизвестная ошибка","err.code":"код {code}","err.too_large":"файл больше {mb} МБ","err.bad_ext":"недопустимый тип (нужен PDF/изображение)","err.unauthorized":"нужны права администратора","editor.title":"Заголовок","editor.default_floor":"Стартовое пространство","editor.default_floor_missing":"Стартовое пространство «{id}» больше не существует. Выберите другое.","editor.floor":"Закреплённое пространство","editor.floor_none":"— не закреплять —","editor.floor_index":"YAML-индекс {index} (сохранён)","fixed_floor.loading":"Загружаем закреплённое пространство…","fixed_floor.invalid_title":"Закреплённое пространство недоступно","fixed_floor.invalid_body":"Проверьте floor в конфигурации карточки. Настроенное значение: {value}","editor.icon_size":"Размер иконок, % ширины плана","editor.show_temperature":"Показывать температуру","editor.live_states":"Живые состояния (вкл/выкл, открыто…)","editor.light_pools":"Световые пулы и тени от стен","editor.show_signal":"Показывать сигнал zigbee (LQI)","editor.language":"Язык интерфейса","editor.lang_auto":"Авто (профиль HA)","title.icon_rules":"Правила иконок: какая MDI-иконка достаётся устройству по имени","rules.title":"Правила иконок","rules.hint":"Правила проверяются сверху вниз по строке «имя устройства + модель» (regex без учёта регистра); срабатывает первое совпадение. Если ничего не подошло — решает device class сущности, затем — иконка-заглушка.","rules.pattern_ph":"regex, напр. розетк|plug","rules.icon_ph":"mdi:power-socket-de","rules.add":"Добавить правило","rules.reset":"Сбросить к умолчаниям","rules.test_ph":"Проверьте имя устройства…","rules.invalid":"некорректный regex","rules.saved":"Правила иконок сохранены","btn.up":"Вверх","btn.down":"Вниз","tap.info":"Карточка устройства","tap.more_info":"Диалог HA (more-info)","tap.toggle":"Переключить состояние","marker.tap_label":"Действие по нажатию для этого устройства","tap.toggle_note":"Под селектором показано, какое состояние изменится. Защищённые устройства не переключаются с плана.","import.title":"Создать пространства из этажей HA","import.hint":"Home Assistant уже знает эти этажи. Отметьте, какие превратить в пространства плана — далее для каждого попросим картинку плана. Комнаты затем обводятся вручную по плану.","import.start":"Создать: {n}","import.manual":"Начать с нуля","import.progress":"Этаж {i} из {n}","import.done":"Пространства созданы. Обведите комнаты: кликайте по точкам сетки и замкните контур.","btn.skip":"Пропустить","space.scale_label":"Масштаб (размер клетки сетки)","space.cell_cm.help":"Связывает сетку с реальными размерами: от значения зависят длины и площади, толщина стен, размеры проёмов и радиус свечения. Изменение после разметки меняет расчётные размеры всего пространства, но не двигает его точки на плане.","space.cell_cm.help.aria":"Подсказка: масштаб пространства","space.scale_unit":"см на клетку","space.scale_unit_imperial":"дюйм на клетку","space.display_section":"Внешний вид","space.show_borders":"Всегда отображать границы комнат","space.zero_wall_style":"Стены нулевой толщины","space.zero_wall_style.help":"Пунктирные стены нулевой толщины пропускают Glow и солнечные лучи, сплошные блокируют их как барьер нулевой площади. Выбор меняет все такие стены пространства, даже когда их линии скрыты в просмотре.","space.zero_wall_style.help.aria":"Подсказка: вид стен нулевой толщины","space.zero_wall_dashed":"Пунктирные","space.zero_wall_solid":"Сплошные","space.show_names":"Показывать названия комнат","space.room_color":"Цвет границ и названий","space.opacity":"Прозрачность","space.fill_label":"Заливка комнат","space.fill_mode.help":"«Свой цвет» задаёт оформление, а «Свет», «Температура» и «LQI» используют текущие данные Home Assistant; Glow включается отдельно.","space.fill_mode.help.aria":"Подсказка: режим заливки комнат","fill.none":"Нет","fill.lqi":"По силе зигби-сигнала","fill.light":"По освещению","fill.custom":"Свой цвет","space.custom_fill":"Цвет заливки","space.source_file":"Использовать изображение плана","space.source_draw":"Нарисовать вручную","fill.temp":"По температуре","tip.temp_avg":"средняя температура:","tip.hum_avg":"средняя влажность:","space_card.button":"Перейти к пространству","space_card.not_found":"Пространство «{id}» не найдено","space_card.loading":"Загрузка…","continuity.restore_plan":"Восстанавливаем план…","continuity.restore_connection":"Восстанавливаем подключение к устройствам…","continuity.retry":"Повторить","editor.space":"Пространство","editor.framing":"Кадрирование","editor.fit_content":"Всё видимое содержимое","editor.fit_house":"Плотно по геометрии дома","editor.show_button":"Показывать кнопку","editor.button_label":"Текст кнопки","editor.button_target":"Путь дашборда (куда вести)","marker.sub_entity":"сущность","title.general_settings":"Общие настройки","title.export_pdf":"Сохранить в PDF","pdf.title":"Сохранение в PDF","pdf.dimensions":"Отображать размеры и площади","pdf.decor":"Отображать мебель и другой декор","pdf.room_names":"Отображать названия комнат","pdf.backdrop":"Отображать подложку","pdf.save":"Сохранить","pdf.saving":"Формируем…","pdf.failed":"Не удалось создать PDF.","pdf.too_large":"Размер изображений превышает лимит PDF 25 МБ.","pdf.asset_failed":"Не удалось загрузить подложку или изображение декора.","pdf.scale":"Масштаб 1:{n}","pdf.north":"Север","gs.title":"Общие настройки","gs.light_group":"Освещение","gs.light_on":"Свет включён","gs.light_off":"Весь свет выключен","gs.temp_group":"Температура","gs.temp_cold":"Холодно","gs.temp_ok":"Комфорт","gs.temp_hot":"Жарко","gs.lqi_group":"Сигнал Zigbee","gs.lqi_low":"Слабый сигнал","gs.lqi_high":"Сильный сигнал","gs.reset":"Сбросить к умолчаниям","gs.saved":"Общие настройки сохранены","gs.radar_show_live":"Показывать текущее присутствие на плане","radar.title":"Присутствие на плане","radar.help":"Свяжите маркер с точными сущностями радара Home Assistant, укажите положение датчика и профиль координат. Живые позиции обрезаются по выбранной комнате.","radar.help.aria":"Подсказка: настройки радара присутствия","radar.enabled":"Использовать этот радар присутствия","radar.show_live":"Показывать живые цели","radar.configure":"Настроить радар","radar.configure_on_plan":"Настроить на плане","radar.change_installation":"Сменить установку","radar.no_contour":"У комнаты нет контура. Точки радара не будут обрезаться по комнате.","radar.discard_setup_title":"Отменить настройку радара?","radar.discard_setup":"Несохранённая настройка радара будет потеряна.","radar.step_place_mount":"Укажите физическое положение датчика","radar.step_place_heading":"Укажите точку прямо перед датчиком","radar.step_reference":"Укажите контрольное положение {n}, затем начните измерение","radar.step_check_reference":"Укажите независимое проверочное положение","radar.start_measure":"Начать измерение","radar.countdown":"Встаньте в отмеченное место через {seconds} с","radar.capturing":"Стойте неподвижно и в одиночестве…","radar.fit_ready":"Калибровка готова","radar.check_third":"Проверить в другом положении","radar.check_complete":"Независимая проверка завершена","radar.error_distance":"Расхождение положения: {distance}","radar.ambiguous_target":"Обнаружено несколько целей. Повторите измерение в одиночестве.","radar.insufficient_samples":"Недостаточно актуальных координат. Повторите или настройте вручную.","radar.bad_references":"Выберите разнесённые положения в разных направлениях от датчика.","radar.ambiguous_sources":"Измерения допускают два одинаково вероятных направления. Выберите точки, по которым можно различить левую и правую стороны.","radar.bad_fit":"Измерения не совпадают. Проверьте единицы, положение датчика и контрольные точки.","radar.desktop_hint":"Для точной настройки используйте компьютер. Редактирование на тач-устройствах поддерживается по остаточному принципу.","radar.detected":"House Plan распознал признаки радара у этого устройства. Перед сохранением проверьте точные источники.","radar.detected_ld2450":"House Plan нашёл набор координат ESPHome LD2450. Перед сохранением проверьте точные источники X/Y.","radar.additional_actions":"Дополнительные действия","radar.declare":"Это радар присутствия","radar.profile":"Профиль данных","radar.profile_esphome_ld2450_v1":"ESPHome LD2450 (цели X/Y)","radar.profile_cartesian_v1":"Декартовы цели (X/Y)","radar.profile_polar_v1":"Полярная цель (дальность/угол)","radar.profile_range_v1":"Только дальность","radar.profile_zones_v1":"Состояния зон","radar.profile_presence_v1":"Только присутствие","radar.room":"Комната радара","radar.room_choose":"Выберите комнату","radar.target":"Цель {n}","radar.axis_x":"Сущность координаты X","radar.axis_y":"Сущность координаты Y","radar.add_target":"Добавить слот цели","radar.range_channel":"Канал дальности {n}","radar.add_range":"Добавить канал дальности","radar.presence_gate":"Сущность присутствия для слота","radar.swap_axes":"Поменять оси X и Y местами","radar.axis_x_sign":"Направление X","radar.axis_y_sign":"Направление Y","radar.distance_source":"Сущность дальности","radar.angle_source":"Сущность угла","radar.angle_unit":"Единица угла","radar.degrees":"Градусы","radar.radians":"Радианы","radar.angle_zero":"Направление нулевого угла","radar.angle_forward":"Вперёд","radar.angle_right":"Вправо","radar.angle_clockwise":"Угол растёт по часовой стрелке","radar.zone_source":"Сущность зоны","radar.occupancy_source":"Сущность присутствия","radar.count_source":"Сущность количества целей","radar.availability_source":"Сущность доступности","radar.source_choose":"Выберите сущность","radar.source_optional":"Необязательно","radar.source_missing":"сейчас недоступна","radar.saved_unsupported":"Сохранённая настройка радара не поддерживается или неполна. Она неактивна; удалите её либо обновите House Plan перед повторной настройкой.","radar.occupancy":"Присутствие (вкл/выкл)","radar.count":"Количество","radar.mount":"Положение и направление","radar.mount_hint":"Это физическое положение датчика. Перемещение его декоративного маркера не меняет установку.","radar.heading":"Направление, °","radar.range_cm":"Дальность, см","radar.fov_deg":"Угол обзора, °","radar.unit":"Единица источника","radar.mirror":"Отразить ось влево/вправо","radar.remove":"Удалить настройки радара","radar.invalid":"Перед сохранением заполните комнату, источники и положение радара.","radar.check_sources":"Проверить живые данные","radar.checking":"Проверяем…","radar.health":"Состояние подключения","radar.live_summary":"Текущих целей: {targets}; дуг дальности: {ranges}","radar.health_ok":"Актуальные данные получены","radar.health_off":"Цели не обнаружены","radar.health_stale":"Часть координат устарела","radar.health_partial":"Часть источников актуальна, часть устарела","radar.health_restricted":"Нет доступа к одному или нескольким источникам","radar.health_incomplete":"Текущий отчёт радара неполон","radar.health_position_unavailable":"Есть присутствие, но актуальное положение недоступно","radar.health_unavailable":"Данные датчика недоступны","radar.health_needs_setup":"Требуется настроить установку","radar.health_inconsistent":"Источники передают противоречивые данные","radar.health_unknown":"Текущее состояние неизвестно","radar.health_disabled":"Радар отключён","radar.error_invalid_radar":"Проверьте настройки радара.","radar.error_invalid_selection":"Выберите существующую комнату и допустимые источники.","radar.error_source_restricted":"Нет доступа ко всем выбранным источникам.","radar.error_rate_limited":"Слишком много запросов. Повторите чуть позже.","radar.error_not_ready":"Обработка данных радара ещё не готова.","radar.error_conflict":"План изменился. Откройте настройку радара заново и повторите попытку.","radar.error_source_unavailable":"Один или несколько выбранных источников радара недоступны.","radar.error_unsupported_capability":"Установленная интеграция не поддерживает эту возможность радара.","radar.report_age":"{seconds} с назад","space.show_lqi":"Сигнал Zigbee рядом с устройствами","gs.light_none":"Нет источников света","mode.plan":"Редактор плана","mode.devices":"Редактор устройств","display.value":"Значение + состояние","marker.subarea":"без зоны, вручную","device.new":"Новое устройство — откройте его редактор, чтобы снять отметку","opening.unlock_action":"Открыть замок","opening.lock_action":"Закрыть замок","opening.lock_pending":"Выполняется…","title.close_editor":"Закрыть редактор (вернуться к просмотру)","title.add_device":"Добавить устройство на план","devbar.add":"Добавить","devbar.rules":"Правила иконок","device_inbox.button":"Устройства","device_inbox.title":"Устройства на плане","device_inbox.search":"Поиск по устройствам, сущностям и интеграциям…","device_inbox.add_virtual":"Добавить виртуальное устройство","device_inbox.tab_on_plan":"На плане","device_inbox.tab_available":"Доступны","device_inbox.tab_hidden":"Скрытые","device_inbox.tab_readd":"Доступны снова","device_inbox.only_new":"Только новые","device_inbox.show_entities":"Показывать сущности","device_inbox.show_hidden":"Показывать скрытые на плане","device_inbox.show_hidden.help":"Временно показывает на плане скрытые и деактивированные маркеры служебными призраками только в редакторе устройств. Сохранённая видимость устройств не меняется.","device_inbox.show_hidden.help.aria":"Подсказка: показывать скрытые устройства на плане","device_inbox.new":"Новое","device_inbox.find":"Найти на плане","device_inbox.edit":"Настроить","device_inbox.hide":"Скрыть","device_inbox.show":"Показать","device_inbox.add":"Добавить","device_inbox.readd":"Добавить заново","device_inbox.hide_available":"Скрыть из списка","device_inbox.show_more":"Показать ещё","device_inbox.more_actions":"Другие действия","device_inbox.find_hidden_hint":"Сначала включите «Показывать скрытые на плане»","device_inbox.show_disabled":"Перед показом активируйте эту привязку в Home Assistant","device_inbox.empty_on_plan":"На плане пока нет подходящих устройств.","device_inbox.empty_available":"Нет доступных устройств для добавления.","device_inbox.empty_hidden":"Скрытых устройств нет.","device_inbox.empty_readd":"Нет удалённых устройств, доступных для повторного добавления.","device_inbox.reason_visible_auto":"Найдено автоматически","device_inbox.reason_visible_explicit":"Добавлено явно","device_inbox.reason_manual_hidden":"Скрыто пользователем","device_inbox.reason_automatic_hidden":"Скрыто автоматически","device_inbox.reason_service_entry":"Служебная запись реестра","device_inbox.reason_excluded_integration":"Исключена интеграция «{integration}»","device_inbox.reason_excluded_domain":"Непространственный тип сущности","device_inbox.reason_grouped_light":"Представлено группой света комнаты","device_inbox.reason_represented_by_parent":"Представлено родительским устройством","device_inbox.reason_removed":"Ранее удалено с плана","device_inbox.reason_available":"Можно добавить на план","device_inbox.reason_no_bound_room":"Зона HA не связана с комнатой плана","device_inbox.status_ha_disabled":"Отключено в Home Assistant","device_inbox.status_orphaned":"Привязка больше не найдена в Home Assistant","device_inbox.status_unverified":"Реестр Home Assistant временно недоступен","device_inbox.saved":"Список устройств обновлён","device_inbox.filters_excluded":"Исключённые интеграции","device_inbox.filters_group_lights":"Объединять светильники комнаты в один маркер","device_inbox.filters_preview_appear":"появится: {count}","device_inbox.filters_preview_hide":"скроется: {count}","device_inbox.filters_preview_lights":"затронет светильников: {count}","device_inbox.filters_reset":"Вернуть рекомендуемые","device_inbox.filters_save":"Сохранить фильтры","device_inbox.filters_search_ph":"Добавить интеграцию…","device_inbox.filters_title":"Фильтры обнаружения","space.roomcard_section":"Карточки комнат","space.label_temp":"Температура","space.label_hum":"Влажность","space.label_lqi":"Средний Zigbee-сигнал","space.label_light":"Свет вкл/выкл","roomcard.light_on":"Вкл","roomcard.light_off":"Выкл","roomcard.light_partial":"{on} из {total}","toast.split_pick_inside":"Промежуточные точки разреза — внутри комнаты","mode.decor":"Редактор подложки","decor.select":"Выбрать","decor.line":"Линия","decor.rect":"Прямоугольник","decor.ellipse":"Овал","decor.text":"Надпись","decor.erase":"Стереть","decor.erase_confirm_title":"Стереть объект?","decor.color":"Цвет","decor.width":"Толщина линии","decor.line_style":"Стиль линии","decor.line_style_solid":"Сплошная","decor.line_style_dashed":"Пунктирная","decor.fill":"Заливка","decor.fill_color":"Цвет заливки","decor.length":"Длина","decor.size":"Размер","decor.flip_h":"Отзеркалить по горизонтали","decor.flip_v":"Отзеркалить по вертикали","decor.angle":"Угол поворота, °","decor.text_size":"Размер текста","decor.backdrop_properties":"Свойства картинки-подложки","decor.text_title":"Надпись","decor.object_title":"Редактирование: {kind}","decor.text_label":"Текст","decor.live_group":"Вставить переменную HA","decor.live_entity":"Сущность","decor.live_entity_ph":"выберите сущность","decor.live_attr":"Значение","decor.live_attr_ph":"выберите состояние или атрибут","decor.live_state":"Состояние","decor.backdrop":"Картинка-подложка","decor.backdrop_hint":"Тяните картинку — перемещение; угол — размер; верхнюю ручку — поворот. Shift меняет пропорции или снимает шаг угла.","decor.backdrop_reset":"Вернуть картинку","decor.backdrop_reset_done":"Картинка вернулась на своё место и в свой размер","marker.icon_auto":"Авто: {icon} (по правилам иконок; выберите свою, чтобы заменить)","marker.icon_pin_auto":"Закрепить","mode.plan_tip":"Редактор плана — геометрия дома: рисование и объединение/разделение комнат, привязка к зонам HA, двери, окна и ворота, карточки комнат, масштаб","mode.devices_tip":"Редактор устройств — всё про значки: перетаскивание, клик — настройка привязки/иконки/отображения, виртуальные устройства, правила иконок","mode.decor_tip":"Редактор подложки — чисто визуальный декор под планом: линии, прямоугольники, овалы и надписи, не реагирующие на клики","space.glow_enabled":"Свечение источников света","gs.glow_group":"Свечение источников света","gs.glow_base":"Темнота дома","gs.glow_light":"Цвет света по умолчанию / интенсивность","gs.wall_fill":"Цвет заливки стен","gs.glow_radius":"Радиус свечения","gs.glow_radius.help":"Задаёт общий радиус светового пятна в метрах или футах; персональный радиус устройства заменяет это значение.","gs.glow_radius.help.aria":"Подсказка: общий радиус свечения","gs.unit_m":"м","gs.unit_ft":"фут","marker.controls_label":"Управляет другими источниками света","marker.controls.help":"При действии «Переключить состояние» перечисленные источники переключаются вместе с этим маркером. Их световые пятна остаются у собственных маркеров, а эта связь сама по себе не делает управляющий маркер источником света.","marker.controls.help.aria":"Подсказка: управление другими источниками света","marker.controls_filter":"Поиск ламп и выключателей…","info.controls":"Управляет","marker.glow_radius_label":"Радиус свечения","marker.glow_radius.help":"Задаёт радиус свечения в метрах или футах; пустое значение использует радиус из общих настроек.","marker.glow_radius.help.aria":"Подсказка: радиус свечения","markup.wallthick":"Толщина","markup.select":"Выбрать","title.markup_wallthick":"Толщина — клик по стене задаёт толщину от 0 до 100 см.","markup.hint_wallthick":"клик по стене · Esc закрывает без применения","wallthick.field":"Толщина","wallthick.unit_cm":"см","wallthick.unit_in":"дюйм","wallthick.apply_room":"Применить ко всем стенам комнаты","markup.draw_wall_title":"Толщина каждого нового сегмента стены (0–100 см). Общие стены сохраняют существующее значение.","room.queue_progress":"Комната {current} из {total}","toast.wall_rooms_saved":"Создано комнат: {n}","toast.wall_chain_saved":"Цепочка стен сохранена","toast.wallthick_pick":"Кликните по стене","toast.wallthick_set":"Толщина стены задана","toast.wallthick_cleared":"Толщина стены убрана","toast.physical_range":"Введите значение от {min} до {max} {unit}","toast.zero_wall_opening_conflict":"Сначала удалите проём на этом участке стены.","toast.zero_wall_ambiguous":"Не удалось однозначно выбрать участок стены. Уточните геометрию узла.","toast.zero_wall_migration_blocked":"Пространство не преобразовано: {reason}. Данные не изменены.","toast.physical_angle":"Введите угол поворота от 0° до 90°, не включая 90°","toast.physical_limit":"В пространстве достигнут лимит объектов этого типа","toast.geometry_unsafe":"Изменение отменено: геометрию стен нельзя безопасно построить.","junction.limit_angle":"Слишком острый угол между стенами: {actual}°, минимум {limit}°.","junction.limit_valence":"Слишком много стен в одном узле: {actual}, максимум {limit}.","junction.limit_length":"Слишком короткий участок стены: {actual} см, минимум {limit} см.","junction.limit_distance":"Стены и узлы слишком близко: {actual} см, минимум {limit} см.","junction.limit_clearance":"Внутри комнаты не остаётся места: {actual} см², минимум {limit} см².","junction.limit_check_failed":"Проверку стыков выполнить не удалось — изменение не сохранено","toast.wall_model_migration_blocked":"Не удалось обновить модель стен: {reason}. План не изменён. Запустите «Оптимизировать планы»; если ошибка повторится, исправьте конфликтующую геометрию стен.","toast.wall_model_client_outdated":"Обновите карточку и перезагрузите страницу перед редактированием плана.","wall_model.reason.invalid-room":"некорректный контур комнаты","wall_model.reason.zero-length":"отрезок стены нулевой длины","wall_model.reason.third-owner":"стена принадлежит более чем двум комнатам","wall_model.reason.duplicate-id":"конфликт идентификаторов стен","wall_model.reason.thickness-conflict":"конфликт значений толщины стены","wall_model.reason.opening-host":"проём нельзя однозначно привязать к стене","toast.delete_room_pick":"Кликните внутри комнаты, которую нужно удалить","toast.plan_snap_ambiguous":"Увеличьте масштаб, чтобы выбрать узел стены","toast.wall_repair_ambiguous":"У контура несколько возможных соединений. Увеличьте масштаб и соедините стены явно.","toast.wall_repair_too_large":"Разрыв больше 2 см. Соедините стены перед созданием комнаты.","toast.wall_repair_changed":"Геометрия стен изменилась. Попробуйте создать комнату ещё раз.","toast.opening_on_zero_wall":"Проёмы на стене нулевой толщины запрещены","marker.from_ha_option":"Выбрать из списка HA","marker.show_entities":"Показывать сущности","marker.show_entities_tip":"Добавляет в список не только устройства, но и все их сущности","marker.pick_ph":"Выберите устройство…","room.open_area":"Открыть зону в HA","room.fit_action":"Вписать комнату {name}","view.volumetric":"Объёмный вид","view.flat":"Плоский вид","kiosk.title":"Размеры на этом экране","kiosk.hint":"Хранится только на этом устройстве — у каждого настенного планшета или ТВ свои удобные размеры.","kiosk.icon_scale":"Размер значков устройств","kiosk.font_scale":"Размер текста карточек комнат","editor.kiosk":"Режим настенного устройства (киоск)","editor.cycle":"Автосмена пространств каждые N секунд (киоск, 0 = выкл)","room.settings_title":"Настройки комнаты","room.fill_label":"Заливка в ЭТОЙ комнате","fill.inherit":"Как у пространства","room.custom_fill_space":"Цвет пространства","room.custom_fill_own":"Цвет комнаты","room.temp_range_label":"Диапазон комфорта","room.temp_range_min":"Нижняя граница комфортной температуры","room.temp_range_max":"Верхняя граница комфортной температуры","room.temp_range_reset":"Как у пространства","room.temp_range.help":"Диапазон применяется только к этой комнате. Пустое поле наследует соответствующую границу пространства; если границы поменялись местами, House Plan использует меньшую как нижнюю, а большую как верхнюю.","room.temp_range.help.aria":"О диапазоне комфорта комнаты","room.temp_src_label":"Источник температуры","room.hum_src_label":"Источник влажности","room.src_average":"Среднее по датчикам комнаты","room.src_pick":"Конкретное устройство или сущность","room.src_ph":"Выберите источник…","toast.room_updated":"Комната обновлена","space.card_font":"Размер шрифта карточек","room.sizes_section":"Размеры шрифтов","room.group_basics":"Основное","room.group_basics.help":"Область связывает комнату с зоной Home Assistant: из неё берутся датчики. Без области комната остаётся геометрией.","room.group_basics.help.aria":"Подсказка: имя и область комнаты","room.group_fill":"Заливка","room.group_fill.help":"Заливка этой комнаты перекрывает выбранную для пространства; «Свой цвет» хранится только здесь.","room.group_fill.help.aria":"Подсказка: заливка комнаты","room.group_sources":"Источники","room.group_sources.help":"По умолчанию комната усредняет свои датчики. Выбранный датчик заменяет среднее везде: подсказка, карточка, заливка.","room.group_sources.help.aria":"Подсказка: источники температуры и влажности","room.sizes_section.help":"Масштабы действуют только в этой комнате и умножаются на общий масштаб карточки из настроек пространства.","room.sizes_section.help.aria":"Подсказка: размеры шрифтов комнаты","room.name_scale":"Размер названия","room.label_scale":"Размер подписей","preview.room_name":"Гостиная","toast.cfg_reload_failed":"Не удалось перечитать план с сервера: {err}","toast.locale_load_failed":"Не удалось загрузить языковой пакет. До перезагрузки страницы используется английский.","toast.furniture_art_load_failed":"Не удалось загрузить изображения мебели. Обновите страницу, чтобы их показать.","room.settings_short":"Настройки комнаты","room.unnamed":"Комната без имени","marker.use_climate_temp":"Учитывать температуру устройства в комнате","marker.use_climate_temp_tip":"Добавляет current_temperature кондиционера или термостата в среднюю температуру комнаты. Внешний бейдж со значением настраивается отдельно ниже.","marker.value_badge_title":"Бейдж со значением","marker.value_badge.help":"Показывает одно выбранное значение рядом со значком. Не влияет на комнатные показатели, свет, Glow и действие по нажатию.","marker.value_badge.help.aria":"Подсказка: бейдж со значением устройства","marker.value_badge_enabled":"Отображать бейдж со значением","marker.value_badge_source":"Значение","marker.value_badge_source.help":"Выберите конкретное состояние, поддерживаемый атрибут или производное значение этого устройства.","marker.value_badge_source.help.aria":"Подсказка: источник значения бейджа","marker.value_badge_position":"Расположение","marker.value_badge_position.help":"Выбранная сторона сохраняется постоянно и не переворачивается автоматически у края плана.","marker.value_badge_position.help.aria":"Подсказка: расположение бейджа","marker.value_badge_right":"Справа","marker.value_badge_bottom":"Снизу","marker.value_badge_left":"Слева","marker.value_badge_top":"Сверху","marker.value_badge_empty":"У этого устройства нет доступных значений","marker.value_badge_static":"Статичный значок не показывает живые значения. Настройка сохранится.","marker.value_badge_missing":"Источник недоступен","marker.value_badge_missing_hint":"Сохранённый источник сейчас недоступен. Можно сохранить его, отключить бейдж или выбрать другой.","marker.value_badge_duplicate":"То же значение уже показано внутри значка.","marker.value_badge_state":"Состояние · {name}","marker.value_badge_marker_state":"Состояние источника света · {name}","marker.value_badge_lqi":"Качество Zigbee-сигнала (среднее)","marker.value_badge_attr_current_temperature":"Текущая температура · {name}","marker.value_badge_attr_temperature":"Целевая температура · {name}","marker.value_badge_attr_current_humidity":"Текущая влажность · {name}","marker.value_badge_attr_humidity":"Влажность · {name}","marker.value_badge_attr_current_position":"Положение · {name}","marker.value_badge_attr_percentage":"Скорость · {name}","marker.value_badge_attr_brightness":"Яркость · {name}","marker.value_badge_attr_volume_level":"Громкость · {name}","marker.value_badge_attr_battery_level":"Заряд батареи · {name}","marker.value_badge_attr_fan_speed":"Скорость вентилятора · {name}","marker.value_source":"Источник значения","marker.value_source.help":"Выберите, что заменит значок. Действие по нажатию не изменится.","marker.value_source.help.aria":"Подсказка: источник значения внутри значка","marker.value_source_auto":"Автоматически (как раньше)","marker.value_source_missing_hint":"Сохранённый источник сейчас недоступен. До его восстановления или выбора другого значения внутри будет показано —.","marker.light_role_label":"Является источником света","marker.light_role.help":"«Авто» использует фактическую роль привязанного устройства, «Всегда» принудительно создаёт собственный источник, а «Никогда» исключает его; связанные лампы выше остаются независимыми.","marker.light_role.help.aria":"Подсказка: является ли устройство источником света","marker.light_role_auto_yes":"Автоматически (источник света)","marker.light_role_auto_no":"Автоматически (не источник света)","marker.light_entity_label":"Ведущая сущность света","marker.light_entity.help":"Для составного устройства выберите сущность, состояние, цвет и яркость которой представляют этот источник на плане. Автоматический вариант сохраняет совместимость со старыми планами.","marker.light_entity.help.aria":"Подсказка: ведущая сущность света","marker.light_entity_auto":"Автоматически ({entity})","marker.light_entity_none":"нет управляемой сущности","marker.light_entity_missing":"Сохранённая сущность {entity} недоступна. Временно используется {fallback}; выбор восстановится, если сущность вернётся.","marker.toggle_entity_label":"Переключаемая сущность","marker.toggle_entity.help":"Для составного устройства выберите собственную лампу или переключатель, которой управляет нажатие. Автоматический вариант сохраняет прежние правила цели и не зависит от ведущей сущности света.","marker.toggle_entity.help.aria":"Подсказка: переключаемая сущность","marker.toggle_entity_auto":"Автоматически ({entity})","marker.toggle_entity_none":"нет собственной управляемой сущности","marker.toggle_entity_missing":"Сохранённой сущности {entity} больше нет среди выбираемых каналов этого маркера. Временно используется {fallback}; выбор восстановится, если сущность вернётся.","marker.glow_color_label":"Цвет и яркость свечения","marker.glow_mode.help":"Используйте данные источника, задайте только цвет или зафиксируйте цвет и яркость. Минимум — 1%; чтобы отключить источник, выберите «Никогда».","marker.glow_mode.help.aria":"Подсказка: цвет и яркость свечения","marker.glow_mode_auto":"Из источника","marker.glow_mode_color":"Задать цвет","marker.glow_mode_fixed":"Цвет и яркость","marker.glow_color":"Цвет свечения","marker.glow_brightness":"Яркость","marker.glow_disabled_never":"Настройки свечения недоступны: маркер явно исключён из источников света.","marker.glow_disabled_auto":"В автоматическом режиме у этого маркера не найден пространственный источник света.","marker.glow_disabled_no_entity":"Для пространственного источника нет активной управляемой сущности Home Assistant.","marker.glow_passive_hint":"У источника нет собственных данных Home Assistant. Задайте цвет и яркость вручную; радиус остаётся доступным.","marker.control_broken":"Сохранённый источник отсутствует или больше не отмечен как источник света","marker.control_missing_label":"Отсутствующий источник на плане","marker.control_passive":"пассивный источник","toast.marker_control_cycle":"Такая связь создаст циклическую цепочку управления светом.","toast.marker_binding_required":"Сначала выберите устройство Home Assistant, затем добавьте управляемый источник света.","confirm.unlock_title":"Открыть замок?","confirm.unlock_body":"House Plan отправит этому замку команду открытия.","toast.files_migrate_failed":"Не удалось перенести вложения к новой привязке, ссылки остались на старые файлы: {err}","space.pick_saved":"Уже загруженные","space.pick_saved_hint":"Планы, сохранённые на сервере, включая отцеплённые ранее","space.no_saved":"На сервере пока нет сохранённых планов.","space.loading":"Загрузка…","space.used_by":"используется: {list}","space.in_use":"План используется пространством — сначала отцепите его","btn.use":"Выбрать","confirm.delete_plan_title":"Удалить файл плана?","confirm.delete_plan_body":"Файл будет удалён с сервера. Это действие нельзя отменить.","toast.plans_list_failed":"Не удалось получить список планов: {err}","toast.plan_delete_failed":"Не удалось удалить план: {err}","marker.hide":"Скрыть","marker.hide_tip":"Устройство исчезнет с плана после сохранения, но продолжит участвовать в расчёте сигнала комнаты. Вернуть его можно через каталог «Устройства» в редакторе устройств.","marker.show":"Показать","marker.show_tip":"Устройство снова появится на плане после сохранения.","marker.hidden_ghost":"Устройство скрыто пользователем","marker.ha_disabled_device":"Устройство деактивировано в Home Assistant и скрыто с плана.","marker.ha_disabled_entity":"Сущность деактивирована в Home Assistant и скрыта с плана.","marker.ha_disabled_all_entities":"У устройства нет активных сущностей Home Assistant, поэтому оно скрыто с плана.","marker.ha_registry_limited":"Полный реестр Home Assistant недоступен этому пользователю. Неподтверждённый объект временно нельзя показывать или использовать.","marker.delete_tip":"Полностью удалить устройство с плана и из всех расчётов. Позже его можно добавить заново.","tap.run":"Запустить автоматизацию/скрипт/сцену","tap.none":"Ничего не делать","marker.run_target_label":"Что запускать","marker.run_search_ph":"Поиск: автоматизация, скрипт или сцена…","marker.run_target_gone":"Цель {id} не найдена — выберите заново","marker.tap_confirm":"Спрашивать подтверждение","marker.tap_confirm_tip":"Перед выполнением показать диалог подтверждения — защита от случайных нажатий.","marker.toggle_hint_single":"Цель: {name} ({id}).","marker.virtual_light_target":"Виртуальный свет: {name}.","marker.virtual_light_current":"Ручное состояние: {state} → {effect}.","marker.virtual_light_state_on":"включён","marker.virtual_light_state_off":"выключен","marker.toggle_hint_group":"Переключатся источники ({count}): {names}.","marker.toggle_hint_current":"Сейчас: {state} → {effect}.","marker.toggle_hint_group_current":"Сейчас включено {on} из {count} → {effect}.","marker.toggle_hint_skipped":"Не будут затронуты ({count}): {targets}.","marker.toggle_effect_turn_on":"включится","marker.toggle_effect_turn_off":"выключится","marker.toggle_effect_open":"откроется","marker.toggle_effect_close":"закроется","marker.toggle_effect_stop":"остановится","marker.toggle_effect_toggle":"состояние переключится","marker.toggle_skip_missing":"не найдено","marker.toggle_skip_ha_disabled":"деактивировано в HA","marker.toggle_skip_unavailable":"недоступно","marker.toggle_skip_unsupported":"переключение не поддерживается","marker.toggle_skip_secure":"заблокировано из соображений безопасности","marker.toggle_none_no_binding":"У устройства нет привязки, состояние переключать нечем. По нажатию ничего не произойдёт.","marker.toggle_none_no_actionable_entity":"У устройства нет состояния, которое можно переключить. По нажатию ничего не произойдёт.","marker.toggle_none_configured_targets_missing":"Настроенные цели сейчас недоступны. Собственная сущность устройства не будет подставлена вместо них.","marker.toggle_none_ha_disabled":"Цель деактивирована в Home Assistant и не может использоваться на плане.","marker.toggle_none_unavailable":"Цель сейчас недоступна. По нажатию ничего не произойдёт.","marker.toggle_none_unsupported":"Для этой сущности Home Assistant не предоставляет безопасного переключения. По нажатию ничего не произойдёт.","marker.toggle_none_secure":"Переключение замков, сигнализации и защитных ворот с плана заблокировано из соображений безопасности.","run.automation":"автоматизация","run.script":"скрипт","run.scene":"сцена","confirm.tap_run":"Запустить «{name}»?","confirm.tap_toggle":"Переключить «{name}»?","confirm.current_state":"Текущее состояние: {state}","confirm.expected_state":"После переключения: {state}","confirm.group_current":"включено {on} из {total}","confirm.group_all_on":"все включены","confirm.group_all_off":"все выключены","confirm.unavailable_targets":"Недоступно: {count}","confirm.expected_by_ha":"Состояние определит Home Assistant","confirm.state_on":"Включено","confirm.state_off":"Выключено","confirm.state_open":"Открыто","confirm.state_closed":"Закрыто","confirm.state_opening":"Открывается","confirm.state_closing":"Закрывается","confirm.state_stopped":"Остановлено","confirm.state_unknown":"Неизвестно","toast.run_started":"Запущено: {name}","toast.run_target_missing":"Цель запуска не найдена — проверьте настройки устройства","toast.run_target_required":"Выберите автоматизацию, скрипт или сцену","toast.tap_target_changed":"Цель действия изменилась. Повторите попытку.","toast.virtual_light_toggle_failed":"Не удалось переключить виртуальный свет: {err}","toast.value_badge_source_required":"Выберите значение для бейджа","btn.run":"Выполнить","vac.section":"Робот-пылесос: живая позиция","vac.autocal":"Настроить автоматически","vac.live":"Живая позиция на плане","vac.trail":"Показывать путь робота","vac.autocal_no_rooms":"Интеграция не отдаёт список комнат — откройте «Подогнать вручную»","vac.route_warn_unmapped":"Робот убирает на карте, которая не сопоставлена ни одному этажу","vac.route_warn_needs_calibration":"Карта сопоставлена этажу, но не откалибрована","vac.route_warn_ambiguous":"Две карты неразличимы — этаж не выбран","vac.route_warn_missing_space":"Пространство этой карты удалено","vac.autocal_no_match":"Не совпали имена комнат (нужно ≥3 общих) — откройте «Подогнать вручную»","vac.autocal_done":"Готово: привязка по {rooms} комнатам. Запустите уборку и проверьте","vac.cal_need_pos":"Робот сейчас не отдаёт координаты — запустите уборку и поставьте на паузу","vac.cal_done":"Калибровка сохранена. Запустите уборку и проверьте","vac.cal_cancelled":"Калибровка отменена","vac.fit":"Подогнать вручную","vac.fit_hint":"Перетащите карту робота на место, растяните за уголки","vac.fit_rotate":"Повернуть 90°","vac.fit_mirror":"Отразить","vac.trail_never":"Не показывать никогда","vac.trail_cleaning":"Во время уборки","vac.trail_always":"Показывать всегда","gs.bg_color":"Цвет фона вокруг плана","gs.bg_default":"Как в теме","gs.bg_mode":"Фон плана","gs.bg_mode.help":"«Следует за Солнцем» использует sun.sun, а при недоступности — локальные часы браузера; статичный режим всегда показывает выбранный цвет.","gs.bg_mode.help.aria":"Подсказка: общий фон плана","gs.bg_static":"Статичный цвет","gs.bg_daynight":"Следует за Солнцем","gs.sun_group":"Солнце","gs.sun_missing":"Сущность sun.sun не найдена — фон следует локальным часам, а оконные лучи недоступны.","gs.north":"Север на плане","gs.north.help":"Угол отсчитывается по часовой стрелке от верхней вертикали плана; север нужен для оконных лучей, а не для фона «Следует за Солнцем».","gs.north.help.aria":"Подсказка: общее направление севера","gs.north_ph":"не задан","gs.north_clear":"Сбросить","gs.north_letter":"С","gs.sun_rays":"Солнце в окнах","gs.sun_ray_origin":"Лучи солнца","gs.sun_ray_origin.inner":"От внутренних углов окон","gs.sun_ray_origin.outer":"От внешних углов окон","gs.about_version":"Houseplan Card v{v}","gs.about_github":"GitHub · документация и issues","gs.about_telegram":"Чат в Telegram","support.title":"Помощь и обратная связь","space.bg_color":"Цвет фона вокруг плана","space.bg_inherit":"Наследовать общий","space.bg_mode":"Фон плана","space.bg_mode.help":"Выберите наследование общего фона либо переопределите это пространство статичным цветом или режимом «Следует за Солнцем».","space.bg_mode.help.aria":"Подсказка: фон пространства","space.north":"Север на плане","space.north.help":"Переопределяет общий север для этого пространства; угол отсчитывается по часовой стрелке от верхней вертикали плана и используется оконными лучами.","space.north.help.aria":"Подсказка: север для пространства","space.sun_rays":"Солнце в окнах","space.sun_inherit":"Общие настройки","space.sun_on":"Вкл","space.sun_off":"Выкл","canvas.far_objects":"Объектов далеко от плана: {n}","canvas.show_far":"Показать","canvas.home_tip":"План там — нажмите, чтобы вписать","gs.grid_group":"Обслуживание планов","gs.align_all":"Оптимизировать планы","gs.align_title":"Оптимизировать планы","gs.align_none":"Все планы уже используют актуальную и оптимальную модель данных.","gs.optimize_no_automatic_changes":"Автоматических изменений нет. Проверьте пункты ниже.","gs.align_count":"Сдвинется элементов: {n} из {total}, максимум на {cm} см.","gs.align_where":"Наибольший сдвиг — в пространстве «{s}».","gs.align_turned":"Проёмов с исправлением угла: {n}.","gs.align_preflight_failed":"Не удалось безопасно проверить геометрию следующих пространств: {spaces}{more}.","gs.align_preflight_hint":"Планы не изменены. Скопируйте диагностику кнопкой ниже и приложите её к отчёту об ошибке вместе с экспортом пространства.","gs.preflight_reason_prepare-exception":"Не удалось подготовить геометрию пространства (исключение при сборке модели)","gs.preflight_reason_wall-null":"Тело стен не построилось (объединение вернуло пустоту)","gs.preflight_reason_wall-degraded-extra":"Тело стен деградировало с лишней геометрией","gs.preflight_reason_wall-failed-core":"Ядро тела стен не собралось","gs.preflight_reason_wall-exception":"Построение стен упало с исключением","gs.preflight_reason_floor-null":"Контур пола не построился","gs.preflight_reason_floor-exception":"Построение пола упало с исключением","gs.preflight_copy":"Скопировать диагностику","gs.preflight_copied":"Диагностика скопирована","gs.preflight_update_hint":"Версии карточки и интеграции различаются — обновите House Plan и повторите.","gs.align_preflight_space":"Пространство {n}","gs.align_preflight_more":" и ещё {n}","gs.optimize_changes":"Миграций модели: {m}; обновлено пространств: {c}; устранён шум координат: {p}; объединено отрезков реальных стен: {w}; объединено отрезков стен нулевой толщины: {s}; независимых: {i}.","gs.zero_walls_migrated":"Преобразовано виртуальных участков: {n}.","gs.wall_segments_migrated":"Стабилизировано сегментов стен: {n}.","gs.room_drafts_migrated":"Незавершённые контуры преобразованы в обычные стены: {drafts}; отрезков: {segments}.","gs.optimize_lattice_summary":"Канонизировано шумовых значений координат: {n}; максимальный сдвиг: {cm} см.","gs.optimize_lattice_space":"{space}: канонизировано значений координат: {n}; оставлено значений вне сетки: {far}.","gs.optimize_coincident_partitions":"Скрытые участки независимых стен поглощены стенами комнат: {n}.","gs.optimize_openings_rehosted":"Проёмы перепривязаны к стенам комнат: {n}.","gs.optimize_walls_straightened":"Выпрямлено стен: {n}; максимальное перемещение: {cm} см.","gs.optimize_walls_straightened_where":"Максимальная правка стены: {s}.","gs.optimize_walls_straighten_skipped":"Оставлено почти осевых стен, которые нельзя безопасно выпрямить: {n}.","gs.optimize_glow_migration":"Старый Glow: пространств — {spaces} → без заливки данных + независимый Glow; комнат — {rooms} → наследуемая заливка + независимый Glow.","gs.optimize_references":"Исправлено ссылок: пространства — {spaces}; комнаты — {rooms}; позиции — {positions}; устройств отвязано от отсутствующих пространств — {detached}.","gs.optimize_reference_more":", и ещё {n}","gs.optimize_orphans_removed":"Убрано забытых записей: {total} — подписи комнат: {rooms}; устройства: {devices}; групповые метки: {groups}. Все они принадлежали пространствам, удалённым ранее.","gs.optimize_live_positions":"Старые позиции в удалённых пространствах принадлежат существующим объектам: {n}{names}. Они будут сохранены.","gs.optimize_live_positions_remove":"Старые позиции в удалённых пространствах принадлежат существующим объектам: {n}{names}. Они выбраны для удаления.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Убрать старые позиции","gs.optimize_live_keep":"Сохранить старые позиции","gs.optimize_live_selected":"Старые позиции будут убраны после применения оптимизации.","gs.optimize_unverified":"Не удалось безопасно проверить позиций: {n}. Они оставлены без изменений.","gs.optimize_registry_limited":"Для безопасной проверки нужен полный доступ администратора к реестрам Home Assistant.","gs.optimize_vacuum_warning":"Сопоставления комнат пылесоса требуют проверки: {n}.","gs.optimize_details":"Подробности","gs.optimize_details_more":"И ещё записей: {n}.","gs.optimize_detail_removed":"будет удалено","gs.optimize_detail_live":"будет сохранено","gs.optimize_detail_unverified":"не проверено","gs.optimize_detail_room_label":"подпись комнаты","gs.optimize_detail_device":"устройство","gs.optimize_detail_group":"групповая метка","gs.optimize_detail_unknown":"неизвестный владелец","gs.optimize_detail_item":"{status}: {kind} {id}; прежнее пространство {space}","gs.align_warn":"Элементы, намеренно поставленные между узлами, будут сдвинуты. После операции доступна одна отмена — только до следующего изменения плана.","gs.align_run":"Оптимизировать","gs.align_done":"Планы оптимизированы: сдвинуто элементов — {n}, обслужено записей — {m}, исправлено ссылок — {r}","gs.optimize_undo":"Отменить последнюю оптимизацию","gs.optimize_undone":"Последняя оптимизация отменена","decor.furniture":"Мебель","decor.image":"Изображение","decor.image_title":"Свои изображения","decor.image_upload":"Загрузить изображение","decor.image_replace":"Заменить изображение","decor.image_uploading":"Загрузка…","decor.image_asset":"Файл изображения","decor.image_pick_hint":"Загрузите изображение или выберите уже используемое в House Plan.","decor.image_place_hint":"Кликните по плану, чтобы разместить изображение.","decor.image_none":"Загруженных изображений пока нет.","decor.image_unavailable":"Изображение недоступно","decor.image_used":"Используется в объектах: {n}","decor.image_upload_failed":"Не удалось загрузить изображение: {err}","decor.image_error_capacity":"Хранилище пользовательских изображений заполнено.","decor.image_in_use":"Перед удалением файла удалите все размещённые копии.","decor.image_delete_title":"Удалить файл изображения?","decor.image_delete_message":"Удалить «{name}» из House Plan? Это действие нельзя отменить.","furn.title":"Библиотека мебели","furn.symbol":"Символ","furn.group_furniture":"Мебель","furn.group_appliance":"Техника","furn.group_sanitary":"Сантехника","furn.group_other":"Прочее","furn.width":"Ширина","furn.depth":"Глубина","furn.back_to_categories":"Все категории","furn.pick_hint":"Выберите категорию, затем символ.","furn.place_hint":"Кликните по плану — предмет встанет к ближайшей стене. Shift — свободно.","furn.cat_air_conditioner":"Кондиционеры","furn.cat_armchair":"Кресла","furn.cat_bathtub":"Ванны","furn.cat_bed":"Кровати","furn.cat_bidet":"Биде","furn.cat_boiler":"Бойлеры","furn.cat_chair":"Стулья","furn.cat_coffee_table":"Журнальные столы","furn.cat_computer":"Компьютер","furn.cat_cooktop":"Варочные панели","furn.cat_dining_table":"Обеденные столы","furn.cat_dishwasher":"Посудомоечные машины","furn.cat_dryer":"Сушильные машины","furn.cat_fireplace":"Камины","furn.cat_fridge":"Холодильники","furn.cat_hood":"Вытяжка","furn.cat_kitchen_cabinet":"Кухонные шкафы","furn.cat_kitchen_sink":"Кухонные мойки","furn.cat_nightstand":"Тумбы","furn.cat_oven":"Духовка","furn.cat_plant":"Растения","furn.cat_rug":"Ковры","furn.cat_shelving":"Стеллажи","furn.cat_shower":"Душевые","furn.cat_sink":"Раковины","furn.cat_sofa":"Диваны","furn.cat_stairs":"Лестницы","furn.cat_toilet":"Унитазы","furn.cat_tv":"Телевизоры","furn.cat_wardrobe":"Шкафы","furn.cat_washer":"Стиральные машины","furn.cat_work_table":"Рабочие столы","furn.sym_cactus":"Кактус","furn.sym_computer":"Компьютер","furn.sym_hood":"Вытяжка","furn.sym_oven":"Духовка","furn.sym_sofa":"Диван двухместный","furn.sym_sofa_three_seat":"Диван трёхместный","furn.sym_sofa_corner_right":"Угловой диван, правый","furn.sym_armchair":"Кресло мягкое","furn.sym_armchair_office":"Кресло офисное","furn.sym_coffee_table":"Журнальный стол, прямоугольный","furn.sym_coffee_table_round":"Журнальный стол, круглый","furn.sym_coffee_table_oval":"Журнальный стол, овальный","furn.sym_coffee_table_rounded":"Журнальный стол, скруглённый","furn.sym_table_dining":"Обеденный стол, прямоугольный","furn.sym_table_round":"Круглый стол","furn.sym_table_dining_oval":"Обеденный стол, овальный","furn.sym_table_dining_rounded":"Обеденный стол, скруглённый","furn.sym_chair":"Стул","furn.sym_chair_bar":"Барный стул","furn.sym_desk":"Рабочий стол, прямоугольный","furn.sym_desk_corner":"Рабочий стол, угловой","furn.sym_bed_double":"Двуспальная кровать","furn.sym_bed_single":"Односпальная кровать","furn.sym_nightstand":"Тумба прикроватная","furn.sym_cabinet_tv":"Тумба под телевизор","furn.sym_cabinet_shoe":"Тумба для обуви","furn.sym_cabinet_sink":"Тумба под раковину","furn.sym_wardrobe":"Шкаф гардеробный","furn.sym_bookshelf":"Шкаф книжный","furn.sym_wall_unit":"Шкаф-стенка","furn.sym_kitchen_floor":"Кухонный напольный модуль","furn.sym_kitchen_floor_corner":"Кухонный напольный угловой модуль","furn.sym_kitchen_wall":"Кухонный навесной модуль","furn.sym_kitchen_wall_corner":"Кухонный навесной угловой модуль","furn.sym_shelf_floor":"Стеллаж напольный","furn.sym_shelf_wall":"Полка настенная","furn.sym_fridge":"Холодильник","furn.sym_stove":"Варочная панель, 4 конфорки","furn.sym_cooktop_two":"Варочная панель, 2 конфорки","furn.sym_dishwasher":"Посудомоечная машина","furn.sym_washer":"Стиральная машина","furn.sym_dryer":"Сушильная машина","furn.sym_tv":"Телевизор на подставке","furn.sym_tv_wall":"Телевизор на кронштейне","furn.sym_ac":"Кондиционер","furn.sym_water_heater":"Бойлер","furn.sym_toilet":"Унитаз напольный","furn.sym_toilet_built_in":"Унитаз встроенный","furn.sym_bathtub":"Ванна прямоугольная","furn.sym_bathtub_corner":"Ванна угловая","furn.sym_shower":"Душ","furn.sym_sink":"Раковина","furn.sym_kitchen_sink":"Кухонная мойка одинарная","furn.sym_kitchen_sink_double":"Кухонная мойка двойная","furn.sym_bidet":"Биде напольное","furn.sym_bidet_built_in":"Биде встроенное","furn.sym_stairs":"Лестница","furn.sym_fireplace":"Камин","furn.sym_plant":"Растение","furn.sym_rug":"Ковёр","common.yes":"Да","common.no":"Нет","vac.diag_source":"Источник","vac.diag_platform":"Интеграция","vac.diag_status":"Статус","vac.diag_position":"Позиция","vac.diag_rooms":"Комнаты","vac.diag_rooms_value":"{total} · совпало имён: {matched} · {readiness}","vac.autocal_ready":"автокалибровка доступна","vac.autocal_not_ready":"нужно 3 совпавших имени","vac.diag_path":"Путь интеграции","vac.diag_map":"ID карты","vac.source_none":"не выбран","vac.source_status_ok":"Готов","vac.source_status_missing":"Не найден","vac.source_status_disabled":"Деактивирован в Home Assistant","vac.source_status_unavailable":"Недоступен","vac.source_status_unverified":"Нельзя проверить с текущими правами","vac.source_status_unsupported":"Нет данных позиции","vac.source_status_none":"Нет источника","vac.source_banner_missing":"Сохранённый источник больше не существует. Он не заменён автоматически: выберите другой или восстановите его в Home Assistant.","vac.source_banner_disabled":"Сохранённый источник деактивирован в Home Assistant. Активируйте его там или выберите другой.","vac.source_banner_unverified":"Текущих прав Home Assistant недостаточно для проверки источника. Привязка сохранена и не будет заменена автоматически.","vac.choose_source":"Выбрать источник","vac.source_auto":"Автоматически","vac.source_auto_hint":"Использовать совместимую сущность этого устройства","vac.all_cameras":"Все камеры","vac.all_cameras_warn":"Камера может не отдавать данные робота. Выбирайте её только если это карта вашего пылесоса.","vac.all_cameras_empty":"Других сущностей камеры не найдено.","vac.platform_unknown":"интеграция неизвестна","vac.cap_position":"позиция","vac.cap_rooms_short":"комнаты","vac.cap_path":"путь","vac.cap_map":"ID карты","vac.cap_none":"данные робота не обнаружены","vac.xcme_hint":"Включите атрибуты Xiaomi Cloud Map Extractor:","vac.documentation":"Документация","vac.residual_title":"Проверьте автокалибровку","vac.residual_message":"Совпавшие комнаты расходятся максимум на {error}. Примените приблизительную калибровку, подгоните её вручную либо отмените без изменения сохранённых настроек.","vac.apply_proposal":"Применить","gs.backup_group":"Резервная копия и перенос","backup.export_open":"Экспорт","backup.import_open":"Импорт","backup.export_title":"Экспорт House Plan","backup.import_title":"Импорт House Plan","backup.export_hint":"Выберите, должна ли копия содержать всю конфигурацию House Plan или только текущее пространство.","backup.full":"Полная копия","backup.current_space":"Текущее пространство","backup.current_space_title":"Текущее пространство: {title}","backup.no_current_space":"Нет текущего пространства","backup.plan_only":"Только планировка","backup.plan_only_hint":"Сохранить комнаты, стены, проёмы, декор и позиции подписей комнат без устройств и привязок Home Assistant.","backup.plan_only_preview":"Файл содержит только планировку","backup.privacy_warning":"Архив сохраняет названия, идентификаторы Home Assistant и точные координаты. Внутренние планы и вложения указываются ссылками, но не вкладываются; текущие состояния и маршруты пылесосов не включаются.","backup.download":"Скачать JSON","backup.export_done":"Резервная копия скачана","backup.reading":"Проверяем резервную копию…","backup.revalidated":"После предпросмотра план изменился. Сводка обновлена — проверьте её и подтвердите ещё раз.","backup.error.support_invalid_message":"Проверьте сообщение для поддержки и повторите попытку.","backup.error.support_package_too_large":"Обезличенный пакет для поддержки превышает лимит 8 МиБ.","backup.error.support_preview_expired":"Предпросмотр вложения для поддержки истёк или больше недоступен.","backup.error.support_rate_limited":"Запрошено слишком много репортов или предпросмотров. Повторите позже.","backup.error.support_rejected":"Репорт не прошёл проверку службы поддержки.","backup.error.support_unavailable":"Закрытая служба поддержки временно недоступна.","backup.error.unauthorized":"У вас нет прав на экспорт или импорт этого плана.","backup.error.not_ready":"House Plan ещё не готов. Повторите попытку через несколько секунд.","backup.error.too_large":"Размер резервной копии превышает 8 МиБ.","backup.error.invalid_json":"Выбранный файл не является корректным JSON.","backup.error.invalid_format":"Выбранный файл не является резервной копией House Plan.","backup.error.invalid_image":"Изображение повреждено или не соответствует своему формату.","backup.error.unsupported_export_version":"Эта версия формата резервной копии не поддерживается установленной версией.","backup.error.unsupported_image":"Используйте поддерживаемое изображение PNG, JPEG, WebP или SVG.","backup.error.future_model":"Резервная копия создана в более новой версии модели данных House Plan.","backup.error.invalid_config":"Резервная копия содержит некорректную конфигурацию House Plan.","backup.error.wall_model_migration_blocked":"Не удалось безопасно обновить модель стен из резервной копии. Сначала оптимизируйте исходный план и повторите экспорт.","backup.error.invalid_layout":"Резервная копия содержит некорректные позиции объектов.","backup.error.invalid_content":"Резервная копия содержит некорректные или несогласованные ссылки на файлы.","backup.error.space_not_found":"Выбранное пространство больше не существует.","backup.error.capacity_exceeded":"Добавление этой копии превысит ограничения размера плана.","backup.error.preview_expired":"Время предпросмотра истекло. Выберите файл резервной копии заново.","backup.error.preview_owner_mismatch":"Этот предпросмотр принадлежит другому пользователю Home Assistant.","backup.error.conflict":"После предпросмотра план изменился. Проверьте обновлённую сводку.","backup.error.content_confirmation_required":"Подтвердите отсоединение недоступных локальных файлов.","backup.error.commit_failed":"Не удалось безопасно применить копию. Предыдущий план восстановлен или ожидает восстановления.","backup.error.missing_plan":"После предпросмотра исчез связанный файл плана. Проверьте копию ещё раз.","backup.error.missing_content":"После предпросмотра исчез связанный локальный файл. Проверьте копию ещё раз.","backup.error.marker_control_missing":"В резервной копии отсутствует связанный источник света на плане.","backup.error.marker_control_not_light":"Связанная цель больше не отмечена как источник света.","backup.error.marker_control_self":"Источник света не может управлять самим собой.","backup.error.marker_control_cycle":"Резервная копия содержит циклическую цепочку управления светом.","backup.error.duplicate_marker_control":"Резервная копия содержит повторяющуюся связь с источником света.","backup.error.no_backup":"Нет снимка импорта или оптимизации, который можно восстановить.","backup.error.in_use":"Элемент ещё используется","backup.error.invalid_data":"Запрос содержит некорректные данные","backup.error.invalid_light_entity":"Ведущий свет должен быть сущностью light.* или switch.*","backup.error.invalid_marker_control":"Некорректная ссылка управления маркером","backup.error.invalid_name":"Некорректное имя","backup.error.invalid_partition_opening_host":"Проём должен сохранить свою перегородку-носитель","backup.error.invalid_partition_opening_jamb_margin":"Проём не оставляет физического простенка у края стены","backup.error.invalid_passage_fields":"Открытый проход не может нести настройки двери","backup.error.invalid_space_id":"Неизвестное пространство","backup.error.invalid_toggle_entity":"Сущность переключения должна быть light.* или switch.*","backup.error.invalid_value_badge":"Некорректные настройки бейджа значения","backup.error.invalid_value_badge_attribute":"Некорректный атрибут бейджа значения","backup.error.invalid_value_badge_position":"Некорректная позиция бейджа значения","backup.error.invalid_value_badge_source":"Некорректный источник бейджа значения","backup.error.invalid_vacuum_map_route":"Проверьте сопоставление карт робота пространствам.","backup.error.invalid_value_source":"Некорректный источник значения","backup.error.invalid_value_source_attribute":"Некорректный атрибут источника значения","backup.error.io_error":"Файловая операция на сервере не удалась","backup.error.not_toggleable":"Это устройство нельзя переключить","backup.error.nothing_to_repair":"Нечего чинить","backup.error.space_in_use":"На пространство ещё есть ссылки","backup.error.value_badge_source_required":"Бейджу значения нужен источник","backup.error.wall_model_client_outdated":"План обновлён в другом месте — перезагрузите страницу","backup.same_source":"Создано на этом экземпляре Home Assistant","backup.foreign_source":"Создано на другом экземпляре Home Assistant","backup.created":"Создано: {value}","backup.versions":"Карточка {card}; интеграция {integration}; модель данных {model}","backup.count_spaces":"Пространств: {n}","backup.count_rooms":"Комнат: {n}","backup.count_walls":"Стен: {n}","backup.count_openings":"Проёмов: {n}","backup.count_decor":"Объектов декора: {n}","backup.count_markers":"Устройств: {n}","backup.count_layout":"Позиций: {n}","backup.bindings":"Привязки — устройства: {device}, сущности: {entity}, виртуальные: {virtual}; позиций без пространства: {legacy}","backup.binding_status":"Статус на целевом экземпляре — активных: {active}, деактивированных: {disabled}, отсутствующих: {missing}","backup.missing_areas":"На целевом экземпляре отсутствуют зоны: {areas}","backup.dropped_marker_links":"Связи с источниками света вне переносимого пространства пропущены: {n}.","backup.room_drafts_migrated":"Старые незавершённые контуры преобразованы в обычные стены: {drafts}; отрезков: {segments}.","backup.repaired_target_refs":"Существующих ссылок восстановлено этим импортом: {n}.","backup.preserved_unresolved_refs":"Неоднозначные ссылки сохранены без изменений: {n}.","backup.preserved_unresolved_hint":"House Plan ничего не угадывал и не удалял. После импорта запустите «Оптимизировать планы», чтобы проверить оставшиеся ссылки.","backup.import_details":"Подробности восстановления ссылок","backup.import_detail.incoming_remapped":"Ссылок обновлено внутри импортируемой копии: {n}","backup.import_detail.target_repaired":"Существующих ссылок восстановлено: {n}","backup.import_detail.preserved_unresolved":"Неразрешимых ссылок сохранено: {n}","backup.import_detail.collisions":"Конфликтов назначения безопасно сохранено: {n}","backup.import_detail.dropped_links":"Входящих связей пропущено по правилам переноса: {n}","backup.import_detail.bounded_lineages":"Чрезмерно вложенных идентификаторов ограничено: {n}","backup.replace_warning":"Текущая конфигурация и расположение будут заменены. Загруженные файлы не удаляются. Одну отмену можно выполнить до следующего изменения плана.","backup.foreign_bookkeeping":"Служебные списки известных и новых устройств другого экземпляра импортированы не будут.","backup.final_name":"Название нового пространства","backup.target_settings":"Глобальные настройки целевого экземпляра не изменятся.","backup.duplicates":"Уже существующих привязок: {n}","backup.skip":"Пропустить повторяющиеся устройства","backup.virtual_copy":"Добавить безопасные статичные виртуальные копии","backup.content":"Связанное содержимое","backup.decor_images_summary":"Свои изображения: объектов — {objects}, файлов — {assets}; отсутствует файлов — {missing}.","backup.content_available":"доступно локально","backup.content_external":"внешняя ссылка","backup.content_detach_required":"будет отвязано","backup.confirm_detach":"Я понимаю, что недоступные внутренние планы и вложения будут отвязаны от импортируемой конфигурации.","backup.confirm_missing_images":"Я понимаю, что отсутствующие свои изображения останутся восстанавливаемыми заглушками, а остальные недоступные локальные файлы будут отвязаны.","backup.replace":"Заменить","backup.add":"Добавить пространство","backup.space_done":"Пространство импортировано: комнат — {rooms}, устройств — {markers}, существующих ссылок восстановлено — {refs}","backup.full_done":"Копия восстановлена: пространств — {spaces}, комнат — {rooms}, устройств — {markers}","backup.undo_import":"Отменить последний полный импорт","backup.import_undone":"Полный импорт отменён","backdrop.large_title":"Большое изображение","backdrop.large_body":"Изображение {w}×{h} ({fileMb} МБ), для показа потребуется около {decodedMb} МБ памяти. На планшетах это может привести к падению страницы.","backdrop.unknown_body":"Не удалось прочитать размеры изображения — файл может быть повреждён. Продолжение может привести к падению страницы на планшете.","backdrop.reduced_dimensions":"Уменьшенная копия: {w}×{h} px.","backdrop.use_downscaled":"Загрузить уменьшенную копию","backdrop.reducing":"Уменьшаем…","backdrop.keep_original":"Оставить оригинал","backdrop.too_large_title":"Изображение слишком большое","backdrop.too_large_body":"Изображение превышает возможности браузера ({w}×{h}, предел {limit} px по стороне). Уменьшите его в редакторе на компьютере и загрузите снова.","backdrop.downscale_failed":"Не удалось создать уменьшенную копию. Текущий план не изменён.","gs.card_display":"Отображение","gs.card_zigbee":"Связи Zigbee","gs.card_fills":"Цвета заливки комнат","gs.card_plan":"План","gs.card_data":"Данные","gs.card_fills.help.aria":"О цветах заливки комнат","gs.backup_group.help.aria":"О резервной копии и переносе","gs.grid_group.help.aria":"Об обслуживании плана","gs.backup_group.help":"Скачайте переносимую JSON-копию или проверьте и импортируйте копию, созданную House Plan.","gs.grid_group.help":"Обновляет модели данных, выравнивает элементы по сетке и объединяет лишние фрагменты стен. Перед записью будет показан точный отчёт.","gs.card_fills.help":"Цвета заливок действуют на все пространства; у каждого цвета своя прозрачность. Какой режим заливки использует пространство — задаётся в его диалоге.","space.card_basics":"Основное","space.card_sun":"Солнце и свет","marker.card_basics":"Основное","marker.card_tap":"Действие по нажатию","marker.card_light":"Свет и свечение","marker.card_appearance":"Внешний вид","marker.card_details":"Подробности"}},{code:"de",nativeLabel:"Deutsch",loadDictionary:async function(e){const t=0===e?await import("./de-AkOtg0jq.js"):await import(new URL("./de-AkOtg0jq.js?retry",import.meta.url).href);return{dictionary:t.dictionary,fingerprint:t.fingerprint}}},{code:"fr",nativeLabel:"Français",loadDictionary:async function(e){const t=0===e?await import("./fr-Ds3OdruH.js"):await import(new URL("./fr-Ds3OdruH.js?retry",import.meta.url).href);return{dictionary:t.dictionary,fingerprint:t.fingerprint}}}],_p=lp,mp=new Set;const gp=new class{constructor(e,t,i=console.warn,n){this.entries=e,this.expectedFingerprint=t,this.warn=i,this.loadFailed=n,this.dictionaries=new Map,this.pending=new Map,this.failed=new Set;for(const t of e)t.dictionary&&this.dictionaries.set(t.code,t.dictionary)}state(e){return this.dictionaries.has(e)?"ready":this.failed.has(e)?"fallback":"pending"}dictionary(e){return this.dictionaries.get(e)}ensure(e){if("pending"!==this.state(e))return Promise.resolve();const t=this.pending.get(e);if(t)return t;const i=this.entries.find(t=>t.code===e),n=this.load(i).finally(()=>this.pending.delete(e));return this.pending.set(e,n),n}async load(e){if(!e?.loadDictionary)return void(e&&this.failed.add(e.code));let t;for(const i of[0,1])try{const t=await e.loadDictionary(i);if(t.fingerprint!==this.expectedFingerprint)throw new Error(`locale fingerprint mismatch for ${e.code}`);return this.dictionaries.set(e.code,t.dictionary),void this.failed.delete(e.code)}catch(e){t=e}this.failed.add(e.code),this.warn(`[houseplan] unable to load ${e.code} locale; using English`,t),this.loadFailed?.(e.code)}}(pp,"c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f",console.warn,function(e){for(const t of mp)t(e)});function fp(e){const t=bp(e)?.code??"en";return gp.dictionary(t)??_p}function vp(e){return"string"==typeof e?e.trim().replaceAll("_","-").toLowerCase():""}const yp=new Map(pp.map(e=>[vp(e.code),e]));function bp(e){return yp.get(vp(e))}function wp(e,t){const i=[{value:"",label:e},...pp.map(({code:e,nativeLabel:t})=>({value:e,label:t}))],n="string"==typeof t?t:"";return n&&!i.some(e=>e.value===n)&&i.push({value:n,label:bp(n)?.nativeLabel??n}),i}function kp(e,t){return function(e,t,i,n){const r=new Map(i.map(e=>[vp(e),e])),o=r.get(vp(e));if(o)return o;const s=vp(t),a=r.get(s);return a||(r.get(s.split("-")[0]||"")??n)}(t,e?.locale?.language||e?.language,pp.map(({code:e})=>e),"en")}function xp(e,t,i){return on(fp(e)[t]??_p[t]??t,i)}function Sp(e,t){const i=fp(e)[t]??_p[t];return"string"==typeof i&&i.trim().length>0}function $p(e,t,i,n){return{ox:0,oy:0}}function Mp(e,t){const i=(e.angle+90)*Math.PI/180,n=Wa(16,t),r=e.gateFace?-n*e.gateFace.side:n*(e.flipV?-1:1);return[[e.x+Math.cos(i)*r,e.y+Math.sin(i)*r],r<0]}function Rp(e){const t=e.length/2,i=e.face.cm>0?e.face.cm/e.cellCm*e.gridPitch/2:Wa(4,e.cellCm),n="gate"===e.type?Math.sin(10*Math.PI/180)*t:0;return{half:t,jambHalf:i,gateDepth:n,outlineHalf:Math.max(Wa(16,e.cellCm),i+Wa(8,e.cellCm),n+Wa(8,e.cellCm)),hitHalf:Math.max(Wa(20,e.cellCm),i+Wa(10,e.cellCm),n+Wa(12,e.cellCm))}}function Cp(e,t,i){e.minX=Math.min(e.minX,t),e.minY=Math.min(e.minY,i),e.maxX=Math.max(e.maxX,t),e.maxY=Math.max(e.maxY,i)}function Tp(e,t,i,n,r,o,s,a){const l=Math.min(s,a)*Math.PI/180,c=Math.max(s,a)*Math.PI/180,h=(e,t)=>{const i=Math.atan2(t,e),n=[l,c];for(let e=-3;e<=3;e++){const t=e*Math.PI-i,r=Math.PI/2+e*Math.PI-i;t>l&&tl&&r0&&[e.length,e.angle,t[0],t[1]].every(Number.isFinite)))return null;const{half:i,jambHalf:n}=Rp(e),r=ja(e.cellCm),o=1.75*r,s=1.25*r,a=.75*r,l={minX:-i-s,minY:-n-s,maxX:i+s,maxY:n+s},c={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};if("window"===e.type)Tp(c,-i,0,i,-o,o,-90,0),Tp(c,i,-i,0,-o,o,0,90),Cp(c,-i-a,-i-a),Cp(c,i+a,a);else if("gate"===e.type){const t=10*e.face.side;Tp(c,-i,0,i,-o,o,0,t),Tp(c,i,-i,0,-o,o,-t,0)}else Tp(c,-i,0,e.length,-o,o,-90,0),Cp(c,-i-a,-e.length-a),Cp(c,i+a,a);const[h,d]=Dp(e),u={...l};Cp(u,c.minX+h,c.minY+d),Cp(u,c.maxX+h,c.maxY+d);const p=e.flipH?-1:1,_="gate"===e.type?1:e.flipV?-1:1,m=e.angle*Math.PI/180,g=Math.cos(m),f=Math.sin(m),v={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};for(const e of[u.minX,u.maxX])for(const i of[u.minY,u.maxY]){const n=e*p,r=i*_;Cp(v,t[0]+n*g-r*f,t[1]+n*f+r*g)}return v}function Pp(e){if("passage"===e.type)return W``;const t=Math.max(0,Math.min(1,e.amount)),{half:i,jambHalf:n}=Rp(e),r=ja(e.cellCm),o=1.75*r,s=e.flipH?-1:1,a=e.flipV?-1:1,l="gate"===e.type?1:a,[c,h]=Dp(e);let d;if("window"===e.type){const o=Math.PI/2*i,s=e.face.cm>0?W``)}`}const Cr={color:"#607d8b",opacity:1,widthCm:3.6,fill:!1,fillColor:"#607d8b",fillOpacity:.25},Tr=(e,t=1)=>{const i=Number(e);return Number.isFinite(i)?Math.min(1,Math.max(0,i)):t},Dr=e=>{let t=Number(e);return Number.isFinite(t)?(t=(t%360+360)%360,t>180?t-360:t):0};function Ar(e,t,i){return Dr(t)?[e.x,e.y]:i([e.x,e.y])}function Pr(e,t,i,n){const r=Math.abs(i[0]-t[0]),o=Math.abs(i[1]-t[1]);return"line"===e?Math.hypot(r,o)>=n:r>=n&&o>=n}const Fr=(e,t,i)=>{const n=Number(e),r=Number.isFinite(t)&&t>0?t:5;return Number.isFinite(n)&&n>0?n/r*i:0},zr=(e,t,i)=>{const n=Number(e),r=Number.isFinite(t)&&t>0?t:5;return Number.isFinite(n)&&i>0?n/i*r:0},Ir=(e,t,i,n=Cr.widthCm)=>{const r=Number(e?.width_cm);if(Number.isFinite(r)&&r>0)return r;const o=Number(e?.width);return Number.isFinite(o)&&o>0?zr(o,t,i):n};function Or(e){const t=Cr;return e.color===t.color&&e.opacity===t.opacity&&e.widthCm===t.widthCm&&e.fill===t.fill&&e.fillColor===t.fillColor&&e.fillOpacity===t.fillOpacity?null:{color:e.color,opacity:Tr(e.opacity),width_cm:Math.max(.1,Math.min(100,Number(e.widthCm)||.1)),fill:!!e.fill,fill_color:e.fillColor,fill_opacity:Tr(e.fillOpacity,.25)}}function Er(e,t){return{color:e.color,opacity:Tr(e.opacity),width_cm:Math.max(.1,Math.min(100,Number(e.widthCm)||.1)),...t?{fill:e.fill,fill_color:e.fillColor,fill_opacity:Tr(e.fillOpacity,.25)}:{}}}function Nr(e){const t=e.x+e.w/2,i=e.y+e.h/2,n=Dr(e.angle)*Math.PI/180,r=Math.cos(n),o=Math.sin(n),s=(e,n)=>{const s=e-t,a=n-i;return[t+s*r-a*o,i+s*o+a*r]};return[s(e.x,e.y),s(e.x+e.w,e.y),s(e.x+e.w,e.y+e.h),s(e.x,e.y+e.h)]}function Hr(e){const t=Nr(e),i=(e,t)=>[(e[0]+t[0])/2,(e[1]+t[1])/2],n=[(t[0][0]+t[2][0])/2,(t[0][1]+t[2][1])/2];return{points:[...t,i(t[0],t[1]),i(t[1],t[2]),i(t[2],t[3]),i(t[3],t[0]),n],segments:t.map((e,i)=>({a:e,b:t[(i+1)%4]}))}}function Lr(e,t,i,n,r,o,s,a){const l=Dr(e.angle)*Math.PI/180,c=Math.cos(l),h=Math.sin(l),d=-Math.sin(l),u=Math.cos(l),p=e.x+e.w/2,_=e.y+e.h/2,m=t>0?-e.w/2:e.w/2,g=i>0?-e.h/2:e.h/2,f=p+m*c+g*d,v=_+m*h+g*u,y=n-f,b=r-v;let w=(y*c+b*h)*(t>0?1:-1),k=(y*d+b*u)*(i>0?1:-1),x=null;if(o){const t=w/Math.max(e.w,a),i=k/Math.max(e.h,a);x=Math.max(a/Math.max(e.w,a),a/Math.max(e.h,a),t,i),w=e.w*x,k=e.h*x}if(s>0)if(o){const t=Math.max(1,Math.round(e.w/s)),i=Math.max(1,Math.round(e.h/s));if(Math.abs(e.w-t*s)<1e-6&&Math.abs(e.h-i*s)<1e-6){const n=(e,t)=>{let i=Math.abs(e),n=Math.abs(t);for(;n;)[i,n]=[n,i%n];return Math.max(1,i)},r=1/n(t,i),o=Math.max(a/e.w,a/e.h),s=Math.max(o,Math.round((x??1)/r)*r);w=e.w*s,k=e.h*s}else{e.w>=e.h?(w=Math.round(w/s)*s,k=w*(e.h/Math.max(e.w,a))):(k=Math.round(k/s)*s,w=k*(e.w/Math.max(e.h,a)))}}else w=Math.round(w/s)*s,k=Math.round(k/s)*s;w=Math.max(a,w),k=Math.max(a,k);return{x:f+(t>0?w/2:-w/2)*c+(i>0?k/2:-k/2)*d-w/2,y:v+(t>0?w/2:-w/2)*h+(i>0?k/2:-k/2)*u-k/2,w:w,h:k,angle:Dr(e.angle)||void 0}}const Br=(e,t,i)=>{const n=i[0]-t[0],r=i[1]-t[1],o=n*n+r*r;if(o<1e-12)return[...t];const s=Math.max(0,Math.min(1,((e[0]-t[0])*n+(e[1]-t[1])*r)/o));return[t[0]+n*s,t[1]+r*s]};function qr(e,t,i,n){const r=n(e);let o=null;for(const r of t.points){const t=n(r),s=Math.hypot(t[0]-e[0],t[1]-e[1]);s<=i&&(!o||se.points),segments:e.flatMap(e=>e.segments)}}const Wr=Math.tan(.25*Math.PI/180);function Ur(e,t){const i=Math.abs(Number(t[0])-Number(e[0])),n=Math.abs(Number(t[1])-Number(e[1]));if(!([i,n].every(Number.isFinite)&&i>0&&n>0))return null;const r=i>=n?"horizontal":"vertical",o=Math.max(i,n),s=Math.min(i,n);return s/o>Wr?null:{axis:r,major:o,minor:s,angleDegrees:180*Math.atan2(s,o)/Math.PI}}function Gr(e,t){const i=Ur(e,t);return i?"horizontal"===i.axis?[Number(t[0]),Number(e[1])]:[Number(e[0]),Number(t[1])]:[Number(t[0]),Number(t[1])]}const Vr=e=>`${e[0]},${e[1]}`,Kr=(e,t)=>e[0]===t[0]&&e[1]===t[1],Yr=(e,t)=>{const i=Vr(e),n=Vr(t);return i{let t=0;for(let i=0;i{if(e.length<3)return!1;for(let t=0;t1e-12},Jr=(e,t)=>Kr(e,t.from)?[...t.to]:[...e],Qr=(e,t)=>e.map(e=>Array.isArray(e?.poly)?{...e,poly:e.poly.map(e=>Jr(e,t))}:e),eo=(e,t,i)=>{const n=e.flatMap((e,t)=>ni(e)?.some(e=>Kr(e,i.from))?[t]:[]);if(!n.length)return!1;for(const i of n){const n=ni(e[i]),r=ni(t[i]);if(!n||!r)continue;if(!Zr(r))return!1;const o=Math.sign(Xr(n)),s=Math.sign(Xr(r));if(o&&s&&o!==s)return!1}const r=new Set;for(const e of n){const i=ni(t[e]);if(i)for(let n=0;n{let i=0;for(const n of e){const e=ni(n);if(e)for(let n=0;n{const{a:i,b:n,axis:r}=e,o="horizontal"===r?{from:n,to:[n[0],i[1]]}:{from:n,to:[i[0],n[1]]},s="horizontal"===r?{from:i,to:[i[0],n[1]]}:{from:i,to:[n[0],i[1]]};return[{move:o,preservedDegree:to(t,i)},{move:s,preservedDegree:to(t,n)}].sort((e,t)=>t.preservedDegree-e.preservedDegree||Vr(e.move.to).localeCompare(Vr(t.move.to))||Vr(e.move.from).localeCompare(Vr(t.move.from))).map(e=>e.move)};function no(e){const t=JSON.parse(JSON.stringify(e||{}));let i=Array.isArray(t.rooms)?t.rooms:[];const n=new Map;for(const e of i){const t=ni(e);if(t)for(let e=0;ee.key.localeCompare(t.key))){let t=null;for(const n of io(e,i)){const e=a.get(Vr(n.from));if(e&&e!==Vr(n.to))continue;const r=Qr(i,n);if(eo(i,r,n)){t=n,i=r;break}}t?(a.set(Vr(t.from),Vr(t.to)),r++,s=Math.max(s,Math.hypot(t.to[0]-t.from[0],t.to[1]-t.from[1]))):o++}t.rooms=i;for(const e of t.partitions||[]){if(!Array.isArray(e?.a)||!Array.isArray(e?.b))continue;const i=Ur(e.a,e.b);if(!i)continue;const n={key:String(e.id||Yr(e.a,e.b)),a:[...e.a],b:[...e.b],axis:i.axis};let a=null;for(const i of io(n,[{poly:[e.a,e.b]}])){const n=Jr(e.a,i),r=Jr(e.b,i),o=Math.hypot(r[0]-n[0],r[1]-n[1]);if(!(o>0))continue;const s=(t.openings||[]).filter(t=>"partition"===t?.host?.kind&&t.host.id===e.id).every(e=>{const t=Number(e.host.t),i=Number(e.length);return Number.isFinite(t)&&t>=0&&t<=1&&Number.isFinite(i)&&i>0&&t*o-i/2>=-1e-12&&t*o+i/2<=o+1e-12});if(s){a=i,e.a=n,e.b=r;break}}a?(r++,s=Math.max(s,Math.hypot(a.to[0]-a.from[0],a.to[1]-a.from[1]))):o++}return{space:t,report:{wallsStraightened:r,wallsStraightenSkipped:o,maxStraightenShift:s},changed:r>0}}const ro=["rect","ellipse","furniture","image"],oo=10**9,so=240,ao=1e-4;function lo(e){if(Array.isArray(e))return e.map(e=>lo(e));if(null!==e&&"object"==typeof e){const t={};for(const[i,n]of Object.entries(e))t[i]=lo(n);return t}return e}function co(e){if("number"!=typeof e||!Number.isFinite(e))return e;const t=(e<0||Object.is(e,-0)?-1:1)*(Math.floor(Math.abs(e)*oo+.5)/oo);return 0===t?0:t}function ho(e){if("number"!=typeof e||!Number.isFinite(e))return e;const t=e*so,i=Math.round(t);if(Math.abs(t-i)null!==po(e)):[]}function mo(e){return"string"==typeof e&&ro.includes(e)}function go(e,t){for(const i of t)Object.prototype.hasOwnProperty.call(e,i)&&(e[i]=co(e[i]))}function fo(e,t){for(const i of t)Object.prototype.hasOwnProperty.call(e,i)&&(e[i]=ho(e[i]))}function vo(e){if(Array.isArray(e))for(let t=0;t{for(const r of n){const n=t[r];"number"==typeof n&&Number.isFinite(n)&&i(n,e)}},n=t=>{if(Array.isArray(t))for(let n=0;n{if(Array.isArray(e))for(const t of e)n(t)};for(const i of _o(e.rooms))t(i,["x","y","w","h"]),r(i.poly);for(const t of _o(e.walls))n(t.a),n(t.b);for(const t of _o(e.wall_segments))n(t.a),n(t.b);for(const i of _o(e.openings))t(i,["x","y"]);for(const i of _o(e.decor))"line"===i.kind?t(i,["x1","y1","x2","y2"]):mo(i.kind)?t(i,["x","y","w","h"]):"text"===i.kind&&t(i,["x","y"]);for(const t of _o(e.room_drafts))r(t.points);for(const t of _o(e.partitions))n(t.a),n(t.b);for(const t of _o(e.wall_columns))n(t.center);for(const t of _o(e.open_spans))n(t.a),n(t.b)}const r=po(t);if(!r)return;const o=new Map;if(n)for(const e of _o(n.spaces))null!=e.id&&o.set(String(e.id),e);for(const e of Object.values(r)){const t=po(e);if(!t)continue;const n=null!=t.s&&o.get(String(t.s))||null;for(const e of["x","y"]){const r=t[e];"number"==typeof r&&Number.isFinite(r)&&i(r,n)}}}function wo(e){const t=Number(e?.cell_cm);return t>0?t:5}function ko(e,t={}){const i={canonicalized:0,far:0,maxShift:0,maxShiftCm:0,spaces:[],bySpace:new Map},n=_o(po(e)?.spaces);let r=5;for(const e of n)r=Math.max(r,wo(e));bo(e,t,(e,t)=>{const n=e*so,o=Math.abs(n-Math.round(n)),s=ho(e),a=o>0&&o=ao))return;const l=a&&"number"==typeof s?Math.abs(s-e):0;if(a?i.canonicalized++:i.far++,i.maxShift=Math.max(i.maxShift,l),i.maxShiftCm=Math.max(i.maxShiftCm,l*so*(t?wo(t):r)),!t?.id||!a)return;const c=String(t.id);let h=i.bySpace.get(c);h||(h={spaceId:c,space:String(t.title||c),canonicalized:0,far:0,maxShift:0,maxShiftCm:0},i.bySpace.set(c,h)),h.canonicalized++,h.maxShift=Math.max(h.maxShift,l),h.maxShiftCm=Math.max(h.maxShiftCm,l*so*wo(t))}),i.bySpace.size&&bo(e,t,(e,t)=>{if(!t?.id)return;const n=i.bySpace.get(String(t.id));if(!n)return;const r=e*so;Math.abs(r-Math.round(r))>=ao&&n.far++}),i.spaces=[...i.bySpace.values()];const{bySpace:o,...s}=i;return s}function xo(e){return function(e){const t=e,i=po(t);i&&fo(i,["x","y"]);return t}(lo(e))}function So(e){const t=e,i=po(t);if(!i)return t;for(const e of Object.values(i)){const t=po(e);t&&fo(t,["x","y"])}return t}function $o(e){return Mo(lo(e))}function Mo(e){const t=e,i=po(t);if(!i)return t;for(const e of _o(i.spaces)){go(e,["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"]);for(const t of _o(e.rooms))fo(t,["x","y","w","h"]),yo(t.poly);for(const t of _o(e.walls))vo(t.a),vo(t.b);for(const t of _o(e.wall_segments))vo(t.a),vo(t.b);for(const t of _o(e.openings)){fo(t,["x","y"]),go(t,["angle","length"]);const e=po(t.host);e&&go(e,["t"])}for(const t of _o(e.decor))"line"===t.kind?fo(t,["x1","y1","x2","y2"]):mo(t.kind)?(fo(t,["x","y","w","h"]),go(t,["angle"])):"text"===t.kind&&(fo(t,["x","y"]),go(t,["scale","angle"]));for(const t of _o(e.room_drafts))yo(t.points);for(const t of _o(e.partitions))vo(t.a),vo(t.b);for(const t of _o(e.wall_columns))vo(t.center),"square"===t.shape&&go(t,["angle"]);for(const t of _o(e.open_spans))vo(t.a),vo(t.b)}for(const e of _o(i.markers))go(e,["angle"]);return t}const Ro=15,Co=8;function To(e,t,i,n,r){const o=i[0]-e[0],s=i[1]-e[1],a=Math.hypot(o,s);if(!(a>0)||a<=r+1e-9)return null;const l=o/a,c=s/a,h=t=>{const n=(t[0]-e[0])*l+(t[1]-e[1])*c,o=(r-n)/(a-n);return!Number.isFinite(o)||o<-1e-9||o>1+1e-9?null:[t[0]+(i[0]-t[0])*o,t[1]+(i[1]-t[1])*o]},d=h(t),u=h(n);return d&&u?[[e[0],e[1]],t,d,u,n]:null}const Do=Math.sin(.25*Math.PI/180);function Ao(e,t){return Number.isFinite(e)&&e>0&&Number.isFinite(t)&&t>0&&e*t<3}function Po(e){const t=Number(e)>0?Number(e):5;if(5===t)return 8;const i=5/t*8;return Math.min(80,Math.max(.5,i))}function Fo(e,t){return Number.isFinite(e)&&e>0&&Number.isFinite(t)&&t>0&&e*t<2}function zo(e){return Number.isFinite(e)?Math.max(1,Math.min(100,e)):1}function Io(e,t){return!Number.isFinite(e)||e<0?"":String(t?Math.round(e/2.54*100)/100:Math.round(100*e)/100)}function Oo(e,t,i){if(!Number.isFinite(e)||e<=0)return 0;const n=Number(t)>0?Number(t):5;return zo(e)/n*i}function Eo(e,t){return t>0&&Number.isFinite(e)?Math.round(e/t)*t:e}function No(e){return Math.max(1e-6*Math.abs(e),1e-9)}function Ho(e,t){if(!(t>0&&Number.isFinite(e)))return e;const i=Eo(e,t);return Math.abs(i-e)<=No(t)?i:e}function Lo(e,t){let i=t[0]-e[0],n=t[1]-e[1];const r=Math.hypot(i,n);return r<1e-12?[1,0]:(i/=r,n/=r,(i<-1e-12||Math.abs(i)<=1e-12&&n<0)&&(i=-i,n=-n),[i,n])}function Bo(e,t,i){const n=[Ho(e[0],i),Ho(e[1],i)],r=[Ho(t[0],i),Ho(t[1],i)],o=Eo((n[0]+r[0])/2,i),s=Eo((n[1]+r[1])/2,i),[a,l]=Lo(n,r);let c=Math.atan2(l,a);c<0&&(c+=Math.PI);const h=Math.round(1800*c)/1800,d=i>0&&i<.01?6:i<1?4:2;return`${o.toFixed(d)},${s.toFixed(d)}@${h.toFixed(4)}`}function qo(e,t,i,n){return 1===n?Bo(e,t,i):Bo([e[0]/n,e[1]/n],[t[0]/n,t[1]/n],i)}function jo(e,t){if(!Array.isArray(e.a)||!Array.isArray(e.b)||e.a.length<2||e.b.length<2)return null;const i=[Number(e.a[0]),Number(e.a[1]),Number(e.b[0]),Number(e.b[1])];if(!i.every(Number.isFinite))return null;const n=t>0?t:1;return[[i[0]*n,i[1]*n],[i[2]*n,i[3]*n]]}function Wo(e,t,i,n,r){const o=r>0?r:1;return{key:qo(e,t,n,o),cm:zo(i),a:[e[0]/o,e[1]/o],b:[t[0]/o,t[1]/o]}}function Uo(e,t){const i=t>0?t:1,n=[];for(const t of e){const e=t.key.lastIndexOf("@");if(e<0)continue;const[r,o]=t.key.slice(0,e).split(",").map(Number),s=Number(t.key.slice(e+1));[r,o,s].every(Number.isFinite)&&n.push({w:t,x:r*i,y:o*i,ang:s})}return n}function Go(e,t){const[i,n]=Lo(e,t);let r=Math.atan2(n,i);return r<0&&(r+=Math.PI),r}function Vo(e,t){let i=Math.abs(e-t);return i>Math.PI/2&&(i=Math.PI-i),i<.02}function Ko(e,t,i,n,r=1){if(!e?.length)return null;const o=qo(t,i,n,r),s=e.find(e=>e.key===o);if(s)return s;const a=r>0?r:1,l=No(n)*a,c=(e,t)=>Math.abs(e[0]-t[0])<=l&&Math.abs(e[1]-t[1])<=l;for(const n of e){const e=jo(n,a);if(e&&(c(e[0],t)&&c(e[1],i)||c(e[0],i)&&c(e[1],t)))return n}const h=(t[0]+i[0])/2,d=(t[1]+i[1])/2,u=Go(t,i),p=Math.max(.5*n,1e-9)*a;for(const t of Uo(e,a))if(Vo(t.ang,u)&&Math.hypot(t.x-h,t.y-d)<=p)return t.w;return null}function Yo(e,t,i,n,r=1){const o=Ko(e,t,i,n,r);if(o&&o.cm>0)return zo(o.cm);const s=function(e,t,i,n,r){if(!e?.length)return null;const o=r>0?r:1,s=Math.hypot(i[0]-t[0],i[1]-t[1]);if(s<1e-12)return null;const a=Go(t,i),l=Math.max(.5*n,1e-9)*o;let c=null;for(const n of e){if(!(n.cm>0))continue;const e=jo(n,o);if(!e)continue;const r=Math.hypot(e[1][0]-e[0][0],e[1][1]-e[0][1]);if(r<1e-12||!Vo(Go(e[0],e[1]),a))continue;if(Ns(t[0],t[1],e[0][0],e[0][1],e[1][0],e[1][1])>l||Ns(i[0],i[1],e[0][0],e[0][1],e[1][0],e[1][1])>l)continue;if(r+l(o.has(e.key)||(e=>{const t=jo(e,n);if(!t)return!1;const[i,o]=t,a=o[0]-i[0],c=o[1]-i[1],h=Math.hypot(a,c);if(h<=l)return!1;if(!s.some(e=>{const t=[e[0],e[1]],n=[e[2],e[3]];return Vo(Go(i,o),Go(t,n))&&Ns(i[0],i[1],t[0],t[1],n[0],n[1])<=l&&Ns(o[0],o[1],t[0],t[1],n[0],n[1])<=l}))return!1;const d=(r||[]).some(e=>{const t=[e[0],e[1]],n=[e[2],e[3]];if(!Vo(Go(i,o),Go(t,n)))return!1;const r=e=>Math.abs((e[0]-i[0])*c-(e[1]-i[1])*a)/h;if(r(t)>l||r(n)>l)return!1;const s=h*h,d=((t[0]-i[0])*a+(t[1]-i[1])*c)/s,u=((n[0]-i[0])*a+(n[1]-i[1])*c)/s;return Math.min(1,Math.max(d,u))-Math.max(0,Math.min(d,u))>l/h});return!d})(e))&&e.cm>=1&&e.cm<=100)}function Zo(e,t,i,n=8){const[r,o]=Lo(e,t);let s=Math.atan2(o,r);s<0&&(s+=Math.PI);let a=i*Math.PI/180%Math.PI;a<0&&(a+=Math.PI);let l=Math.abs(s-a);return l>Math.PI/2&&(l=Math.PI-l),l<=n*Math.PI/180}function Jo(e,t,i,n,r=1,o="affine",s){if(!e?.length)return[];if(t.length!==i.length)return"fixed-topology"===o&&s?.(),e.slice();const a=r>0?r:1,l=Math.max(.5*n,1e-9)*a,c=Math.max(n*a*1e-6,1e-9),h=[],d=new Map,u=new Map,p=(e,t,i)=>{const n=e.get(t)||new Set;n.add(i),e.set(t,n)};for(let e=0;e[e[0]+(t[0]-e[0])*i,e[1]+(t[1]-e[1])*i],m=(e,t)=>Math.hypot(e[0]-t[0],e[1]-t[1])<=c,g=(e,t)=>{if("fixed-topology"===o){const i=t.na[0]-t.oa[0],n=t.na[1]-t.oa[1],r=t.nb[0]-t.ob[0],o=t.nb[1]-t.ob[1];return Math.hypot(i-r,n-o)<=c?[e[0]+i,e[1]+n]:m(e,t.oa)?[...t.na]:m(e,t.ob)?[...t.nb]:[...e]}const i=Math.max(0,Math.min(1,((e[0]-t.oa[0])*t.dx+(e[1]-t.oa[1])*t.dy)/t.len2));return _(t.na,t.nb,i)},f=(e,t)=>{const[i,n]=Lo(e,t);return(t[0]-e[0])*i+(t[1]-e[1])*n>=0?[[...e],[...t]]:[[...t],[...e]]},v=[],y=[],b=(e,t,i)=>{if(Math.hypot(t[0]-e[0],t[1]-e[1])<=c)return;const[r,o]=f(e,t),s=zo(i);if(y.some(e=>e.entry.cm===s&&m(e.span[0],r)&&m(e.span[1],o)))return;const l=Wo(r,o,s,n,a);v.push(l),y.push({entry:l,span:[r,o]})};for(const t of e){const e=jo(t,a);if(e){const[i,n]=f(e[0],e[1]),r=n[0]-i[0],s=n[1]-i[1],a=r*r+s*s,d=Math.sqrt(a);if(d<=c){v.push({...t,cm:zo(t.cm)});continue}const u=[];for(const e of h){if(!Vo(Go(i,n),Go(e.oa,e.ob)))continue;const t=e=>Math.abs((e[0]-i[0])*s-(e[1]-i[1])*r)/d;if(t(e.oa)>l||t(e.ob)>l)continue;const o=((e.oa[0]-i[0])*r+(e.oa[1]-i[1])*s)/a,h=((e.ob[0]-i[0])*r+(e.ob[1]-i[1])*s)/a,p=Math.max(0,Math.min(o,h)),_=Math.min(1,Math.max(o,h));(_-p)*d>c&&u.push({lo:p,hi:_,move:e})}if(!u.length){"fixed-topology"===o?v.push({...t}):b(i,n,t.cm);continue}const p=[0,1,...u.flatMap(({lo:e,hi:t})=>[e,t])].sort((e,t)=>e-t).filter((e,t,i)=>0===t||Math.abs(e-i[t-1])*d>c),y=[];for(let e=0;e+1a>=e.lo-1e-12&&a<=e.hi+1e-12);if(!l.length){y.push([o,s]);continue}const h=[g(o,l[0].move),g(s,l[0].move)],f=l.slice(1).some(e=>{const t=g(o,e.move),i=g(s,e.move);return!m(h[0],t)||!m(h[1],i)});y.push(f?[o,s]:h)}const w=(e,t)=>{const i=e[1][0]-e[0][0],n=e[1][1]-e[0][1],r=t[1][0]-t[0][0],o=t[1][1]-t[0][1],s=Math.hypot(i,n);return!(s<=c||i*r+n*o<=0)&&Math.abs(i*o-n*r)/s<=c},k=[];for(const e of y){const t=k[k.length-1];t&&m(t[1],e[0])&&w(t,e)?t[1]=e[1]:k.push([[...e[0]],[...e[1]]])}if("fixed-topology"===o&&1===k.length){const[i,n]=k[0];if(m(i,e[0])&&m(n,e[1])||m(i,e[1])&&m(n,e[0])){v.push({...t});continue}}for(const[e,i]of k)b(e,i,t.cm);continue}if("fixed-topology"===o){const e=u.get(t.key);if(1===e?.size){const i=[...e][0];v.push(i===t.key?{...t}:{...t,key:i});continue}const i=[Uo([t],a)[0]];1!==a&&i.push(Uo([t],1)[0]);const n=i.filter(Boolean).some(e=>h.some(t=>{if(!Vo(e.ang,Go(t.oa,t.ob)))return!1;const i=((e.x-t.oa[0])*t.dx+(e.y-t.oa[1])*t.dy)/t.len2;return i>=-1e-6&&i<=1.000001&&Ns(e.x,e.y,t.oa[0],t.oa[1],t.ob[0],t.ob[1])<=l}));((e?.size||0)>1||n)&&s?.(),v.push({...t});continue}let i="";const r=d.get(t.key);if(1===r?.size&&(i=[...r][0]),!i){const e=Uo([t],a)[0];if(e){const t=new Set;for(const i of h){if(!Vo(e.ang,Go(i.oa,i.ob)))continue;const r=((e.x-i.oa[0])*i.dx+(e.y-i.oa[1])*i.dy)/i.len2;if(r<-1e-6||r>1.000001)continue;if(Ns(e.x,e.y,i.oa[0],i.oa[1],i.ob[0],i.ob[1])>l)continue;const o=g([e.x,e.y],i),[s,c]=Lo(i.na,i.nb),h=Math.max(n*a,1e-6);t.add(qo([o[0]-s*h,o[1]-c*h],[o[0]+s*h,o[1]+c*h],n,a))}1===t.size&&(i=[...t][0])}}v.push({...t,key:i||t.key,cm:zo(t.cm)})}return v}function Qo(e,t,i,n,r=1,o="affine"){return Jo(e,t,i,n,r,o)}function es(e,t,i,n,r=1,o="fixed-topology"){let s=!1;const a=Jo(e,t,i,n,r,o,()=>{s=!0});return{walls:s?(e||[]).map(e=>({...e})):a,rejected:s}}function ts(e,t,i,n=1,r=[]){const o=n>0?n:1,s=Math.abs(i),a=Math.max(s*o*ao,1e-9),l=(r||[]).flatMap(e=>{const t=jo(e,o);return t?t.map(e=>[...e]):[]}),c=e=>e.every((e,t)=>(e=>{if(!(s>0))return!0;const t=e/o/s;return Math.abs(t-Math.round(t))Math.abs(e-i[t])<=a)),h=[],d=e=>JSON.stringify([e.key,e.cm,e.a,e.b]);for(const i of e||[]){const e=jo(i,o);if(!e)continue;const[n,r]=e;if(![n[0],n[1],r[0],r[1]].every(Number.isFinite)||!c(n)||!c(r)){h.push(d(i));continue}const s=r[0]-n[0],l=r[1]-n[1],u=Math.hypot(s,l);if(u<=a){h.push(d(i));continue}const p=s/u,_=l/u,m=[];for(const e of t){const[t,i]=e;if(![t?.[0],t?.[1],i?.[0],i?.[1]].every(Number.isFinite))continue;const r=e=>Math.abs((e[0]-n[0])*_-(e[1]-n[1])*p);if(r(t)>a||r(i)>a)continue;const o=(t[0]-n[0])*p+(t[1]-n[1])*_,s=(i[0]-n[0])*p+(i[1]-n[1])*_,l=Math.max(0,Math.min(o,s)),c=Math.min(u,Math.max(o,s));c-l>a&&m.push([l,c])}m.sort((e,t)=>e[0]-t[0]||e[1]-t[1]);let g=0;for(const[e,t]of m){if(e>g+a)break;if(g=Math.max(g,t),g>=u-a)break}ge.key!==s);return null==n||n<1?a:[...a,Wo(t,i,n,r,o)]}function ns(e,t,i,n,r,o=[],s=1){let a=e?e.slice():[];for(const e of function(e,t,i,n,r=1,o=[]){const s=Ss(e,t,i,n,r,o);if(!s)return[];const a=[];for(let e=0;e0||(c=is(c,t,i,n,r,s)))}return c}function os(e){const{a:t,b:i,halfDepth:n}=e;if(!Array.isArray(t)||!Array.isArray(i)||t.length<2||i.length<2||![t[0],t[1],i[0],i[1]].every(Number.isFinite))return null;const r=i[0]-t[0],o=i[1]-t[1],s=Math.hypot(r,o);if(!(s>1e-9&&n>0&&Number.isFinite(n)))return null;const a=-o/s*n,l=r/s*n;return[[t[0]+a,t[1]+l],[i[0]+a,i[1]+l],[i[0]-a,i[1]-l],[t[0]-a,t[1]-l]]}function ss(e,t,i){return Math.hypot(e[0]-t[0],e[1]-t[1])<=i}function as(e,t,i){const n=t.b[0]-t.a[0],r=t.b[1]-t.a[1],o=n*n+r*r;if(!(o>i*i))return!1;const s=((e[0]-t.a[0])*n+(e[1]-t.a[1])*r)/o;if(!(s>0&&s<1))return!1;const a=[t.a[0]+n*s,t.a[1]+r*s];return Math.hypot(e[0]-a[0],e[1]-a[1])<=i}function ls(e,t,i,n){const r=Math.hypot(t,i);if(!(r>1e-9&&n>0))return;const o=[t/r,i/r],s=e.find(e=>Math.abs(e.u[0]*o[1]-e.u[1]*o[0])<1e-9&&e.u[0]*o[0]+e.u[1]*o[1]>1-1e-9);s?s.halfDepth=Math.max(s.halfDepth,n):e.push({u:o,halfDepth:n})}function cs(e,t){try{const i=Gt(Bs(e),Bs(t));let n=null,r=0;for(const e of i||[]){const t=e?.[0]||[],i=Math.abs(ms(t));t.length>=4&&i>r&&(r=i,n=t.slice(0,-1).map(e=>[e[0],e[1]]))}return n}catch{return null}}function hs(e,t=1e-6){const i=(e||[]).map((e,t)=>({segment:e,index:t})).filter(({segment:e})=>e&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&e.a.every(Number.isFinite)&&e.b.every(Number.isFinite)&&Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>1e-9);if(i.length<2)return[];const n=Math.max(Number.isFinite(t)?t:0,1e-9),r=i.flatMap(({segment:e})=>[e.a,e.b]).map(e=>[e[0],e[1]]).sort((e,t)=>e[0]-t[0]||e[1]-t[1]),o=[];for(const e of r)o.some(t=>ss(t,e,n))||o.push(e);const s=[];for(const e of o){const t=[];let r=!1;for(const{segment:o,index:s}of i){const i=Math.hypot(o.b[0]-o.a[0],o.b[1]-o.a[1]);ss(e,o.a,n)?t.push({u:[(o.b[0]-o.a[0])/i,(o.b[1]-o.a[1])/i],halfDepth:o.halfDepth,length:i,index:s}):ss(e,o.b,n)?t.push({u:[(o.a[0]-o.b[0])/i,(o.a[1]-o.b[1])/i],halfDepth:o.halfDepth,length:i,index:s}):as(e,o,n)&&(r=!0)}if(r||2!==t.length)continue;const[o,a]=t,l=o.u[0]*a.u[1]-o.u[1]*a.u[0];if(Math.abs(l)<1e-9)continue;const c=l<0?1:-1,h=[-o.u[1],o.u[0]],d=[-a.u[1],a.u[0]],u=[e[0]+h[0]*o.halfDepth*c,e[1]+h[1]*o.halfDepth*c],p=[e[0]-d[0]*a.halfDepth*c,e[1]-d[1]*a.halfDepth*c];if(!vs(u,o.u,p,a.u))continue;const _=[[o,a,p,[d[0]*-c,d[1]*-c]],[a,o,u,[h[0]*c,h[1]*c]]];for(const[t,,i,r]of _){const o=Math.min(2*t.halfDepth,t.length),a=[-t.u[1]*t.halfDepth,t.u[0]*t.halfDepth],l=[[e[0]+a[0],e[1]+a[1]],[e[0]+t.u[0]*o+a[0],e[1]+t.u[1]*o+a[1]],[e[0]+t.u[0]*o-a[0],e[1]+t.u[1]*o-a[1]],[e[0]-a[0],e[1]-a[1]]],c=e=>(e[0]-i[0])*r[0]+(e[1]-i[1])*r[1],h=[];for(let e=0;e=-1e-12&&h.push(t),n>1e-12&&r<-1e-12||n<-1e-12&&r>1e-12){const e=n/(n-r);h.push([t[0]+(i[0]-t[0])*e,t[1]+(i[1]-t[1])*e])}}h.length>=3&&Math.abs(ms(h))>n*n&&s.push({segmentIndex:t.index,wedge:h})}}return s}function ds(e,t=1e-6){const i=(e||[]).filter(e=>e&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&e.a.every(Number.isFinite)&&e.b.every(Number.isFinite)&&Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>1e-9);if(i.length<2)return[];const n=Math.max(Number.isFinite(t)?t:0,1e-9),r=i.flatMap(e=>[e.a,e.b]).map(e=>[e[0],e[1]]).sort((e,t)=>e[0]-t[0]||e[1]-t[1]),o=[];for(const e of r)o.some(t=>ss(t,e,n))||o.push(e);const s=[],a=i.map((e,t)=>({roomId:"",a:[e.a[0],e.a[1]],b:[e.b[0],e.b[1]],key:`join-${t}`,kind:"outer",cm:0,open:!1,half:e.halfDepth})),l=Ts(a,n);for(const e of Ds(l).fans)s.push(e);const c=e=>!!As(l,e);for(const e of o){if(c(e))continue;const t=[];for(const r of i)ss(e,r.a,n)?ls(t,r.b[0]-r.a[0],r.b[1]-r.a[1],r.halfDepth):ss(e,r.b,n)?ls(t,r.a[0]-r.b[0],r.a[1]-r.b[1],r.halfDepth):as(e,r,n)&&(ls(t,r.a[0]-e[0],r.a[1]-e[1],r.halfDepth),ls(t,r.b[0]-e[0],r.b[1]-e[1],r.halfDepth));if(!(t.length<2)){t.sort((e,t)=>Math.atan2(e.u[1],e.u[0])-Math.atan2(t.u[1],t.u[0])||e.halfDepth-t.halfDepth);for(let i=0;in*n&&s.push(m)}}}return s}function us(e,t,i,n){if(!(t>0)||!e||e.length<2)return"";if(i&&e.length>=3){let i=e;const r=e[e.length-1];if(e.length>=4&&Math.hypot(e[0][0]-r[0],e[0][1]-r[1])<1e-9&&(i=e.slice(0,-1)),i.length>=3){const e=i.map((e,i)=>n?.[i]||t),r=aa(i,e),o=ws(i,e);if(r&&o)return`${ks(r)} ${ks(xs(o))}`}}const r=[];for(let i=0;i=1e-9&&a>0&&r.push({a:o,b:s,halfDepth:a})}const o=r.map(os);for(const{segmentIndex:e,wedge:t}of hs(r)){const i=o[e];if(!i)continue;const n=cs(i,t);n&&(o[e]=n)}const s=[...o.filter(e=>!!e),...ds(r)],a=function(e){let t=null;try{for(const i of e){if(i.length<3)continue;const e=Bs(i);t=t?Wt(t,e):[e]}return t}catch{return null}}(s);return a?Qs(a):s.map(e=>ks(e)).join(" ")}function ps(e,t,i,n,r=1){if(!i.length)return!1;const o=_s(n,r),s=(e[0]+t[0])/2,a=(e[1]+t[1])/2,[l,c]=Lo(e,t);for(const e of i){const[t,i]=Lo([e[0],e[1]],[e[2],e[3]]);if(!(Math.abs(l*i-c*t)>.05)&&Ns(s,a,e[0],e[1],e[2],e[3])<=o)return!0}return!1}function _s(e,t){return Math.max(e*(t>0?t:1)*.04,1e-9)}function ms(e){let t=0;for(let i=0;ie[1]!=l>e[1]&&e[0]<(a-o)*(e[1]-s)/(l-s+0)+o&&(i=!i)}return i}([c[0]+.001*a,c[1]+.001*l],e)||(a=-a,l=-l),[a,l]}function fs(e,t){const i=e[0]*t[1]-e[1]*t[0],n=e[0]*t[0]+e[1]*t[1];return Math.abs(i)<1e-9&&n>0}function vs(e,t,i,n){const r=t[0]*n[1]-t[1]*n[0];if(Math.abs(r)<1e-12)return null;const o=[i[0]-e[0],i[1]-e[1]],s=(o[0]*n[1]-o[1]*n[0])/r;return[e[0]+s*t[0],e[1]+s*t[1]]}function ys(e,t,i){const n=e?.length||0;if(n<3||!Array.isArray(i)||i.length!==n)return 0;const r=(Math.trunc(t)%n+n)%n,o=e[r],s=e[(r+1)%n],a=s[0]-o[0],l=s[1]-o[1],c=Math.hypot(a,l);if(!(c>0))return 0;const h=Math.max(0,Number(i[r])||0);if(!(h>0))return c;const d=[a/c,l/c],u=gs(e,r),p=[o[0]+u[0]*h,o[1]+u[1]*h],_=t=>{const r=Math.max(0,Number(i[t])||0);if(!(r>0))return null;const s=e[t],a=e[(t+1)%n],l=a[0]-s[0],c=a[1]-s[1],h=Math.hypot(l,c);if(!(h>0))return null;const u=gs(e,t),_=vs(p,d,[s[0]+u[0]*r,s[1]+u[1]*r],[l/h,c/h]);return _?(_[0]-o[0])*d[0]+(_[1]-o[1])*d[1]:null},m=_((r-1+n)%n)??0,g=(_((r+1)%n)??c)-m;return g>0?g:0}function bs(e,t,i,n,r,o,s,a=1){const l=(e||[]).find(e=>e?.id===t),c=ni(l);if(!c||c.length<3)return null;const h=Fs(e,t,i,n,r,o,s,a);if(!h)return c.map(()=>0);const d=4*_s(r,a);return c.map((e,t)=>{const i=c[(t+1)%c.length],n=[(e[0]+i[0])/2,(e[1]+i[1])/2];for(let e=0;e!(e>0)))return e.map(e=>[e[0],e[1]]);const r=[];for(let o=0;o0||u>0)){r.push([e[o][0],e[o][1]]);continue}if(d>0!=u>0){const t=e[o],i=d>0?[t[0]+p*d,t[1]+_*d]:[t[0],t[1]],n=u>0?[t[0]+m*u,t[1]+g*u]:[t[0],t[1]];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}if(fs(w,k)){const t=e[o],i=[t[0]+p*d,t[1]+_*d],n=[t[0]+m*u,t[1]+g*u];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}const $=vs(x,w,S,k),M=Math.max(d,u,1e-9),R=As(i,e[o])?.limit??4*M;if($){const i=Math.hypot($[0]-e[o][0],$[1]-e[o][1]);if(Number.isFinite(i)&&i<=R){r.push($);continue}if(ta(e,t,o)){r.push($);continue}}d>0&&r.push([e[o][0]+p*d,e[o][1]+_*d]),u>0&&r.push([e[o][0]+m*u,e[o][1]+g*u]),d>0||u>0||r.push([e[o][0],e[o][1]])}return r.length>=3?r:null}function ks(e,t=!0){if(!e.length)return"";let i=`M ${e[0][0]} ${e[0][1]}`;for(let t=1;te?.id===t),a=ni(s);if(!a||a.length<3)return null;const l=_s(n,r),c=[];for(const i of e||[]){if(!i||i.id===t)continue;const e=ni(i);if(e)for(const t of Fn(a,e,l))c.push([t[0],t[1]],[t[2],t[3]])}for(const e of i||[])c.push([e[0],e[1]],[e[2],e[3]]);for(const e of o||[]){const t=jo(e,r);t&&c.push(t[0],t[1])}const h=[],d=[];for(let e=0;el)continue;const s=((e[0]-t[0])*(i[0]-t[0])+(e[1]-t[1])*(i[1]-t[1]))/(n*n);s<=r||s>=1-r||(o.some(e=>Math.abs(e-s)*n<=2*l)||o.push(s))}o.sort((e,t)=>e-t);for(const n of o)h.push([t[0]+(i[0]-t[0])*n,t[1]+(i[1]-t[1])*n]),d.push(e)}return{poly:h,parent:d,orig:a}}function $s(e,t,i,n){const r=t.poly.length,o=new Array(r).fill(0);if(!e?.length)return o;const s=new Set,a=[];for(let l=0;l0?(o[l]=zo(c.cm),s.add(c.key)):a.push(l)}if(!a.length)return o;const l=n>0?n:1,c=Math.max(.5*i,1e-9)*l,h=Uo(e,l).filter(e=>e.w.cm>0);for(let e=a.length-1;e>=0;e--){const i=a[e],n=t.poly[i],s=t.poly[(i+1)%r],d=Go(n,s);let u=null;for(const e of h){const t=jo(e.w,l);if(!t||!Vo(Go(t[0],t[1]),d))continue;if(Ns(n[0],n[1],t[0][0],t[0][1],t[1][0],t[1][1])>c||Ns(s[0],s[1],t[0][0],t[0][1],t[1][0],t[1][1])>c)continue;const i=Math.hypot(s[0]-n[0],s[1]-n[1]),r=Math.hypot(t[1][0]-t[0][0],t[1][1]-t[0][1]),o=Math.max(0,r-i);(!u||oc||Ns(r[0],r[1],t[0][0],t[0][1],t[1][0],t[1][1])>c)continue;i=!0,o=Math.max(0,Math.hypot(t[1][0]-t[0][0],t[1][1]-t[0][1])-_)}else{if(Ns(e.x,e.y,n[0],n[1],r[0],r[1])>c)continue;o=Math.hypot(e.x-d,e.y-u)}(!p||i&&!p.exact||i===p.exact&&o0?i:1,o=(e||[]).filter(e=>e&&!e.open&&null!==e.kind&&Number.isFinite(e.half)&&e.half>0&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&[e.a[0],e.a[1],e.b[0],e.b[1]].every(Number.isFinite)&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>n).sort((e,t)=>e.key.localeCompare(t.key)||e.a[0]-t.a[0]||e.a[1]-t.a[1]||e.b[0]-t.b[0]||e.b[1]-t.b[1]||e.half-t.half),s=new Map;for(const e of o){const t=s.get(e.key);t?e.half>t.half&&s.set(e.key,{...t,half:e.half}):s.set(e.key,e)}const a=[...s.values()].flatMap(e=>[{point:[e.a[0],e.a[1]],other:e.b,halfDepth:e.half,kind:e.kind,key:e.key},{point:[e.b[0],e.b[1]],other:e.a,halfDepth:e.half,kind:e.kind,key:e.key}]).sort((e,t)=>e.point[0]-t.point[0]||e.point[1]-t.point[1]||e.other[0]-t.other[0]||e.other[1]-t.other[1]||e.halfDepth-t.halfDepth),l=new Map;for(const e of a){const[t,i]=Ms(e.point,n),r=Rs(t,i),o=l.get(r)||[];o.push(e),l.set(r,o)}const c=[],h=new Map;for(const e of a){const t=Cs(h,e.point,n).filter(t=>Math.hypot(t.point[0]-e.point[0],t.point[1]-e.point[1])<=n).sort((t,i)=>Math.hypot(t.point[0]-e.point[0],t.point[1]-e.point[1])-Math.hypot(i.point[0]-e.point[0],i.point[1]-e.point[1])||t.point[0]-i.point[0]||t.point[1]-i.point[1]);let i=t[0];if(!i){i={point:[...e.point],rays:[]},c.push(i);const[t,r]=Ms(i.point,n),o=Rs(t,r),s=h.get(o)||[];s.push(i),h.set(o,s)}const r=e.other[0]-e.point[0],o=e.other[1]-e.point[1],s=Math.hypot(r,o);if(!(s>n))continue;const a=[r/s,o/s];let l=Math.atan2(a[1],a[0]);l<0&&(l+=2*Math.PI),i.rays.push({u:a,halfDepth:e.halfDepth,length:s,angle:l})}const d=[],u=e=>{const t=1e-9*Math.max(1,r),i=e.filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Number.isFinite(e.length)&&e.length>n);return i.filter((e,n)=>!i.some((i,r)=>r!==n&&i.halfDepth>=e.halfDepth-t&&i.length>=e.length-t&&(i.halfDepth>e.halfDepth+t||i.length>e.length+t||re.length-t.length||e.halfDepth-t.halfDepth).map(e=>({...e}))};for(const e of c){const t=e.rays.sort((e,t)=>e.angle-t.angle||e.length-t.length||e.halfDepth-t.halfDepth),i=[];for(const e of t){const t=i[i.length-1];t&&Math.abs(e.angle-t.angle)<=1e-9?t.supports.push({halfDepth:e.halfDepth,length:e.length}):i.push({u:[...e.u],angle:e.angle,supports:[{halfDepth:e.halfDepth,length:e.length}]})}if(i.length>1&&2*Math.PI-i[i.length-1].angle+i[0].angle<=1e-9){const e=i.pop();i[0].supports.push(...e.supports)}if(i.length<3)continue;const r=i.map(t=>{const i=u(t.supports),r=new Set,o=[];for(const s of i){const i=[e.point[0]+t.u[0]*s.length,e.point[1]+t.u[1]*s.length];for(const t of Cs(l,i,n)){if("shared"!==t.kind||Math.hypot(t.point[0]-i[0],t.point[1]-i[1])>n)continue;const s=t.other[0]-t.point[0],a=t.other[1]-t.point[1],l=Math.hypot(s,a);if(!(l>n))continue;const c=s/l,h=a/l;if(Math.hypot(t.other[0]-e.point[0],t.other[1]-e.point[1])<=n)continue;const d=`${t.key}|${t.point[0]}|${t.point[1]}|${t.other[0]}|${t.other[1]}|${t.halfDepth}`;r.has(d)||(r.add(d),o.push({start:[t.point[0],t.point[1]],u:[c,h],length:l,halfDepth:t.halfDepth}))}}return o.sort((e,t)=>e.start[0]-t.start[0]||e.start[1]-t.start[1]||e.u[0]-t.u[0]||e.u[1]-t.u[1]||e.length-t.length||e.halfDepth-t.halfDepth),{u:[...t.u],halfDepth:Math.max(...i.map(e=>e.halfDepth)),length:Math.max(...i.map(e=>e.length)),supports:i,continuations:o}}).filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Number.isFinite(e.length)&&e.length>n);if(r.length<3)continue;const o=Math.max(...r.map(e=>e.halfDepth));o>0&&Number.isFinite(o)&&d.push({point:[...e.point],rays:r,halfDepth:o,limit:1.25*o})}d.sort((e,t)=>e.point[0]-t.point[0]||e.point[1]-t.point[1]);const p=new Map;for(const e of d){const[t,i]=Ms(e.point,n),r=Rs(t,i),o=p.get(r)||[];o.push(e),p.set(r,o)}return{epsilon:n,coordinateScale:r,nodes:d,index:p}}function Ds(e){const t={fans:[],supports:[]};if(!e?.nodes?.length)return t;const i=Math.max(e.epsilon,1e-9)**2;for(const n of e.nodes){const e=n.rays.filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0).map(e=>({...e,thickLength:Math.max(...e.supports.filter(t=>t.halfDepth>=e.halfDepth-1e-12).map(e=>e.length),0),angle:(()=>{const t=Math.atan2(e.u[1],e.u[0]);return t<0?t+2*Math.PI:t})()})).sort((e,t)=>e.angle-t.angle);if(e.length<2)continue;const r=n.point;for(const i of e)for(const e of i.supports){if(!(e.halfDepth>0&&e.length>0))continue;const n=-i.u[1]*e.halfDepth,o=i.u[0]*e.halfDepth,s=[r[0]+i.u[0]*e.length,r[1]+i.u[1]*e.length];t.supports.push([[r[0]+n,r[1]+o],[s[0]+n,s[1]+o],[s[0]-n,s[1]-o],[r[0]-n,r[1]-o]])}for(let n=0;n{const e=s.angle-o.angle;return e>0?e:e+2*Math.PI})();if(a<1e-9)continue;const l=a>Math.PI+1e-9,c=4*Math.max(o.halfDepth,s.halfDepth),h=[r[0]-o.u[1]*o.halfDepth,r[1]+o.u[0]*o.halfDepth],d=[r[0]+s.u[1]*s.halfDepth,r[1]-s.u[0]*s.halfDepth],u=o.u[0]*s.u[1]-o.u[1]*s.u[0],p=e=>{let t=Math.atan2(e[1]-r[1],e[0]-r[0])-o.angle;for(;t<0;)t+=2*Math.PI;return t<=a+1e-9};let _=null;if(Math.abs(u)>1e-9){const e=((d[0]-h[0])*s.u[1]-(d[1]-h[1])*s.u[0])/u,t=((d[0]-h[0])*o.u[1]-(d[1]-h[1])*o.u[0])/u,i=[h[0]+o.u[0]*e,h[1]+o.u[1]*e];(l?e<=1e-9&&t<=1e-9:e>1e-9&&e<=o.thickLength&&t<=s.thickLength)&&Math.hypot(i[0]-r[0],i[1]-r[1])<=c&&p(i)&&(_=i)}const m=e=>{Math.abs(ms(e))>i&&t.fans.push(e)};if(_){const e=1.5*Math.max(o.halfDepth,s.halfDepth);m(To([r[0],r[1]],h,_,d,e)??[[r[0],r[1]],h,_,d]);continue}if(l){m([[r[0],r[1]],h,d]);continue}const g=(e,t)=>Math.min(t,Math.sqrt(Math.max(c**2-e**2,0)),2*Math.max(o.halfDepth,s.halfDepth)),f=[h[0]+o.u[0]*g(o.halfDepth,o.thickLength),h[1]+o.u[1]*g(o.halfDepth,o.thickLength)],v=[d[0]+s.u[0]*g(s.halfDepth,s.thickLength),d[1]+s.u[1]*g(s.halfDepth,s.thickLength)];m([[r[0],r[1]],h,f,v,d])}}return t}function As(e,t){return!e||!Array.isArray(t)||t.length<2||!t.slice(0,2).every(Number.isFinite)?null:Cs(e.index,t,e.epsilon).filter(i=>Math.hypot(i.point[0]-t[0],i.point[1]-t[1])<=e.epsilon).sort((e,i)=>Math.hypot(e.point[0]-t[0],e.point[1]-t[1])-Math.hypot(i.point[0]-t[0],i.point[1]-t[1])||e.point[0]-i.point[0]||e.point[1]-i.point[1])[0]||null}function Ps(e,t,i,n,r,o,s){return Ts(zs(e,t,i,n,r,o,s),4*_s(n,s),s)}function Fs(e,t,i,n,r,o,s,a=1){const l=Ss(e,t,n,r,a,i);if(!l)return null;const c=function(e,t,i){const n=(e||[]).find(e=>e?.id===t),r=ni(n);if(!r)return[];const o=[];for(const n of e||[]){if(!n||n.id===t)continue;const e=ni(n);if(e)for(const t of Fn(r,e,i))o.push(t)}return o}(e,t,_s(r,a)),h=function(e,t,i,n,r){const o=_s(n,r),s=[];for(let a=0;aNs(h,d,e[0],e[1],e[2],e[3])<=o);s.push(u?"shared":"outer")}return s}(l.poly,c,n,r,a),d=$s(i,l,r,a),u=d.map((e,t)=>h[t]&&e>0?Oo(e,o,s)/2:0);return{...l,kinds:h,cms:d,offsets:u}}function zs(e,t,i,n,r,o,s=1){const a=[];for(const l of e||[]){if(!l?.id)continue;const c=Fs(e,l.id,t,i,n,r,o,s);if(c)for(let e=0;e0&&(a=is(a,e.a,e.b,e.cm,n,s));return a}function Os(e,t,i,n,r,o,s=1){if(!t?.length)return[];const a=zs(e,t,i,n,r,o,s),l=new Map;for(const e of a){if(e.open||!e.kind||!e.roomId)continue;const t=l.get(e.key)||new Set;t.add(e.roomId),l.set(e.key,t)}const c=e=>{const t=[...l.get(e)||[]].sort();return 1!==t.length&&2!==t.length?`ambiguous:${e}`:`${1===t.length?"outer":"shared"}:${t.join("|")}`},h=[],d=new Set;for(const e of a)!e.open&&e.cm>0&&!d.has(e.key)&&(d.add(e.key),h.push({...e,ownerSignature:c(e.key)}));const u=[];for(const a of e||[]){if(!a?.id)continue;const l=Fs(e,a.id,t,i,n,r,o,s);if(l)for(let e=0;e0)||null===l.kinds[i]){e++;continue}const o=c(qo(l.poly[i],l.poly[(i+1)%l.poly.length],n,s));let a=e;for(;a+10&&u.push({a:[d[0],d[1]],b:[p[0],p[1]],key:qo(d,p,n,s),cm:r,len:_,ownerSignature:o}),e=a+1}}}u.sort((e,t)=>t.len-e.len||e.key.localeCompare(t.key));const p=[],_=new Set,m=new Set,g=4*_s(n,s);for(const e of u){const t=h.filter(t=>!m.has(t.key)&&t.cm===e.cm&&t.ownerSignature===e.ownerSignature&&Vo(Go(t.a,t.b),Go(e.a,e.b))&&Ns(t.a[0],t.a[1],e.a[0],e.a[1],e.b[0],e.b[1])<=g&&Ns(t.b[0],t.b[1],e.a[0],e.a[1],e.b[0],e.b[1])<=g);if(t.length){for(const e of t)m.add(e.key);_.has(e.key)||(_.add(e.key),p.push(Wo(e.a,e.b,e.cm,n,s)))}}for(const e of h)m.has(e.key)||_.has(e.key)||(_.add(e.key),p.push(Wo(e.a,e.b,e.cm,n,s)));return p}function Es(e,t,i,n,r,o,s,a=1){const l=_s(r,a),c=(n[0]+n[2])/2,h=(n[1]+n[3])/2,d=Go([n[0],n[1]],[n[2],n[3]]);let u=null;for(const n of zs(e,t,i,r,o,s,a)){if(!Vo(Go(n.a,n.b),d))continue;const e=Ns(c,h,n.a[0],n.a[1],n.b[0],n.b[1]);e>4*l||(!u||e[e[0],e[1]]),o=Math.abs(ms(r));r.length>=3&&o>i&&(t=r,i=o)}return t}function Ls(e,t,i,n,r,o,s,a=1,l,c){const h=(e||[]).find(e=>e?.id===t),d=ni(h);if(!d||d.length<3)return null;if(!i?.length)return d.map(e=>[e[0],e[1]]);const u=Fs(e,t,i,n,r,o,s,a);if(!u||!u.offsets.some(e=>e>0))return d.map(e=>[e[0],e[1]]);const p=c||Ps(e,i,n,r,o,s,a),_=ws(u.poly,u.offsets,p);if(!_)return d.map(e=>[e[0],e[1]]);if(!p.nodes.length)return _;const m=void 0===l?ia(e,i,n,[],r,o,s,a):null,g=l??("ok"===m?.status||"degraded-extra"===m?.status?m.roomGeom:void 0);if(g)try{const e=Hs(Gt(Bs(u.poly),g));if(e)return e}catch{}return function(e,t){try{return Hs(Ut(Bs(e),Bs(t)))}catch{return null}}(_,u.poly)||d.map(e=>[e[0],e[1]])}function Bs(e){const t=e.map(e=>[e[0],e[1]]);return t.push([e[0][0],e[0][1]]),[t]}function qs(e){return!(!Array.isArray(e)||!e.length)&&e.every(e=>Array.isArray(e)&&e.length&&e.every(e=>Array.isArray(e)&&e.length>=4&&e.every(e=>Array.isArray(e)&&e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1])))&&Math.abs(Ci(e[0]))>1e-9)}function js(e,t,i,n){const r=n?new Set(n):null;let o=null;for(let n=0;nt.epsilon))continue;const l=Ks([[e.point[0]+a[0]*n.halfDepth,e.point[1]+a[1]*n.halfDepth],[e.point[0]+s.u[0]*r+a[0]*n.halfDepth,e.point[1]+s.u[1]*r+a[1]*n.halfDepth],[e.point[0]+s.u[0]*r-a[0]*n.halfDepth,e.point[1]+s.u[1]*r-a[1]*n.halfDepth],[e.point[0]-a[0]*n.halfDepth,e.point[1]-a[1]*n.halfDepth]],t.coordinateScale);if(!l)continue;const c=Bs(l);o=o?Wt(o,c):c}}return o}function Ws(e,t,i){let n=null;for(const r of e.rays)for(const e of r.continuations){const r=[-e.u[1],e.u[0]],o=[e.start[0]+e.u[0]*e.length,e.start[1]+e.u[1]*e.length],s=Ks([[e.start[0]+r[0]*e.halfDepth,e.start[1]+r[1]*e.halfDepth],[o[0]+r[0]*e.halfDepth,o[1]+r[1]*e.halfDepth],[o[0]-r[0]*e.halfDepth,o[1]-r[1]*e.halfDepth],[e.start[0]-r[0]*e.halfDepth,e.start[1]-r[1]*e.halfDepth]],t.coordinateScale);if(!s)continue;const a=Ut(Bs(s),i);Array.isArray(a)&&0!==a.length&&(n=n?Wt(n,a):a)}return n}function Us(e,t,i=2*(4*e.halfDepth+2*t.epsilon)){const n=function(e,t=Do){const i=new Set,n=Number.isFinite(t)&&t>=0?t:Do;for(let t=0;te-t)}(e);return n.length?js(e,t,i,n):null}function Gs(e,t,i,n,r){const o=function(e){let t=null;for(const i of e){const e=Bs(i);try{t=t?Wt(t,e):e}catch{}}return t}(function(e,t,i=!1){if(!e)return[];const n=[];for(const r of e.nodes)for(let o=0;o1e-9)||h>=Math.PI-1e-9)continue;const d=[-s.u[1],s.u[0]],u=[-a.u[1],a.u[0]],p=[r.point[0]+d[0]*s.halfDepth,r.point[1]+d[1]*s.halfDepth],_=[r.point[0]-u[0]*a.halfDepth,r.point[1]-u[1]*a.halfDepth],m=vs(p,s.u,_,a.u);if(!m)continue;const g=Math.hypot(m[0]-r.point[0],m[1]-r.point[1]);if(!Number.isFinite(g)||g<=r.limit)continue;const f=t?Math.sqrt(Math.max(0,r.limit*r.limit-s.halfDepth*s.halfDepth)):0,v=t?Math.sqrt(Math.max(0,r.limit*r.limit-a.halfDepth*a.halfDepth)):0,y=Ks([[p[0]+s.u[0]*f,p[1]+s.u[1]*f],[_[0]+a.u[0]*v,_[1]+a.u[1]*v],m],e.coordinateScale);if(y&&n.push(y),i){const t=m[0]-r.point[0],i=m[1]-r.point[1],o=Math.hypot(t,i),s=g-r.limit;if(o>e.epsilon&&s>e.epsilon){const a=Math.min(Math.max(8*e.epsilon,.05*r.halfDepth),.25*s),l=t/o,c=i/o,h=-c,d=l,u=Ks([[m[0]-l*a+h*a,m[1]-c*a+d*a],[m[0]-l*a-h*a,m[1]-c*a-d*a],[m[0]+l*a,m[1]+c*a]],e.coordinateScale);u&&n.push(u)}}}return n}({...t,nodes:[e]},i,n));return o&&r?Gt(o,r):o}function Vs(e,t,i,n){if(!e||!t.nodes.length)return e;let r=null;try{r=function(e){let t=null;for(const i of e.nodes){const n=Us(i,e);n&&(t=t?Wt(t,n):n)}return t}(t)}catch{return e}let o=e;for(const e of t.nodes){const s=4*e.halfDepth+2*t.epsilon,a=2*s,l=[[e.point[0]-s,e.point[1]-s],[e.point[0]+s,e.point[1]-s],[e.point[0]+s,e.point[1]+s],[e.point[0]-s,e.point[1]+s]];try{let s=o;const c=Gs(e,t,!1,!0,r);c&&(s=Gt(s,c));let h=js(e,t,a);const d=Gs(e,t,!0,!0,r);d&&(h=Gt(h,d)),r&&(h=Wt(h,r));const u=.02*Math.min(...e.rays.map(e=>e.halfDepth));if(h=Wt(h,Bs([[e.point[0]-u,e.point[1]-u],[e.point[0]+u,e.point[1]-u],[e.point[0]+u,e.point[1]+u],[e.point[0]-u,e.point[1]+u]])),!h)continue;let p=Ut(h,Bs(l));n?p=Ut(p,n):i&&(p=Ut(p,i));const _=Bs(l),m=Gt(s,_),g=i?Gt(Ut(s,_),i):null,f=Ws(e,t,_);o=Wt(m,...g?[g]:[],...f?[f]:[],p)}catch{}}if(r)try{let e=r;n?e=Ut(e,n):i&&(e=Ut(e,i)),o=Wt(o,e)}catch{}return o}function Ks(e,t=1){if(!Array.isArray(e)||e.length<3)return null;const i=Number.isFinite(t)&&t>0?t:1,n=1e-12*Math.max(1,i),r=[];for(const t of e){if(!Array.isArray(t)||t.length<2)return null;const e=Number(t[0]),i=Number(t[1]);if(!Number.isFinite(e)||!Number.isFinite(i))return null;const o=Math.round(e/n)*n,s=Math.round(i/n)*n;if(!Number.isFinite(o)||!Number.isFinite(s))return null;r.push([Object.is(o,-0)?0:o,Object.is(s,-0)?0:s])}return Math.abs(ms(r))>n*n?r:null}function Ys(e,t,i,n){if(Ns(e[0],e[1],t[0],t[1],i[0],i[1])>n)return!1;const r=i[0]-t[0],o=i[1]-t[1],s=(e[0]-t[0])*r+(e[1]-t[1])*o,a=r*r+o*o,l=n*Math.sqrt(a);return s>=-l&&s<=a+l}function Xs(e,t,i){const n=[],r=[];for(let o=0;oi*i))continue;const d=i/Math.sqrt(h),u=[0,1];for(const e of t)for(const t of[e.a,e.b]){if(!Ys(t,s,a,i))continue;const e=((t[0]-s[0])*l+(t[1]-s[1])*c)/h;e>d&&e<1-d&&u.push(e)}u.sort((e,t)=>e-t);const p=u.filter((e,t)=>0===t||Math.abs(e-u[t-1])>d);for(let e=0;e=3&&r.length===n.length?{poly:n,offsets:r}:null}function Zs(e,t,i,n,r,o,s,a){const l=(e||[]).map(ni).filter(e=>!!e&&e.length>=3);if(!l.length)return null;let c=Wt(Bs(l[0]));for(let e=1;e"outer"===e.kind&&e.half>0),u=4*_s(n,s),p=a||Ts(h,u,s);let _=null;for(const e of function(e){const t=[];for(const i of Array.isArray(e)?e:[])if(Array.isArray(i))for(const e of i){if(!Array.isArray(e)||e.length<4)continue;const i=e.slice(0,-1).map(e=>[e[0],e[1]]);i.length>=3&&t.push(i)}return t}(c)){const t=Xs(e,d,u);if(!t||!t.offsets.some(e=>e>0))continue;const i=aa(t.poly,t.offsets,p),n=ws(t.poly,t.offsets,p);if(!i||!n)continue;const r=Gt(Bs(i),Bs(n));_=_?Wt(_,r):r}return{centre:c,shell:_||[]}}function Js(e,t,i,n,r,o,s=1){try{const a=Zs(e,t,i,n,r,o,s,Ps(e,t,i,n,r,o,s));if(!a)return[];return a.shell?.length?Wt(a.centre,a.shell):a.centre}catch{return null}}function Qs(e){if(!e)return"";let t="";for(const i of e)if(Array.isArray(i))for(const e of i){if(!Array.isArray(e)||e.length<4)continue;const i=e.slice(0,e.length-1);i.length<3||(t+=(t?" ":"")+ks(i.map(e=>[e[0],e[1]])))}return t}const ea=15;function ta(e,t,i){const n=e?.length||0;if(n<3||t?.length!==n)return!1;const r=e[(i-1+n)%n],o=e[i],s=e[(i+1)%n],a=[r[0]-o[0],r[1]-o[1]],l=[s[0]-o[0],s[1]-o[1]],c=Math.hypot(a[0],a[1]),h=Math.hypot(l[0],l[1]);if(!(c>1e-9&&h>1e-9))return!1;const d=Math.max(-1,Math.min(1,(a[0]*l[0]+a[1]*l[1])/(c*h))),u=Math.acos(d);if(!(u>1e-9))return!1;if(u>=ea*Math.PI/180)return!1;const p=Math.max(0,t[(i-1+n)%n]),_=Math.max(0,t[i]);if(!(p>0||_>0))return!1;const m=Math.sin(u);if(!(m>1e-12))return!1;const g=(_+p*d)/m,f=(p+_*d)/m;return Number.isFinite(g)&&Number.isFinite(f)&&g>0&&f>0&&ge>0))continue;for(const e of l.offsets)e>0&&(u=Math.max(u,2*e));const c=aa(l.poly,l.offsets,d),p=ws(l.poly,l.offsets,d);c&&h.push({outset:c,inset:p})}for(const e of l){const t=e.map(e=>e[0]),i=e.map(e=>e[1]);if(t.length){const n=Math.min(Math.max(...t)-Math.min(...t),Math.max(...i)-Math.min(...i)),r=Math.min(...e.map((t,i)=>{const n=e[(i+1)%e.length];return Math.hypot(n[0]-t[0],n[1]-t[1])}));u=Math.max(u,e.length>16?n:r)}}const p=function(e,t,i,n,r,o,s,a){if(!t?.length||!i?.length)return[];const l=4*_s(n,s),c=new Map;for(const a of zs(e,t,i,n,r,o,s))!a.open&&a.half>0&&!c.has(a.key)&&c.set(a.key,a);const h=[...c.values()];if(h.length<2)return[];const d=a||Ts(h,l),u=[];for(const e of i)for(const t of[[e[0],e[1]],[e[2],e[3]]])u.some(e=>Math.hypot(e[0]-t[0],e[1]-t[1])<=l)||u.push(t);const p=[],_=(e,t)=>{let i=0,n=0;if(Math.hypot(e.a[0]-t[0],e.a[1]-t[1])<=l)i=e.b[0]-e.a[0],n=e.b[1]-e.a[1];else{if(!(Math.hypot(e.b[0]-t[0],e.b[1]-t[1])<=l))return null;i=e.a[0]-e.b[0],n=e.a[1]-e.b[1]}const r=Math.hypot(i,n);return r>l?[i/r,n/r]:null};for(const e of u){const t=h.map(t=>({iv:t,u:_(t,e)})).filter(e=>!!e.u);for(let i=0;i0?[e.slice(),u,m,_]:[e.slice(),_,m,u];else{if(!f)continue;{const t=[-r.u[1],r.u[0]],i=[-o.u[1],o.u[0]],n=s<0?1:-1,a=[e[0]+t[0]*r.iv.half*n,e[1]+t[1]*r.iv.half*n],l=[e[0]-i[0]*o.iv.half*n,e[1]-i[1]*o.iv.half*n];y=s>0?[e.slice(),a,l]:[e.slice(),l,a]}}Math.abs(ms(y))>l*l&&p.push(y)}}return p}(e,t,i,r,o,s,a,d),_=n.length?la(e,t,i,r,o,s,a):null;let m="exterior";try{const v=Zs(e,t,i,r,o,s,a,d);m="paper";const y=v?v.shell?.length?Wt(v.centre,v.shell):v.centre:[],b=e=>{const t=Bs(e.outset);if(!e.inset)return t;const i=Bs(e.inset);return Gt(t,i)};m="room-rings";let w=null;for(const e of h)try{const t=b(e);w=w?Wt(w,t):t}catch{}if(m="edge-bodies",v)for(const n of oa(e,t,i,r,o,s,a))try{const e=Ut(Bs(n.quad),v.centre);w=w?Wt(w,e):e}catch{}m="junctions",w=function(e,t,i=1,n=Wt){let r=e;for(const e of t||[]){const t=Ks(e,i);if(t)try{const e=Bs(t);r=r?n(r,e):e}catch{}}return r}(w,p,a),m="facade-clip",w&&v&&(w=Ut(w,v.centre)),m="exterior-shell";const k=[];let x=0;if(v?.shell?.length)if(w)try{const e=Wt(w,v.shell);if(!qs(e))throw new Error("invalid shell union");w=e}catch{if(!qs(w)||!qs(v.shell))throw new Error("invalid shell");k.push({id:"exterior-shell",geom:v.shell}),x++}else w=v.shell;if(m="multi-wall-trim",w&&d.nodes.length){const e=e=>e.rays.some(e=>e.supports.some(e=>e.length<2*e.halfDepth)),t=d.nodes.filter(e);if(t.length){w=Vs(w,{...d,nodes:t},v?.centre,y)}}if(m="junction-corners",d.nodes.length){const n=Ds(d),l=function(e,t,i,n,r,o,s,a){try{const l=Zs(e,t,i,n,r,o,s,{epsilon:a.epsilon,coordinateScale:a.coordinateScale,nodes:[],index:new Map});return l?l.shell?.length?Wt(l.centre,l.shell):l.centre:null}catch{return null}}(e,t,i,r,o,s,a,d);for(const e of n.fans)try{let t=[Bs(e)];if(l&&(t=Ut(t,l)),!t?.length)continue;w=w?Wt(w,t):t}catch{}g=w,f=Math.max(d.epsilon,1e-9)**2,w=Array.isArray(g)?g.map(e=>{if(!Array.isArray(e)||!e.length)return e;const[t,...i]=e;return Math.abs(ms(t||[]))<=f?null:[t,...i.filter(e=>Math.abs(ms(e||[]))>f)]}).filter(e=>!!e):g}const S=w||[],$=[...qs(S)?[{id:"room-primary",geom:S}]:[],...k.map((e,t)=>({id:`room-isolated-${t}`,geom:e.geom}))];m="openings";for(const e of n){if(!(e.length>0))continue;const t=da(_,e,!0);if(!t.negative&&!t.positive)continue;const i=e.angle*Math.PI/180,n=Math.cos(i),o=Math.sin(i),s=-o,l=n,c=e.length/2,h=1.25*Math.max(u,r*a),d=[[e.x-n*c-s*h,e.y-o*c-l*h],[e.x+n*c-s*h,e.y+o*c-l*h],[e.x+n*c+s*h,e.y+o*c+l*h],[e.x-n*c+s*h,e.y-o*c+l*h]];w&&(w=Gt(w,Bs(d)));for(const e of k)e.geom=Gt(e.geom,Bs(d))}m="extras";const M=[];let R=0;const C=c.mergeExtra||((e,t)=>e?Wt(e,t):t);for(let e=0;ee.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]))||Math.abs(Ci(t))<=1e-9){R++;continue}const i=[Bs(t)];try{const t=C(w,i,e);if(!qs(t))throw new Error("invalid extra union");w=t}catch{R++,qs(i)&&M.push({id:`extra-${e}`,geom:i})}}M.push(...k),M.sort((e,t)=>Qs(e.geom).localeCompare(Qs(t.geom)));const T=w||[];return{status:R||x?"degraded-extra":"ok",geom:T,components:[...qs(T)?[{id:"primary",geom:T}]:[],...M.map((e,t)=>({...e,id:`isolated-${t}`}))],roomGeom:S,roomComponents:$,paperGeom:y,depthUnits:u,openingPadUnits:1.25*Math.max(u,r*a),openingIndex:_,multiWallNodes:d,degradedExtraCount:R+x}}catch{return c.onCoreFailure?.(m),{status:"failed-core",geom:[],components:[],roomGeom:[],paperGeom:[],roomComponents:[],depthUnits:u,openingIndex:null,multiWallNodes:d,degradedExtraCount:0}}var g,f}function na(e,t,i,n=[],r,o,s,a=1,l=[],c={}){if(!t?.length&&!l.length)return null;return ra(ia(e,t,i,n,r,o,s,a,l,c))}function ra(e){if("failed-core"===e.status||"not-applicable"===e.status)return null;const t=e.components.map(e=>({id:e.id,d:Qs(e.geom),fillRule:"evenodd"})).filter(e=>!!e.d),i=t[0]?.d||"",n=Qs(e.paperGeom);if(t.length){const r={status:e.status,d:i,paths:t,components:e.components,roomGeom:e.roomGeom,multiWallNodes:e.multiWallNodes,paperD:n,depthUnits:e.depthUnits,fillRule:"evenodd"};return Object.defineProperties(r,{roomComponents:{value:e.roomComponents||[],enumerable:!1},openingIndex:{value:e.openingIndex,enumerable:!1},openingPadUnits:{value:e.openingPadUnits,enumerable:!1}}),r}return null}function oa(e,t,i,n,r,o,s=1){if(!t?.length)return[];const a=new Set,l=[];for(const c of e||[]){if(!c?.id)continue;const h=Fs(e,c.id,t,i,n,r,o,s);if(!h)continue;const d=h.poly;for(let e=0;e0))continue;const p=qo(t,i,n,s);if(a.has(p))continue;a.add(p);const _=Oo(u,r,o),[m,g]=gs(d,e),f=-m,v=-g,y=_/2,b=[[t[0]+f*y,t[1]+v*y],[i[0]+f*y,i[1]+v*y],[i[0]+m*y,i[1]+g*y],[t[0]+m*y,t[1]+g*y]];l.push({key:p,kind:c,cm:u,quad:b,a:[t[0],t[1]],b:[i[0],i[1]],depthUnits:_})}}return l}function sa(e,t=[]){let i=ks(e.quad);const[n,r]=Lo(e.a,e.b),o=n,s=r,a=-s,l=o;for(const n of t){if(!Zo(e.a,e.b,n.angle))continue;if(Ns(n.x,n.y,e.a[0],e.a[1],e.b[0],e.b[1])>Math.max(.55*e.depthUnits,.001))continue;const t=n.length/2,r=e.depthUnits,c=n.x,h=n.y;i+=` ${ks(xs([[c-o*t-a*r,h-s*t-l*r],[c+o*t-a*r,h+s*t-l*r],[c+o*t+a*r,h+s*t+l*r],[c-o*t+a*r,h-s*t+l*r]]))}`}return i}function aa(e,t,i){const n=e?.length||0;if(n<3||t.length!==n)return null;if(t.every(e=>!(e>0)))return e.map(e=>[e[0],e[1]]);xs(e),t.slice().reverse();const r=[];for(let o=0;o0||l>0)){r.push([e[o][0],e[o][1]]);continue}if(a>0!=l>0){const t=e[o],i=a>0?[t[0]-c*a,t[1]-h*a]:[t[0],t[1]],n=l>0?[t[0]-d*l,t[1]-u*l]:[t[0],t[1]];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}if(fs(w,k)){const t=e[o],i=[t[0]-c*a,t[1]-h*a],n=[t[0]-d*l,t[1]-u*l];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}const $=vs(x,w,S,k),M=Math.max(a,l,1e-9),R=As(i,e[o])?.limit??4*M;if($){const i=Math.hypot($[0]-e[o][0],$[1]-e[o][1]);if(Number.isFinite(i)&&i<=R){r.push($);continue}if(ta(e,t,o)){r.push([e[o][0],e[o][1]]);continue}}a>0&&r.push([e[o][0]-c*a,e[o][1]-h*a]),l>0&&r.push([e[o][0]-d*l,e[o][1]-u*l])}return r.length>=3?r:null}function la(e,t,i,n,r,o,s=1){const a=[];for(const l of e||[]){if(!l?.id)continue;const c=Fs(e,l.id,t,i,n,r,o,s);if(!c)continue;const h=Math.abs(Ci(c.poly));for(let e=0;e[Math.max(t,e.x0),Math.min(i,e.x1)]).filter(e=>e[1]-e[0]>n).sort((e,t)=>e[0]-t[0]||e[1]-t[1]);if(!r.length)return{coverage:0,full:!1};let o=r[0][0],s=r[0][1],a=0,l=o<=t+n;for(let e=1;e=i-n,{coverage:a,full:l}}function ha(e,t){return Number(t.full)-Number(e.full)||e.faceDistance-t.faceDistance||e.area-t.area||e.roomId.localeCompare(t.roomId)}function da(e,t,i=!1){const n=Number(t?.x),r=Number(t?.y),o=Number(t?.angle),s=Number(t?.length);if(!([n,r,o,s].every(Number.isFinite)&&s>0))return{negative:null,positive:null};const a=o*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=-c,d=l,u=s/2,p=Math.max(1e-9,e.adjacencyEps),_=new Map;let m=0;for(const t of e.edges){if(i&&!(t.half>0))continue;if(!Zo(t.a,t.b,o))continue;const[e,s]=Lo(t.a,t.b);if(Math.abs((n-t.a[0])*s-(r-t.a[1])*e)>p)continue;const a=(t.a[0]-n)*l+(t.a[1]-r)*c,g=(t.b[0]-n)*l+(t.b[1]-r)*c,f=Math.max(-u,Math.min(a,g)),v=Math.min(u,Math.max(a,g));if(v-f<=p)continue;const y=t.inward[0]*h+t.inward[1]*d>=0?1:-1,b=((t.a[0]+t.b[0])/2-n)*h+((t.a[1]+t.b[1])/2-r)*d,w=Math.abs(b+y*t.half),k=`${y}|${t.roomId}`,x={x0:f,x1:v,half:t.half,cm:t.cm,key:t.key,axis:[e,s]},S=_.get(k);S?(S.pieces.push(x),S.faceDistance=Math.min(S.faceDistance,w)):_.set(k,{roomId:t.roomId,side:y,order:m++,pieces:[x],faceDistance:w,area:t.area,coverage:0,full:!1})}for(const e of _.values()){const t=ca(e.pieces,-u,u,p);e.coverage=t.coverage,e.full=t.full}const g=e=>{const t=[..._.values()].filter(t=>t.side===e&&t.coverage>p);return t.sort(ha),t[0]||null};return{negative:g(-1),positive:g(1)}}function ua(e,t,i,n,r,o,s=1,a=[]){return pa(la(e,i,a,n,r,o,s),t)}function pa(e,t){const i=da(e,t),n=[i.negative,i.positive].filter(e=>!!e);if(!n.length)return{ox:0,oy:0,cm:0,side:-1};const r=i.negative&&i.positive?-1:n[0].side,o=t.flip_v?-r:r,s=(-1===o?i.negative:i.positive)||n[0],a=[...s.pieces].sort((e,t)=>(e.x0<=0&&e.x1>=0?0:Math.min(Math.abs(e.x0),Math.abs(e.x1)))-(t.x0<=0&&t.x1>=0?0:Math.min(Math.abs(t.x0),Math.abs(t.x1)))||t.x1-t.x0-(e.x1-e.x0)||e.key.localeCompare(t.key))[0];if(!(a.half>0&&a.cm>0))return{ox:0,oy:0,cm:0,side:o};const l=t.angle*Math.PI/180,c=-Math.sin(l),h=Math.cos(l);return{ox:c*o*a.half,oy:h*o*a.half,cm:a.cm,side:o}}function _a(e,t){const i=1e-9,n=t.filter(e=>Number.isFinite(e.x0)&&Number.isFinite(e.x1)&&Number.isFinite(e.half)&&e.x1>e.x0&&e.half>0);if(!n.length)return"";const r=n.flatMap(e=>[e.x0,e.x1]).sort((e,t)=>e-t),o=[];for(const e of r){const t=o[o.length-1];(void 0===t||e>t+i)&&o.push(e)}const s=[];for(let e=0;e+1t+i))continue;const a=(t+r)/2,l=n.reduce((e,t)=>a>=t.x0-i&&a<=t.x1+i?Math.max(e,t.half):e,0);if(!(l>0))continue;const c=s[s.length-1];c&&t<=c.x1+i&&Math.abs(l-c.half)<=i?c.x1=r:s.push({x0:t,x1:r,half:l})}const a=[];for(const e of s){const t=a[a.length-1],n=t?.[t.length-1];n&&e.x0<=n.x1+i?(e.x0=n.x1,t.push(e)):a.push([e])}return a.map(t=>{const i=t[0],n=t[t.length-1],r=Math.min(.25*Math.min(...t.map(e=>e.half)),.75),o=-e*r,s=[];if(1===e){s.push(`M ${i.x0} ${o} L ${n.x1} ${o}`);for(let e=t.length-1;e>=0;e--){const i=t[e];s.push(`L ${i.x1} ${i.half} L ${i.x0} ${i.half}`)}}else{s.push(`M ${n.x1} ${o} L ${i.x0} ${o}`);for(const e of t)s.push(`L ${e.x0} ${-e.half} L ${e.x1} ${-e.half}`)}return s.push("Z"),s.join(" ")}).join(" ")}function ma(e,t,i,n){if(!n)return i;const r=e.angle*Math.PI/180,o=Math.cos(r),s=Math.sin(r),a=[],l=1e-9;for(const r of i){const[i,c]=r.axis,h=o*i+s*c;if(Math.abs(h)<=l)continue;const d=e.x*i+e.y*c,u=d+h*r.x0,p=d+h*r.x1,_=Math.min(u,p),m=Math.max(u,p),g=`${r.key}|${t}`,f=n.get(g)||[];let v=[[_,m]];for(const[e,t]of f){const i=[];for(const[n,r]of v)t<=n+l||e>=r-l?i.push([n,r]):(e>n+l&&i.push([n,Math.min(r,e)]),te[0]-t[0]||e[1]-t[1]),b=[];for(const e of y){const t=b[b.length-1];t&&e[0]<=t[1]+l?t[1]=Math.max(t[1],e[1]):b.push([e[0],e[1]])}n.set(g,b)}return a}function ga(e,t){const i=new Map;return t.map(t=>function(e,t,i){const n=da(e,t,!0),r=n.negative,o=n.positive;if(!r&&!o)return null;let s;if(r&&o)s=[{candidate:r,side:-1},{candidate:o,side:1}];else{const e=r||o;s=[{candidate:e,side:-1},{candidate:e,side:1}]}const a=s.map(({candidate:e,side:n})=>({candidate:e,side:n,pieces:ma(t,n,e.pieces,i)})),l=a.map(({candidate:e,side:t,pieces:i})=>({side:t,roomId:e.roomId,d:_a(t,i)})),c=a.flatMap(({pieces:e})=>e);if(!c.length)return null;const h=Math.max(...c.map(e=>e.half));return{faces:l,minY:-h,maxY:h,wallKey:[...new Set(c.map(e=>e.key))].sort().join("|")}}(e,t,i))}const fa=150,va=1e-6;function ya(e){return Number.isFinite(e)?Math.max(1,Math.min(fa,e)):1}function ba(e){return((Number.isFinite(Number(e))?Number(e):0)%90+90)%90}const wa=e=>{const t=e.map(e=>[e[0],e[1]]);return!t.length||t[0][0]===t[t.length-1][0]&&t[0][1]===t[t.length-1][1]||t.push([...t[0]]),[t]},ka=(e,t)=>e[0]===t[0]&&e[1]===t[1];function xa(e,t=1e-6){const i=Number.isFinite(t)&&t>0?t:va,n=[];for(const t of e||[]){if(!Array.isArray(t)||t.length<2)return null;const e=Number(t[0]),r=Number(t[1]);if(!Number.isFinite(e)||!Number.isFinite(r))return null;const o=Math.round(e/i)*i,s=Math.round(r/i)*i;if(!Number.isFinite(o)||!Number.isFinite(s))return null;const a=[Object.is(o,-0)?0:o,Object.is(s,-0)?0:s];n.length&&ka(n[n.length-1],a)||n.push(a)}return n.length>1&&ka(n[0],n[n.length-1])&&n.pop(),n.length<3||new Set(n.map(e=>`${e[0]},${e[1]}`)).size<3?null:Ci(n)>i*i?n:null}function Sa(e){const t=[];for(const i of e||[])for(const e of i||[]){const i=(e||[]).filter(e=>Array.isArray(e)&&e.length>=2);i.length<4||t.push(`M ${i.slice(0,-1).map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`)}return t.join(" ")}function $a(e,t,i,n,r){return os({a:e,b:t,halfDepth:Oo(i,n,r)/2})}function Ma(e,t,i){const n=Number(t)>0?Number(t):5,r=ya(e.cm)/n*i,o=e.center[0],s=e.center[1];if("circle"===e.shape){const e=r/2;return Array.from({length:96},(t,i)=>{const n=i/96*Math.PI*2;return[o+Math.cos(n)*e,s+Math.sin(n)*e]})}const a=r/2,l=ba(e.angle)*Math.PI/180,c=Math.cos(l),h=Math.sin(l);return[[-a,-a],[a,-a],[a,a],[-a,a]].map(([e,t])=>[o+e*c-t*h,s+e*h+t*c])}function Ra(e,t){const i=Number.isFinite(t)?Math.max(0,Math.min(1,t)):0,n=(e.a[0]+e.b[0])/2,r=(e.a[1]+e.b[1])/2,o=(e.b[0]-e.a[0])*i/2,s=(e.b[1]-e.a[1])*i/2;return{...e,a:[n-o,r-s],b:[n+o,r+s]}}function Ca(e,t,i=1e-9){if(!t.length)return[e];let n=[wa(e)];try{for(const e of t){const t=e.b[0]-e.a[0],r=e.b[1]-e.a[1],o=Math.hypot(t,r);if(!(o>i))continue;const s=t/o,a=r/o,l=-a,c=s,h=1.25*Math.max(Number(e.depth)||0,4*i),d=Math.max(2*i,1e-9*o),u=[[e.a[0]-s*d-l*h,e.a[1]-a*d-c*h],[e.b[0]+s*d-l*h,e.b[1]+a*d-c*h],[e.b[0]+s*d+l*h,e.b[1]+a*d+c*h],[e.a[0]-s*d+l*h,e.a[1]-a*d+c*h]];n=Gt(n,wa(u))}return Na(n)}catch{return[e]}}function Ta(e,t){try{const i=Gt([[...e.map(e=>[e[0],e[1]]),[e[0][0],e[0][1]]]],[[...t.map(e=>[e[0],e[1]]),[t[0][0],t[0][1]]]]);let n=null,r=0;for(const e of i||[]){const t=e?.[0]||[],i=Math.abs(Ci(t));t.length>=4&&i>r&&(r=i,n=t.slice(0,-1).map(e=>[e[0],e[1]]))}return n}catch{return null}}function Da(e,t,i,n=Math.max(2e-4*i,1e-9),r=[]){const o=[],s=new Map;for(const e of r){const t=s.get(e.hostId)||[];t.push(e),s.set(e.hostId,t)}const a=[],l=[],c=[];for(const n of e.partitions||[]){const e={a:n.a,b:n.b,halfDepth:Oo(n.cm,t,i)/2};if(!(e.halfDepth>0))continue;const r=os(e);r&&(o.push(e),a.push(r),c.push({id:n.id,body:r}))}const h=o;for(const{segmentIndex:e,wedge:t}of hs(h,n)){const i={list:a,at:e},n=Ta(i.list[i.at],t);n&&(i.list[i.at]=n,c[i.at].body=n)}for(const e of c)l.push(...Ca(e.body,s.get(e.id)||[],n));const d=(e.wall_columns||[]).map(e=>Ma(e,t,i)),u=ds(o,n).flatMap(e=>Ca(e,r,n));return{partitions:a,columns:d,patches:u,all:[...l,...u,...d]}}function Aa(e){try{const t=e.map(e=>xa(e)).filter(e=>!!e).map(e=>wa(e));return t.length?Wt(t[0],...t.slice(1)):null}catch{return null}}const Pa=e=>`M ${e.map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`;function Fa(e){const t=[];for(const i of e||[]){if(Oa([i])<=1e-6)continue;const e=[];for(const t of i||[]){const i=(t||[]).filter(e=>Array.isArray(e)&&e.length>=2);i.length<4||e.push(Pa(i.slice(0,-1)))}e.length&&t.push(e.join(" "))}return t}function za(e,t,i={}){const n=Aa(e.filter(e=>e.length>=3)),r=t.some(e=>!xa(e))?null:Aa(t);if(!n)return[];if(r)try{return Fa(Ut(n,r))}catch{}return function(e,t,i){let n=null;for(let r=0;r=4&&t.push(e.slice(0,-1).map(e=>[e[0],e[1]]));return t}function Na(e){const t=[];for(const i of e||[]){const e=i?.[0];e?.length>=4&&t.push(e.slice(0,-1).map(e=>[e[0],e[1]]))}return t}function Ha(e,t){let i=!1;for(let n=0,r=t.length-1;ne[1]!=l>e[1]&&e[0]<(a-o)*(e[1]-s)/(l-s||1e-12)+o&&(i=!i)}return i}function La(e,t){for(const i of t||[]){const t=i?.[0];if(!t?.length||!Ha(e,t))continue;let n=!1;for(let t=1;ti)return!1;if(Math.abs(ya(e.cm)-ya(t.cm))>1e-6)return!1;if(e.shape!==t.shape)return!0;if("circle"===e.shape||"circle"===t.shape)return!0;const n=Math.abs(ba(e.angle)-ba(t.angle));return Math.min(n,90-n)<=1e-6}const qa=2.54;function ja(e){const t="number"==typeof e?e:NaN;return!Number.isFinite(t)||t<=0||5===t?1:5/t}function Wa(e,t){return e*ja(t)}function Ua(e){return e?qa:1}function Ga(e,t){if(!t)return String(e);const i=e/qa;return String(Math.round(1e6*i)/1e6)}function Va(e,t){return t?e*qa:e}const Ka=1e3;function Ya(e,t){const i=Number(e),n=Number.isFinite(i)&&i>0?i:1,r=n>=1?t:t*n,o=n>=1?t/n:t;return{x:(t-r)/2,y:(t-o)/2,w:r,h:o}}const Xa=.01,Za=100;function Ja(e,t=1e3){const i=Ya(e?.plan_aspect,t),n=Number(e?.plan_scale),r=Number.isFinite(n)&&n>0?Math.min(Za,Math.max(Xa,n)):1,o=Number(e?.plan_scale_x),s=Number(e?.plan_scale_y),a=Number.isFinite(o)&&o>0?Math.min(Za,Math.max(Xa,o)):r,l=Number.isFinite(s)&&s>0?Math.min(Za,Math.max(Xa,s)):r,c=Number(e?.plan_x),h=Number(e?.plan_y),d=Dr(e?.plan_angle);return{x:i.x+(Number.isFinite(c)?cl(c):0)*t,y:i.y+(Number.isFinite(h)?cl(h):0)*t,w:i.w*a,h:i.h*l,...d?{angle:d}:{}}}function Qa(e){if(null==e.x||null==e.y)return{x:e.x,y:e.y,w:e.w,h:e.h};const t=Number(e.w)||0,i=Number(e.h)||0;return{x:t<0?e.x+t:e.x,y:i<0?e.y+i:e.y,w:Math.abs(t),h:Math.abs(i)}}function el(e){return e&&Array.isArray(e.spaces)?e.spaces.map(e=>{const t=Ka,i=function(e){return Array.isArray(e)&&4===e.length&&e.every(e=>Number.isFinite(e))&&e[2]>1e-6&&e[3]>1e-6?e:[0,0,1,1]}(e.view_box);return{id:e.id,title:e.title,cellCm:Number.isFinite(Number(e.cell_cm))&&Number(e.cell_cm)>0?Number(e.cell_cm):5,vb:[i[0]*Ka,i[1]*t,i[2]*Ka,i[3]*t],bg:e.plan_url?{href:Hn(e.plan_url),...Ja(e,Ka)}:null,rooms:(e.rooms||[]).map(e=>{const i={...e,...Qa(e)};return{id:i.id,name:i.name,area:i.area??null,open_to:i.open_to||void 0,settings:i.settings||void 0,x:null!=i.x?i.x*Ka:void 0,y:null!=i.y?i.y*t:void 0,w:null!=i.w?i.w*Ka:void 0,h:null!=i.h?i.h*t:void 0,poly:i.poly?i.poly.map(e=>[e[0]*Ka,e[1]*t]):void 0,wall_ids:Array.isArray(i.wall_ids)?[...i.wall_ids]:void 0}}),wall_segments:(e.wall_segments||[]).map(e=>({...e,id:String(e.id),a:[Number(e.a?.[0])*Ka,Number(e.a?.[1])*t],b:[Number(e.b?.[0])*Ka,Number(e.b?.[1])*t],cm:Number(e.cm)})),partitions:(e.partitions||[]).map(e=>({id:e.id,a:[e.a[0]*Ka,e.a[1]*t],b:[e.b[0]*Ka,e.b[1]*t],cm:Number(e.cm)})),wall_columns:(e.wall_columns||[]).map(e=>({id:e.id,shape:"circle"===e.shape?"circle":"square",center:[e.center[0]*Ka,e.center[1]*t],cm:Number(e.cm),..."circle"===e.shape?{}:{angle:ba(e.angle)}}))}}):[]}const tl=5e3,il=tl*Ka,nl=240,rl=Ka/nl,ol=1/nl;function sl(e){if(!Number.isFinite(e))return e;const t=Math.round(e*nl/Ka)*Ka/nl;return Math.abs(t-e)<=1e-9*rl?e:t}function al(e){return{x:sl(e.x),y:sl(e.y)}}function ll(e){return Number.isFinite(e)?Math.min(il,Math.max(-il,e)):0}function cl(e){return Number.isFinite(e)?Math.min(tl,Math.max(-tl,e)):0}const hl=1/3,dl=200;function ul(e){return"house"===e?"house":"content"}function pl(e){let t=1/0,i=1/0,n=-1/0,r=-1/0;for(const o of e){const e=Number(o[0]),s=Number(o[1]);Number.isFinite(e)&&Number.isFinite(s)&&(en&&(n=e),s>r&&(r=s))}return t>n?null:{minX:t,minY:i,maxX:n,maxY:r}}function _l(e){const t=[],i=e=>{if(Array.isArray(e))if(e.length>=2&&Number.isFinite(Number(e[0]))&&Number.isFinite(Number(e[1])))t.push([Number(e[0]),Number(e[1])]);else for(const t of e)i(t)};return i(e),pl(t)}function ml(e,t){const i=Number.isFinite(t)&&t>0?t:0;return{minX:e.minX-i,minY:e.minY-i,maxX:e.maxX+i,maxY:e.maxY+i}}function gl(e){return e.poly&&e.poly.length?pl(e.poly):null==e.x||null==e.y?null:pl([[e.x,e.y],[e.x+(e.w||0),e.y+(e.h||0)]])}function fl(e,t=1e3,i=1e3){const n=Number(e.x)*t,r=Number(e.y)*i,o=Number(e.w)*t,s=Number(e.h)*i;return![n,r,o,s].every(Number.isFinite)||o<=0||s<=0?null:pl(Nr({x:n,y:r,w:o,h:s,angle:Dr(e.angle)||void 0}))}function vl(e,t){const i=[];for(const t of e.rooms||[]){const e=gl(t);e&&i.push(e)}if(e.bg){const t=pl(Nr(e.bg));t&&i.push(t)}for(const e of t||[])if(Array.isArray(e)){const t=pl([e]);t&&i.push(t)}else i.push(e);return i}const yl=e=>{if(!e.length)return 0;const t=[...e].sort((e,t)=>e-t),i=t.length>>1;return t.length%2?t[i]:(t[i-1]+t[i])/2},bl=e=>{let t=1/0,i=1/0,n=-1/0,r=-1/0;for(const o of e)o.minXn&&(n=o.maxX),o.maxY>r&&(r=o.maxY);return t>n||i>r?null:{x:t,y:i,w:n-t,h:r-i}};function wl(e,t){let{x:i,y:n,w:r,h:o}=e;r<30&&(i=i+r/2-100,r=dl),o<30&&(n=n+o/2-100,o=dl);const s="number"==typeof t?{top:t,right:t,bottom:t,left:t}:t,a=Math.max(r,o),l=a*s.top,c=a*s.right,h=a*s.bottom,d=a*s.left;return{x:i-d,y:n-l,w:r+d+c,h:o+l+h}}function kl(e,t={}){const i=t.pad??.05,n=t.k??10,r=t.minSpread??50,o=e.filter(e=>Number.isFinite(e.minX)&&Number.isFinite(e.minY)&&Number.isFinite(e.maxX)&&Number.isFinite(e.maxY)&&Math.abs(e.minX)<=il&&Math.abs(e.maxX)<=il&&Math.abs(e.minY)<=il&&Math.abs(e.maxY)<=il);if(!o.length)return{core:null,all:null,outliers:0};const s=bl(o);if(o.length<4){const e=wl(s,i);return{core:e,all:e,outliers:0}}const a=o.map(e=>(e.minX+e.maxX)/2),l=o.map(e=>(e.minY+e.maxY)/2),c=yl(a),h=yl(l),d=o.map((e,t)=>Math.max(Math.abs(a[t]-c),Math.abs(l[t]-h))),u=Math.max(((e,t)=>e.length?e[Math.min(e.length-1,Math.max(0,Math.round(t*(e.length-1))))]:0)([...d].sort((e,t)=>e-t),.75),r),p=d.map(e=>e>n*u),_=p.filter(Boolean).length,m=_&&_<=o.length*hl?o.filter((e,t)=>!p[t]):o;return{core:wl(bl(m)||s,i),all:wl(s,i),outliers:m===o?0:_}}function xl(e){return kl(e,{pad:0}).all}function Sl(e,t,i=.05){const n=kl(vl(e,t),{pad:i});if(n.core)return n.core;const r=e.vb&&4===e.vb.length&&e.vb[2]>0&&e.vb[3]>0?e.vb:[0,0,Ka,Ka];return{x:r[0],y:r[1],w:r[2],h:r[3]}}function $l(e){const t=Sl(e);return{x:t.x+t.w/2,y:t.y+t.h/2}}function Ml(e){const t=[];for(const i of e.rooms||[]){const e=gl(i);e&&t.push(e)}const i=kl(t,{pad:0}).core,n=Ka*ja(e.cellCm??5);return i?Math.max(n,Math.min(il,Math.max(i.w,i.h))):n}function Rl(e,t,i,n=1){const r=Number(i),o=Number.isFinite(n)&&n>0?n:1;return!Number.isFinite(r)||r<=0?e*o:e*Ml(t)*o/r}const Cl=[1,2,5,10,20,50,100,200,500,1e3];function Tl(e,t,i=7){if(!(e>0&&t>0&&Number.isFinite(t)))return null;const n=Cl.find(n=>e*n*t>=i);if(void 0===n)return null;const r=Cl.find(e=>e>=5*n)??5*n;return{fine:n,coarse:r}}function Dl(e){if(e.poly&&e.poly.length){const t=e.poly.map(e=>e[0]),i=e.poly.map(e=>e[1]),n=Math.min(...t),r=Math.min(...i);return{x:n,y:r,w:Math.max(...t)-n,h:Math.max(...i)-r}}return{x:e.x??0,y:e.y??0,w:e.w??0,h:e.h??0}}function Al(e,t,i,n,r,o=new Set){const s=t[e.id];return!o.has(e.id)&&s&&s.s===e.space?{x:s.x*Ka,y:s.y*Ka}:n[e.id]?n[e.id]:al($l(r))}function Pl(e,t,i,n){const r=i["rl_"+(e.id||"")];if(r&&r.s===t)return{x:r.x*Ka,y:r.y*Ka};const o=function(e){if(e.poly){const t=e.poly.length;return[e.poly.reduce((e,t)=>e+t[0],0)/t,e.poly.reduce((e,t)=>e+t[1],0)/t]}return[e.x+e.w/2,e.y+.1*Math.min(e.w,e.h)]}(e);return al({x:o[0],y:o[1]})}function Fl(e,t){for(const i of e?.spaces??[])for(const e of i?.decor??[])if("furniture"===e?.kind&&"string"==typeof e.symbol&&t(e.symbol))return!0;return!1}let zl=0;const Il=new Set;const Ol=new class{constructor(e){this.options=e,this._art=null,this._failed=!1,this._terminal=!1,this._inFlight=null,this._hosts=new Set,this._settled=[]}state(){return this._art?"ready":this._failed?"fallback":"pending"}get terminal(){return this._terminal}art(e,t){if(this._art)return this._art[e];t&&!this._failed&&this._hosts.add(t)}adopt(e,t){return!!this._art||(t!==this.options.expectedFingerprint?((this.options.warn??console.warn)("[houseplan] furniture artwork from another build ignored",{fingerprint:t}),!1):(this._install(e),!0))}ensure(){return"pending"!==this.state()?Promise.resolve():(this._inFlight||(this._inFlight=this._loadWithRetry().finally(()=>{this._inFlight=null})),this._inFlight)}onSettled(e){"pending"===this.state()?this._settled.push(e):Promise.resolve().then(e)}async _loadWithRetry(){let e=new Error("furniture artwork did not load");for(const t of[0,1])try{const i=await this.options.load(t);if(i.FURNITURE_ART_FINGERPRINT!==this.options.expectedFingerprint){this._terminal=!0,e=new Error(`furniture artwork fingerprint mismatch: expected ${this.options.expectedFingerprint}, got ${i.FURNITURE_ART_FINGERPRINT}`);break}if(this._art)return;return void this._install(i.GENERATED_FURNITURE_ART)}catch(t){e=t}this._art||(this._failed=!0,(this.options.warn??console.warn)("[houseplan] furniture artwork unavailable",e),this.options.loadFailed?.(this._terminal),this._flush())}_install(e){this._art=e,this._failed=!1,this._flush()}_flush(){const e=[...this._hosts];this._hosts.clear();for(const t of e)t.isConnected&&t.requestUpdate();const t=this._settled.splice(0);for(const e of t)e()}}({expectedFingerprint:"54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32",load:async e=>0===e?await import("./furniture-plan-art.generated-DaxkO8ol.js"):await import((()=>{const e=new URL("./furniture-plan-art.generated-DaxkO8ol.js",import.meta.url);return e.searchParams.set("hp_retry","art-"+ ++zl),e.href})()),loadFailed:e=>{for(const t of Il)t(e)}}),El=["furniture","appliance","sanitary","other"],Nl=[{id:"coffee_table",group:"furniture",category:"coffee_table",w:120,h:60},{id:"coffee_table_round",group:"furniture",category:"coffee_table",w:80,h:80},{id:"coffee_table_oval",group:"furniture",category:"coffee_table",w:120,h:60},{id:"coffee_table_rounded",group:"furniture",category:"coffee_table",w:120,h:60},{id:"table_dining",group:"furniture",category:"dining_table",w:160,h:90},{id:"table_round",group:"furniture",category:"dining_table",w:110,h:110},{id:"table_dining_oval",group:"furniture",category:"dining_table",w:180,h:100},{id:"table_dining_rounded",group:"furniture",category:"dining_table",w:160,h:90},{id:"desk",group:"furniture",category:"work_table",w:140,h:70},{id:"desk_corner",group:"furniture",category:"work_table",w:160,h:160},{id:"chair",group:"furniture",category:"chair",w:50,h:50},{id:"chair_bar",group:"furniture",category:"chair",w:45,h:48},{id:"armchair",group:"furniture",category:"armchair",w:90,h:90},{id:"armchair_office",group:"furniture",category:"armchair",w:65,h:65},{id:"sofa",group:"furniture",category:"sofa",w:180,h:90},{id:"sofa_three_seat",group:"furniture",category:"sofa",w:240,h:90},{id:"sofa_corner_right",group:"furniture",category:"sofa",w:260,h:170},{id:"bed_single",group:"furniture",category:"bed",w:90,h:200},{id:"bed_double",group:"furniture",category:"bed",w:160,h:200},{id:"nightstand",group:"furniture",category:"nightstand",w:50,h:40},{id:"cabinet_tv",group:"furniture",category:"nightstand",w:140,h:45},{id:"cabinet_shoe",group:"furniture",category:"nightstand",w:80,h:35},{id:"cabinet_sink",group:"furniture",category:"nightstand",w:80,h:50},{id:"bookshelf",group:"furniture",category:"wardrobe",w:100,h:35},{id:"wall_unit",group:"furniture",category:"wardrobe",w:240,h:45},{id:"wardrobe",group:"furniture",category:"wardrobe",w:180,h:60},{id:"kitchen_floor",group:"furniture",category:"kitchen_cabinet",w:60,h:60},{id:"kitchen_floor_corner",group:"furniture",category:"kitchen_cabinet",w:90,h:90},{id:"kitchen_wall",group:"furniture",category:"kitchen_cabinet",w:60,h:35},{id:"kitchen_wall_corner",group:"furniture",category:"kitchen_cabinet",w:60,h:60},{id:"shelf_floor",group:"furniture",category:"shelving",w:100,h:35},{id:"shelf_wall",group:"furniture",category:"shelving",w:100,h:25},{id:"cooktop_two",group:"appliance",category:"cooktop",w:30,h:50},{id:"stove",group:"appliance",category:"cooktop",w:60,h:60},{id:"tv",group:"appliance",category:"tv",w:120,h:28},{id:"tv_wall",group:"appliance",category:"tv",w:120,h:15},{id:"toilet",group:"sanitary",category:"toilet",w:40,h:70},{id:"toilet_built_in",group:"sanitary",category:"toilet",w:40,h:55},{id:"bathtub",group:"sanitary",category:"bathtub",w:170,h:75},{id:"bathtub_corner",group:"sanitary",category:"bathtub",w:140,h:140},{id:"bidet",group:"sanitary",category:"bidet",w:40,h:60},{id:"bidet_built_in",group:"sanitary",category:"bidet",w:40,h:50},{id:"kitchen_sink",group:"sanitary",category:"kitchen_sink",w:60,h:50},{id:"kitchen_sink_double",group:"sanitary",category:"kitchen_sink",w:90,h:50},{id:"fridge",group:"appliance",category:"fridge",w:60,h:65},{id:"dishwasher",group:"appliance",category:"dishwasher",w:60,h:60},{id:"washer",group:"appliance",category:"washer",w:60,h:60},{id:"dryer",group:"appliance",category:"dryer",w:60,h:60},{id:"ac",group:"appliance",category:"air_conditioner",w:90,h:25},{id:"water_heater",group:"appliance",category:"boiler",w:45,h:45},{id:"shower",group:"sanitary",category:"shower",w:90,h:90},{id:"sink",group:"sanitary",category:"sink",w:60,h:45},{id:"stairs",group:"other",category:"stairs",w:100,h:280},{id:"fireplace",group:"other",category:"fireplace",w:120,h:40},{id:"plant",group:"other",category:"plant",w:40,h:40},{id:"rug",group:"other",category:"rug",w:200,h:140},{id:"computer",group:"appliance",category:"computer",w:120,h:60},{id:"hood",group:"appliance",category:"hood",w:60,h:50},{id:"oven",group:"appliance",category:"oven",w:60,h:60},{id:"cactus",group:"other",category:"plant",w:70,h:120}].map(e=>({id:e.id,group:e.group,category:e.category,w:e.w,h:e.h})),Hl=new Map(Nl.map(e=>[e.id,e]));function Ll(e){return e&&Hl.get(e)||null}function Bl(e){return Hl.has(e)}function ql(e){return Nl.filter(t=>t.group===e)}function jl(e){const t=Ll(e);return t?{w:t.w,h:t.h}:{w:60,h:60}}function Wl(e,t,i=rl,n=1e3){const r=Number(t)>0?Number(t):5;return(Number(e)||0)/r*i/n}const Ul=5e-4,Gl=tl;function Vl(e){return Number.isFinite(e)?Math.max(Ul,Math.min(Gl,e)):Ul}function Kl(e){return Number.isFinite(e)?Math.max(1,Math.min(1e4,e)):1}function Yl(e,t){return Ll(e)?Ol.art(e,t)??null:null}function Xl(e,t,i=1){const n=Number(e),r=Number(i),o=Number.isFinite(n)&&n>0?n:Number.isFinite(r)&&r>0?r:1,s=Number(t),a=o*(Number.isFinite(s)&&s>0?s:1);return Number.isFinite(a)&&a>0?a:o}function Zl(e,t,i,n,r){const o=e+i/2,s=t+n/2,a=(Number(r)||0)*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=(e,t)=>{const i=e-o,n=t-s;return[o+i*l-n*c,s+i*c+n*l]};return[h(e,t),h(e+i,t),h(e+i,t+n),h(e,t+n)]}function Jl(e,t,i,n,r,o,s){const a=Number.isFinite(s)&&s>0?s:1e-6,l=(Number(e.angle)||0)*Math.PI/180,c=Math.cos(l),h=Math.sin(l),d=-Math.sin(l),u=Math.cos(l),p=e.x+e.w/2,_=e.y+e.h/2,m=t>0?-e.w/2:t<0?e.w/2:0,g=i>0?-e.h/2:i<0?e.h/2:0,f=p+m*c+g*d,v=_+m*h+g*u,y=n-f,b=r-v,w=t?(y*c+b*h)*(t>0?1:-1):e.w,k=i?(y*d+b*u)*(i>0?1:-1):e.h;let x=t?Math.abs(w):e.w,S=i?Math.abs(k):e.h;if(o&&t&&i){const t=x/Math.max(e.w,a),i=S/Math.max(e.h,a),n=Math.abs(t-1)>=Math.abs(i-1)?t:i,r=Math.max(a/e.w,a/e.h),o=Math.max(r,Number.isFinite(n)?n:r);x=e.w*o,S=e.h*o}x=Math.max(a,Number.isFinite(x)?x:a),S=Math.max(a,Number.isFinite(S)?S:a);const $=!!t&&w<0,M=!!i&&k<0,R=t?(t>0?1:-1)*($?-1:1):0,C=i?(i>0?1:-1)*(M?-1:1):0,T=f+R*(x/2)*c+C*(S/2)*d,D=v+R*(x/2)*h+C*(S/2)*u,A=!!e.flip_h!==$,P=!!e.flip_v!==M;return{x:T-x/2,y:D-S/2,w:x,h:S,...Number(e.angle)?{angle:Number(e.angle)}:{},...A?{flip_h:!0}:{},...P?{flip_v:!0}:{}}}function Ql(e,t,i,n){let r=Number(e)+(Number(i)-Number(t));if([r,t,i].every(Number.isFinite)||(r=0),n){const e=r/45;r=45*(e<0?-Math.round(Math.abs(e)):Math.round(e))}return r=(r%360+360)%360,r>180?r-360:r}function ec(e,t,i,n,r){const o=e.x*t,s=e.y*i,a=e.w*t,l=e.h*i,c=o+a/2,h=s+l/2,d=o+(e.flip_h?a:0),u=s+(e.flip_v?l:0),p=(e.flip_h?-1:1)*a/n,_=(e.flip_v?-1:1)*l/r,m=Number(e.angle)||0;return(m?`rotate(${m} ${c} ${h}) `:"")+`translate(${d} ${u}) scale(${p} ${_})`}function tc(e,t,i,n=.1){if("string"==typeof e&&!e.trim())return null;const r=Number(e);if(!Number.isFinite(r)||0===r)return null;const o=r*(t?30.48:100),s=Math.abs(o);return si?null:o}function ic(e,t,i){const n=Math.abs(Number(e))/(i?30.48:100),r=Number(n.toFixed(6));return String(t?-r:r)}const nc=15e3,rc=2e3,oc=new WeakMap;function sc(e,t){let i=oc.get(e);if(!i){const t=new Set;i={hiddenAt:"hidden"===e.visibilityState?Date.now():0,token:0,subscribers:t,onVisibility:()=>{const t=oc.get(e);if(!t)return;const i=Date.now();if("hidden"===e.visibilityState){t.hiddenAt||(t.hiddenAt=i);const e={kind:"hidden",token:t.token,at:i,hiddenFor:0,long:!1};for(const i of[...t.subscribers])i(e);return}const n=t.hiddenAt?Math.max(0,i-t.hiddenAt):0;t.hiddenAt=0,t.token++;const r={kind:"visible",token:t.token,at:i,hiddenFor:n,long:n>=nc};for(const e of[...t.subscribers])e(r)},onPageShow:t=>{const i=oc.get(e);if(!i)return;const n=Date.now();i.token++;const r={kind:"pageshow",token:i.token,at:n,hiddenFor:0,long:!!t.persisted,persisted:!!t.persisted};for(const e of[...i.subscribers])e(r)}},oc.set(e,i),e.addEventListener("visibilitychange",i.onVisibility),e.defaultView?.addEventListener("pageshow",i.onPageShow)}return i.subscribers.add(t),()=>{const i=oc.get(e);i&&(i.subscribers.delete(t),i.subscribers.size||(e.removeEventListener("visibilitychange",i.onVisibility),e.defaultView?.removeEventListener("pageshow",i.onPageShow),oc.delete(e)))}}const ac={now:()=>Date.now(),setTimeout:(e,t)=>window.setTimeout(e,t),clearTimeout:e=>window.clearTimeout(e),requestAnimationFrame:e=>window.requestAnimationFrame(e),cancelAnimationFrame:e=>window.cancelAnimationFrame(e)};class lc{constructor(e,t=ac){this.onChange=e,this.clock=t,this._state="steady",this._token=0,this._frameFingerprint="",this._hasCompleteFrame=!1,this._overlayPhase="none",this._recoveryReason=null,this._overlayTimer=0,this._overlayRaf=0,this._overlayOpaqueAt=0,this._barrierRafs=new Set,this._trace=[],this._disposed=!1}get state(){return this._state}get token(){return this._token}get frameFingerprint(){return this._frameFingerprint}get hasCompleteFrame(){return this._hasCompleteFrame}get overlayPhase(){return this._overlayPhase}get overlayVisible(){return"none"!==this._overlayPhase}get overlayBlocksInteraction(){return this.overlayVisible}get recoveryReason(){return this._recoveryReason}get trace(){return this._trace.map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}note(e,t={}){this.record(e,void 0,t)}record(e,t,i={}){this._trace.push({at:this.clock.now(),token:this._token,event:e,state:this._state,...t?{reason:t}:{},...i}),this._trace.length>80&&this._trace.splice(0,this._trace.length-80)}changed(){this._disposed||this.onChange()}adoptCompleteFrame(e){e&&(this._hasCompleteFrame=!0,this._frameFingerprint=e,this._state="steady",this._recoveryReason=null,this.clearOverlay(),this.record("frame-adopted"),this.changed())}markCompleteFrame(e){e&&(this._hasCompleteFrame=!0,this._frameFingerprint=e,this._state="steady",this._recoveryReason=null,this.clearOverlay(),this.record("frame-complete"),this.changed())}refreshCompleteFrame(e){!this._disposed&&this._hasCompleteFrame&&"steady"===this._state&&e&&e!==this._frameFingerprint&&(this._frameFingerprint=e,this.record("frame-refreshed"))}visibility(e){return"hidden"===e.kind?(this.record("visibility-hidden"),this._token):e.long||"visible"!==e.kind&&"pageshow"!==e.kind?this.beginCandidate("pageshow"===e.kind?"pageshow":"long-resume"):(this.record("pageshow"===e.kind?"pageshow-noop":"visibility-visible-quick"),this._token)}beginCandidate(e,t="plan"){return this._token++,this._recoveryReason=t,this._hasCompleteFrame?(this._state="connection"===t?"offline-stale":"holding",this.clearOverlay()):this.overlayVisible?this._state="overlay-visible":(this._state="overlay-pending",this.scheduleOverlay(t)),this.record("candidate-start",e),this.changed(),this._token}connectionLost(){return this.beginCandidate("connection-lost","connection")}candidateReady(e){return!this._disposed&&e===this._token&&(this._state="candidate-ready",this.record("candidate-ready"),this.changed(),!0)}async commitAfterPaint(e,t){if(this._disposed||e!==this._token)return!1;let i=!0;const n=(async()=>{for(await t.updateComplete();i&&!this._disposed&&e===this._token;)if(t.stageValid()&&t.assetsReady()){if(await this.nextFrame(),e!==this._token||!t.stageValid()||!t.assetsReady())continue;if(await this.nextFrame(),e===this._token&&t.stageValid()&&t.assetsReady())return!0}else await this.nextFrame();return!1})();let r=0;const o=new Promise(e=>{r=this.clock.setTimeout(()=>e({ready:!1,timedOut:!0}),rc)}),s=await Promise.race([n.then(e=>({ready:e,timedOut:!1})),o]);return i=!1,this.clock.clearTimeout(r),!this._disposed&&e===this._token&&(!(!s.ready&&!s.timedOut)&&(s.ready?(this._hasCompleteFrame=!0,this._frameFingerprint=t.frameFingerprint(),this.record("paint-barrier"),this.finishOverlayAfterCommit(),!0):(this.record("paint-barrier-timeout"),this._hasCompleteFrame?(this._state="connection"===this._recoveryReason?"offline-stale":"steady",this.clearOverlay()):(this._state="recovery-error","opaque"!==this._overlayPhase&&this.showOverlayNow()),this.changed(),!1)))}retry(e=this._recoveryReason||"plan"){return this.beginCandidate("retry",e)}nextFrame(){return new Promise(e=>{const t=this.clock.requestAnimationFrame(()=>{this._barrierRafs.delete(t),e()});this._barrierRafs.add(t)})}scheduleOverlay(e){this.clearOverlayTimer(),this._recoveryReason=e,this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._hasCompleteFrame||"overlay-pending"!==this._state&&"candidate-ready"!==this._state||(this._state="overlay-visible",this._overlayPhase="entering",this.record("overlay-enter"),this.changed(),this._overlayRaf=this.clock.requestAnimationFrame(()=>{this._overlayRaf=0,"entering"===this._overlayPhase&&(this._overlayPhase="fading-in",this.changed(),this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,"fading-in"===this._overlayPhase&&(this._overlayPhase="opaque",this._overlayOpaqueAt=this.clock.now(),this.record("overlay-opaque"),this.changed())},150))}))},150)}showOverlayNow(){this.clearOverlayTimer(),this._overlayPhase="opaque",this._overlayOpaqueAt=this.clock.now(),this.record("overlay-error")}finishOverlayAfterCommit(){if(this.clearOverlayTimer(),"none"===this._overlayPhase||"entering"===this._overlayPhase||"fading-in"===this._overlayPhase)return this.clearOverlay(),this._state="steady",this._recoveryReason=null,this.record("candidate-committed"),void this.changed();const e=Math.max(0,this._overlayOpaqueAt+250-this.clock.now());this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._overlayPhase="leaving",this.record("overlay-leave"),this.changed(),this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._overlayPhase="none",this._state="steady",this._recoveryReason=null,this.record("candidate-committed"),this.changed()},180)},e)}clearOverlayTimer(){this._overlayTimer&&this.clock.clearTimeout(this._overlayTimer),this._overlayTimer=0}clearOverlay(){this.clearOverlayTimer(),this._overlayRaf&&this.clock.cancelAnimationFrame(this._overlayRaf),this._overlayRaf=0,this._overlayPhase="none",this._overlayOpaqueAt=0}dispose(){this._disposed=!0,this._token++,this.clearOverlay();for(const e of this._barrierRafs)this.clock.cancelAnimationFrame(e);this._barrierRafs.clear()}}function cc(e){let t=2166136261,i=2654435769;const n=new WeakSet,r=e=>{for(let n=0;n>>0)+(i>>>2)}},o=e=>{if(null===e)return void r("n");const t=typeof e;if("string"===t)return void r(`s${e.length}:${e}`);if("number"===t)return void r(`d${Number.isNaN(e)?"NaN":String(e)}`);if("boolean"===t)return void r(e?"t":"f");if("undefined"===t)return void r("u");if("object"!==t)return void r(`${t}:${String(e)}`);const i=e;if(n.has(i))r("[cycle]");else{if(n.add(i),Array.isArray(e)){r("[");for(const t of e)o(t);return r("]"),void n.delete(i)}r("{");for(const t of Object.keys(e).sort())r(t),o(e[t]);r("}"),n.delete(i)}};return o(e),`${(t>>>0).toString(16).padStart(8,"0")}${(i>>>0).toString(16).padStart(8,"0")}`}function hc(e){return cc(e)}const dc=new WeakMap;class uc{constructor(e,t=()=>Date.now()){this.onUpdate=e,this.now=t,this.fallbackAuthority={},this.referenceOwner={},this.referenced=new Set,this.queued=new Set,this.disposed=!1,this.sharedUpdate=()=>{this.disposed||this.onUpdate()}}bind(e){const t=((e,t)=>{const i=e?.connection||e?.callWS||t;return!i||"object"!=typeof i&&"function"!=typeof i?t:i})(e,this.fallbackAuthority);return this.shared&&this.authority===t||(this.shared&&(this.shared.listeners.delete(this.sharedUpdate),this.shared.references.delete(this.referenceOwner)),this.authority=t,this.shared=(e=>{let t=dc.get(e);return t||(t={signed:{},queued:new Set,inFlight:new Map,retry:new Map,listeners:new Set,settlers:new Set,references:new Map},dc.set(e,t)),t})(t),this.disposed||(this.shared.listeners.add(this.sharedUpdate),this.shared.references.set(this.referenceOwner,new Set(this.referenced)))),this.shared}start(e,t){this.disposed=!1,this.referenced=new Set(t());const i=this.bind(e());i.listeners.add(this.sharedUpdate),i.references.set(this.referenceOwner,new Set(this.referenced)),this.stopTimer(),this.resignTimer=setInterval(()=>this.resign(e(),t()),288e5)}dispose(){if(this.disposed=!0,this.stopTimer(),clearTimeout(this.batchTimer),this.shared){this.shared.listeners.delete(this.sharedUpdate),this.shared.references.delete(this.referenceOwner);for(const e of this.queued)this.shared.queued.delete(e)}this.queued.clear()}invalidate(e){const t=this.bind(e);clearTimeout(this.batchTimer),this.queued.clear(),t.queued.clear(),t.inFlight.clear(),t.retry.clear(),t.signed={}}stopTimer(){void 0!==this.resignTimer&&clearInterval(this.resignTimer),this.resignTimer=void 0}display(e,t){const i=Hn(t);if(!i.startsWith("/api/houseplan/content/"))return i;const n=this.bind(e);this.referenced.add(i),n.references.set(this.referenceOwner,new Set(this.referenced));const r=n.signed[i],o=r?this.now()-r.at:1/0;return o{const t=[...this.queued];this.queued.clear();for(const e of t)i.queued.delete(e);this.sign(e,t)},30))}sign(e,t){if(!t.length||!e?.callWS)return;const i=this.bind(e);for(const n of function(e,t){const i=Math.max(1,Math.floor(t)),n=[];for(let t=0;t{const n=i.inFlight.get(e);return!(void 0!==n&&t-n<15e3)&&(i.inFlight.set(e,t),!0)});r.length&&e.callWS({type:"houseplan/content/sign",paths:r}).then(e=>{const t=this.now();let n=0,o=!1;for(const s of r){const r=e?.urls?.[s];if("string"==typeof r&&r){const e=i.signed[s];e?.loaded&&e.url!==r?(e.pending={url:r,at:t},this.preloadReplacement(i,s,r,t)):(i.signed[s]={url:r,at:t,loaded:e?.url===r&&!!e.loaded},o=!0),i.retry.delete(s),n++}else this.backOff(i,s)}if(n&&(this.trimShared(i),o))for(const e of[...i.listeners])e()}).catch(()=>{for(const e of r)this.backOff(i,e)}).finally(()=>{for(const e of r)i.inFlight.get(e)===t&&i.inFlight.delete(e);for(const e of[...i.settlers])e()})}}preloadReplacement(e,t,i,n){const r=()=>{const r=e.signed[t];if(r?.pending?.url===i){e.signed[t]={url:i,at:n,loaded:!0},e.retry.delete(t),this.trimShared(e);for(const t of[...e.listeners])t()}},o=()=>{const n=e.signed[t];n?.pending?.url===i&&(delete n.pending,this.backOff(e,t))};if("undefined"==typeof Image)return void r();const s=new Image;s.onload=()=>{("function"==typeof s.decode?s.decode():Promise.resolve()).then(r).catch(o)},s.onerror=o,s.src=i}preloadCurrentImage(e,t,i){if(i.loaded)return Promise.resolve(!0);if(i.preload)return i.preload;if("undefined"==typeof Image)return i.loaded=!0,Promise.resolve(!0);const n=i.url;return i.preload=new Promise(r=>{const o=new Image;let s=!1;const a=o=>{if(s)return;s=!0,clearTimeout(l);const a=e.signed[t];if(a===i&&delete a.preload,o&&a===i&&a.url===n){a.loaded=!0;for(const t of[...e.listeners])t();r(!0)}else o||a!==i||this.backOff(e,t),r(!1)};o.onload=()=>{("function"==typeof o.decode?o.decode():Promise.resolve()).then(()=>a(!0)).catch(()=>a(!1))},o.onerror=()=>a(!1);const l=setTimeout(()=>a(!1),rc);o.src=n}),i.preload}prepareImage(e,t){const i=Hn(t);if(!i.startsWith("/api/houseplan/content/"))return Promise.resolve(!0);const n=this.bind(e),r=()=>{const t=n.signed[i];if(t&&this.now()-t.atthis.now()&&!n.inFlight.has(i)&&!n.queued.has(i)?Promise.resolve(!1):null},o=r();return o?(s=o,new Promise(e=>{let t=!1;const i=i=>{t||(t=!0,clearTimeout(n),e(i))},n=setTimeout(()=>i(!1),rc);s.then(i).catch(()=>i(!1))})):new Promise(e=>{let t=!1,i=null;const o=i=>{t||(t=!0,clearTimeout(a),n.settlers.delete(s),e(i))},s=()=>{t||i||(i=r(),i&&i.then(o).catch(()=>o(!1)))},a=setTimeout(()=>o(!1),rc);n.settlers.add(s),s()});var s}backOff(e,t){const i=e.retry.get(t)?.delay||0,n=Math.min(6e4,i?2*i:2e3);e.retry.set(t,{notBefore:this.now()+n,delay:n})}trimShared(e){const t=Object.entries(e.signed);if(t.length<=512)return;const i=new Set(e.inFlight.keys());for(const t of e.references.values())for(const e of t)i.add(e);for(const[e,n]of t)(n.pending||n.preload)&&i.add(e);t.sort((e,t)=>t[1].at-e[1].at);const n=t.filter(([e])=>i.has(e));for(const e of t){if(n.length>=512)break;i.has(e[0])||n.push(e)}e.signed=Object.fromEntries(n)}resign(e,t){const i=this.bind(e);this.referenced=new Set(t),i.references.set(this.referenceOwner,new Set(this.referenced));const n=this.now(),r=new Set;for(const e of i.references.values())for(const t of e)r.add(t);const o={};for(const[e,t]of Object.entries(i.signed))r.has(e)&&n-t.at!!o[e]&&!o[e].pending))}markLoaded(e,t,i){const n=Hn(t);if(!n.startsWith("/api/houseplan/content/"))return;const r=this.bind(e).signed[n];if(r&&(!i||r.url===i)&&!r.loaded){r.loaded=!0;for(const t of[...this.bind(e).listeners])t()}}isReady(e,t){const i=Hn(t);if(!i.startsWith("/api/houseplan/content/"))return!0;const n=this.bind(e).signed[i];return!!n&&this.now()-n.at=2&&(this._sequenceMultitouch=!0,this._postGestureClickBlocked=!0))}pointerTerminal(e,t){if("touch"!==t)return!1;const i=this._sequenceMultitouch;return this._activeTouchPointers.delete(e),0===this._activeTouchPointers.size&&(this._sequenceMultitouch=!1),i}reset(){this._activeTouchPointers.clear(),this._sequenceMultitouch=!1,this._postGestureClickBlocked=!1}}const _c=1e-7,mc=(e,t)=>{const i=e.x-t.x,n=e.y-t.y;return i*i+n*n};function gc(e){const t=Math.max(0,e.floorRadius);return{left:Math.min(e.painted.left,e.center.x-t),top:Math.min(e.painted.top,e.center.y-t),right:Math.max(e.painted.right,e.center.x+t),bottom:Math.max(e.painted.bottom,e.center.y+t)}}function fc(e,t){let i=null,n=Number.POSITIVE_INFINITY;for(const r of e){const e=mc(t,r.center);(efunction(e,t){const i=Math.max(0,t.right-t.left),n=Math.max(0,t.bottom-t.top);if(i<=0||n<=0)return!1;const r=Math.min(i,n)/2,o=Math.max(t.left+r,Math.min(t.right-r,e.x)),s=Math.max(t.top+r,Math.min(t.bottom-r,e.y));return mc(e,{x:o,y:s})<=r*r+_c}(t,e.painted));if(i.length)return fc(i,t);return fc(e.filter(e=>{const i=Math.max(0,e.floorRadius);return mc(t,e.center)<=i*i+_c}),t)}class yc{constructor(e,t=44){this.cellSize=t,this.buckets=new Map;const i=Number.isFinite(t)&&t>0?t:44;this.cellSize=i;for(const t of e){const e=gc(t),n=Math.floor(e.left/i),r=Math.floor(e.right/i),o=Math.floor(e.top/i),s=Math.floor(e.bottom/i);for(let e=n;e<=r;e++)for(let i=o;i<=s;i++){const n=`${e}:${i}`,r=this.buckets.get(n);r?r.push(t):this.buckets.set(n,[t])}}}resolve(e){const t=`${Math.floor(e.x/this.cellSize)}:${Math.floor(e.y/this.cellSize)}`;return vc(this.buckets.get(t)||[],e)}}class bc{constructor(){this.active=new Map,this.released=new Map}begin(e,t){this.released.delete(e),this.active.set(e,t)}owner(e){return this.active.get(e)||null}release(e){const t=this.active.get(e)||null;if(!t)return this.released.get(e)||null;for(this.active.delete(e),this.released.set(e,t);this.released.size>16;){const e=this.released.keys().next().value;if(void 0===e)break;this.released.delete(e)}return t}consumeClick(e){const t=this.released.get(e)||null;return this.released.delete(e),t}cancel(e){const t=this.active.get(e)||null;return this.active.delete(e),t}clear(){this.active.clear(),this.released.clear()}}class wc{constructor(){this.index=null,this.pointers=new bc,this.hoverId=null,this.hoverElement=null}invalidate(){this.index=null}reset(e){this.invalidate(),this.pointers.clear(),this.hover(e,null)}clearPointers(){this.pointers.clear()}cancel(e){return this.pointers.cancel(e)}release(e){return this.pointers.release(e)}indexFor(e){if(this.index)return this.index;const t=[];for(const i of e.querySelectorAll('.devlayer > .dev[data-hp="device"][data-id]')){const e=i.querySelector(".device-shell-frame"),n=i.getBoundingClientRect(),r=e?.getBoundingClientRect();!i.dataset.id||!i.isConnected||!r||n.width<=0||n.height<=0||r.width<=0||r.height<=0||t.push({id:i.dataset.id,center:{x:n.left+n.width/2,y:n.top+n.height/2},painted:{left:r.left,top:r.top,right:r.right,bottom:r.bottom},floorRadius:Math.max(22,Math.min(r.width,r.height)/2)})}return this.index=new yc(t),this.index}at(e,t,i,n,r){const o=this.indexFor(e).resolve({x:n,y:r})?.id;return o&&t.find(e=>e.id===o&&e.space===i)||null}byId(e,t,i){return i&&e.find(e=>e.id===i&&e.space===t)||null}begin(e,t,i,n,r){const o=this.at(e,t,i,n.clientX,n.clientY)||r;return this.pointers.begin(n.pointerId,o.id),o}pointer(e,t,i,n,r){const o=n.pointerId;return(Number.isFinite(o)?this.byId(t,i,this.pointers.owner(o)):null)||this.at(e,t,i,n.clientX,n.clientY)||r}click(e,t,i,n,r){if(!(n instanceof PointerEvent))return r;const o=n,s=Number.isFinite(o.pointerId)?this.pointers.consumeClick(o.pointerId):null;return this.byId(t,i,s)||this.at(e,t,i,o.clientX,o.clientY)||r}hover(e,t){this.hoverId===t&&this.hoverElement?.isConnected||(this.hoverElement?.removeAttribute("data-hp-device-hover"),this.hoverId=t,this.hoverElement=t&&[...e.querySelectorAll('.devlayer > .dev[data-hp="device"][data-id]')].find(e=>e.dataset.id===t)||null,this.hoverElement?.setAttribute("data-hp-device-hover",""))}}function kc(e,t){if(t)return e.find(e=>e.id===t)}function xc(e,t){return{id:e,title:t,plan_url:null,view_box:[0,0,1,1],rooms:[],wall_segments:[]}}function Sc(e="file"){const t="draw"===e;return{source:e,showBorders:t,showNames:t,displayTouched:!1}}function $c(e,t){if(e.displayTouched)return{...e,source:t};const i="draw"===t;return{...e,source:t,showBorders:i,showNames:i}}function Mc(e,t,i){return{...e,[t]:i,displayTouched:!0}}function Rc(e){const t=String(e??"").trim().replace(",",".");if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(t))return null;const i=Number(t);return Number.isFinite(i)?i:null}function Cc(e,t){const i=e=>{if(""===String(e??"").trim())return{valid:!0,value:null};const t=Rc(e);return{valid:null!==t,value:t}},n=i(e),r=i(t);return n.valid&&r.valid?null!==n.value&&null!==r.value&&n.value>r.value?{valid:!0,min:r.value,max:n.value}:{valid:!0,min:n.value,max:r.value}:{valid:!1,min:n.value,max:r.value}}function Tc(e,t,i,n,r,o){const s=Cc(n,r);return pn(e,t,o&&s.valid?{settings:{...i.settings||{},temp_min:s.min,temp_max:s.max}}:i)}function Dc(e){const t=e=>"number"==typeof e&&Number.isFinite(e)?String(e):"";return[t(e?.temp_min),t(e?.temp_max)]}function Ac(e,t,i){const n=Cc(t,i);return!!n.valid&&(null===n.min?delete e.temp_min:e.temp_min=n.min,null===n.max?delete e.temp_max:e.temp_max=n.max,!0)}var Pc="M11,18H13V16H11V18M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,6A4,4 0 0,0 8,10H10A2,2 0 0,1 12,8A2,2 0 0,1 14,10C14,12 11,11.75 11,15H13C13,12.75 16,12.5 16,10A4,4 0 0,0 12,6Z";function Fc(e,t,i){return[e[0]*t+e[1]*i+e[2],e[3]*t+e[4]*i+e[5]]}function zc(e,t){let i=0;for(const[n,r]of t){const t=Fc(e,n[0],n[1]);i=Math.max(i,Math.hypot(t[0]-r[0],t[1]-r[1]))}return i}const Ic=e=>{if(null==e||""===e)return null;const t=Number(e);return Number.isFinite(t)?t:null},Oc=e=>{const t=e,i=Ic(Array.isArray(t)?t[0]:t?.x),n=Ic(Array.isArray(t)?t[1]:t?.y);return null==i||null==n?null:[i,n]};function Ec(e){if(!Array.isArray(e))return null;const t=[];for(const i of e){const e=Oc(i);if(!e)return null;t.push(e)}if(t.length>1){const e=t[0],i=t[t.length-1];e[0]===i[0]&&e[1]===i[1]&&t.pop()}if(t.length<3)return null;let i=0,n=0,r=0;for(let e=0;ee+t[0],0)/t.length,t.reduce((e,t)=>e+t[1],0)/t.length]:[n/(3*i),r/(3*i)]}function Nc(e){if(!Array.isArray(e))return null;const t=[];for(const i of e){const e=Oc(i);if(!e)return null;t.push(e)}if(t.length>1){const e=t[0],i=t[t.length-1];e[0]===i[0]&&e[1]===i[1]&&t.pop()}const i=Ec(t);if(!i)return null;const n=t.map(e=>e[0]),r=t.map(e=>e[1]);return{centroid:i,bbox:[Math.min(...n),Math.min(...r),Math.max(...n),Math.max(...r)]}}function Hc(e){let t=e;if(t&&"object"==typeof t&&!Array.isArray(t)){const e=t;t=e.path??e.points??t}if(!Array.isArray(t)||!t.length)return[];let i=(t.some(e=>(e=>Array.isArray(e)?e.length>=2&&!Array.isArray(e[0])&&("object"!=typeof e[0]||null==e[0]):!!e&&"object"==typeof e&&("x"in e||"y"in e))(e))?[t]:t.filter(Array.isArray)).map(e=>e.map(Oc).filter(e=>null!=e)).filter(e=>e.length>=2);i.length>64&&(i=i.slice(-64));const n=i.reduce((e,t)=>e+t.length,0);if(n<=4e3)return i.map(e=>e.slice());const r=4e3-2*i.length,o=i.map(e=>e.length-2),s=o.reduce((e,t)=>e+t,0),a=o.map(e=>r*e/s),l=a.map(Math.floor);let c=r-l.reduce((e,t)=>e+t,0);const h=a.map((e,t)=>({index:t,fraction:e-Math.floor(e)})).sort((e,t)=>t.fraction-e.fraction||e.index-t.index);for(let e=0;efunction(e,t){if(t>=e.length)return e.slice();if(t<=2)return[e[0],e[e.length-1]];const i=[];for(let n=0;ne.slice()),i=t[t.length-1];return i?(i.length>2?i.pop():t.pop(),t):[]}const qc=e=>Number.isFinite(e[0])&&Number.isFinite(e[1]),jc=(e,t)=>e[0]===t[0]&&e[1]===t[1];function Wc(e){if(!e)return null;const t=e.vacuum_position||e.robot_position||null,i=t&&null!=Ic(t.x)&&null!=Ic(t.y)?{x:Ic(t.x),y:Ic(t.y),a:Ic(t.a??t.angle??t.theta)}:null,n=Hc(e.path?.path??e.path?.points??e.path),r=[],o=e.rooms,s=Array.isArray(o)?o.map((e,t)=>[String(e?.id??t),e]):o&&"object"==typeof o?Object.entries(o):[];for(const[e,t]of s){if(!t||"object"!=typeof t)continue;const i=String(t.name??t.label??"").trim(),n=[[Ic(t.cx),Ic(t.cy)],[Ic(t.center?.x),Ic(t.center?.y)],[Ic(t.x),Ic(t.y)]].find(([e,t])=>null!=e&&null!=t);let o=n?.[0]??null,s=n?.[1]??null;const a=Nc(t.outline),l=Ic(t.x0),c=Ic(t.y0),h=Ic(t.x1),d=Ic(t.y1),u=(null!=l&&null!=c&&null!=h&&null!=d?[Math.min(l,h),Math.min(c,d),Math.max(l,h),Math.max(c,d)]:null)||a?.bbox||null;if(null!=o&&null!=s||!a||([o,s]=a.centroid),null!=o&&null!=s||!u||(o=(u[0]+u[2])/2,s=(u[1]+u[3])/2),i&&null!=o&&null!=s){const t={id:e,name:i,cx:o,cy:s};u&&([t.x0,t.y0,t.x1,t.y1]=u),r.push(t)}}const a=function(e){return String(e.map_name??e.current_map??e.map_index??e.selected_map??"default")}(e);return i||r.length||n.length?{pos:i,path:n,rooms:r,mapId:a}:null}function Uc(e,t,i){return![e,t,i].every(Number.isFinite)||e<0||t<=0||i<=0?Number.POSITIVE_INFINITY:e/t*i}const Gc=40;function Vc(e,t,i){if(!e||!t)return null;const n=t.attributes||{},r=e.split(".")[0]||"",o=null!=i?.platform?String(i.platform):null,s=!!Oc(n.vacuum_position??n.robot_position),a=!(!n.rooms||"object"!=typeof n.rooms),l=Hc(n.path?.path??n.path?.points??n.path).length>0,c=[n.map_name,n.current_map,n.map_index,n.selected_map].some(e=>null!=e),h="xiaomi_cloud_map_extractor"===o,d=a||l||c;let u=null;if(s?u="compatible":h?u="known_xcme_incomplete":d?u="partial":"camera"===r&&(u="camera"),!u)return null;const p=s?"camera"===r?300:200:h?100:d?50:0;return{entityId:e,name:String(n.friendly_name||e),platform:o,category:u,hasPosition:s,hasRooms:a,hasPath:l,hasMapId:c,score:p}}const Kc=e=>e.toLowerCase().replace(/[\s_\-.,]+/g,"");function Yc(e,t){const i=new Set(t.map(Kc).filter(Boolean)),n=new Set;for(const t of e){const e=Kc(t.name||"");e&&i.has(e)&&n.add(e)}return n.size}function Xc(e,t){const i=new Map(t.map(e=>[Kc(e.name),e])),n=[],r=[];for(const t of e){const e=i.get(Kc(t.name));e&&(n.push([[t.cx,t.cy],[e.cx,e.cy]]),r.push(t.name))}if(n.length<3)return null;const o=function(e){if(e.length<3)return null;let t=0,i=0,n=0,r=0,o=0,s=0,a=0,l=0,c=0,h=0,d=0,u=0;for(const[[p,_],[m,g]]of e){if(![p,_,m,g].every(Number.isFinite))return null;t+=p*p,i+=p*_,n+=p,r+=_*_,o+=_,s+=1,a+=p*m,l+=_*m,c+=m,h+=p*g,d+=_*g,u+=g}const p=[t,i,n,i,r,o,n,o,s],_=e=>{const[t,i,n,r,o,s,a,l,c]=p,h=t*(o*c-s*l)-i*(r*c-s*a)+n*(r*l-o*a);if(!Number.isFinite(h)||Math.abs(h)<1e-9)return null;const d=[(o*c-s*l)/h,(n*l-i*c)/h,(i*s-n*o)/h,(s*a-r*c)/h,(t*c-n*a)/h,(n*r-t*s)/h,(r*l-o*a)/h,(i*a-t*l)/h,(t*o-i*r)/h];return[d[0]*e[0]+d[1]*e[1]+d[2]*e[2],d[3]*e[0]+d[4]*e[1]+d[5]*e[2],d[6]*e[0]+d[7]*e[1]+d[8]*e[2]]},m=_([a,l,c]),g=_([h,d,u]);if(!m||!g)return null;const f=[m[0],m[1],m[2],g[0],g[1],g[2]];return f.every(Number.isFinite)?f:null}(n);return o?{matrix:o,matched:r,residual:zc(o,n)}:null}function Zc(e,t,i){const n=e[e.length-1];if(n&&n[0]===t[0]&&n[1]===t[1])return e;if(e.push(t),e.length<=600)return e;let r=function(e,t){if(e.length<3)return e.slice();const i=new Uint8Array(e.length);i[0]=i[e.length-1]=1;const n=[[0,e.length-1]];for(;n.length;){const[r,o]=n.pop(),[s,a]=e[r],[l,c]=e[o],h=l-s,d=c-a,u=Math.hypot(h,d)||1e-9;let p=0,_=-1;for(let t=r+1;tp&&(p=i,_=t)}_>0&&p>t&&(i[_]=1,n.push([r,_],[_,o]))}const r=[];for(let t=0;t600&&(r=r.filter((e,t)=>t%2==0||t===r.length-1)),r}function Jc(e){return"cleaning"===e||"returning"===e||"on"===e}const Qc={0:[1,0],90:[0,1],180:[-1,0],270:[0,-1]};function eh(e){const[t,i]=Qc[e.rot]||[1,0],n=e.mir?-1:1;return[e.s*t*n,-e.s*i,e.ox,e.s*i*n,e.s*t,e.oy]}function th(e){const t=e[0]*e[4]-e[1]*e[3];if(!Number.isFinite(t)||Math.abs(t)<1e-12)return null;const i=t<0,n=Math.sqrt(Math.abs(t));let r=180*Math.atan2(-e[1],e[4])/Math.PI;return r=(90*Math.round(r/90)%360+360)%360,{ox:e[2],oy:e[5],s:n,rot:r,mir:i}}function ih(e,t){const i=[],n=[];for(const t of e)null!=t.x0?(i.push(t.x0,t.x1),n.push(t.y0,t.y1)):(i.push(t.cx),n.push(t.cy));if(!i.length)return{ox:t[0]+t[2]/2,oy:t[1]+t[3]/2,s:t[2]/1e4,rot:0,mir:!0};const r=Math.min(...i),o=Math.max(...i),s=Math.min(...n),a=Math.max(...n),l=Math.max(o-r,a-s)||1,c={ox:0,oy:0,s:.6*Math.min(t[2],t[3])/l,rot:0,mir:!0},h=eh(c),[d,u]=Fc(h,(r+o)/2,(s+a)/2);return c.ox=t[0]+t[2]/2-d,c.oy=t[1]+t[3]/2-u,c}function nh(e,t,i,n){const[r,o]=Fc(eh(t),i,n),s=eh({...e,ox:0,oy:0}),[a,l]=Fc(s,i,n);return{...e,ox:r-a,oy:o-l}}function rh(e){const t=e?.trail_mode;return"never"===t||"cleaning"===t||"always"===t?t:!1===e?.trail?"never":"cleaning"}const oh=e=>"number"==typeof e&&Number.isFinite(e);function sh(e){return Array.isArray(e)&&6===e.length&&e.every(oh)?[e[0],e[1],e[2],e[3],e[4],e[5]]:null}function ah(e,t,i){return"legacy:"+e+" "+t+" "+i}function lh(e,t,i,n){const r=t?.map_routes;if(Array.isArray(r))return r.filter(e=>e&&"string"==typeof e.id&&e.id).map(e=>({id:e.id,source:String(e.source??""),map_id:String(e.map_id??""),space:String(e.space??""),calibration:sh(e.calibration)}));const o="string"==typeof t?.source&&t.source?t.source:n||"";if(!o)return[];const s=t?.calibration;if(!s||"object"!=typeof s)return[];const a=[];for(const t of Object.keys(s)){const n=sh(s[t]);n&&a.push({id:ah(e,o,t),source:o,map_id:t,space:i,calibration:n})}return a}const ch=(e,t)=>e instanceof Map?e.get(t):e?.[t];function hh(e){const t=[];let i=!1,n="",r="";for(const o of e.routes){const s=ch(e.observed,o.source);void 0!==s&&(i=!0,n||(n=o.source,r=s),s===o.map_id&&t.push(o))}if(t.length>1)return{kind:"ambiguous",routeIds:t.map(e=>e.id).sort()};if(1===t.length){const i=t[0];if(e.spaceIds&&!e.spaceIds.has(i.space))return{kind:"missing_space",route:i};const n=sh(i.calibration);return n?{kind:"ready",route:{...i,calibration:n}}:{kind:"needs_calibration",route:i}}if(i)return{kind:"unmapped",source:n,mapId:r};const o=e.observed instanceof Map?[...e.observed.entries()]:Object.entries(e.observed||{});if(o.length){const e=o.slice().sort((e,t)=>e[0].localeCompare(t[0]))[0];return{kind:"unmapped",source:e[0],mapId:e[1]}}return{kind:"none"}}function dh(e,t,i){const n=new Set;for(const t of e)t.source&&n.add(t.source);for(const e of t)e&&n.add(e);const r={};for(const e of[...n].sort()){const t=i(e);void 0!==t&&(r[e]=t)}return r}function uh(e,t,i){if(!e)return null;const n="string"==typeof e.route_id?e.route_id:"";if(n)return t.find(e=>e.id===n)||null;const r=function(e,t,i){if(!e||"string"!=typeof e.map_id)return{kind:"orphan_run"};const n=e.map_id,r="string"==typeof i?i:"";let o=t.filter(e=>e.map_id===n);return r&&(o=o.filter(e=>e.source===r)),1===o.length?{kind:"adopted",route:o[0]}:0===o.length?{kind:"orphan_run"}:{kind:"ambiguous_run",routeIds:o.map(e=>e.id).sort()}}(e,t,i);return"adopted"===r.kind?r.route:null}function ph(e){const t="ready"===e.resolution.kind?e.resolution.route:null,i=t&&t.space===e.renderSpace?sh(t.calibration):null,n=uh(e.serverCurrent,e.routes,e.rootSource),r=!!t&&!!n&&n.id===t.id,o=uh(e.serverPrevious,e.routes,e.rootSource);return{live:i,currentRunMatches:r,previous:!!o&&o.space===e.renderSpace&&(e.explicitRoutes||!!t&&o.id===t.id)?sh(o.calibration):null}}const _h={availability:"available",status:"alarm",activity:"none"},mh=new Set(["motion","vibration","sound"]),gh=new Set(["occupancy","presence"]),fh=new Set(["door","window","garage_door","opening"]),vh=new Set(["running","power"]),yh=new Set(["smoke","gas","carbon_monoxide","moisture","safety","tamper","problem"]);const bh=new Set(["running","working","washing","rinsing","spinning","drying","heating","cooling","cleaning","cooking","playing","recording","pumping","irrigating","humidifying","dehumidifying","fan","preheating","defrosting"]),wh=new Set([...bh,"start","started","run","active","in_progress","wash","rinse","spin","dry"]),kh=new Set(["off","idle","paused","standby","docked","finished","complete","completed","stopped","ready","sleeping","stop","end","done","inactive"]),xh=new Set(["heat","cool","heat_cool","auto","dry","fan_only"]),Sh=e=>""===e||"unknown"===e||"unavailable"===e||"__missing__"===e,$h=e=>String(e??"").trim().toLowerCase(),Mh=e=>$h(e).replace(/[\s-]+/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,""),Rh=new Map([["run_state",0],["job_state",0],["operation_state",0],["activity_state",0],["machine_state",1],["running_state",1],["status",2],["device_status",2],["machine_status",2]]),Ch=new Set(["wifi","connection","signal","battery"]);function Th(e,t){const i=e?.entities?.[t]||{};if("config"===i.entity_category)return null;const n=String(t||"").split(".").slice(1).join("."),r=[i.translation_key,i.original_name,i.name],o=[...r,n];r.some(e=>$h(e))||o.push(e?.states?.[t]?.attributes?.friendly_name);const s=o.map(Mh).filter(Boolean);if(s.some(e=>e.split("_").some(e=>Ch.has(e))))return null;let a=null;for(const e of s)for(const[t,i]of Rh)(e===t||e.endsWith(`_${t}`))&&(a=null==a?i:Math.min(a,i));return a}const Dh=(e,t)=>null!=Th(e,t);function Ah(e,t){if(!t.startsWith("switch."))return!1;const i=e?.entities?.[t]||{},n=e?.states?.[t],r=t.slice(7).toLowerCase();if(/(?:^|_)(?:main_)?power$/.test(r))return!0;if([i.translation_key,i.original_name,i.name].map($h).some(e=>["power","main power","power switch","питание"].includes(e)))return!0;const o=$h(n?.attributes?.friendly_name);return/(?:^|[\s._-])(?:main[\s._-]+)?power$/.test(o)||/(?:^|[\s._-])питание$/.test(o)}function Ph(e){for(const t of["hvac_action","action","current_operation","run_state","job_state","operation","activity"]){const i=$h(e?.[t]);if(bh.has(i)||kh.has(i))return i}return""}function Fh(e,t){const i=e?.states?.[t],n=i?$h(i.state):"__missing__",r=String(t||"").split(".")[0],o=$h(i?.attributes?.device_class),s={eid:t,state:n,availability:Sh(n)?"unavailable":"available",status:"neutral",activity:"none",edge:"none"};if("unavailable"===s.availability)return s;if(function(e,t,i){return"alarm_control_panel"===e?"triggered"===i:"on"===i&&Yn(e,t)}(r,o,n))return{...s,status:"alarm"};if("binary_sensor"===r)return mh.has(o)?{...s,edge:"rising"}:gh.has(o)?{...s,activity:"on"===n?"presence":"none"}:fh.has(o)?{...s,status:"on"===n?"open":"neutral",edge:"rising"}:"moving"===o?{...s,activity:"on"===n?"transition":"none"}:vh.has(o)&&"on"===n?{...s,status:"working",activity:"running"}:s;if("cover"===r)return{...s,activity:"opening"===n||"closing"===n?"transition":"none",edge:"terminal_transition"};if("lock"===r)return{...s,status:"unlocked"===n||"open"===n?"open":"neutral",activity:"locking"===n||"unlocking"===n?"transition":"none",edge:"terminal_transition"};if("valve"===r)return{...s,status:["open","opening","closing"].includes(n)?"open":"neutral",activity:"opening"===n||"closing"===n?"transition":"none",edge:"terminal_transition"};if("climate"===r){const e=Ph(i.attributes),t=Array.isArray(i.attributes?.hvac_modes)?i.attributes.hvac_modes.map($h):[],r=!kh.has(n)&&(xh.has(n)||bh.has(n)||t.includes(n));return(e?bh.has(e):r)?{...s,status:"working",activity:"running"}:s}if(["light","switch","fan","humidifier"].includes(r))return"on"===n?{...s,status:"working",activity:"running"}:s;if("media_player"===r)return"off"===n?{...s,availability:"unavailable"}:s;if("vacuum"===r)return"cleaning"===n?{...s,status:"working",activity:"running"}:"returning"===n?{...s,status:"working",activity:"transition"}:s;if("script"===r)return"on"===n?{...s,status:"working",activity:"running"}:s;if("automation"===r)return s;if("button"===r||"event"===r)return{...s,edge:"change"};const a=Ph(i.attributes);return bh.has(a)||bh.has(n)&&!kh.has(n)?{...s,status:"working",activity:"running"}:s}function zh(e,t,i){const n=i.filter(t=>t.startsWith("switch.")&&!e?.entities?.[t]?.entity_category),r=t.find(t=>Ah(e,t));if(!(n.length>1&&!!r))return t.map(t=>Fh(e,t));const o=t.find(t=>t!==r&&Dh(e,t)),s=Fh(e,r);return"unavailable"===s.availability||"off"===s.state?t.map(t=>({eid:t,state:e?.states?.[t]?$h(e.states[t].state):"__missing__",availability:"unavailable",status:"neutral",activity:"none",edge:"none"})):t.map(t=>{if(t===o)return function(e,t){const i=e?.states?.[t],n=i?$h(i.state):"__missing__",r={eid:t,state:n,availability:Sh(n)?"unavailable":"available",status:"neutral",activity:"none",edge:"none"};if("unavailable"===r.availability)return r;const o=Ph(i?.attributes);return bh.has(o)||wh.has(n)&&!kh.has(n)?{...r,status:"working",activity:"running"}:r}(e,t);return{...t===r?s:Fh(e,t),status:"neutral",activity:"none",edge:"none"}})}function Ih(e){if(!e.length)return{availability:"available",status:"neutral",activity:"none"};const t=e.filter(e=>"available"===e.availability);if(!t.length)return{availability:"unavailable",status:"neutral",activity:"none"};if(t.some(e=>"alarm"===e.status))return _h;const i=t.some(e=>"working"===e.status)?"working":t.some(e=>"open"===e.status)?"open":"neutral",n=t.some(e=>"transition"===e.activity)?"transition":t.some(e=>"presence"===e.activity)?"presence":t.some(e=>"running"===e.activity)?"running":"none";return{availability:"available",status:i,activity:n}}function Oh(e,t){if(!(e=>!!e&&!Sh(e))(e)||"unavailable"===t.availability||e===t.state)return null;if("rising"===t.edge)return"off"===e&&"on"===t.state?"event":null;if("change"===t.edge)return"event";if("terminal_transition"===t.edge){const i=new Set([e,t.state]);if(i.has("closed")&&i.has("open")||i.has("locked")&&i.has("unlocked"))return"transition"}return null}const Eh=(e,t=0)=>{const i=Number(e);return Number.isInteger(i)&&i>=0?i:t},Nh=(e,t)=>{const i={rev:0,configRev:Eh(t),off:new Set};if(null==e)return{snapshot:i,valid:!1};const n=e.off;return!Number.isInteger(e.rev)||Number(e.rev)<0||!Number.isInteger(e.config_rev)||Number(e.config_rev)<0||!Array.isArray(n)||n.some(e=>"string"!=typeof e||!e)?{snapshot:i,valid:!1}:{snapshot:{rev:Number(e.rev),configRev:Number(e.config_rev),off:new Set(n)},valid:!0}};function Hh(e,t=0){return Nh(e,t).snapshot}function Lh(e,t,i,n){const r=Nh(t,i);return n&&r.valid&&r.snapshot.configRev===i?e.configRev===i&&r.snapshot.rev{try{const[i,n]=await Promise.all([e.callWS({type:"config/device_registry/list"}),e.callWS({type:"config/entity_registry/list"})]),r=Zh(i,"id"),o=Zh(n,"entity_id");if(!r||!o)throw new Error("invalid_registry_response");t.devices=r,t.entities=o,t.authoritative=!0,t.access="full",t.lastSuccess=Date.now(),t.error=void 0}catch(e){t.authoritative=!1,t.access="limited",t.error=function(e){if(e&&"object"==typeof e){const t=e;return String(t.message||t.code||t.error||"registry_unavailable")}return String(e||"registry_unavailable")}(e)}finally{t.revision++,t.loading=void 0,function(e){for(const t of[...e.listeners])try{t()}catch{}}(t)}})()),t.loading}function Qh(e,t){void 0===t.reloadTimer&&(t.reloadTimer=globalThis.setTimeout(()=>{t.reloadTimer=void 0,Jh(e,t)},80))}async function ed(e,t){if(t.subscribing||t.unsubDevice&&t.unsubEntity)return t.subscribing;const i=e?.connection?.subscribeEvents;return"function"==typeof i?(t.subscribing=(async()=>{try{t.unsubDevice||(t.unsubDevice=await i.call(e.connection,()=>Qh(e,t),"device_registry_updated")),t.unsubEntity||(t.unsubEntity=await i.call(e.connection,()=>Qh(e,t),"entity_registry_updated"))}catch{}finally{0===t.refs&&(t.unsubDevice?.(),t.unsubEntity?.(),t.unsubDevice=void 0,t.unsubEntity=void 0),t.subscribing=void 0}})(),t.subscribing):void 0}function td(e,t){const i=Xh(e);if(!i)return()=>{};const n=0===i.refs;i.refs++,i.listeners.add(t),("pending"===i.access||n)&&Jh(e,i),ed(e,i);let r=!1;return()=>{r||(r=!0,i.listeners.delete(t),i.refs=Math.max(0,i.refs-1),i.refs>0||(i.unsubDevice?.(),i.unsubEntity?.(),i.unsubDevice=void 0,i.unsubEntity=void 0,void 0!==i.reloadTimer&&globalThis.clearTimeout(i.reloadTimer),i.reloadTimer=void 0))}}function id(e){const t=Xh(e);t&&(Qh(e,t),ed(e,t))}function nd(e){const t=Xh(e);if(!t)return{revision:0,authoritative:!1,access:"limited",devices:e?.devices||{},entities:e?.entities||{},lastSuccess:0,error:"registry_unavailable"};let i=e?.devices||{},n=e?.entities||{};if(t.authoritative){const r=t.liveDevices!==i||t.liveEntities!==n,o=void 0!==t.liveDevices||void 0!==t.liveEntities;if(r&&(t.liveDevices=i,t.liveEntities=n,t.projectedRevision=void 0,o&&Qh(e,t)),t.projectedRevision!==t.revision||!t.projectedDevices||!t.projectedEntities){const e={...t.devices},r={...t.entities};for(const[t,n]of Object.entries(i))Object.prototype.hasOwnProperty.call(e,t)||(e[t]=n);for(const[e,t]of Object.entries(n))Object.prototype.hasOwnProperty.call(r,e)||(r[e]=t);t.projectedDevices=e,t.projectedEntities=r,t.projectedRevision=t.revision}i=t.projectedDevices,n=t.projectedEntities}return{revision:t.revision,authoritative:t.authoritative,access:t.access,devices:i,entities:n,lastSuccess:t.lastSuccess,error:t.error}}function rd(e){if(!e||"object"!=typeof e&&"function"!=typeof e)return 0;let t=Gh.get(e);return t||(t=Vh++,Gh.set(e,t)),t}function od(e,t=nd(e)){return[t.revision,t.access,rd(t.devices),rd(t.entities)].join(":")}function sd(e){return!!e&&null==e.disabled_by}function ad(e,t=nd(e)){const i={},n={},r={};for(const[e,n]of Object.entries(t.devices||{}))sd(n)&&(i[e]=n);for(const[e,i]of Object.entries(t.entities||{})){if(!sd(i))continue;const r=i.device_id?t.devices?.[i.device_id]:null;t.authoritative&&i.device_id&&!r||(r&&!sd(r)||(n[e]=i))}for(const[i,n]of Object.entries(e?.states||{})){const e=t.entities?.[i];if(e&&!sd(e))continue;const o=e?.device_id?t.devices?.[e.device_id]:null;t.authoritative&&e?.device_id&&!o||(o&&!sd(o)||(r[i]=n))}return{...e,devices:i,entities:n,states:r}}function ld(e,t=nd(e)){return{...e,devices:t.devices||{},entities:t.entities||{}}}function cd(e,t){const i=[];for(const[n,r]of Object.entries(e||{}))r?.device_id===t&&i.push(n);return i}function hd(){if(Yh)return Yh;if("undefined"==typeof localStorage)return{};try{const e=JSON.parse(localStorage.getItem(Kh)||"{}");if(!e||"object"!=typeof e||Array.isArray(e))return{};const t=Date.now(),i={};for(const[n,r]of Object.entries(e))!r||"active"!==r.kind&&"ha_disabled"!==r.kind||!Number.isFinite(r.ts)||t-r.ts>7776e6||(i[n]=r);return Yh=i,Yh}catch{return{}}}function dd(e,t,i=nd(e)){if(!t||"virtual"===t)return{kind:"active",enabledEntityIds:[],allEntityIds:[]};const n=t.indexOf(":");if(n<1)return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]};const r=t.slice(0,n),o=t.slice(n+1);if("device"!==r&&"entity"!==r||!o)return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]};const s=i.devices||{},a=i.entities||{};if(i.authoritative){if("device"===r){const e=s[o];if(!e)return{kind:"orphaned",reason:"device_missing",enabledEntityIds:[],allEntityIds:[]};const t=cd(a,o);if(!sd(e))return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:t};const i=t.filter(e=>sd(a[e]));return t.length&&!i.length?{kind:"ha_disabled",reason:"all_entities",enabledEntityIds:[],allEntityIds:t}:{kind:"active",enabledEntityIds:i,allEntityIds:t}}const t=a[o];return t&&!sd(t)?{kind:"ha_disabled",reason:"entity",enabledEntityIds:[],allEntityIds:[o]}:t?.device_id&&!s[t.device_id]?{kind:"orphaned",reason:"device_missing",enabledEntityIds:[],allEntityIds:[o]}:t?.device_id&&!sd(s[t.device_id])?{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:[o]}:t||e?.states?.[o]?{kind:"active",enabledEntityIds:[o],allEntityIds:[o]}:{kind:"orphaned",reason:"entity_missing",enabledEntityIds:[],allEntityIds:[]}}const l=function(e){return hd()[e]||null}(t);if("device"===r){const t=s[o],i=cd(a,o);if(null!=t?.disabled_by)return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:i};const n=i.filter(e=>{const t=a[e];return null==t?.disabled_by&&(!t.device_id||null==s[t.device_id]?.disabled_by)});if(i.length&&!n.length&&i.every(e=>null!=a[e]?.disabled_by))return{kind:"ha_disabled",reason:"all_entities",enabledEntityIds:[],allEntityIds:i};if("ha_disabled"===l?.kind)return{kind:"ha_disabled",reason:l.reason||"device",enabledEntityIds:[],allEntityIds:i};if(t||n.some(t=>!!e?.states?.[t]))return{kind:"active",enabledEntityIds:n,allEntityIds:i}}else{const t=a[o];if(null!=t?.disabled_by)return{kind:"ha_disabled",reason:"entity",enabledEntityIds:[],allEntityIds:[o]};if(t?.device_id&&null!=s[t.device_id]?.disabled_by)return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:[o]};if("ha_disabled"===l?.kind)return{kind:"ha_disabled",reason:l.reason||"entity",enabledEntityIds:[],allEntityIds:[o]};if(t||e?.states?.[o])return{kind:"active",enabledEntityIds:[o],allEntityIds:[o]}}return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]}}function ud(e){const t=nd(e);return{access:t.access,authoritative:t.authoritative,revision:t.revision,lastSuccess:t.lastSuccess,error:t.error}}function pd(e){const t={};for(const[i,n]of Object.entries(e.entities)){if(!n?.device_id||!sd(n))continue;const r=e.devices?.[n.device_id];r&&!sd(r)||(t[n.device_id]=t[n.device_id]||[]).push(i)}return t}function _d(e,t){const i=new Map;for(const n of e){if(!0===n?.removed)continue;const e=n?.binding||"";if(!e.startsWith("entity:"))continue;const r=e.slice(7);if(!r)continue;const o=t?.entities?.[r]?.device_id;if(!o)continue;const s=i.get(o)||new Set;s.add(r),i.set(o,s)}return{byDevice:i}}function md(e,t,i,n){const r=n.byDevice.get(t);return r?.size?{partial:!0,entityIds:i.filter(t=>!r.has(t)&&!e?.entities?.[t]?.hidden)}:{partial:!1,entityIds:[...i]}}function gd(e,t,i){if(t.identifiers?.[0]?.[0])return t.identifiers[0][0];for(const t of i){const i=e.entities[t]?.platform;if(i)return i}return""}function fd(e,t){if(/_device_temperature$/.test(t))return!1;if(e.entities?.[t]?.entity_category)return!1;const i=e.states[t];if(!i)return/_temperature$/.test(t);const n=i.attributes||{};return"temperature"===n.device_class||/°C|°F/.test(n.unit_of_measurement||"")||/_temperature$/.test(t)}const vd=["vacuum","lawn_mower","climate","media_player","light","cover","lock","valve","alarm_control_panel","water_heater","fan","humidifier","siren","camera","remote"],yd=e=>[...e.filter(e=>!e.reg?.hidden),...e.filter(e=>!!e.reg?.hidden)];function bd(e,t){const i=t.map(t=>({eid:t,reg:e?.entities?.[t]})).filter(e=>!!e.reg);if(!i.length)return[];const n=i.filter(e=>!e.reg.entity_category),r=n.length?n:i;for(const e of vd){const t=r.filter(t=>t.eid.startsWith(e+"."));if(t.length)return yd(t).map(e=>e.eid)}const o=r.filter(t=>function(e,t){if(!t.startsWith("binary_sensor."))return!1;const i=$h(e?.states?.[t]?.attributes?.device_class||e?.entities?.[t]?.device_class||e?.entities?.[t]?.original_device_class);return mh.has(i)||gh.has(i)||fh.has(i)||vh.has(i)||"moving"===i||yh.has(i)}(e,t.eid));if(o.length)return yd(o).map(e=>e.eid);const s=r.filter(e=>e.eid.startsWith("switch."));if(s.length){const t=yd(s),n=t.find(t=>Ah(e,t.eid));if(s.length>1&&n){const t=i.filter(t=>t.eid!==n.eid&&"config"!==t.reg?.entity_category&&null!=Th(e,t.eid)),r=t.filter(e=>!e.reg?.entity_category),o=r.length?r:t;for(const t of[0,1,2]){const i=yd(o.filter(i=>Th(e,i.eid)===t));if(i.length)return[i[0].eid,n.eid]}}return[(n||t[0]).eid]}const a=[];for(const e of je)a.push(...yd(r.filter(t=>t.eid.startsWith(e+"."))));return a.push(...yd(r.filter(e=>!je.includes(e.eid.split(".")[0])))),a.map(e=>e.eid)}function wd(e,t,i){const n=t.map(t=>({eid:t,reg:e.entities[t],st:e.states[t]})).filter(e=>e.reg),r=[n.filter(e=>!e.reg.hidden&&!e.reg.entity_category),n.filter(e=>!e.reg.entity_category),n.filter(e=>!e.reg.hidden),n];if("mdi:thermometer"===i||"mdi:air-filter"===i)for(const t of r){const i=t.find(t=>fd(e,t.eid));if(i)return i.eid}const o=bd(e,t);return o.find(Pn)||o[0]}function kd(e,t,i=[]){return[...new Set(xd(e,t,i))].filter(e=>Pn(e))}function xd(e,t,i=[]){const n=e?.startsWith("entity:")?new Set([e.slice(7)]):new Set(i);return(t||[]).filter(e=>"string"==typeof e&&!n.has(e))}function Sd(e,t){if("string"==typeof t)return e.area===t;const i=e.marker?.room_id;return i?!!t.id&&i===t.id:!!t.area&&e.area===t.area}function $d(e){const t=e.marker?.binding?.startsWith("entity:")?e.marker.binding.slice(7):null,i=e.entities.filter(Pn),n=e.primary&&Pn(e.primary)?e.primary:null;return[...new Set([t,n,...i].filter(e=>!!e&&Pn(e)))]}function Md(e){const t=$d(e),i=e.marker?.light_entity;return i&&t.includes(i)?i:t[0]||null}function Rd(e,t){if(!1===t.marker?.is_light)return[];if(!0===t.marker?.is_light){return[{eid:Md(t),via:"forced"}]}const i=t.primary||bd(e,t.entities)[0];return i&&!i.startsWith("light.")?[]:t.entities.filter(t=>t.startsWith("light.")&&!!e.states?.[t]).map(e=>({eid:e,via:"light"}))}const Cd=new WeakMap,Td=new WeakMap;function Dd(e){return e.map(e=>[e.id||"",!0===e.hidden?1:0,e.primary||"",[...e.entities].join(","),void 0===e.controls?"":[...e.controls].join(","),e.marker?.id||"",e.marker?.binding||"",e.marker?.is_light,e.marker?.tap_action||"",!0===e.marker?.removed?1:0,e.marker?.light_entity||"",null==e.marker?.controls?"":[...e.marker.controls].join(",")].join("")).join("")}function Ad(e){const t=Dd(e),i=Cd.get(e);if(i?.fingerprint===t)return i;const n=e.filter(e=>!e.hidden),r=new Map,o=new Map;for(const t of e){o.set(t,xd(t.marker?.binding,t.marker?.controls??t.controls,t.entities));const e=t.hidden||!0!==t.marker?.is_light?null:t.marker?.id||t.id;e&&r.set(String(e),t)}const s=new Map;for(const t of e){const e=o.get(t)||[],i=new Set(void 0===t.controls?e.filter(Pn):t.controls.filter(Pn)),n=Md(t),a=i.size?[...i]:n?[n]:[];for(const i of e){if(!i.startsWith("marker:"))continue;const e=i.slice(7);if(!e||e===String(t.marker?.id||t.id||""))continue;if(!r.has(e))continue;const n=s.get(e)||{markerId:e,controllers:[],driverEids:[]};n.controllers.push({device:t,driverEids:[...a]}),n.driverEids=[...new Set([...n.driverEids,...a])],s.set(e,n)}}const a={fingerprint:t,visible:n,markerById:r,persistedByDevice:o,incomingByMarker:s};return Cd.set(e,a),a}function Pd(e){return Ad(e).incomingByMarker}function Fd(e,t){const i=kd(t.marker?.binding,t.controls??t.marker?.controls,t.entities),n=xd(t.marker?.binding,t.marker?.controls??t.controls,t.entities);return(null!=t.marker?.is_light||!i.length&&!n.some(e=>e.startsWith("marker:")))&&Rd(e,t).length>0}function zd(e,t){return Rd(e,t).some(e=>!!e.eid)}function Id(e,t,i,n){const r="always"===e||"auto"===e&&t,o=r&&!i;return{sourceExists:r,fromSourceEnabled:r&&i,manualEnabled:r,radiusEnabled:r,passive:o,effectiveMode:o&&"auto"===n?"fixed":n}}function Od(e,t){const i=kd(t.marker?.binding,t.controls??t.marker?.controls,t.entities).map(e=>({eid:e,via:"controls"})),n=Fd(e,t)?Rd(e,t):[];for(const e of n)e.eid&&i.some(t=>t.eid===e.eid)||i.push(e);return i}function Ed(e,t,i,n){if(null!=i)return Ed(e,t,null,n).filter(e=>Sd(e.device,i));const r=Dd(t),o=function(e,t){const i=new Set;for(const e of t){for(const t of e.entities)i.add(t);for(const t of e.controls||e.marker?.controls||[])"string"!=typeof t||t.startsWith("marker:")||i.add(t)}return[...i].sort().map(t=>`${t}:${e?.states?.[t]?.state??""}`).join("|")}(e,t),s=Bh(n),a=Td.get(t);if(a?.graphFingerprint===r&&a.stateFingerprint===o&&a.virtualLightFingerprint===s&&a.registry===e?.entities)return a.sources;const{visible:l,markerById:c,persistedByDevice:h,incomingByMarker:d}=Ad(t),u=null==i?l:l.filter(e=>Sd(e,i)),p=new Map,_=new Map;for(const t of u){const i=Od(e,t).filter(e=>"controls"!==e.via);for(const n of i){const i=!0===t.marker?.is_light?String(t.marker?.id||t.id||""):"",r=i?`marker:${i}`:`entity:${n.eid}`,o=n.eid?[n.eid]:[],s={key:r,eid:n.eid||"",stateEids:o,serviceEids:o,device:t,via:n.via,castsGlow:!0,passive:!n.eid,on:!n.eid||"on"===e.states?.[n.eid]?.state};p.set(t,[...p.get(t)||[],s]),n.eid&&_.set(n.eid,s)}}const m=new Map;for(const e of t){const t=h.get(e)||[],i=new Set(void 0===e.controls?t.filter(Pn):e.controls);m.set(e,i)}for(const t of p.values())for(const i of t){if(!i.passive)continue;const t=i.key.slice(7),r=d.get(t);i.on=!r||r.driverEids.some(t=>"on"===e.states?.[t]?.state),!r&&qh(i.device.marker)&&(i.on=jh(i.device.marker,n))}const g=new Map,f=e=>{const t=g.get(e.key);(!t||e.castsGlow&&!t.castsGlow)&&g.set(e.key,e)};for(const t of l){const n=h.get(t)||[],r=null==i||Sd(t,i);for(const i of n){if(i.startsWith("marker:")){const e=c.get(i.slice(7)),t=e?p.get(e):null;if(t)for(const e of t)f(e);continue}if(!Pn(i)||!m.get(t)?.has(i))continue;const n=_.get(i);n?f(n):r&&f({key:`entity:${i}`,eid:i,stateEids:[i],serviceEids:[i],device:t,via:"controls",castsGlow:!1,passive:!1,on:"on"===e.states?.[i]?.state})}for(const e of p.get(t)||[])f(e)}const v=[...g.values()];return Td.set(t,{graphFingerprint:r,stateFingerprint:o,virtualLightFingerprint:s,registry:e?.entities,sources:v}),v}function Nd(e){const t=e.filter(e=>e.castsGlow);return t.find(e=>e.on)||t[0]||null}function Hd(e){return e.length?e.some(e=>e.on)?"on":"off":"none"}function Ld(e,t){const i=[];for(const n of t){const t=e.states[n];if(!t)continue;const r=(t.attributes?.unit_of_measurement||"").toLowerCase();if(/_(linkquality|lqi)$/.test(n)||"lqi"===r){const e=parseFloat(t.state);isNaN(e)||i.push(e);continue}const o=t.attributes?.linkquality??t.attributes?.lqi;if(null!=o){const e=parseFloat(o);isNaN(e)||i.push(e)}}return Ii(i)}function Bd(e,t){for(const i of t){if(!fd(e,i))continue;const t=e.states[i];if(!t)continue;const n=parseFloat(t.state);if(!isNaN(n))return Math.round(10*n)/10}return null}function qd(e,t){for(const i of t){if(!i.startsWith("climate."))continue;const t=e.states[i];if(!t||"unavailable"===t.state||"unknown"===t.state)continue;const n=parseFloat(t.attributes?.current_temperature);if(Number.isFinite(n))return Math.round(10*n)/10}return null}function jd(e,t){if(e.entities?.[t]?.entity_category)return!1;const i=e.states[t];if(!i)return/_humidity$/.test(t);const n=i.attributes||{};return"humidity"===n.device_class||"%"===n.unit_of_measurement&&/_humidity$/.test(t)||/_humidity$/.test(t)}function Wd(e,t){for(const i of t){if(!jd(e,i))continue;const t=e.states[i];if(!t)continue;const n=parseFloat(t.state);if(!isNaN(n))return Math.round(n)}return null}function Ud(e,t){if(!t)return[];const i=[];for(const[t,n]of Object.entries(e.entities)){if(!t.startsWith("light.")||n.hidden||!sd(n))continue;let r=null;if("group"===n.platform)r=n.area_id||null;else{if(!n.device_id)continue;{const t=e.devices[n.device_id];if(!sd(t))continue;if("Group"!==t?.model)continue;r=t.area_id||n.area_id||null}}if(!r)continue;const o=e.states[t];i.push({eid:t,name:n.name||o?.attributes?.friendly_name||t,area:r})}return i}function Gd(e,t,i,n,r){const o=qe(t,i,r);if(o!==Be)return o;const s=[];for(const t of n){const i=e.states[t]?.attributes?.device_class;i&&s.push(i)}return function(e){for(const t of e){const e=Le[t];if(e)return e}return null}(s)??Be}function Vd(e,t){return e.map(e=>{if(!Array.isArray(e.controls))return e;const i=e.controls.filter(e=>!("string"==typeof e&&e.startsWith("marker:")&&t.has(e.slice(7))));return i.length===e.controls.length?e:{...e,controls:i.length?i:null}})}function Kd(e,t,i){if(!t||!i||t===i)return[...e];const n=`marker:${t}`,r=`marker:${i}`;return e.map(e=>{const t=Array.isArray(e.controls)?e.controls.map(e=>e===n?r:e):e.controls,i="derived_marker_state"===e.value_badge?.source?.kind&&e.value_badge.source.ref===n?{...e.value_badge,source:{...e.value_badge.source,ref:r}}:e.value_badge,o="derived_marker_state"===e.value_source?.kind&&e.value_source.ref===n?{...e.value_source,ref:r}:e.value_source;return t===e.controls&&i===e.value_badge&&o===e.value_source?e:{...e,controls:t,...void 0!==i?{value_badge:i}:{},...void 0!==o?{value_source:o}:{}}})}function Yd(e,t,i){if(!t||t===i)return!0;const n=new Map;for(const t of e)n.set(t.id,(t.controls||[]).filter(e=>"string"==typeof e&&e.startsWith("marker:")).map(e=>e.slice(7)));const r=new Set,o=[i];for(;o.length;){const e=o.pop();if(e===t)return!0;r.has(e)||(r.add(e),o.push(...n.get(e)||[]))}return!1}function Xd(e,t,i,n){const r=new Set([t]),o=e.filter(e=>{const o=e.id===t||!n&&e.binding===i;return o&&r.add(e.id),!o});return{markers:n?o:[...o,{id:t,binding:i,removed:!0,hidden:!0}],cleanupIds:r}}function Zd(e){const t=new Set,i=new Set,n=new Set;for(const r of e||[]){const e=String(r.binding||"").indexOf(":");if(e<1)continue;const o=r.binding.slice(0,e),s=r.binding.slice(e+1);s&&(!0===r?.removed?"device"===o?t.add(s):"entity"===o&&i.add(s):"entity"===o&&n.add(s))}return{devices:t,entities:i,liveEntities:n}}function Jd(e,t,i){if(i.liveEntities.has(t))return!1;if(i.entities.has(t))return!0;const n=e?.entities?.[t]?.device_id;return!!n&&i.devices.has(n)}function Qd(e,t,i,n,r){const o=kd(t.binding,t.controls,e.entities).filter(e=>!Jd(i,e,n)).filter(e=>"active"===dd(i,"entity:"+e,r).kind);e.marker=t,e.controls=o,e.userHidden=!0===t.hidden,e.hidden=e.userHidden||"ha_disabled"===e.bindingStatus?.kind,t.name&&(e.name=t.name),t.icon&&(e.icon=t.icon),null!=t.model&&(e.model=t.model),e.link=t.link??null,e.description=t.description??null,e.pdfs=t.pdfs||[],e.tapAction=t.tap_action??null}function eu(e){const t=e.hass,i=e.registry||nd(t),n=ad(t,i),r=ld(t,i),{areaToSpace:o,markers:s,settings:a,excluded:l,iconRules:c}=e,h=!1!==a.group_lights,d=Zd(s),u=Ud(n,h).filter(e=>!Jd(n,e.eid,d)),p=new Set(u.map(e=>e.area)),_=pd(n),m=_d(s,r),g=new Set(s.map(e=>e.binding)),f=[];for(const e of Object.values(n.devices)){const r=e.area_id;if(!r||!o[r])continue;if("service"===e.entry_type)continue;if(g.has("device:"+e.id))continue;if("active"!==dd(t,"device:"+e.id,i).kind)continue;const s=md(n,e.id,_[e.id]||[],m);if(s.partial&&!s.entityIds.length)continue;const a=s.entityIds,d=gd(n,e,a);let u=l.has(d)||"Group"===e.model||/scene/i.test(e.model||"")||/bridge/i.test((e.model||"")+(e.name||""))||"myheat"===d&&!!e.via_device_id;if(!u&&h&&p.has(r)){const t=(e.name_by_user||e.name||"").trim();"mdi:lightbulb"===Gd(n,t,e.model,a,c)&&(u=!0)}u&&f.push("device:"+e.id)}return f}function tu(e,t,i,n){if("string"==typeof e.room_id&&e.room_id.length>0&&null===e.area)return{area:"",space:e.space||n};const r=e.area||t||"";return{area:r,space:r&&i[r]||e.space||n}}function iu(e){const t=e.hass,i=e.registry||nd(t),n=ad(t,i),r=ld(t,i),{areaToSpace:o,markers:s,settings:a,excluded:l,showAll:c,firstSpaceId:h,loc:d,iconRules:u}=e,p=!1!==a.group_lights,_=Zd(s),m=Ud(n,p).filter(e=>!Jd(n,e.eid,_)),g=new Set(m.map(e=>e.area)),f=pd(n),v=function(e){const t={};for(const[i,n]of Object.entries(e.entities||{}))n?.device_id&&(t[n.device_id]=t[n.device_id]||[]).push(i);return t}(r),y=_d(s,r),b=new Set;for(const e of s){const[t,i]=e.binding.split(":");"device"!==t&&"entity"!==t||!i||b.add(e.binding)}const w=(e,t)=>s.find(i=>i.binding===e+":"+t),k={},x=[];for(const e of Object.values(n.devices)){const r=e.area_id;if(!r||!o[r])continue;if("service"===e.entry_type)continue;if(b.has("device:"+e.id))continue;const s=dd(t,"device:"+e.id,i);if("active"!==s.kind)continue;const h=w("device",e.id);if(h&&h.hidden&&!a.filter_seeded)continue;const _=md(n,e.id,f[e.id]||[],y);if(_.partial&&!_.entityIds.length)continue;const m=_.entityIds,v=_.partial?{kind:"active",enabledEntityIds:m,allEntityIds:m}:s,S=gd(n,e,m),$=!a.filter_seeded;if($&&!c){if(l.has(S))continue;if("Group"===e.model)continue;if(/scene/i.test(e.model||""))continue;if(/bridge/i.test((e.model||"")+(e.name||"")))continue;if("myheat"===S&&e.via_device_id)continue}const M=(e.name_by_user||e.name||d("device.unnamed")).trim(),R=M+"|"+r;let C=Gd(n,M,e.model,m,u);if(m.some(e=>e.startsWith("lock."))&&(C="mdi:lock"),$&&!c&&p&&"mdi:lightbulb"===C&&g.has(r))continue;k[R]=(k[R]||0)+1;const T=k[R]>1?M+" "+k[R]:M,D={id:e.id,name:T,model:e.model||"",area:r,space:o[r],icon:C,entities:m,allEntities:v.allEntityIds,bindingStatus:v,bindingKind:"device",bindingRef:e.id,pdfs:[]};D.primary=wd(n,m,C),"mdi:thermometer"!==C&&"mdi:air-filter"!==C||(D.temp=Bd(n,m)),D.primary&&jd(n,D.primary)&&(D.hum=Wd(n,m)),x.push(D)}for(const e of m)o[e.area]&&(b.has("entity:"+e.eid)||x.push({id:"lg_"+e.eid,name:e.name,model:d("device.light_group"),area:e.area,space:o[e.area],icon:"mdi:lightbulb-group",entities:[e.eid],allEntities:[e.eid],bindingStatus:{kind:"active",enabledEntityIds:[e.eid],allEntityIds:[e.eid]},primary:e.eid,bindingKind:"entity",bindingRef:e.eid,pdfs:[]}));for(const e of s){if(e.removed)continue;const[s,l]=e.binding.split(":"),c="device"===s||"entity"===s?dd(t,e.binding,i):null;if(!e.hidden||a.filter_seeded||"ha_disabled"===c?.kind)if("device"===s){const t=c;if("unverified"===t.kind)continue;const s=r.devices[l],{area:a,space:p}=tu(e,s?.area_id,o,h),m="active"===t.kind?t.enabledEntityIds:[];let g=s?Gd(n,s.name_by_user||s.name||"",s.model,m,u):"mdi:help-circle";m.some(e=>e.startsWith("lock."))&&(g="mdi:lock");const f={id:e.id,name:s?.name_by_user||s?.name||d("device.fallback"),model:s?.model||"",area:a,space:p,icon:g,entities:m,allEntities:t.allEntityIds.length?t.allEntityIds:s&&v[s.id]||[],bindingStatus:t,bindingKind:"device",bindingRef:l};f.primary=wd(n,m,g),"mdi:thermometer"!==g&&"mdi:air-filter"!==g||(f.temp=Bd(n,m)),f.primary&&jd(n,f.primary)&&(f.hum=Wd(n,m)),Qd(f,e,r,_,i),x.push(f)}else if("entity"===s){if(Jd(r,l,_))continue;const t=c;if("unverified"===t.kind)continue;const s=r.entities[l],a=s?.area_id||s?.device_id&&r.devices[s.device_id]?.area_id||"",{area:d,space:p}=tu(e,a,o,h),m=n.states[l],g=s?.name||m?.attributes?.friendly_name||l;let f=Gd(n,g,"",[l],u);l.startsWith("lock.")&&(f="mdi:lock");const v={id:e.id,name:g,model:"",area:d,space:p,icon:f,entities:"active"===t.kind?[l]:[],allEntities:[l],bindingStatus:t,primary:"active"===t.kind?l:void 0,bindingKind:"entity",bindingRef:l};"mdi:thermometer"!==f&&"mdi:air-filter"!==f||!v.entities.length||(v.temp=Bd(n,v.entities)),v.entities.length&&jd(n,l)&&(v.hum=Wd(n,v.entities)),Qd(v,e,r,_,i),x.push(v)}else{const t=e.area||"",n=e.space||t&&o[t]||h,s={id:e.id,name:e.name||d("device.virtual"),model:e.model||"",area:t,space:n,icon:e.icon||"mdi:map-marker",entities:[],allEntities:[],bindingStatus:{kind:"active",enabledEntityIds:[],allEntityIds:[]},bindingKind:"virtual",virtual:!0};Qd(s,e,r,_,i),x.push(s)}}return x}function nu(e){const{marker:t,siblingMarkers:i=[],...n}=e;return iu({...n,markers:[...i.filter(e=>e.id!==t.id),t]}).find(e=>e.id===t.id)||null}function ru(e,t,i,n){if(!t)return null;if(function(e,t,i){if(!t)return!1;const n=t.indexOf(":");if(n<1)return!1;const r=t.slice(0,n),o=t.slice(n+1),s=Zd(i);return"device"===r?s.devices.has(o):"entity"===r&&Jd(e,o,s)}(e,t,n))return null;const r=t.indexOf(":");if(r<0)return null;const o=t.slice(0,r),s=t.slice(r+1);if(!s)return null;if("entity"===o){const t=parseFloat(e.states[s]?.state);return Number.isFinite(t)?"temp"===i?Math.round(10*t)/10:Math.round(t):null}if("device"===o){const t=Object.entries(e.entities).filter(([,e])=>e.device_id===s).map(([e])=>e);return"temp"===i?Bd(e,t):Wd(e,t)}return null}const ou=new RegExp(["water","voda","coolant","flow_?temp","return_?temp","target","setpoint","chip","cpu","processor","board","core_temp","device_temp","batter","akkum","freezer","fridge","oven","kettle","boiler"].join("|"),"i");function su(e,t){return t.area?t.area:e&&t.id?`@room/${encodeURIComponent(e)}/${encodeURIComponent(t.id)}`:null}function au(e){return null==e.area&&e.space&&e.room_id?su(e.space,{id:e.room_id,area:null}):e.area||null}function lu(e){const t=e?.exclude_integrations;return t?new Set(t):Ie}function cu(e,t,i,n=Ie){const r=new Map;if(!e?.entities)return r;const o=Zd(i),s=new Set,a=new Map,l=new Map;for(const e of i||[]){if(e?.removed)continue;const t=(e.binding||"").indexOf(":");if(t<=0)continue;const i=e.binding.slice(0,t),n=e.binding.slice(t+1);if(!n)continue;!0===e.use_climate_temp&&s.add(n);const r=au(e);r&&("entity"!==i||a.has(n)?"device"!==i||l.has(n)||l.set(n,r):a.set(n,r))}const c=new Map;for(const[t,i]of Object.entries(e.entities)){if(i.device_id&&o.devices.has(i.device_id)&&!o.liveEntities.has(t)||!i.device_id&&o.entities.has(t)&&!o.liveEntities.has(t))continue;const r=i.device_id?e.devices?.[i.device_id]:null;if(!sd(i)||r&&!sd(r))continue;const h=a.get(t)||(i.device_id?l.get(i.device_id):null)||i.area_id||r?.area_id||null;if(!h)continue;if(i.entity_category)continue;if(!(s.size>0&&t.startsWith("climate.")&&(s.has(t)||i.device_id&&s.has(i.device_id)))){if(n.has(i.platform))continue;if(ou.test(t))continue}let d=c.get(h);d||(d=new Map,c.set(h,d));const u=i.device_id||t;let p=d.get(u);if(!p){const n=e.states?.[t];p={name:(r?r.name_by_user||r.name:i.name||n?.attributes?.friendly_name||t)||t,model:r?.model,ents:[]},d.set(u,p)}p.ents.push(t)}for(const[i,n]of c){const o=[],a=[];for(const[i,r]of n){const n=Gd(e,r.name,r.model,r.ents,t),l="mdi:thermometer"===n||"mdi:air-filter"===n;if(l){const t=Bd(e,r.ents);null!=t&&o.push(t)}if(s.size>0&&(s.has(i)||r.ents.some(e=>s.has(e)))){const t=qd(e,r.ents);null!=t&&o.push(t)}if(l||"mdi:water-percent"===n){const t=Wd(e,r.ents);null!=t&&a.push(t)}}(o.length||a.length)&&r.set(i,{temp:o.length?Math.round(o.reduce((e,t)=>e+t,0)/o.length*10)/10:null,hum:a.length?Math.round(a.reduce((e,t)=>e+t,0)/a.length):null})}return r}function hu(e,t,i){const n=[];for(const r of t){if(r.area!==i||r.virtual)continue;const t=Ld(e,r.entities);null!=t&&n.push(t)}return Ii(n)}const du={offStates:["off"],unknownUsesToggle:!0},uu={light:du,switch:du,fan:du,humidifier:du,input_boolean:du,automation:du,remote:du,group:du,climate:{...du,featureMasks:{turn_on:256,turn_off:128,toggle:384}},media_player:{...du,featureMasks:{turn_on:128,turn_off:256,toggle:384}},siren:{...du,featureMasks:{turn_on:1,turn_off:2,toggle:3}},vacuum:{...du,featureMasks:{turn_on:1,turn_off:2,toggle:3}},water_heater:{...du,featureMasks:{turn_on:8,turn_off:8,toggle:8}},camera:{...du,featureMasks:{turn_on:1,turn_off:1,toggle:1}}};function pu(e){return e.slice(0,e.indexOf("."))}function _u(e,t,i){if(!e?.services||"object"!=typeof e.services)return!1;const n=e.services?.[t];return!!n&&Object.prototype.hasOwnProperty.call(n,i)}function mu(e,t,i){return _u(e,t,i)?{domain:t,service:i}:_u(e,"homeassistant",i)?{domain:"homeassistant",service:i}:null}function gu(e,t){return e?.entities?.[t]||null}function fu(e,t,i){const n=e?.states?.[i],r=gu(t,i);return n?.attributes?.friendly_name||r?.name||r?.original_name||i}function vu(e,t){const i=gu(e,t);if(null!=i?.disabled_by)return!0;const n=i?.device_id?e?.devices?.[i.device_id]:null;return null!=n?.disabled_by}function yu(e,t){const i=e?.attributes?.supported_features;if(null==i||""===i)return!1;const n=Number(i);return Number.isFinite(n)&&(n&t)===t}function bu(e,t,i){const n=pu(i);if("lock"===n||"alarm_control_panel"===n)return!0;if("cover"!==n)return!1;const r=e?.states?.[i],o=gu(t,i),s=String(r?.attributes?.device_class||o?.device_class||o?.original_device_class||"");return Gi.has(s)}function wu(e,t,i,n,r){return{ref:i,entityId:n,name:n?fu(e,t,n):null,reason:r}}function ku(e,t,i,n,r,o=null){return{target:null,skipped:wu(e,t,i,n,r),semantics:o,nextEffect:null,command:null}}function xu(e,t,i,n,r=i){const o=pu(i);if("cover"!==o&&"valve"!==o)return function(e,t,i,n,r=i){const o=pu(i),s=e?.states?.[i];if(vu(t,i))return ku(e,t,r,i,"ha-disabled","power");if(bu(e,t,i))return ku(e,t,r,i,"secure");if(!s)return ku(e,t,r,i,"missing","power");if("unavailable"===s.state)return ku(e,t,r,i,"unavailable","power");const a=uu[o];if(!a)return ku(e,t,r,i,"unsupported");let l,c;if("unknown"===s.state||""===s.state){if(!a.unknownUsesToggle)return ku(e,t,r,i,"unsupported","power");l="toggle",c="toggle"}else a.offStates.includes(String(s.state))?(l="turn-on",c="turn_on"):(l="turn-off",c="turn_off");const h=a.featureMasks?.[c];if(h&&!yu(s,h))return ku(e,t,r,i,"unsupported","power");const d=mu(e,o,c);return d?{target:{entityId:i,name:fu(e,t,i),state:String(s.state||""),via:n},skipped:null,semantics:"power",nextEffect:l,command:{...d,data:{entity_id:i}}}:ku(e,t,r,i,"unsupported","power")}(e,t,i,n,r);if(vu(t,i))return ku(e,t,r,i,"ha-disabled",o);if(bu(e,t,i))return ku(e,t,r,i,"secure",o);const s=e?.states?.[i];if(!s)return ku(e,t,r,i,"missing",o);if("unavailable"===s.state)return ku(e,t,r,i,"unavailable",o);const a=function(e,t,i){const n=String(i?.state||""),r="closed"===n?{service:`open_${t}`,effect:"open",feature:1}:"open"===n?{service:`close_${t}`,effect:"close",feature:2}:"opening"===n||"closing"===n?{service:`stop_${t}`,effect:"stop",feature:8}:null;return r&&yu(i,r.feature)&&_u(e,t,r.service)?r:yu(i,3)&&_u(e,t,"toggle")?{service:"toggle",effect:"toggle"}:null}(e,o,s);if(!a)return ku(e,t,r,i,"unsupported",o);return{target:{entityId:i,name:fu(e,t,i),state:String(s.state||""),via:n},skipped:null,semantics:o,nextEffect:a.effect,command:{domain:o,service:a.service,data:{entity_id:i}}}}function Su(e){return"entity"===e.bindingKind?e.bindingRef&&Pn(e.bindingRef)?[e.bindingRef]:[]:"virtual"===e.bindingKind?[]:$d(e)}function $u(e){const t=e.marker?.toggle_entity;return t&&Su(e).includes(t)?t:null}function Mu(e,t,i){const n=function(e,t){if("entity"===e.bindingKind&&e.bindingRef){const t=e.marker?.light_entity?Md(e):null;return[...new Set([t,e.bindingRef].filter(e=>!!e))]}const i=e.entities.length?e.entities:e.allEntities||[],n=e.marker?.light_entity||e.primary&&Pn(e.primary)?Md(e):null;return[...new Set([n,...bd(t,i)].filter(e=>!!e))]}(i,t);if(!n.length)return null;const r="entity"===i.bindingKind?"binding":"device-role";if("binding"===r)return xu(e,t,n[0],r);let o=null,s=null;for(const i of n){const n=xu(e,t,i,r);if(n.command)return n;const a=n.skipped?.reason;if("missing"===a||"unavailable"===a||"secure"===a)return n;"ha-disabled"!==a?o||=n:s||=n}return o||s}function Ru(e){const t=e.skipped?.reason;return"missing"===t?"unavailable":t||"unsupported"}function Cu(e,t){return{origin:e,kind:"none",semantics:null,targets:[],skippedTargets:[],noneReason:t,nextEffect:null,command:null}}function Tu(e,t){return"cover"===e||"toggle"===e?"toggle":"more-info"===e||"run"===e||"info"===e||"none"===e?e:(null==e||""===e)&&"light"===t?"toggle":"info"}function Du(e,t){return{origin:e,kind:"single",semantics:t.semantics,targets:t.target?[t.target]:[],skippedTargets:t.skipped?[t.skipped]:[],noneReason:t.command?null:Ru(t),nextEffect:t.nextEffect,command:t.command}}function Au(e,t,i,n=[]){const r=new Map,o=[],s=new Set,a=e=>{const t=`${e.ref}\n${e.entityId||""}\n${e.reason}`;s.has(t)||(s.add(t),o.push(e))};for(const e of n)a(e);for(const n of i){const i=xu(e,t,n.entityId,n.via,n.ref);i.target?r.set(n.entityId,r.get(n.entityId)||i.target):i.skipped&&a(i.skipped)}const l=[...r.values()];if(!l.length)return{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:l,skippedTargets:o,noneReason:o.length&&o.every(e=>"secure"===e.reason)?"secure":"configured-targets-missing",nextEffect:null,command:null};const c=l.some(e=>"on"===e.state)?"turn_off":"turn_on",h=mu(e,"homeassistant",c);return h?{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:l,skippedTargets:o,noneReason:null,nextEffect:"turn_on"===c?"turn-on":"turn-off",command:{...h,data:{entity_id:l.map(e=>e.entityId)}}}:{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:[],skippedTargets:[...o,...l.map(i=>wu(e,t,i.entityId,i.entityId,"unsupported"))],noneReason:"unsupported",nextEffect:null,command:null}}function Pu(e){return String(e.marker?.id||e.id||"")}function Fu(e){const{hass:t,device:i}=e,n=e.registryHass||t,r=function(e){return"toggle"===e.tapAction?"explicit-toggle":"cover"===e.tapAction?"legacy-cover":!e.tapAction&&e.primary?.startsWith("light.")?"default-light":null}(i);if(!r)return null;const o=i.marker;if("explicit-toggle"===r&&qh(o)){const t=String(o?.id||i.id||""),n=Pd(e.devices).get(t);if(n)return function(e,t){const i=e.registryHass||e.hass;return Au(e.hass,i,t.driverEids.map(e=>({entityId:e,via:"control-marker-driver",ref:`marker:${t.markerId}`})))}(e,n);const s=jh(o,e.virtualLights);return{origin:r,kind:"single",semantics:"power",targets:[{entityId:"",name:i.name,state:s?"on":"off",via:"virtual-light"}],skippedTargets:[],noneReason:null,nextEffect:s?"turn-off":"turn-on",command:null,operation:{kind:"virtual-light",markerId:o.id}}}if("explicit-toggle"===r){if(xd(i.marker?.binding,i.marker?.controls??i.controls,i.entities).length)return function(e,t=null){const{hass:i,device:n,devices:r}=e,o=e.registryHass||i,s=xd(n.marker?.binding,n.marker?.controls??n.controls,n.entities),a=e.lightSources||Ed(i,r,null,e.virtualLights),l=new Map;for(const e of a){if(!e.key.startsWith("marker:"))continue;const t=l.get(e.key)||[];t.push(e),l.set(e.key,t)}const c=Pd(r),h=new Map;for(const e of r){const t=String(e.marker?.id||e.id||"");t&&h.set(t,e)}const d=[],u=[];t&&d.push({entityId:t,via:"entity"===n.bindingKind?"binding":"device-role",ref:t});for(const e of s){if(!e.startsWith("marker:")){Pn(e)?d.push({entityId:e,via:"control-entity",ref:e}):u.push(wu(i,o,e,e.includes(".")?e:null,"unsupported"));continue}const t=l.get(e)||[];if(!t.length){const t=h.get(e.slice(7));if("ha_disabled"===t?.bindingStatus?.kind){const n=t.bindingStatus.allEntityIds[0]||null;u.push({ref:e,entityId:n,name:t.name||(n?fu(i,o,n):null),reason:"ha-disabled"})}else u.push(wu(i,o,e,null,"missing"));continue}const r=[...new Set(t.flatMap(e=>e.serviceEids))];if(r.length){for(const t of r)d.push({entityId:t,via:"control-entity",ref:e});continue}const s=t.some(e=>e.passive),a=e.slice(7),p=Pu(n),_=c.get(a)?.controllers.find(e=>Pu(e.device)===p);if(s&&_?.driverEids.length)for(const t of _.driverEids)d.push({entityId:t,via:"control-marker-driver",ref:e});else u.push(wu(i,o,e,null,s?"missing":"unsupported"))}return Au(i,o,d,u)}(e,$u(i))}if("legacy-cover"===r){const e=i.entities.find(e=>e.startsWith("cover."))||i.allEntities?.find(e=>e.startsWith("cover."));return e?Du(r,xu(t,n,e,"device-role")):Cu(r,"no-actionable-entity")}const s=$u(i),a=s?xu(t,n,s,"entity"===i.bindingKind?"binding":"device-role"):Mu(t,n,i);return a?Du(r,a):Cu(r,i.virtual||"virtual"===i.bindingKind?"no-actionable-entity":"no-binding")}function zu(e){if(!e)return[];const t=Array.isArray(e.data.entity_id)?e.data.entity_id:[e.data.entity_id];return[...new Set(t)].sort()}function Iu(e){return e?e.operation?e.operation:e.command?{kind:"ha-service",command:e.command}:null:null}const Ou=new Set(["missing","ha-disabled","unavailable"]);function Eu(e,t){const i=Iu(e),n=Iu(t);return!(!i||!n||i.kind!==n.kind)&&("virtual-light"===i.kind&&"virtual-light"===n.kind?i.markerId===n.markerId:"ha-service"===i.kind&&"ha-service"===n.kind&&function(e,t){const i=zu(e),n=zu(t);return i.length===n.length&&i.every((e,t)=>e===n[t])}(i.command,n.command))}function Nu(e,t){const i=e.targets[0]||e.skippedTargets[0],n=[];return"group"===e.kind?e.targets.length&&n.push(t.group(e.targets)):i&&n.push(t.single(i)),e.nextEffect&&e.targets.length&&n.push("group"===e.kind?t.groupCurrentNext(e.targets,e.nextEffect):t.currentNext(e.targets[0],e.nextEffect)),e.skippedTargets.length&&n.push(t.skipped(e.skippedTargets)),!e.command&&e.noneReason&&n.push(t.none(e.noneReason)),n}function Hu(e,t){return e.catch(()=>{}).then(t)}const Lu=e=>{const t=e?.config;return t&&Array.isArray(t.spaces)?t:null},Bu=(e,t)=>"number"==typeof e&&Number.isFinite(e)?e:t;class qu{constructor(e){this.onBodyReplaced=e,this.config=null,this.configRev=0,this.configFingerprint="",this.layout={},this.layoutRev=0,this.layoutFingerprint=""}setConfig(e){const t=this.config;e!==t&&(this.config=e,this.onBodyReplaced?.("_serverCfg",t))}setLayout(e){const t=this.layout;e!==t&&(this.layout=e,this.onBodyReplaced?.("_layout",t))}currentConfigFingerprint(){return this.configFingerprint||cc(this.config)}currentLayoutFingerprint(){return this.layoutFingerprint||cc(this.layout)}adoptResponses(e,t,i,n){const r=Lu(e),o=cc(r),s=o!==this.currentConfigFingerprint();s&&(i(),this.setConfig(r),this.configFingerprint=o),this.configRev=e?.rev??this.configRev;let a=!1;if(void 0!==t){const e=t?.layout??{},i=cc(e);a=i!==this.currentLayoutFingerprint(),a&&(n(),this.setLayout(e),this.layoutFingerprint=i),this.layoutRev=t?.rev??this.layoutRev}return{configChanged:s,layoutChanged:a}}adoptMergedLayout(e,t,i){const n=cc(e),r=n!==cc(this.layout);return r&&(i?.(),this.setLayout(e)),this.layoutFingerprint=n,this.layoutRev=t?.rev??this.layoutRev,r}stageConfigCandidate(e){const t=cc(e);t!==cc(this.config)&&this.setConfig(e),this.configFingerprint=t}acceptConfigWrite(e,t){this.configFingerprint=cc(e),this.configRev=Bu(t?.rev,this.configRev+1)}acceptPairWrite(e,t,i){this.setConfig(e),this.configFingerprint=cc(e),this.setLayout(t),this.layoutFingerprint=cc(t),this.configRev=Bu(i?.config_rev,this.configRev+1),this.layoutRev=Bu(i?.layout_rev,this.layoutRev+1)}noteLayoutRevision(e){"number"==typeof e&&e>this.layoutRev&&(this.layoutRev=e)}stageLocalConfig(e){this.setConfig(e)}stageLocalLayout(e){this.setLayout(e)}seedIdentity(e){Object.assign(this,e)}refreshConfigFingerprint(){this.configFingerprint=cc(this.config)}refreshLayoutFingerprint(){this.layoutFingerprint=cc(this.layout)}beginOptimistic(e,t){return function(e,t,i,n,r){return{previous:JSON.parse(JSON.stringify(e)),previousFingerprint:i,revision:n,attempted:t,attemptedFingerprint:r(t)}}(e,t,this.configFingerprint,this.configRev,cc)}rollbackOptimistic(e){const t=this.config;return!(!t||this.configRev!==e.revision||cc(t)!==e.attemptedFingerprint)&&(this.setConfig(e.previous),this.configFingerprint=e.previousFingerprint,!0)}restoreCached(e){const t=e?.config;return!(!t||!Array.isArray(t.spaces))&&(this.setConfig(t),this.configRev=e?.rev||0,this.configFingerprint=e?.config_fingerprint||cc(t),this.setLayout(e?.layout||{}),this.layoutRev=e?.layout_rev||0,this.layoutFingerprint=e?.layout_fingerprint||cc(this.layout),!0)}snapshot(e){return this.config?(this.refreshConfigFingerprint(),this.refreshLayoutFingerprint(),{config:this.config,rev:this.configRev,config_fingerprint:this.configFingerprint,layout:this.layout,layout_rev:this.layoutRev,layout_fingerprint:this.layoutFingerprint,virtual_lights:e}):null}}async function ju(e,t){const i=t.isCurrent??(()=>!0);if(!i())return{status:"superseded"};const{cfgResp:n,layResp:r}=t,o=e._adoption,s=Lu(n),a=null!=n&&cc(s)!==o.currentConfigFingerprint()||null!=r&&cc(r.layout??{})!==o.currentLayoutFingerprint();if(a){const t=await e._signer.prepareImage(e.hass,e._candidateBackdrop(s));if(!i())return{status:"superseded"};if(!t)return e._continuity.note("asset-failed"),e._scheduleLoadRetry(!0),{status:"asset-wait"}}if(!i())return{status:"superseded"};a&&e._continuity.hasCompleteFrame&&"steady"===e._continuity.state&&e._beginContinuityCandidate(t.reason,!0),t.beforeAdopt?.();const l=e._space;return function(e,t,i){const n=e._adoption,r=!!n.config,{configChanged:o,layoutChanged:s}=n.adoptResponses(t??{},i,()=>{e._geometryHistory.clear(),e._devicePositionHistory.clear(),e._cancelDeviceDrag(),e._pendingPhysicalWrites.clear(),e._clearRoomFocus(!0),e._cancelCameraTransition(!1),r&&e._clearGeometryGesture()},()=>{e._cancelCameraTransition(!1),e._devicePositionHistory.clear(),e._cancelDeviceDrag()});if(o&&e._seedDecorStyle(n.config),t&&("virtual_lights"in t||"config"in t)){const i=Lh(e._virtualLights,t.virtual_lights,n.configRev,"virtual_lights"in t);Bh(i)!==Bh(e._virtualLights)&&(e._virtualLights=i,e._capturedSnapshotVirtual="")}e._canOptimizeUndo=!(!t?.can_optimize_undo&&!i?.can_optimize_undo),e._adoptConfigCapabilities(t),e._undoKind=t?.undo_kind||i?.undo_kind||null,"boolean"==typeof t?.can_write&&(e._serverCanWrite=t.can_write),o&&e._continuity.note("config-candidate",{configRev:n.configRev}),s&&e._continuity.note("layout-candidate",{layoutRev:n.layoutRev})}(e,n,r),"reload"===t.profile&&(e._syncDecorAssets(s).catch(()=>{}),e._adoptInitialSpace(e._model,!0),e._resumePendingNavMode(),e._cacheSnapshot()),t.afterAdopt?.(),{status:"adopted",spaceChanged:e._space!==l}}const Wu=(e,t)=>e.connection===t.connection&&e.userId===t.userId&&e.route===t.route,Uu=e=>"number"==typeof e&&Number.isFinite(e)?e:null;class Gu{constructor(){this.sequence=0,this.currentSequence=0,this.lifecycle=0,this.observedHighWater=null,this.context=null}observeContext(e){this.context?Wu(this.context,e)||(this.context={...e},this.invalidateLifecycle()):this.context={...e}}invalidateLifecycle(){this.lifecycle+=1,this.currentSequence=++this.sequence,this.observedHighWater=null}observeRevision(e,t,i){this.observeContext(i);const n=Uu(e);if(null===n)return null;const r=Uu(t)??Number.NEGATIVE_INFINITY;return n<=Math.max(r,this.observedHighWater??Number.NEGATIVE_INFINITY)?null:(this.observedHighWater=n,Object.freeze({sequence:this.currentSequence,lifecycle:this.lifecycle,context:{...i},observedRevision:n}))}isReservationCurrent(e,t,i){this.observeContext(t);const n=Uu(i)??Number.NEGATIVE_INFINITY;return e.sequence===this.currentSequence&&e.lifecycle===this.lifecycle&&Wu(e.context,t)&&e.observedRevision===this.observedHighWater&&e.observedRevision>n}begin(e){this.observeContext(e.context),e.force&&this.invalidateLifecycle();const t=++this.sequence;return this.currentSequence=t,Object.freeze({sequence:t,lifecycle:this.lifecycle,force:e.force,context:{...e.context},baselineRevision:e.baselineRevision,baselineFingerprint:e.baselineFingerprint})}isCurrent(e){this.observeContext(e.context);const t=e.claim;return e.connected&&(t.force||!e.writePending)&&t.sequence===this.currentSequence&&t.lifecycle===this.lifecycle&&Wu(t.context,e.context)&&t.baselineRevision===e.baselineRevision&&t.baselineFingerprint===e.baselineFingerprint}}const Vu=e=>{const t=e.hass,i=t?.user?.id;return{connection:t?.connection??null,userId:"string"==typeof i?i:null,route:location.pathname}};async function Ku(e,t=!1,i){let n=null;const r=e._configReloadAuthority;if(!t){if(void 0!==i&&(n=r.observeRevision(i,e._cfgRev,Vu(e)),!n))return;if(e._saveConfigDebounced.pending()&&e._saveConfigDebounced.flush(),e._cfgWriting)return clearTimeout(e._reloadRetry),void(e._reloadRetry=window.setTimeout(()=>{n&&!r.isReservationCurrent(n,Vu(e),e._cfgRev)||Ku(e,!1)},400))}const o=r.begin({force:t,context:Vu(e),baselineRevision:e._cfgRev,baselineFingerprint:e._adoption.currentConfigFingerprint()}),s=()=>((e,t)=>e._configReloadAuthority.isCurrent({claim:t,context:Vu(e),connected:e.isConnected,baselineRevision:e._cfgRev,baselineFingerprint:e._adoption.currentConfigFingerprint(),writePending:e._saveConfigDebounced.pending()||e._cfgWriting}))(e,o);let a=!1;try{const t=await e._getAuthoritativeConfig();if(!s())return;const i=await e._adoptAuthoritative({cfgResp:t,reason:"config-reload",profile:"reload",isCurrent:s,afterAdopt:()=>{e._regSignature="",e._maybeRebuildDevices()}});if("superseded"===i.status)return;if(a=!0,"adopted"!==i.status)return;i.spaceChanged&&e._restoreZoom(),e.requestUpdate()}catch(t){if(!s())return;a=!0,e._showToast(e._t("toast.cfg_reload_failed",{err:e._errText(t)}))}finally{(a||s())&&(e._continuityDataReady=!0,e.requestUpdate())}}const Yu=e=>!!e&&e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]);function Xu(e,t=5,i=5){return Oo(e.cm,t,i)/2}function Zu(e,t,i=1,n=5,r=5,o=0){const s=e.host;if(!s||"partition"!==s.kind||"string"!=typeof s.id||!s.id)return{resolved:null,reason:"invalid-host"};const a=t.find(e=>e.id===s.id);if(!a)return{resolved:null,reason:"missing-partition"};if(!Yu(a.a)||!Yu(a.b)||!Number.isFinite(s.t)||s.t<0||s.t>1)return{resolved:null,reason:"invalid-position"};const l=a.b[0]-a.a[0],c=a.b[1]-a.a[1],h=Math.hypot(l,c),d=Number(e.length)*i;if(!(h>1e-9&&d>0&&Number.isFinite(d)))return{resolved:null,reason:"invalid-length"};const u=s.t*h;if(u-d/2h-o+1e-9)return{resolved:null,reason:"does-not-fit"};const p=l/h,_=c/h;let m=180*Math.atan2(c,l)/Math.PI;return m>=90?m-=180:m<-90&&(m+=180),{reason:null,resolved:{opening:e,host:s,partition:a,center:[a.a[0]+l*s.t,a.a[1]+c*s.t],angle:m,length:d,depth:Oo(a.cm,n,r),t:s.t,axis:{a:[a.a[0],a.a[1]],b:[a.b[0],a.b[1]],ux:p,uy:_,length:h}}}}function Ju(e,t,i=1,n=5,r=5){return Zu(e,t,i,n,r,0)}function Qu(e,t,i=1,n=5,r=5){const o=e.host,s="partition"===o?.kind?t.find(e=>e.id===o.id):void 0;if(!s)return Ju(e,t,i,n,r);const a=Zu(e,t,i,n,r,Xu(s,n,r));return"does-not-fit"===a.reason?{resolved:null,reason:"does-not-fit-jamb"}:a}function ep(e,t){return!e||(e.length!==t.length||e.host?.kind!==t.host?.kind||e.host?.id!==t.host?.id||e.host?.t!==t.host?.t)}function tp(e){const{center:t,length:i,axis:n,host:r}=e,o=i/2;return{hostId:r.id,a:[t[0]-n.ux*o,t[1]-n.uy*o],b:[t[0]+n.ux*o,t[1]+n.uy*o],depth:e.depth}}function ip(e,t=!1){const i=t?1:-1,n=e.depth/2;return{ox:-e.axis.uy*i*n,oy:e.axis.ux*i*n,cm:e.partition.cm,side:i}}function np(e,t,i){return e.flatMap(e=>!Yu(e.a)||!Yu(e.b)||Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])<=1e-9?[]:[{roomId:"",a:[e.a[0],e.a[1]],b:[e.b[0],e.b[1]],key:`partition:${e.id}`,kind:"outer",cm:e.cm,open:!1,half:Oo(e.cm,t,i)/2,partitionHost:{kind:"partition",id:e.id}}])}function rp(e,t,i){const{center:n,length:r,axis:o}=e,s=r/2,a=t.flatMap(e=>{if(!e.kind||e.open)return[];const t=e.b[0]-e.a[0],r=e.b[1]-e.a[1],a=Math.hypot(t,r);if(!(a>i))return[];const l=t/a,c=r/a;if(Math.abs(o.ux*c-o.uy*l)>1e-6)return[];if(Math.abs((n[0]-e.a[0])*c-(n[1]-e.a[1])*l)>i)return[];const h=e=>(e[0]-n[0])*o.ux+(e[1]-n[1])*o.uy,d=h(e.a),u=h(e.b),p=Math.max(-s,Math.min(d,u)),_=Math.min(s,Math.max(d,u));return _>=p-i?[[p,_]]:[]});if(!a.length)return!1;a.sort((e,t)=>e[0]-t[0]||e[1]-t[1]);let l=-s;for(const[e,t]of a){if(e>l+i)return!1;if(l=Math.max(l,t),l>=s-i)return!0}return!1}function op(e,t,i=1e-9){const n=e.length/(2*e.axis.length),r=e.t-n,o=e.t+n;return t.some(t=>{if(t.host.id!==e.host.id||t.opening.id===e.opening.id)return!1;const n=t.length/(2*t.axis.length);return Math.max(r,t.t-n)ha-icon{align-self:start;color:var(--hp-accent);}.version-recovery-copy{min-width:0;display:flex;flex-direction:column;gap:var(--sp-2);font-size:var(--fs-m);line-height:1.35;}.version-recovery-copy>span{color:var(--hp-muted);}.version-recovery-versions{display:flex;flex-wrap:wrap;gap:var(--sp-2) var(--sp-5);}.version-recovery-versions span,.version-recovery-versions b{overflow-wrap:anywhere;}.version-recovery-reload{min-height:44px;white-space:normal;}@keyframes hp-version-recovery-in{from{opacity:0;}to{opacity:1;}}@keyframes hp-version-recovery-out{from{opacity:1;}to{opacity:0;}}@media (max-width:520px){.version-recovery-card{grid-template-columns:auto minmax(0,1fr);}.version-recovery-reload{grid-column:1 / -1;width:100%;}}@keyframes fixedfloor-spin{to{transform:rotate(360deg);}}.spacer{flex:1;}.bootveil{position:absolute;inset:0;z-index:40;display:flex;align-items:center;justify-content:center;background:var(--hp-bg,#16212e);opacity:1;transition:opacity 0.15s ease;pointer-events:none;}.bootveil.off{opacity:0;}.bootveil .boothouse{position:static;width:56px;height:56px;fill:var(--hp-accent);opacity:0.85;animation:hp-boot-pulse 1.3s ease-in-out infinite;}@keyframes hp-boot-pulse{0%,100%{opacity:0.3;transform:scale(0.94);}50%{opacity:0.9;transform:scale(1);}}@media (prefers-reduced-motion:reduce){.bootveil .boothouse{animation:none;opacity:0.7;}.version-recovery.phase-visible,.version-recovery.phase-leaving{animation:none;}}@keyframes hp-pulse-short{0%{transform:scale(1);opacity:0.55;}70%{opacity:0.22;}100%{transform:scale(var(--ripple-scale,1.5));opacity:0;}}@keyframes hp-pulse-short-b{0%{transform:scale(1);opacity:0.55;}70%{opacity:0.22;}100%{transform:scale(var(--ripple-scale,1.5));opacity:0;}}@keyframes hp-pulse-continuous{0%{transform:scale(1);opacity:0.55;}65%{opacity:0.18;}100%{transform:scale(var(--ripple-scale,1.5));opacity:0;}}@keyframes hp-pulse-alarm{0%{transform:scale(1);opacity:0.72;}100%{transform:scale(1.5);opacity:0;}}@keyframes hp-slide-left{0%{transform:translateX(4%);opacity:0.72;}100%{transform:translateX(0);opacity:1;}}@keyframes hp-slide-right{0%{transform:translateX(-4%);opacity:0.72;}100%{transform:translateX(0);opacity:1;}}@keyframes hp-sunfade-in{from{opacity:0;}to{opacity:1;}}@keyframes hp-sunfade-out{from{opacity:1;}to{opacity:0;}}.sr-only{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0,0,0,0) !important;white-space:nowrap !important;border:0 !important;}.toast{position:fixed;pointer-events:none;left:50%;bottom:22px;transform:translateX(-50%);background:var(--hp-bg);border:1px solid var(--hp-accent);color:var(--hp-txt);padding:var(--sp-4) var(--sp-6);border-radius:var(--rad-l);font-size:var(--fs-m);box-shadow:var(--shadow-2);z-index:120;max-width:90vw;}`,o`.fixedfloor-loading{animation:fixedfloor-spin 1.1s linear infinite;}.fixedfloor-error p{max-width:42rem;margin:0;overflow-wrap:anywhere;}@media (prefers-reduced-motion:reduce){.fixedfloor-loading{animation:none;}.radar-target{transition:none;}}.stage.noplan{background:#ffffff;}.stage.mode-plan,.stage.mode-devices,.stage.mode-decor{background:#ffffff;}.stage{position:relative;width:100%;container-type:inline-size;overflow:hidden;touch-action:none;background:var(--ha-card-background,var(--card-background-color,#111));}.zoomwrap{position:absolute;inset:0;z-index:1;}.stage.mode-transition,.stage.mode-transition .zoomwrap{transition:none !important;}.stage.mode-transition .hp-view-only-layer,.stage.mode-transition .hp-editor-only-layer{pointer-events:none;will-change:opacity;}.stage.mode-transition .hp-paper{fill:var(--hp-mode-paper) !important;}.hp-day-cycle-env{position:absolute;inset:0;z-index:0;overflow:hidden;pointer-events:none;isolation:isolate;}.hp-day-cycle-bg{position:absolute;inset:0;opacity:0;overflow:hidden;transition:opacity 1100ms cubic-bezier(.22,.61,.36,1);}.hp-day-cycle-bg.active{opacity:1;}.hp-day-cycle-sun{position:absolute;left:var(--hp-day-cycle-sun-x);top:var(--hp-day-cycle-sun-y);width:clamp(140px,25cqw,250px);height:clamp(140px,25cqw,250px);transform:translate(-50%,-50%);border-radius:50%;filter:blur(10px);opacity:var(--hp-day-cycle-sun-opacity);transition:left 1100ms cubic-bezier(.22,.61,.36,1),top 1100ms cubic-bezier(.22,.61,.36,1),opacity 1100ms cubic-bezier(.22,.61,.36,1);}.stage.mode-transition .hp-day-cycle-env{transition:none;}.stage.daycycle .hp-paperg,.stage.daycycle.hp-safe-daycycle-outline .hp-paper-outline-svg,.hp-static-stage.daycycle .hp-paper-outline-svg{filter:drop-shadow(0 0 1px var(--hp-day-cycle-outline-near)) drop-shadow(0 0 5px var(--hp-day-cycle-outline-mid)) drop-shadow(0 0 10px var(--hp-day-cycle-outline-far));will-change:filter;transition:filter 1100ms cubic-bezier(.22,.61,.36,1);}.stage.daycycle.hp-safe-daycycle-outline .hp-paperg{filter:none;will-change:auto;transition:none;}.hp-static-stage.daycycle .hp-paperg{filter:none;will-change:auto;transition:none;}.stage.daycycle.hp-safe-daycycle-outline .hp-paper-outline-svg{transition:none;}.stage.daycycle.hp-safe-daycycle-outline .plan-svg{will-change:transform;}@media (prefers-reduced-motion:reduce){.hp-day-cycle-bg,.hp-day-cycle-sun,.stage.daycycle .hp-paperg,.stage.daycycle.hp-safe-daycycle-outline .hp-paper-outline-svg,.hp-static-stage.daycycle .hp-paper-outline-svg{transition:none;}}.sunlayer{pointer-events:none;}.compass{touch-action:none;cursor:grab;user-select:none;}.compass:active{cursor:grabbing;}.stage.hpboot .zoomwrap,.stage.hpboot .zoombadge{visibility:hidden;}.stage.hpsettle{transition:height 0.25s ease;}@media (prefers-reduced-motion:reduce){.stage.hpsettle{transition:none;}}.zoomctl{display:inline-flex;gap:var(--sp-1);background:rgba(127,127,127,0.12);border-radius:var(--rad-m);padding:var(--sp-1);}.zoomctl .zb{border:none;padding:var(--sp-3) var(--sp-4);}.zoomctl .zb[disabled]{opacity:0.4;pointer-events:none;}.projection-toggle{min-width:44px;min-height:44px;justify-content:center;padding:var(--sp-3);}.header-action{min-width:44px;min-height:44px;justify-content:center;padding:var(--sp-3);}.homearrow{position:absolute;z-index:12;transform:translate(-50%,-50%);width:40px;height:40px;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;background:var(--card-background-color,var(--hp-bg));color:var(--hp-accent);border:1px solid var(--hp-accent);opacity:0.9;padding:0;}.homearrow ha-icon{--mdc-icon-size:22px;line-height:1;}.zoombadge{position:absolute;z-index:12;left:var(--sp-4);bottom:var(--sp-4);background:var(--card-background-color,var(--hp-bg));opacity:0.92;color:var(--hp-txt);border:1px solid var(--hp-accent);border-radius:var(--rad-m);padding:var(--sp-1) var(--sp-4);font-size:var(--fs-s);font-weight:600;pointer-events:none;}.zoomwrap>svg{position:absolute;inset:0;width:100%;height:100%;display:block;}.plan-svg{z-index:1;}.hp-paper-outline-svg{z-index:0;overflow:visible;pointer-events:none;visibility:hidden;}.stage.hp-safe-daycycle-outline .hp-paper-outline-svg{visibility:visible;}.hp-static-stage .hp-paper-outline-svg{visibility:visible;}.iso-underlay-svg{z-index:0;overflow:visible;}.iso-shadows-svg{z-index:3;overflow:visible;}.iso-walls-svg{z-index:4;overflow:visible;}.iso-overlays-svg{z-index:5;overflow:visible;}.iso-underlay-svg,.iso-shadows-svg,.iso-walls-svg,.iso-overlays-svg,.iso-underlay,.iso-shadows,.iso-walls,.iso-openings{pointer-events:none;}.iso-side-hi{stop-color:#b9bdbe;}.iso-side-lo{stop-color:#969c9f;}.iso-top-hi{stop-color:#fafaf7;}.iso-top-lo{stop-color:#e2e4e2;}.iso-wall-side{fill:url(#hp-iso-wall-side) #a8acae;stroke:#92989b;stroke-width:0.7;vector-effect:non-scaling-stroke;}.iso-wall-top{fill:url(#hp-iso-wall-top) #f3f3f1;stroke:#d7d9d8;stroke-width:0.8;vector-effect:non-scaling-stroke;}.iso-material-texture{fill:url(#hp-iso-wall-texture);stroke:none;opacity:0.12;pointer-events:none;}.iso-floor-texture{fill:url(#hp-iso-floor-texture);opacity:0.1;}.iso-texture-mark{fill:rgba(36,43,47,0.34);}.iso-texture-line{fill:none;stroke:rgba(36,43,47,0.24);stroke-width:0.55;}.iso-floor-side{fill:#858b8d;stroke:#71787b;stroke-width:0.7;vector-effect:non-scaling-stroke;}.iso-opening-panel{fill:#d7d9d7;fill-opacity:0.96;stroke:#7f878b;stroke-width:0.9;vector-effect:non-scaling-stroke;}.iso-opening-panel.iso-window{fill:#dfeff4;fill-opacity:0.72;stroke:#8aa7b1;}.iso-opening-panel.iso-material-reveal{fill:#c7cbca;stroke:#8b9294;}.iso-opening-panel.iso-material-matte-leaf{fill:#a6abad;stroke:none;}.iso-opening-panel.iso-opening-leaf-edge,.iso-opening-panel.iso-opening-leaf-top{fill:#8d9497;}.iso-opening-panel.iso-material-light-frame,.iso-opening-panel.iso-material-light-sill{fill:#fffef8;fill-opacity:0.94;stroke:#b3b5ae;}.iso-opening-panel.iso-material-light-window,.iso-opening-panel.iso-material-glass-side{fill:#c9e4f3;fill-opacity:0.88;stroke:#8fb4c7;}.iso-opening-panel.iso-material-glass-top{fill:#e3f2fa;fill-opacity:0.96;stroke:#9fc4d5;}.iso-ambient-shadow{fill:rgba(15,21,25,0.22);filter:url(#hp-iso-ambient-shadow);}.stage.theme-dark .iso-side-hi{stop-color:#4c555a;}.stage.theme-dark .iso-side-lo{stop-color:#343c40;}.stage.theme-dark .iso-top-hi{stop-color:#687176;}.stage.theme-dark .iso-top-lo{stop-color:#50585d;}.stage.theme-dark .iso-wall-side{stroke:#30373b;}.stage.theme-dark .iso-wall-top{stroke:#7b858a;}.stage.theme-dark .iso-floor-side{fill:#2d3438;stroke:#20272a;}.stage.theme-dark .iso-opening-panel{fill:#626b70;stroke:#899399;}.stage.theme-dark .iso-opening-panel.iso-window{fill:#75919b;stroke:#abc6ce;}.stage.theme-dark .iso-opening-panel.iso-material-reveal{fill:#454e52;stroke:#727d82;}.stage.theme-dark .iso-opening-panel.iso-material-matte-leaf{fill:#626a6e;stroke:none;}.stage.theme-dark .iso-opening-panel.iso-opening-leaf-edge,.stage.theme-dark .iso-opening-panel.iso-opening-leaf-top{fill:#4b5458;}.stage.theme-dark .iso-opening-panel.iso-material-light-frame,.stage.theme-dark .iso-opening-panel.iso-material-light-sill{fill:#e8e7df;stroke:#a9aca7;}.stage.theme-dark .iso-opening-panel.iso-material-light-window,.stage.theme-dark .iso-opening-panel.iso-material-glass-side{fill:#8fbfd5;stroke:#bad9e6;}.stage.theme-dark .iso-opening-panel.iso-material-glass-top{fill:#c9e6f2;stroke:#d9eef6;}.stage.theme-dark .iso-ambient-shadow{fill:rgba(0,0,0,0.34);}.stage.theme-dark .iso-texture-mark{fill:rgba(255,255,255,0.24);}.stage.theme-dark .iso-texture-line{stroke:rgba(255,255,255,0.18);}@media (prefers-color-scheme:dark){.stage:not(.theme-light) .iso-side-hi{stop-color:#4c555a;}.stage:not(.theme-light) .iso-side-lo{stop-color:#343c40;}.stage:not(.theme-light) .iso-top-hi{stop-color:#687176;}.stage:not(.theme-light) .iso-top-lo{stop-color:#50585d;}.stage:not(.theme-light) .iso-wall-side{stroke:#30373b;}.stage:not(.theme-light) .iso-wall-top{stroke:#7b858a;}.stage:not(.theme-light) .iso-floor-side{fill:#2d3438;stroke:#20272a;}.stage:not(.theme-light) .iso-opening-panel{fill:#626b70;stroke:#899399;}.stage:not(.theme-light) .iso-opening-panel.iso-window{fill:#75919b;stroke:#abc6ce;}.stage:not(.theme-light) .iso-opening-panel.iso-material-reveal{fill:#454e52;stroke:#727d82;}.stage:not(.theme-light) .iso-opening-panel.iso-material-matte-leaf{fill:#626a6e;stroke:none;}.stage:not(.theme-light) .iso-opening-panel.iso-opening-leaf-edge,.stage:not(.theme-light) .iso-opening-panel.iso-opening-leaf-top{fill:#4b5458;}.stage:not(.theme-light) .iso-opening-panel.iso-material-light-frame,.stage:not(.theme-light) .iso-opening-panel.iso-material-light-sill{fill:#e8e7df;stroke:#a9aca7;}.stage:not(.theme-light) .iso-opening-panel.iso-material-light-window,.stage:not(.theme-light) .iso-opening-panel.iso-material-glass-side{fill:#8fbfd5;stroke:#bad9e6;}.stage:not(.theme-light) .iso-opening-panel.iso-material-glass-top{fill:#c9e6f2;stroke:#d9eef6;}.stage:not(.theme-light) .iso-ambient-shadow{fill:rgba(0,0,0,0.34);}.stage:not(.theme-light) .iso-texture-mark{fill:rgba(255,255,255,0.24);}.stage:not(.theme-light) .iso-texture-line{stroke:rgba(255,255,255,0.18);}}@media (forced-colors:active){.iso-wall-side,.iso-wall-top,.iso-floor-side,.iso-opening-panel{fill:Canvas;stroke:CanvasText;forced-color-adjust:auto;}.iso-ambient-shadow,.iso-material-texture{display:none;}}@supports not (filter:blur(1px)){.iso-ambient-shadow,.iso-material-texture{display:none;}}.hp-paper{fill:var(--ha-card-background,var(--card-background-color,#111));stroke:none;}.stage.noplan .hp-paper,.stage.mode-plan .hp-paper,.stage.mode-devices .hp-paper,.stage.mode-decor .hp-paper{fill:#ffffff;}.room{transition:0.12s;cursor:default;stroke-linejoin:round;stroke-linecap:round;}.stage.mode-view .room{cursor:pointer;}.room.overlay{fill:transparent;stroke:transparent;stroke-width:calc(2px * var(--hp-cell-visual-scale,1));}:host([data-pointer-hover]) .stage.mode-view .room.overlay:not(.styled):hover{stroke:var(--hp-accent);stroke-opacity:1;}.room.yard{fill:rgba(75,140,90,0.14);stroke:#4b8c5a;stroke-width:calc(2px * var(--hp-cell-visual-scale,1));}:host([data-pointer-hover]) .stage.mode-view .room.yard:not(.styled):hover{stroke:var(--hp-accent);stroke-opacity:1;}.room.styled{stroke:var(--room-stroke,transparent);stroke-opacity:var(--room-stroke-op,0);stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));fill:var(--room-fill,transparent);fill-opacity:var(--room-fill-op,0);}.glow-base-layer,.glow-base-tunnels,.glow-pools-frame,.glow-pools,.glow-spot{pointer-events:none;}.glow-pools-frame,.glow-pools,.glow-spot{isolation:isolate;}.glow-pools.blend-screen .glow-spot{mix-blend-mode:screen;}.glow-spot{opacity:1;transition:opacity 500ms ease;}.glow-spot.is-entering,.glow-spot.is-leaving{opacity:0;}@media (prefers-reduced-motion:reduce){.glow-spot{transition:none;}}:host([data-pointer-hover]) .stage.mode-view .room.styled:hover{stroke:var(--hp-accent);stroke-opacity:1;}.op-leaf{transition:transform 0.6s ease;}.op-arc{stroke-width:calc(1.5px * var(--hp-cell-visual-scale,1));transition:stroke-dashoffset 0.6s ease;}.op-outline{fill:none;stroke:var(--hp-accent);stroke-width:calc(1.5px * var(--hp-cell-visual-scale,1));opacity:0;transition:opacity 0.15s;pointer-events:none;}:host([data-pointer-hover]) .stage.markup g.opening:hover .op-outline{opacity:0.9;}.op-hit{fill:transparent;pointer-events:none;cursor:default;}.stage.markup .op-hit{pointer-events:auto;cursor:grab;touch-action:none;}.stage.markup .op-hit:active{cursor:grabbing;}.stage.markup .opening.orphan{pointer-events:auto;cursor:pointer;color:var(--error-color,#db4437);}.stage.markup .opening.orphan circle{fill:var(--hp-bg);stroke:currentColor;stroke-width:calc(2px * var(--hp-cell-visual-scale,1));}.stage.markup .opening.orphan text{fill:currentColor;font-weight:800;font-size:calc(12px * var(--hp-cell-visual-scale,1));pointer-events:none;}.stage.markup.tool-resize .op-hit{pointer-events:none;cursor:default;}.stage.mode-view .oplock{pointer-events:auto;cursor:pointer;}.stage.projection-iso.mode-view .oplock::before{content:'';position:absolute;left:50%;top:50%;width:max(44px,100%);height:max(44px,100%);transform:translate(-50%,-50%);border-radius:50%;pointer-events:auto;}@media (prefers-reduced-motion:reduce){.op-leaf,.op-arc{transition:none;}}.roomlabel{pointer-events:none;position:absolute;transform:translate(-50%,-50%);font-size:calc(var(--rl-icon-size,var(--icon-size,2.5cqw)) * 0.5 * var(--rl-scale,1) * var(--rl-font,1) * var(--rl-space,1));font-weight:700;letter-spacing:0.04em;white-space:nowrap;cursor:grab;user-select:none;z-index:1;display:flex;flex-direction:column;align-items:center;gap:0.15em;text-align:center;}.rlname{display:inline-flex;align-items:center;gap:0.25em;font-size:calc(1em * var(--rl-name,1));}.zoomwrap.slide-left{animation:hp-slide-left 0.18s cubic-bezier(0.2,0.7,0.2,1);}.zoomwrap.slide-right{animation:hp-slide-right 0.18s cubic-bezier(0.2,0.7,0.2,1);}@media (prefers-reduced-motion:reduce){.zoomwrap.slide-left,.zoomwrap.slide-right{animation:none;}}.rlgearbtn{--gear-h:calc(var(--icon-size,2.5cqw) * 0.77);position:absolute;transform:translate(-50%,-50%);display:inline-flex;align-items:center;gap:0.35em;height:var(--gear-h);padding:0 calc(var(--gear-h) * 0.38);border:0;border-radius:999px;background:var(--hp-accent);color:var(--text-primary-color,#fff);font:inherit;font-size:calc(var(--gear-h) * 0.42);font-weight:600;line-height:1;white-space:nowrap;cursor:pointer;pointer-events:auto;opacity:0.92;box-shadow:var(--shadow-1);z-index:2;}.rlgearbtn{transition:opacity 0.15s,filter 0.15s;}:host([data-pointer-hover]) .rlgearbtn:hover{opacity:1;filter:brightness(1.18);}.rlgearbtn ha-icon{--mdc-icon-size:calc(var(--gear-h) * 0.55);display:inline-flex;}.rlgear{--mdc-icon-size:0.9em;display:inline-flex;margin-right:0.2em;opacity:0.6;cursor:pointer;pointer-events:auto;}:host([data-pointer-hover]) .rlgear:hover{opacity:1;}.rlgo{--mdc-icon-size:0.85em;display:inline-flex;opacity:0.55;}.stage.mode-view .rlgo{pointer-events:auto;cursor:pointer;}:host([data-pointer-hover]) .stage.mode-view .rlgo:hover{opacity:1;}.roomlabel .rlmetrics{position:absolute;top:calc(100% + 0.15em);left:50%;transform:translateX(-50%);white-space:nowrap;display:flex;align-items:center;gap:0.55em;font-size:calc(0.75em * var(--rl-meta,1));font-weight:600;letter-spacing:0.02em;opacity:0.9;}.roomlabel .rlm{display:inline-flex;align-items:center;gap:0.12em;}.roomlabel .rlm ha-icon{--mdc-icon-size:1.05em;display:inline-flex;}.roomlabel .rlm.lit{opacity:1;}.rlhandle{display:none;position:absolute;width:9px;height:9px;border-radius:2px;background:var(--hp-accent);border:1px solid var(--card-background-color,#fff);z-index:2;}.rlhandle.tl{left:-6px;top:-6px;cursor:nwse-resize;}.rlhandle.br{right:-6px;bottom:-6px;cursor:nwse-resize;}.rlhandle.tr{right:-6px;top:-6px;cursor:nesw-resize;}.rlhandle.bl{left:-6px;bottom:-6px;cursor:nesw-resize;}:host([data-pointer-hover]) .stage.markup .roomlabel:hover .rlhandle{display:block;}.stage.markup .roomlabel{pointer-events:auto;}.stage.mode-view .roomlabel{pointer-events:auto;cursor:pointer;border-radius:0.2em;}.stage.projection-iso.mode-view .roomlabel{box-sizing:border-box;min-width:44px;min-height:44px;justify-content:center;text-shadow:none;filter:none;-webkit-text-stroke:0 transparent;color:#303936 !important;}.stage.projection-iso.mode-view .dev,.stage.projection-iso.mode-view .oplock{z-index:2;}.stage.projection-iso.theme-dark.mode-view .roomlabel{color:#f2f0e8 !important;}@media (prefers-color-scheme:dark){.stage.projection-iso:not(.theme-light).mode-view .roomlabel{color:#f2f0e8 !important;}}.stage.mode-view .roomlabel:focus-visible{outline:2px solid var(--hp-accent);outline-offset:4px;}.roomlabel:active{cursor:grabbing;}.measurelayer{position:absolute;inset:0;pointer-events:none;}.alignline{stroke:var(--hp-accent);stroke-width:calc(1.2px * var(--hp-cell-visual-scale,1));stroke-dasharray:calc(4px * var(--hp-cell-visual-scale,1)) calc(4px * var(--hp-cell-visual-scale,1));pointer-events:none;opacity:0.9;}.aligndot{fill:var(--hp-accent);pointer-events:none;}.measurelabel.on45{color:#4bd28f;border-color:#4bd28f;}.measurelabel{position:absolute;transform:translate(12px,-150%);font-size:var(--fs-s);font-weight:600;padding:1px var(--sp-3);border-radius:var(--rad-s);background:rgba(0,0,0,0.72);color:#fff;white-space:nowrap;pointer-events:none;user-select:none;z-index:3;}.measurelabel.opdimension{transform:translate(calc(-50% + var(--op-label-shift-x,0px)),calc(-50% + var(--op-label-shift-y,-12px)));border:1px solid var(--hp-open,#ff9800);}.decorlayer .dshape{pointer-events:none;}.stage.mode-decor .decorlayer .dshape{pointer-events:visiblePainted;cursor:pointer;}.stage.mode-decor.dtool-select .decorlayer .dshape{cursor:move;}.stage.mode-decor.dtool-line .decorlayer .dshape,.stage.mode-decor.dtool-rect .decorlayer .dshape,.stage.mode-decor.dtool-ellipse .decorlayer .dshape,.stage.mode-decor.dtool-text .decorlayer .dshape,.stage.mode-decor.dtool-furniture .decorlayer .dshape,.stage.mode-decor.dtool-image .decorlayer .dshape,.stage.mode-decor.dtool-backdrop .decorlayer .dshape{pointer-events:none;}.stage.mode-decor.dtool-furniture,.stage.mode-decor.dtool-image{cursor:copy;}.stage.mode-decor.dtool-select .decorlayer .dimage,.stage.mode-decor.dtool-erase .decorlayer .dimage,.stage.mode-decor.dtool-select .decorlayer .dimage-missing,.stage.mode-decor.dtool-erase .decorlayer .dimage-missing{pointer-events:bounding-box;}.decorlayer .dimage-missing rect{fill:rgba(127,127,127,0.12);stroke:var(--hp-accent);stroke-dasharray:8 5;vector-effect:non-scaling-stroke;}.decorlayer .dimage-missing path{fill:none;stroke:var(--hp-accent);vector-effect:non-scaling-stroke;}.decorlayer .decor-image-placement-preview{opacity:0.65;}.stage.mode-decor.dtool-text .decorlayer .dshape.dtext,.stage.mode-decor.dtool-select .decorlayer .dshape.dtext,.stage.mode-decor.dtool-erase .decorlayer .dshape.dtext{pointer-events:visiblePainted;pointer-events:bounding-box;}.stage.mode-decor.dtool-text .decorlayer .dshape.dtext{cursor:text;}.decorlayer .derasehit{fill:none;stroke:transparent;stroke-width:16px;stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke;pointer-events:none;}.stage.mode-decor.dtool-erase .decorlayer .derasehit{pointer-events:stroke;}.decorlayer .dselecthit{fill:none;stroke:transparent;stroke-width:16px;stroke-linecap:round;vector-effect:non-scaling-stroke;pointer-events:none;}.stage.mode-decor.dtool-select .decorlayer .dselecthit{pointer-events:stroke;cursor:move;}.stage.mode-decor .decorlayer .dshape.dfurniturehit{fill:none;stroke:transparent;pointer-events:none;}.stage.mode-decor.dtool-select .decorlayer .dshape.dfurniturehit{pointer-events:stroke;cursor:move;}.decorlayer .dsel{filter:drop-shadow(0 0 3px var(--hp-accent));}.decorlayer .ddraft{stroke-dasharray:calc(6px * var(--hp-cell-visual-scale,1)) calc(5px * var(--hp-cell-visual-scale,1));pointer-events:none;}.decorlayer .furniture-placement-preview{opacity:0.55;pointer-events:none;}.decorlayer text{font-weight:600;user-select:none;dominant-baseline:middle;text-anchor:middle;}.stage.mode-decor{outline:2px solid #26a69a;outline-offset:-2px;}.bdframe .bdbox{fill:none;stroke:var(--hp-accent);stroke-width:2;stroke-dasharray:10 7;vector-effect:non-scaling-stroke;pointer-events:none;opacity:0.9;}.bdframe .bdhandle{fill:transparent;stroke:none;pointer-events:all;touch-action:none;}.bdframe .bdknob{fill:var(--hp-accent);stroke:#fff;stroke-width:1;vector-effect:non-scaling-stroke;pointer-events:none;}:host([data-pointer-hover]) .bdframe .bdhandle:hover + .bdknob{fill:#fff;stroke:var(--hp-accent);}.bdframe .bd-nwse{cursor:nwse-resize;}.bdframe .bd-nesw{cursor:nesw-resize;}.stage.mode-decor.bdgrab{cursor:grab;}.stage.mode-decor.bdgrabbing,.stage.mode-decor.bdgrabbing .bdframe .bdhandle{cursor:grabbing;}.measurelabel.bdmeasure{transform:translate(-50%,-50%);border:1px solid var(--hp-accent);}.dtframe .dtbox{fill:none;stroke:var(--hp-accent);stroke-width:1.5;stroke-dasharray:7 5;vector-effect:non-scaling-stroke;pointer-events:none;opacity:0.85;}.dtframe .dtstem,.bdframe .dtstem{stroke:var(--hp-accent);stroke-width:1.5;vector-effect:non-scaling-stroke;pointer-events:none;opacity:0.85;}.dtframe .dthandle{fill:transparent;stroke:none;pointer-events:all;touch-action:none;}.dtframe .dtknob{fill:var(--hp-accent);stroke:#fff;stroke-width:1;vector-effect:non-scaling-stroke;pointer-events:none;}:host([data-pointer-hover]) .dtframe .dthandle:hover + .dtknob{fill:#fff;stroke:var(--hp-accent);}.dtframe .dt-nwse{cursor:nwse-resize;}.dtframe .dt-nesw{cursor:nesw-resize;}.dtframe .dtrot{cursor:grab;}.dtframe .dt-ew{cursor:ew-resize;}.dtframe .dt-ns{cursor:ns-resize;}.dtfurnitureframe .dtrot{cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M18.4 7.2A8 8 0 1 0 20 12' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'/%3E%3Cpath d='m15.5 3.8 3.2 3.5-4.6.8' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 12 12,grab;}.dtfurnitureframe .dtrot:active{cursor:grabbing;}.dtframe .dtendpoint{cursor:crosshair;}.bdframe .dtrot{cursor:grab;}.dtarea{resize:vertical;min-height:3.4em;font:inherit;line-height:1.35;}.stage.mode-decor.dtool-line,.stage.mode-decor.dtool-rect,.stage.mode-decor.dtool-ellipse,.stage.mode-decor.dtool-text{cursor:crosshair;}.stage.mode-decor.dtool-erase,.stage.mode-decor.dtool-erase .decorlayer .dshape{cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg transform='rotate(-45 12 12)'%3E%3Crect x='7' y='2' width='10' height='18' rx='2' fill='%23fff' stroke='%23111' stroke-width='1.5'/%3E%3Cpath d='M7 13h10v5a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2z' fill='%23ff9f43' stroke='%23111' stroke-width='1.5'/%3E%3C/g%3E%3C/svg%3E") 5 22,pointer;}.stage.mode-decor .room{pointer-events:none;}.stage.mode-decor .devlayer,.stage.mode-decor .devlayer *,.stage.mode-decor .dev::before{pointer-events:none;}.stage .room,.stage .devlayer,.stage .opening,.stage .room-outline,.stage .wallbodies,.stage .opening-tunnels,.stage .glow-base-layer,.stage .glow-pools-frame,.stage .zero-walls{opacity:var(--hp-mode-architecture-opacity,1);}.opening-preview{opacity:0.5;pointer-events:none;}.opening-preview[data-kind="passage"]{opacity:1;}.passage-preview-cut{fill:var(--wall-fill,#ffffff);fill-opacity:0.35;stroke:none;pointer-events:none;}.passage-preview-boundary{stroke:var(--hp-open,#ff9800);stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));pointer-events:none;}.opening-preview .op-leaf,.opening-preview .op-arc{transition:none;}.opening-preview-dot{fill:var(--hp-open,#ff9800);pointer-events:none;}.opening-dimensions,.opening-dimension{pointer-events:none;}.opening-dimension-line,.opening-dimension-tick{fill:none;stroke:var(--hp-open,#ff9800);stroke-width:1.5;vector-effect:non-scaling-stroke;pointer-events:none;}.opening-dimension-tick{stroke-width:2;}.stage.edit .room{pointer-events:none;}.stage.markup{cursor:crosshair;}.stage.markup.tool-merge,.stage.markup.tool-split.pickstage,.stage.markup.tool-delroom{cursor:pointer;}.stage.markup.tool-wallthick{cursor:default;}.stage.markup.tool-wallthick.wallhot{cursor:pointer;}.wallbody-fill{fill:var(--wall-fill,#ffffff);fill-opacity:var(--wall-fill-op,1);fill-rule:evenodd;stroke:none;pointer-events:none;}.wallbody{fill:url(#hp-wall-hatch);fill-rule:evenodd;stroke:var(--room-stroke,var(--hp-muted));stroke-width:calc(0.6px * var(--hp-cell-visual-scale,1));pointer-events:none;}.wallbody.solid{fill:none;}.wallthick-hover{fill:var(--accent-color,#03a9f4);fill-opacity:0.38;stroke:var(--accent-color,#03a9f4);stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));stroke-linejoin:round;stroke-linecap:round;pointer-events:none;}.wallthick-hover.isopen{fill:var(--error-color,#f44336);stroke:var(--error-color,#f44336);}.zero-wall{stroke:var(--zero-wall-stroke,var(--hp-muted));stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));stroke-dasharray:calc(7px * var(--hp-cell-visual-scale,1)) calc(7px * var(--hp-cell-visual-scale,1));stroke-linecap:butt;pointer-events:none;opacity:0.9;}.zero-walls.solid .zero-wall{stroke-dasharray:none;}.room.noedge{stroke-opacity:0 !important;}.room-outline{fill:none;stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));stroke-linejoin:round;stroke-linecap:round;pointer-events:none;}.room-outline.outlined{stroke:rgba(62,166,255,0.55);stroke-opacity:1;}.room-hover-fill{fill:#000;fill-opacity:0.22;pointer-events:none;}.room-hover-halo{fill:none;stroke:var(--hp-accent);stroke-opacity:0.28;stroke-width:calc(8px * var(--hp-cell-visual-scale,1));stroke-linejoin:round;stroke-linecap:round;pointer-events:none;}.room-hover-outline{fill:none;stroke:var(--hp-accent);stroke-width:calc(3px * var(--hp-cell-visual-scale,1));stroke-linejoin:round;stroke-linecap:round;pointer-events:none;}.stage.markup .room{pointer-events:none;}.stage.markup .devlayer .dev{display:none;}.stage.mode-plan{outline:2px solid #ffc14d;outline-offset:-2px;}.stage.mode-devices{outline:2px solid var(--hp-accent);outline-offset:-2px;}.room.outlined{stroke:rgba(62,166,255,0.55);fill:rgba(62,166,255,0.06);}.room.picked{stroke:#ffc14d;stroke-width:calc(3px * var(--hp-cell-visual-scale,1));fill:rgba(255,193,77,0.25);}.griddot{fill:var(--hp-accent);opacity:0.35;stroke:rgba(0,0,0,0.35);stroke-width:0.4;}.griddot.major{opacity:0.5;stroke-width:0;}.seg{stroke:var(--hp-accent);stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));stroke-linecap:round;stroke-linejoin:round;}.pathline{stroke:#ffc14d;stroke-width:calc(3px * var(--hp-cell-visual-scale,1));fill:none;stroke-linecap:round;stroke-linejoin:round;}.preview{stroke:#ffc14d;stroke-width:calc(2px * var(--hp-cell-visual-scale,1));stroke-dasharray:calc(6px * var(--hp-cell-visual-scale,1)) calc(5px * var(--hp-cell-visual-scale,1));opacity:0.7;}.active-axis{stroke:#ffc14d;stroke-width:2;stroke-linecap:round;vector-effect:non-scaling-stroke;pointer-events:none;}.active-vertex{fill:#ffc14d;stroke:#171006;stroke-width:2;vector-effect:non-scaling-stroke;pointer-events:none;}.wall-repair-preview{stroke:#d93025;stroke-width:4;stroke-linecap:round;stroke-dasharray:5 4;vector-effect:non-scaling-stroke;pointer-events:none;}.drawwall-preview-fill{fill:var(--wall-fill,#ffffff);fill-opacity:calc(var(--wall-fill-op,1) * 0.55);fill-rule:evenodd;stroke:none;pointer-events:none;}.drawwall-preview{fill:url(#hp-wall-hatch);fill-opacity:0.55;fill-rule:evenodd;stroke:var(--accent-color,#03a9f4);stroke-width:calc(0.5px * var(--hp-cell-visual-scale,1));stroke-opacity:0.7;pointer-events:none;}.drawwall-zero-preview{fill:none;stroke:var(--accent-color,#03a9f4);stroke-width:calc(3px * var(--hp-cell-visual-scale,1));stroke-linecap:butt;stroke-linejoin:round;opacity:0.72;pointer-events:none;}.drawwall-zero-preview.dashed{stroke-dasharray:calc(7px * var(--hp-cell-visual-scale,1)) calc(7px * var(--hp-cell-visual-scale,1));}.vertex{fill:#ffc14d;stroke:#4a2800;stroke-width:calc(1px * var(--hp-cell-visual-scale,1));}.vertex.first{fill:#4bd28f;stroke:#04121f;}.plan-snap-overlay,.plan-snap-overlay *,.hidden-wall-diagnostic,.hidden-wall-diagnostic *{pointer-events:none;}.plan-snap-line,.hidden-wall-line{fill:none;stroke:color-mix(in srgb,var(--hp-accent) 82%,white 18%);stroke-width:1;stroke-linecap:round;opacity:0.92;}.plan-snap-node,.hidden-wall-node{fill:var(--ha-card-background,var(--card-background-color,#fff));stroke:color-mix(in srgb,var(--hp-accent) 88%,#07131c 12%);stroke-width:1;vector-effect:non-scaling-stroke;}.plan-snap-node.active{fill:#ffc14d;stroke:#171006;stroke-width:2;}.plan-snap-node.active.dynamic{fill:#4bd28f;stroke:#04121f;}.plan-snap-node.conflict{fill:#fff;stroke:#d93025;stroke-width:3;}@media (prefers-color-scheme:dark){.plan-snap-line{stroke:color-mix(in srgb,var(--hp-accent) 72%,white 28%);}.hidden-wall-line{stroke:color-mix(in srgb,var(--hp-accent) 72%,white 28%);}.plan-snap-node,.hidden-wall-node{fill:#17242c;stroke:#9bdcf5;}.plan-snap-node.active{fill:#ffc14d;stroke:#fff4d6;}.plan-snap-node.active.dynamic{fill:#4bd28f;stroke:#eafff4;}}@media (forced-colors:active){.plan-snap-line,.hidden-wall-line{stroke:CanvasText;opacity:1;forced-color-adjust:auto;}.plan-snap-node,.hidden-wall-node{fill:Canvas;stroke:CanvasText;forced-color-adjust:auto;}.plan-snap-node.active,.plan-snap-node.active.dynamic{fill:Highlight;stroke:HighlightText;forced-color-adjust:auto;}}.sunlayer{animation:hp-sunfade-in 2s linear both;}.sunlayer.out{animation:hp-sunfade-out 2s linear both;}@media (prefers-reduced-motion:reduce){.sunlayer,.sunlayer.out{animation:none;}.sunlayer.out{opacity:0;}}.devlayer{position:absolute;inset:0;pointer-events:none;z-index:6;}.radar-target{position:absolute;width:8px;height:8px;box-sizing:border-box;transform:translate(-50%,-50%);border-radius:50%;background:var(--success-color,#43a047);border:2px solid var(--primary-text-color,#1f1f1f);box-shadow:0 0 0 1px color-mix(in srgb,var(--card-background-color,#fff) 80%,transparent);pointer-events:none;z-index:0;}.radar-target.smooth{transition:left 200ms linear,top 200ms linear;}.radar-ranges{position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none;z-index:0;}.radar-ranges path,.radar-ranges polyline{fill:none;stroke:var(--success-color,#43a047);stroke-width:2px;stroke-dasharray:5 4;vector-effect:non-scaling-stroke;opacity:0.72;}.radar-ranges .radar-zone{fill:color-mix(in srgb,var(--success-color,#43a047) 8%,transparent);stroke:var(--success-color,#43a047);stroke-width:2px;vector-effect:non-scaling-stroke;opacity:0.8;}.stage.mode-devices .dev{cursor:grab;}.stage.mode-devices .dev:active{cursor:grabbing;}.physical-hit{fill:transparent;stroke:transparent;pointer-events:none;cursor:grab;}.stage.tool-select .physical-hit{pointer-events:all;}.physical-hit:active{cursor:grabbing;}line.physical-hit{cursor:pointer;}.physical-hit.selected{fill:rgba(255,193,77,0.24);stroke:transparent;}line.physical-hit.selected{stroke:transparent;}.physical-drag{fill:rgba(255,193,77,0.38);stroke:#ffc14d;stroke-width:2.5;vector-effect:non-scaling-stroke;pointer-events:none;}.physical-chrome{pointer-events:none;}.physical-chrome .frame,.physical-chrome .stem{fill:none;stroke:#ffc14d;stroke-width:2;vector-effect:non-scaling-stroke;}.physical-chrome .frame{fill:rgba(255,193,77,0.22);}.physical-chrome polyline.frame{fill:none;}.physical-chrome .move-dot{fill:#ffc14d;stroke:#24262d;stroke-width:1.5;vector-effect:non-scaling-stroke;}.physical-chrome .rotate-handle{fill:#24262d;stroke:#ffc14d;stroke-width:2.5;vector-effect:non-scaling-stroke;pointer-events:all;cursor:crosshair;}.drawwall.invalid input{border-color:var(--error-color,#db4437);}.drawwall .rangehint{margin-inline-start:4px;font-size:0.78em;opacity:0.72;}.drawwall.invalid .rangehint{color:var(--error-color,#db4437);opacity:1;}.stage.markup.tool-partition,.stage.markup.tool-column{cursor:crosshair;}.rszhandle{fill:transparent;stroke:none;pointer-events:all;cursor:grab;touch-action:none;}.rszhandle:active{cursor:grabbing;}.rszhandle.disabled,.rszhandle.disabled:active{cursor:not-allowed;}.rszicon{pointer-events:none;}.rszicon path{fill:none;stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke;}.rszhalo{stroke:var(--hp-bg);stroke-width:6;}.rszink{stroke:var(--hp-accent);stroke-width:2;}:host([data-pointer-hover]) .rszhandle:hover + .rszicon .rszink{stroke-width:3;}.rszicon.disabled{opacity:0.38;}:host([data-pointer-hover]) .rszhandle.disabled:hover + .rszicon .rszink{stroke-width:2;}.rszmeasurelayer,.rszmeasurelayer *{pointer-events:none;}.rszmeasurehalo,.rszmeasureink,.rszleader{fill:none;stroke-linecap:round;vector-effect:non-scaling-stroke;}.rszmeasurehalo{stroke:var(--hp-bg);stroke-width:7px;opacity:0.9;}.rszmeasureink{stroke:var(--hp-accent);stroke-width:3px;}.rszleader{stroke:var(--hp-accent);stroke-width:2px;opacity:0.95;}.measurelabel.dmeasure{transform:translate(-50%,-160%);}.measurelabel.rszarea{transform:translate(calc(-50% + var(--rsz-label-x,0px)),calc(-50% + var(--rsz-label-y,0px)));background:rgba(0,0,0,0.6);border:1px solid var(--hp-accent);}.measurelabel.furnmeasure{transform:translate(-50%,-50%);border:1px solid var(--hp-accent);}.alignmsg{margin:0 0 8px;font-size:13px;line-height:1.45;}`,o`.dev ha-icon{position:relative;z-index:1;}.device-pulse{position:absolute;left:50%;top:50%;width:var(--dev-size);height:var(--dev-size);transform:translate(-50%,-50%);pointer-events:none;z-index:0;}.device-pulse i{position:absolute;inset:0;border-radius:50%;border:2px solid var(--ripple-color,var(--hp-accent));opacity:0;}.device-pulse.short i{animation:hp-pulse-short 1.1s cubic-bezier(.22,.61,.36,1) 1 forwards;}.device-pulse.short i:nth-child(2){animation-delay:1.1s;}.device-pulse.short i:nth-child(3){animation-delay:2.2s;}.device-pulse.short.gen2 i{animation-name:hp-pulse-short-b;}.device-pulse.continuous i:nth-child(n + 2),.device-pulse.alarm i:nth-child(n + 3){display:none;}.device-pulse.continuous i:first-child{animation:hp-pulse-continuous 3.6s cubic-bezier(.45,.05,.55,.95) infinite;}.device-pulse.alarm i{border-width:3px;border-color:#F0410C;animation:hp-pulse-alarm 2.4s cubic-bezier(.22,.61,.36,1) infinite;}.device-pulse.alarm i:nth-child(2){animation-delay:1.2s;}.activity-dot{position:absolute;right:8%;bottom:8%;width:18%;height:18%;min-width:4px;min-height:4px;border-radius:50%;background:var(--ripple-color,var(--hp-accent));border:1px solid color-mix(in srgb,var(--hp-bg) 82%,transparent);pointer-events:none;z-index:3;}.kioskdots{position:absolute;left:50%;bottom:var(--sp-5);transform:translateX(-50%);display:flex;gap:var(--sp-4);z-index:5;pointer-events:none;}.kdot{width:9px;height:9px;border-radius:50%;background:var(--hp-muted);opacity:0.55;}.kdot.on{background:var(--hp-accent);opacity:1;}.dev.valonly{width:var(--dev-size,var(--icon-size,2.5cqw));}.dev.valonly .device-core{width:max-content;min-width:var(--dev-size,var(--icon-size,2.5cqw));padding-inline:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.16);border-radius:calc(var(--dev-size,var(--icon-size,2.5cqw)) / 2);}.dev .valtext{overflow:visible;font-size:calc(var(--dev-size,var(--icon-size,2.5cqw)) * var(--value-font-scale,.45));font-weight:600;white-space:nowrap;}@media (prefers-reduced-motion:reduce){.device-pulse{display:none;}}.dev .newdot{position:absolute;top:calc(var(--dev-size,var(--icon-size,2.5cqw)) * -0.12);right:calc(var(--dev-size,var(--icon-size,2.5cqw)) * -0.12);width:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.34);height:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.34);border-radius:50%;background:#f0301f;border:2px solid var(--card-background-color,var(--hp-bg));pointer-events:none;z-index:2;}.dev{position:absolute;--dev-size:calc(var(--device-base-size,2.25cqw) * var(--dev-scale,1));--device-shell-size:calc(var(--dev-size) * 1.26875);--device-shell-inset:calc(var(--dev-size) * 0.134375);--device-shell-stroke-ratio:0.01875;--device-shell-border-width:max(1px,calc(var(--dev-size) * var(--device-shell-stroke-ratio)));--device-core-bg:var(--card-background-color,#fff);--device-core-fg:var(--primary-text-color,#252525);--device-core-bg:light-dark(#fff,#252525);--device-core-fg:light-dark(#252525,#fff);--device-face-bg:var(--device-core-bg);--device-face-fg:var(--device-core-fg);--device-shell-base-stroke:light-dark(#BCBCBC,rgb(37 37 37 / 75%));--device-shell-stroke:var(--device-shell-base-stroke);--device-shell-shadow:0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .05) rgb(37 40 45 / 12%),0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%);--device-core-inset-shadow:0 0 0 0 transparent;--device-ring-color:transparent;--device-ring-width:0px;width:var(--dev-size);height:var(--dev-size);margin:calc(var(--dev-size) / -2) 0 0 calc(var(--dev-size) / -2);border:0;background:transparent;display:block;color:var(--device-core-fg);cursor:pointer;pointer-events:none;transition:opacity 0.2s;box-shadow:none;outline:none;z-index:auto;}.dev.theme-light{--device-core-bg:#fff;--device-core-fg:#000;--device-shell-base-stroke:#BCBCBC;--device-shell-stroke:var(--device-shell-base-stroke);--device-shell-shadow:0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .05) rgb(37 40 45 / 12%),0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%);--device-core-inset-shadow:0 0 0 0 transparent;}.dev.theme-dark{--device-core-bg:#252525;--device-core-fg:#fff;--device-shell-base-stroke:rgb(37 37 37 / 75%);--device-shell-stroke:var(--device-shell-base-stroke);--device-shell-shadow:0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .0375) rgb(37 40 45 / 12%),0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%);--device-core-inset-shadow:inset 0 calc(var(--dev-size) * 0.0125) calc(var(--dev-size) * 0.0125) rgb(255 255 255 / 70%);}.dev::before{content:'';position:absolute;left:50%;top:50%;width:max(44px,var(--device-shell-size));height:max(44px,var(--device-shell-size));transform:translate(-50%,-50%);border-radius:50%;pointer-events:auto;z-index:1;}.device-shell{position:absolute;box-sizing:border-box;display:flex;align-items:center;gap:calc(var(--dev-size) * 0.1);padding:0;min-width:var(--dev-size);min-height:var(--dev-size);border:0;background:transparent;box-shadow:none;transition:opacity .2s;pointer-events:none;z-index:2;}.device-shell-frame{position:absolute;z-index:0;box-sizing:border-box;inset:calc(var(--device-shell-inset) / -1);border:var(--device-shell-border-width) solid var(--device-shell-stroke);border-radius:9999px;background:transparent;box-shadow:var(--device-shell-shadow);transition:border-color .15s,opacity .2s;pointer-events:auto;backdrop-filter:none;}.device-shell:not(.with-values){left:0;top:0;}.device-shell:not(.with-values):not(.text-shell) .device-shell-frame{border-radius:50%;}.device-shell.with-values.pos-right{left:0;top:50%;transform:translateY(-50%);}.device-shell.with-values.pos-left{right:0;top:50%;transform:translateY(-50%);flex-direction:row-reverse;}.device-shell.with-values.pos-bottom{left:50%;top:0;transform:translateX(-50%);flex-direction:column;}.device-shell.with-values.pos-top{left:50%;bottom:0;transform:translateX(-50%);flex-direction:column-reverse;}.device-core{position:relative;z-index:1;box-sizing:border-box;flex:0 0 auto;width:var(--dev-size);height:var(--dev-size);display:flex;align-items:center;justify-content:center;border-radius:50%;background:var(--device-face-bg);color:var(--device-face-fg);box-shadow:var(--device-core-inset-shadow),0 0 0 var(--device-ring-width) var(--device-ring-color);line-height:0;transition:background .15s,color .15s,opacity .2s;pointer-events:none;}.device-sections{display:flex;flex-direction:column;align-items:stretch;justify-content:center;gap:calc(var(--dev-size) * .08);min-width:0;pointer-events:none;}.device-shell.pos-top .device-sections,.device-shell.pos-bottom .device-sections{flex-direction:row;}.dev ha-icon{--mdc-icon-size:calc(var(--dev-size,var(--device-base-size,2.25cqw)) * 0.55);display:flex;align-items:center;justify-content:center;line-height:0;}.dev.on{--device-face-bg:#F0A00C;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:#F0A00C;}.dev.theme-light.on{--device-face-fg:#fff;}.dev.theme-dark.on{--device-face-fg:#252525;--device-shell-stroke-ratio:.0375;}.dev.open{--device-face-bg:var(--hp-open);--device-face-fg:light-dark(#fff,#252525);}.dev.theme-light.open{--device-face-fg:#fff;}.dev.theme-dark.open{--device-face-fg:#252525;}.dev.lock-locked{--device-face-bg:#66D17A;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:#66D17A;}.dev.theme-light.lock-locked{--device-face-fg:#fff;}.dev.theme-dark.lock-locked{--device-face-fg:#252525;--device-shell-stroke-ratio:.025;}.dev.lock-unlocked{--device-face-bg:#F0410C;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:#F0410C;}.dev.theme-light.lock-unlocked{--device-face-fg:#fff;}.dev.theme-dark.lock-unlocked{--device-face-fg:#252525;--device-shell-stroke-ratio:.025;}:host([data-pointer-hover]) .dev:not(.unavail)[data-hp-device-hover]{--device-face-bg:#0C82F0;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:var(--device-shell-base-stroke);}:host([data-pointer-hover]) .dev.theme-light:not(.unavail)[data-hp-device-hover]{--device-face-fg:#fff;}:host([data-pointer-hover]) .dev.theme-dark:not(.unavail)[data-hp-device-hover]{--device-face-fg:#252525;}:host([data-pointer-hover]) .dev[data-hp-device-hover],.dev:focus-visible{z-index:5;}.dev[data-hp-zigbee-topology-endpoint]{z-index:8;}:host([data-pointer-hover]) .dev[data-hp-zigbee-topology-endpoint][data-hp-device-hover]{z-index:8;}.dev.unavail{opacity:0.35;--device-face-bg:#B5BAC1;--device-shell-stroke:var(--device-shell-base-stroke);}.dev.virtual .device-shell-frame{border-style:dashed;}.dev.ghost{opacity:0.6;color:var(--hp-accent);}.dev.ghost .device-shell-frame{border-style:dashed;border-color:var(--hp-accent);box-shadow:none;}.dev.ghost .device-core{background:rgba(62,166,255,0.22);background:color-mix(in srgb,var(--hp-accent) 30%,var(--card-background-color,#1c2530));color:var(--hp-accent);}.dev.ghost.ha-disabled{opacity:0.62;color:var(--secondary-text-color,#9aa0aa);}.dev.ghost.ha-disabled .device-shell-frame{border-color:var(--secondary-text-color,#9aa0aa);}.dev.ghost.ha-disabled .device-core{background:rgba(120,124,134,0.2);background:color-mix(in srgb,var(--secondary-text-color,#9aa0aa) 24%,var(--card-background-color,#1c2530));color:var(--secondary-text-color,#9aa0aa);}.dev .habadge{position:absolute;right:-18%;bottom:-18%;display:grid;place-items:center;width:46%;height:46%;min-width:12px;min-height:12px;border-radius:50%;background:var(--card-background-color,#242832);border:1px solid currentColor;}.dev .habadge ha-icon{width:72%;height:72%;}.dev.sel{--device-ring-color:#F0A00C;--device-ring-width:calc(var(--dev-size) * 0.0375);}.dev:focus-visible{--device-ring-color:#0C82F0;--device-ring-width:calc(var(--dev-size) * 0.0375);}.dev:not(.on):not(.open):not(.alarm):not(.lock-locked):not(.lock-unlocked):not(.unavail):focus-visible{--device-face-fg:#0C82F0;}.dev.alarm,:host([data-pointer-hover]) .dev.alarm[data-hp-device-hover],.dev.alarm:focus-visible{--device-face-bg:#F0410C;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:#F0410C;}.dev.theme-light.alarm{--device-face-fg:#fff;}.dev.theme-dark.alarm{--device-face-fg:#252525;--device-shell-stroke-ratio:.025;}.dev .value-badge{position:relative;z-index:2;box-sizing:border-box;width:max-content;min-width:calc(var(--dev-size,var(--icon-size,2.5cqw)) * .7875);height:calc(var(--dev-size,var(--icon-size,2.5cqw)) * .7875);display:flex;align-items:center;justify-content:center;overflow:visible;background:var(--device-core-bg);border:0;border-radius:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.39375);padding:0 calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.14);font-size:calc(var(--dev-size,var(--icon-size,2.5cqw)) * var(--value-font-scale,.45));font-weight:600;line-height:1;color:var(--device-core-fg);white-space:nowrap;pointer-events:none;}.dev .value-badge.unavailable,.dev .value-badge.missing{opacity:0.66;}.dev .lqi{position:absolute;top:calc(50% + var(--device-shell-size) / 2 + var(--dev-size) * .05);left:50%;transform:translateX(-50%);margin-top:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.05);font-size:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.38);font-weight:600;line-height:1;text-shadow:0 0 3px rgba(0,0,0,0.9),0 0 2px rgba(0,0,0,0.9);white-space:nowrap;pointer-events:none;}.dev .lqi.below-value-badge{margin-top:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.8875);}.temprange{display:inline-flex;align-items:center;gap:var(--sp-3);margin-left:auto;color:var(--hp-muted);font-size:var(--fs-s);}.vacwarn{position:absolute;top:-12%;right:-12%;width:calc(var(--device-base-size,2.25cqw) * 0.42);height:calc(var(--device-base-size,2.25cqw) * 0.42);border-radius:50%;display:flex;align-items:center;justify-content:center;background:light-dark(#fff,#252525);border:1px solid #E5A100;color:#E5A100;z-index:7;pointer-events:none;}.vacwarn ha-icon{--mdc-icon-size:calc(var(--device-base-size,2.25cqw) * 0.32);color:inherit;}.vacpuck{position:absolute;--puck-size:calc(var(--device-base-size,2.25cqw) * 0.8);width:var(--puck-size);height:var(--puck-size);border-radius:50%;transform:translate(-50%,-50%);--vac-core-bg:light-dark(#fff,#252525);--vac-core-fg:light-dark(#252525,#fff);background:var(--vac-core-bg);border:1px solid #BCBCBC;box-shadow:0 1px 2px rgb(37 40 45 / 12%),0 4px 8px -1.07px rgb(37 40 45 / 18%);color:var(--vac-core-fg);display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:6;transition:left 1.2s linear,top 1.2s linear;animation:vacpulse 2.2s ease-out infinite;}.vacpuck.theme-light{--vac-core-bg:#fff;--vac-core-fg:#252525;}.vacpuck.theme-dark{--vac-core-bg:#252525;--vac-core-fg:#fff;}.vacpuck.jump{transition:none;}.vacpuck.stale{opacity:0.45;animation:none;}.vacpuck ha-icon{--mdc-icon-size:calc(var(--puck-size) * 0.68);color:var(--vac-core-fg);display:flex;align-items:center;justify-content:center;line-height:0;width:var(--mdc-icon-size);height:var(--mdc-icon-size);}@keyframes vacpulse{0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--hp-accent) 45%,transparent);}70%{box-shadow:0 0 0 12px transparent;}100%{box-shadow:0 0 0 0 transparent;}}@media (prefers-reduced-motion:reduce){.vacpuck{animation:none;}}.vactrail{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:5;overflow:visible;}.vactrail polyline,.vactrail path{fill:none;stroke-linejoin:round;stroke-linecap:round;vector-effect:non-scaling-stroke;}.vactrail g.prev{opacity:0.4;}.vactrail .case{stroke:rgba(0,0,0,0.4);stroke-width:2.25;}.vactrail .core{stroke:rgba(255,255,255,0.82);stroke-width:0.9;}.devicepreview-empty{min-height:82px;margin:4px 0 14px;padding:var(--sp-4);display:flex;align-items:center;justify-content:center;gap:var(--sp-3);border:1px dashed var(--hp-line);border-radius:var(--rad-m);color:var(--hp-muted);text-align:center;}`,o`.hdr{position:sticky;top:var(--header-height,56px);z-index:20;background:var(--card-background-color,var(--hp-bg));border-radius:var(--ha-card-border-radius,12px) var(--ha-card-border-radius,12px) 0 0;}.tabs{display:flex;gap:var(--sp-2);background:rgba(127,127,127,0.12);padding:var(--sp-2);border-radius:var(--rad-l);flex-wrap:wrap;}.tab{border:0;background:transparent;color:var(--hp-muted);display:inline-flex;align-items:center;padding:var(--sp-3) var(--sp-5);border-radius:var(--rad-m);font-size:var(--fs-m);font-weight:600;cursor:pointer;transition:0.15s;font-family:inherit;}:host([data-pointer-hover]) .tab:hover{color:var(--hp-txt);}.tab.active{background:var(--hp-accent);color:var(--text-primary-color,#fff);}.farhint{position:absolute;left:50%;transform:translateX(-50%);bottom:var(--sp-4);z-index:12;display:flex;align-items:center;gap:var(--sp-2);max-width:calc(100% - var(--sp-8));background:var(--card-background-color,var(--hp-bg));opacity:0.94;color:var(--hp-txt);border:1px solid var(--divider-color,#33404d);border-radius:var(--rad-m);padding:var(--sp-1) var(--sp-3);font-size:var(--fs-s);}.farhint ha-icon{--mdc-icon-size:18px;color:var(--hp-warn,#e2a03f);flex:none;}.farhint span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.dropbtn{display:flex;align-items:center;gap:var(--sp-4);width:100%;text-align:left;border:1px solid var(--hp-muted);border-radius:var(--rad-m);background:transparent;color:var(--hp-txt);padding:var(--sp-4) 10px;cursor:pointer;font-family:inherit;font-size:var(--fs-m);margin-top:var(--sp-3);}.dropbtn .ref{color:var(--hp-muted);font-size:var(--fs-s);margin-left:auto;}.dropbtn ha-icon{--mdc-icon-size:18px;margin-left:var(--sp-2);}.dropbtn.open{border-color:var(--hp-accent);}.droppanel{border:1px solid var(--hp-accent);border-top:none;border-radius:0 0 var(--rad-m) var(--rad-m);padding:var(--sp-3);margin-top:-4px;}.hdr.kioskhide{display:none;}.decorbar .dcolor{width:30px;height:26px;padding:0;border:none;background:none;cursor:pointer;}.decorbar .dwidth{font-family:inherit;font-size:var(--fs-s);border-radius:var(--rad-s);background:var(--hp-bg2,transparent);color:var(--hp-txt);border:1px solid var(--hp-muted);padding:var(--sp-2) var(--sp-3);}.decorbar .bdhint{font-size:var(--fs-s);color:var(--hp-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.decorbar .dfill{display:inline-flex;align-items:center;gap:var(--sp-2);font-size:var(--fs-s);cursor:pointer;}.decorbar .dfill input[type="checkbox"]{width:16px;height:16px;flex:none;margin:0;padding:0;}.decorbar hp-color-opacity{flex:0 0 auto;}.modes{display:inline-flex;gap:var(--sp-1);background:rgba(127,127,127,0.12);border-radius:var(--rad-l);padding:var(--sp-2);}.modetab{display:inline-flex;align-items:center;gap:var(--sp-3);border:0;background:transparent;color:var(--hp-muted);padding:var(--sp-3) 10px;border-radius:var(--rad-m);font-size:var(--fs-m);font-weight:600;cursor:pointer;font-family:inherit;transition:background-color 0.14s ease,color 0.14s ease,transform 0.14s ease;}.modetab:active{transform:scale(0.97);}.modetab ha-icon{--mdc-icon-size:15px;}.tab[data-reorderable]{cursor:grab;}.tab.dragging{cursor:grabbing;opacity:0.55;}.tab.drop-before{box-shadow:inset 2px 0 0 0 var(--primary-color,#03a9f4);}.tab.drop-after{box-shadow:inset -2px 0 0 0 var(--primary-color,#03a9f4);}.modetab .closex{--mdc-icon-size:13px;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;min-width:24px;min-height:24px;margin:-5.5px -5.5px -5.5px -3.5px;opacity:0.75;cursor:pointer;border-radius:var(--rad-s);}:host([data-pointer-hover]) .modetab .closex:hover{opacity:1;}.editbar .barclose{box-sizing:border-box;width:40px;height:40px;padding:0;margin:0;min-width:40px;min-height:40px;justify-content:center;gap:0;line-height:0;}.editbar .barclose ha-icon{flex:none;margin:0;}.modetab.active{background:var(--hp-accent);color:var(--text-primary-color,#fff);}@media (max-width:720px){.modetab .ml{display:none;}}.editbar{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:stretch;border-bottom:1px solid var(--hp-line);font-size:var(--fs-m);}.editbar-tools{display:flex;align-items:center;gap:10px;padding:var(--sp-4) var(--sp-5);flex-wrap:wrap;min-width:0;outline:none;}.editbar-end{display:flex;align-items:center;padding:var(--sp-4) var(--sp-5);border-inline-start:1px solid var(--hp-line);background:var(--card-background-color,var(--hp-bg));position:relative;z-index:2;}.tab .tabedit{--mdc-icon-size:13px;display:inline-flex;align-items:center;margin-left:var(--sp-3);opacity:0.4;}:host([data-pointer-hover]) .tab:hover .tabedit{opacity:0.9;}.tab.tabadd{padding:var(--sp-3) var(--sp-4);}.tab.tabadd ha-icon{--mdc-icon-size:15px;}.rhint{font-size:var(--fs-s);color:var(--hp-muted);margin-bottom:var(--sp-3);}.editorchrome{display:block;height:0;opacity:0;visibility:hidden;overflow:hidden;}.editorchrome:not(.open){pointer-events:none;}.editorchrome.open{height:auto;opacity:1;visibility:visible;overflow:visible;}.editorchrome.transitioning{overflow:hidden;will-change:height;pointer-events:none;}.editorchrome.transitioning .barclose{pointer-events:auto;}.editorchrome-inner{min-height:0;transform-origin:top center;}.editorchrome.transitioning .editorchrome-inner{will-change:opacity;}@media (prefers-reduced-motion:reduce){.modetab{transition:none;}}.editbar .warn{color:#ffc14d;}.editbar .sname{font-weight:600;}.editbar input{width:74px;background:transparent;border:1px solid var(--hp-line);color:var(--hp-txt);border-radius:var(--rad-s);padding:var(--sp-3) var(--sp-4);font-size:var(--fs-m);}.editbar label,.editbar .hint{color:var(--hp-muted);font-size:var(--fs-s);}.editbar .drawwall{display:inline-flex;align-items:center;gap:var(--sp-3);white-space:nowrap;}.editbar .wallsgroup{display:inline-flex;align-items:center;gap:10px;white-space:nowrap;}.editbar .drawwall input{width:4.2em;}.editbar .drawwall .opl{color:var(--hp-muted);font-size:var(--fs-s);}.menuwrap{position:fixed;inset:0;z-index:80;}.menu{position:fixed;background:var(--hp-bg);border:1px solid var(--hp-accent);border-radius:var(--rad-l);box-shadow:var(--shadow-2);min-width:210px;max-width:300px;overflow:hidden;transform:translate(0,8px);}.menu .hd{padding:var(--sp-4) var(--sp-5);font-weight:600;font-size:var(--fs-m);border-bottom:1px solid var(--hp-line);display:flex;align-items:center;gap:var(--sp-3);}.menu .hd ha-icon,.menu .it.all ha-icon{color:var(--hp-accent);--mdc-icon-size:16px;}.menu .it{padding:var(--sp-4) var(--sp-5);font-size:var(--fs-m);cursor:pointer;display:flex;align-items:center;gap:var(--sp-4);}.menu .it ha-icon{--mdc-icon-size:16px;color:var(--hp-muted);}:host([data-pointer-hover]) .menu .it:hover{background:rgba(127,127,127,0.15);}.menu .it.all{color:var(--hp-accent);font-weight:600;}.tip{position:fixed;pointer-events:none;background:var(--hp-bg);border:1px solid var(--hp-accent);color:var(--hp-txt);padding:var(--sp-3) 10px;border-radius:var(--rad-m);font-size:var(--fs-m);box-shadow:var(--shadow-2);z-index:60;max-width:260px;}.tip .m{color:var(--hp-muted);font-size:var(--fs-s);display:block;}`,o`.head{display:flex;align-items:center;gap:10px;padding:10px var(--sp-5);border-bottom:1px solid var(--hp-line);flex-wrap:wrap;}.title{font-size:var(--fs-l);font-weight:600;display:flex;align-items:center;gap:var(--sp-3);white-space:nowrap;}.title ha-icon{color:var(--hp-accent);--mdc-icon-size:18px;}@media (max-width:1100px){.head .count{display:none;}}@media (max-width:620px){.head{gap:var(--sp-3);padding:var(--sp-4) 10px;}.head .title{font-size:var(--fs-m);}}.count{font-size:var(--fs-s);color:var(--hp-muted);}.btn{display:inline-flex;align-items:center;gap:var(--sp-3);border:1px solid var(--hp-line);background:transparent;color:var(--hp-txt);padding:var(--sp-3) 10px;border-radius:var(--rad-m);cursor:pointer;transition:0.15s;font-family:inherit;font-size:var(--fs-m);}.btn ha-icon{--mdc-icon-size:17px;}:host([data-pointer-hover]) .btn:hover{border-color:var(--hp-accent);}.btn.on{background:var(--hp-accent);color:var(--text-primary-color,#fff);border-color:var(--hp-accent);}.btn.ghost{border:none;}.btn[disabled]{opacity:0.5;pointer-events:none;}.recoveryoverlay{position:absolute;inset:0;z-index:75;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--sp-4);padding:var(--sp-6);box-sizing:border-box;background:linear-gradient(var(--ha-card-background,var(--card-background-color,#111)),var(--ha-card-background,var(--card-background-color,#111))),#111;color:var(--primary-text-color,#fff);text-align:center;pointer-events:auto;transition:opacity 0.15s ease;}.recoveryoverlay.phase-entering,.recoveryoverlay.phase-leaving{opacity:0;}.recoveryoverlay.phase-fading-in,.recoveryoverlay.phase-opaque{opacity:1;}.recoveryoverlay ha-icon{--mdc-icon-size:44px;color:var(--hp-accent);}.editorloading{position:absolute;z-index:74;left:50%;top:50%;display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-5);border:1px solid color-mix(in srgb,var(--hp-accent) 45%,transparent);border-radius:999px;background:color-mix(in srgb,var(--ha-card-background,var(--card-background-color,#111)) 92%,transparent);color:var(--primary-text-color);box-shadow:0 6px 22px rgb(0 0 0 / 18%);transform:translate(-50%,-50%);pointer-events:none;animation:editor-loading-in 0.15s ease both;}.editorloading ha-icon{--mdc-icon-size:22px;color:var(--hp-accent);animation:editor-loading-spin 0.9s linear infinite;}@keyframes editor-loading-in{from{opacity:0;transform:translate(-50%,calc(-50% + 4px));}to{opacity:1;transform:translate(-50%,-50%);}}@keyframes editor-loading-spin{to{transform:rotate(360deg);}}@media (prefers-reduced-motion:reduce){.recoveryoverlay,.editorloading,.editorloading ha-icon{transition:none;animation:none;}}.oplock{--oplock-size:calc(var(--icon-size,2.5cqw) * 0.62);--oplock-core-size:calc(var(--oplock-size) / 1.26875);--oplock-stroke-ratio:0.01875;--oplock-stroke-width:max(1px,calc(var(--oplock-core-size) * var(--oplock-stroke-ratio)));--oplock-core-bg:light-dark(#fff,#252525);--oplock-core-fg:light-dark(#252525,#fff);--oplock-shell-stroke:light-dark(#BCBCBC,rgb(37 37 37 / 75%));--oplock-shell-shadow:0 calc(var(--oplock-core-size) * .025) calc(var(--oplock-core-size) * .05) rgb(37 40 45 / 12%),0 calc(var(--oplock-core-size) * .1) calc(var(--oplock-core-size) * .175) calc(var(--oplock-core-size) * -.025) rgb(37 40 45 / 18%);--oplock-core-shadow:0 0 0 0 transparent;pointer-events:none;position:absolute;transform:translate(-50%,-50%);width:var(--oplock-size);height:var(--oplock-size);display:grid;place-items:center;border:0;background:transparent;z-index:1;}.oplock.theme-light{--oplock-core-bg:#fff;--oplock-core-fg:#252525;--oplock-shell-stroke:#BCBCBC;}.oplock.theme-dark{--oplock-core-bg:#252525;--oplock-core-fg:#fff;--oplock-shell-stroke:rgb(37 37 37 / 75%);--oplock-core-shadow:inset 0 calc(var(--oplock-core-size) * .0125) calc(var(--oplock-core-size) * .0125) rgb(255 255 255 / 70%);}.oplock-shell{box-sizing:border-box;width:100%;height:100%;border:var(--oplock-stroke-width) solid var(--oplock-shell-stroke);border-radius:50%;background:transparent;box-shadow:var(--oplock-shell-shadow);display:grid;place-items:center;pointer-events:none;backdrop-filter:none;}.oplock-core{width:var(--oplock-core-size);height:var(--oplock-core-size);border-radius:50%;background:var(--oplock-core-bg);color:var(--oplock-core-fg);box-shadow:var(--oplock-core-shadow);display:grid;place-items:center;pointer-events:none;}.oplock ha-icon{--mdc-icon-size:calc(var(--oplock-core-size) * 0.55);display:flex;line-height:0;}.oplock.locked{--oplock-core-bg:#66D17A;--oplock-core-fg:light-dark(#fff,#252525);--oplock-shell-stroke:#66D17A;}.oplock.theme-light.locked{--oplock-core-fg:#fff;}.oplock.theme-dark.locked{--oplock-core-fg:#252525;--oplock-stroke-ratio:.025;}.oplock.unlocked{--oplock-core-bg:#F0410C;--oplock-core-fg:light-dark(#fff,#252525);--oplock-shell-stroke:#F0410C;}.oplock.theme-light.unlocked{--oplock-core-fg:#fff;}.oplock.theme-dark.unlocked{--oplock-core-fg:#252525;--oplock-stroke-ratio:.025;}.oplock.unknown{--oplock-core-fg:var(--hp-muted);}.btn.lockact{width:100%;justify-content:center;display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-4);}.btn.lockact.warn{color:var(--error-color,#d33);border-color:var(--error-color,#d33);}.oprow{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-3) 0;}.oprow b{margin-left:auto;}.oprow.ok b{color:#66d17a;}.oprow.warn b{color:var(--hp-open);}.ctrlstates{display:flex;flex-direction:column;gap:var(--sp-2);}.ctrlstate{display:inline-flex;align-items:center;gap:var(--sp-3);color:var(--hp-muted);}.ctrlstate.on{color:var(--hp-txt);}.ctrlstate ha-icon{--mdc-icon-size:15px;}.cardpreview{display:flex;flex-direction:column;align-items:center;gap:var(--sp-2);margin:var(--sp-4) 0 var(--sp-1);padding:10px;border:1px dashed var(--hp-muted);border-radius:var(--rad-m);}.cardpreview .cpname{font-weight:700;letter-spacing:0.04em;}.cardpreview .cpmeta{display:inline-flex;align-items:center;gap:0.3em;font-weight:600;opacity:0.85;}.cardpreview .cpmeta ha-icon{--mdc-icon-size:1.05em;}hp-dialog .dfill{display:inline-flex;align-items:center;gap:var(--sp-3);cursor:pointer;}.wallthick-dlg{position:absolute;z-index:40;min-width:200px;transform:translate(-50%,8px);padding:10px 12px;border-radius:10px;background:var(--card-background-color,#fff);box-shadow:0 8px 28px rgba(0,0,0,.22);display:flex;flex-direction:column;gap:8px;pointer-events:auto;}.wallthick-dlg .row{display:flex;align-items:center;gap:8px;}.wallthick-dlg input[type="number"]{width:5.5em;padding:4px 6px;border:1px solid var(--divider-color,#ccc);border-radius:6px;background:var(--input-fill,transparent);color:var(--primary-text-color);}.areasel,.namein{background:var(--hp-bg);border:1px solid var(--hp-line);color:var(--hp-txt);border-radius:var(--rad-s);padding:var(--sp-3) var(--sp-4);font-size:var(--fs-m);font-family:inherit;}.namein{width:130px;}.habindingbanner{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);margin-bottom:var(--sp-4);border:1px solid var(--warning-color,#ff9800);border-radius:var(--rad-m);background:color-mix(in srgb,var(--warning-color,#ff9800) 12%,transparent);color:var(--primary-text-color,#f1f3f6);}.habindingbanner>span{flex:1;min-width:0;}.habindingbanner>ha-icon{color:var(--warning-color,#ff9800);flex:0 0 auto;}.habindingbanner.limited{border-color:var(--secondary-text-color,#9aa0aa);background:color-mix(in srgb,var(--secondary-text-color,#9aa0aa) 10%,transparent);}.habindingbanner.limited>ha-icon{color:var(--secondary-text-color,#9aa0aa);}.srcrow{display:flex;align-items:center;gap:var(--sp-4);font-size:var(--fs-m);cursor:pointer;padding:var(--sp-1) 0;}.dispsection{margin-top:var(--sp-5) !important;padding-top:var(--sp-4);border-top:1px solid var(--hp-line);font-weight:600;color:var(--hp-txt) !important;}.colorrow{display:flex;align-items:center;gap:var(--sp-4);}.colorrow input[type='range']{flex:1;}.colorrow .tempin{width:70px;flex:none;}hp-dialog .body .temprange .tempin{width:56px;flex:none;padding:var(--sp-2) var(--sp-3);}hp-dialog .body .colorrow .tempin{width:72px;flex:none;}.srcrow{flex-wrap:nowrap;}.srcrow ha-switch{flex:none;}.colorrow ha-slider{flex:1;min-width:0;}.srcrow>span:first-of-type{white-space:nowrap;}.colorrow .opl{color:var(--hp-muted);font-size:var(--fs-s);}.colorrow .opv{font-size:var(--fs-s);min-width:34px;text-align:right;}.markerlightgroup{min-width:0;margin:var(--sp-5) 0 0;padding:var(--sp-4);border:1px solid var(--hp-line);border-radius:var(--rad-m);}.markerlightgroup legend{display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-1);padding:0 var(--sp-2);color:var(--hp-txt);font-weight:600;}.markerlightgroup legend>span{min-width:0;overflow-wrap:anywhere;}.markerlightgroup[disabled]>:not(legend){opacity:.62;}.radargroup{display:grid;gap:var(--sp-2);}.radargroup>p{margin:0;}.radargroup>label:not(.srcrow){margin-top:var(--sp-2);}.radarcoordinates{align-items:flex-end;flex-wrap:wrap;}.radarcoordinates>label{display:grid;flex:1 1 92px;gap:var(--sp-1);min-width:0;margin:0;}hp-dialog .body .radarcoordinates .tempin{box-sizing:border-box;width:100%;}.radarinspection{display:grid;gap:6px;padding:10px 12px;border-radius:10px;background:color-mix(in srgb,var(--primary-color) 7%,transparent);}.radarinspection code{overflow-wrap:anywhere;font-size:12px;}.radarsetup{display:grid;gap:10px;margin-top:10px;padding:12px;border:1px solid var(--hp-accent);border-radius:var(--rad-m);background:color-mix(in srgb,var(--secondary-background-color) 88%,transparent);}.radarsetup-head{display:flex;align-items:center;gap:8px;}.radarsetup-head strong{flex:1;}.radarsetup>svg{width:min(100%,460px);aspect-ratio:1;justify-self:center;border-radius:var(--rad-m);background:var(--primary-background-color);touch-action:none;cursor:crosshair;}.radarsetup .room{fill:color-mix(in srgb,var(--hp-accent) 8%,transparent);stroke:var(--divider-color);stroke-width:3;vector-effect:non-scaling-stroke;}.radarsetup .heading{stroke:var(--hp-accent);stroke-width:4;vector-effect:non-scaling-stroke;}.radarsetup .trail{fill:none;stroke:var(--success-color,#43a047);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke;opacity:.55;}.radarsetup g circle{fill:var(--hp-bg);stroke:var(--hp-accent);stroke-width:3;vector-effect:non-scaling-stroke;}.radarsetup g.pending circle{stroke-dasharray:5 4;}.radarsetup g text{fill:var(--hp-txt);font-size:22px;font-weight:700;text-anchor:middle;dominant-baseline:middle;pointer-events:none;}.help-inline-label{display:inline-flex;align-items:center;flex-wrap:wrap;gap:var(--sp-1);}hp-dialog .body .help-inline-label>label{min-width:0;margin-top:0;overflow-wrap:anywhere;}.markerlightgroup .srcrow>span:first-of-type{min-width:0;white-space:normal;overflow-wrap:anywhere;}.planrow{display:flex;align-items:center;gap:10px;}.savedplans{display:flex;flex-direction:column;gap:var(--sp-3);max-height:240px;overflow:auto;margin:var(--sp-3) 0 var(--sp-1);padding:var(--sp-3);border:1px solid var(--hp-line);border-radius:var(--rad-m);background:var(--hp-bg2,rgba(255,255,255,0.03));flex:0 0 auto;min-height:2.6em;}.savedplan{display:flex;align-items:center;gap:10px;}.savedplan.cur{outline:1px solid var(--hp-accent);border-radius:var(--rad-s);}.savedplan img{width:56px;height:40px;object-fit:contain;border:1px solid var(--hp-line);border-radius:var(--rad-s);background:#fff;flex:none;}.savedmeta{display:flex;flex-direction:column;min-width:0;flex:1;}.savedmeta b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.savedmeta .muted{font-size:var(--fs-s);}.savedplan .btn.danger ha-icon{color:#f25a4a;}.savedplan .btn[disabled]{opacity:0.4;pointer-events:none;}.planprev{max-width:120px;max-height:70px;border:1px solid var(--hp-line);border-radius:var(--rad-s);background:#fff;}.planname{font-size:var(--fs-m);max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.planname.muted{color:var(--hp-muted);}.filebtn{cursor:pointer;}.btn.danger{border-color:#b3402a;color:#ff7a5c;}hp-dialog .row .spacer{flex:1;}hp-dialog .body{max-height:66vh;overflow-y:auto;}hp-dialog[form-shell] .body{max-height:none;overflow:visible;padding:16px;box-sizing:border-box;}@media (max-width:480px){hp-dialog[form-shell] .body{padding:12px;}}hp-confirm{display:contents;}hp-dialog .danger-confirm-body{display:flex;flex-direction:column;gap:var(--sp-4);}hp-dialog .danger-confirm-body p{margin:0;line-height:1.45;}hp-dialog .danger-confirm-object{overflow-wrap:anywhere;font-size:var(--fs-l);line-height:1.3;}.curbind{display:flex;align-items:center;gap:var(--sp-3);font-size:var(--fs-m);color:var(--hp-txt);flex-wrap:wrap;}.curbind .ref{color:var(--hp-muted);font-size:var(--fs-s);}.vacbox .vacbtns{display:flex;gap:var(--sp-4);margin:var(--sp-3) 0;flex-wrap:wrap;}.vacdiag{display:grid;gap:4px;margin-bottom:var(--sp-3);}.vacdiag>div{display:flex;justify-content:space-between;gap:var(--sp-5);}.vacdiag>div>span{color:var(--secondary-text-color);}.vacdiag>div>b{text-align:right;overflow-wrap:anywhere;}.vacroute-missing-group{margin-top:var(--sp-4);padding-top:var(--sp-4);border-top:1px solid var(--hp-line);}.vacroute-group-title{margin:0 0 var(--sp-3);color:var(--secondary-text-color);font-size:var(--fs-m);font-weight:600;}.vacroute-missing-group .vacroute-list{margin-top:0;}.vacpicker{margin:var(--sp-3) 0;}.vacsource-warning{display:grid;gap:8px;}.vacsource-warning .btn{justify-self:start;}.vacpicker>summary{display:inline-flex;width:auto;list-style:none;cursor:pointer;}.vacpicker>summary::-webkit-details-marker{display:none;}.vacsource-list{display:grid;gap:6px;margin-top:8px;}.vacsource-list details{padding:6px 0 0;}.vacsource-list details>summary{cursor:pointer;font-weight:600;}.vacsource{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;min-width:0;padding:9px 10px;border:1px solid var(--divider-color);border-radius:10px;color:var(--primary-text-color);background:var(--secondary-background-color);text-align:left;cursor:pointer;}.vacsource.on{border-color:var(--accent-color);box-shadow:inset 3px 0 var(--accent-color);}.vacsource>span:first-child{min-width:0;display:grid;gap:2px;}.vacsource small{color:var(--secondary-text-color);overflow-wrap:anywhere;}.vacsource-meta{color:var(--secondary-text-color);text-align:right;font-size:0.82em;}.vacxcme pre{margin:8px 0 0;white-space:pre-wrap;user-select:text;}.vacfit{position:absolute;inset:0;width:100%;height:100%;z-index:12;overflow:visible;touch-action:none;cursor:grab;pointer-events:auto;}.vacfit:active{cursor:grabbing;}.vacfit polygon{fill:color-mix(in srgb,var(--hp-accent) 16%,transparent);stroke:var(--hp-accent);stroke-width:2;vector-effect:non-scaling-stroke;stroke-dasharray:6 4;}.vacfit text{fill:var(--hp-accent);font-size:26px;text-anchor:middle;dominant-baseline:middle;pointer-events:none;user-select:none;}.furnpalette{display:flex;flex-direction:column;max-height:38vh;border-top:1px solid var(--hp-border,rgba(255,255,255,0.12));background:var(--card-background-color,var(--hp-bg));font-size:0.85em;}.furnhd{display:flex;align-items:center;gap:6px;padding:4px 8px;font-weight:600;opacity:0.9;}.furnhd .spacer{flex:1;}.furnbody{overflow:auto;padding:0 8px 6px;}.furngroup{margin:6px 0 3px;font-size:0.85em;text-transform:uppercase;letter-spacing:0.04em;opacity:0.6;}.furnrow{display:flex;flex-wrap:wrap;gap:4px;}.furnback{min-height:34px;gap:5px;margin:2px 0 4px;}.furnitem{display:flex;flex-direction:column;align-items:center;gap:2px;width:74px;padding:4px 2px;border:1px solid transparent;border-radius:8px;background:rgba(127,127,127,0.08);color:inherit;font:inherit;font-size:0.8em;line-height:1.15;text-align:center;cursor:pointer;}:host([data-pointer-hover]) .furnitem:hover{background:rgba(127,127,127,0.18);}.furnitem.on{border-color:var(--hp-accent);background:rgba(38,166,154,0.18);}.furnprev{width:40px;height:40px;color:var(--primary-text-color,currentColor);}.furncategory{width:92px;min-height:76px;}.furncatprev{width:48px;height:48px;}.furnvariants .furnitem{min-height:74px;}.furnsize{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:6px 8px;border-top:1px solid var(--hp-border,rgba(255,255,255,0.12));}.furnsize label{display:flex;align-items:baseline;gap:3px;opacity:0.8;}.furnsize .furnunit{opacity:0.6;font-size:0.85em;}.furnsize input{width:5.5em;padding:3px 5px;}.furnhint{opacity:0.6;}.imageupload{display:inline-flex;gap:6px;margin:4px 0 8px;cursor:pointer;}.imageupload.disabled{opacity:0.55;pointer-events:none;}.imageupload input{display:none;}.imageassets{align-items:stretch;}.imageempty{padding:12px 6px;}.imageasset{position:relative;}.imageasset .furnitem{width:104px;min-height:92px;}.imageasset img{width:64px;height:54px;object-fit:contain;border-radius:4px;background:repeating-conic-gradient(#ddd 0 25%,#fff 0 50%) 50% / 12px 12px;}.imageasset .furnitem span{max-width:96px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.imageasset .furnitem small{opacity:0.65;font-size:0.72em;}.imageassetdelete{position:absolute;top:0;right:0;min-width:30px;width:30px;min-height:30px;padding:3px;}.imagepropertypreview{display:flex;align-items:center;gap:10px;min-width:0;}.imagepropertypreview img{width:72px;height:54px;object-fit:contain;border-radius:4px;background:repeating-conic-gradient(#ddd 0 25%,#fff 0 50%) 50% / 12px 12px;}.imagepropertypreview span{overflow-wrap:anywhere;}.vacfitdot{fill:var(--hp-accent);pointer-events:none;}.vacfithandle{fill:transparent;stroke:none;cursor:nwse-resize;}.vacfitknob{fill:var(--hp-bg);stroke:var(--hp-accent);stroke-width:2;vector-effect:non-scaling-stroke;pointer-events:none;}.vaccalbar{position:fixed;left:50%;bottom:24px;transform:translateX(-50%);display:flex;gap:var(--sp-5);align-items:center;background:var(--hp-bg);color:var(--hp-txt);border:1px solid var(--hp-accent);border-radius:var(--rad-l);padding:10px var(--sp-5);z-index:60;box-shadow:var(--shadow-2);}.candlist{max-height:160px;overflow-y:auto;border-top:1px solid var(--hp-line);flex:0 0 auto;min-height:2.6em;}.cand{display:flex;justify-content:space-between;gap:var(--sp-4);padding:var(--sp-3) var(--sp-4);cursor:pointer;border-radius:var(--rad-s);font-size:var(--fs-m);}:host([data-pointer-hover]) .cand:hover{background:rgba(127,127,127,0.15);}.cand.sel{background:var(--hp-accent);color:var(--text-primary-color,#fff);}.cand .cs{color:var(--hp-muted);font-size:var(--fs-s);white-space:nowrap;}.opening-entity-candidate{width:100%;border:0;background:transparent;color:inherit;font:inherit;text-align:left;}.opening-entity-candidate.sel{background:var(--hp-accent);color:var(--text-primary-color,#fff);}.opening-entity-empty{cursor:default;}.cand.sel .cs{color:var(--text-primary-color,#fff);opacity:0.85;}.cand.muted{color:var(--hp-muted);cursor:default;}.entlist{display:flex;flex-direction:column;gap:var(--sp-2);margin-bottom:10px;}.entrow{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-3) var(--sp-4);border-radius:var(--rad-m);background:var(--secondary-background-color,rgba(128,128,128,0.12));}.entrow ha-icon{--mdc-icon-size:20px;color:var(--hp-muted);}.entrow.on ha-icon{color:var(--hp-accent);}.entrow .en{flex:1;font-size:var(--fs-m);}.entrow .ev{font-size:var(--fs-m);color:var(--hp-muted);}.entbtn{min-width:74px;min-height:32px;padding:var(--sp-2) var(--sp-5);border:1px solid var(--hp-muted);border-radius:999px;background:transparent;color:var(--hp-txt);font:inherit;font-size:var(--fs-m);cursor:pointer;}.entbtn.on{background:var(--hp-accent);border-color:var(--hp-accent);color:var(--text-primary-color,#fff);font-weight:600;}.inforow{display:flex;gap:10px;font-size:var(--fs-m);margin:var(--sp-2) 0;}.inforow .k{color:var(--hp-muted);min-width:84px;}.inforow a{color:var(--hp-accent);word-break:break-all;}.infodesc{font-size:var(--fs-m);white-space:pre-wrap;margin-top:var(--sp-3);}.infodesc.muted{color:var(--hp-muted);}.pdflist{display:flex;flex-direction:column;gap:var(--sp-2);}.pdf{display:inline-flex;align-items:center;gap:var(--sp-2);color:var(--hp-accent);text-decoration:none;}ha-icon-picker{display:block;}.floorrow{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-3) var(--sp-2);font-size:var(--fs-m);cursor:pointer;}.floorrow .floorlvl{color:var(--hp-muted);font-size:var(--fs-s);border:1px solid var(--hp-line);border-radius:var(--rad-s);padding:0 var(--sp-3);}.rtest{display:flex;align-items:center;gap:var(--sp-4);margin-bottom:var(--sp-4);}.rtest .namein{flex:1;}.rtest ha-icon{color:var(--hp-accent);}.rtesticon{font-size:var(--fs-s);color:var(--hp-muted);}.rrow{display:flex;align-items:center;gap:var(--sp-3);margin:var(--sp-1) 0;}.rrow .rpat{flex:2;}.rrow .ricon{flex:1.4;}.rrow .rpat.bad{border-color:#ff7a5c;}.rrow .rprev{--mdc-icon-size:18px;color:var(--hp-txt);min-width:18px;}.rrow .ract{--mdc-icon-size:16px;color:var(--hp-muted);cursor:pointer;}:host([data-pointer-hover]) .rrow .ract:hover{color:var(--hp-txt);}:host([data-pointer-hover]) .rrow .ract.del:hover{color:#ff7a5c;}.optimize-live{display:grid;justify-items:start;gap:var(--sp-2);margin-bottom:var(--sp-3);}.optimize-live .alignmsg,.optimize-live .rhint{margin-bottom:0;}.optimize-cleanup{min-height:44px;}.optimize-selected{color:var(--hp-txt);}.optimize-details{margin-top:var(--sp-3);color:var(--hp-muted);font-size:var(--fs-s);overflow-wrap:anywhere;}.optimize-details>summary{width:fit-content;color:var(--hp-txt);cursor:pointer;font-weight:600;}.optimize-details>summary:focus-visible{outline:2px solid var(--hp-accent);outline-offset:3px;border-radius:var(--rad-s);}.optimize-details ul{margin:var(--sp-3) 0;padding-inline-start:22px;}.optimize-details li + li{margin-top:var(--sp-1);}.btn.alignall{width:100%;justify-content:center;}.backupactions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-3);}.backupactions .btn{justify-content:center;min-width:0;}.backupupload{display:inline-flex;min-width:0;}.backupupload>.btn{width:100%;justify-content:center;}.backupupload input{display:none;}.backupbody{min-width:0;}.backupplanonly{margin-inline-start:var(--sp-4) !important;align-items:flex-start !important;}.backupplanonly>span:first-of-type{display:grid;gap:2px;white-space:normal;}.backupplanonly small{color:var(--secondary-text-color);line-height:1.35;}.backupplanonlystatus{color:var(--hp-accent) !important;font-weight:700;}.backupfile,.backupsummary,.backupcontent{display:flex;flex-direction:column;min-width:0;gap:var(--sp-1);}.backupfile b,.backupcontent span{overflow-wrap:anywhere;}.backupfile span,.backupsummary span,.backupcontent span{color:var(--hp-muted);font-size:var(--fs-s);}.backupcounts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-2) var(--sp-4);font-size:var(--fs-s);}.backupwarn,.backuperror{border-radius:var(--rad-s);padding:var(--sp-3);font-size:var(--fs-s);line-height:1.45;overflow-wrap:anywhere;}.backupwarn{background:color-mix(in srgb,var(--hp-accent) 12%,transparent);}.backuperror{background:rgba(179,64,42,.16);color:#ff7a5c;}.backupdetails{border:1px solid var(--hp-line);border-radius:var(--rad-s);padding:var(--sp-2) var(--sp-3);font-size:var(--fs-s);}.backupdetails summary{cursor:pointer;font-weight:700;}.backupdetails>div{display:grid;gap:var(--sp-1);padding-block-start:var(--sp-2);}.backupdetails code{overflow-wrap:anywhere;color:var(--hp-muted);}.backupchoices{display:flex;flex-direction:column;gap:var(--sp-2);border:1px solid var(--hp-line);border-radius:var(--rad-s);min-width:0;}.backupchoices label{margin:0 !important;display:flex;gap:var(--sp-2);}.backupconfirm{align-items:flex-start !important;}.backupconfirm>span:first-of-type{min-width:0;white-space:normal;overflow-wrap:anywhere;}@media (max-width:520px){.backupactions,.backupcounts{grid-template-columns:1fr;}}.aboutver{font-size:var(--fs-s);color:var(--hp-muted);margin:var(--sp-2) 0 var(--sp-3);}.aboutlink{display:flex;align-items:center;gap:var(--sp-3);width:fit-content;color:var(--hp-accent);text-decoration:none;font-size:var(--fs-m);padding:var(--sp-1) 0;}:host([data-pointer-hover]) .aboutlink:hover{text-decoration:underline;}.aboutlink ha-icon{--mdc-icon-size:18px;line-height:1;}hp-dialog .supportbody{min-width:0;overflow-x:hidden;gap:var(--sp-5);}.supportsection{display:grid;min-width:0;gap:var(--sp-2);}.supportsection + .supportsection{padding-top:var(--sp-4);border-top:1px solid var(--hp-line);}.supportsection h3{margin:0;color:var(--hp-txt);font-size:var(--fs-m);}.supportlinks,.supportactions{display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-2) var(--sp-4);min-width:0;}.supportform>label:not(.srcrow){margin-top:var(--sp-2);color:var(--hp-muted);font-size:var(--fs-s);}.supportmessage,.supportraw{width:100%;min-width:0;box-sizing:border-box;resize:vertical;border:1px solid var(--hp-line);border-radius:var(--rad-s);padding:var(--sp-3);color:var(--hp-txt);background:color-mix(in srgb,var(--card-background-color,var(--hp-bg)) 92%,var(--hp-txt));font:inherit;}.supportmessage{min-height:120px;background:var(--hp-bg);}.supportraw{min-height:220px;margin-top:var(--sp-2);resize:none;white-space:pre;overflow:auto;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;}.supportattach{min-width:0;align-items:flex-start;margin:var(--sp-2) 0 0 !important;}.supportattach>span:first-of-type{min-width:0;white-space:normal;overflow-wrap:anywhere;}.supportwarning,.supportstatus,.supportupdate{display:flex;align-items:flex-start;gap:var(--sp-2);min-width:0;margin:0;padding:var(--sp-3);border-radius:var(--rad-s);background:color-mix(in srgb,var(--hp-accent) 14%,transparent);overflow-wrap:anywhere;font-size:var(--fs-s);line-height:1.45;}.supportwarning ha-icon,.supportstatus ha-icon,.supportupdate ha-icon{flex:none;color:var(--hp-accent);--mdc-icon-size:20px;}.supportpreview,.supportmanual,.supporterror,.supportsuccess{display:grid;min-width:0;gap:var(--sp-2);padding:var(--sp-3);border:1px solid var(--hp-line);border-radius:var(--rad-s);}.supportsummary{font-weight:600;overflow-wrap:anywhere;}.supporthash{display:grid;min-width:0;gap:var(--sp-1);color:var(--hp-muted);font-size:var(--fs-s);}.supporthash code{overflow-wrap:anywhere;color:var(--hp-txt);}.supportpreview details{min-width:0;}.supportpreview summary{cursor:pointer;color:var(--hp-accent);}.supportprivacy{margin:0 !important;line-height:1.45;}.supporterror{background:color-mix(in srgb,var(--error-color,#db4437) 12%,transparent);border-color:color-mix(in srgb,var(--error-color,#db4437) 45%,var(--hp-line));}.supportsuccess{background:color-mix(in srgb,var(--success-color,#43a047) 12%,transparent);border-color:color-mix(in srgb,var(--success-color,#43a047) 45%,var(--hp-line));}.supportfooter{flex-wrap:wrap;}@media (max-width:520px){hp-dialog .supportbody{padding-inline:var(--sp-4);}hp-dialog .supportfooter{padding-inline:var(--sp-4);}.supportactions .btn,.supportactions .aboutlink{max-width:100%;}}hp-dialog .body{padding:var(--sp-5) var(--sp-6);display:flex;flex-direction:column;gap:var(--sp-3);}hp-dialog .tapconfirm-body{min-width:0;overflow-x:hidden;}hp-dialog .tapconfirm-body p{max-width:100%;min-width:0;margin:0;overflow-wrap:anywhere;white-space:normal;}hp-dialog .tapconfirm-line{color:var(--hp-muted);}hp-dialog .body label{font-size:var(--fs-s);color:var(--hp-muted);margin-top:var(--sp-3);}hp-dialog .body .namein,hp-dialog .body .areasel{width:100%;box-sizing:border-box;}hp-dialog .row{display:flex;justify-content:flex-end;gap:var(--sp-4);width:100%;min-width:0;box-sizing:border-box;padding:var(--sp-5) var(--sp-6);border-top:1px solid var(--hp-line);}hp-dialog>.row[slot='footer'] button{min-height:44px;}hp-dialog .row.dialog-action-footer{align-items:center;justify-content:flex-start;flex-wrap:wrap;row-gap:var(--sp-4);}hp-dialog .dialog-action-group{display:flex;flex:0 1 auto;flex-wrap:wrap;align-items:center;gap:var(--sp-4);max-width:100%;min-width:0;}hp-dialog .dialog-action-group .btn{flex:0 0 auto;min-height:44px;}hp-dialog .dialog-action-danger{margin-right:auto;}hp-dialog .dialog-action-commit{margin-left:auto;justify-content:flex-end;}hp-dialog .row.infofooter{align-items:center;justify-content:flex-start;flex-wrap:wrap;gap:var(--sp-3);}hp-dialog .row.infofooter .btn{flex-shrink:0;}hp-dialog .row.infofooter .infofooter-close{margin-left:auto;}@media (max-width:480px){hp-dialog .row.infofooter{padding:var(--sp-4) var(--sp-5);}}.device-inbox{display:flex;flex-direction:column;gap:var(--sp-4);padding:var(--sp-5) var(--sp-6);min-width:0;}.device-inbox-dialog{--hp-dialog-wide-width:920px;}.device-inbox-head{display:grid;grid-template-columns:minmax(180px,1fr) auto;align-items:center;gap:var(--sp-4);}.device-inbox-search{width:100%;min-width:0;box-sizing:border-box;border:1px solid var(--hp-line);border-radius:var(--rad-m);background:transparent;color:var(--hp-txt);font:inherit;padding:11px 14px;}.device-inbox-tabs{display:flex;gap:var(--sp-2);overflow-x:auto;scrollbar-width:thin;padding-bottom:var(--sp-1);}.device-inbox-tabs button{flex:0 0 auto;border:1px solid var(--hp-line);border-radius:999px;background:transparent;color:var(--hp-txt);font:inherit;padding:8px 12px;cursor:pointer;}.device-inbox-tabs button.on{border-color:var(--hp-accent);background:color-mix(in srgb,var(--hp-accent) 18%,transparent);}.device-inbox-tabs button span{color:var(--hp-muted);margin-inline-start:4px;}.device-inbox-discovery{margin:8px 0;padding:8px 10px;border:1px solid var(--divider-color,#e0e0e0);border-radius:8px;}.device-inbox-discovery summary{cursor:pointer;font-weight:600;}.device-inbox-discovery .srcrow{display:flex;gap:6px;align-items:center;margin:8px 0;}.device-inbox-excluded{display:flex;flex-wrap:wrap;gap:6px;align-items:center;}.device-inbox-excluded>span{font-weight:500;}.device-inbox-chips{display:flex;flex-wrap:wrap;gap:4px;}.device-inbox-chips .chip{display:inline-flex;align-items:center;gap:2px;padding:1px 6px;border-radius:10px;background:var(--secondary-background-color,#f0f0f0);font-size:12px;}.device-inbox-chips .chip button{border:none;background:none;cursor:pointer;padding:0 2px;color:var(--secondary-text-color,#666);}.device-inbox-excluded input[type="text"]{flex:1 1 140px;min-width:120px;padding:4px 6px;border:1px solid var(--divider-color,#e0e0e0);border-radius:6px;background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);}.device-inbox-preview{margin:8px 0 4px;font-size:13px;opacity:0.85;}.device-inbox-filters{display:flex;flex-wrap:wrap;gap:var(--sp-4) var(--sp-6);color:var(--hp-muted);}.device-inbox-filters label{display:inline-flex;align-items:center;gap:var(--sp-2);cursor:pointer;}.device-inbox-filter-help{display:inline-flex;align-items:center;gap:var(--sp-1);min-width:0;}.device-inbox-results{display:grid;gap:var(--sp-3);min-width:0;}.device-inbox-row{display:grid;grid-template-columns:42px minmax(180px,1fr) minmax(180px,auto);align-items:center;gap:var(--sp-4);min-width:0;border:1px solid var(--hp-line);border-radius:var(--rad-m);padding:var(--sp-4);background:color-mix(in srgb,var(--hp-txt) 3%,transparent);}.device-inbox-icon{--mdc-icon-size:28px;color:var(--hp-txt);justify-self:center;}.device-inbox-copy{min-width:0;}.device-inbox-name{display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-2);}.device-inbox-new{border-radius:999px;background:var(--hp-accent);color:var(--text-primary-color,#fff);font-size:var(--fs-s);padding:2px 7px;}.device-inbox-meta,.device-inbox-reason,.device-inbox-copy code{display:block;color:var(--hp-muted);font-size:var(--fs-s);overflow-wrap:anywhere;white-space:normal;}.device-inbox-status{color:var(--error-color,#db4437);margin-inline-start:var(--sp-2);}.device-inbox-actions{display:flex;justify-content:flex-end;align-items:center;flex-wrap:wrap;gap:var(--sp-2);}.device-inbox-actions .btn{min-height:36px;padding:7px 10px;}.device-inbox-menu{position:relative;}.device-inbox-menu summary{list-style:none;cursor:pointer;}.device-inbox-menu summary::-webkit-details-marker{display:none;}.device-inbox-menu-items{position:absolute;z-index:2;inset-inline-end:0;top:calc(100% + var(--sp-1));display:grid;gap:var(--sp-1);min-width:180px;padding:var(--sp-2);border:1px solid var(--hp-line);border-radius:var(--rad-m);background:var(--hp-panel,var(--card-background-color,#fff));box-shadow:0 8px 24px rgba(0,0,0,.22);}.device-inbox-menu-items .btn{justify-content:flex-start;width:100%;}.device-inbox-empty{color:var(--hp-muted);text-align:center;padding:var(--sp-8);}.device-inbox-more{align-self:center;}@media (max-width:680px){.device-inbox{padding:var(--sp-4);}.device-inbox-head{grid-template-columns:minmax(0,1fr);}.device-inbox-head .btn{justify-self:stretch;}.device-inbox-tabs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));overflow-x:visible;}.device-inbox-tabs button{min-width:0;overflow-wrap:anywhere;}.device-inbox-row{grid-template-columns:36px minmax(0,1fr);}.device-inbox-actions{grid-column:1 / -1;justify-content:flex-start;}}`];var lp={"editor.context_actions":"Actions: {object}","editor.tool_options":"Tool options: {tool}","editor.palette":"Palette: {tool}","editor.open_group":"Tool group: {group}","editor.group_active":"{group} — active: {item}","editor.disabled_action":"{action} is unavailable: {reason}","editor.loading":"Loading…","editor.loading_aria":"The plan editor is loading","editor.load_failed":"Could not load the editor.","editor.refresh_advice":"Refresh the page and try again.","editor.retry_advice":"Check your connection and press again.","version_mismatch.title":"House Plan versions do not match","version_mismatch.body":"If Home Assistant is still restarting, let it finish, then reload this page.","version_mismatch.frontend":"Card","version_mismatch.backend":"Integration","version_mismatch.reload":"Reload page","color_picker.title":"Color picker","color_picker.hue":"Hue","color_picker.saturation":"Saturation","color_picker.value":"Brightness","color_picker.hex":"Hex color","color_picker.invalid_hex":"Enter a 3- or 6-digit hex color","color_picker.confirm":"OK","btn.properties":"Properties","btn.keep_as_walls":"Keep as walls","btn.delete_room_keep_walls":"Delete room, keep walls","btn.delete_room_with_walls":"Delete room and walls","title.markup_select":"Select and edit walls and columns","title.markup_column":"Column: click a grid point to place a square column","markup.partition":"Partition","markup.column":"Column","markup.hint_column":"click a grid point to place a square column","history.wall_segment":"Add wall segment","history.column_add":"Add column","history.physical_edit":"Change physical object","history.physical_delete":"Delete physical object","history.physical_move":"Move physical object","history.wall_face_batch":"Create rooms from walls","toast.column_duplicate":"A column with the same centre and outer size already exists","physical.partition_properties":"Partition properties","physical.column_properties":"Column properties","physical.shape":"Shape","physical.square":"Square","physical.circle":"Circle","physical.diameter":"Diameter","physical.side":"Side","physical.rotation":"Rotation angle","physical.length":"Length","physical.allowed_range":"Allowed: {min}–{max} {unit}","physical.column_size_title":"Outer side of the square column placed by the click (1–150 cm).","card.title":"House plan","count.devices":"{n} dev.","empty.no_spaces":"No spaces yet.","nav.spaces":"House Plan spaces","empty.add_first":"Add the first space and upload a floor plan.","empty.read_only":"No spaces are configured. Ask an administrator to add one.","empty.install":'Install the House Plan integration and add it in "Devices & services".',"btn.add_space":"Add space","btn.cancel":"Cancel","btn.save":"Save","btn.close":"Close","btn.delete":"Delete","btn.copy":"Copy","btn.edit":"Edit","btn.open_in_ha":"Open in HA","btn.reset":"Reset","btn.attach":"Attach…","btn.upload":"Upload…","btn.replace":"Replace…","title.zoom_in":"Zoom in","title.zoom_out":"Zoom out","title.zoom_fit":"Fit all","title.configure_space":"Configure space","title.add_space":"Add space","title.markup_add":"Walls: draw a continuous chain; each accepted segment is saved independently. Shift locks to 45°","title.markup_merge":"Merge: click one room, then the neighbour it shares a wall with","title.markup_split":"Split a room: click the room, then two points on its walls","title.markup_delroom":"Delete room: click inside a room and confirm","markup.add":"Walls","markup.merge":"Merge","markup.split":"Split","markup.resize":"Resize","title.markup_resize":"Resize rooms: drag an available horizontal or vertical wall handle","markup.hint_resize":"drag an available wall handle · the wall stops at the first unsafe position · Esc cancels · Ctrl+Z — undo","resize.disabled.diagonal":"This wall is angled; Resize supports only horizontal and vertical walls","resize.disabled.side-angle":"An adjoining wall is angled; Resize requires both adjoining walls to meet this wall at right angles","resize.disabled.duplicate-physical-wall":"A separate partition or column overlaps this wall; remove or move it before resizing","resize.disabled.partial-shared":"A neighbouring room uses only part of this wall, so it cannot be moved safely as one shared wall","resize.disabled.unequal-shared":"The neighbouring room uses different endpoints or wall length, so the walls cannot move together safely","resize.disabled.multiple-rooms":"Moving this wall would affect more than two rooms","resize.disabled.thickness-conflict":"The wall thickness cannot be preserved safely","resize.disabled.opening-conflict":"An opening on this wall cannot be moved safely","resize.disabled.invalid-geometry":"This wall cannot be resized without changing the plan structure","resize.limit_stopped":"Wall stopped: the next step would break a junction limit","resize.commit_failed":"Resize was cancelled because the final plan did not pass the geometry check","resize.preview_failed":"Resize stopped at the last safe position because the plan geometry could not be preserved","markup.opening":"Opening","markup.delete_room":"Delete room","history.undo":"Undo","history.redo":"Redo","history.undo_named":"Undo: {name} (Ctrl+Z)","history.redo_named":"Redo: {name} (Ctrl+Shift+Z / Ctrl+Y)","history.undo_empty":"Nothing to undo","history.redo_empty":"Nothing to redo","history.undone":"Undone: {name}","history.redone":"Redone: {name}","history.add_room":"Create room","history.split_room":"Split room","history.merge_rooms":"Merge rooms","history.resize_room":"Resize room","history.wall_thickness":"Change wall thickness","history.add_opening":"Add door or window opening","history.edit_opening":"Edit opening","history.move_opening":"Move opening","history.delete_opening":"Delete opening","history.delete_room_keep_walls":"Delete room, keep walls","history.delete_room_with_walls":"Delete room and walls","history.decor_add":"Add decor object","history.decor_edit":"Edit decor object","history.decor_move":"Move decor object","history.decor_transform":"Transform decor object","history.decor_delete":"Delete decor object","history.backdrop_transform":"Transform plan backdrop","history.device_move":"Move {name}","history.device_stale":"Device position history is no longer applicable and was cleared","opening.new":"New opening","opening.edit":"Opening","opening.door":"Door","opening.window":"Window","opening.gate":"Gate","opening.passage":"Open passage","opening.passage_binding_warning":"Saving will remove the open/close sensor and lock.","opening.invalid_passage_fields":"The open passage on plan “{room}” has unsupported settings: {fields}.","opening.type_label":"Type","opening.length_label":"Length, cm","opening.contact_label":"Open/close sensor","opening.lock_label":"Lock","opening.none":"— none —","opening.search_ph":"Search: name or entity id…","opening.invert":"Invert open/closed","opening.flip_h":"Hinge on the other jamb","opening.flip_v":"Opens to the other side","opening.open":"Open","opening.closed":"Closed","opening.locked":"Locked","opening.unlocked":"Unlocked","opening.state_unknown":"unavailable","opening.no_entities":"No sensors bound — a static symbol on the plan.","toast.opening_no_wall":"Click next to a room wall or independent wall","opening.host_partition":"Independent wall","opening.partition_orphan":"The independent wall for this opening no longer exists","opening.partition_jamb_margin":"Leave at least {distance} between the opening and the end of the wall","opening.rebind_partition":"Attach to another independent wall","confirm.delete_partition_openings_title":"Delete wall and openings?","confirm.delete_partition_openings_body":"This wall contains {count} opening(s). They will be deleted together.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.hint_points":"points: {n} · Shift — 45° steps · Esc — finish chain · Ctrl+Z — undo a point · closing an area offers a room","markup.hint_start":"click a grid dot to start a wall chain","tip.lqi":"average zigbee signal:","tip.area":"area: {value}","info.device_header":"Device on the plan","info.model":"Model","info.state":"State","info.link":"Link","info.manuals":"Manuals","info.none":"No additional information","marker.new_device":"New device","marker.name_label":"Name","marker.name_ph":"Name","marker.binding_label":"Bind to an HA device","marker.binding_disabled":"disabled in Home Assistant","marker.virtual_option":"Virtual device (no binding)","marker.search_ph":"Search device / group…","marker.nothing_found":"nothing found","marker.room_label":"Room","marker.room_choose":"— select a room —","marker.room_auto":"— by device area (auto) —","marker.icon_label":"Icon","marker.icon_ph":"mdi:… (empty = auto)","marker.display_label":"Display","display.badge":"Icon + state","display.icon_ripple":"Icon + state and activity","display.static_icon":"Always static icon","display.value_static_icon":"Value + static icon","marker.display_hint_badge":"The icon and dynamic plate show device state without the ordinary activity pulse. Red alarms remain visible.","marker.display_hint_icon_ripple":"The icon, dynamic plate and pulse show a short pulse for events and a continuous pulse for work, motion or presence. Red alarms have separate priority.","marker.display_hint_value":"A selected or automatically resolved Home Assistant value replaces the icon while the plate continues to show state. Red alarms remain visible.","marker.display_hint_static_icon":"The theme-aware shell and icon always stay the same. State, activity, unavailability and alarms do not change the face.","marker.display_hint_value_static_icon":"The marker shows the selected value while the shell stays theme-aware. State, activity, unavailability and alarms do not change the marker colour.","marker.static_alarm_warning":"This device can report alarms. Static display hides the marker's visual alarm indication.","marker.preview.title":"Display preview","marker.preview.actual":"Now","marker.preview.example":"Example","marker.preview.integration":"Provided by","marker.preview.source":"Display source","marker.preview.current_state":"Current state","marker.preview.result":"On the plan","marker.preview.details":"Source details","marker.preview.select_source":"Choose a Home Assistant device or entity to see its actual display.","marker.preview.unknown_provider":"Unknown integration","marker.preview.virtual_provider":"House Plan · virtual device","marker.preview.no_source":"No active source","marker.preview.no_state":"No current state","marker.preview.mixed_states":"Several different states","marker.preview.multiple_sources":"{n} sources","marker.preview.more_sources":"+{n} more","marker.preview.scaled":"The preview is scaled to {n}% to fit. The saved size is unchanged.","marker.preview.demo_short":"Show short activity","marker.preview.demo_continuous":"Show continuous activity","marker.preview.stop_continuous":"Stop continuous activity","marker.preview.demo_short_notice":"Short activity example; the actual device state is unchanged.","marker.preview.demo_continuous_notice":"Continuous activity example; the actual device state is unchanged.","marker.preview.demo_already_visible":"The current state already shows a real activity or alarm effect.","marker.preview.reduced_motion":"System reduced-motion is enabled, so ordinary activity is shown as a dot.","marker.preview.reason.neutral":"Neutral dark plate","marker.preview.reason.working":"Yellow plate: the device is working now","marker.preview.reason.working_activity":"Yellow plate and activity effect: the device is working now","marker.preview.reason.open":"Orange plate: physically open or unlocked","marker.preview.reason.cover_icon_state":"Neutral plate; the cover entity controls the displayed state and icon","marker.preview.reason.presence":"Activity effect while presence is detected","marker.preview.reason.event":"Short activity effect after a detected event","marker.preview.reason.transition":"Activity effect while the device is moving or changing state","marker.preview.reason.media_neutral":"Media devices stay on a neutral dark plate while available","marker.preview.reason.unavailable":"Subdued neutral plate: unavailable or off","marker.preview.reason.alarm":"Red alarm plate; alarm indication is always shown","marker.preview.reason.live_states_disabled":"Live-state styling is disabled for this card","marker.preview.reason.value_no_state":"No usable state value; the icon is shown instead","marker.preview.reason.value_ambiguous_sources":"Several possible value sources; the icon is shown instead","marker.preview.reason.value_non_scalar":"The source did not return a simple value; the icon is shown instead","marker.preview.reason.value_virtual":"A virtual device has no Home Assistant value; the icon is shown instead","marker.preview.reason.vacuum_live_plan_only":"Live vacuum position and trail are available only on the full plan","marker.preview.reason.hidden_design_preview":"The device is hidden on the plan; this design preview remains visible","marker.preview.reason.composite_power_source":"State comes from the device Power entity; auxiliary switches are ignored","marker.preview.reason.activity_display_disabled":"The selected display mode does not show ordinary activity effects","marker.preview.reason.ha_disabled":"The Home Assistant binding is disabled and will be hidden on the plan","marker.preview.reason.orphaned":"The saved Home Assistant binding can no longer be found","marker.preview.reason.static_icon":"Static mode: device state does not change the icon","marker.preview.reason.value_static_icon":"Static mode with a value: device state does not change the marker colour","marker.activity_color":"Activity pulse color","marker.ripple_size":"Activity pulse size","marker.activity_alarm_note":"Color and size affect ordinary activity only and do not change red alarms.","marker.pulse_a11y_alarm":"Alarm","marker.pulse_a11y_event":"Recent event","marker.pulse_a11y_presence":"Presence detected","marker.pulse_a11y_transition":"Changing state","marker.pulse_a11y_running":"Working","marker.state_a11y_neutral":"Default state","marker.state_a11y_working":"Working","marker.state_a11y_open":"Open","marker.state_a11y_locked":"Locked","marker.state_a11y_unlocked":"Unlocked","marker.state_a11y_alarm":"Alarm","marker.state_a11y_unavailable":"Unavailable","marker.lqi_a11y_low":"LQI {value}, low signal","marker.lqi_a11y_mid":"LQI {value}, medium signal","marker.lqi_a11y_high":"LQI {value}, high signal","marker.size_label":"Icon size and rotation","marker.angle_label":"Rotate","marker.model_label":"Model","marker.model_ph":"e.g. Aqara T&H","marker.link_label":"Link","marker.desc_label":"Description","marker.desc_ph":"Notes, specs…","marker.manuals_label":"Manuals (PDF etc.)","marker.sub_device":"device","marker.sub_z2m_group":" · Z2M group","marker.sub_group":"group","marker.sub_helper":"helper","space.new":"New space","space.copy_title":"Copy space","space.copy_name":"New space name","space.copy_fallback":"Space","space.copy_create":"Create copy","space.copy_optimize_title":"Optimize before copying?","space.copy_optimize_body":"Before creating “{name}”, House Plan must optimize the entire plan, including other spaces. Continue?","space.copy_optimize_confirm":"Optimize and copy","space.copy_error_changed":"The plan changed while confirmation was open. Review it and try again.","space.copy_error_source_missing":"The source space no longer exists. Reopen its settings and try again.","space.copy_error_source_invalid":"House Plan could not validate every wall in this space. Fix the source space and try again.","space.copy_error_spaces_limit":"House Plan already has the maximum number of spaces.","space.copy_error_partitions_limit":"This space has too many walls to copy.","space.copy_error_openings_limit":"This space has too many openings to copy.","space.copy_error_decor_limit":"This space has too many background objects to copy.","space.copy_error_columns_limit":"This space has too many columns to copy.","space.copy_error_opening_host":"One of the openings is no longer attached to a wall. Fix or delete it before copying.","space.copy_error_geometry":"The copy would create unsafe wall geometry. Fix the source space and try again.","space.copy_error_optimize_geometry":"Copy stopped because optimizing the entire plan is unsafe for one of the spaces.","space.header":"Space","space.title_label":"Space name","space.title_ph":"e.g. Garage","space.plan_label":"Floor plan","space.no_plan":"no plan image","space.plan_alt":"plan","room.new":"New room","room.name_label":"Display name","room.name_ph":"e.g. Terrace","room.area_label":"Home Assistant area","room.no_area_option":"— no area —","room.default_name":"Room","device.unnamed":"unnamed","device.light_group":"light group","device.fallback":"device","device.virtual":"virtual device","confirm.delete_room_title":'Delete room "{name}"?',"confirm.delete_room_body":"Choose whether the room's exclusive physical walls should remain. Walls shared with another room are always kept.","confirm.remove_marker_title":"Delete device from the plan?","confirm.remove_marker_body":"The device will disappear completely and stop contributing to plan data. You can add it again later.","confirm.erase_decor":"Erase the {kind} object? You can undo this action from the editor history.","confirm.delete_space_title":"Delete space?","confirm.delete_space_body":"The space, all its rooms and all its plan markup will be deleted.","confirm.delete_space_vac_routes":"Robot map assignments will also be removed: {count}.","space.delete_blocked":"This space is still used by {n} device(s). Move them to another space or delete them first.","toast.pos_save_failed":"Failed to save position: {err}","toast.no_entity":"The device has no suitable entity","toast.ha_disabled_action":"A Home Assistant object that is disabled cannot be used on the plan.","toast.ha_disabled_show_device":"A device disabled in Home Assistant cannot be shown on the plan. Enable it in Home Assistant first.","toast.ha_disabled_show_entity":"An entity disabled in Home Assistant cannot be shown on the plan. Enable it in Home Assistant first.","toast.ha_disabled_add":"A disabled Home Assistant object cannot be added to the plan. Enable it in Home Assistant first.","toast.ha_binding_unverified":"The object status could not be verified through the Home Assistant registry. Display and actions are temporarily unavailable.","toast.markup_needs_server":"Markup is available after the config is moved to the server","toast.space_order_changed":"Order changed. If any card pins its floor by number, check those panels.","toast.conflict":"Config was changed in another window — data refreshed, repeat your last action","toast.cfg_save_failed":"Failed to save config: {err}","toast.room_overlap":"The outline overlaps room “{name}” — rooms must not overlap","toast.contour_cannot_close":"The outline cannot close because it is degenerate or intersects itself","toast.merge_not_adjacent":"Only rooms that share a wall can be merged","toast.rooms_merged":"Rooms merged into “{name}”","toast.split_pick_wall":"Start the cut on the room’s wall","toast.split_bad_cut":"The cut must run wall to wall inside the room, without crossing walls or itself","merge.header":"Merge rooms","merge.hint":"The merged room keeps one name and one area. The other area is released — its devices leave the plan until another room claims it.","merge.keep":"Keep","merge.no_area":"no area","toast.room_saved":"Room saved ({n}). Devices added: {added}. Outline the next one or exit markup.","toast.room_saved_no_area":"Room saved ({n}, no area). Outline the next one or exit markup.","toast.marker_needs_server":"Device editing is available after the config is moved to the server","toast.virtual_name_required":"Enter a name for the virtual device","toast.marker_saved":"Device saved","toast.marker_removed":"Device deleted from the plan","toast.integration_missing":"The House Plan integration is not installed — management unavailable","toast.plan_formats":"Supported formats: SVG, PNG, JPG, WebP","toast.plan_required":"Upload a floor plan — it is required","toast.space_added_onboard":"Space added. Outline the rooms: click grid dots and close the contour.","toast.space_added":"Space added","toast.space_copied":"Space “{name}” created","toast.space_saved":"Space saved","toast.space_deleted":"Space deleted","toast.delete_failed":"Delete failed: {err}","toast.error":"Error: {err}","toast.toggle_target_unavailable":"Target “{name}” is unavailable — no action was performed","toast.toggle_targets_unavailable":"Targets are unavailable: {names}. No action was performed","toast.file_failed":'File "{name}" was not uploaded: {err}',"toast.files_attached":"Files attached: {n}","err.unknown":"unknown error","err.code":"code {code}","err.too_large":"file larger than {mb} MB","err.bad_ext":"unsupported type (PDF/image expected)","err.unauthorized":"administrator rights required","editor.title":"Title","editor.default_floor":"Initial space","editor.default_floor_missing":"Initial space “{id}” no longer exists. Choose another space.","editor.floor":"Fixed space","editor.floor_none":"— not fixed —","editor.floor_index":"YAML index {index} (preserved)","fixed_floor.loading":"Loading the fixed space…","fixed_floor.invalid_title":"The fixed space is unavailable","fixed_floor.invalid_body":"Check floor in the card configuration. The configured value is: {value}","editor.icon_size":"Icon size, % of plan width","editor.show_temperature":"Show temperature","editor.live_states":"Live states (on/off, open…)","editor.light_pools":"Light pools and wall shadows","editor.show_signal":"Show zigbee signal (LQI)","editor.language":"Interface language","editor.lang_auto":"Auto (HA profile)","title.icon_rules":"Icon rules: which MDI icon devices get by name","rules.title":"Icon rules","rules.hint":"Rules are checked top-down against “device name + model” (case-insensitive regex); the first match wins. When nothing matches, the entity device class decides, then the generic chip icon.","rules.pattern_ph":"regex, e.g. plug|socket","rules.icon_ph":"mdi:power-socket-de","rules.add":"Add rule","rules.reset":"Reset to defaults","rules.test_ph":"Try a device name…","rules.invalid":"invalid regex","rules.saved":"Icon rules saved","btn.up":"Up","btn.down":"Down","tap.info":"Device card","tap.more_info":"HA more-info dialog","tap.toggle":"Toggle state","marker.tap_label":"Tap action for this device","tap.toggle_note":"The resolved state is shown below. Secure devices are never toggled from the plan.","import.title":"Create spaces from HA floors","import.hint":"Your Home Assistant already knows these floors. Pick the ones to turn into plan spaces — you will upload a floor-plan image for each one next. Rooms are then outlined by hand on the plan.","import.start":"Create {n} space(s)","import.manual":"Start from scratch","import.progress":"Floor {i} of {n}","import.done":"Spaces created. Outline the rooms: click grid dots and close the contour.","btn.skip":"Skip","space.scale_label":"Scale (grid cell size)","space.cell_cm.help":"Links the grid to real dimensions: lengths, areas, wall thickness, opening sizes and glow radius depend on it. Changing it after drawing changes the calculated dimensions of the whole space without moving its points on the plan.","space.cell_cm.help.aria":"Help: space scale","space.scale_unit":"cm per cell","space.scale_unit_imperial":"in per cell","space.display_section":"Appearance","space.show_borders":"Always show room borders","space.zero_wall_style":"Zero-thickness walls","space.zero_wall_style.help":"Dashed zero-thickness walls pass Glow and sun rays, while solid ones block them as zero-area barriers. The choice affects every such wall in the space even when its line is hidden in View.","space.zero_wall_style.help.aria":"Help: zero-thickness wall style","space.zero_wall_dashed":"Dashed","space.zero_wall_solid":"Solid","space.show_names":"Show room names","space.room_color":"Border & name color","space.opacity":"Opacity","space.fill_label":"Room fill","space.fill_mode.help":"“Custom colour” is styling, while “Light”, “Temperature” and “LQI” use current Home Assistant data; Glow is enabled separately.","space.fill_mode.help.aria":"Help: room fill mode","fill.none":"None","fill.lqi":"Zigbee signal","fill.light":"Lights","fill.custom":"Custom color","space.custom_fill":"Fill color","space.source_file":"Use a floor-plan image","space.source_draw":"Draw it myself","fill.temp":"Temperature","tip.temp_avg":"average temperature:","tip.hum_avg":"average humidity:","space_card.button":"Open the space plan","space_card.not_found":"Space “{id}” not found","space_card.loading":"Loading…","continuity.restore_plan":"Restoring floor plan…","continuity.restore_connection":"Restoring device connection…","continuity.retry":"Try again","editor.space":"Space","editor.framing":"Framing","editor.fit_content":"All visible content","editor.fit_house":"Tight to house geometry","editor.show_button":"Show button","editor.button_label":"Button label","editor.button_target":"Target dashboard path","marker.sub_entity":"entity","title.general_settings":"General settings","title.export_pdf":"Save as PDF","pdf.title":"Save as PDF","pdf.dimensions":"Show dimensions and areas","pdf.decor":"Show furniture and other decor","pdf.room_names":"Show room names","pdf.backdrop":"Show backdrop","pdf.save":"Save","pdf.saving":"Creating…","pdf.failed":"Could not create the PDF.","pdf.too_large":"The images exceed the 25 MB PDF limit.","pdf.asset_failed":"A backdrop or decor image could not be loaded.","pdf.scale":"Scale 1:{n}","pdf.north":"North","gs.title":"General settings","gs.light_group":"Lights","gs.light_on":"Lights on","gs.light_off":"All lights off","gs.temp_group":"Temperature","gs.temp_cold":"Cold","gs.temp_ok":"Comfortable","gs.temp_hot":"Hot","gs.lqi_group":"Zigbee signal","gs.lqi_low":"Weak signal","gs.lqi_high":"Strong signal","gs.reset":"Reset to defaults","gs.saved":"General settings saved","gs.radar_show_live":"Show live presence on the plan","radar.title":"Presence on the plan","radar.help":"Connect this marker to exact Home Assistant radar entities, place the sensor and choose its coordinate profile. Live positions are clipped to the selected room.","radar.help.aria":"Help: presence radar settings","radar.enabled":"Use this presence radar","radar.show_live":"Show live targets","radar.configure":"Configure radar","radar.configure_on_plan":"Configure on plan","radar.change_installation":"Change installation","radar.no_contour":"This room has no boundary. Radar points will not be clipped.","radar.discard_setup_title":"Discard radar setup?","radar.discard_setup":"The unsaved radar setup will be lost.","radar.step_place_mount":"Mark the physical sensor position","radar.step_place_heading":"Mark a point straight ahead of the sensor","radar.step_reference":"Mark reference position {n}, then start measurement","radar.step_check_reference":"Mark an independent check position","radar.start_measure":"Start measurement","radar.countdown":"Stand at the mark in {seconds} s","radar.capturing":"Stand still and alone while measuring…","radar.fit_ready":"Calibration is ready","radar.check_third":"Check at another position","radar.check_complete":"Independent check completed","radar.error_distance":"Position difference: {distance}","radar.ambiguous_target":"More than one target was reported. Repeat the measurement alone.","radar.insufficient_samples":"Not enough current coordinates. Retry or use manual setup.","radar.bad_references":"Choose separated references in different directions from the sensor.","radar.ambiguous_sources":"The measurements allow two equally plausible directions. Choose reference points that distinguish left from right.","radar.bad_fit":"Measurements do not match. Check units, mounting point and references.","radar.desktop_hint":"Use a computer for precise setup. Editing on touch devices is best effort.","radar.detected":"House Plan recognized radar metadata for this device. Review the exact sources before saving.","radar.detected_ld2450":"House Plan found an ESPHome LD2450 coordinate set. Review the exact X/Y sources before saving.","radar.additional_actions":"Additional actions","radar.declare":"This is a presence radar","radar.profile":"Data profile","radar.profile_esphome_ld2450_v1":"ESPHome LD2450 (X/Y targets)","radar.profile_cartesian_v1":"Cartesian targets (X/Y)","radar.profile_polar_v1":"Polar target (distance/angle)","radar.profile_range_v1":"Distance only","radar.profile_zones_v1":"Zone states","radar.profile_presence_v1":"Presence only","radar.room":"Radar room","radar.room_choose":"Choose a room","radar.target":"Target {n}","radar.axis_x":"X coordinate entity","radar.axis_y":"Y coordinate entity","radar.add_target":"Add target slot","radar.range_channel":"Range channel {n}","radar.add_range":"Add range channel","radar.presence_gate":"Presence gate entity","radar.swap_axes":"Swap X and Y axes","radar.axis_x_sign":"X direction","radar.axis_y_sign":"Y direction","radar.distance_source":"Distance entity","radar.angle_source":"Angle entity","radar.angle_unit":"Angle unit","radar.degrees":"Degrees","radar.radians":"Radians","radar.angle_zero":"Zero-angle direction","radar.angle_forward":"Forward","radar.angle_right":"Right","radar.angle_clockwise":"Angles increase clockwise","radar.zone_source":"Zone entity","radar.occupancy_source":"Presence entity","radar.count_source":"Target count entity","radar.availability_source":"Availability entity","radar.source_choose":"Choose an entity","radar.source_optional":"Optional","radar.source_missing":"currently unavailable","radar.saved_unsupported":"This saved radar setup is unsupported or incomplete. It remains inactive; remove it or update House Plan before configuring it again.","radar.occupancy":"Presence (on/off)","radar.count":"Count","radar.mount":"Position and direction","radar.mount_hint":"This is the physical sensor position. Moving its decorative marker does not change it.","radar.heading":"Direction, °","radar.range_cm":"Range, cm","radar.fov_deg":"Field of view, °","radar.unit":"Source unit","radar.mirror":"Mirror the left/right axis","radar.remove":"Remove radar settings","radar.invalid":"Complete the radar room, sources and position before saving.","radar.check_sources":"Check live data","radar.checking":"Checking…","radar.health":"Connection status","radar.live_summary":"Current targets: {targets}; range arcs: {ranges}","radar.health_ok":"Current data received","radar.health_off":"No targets detected","radar.health_stale":"Some coordinate data is out of date","radar.health_partial":"Some sources are current; others are out of date","radar.health_restricted":"Access to one or more sources is restricted","radar.health_incomplete":"The current radar report is incomplete","radar.health_position_unavailable":"Presence reported; current position unavailable","radar.health_unavailable":"Sensor data unavailable","radar.health_needs_setup":"Installation needs setup","radar.health_inconsistent":"The sources report conflicting values","radar.health_unknown":"Current state is unknown","radar.health_disabled":"Radar is disabled","radar.error_invalid_radar":"Check the radar settings.","radar.error_invalid_selection":"Select an existing room and valid sources.","radar.error_source_restricted":"You do not have access to all selected sources.","radar.error_rate_limited":"Too many requests. Try again shortly.","radar.error_not_ready":"Radar processing is not ready.","radar.error_conflict":"The plan changed. Reopen the radar setup and try again.","radar.error_source_unavailable":"One or more selected radar sources are unavailable.","radar.error_unsupported_capability":"This radar capability is not supported by the installed integration.","radar.report_age":"{seconds} s ago","space.show_lqi":"Zigbee signal next to devices","gs.light_none":"No light sources","mode.plan":"Plan editor","mode.devices":"Device editor","display.value":"Value + state","marker.subarea":"no area, manual","device.new":"New device — open its editor to dismiss","opening.unlock_action":"Unlock","opening.lock_action":"Lock","opening.lock_pending":"Working…","title.close_editor":"Close editor (back to view)","title.add_device":"Add a device to the plan","devbar.add":"Add","devbar.rules":"Icon rules","device_inbox.button":"Devices","device_inbox.title":"Devices on the plan","device_inbox.search":"Search devices, entities and integrations…","device_inbox.add_virtual":"Add virtual device","device_inbox.tab_on_plan":"On plan","device_inbox.tab_available":"Available","device_inbox.tab_hidden":"Hidden","device_inbox.tab_readd":"Available again","device_inbox.only_new":"New only","device_inbox.show_entities":"Show entities","device_inbox.show_hidden":"Show hidden on plan","device_inbox.show_hidden.help":"Temporarily shows hidden and disabled markers as editor-only ghosts on the plan. Saved device visibility does not change.","device_inbox.show_hidden.help.aria":"Help: show hidden devices on the plan","device_inbox.new":"New","device_inbox.find":"Find on plan","device_inbox.edit":"Edit","device_inbox.hide":"Hide","device_inbox.show":"Show","device_inbox.add":"Add","device_inbox.readd":"Add again","device_inbox.hide_available":"Hide from list","device_inbox.show_more":"Show more","device_inbox.more_actions":"More actions","device_inbox.find_hidden_hint":"Enable “Show hidden on plan” first","device_inbox.show_disabled":"Activate this binding in Home Assistant before showing it","device_inbox.empty_on_plan":"No matching devices are on the plan yet.","device_inbox.empty_available":"No devices are available to add.","device_inbox.empty_hidden":"There are no hidden devices.","device_inbox.empty_readd":"No removed devices are available to add again.","device_inbox.reason_visible_auto":"Discovered automatically","device_inbox.reason_visible_explicit":"Added explicitly","device_inbox.reason_manual_hidden":"Hidden by user","device_inbox.reason_automatic_hidden":"Hidden automatically","device_inbox.reason_service_entry":"Service-only registry entry","device_inbox.reason_excluded_integration":"Integration “{integration}” excluded by discovery filters","device_inbox.reason_excluded_domain":"Non-spatial entity type","device_inbox.reason_grouped_light":"Represented by a room light group","device_inbox.reason_represented_by_parent":"Represented by its parent device","device_inbox.reason_removed":"Previously removed from the plan","device_inbox.reason_available":"Available to add to the plan","device_inbox.reason_no_bound_room":"HA area is not linked to a plan room","device_inbox.status_ha_disabled":"Disabled in Home Assistant","device_inbox.status_orphaned":"Binding is no longer present in Home Assistant","device_inbox.status_unverified":"Home Assistant registry is temporarily unavailable","device_inbox.saved":"Device list updated","device_inbox.filters_excluded":"Excluded integrations","device_inbox.filters_group_lights":"Group room lights into one marker","device_inbox.filters_preview_appear":"will appear: {count}","device_inbox.filters_preview_hide":"will disappear: {count}","device_inbox.filters_preview_lights":"lights affected: {count}","device_inbox.filters_reset":"Restore recommended","device_inbox.filters_save":"Save filters","device_inbox.filters_search_ph":"Add an integration…","device_inbox.filters_title":"Discovery filters","space.roomcard_section":"Room cards","space.label_temp":"Temperature","space.label_hum":"Humidity","space.label_lqi":"Average Zigbee signal","space.label_light":"Lights on/off","roomcard.light_on":"On","roomcard.light_off":"Off","roomcard.light_partial":"{on} of {total}","toast.split_pick_inside":"Intermediate cut points must be inside the room","mode.decor":"Background editor","decor.select":"Select","decor.line":"Line","decor.rect":"Rectangle","decor.ellipse":"Oval","decor.text":"Text","decor.erase":"Erase","decor.erase_confirm_title":"Erase object?","decor.color":"Color","decor.width":"Line width","decor.line_style":"Line style","decor.line_style_solid":"Solid","decor.line_style_dashed":"Dashed","decor.fill":"Fill","decor.fill_color":"Fill color","decor.length":"Length","decor.size":"Size","decor.flip_h":"Flip horizontally","decor.flip_v":"Flip vertically","decor.angle":"Rotation angle, °","decor.text_size":"Text size","decor.backdrop_properties":"Plan backdrop properties","decor.text_title":"Text label","decor.object_title":"Edit {kind}","decor.text_label":"Text","decor.live_group":"Insert HA variable","decor.live_entity":"Entity","decor.live_entity_ph":"choose an entity","decor.live_attr":"Value","decor.live_attr_ph":"choose state or attribute","decor.live_state":"State","decor.backdrop":"Backdrop image","decor.backdrop_hint":"Drag to move; pull a corner to resize; use the top handle to rotate. Shift changes proportions or frees the angle.","decor.backdrop_reset":"Reset the picture","decor.backdrop_reset_done":"The picture is back at its original place and size","marker.icon_auto":"Auto: {icon} (by icon rules; pick one to override)","marker.icon_pin_auto":"Pin","mode.plan_tip":"Plan editor — the geometry of the home: draw and split/merge rooms, bind them to HA areas, place doors, windows and gates, move room cards, set the scale","mode.devices_tip":"Device editor — everything about icons: drag to position, click to edit binding/icon/display, add virtual devices, icon rules","mode.decor_tip":"Background editor — purely visual decor under the plan: lines, rectangles, ovals and text labels that never react to clicks","space.glow_enabled":"Light-source glow","gs.glow_group":"Light-source glow","gs.glow_base":"House darkness","gs.glow_light":"Default light color / intensity","gs.wall_fill":"Wall fill","gs.glow_radius":"Glow radius","gs.glow_radius.help":"Sets the default glow radius in metres or feet; a device-specific radius overrides it.","gs.glow_radius.help.aria":"Help: default glow radius","gs.unit_m":"m","gs.unit_ft":"ft","marker.controls_label":"Controls other light sources","marker.controls.help":"With the “Toggle state” action, the listed sources toggle together with this marker. Their glow stays at their own markers, and the link alone does not turn the controlling marker into a light source.","marker.controls.help.aria":"Help: controlling other light sources","marker.controls_filter":"Search lights and switches…","info.controls":"Controls","marker.glow_radius_label":"Glow radius","marker.glow_radius.help":"Sets the glow radius in metres or feet; an empty value uses the radius from general settings.","marker.glow_radius.help.aria":"Help: glow radius","markup.wallthick":"Thickness","markup.select":"Select","title.markup_wallthick":"Thickness — click a wall to set its thickness from 0 to 100 cm.","markup.hint_wallthick":"click a wall · Esc closes without applying","wallthick.field":"Thickness","wallthick.unit_cm":"cm","wallthick.unit_in":"in","wallthick.apply_room":"Apply to all walls of this room","markup.draw_wall_title":"Thickness of each new wall segment (0–100 cm). Shared walls keep the existing value.","room.queue_progress":"Room {current} of {total}","toast.wall_rooms_saved":"Created rooms: {n}","toast.wall_chain_saved":"Wall chain saved","toast.wallthick_pick":"Click a wall","toast.wallthick_set":"Wall thickness set","toast.wallthick_cleared":"Wall thickness removed","toast.physical_range":"Enter a value from {min} to {max} {unit}","toast.zero_wall_opening_conflict":"Remove the opening on this wall segment first.","toast.zero_wall_ambiguous":"The wall segment is ambiguous. Simplify or adjust the junction.","toast.zero_wall_migration_blocked":"The space was not converted: {reason}. No data was changed.","toast.physical_angle":"Enter a rotation angle from 0° up to, but not including, 90°","toast.physical_limit":"The space has reached the limit for this type of geometry","toast.geometry_unsafe":"Change canceled: wall geometry could not be built safely.","junction.limit_angle":"The angle between walls is too sharp: {actual}°, minimum {limit}°.","junction.limit_valence":"Too many walls meet in one node: {actual}, maximum {limit}.","junction.limit_length":"The wall segment is too short: {actual} cm, minimum {limit} cm.","junction.limit_distance":"Walls and nodes are too close: {actual} cm, minimum {limit} cm.","junction.limit_clearance":"No room interior is left: {actual} cm², minimum {limit} cm².","junction.limit_check_failed":"The junction check could not run — the change was not saved","toast.wall_model_migration_blocked":"The wall model could not be updated: {reason}. The plan was not changed. Run “Optimize plans”; if the error repeats, fix the conflicting wall geometry.","toast.wall_model_client_outdated":"Update the card and reload the page before editing the plan.","wall_model.reason.invalid-room":"invalid room contour","wall_model.reason.zero-length":"zero-length wall segment","wall_model.reason.third-owner":"wall shared by more than two rooms","wall_model.reason.duplicate-id":"conflicting wall identifiers","wall_model.reason.thickness-conflict":"conflicting wall thickness values","wall_model.reason.opening-host":"opening cannot be assigned to one wall","toast.delete_room_pick":"Click inside the room you want to delete","toast.plan_snap_ambiguous":"Zoom in to choose the wall node","toast.wall_repair_ambiguous":"The room outline has more than one possible connection. Zoom in and connect it explicitly.","toast.wall_repair_too_large":"The gap is larger than 2 cm. Connect the walls before creating the room.","toast.wall_repair_changed":"The wall geometry changed. Try creating the room again.","toast.opening_on_zero_wall":"Openings cannot sit on a zero-thickness wall","marker.from_ha_option":"Pick from the HA list","marker.show_entities":"Show entities","marker.show_entities_tip":"Adds not only devices to the list, but all their entities too","marker.pick_ph":"Choose a device…","room.open_area":"Open the HA area","room.fit_action":"Fit room {name}","view.volumetric":"Volumetric view","view.flat":"Flat view","kiosk.title":"This screen's sizes","kiosk.hint":"Stored on this device only — every wall tablet or TV can have its own comfortable sizes.","kiosk.icon_scale":"Device icon size","kiosk.font_scale":"Room card text size","editor.kiosk":"Wall device (kiosk) mode","editor.cycle":"Auto-switch spaces every N seconds (kiosk, 0 = off)","room.settings_title":"Room settings","room.fill_label":"Fill in THIS room","fill.inherit":"As the space","room.custom_fill_space":"Space color","room.custom_fill_own":"Room color","room.temp_range_label":"Comfort range","room.temp_range_min":"Lower comfort-temperature bound","room.temp_range_max":"Upper comfort-temperature bound","room.temp_range_reset":"As the space","room.temp_range.help":"This range applies only to this room. Empty fields inherit the corresponding space bounds; if the bounds are reversed, House Plan uses the smaller value as the lower bound and the larger value as the upper bound.","room.temp_range.help.aria":"About the room comfort range","room.temp_src_label":"Temperature source","room.hum_src_label":"Humidity source","room.src_average":"Average of the room’s sensors","room.src_pick":"Specific device or entity","room.src_ph":"Choose a source…","toast.room_updated":"Room updated","space.card_font":"Room-card font size","room.sizes_section":"Font sizes","room.group_basics":"Basics","room.group_basics.help":"The area links the room to a Home Assistant area, which is where its sensors come from. Without one the room stays geometry.","room.group_basics.help.aria":"Help: room name and area","room.group_fill":"Fill","room.group_fill.help":"This room’s fill overrides the space one; a custom colour is kept for this room only.","room.group_fill.help.aria":"Help: room fill","room.group_sources":"Sensor sources","room.group_sources.help":"By default the room averages its own sensors. A selected sensor replaces that average everywhere: tooltip, card, fill.","room.group_sources.help.aria":"Help: temperature and humidity sources","room.sizes_section.help":"These scales apply to this room only and multiply the shared card scale from the space settings.","room.sizes_section.help.aria":"Help: room font sizes","room.name_scale":"Room name size","room.label_scale":"Metrics size","preview.room_name":"Living room","toast.cfg_reload_failed":"Could not reload the plan from the server: {err}","toast.locale_load_failed":"Could not load the language pack. English is used until the page reloads.","toast.furniture_art_load_failed":"Could not load the furniture drawings. Reload the page to show them.","room.settings_short":"Room settings","room.unnamed":"Unnamed room","marker.use_climate_temp":"Include the device temperature in the room","marker.use_climate_temp_tip":"Adds an air conditioner or thermostat current_temperature to the room average. Configure the external value badge separately below.","marker.value_badge_title":"Value badge","marker.value_badge.help":"Shows one selected value next to the icon. It does not affect room metrics, light, Glow or the tap action.","marker.value_badge.help.aria":"Help: device value badge","marker.value_badge_enabled":"Show a value badge","marker.value_badge_source":"Value","marker.value_badge_source.help":"Choose a specific state, supported attribute, or derived value of this device.","marker.value_badge_source.help.aria":"Help: value badge source","marker.value_badge_position":"Position","marker.value_badge_position.help":"The chosen side stays fixed and does not flip automatically at a plan edge.","marker.value_badge_position.help.aria":"Help: value badge position","marker.value_badge_right":"Right","marker.value_badge_bottom":"Below","marker.value_badge_left":"Left","marker.value_badge_top":"Above","marker.value_badge_empty":"This device has no available values","marker.value_badge_static":"A static icon does not show live values. The setting is preserved.","marker.value_badge_missing":"Source unavailable","marker.value_badge_missing_hint":"The saved source is currently unavailable. Keep it, disable the badge, or choose another value.","marker.value_badge_duplicate":"The same value is already shown inside the icon.","marker.value_badge_state":"State · {name}","marker.value_badge_marker_state":"Light-source state · {name}","marker.value_badge_lqi":"Average Zigbee signal quality","marker.value_badge_attr_current_temperature":"Current temperature · {name}","marker.value_badge_attr_temperature":"Target temperature · {name}","marker.value_badge_attr_current_humidity":"Current humidity · {name}","marker.value_badge_attr_humidity":"Humidity · {name}","marker.value_badge_attr_current_position":"Position · {name}","marker.value_badge_attr_percentage":"Speed · {name}","marker.value_badge_attr_brightness":"Brightness · {name}","marker.value_badge_attr_volume_level":"Volume · {name}","marker.value_badge_attr_battery_level":"Battery · {name}","marker.value_badge_attr_fan_speed":"Fan speed · {name}","marker.value_source":"Value source","marker.value_source.help":"Choose the value that replaces the icon. The tap action does not change.","marker.value_source.help.aria":"Help: value face source","marker.value_source_auto":"Automatic (as before)","marker.value_source_missing_hint":"The saved source is currently unavailable. The face shows — until it recovers or you choose another value.","marker.light_role_label":"Is this device a light source?","marker.light_role.help":"“Auto” uses the bound device's resolved role, “Always” forces its own source and “Never” excludes it; linked lights above remain independent.","marker.light_role.help.aria":"Help: whether this device is a light source","marker.light_role_auto_yes":"Auto (light source)","marker.light_role_auto_no":"Auto (not a light source)","marker.light_entity_label":"Leading light entity","marker.light_entity.help":"For a composite device, choose the entity whose state, colour and brightness represent this plan source. The automatic fallback remains compatible with older plans.","marker.light_entity.help.aria":"Help: leading light entity","marker.light_entity_auto":"Automatic ({entity})","marker.light_entity_none":"no controllable entity","marker.light_entity_missing":"The saved entity {entity} is unavailable. House Plan temporarily uses {fallback}; the saved choice will be restored if it returns.","marker.toggle_entity_label":"Entity to toggle","marker.toggle_entity.help":"For a composite device, choose the exact own light or switch operated by a tap. Automatic keeps the previous target rules and is independent from the leading light entity.","marker.toggle_entity.help.aria":"Help: entity to toggle","marker.toggle_entity_auto":"Automatic ({entity})","marker.toggle_entity_none":"no own controllable entity","marker.toggle_entity_missing":"The saved entity {entity} is no longer among this marker’s selectable channels. House Plan temporarily uses {fallback}; the saved choice will be restored if it returns.","marker.glow_color_label":"Glow colour and brightness","marker.glow_mode.help":"Use live source values, override only its colour, or fix both colour and brightness. The minimum is 1%; to disable the source, choose “Never”.","marker.glow_mode.help.aria":"Help: glow colour and brightness","marker.glow_mode_auto":"From source","marker.glow_mode_color":"Set colour","marker.glow_mode_fixed":"Colour and brightness","marker.glow_color":"Glow colour","marker.glow_brightness":"Brightness","marker.glow_disabled_never":"Glow settings are unavailable because this marker is explicitly not a light source.","marker.glow_disabled_auto":"Auto mode found no spatial light source for this marker.","marker.glow_disabled_no_entity":"No active controllable Home Assistant entity is available for this spatial source.","marker.glow_passive_hint":"This source has no own Home Assistant data. Set its colour and brightness manually; its radius remains available.","marker.control_broken":"Saved source is missing or no longer marked as a light","marker.control_missing_label":"Missing plan light","marker.control_passive":"passive source","toast.marker_control_cycle":"This link would create a circular chain of light controls.","toast.marker_binding_required":"Choose a Home Assistant device before linking another light source.","confirm.unlock_title":"Unlock?","confirm.unlock_body":"House Plan will send an unlock command to this lock.","toast.files_migrate_failed":"Attachments could not be moved to the new binding, links keep pointing at the old files: {err}","space.pick_saved":"Already uploaded","space.pick_saved_hint":"Plans stored on the server, including ones you detached earlier","space.no_saved":"No plans stored on the server yet.","space.loading":"Loading…","space.used_by":"in use: {list}","space.in_use":"A space still uses this plan — detach it first","btn.use":"Use","confirm.delete_plan_title":"Delete plan file?","confirm.delete_plan_body":"The file will be deleted from the server. This action cannot be undone.","toast.plans_list_failed":"Could not list the stored plans: {err}","toast.plan_delete_failed":"Could not delete the plan: {err}","marker.hide":"Hide","marker.hide_tip":'The device will disappear from the plan after saving but will still count toward the room signal. Restore it through the "Devices" catalog in the device editor.',"marker.show":"Show","marker.show_tip":"The device will appear on the plan again after saving.","marker.hidden_ghost":"Device hidden by the user","marker.ha_disabled_device":"The device is disabled in Home Assistant and hidden from the plan.","marker.ha_disabled_entity":"The entity is disabled in Home Assistant and hidden from the plan.","marker.ha_disabled_all_entities":"The device has no active Home Assistant entities, so it is hidden from the plan.","marker.ha_registry_limited":"The full Home Assistant registry is unavailable to this user. The unverified object cannot be shown or used for now.","marker.delete_tip":"Completely delete the device from the plan and every aggregate. You can add it again later.","tap.run":"Run automation/script/scene","tap.none":"Do nothing","marker.run_target_label":"What to run","marker.run_search_ph":"Search: automation, script or scene…","marker.run_target_gone":"Target {id} not found — pick again","marker.tap_confirm":"Ask for confirmation","marker.tap_confirm_tip":"Show a confirmation dialog before acting — a guard against accidental taps.","marker.toggle_hint_single":"Target: {name} ({id}).","marker.virtual_light_target":"Virtual light: {name}.","marker.virtual_light_current":"Manual state: {state} → {effect}.","marker.virtual_light_state_on":"on","marker.virtual_light_state_off":"off","marker.toggle_hint_group":"Will toggle {count} source(s): {names}.","marker.toggle_hint_current":"Now: {state} → {effect}.","marker.toggle_hint_group_current":"Currently on: {on} of {count} → {effect}.","marker.toggle_hint_skipped":"Will be skipped ({count}): {targets}.","marker.toggle_effect_turn_on":"will turn on","marker.toggle_effect_turn_off":"will turn off","marker.toggle_effect_open":"will open","marker.toggle_effect_close":"will close","marker.toggle_effect_stop":"will stop","marker.toggle_effect_toggle":"state will toggle","marker.toggle_skip_missing":"not found","marker.toggle_skip_ha_disabled":"disabled in HA","marker.toggle_skip_unavailable":"unavailable","marker.toggle_skip_unsupported":"toggle is unsupported","marker.toggle_skip_secure":"blocked for security","marker.toggle_none_no_binding":"This device has no binding, so there is no state to toggle. Tapping will do nothing.","marker.toggle_none_no_actionable_entity":"This device has no state that can be toggled. Tapping will do nothing.","marker.toggle_none_configured_targets_missing":"The configured targets are unavailable. The device's own entity will not be substituted for them.","marker.toggle_none_ha_disabled":"The target is disabled in Home Assistant and cannot be used on the plan.","marker.toggle_none_unavailable":"The target is currently unavailable. Tapping will do nothing.","marker.toggle_none_unsupported":"Home Assistant exposes no safe toggle operation for this entity. Tapping will do nothing.","marker.toggle_none_secure":"Toggling locks, alarms and secure gates from the plan is blocked for security.","run.automation":"automation","run.script":"script","run.scene":"scene","confirm.tap_run":'Run "{name}"?',"confirm.tap_toggle":'Toggle "{name}"?',"confirm.current_state":"Current state: {state}","confirm.expected_state":"After switching: {state}","confirm.group_current":"on {on} of {total}","confirm.group_all_on":"all are on","confirm.group_all_off":"all are off","confirm.unavailable_targets":"Unavailable: {count}","confirm.expected_by_ha":"Home Assistant will determine the state","confirm.state_on":"On","confirm.state_off":"Off","confirm.state_open":"Open","confirm.state_closed":"Closed","confirm.state_opening":"Opening","confirm.state_closing":"Closing","confirm.state_stopped":"Stopped","confirm.state_unknown":"Unknown","toast.run_started":"Started: {name}","toast.run_target_missing":"Run target not found — check the device settings","toast.run_target_required":"Pick an automation, script or scene","toast.tap_target_changed":"The action target changed. Try again.","toast.virtual_light_toggle_failed":"Could not toggle the virtual light: {err}","toast.value_badge_source_required":"Choose a value for the badge","btn.run":"Run","vac.section":"Robot vacuum: live position","vac.autocal":"Set up automatically","vac.live":"Live position on the plan","vac.trail":"Show the robot's path","vac.autocal_no_rooms":"The integration reports no room list — open “Fit manually”","vac.route_warn_unmapped":"The robot is cleaning a map that is not assigned to any floor","vac.route_warn_needs_calibration":"The map is assigned to a floor but not calibrated","vac.route_warn_ambiguous":"Two maps are indistinguishable — no floor was chosen","vac.route_warn_missing_space":"The space of this map was deleted","vac.autocal_no_match":"Room names did not match (need ≥3 in common) — open “Fit manually”","vac.autocal_done":"Done: bound via {rooms} rooms. Start a cleanup and check","vac.cal_need_pos":"The robot is not reporting coordinates — start a cleanup and pause it","vac.cal_done":"Calibration saved. Start a cleanup and check","vac.cal_cancelled":"Calibration cancelled","vac.fit":"Fit manually","vac.fit_hint":"Drag the robot map into place, stretch by the corners","vac.fit_rotate":"Rotate 90°","vac.fit_mirror":"Mirror","vac.trail_never":"Never","vac.trail_cleaning":"While cleaning","vac.trail_always":"Always","gs.bg_color":"Background around the plan","gs.bg_default":"Theme default","gs.bg_mode":"Plan background","gs.bg_mode.help":"“Follows the Sun” uses sun.sun, falling back to the browser's local clock; Static always shows the selected colour.","gs.bg_mode.help.aria":"Help: general plan background","gs.bg_static":"Static color","gs.bg_daynight":"Follows the Sun","gs.sun_group":"Sun","gs.sun_missing":"The sun.sun entity was not found — the background follows your local clock; window rays are unavailable.","gs.north":"North on the plan","gs.north.help":"The angle is measured clockwise from the plan's upward vertical; north is required for window rays, not for the “Follows the Sun” background.","gs.north.help.aria":"Help: general north direction","gs.north_ph":"not set","gs.north_clear":"Clear","gs.north_letter":"N","gs.sun_rays":"Sunlight through windows","gs.sun_ray_origin":"Sun rays","gs.sun_ray_origin.inner":"From the inner window corners","gs.sun_ray_origin.outer":"From the outer window corners","gs.about_version":"Houseplan Card v{v}","gs.about_github":"GitHub · docs & issues","gs.about_telegram":"Telegram chat","support.title":"Help & feedback","space.bg_color":"Background around the plan","space.bg_inherit":"Inherit general","space.bg_mode":"Plan background","space.bg_mode.help":"Inherit the general background or override this space with a static colour or “Follows the Sun”.","space.bg_mode.help.aria":"Help: space background","space.north":"North on the plan","space.north.help":"Overrides general north for this space; the angle is measured clockwise from the plan's upward vertical and is used by window rays.","space.north.help.aria":"Help: north for this space","space.sun_rays":"Sunlight through windows","space.sun_inherit":"General settings","space.sun_on":"On","space.sun_off":"Off","canvas.far_objects":"{n} object(s) far from the plan","canvas.show_far":"Show","canvas.home_tip":"The plan is over there — click to fit it","gs.grid_group":"Plan maintenance","gs.align_all":"Optimize plans","gs.align_title":"Optimize plans","gs.align_none":"All plans already use the current optimized data model.","gs.optimize_no_automatic_changes":"There are no automatic changes to apply. Review the items below.","gs.align_count":"{n} of {total} elements will move, by at most {cm} cm.","gs.align_where":"The largest shift is in “{s}”.","gs.align_turned":"Openings whose angle is corrected: {n}.","gs.align_preflight_failed":"Could not safely verify the geometry of the following spaces: {spaces}{more}.","gs.align_preflight_hint":"Plans were not changed. Copy the diagnostics with the button below and attach them to the bug report together with a space export.","gs.preflight_reason_prepare-exception":"Could not prepare the space geometry (exception while building the model)","gs.preflight_reason_wall-null":"The wall body did not build (the union came back empty)","gs.preflight_reason_wall-degraded-extra":"The wall body degraded with extra geometry","gs.preflight_reason_wall-failed-core":"The wall body core failed to assemble","gs.preflight_reason_wall-exception":"Wall construction threw an exception","gs.preflight_reason_floor-null":"The floor outline did not build","gs.preflight_reason_floor-exception":"Floor construction threw an exception","gs.preflight_copy":"Copy diagnostics","gs.preflight_copied":"Diagnostics copied","gs.preflight_update_hint":"The card and integration versions differ — update House Plan and retry.","gs.align_preflight_space":"Space {n}","gs.align_preflight_more":", and {n} more","gs.optimize_changes":"Model migrations: {m}; spaces updated: {c}; noisy coordinate values removed: {p}; merged real-wall fragments: {w}; merged zero-thickness wall fragments: {s}; independent walls: {i}.","gs.zero_walls_migrated":"Virtual wall spans converted: {n}.","gs.wall_segments_migrated":"Wall segments stabilised: {n}.","gs.room_drafts_migrated":"Unfinished contours converted to ordinary walls: {drafts}; wall segments: {segments}.","gs.optimize_lattice_summary":"Noisy coordinate values canonicalized: {n}; maximum movement: {cm} cm.","gs.optimize_lattice_space":"{space}: coordinate values canonicalized: {n}; off-grid values left unchanged: {far}.","gs.optimize_coincident_partitions":"Hidden independent wall sections absorbed into room walls: {n}.","gs.optimize_openings_rehosted":"Openings reattached to room walls: {n}.","gs.optimize_walls_straightened":"Walls straightened: {n}; maximum movement: {cm} cm.","gs.optimize_walls_straightened_where":"Largest wall correction: {s}.","gs.optimize_walls_straighten_skipped":"Near-axis walls left unchanged because they could not be repaired safely: {n}.","gs.optimize_glow_migration":"Legacy Glow: {spaces} spaces → no data fill + independent Glow; {rooms} rooms → inherited data fill + independent Glow.","gs.optimize_references":"References repaired: spaces — {spaces}; rooms — {rooms}; positions — {positions}; devices detached from missing spaces — {detached}.","gs.optimize_reference_more":", and {n} more","gs.optimize_orphans_removed":"Forgotten records removed: {total} — room labels: {rooms}; devices: {devices}; group markers: {groups}. They belonged to spaces deleted earlier.","gs.optimize_live_positions":"Old positions in deleted spaces belong to existing objects: {n}{names}. They will be kept.","gs.optimize_live_positions_remove":"Old positions in deleted spaces belong to existing objects: {n}{names}. They are selected for removal.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Remove old positions","gs.optimize_live_keep":"Keep old positions","gs.optimize_live_selected":"Old positions will be removed after Optimize is applied.","gs.optimize_unverified":"Could not safely verify positions: {n}. They were left unchanged.","gs.optimize_registry_limited":"Full administrator access to the Home Assistant registries is required for a safe check.","gs.optimize_vacuum_warning":"Vacuum room mappings that still need review: {n}.","gs.optimize_details":"Details","gs.optimize_details_more":"And {n} more records.","gs.optimize_detail_removed":"will be removed","gs.optimize_detail_live":"will be kept","gs.optimize_detail_unverified":"not verified","gs.optimize_detail_room_label":"room label","gs.optimize_detail_device":"device","gs.optimize_detail_group":"group marker","gs.optimize_detail_unknown":"unknown owner","gs.optimize_detail_item":"{status}: {kind} {id}; old space {space}","gs.align_warn":"Elements deliberately placed between grid nodes will move. One undo is available after the operation, only until the next plan edit.","gs.align_run":"Optimize","gs.align_done":"Plans optimized: {n} elements moved, {m} records maintained, {r} references repaired","gs.optimize_undo":"Undo last optimization","gs.optimize_undone":"The last optimization was undone","decor.furniture":"Furniture","decor.image":"Image","decor.image_title":"Custom images","decor.image_upload":"Upload image","decor.image_replace":"Replace image","decor.image_uploading":"Uploading…","decor.image_asset":"Image file","decor.image_pick_hint":"Upload an image or choose one already used in House Plan.","decor.image_place_hint":"Click on the plan to place the image.","decor.image_none":"No uploaded images yet.","decor.image_unavailable":"Image unavailable","decor.image_used":"Used in {n} objects","decor.image_upload_failed":"Could not upload the image: {err}","decor.image_error_capacity":"The custom image storage limit has been reached.","decor.image_in_use":"Remove every placed copy before deleting this image.","decor.image_delete_title":"Delete image file?","decor.image_delete_message":"Delete “{name}” from House Plan? This cannot be undone.","furn.title":"Furniture library","furn.symbol":"Symbol","furn.group_furniture":"Furniture","furn.group_appliance":"Appliances","furn.group_sanitary":"Plumbing","furn.group_other":"Other","furn.width":"Width","furn.depth":"Depth","furn.back_to_categories":"All categories","furn.pick_hint":"Choose a category, then a symbol.","furn.place_hint":"Click on the plan — the piece lands against the nearest wall. Shift places it free.","furn.cat_air_conditioner":"Air conditioners","furn.cat_armchair":"Armchairs","furn.cat_bathtub":"Bathtubs","furn.cat_bed":"Beds","furn.cat_bidet":"Bidets","furn.cat_boiler":"Water heaters","furn.cat_chair":"Chairs","furn.cat_coffee_table":"Coffee tables","furn.cat_computer":"Computer","furn.cat_cooktop":"Cooktops","furn.cat_dining_table":"Dining tables","furn.cat_dishwasher":"Dishwashers","furn.cat_dryer":"Dryers","furn.cat_fireplace":"Fireplaces","furn.cat_fridge":"Refrigerators","furn.cat_hood":"Cooker hood","furn.cat_kitchen_cabinet":"Kitchen cabinets","furn.cat_kitchen_sink":"Kitchen sinks","furn.cat_nightstand":"Cabinets","furn.cat_oven":"Oven","furn.cat_plant":"Plants","furn.cat_rug":"Rugs","furn.cat_shelving":"Shelving","furn.cat_shower":"Showers","furn.cat_sink":"Sinks","furn.cat_sofa":"Sofas","furn.cat_stairs":"Stairs","furn.cat_toilet":"Toilets","furn.cat_tv":"Televisions","furn.cat_wardrobe":"Wardrobes","furn.cat_washer":"Washing machines","furn.cat_work_table":"Desks","furn.sym_cactus":"Cactus","furn.sym_computer":"Computer","furn.sym_hood":"Cooker hood","furn.sym_oven":"Oven","furn.sym_sofa":"Two-seat sofa","furn.sym_sofa_three_seat":"Three-seat sofa","furn.sym_sofa_corner_right":"Right sectional sofa","furn.sym_armchair":"Soft armchair","furn.sym_armchair_office":"Office chair","furn.sym_coffee_table":"Rectangular coffee table","furn.sym_coffee_table_round":"Round coffee table","furn.sym_coffee_table_oval":"Oval coffee table","furn.sym_coffee_table_rounded":"Rounded coffee table","furn.sym_table_dining":"Rectangular dining table","furn.sym_table_round":"Round table","furn.sym_table_dining_oval":"Oval dining table","furn.sym_table_dining_rounded":"Rounded dining table","furn.sym_chair":"Chair","furn.sym_chair_bar":"Bar stool","furn.sym_desk":"Rectangular desk","furn.sym_desk_corner":"Corner desk","furn.sym_bed_double":"Double bed","furn.sym_bed_single":"Single bed","furn.sym_nightstand":"Bedside table","furn.sym_cabinet_tv":"TV cabinet","furn.sym_cabinet_shoe":"Shoe cabinet","furn.sym_cabinet_sink":"Sink cabinet","furn.sym_wardrobe":"Wardrobe","furn.sym_bookshelf":"Bookcase","furn.sym_wall_unit":"Wall unit","furn.sym_kitchen_floor":"Kitchen floor module","furn.sym_kitchen_floor_corner":"Kitchen floor corner module","furn.sym_kitchen_wall":"Kitchen wall module","furn.sym_kitchen_wall_corner":"Kitchen wall corner module","furn.sym_shelf_floor":"Floor shelving unit","furn.sym_shelf_wall":"Wall shelf","furn.sym_fridge":"Fridge","furn.sym_stove":"Four-burner cooktop","furn.sym_cooktop_two":"Two-burner cooktop","furn.sym_dishwasher":"Dishwasher","furn.sym_washer":"Washing machine","furn.sym_dryer":"Tumble dryer","furn.sym_tv":"TV on stand","furn.sym_tv_wall":"Wall-mounted TV","furn.sym_ac":"Air conditioner","furn.sym_water_heater":"Water heater","furn.sym_toilet":"Floor-standing toilet","furn.sym_toilet_built_in":"Built-in toilet","furn.sym_bathtub":"Rectangular bathtub","furn.sym_bathtub_corner":"Corner bathtub","furn.sym_shower":"Shower","furn.sym_sink":"Washbasin","furn.sym_kitchen_sink":"Single kitchen sink","furn.sym_kitchen_sink_double":"Double kitchen sink","furn.sym_bidet":"Floor-standing bidet","furn.sym_bidet_built_in":"Built-in bidet","furn.sym_stairs":"Stairs","furn.sym_fireplace":"Fireplace","furn.sym_plant":"Plant","furn.sym_rug":"Rug","common.yes":"Yes","common.no":"No","vac.diag_source":"Source","vac.diag_platform":"Integration","vac.diag_status":"Status","vac.diag_position":"Position","vac.diag_rooms":"Rooms","vac.diag_rooms_value":"{total} · {matched} names match · {readiness}","vac.autocal_ready":"auto-calibration available","vac.autocal_not_ready":"need 3 matching names","vac.diag_path":"Integration path","vac.diag_map":"Map ID","vac.source_none":"not selected","vac.source_status_ok":"Ready","vac.source_status_missing":"Missing","vac.source_status_disabled":"Disabled in Home Assistant","vac.source_status_unavailable":"Unavailable","vac.source_status_unverified":"Cannot verify with current permissions","vac.source_status_unsupported":"No position data","vac.source_status_none":"No source","vac.source_banner_missing":"The saved source no longer exists. It was not replaced automatically; choose another source or restore it in Home Assistant.","vac.source_banner_disabled":"The saved source is disabled in Home Assistant. Enable it there or choose another source.","vac.source_banner_unverified":"Current Home Assistant permissions cannot verify this saved source. It remains pinned and will not be replaced automatically.","vac.choose_source":"Choose source","vac.source_auto":"Automatic","vac.source_auto_hint":"Use a compatible entity from this device","vac.all_cameras":"All cameras","vac.all_cameras_warn":"A camera may not provide robot data. Choose one only if it is your vacuum map.","vac.all_cameras_empty":"No other camera entities found.","vac.platform_unknown":"unknown integration","vac.cap_position":"position","vac.cap_rooms_short":"rooms","vac.cap_path":"path","vac.cap_map":"map ID","vac.cap_none":"no robot data detected","vac.xcme_hint":"Enable these Xiaomi Cloud Map Extractor attributes:","vac.documentation":"Documentation","vac.residual_title":"Check automatic calibration","vac.residual_message":"The matched rooms disagree by up to {error}. Apply this approximate calibration, refine it manually, or cancel without changing the saved setup.","vac.apply_proposal":"Apply","gs.backup_group":"Backup and transfer","backup.export_open":"Export","backup.import_open":"Import","backup.export_title":"Export House Plan","backup.import_title":"Import House Plan","backup.export_hint":"Choose whether the backup should contain the whole House Plan configuration or only the current space.","backup.full":"Full backup","backup.current_space":"Current space","backup.current_space_title":"Current space: {title}","backup.no_current_space":"No current space","backup.plan_only":"Plan only","backup.plan_only_hint":"Keep rooms, walls, openings, decor and room-label positions without devices or Home Assistant bindings.","backup.plan_only_preview":"This file contains the plan only","backup.privacy_warning":"The archive keeps names, Home Assistant identifiers and exact coordinates. Internal plans and attachments are referenced, not embedded; runtime states and vacuum trails are not included.","backup.download":"Download JSON","backup.export_done":"Backup downloaded","backup.reading":"Checking the backup…","backup.revalidated":"The plan changed after this preview. The summary was refreshed; review it and confirm again.","backup.error.support_invalid_message":"Check the support message and try again.","backup.error.support_package_too_large":"The anonymized support package exceeds the 8 MiB limit.","backup.error.support_preview_expired":"The support attachment preview expired or is no longer available.","backup.error.support_rate_limited":"Too many support reports or previews were requested. Try again later.","backup.error.support_rejected":"The report did not pass support service validation.","backup.error.support_unavailable":"The private support service is temporarily unavailable.","backup.error.unauthorized":"You do not have permission to export or import this plan.","backup.error.not_ready":"House Plan is not ready yet. Try again in a moment.","backup.error.too_large":"The backup exceeds the 8 MiB limit.","backup.error.invalid_json":"The selected file is not valid JSON.","backup.error.invalid_format":"The selected file is not a House Plan backup.","backup.error.invalid_image":"The image is damaged or does not match its format.","backup.error.unsupported_export_version":"This backup format is not supported by the installed version.","backup.error.unsupported_image":"Use a supported PNG, JPEG, WebP or SVG image.","backup.error.future_model":"The backup was created by a newer House Plan data model.","backup.error.invalid_config":"The backup contains an invalid House Plan configuration.","backup.error.wall_model_migration_blocked":"The backup wall model could not be upgraded safely. Optimize the source plan first, then export it again.","backup.error.invalid_layout":"The backup contains invalid object positions.","backup.error.invalid_content":"The backup contains invalid or inconsistent content references.","backup.error.space_not_found":"The selected space no longer exists.","backup.error.capacity_exceeded":"Adding this backup would exceed the plan limits.","backup.error.preview_expired":"The preview expired. Select the backup file again.","backup.error.preview_owner_mismatch":"This preview belongs to another Home Assistant user.","backup.error.conflict":"The plan changed after the preview. Review the refreshed summary.","backup.error.content_confirmation_required":"Confirm that unavailable local content may be detached.","backup.error.commit_failed":"The backup could not be applied safely. The previous plan was restored or is pending recovery.","backup.error.missing_plan":"A referenced plan file disappeared after the preview. Review the backup again.","backup.error.missing_content":"A referenced local attachment disappeared after the preview. Review the backup again.","backup.error.marker_control_missing":"A linked plan light is missing from the backup.","backup.error.marker_control_not_light":"A linked plan target is no longer marked as a light source.","backup.error.marker_control_self":"A light source cannot control itself.","backup.error.marker_control_cycle":"The backup contains a circular chain of light controls.","backup.error.duplicate_marker_control":"The backup contains a duplicate plan-light link.","backup.error.no_backup":"There is no import or optimization snapshot to restore.","backup.error.in_use":"The item is still in use","backup.error.invalid_data":"The request carries invalid data","backup.error.invalid_light_entity":"The leading light must be a light.* or switch.* entity","backup.error.invalid_marker_control":"Invalid marker control reference","backup.error.invalid_name":"The name is invalid","backup.error.invalid_partition_opening_host":"The opening must keep its partition host","backup.error.invalid_partition_opening_jamb_margin":"The opening leaves no physical jamb at the wall end","backup.error.invalid_passage_fields":"An open passage cannot carry door-only settings","backup.error.invalid_space_id":"Unknown space","backup.error.invalid_toggle_entity":"The toggle entity must be light.* or switch.*","backup.error.invalid_value_badge":"Invalid value badge settings","backup.error.invalid_value_badge_attribute":"Invalid value badge attribute","backup.error.invalid_value_badge_position":"Invalid value badge position","backup.error.invalid_value_badge_source":"Invalid value badge source","backup.error.invalid_vacuum_map_route":"Check how the robot's maps are assigned to spaces.","backup.error.invalid_value_source":"Invalid value source","backup.error.invalid_value_source_attribute":"Invalid value source attribute","backup.error.io_error":"A file operation failed on the server","backup.error.not_toggleable":"This device cannot be toggled","backup.error.nothing_to_repair":"Nothing to repair","backup.error.space_in_use":"The space is still referenced","backup.error.value_badge_source_required":"The value badge needs a source","backup.error.wall_model_client_outdated":"The plan was updated elsewhere — reload the page","backup.same_source":"Created on this Home Assistant instance","backup.foreign_source":"Created on another Home Assistant instance","backup.created":"Created: {value}","backup.versions":"Card {card}; integration {integration}; data model {model}","backup.count_spaces":"Spaces: {n}","backup.count_rooms":"Rooms: {n}","backup.count_walls":"Walls: {n}","backup.count_openings":"Openings: {n}","backup.count_decor":"Decor objects: {n}","backup.count_markers":"Devices: {n}","backup.count_layout":"Positions: {n}","backup.bindings":"Bindings — devices: {device}, entities: {entity}, virtual: {virtual}; positions without a space: {legacy}","backup.binding_status":"Target status — active: {active}, disabled: {disabled}, missing: {missing}","backup.missing_areas":"Areas missing on the target: {areas}","backup.dropped_marker_links":"Plan-light links outside this transferred space were omitted: {n}.","backup.room_drafts_migrated":"Legacy unfinished contours converted to ordinary walls: {drafts}; wall segments: {segments}.","backup.repaired_target_refs":"Existing references restored by this space import: {n}.","backup.preserved_unresolved_refs":"References that could not be restored unambiguously were preserved: {n}.","backup.preserved_unresolved_hint":"No data was guessed or deleted. After the import, run Optimize plans to inspect the remaining references.","backup.import_details":"Import reference details","backup.import_detail.incoming_remapped":"References updated inside the imported copy: {n}","backup.import_detail.target_repaired":"Existing references restored: {n}","backup.import_detail.preserved_unresolved":"Unresolved references preserved: {n}","backup.import_detail.collisions":"Destination conflicts preserved safely: {n}","backup.import_detail.dropped_links":"Incoming links omitted by transfer rules: {n}","backup.import_detail.bounded_lineages":"Overly nested identifiers left bounded: {n}","backup.replace_warning":"This replaces the current configuration and layout. Uploaded files are never deleted. One undo remains available until the next plan edit.","backup.foreign_bookkeeping":"Instance-specific known/new-device bookkeeping will not be imported.","backup.final_name":"New space name","backup.target_settings":"The target instance's global settings remain unchanged.","backup.duplicates":"Bindings already present: {n}","backup.skip":"Skip duplicate devices","backup.virtual_copy":"Add safe static virtual copies","backup.content":"Referenced content","backup.decor_images_summary":"Custom images: {objects} objects, {assets} files; missing files: {missing}.","backup.content_available":"available locally","backup.content_external":"external link","backup.content_detach_required":"will be detached","backup.confirm_detach":"I understand that unavailable internal plans and attachments will be detached from the imported configuration.","backup.confirm_missing_images":"I understand that missing custom images will remain as repair placeholders and other unavailable local files will be detached.","backup.replace":"Replace","backup.add":"Add space","backup.space_done":"Space imported: {rooms} rooms, {markers} devices, {refs} existing references restored","backup.full_done":"Backup restored: {spaces} spaces, {rooms} rooms, {markers} devices","backup.undo_import":"Undo last full import","backup.import_undone":"Full import undone","backdrop.large_title":"Large image","backdrop.large_body":"This image is {w}×{h} ({fileMb} MB file) and needs about {decodedMb} MB of memory to display. On tablets this can crash the page.","backdrop.unknown_body":"The image dimensions could not be read — the file may be damaged. Continuing may crash the page on tablets.","backdrop.reduced_dimensions":"Reduced copy: {w}×{h} px.","backdrop.use_downscaled":"Upload a reduced copy","backdrop.reducing":"Reducing…","backdrop.keep_original":"Keep the original","backdrop.too_large_title":"Image is too large","backdrop.too_large_body":"This image exceeds what browsers can display ({w}×{h}, limit {limit} px per side). Please reduce it in a desktop editor and upload again.","backdrop.downscale_failed":"Could not create the reduced copy. The original plan was not changed.","gs.card_display":"Display","gs.card_zigbee":"Zigbee links","gs.card_fills":"Room fill colors","gs.card_plan":"Plan","gs.card_data":"Data","gs.card_fills.help.aria":"About room fill colors","gs.backup_group.help.aria":"About backup and transfer","gs.grid_group.help.aria":"About plan maintenance","gs.backup_group.help":"Download a portable JSON backup or preview and import a backup made by House Plan.","gs.grid_group.help":"Updates data models, aligns plan elements to the grid and merges redundant wall fragments. An exact report is shown before anything is stored.","gs.card_fills.help":"Fill colors apply to every space; each color has its own opacity. Which fill mode a space uses is set in that space's dialog.","space.card_basics":"Basics","space.card_sun":"Sun & light","marker.card_basics":"Basics","marker.card_tap":"Tap action","marker.card_light":"Light and glow","marker.card_appearance":"Appearance","marker.card_details":"Details"};const cp=new WeakSet,hp=new WeakSet;function dp(e,t,i){const n=i?t.state(i):"ready";return i&&"pending"===n?(hp.has(e)||(e.inert=!0,e.setAttribute("aria-busy","true"),hp.add(e)),t.ensure(i).then(()=>{e.isConnected&&e.requestUpdate()}),cp.has(e)?"warm":"cold"):(hp.delete(e)&&(e.inert=!1,e.removeAttribute("aria-busy")),i&&(e.setAttribute("lang","fallback"===n?"en":i),cp.add(e)),"ready")}function up(){return j``}const pp=[{code:"en",nativeLabel:"English",dictionary:lp},{code:"ru",nativeLabel:"Русский",dictionary:{"editor.context_actions":"Действия: {object}","editor.tool_options":"Параметры инструмента: {tool}","editor.palette":"Палитра: {tool}","editor.open_group":"Группа инструментов: {group}","editor.group_active":"{group} — активно: {item}","editor.disabled_action":"{action} недоступно: {reason}","editor.loading":"Загрузка…","editor.loading_aria":"Редактор плана загружается","editor.load_failed":"Не удалось загрузить редактор.","editor.refresh_advice":"Обновите страницу и повторите попытку.","editor.retry_advice":"Проверьте сеть и нажмите ещё раз.","version_mismatch.title":"Версии House Plan не совпадают","version_mismatch.body":"Если Home Assistant ещё перезапускается, дождитесь завершения, затем перезагрузите эту страницу.","version_mismatch.frontend":"Карточка","version_mismatch.backend":"Интеграция","version_mismatch.reload":"Перезагрузить страницу","color_picker.title":"Выбор цвета","color_picker.hue":"Оттенок","color_picker.saturation":"Насыщенность","color_picker.value":"Яркость","color_picker.hex":"Цвет HEX","color_picker.invalid_hex":"Введите цвет HEX из 3 или 6 цифр","color_picker.confirm":"ОК","btn.properties":"Свойства","btn.keep_as_walls":"Оставить стенами","btn.delete_room_keep_walls":"Удалить комнату, оставить стены","btn.delete_room_with_walls":"Удалить комнату и стены","title.markup_select":"Выбор и редактирование стен и колонн","title.markup_column":"Колонна: кликните точку сетки для квадратной колонны","markup.partition":"Перегородка","markup.column":"Колонна","markup.hint_column":"кликните точку сетки, чтобы поставить квадратную колонну","history.wall_segment":"Добавление отрезка стены","history.column_add":"Добавление колонны","history.physical_edit":"Изменение физического объекта","history.physical_delete":"Удаление физического объекта","history.physical_move":"Перемещение физического объекта","history.wall_face_batch":"Создание комнат из стен","toast.column_duplicate":"Колонна с тем же центром и внешним размером уже существует","physical.partition_properties":"Свойства перегородки","physical.column_properties":"Свойства колонны","physical.shape":"Форма","physical.square":"Квадрат","physical.circle":"Круг","physical.diameter":"Диаметр","physical.side":"Сторона","physical.rotation":"Угол поворота","physical.length":"Длина","physical.allowed_range":"Допустимо: {min}–{max} {unit}","physical.column_size_title":"Внешняя сторона квадратной колонны, создаваемой кликом (1–150 см).","card.title":"План дома","count.devices":"{n} устр.","empty.no_spaces":"Пространств пока нет.","nav.spaces":"Пространства House Plan","empty.add_first":"Добавьте первое пространство и загрузите план этажа.","empty.read_only":"Пространства не настроены. Попросите администратора добавить первое.","empty.install":"Установите интеграцию House Plan и добавьте запись в «Устройства и службы».","btn.add_space":"Добавить пространство","btn.cancel":"Отмена","btn.save":"Сохранить","btn.close":"Закрыть","btn.delete":"Удалить","btn.copy":"Копировать","btn.edit":"Редактировать","btn.open_in_ha":"Открыть в HA","btn.reset":"Сброс","btn.attach":"Прикрепить…","btn.upload":"Загрузить…","btn.replace":"Заменить…","title.zoom_in":"Приблизить","title.zoom_out":"Отдалить","title.zoom_fit":"Вписать всё","title.configure_space":"Настроить пространство","title.add_space":"Добавить пространство","title.markup_add":"Стены: рисуйте непрерывную цепочку; каждый принятый отрезок сохраняется отдельно. Shift фиксирует 45°","title.markup_merge":"Объединить: клик по одной комнате, затем по соседней с общей стеной","title.markup_split":"Разделить комнату: клик по комнате, затем две точки на её стенах","title.markup_delroom":"Удалить комнату: кликните внутри комнаты и подтвердите удаление","markup.add":"Стены","markup.merge":"Объединить","markup.split":"Разделить","markup.resize":"Размер","title.markup_resize":"Изменение размера комнат: тяните доступную ручку горизонтальной или вертикальной стены","markup.hint_resize":"тяните доступную ручку стены · стена упирается в первую небезопасную позицию · Esc — отмена · Ctrl+Z — отмена шага","resize.disabled.diagonal":"Стена расположена под углом: Resize поддерживает только горизонтальные и вертикальные стены","resize.disabled.side-angle":"Примыкающая стена расположена под углом: для Resize обе примыкающие стены должны образовывать прямой угол","resize.disabled.duplicate-physical-wall":"Стену перекрывает отдельная перегородка или колонна; удалите или переместите её перед изменением размера","resize.disabled.partial-shared":"Соседняя комната использует только часть этой стены, поэтому её нельзя безопасно двигать как одну общую стену","resize.disabled.unequal-shared":"У соседней комнаты другие конечные точки или длина стены, поэтому стены нельзя безопасно двигать вместе","resize.disabled.multiple-rooms":"Перемещение затронуло бы больше двух комнат","resize.disabled.thickness-conflict":"Толщину стены нельзя безопасно сохранить","resize.disabled.opening-conflict":"Проём на этой стене нельзя безопасно переместить","resize.disabled.invalid-geometry":"Эту стену нельзя переместить без изменения структуры плана","resize.limit_stopped":"Стена остановлена: дальше нарушается ограничение стыков","resize.commit_failed":"Изменение размера отменено: итоговый план не прошёл проверку геометрии","resize.preview_failed":"Стена остановлена в последней безопасной позиции: геометрию плана нельзя сохранить без потерь","markup.opening":"Проём","markup.delete_room":"Удалить комнату","history.undo":"Отменить","history.redo":"Повторить","history.undo_named":"Отменить: {name} (Ctrl+Z)","history.redo_named":"Повторить: {name} (Ctrl+Shift+Z / Ctrl+Y)","history.undo_empty":"Нет операций для отмены","history.redo_empty":"Нет операций для повтора","history.undone":"Отменено: {name}","history.redone":"Повторено: {name}","history.add_room":"Создание комнаты","history.split_room":"Разделение комнаты","history.merge_rooms":"Объединение комнат","history.resize_room":"Изменение размера комнаты","history.wall_thickness":"Изменение толщины стены","history.add_opening":"Добавление дверного или оконного проёма","history.edit_opening":"Изменение проёма","history.move_opening":"Перемещение проёма","history.delete_opening":"Удаление проёма","history.delete_room_keep_walls":"Удаление комнаты с сохранением стен","history.delete_room_with_walls":"Удаление комнаты и её стен","history.decor_add":"Добавление объекта декора","history.decor_edit":"Изменение объекта декора","history.decor_move":"Перемещение объекта декора","history.decor_transform":"Трансформация объекта декора","history.decor_delete":"Удаление объекта декора","history.backdrop_transform":"Трансформация подложки плана","history.device_move":"Перемещение: {name}","history.device_stale":"История позиций больше неприменима и была очищена","opening.new":"Новый проём","opening.edit":"Проём","opening.door":"Дверь","opening.window":"Окно","opening.gate":"Ворота","opening.passage":"Открытый проём","opening.passage_binding_warning":"При сохранении датчик открытия и замок будут удалены.","opening.invalid_passage_fields":"У открытого проёма на плане «{room}» есть недопустимые параметры: {fields}.","opening.type_label":"Тип","opening.length_label":"Длина, см","opening.contact_label":"Датчик открытия","opening.lock_label":"Замок","opening.none":"— нет —","opening.search_ph":"Поиск: имя или entity_id…","opening.invert":"Инвертировать открыто/закрыто","opening.flip_h":"Петли с другой стороны","opening.flip_v":"Открывается в другую сторону","opening.open":"Открыто","opening.closed":"Закрыто","opening.locked":"Заперто","opening.unlocked":"Не заперто","opening.state_unknown":"недоступно","opening.no_entities":"Датчики не привязаны — статичный символ на плане.","toast.opening_no_wall":"Кликните рядом со стеной комнаты или независимой стеной","opening.host_partition":"Независимая стена","opening.partition_orphan":"Независимая стена этого проёма больше не существует","opening.partition_jamb_margin":"Оставьте от края проёма до торца стены минимум {distance}","opening.rebind_partition":"Привязать к другой независимой стене","confirm.delete_partition_openings_title":"Удалить стену и проёмы?","confirm.delete_partition_openings_body":"В стене есть проёмы: {count}. Они будут удалены вместе со стеной.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.hint_points":"точек: {n} · Shift — шаг 45° · Esc — завершить цепочку · Ctrl+Z — убрать точку · при замыкании будет предложена комната","markup.hint_start":"кликните точку сетки, чтобы начать цепочку стен","tip.lqi":"средний сигнал zigbee:","tip.area":"площадь: {value}","info.device_header":"Устройство на плане","info.model":"Модель","info.state":"Состояние","info.link":"Ссылка","info.manuals":"Инструкции","info.none":"Нет дополнительной информации","marker.new_device":"Новое устройство","marker.name_label":"Название","marker.name_ph":"Название","marker.binding_label":"Привязка к устройству HA","marker.binding_disabled":"деактивировано в Home Assistant","marker.virtual_option":"Виртуальное устройство (без привязки)","marker.search_ph":"Поиск устройства / группы…","marker.nothing_found":"ничего не найдено","marker.room_label":"Комната","marker.room_choose":"— выберите комнату —","marker.room_auto":"— по зоне устройства (авто) —","marker.icon_label":"Иконка","marker.icon_ph":"mdi:… (пусто = авто)","marker.display_label":"Отображение","display.badge":"Значок + состояние","display.icon_ripple":"Значок + состояние и активность","display.static_icon":"Всегда статичный значок","display.value_static_icon":"Значение + статичный значок","marker.display_hint_badge":"Значок и динамическая подложка показывают состояние устройства без обычной пульсации активности. Красная тревога сохраняется.","marker.display_hint_icon_ripple":"Значок, динамическая подложка и пульсация: короткая — для событий, постоянная — для работы, движения или присутствия. Красная тревога имеет отдельный приоритет.","marker.display_hint_value":"Значок заменяется выбранным или автоматически найденным значением Home Assistant; подложка продолжает показывать состояние. Красная тревога сохраняется.","marker.display_hint_static_icon":"Подложка в цветах темы и значок всегда остаются одинаковыми. Состояния, активность, недоступность и тревоги не меняют отображение.","marker.display_hint_value_static_icon":"Маркер показывает выбранное значение, а подложка остаётся в цветах темы. Состояния, активность, недоступность и тревоги не меняют цвет маркера.","marker.static_alarm_warning":"Это устройство может сообщать о тревогах. Статичный режим скрывает визуальную тревогу маркера.","marker.preview.title":"Предпросмотр отображения","marker.preview.actual":"Сейчас","marker.preview.example":"Пример","marker.preview.integration":"Интеграция","marker.preview.source":"Источник отображения","marker.preview.current_state":"Текущее состояние","marker.preview.result":"На плане","marker.preview.details":"Подробнее об источниках","marker.preview.select_source":"Выберите устройство или сущность Home Assistant, чтобы увидеть фактическое отображение.","marker.preview.unknown_provider":"Интеграция неизвестна","marker.preview.virtual_provider":"House Plan · виртуальное устройство","marker.preview.no_source":"Нет активного источника","marker.preview.no_state":"Нет текущего состояния","marker.preview.mixed_states":"Несколько разных состояний","marker.preview.multiple_sources":"Источников: {n}","marker.preview.more_sources":"ещё {n}","marker.preview.scaled":"Предпросмотр уменьшен до {n}%, чтобы поместиться. Сохранённый размер не изменится.","marker.preview.demo_short":"Показать краткую активность","marker.preview.demo_continuous":"Показать постоянную активность","marker.preview.stop_continuous":"Остановить постоянную активность","marker.preview.demo_short_notice":"Пример краткой активности; фактическое состояние устройства не меняется.","marker.preview.demo_continuous_notice":"Пример постоянной активности; фактическое состояние устройства не меняется.","marker.preview.demo_already_visible":"Текущее состояние уже показывает реальную активность или тревогу.","marker.preview.reduced_motion":"В системе включено уменьшение движения, поэтому обычная активность показана точкой.","marker.preview.reason.neutral":"Нейтральная тёмная подложка","marker.preview.reason.working":"Жёлтая подложка: устройство сейчас работает","marker.preview.reason.working_activity":"Жёлтая подложка и эффект активности: устройство сейчас работает","marker.preview.reason.open":"Оранжевая подложка: физически открыто или разблокировано","marker.preview.reason.cover_icon_state":"Нейтральная подложка; состояние и значок определяет сущность шторы или заслонки","marker.preview.reason.presence":"Эффект активности, пока обнаружено присутствие","marker.preview.reason.event":"Короткий эффект активности после события","marker.preview.reason.transition":"Эффект активности во время движения или смены состояния","marker.preview.reason.media_neutral":"Медиаустройство остаётся на нейтральной тёмной подложке, пока доступно","marker.preview.reason.unavailable":"Приглушённая нейтральная подложка: отключено или недоступно","marker.preview.reason.alarm":"Красная тревожная подложка; тревога отображается всегда","marker.preview.reason.live_states_disabled":"Оформление по живым состояниям отключено в настройках карточки","marker.preview.reason.value_no_state":"Нет подходящего значения состояния — вместо него показан значок","marker.preview.reason.value_ambiguous_sources":"Подходит несколько источников значения — вместо него показан значок","marker.preview.reason.value_non_scalar":"Источник вернул не простое значение — вместо него показан значок","marker.preview.reason.value_virtual":"У виртуального устройства нет значения HA — вместо него показан значок","marker.preview.reason.vacuum_live_plan_only":"Живая позиция и след пылесоса доступны только на полном плане","marker.preview.reason.hidden_design_preview":"Устройство скрыто на плане, но его оформление видно в предпросмотре","marker.preview.reason.composite_power_source":"Состояние берётся из сущности питания устройства; вспомогательные переключатели не учитываются","marker.preview.reason.activity_display_disabled":"Выбранный режим отображения не показывает обычные эффекты активности","marker.preview.reason.ha_disabled":"Привязка отключена в Home Assistant, поэтому устройство будет скрыто на плане","marker.preview.reason.orphaned":"Сохранённая привязка Home Assistant больше не найдена","marker.preview.reason.static_icon":"Статичный режим: состояние устройства не меняет значок","marker.preview.reason.value_static_icon":"Статичный режим со значением: состояние устройства не меняет цвет маркера","marker.activity_color":"Цвет пульсации активности","marker.ripple_size":"Размер пульсации активности","marker.activity_alarm_note":"Цвет и размер относятся только к обычной активности и не влияют на красную тревогу.","marker.pulse_a11y_alarm":"Тревога","marker.pulse_a11y_event":"Недавнее событие","marker.pulse_a11y_presence":"Обнаружено присутствие","marker.pulse_a11y_transition":"Изменение состояния","marker.pulse_a11y_running":"Работает","marker.state_a11y_neutral":"Обычное состояние","marker.state_a11y_working":"Работает","marker.state_a11y_open":"Открыто","marker.state_a11y_locked":"Заблокировано","marker.state_a11y_unlocked":"Разблокировано","marker.state_a11y_alarm":"Тревога","marker.state_a11y_unavailable":"Недоступно","marker.lqi_a11y_low":"LQI {value}, слабый сигнал","marker.lqi_a11y_mid":"LQI {value}, средний сигнал","marker.lqi_a11y_high":"LQI {value}, сильный сигнал","marker.size_label":"Размер и поворот иконки","marker.angle_label":"Поворот","marker.model_label":"Модель","marker.model_ph":"напр. Aqara T&H","marker.link_label":"Ссылка","marker.desc_label":"Описание","marker.desc_ph":"Заметки, характеристики…","marker.manuals_label":"Инструкции (PDF и т.п.)","marker.sub_device":"устройство","marker.sub_z2m_group":" · Z2M-группа","marker.sub_group":"группа","marker.sub_helper":"хелпер","space.new":"Новое пространство","space.copy_title":"Копирование пространства","space.copy_name":"Название нового пространства","space.copy_fallback":"Пространство","space.copy_create":"Создать копию","space.copy_optimize_title":"Оптимизировать перед копированием?","space.copy_optimize_body":"Перед созданием «{name}» House Plan должен оптимизировать весь план, включая другие пространства. Продолжить?","space.copy_optimize_confirm":"Оптимизировать и скопировать","space.copy_error_changed":"План изменился, пока было открыто подтверждение. Проверьте его и повторите попытку.","space.copy_error_source_missing":"Исходного пространства больше нет. Снова откройте его настройки и повторите попытку.","space.copy_error_source_invalid":"House Plan не смог проверить все стены этого пространства. Исправьте исходное пространство и повторите попытку.","space.copy_error_spaces_limit":"В House Plan уже создано максимальное число пространств.","space.copy_error_partitions_limit":"В этом пространстве слишком много стен для копирования.","space.copy_error_openings_limit":"В этом пространстве слишком много проёмов для копирования.","space.copy_error_decor_limit":"В этом пространстве слишком много элементов подложки для копирования.","space.copy_error_columns_limit":"В этом пространстве слишком много колонн для копирования.","space.copy_error_opening_host":"Один из проёмов больше не привязан к стене. Исправьте или удалите его перед копированием.","space.copy_error_geometry":"Копия создаст небезопасную геометрию стен. Исправьте исходное пространство и повторите попытку.","space.copy_error_optimize_geometry":"Копирование остановлено: оптимизация всего плана небезопасна для одного из пространств.","space.header":"Пространство","space.title_label":"Название пространства","space.title_ph":"Например: Гараж","space.plan_label":"Подложка","space.no_plan":"нет подложки","space.plan_alt":"план","room.new":"Новая комната","room.name_label":"Отображаемое имя","room.name_ph":"Например: Терраса","room.area_label":"Зона Home Assistant","room.no_area_option":"— без зоны —","room.default_name":"Комната","device.unnamed":"без имени","device.light_group":"группа света","device.fallback":"устройство","device.virtual":"виртуальное устройство","confirm.delete_room_title":"Удалить комнату «{name}»?","confirm.delete_room_body":"Выберите, нужно ли оставить физические стены, принадлежащие только этой комнате. Общие с другой комнатой стены сохраняются всегда.","confirm.remove_marker_title":"Удалить устройство с плана?","confirm.remove_marker_body":"Устройство исчезнет полностью и перестанет участвовать в данных плана. Позже его можно будет добавить заново.","confirm.erase_decor":"Стереть объект «{kind}»? Действие можно отменить из истории редактора.","confirm.delete_space_title":"Удалить пространство?","confirm.delete_space_body":"Пространство, все его комнаты и вся разметка плана будут удалены.","confirm.delete_space_vac_routes":"Также будет снято сопоставление карт роботов: {count}.","space.delete_blocked":"Это пространство всё ещё используется устройствами: {n}. Сначала перенесите их в другое пространство или удалите.","toast.pos_save_failed":"Не удалось сохранить позицию: {err}","toast.no_entity":"У устройства нет подходящей сущности","toast.ha_disabled_action":"Деактивированный объект Home Assistant нельзя использовать на плане.","toast.ha_disabled_show_device":"Деактивированное в Home Assistant устройство нельзя показать на плане. Сначала активируйте его в Home Assistant.","toast.ha_disabled_show_entity":"Деактивированную в Home Assistant сущность нельзя показать на плане. Сначала активируйте её в Home Assistant.","toast.ha_disabled_add":"Деактивированный объект Home Assistant нельзя добавить на план. Сначала активируйте его в Home Assistant.","toast.ha_binding_unverified":"Статус объекта не удалось подтвердить по реестру Home Assistant. Отображение и действия временно недоступны.","toast.markup_needs_server":"Разметка доступна после переноса конфига на сервер","toast.space_order_changed":"Порядок изменён. Если где-то этаж карточки задан номером, проверьте такие панели.","toast.conflict":"Конфиг изменён в другом окне — данные обновлены, повторите последнее действие","toast.cfg_save_failed":"Не удалось сохранить конфиг: {err}","toast.room_overlap":"Контур накладывается на комнату «{name}» — комнаты не должны накладываться","toast.contour_cannot_close":"Контур нельзя замкнуть: он вырожден или пересекает сам себя","toast.merge_not_adjacent":"Объединять можно только комнаты с общей стеной","toast.rooms_merged":"Комнаты объединены в «{name}»","toast.split_pick_wall":"Начните разрез на стене комнаты","toast.split_bad_cut":"Разрез — от стены до стены внутри комнаты, без пересечения стен и самого себя","merge.header":"Объединение комнат","merge.hint":"У объединённой комнаты одно имя и одна зона. Вторая зона освобождается — её устройства уйдут с плана, пока их не заберёт другая комната.","merge.keep":"Оставить","merge.no_area":"без зоны","toast.room_saved":"Комната сохранена ({n}). Устройств добавлено: {added}. Обведите следующую или выйдите из разметки.","toast.room_saved_no_area":"Комната сохранена ({n}, без зоны). Обведите следующую или выйдите из разметки.","toast.marker_needs_server":"Редактирование устройств доступно после переноса конфига на сервер","toast.virtual_name_required":"Укажите имя виртуального устройства","toast.marker_saved":"Устройство сохранено","toast.marker_removed":"Устройство удалено с плана","toast.integration_missing":"Интеграция House Plan не установлена — управление недоступно","toast.plan_formats":"Поддерживаются SVG, PNG, JPG, WebP","toast.plan_required":"Загрузите подложку — план этажа обязателен","toast.space_added_onboard":"Пространство добавлено. Обведите комнаты: кликайте по точкам сетки и замкните контур.","toast.space_added":"Пространство добавлено","toast.space_copied":"Пространство «{name}» создано","toast.space_saved":"Пространство сохранено","toast.space_deleted":"Пространство удалено","toast.delete_failed":"Ошибка удаления: {err}","toast.error":"Ошибка: {err}","toast.toggle_target_unavailable":"Цель «{name}» недоступна — действие не выполнено","toast.toggle_targets_unavailable":"Цели недоступны: {names}. Действие не выполнено","toast.file_failed":"Файл «{name}» не загружен: {err}","toast.files_attached":"Прикреплено файлов: {n}","err.unknown":"неизвестная ошибка","err.code":"код {code}","err.too_large":"файл больше {mb} МБ","err.bad_ext":"недопустимый тип (нужен PDF/изображение)","err.unauthorized":"нужны права администратора","editor.title":"Заголовок","editor.default_floor":"Стартовое пространство","editor.default_floor_missing":"Стартовое пространство «{id}» больше не существует. Выберите другое.","editor.floor":"Закреплённое пространство","editor.floor_none":"— не закреплять —","editor.floor_index":"YAML-индекс {index} (сохранён)","fixed_floor.loading":"Загружаем закреплённое пространство…","fixed_floor.invalid_title":"Закреплённое пространство недоступно","fixed_floor.invalid_body":"Проверьте floor в конфигурации карточки. Настроенное значение: {value}","editor.icon_size":"Размер иконок, % ширины плана","editor.show_temperature":"Показывать температуру","editor.live_states":"Живые состояния (вкл/выкл, открыто…)","editor.light_pools":"Световые пулы и тени от стен","editor.show_signal":"Показывать сигнал zigbee (LQI)","editor.language":"Язык интерфейса","editor.lang_auto":"Авто (профиль HA)","title.icon_rules":"Правила иконок: какая MDI-иконка достаётся устройству по имени","rules.title":"Правила иконок","rules.hint":"Правила проверяются сверху вниз по строке «имя устройства + модель» (regex без учёта регистра); срабатывает первое совпадение. Если ничего не подошло — решает device class сущности, затем — иконка-заглушка.","rules.pattern_ph":"regex, напр. розетк|plug","rules.icon_ph":"mdi:power-socket-de","rules.add":"Добавить правило","rules.reset":"Сбросить к умолчаниям","rules.test_ph":"Проверьте имя устройства…","rules.invalid":"некорректный regex","rules.saved":"Правила иконок сохранены","btn.up":"Вверх","btn.down":"Вниз","tap.info":"Карточка устройства","tap.more_info":"Диалог HA (more-info)","tap.toggle":"Переключить состояние","marker.tap_label":"Действие по нажатию для этого устройства","tap.toggle_note":"Под селектором показано, какое состояние изменится. Защищённые устройства не переключаются с плана.","import.title":"Создать пространства из этажей HA","import.hint":"Home Assistant уже знает эти этажи. Отметьте, какие превратить в пространства плана — далее для каждого попросим картинку плана. Комнаты затем обводятся вручную по плану.","import.start":"Создать: {n}","import.manual":"Начать с нуля","import.progress":"Этаж {i} из {n}","import.done":"Пространства созданы. Обведите комнаты: кликайте по точкам сетки и замкните контур.","btn.skip":"Пропустить","space.scale_label":"Масштаб (размер клетки сетки)","space.cell_cm.help":"Связывает сетку с реальными размерами: от значения зависят длины и площади, толщина стен, размеры проёмов и радиус свечения. Изменение после разметки меняет расчётные размеры всего пространства, но не двигает его точки на плане.","space.cell_cm.help.aria":"Подсказка: масштаб пространства","space.scale_unit":"см на клетку","space.scale_unit_imperial":"дюйм на клетку","space.display_section":"Внешний вид","space.show_borders":"Всегда отображать границы комнат","space.zero_wall_style":"Стены нулевой толщины","space.zero_wall_style.help":"Пунктирные стены нулевой толщины пропускают Glow и солнечные лучи, сплошные блокируют их как барьер нулевой площади. Выбор меняет все такие стены пространства, даже когда их линии скрыты в просмотре.","space.zero_wall_style.help.aria":"Подсказка: вид стен нулевой толщины","space.zero_wall_dashed":"Пунктирные","space.zero_wall_solid":"Сплошные","space.show_names":"Показывать названия комнат","space.room_color":"Цвет границ и названий","space.opacity":"Прозрачность","space.fill_label":"Заливка комнат","space.fill_mode.help":"«Свой цвет» задаёт оформление, а «Свет», «Температура» и «LQI» используют текущие данные Home Assistant; Glow включается отдельно.","space.fill_mode.help.aria":"Подсказка: режим заливки комнат","fill.none":"Нет","fill.lqi":"По силе зигби-сигнала","fill.light":"По освещению","fill.custom":"Свой цвет","space.custom_fill":"Цвет заливки","space.source_file":"Использовать изображение плана","space.source_draw":"Нарисовать вручную","fill.temp":"По температуре","tip.temp_avg":"средняя температура:","tip.hum_avg":"средняя влажность:","space_card.button":"Перейти к пространству","space_card.not_found":"Пространство «{id}» не найдено","space_card.loading":"Загрузка…","continuity.restore_plan":"Восстанавливаем план…","continuity.restore_connection":"Восстанавливаем подключение к устройствам…","continuity.retry":"Повторить","editor.space":"Пространство","editor.framing":"Кадрирование","editor.fit_content":"Всё видимое содержимое","editor.fit_house":"Плотно по геометрии дома","editor.show_button":"Показывать кнопку","editor.button_label":"Текст кнопки","editor.button_target":"Путь дашборда (куда вести)","marker.sub_entity":"сущность","title.general_settings":"Общие настройки","title.export_pdf":"Сохранить в PDF","pdf.title":"Сохранение в PDF","pdf.dimensions":"Отображать размеры и площади","pdf.decor":"Отображать мебель и другой декор","pdf.room_names":"Отображать названия комнат","pdf.backdrop":"Отображать подложку","pdf.save":"Сохранить","pdf.saving":"Формируем…","pdf.failed":"Не удалось создать PDF.","pdf.too_large":"Размер изображений превышает лимит PDF 25 МБ.","pdf.asset_failed":"Не удалось загрузить подложку или изображение декора.","pdf.scale":"Масштаб 1:{n}","pdf.north":"Север","gs.title":"Общие настройки","gs.light_group":"Освещение","gs.light_on":"Свет включён","gs.light_off":"Весь свет выключен","gs.temp_group":"Температура","gs.temp_cold":"Холодно","gs.temp_ok":"Комфорт","gs.temp_hot":"Жарко","gs.lqi_group":"Сигнал Zigbee","gs.lqi_low":"Слабый сигнал","gs.lqi_high":"Сильный сигнал","gs.reset":"Сбросить к умолчаниям","gs.saved":"Общие настройки сохранены","gs.radar_show_live":"Показывать текущее присутствие на плане","radar.title":"Присутствие на плане","radar.help":"Свяжите маркер с точными сущностями радара Home Assistant, укажите положение датчика и профиль координат. Живые позиции обрезаются по выбранной комнате.","radar.help.aria":"Подсказка: настройки радара присутствия","radar.enabled":"Использовать этот радар присутствия","radar.show_live":"Показывать живые цели","radar.configure":"Настроить радар","radar.configure_on_plan":"Настроить на плане","radar.change_installation":"Сменить установку","radar.no_contour":"У комнаты нет контура. Точки радара не будут обрезаться по комнате.","radar.discard_setup_title":"Отменить настройку радара?","radar.discard_setup":"Несохранённая настройка радара будет потеряна.","radar.step_place_mount":"Укажите физическое положение датчика","radar.step_place_heading":"Укажите точку прямо перед датчиком","radar.step_reference":"Укажите контрольное положение {n}, затем начните измерение","radar.step_check_reference":"Укажите независимое проверочное положение","radar.start_measure":"Начать измерение","radar.countdown":"Встаньте в отмеченное место через {seconds} с","radar.capturing":"Стойте неподвижно и в одиночестве…","radar.fit_ready":"Калибровка готова","radar.check_third":"Проверить в другом положении","radar.check_complete":"Независимая проверка завершена","radar.error_distance":"Расхождение положения: {distance}","radar.ambiguous_target":"Обнаружено несколько целей. Повторите измерение в одиночестве.","radar.insufficient_samples":"Недостаточно актуальных координат. Повторите или настройте вручную.","radar.bad_references":"Выберите разнесённые положения в разных направлениях от датчика.","radar.ambiguous_sources":"Измерения допускают два одинаково вероятных направления. Выберите точки, по которым можно различить левую и правую стороны.","radar.bad_fit":"Измерения не совпадают. Проверьте единицы, положение датчика и контрольные точки.","radar.desktop_hint":"Для точной настройки используйте компьютер. Редактирование на тач-устройствах поддерживается по остаточному принципу.","radar.detected":"House Plan распознал признаки радара у этого устройства. Перед сохранением проверьте точные источники.","radar.detected_ld2450":"House Plan нашёл набор координат ESPHome LD2450. Перед сохранением проверьте точные источники X/Y.","radar.additional_actions":"Дополнительные действия","radar.declare":"Это радар присутствия","radar.profile":"Профиль данных","radar.profile_esphome_ld2450_v1":"ESPHome LD2450 (цели X/Y)","radar.profile_cartesian_v1":"Декартовы цели (X/Y)","radar.profile_polar_v1":"Полярная цель (дальность/угол)","radar.profile_range_v1":"Только дальность","radar.profile_zones_v1":"Состояния зон","radar.profile_presence_v1":"Только присутствие","radar.room":"Комната радара","radar.room_choose":"Выберите комнату","radar.target":"Цель {n}","radar.axis_x":"Сущность координаты X","radar.axis_y":"Сущность координаты Y","radar.add_target":"Добавить слот цели","radar.range_channel":"Канал дальности {n}","radar.add_range":"Добавить канал дальности","radar.presence_gate":"Сущность присутствия для слота","radar.swap_axes":"Поменять оси X и Y местами","radar.axis_x_sign":"Направление X","radar.axis_y_sign":"Направление Y","radar.distance_source":"Сущность дальности","radar.angle_source":"Сущность угла","radar.angle_unit":"Единица угла","radar.degrees":"Градусы","radar.radians":"Радианы","radar.angle_zero":"Направление нулевого угла","radar.angle_forward":"Вперёд","radar.angle_right":"Вправо","radar.angle_clockwise":"Угол растёт по часовой стрелке","radar.zone_source":"Сущность зоны","radar.occupancy_source":"Сущность присутствия","radar.count_source":"Сущность количества целей","radar.availability_source":"Сущность доступности","radar.source_choose":"Выберите сущность","radar.source_optional":"Необязательно","radar.source_missing":"сейчас недоступна","radar.saved_unsupported":"Сохранённая настройка радара не поддерживается или неполна. Она неактивна; удалите её либо обновите House Plan перед повторной настройкой.","radar.occupancy":"Присутствие (вкл/выкл)","radar.count":"Количество","radar.mount":"Положение и направление","radar.mount_hint":"Это физическое положение датчика. Перемещение его декоративного маркера не меняет установку.","radar.heading":"Направление, °","radar.range_cm":"Дальность, см","radar.fov_deg":"Угол обзора, °","radar.unit":"Единица источника","radar.mirror":"Отразить ось влево/вправо","radar.remove":"Удалить настройки радара","radar.invalid":"Перед сохранением заполните комнату, источники и положение радара.","radar.check_sources":"Проверить живые данные","radar.checking":"Проверяем…","radar.health":"Состояние подключения","radar.live_summary":"Текущих целей: {targets}; дуг дальности: {ranges}","radar.health_ok":"Актуальные данные получены","radar.health_off":"Цели не обнаружены","radar.health_stale":"Часть координат устарела","radar.health_partial":"Часть источников актуальна, часть устарела","radar.health_restricted":"Нет доступа к одному или нескольким источникам","radar.health_incomplete":"Текущий отчёт радара неполон","radar.health_position_unavailable":"Есть присутствие, но актуальное положение недоступно","radar.health_unavailable":"Данные датчика недоступны","radar.health_needs_setup":"Требуется настроить установку","radar.health_inconsistent":"Источники передают противоречивые данные","radar.health_unknown":"Текущее состояние неизвестно","radar.health_disabled":"Радар отключён","radar.error_invalid_radar":"Проверьте настройки радара.","radar.error_invalid_selection":"Выберите существующую комнату и допустимые источники.","radar.error_source_restricted":"Нет доступа ко всем выбранным источникам.","radar.error_rate_limited":"Слишком много запросов. Повторите чуть позже.","radar.error_not_ready":"Обработка данных радара ещё не готова.","radar.error_conflict":"План изменился. Откройте настройку радара заново и повторите попытку.","radar.error_source_unavailable":"Один или несколько выбранных источников радара недоступны.","radar.error_unsupported_capability":"Установленная интеграция не поддерживает эту возможность радара.","radar.report_age":"{seconds} с назад","space.show_lqi":"Сигнал Zigbee рядом с устройствами","gs.light_none":"Нет источников света","mode.plan":"Редактор плана","mode.devices":"Редактор устройств","display.value":"Значение + состояние","marker.subarea":"без зоны, вручную","device.new":"Новое устройство — откройте его редактор, чтобы снять отметку","opening.unlock_action":"Открыть замок","opening.lock_action":"Закрыть замок","opening.lock_pending":"Выполняется…","title.close_editor":"Закрыть редактор (вернуться к просмотру)","title.add_device":"Добавить устройство на план","devbar.add":"Добавить","devbar.rules":"Правила иконок","device_inbox.button":"Устройства","device_inbox.title":"Устройства на плане","device_inbox.search":"Поиск по устройствам, сущностям и интеграциям…","device_inbox.add_virtual":"Добавить виртуальное устройство","device_inbox.tab_on_plan":"На плане","device_inbox.tab_available":"Доступны","device_inbox.tab_hidden":"Скрытые","device_inbox.tab_readd":"Доступны снова","device_inbox.only_new":"Только новые","device_inbox.show_entities":"Показывать сущности","device_inbox.show_hidden":"Показывать скрытые на плане","device_inbox.show_hidden.help":"Временно показывает на плане скрытые и деактивированные маркеры служебными призраками только в редакторе устройств. Сохранённая видимость устройств не меняется.","device_inbox.show_hidden.help.aria":"Подсказка: показывать скрытые устройства на плане","device_inbox.new":"Новое","device_inbox.find":"Найти на плане","device_inbox.edit":"Настроить","device_inbox.hide":"Скрыть","device_inbox.show":"Показать","device_inbox.add":"Добавить","device_inbox.readd":"Добавить заново","device_inbox.hide_available":"Скрыть из списка","device_inbox.show_more":"Показать ещё","device_inbox.more_actions":"Другие действия","device_inbox.find_hidden_hint":"Сначала включите «Показывать скрытые на плане»","device_inbox.show_disabled":"Перед показом активируйте эту привязку в Home Assistant","device_inbox.empty_on_plan":"На плане пока нет подходящих устройств.","device_inbox.empty_available":"Нет доступных устройств для добавления.","device_inbox.empty_hidden":"Скрытых устройств нет.","device_inbox.empty_readd":"Нет удалённых устройств, доступных для повторного добавления.","device_inbox.reason_visible_auto":"Найдено автоматически","device_inbox.reason_visible_explicit":"Добавлено явно","device_inbox.reason_manual_hidden":"Скрыто пользователем","device_inbox.reason_automatic_hidden":"Скрыто автоматически","device_inbox.reason_service_entry":"Служебная запись реестра","device_inbox.reason_excluded_integration":"Исключена интеграция «{integration}»","device_inbox.reason_excluded_domain":"Непространственный тип сущности","device_inbox.reason_grouped_light":"Представлено группой света комнаты","device_inbox.reason_represented_by_parent":"Представлено родительским устройством","device_inbox.reason_removed":"Ранее удалено с плана","device_inbox.reason_available":"Можно добавить на план","device_inbox.reason_no_bound_room":"Зона HA не связана с комнатой плана","device_inbox.status_ha_disabled":"Отключено в Home Assistant","device_inbox.status_orphaned":"Привязка больше не найдена в Home Assistant","device_inbox.status_unverified":"Реестр Home Assistant временно недоступен","device_inbox.saved":"Список устройств обновлён","device_inbox.filters_excluded":"Исключённые интеграции","device_inbox.filters_group_lights":"Объединять светильники комнаты в один маркер","device_inbox.filters_preview_appear":"появится: {count}","device_inbox.filters_preview_hide":"скроется: {count}","device_inbox.filters_preview_lights":"затронет светильников: {count}","device_inbox.filters_reset":"Вернуть рекомендуемые","device_inbox.filters_save":"Сохранить фильтры","device_inbox.filters_search_ph":"Добавить интеграцию…","device_inbox.filters_title":"Фильтры обнаружения","space.roomcard_section":"Карточки комнат","space.label_temp":"Температура","space.label_hum":"Влажность","space.label_lqi":"Средний Zigbee-сигнал","space.label_light":"Свет вкл/выкл","roomcard.light_on":"Вкл","roomcard.light_off":"Выкл","roomcard.light_partial":"{on} из {total}","toast.split_pick_inside":"Промежуточные точки разреза — внутри комнаты","mode.decor":"Редактор подложки","decor.select":"Выбрать","decor.line":"Линия","decor.rect":"Прямоугольник","decor.ellipse":"Овал","decor.text":"Надпись","decor.erase":"Стереть","decor.erase_confirm_title":"Стереть объект?","decor.color":"Цвет","decor.width":"Толщина линии","decor.line_style":"Стиль линии","decor.line_style_solid":"Сплошная","decor.line_style_dashed":"Пунктирная","decor.fill":"Заливка","decor.fill_color":"Цвет заливки","decor.length":"Длина","decor.size":"Размер","decor.flip_h":"Отзеркалить по горизонтали","decor.flip_v":"Отзеркалить по вертикали","decor.angle":"Угол поворота, °","decor.text_size":"Размер текста","decor.backdrop_properties":"Свойства картинки-подложки","decor.text_title":"Надпись","decor.object_title":"Редактирование: {kind}","decor.text_label":"Текст","decor.live_group":"Вставить переменную HA","decor.live_entity":"Сущность","decor.live_entity_ph":"выберите сущность","decor.live_attr":"Значение","decor.live_attr_ph":"выберите состояние или атрибут","decor.live_state":"Состояние","decor.backdrop":"Картинка-подложка","decor.backdrop_hint":"Тяните картинку — перемещение; угол — размер; верхнюю ручку — поворот. Shift меняет пропорции или снимает шаг угла.","decor.backdrop_reset":"Вернуть картинку","decor.backdrop_reset_done":"Картинка вернулась на своё место и в свой размер","marker.icon_auto":"Авто: {icon} (по правилам иконок; выберите свою, чтобы заменить)","marker.icon_pin_auto":"Закрепить","mode.plan_tip":"Редактор плана — геометрия дома: рисование и объединение/разделение комнат, привязка к зонам HA, двери, окна и ворота, карточки комнат, масштаб","mode.devices_tip":"Редактор устройств — всё про значки: перетаскивание, клик — настройка привязки/иконки/отображения, виртуальные устройства, правила иконок","mode.decor_tip":"Редактор подложки — чисто визуальный декор под планом: линии, прямоугольники, овалы и надписи, не реагирующие на клики","space.glow_enabled":"Свечение источников света","gs.glow_group":"Свечение источников света","gs.glow_base":"Темнота дома","gs.glow_light":"Цвет света по умолчанию / интенсивность","gs.wall_fill":"Цвет заливки стен","gs.glow_radius":"Радиус свечения","gs.glow_radius.help":"Задаёт общий радиус светового пятна в метрах или футах; персональный радиус устройства заменяет это значение.","gs.glow_radius.help.aria":"Подсказка: общий радиус свечения","gs.unit_m":"м","gs.unit_ft":"фут","marker.controls_label":"Управляет другими источниками света","marker.controls.help":"При действии «Переключить состояние» перечисленные источники переключаются вместе с этим маркером. Их световые пятна остаются у собственных маркеров, а эта связь сама по себе не делает управляющий маркер источником света.","marker.controls.help.aria":"Подсказка: управление другими источниками света","marker.controls_filter":"Поиск ламп и выключателей…","info.controls":"Управляет","marker.glow_radius_label":"Радиус свечения","marker.glow_radius.help":"Задаёт радиус свечения в метрах или футах; пустое значение использует радиус из общих настроек.","marker.glow_radius.help.aria":"Подсказка: радиус свечения","markup.wallthick":"Толщина","markup.select":"Выбрать","title.markup_wallthick":"Толщина — клик по стене задаёт толщину от 0 до 100 см.","markup.hint_wallthick":"клик по стене · Esc закрывает без применения","wallthick.field":"Толщина","wallthick.unit_cm":"см","wallthick.unit_in":"дюйм","wallthick.apply_room":"Применить ко всем стенам комнаты","markup.draw_wall_title":"Толщина каждого нового сегмента стены (0–100 см). Общие стены сохраняют существующее значение.","room.queue_progress":"Комната {current} из {total}","toast.wall_rooms_saved":"Создано комнат: {n}","toast.wall_chain_saved":"Цепочка стен сохранена","toast.wallthick_pick":"Кликните по стене","toast.wallthick_set":"Толщина стены задана","toast.wallthick_cleared":"Толщина стены убрана","toast.physical_range":"Введите значение от {min} до {max} {unit}","toast.zero_wall_opening_conflict":"Сначала удалите проём на этом участке стены.","toast.zero_wall_ambiguous":"Не удалось однозначно выбрать участок стены. Уточните геометрию узла.","toast.zero_wall_migration_blocked":"Пространство не преобразовано: {reason}. Данные не изменены.","toast.physical_angle":"Введите угол поворота от 0° до 90°, не включая 90°","toast.physical_limit":"В пространстве достигнут лимит объектов этого типа","toast.geometry_unsafe":"Изменение отменено: геометрию стен нельзя безопасно построить.","junction.limit_angle":"Слишком острый угол между стенами: {actual}°, минимум {limit}°.","junction.limit_valence":"Слишком много стен в одном узле: {actual}, максимум {limit}.","junction.limit_length":"Слишком короткий участок стены: {actual} см, минимум {limit} см.","junction.limit_distance":"Стены и узлы слишком близко: {actual} см, минимум {limit} см.","junction.limit_clearance":"Внутри комнаты не остаётся места: {actual} см², минимум {limit} см².","junction.limit_check_failed":"Проверку стыков выполнить не удалось — изменение не сохранено","toast.wall_model_migration_blocked":"Не удалось обновить модель стен: {reason}. План не изменён. Запустите «Оптимизировать планы»; если ошибка повторится, исправьте конфликтующую геометрию стен.","toast.wall_model_client_outdated":"Обновите карточку и перезагрузите страницу перед редактированием плана.","wall_model.reason.invalid-room":"некорректный контур комнаты","wall_model.reason.zero-length":"отрезок стены нулевой длины","wall_model.reason.third-owner":"стена принадлежит более чем двум комнатам","wall_model.reason.duplicate-id":"конфликт идентификаторов стен","wall_model.reason.thickness-conflict":"конфликт значений толщины стены","wall_model.reason.opening-host":"проём нельзя однозначно привязать к стене","toast.delete_room_pick":"Кликните внутри комнаты, которую нужно удалить","toast.plan_snap_ambiguous":"Увеличьте масштаб, чтобы выбрать узел стены","toast.wall_repair_ambiguous":"У контура несколько возможных соединений. Увеличьте масштаб и соедините стены явно.","toast.wall_repair_too_large":"Разрыв больше 2 см. Соедините стены перед созданием комнаты.","toast.wall_repair_changed":"Геометрия стен изменилась. Попробуйте создать комнату ещё раз.","toast.opening_on_zero_wall":"Проёмы на стене нулевой толщины запрещены","marker.from_ha_option":"Выбрать из списка HA","marker.show_entities":"Показывать сущности","marker.show_entities_tip":"Добавляет в список не только устройства, но и все их сущности","marker.pick_ph":"Выберите устройство…","room.open_area":"Открыть зону в HA","room.fit_action":"Вписать комнату {name}","view.volumetric":"Объёмный вид","view.flat":"Плоский вид","kiosk.title":"Размеры на этом экране","kiosk.hint":"Хранится только на этом устройстве — у каждого настенного планшета или ТВ свои удобные размеры.","kiosk.icon_scale":"Размер значков устройств","kiosk.font_scale":"Размер текста карточек комнат","editor.kiosk":"Режим настенного устройства (киоск)","editor.cycle":"Автосмена пространств каждые N секунд (киоск, 0 = выкл)","room.settings_title":"Настройки комнаты","room.fill_label":"Заливка в ЭТОЙ комнате","fill.inherit":"Как у пространства","room.custom_fill_space":"Цвет пространства","room.custom_fill_own":"Цвет комнаты","room.temp_range_label":"Диапазон комфорта","room.temp_range_min":"Нижняя граница комфортной температуры","room.temp_range_max":"Верхняя граница комфортной температуры","room.temp_range_reset":"Как у пространства","room.temp_range.help":"Диапазон применяется только к этой комнате. Пустое поле наследует соответствующую границу пространства; если границы поменялись местами, House Plan использует меньшую как нижнюю, а большую как верхнюю.","room.temp_range.help.aria":"О диапазоне комфорта комнаты","room.temp_src_label":"Источник температуры","room.hum_src_label":"Источник влажности","room.src_average":"Среднее по датчикам комнаты","room.src_pick":"Конкретное устройство или сущность","room.src_ph":"Выберите источник…","toast.room_updated":"Комната обновлена","space.card_font":"Размер шрифта карточек","room.sizes_section":"Размеры шрифтов","room.group_basics":"Основное","room.group_basics.help":"Область связывает комнату с зоной Home Assistant: из неё берутся датчики. Без области комната остаётся геометрией.","room.group_basics.help.aria":"Подсказка: имя и область комнаты","room.group_fill":"Заливка","room.group_fill.help":"Заливка этой комнаты перекрывает выбранную для пространства; «Свой цвет» хранится только здесь.","room.group_fill.help.aria":"Подсказка: заливка комнаты","room.group_sources":"Источники","room.group_sources.help":"По умолчанию комната усредняет свои датчики. Выбранный датчик заменяет среднее везде: подсказка, карточка, заливка.","room.group_sources.help.aria":"Подсказка: источники температуры и влажности","room.sizes_section.help":"Масштабы действуют только в этой комнате и умножаются на общий масштаб карточки из настроек пространства.","room.sizes_section.help.aria":"Подсказка: размеры шрифтов комнаты","room.name_scale":"Размер названия","room.label_scale":"Размер подписей","preview.room_name":"Гостиная","toast.cfg_reload_failed":"Не удалось перечитать план с сервера: {err}","toast.locale_load_failed":"Не удалось загрузить языковой пакет. До перезагрузки страницы используется английский.","toast.furniture_art_load_failed":"Не удалось загрузить изображения мебели. Обновите страницу, чтобы их показать.","room.settings_short":"Настройки комнаты","room.unnamed":"Комната без имени","marker.use_climate_temp":"Учитывать температуру устройства в комнате","marker.use_climate_temp_tip":"Добавляет current_temperature кондиционера или термостата в среднюю температуру комнаты. Внешний бейдж со значением настраивается отдельно ниже.","marker.value_badge_title":"Бейдж со значением","marker.value_badge.help":"Показывает одно выбранное значение рядом со значком. Не влияет на комнатные показатели, свет, Glow и действие по нажатию.","marker.value_badge.help.aria":"Подсказка: бейдж со значением устройства","marker.value_badge_enabled":"Отображать бейдж со значением","marker.value_badge_source":"Значение","marker.value_badge_source.help":"Выберите конкретное состояние, поддерживаемый атрибут или производное значение этого устройства.","marker.value_badge_source.help.aria":"Подсказка: источник значения бейджа","marker.value_badge_position":"Расположение","marker.value_badge_position.help":"Выбранная сторона сохраняется постоянно и не переворачивается автоматически у края плана.","marker.value_badge_position.help.aria":"Подсказка: расположение бейджа","marker.value_badge_right":"Справа","marker.value_badge_bottom":"Снизу","marker.value_badge_left":"Слева","marker.value_badge_top":"Сверху","marker.value_badge_empty":"У этого устройства нет доступных значений","marker.value_badge_static":"Статичный значок не показывает живые значения. Настройка сохранится.","marker.value_badge_missing":"Источник недоступен","marker.value_badge_missing_hint":"Сохранённый источник сейчас недоступен. Можно сохранить его, отключить бейдж или выбрать другой.","marker.value_badge_duplicate":"То же значение уже показано внутри значка.","marker.value_badge_state":"Состояние · {name}","marker.value_badge_marker_state":"Состояние источника света · {name}","marker.value_badge_lqi":"Качество Zigbee-сигнала (среднее)","marker.value_badge_attr_current_temperature":"Текущая температура · {name}","marker.value_badge_attr_temperature":"Целевая температура · {name}","marker.value_badge_attr_current_humidity":"Текущая влажность · {name}","marker.value_badge_attr_humidity":"Влажность · {name}","marker.value_badge_attr_current_position":"Положение · {name}","marker.value_badge_attr_percentage":"Скорость · {name}","marker.value_badge_attr_brightness":"Яркость · {name}","marker.value_badge_attr_volume_level":"Громкость · {name}","marker.value_badge_attr_battery_level":"Заряд батареи · {name}","marker.value_badge_attr_fan_speed":"Скорость вентилятора · {name}","marker.value_source":"Источник значения","marker.value_source.help":"Выберите, что заменит значок. Действие по нажатию не изменится.","marker.value_source.help.aria":"Подсказка: источник значения внутри значка","marker.value_source_auto":"Автоматически (как раньше)","marker.value_source_missing_hint":"Сохранённый источник сейчас недоступен. До его восстановления или выбора другого значения внутри будет показано —.","marker.light_role_label":"Является источником света","marker.light_role.help":"«Авто» использует фактическую роль привязанного устройства, «Всегда» принудительно создаёт собственный источник, а «Никогда» исключает его; связанные лампы выше остаются независимыми.","marker.light_role.help.aria":"Подсказка: является ли устройство источником света","marker.light_role_auto_yes":"Автоматически (источник света)","marker.light_role_auto_no":"Автоматически (не источник света)","marker.light_entity_label":"Ведущая сущность света","marker.light_entity.help":"Для составного устройства выберите сущность, состояние, цвет и яркость которой представляют этот источник на плане. Автоматический вариант сохраняет совместимость со старыми планами.","marker.light_entity.help.aria":"Подсказка: ведущая сущность света","marker.light_entity_auto":"Автоматически ({entity})","marker.light_entity_none":"нет управляемой сущности","marker.light_entity_missing":"Сохранённая сущность {entity} недоступна. Временно используется {fallback}; выбор восстановится, если сущность вернётся.","marker.toggle_entity_label":"Переключаемая сущность","marker.toggle_entity.help":"Для составного устройства выберите собственную лампу или переключатель, которой управляет нажатие. Автоматический вариант сохраняет прежние правила цели и не зависит от ведущей сущности света.","marker.toggle_entity.help.aria":"Подсказка: переключаемая сущность","marker.toggle_entity_auto":"Автоматически ({entity})","marker.toggle_entity_none":"нет собственной управляемой сущности","marker.toggle_entity_missing":"Сохранённой сущности {entity} больше нет среди выбираемых каналов этого маркера. Временно используется {fallback}; выбор восстановится, если сущность вернётся.","marker.glow_color_label":"Цвет и яркость свечения","marker.glow_mode.help":"Используйте данные источника, задайте только цвет или зафиксируйте цвет и яркость. Минимум — 1%; чтобы отключить источник, выберите «Никогда».","marker.glow_mode.help.aria":"Подсказка: цвет и яркость свечения","marker.glow_mode_auto":"Из источника","marker.glow_mode_color":"Задать цвет","marker.glow_mode_fixed":"Цвет и яркость","marker.glow_color":"Цвет свечения","marker.glow_brightness":"Яркость","marker.glow_disabled_never":"Настройки свечения недоступны: маркер явно исключён из источников света.","marker.glow_disabled_auto":"В автоматическом режиме у этого маркера не найден пространственный источник света.","marker.glow_disabled_no_entity":"Для пространственного источника нет активной управляемой сущности Home Assistant.","marker.glow_passive_hint":"У источника нет собственных данных Home Assistant. Задайте цвет и яркость вручную; радиус остаётся доступным.","marker.control_broken":"Сохранённый источник отсутствует или больше не отмечен как источник света","marker.control_missing_label":"Отсутствующий источник на плане","marker.control_passive":"пассивный источник","toast.marker_control_cycle":"Такая связь создаст циклическую цепочку управления светом.","toast.marker_binding_required":"Сначала выберите устройство Home Assistant, затем добавьте управляемый источник света.","confirm.unlock_title":"Открыть замок?","confirm.unlock_body":"House Plan отправит этому замку команду открытия.","toast.files_migrate_failed":"Не удалось перенести вложения к новой привязке, ссылки остались на старые файлы: {err}","space.pick_saved":"Уже загруженные","space.pick_saved_hint":"Планы, сохранённые на сервере, включая отцеплённые ранее","space.no_saved":"На сервере пока нет сохранённых планов.","space.loading":"Загрузка…","space.used_by":"используется: {list}","space.in_use":"План используется пространством — сначала отцепите его","btn.use":"Выбрать","confirm.delete_plan_title":"Удалить файл плана?","confirm.delete_plan_body":"Файл будет удалён с сервера. Это действие нельзя отменить.","toast.plans_list_failed":"Не удалось получить список планов: {err}","toast.plan_delete_failed":"Не удалось удалить план: {err}","marker.hide":"Скрыть","marker.hide_tip":"Устройство исчезнет с плана после сохранения, но продолжит участвовать в расчёте сигнала комнаты. Вернуть его можно через каталог «Устройства» в редакторе устройств.","marker.show":"Показать","marker.show_tip":"Устройство снова появится на плане после сохранения.","marker.hidden_ghost":"Устройство скрыто пользователем","marker.ha_disabled_device":"Устройство деактивировано в Home Assistant и скрыто с плана.","marker.ha_disabled_entity":"Сущность деактивирована в Home Assistant и скрыта с плана.","marker.ha_disabled_all_entities":"У устройства нет активных сущностей Home Assistant, поэтому оно скрыто с плана.","marker.ha_registry_limited":"Полный реестр Home Assistant недоступен этому пользователю. Неподтверждённый объект временно нельзя показывать или использовать.","marker.delete_tip":"Полностью удалить устройство с плана и из всех расчётов. Позже его можно добавить заново.","tap.run":"Запустить автоматизацию/скрипт/сцену","tap.none":"Ничего не делать","marker.run_target_label":"Что запускать","marker.run_search_ph":"Поиск: автоматизация, скрипт или сцена…","marker.run_target_gone":"Цель {id} не найдена — выберите заново","marker.tap_confirm":"Спрашивать подтверждение","marker.tap_confirm_tip":"Перед выполнением показать диалог подтверждения — защита от случайных нажатий.","marker.toggle_hint_single":"Цель: {name} ({id}).","marker.virtual_light_target":"Виртуальный свет: {name}.","marker.virtual_light_current":"Ручное состояние: {state} → {effect}.","marker.virtual_light_state_on":"включён","marker.virtual_light_state_off":"выключен","marker.toggle_hint_group":"Переключатся источники ({count}): {names}.","marker.toggle_hint_current":"Сейчас: {state} → {effect}.","marker.toggle_hint_group_current":"Сейчас включено {on} из {count} → {effect}.","marker.toggle_hint_skipped":"Не будут затронуты ({count}): {targets}.","marker.toggle_effect_turn_on":"включится","marker.toggle_effect_turn_off":"выключится","marker.toggle_effect_open":"откроется","marker.toggle_effect_close":"закроется","marker.toggle_effect_stop":"остановится","marker.toggle_effect_toggle":"состояние переключится","marker.toggle_skip_missing":"не найдено","marker.toggle_skip_ha_disabled":"деактивировано в HA","marker.toggle_skip_unavailable":"недоступно","marker.toggle_skip_unsupported":"переключение не поддерживается","marker.toggle_skip_secure":"заблокировано из соображений безопасности","marker.toggle_none_no_binding":"У устройства нет привязки, состояние переключать нечем. По нажатию ничего не произойдёт.","marker.toggle_none_no_actionable_entity":"У устройства нет состояния, которое можно переключить. По нажатию ничего не произойдёт.","marker.toggle_none_configured_targets_missing":"Настроенные цели сейчас недоступны. Собственная сущность устройства не будет подставлена вместо них.","marker.toggle_none_ha_disabled":"Цель деактивирована в Home Assistant и не может использоваться на плане.","marker.toggle_none_unavailable":"Цель сейчас недоступна. По нажатию ничего не произойдёт.","marker.toggle_none_unsupported":"Для этой сущности Home Assistant не предоставляет безопасного переключения. По нажатию ничего не произойдёт.","marker.toggle_none_secure":"Переключение замков, сигнализации и защитных ворот с плана заблокировано из соображений безопасности.","run.automation":"автоматизация","run.script":"скрипт","run.scene":"сцена","confirm.tap_run":"Запустить «{name}»?","confirm.tap_toggle":"Переключить «{name}»?","confirm.current_state":"Текущее состояние: {state}","confirm.expected_state":"После переключения: {state}","confirm.group_current":"включено {on} из {total}","confirm.group_all_on":"все включены","confirm.group_all_off":"все выключены","confirm.unavailable_targets":"Недоступно: {count}","confirm.expected_by_ha":"Состояние определит Home Assistant","confirm.state_on":"Включено","confirm.state_off":"Выключено","confirm.state_open":"Открыто","confirm.state_closed":"Закрыто","confirm.state_opening":"Открывается","confirm.state_closing":"Закрывается","confirm.state_stopped":"Остановлено","confirm.state_unknown":"Неизвестно","toast.run_started":"Запущено: {name}","toast.run_target_missing":"Цель запуска не найдена — проверьте настройки устройства","toast.run_target_required":"Выберите автоматизацию, скрипт или сцену","toast.tap_target_changed":"Цель действия изменилась. Повторите попытку.","toast.virtual_light_toggle_failed":"Не удалось переключить виртуальный свет: {err}","toast.value_badge_source_required":"Выберите значение для бейджа","btn.run":"Выполнить","vac.section":"Робот-пылесос: живая позиция","vac.autocal":"Настроить автоматически","vac.live":"Живая позиция на плане","vac.trail":"Показывать путь робота","vac.autocal_no_rooms":"Интеграция не отдаёт список комнат — откройте «Подогнать вручную»","vac.route_warn_unmapped":"Робот убирает на карте, которая не сопоставлена ни одному этажу","vac.route_warn_needs_calibration":"Карта сопоставлена этажу, но не откалибрована","vac.route_warn_ambiguous":"Две карты неразличимы — этаж не выбран","vac.route_warn_missing_space":"Пространство этой карты удалено","vac.autocal_no_match":"Не совпали имена комнат (нужно ≥3 общих) — откройте «Подогнать вручную»","vac.autocal_done":"Готово: привязка по {rooms} комнатам. Запустите уборку и проверьте","vac.cal_need_pos":"Робот сейчас не отдаёт координаты — запустите уборку и поставьте на паузу","vac.cal_done":"Калибровка сохранена. Запустите уборку и проверьте","vac.cal_cancelled":"Калибровка отменена","vac.fit":"Подогнать вручную","vac.fit_hint":"Перетащите карту робота на место, растяните за уголки","vac.fit_rotate":"Повернуть 90°","vac.fit_mirror":"Отразить","vac.trail_never":"Не показывать никогда","vac.trail_cleaning":"Во время уборки","vac.trail_always":"Показывать всегда","gs.bg_color":"Цвет фона вокруг плана","gs.bg_default":"Как в теме","gs.bg_mode":"Фон плана","gs.bg_mode.help":"«Следует за Солнцем» использует sun.sun, а при недоступности — локальные часы браузера; статичный режим всегда показывает выбранный цвет.","gs.bg_mode.help.aria":"Подсказка: общий фон плана","gs.bg_static":"Статичный цвет","gs.bg_daynight":"Следует за Солнцем","gs.sun_group":"Солнце","gs.sun_missing":"Сущность sun.sun не найдена — фон следует локальным часам, а оконные лучи недоступны.","gs.north":"Север на плане","gs.north.help":"Угол отсчитывается по часовой стрелке от верхней вертикали плана; север нужен для оконных лучей, а не для фона «Следует за Солнцем».","gs.north.help.aria":"Подсказка: общее направление севера","gs.north_ph":"не задан","gs.north_clear":"Сбросить","gs.north_letter":"С","gs.sun_rays":"Солнце в окнах","gs.sun_ray_origin":"Лучи солнца","gs.sun_ray_origin.inner":"От внутренних углов окон","gs.sun_ray_origin.outer":"От внешних углов окон","gs.about_version":"Houseplan Card v{v}","gs.about_github":"GitHub · документация и issues","gs.about_telegram":"Чат в Telegram","support.title":"Помощь и обратная связь","space.bg_color":"Цвет фона вокруг плана","space.bg_inherit":"Наследовать общий","space.bg_mode":"Фон плана","space.bg_mode.help":"Выберите наследование общего фона либо переопределите это пространство статичным цветом или режимом «Следует за Солнцем».","space.bg_mode.help.aria":"Подсказка: фон пространства","space.north":"Север на плане","space.north.help":"Переопределяет общий север для этого пространства; угол отсчитывается по часовой стрелке от верхней вертикали плана и используется оконными лучами.","space.north.help.aria":"Подсказка: север для пространства","space.sun_rays":"Солнце в окнах","space.sun_inherit":"Общие настройки","space.sun_on":"Вкл","space.sun_off":"Выкл","canvas.far_objects":"Объектов далеко от плана: {n}","canvas.show_far":"Показать","canvas.home_tip":"План там — нажмите, чтобы вписать","gs.grid_group":"Обслуживание планов","gs.align_all":"Оптимизировать планы","gs.align_title":"Оптимизировать планы","gs.align_none":"Все планы уже используют актуальную и оптимальную модель данных.","gs.optimize_no_automatic_changes":"Автоматических изменений нет. Проверьте пункты ниже.","gs.align_count":"Сдвинется элементов: {n} из {total}, максимум на {cm} см.","gs.align_where":"Наибольший сдвиг — в пространстве «{s}».","gs.align_turned":"Проёмов с исправлением угла: {n}.","gs.align_preflight_failed":"Не удалось безопасно проверить геометрию следующих пространств: {spaces}{more}.","gs.align_preflight_hint":"Планы не изменены. Скопируйте диагностику кнопкой ниже и приложите её к отчёту об ошибке вместе с экспортом пространства.","gs.preflight_reason_prepare-exception":"Не удалось подготовить геометрию пространства (исключение при сборке модели)","gs.preflight_reason_wall-null":"Тело стен не построилось (объединение вернуло пустоту)","gs.preflight_reason_wall-degraded-extra":"Тело стен деградировало с лишней геометрией","gs.preflight_reason_wall-failed-core":"Ядро тела стен не собралось","gs.preflight_reason_wall-exception":"Построение стен упало с исключением","gs.preflight_reason_floor-null":"Контур пола не построился","gs.preflight_reason_floor-exception":"Построение пола упало с исключением","gs.preflight_copy":"Скопировать диагностику","gs.preflight_copied":"Диагностика скопирована","gs.preflight_update_hint":"Версии карточки и интеграции различаются — обновите House Plan и повторите.","gs.align_preflight_space":"Пространство {n}","gs.align_preflight_more":" и ещё {n}","gs.optimize_changes":"Миграций модели: {m}; обновлено пространств: {c}; устранён шум координат: {p}; объединено отрезков реальных стен: {w}; объединено отрезков стен нулевой толщины: {s}; независимых: {i}.","gs.zero_walls_migrated":"Преобразовано виртуальных участков: {n}.","gs.wall_segments_migrated":"Стабилизировано сегментов стен: {n}.","gs.room_drafts_migrated":"Незавершённые контуры преобразованы в обычные стены: {drafts}; отрезков: {segments}.","gs.optimize_lattice_summary":"Канонизировано шумовых значений координат: {n}; максимальный сдвиг: {cm} см.","gs.optimize_lattice_space":"{space}: канонизировано значений координат: {n}; оставлено значений вне сетки: {far}.","gs.optimize_coincident_partitions":"Скрытые участки независимых стен поглощены стенами комнат: {n}.","gs.optimize_openings_rehosted":"Проёмы перепривязаны к стенам комнат: {n}.","gs.optimize_walls_straightened":"Выпрямлено стен: {n}; максимальное перемещение: {cm} см.","gs.optimize_walls_straightened_where":"Максимальная правка стены: {s}.","gs.optimize_walls_straighten_skipped":"Оставлено почти осевых стен, которые нельзя безопасно выпрямить: {n}.","gs.optimize_glow_migration":"Старый Glow: пространств — {spaces} → без заливки данных + независимый Glow; комнат — {rooms} → наследуемая заливка + независимый Glow.","gs.optimize_references":"Исправлено ссылок: пространства — {spaces}; комнаты — {rooms}; позиции — {positions}; устройств отвязано от отсутствующих пространств — {detached}.","gs.optimize_reference_more":", и ещё {n}","gs.optimize_orphans_removed":"Убрано забытых записей: {total} — подписи комнат: {rooms}; устройства: {devices}; групповые метки: {groups}. Все они принадлежали пространствам, удалённым ранее.","gs.optimize_live_positions":"Старые позиции в удалённых пространствах принадлежат существующим объектам: {n}{names}. Они будут сохранены.","gs.optimize_live_positions_remove":"Старые позиции в удалённых пространствах принадлежат существующим объектам: {n}{names}. Они выбраны для удаления.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Убрать старые позиции","gs.optimize_live_keep":"Сохранить старые позиции","gs.optimize_live_selected":"Старые позиции будут убраны после применения оптимизации.","gs.optimize_unverified":"Не удалось безопасно проверить позиций: {n}. Они оставлены без изменений.","gs.optimize_registry_limited":"Для безопасной проверки нужен полный доступ администратора к реестрам Home Assistant.","gs.optimize_vacuum_warning":"Сопоставления комнат пылесоса требуют проверки: {n}.","gs.optimize_details":"Подробности","gs.optimize_details_more":"И ещё записей: {n}.","gs.optimize_detail_removed":"будет удалено","gs.optimize_detail_live":"будет сохранено","gs.optimize_detail_unverified":"не проверено","gs.optimize_detail_room_label":"подпись комнаты","gs.optimize_detail_device":"устройство","gs.optimize_detail_group":"групповая метка","gs.optimize_detail_unknown":"неизвестный владелец","gs.optimize_detail_item":"{status}: {kind} {id}; прежнее пространство {space}","gs.align_warn":"Элементы, намеренно поставленные между узлами, будут сдвинуты. После операции доступна одна отмена — только до следующего изменения плана.","gs.align_run":"Оптимизировать","gs.align_done":"Планы оптимизированы: сдвинуто элементов — {n}, обслужено записей — {m}, исправлено ссылок — {r}","gs.optimize_undo":"Отменить последнюю оптимизацию","gs.optimize_undone":"Последняя оптимизация отменена","decor.furniture":"Мебель","decor.image":"Изображение","decor.image_title":"Свои изображения","decor.image_upload":"Загрузить изображение","decor.image_replace":"Заменить изображение","decor.image_uploading":"Загрузка…","decor.image_asset":"Файл изображения","decor.image_pick_hint":"Загрузите изображение или выберите уже используемое в House Plan.","decor.image_place_hint":"Кликните по плану, чтобы разместить изображение.","decor.image_none":"Загруженных изображений пока нет.","decor.image_unavailable":"Изображение недоступно","decor.image_used":"Используется в объектах: {n}","decor.image_upload_failed":"Не удалось загрузить изображение: {err}","decor.image_error_capacity":"Хранилище пользовательских изображений заполнено.","decor.image_in_use":"Перед удалением файла удалите все размещённые копии.","decor.image_delete_title":"Удалить файл изображения?","decor.image_delete_message":"Удалить «{name}» из House Plan? Это действие нельзя отменить.","furn.title":"Библиотека мебели","furn.symbol":"Символ","furn.group_furniture":"Мебель","furn.group_appliance":"Техника","furn.group_sanitary":"Сантехника","furn.group_other":"Прочее","furn.width":"Ширина","furn.depth":"Глубина","furn.back_to_categories":"Все категории","furn.pick_hint":"Выберите категорию, затем символ.","furn.place_hint":"Кликните по плану — предмет встанет к ближайшей стене. Shift — свободно.","furn.cat_air_conditioner":"Кондиционеры","furn.cat_armchair":"Кресла","furn.cat_bathtub":"Ванны","furn.cat_bed":"Кровати","furn.cat_bidet":"Биде","furn.cat_boiler":"Бойлеры","furn.cat_chair":"Стулья","furn.cat_coffee_table":"Журнальные столы","furn.cat_computer":"Компьютер","furn.cat_cooktop":"Варочные панели","furn.cat_dining_table":"Обеденные столы","furn.cat_dishwasher":"Посудомоечные машины","furn.cat_dryer":"Сушильные машины","furn.cat_fireplace":"Камины","furn.cat_fridge":"Холодильники","furn.cat_hood":"Вытяжка","furn.cat_kitchen_cabinet":"Кухонные шкафы","furn.cat_kitchen_sink":"Кухонные мойки","furn.cat_nightstand":"Тумбы","furn.cat_oven":"Духовка","furn.cat_plant":"Растения","furn.cat_rug":"Ковры","furn.cat_shelving":"Стеллажи","furn.cat_shower":"Душевые","furn.cat_sink":"Раковины","furn.cat_sofa":"Диваны","furn.cat_stairs":"Лестницы","furn.cat_toilet":"Унитазы","furn.cat_tv":"Телевизоры","furn.cat_wardrobe":"Шкафы","furn.cat_washer":"Стиральные машины","furn.cat_work_table":"Рабочие столы","furn.sym_cactus":"Кактус","furn.sym_computer":"Компьютер","furn.sym_hood":"Вытяжка","furn.sym_oven":"Духовка","furn.sym_sofa":"Диван двухместный","furn.sym_sofa_three_seat":"Диван трёхместный","furn.sym_sofa_corner_right":"Угловой диван, правый","furn.sym_armchair":"Кресло мягкое","furn.sym_armchair_office":"Кресло офисное","furn.sym_coffee_table":"Журнальный стол, прямоугольный","furn.sym_coffee_table_round":"Журнальный стол, круглый","furn.sym_coffee_table_oval":"Журнальный стол, овальный","furn.sym_coffee_table_rounded":"Журнальный стол, скруглённый","furn.sym_table_dining":"Обеденный стол, прямоугольный","furn.sym_table_round":"Круглый стол","furn.sym_table_dining_oval":"Обеденный стол, овальный","furn.sym_table_dining_rounded":"Обеденный стол, скруглённый","furn.sym_chair":"Стул","furn.sym_chair_bar":"Барный стул","furn.sym_desk":"Рабочий стол, прямоугольный","furn.sym_desk_corner":"Рабочий стол, угловой","furn.sym_bed_double":"Двуспальная кровать","furn.sym_bed_single":"Односпальная кровать","furn.sym_nightstand":"Тумба прикроватная","furn.sym_cabinet_tv":"Тумба под телевизор","furn.sym_cabinet_shoe":"Тумба для обуви","furn.sym_cabinet_sink":"Тумба под раковину","furn.sym_wardrobe":"Шкаф гардеробный","furn.sym_bookshelf":"Шкаф книжный","furn.sym_wall_unit":"Шкаф-стенка","furn.sym_kitchen_floor":"Кухонный напольный модуль","furn.sym_kitchen_floor_corner":"Кухонный напольный угловой модуль","furn.sym_kitchen_wall":"Кухонный навесной модуль","furn.sym_kitchen_wall_corner":"Кухонный навесной угловой модуль","furn.sym_shelf_floor":"Стеллаж напольный","furn.sym_shelf_wall":"Полка настенная","furn.sym_fridge":"Холодильник","furn.sym_stove":"Варочная панель, 4 конфорки","furn.sym_cooktop_two":"Варочная панель, 2 конфорки","furn.sym_dishwasher":"Посудомоечная машина","furn.sym_washer":"Стиральная машина","furn.sym_dryer":"Сушильная машина","furn.sym_tv":"Телевизор на подставке","furn.sym_tv_wall":"Телевизор на кронштейне","furn.sym_ac":"Кондиционер","furn.sym_water_heater":"Бойлер","furn.sym_toilet":"Унитаз напольный","furn.sym_toilet_built_in":"Унитаз встроенный","furn.sym_bathtub":"Ванна прямоугольная","furn.sym_bathtub_corner":"Ванна угловая","furn.sym_shower":"Душ","furn.sym_sink":"Раковина","furn.sym_kitchen_sink":"Кухонная мойка одинарная","furn.sym_kitchen_sink_double":"Кухонная мойка двойная","furn.sym_bidet":"Биде напольное","furn.sym_bidet_built_in":"Биде встроенное","furn.sym_stairs":"Лестница","furn.sym_fireplace":"Камин","furn.sym_plant":"Растение","furn.sym_rug":"Ковёр","common.yes":"Да","common.no":"Нет","vac.diag_source":"Источник","vac.diag_platform":"Интеграция","vac.diag_status":"Статус","vac.diag_position":"Позиция","vac.diag_rooms":"Комнаты","vac.diag_rooms_value":"{total} · совпало имён: {matched} · {readiness}","vac.autocal_ready":"автокалибровка доступна","vac.autocal_not_ready":"нужно 3 совпавших имени","vac.diag_path":"Путь интеграции","vac.diag_map":"ID карты","vac.source_none":"не выбран","vac.source_status_ok":"Готов","vac.source_status_missing":"Не найден","vac.source_status_disabled":"Деактивирован в Home Assistant","vac.source_status_unavailable":"Недоступен","vac.source_status_unverified":"Нельзя проверить с текущими правами","vac.source_status_unsupported":"Нет данных позиции","vac.source_status_none":"Нет источника","vac.source_banner_missing":"Сохранённый источник больше не существует. Он не заменён автоматически: выберите другой или восстановите его в Home Assistant.","vac.source_banner_disabled":"Сохранённый источник деактивирован в Home Assistant. Активируйте его там или выберите другой.","vac.source_banner_unverified":"Текущих прав Home Assistant недостаточно для проверки источника. Привязка сохранена и не будет заменена автоматически.","vac.choose_source":"Выбрать источник","vac.source_auto":"Автоматически","vac.source_auto_hint":"Использовать совместимую сущность этого устройства","vac.all_cameras":"Все камеры","vac.all_cameras_warn":"Камера может не отдавать данные робота. Выбирайте её только если это карта вашего пылесоса.","vac.all_cameras_empty":"Других сущностей камеры не найдено.","vac.platform_unknown":"интеграция неизвестна","vac.cap_position":"позиция","vac.cap_rooms_short":"комнаты","vac.cap_path":"путь","vac.cap_map":"ID карты","vac.cap_none":"данные робота не обнаружены","vac.xcme_hint":"Включите атрибуты Xiaomi Cloud Map Extractor:","vac.documentation":"Документация","vac.residual_title":"Проверьте автокалибровку","vac.residual_message":"Совпавшие комнаты расходятся максимум на {error}. Примените приблизительную калибровку, подгоните её вручную либо отмените без изменения сохранённых настроек.","vac.apply_proposal":"Применить","gs.backup_group":"Резервная копия и перенос","backup.export_open":"Экспорт","backup.import_open":"Импорт","backup.export_title":"Экспорт House Plan","backup.import_title":"Импорт House Plan","backup.export_hint":"Выберите, должна ли копия содержать всю конфигурацию House Plan или только текущее пространство.","backup.full":"Полная копия","backup.current_space":"Текущее пространство","backup.current_space_title":"Текущее пространство: {title}","backup.no_current_space":"Нет текущего пространства","backup.plan_only":"Только планировка","backup.plan_only_hint":"Сохранить комнаты, стены, проёмы, декор и позиции подписей комнат без устройств и привязок Home Assistant.","backup.plan_only_preview":"Файл содержит только планировку","backup.privacy_warning":"Архив сохраняет названия, идентификаторы Home Assistant и точные координаты. Внутренние планы и вложения указываются ссылками, но не вкладываются; текущие состояния и маршруты пылесосов не включаются.","backup.download":"Скачать JSON","backup.export_done":"Резервная копия скачана","backup.reading":"Проверяем резервную копию…","backup.revalidated":"После предпросмотра план изменился. Сводка обновлена — проверьте её и подтвердите ещё раз.","backup.error.support_invalid_message":"Проверьте сообщение для поддержки и повторите попытку.","backup.error.support_package_too_large":"Обезличенный пакет для поддержки превышает лимит 8 МиБ.","backup.error.support_preview_expired":"Предпросмотр вложения для поддержки истёк или больше недоступен.","backup.error.support_rate_limited":"Запрошено слишком много репортов или предпросмотров. Повторите позже.","backup.error.support_rejected":"Репорт не прошёл проверку службы поддержки.","backup.error.support_unavailable":"Закрытая служба поддержки временно недоступна.","backup.error.unauthorized":"У вас нет прав на экспорт или импорт этого плана.","backup.error.not_ready":"House Plan ещё не готов. Повторите попытку через несколько секунд.","backup.error.too_large":"Размер резервной копии превышает 8 МиБ.","backup.error.invalid_json":"Выбранный файл не является корректным JSON.","backup.error.invalid_format":"Выбранный файл не является резервной копией House Plan.","backup.error.invalid_image":"Изображение повреждено или не соответствует своему формату.","backup.error.unsupported_export_version":"Эта версия формата резервной копии не поддерживается установленной версией.","backup.error.unsupported_image":"Используйте поддерживаемое изображение PNG, JPEG, WebP или SVG.","backup.error.future_model":"Резервная копия создана в более новой версии модели данных House Plan.","backup.error.invalid_config":"Резервная копия содержит некорректную конфигурацию House Plan.","backup.error.wall_model_migration_blocked":"Не удалось безопасно обновить модель стен из резервной копии. Сначала оптимизируйте исходный план и повторите экспорт.","backup.error.invalid_layout":"Резервная копия содержит некорректные позиции объектов.","backup.error.invalid_content":"Резервная копия содержит некорректные или несогласованные ссылки на файлы.","backup.error.space_not_found":"Выбранное пространство больше не существует.","backup.error.capacity_exceeded":"Добавление этой копии превысит ограничения размера плана.","backup.error.preview_expired":"Время предпросмотра истекло. Выберите файл резервной копии заново.","backup.error.preview_owner_mismatch":"Этот предпросмотр принадлежит другому пользователю Home Assistant.","backup.error.conflict":"После предпросмотра план изменился. Проверьте обновлённую сводку.","backup.error.content_confirmation_required":"Подтвердите отсоединение недоступных локальных файлов.","backup.error.commit_failed":"Не удалось безопасно применить копию. Предыдущий план восстановлен или ожидает восстановления.","backup.error.missing_plan":"После предпросмотра исчез связанный файл плана. Проверьте копию ещё раз.","backup.error.missing_content":"После предпросмотра исчез связанный локальный файл. Проверьте копию ещё раз.","backup.error.marker_control_missing":"В резервной копии отсутствует связанный источник света на плане.","backup.error.marker_control_not_light":"Связанная цель больше не отмечена как источник света.","backup.error.marker_control_self":"Источник света не может управлять самим собой.","backup.error.marker_control_cycle":"Резервная копия содержит циклическую цепочку управления светом.","backup.error.duplicate_marker_control":"Резервная копия содержит повторяющуюся связь с источником света.","backup.error.no_backup":"Нет снимка импорта или оптимизации, который можно восстановить.","backup.error.in_use":"Элемент ещё используется","backup.error.invalid_data":"Запрос содержит некорректные данные","backup.error.invalid_light_entity":"Ведущий свет должен быть сущностью light.* или switch.*","backup.error.invalid_marker_control":"Некорректная ссылка управления маркером","backup.error.invalid_name":"Некорректное имя","backup.error.invalid_partition_opening_host":"Проём должен сохранить свою перегородку-носитель","backup.error.invalid_partition_opening_jamb_margin":"Проём не оставляет физического простенка у края стены","backup.error.invalid_passage_fields":"Открытый проход не может нести настройки двери","backup.error.invalid_space_id":"Неизвестное пространство","backup.error.invalid_toggle_entity":"Сущность переключения должна быть light.* или switch.*","backup.error.invalid_value_badge":"Некорректные настройки бейджа значения","backup.error.invalid_value_badge_attribute":"Некорректный атрибут бейджа значения","backup.error.invalid_value_badge_position":"Некорректная позиция бейджа значения","backup.error.invalid_value_badge_source":"Некорректный источник бейджа значения","backup.error.invalid_vacuum_map_route":"Проверьте сопоставление карт робота пространствам.","backup.error.invalid_value_source":"Некорректный источник значения","backup.error.invalid_value_source_attribute":"Некорректный атрибут источника значения","backup.error.io_error":"Файловая операция на сервере не удалась","backup.error.not_toggleable":"Это устройство нельзя переключить","backup.error.nothing_to_repair":"Нечего чинить","backup.error.space_in_use":"На пространство ещё есть ссылки","backup.error.value_badge_source_required":"Бейджу значения нужен источник","backup.error.wall_model_client_outdated":"План обновлён в другом месте — перезагрузите страницу","backup.same_source":"Создано на этом экземпляре Home Assistant","backup.foreign_source":"Создано на другом экземпляре Home Assistant","backup.created":"Создано: {value}","backup.versions":"Карточка {card}; интеграция {integration}; модель данных {model}","backup.count_spaces":"Пространств: {n}","backup.count_rooms":"Комнат: {n}","backup.count_walls":"Стен: {n}","backup.count_openings":"Проёмов: {n}","backup.count_decor":"Объектов декора: {n}","backup.count_markers":"Устройств: {n}","backup.count_layout":"Позиций: {n}","backup.bindings":"Привязки — устройства: {device}, сущности: {entity}, виртуальные: {virtual}; позиций без пространства: {legacy}","backup.binding_status":"Статус на целевом экземпляре — активных: {active}, деактивированных: {disabled}, отсутствующих: {missing}","backup.missing_areas":"На целевом экземпляре отсутствуют зоны: {areas}","backup.dropped_marker_links":"Связи с источниками света вне переносимого пространства пропущены: {n}.","backup.room_drafts_migrated":"Старые незавершённые контуры преобразованы в обычные стены: {drafts}; отрезков: {segments}.","backup.repaired_target_refs":"Существующих ссылок восстановлено этим импортом: {n}.","backup.preserved_unresolved_refs":"Неоднозначные ссылки сохранены без изменений: {n}.","backup.preserved_unresolved_hint":"House Plan ничего не угадывал и не удалял. После импорта запустите «Оптимизировать планы», чтобы проверить оставшиеся ссылки.","backup.import_details":"Подробности восстановления ссылок","backup.import_detail.incoming_remapped":"Ссылок обновлено внутри импортируемой копии: {n}","backup.import_detail.target_repaired":"Существующих ссылок восстановлено: {n}","backup.import_detail.preserved_unresolved":"Неразрешимых ссылок сохранено: {n}","backup.import_detail.collisions":"Конфликтов назначения безопасно сохранено: {n}","backup.import_detail.dropped_links":"Входящих связей пропущено по правилам переноса: {n}","backup.import_detail.bounded_lineages":"Чрезмерно вложенных идентификаторов ограничено: {n}","backup.replace_warning":"Текущая конфигурация и расположение будут заменены. Загруженные файлы не удаляются. Одну отмену можно выполнить до следующего изменения плана.","backup.foreign_bookkeeping":"Служебные списки известных и новых устройств другого экземпляра импортированы не будут.","backup.final_name":"Название нового пространства","backup.target_settings":"Глобальные настройки целевого экземпляра не изменятся.","backup.duplicates":"Уже существующих привязок: {n}","backup.skip":"Пропустить повторяющиеся устройства","backup.virtual_copy":"Добавить безопасные статичные виртуальные копии","backup.content":"Связанное содержимое","backup.decor_images_summary":"Свои изображения: объектов — {objects}, файлов — {assets}; отсутствует файлов — {missing}.","backup.content_available":"доступно локально","backup.content_external":"внешняя ссылка","backup.content_detach_required":"будет отвязано","backup.confirm_detach":"Я понимаю, что недоступные внутренние планы и вложения будут отвязаны от импортируемой конфигурации.","backup.confirm_missing_images":"Я понимаю, что отсутствующие свои изображения останутся восстанавливаемыми заглушками, а остальные недоступные локальные файлы будут отвязаны.","backup.replace":"Заменить","backup.add":"Добавить пространство","backup.space_done":"Пространство импортировано: комнат — {rooms}, устройств — {markers}, существующих ссылок восстановлено — {refs}","backup.full_done":"Копия восстановлена: пространств — {spaces}, комнат — {rooms}, устройств — {markers}","backup.undo_import":"Отменить последний полный импорт","backup.import_undone":"Полный импорт отменён","backdrop.large_title":"Большое изображение","backdrop.large_body":"Изображение {w}×{h} ({fileMb} МБ), для показа потребуется около {decodedMb} МБ памяти. На планшетах это может привести к падению страницы.","backdrop.unknown_body":"Не удалось прочитать размеры изображения — файл может быть повреждён. Продолжение может привести к падению страницы на планшете.","backdrop.reduced_dimensions":"Уменьшенная копия: {w}×{h} px.","backdrop.use_downscaled":"Загрузить уменьшенную копию","backdrop.reducing":"Уменьшаем…","backdrop.keep_original":"Оставить оригинал","backdrop.too_large_title":"Изображение слишком большое","backdrop.too_large_body":"Изображение превышает возможности браузера ({w}×{h}, предел {limit} px по стороне). Уменьшите его в редакторе на компьютере и загрузите снова.","backdrop.downscale_failed":"Не удалось создать уменьшенную копию. Текущий план не изменён.","gs.card_display":"Отображение","gs.card_zigbee":"Связи Zigbee","gs.card_fills":"Цвета заливки комнат","gs.card_plan":"План","gs.card_data":"Данные","gs.card_fills.help.aria":"О цветах заливки комнат","gs.backup_group.help.aria":"О резервной копии и переносе","gs.grid_group.help.aria":"Об обслуживании плана","gs.backup_group.help":"Скачайте переносимую JSON-копию или проверьте и импортируйте копию, созданную House Plan.","gs.grid_group.help":"Обновляет модели данных, выравнивает элементы по сетке и объединяет лишние фрагменты стен. Перед записью будет показан точный отчёт.","gs.card_fills.help":"Цвета заливок действуют на все пространства; у каждого цвета своя прозрачность. Какой режим заливки использует пространство — задаётся в его диалоге.","space.card_basics":"Основное","space.card_sun":"Солнце и свет","marker.card_basics":"Основное","marker.card_tap":"Действие по нажатию","marker.card_light":"Свет и свечение","marker.card_appearance":"Внешний вид","marker.card_details":"Подробности"}},{code:"de",nativeLabel:"Deutsch",loadDictionary:async function(e){const t=0===e?await import("./de-DVCIKwC0.js"):await import(new URL("./de-DVCIKwC0.js?retry",import.meta.url).href);return{dictionary:t.dictionary,fingerprint:t.fingerprint}}},{code:"fr",nativeLabel:"Français",loadDictionary:async function(e){const t=0===e?await import("./fr-DHxhbm5E.js"):await import(new URL("./fr-DHxhbm5E.js?retry",import.meta.url).href);return{dictionary:t.dictionary,fingerprint:t.fingerprint}}}],_p=lp,mp=new Set;const gp=new class{constructor(e,t,i=console.warn,n){this.entries=e,this.expectedFingerprint=t,this.warn=i,this.loadFailed=n,this.dictionaries=new Map,this.pending=new Map,this.failed=new Set;for(const t of e)t.dictionary&&this.dictionaries.set(t.code,t.dictionary)}state(e){return this.dictionaries.has(e)?"ready":this.failed.has(e)?"fallback":"pending"}dictionary(e){return this.dictionaries.get(e)}ensure(e){if("pending"!==this.state(e))return Promise.resolve();const t=this.pending.get(e);if(t)return t;const i=this.entries.find(t=>t.code===e),n=this.load(i).finally(()=>this.pending.delete(e));return this.pending.set(e,n),n}async load(e){if(!e?.loadDictionary)return void(e&&this.failed.add(e.code));let t;for(const i of[0,1])try{const t=await e.loadDictionary(i);if(t.fingerprint!==this.expectedFingerprint)throw new Error(`locale fingerprint mismatch for ${e.code}`);return this.dictionaries.set(e.code,t.dictionary),void this.failed.delete(e.code)}catch(e){t=e}this.failed.add(e.code),this.warn(`[houseplan] unable to load ${e.code} locale; using English`,t),this.loadFailed?.(e.code)}}(pp,"54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32",console.warn,function(e){for(const t of mp)t(e)});function fp(e){const t=bp(e)?.code??"en";return gp.dictionary(t)??_p}function vp(e){return"string"==typeof e?e.trim().replaceAll("_","-").toLowerCase():""}const yp=new Map(pp.map(e=>[vp(e.code),e]));function bp(e){return yp.get(vp(e))}function wp(e,t){const i=[{value:"",label:e},...pp.map(({code:e,nativeLabel:t})=>({value:e,label:t}))],n="string"==typeof t?t:"";return n&&!i.some(e=>e.value===n)&&i.push({value:n,label:bp(n)?.nativeLabel??n}),i}function kp(e,t){return function(e,t,i,n){const r=new Map(i.map(e=>[vp(e),e])),o=r.get(vp(e));if(o)return o;const s=vp(t),a=r.get(s);return a||(r.get(s.split("-")[0]||"")??n)}(t,e?.locale?.language||e?.language,pp.map(({code:e})=>e),"en")}function xp(e,t,i){return on(fp(e)[t]??_p[t]??t,i)}function Sp(e,t){const i=fp(e)[t]??_p[t];return"string"==typeof i&&i.trim().length>0}function $p(e,t,i,n){return{ox:0,oy:0}}function Mp(e,t){const i=(e.angle+90)*Math.PI/180,n=Wa(16,t),r=e.gateFace?-n*e.gateFace.side:n*(e.flipV?-1:1);return[[e.x+Math.cos(i)*r,e.y+Math.sin(i)*r],r<0]}function Rp(e){const t=e.length/2,i=e.face.cm>0?e.face.cm/e.cellCm*e.gridPitch/2:Wa(4,e.cellCm),n="gate"===e.type?Math.sin(10*Math.PI/180)*t:0;return{half:t,jambHalf:i,gateDepth:n,outlineHalf:Math.max(Wa(16,e.cellCm),i+Wa(8,e.cellCm),n+Wa(8,e.cellCm)),hitHalf:Math.max(Wa(20,e.cellCm),i+Wa(10,e.cellCm),n+Wa(12,e.cellCm))}}function Cp(e,t,i){e.minX=Math.min(e.minX,t),e.minY=Math.min(e.minY,i),e.maxX=Math.max(e.maxX,t),e.maxY=Math.max(e.maxY,i)}function Tp(e,t,i,n,r,o,s,a){const l=Math.min(s,a)*Math.PI/180,c=Math.max(s,a)*Math.PI/180,h=(e,t)=>{const i=Math.atan2(t,e),n=[l,c];for(let e=-3;e<=3;e++){const t=e*Math.PI-i,r=Math.PI/2+e*Math.PI-i;t>l&&tl&&r0&&[e.length,e.angle,t[0],t[1]].every(Number.isFinite)))return null;const{half:i,jambHalf:n}=Rp(e),r=ja(e.cellCm),o=1.75*r,s=1.25*r,a=.75*r,l={minX:-i-s,minY:-n-s,maxX:i+s,maxY:n+s},c={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};if("window"===e.type)Tp(c,-i,0,i,-o,o,-90,0),Tp(c,i,-i,0,-o,o,0,90),Cp(c,-i-a,-i-a),Cp(c,i+a,a);else if("gate"===e.type){const t=10*e.face.side;Tp(c,-i,0,i,-o,o,0,t),Tp(c,i,-i,0,-o,o,-t,0)}else Tp(c,-i,0,e.length,-o,o,-90,0),Cp(c,-i-a,-e.length-a),Cp(c,i+a,a);const[h,d]=Dp(e),u={...l};Cp(u,c.minX+h,c.minY+d),Cp(u,c.maxX+h,c.maxY+d);const p=e.flipH?-1:1,_="gate"===e.type?1:e.flipV?-1:1,m=e.angle*Math.PI/180,g=Math.cos(m),f=Math.sin(m),v={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};for(const e of[u.minX,u.maxX])for(const i of[u.minY,u.maxY]){const n=e*p,r=i*_;Cp(v,t[0]+n*g-r*f,t[1]+n*f+r*g)}return v}function Pp(e){if("passage"===e.type)return W``;const t=Math.max(0,Math.min(1,e.amount)),{half:i,jambHalf:n}=Rp(e),r=ja(e.cellCm),o=1.75*r,s=e.flipH?-1:1,a=e.flipV?-1:1,l="gate"===e.type?1:a,[c,h]=Dp(e);let d;if("window"===e.type){const o=Math.PI/2*i,s=e.face.cm>0?W``:W``;d=W` ${l} `:G} - `}}_g.properties={hass:{attribute:!1},_config:{state:!0},_snap:{state:!0},_continuityEpoch:{state:!0}},_g.styles=[ap,o`.hp-static-title{font-weight:700;padding:10px 14px 6px;font-size:16px;color:var(--primary-text-color);}.hp-static-body{position:relative;}.hp-static-stage{position:relative;width:100%;container-type:inline-size;overflow:hidden;pointer-events:none;background:var(--ha-card-background,var(--card-background-color,#111));}.hp-static-stage>svg{position:absolute;inset:0;width:100%;height:100%;display:block;z-index:1;}.hp-static-stage>.hp-paper-outline-svg{z-index:0;overflow:visible;}.hp-paper{fill:var(--ha-card-background,var(--card-background-color,#111));stroke:none;}.wallbody-fill{fill:var(--wall-fill,#ffffff);fill-opacity:var(--wall-fill-op,1);fill-rule:evenodd;stroke:none;pointer-events:none;}.wallbody{fill:url(#hp-wall-hatch);fill-rule:evenodd;stroke:var(--room-stroke,var(--hp-muted,#607d8b));stroke-width:calc(0.6px * var(--hp-cell-visual-scale,1));pointer-events:none;}.wallbody.solid{fill:none;}.hp-static-stage .devlayer{position:absolute;inset:0;z-index:2;}.hp-static-foot{padding:8px 12px 12px;pointer-events:auto;}.hp-static-btn{width:100%;padding:9px 14px;border:none;border-radius:10px;background:var(--primary-color,#3ea6ff);color:var(--text-primary-color,#fff);font-size:14px;font-weight:600;cursor:pointer;}:host([data-pointer-hover]) .hp-static-btn:hover{filter:brightness(1.08);}.hp-static-error{padding:24px;text-align:center;color:var(--secondary-text-color,#9aa4ad);}`],customElements.get("houseplan-space-card")||customElements.define("houseplan-space-card",_g),window.customCards=window.customCards||[],window.customCards.find(e=>"houseplan-space-card"===e.type)||window.customCards.push({type:"houseplan-space-card",name:"House Plan — Space (static)",description:"Read-only live schematic of a single houseplan space, with a deep-link button.",preview:!1,documentation:"https://github.com/Matysh/houseplan-card"});const mg=o`:host{--hp-editor-tray-bg-fallback:color-mix(in srgb,var(--card-background-color,var(--hp-bg)) 94%,var(--hp-line));--hp-editor-tray-bg:color-mix(in srgb,var(--card-background-color,var(--hp-bg)) 86%,transparent);--hp-editor-tray-border:color-mix(in srgb,var(--hp-line) 82%,var(--hp-accent));--hp-editor-tray-blur:8px;--hp-editor-tray-shadow:var(--shadow-2);}.editor-secondary-host{position:absolute;inset:var(--sp-2) var(--sp-4) auto;z-index:70;display:flex;justify-content:flex-end;pointer-events:none;}.editor-secondary-host.kind-palette,.editor-secondary-host.kind-group{justify-content:flex-start;}.editor-secondary{pointer-events:none;max-width:100%;display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);color:var(--hp-txt);background:var(--card-background-color,var(--hp-bg));background:var(--hp-editor-tray-bg-fallback);border:1px solid var(--hp-line);border-color:var(--hp-editor-tray-border);border-radius:var(--rad-l);box-shadow:var(--hp-editor-tray-shadow);opacity:0;visibility:hidden;transform:translateY(-4px);transition:opacity 0.1s ease,transform 0.1s cubic-bezier(0.2,0.7,0.2,1),visibility 0s linear 0.1s;touch-action:auto;}.editor-secondary-host.open .editor-secondary{pointer-events:auto;opacity:1;visibility:visible;transform:translateY(0);transition-duration:0.14s,0.14s,0s;transition-delay:0s;}.editor-secondary-host.blocked .editor-secondary{pointer-events:none;}@supports ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){.editor-secondary{background:var(--hp-editor-tray-bg);-webkit-backdrop-filter:blur(var(--hp-editor-tray-blur));backdrop-filter:blur(var(--hp-editor-tray-blur));}}.editor-secondary-content,.editor-group-items{display:flex;align-items:center;gap:var(--sp-3);min-width:0;}.editor-context-label{max-width:14rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding-inline-end:var(--sp-4);border-inline-end:1px solid var(--hp-line);color:var(--hp-muted);font-size:var(--fs-s);}.editor-secondary.kind-palette{width:min(760px,100%);align-items:stretch;padding:0;overflow:hidden;}.editor-secondary.kind-palette .editor-secondary-content,.editor-secondary.kind-palette .furnpalette{width:100%;}.editor-secondary.kind-palette .furnpalette{max-height:38vh;border:0;background:transparent;}.editor-group-launcher .group-chevron{--mdc-icon-size:16px;transition:transform 0.14s ease;}.editor-group-launcher[aria-expanded="true"] .group-chevron{transform:rotate(180deg);}.editor-secondary .bdhint{font-size:var(--fs-s);color:var(--hp-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.editor-secondary .dfill{display:inline-flex;align-items:center;gap:var(--sp-2);font-size:var(--fs-s);cursor:pointer;}.editor-secondary .dfill input[type="checkbox"]{width:16px;height:16px;flex:none;margin:0;padding:0;}.editor-secondary hp-color-opacity{flex:0 0 auto;}.editor-secondary input{width:74px;background:transparent;border:1px solid var(--hp-line);color:var(--hp-txt);border-radius:var(--rad-s);padding:var(--sp-3) var(--sp-4);font-size:var(--fs-m);}.editor-secondary label,.editor-secondary .hint{color:var(--hp-muted);font-size:var(--fs-s);}.editor-secondary .drawwall{display:inline-flex;align-items:center;gap:var(--sp-3);white-space:nowrap;}.editor-secondary .drawwall input{width:4.2em;}.editor-secondary .drawwall .opl{color:var(--hp-muted);font-size:var(--fs-s);}@container (min-width:560px) and (max-width:899px){.editor-secondary-content,.editor-group-items{flex-wrap:wrap;justify-content:flex-end;}}@container (max-width:559px){.editor-secondary-host{inset-inline:var(--sp-4);}.editor-secondary{max-width:100%;}.editor-secondary-content,.editor-group-items{overflow-x:auto;scrollbar-width:thin;}.editor-secondary-content>*,.editor-group-items>*{flex:none;}.editor-context-label{display:none;}}@media (prefers-reduced-motion:reduce){.editor-secondary{transition:none;}.editor-group-launcher .group-chevron{transition:none;}}`;class gg{constructor(e=50){this._undo=[],this._redo=[],this._limit=Math.max(30,Math.floor(e))}get canUndo(){return this._undo.length>0}get canRedo(){return this._redo.length>0}get undoName(){return this._undo[this._undo.length-1]?.name??null}get redoName(){return this._redo[this._redo.length-1]?.name??null}get size(){return this._undo.length}push(e){this._undo.push(e),this._undo.length>this._limit&&this._undo.splice(0,this._undo.length-this._limit),this._redo=[]}undo(){const e=this._undo.pop()??null;return e&&this._redo.push(e),e}redo(){const e=this._redo.pop()??null;return e&&this._undo.push(e),e}removeWhere(e){const t=this._undo.length,i=this._redo.length;return this._undo=this._undo.filter(t=>!e(t)),this._redo=this._redo.filter(t=>!e(t)),t+i-this._undo.length-this._redo.length}clear(){this._undo=[],this._redo=[]}}function fg(e,t){const i=e[t];return i&&Number.isFinite(i.x)&&Number.isFinite(i.y)?{x:i.x,y:i.y,..."string"==typeof i.s?{s:i.s}:{}}:null}function vg(e,t,i){if(null===i){if(!(t in e))return e;const i={...e};return delete i[t],i}const n={...e[t]||{}};delete n.x,delete n.y,delete n.s;const r={...n,x:i.x,y:i.y,...void 0!==i.s?{s:i.s}:{}};return{...e,[t]:r}}const yg="houseplan-card:version-reload-target:v1";function bg(e){if("string"!=typeof e)return null;return e.trim()||null}class wg{constructor(e){this.hooks=e,this._input={frontendVersion:null,backendVersion:null,kiosk:!1,reducedMotion:!1},this._relation={kind:"unknown"},this._banner=null,this._connected=!1,this._attemptTarget=null,this._attemptState=null,this._noticeToken=0}get relation(){return this._relation}get banner(){return this._banner}get hasCurrentMismatchNotice(){return"mismatch"===this._relation.kind&&"visible"===this._banner?.phase}connect(){this._connected||(this._connected=!0,this._attemptTarget=null,this._attemptState=null,this._reconcile())}disconnect(){(this._connected||this._banner)&&(this._connected=!1,this._cancelTimer(),this._banner&&(this._banner=null,this.hooks.changed()))}update(e){const t={frontendVersion:bg(e.frontendVersion),backendVersion:bg(e.backendVersion),kiosk:!0===e.kiosk,reducedMotion:!0===e.reducedMotion},i=function(e,t){const i=bg(e),n=bg(t);return i&&n?i===n?{kind:"equal",frontend:i,backend:n}:{kind:"mismatch",frontend:i,backend:n}:{kind:"unknown"}}(t.frontendVersion,t.backendVersion),n=!((e,t)=>e.frontendVersion===t.frontendVersion&&e.backendVersion===t.backendVersion&&e.kiosk===t.kiosk&&e.reducedMotion===t.reducedMotion)(this._input,t)||!((e,t)=>e.kind===t.kind&&("unknown"===e.kind||"unknown"!==t.kind&&e.frontend===t.frontend&&e.backend===t.backend))(this._relation,i);this._input=t,this._relation=i,n&&this._reconcile()}finishBannerExit(e){this._banner&&"leaving"===this._banner.phase&&this._banner.token===e&&(this._banner=null,this.hooks.changed())}_reconcile(){if(this._cancelTimer(),!this._connected||"mismatch"!==this._relation.kind)return this._attemptTarget=null,this._attemptState=null,void this._hideBanner();if(!this._input.kiosk)return this._attemptTarget=null,this._attemptState=null,void this._showBanner(this._relation.frontend,this._relation.backend);const e=this._relation.backend;if(this._attemptTarget===e&&null!==this._attemptState||(this._attemptTarget=e,this._attemptState=function(e,t){try{const i=e();return i?i.getItem(yg)===t?"attempted":"fresh":"unavailable"}catch{return"unavailable"}}(this.hooks.storage,e)),"fresh"===this._attemptState)return this._hideBanner(),void this._armTimer();this._showBanner(this._relation.frontend,e)}_armTimer(){this._connected&&void 0===this._timer&&"mismatch"===this._relation.kind&&this._input.kiosk&&"fresh"===this._attemptState&&(this._timer=this.hooks.clock.setTimeout(()=>{this._timer=void 0,this._tick()},250))}_cancelTimer(){void 0!==this._timer&&(this.hooks.clock.clearTimeout(this._timer),this._timer=void 0)}_tick(){if(!this._connected||"mismatch"!==this._relation.kind||!this._input.kiosk||"fresh"!==this._attemptState)return;if(!function(e){return e.connected&&e.initialFrameSettled&&e.viewOnly&&e.surfacesIdle&&e.configWritesIdle&&e.physicalWritesIdle&&e.layoutWritesIdle&&e.gesturesIdle&&e.interactionPauseElapsed&&e.baseZoom}(this.hooks.safety()))return void this._armTimer();const e=this._relation.backend,t=function(e,t){try{const i=e();return i?i.getItem(yg)===t?"attempted":(i.setItem(yg,t),"claimed"):"unavailable"}catch{return"unavailable"}}(this.hooks.storage,e);if(this._attemptTarget=e,this._attemptState="claimed"===t?"attempted":t,"claimed"===t){this._showBanner(this._relation.frontend,e);try{this.hooks.reload()}catch{}}else this._showBanner(this._relation.frontend,e)}_showBanner(e,t){"visible"===this._banner?.phase&&this._banner.frontend===e&&this._banner.backend===t||(this._banner={frontend:e,backend:t,phase:"visible",token:++this._noticeToken},this.hooks.changed())}_hideBanner(){if(this._banner)return this._input.reducedMotion?(this._banner=null,void this.hooks.changed()):void("leaving"!==this._banner.phase&&(this._banner={...this._banner,phase:"leaving",token:++this._noticeToken},this.hooks.changed()))}}const kg=1;function xg(e,t){const i=t&&"object"==typeof t?t:{};e._haIntegrationVersion=bg(i.integration_version);const n=i.support_api;e._haSupportApi="number"==typeof n&&Number.isSafeInteger(n)?n:null,e._haDecorAssetsApi=1===i.decor_assets_api?1:null,e._haSummaryPanelApi=1===i.summary_panel_api?1:null,e._haRadarStage1Api=1===i.radar_stage1_api?1:null,e._syncVersionRecovery()}function Sg(e){const t=e._stageEl,i=e._loadOk&&!e._loading&&e._continuityDataReady&&!e._resumeSettling&&!e._connectionWasLost&&!e._booting&&!e._bootFading&&!e._bootSettling&&!e._bootSoft&&e._continuity.hasCompleteFrame&&"steady"===e._continuity.state&&!e._continuity.overlayBlocksInteraction&&!!t&&t.clientWidth>0&&t.clientHeight>0,n=!(0!==e._pointers.size||0!==e._touchContacts.size||e._touchSequenceMultitouch||e._roomPointer||e._panStart||e._panLock||e._pinchStart||e._swipeStart||e._tabDrag||e._tabDragRelease||e._drag||e._deviceDrag||e._rlResize||e._resize?.dragging||e._physicalDrag||e._physicalRotate||e._opDrag||e._decorDraft||e._decorMove||e._dtDrag||e._bdDrag||e._furnTouchPending||e._compassDrag||e._viewportGestureDirty||e._devicePositionBusy||e._modeTransitionBusy||e._cameraTransition.active||e._slide||0!==e._warmModeRequest),r=!(e._editorSecondaryDialogBlocked||e._partitionDeleteDialog||e._roomDeleteDialog||e._backdropGuard||e._vacFit||e._editorSecondary?.hasOpenGroup||e._furnPalette||e._decorImagePalette);return{connected:e.isConnected,initialFrameSettled:i,viewOnly:!0===e._config?.kiosk&&"view"===e._mode&&!e._editing,surfacesIdle:r,configWritesIdle:0===e._writesPending&&!e._saveConfigDebounced.pending(),physicalWritesIdle:0===e._pendingPhysicalWrites.size,layoutWritesIdle:!e._persistLayout.pending()&&0===e._dirtyPos.size&&0===e._sentPos.size&&!e._devicePositionBusy,gesturesIdle:n,interactionPauseElapsed:Date.now()>=e._cyclePausedUntil,baseZoom:e._zoom<=1.001}}class $g{constructor(){this.seen=null,this.diagnosticsCache=null}observe(e,t,i,n){this.invalidateDiagnosticsForHass(e,t,i),this.intake(t,n)}intake(e,t){e&&this.seen!==e&&(this.seen=e,t())}invalidate(){this.diagnosticsCache=null}invalidateDiagnosticsForHass(e,t,i){this.diagnosticsCache&&(e?.entities!==t?.entities||e?.devices!==t?.devices||[...i?.entityIds||[]].some(i=>!!e?.states?.[i]!=!!t?.states?.[i]))&&this.invalidate()}diagnostics(e,t,i){if(this.diagnosticsCache)return this.diagnosticsCache;const n={active:0,ha_disabled:0,orphaned:0,unverified:0};for(const e of t)e.removed||"virtual"===e.binding||n[i(e.binding).kind]++;return this.diagnosticsCache={registry:ud(e),bindings:n},this.diagnosticsCache}}function Mg(e){const t=e;t._hassSequence++,t._renderSnapshotAt=Date.now(),t._continuity.note("hass-snapshot"),t._ensureHaRegistryAuthority(),t._planHassMemo=null,t._hookConnection(),!t._loadOk&&!t._loading&&t._loadTries<8&&t._loadFromServer(),t._maybeRebuildDevices(),t._vacTick(),t._activityTick()}function Rg(e){return!!e&&"object"==typeof e&&1===e.version}function Cg(e,t){const i=e.radar;return e.space===t&&!0!==e.hidden&&!0!==e.removed&&Rg(i)&&!0===i.enabled&&!1!==i.show_live}const Tg={ok:"radar.health_ok",off:"radar.health_off",stale:"radar.health_stale",partial:"radar.health_partial",restricted:"radar.health_restricted",incomplete:"radar.health_incomplete",position_unavailable:"radar.health_position_unavailable",unavailable:"radar.health_unavailable",needs_setup:"radar.health_needs_setup",inconsistent:"radar.health_inconsistent",unknown:"radar.health_unknown"};const Dg=e=>"number"==typeof e&&Number.isFinite(e);class Ag{constructor(e){this.host=e,this.frames=new Map,this.connection=null,this.space="",this.generation=0,this.expiryTimer=0,this.deadlines=new Map}sync(e,t){const i=this.host.hass?.connection;if(!t||!i||!this.host.isConnected)return void this.stop();if(this.unsubscribe&&this.connection===i&&this.space===e)return;this.stop(),this.connection=i,this.space=e;const n=++this.generation,r=i.subscribeMessage?.bind(i);"function"==typeof r&&Promise.resolve(r(e=>{if(n!==this.generation||!this.host.isConnected)return;const t=function(e){if(!e||"object"!=typeof e)return null;const t=e;if("string"!=typeof t.marker_id||"string"!=typeof t.server_session_id||!Number.isSafeInteger(t.seq)||"string"!=typeof t.health)return null;const i=Array.isArray(t.targets)?t.targets.slice(0,256).flatMap(e=>{if(!e||"object"!=typeof e)return[];const t=e;return"string"==typeof t.slot&&Dg(t.x)&&Dg(t.y)&&Dg(t.expires_at)&&Dg(t.reported_at)&&("bounded_latest"===t.pair_quality||"coherent"===t.pair_quality)?[{...t,included:!0===t.included,smooth:!0===t.smooth}]:[]}):[],n=Array.isArray(t.ranges)?t.ranges.slice(0,64).flatMap(e=>{if(!e||"object"!=typeof e)return[];const t=e;if(!("string"==typeof t.id&&Dg(t.x)&&Dg(t.y)&&Dg(t.radius)&&Dg(t.expires_at)&&Dg(t.reported_at)))return[];const i=Array.isArray(t.segments)?t.segments.slice(0,64).flatMap(e=>{if(!Array.isArray(e))return[];const t=e.slice(0,181).flatMap(e=>Array.isArray(e)&&2===e.length&&Dg(e[0])&&Dg(e[1])?[[e[0],e[1]]]:[]);return t.length>=2?[t]:[]}):void 0;return[{...t,...i?{segments:i}:{}}]}):[],r=Array.isArray(t.zones)?t.zones.slice(0,64).flatMap(e=>{if(!e||"object"!=typeof e)return[];const t=e;if("string"!=typeof t.id)return[];const i=t.state;if(null!==i&&"boolean"!=typeof i&&!Dg(i))return[];const n=Array.isArray(t.polygon)?t.polygon.slice(0,64).flatMap(e=>Array.isArray(e)&&2===e.length&&Dg(e[0])&&Dg(e[1])?[[e[0],e[1]]]:[]):[];return[{id:t.id,state:i,...n.length>=3?{polygon:n}:{}}]}):[];return{server_session_id:t.server_session_id,marker_id:t.marker_id,source_generation:"string"==typeof t.source_generation?t.source_generation:void 0,calibration_revision:"string"==typeof t.calibration_revision?t.calibration_revision:void 0,seq:t.seq,reported_at:Dg(t.reported_at)?t.reported_at:void 0,expires_at:Dg(t.expires_at)?t.expires_at:void 0,health:t.health,reported_presence:"boolean"==typeof t.reported_presence?t.reported_presence:null,complete:!0===t.complete,targets:i,ranges:n,zones:r}}(e);if(!t)return;if(!function(e,t){return!e||t.server_session_id!==e.server_session_id||t.source_generation!==e.source_generation||t.calibration_revision!==e.calibration_revision||t.seq>e.seq}(this.frames.get(t.marker_id),t))return;const i=function(e,t=Date.now()){if(!Dg(e.expires_at))return null;if(!Dg(e.reported_at))return Math.max(0,1e3*e.expires_at-t);const i=Math.max(0,1e3*(e.expires_at-e.reported_at)),n=Math.max(0,t-1e3*e.reported_at);return Math.max(0,i-n)}(t);"restricted"===t.health||"disabled"===t.health||0===i?(this.frames.delete(t.marker_id),this.deadlines.delete(t.marker_id)):(this.frames.set(t.marker_id,t),null==i?this.deadlines.delete(t.marker_id):this.deadlines.set(t.marker_id,this.monotonicNow()+i)),this.armExpiry(),this.host.requestUpdate()},{type:"houseplan/radar/subscribe",space_id:e})).then(e=>{n===this.generation&&this.host.isConnected?"function"==typeof e&&(this.unsubscribe=e):"function"==typeof e&&e()}).catch(()=>{n===this.generation&&this.stop()})}stop(){this.generation++,this.unsubscribe?.(),this.unsubscribe=void 0,this.connection=null,this.space="",clearTimeout(this.expiryTimer),this.expiryTimer=0,this.frames.size&&(this.frames.clear(),this.host.isConnected&&this.host.requestUpdate()),this.deadlines.clear()}armExpiry(){clearTimeout(this.expiryTimer);const e=this.monotonicNow(),t=[...this.deadlines.values()].filter(t=>t>e);if(!t.length)return;const i=Math.max(20,Math.min(...t)-e+10);this.expiryTimer=window.setTimeout(()=>{this.expiryTimer=0;let e=!1;const t=this.monotonicNow();for(const[i,n]of this.deadlines)n>t||(this.deadlines.delete(i),this.frames.delete(i),e=!0);this.armExpiry(),e&&this.host.isConnected&&this.host.requestUpdate()},i)}monotonicNow(){return globalThis.performance?.now?.()??Date.now()}}const Pg=Object.freeze({enabled:!1,z2mBaseTopics:Object.freeze([])});function Fg(e){if("string"!=typeof e)return null;const t=e.trim().replace(/^\/+|\/+$/g,"").replace(/\/{2,}/g,"/");return!t||t.length>180||/[#+\u0000-\u001f\u007f]/.test(t)?null:t}function zg(e){const t=e?.zigbee_topology;if(!t||"object"!=typeof t)return Pg;const i=t,n=Array.isArray(i.z2m_base_topics)?i.z2m_base_topics:Array.isArray(i.z2mBaseTopics)?i.z2mBaseTopics:[],r=new Set,o=[];for(const e of n){const t=Fg(e);if(t&&!r.has(t)&&(r.add(t),o.push(t),8===o.length))break}return{enabled:!0===i.enabled,z2mBaseTopics:o}}function Ig(e,t){const i={...e},n=t.z2mBaseTopics.map(Fg).filter(Boolean);return t.enabled||n.length?i.zigbee_topology={enabled:!0===t.enabled,z2m_base_topics:[...new Set(n)].slice(0,8)}:delete i.zigbee_topology,i}const Og={now:()=>performance.now(),requestFrame:e=>requestAnimationFrame(e),cancelFrame:e=>cancelAnimationFrame(e)},Eg=e=>Math.max(0,Math.min(1,e)),Ng=(e,t,i)=>e+(t-e)*i,Hg=(e,t,i)=>{const n=1-e;return 3*n*n*e*t+3*n*e*e*i+e*e*e},Lg=e=>{const t=Eg(e);if(0===t||1===t)return t;let i=0,n=1,r=t;for(let e=0;e<12;e++)r=(i+n)/2,Hg(r,.2,.2)0&&e.w>0?t/e.w:1,viewBox:{...e}}}function qg(e,t,i){const n=Math.max(1e-9,e.pixelsPerUnit),r=Math.max(1e-9,t/n),o=Math.max(1e-9,i/n);return{x:e.centerX-r/2,y:e.centerY-o/2,w:r,h:o}}function jg(e){const t=e.trim(),i=/^rgba?\(\s*([\d.]+)[, ]+([\d.]+)[, ]+([\d.]+)(?:\s*[,/]\s*([\d.]+))?\s*\)$/i.exec(t);if(i)return[Number(i[1]),Number(i[2]),Number(i[3]),null==i[4]?1:Number(i[4])];const n=/^#([0-9a-f]{6}|[0-9a-f]{8})$/i.exec(t)?.[1];return n?[parseInt(n.slice(0,2),16),parseInt(n.slice(2,4),16),parseInt(n.slice(4,6),16),8===n.length?parseInt(n.slice(6,8),16)/255:1]:null}function Wg(e,t,i){const n=jg(e),r=jg(t);if(!n||!r)return i<.5?e:t;const o=Eg(i);return`rgba(${Math.round(Ng(n[0],r[0],o))}, ${Math.round(Ng(n[1],r[1],o))}, ${Math.round(Ng(n[2],r[2],o))}, ${Ng(n[3],r[3],o).toFixed(3)})`}class Ug{constructor(e,t=Og){this._hooks=e,this._clock=t,this._token=0,this._raf=0,this._state=null}get state(){return this._state}get active(){return"running"===this._state?.phase||"preparing"===this._state?.phase}get presented(){return this._state?.presented||null}start(e,t,i,n=220){this.cancel(!1);const r=++this._token,o=this._clock.now();if(this._state={token:r,phase:n<=0?"settling":"running",from:e,to:t,presented:n<=0?t:e,startedAt:o,duration:Math.max(0,n),targetMode:i},n<=0)return this._hooks.frame(this._state),this._hooks.settled(this._state),this._state=null,r;this._hooks.frame(this._state);const s=e=>{const t=this._state;if(!t||t.token!==r)return;const i=Eg((e-t.startedAt)/t.duration);t.presented=i>=1?t.to:function(e,t,i){const n=Lg(i),r=Ng(e.stageWidth,t.stageWidth,n),o=Ng(e.stageHeight,t.stageHeight,n),s=Math.max(1e-9,e.viewport.pixelsPerUnit),a=Math.max(1e-9,t.viewport.pixelsPerUnit),l={centerX:Ng(e.viewport.centerX,t.viewport.centerX,n),centerY:Ng(e.viewport.centerY,t.viewport.centerY,n),pixelsPerUnit:Math.exp(Ng(Math.log(s),Math.log(a),n))};return{presentedMode:n<.5?e.presentedMode:t.presentedMode,editorChromeHeight:Ng(e.editorChromeHeight,t.editorChromeHeight,n),stageWidth:r,stageHeight:o,viewport:{...l,viewBox:qg(l,r,o)},stageColor:Wg(e.stageColor,t.stageColor,n),paperColor:Wg(e.paperColor,t.paperColor,n),sceneBrightness:Ng(e.sceneBrightness,t.sceneBrightness,n),architectureOpacity:Ng(e.architectureOpacity,t.architectureOpacity,n),backdropOpacity:Ng(e.backdropOpacity,t.backdropOpacity,n),viewWeight:Ng(e.viewWeight,t.viewWeight,n),editorWeight:Ng(e.editorWeight,t.editorWeight,n),toolbarContentOpacity:Ng(e.toolbarContentOpacity,t.toolbarContentOpacity,n)}}(t.from,t.to,i),t.phase=i>=1?"settling":"running",this._hooks.frame(t),i<1?this._raf=this._clock.requestFrame(s):(this._raf=0,this._hooks.settled(t),this._state?.token===r&&(this._state=null))};return this._raf=this._clock.requestFrame(s),r}cancel(e=!0){this._raf&&this._clock.cancelFrame(this._raf),this._raf=0;const t=this._state;this._state=null,this._token++,t&&e&&(t.phase="settling",t.presented=t.to,this._hooks.frame(t),this._hooks.settled(t))}dispose(){this.cancel(!1)}}const Gg={now:()=>"undefined"!=typeof performance?performance.now():Date.now(),requestFrame:e=>"function"==typeof requestAnimationFrame?requestAnimationFrame(e):null,cancelFrame:e=>{"function"==typeof cancelAnimationFrame&&cancelAnimationFrame(e)}},Vg=e=>Number.isFinite(e);function Kg(e){return!!e&&Vg(e.zoom)&&e.zoom>0&&Vg(e.viewBox.x)&&Vg(e.viewBox.y)&&Vg(e.viewBox.w)&&e.viewBox.w>0&&Vg(e.viewBox.h)&&e.viewBox.h>0}function Yg(e){return{zoom:e.zoom,viewBox:{...e.viewBox}}}function Xg(e,t){return Math.abs(e.zoom-t.zoom)<1e-9&&Math.abs(e.viewBox.x-t.viewBox.x)<1e-6&&Math.abs(e.viewBox.y-t.viewBox.y)<1e-6&&Math.abs(e.viewBox.w-t.viewBox.w)<1e-6&&Math.abs(e.viewBox.h-t.viewBox.h)<1e-6}const Zg=(e,t,i)=>e+(t-e)*i,Jg=(e,t,i)=>Math.exp(Zg(Math.log(e),Math.log(t),i));class Qg{constructor(e,t=Gg){this._hooks=e,this._clock=t,this._token=0,this._raf=null,this._state=null}get state(){return this._state}get active(){return"running"===this._state?.phase}get presented(){return this._state?.presented||null}get target(){return this._state?.to||null}start(e,t,i,n){this.cancel(!1);const r=++this._token,o=Yg(e),s=Yg(t),a=n>0&&Kg(o)&&Kg(s),l=this._clock.now(),c={token:r,phase:a?"running":"settling",from:o,to:s,presented:Yg(a?o:s),startedAt:l,duration:a?n:0,reason:i};if(this._state=c,this._hooks.frame(c),!a)return this._settle(r),r;const h=e=>{const t=this._state;if(!t||t.token!==r)return;const i=Math.max(0,Math.min(1,(e-t.startedAt)/t.duration));if(t.presented=i>=1?Yg(t.to):function(e,t,i){if(!Kg(e))return Yg(t);if(!Kg(t))return Yg(e);const n=Lg(i);if(n<=0)return Yg(e);if(n>=1)return Yg(t);const r=e.viewBox.x+e.viewBox.w/2,o=e.viewBox.y+e.viewBox.h/2,s=t.viewBox.x+t.viewBox.w/2,a=t.viewBox.y+t.viewBox.h/2,l=Jg(e.viewBox.w,t.viewBox.w,n),c=Jg(e.viewBox.h,t.viewBox.h,n),h=Zg(r,s,n),d=Zg(o,a,n);return{zoom:Jg(e.zoom,t.zoom,n),viewBox:{x:h-l/2,y:d-c/2,w:l,h:c}}}(t.from,t.to,i),t.phase=i>=1?"settling":"running",this._hooks.frame(t),i>=1)return this._raf=null,void this._settle(r);this._raf=this._clock.requestFrame(h),null===this._raf&&this._settle(r)};return this._raf=this._clock.requestFrame(h),null===this._raf&&(c.phase="settling",c.presented=Yg(s),this._hooks.frame(c),this._settle(r)),r}cancel(e=!0){null!==this._raf&&this._clock.cancelFrame(this._raf),this._raf=null;const t=this._state;this._state=null,this._token++,t&&e&&(t.phase="settling",t.presented=Yg(t.to),this._hooks.frame(t),this._hooks.settled(t))}dispose(){this.cancel(!1)}_settle(e){const t=this._state;t&&t.token===e&&(t.phase="settling",t.presented=Yg(t.to),this._hooks.settled(t),this._state?.token===e&&(this._state=null))}}function ef(e,t,i){const n=e.querySelector("ha-card");if(!n)return null;const r=n.getBoundingClientRect(),o=t.getBoundingClientRect().top-r.top,s=i?0:Math.min(Math.max(r.top,0),120),a=Math.round(o+s);return a>=0?a:null}const tf=Object.freeze({rotDeg:0,tiltDeg:20,xyScale:1,zScale:1,origin:Object.freeze([500,500])}),nf=84,rf=10,of=4,sf=4;function af(e){return[e.rotDeg,e.tiltDeg,e.xyScale,e.zScale,e.origin[0],e.origin[1]].every(Number.isFinite)&&Math.abs(e.xyScale)>1e-12&&Math.abs(Math.cos(e.tiltDeg*Math.PI/180))>1e-12}function lf(e,t,i=tf){if(!Number.isFinite(e[0])||!Number.isFinite(e[1]))throw new Error("invalid isometric projection input");return function(e,t){if(!Number.isFinite(e[0])||!Number.isFinite(e[1])||!t.every(Number.isFinite))throw new Error("invalid isometric affine input");const[i,n,r,o,s,a]=t;return[i*e[0]+r*e[1]+s,n*e[0]+o*e[1]+a]}(e,hf(t,i))}function cf(e,t=tf){if(!af(t)||!Number.isFinite(e[0])||!Number.isFinite(e[1]))throw new Error("invalid isometric projection input");const i=t.rotDeg*Math.PI/180,n=t.tiltDeg*Math.PI/180,r=(e[0]-t.origin[0])/t.xyScale,o=(e[1]-t.origin[1])/(t.xyScale*Math.cos(n));return[t.origin[0]+r*Math.cos(i)+o*Math.sin(i),t.origin[1]-r*Math.sin(i)+o*Math.cos(i)]}function hf(e=0,t=tf){if(!af(t)||!Number.isFinite(e))throw new Error("invalid isometric camera");const i=t.rotDeg*Math.PI/180,n=t.tiltDeg*Math.PI/180,r=t.xyScale*Math.cos(i),o=-t.xyScale*Math.sin(i),s=t.xyScale*Math.sin(i)*Math.cos(n),a=t.xyScale*Math.cos(i)*Math.cos(n);return[r,s,o,a,t.origin[0]-r*t.origin[0]-o*t.origin[1],t.origin[1]-s*t.origin[0]-a*t.origin[1]-e*t.zScale*Math.sin(n)]}function df(e=tf){return function(e=0,t=tf){return`matrix(${hf(e,t).map(e=>Number(e.toFixed(12))).join(" ")})`}(0,e)}function uf(e,t=tf){const{rect:i,wallHeight:n}=e,r=e.openingHeight??n,o=e.floorDepth??0,s=e.raisedHeight??n;if(!(i.w>=0)||!(i.h>=0)||!Number.isFinite(n)||!Number.isFinite(r)||!Number.isFinite(o)||!Number.isFinite(s)||n<0||r<0||o<0||s<0)throw new Error("invalid isometric frame");const a=[[i.x,i.y],[i.x+i.w,i.y],[i.x+i.w,i.y+i.h],[i.x,i.y+i.h]],l=Math.max(n,r,s),c=a.flatMap(e=>[lf(e,-o,t),lf(e,l,t)]),h=c.map(e=>e[0]),d=c.map(e=>e[1]),u=Math.min(...h),p=Math.min(...d);return{x:u,y:p,w:Math.max(...h)-u,h:Math.max(...d)-p}}const pf=[".dev",".vacpuck",".oplock",".op-hit",".opening",".rlgo","a","button","input","select","textarea",'[contenteditable]:not([contenteditable="false"])',"[data-room-fit-block]",'[role="link"]','[role="button"]'].join(","),_f=(e,t)=>{try{return"function"==typeof e?.matches&&e.matches(t)}catch{return!1}};function mf(e){for(const t of e){const e=t;if(_f(e,".roomlabel[data-id]")){const t=e.getAttribute?.("data-id");return t?{kind:"room",roomId:t}:{kind:"interactive"}}if(_f(e,pf))return{kind:"interactive"};if(_f(e,'[data-hp="room"][data-id]')){const t=e.getAttribute?.("data-id");return t?{kind:"room",roomId:t}:{kind:"interactive"}}if(_f(e,".stage"))return{kind:"background"}}return{kind:"outside"}}function gf(e){const t=mf(e);return"room"===t.kind?t.roomId:null}class ff{constructor(){this.pointer=null,this.sequence=null}clear(){this.pointer=null,this.sequence=null}clearOutside(e){let t={kind:"outside"};try{t=mf(e.composedPath())}catch{}"outside"===t.kind&&this.clear()}pointerDown(e,t,i){let n={kind:"outside"};try{n=mf(e.composedPath())}catch{}this.pointer=function(e){const t="mouse"===(i=e.pointerType)||"touch"===i||"pen"===i?i:null;var i;return t&&"view"===e.mode&&"background"===e.owner.kind&&!e.blocked&&e.isPrimary&&0===e.button&&Number.isFinite(e.x)&&Number.isFinite(e.y)?{pointerId:e.pointerId,spaceId:e.spaceId,modality:t,x:e.x,y:e.y}:null}({pointerId:e.pointerId,pointerType:e.pointerType,isPrimary:e.isPrimary,button:e.button,spaceId:t,mode:i?"view":"blocked",owner:n,blocked:!i,x:e.clientX,y:e.clientY}),this.pointer||(this.sequence=null)}pointerUp(e,t,i,n,r=Date.now()){let o={kind:"outside"};try{o=mf(e.composedPath())}catch{}const s=function(e,t,i){if(!t||"view"!==i.mode||"background"!==i.owner.kind||i.blocked||t.pointerId!==i.pointerId||t.spaceId!==i.spaceId||!Number.isFinite(i.x)||!Number.isFinite(i.y)||!Number.isFinite(i.now)||Math.abs(i.x-t.x)+Math.abs(i.y-t.y)>=8)return{sequence:null,trigger:!1};const n=e?i.now-e.at:Number.POSITIVE_INFINITY;return e&&e.spaceId===i.spaceId&&e.modality===t.modality&&n>=0&&n<=350?{sequence:null,trigger:!0}:{sequence:{at:i.now,spaceId:i.spaceId,modality:t.modality},trigger:!1}}(this.sequence,this.pointer,{pointerId:e.pointerId,spaceId:t,mode:i?"view":"blocked",owner:o,blocked:n||!i,x:e.clientX,y:e.clientY,now:r});return this.pointer=null,this.sequence=s.sequence,s.trigger}}const vf=e=>e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]);function yf(e){return!!e&&Number.isFinite(e.x)&&Number.isFinite(e.y)&&Number.isFinite(e.w)&&e.w>0&&Number.isFinite(e.h)&&e.h>0}function bf(e,t=0){if(!e.length||!Number.isFinite(t)||t<0||!e.every(vf))return null;let i=1/0,n=1/0,r=-1/0,o=-1/0;for(const t of e)i=Math.min(i,t[0]),n=Math.min(n,t[1]),r=Math.max(r,t[0]),o=Math.max(o,t[1]);const s=r-i,a=o-n;return s>0&&a>0?{x:i-t,y:n-t,w:s+2*t,h:a+2*t}:null}function wf(e,t,i){const n="string"!=typeof t||"invalid"!==t&&"no-borders"!==t&&"unverified"!==t&&!/^[a-z0-9]{1,8}$/i.test(t)?"redacted":t;return Object.freeze({kind:e,fingerprint:n,terminal:!!i})}function kf(e,t){return`${e("editor.load_failed")} ${e(t.terminal?"editor.refresh_advice":"editor.retry_advice")}`}class xf extends Error{}class Sf{constructor(e){this.options=e,this._state="idle",this._inFlight=null}get state(){return this._state}ensure(){return"ready"===this._state?Promise.resolve(!0):"failed"===this._state?Promise.resolve(!1):(this._inFlight||(this._setState("loading"),this._inFlight=this._loadWithRetry().finally(()=>{this._inFlight=null})),this._inFlight)}async _loadWithRetry(){let e=new Error("Editor runtime did not load"),t=!1;for(const i of[0,1])try{const e=await this.options.load(i);if(e.fingerprint!==this.options.expectedFingerprint)throw new xf(`Editor runtime fingerprint mismatch: expected ${this.options.expectedFingerprint}, got ${e.fingerprint}`);const t=e.create();return this.options.install(t),this._setState("ready"),!0}catch(i){e=i,i instanceof xf&&(t=!0)}return this._setState(t?"failed":"idle"),this.options.failed?.(e,{terminal:t}),!1}_setState(e){e!==this._state&&(this._state=e,this.options.stateChanged?.(e))}}const $f=(e,t)=>{if(!e.has(t))return{hit:!1};const i=e.get(t);return e.delete(t),e.set(t,i),{hit:!0,value:i}},Mf=(e,t,i,n)=>{for(e.delete(t),e.set(t,i);e.size>n;){const t=e.keys().next().value;if(void 0===t)break;e.delete(t)}},Rf=new Set(["select","draw","column","merge","split","resize","opening","wallthick","delroom"]),Cf=e=>`${window.innerWidth}x${window.innerHeight}|${location.pathname}|${JSON.stringify(e??{})}`,Tf="houseplan_card_alpha_v1",Df=Object.freeze([Object.freeze({id:"iso",issue:89,summary:"Volumetric plan renderer"})]);function Af(e){return/^[a-z][a-z0-9-]*$/.test(e.id)&&Number.isInteger(e.issue)&&e.issue>0&&!!e.summary.trim()}function Pf(e){const t=String(e||"").replace(/^#/,"");return new URLSearchParams(t)}function Ff(e){return Pf(e).get("space")||""}function zf(e,t,i=Df){const n=function(e){const t=new Set;for(const i of e){if(!Af(i)||t.has(i.id))return!1;t.add(i.id)}return!0}(i),r=function(e){let t,i=!1;const n=e=>{for(const n of e.getAll("hp_alpha"))i=!0,"1"===n?t=!0:"0"===n&&(t=!1)};return n(new URLSearchParams(String(e.search||"").replace(/^\?/,""))),n(Pf(e.hash)),{present:i,value:t}}(e),o=void 0!==r.value,s="1"===t,a=o?!0===r.value:!r.present&&s,l=n&&a;return{alpha:l,active:Object.freeze(l?i.map(e=>e.id).sort():[]),space:Ff(e.hash),persist:n&&o?l?"1":"0":void 0,knownUrlOperation:o}}let If={alpha:!1,active:Object.freeze([]),space:""},Of=!1,Ef="";const Nf=new Set;function Hf(){if("undefined"==typeof window)return If;const e=zf(window.location,function(){try{return window.localStorage.getItem(Tf)}catch{return null}}());void 0!==e.persist&&function(e){try{window.localStorage.setItem(Tf,e)}catch{}}(e.persist),If={alpha:e.alpha,active:e.active,space:e.space},window.__hpAlpha=e.alpha,window.__hpLabs=e.active;for(const e of Nf)e(If);return If}function Lf(){Hf()}function Bf(){if("undefined"==typeof window)return If;if(!Of){Of=!0,window.__hpLabsListenerCleanup?.(),window.addEventListener("hashchange",Lf),window.addEventListener("popstate",Lf);const e=()=>{window.removeEventListener("hashchange",Lf),window.removeEventListener("popstate",Lf),window.__hpLabsListenerCleanup===e&&delete window.__hpLabsListenerCleanup};window.__hpLabsListenerCleanup=e}return Hf()}const qf={window:120,door:90,passage:90,gate:300};function jf(e){return qf[e]}function Wf(e,t){return{type:e,lengthCm:jf(e),flipH:!1,flipV:!1,revision:t}}function Uf(e,t){const i=Math.max(0,e.renderedLength)/2,n=Math.max(0,e.target.physicalHalfWidth),r=n+.18*Math.max(0,t),o=e=>({x1:e,y1:-r,x2:e,y2:r});return{rect:{x:-i,y:n?-n:0,width:2*i,height:2*n},boundaries:[o(-i),o(i)]}}function Gf(e,t){const i=[e[0],e[1]],n=[t[0],t[1]];return function(e,t){return e[0]-t[0]||e[1]-t[1]}(i,n)<=0?{a:i,b:n}:{a:n,b:i}}function Vf(e){const t=new Map;return e.forEach((e,i)=>{if(!e.kind||e.open)return;const n=Gf(e.a,e.b);if(Math.hypot(n.b[0]-n.a[0],n.b[1]-n.a[1])<=1e-9)return;const r=function(e,t){const i=e=>(Math.abs(e)<=5e-10?0:Math.round(1e6*e)/1e6).toFixed(6);return`${i(e[0])},${i(e[1])}>${i(t[0])},${i(t[1])}`}(n.a,n.b),o=t.get(r);if(o)return o.physicalHalfWidth=Math.max(o.physicalHalfWidth,e.half||0),o.sourceOrder=Math.min(o.sourceOrder,i),void(e.partitionHost&&(o.partitionHost&&o.partitionHost.id!==e.partitionHost.id?o.ambiguousPartitionHost=!0:o.partitionHost=e.partitionHost));t.set(r,{segmentKey:r,a:n.a,b:n.b,physicalHalfWidth:Math.max(0,e.half||0),sourceOrder:i,...e.partitionHost?{partitionHost:e.partitionHost}:{}})}),[...t.values()]}function Kf(e,t){if(Math.abs(e.distance-t.distance)>1e-9)return e.distance-t.distance;if(Math.abs(e.perpendicular-t.perpendicular)>1e-9)return e.perpendicular-t.perpendicular;return(e.target.segmentKeyt.target.segmentKey?1:0)||e.target.sourceOrder-t.target.sourceOrder}function Yf(e){const t=Vf(e.intervals).map(t=>{const i=function(e,t){const i=t.b[0]-t.a[0],n=t.b[1]-t.a[1],r=Math.hypot(i,n),o=i/r,s=n/r,a=(e[0]-t.a[0])*o+(e[1]-t.a[1])*s,l=Math.max(0,Math.min(r,a)),c=t.a[0]+l*o,h=t.a[1]+l*s;return{along:l,length:r,x:c,y:h,distance:Math.hypot(e[0]-c,e[1]-h),perpendicular:Math.abs((e[0]-t.a[0])*s-(e[1]-t.a[1])*o)}}(e.pointer,t);return{target:t,...i,envelope:Math.max(e.baseTolerance,t.physicalHalfWidth+e.bodyPointerPadding)}}).filter(e=>e.distance<=e.envelope+1e-9).filter(t=>!function(e,t,i,n,r){const o=t.b[0]-t.a[0],s=t.b[1]-t.a[1],a=Math.hypot(o,s);if(!(a>1e-9))return!1;const l=o/a,c=s/a;for(const o of i){if(!o.open&&o.kind)continue;const i=Gf(o.a,o.b),s=i.b[0]-i.a[0],a=i.b[1]-i.a[1],h=Math.hypot(s,a);if(!(h>1e-9))continue;const d=s/h,u=a/h;if(Math.abs(l*u-c*d)>1e-6)continue;if(Math.abs((i.a[0]-t.a[0])*c-(i.a[1]-t.a[1])*l)>r)continue;const p=(e[0]-i.a[0])*d+(e[1]-i.a[1])*u,_=1e-9;if(!(p<=_||p>=h-_)&&Math.abs((e[0]-i.a[0])*u-(e[1]-i.a[1])*d)<=n+1e-9)return!0}return!1}(e.pointer,t.target,e.intervals,t.envelope,Math.max(1e-9,Math.min(e.baseTolerance,.04*e.gridStep)))),i=t.filter(t=>!!t.target.partitionHost&&e.renderedLength+2*t.target.physicalHalfWidth>t.length+1e-9).sort(Kf),n=t.filter(t=>!t.target.partitionHost||e.renderedLength+2*t.target.physicalHalfWidth<=t.length+1e-9).sort(Kf);let r=n[0];if(!r)return{candidate:null,jambBlockedTarget:i[0]?.target||null};const o=n.filter(e=>Math.abs(e.distance-r.distance)<=1e-9&&Math.abs(e.perpendicular-r.perpendicular)<=1e-9),s=o.filter(e=>e.target.partitionHost);if(s.length){if(1!==new Set(s.map(e=>e.target.partitionHost.id)).size||s.some(e=>e.target.ambiguousPartitionHost))return{candidate:null,jambBlockedTarget:null};const e=s[0],t=e.target.b[0]-e.target.a[0],i=e.target.b[1]-e.target.a[1],n=Math.hypot(t,i),a=t/n,l=i/n;if(!o.every(t=>{const i=t.target.b[0]-t.target.a[0],n=t.target.b[1]-t.target.a[1],r=Math.hypot(i,n),o=i/r,s=n/r,c=Math.abs(a*s-l*o)<=1e-6,h=Math.abs((t.target.a[0]-e.target.a[0])*l-(t.target.a[1]-e.target.a[1])*a);return c&&h<=1e-9}))return{candidate:null,jambBlockedTarget:null};r=e}if(r.target.ambiguousPartitionHost)return{candidate:null,jambBlockedTarget:null};const{target:a,length:l}=r,c=a.b[0]-a.a[0],h=a.b[1]-a.a[1],d=c/l,u=h/l,p=a.partitionHost?a.physicalHalfWidth:0,_=Math.min(Math.max(0,e.renderedLength)/2+p,l/2);let m=r.along;const g=Math.max(e.gridStep,1e-9),f=l/2;m=Math.abs(m-f)<=g/2?f:Math.round(m/g)*g,m=Math.max(_,Math.min(l-_,m));const v=a.a[0]+d*m,y=a.a[1]+u*m,b=Math.max(0,e.renderedLength)/2,w=m-b,k=m+b,x=Math.max(0,w),S=Math.max(0,l-k),$=[a.a[0]+d*(w-x/2),a.a[1]+u*(w-x/2)],M=[a.a[0]+d*(k+S/2),a.a[1]+u*(k+S/2)];let R=180*Math.atan2(h,c)/Math.PI;R>=90?R-=180:R<-90&&(R+=180);const C=Math.abs(m-f)<=1e-9;return{candidate:{presetRevision:e.preset.revision,geometryRevision:e.geometryRevision,pointer:[e.pointer[0],e.pointer[1]],type:e.preset.type,lengthCm:e.preset.lengthCm,flipH:e.preset.flipH,flipV:e.preset.flipV,x:v,y:y,angle:R,renderedLength:e.renderedLength,target:a,...a.partitionHost?{host:{...a.partitionHost,t:l>0?m/l:0}}:{},measure:{labels:[{distance:x,midpoint:$},{distance:S,midpoint:M}],guide:C?{x:v,y:y,angle:R}:null}},jambBlockedTarget:null}}function Xf(e,t,i,n,r=1e-6){return e.presetRevision===i&&e.geometryRevision===n&&Math.hypot(e.pointer[0]-t[0],e.pointer[1]-t[1])<=r}function Zf(e){return!(!e.canEdit||e.kiosk||e.fixedFloor)&&("view"!==e.mode&&("mouse"===e.pointerType&&e.spaceCount>1))}class Jf{constructor(e,t,i){this.loader=e,this.host=t,this.adopted=i,this.attachment=null}connect(){if(this.runtime)return void this.runtime.connect();this.attachment?.cancel();const e=this.loader.attach(this.host,e=>this.adopt(e));this.runtime||(this.attachment=e)}disconnect(){this.attachment?.cancel(),this.attachment=null,this.runtime?.disconnect()}adopt(e){this.attachment=null,this.runtime||(this.runtime=e,this.adopted(e))}}const Qf=new class{constructor(e){this.load=e,this.factory=null,this.pending=null}get warm(){return null!==this.factory}create(e){return this.factory?this.factory(e):null}attach(e,t){let i=!0;const n={cancel:()=>{i=!1}},r=this.create(e);return r?(t(r),n):(this.ensure().then(n=>{i&&t(n(e))},()=>{}),n)}ensure(){return this.factory?Promise.resolve(this.factory):(this.pending||(this.pending=this.load().then(e=>(this.factory=e,this.pending=null,e),e=>{throw this.pending=null,e})),this.pending)}reset(){this.factory=null,this.pending=null}}(()=>import("./summary-panel-runtime-loaded-BGIJeXIz.js").then(function(e){return e.e}).then(({LoadedSummaryPanelRuntime:e})=>t=>new e(t)));function ev(e){const t=globalThis.__HP_VERSION_OVERRIDE__;return"string"==typeof t&&t.length>0?t:e}let tv=0;const iv="1.77.0-beta.2",nv="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f",rv=1500,ov=new Map;let sv=0,av=1e4;const lv="houseplan_card_layout_v1",cv="houseplan_card_cfg_v1",hv="houseplan_card_zoom_v1",dv="houseplan_card_nav_v1",uv="houseplan_card_view_v1",pv="hp-dialog, hp-help, hp-color-opacity, hp-device-preview",_v=1e3,mv=(e,t)=>{const i=Math.min(e.x,t.x),n=Math.min(e.y,t.y);return{x:i,y:n,w:Math.max(e.x+e.w,t.x+t.w)-i,h:Math.max(e.y+e.h,t.y+t.h)-n}},gv=(e,t,i)=>{const n=new Event(t,{bubbles:!0,composed:!0});n.detail=i??{},e.dispatchEvent(n)},fv=e=>{history.pushState(null,"",e),gv(window,"location-changed",{replace:!1})},vv=(e,t)=>{let i,n=null;const r=(...r)=>{clearTimeout(i),n=r,i=window.setTimeout(()=>{i=void 0;const t=n;n=null,t&&e(...t)},t)};return r.flush=()=>{if(void 0===i)return;clearTimeout(i),i=void 0;const t=n;n=null,t&&e(...t)},r.cancel=()=>{clearTimeout(i),i=void 0,n=null},r.pending=()=>void 0!==i,r},yv=e=>{try{e.target?.setPointerCapture?.(e.pointerId)}catch{}},bv=["edges","corners"];class wv extends he{constructor(){var e;super(...arguments),this._editorRuntime=null,this._liveRt=null,this._onboardingRuntime=null,this._editorRuntimeLoadingVisible=!1,this._backdropGuard=null,this._editorModeRequest=0,this._warmModeRequest=0,this._editorRuntimeLoader=new Sf({expectedFingerprint:nv,load:async e=>{const t=0===e?await import("./houseplan-editor-runtime-BlocE3XU.js"):await import((()=>{const e=new URL("./houseplan-editor-runtime-BlocE3XU.js",import.meta.url);return e.searchParams.set("hp_retry",`${iv}-${++tv}`),e.href})());return{fingerprint:t.EDITOR_RUNTIME_FINGERPRINT,create:()=>new t.HouseplanEditorRuntime(this)}},install:e=>{this._editorRuntime=e},stateChanged:e=>this._editorRuntimeStateChanged(e),failed:(e,t)=>{console.error("[houseplan] unable to load editor runtime",e),t.terminal&&this._versionRecovery.hasCurrentMismatchNotice||this._showToast(kf(e=>this._t(e),t))}}),this._onboardingRuntimeLoader=new Sf({expectedFingerprint:nv,load:async e=>{const t=0===e?await import("./houseplan-onboarding-runtime-DYojoXE_.js"):await import((()=>{const e=new URL("./houseplan-onboarding-runtime-DYojoXE_.js",import.meta.url);return e.searchParams.set("hp_retry",`${iv}-${++tv}`),e.href})());return{fingerprint:t.ONBOARDING_RUNTIME_FINGERPRINT,create:()=>new t.HouseplanOnboardingRuntime(this)}},install:e=>{this._onboardingRuntime=e},failed:(e,t)=>{console.error("[houseplan] unable to load onboarding runtime",e),t.terminal&&this._versionRecovery.hasCurrentMismatchNotice||this._showToast(kf(e=>this._t(e),t))}}),this._isoSceneRuntime=null,this._isoSceneRuntimeLoader=new Sf({expectedFingerprint:nv,load:async e=>{const t=0===e?await import("./iso-scene-render-BfrsUAJf.js"):await import((()=>{const e=new URL("./iso-scene-render-BfrsUAJf.js",import.meta.url);return e.searchParams.set("hp_retry",`${iv}-${++tv}`),e.href})());return{fingerprint:t.ISO_SCENE_RUNTIME_FINGERPRINT,create:()=>t}},install:e=>{const t=this._effectiveProjection();this._isoSceneRuntime=e,this._isoProjectionSnapshot=null;const i=this._effectiveProjection();this._convertProjectionView(t,i),this.isConnected&&this.requestUpdate()},failed:(e,t)=>{console.warn("[houseplan] hidden isometric runtime diagnostic",wf("runtime-load","unverified",t.terminal)),this.isConnected&&this.requestUpdate()}}),this._pdfRuntime=null,this._pdfRuntimeLoader=new Sf({expectedFingerprint:nv,load:async e=>{const t=0===e?await import("./pdf-export-Bslsp3h0.js"):await import((()=>{const e=new URL("./pdf-export-Bslsp3h0.js",import.meta.url);return e.searchParams.set("hp_retry",`${iv}-${++tv}`),e.href})());return{fingerprint:t.PDF_EXPORT_FINGERPRINT,create:()=>new t.PdfExportRuntime}},install:e=>{this._pdfRuntime=e,this.isConnected&&this.requestUpdate()},failed:(e,t)=>{if(console.error("[houseplan] unable to load PDF export runtime",e),!t.terminal||!this._versionRecovery.hasCurrentMismatchNotice){const e=kf(e=>this._t(e),t),i=this._t("editor.load_failed"),n=e.startsWith(i)?e.slice(i.length).trim():e;this._showToast(`${this._t("pdf.failed")} ${n}`.trim())}}}),this.panelHost=!1,this.narrow=null,this._space="f1",this._adoption=new qu((e,t)=>this.requestUpdate(e,t)),this._serverStorage=!1,this._loadOk=!1,this._serverCanWrite=null,this._loading=!1,this._loadTries=0,this._unsubCfg=null,this._unsubLayout=null,this._unsubVirtual=null,this._liveSyncAttempt=null,this._liveSyncGeneration=0,this._liveSyncConnection=null,this._configReloadAuthority=new Gu,this._virtualLights=Hh(null),this._canOptimizeUndo=!1,this._undoKind=null,this._devices=[],this._regSignature="",this._defPos={},this._newSyncKey="",this._areaRelocationIds=new Set,this._areaSnapshotCleanupCandidates=new Map,this._areaRelocationSyncKey="",this._areaRelocationWrite=Promise.resolve(),this._tip=null,this._hoverRoom=null,this._pointerModality=new sg(this,()=>this._syncPointerHoverTargets()),this._devicePressAnimations=new Map,this._selId=null,this._toast="",this._mode="view",this._pendingNavMode=null,this._decorTool="select",this._decorStyle={...Cr},this._decorStyleSeeded=!1,this._decorDraft=null,this._decorMove=null,this._decorSel=null,this._decorEraseConfirm=null,this._decorTextDialog=null,this._decorShapeDialog=null,this._backdropDialog=null,this._decorTextSelection={start:0,end:0},this._furnPalette=null,this._decorImagePalette=null,this._decorAssetCatalog=[],this._decorAssets=new Map,this._decorAssetBusy=!1,this._furnCategory=null,this._furnPreviewInput=null,this._furnTouchPending=null,this._dtBox=null,this._dtDrag=null,this._bdDrag=null,this._slide="",this._reducedMotion=!1,this._onMotionChange=e=>{this._reducedMotion=e.matches,this._cancelDevicePressFeedback(),e.matches&&this._cancelCameraTransition(!0),e.matches&&this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:e.matches&&this._modeTransition.active&&this._cancelModeTransition(!0),this._syncVersionRecovery(),this.requestUpdate()},this._editorChromeMode="plan",this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest=0,this._modeTransitionTargetZoom=1,this._modeTransitionEditorCamera=null,this._modeTransition=new Ug({frame:e=>this._applyModeTransitionFrame(e),settled:e=>this._settleModeTransition(e)}),this._cameraTransitionFit=null,this._cameraTransition=new Qg({frame:e=>this._applyCameraTransitionFrame(e),settled:e=>this._settleCameraTransition(e)}),this._editorSecondaryCopy={groupActive:(e,t)=>this._t("editor.group_active",{group:e,item:t}),openGroup:e=>this._t("editor.open_group",{group:e}),disabledAction:(e,t)=>this._t("editor.disabled_action",{action:e,reason:t})},this._tool="draw",this._geometryHistory=new gg(50),this._devicePositionHistory=new gg(50),this._devicePositionBusy=!1,this._wallDialog=null,this._drawWallField=null,this._activeWallChainId=null,this._activeWallChainPartitionIds=[],this._wallChainRedo=[],this._physicalSel=null,this._physicalDialog=null,this._partitionDeleteDialog=null,this._roomDeleteDialog=null,this._physicalDrag=null,this._physicalRotate=null,this._physicalLastTap=null,this._physicalPickCycle=null,this._wallUnionCacheValue=null,this._wallUnionPool=new Map,this._isoGeometryCache=new Map,this._renderIsoScene=null,this._isoProjectionSnapshot=null,this._isoStructuralBuildCount=0,this._isoFallback=new Set,this._openingTunnelCache=null,this._openingWallIndexCache=new Map,this._openingPlacementIntervalsCache=null,this._openingDimensionContextCache=null,this._planSnapGeometryCache=null,this._planStructuralGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._physicalBodiesCache=null,this._lightPhysicalBodiesCache=null,this._cleanFloorCache=new Map,this._innerContourCache=new Map,this._glowRuntimeState=bm(),this._glowRuntimeHost={window:()=>this.ownerDocument.defaultView||window,isConnected:()=>this.isConnected,requestUpdate:()=>this.requestUpdate(),reducedMotion:()=>this._reducedMotion},this._lightBarrierCache=null,this._lightBarrierPool=new Map,this._glowScreenBlend=!1,this._duplicateColumnId=null,this._duplicateColumnTimer=0,this._rszLimitViolation=null,this._path=[],this._cursorPt=null,this._planSnapHover=null,this._mergeSel=null,this._openingPreset=null,this._openingRebindId=null,this._openingPresetRevision=0,this._openingHoverCandidate=null,this._openingJambBlockCm=null,this._openingDialog=null,this._openingInfo=null,this._opDrag=null,this._opMeasure=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._wallFaceBatch=null,this._wallRepairDiagnostic=null,this._wallFaceGraphCache=[],this._areaSel="",this._nameSel="",this._roomDialog=!1,this._roomEditId=null,this._roomFill="",this._roomCustomFill=null,this._roomTempMin="",this._roomTempMax="",this._roomTempSrc="",this._roomHumSrc="",this._roomSrcOpen=null,this._roomSrcFilter="",this._roomNameScale=1,this._roomLabelScale=1,this._zoom=1,this._view=null,this._zoomBySpace={},this._viewModeSnap=null,this._roomFocus=null,this._roomPointer=null,this._doubleFit=new ff,this._deviceHits=new wc,this._pointers=new Map,this._panStart=null,this._panLock=null,this._pinchStart=null,this._safeDayCycleOutline=!1,this._suppressClick=!1,this._viewportGestureDirty=!1,this._touchContacts=new Map,this._touchClickGuard=new pc,this._connectedPath="",this._routeDepartureHandled=!1,this._onLocationChanged=()=>{this._connectedPath&&location.pathname!==this._connectedPath?this._leaveCardRoute():location.pathname===this._connectedPath&&(this._routeDepartureHandled=!1)},this._touchGestureGuard={capture:!0,handleEvent:e=>this._guardTouchGesture(e)},this._hdrH=118,this._booting=!0,this._bootFading=!1,this._bootSettling=!1,this._bootSettleRaf=0,this._bootLastH=-1,this._bootStart=0,this._bootLastChange=0,this._bootSoft=!1,this._tapConfirm=null,this._dangerConfirm=null,this._dangerConfirmController=new ze(e=>{this._dangerConfirm=e}),this._confirmDanger=e=>this._config&&this.hass?"warm"===this._syncDangerConfirmLocaleGate()||this._dangerConfirmMissingSpace()?Promise.resolve(!1):this._dangerConfirmController.confirm(e):Promise.resolve(!1),this._cancelDangerConfirm=()=>{this._dangerConfirmController.cancel()},this._onDangerConfirmDecision=e=>{this._dangerConfirmController.resolve(e.detail.token,e.detail.accepted)},this._onboardingShown=!1,this._rulesDialog=null,this._preflightClipboardFallback=null,this._haIntegrationVersion=null,this._versionRecovery=(e=this,new wg({clock:{setTimeout:(e,t)=>window.setTimeout(e,t),clearTimeout:e=>window.clearTimeout(e)},storage:()=>e.ownerDocument.defaultView?.sessionStorage??null,safety:()=>Sg(e),reload:()=>e._reloadDocument(),changed:()=>{e.requestUpdate()}})),this._haSupportApi=null,this._haDecorAssetsApi=null,this._haSummaryPanelApi=null,this._haRadarStage1Api=null,this._radarLive=new Ag(this),this._decorAssetSyncToken=0,this._alignDialog=null,this._settingsDialog=null,this._pdfDialog=!1,this._supportDialog=null,this._backupExportDialog=null,this._backupImportDialog=null,this._sunRaysCache=null,this._dayCycleTimer=0,this._dayCycleClockKey="",this._compassDrag=!1,this._importDialog=null,this._importQueue=[],this._importTotal=0,this._rulesCompiledSrc="",this._infoCard=null,this._nativeMoreInfoEntity=null,this._deviceInbox=null,this._deviceInboxReturn=null,this._deviceInboxMemo=null,this._markerDialog=null,this._spaceDialog=null,this._keyHandler=e=>this._onKey(e),this._warmVp=null,this._warmVpArmed=!1,this._warmLongReturn=!1,this._warmRevivePending=!1,this._warmGen=++sv,this._warmKey=null,this._warmSlot=null,this._hashApplied=!1,this._navApplied=!1,this._labs={alpha:!1,active:Object.freeze([]),space:""},this._viewPreference={},this._renderProjection="flat",this._kioskScale={icon:1,font:1},this._kioskDialog=!1,this._summarySlot=new Jf(Qf,this,e=>{this._summary=e,this._capturedSnapshotSequence=-1,this.isConnected&&(e.connect(),this.hasUpdated&&this.requestUpdate())}),this._activityRt=new Map,this._vacRt=new Map,this._vacViewKey="",this._vacLastView=null,this._vacRaf=0,this._vacSrvTrails={},this._vacJumpOnce=!1,this._continuity=this._newContinuityController(),this._continuityHistory=[],this._continuityEpoch=0,this._continuityDataReady=!0,this._continuityPaintToken=-1,this._continuityDisposed=!1,this._renderSnapshotAt=Date.now(),this._hassSequence=0,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotSequence=-1,this._capturedSnapshotDevices=null,this._capturedSnapshotLayout=null,this._capturedSnapshotActivity="",this._capturedSnapshotConfigEpoch=-1,this._capturedSnapshotVirtual="",this._lastValidStageSize=null,this._pendingRefitSize=null,this._refitRaf=0,this._pageVisibility=e=>{if(this._continuity.visibility(e),this._dayCycleVisibility(e),this._summary?.visibility(e.kind),"hidden"===e.kind)return this._radarLive.stop(),this._editorRuntime?._cancelRadarSetup(),this._clearRoomFocus(!0),this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._cancelCameraTransition(!0),void(this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:this._cancelModeTransition(!0));if(this._vacJumpOnce=!0,this._syncRadarLive(),!e.long){const e=Date.now();let t=!1;for(const i of this._activityRt.values())!i.flashKind||(i.expiresAt||i.flashTs+tg)>e||(i.flashTs=0,i.flashKind=null,i.expiresAt=0,t=!0);return void(t&&this.requestUpdate())}Date.now()-this._renderSnapshotAt>1e3&&this._continuity.note("device-snapshot-stale"),this._continuityDataReady=!1,this._continuityPaintToken=-1,this._resumeSettling=!0,this._loading?this.requestUpdate():this._loadFromServer()},this._resumeSettling=!1,this._viewportInvalidAt=0,this._vacFit=null,this._vacAllCamerasFor=null,this._vacAllCameraCache=null,this._vacCalConfirm=null,this._kioskDots=!1,this._cyclePausedUntil=0,this._swipeStart=null,this._tabDrag=null,this._tabDragRelease=null,this._tabSuppressClick=!1,this._tabOrderWarned=!1,this._onLabsSnapshot=e=>{const t=this._effectiveProjection();this._labs=e,this._isoProjectionSnapshot=null,this._labsIso&&this._ensureIsoSceneRuntime();const i=this._effectiveProjection();this._convertProjectionView(t,i),this.requestUpdate()},this._onHashChange=()=>{if(this._hasFixedFloor)return;const e=this._hashSpace();if(e&&this._model.find(t=>t.id===e)&&e!==this._space){if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return;this._commitSpace(e),this._selId=null,this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeWallChainId=null,this._activeWallChainPartitionIds=[],this._wallChainSegmentCms=[],this._closingWallCm=null,this._restoreZoom(),this.requestUpdate()}},this._drag=null,this._deviceDrag=null,this._rlResize=null,this._holdFired=!1,this._retryContinuity=()=>{this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.retry(this._continuity.recoveryReason||"plan"),this._loading||this._loadFromServer()},this._cfgEpoch=0,this._cfgEpochPreservedConfig=null,this._terminalFrame=0,this._modelCache=null,this._emptySpaceStateActive=!1,this._decorSnapCache=null,this._markerPreviewMemo=null,this._markerPreviewDevicesMemo=null,this._showHidden=!1,this._connHooked=null,this._connectionWasLost=!1,this._haRegistryConnection=null,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._renderLife=new $g,this._liveEditorPaintCount=0,this._onHaRegistryUpdate=()=>{const e=nd(this.hass);e.revision===this._haRegistryRev&&this._devices.length||(this._haRegistryRev=e.revision,this._renderLife.invalidate(),this._planHassMemo=null,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate())},this._onConnReady=()=>{if(this._loadTries=0,clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,id(this.hass),this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(this._onConnReady,400));!this._connectionWasLost&&this._continuity.hasCompleteFrame?this._beginContinuityCandidate("connection-ready",!1,"plan"):(this._continuityDataReady=!1,this._continuityPaintToken=-1),this._loading||this._loadFromServer()},this._onConnLost=()=>{this._booting&&!this._continuity.hasCompleteFrame||(this._connectionWasLost=!0,this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.connectionLost())},this._signer=new uc(()=>this.requestUpdate()),this._dirtyPos=new Set,this._sentPos=new Map,this._persistLayout=vv(()=>{if(this._serverStorage){const e=[...this._dirtyPos];this._dirtyPos.clear();for(const t of e){const e=xo(this._layout[t]);e&&(this._layout={...this._layout,[t]:e},this._sentPos.set(t,e),this.hass.callWS({type:"houseplan/layout/update",device_id:t,pos:e}).then(e=>this._noteLayoutRev(e)).catch(e=>this._showToast(this._t("toast.pos_save_failed",{err:this._errText(e)}))).finally(()=>{this._sentPos.get(t)===e&&this._sentPos.delete(t)}))}this._cacheSnapshot()}else this._persistLocalLayout()},600),this._frame=null,this._showFar=!1,this._writesPending=0,this._writeChain=Promise.resolve(),this._pendingPhysicalWrites=new Map,this._undoGeometry=()=>this._editorRuntimeOrThrow()._undoGeometry(),this._redoGeometry=()=>this._editorRuntimeOrThrow()._redoGeometry(),this._saveConfigDebounced=vv(()=>{this._serverCfg&&this._writeConfig().catch(e=>{const t=!0===e?.physicalGeometryRolledBack;"geometry-unsafe"!==e?.code&&("wall_model_client_outdated"===e?.code?this._showToast(this._t("toast.wall_model_client_outdated")):"conflict"===e?.code?(this._showToast(this._t("toast.conflict")),t||(this._cancelPath(),this._reloadConfigOnly(!0))):this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(e)})),t&&this._reloadRejectedPhysicalWrite())})},500),this._wallChainSegmentCms=[],this._closingWallCm=null,this._savePhysicalDialog=()=>this._editorRuntimeOrThrow()._savePhysicalDialog(),this._deletePhysicalSelection=()=>this._editorRuntimeOrThrow()._deletePhysicalSelection(),this._confirmPartitionDelete=()=>this._editorRuntimeOrThrow()._confirmPartitionDelete(),this._confirmRoomDelete=e=>this._editorRuntimeOrThrow()._confirmRoomDelete(e),this._rebindPartitionOpening=()=>this._editorRuntimeOrThrow()._rebindPartitionOpening(),this._keepClosedAsPartitions=()=>this._editorRuntimeOrThrow()._keepClosedAsPartitions(),this._toggleServerPlans=async()=>this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._toggleServerPlans():this._editorRuntimeOrThrow()._toggleServerPlans(),this._aspectJob=null,this._dayCycleTick=()=>{if(!this.isConnected||"hidden"===this.ownerDocument.visibilityState)return;const e=this._dayCycleState();if(!e)return this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),void(this._dayCycleClockKey="");const t=cr(e);t!==this._dayCycleClockKey&&(this._dayCycleClockKey=t,this.requestUpdate())},this._sunShown=!1,this._sunOut=!1,this._sunOutTimer=0,this._openSettingsDialog=()=>{if(this._editorRuntime)return this._editorRuntime._openSettingsDialog();this._ensureEditorRuntime().then(e=>{e&&this._openSettingsDialog()})},this._openSupportDialog=()=>{this._editorRuntime?this._editorRuntime._openSupportDialog():this._ensureEditorRuntime().then(e=>{e&&this._openSupportDialog()})},this._openPdfDialog=()=>{this._pdfRuntimeLoader.ensure().then(e=>{e&&(this._pdfDialog=!0,this.requestUpdate())})},this._reportedPreflightFingerprint=null,this._openAlignDialog=()=>this._editorRuntimeOrThrow()._openAlignDialog(),this._toggleOptimizeLivePositions=()=>this._editorRuntimeOrThrow()._toggleOptimizeLivePositions(),this._optimizeUndoBusy=!1,this._openBackupExport=()=>this._editorRuntimeOrThrow()._openBackupExport(),this._openRulesDialog=()=>this._editorRuntimeOrThrow()._openRulesDialog(),this._climateCache=null,this._gearPtCache=new WeakMap}requestUpdate(e,t,i){if("hass"===e&&this.hass&&this._liveRt){const e=this._visibleDeviceSnapshot||this._candidateDeviceSnapshot;if(!this._liveRt.hass(t,this.hass,e?{entityIds:e.entityIds}:null,()=>Mg(this))&&!this._summary?.observeHassComposition())return}void 0!==e&&(this._terminalFrame=0),this._editorRuntime?._routeLiveEditorUpdate(e,t)||(this._liveRt?.clear(),super.requestUpdate(e,t,i))}_editorRuntimeOrThrow(){if(!this._editorRuntime)throw new Error("Houseplan editor runtime is not loaded");return this._editorRuntime}async _ensureEditorRuntime(){return this._editorRuntimeLoader.ensure()}async _ensureOnboardingRuntime(){return this._onboardingRuntimeLoader.ensure()}async _ensureIsoSceneRuntime(){return this._isoSceneRuntimeLoader.ensure()}_editorRuntimeStateChanged(e){clearTimeout(this._editorRuntimeLoadingTimer),this._editorRuntimeLoadingTimer=void 0,"loading"!==e?(this._editorRuntimeLoadingVisible=!1,this.requestUpdate()):this._editorRuntimeLoadingTimer=window.setTimeout(()=>{this._editorRuntimeLoadingVisible=!0,this.requestUpdate()},150)}async _requestMode(e,t=!0,i=!1){const n=++this._editorModeRequest;if(i&&(this._warmModeRequest=n,this._refitRaf&&(cancelAnimationFrame(this._refitRaf),this._refitRaf=0),this._pendingRefitSize=null),"view"===e||await this._ensureEditorRuntime()){if(n===this._editorModeRequest&&this.isConnected)return i?(this._adoptMode(e),this._warmRevivePending&&(clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmReviveDialog()),this.requestUpdate(),void this.updateComplete.then(()=>requestAnimationFrame(()=>requestAnimationFrame(()=>{if(this._warmModeRequest!==n||n!==this._editorModeRequest)return;const e=this._stageEl;this._lastValidStageSize=e&&e.clientWidth>0&&e.clientHeight>0?[e.clientWidth,e.clientHeight]:null,this._pendingRefitSize=null,this._warmModeRequest=0})))):void this._setMode(e,t);this._warmModeRequest===n&&(this._warmModeRequest=0)}else this._warmModeRequest===n&&(this._warmModeRequest=0)}get _layout(){return this._adoption.layout}set _layout(e){this._adoption.stageLocalLayout(e)}get _layoutRev(){return this._adoption.layoutRev}set _layoutRev(e){this._adoption.seedIdentity({layoutRev:e})}get _layoutContentFingerprint(){return this._adoption.layoutFingerprint}set _layoutContentFingerprint(e){this._adoption.seedIdentity({layoutFingerprint:e})}get _serverCfg(){return this._adoption.config}set _serverCfg(e){this._adoption.stageLocalConfig(e)}get _cfgRev(){return this._adoption.configRev}set _cfgRev(e){this._adoption.seedIdentity({configRev:e})}get _cfgContentFingerprint(){return this._adoption.configFingerprint}set _cfgContentFingerprint(e){this._adoption.seedIdentity({configFingerprint:e})}_seedDecorStyle(e){var t,i;if(t=Ol,i=this,Fl(e,Bl)&&"pending"===t.state()&&(t.art("",i),t.ensure()),this._decorStyleSeeded||!e)return;this._decorStyleSeeded=!0;const n=e.settings?.decor_default_style;n&&(this._decorStyle=function(e,t){if(!e||"object"!=typeof e)return{...t};const i=e,n="string"==typeof i.color&&i.color?i.color:t.color,r="string"==typeof i.fill_color&&i.fill_color?i.fill_color:t.fillColor,o=Number(i.width_cm);return{color:n,opacity:Tr(i.opacity,t.opacity),widthCm:Number.isFinite(o)&&o>0?Math.max(.1,Math.min(100,o)):t.widthCm,fill:"boolean"==typeof i.fill?i.fill:t.fill,fillColor:r,fillOpacity:Tr(i.fill_opacity,t.fillOpacity)}}(n,Cr))}get _canManageConfiguration(){return null!==this._serverCanWrite?this._serverCanWrite:!0===this.hass?.user?.is_admin}get _canEdit(){return this._norm&&this._canManageConfiguration}get _kiosk(){return!!this._config?.kiosk}_showKioskDots(){this._kioskDots=!0,clearTimeout(this._kioskDotsTimer),this._kioskDotsTimer=window.setTimeout(()=>this._kioskDots=!1,2500)}get _modeTransitionBusy(){return this._modeTransitionPreparing||this._modeTransition.active}get _doubleFitEnabled(){return!("view"!==this._mode||this._vacFit||this._modeTransitionBusy||this._touchSequenceMultitouch||"steady"!==this._continuity.state||this._continuity.overlayBlocksInteraction)}_cameraState(){const e=this._viewOr(this._baseVb());return{zoom:this._zoom,viewBox:{...e}}}_normalizeCameraState(e){const t=this._cameraTransitionFit||Oi(this._baseVb(),this._stageAspect());return{zoom:Math.min(wv.ZOOM_MAX,Math.max(wv.ZOOM_MIN,e.zoom)),viewBox:this._clampView({...e.viewBox},t)}}_applyCameraTransitionFrame(e){const t=this._normalizeCameraState(e.presented);e.presented=t,this._zoom=t.zoom,this._view={...t.viewBox},this._liveVp(!0)}_settleCameraTransition(e){const t=this._normalizeCameraState(e.to);this._zoom=t.zoom,this._view={...t.viewBox},this._cameraTransitionFit=null,"room"!==e.reason&&this._saveZoom(),this.requestUpdate()}_cancelCameraTransition(e=!1,t=!1){const i=this._cameraTransition.state?.reason,n=t&&this._cameraTransition.active?this._cameraTransition.presented?.zoom:void 0;this._cameraTransition.cancel(e),this._cameraTransitionFit=null,void 0!==n&&"room"!==i&&this._saveZoom()}_prepareCameraCommand(){this._bootSoftCancel(),this._modeTransitionBusy&&this._cancelModeTransition(!0),"opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1))}_startCameraTransition(e,t,i,n){const r=this._cameraState(),o=this._cameraTransition.target;return(!o||!Xg(o,e))&&(Xg(r,e)?(this._cancelCameraTransition(!1),!1):(this._activateSafeDayCycleOutline(),this._cameraTransitionFit={...t},this._cameraTransition.start(r,e,i,this._reducedMotion?0:n),!0))}_cssColor(e,t){const i=String(e||"").trim();if(!i)return t;const n=document.createElement("span");n.style.cssText=`position:absolute;visibility:hidden;color:${i}`,this.renderRoot.append(n);const r=getComputedStyle(n).color||t;return n.remove(),r}_currentModeVisual(e=this._mode){const t=this._modeTransition.presented||this._modeTransitionVisual;if(t)return{...t,viewport:{...t.viewport,viewBox:{...t.viewport.viewBox}}};const i=this._stageEl;if(!i||i.clientWidth<=0||i.clientHeight<=0)return null;const n=this.renderRoot.querySelector(".editorchrome"),r=this._viewOr(this._baseVb()),o=this.renderRoot.querySelector(".hp-paper"),s=this.renderRoot.querySelector(".hp-backdrop"),a=this.renderRoot.querySelector(".zoomwrap"),l=a?getComputedStyle(a).filter:"",c=Number(/brightness\(([^)]+)\)/.exec(l)?.[1]);return{presentedMode:e,editorChromeHeight:"view"===e?0:n?.getBoundingClientRect().height||0,stageWidth:i.clientWidth,stageHeight:i.clientHeight,viewport:Bg(r,i.clientWidth),stageColor:getComputedStyle(i).backgroundColor||"rgb(255, 255, 255)",paperColor:o?getComputedStyle(o).fill:"rgb(255, 255, 255)",sceneBrightness:Number.isFinite(c)?c:1,architectureOpacity:"decor"===e?.35:1,backdropOpacity:s&&Number(getComputedStyle(s).opacity)||1,viewWeight:"view"===e?1:0,editorWeight:"view"===e?0:1,toolbarContentOpacity:"view"===e?0:1}}_viewForModeTarget(e,t,i,n,r){const o=Oi(this._baseVb(),n/r),s=Math.min(wv.ZOOM_MAX,Math.max(wv.ZOOM_MIN,e)),a=o.w/s,l=o.h/s,c=t??o.x+o.w/2,h=i??o.y+o.h/2;return this._clampView({x:c-a/2,y:h-l/2,w:a,h:l},o)}_targetStageColor(e){return"view"!==e?"rgb(255, 255, 255)":this._cssColor(this._stageBg(this._spaceDisplayForRender()),this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"))}_targetPaperColor(e){return"view"===e&&this._spaceModel()?.bg?this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"):"rgb(255, 255, 255)"}_targetBrightness(e){return 1}_applyModeTransitionFrame(e){e.targetMode===this._mode&&(this._modeTransitionVisual=e.presented,this._view={...e.presented.viewport.viewBox},this.requestUpdate())}_settleModeTransition(e){if(e.targetMode!==this._mode)return;const t=this._modeTransitionRequest;this._view={...e.to.viewport.viewBox},this._zoom=this._modeTransitionTargetZoom,this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._lastValidStageSize=[e.to.stageWidth,e.to.stageHeight],"view"===this._mode&&(this._saveZoom(),this._viewModeSnap=null,this._modeTransitionEditorCamera=null),this.requestUpdate(),this.updateComplete.then(()=>{if(!this.isConnected||t!==this._modeTransitionRequest||this._modeTransitionBusy||e.targetMode!==this._mode)return;const i=this._stageEl;if(i&&i.clientWidth>0&&i.clientHeight>0&&(Math.abs(i.clientWidth-e.to.stageWidth)>.5||Math.abs(i.clientHeight-e.to.stageHeight)>.5)){const e=this._view;this._lastValidStageSize=[i.clientWidth,i.clientHeight],this._applyView(this._zoom,e?e.x+e.w/2:void 0,e?e.y+e.h/2:void 0),this.requestUpdate()}const n=this.renderRoot.activeElement;(!n||!n.isConnected||!!n.closest?.(".editorchrome, .stage"))&&this.renderRoot.querySelector(".modetab.active")?.focus?.({preventScroll:!0})})}_cancelModeTransition(e=!0){this._cancelCameraTransition(!1);const t=!!this._modeTransition.state;this._modeTransitionRequest++,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransition.cancel(e),e&&t||(this._modeTransitionVisual=null)}_adoptMode(e){e!==this._mode&&(this._clearRoomFocus(!0),this._resetDeviceHitState()),this._cancelModeTransition(!1),this._mode=e,this._isoProjectionSnapshot=null,"view"!==e&&(this._editorChromeMode=e)}_commitViewModeAtomic(e,t,i,n){if(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this._zoom=t,e){const r=this._stageEl?.clientWidth||e.stageWidth,o=Math.max(1,e.stageHeight+e.editorChromeHeight);this._view=this._viewForModeTarget(t,i,n,r,o),this._lastValidStageSize=[r,o]}else this._view=null;this._viewModeSnap=null,this._modeTransitionEditorCamera=null,this._saveZoom(),this.requestUpdate()}_prepareModeTransition(e,t,i,n,r,o){this.updateComplete.then(()=>{if(!this.isConnected||e!==this._modeTransitionRequest||this._mode!==i)return void(e===this._modeTransitionRequest&&(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this.requestUpdate()));const s=this.renderRoot.querySelector(".editorchrome-inner"),a="view"===i?0:s?.scrollHeight||0,l=Math.max(1,(this.panelHost?this.clientHeight:innerHeight)-ef(this.renderRoot,this._stageEl,this.panelHost)),c=this._stageEl?.clientWidth||t.stageWidth,h=this._viewForModeTarget(n,r,o,c,l),d={presentedMode:i,editorChromeHeight:a,stageWidth:c,stageHeight:l,viewport:Bg(h,c),stageColor:this._targetStageColor(i),paperColor:this._targetPaperColor(i),sceneBrightness:this._targetBrightness(i),architectureOpacity:"decor"===i?.35:1,backdropOpacity:"decor"===i&&"backdrop"!==this._decorTool?.5:1,viewWeight:"view"===i?1:0,editorWeight:"view"===i?0:1,toolbarContentOpacity:"view"===i?0:1};this._modeTransitionPreparing=!1;const u=this._modeTransitionForceAtomic;this._modeTransitionForceAtomic=!1,this._modeTransition.start(t,d,i,this._reducedMotion||u?0:220)})}get _hasFixedFloor(){return!!this._config&&Object.prototype.hasOwnProperty.call(this._config,"floor")}_fixedFloorState(e=this._model,t=this._loadOk){const i=this._config?.floor,n=function(e){if(!e.hasFloor)return{kind:"absent"};const t=e.floor;if("string"==typeof t)return t.length?e.spaceIds.includes(t)?{kind:"valid",id:t,source:"id"}:{kind:"invalid",reason:"unknown-id",value:t}:{kind:"invalid",reason:"empty-id",value:t};if("number"==typeof t){if(!Number.isFinite(t))return{kind:"invalid",reason:"non-finite-index",value:t};if(!Number.isInteger(t))return{kind:"invalid",reason:"fractional-index",value:t};if(t<0)return{kind:"invalid",reason:"negative-index",value:t};const i=e.spaceIds[t];return void 0===i?{kind:"invalid",reason:"out-of-range-index",value:t}:{kind:"valid",id:i,source:"index"}}return{kind:"invalid",reason:"invalid-type",value:t}}({spaceIds:e.map(e=>e.id),hasFloor:this._hasFixedFloor,floor:i});return!this._hasFixedFloor||t?n:"number"==typeof i?"valid"===n.kind||"invalid"===n.kind&&"out-of-range-index"===n.reason?{kind:"pending",value:i}:n:"valid"===n.kind||"invalid"===n.kind&&"unknown-id"!==n.reason?n:{kind:"pending",value:i}}_canCommitSpace(e,t=!1){if(t||!this._hasFixedFloor)return!0;const i=this._fixedFloorState();return"valid"===i.kind&&i.id===e}_commitSpace(e,t=!1){return!!this._canCommitSpace(e,t)&&(e!==this._space&&(this._clearRoomFocus(!0),this._resetDeviceHitState(),this._cancelDangerConfirm(),this._cancelCameraTransition(!1),this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._editorRuntime?._clearFurniturePreview()),this._space=e,this._isoProjectionSnapshot=null,!0)}_slideTo(e,t){if(e===this._space)return!0;if(!this._canCommitSpace(e))return!1;if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return!1;this._cancelModeTransition(!0);const i=window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;return this._commitSpace(e),this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeWallChainId=null,this._activeWallChainPartitionIds=[],this._wallChainSegmentCms=[],this._closingWallCm=null,this._selId=null,this._physicalSel=null,this._editorSecondary?.closeForNavigation(),this._physicalDialog=null,this._physicalDrag=null,this._restoreZoom(),i||(this._slide=t,clearTimeout(this._slideTimer),this._slideTimer=window.setTimeout(()=>{this._slideTimer=void 0,this._slide="",this.requestUpdate()},190),this.requestUpdate()),!0}get _canReorderTabs(){return Zf({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:"mouse",spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})}_tabPointerDown(e,t){Zf({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:e.pointerType,spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})&&(yv(e),this._tabDragRelease=e=>this._tabPointerUp(e),window.addEventListener("pointerup",this._tabDragRelease),window.addEventListener("pointercancel",this._tabDragRelease),this._tabDrag={id:t,pointerId:e.pointerId,x:e.clientX,y:e.clientY,moved:!1,targetId:null,placement:null})}_tabDropTargetAt(e,t,i){const n=this._model.map(e=>e.id),r=n.indexOf(i);if(r<0)return null;const o=this.renderRoot.querySelectorAll('[data-hp="space-tab"]');for(const s of o){const o=s.dataset.id||"";if(!o||o===i)continue;const a=s.getBoundingClientRect();if(ea.right||ta.bottom)continue;const l=n.indexOf(o);return l<0?null:{targetId:o,placement:l=4)))return;var i,n;const r=this._tabDropTargetAt(e.clientX,e.clientY,t.id);t.moved&&t.targetId===r?.targetId&&t.placement===r?.placement||(this._tabDrag={...t,moved:!0,targetId:r?.targetId||null,placement:r?.placement||null})}_tabPointerUp(e){const t=this._tabDrag;if(t&&t.pointerId!==e.pointerId)return;const i="pointerup"===e.type&&t?.moved?this._tabDropTargetAt(e.clientX,e.clientY,t.id):null;"pointerup"===e.type&&t?.moved&&this._suppressNextTabClick(),this._endTabDrag(),t?.moved&&i&&this._commitTabOrder(t.id,i.targetId)}_endTabDrag(){this._tabDrag=null,this._tabDragRelease&&(window.removeEventListener("pointerup",this._tabDragRelease),window.removeEventListener("pointercancel",this._tabDragRelease),this._tabDragRelease=null)}_tabClick(e){if(this._tabSuppressClick)return this._tabSuppressClick=!1,clearTimeout(this._tabSuppressClickTimer),void(this._tabSuppressClickTimer=void 0);this._pickSpace(e)}_suppressNextTabClick(){this._tabSuppressClick=!0,clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=window.setTimeout(()=>{this._tabSuppressClick=!1,this._tabSuppressClickTimer=void 0},0)}_commitTabOrder(e,t){const i=this._serverCfg;if(!i||!this._canReorderTabs)return;const n=this._model.map(e=>e.id),r=function(e,t,i){const n=e.indexOf(t),r=e.indexOf(i);if(n<0||r<0||n===r)return e;const o=e.slice();return o.splice(n,1),o.splice(r,0,t),o}(n,e,t);if(r===n)return;const o=new Map(this._devices.map(e=>[String(e.id),String(e.area||"")])),s=function(e,t,i,n=()=>""){if(!i)return[];const r=[];for(const o of e){if(!o||!0===o.removed)continue;const e="string"==typeof o.id?o.id:"";if(!e)continue;if("string"==typeof o.space&&o.space)continue;const s=("string"==typeof o.area?o.area:"")||n(e)||"";s&&t[s]||r.push({id:e,space:i})}return r}(i.markers||[],Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),n[0]||"",e=>o.get(e)||"");if(s.length){const e=new Map(s.map(e=>[e.id,e.space]));for(const t of i.markers||[]){const i=e.get(String(t.id));i&&(t.space=i)}}i.spaces=function(e,t){const i=new Map(t.map((e,t)=>[e,t]));return e.map((e,t)=>({space:e,index:t})).sort((e,t)=>(i.get(String(e.space?.id))??Number.MAX_SAFE_INTEGER)-(i.get(String(t.space?.id))??Number.MAX_SAFE_INTEGER)||e.index-t.index).map(e=>e.space)}(i.spaces||[],r),this._saveConfig(),this._tabOrderWarned||(this._tabOrderWarned=!0,this._showToast(this._t("toast.space_order_changed")))}_pickSpace(e){if(this._endTabDrag(),e===this._space)return;const t=this._model.map(e=>e.id),i=t.indexOf(this._space),n=t.indexOf(e);this._navApplied=!0,this._showFar=!1,this._frame=null,this._slideTo(e,i>=0&&n0&&Date.now()>=this._cyclePausedUntil&&this._model.length>1&&this._zoom<=1.001){const e=this._model.map(e=>e.id),t=e.indexOf(this._space);this._slideTo(e[(t+1)%e.length],"left"),this._showKioskDots()}}_syncCycleTimer(){clearInterval(this._cycleTimer),this._cycleTimer=void 0,this.isConnected&&!this._hasFixedFloor&&this._config?.kiosk&&Number(this._config.cycle)>0&&(this._cycleTimer=window.setInterval(()=>this._cycleTick(),1e3*Number(this._config.cycle)))}get _editing(){return"plan"===this._mode||"devices"===this._mode||"decor"===this._mode}get _markup(){return"plan"===this._mode}get _wallUnionCache(){return this._wallUnionCacheValue}set _wallUnionCache(e){this._wallUnionCacheValue=e,null===e&&this._wallUnionPool.clear()}get _glowClipCache(){return this._glowRuntimeState.clipCache}get _glowGeometryWarnings(){return this._glowRuntimeState.geometryWarnings}get _glowFeatherUnits(){return this._glowRuntimeState.featherUnits}set _glowFeatherUnits(e){this._glowRuntimeState.featherUnits=e}get _glowRenderedSources(){return this._glowRuntimeState.renderedSources}get _glowLastAppearance(){return this._glowRuntimeState.lastAppearance}get _glowFeatherSuspendUntil(){return this._glowRuntimeState.featherSuspendUntil}set _glowFeatherSuspendUntil(e){this._glowRuntimeState.featherSuspendUntil=e}get _glowFeatherResumeTimer(){return this._glowRuntimeState.featherResumeTimer}set _glowFeatherResumeTimer(e){this._glowRuntimeState.featherResumeTimer=e}get _glowSourceSeq(){return this._glowRuntimeState.sourceSeq}set _glowSourceSeq(e){this._glowRuntimeState.sourceSeq=e}_activateSafeDayCycleOutline(){this._safeDayCycleOutline=!0,this._stageEl?.classList.add("hp-safe-daycycle-outline")}get _touchSequenceMultitouch(){return this._touchClickGuard.sequenceMultitouch}_syncDangerConfirmLocaleGate(){return this._config&&this.hass?dp(this,gp,kp(this.hass,this._config.language)):"ready"}_dangerConfirmMissingSpace(){const e=this._model;if(!e.length)return!1;const t=this._fixedFloorState(e);return"pending"!==t.kind&&"invalid"!==t.kind&&!this._spaceModel()}_syncVersionRecovery(){this._versionRecovery.update({frontendVersion:ev(iv),backendVersion:this._haIntegrationVersion,kiosk:!0===this._config?.kiosk,reducedMotion:this._reducedMotion})}_newContinuityController(){return new lc(()=>{this._resumeSettling="steady"!==this._continuity.state,this._continuityEpoch++,this.isConnected&&this.requestUpdate()})}get _labsIso(){return this._labs.active.includes("iso")}get _desiredProjection(){return"view"===this._mode&&this._labsIso&&"iso"===this._viewPreference[this._space]?"iso":"flat"}_saveViewPreference(){try{localStorage.setItem(uv,JSON.stringify(this._viewPreference))}catch{}}_logicalViewCenter(e){const t=this._view;if(!t)return null;const i=[t.x+t.w/2,t.y+t.h/2],n="iso"===e?cf(i):i;return{x:n[0],y:n[1]}}_convertProjectionView(e,t){if(e===t)return;this._clearRoomFocus(!0);const i=this._logicalViewCenter(e);this._view=null;const n=i?"iso"===t?lf([i.x,i.y],0):[i.x,i.y]:null;this._applyView(this._zoom,n?.[0],n?.[1]),this._warmPatch({vp:this._warmViewportState()}),this.requestUpdate()}_setProjection(e){if(!this._labsIso||"view"!==this._mode)return;const t=this._effectiveProjection();if(this._viewPreference={...this._viewPreference,[this._space]:e},"iso"===e){this._ensureIsoSceneRuntime();const e=this._isoSceneKey();e&&this._isoFallback.delete(e),this._isoFallback.delete(`${this._space}|no-borders`),this._clearIsoInvalidFallback()}this._saveViewPreference(),this._isoProjectionSnapshot=null;const i=this._effectiveProjection();this._convertProjectionView(t,i)}_hashSpace(){return Ff(window.location.hash||"")}connectedCallback(){this._connectedPath=location.pathname,this._routeDepartureHandled=!1,this._configReloadAuthority.observeContext(Vu(this)),window.addEventListener("location-changed",this._onLocationChanged),window.addEventListener("popstate",this._onLocationChanged),this._continuityDisposed&&(this._continuity=this._newContinuityController(),this._continuityDisposed=!1,this._continuityPaintToken=-1);const e=dg(this.ownerDocument);var t;void 0!==e&&(this._glowScreenBlend=e),this._continuityUnsub?.(),this._continuityUnsub=sc(this.ownerDocument,this._pageVisibility),this._languageFailureUnsub?.(),this._languageFailureUnsub=function(...e){return()=>{for(const t of e)t()}}((t=()=>{this._showToast(this._t("toast.locale_load_failed"))},mp.add(t),()=>mp.delete(t)),function(e){return Il.add(e),()=>{Il.delete(e)}}(()=>this._showToast(this._t("toast.furniture_art_load_failed")))),super.connectedCallback(),this._summarySlot.connect(),this._ensureLiveRuntime().catch(()=>this.requestUpdate()),this._pointerModality.connect(this.ownerDocument.defaultView);const i=this.ownerDocument.defaultView?.MutationObserver;i&&(this._pointerHoverObserver=new i(e=>{let t=!1;for(const i of e){for(const e of i.addedNodes)this._syncPointerHoverSubtree(e);const e=e=>{if(e.nodeType!==Node.ELEMENT_NODE)return!1;const t=e;return t.matches(".devlayer, .devlayer *")||!!t.querySelector?.(".devlayer")};(e(i.target)||[...i.addedNodes,...i.removedNodes].some(e))&&(t=!0)}t&&this._invalidateDeviceHitGeometry()}),this._pointerHoverObserver.observe(this.renderRoot,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["class","style","data-id"]})),this._motionMedia=window.matchMedia?.("(prefers-reduced-motion: reduce)"),this._reducedMotion=!!this._motionMedia?.matches,this._motionMedia?.addEventListener?.("change",this._onMotionChange),this._syncVersionRecovery(),this._versionRecovery.connect(),hg(this.ownerDocument).then(e=>{e!==this._glowScreenBlend&&(this._glowScreenBlend=e,this.isConnected&&this.requestUpdate())}),this.hass&&this._ensureHaRegistryAuthority(),window.addEventListener("keydown",this._keyHandler),this._signer.start(()=>this.hass,()=>this._referencedContentUrls()),this._syncCycleTimer(),window.addEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=function(e){Nf.add(e);const t=Bf();return"undefined"==typeof window&&e(t),()=>{Nf.delete(e)}}(this._onLabsSnapshot),this._labsIso&&this._ensureIsoSceneRuntime(),this._booting?this._bootWatch():this._bootFading&&(clearTimeout(this._bootTimer),this._bootTimer=window.setTimeout(()=>{this._bootFading=!1},220)),this._bootSoft&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},rv)),!this._loadOk&&this._serverCfg&&this.hass&&this._scheduleLoadRetry(),!this._warmSlot&&this._config&&this._warmAdopt(),this._loadOk&&this._ensureLiveSyncSubscriptions(),this._warmVp&&!this._warmRevivePending&&void 0===this._warmReviveTimer&&(this._warmRevivePending=!0,this._warmReviveTimer=window.setTimeout(()=>this._warmReviveDialog(),0)),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1,this.requestUpdate()}disconnectedCallback(){this._versionRecovery.disconnect(),this._configReloadAuthority.invalidateLifecycle(),this._liveRt?.dispose(),this._radarLive.stop(),this._editorRuntime?._disposeLiveEditor(),this._clearRoomFocus(!0),this._cancelDangerConfirm(),this._connectedPath&&location.pathname!==this._connectedPath&&this._leaveCardRoute(),window.removeEventListener("location-changed",this._onLocationChanged),window.removeEventListener("popstate",this._onLocationChanged),this._continuityUnsub?.(),this._continuityUnsub=void 0,this._languageFailureUnsub?.(),this._languageFailureUnsub=void 0,this._motionMedia?.removeEventListener?.("change",this._onMotionChange),this._motionMedia=void 0,this._vacRaf&&(cancelAnimationFrame(this._vacRaf),this._vacRaf=0),this._refitRaf&&(cancelAnimationFrame(this._refitRaf),this._refitRaf=0),this._warmModeRequest=0,this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),this._summarySlot.disconnect(),this._dayCycleClockKey="",this._bootSettleRaf&&(cancelAnimationFrame(this._bootSettleRaf),this._bootSettleRaf=0),this._bootSettling=!1;for(const e of this._activityRt.values())clearTimeout(e.timer);window.removeEventListener("keydown",this._keyHandler),this._endTabDrag(),clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=void 0,this._tabSuppressClick=!1,clearInterval(this._cycleTimer),clearTimeout(this._kioskDotsTimer),clearTimeout(this._kioskHoldTimer),clearTimeout(this._reloadRetry),clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),this._connHooked=null,this._haRegistryRelease?.(),this._haRegistryRelease=void 0,this._haRegistryConnection=null,this._signer.dispose(),clearTimeout(this._toastTimer),clearTimeout(this._slideTimer),clearTimeout(this._editorRuntimeLoadingTimer),this._editorRuntimeLoadingTimer=void 0,this._editorRuntimeLoadingVisible=!1,this._modeTransition.dispose(),this._cameraTransition.dispose(),this._cameraTransitionFit=null,this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest++,this._slideTimer=void 0,this._slide="",clearTimeout(this._bootTimer),this._bootTimer=void 0,clearTimeout(this._bootSoftTimer),this._saveConfigDebounced.flush(),this._cancelDeviceDrag(),window.removeEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=void 0,clearTimeout(this._holdTimer),this._roViewport?.disconnect(),this._roViewport=void 0,this._roHdr?.disconnect(),this._roHdr=void 0,this._onWinResize&&(window.removeEventListener("resize",this._onWinResize),this._onWinResize=void 0),this._unsubCfg&&(this._unsubCfg(),this._unsubCfg=null),this._unsubLayout&&(this._unsubLayout(),this._unsubLayout=null),this._unsubVirtual&&(this._unsubVirtual(),this._unsubVirtual=null),this._unsubTrail&&(this._unsubTrail(),this._unsubTrail=void 0),this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=null,clearTimeout(this._layoutSyncTimer),clearTimeout(this._duplicateColumnTimer),Fm(this._glowRuntimeState,this._glowRuntimeHost),this._warmSnapshot(),this._warmRevivePending=!1,clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmRelease(),this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._editorRuntime?._clearFurniturePreview(),this._editorRuntime?._furnShiftDetach(),this._touchContacts.clear(),this._touchClickGuard.reset(),this._resetDeviceHitState(),this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._pointerHoverObserver?.disconnect(),this._pointerHoverObserver=void 0,this._pointerModality.disconnect(),this._editorSecondary?.reset(),this._resumeSettling=!1,this._continuityHistory=[...this._continuityHistory,...this._continuity.trace].slice(-80),this._continuity.dispose(),this._continuityDisposed=!0,super.disconnectedCallback()}_onKey(e){if("Escape"===e.key&&this._vacFit){if(this._vacFit.busy)return;return this._vacFit=null,this._showToast(this._t("vac.cal_cancelled")),void e.stopPropagation()}if("Escape"===e.key){if(this._tapConfirm)return void(this._tapConfirm=null);if(this._vacCalConfirm)return void(this._vacCalConfirm.busy||(this._vacCalConfirm=null));if(this._decorEraseConfirm)return void(this._decorEraseConfirm=null);if(this._openingInfo)return void(this._openingInfo=null);if(this._infoCard)return void this._closeInfoCard();if(this._rulesDialog)return void(this._rulesDialog=null);if(this._alignDialog)return this._alignDialog=null,void(this._preflightClipboardFallback=null);if(this._backupImportDialog)return void(this._backupImportDialog=null);if(this._backupExportDialog)return void(this._backupExportDialog=null);if(this._pdfDialog)return void(this._pdfDialog=!1);if(this._supportDialog)return void this._editorRuntime?._closeSupportDialog();if(this._settingsDialog)return void(this._settingsDialog=null);if(this._summary?.closeDialogIfIdle())return;if(this._markerDialog)return void this._closeMarkerDialog();if(this._deviceInbox)return void(this._deviceInbox=null);if(this._openingDialog)return void(this._openingDialog=null);if(this._physicalDialog)return void(this._physicalDialog=null);if(this._backdropDialog)return void(this._backdropDialog=null);if(this._decorShapeDialog)return void(this._decorShapeDialog=null);if(this._decorTextDialog)return void(this._decorTextDialog=null);if(this._spaceDialog&&!this._roomDialog)return this._spaceDialog=null,this._importQueue=[],void(this._importTotal=0);if(this._editorSecondary?.hasOpenGroup)return e.preventDefault(),void this._editorSecondary?.closeGroup(!0)}const t=e.composedPath?.()||[e.target],i=t.some(e=>e?.matches?.('input, textarea, select, [contenteditable="true"]')),n=t.some(e=>e?.classList?.contains?.("editor-secondary")),r=e.ctrlKey||e.metaKey,o=e.key.toLowerCase(),s=/^[a-z]$/.test(o),a="z"===o||!s&&"KeyZ"===e.code,l="y"===o||!s&&"KeyY"===e.code,c=r&&(a&&e.shiftKey||l),h=r&&a&&!e.shiftKey;if("decor"===this._mode){if((h||c)&&i)return;if(c)return e.preventDefault(),void this._redoGeometry();if(h)return e.preventDefault(),this._decorDraft?void(this._decorDraft=null):this._decorMove||this._dtDrag||this._bdDrag?void this._cancelDecorGesture():void this._undoGeometry();if(("Delete"===e.key||"Backspace"===e.key)&&this._decorSel&&!i&&!n)return e.preventDefault(),void this._decorDeleteSel();const t="ArrowLeft"===e.key?[-this._gridPitch,0]:"ArrowRight"===e.key?[this._gridPitch,0]:"ArrowUp"===e.key?[0,-this._gridPitch]:"ArrowDown"===e.key?[0,this._gridPitch]:null;return!t||r||e.altKey||"select"!==this._decorTool||!this._decorSel||!this._decorList.some(e=>e.id===this._decorSel)||this._decorDraft||this._decorMove||this._dtDrag||this._bdDrag||i||n||this._editorSecondaryDialogBlocked?void("Escape"===e.key&&(e.preventDefault(),this._decorDraft?this._decorDraft=null:this._decorMove||this._dtDrag||this._bdDrag?this._cancelDecorGesture():"furniture"===this._decorTool?(this._editorRuntime?._clearFurniturePreview(),this._editorRuntime?._furnShiftDetach(),this._furnPalette=null,this._furnCategory=null,this._decorTool="select"):this._decorSel?this._decorSel=null:"select"!==this._decorTool?this._decorTool="select":this._setMode("view"))):(e.preventDefault(),void this._decorNudge(t[0],t[1]))}if("devices"===this._mode){if((h||c)&&i)return;return c?(e.preventDefault(),void this._redoDevicePosition()):h?(e.preventDefault(),void this._undoDevicePosition()):void("Escape"===e.key&&this._deviceDrag&&(e.preventDefault(),this._cancelDeviceDrag()))}if(this._markup&&(!h&&!c||!i)){if(("Delete"===e.key||"Backspace"===e.key)&&this._physicalSel&&!i&&!n)return e.preventDefault(),void this._deletePhysicalSelection();if(c)return e.preventDefault(),void this._redoGeometry();if(h)return e.preventDefault(),this._resize?.dragging?void this._rszCancelDrag():this._wallFaceBatch?(this._roomDialogCancel(),void(this._activeWallChainId&&this._path.length>1?this._undoActiveWallPoint():this._undoPoint())):"draw"===this._tool&&this._path.length?void(this._activeWallChainId&&this._path.length>1?this._undoActiveWallPoint():this._undoPoint()):"split"===this._tool&&this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},void(this._splitSel.pts.length||(this._cursorPt=null))):void this._undoGeometry();if("Escape"===e.key)return this._physicalDrag||this._physicalRotate?(e.preventDefault(),void this._cancelPhysicalGesture()):this._roomDialog?(e.preventDefault(),void this._roomDialogCancel()):"draw"===this._tool&&this._path.length?(e.preventDefault(),void this._finishWallChain()):this._physicalSel?(e.preventDefault(),void(this._physicalSel=null)):"resize"===this._tool?(e.preventDefault(),this._resize?.dragging?void this._rszCancelDrag():("exit-tool"===this._resize?.escapeIdle()&&(this._tool="draw"),void this.requestUpdate())):"split"===this._tool?(e.preventDefault(),void(this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},this._splitSel.pts.length||(this._cursorPt=null)):this._splitSel?this._splitSel=null:this._tool="draw")):"merge"===this._tool?(e.preventDefault(),void(this._mergeSel?this._mergeSel=null:this._tool="draw")):this._wallDialog?(e.preventDefault(),void(this._wallDialog=null)):void("opening"!==this._tool&&"wallthick"!==this._tool&&"delroom"!==this._tool&&"column"!==this._tool||(e.preventDefault(),"opening"===this._tool&&this._clearOpeningPlacement(!0),this._tool="draw"))}}_undoPoint(){if(this._path.length)return this._contourClosed?(this._path=this._path.slice(0,-1),void(this._closingWallCm=null)):void(this._activeWallChainPartitionIds.length&&this._path.length>1?this._undoActiveWallPoint():this._path=this._path.slice(0,-1))}_undoActiveWallPoint(){const e=[...this._activeWallChainPartitionIds],t=e[e.length-1],i=this._spaceModel()?.partitions.find(e=>e.id===t),n=this._path[0]?[...this._path[0]]:null,r=this._path.slice(0,-1).map(e=>[...e]),o=this._wallChainSegmentCms.slice(0,-1),s=this._geometryHistory.undo();if(!s)return this._activeWallChainPartitionIds=[],this._wallChainSegmentCms=[],this._wallChainRedo=[],void(this._path=n?[n]:[]);this._applyGeometryState(s.before,!0)?(this._activeWallChainId||=`chain-${Date.now().toString(36)}`,this._activeWallChainPartitionIds=e.slice(0,-1),this._path=r.length?r:n?[n]:[],this._wallChainSegmentCms=o,i&&this._wallChainRedo.push({id:i.id,point:[...i.b],cm:i.cm}),this._clearPlanSnapHover(),this._showToast(this._t("history.undone",{name:s.name}))):this._geometryHistory.clear()}static async getConfigElement(){return await import("./editor-_VTHnoKH.js"),document.createElement("houseplan-card-editor")}static getStubConfig(){return{type:"custom:houseplan-card"}}static _warmBootReset(e){for(const e of ov.values())for(const t of e)clearTimeout(t.evict);ov.clear(),av=e&&e>0?e:1e4}static _warmBootStats(){let e=0,t=0;const i=[];for(const n of ov.values())for(const r of n)e++,r.dlg&&(t++,i.push(r.dlg.kind));return{keys:ov.size,slots:e,dlgs:t,drafts:i}}setConfig(e){const t=this._config,i=!!t&&Object.prototype.hasOwnProperty.call(t,"floor");this._config={icon_size:2.5,show_temperature:!0,live_states:!0,show_signal:!0,...e};(i!==this._hasFixedFloor||t?.floor!==this._config.floor)&&(this._hashApplied=!1,this._navApplied=!1,this._warmVpArmed=!1),this._config.kiosk&&(this._booting=!1,this._bootFading=!1),!this._hasFixedFloor&&e.default_floor&&this._commitSpace(e.default_floor,!0);try{this._zoomBySpace=JSON.parse(localStorage.getItem(hv)||"{}")||{}}catch{this._zoomBySpace={}}try{const e=JSON.parse(localStorage.getItem(uv)||"{}")||{};this._viewPreference=Object.fromEntries(Object.entries(e).filter(e=>"flat"===e[1]||"iso"===e[1]))}catch{this._viewPreference={}}if(this._labs=Bf(),this.isConnected&&this._labsIso&&this._ensureIsoSceneRuntime(),!this._summary?.applyLocalScaleForCurrentIdentity())try{const e=JSON.parse(localStorage.getItem("houseplan_card_kiosk_v1")||"null");this._kioskScale={icon:jn(e?.icon),font:jn(e?.font)}}catch{}try{const e=JSON.parse(localStorage.getItem(cv)||"null");this._adoption.restoreCached(e)&&(this._seedDecorStyle(this._serverCfg),this._cfgEpoch++,this._virtualLights=Hh(e.virtual_lights,this._cfgRev),this._serverStorage=!0)}catch{}this._adoptInitialSpace(this._model,this._loadOk),"view"!==this._mode||this._view||(this._zoom=this._zoomBySpace[this._space]||1),this.isConnected&&(this._syncCycleTimer(),this._warmAdopt(),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1),this._syncVersionRecovery()}_warmAdopt(){if(this._config?.kiosk)return;const e=Cf(this._config);if(this._warmKey===e&&this._warmSlot)return;this._warmSlot&&this._warmRelease();const t=this.parentNode,i=this._warmIdx(t),n=ov.get(e);if(!n||!n.length)return;const r=n.find(e=>e.owner===this._warmGen);if(r)return this._warmLongReturn=!!r.freed&&Date.now()-r.freed>=nc,clearTimeout(r.evict),r.evict=0,r.freed=0,r.live=!0,this._warmSlot=r,this._warmKey=e,r.frameFingerprint&&this._continuity.adoptCompleteFrame(r.frameFingerprint),void(!this._devices.length&&r.devices?.length&&(this._devices=[...r.devices]));const{slot:o,sure:s}=((e,t,i,n)=>{const r=e=>{const t=!!i&&e.place?.deref()===i;return t&&e.idx===n?4:e.live?0:t?3:2};let o=null,s=0,a=0,l=null;for(const i of e){if(i.owner===t)continue;l=i;const e=r(i);e<=0||(e>s?(o=i,s=e,a=1):e===s&&a++)}return!o||a>1?{slot:o||l,sure:!1}:{slot:o,sure:!0}})(n,this._warmGen,t,i);o&&(this._warmLongReturn=!!o.freed&&Date.now()-o.freed>=nc,this._booting=!1,this._bootFading=!1,this._hdrH=o.hdrH,this._bootSoft=!0,this.isConnected&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},rv)),this._warmKey=e,s?(clearTimeout(o.evict),o.evict=0,o.owner=this._warmGen,o.place=t?new WeakRef(t):null,o.idx=i,o.live=!0,this._warmSlot=o,this._warmVp=o.vp,o.frameFingerprint&&this._continuity.adoptCompleteFrame(o.frameFingerprint),!this._devices.length&&o.devices?.length&&(this._devices=[...o.devices]),this._warmAdoptViewport(this._config)):(this._warmSlot={owner:this._warmGen,path:location.pathname,place:t?new WeakRef(t):null,idx:i,live:!0,hdrH:o.hdrH,stageH:o.stageH,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0},n.push(this._warmSlot),this._warmTrim(n)))}_warmIdx(e){const t=e?.children;if(!t)return-1;for(let e=0;e4;){const t=e.findIndex(e=>!e.live);if(t<0)break;clearTimeout(e[t].evict),e.splice(t,1)}}_warmScheduleEvict(e,t){if(clearTimeout(e.evict),!(e.dlg||e.vp&&"view"!==e.vp.mode))return;const i=e.freed,n=e.owner;e.evict=window.setTimeout(()=>{if(e.evict=0,e.freed!==i||e.owner!==n)return;var r;e.dlg=null,e.vp=(r=e.vp)&&"view"!==r.mode?{...r,mode:"view",zoom:r.snap?.space===r.space?r.snap.zoom:r.zoom,view:null,snap:null,tool:"draw",decorTool:"select",showHidden:!1,selId:null,rszSel:null,decorSel:null}:r,e.frameFingerprint="";const o=ov.get(t);if(!e.live&&o&&o.length>1){const t=o.indexOf(e);t>=0&&o.splice(t,1)}},av+250)}_warmAdoptViewport(e){const t=this._warmVp;if(!t||this._warmSlot?.path!==location.pathname)return void(this._warmVp=null);const i=this._fixedFloorState();if(this._hashApplied||!this._model.find(e=>e.id===t.space)||"valid"===i.kind&&i.id!==t.space||this._hasFixedFloor&&"valid"!==i.kind)return void(this._warmVp=null);this._commitSpace(t.space,!0),this._navApplied=!0;const n="view"!==t.mode&&this._canEdit&&!e.kiosk?t.mode:"view";this._adoptMode("view"),this._pendingNavMode="view"===t.mode||this._canEdit||e.kiosk?null:t.mode,this._zoom=t.zoom;const r=this._effectiveProjection(),o=r===t.projection&&this._labsIso===t.activeLabsIso;if(this._view=o&&t.view?{...t.view}:null,this._viewModeSnap=o&&t.snap?{...t.snap}:null,!o&&t.logicalCenter){const e="iso"===r?lf([t.logicalCenter.x,t.logicalCenter.y],0):[t.logicalCenter.x,t.logicalCenter.y];this._applyView(t.zoom,e[0],e[1])}var s;this._tool="opening"===(s=function(e){return"partition"===e?"draw":e}(s=t.tool))?"draw":"string"==typeof s&&Rf.has(s)?s:"draw",this._decorTool=t.decorTool,this._showHidden=t.showHidden,this._showFar!==t.showFar&&(this._showFar=t.showFar,this._frame=null),this._selId=t.selId,this._resize?.restoreSelection(t.rszSel),this._decorSel=t.decorSel,this._warmVpArmed=!0,"view"!==n&&this._requestMode(n,!1,!0)}_warmPatch(e,t=!1){if(this._config?.kiosk)return;const i=Cf(this._config);if(!this._warmSlot||this._warmKey===i){if(!this._warmSlot){if(!t)return;const e=this.parentNode;this._warmKey=i,this._warmSlot={owner:this._warmGen,path:location.pathname,place:e?new WeakRef(e):null,idx:this._warmIdx(e),live:!0,hdrH:this._hdrH,stageH:0,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0};const n=ov.get(i)||[];for(n.push(this._warmSlot),ov.set(i,n),this._warmTrim(n);ov.size>8;){const e=ov.keys().next().value;if(void 0===e||e===i)break;for(const t of ov.get(e)||[])clearTimeout(t.evict);ov.delete(e)}}Object.assign(this._warmSlot,e)}}_warmViewportState(){const e=this._effectiveProjection();return{space:this._space,mode:this._mode,projection:e,activeLabsIso:this._labsIso,logicalCenter:this._logicalViewCenter(e),zoom:this._zoom,view:this._view?{...this._view}:null,snap:this._viewModeSnap?{...this._viewModeSnap}:null,tool:this._tool,decorTool:this._decorTool,showHidden:this._showHidden,showFar:this._showFar,selId:this._selId,rszSel:this._resize?.selectedRoomId,decorSel:this._decorSel}}_warmDialogState(){const e=(e,t)=>({kind:e,space:this._space,mode:this._mode,data:t});return this._tapConfirm||this._alignDialog||this._mergeDialog||this._importDialog||this._backupExportDialog||this._backupImportDialog?null:this._openingInfo?e("openingInfo",this._openingInfo.id):this._infoCard?e("info",this._infoCard.id):this._rulesDialog?this._rulesDialog.busy?null:e("rules",this._rulesDialog):this._settingsDialog?this._settingsDialog.busy?null:e("settings",this._settingsDialog):this._markerDialog?this._markerDialog.busy?null:e("marker",this._markerDialog):this._openingDialog?e("opening",this._openingDialog):this._backdropDialog?e("backdrop",this._backdropDialog):this._decorShapeDialog?e("decorShape",this._decorShapeDialog):this._decorTextDialog?e("decorText",this._decorTextDialog):this._roomDialog?e("room",{editId:this._roomEditId,fill:this._roomFill,customFill:this._roomCustomFill,tempMin:this._roomTempMin,tempMax:this._roomTempMax,tempSrc:this._roomTempSrc,humSrc:this._roomHumSrc,srcOpen:this._roomSrcOpen,srcFilter:this._roomSrcFilter,nameScale:this._roomNameScale,labelScale:this._roomLabelScale,areaSel:this._areaSel,nameSel:this._nameSel,pendingSplit:this._pendingSplit,wallFaceBatch:this._wallFaceBatch,path:this._path}):this._spaceDialog?this._spaceDialog.busy?null:e("space",this._spaceDialog):null}_warmSnapshot(){if(this._booting||this._config?.kiosk||"steady"!==this._continuity.state)return;const e={vp:this._warmViewportState(),frameFingerprint:this._continuity.frameFingerprint,devices:this._devices,hdrH:this._hdrH};if(this._warmRevivePending||(e.dlg=this._warmDialogState()),this.isConnected&&this._warmSlot?.owner===this._warmGen){const t=this.parentNode;e.place=t?new WeakRef(t):null,e.idx=this._warmIdx(t)}this._warmPatch(e)}_warmReviveDialog(){const e=this._warmSlot;if(this._warmReviveTimer=void 0,!e||!e.dlg)return void(this._warmRevivePending=!1);const t=e.dlg,i=e.freed;if(t.mode===this._mode||"view"===t.mode||this._warmVp?.mode!==t.mode||this._editorRuntime){if(this._warmRevivePending=!1,e.dlg=null,e.freed=0,clearTimeout(e.evict),e.evict=0,i&&!(Date.now()-i>av)&&t.space===this._space&&t.mode===this._mode){switch(t.kind){case"space":this._spaceDialog={...t.data,busy:!1,savedBusy:!1};break;case"marker":this._markerDialog={...t.data,busy:!1};break;case"settings":this._settingsDialog={...t.data,busy:!1};break;case"rules":this._rulesDialog={...t.data,busy:!1};break;case"opening":this._openingDialog={...t.data};break;case"backdrop":this._backdropDialog={...t.data};break;case"decorShape":this._decorShapeDialog={...t.data};break;case"decorText":{this._decorTextDialog={...t.data};const e=String(this._decorTextDialog?.text??"").length;this._decorTextSelection={start:e,end:e};break}case"room":{const e=t.data;this._roomEditId=e.editId,this._roomFill=e.fill,this._roomCustomFill=e.customFill||null,this._roomTempMin=e.tempMin||"",this._roomTempMax=e.tempMax||"",this._roomTempSrc=e.tempSrc,this._roomHumSrc=e.humSrc,this._roomSrcOpen=e.srcOpen,this._roomSrcFilter=e.srcFilter,this._roomNameScale=e.nameScale,this._roomLabelScale=e.labelScale,this._areaSel=e.areaSel,this._nameSel=e.nameSel,this._pendingSplit=e.pendingSplit,this._wallFaceBatch=e.wallFaceBatch||null,this._path=e.path,this._wallFaceBatch&&(this._activeWallChainId=`chain-${Date.now().toString(36)}`,this._activeWallChainPartitionIds=[...this._wallFaceBatch.activePartitionIds],this._wallChainSegmentCms=[...this._wallFaceBatch.activeCms]),this._roomDialog=!0;break}case"info":{const e=this._devices.find(e=>e.id===t.data);e&&(this._infoCard=e);break}case"openingInfo":{const e=(this._curSpaceCfg?.openings||[]).find(e=>e.id===t.data);e&&(this._openingInfo=e);break}}this.requestUpdate()}}else this._warmRevivePending=!0}_cacheSnapshot(){if(this._serverCfg)try{this._virtualLights=function(e,t,i){if(e.configRev===i)return e;const n=new Set((Array.isArray(t?.markers)?t.markers:[]).filter(qh).map(e=>e.id));return{...e,configRev:i,off:new Set([...e.off].filter(e=>n.has(e)))}}(this._virtualLights,this._serverCfg,this._cfgRev);const e=this._adoption.snapshot(function(e){return{rev:e.rev,config_rev:e.configRev,off:[...e.off].sort()}}(this._virtualLights));e&&localStorage.setItem(cv,JSON.stringify(e))}catch{}}_beginContinuityCandidate(e,t,i="plan"){return this._booting&&!this._continuity.hasCompleteFrame?this._continuity.token:(this._continuityDataReady=t,this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._resumeSettling=!0,this._continuity.beginCandidate(e,i))}_continuityStageValid(){const e=this._stageEl;return!!e&&e.clientWidth>0&&e.clientHeight>0}_versionReloadSafetySnapshot(){return Sg(this)}_continuityAssetsReady(){if(!this._model.length)return!1;const e=this._model.length?this._spaceModel():null;return!e?.bg?.href||this._signer.isReady(this.hass,e.bg.href)}_initialSpaceSelection(e,t=this._loadOk){const i=this._fixedFloorState(e,t);return"valid"===i.kind?{id:i.id,source:"fixed"}:this._hasFixedFloor?{id:null,source:"none"}:function(e){const t=new Set(e.spaceIds.filter(e=>!!e));if(!t.size)return{id:null,source:"none"};const i=[["hash",!1===e.acceptHash?null:e.hashSpace],["current",e.preserveCurrent?e.currentSpace:null],["saved",e.savedSpace],["default",e.defaultSpace],["first",e.spaceIds[0]]];for(const[e,n]of i)if(n&&t.has(n))return{id:n,source:e};return{id:null,source:"none"}}({spaceIds:e.map(e=>e.id),hashSpace:this._hashSpace(),acceptHash:!this._hashApplied,currentSpace:this._space,preserveCurrent:this._hashApplied||this._navApplied||this._warmVpArmed,savedSpace:this._savedNav()?.space,defaultSpace:this._config?.default_floor})}_adoptInitialSpace(e,t=this._loadOk){const i=this._initialSpaceSelection(e,t);return i.id?(this._commitSpace(i.id,!0),"hash"===i.source&&(this._hashApplied=!0),"saved"===i.source&&(this._navApplied=!0),i):i}_candidateBackdrop(e,t=this._space){const i=el(e),n=this._fixedFloorState(i,!0);if(this._hasFixedFloor&&"valid"!==n.kind)return"";const r=this._initialSpaceSelection(i,!0).id||(i.some(e=>e.id===t)?t:i[0]?.id);return i.find(e=>e.id===r)?.bg?.href||""}_visualFrameFingerprint(){const e=this._stageEl,t=e?[e.clientWidth,e.clientHeight]:[0,0];return hc([this._cfgRev,this._adoption.currentConfigFingerprint(),this._layoutRev,this._adoption.currentLayoutFingerprint(),this._space,this._mode,this._view,t,this._glowScreenBlend?"screen":"normal",this.hass?.themes?.darkMode??this.hass?.themes?.default_theme??""])}_settleContinuityFrame(){if(this._booting||!this._continuityStageValid())return;if(!this._continuity.hasCompleteFrame&&"steady"===this._continuity.state)return void(this._continuityAssetsReady()&&(this._renderSnapshotAt=Date.now(),this._continuity.markCompleteFrame(this._visualFrameFingerprint())));if(!this._continuityDataReady)return;if(!["holding","offline-stale","overlay-pending","overlay-visible","candidate-ready"].includes(this._continuity.state))return;const e=this._continuity.token;if(this._candidateDeviceSnapshot&&this._candidateDeviceSnapshot!==this._visibleDeviceSnapshot&&this._stagedDeviceSnapshotToken!==e)return this._stagedDeviceSnapshotToken=e,void this.requestUpdate();this._continuityPaintToken!==e&&(this._continuityPaintToken=e,this._continuity.candidateReady(e)&&this._continuity.commitAfterPaint(e,{updateComplete:()=>this.updateComplete,stageValid:()=>this.isConnected&&this._continuityStageValid(),assetsReady:()=>this._continuityAssetsReady(),frameFingerprint:()=>this._visualFrameFingerprint()}).then(t=>{t&&e===this._continuity.token?(this._resumeSettling=!1,this._renderSnapshotAt=Date.now(),this._candidateDeviceSnapshot&&(this._visibleDeviceSnapshot=this._candidateDeviceSnapshot),this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._warmSnapshot()):e===this._continuity.token&&(this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._candidateDeviceSnapshot=null,this.requestUpdate())}))}_onBackdropLoaded(e,t){this._signer.markLoaded(this.hass,e,t),this._continuity.note("asset-ready"),this._continuityPaintToken=-1,"steady"!==this._continuity.state&&this.requestUpdate()}_renderRecoveryOverlay(){if(!this._continuity.overlayVisible&&"recovery-error"!==this._continuity.state)return G;const e="connection"===this._continuity.recoveryReason;return j`
svg{position:absolute;inset:0;width:100%;height:100%;display:block;z-index:1;}.hp-static-stage>.hp-paper-outline-svg{z-index:0;overflow:visible;}.hp-paper{fill:var(--ha-card-background,var(--card-background-color,#111));stroke:none;}.wallbody-fill{fill:var(--wall-fill,#ffffff);fill-opacity:var(--wall-fill-op,1);fill-rule:evenodd;stroke:none;pointer-events:none;}.wallbody{fill:url(#hp-wall-hatch);fill-rule:evenodd;stroke:var(--room-stroke,var(--hp-muted,#607d8b));stroke-width:calc(0.6px * var(--hp-cell-visual-scale,1));pointer-events:none;}.wallbody.solid{fill:none;}.hp-static-stage .devlayer{position:absolute;inset:0;z-index:2;}.hp-static-foot{padding:8px 12px 12px;pointer-events:auto;}.hp-static-btn{width:100%;padding:9px 14px;border:none;border-radius:10px;background:var(--primary-color,#3ea6ff);color:var(--text-primary-color,#fff);font-size:14px;font-weight:600;cursor:pointer;}:host([data-pointer-hover]) .hp-static-btn:hover{filter:brightness(1.08);}.hp-static-error{padding:24px;text-align:center;color:var(--secondary-text-color,#9aa4ad);}`],customElements.get("houseplan-space-card")||customElements.define("houseplan-space-card",_g),window.customCards=window.customCards||[],window.customCards.find(e=>"houseplan-space-card"===e.type)||window.customCards.push({type:"houseplan-space-card",name:"House Plan — Space (static)",description:"Read-only live schematic of a single houseplan space, with a deep-link button.",preview:!1,documentation:"https://github.com/Matysh/houseplan-card"});const mg=o`:host{--hp-editor-tray-bg-fallback:color-mix(in srgb,var(--card-background-color,var(--hp-bg)) 94%,var(--hp-line));--hp-editor-tray-bg:color-mix(in srgb,var(--card-background-color,var(--hp-bg)) 86%,transparent);--hp-editor-tray-border:color-mix(in srgb,var(--hp-line) 82%,var(--hp-accent));--hp-editor-tray-blur:8px;--hp-editor-tray-shadow:var(--shadow-2);}.editor-secondary-host{position:absolute;inset:var(--sp-2) var(--sp-4) auto;z-index:70;display:flex;justify-content:flex-end;pointer-events:none;}.editor-secondary-host.kind-palette,.editor-secondary-host.kind-group{justify-content:flex-start;}.editor-secondary{pointer-events:none;max-width:100%;display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);color:var(--hp-txt);background:var(--card-background-color,var(--hp-bg));background:var(--hp-editor-tray-bg-fallback);border:1px solid var(--hp-line);border-color:var(--hp-editor-tray-border);border-radius:var(--rad-l);box-shadow:var(--hp-editor-tray-shadow);opacity:0;visibility:hidden;transform:translateY(-4px);transition:opacity 0.1s ease,transform 0.1s cubic-bezier(0.2,0.7,0.2,1),visibility 0s linear 0.1s;touch-action:auto;}.editor-secondary-host.open .editor-secondary{pointer-events:auto;opacity:1;visibility:visible;transform:translateY(0);transition-duration:0.14s,0.14s,0s;transition-delay:0s;}.editor-secondary-host.blocked .editor-secondary{pointer-events:none;}@supports ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){.editor-secondary{background:var(--hp-editor-tray-bg);-webkit-backdrop-filter:blur(var(--hp-editor-tray-blur));backdrop-filter:blur(var(--hp-editor-tray-blur));}}.editor-secondary-content,.editor-group-items{display:flex;align-items:center;gap:var(--sp-3);min-width:0;}.editor-context-label{max-width:14rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding-inline-end:var(--sp-4);border-inline-end:1px solid var(--hp-line);color:var(--hp-muted);font-size:var(--fs-s);}.editor-secondary.kind-palette{width:min(760px,100%);align-items:stretch;padding:0;overflow:hidden;}.editor-secondary.kind-palette .editor-secondary-content,.editor-secondary.kind-palette .furnpalette{width:100%;}.editor-secondary.kind-palette .furnpalette{max-height:38vh;border:0;background:transparent;}.editor-group-launcher .group-chevron{--mdc-icon-size:16px;transition:transform 0.14s ease;}.editor-group-launcher[aria-expanded="true"] .group-chevron{transform:rotate(180deg);}.editor-secondary .bdhint{font-size:var(--fs-s);color:var(--hp-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.editor-secondary .dfill{display:inline-flex;align-items:center;gap:var(--sp-2);font-size:var(--fs-s);cursor:pointer;}.editor-secondary .dfill input[type="checkbox"]{width:16px;height:16px;flex:none;margin:0;padding:0;}.editor-secondary hp-color-opacity{flex:0 0 auto;}.editor-secondary input{width:74px;background:transparent;border:1px solid var(--hp-line);color:var(--hp-txt);border-radius:var(--rad-s);padding:var(--sp-3) var(--sp-4);font-size:var(--fs-m);}.editor-secondary label,.editor-secondary .hint{color:var(--hp-muted);font-size:var(--fs-s);}.editor-secondary .drawwall{display:inline-flex;align-items:center;gap:var(--sp-3);white-space:nowrap;}.editor-secondary .drawwall input{width:4.2em;}.editor-secondary .drawwall .opl{color:var(--hp-muted);font-size:var(--fs-s);}@container (min-width:560px) and (max-width:899px){.editor-secondary-content,.editor-group-items{flex-wrap:wrap;justify-content:flex-end;}}@container (max-width:559px){.editor-secondary-host{inset-inline:var(--sp-4);}.editor-secondary{max-width:100%;}.editor-secondary-content,.editor-group-items{overflow-x:auto;scrollbar-width:thin;}.editor-secondary-content>*,.editor-group-items>*{flex:none;}.editor-context-label{display:none;}}@media (prefers-reduced-motion:reduce){.editor-secondary{transition:none;}.editor-group-launcher .group-chevron{transition:none;}}`;class gg{constructor(e=50){this._undo=[],this._redo=[],this._limit=Math.max(30,Math.floor(e))}get canUndo(){return this._undo.length>0}get canRedo(){return this._redo.length>0}get undoName(){return this._undo[this._undo.length-1]?.name??null}get redoName(){return this._redo[this._redo.length-1]?.name??null}get size(){return this._undo.length}push(e){this._undo.push(e),this._undo.length>this._limit&&this._undo.splice(0,this._undo.length-this._limit),this._redo=[]}undo(){const e=this._undo.pop()??null;return e&&this._redo.push(e),e}redo(){const e=this._redo.pop()??null;return e&&this._undo.push(e),e}removeWhere(e){const t=this._undo.length,i=this._redo.length;return this._undo=this._undo.filter(t=>!e(t)),this._redo=this._redo.filter(t=>!e(t)),t+i-this._undo.length-this._redo.length}clear(){this._undo=[],this._redo=[]}}function fg(e,t){const i=e[t];return i&&Number.isFinite(i.x)&&Number.isFinite(i.y)?{x:i.x,y:i.y,..."string"==typeof i.s?{s:i.s}:{}}:null}function vg(e,t,i){if(null===i){if(!(t in e))return e;const i={...e};return delete i[t],i}const n={...e[t]||{}};delete n.x,delete n.y,delete n.s;const r={...n,x:i.x,y:i.y,...void 0!==i.s?{s:i.s}:{}};return{...e,[t]:r}}const yg="houseplan-card:version-reload-target:v1";function bg(e){if("string"!=typeof e)return null;return e.trim()||null}class wg{constructor(e){this.hooks=e,this._input={frontendVersion:null,backendVersion:null,kiosk:!1,reducedMotion:!1},this._relation={kind:"unknown"},this._banner=null,this._connected=!1,this._attemptTarget=null,this._attemptState=null,this._noticeToken=0}get relation(){return this._relation}get banner(){return this._banner}get hasCurrentMismatchNotice(){return"mismatch"===this._relation.kind&&"visible"===this._banner?.phase}connect(){this._connected||(this._connected=!0,this._attemptTarget=null,this._attemptState=null,this._reconcile())}disconnect(){(this._connected||this._banner)&&(this._connected=!1,this._cancelTimer(),this._banner&&(this._banner=null,this.hooks.changed()))}update(e){const t={frontendVersion:bg(e.frontendVersion),backendVersion:bg(e.backendVersion),kiosk:!0===e.kiosk,reducedMotion:!0===e.reducedMotion},i=function(e,t){const i=bg(e),n=bg(t);return i&&n?i===n?{kind:"equal",frontend:i,backend:n}:{kind:"mismatch",frontend:i,backend:n}:{kind:"unknown"}}(t.frontendVersion,t.backendVersion),n=!((e,t)=>e.frontendVersion===t.frontendVersion&&e.backendVersion===t.backendVersion&&e.kiosk===t.kiosk&&e.reducedMotion===t.reducedMotion)(this._input,t)||!((e,t)=>e.kind===t.kind&&("unknown"===e.kind||"unknown"!==t.kind&&e.frontend===t.frontend&&e.backend===t.backend))(this._relation,i);this._input=t,this._relation=i,n&&this._reconcile()}finishBannerExit(e){this._banner&&"leaving"===this._banner.phase&&this._banner.token===e&&(this._banner=null,this.hooks.changed())}_reconcile(){if(this._cancelTimer(),!this._connected||"mismatch"!==this._relation.kind)return this._attemptTarget=null,this._attemptState=null,void this._hideBanner();if(!this._input.kiosk)return this._attemptTarget=null,this._attemptState=null,void this._showBanner(this._relation.frontend,this._relation.backend);const e=this._relation.backend;if(this._attemptTarget===e&&null!==this._attemptState||(this._attemptTarget=e,this._attemptState=function(e,t){try{const i=e();return i?i.getItem(yg)===t?"attempted":"fresh":"unavailable"}catch{return"unavailable"}}(this.hooks.storage,e)),"fresh"===this._attemptState)return this._hideBanner(),void this._armTimer();this._showBanner(this._relation.frontend,e)}_armTimer(){this._connected&&void 0===this._timer&&"mismatch"===this._relation.kind&&this._input.kiosk&&"fresh"===this._attemptState&&(this._timer=this.hooks.clock.setTimeout(()=>{this._timer=void 0,this._tick()},250))}_cancelTimer(){void 0!==this._timer&&(this.hooks.clock.clearTimeout(this._timer),this._timer=void 0)}_tick(){if(!this._connected||"mismatch"!==this._relation.kind||!this._input.kiosk||"fresh"!==this._attemptState)return;if(!function(e){return e.connected&&e.initialFrameSettled&&e.viewOnly&&e.surfacesIdle&&e.configWritesIdle&&e.physicalWritesIdle&&e.layoutWritesIdle&&e.gesturesIdle&&e.interactionPauseElapsed&&e.baseZoom}(this.hooks.safety()))return void this._armTimer();const e=this._relation.backend,t=function(e,t){try{const i=e();return i?i.getItem(yg)===t?"attempted":(i.setItem(yg,t),"claimed"):"unavailable"}catch{return"unavailable"}}(this.hooks.storage,e);if(this._attemptTarget=e,this._attemptState="claimed"===t?"attempted":t,"claimed"===t){this._showBanner(this._relation.frontend,e);try{this.hooks.reload()}catch{}}else this._showBanner(this._relation.frontend,e)}_showBanner(e,t){"visible"===this._banner?.phase&&this._banner.frontend===e&&this._banner.backend===t||(this._banner={frontend:e,backend:t,phase:"visible",token:++this._noticeToken},this.hooks.changed())}_hideBanner(){if(this._banner)return this._input.reducedMotion?(this._banner=null,void this.hooks.changed()):void("leaving"!==this._banner.phase&&(this._banner={...this._banner,phase:"leaving",token:++this._noticeToken},this.hooks.changed()))}}const kg=1;function xg(e,t){const i=t&&"object"==typeof t?t:{};e._haIntegrationVersion=bg(i.integration_version);const n=i.support_api;e._haSupportApi="number"==typeof n&&Number.isSafeInteger(n)?n:null,e._haDecorAssetsApi=1===i.decor_assets_api?1:null,e._haSummaryPanelApi=1===i.summary_panel_api?1:null,e._haRadarStage1Api=1===i.radar_stage1_api?1:null,e._syncVersionRecovery()}function Sg(e){const t=e._stageEl,i=e._loadOk&&!e._loading&&e._continuityDataReady&&!e._resumeSettling&&!e._connectionWasLost&&!e._booting&&!e._bootFading&&!e._bootSettling&&!e._bootSoft&&e._continuity.hasCompleteFrame&&"steady"===e._continuity.state&&!e._continuity.overlayBlocksInteraction&&!!t&&t.clientWidth>0&&t.clientHeight>0,n=!(0!==e._pointers.size||0!==e._touchContacts.size||e._touchSequenceMultitouch||e._roomPointer||e._panStart||e._panLock||e._pinchStart||e._swipeStart||e._tabDrag||e._tabDragRelease||e._drag||e._deviceDrag||e._rlResize||e._resize?.dragging||e._physicalDrag||e._physicalRotate||e._opDrag||e._decorDraft||e._decorMove||e._dtDrag||e._bdDrag||e._furnTouchPending||e._compassDrag||e._viewportGestureDirty||e._devicePositionBusy||e._modeTransitionBusy||e._cameraTransition.active||e._slide||0!==e._warmModeRequest),r=!(e._editorSecondaryDialogBlocked||e._partitionDeleteDialog||e._roomDeleteDialog||e._backdropGuard||e._vacFit||e._editorSecondary?.hasOpenGroup||e._furnPalette||e._decorImagePalette);return{connected:e.isConnected,initialFrameSettled:i,viewOnly:!0===e._config?.kiosk&&"view"===e._mode&&!e._editing,surfacesIdle:r,configWritesIdle:0===e._writesPending&&!e._saveConfigDebounced.pending(),physicalWritesIdle:0===e._pendingPhysicalWrites.size,layoutWritesIdle:!e._persistLayout.pending()&&0===e._dirtyPos.size&&0===e._sentPos.size&&!e._devicePositionBusy,gesturesIdle:n,interactionPauseElapsed:Date.now()>=e._cyclePausedUntil,baseZoom:e._zoom<=1.001}}class $g{constructor(){this.seen=null,this.diagnosticsCache=null}observe(e,t,i,n){this.invalidateDiagnosticsForHass(e,t,i),this.intake(t,n)}intake(e,t){e&&this.seen!==e&&(this.seen=e,t())}invalidate(){this.diagnosticsCache=null}invalidateDiagnosticsForHass(e,t,i){this.diagnosticsCache&&(e?.entities!==t?.entities||e?.devices!==t?.devices||[...i?.entityIds||[]].some(i=>!!e?.states?.[i]!=!!t?.states?.[i]))&&this.invalidate()}diagnostics(e,t,i){if(this.diagnosticsCache)return this.diagnosticsCache;const n={active:0,ha_disabled:0,orphaned:0,unverified:0};for(const e of t)e.removed||"virtual"===e.binding||n[i(e.binding).kind]++;return this.diagnosticsCache={registry:ud(e),bindings:n},this.diagnosticsCache}}function Mg(e){const t=e;t._hassSequence++,t._renderSnapshotAt=Date.now(),t._continuity.note("hass-snapshot"),t._ensureHaRegistryAuthority(),t._planHassMemo=null,t._hookConnection(),!t._loadOk&&!t._loading&&t._loadTries<8&&t._loadFromServer(),t._maybeRebuildDevices(),t._vacTick(),t._activityTick()}function Rg(e){return!!e&&"object"==typeof e&&1===e.version}function Cg(e,t){const i=e.radar;return e.space===t&&!0!==e.hidden&&!0!==e.removed&&Rg(i)&&!0===i.enabled&&!1!==i.show_live}const Tg={ok:"radar.health_ok",off:"radar.health_off",stale:"radar.health_stale",partial:"radar.health_partial",restricted:"radar.health_restricted",incomplete:"radar.health_incomplete",position_unavailable:"radar.health_position_unavailable",unavailable:"radar.health_unavailable",needs_setup:"radar.health_needs_setup",inconsistent:"radar.health_inconsistent",unknown:"radar.health_unknown"};const Dg=e=>"number"==typeof e&&Number.isFinite(e);class Ag{constructor(e){this.host=e,this.frames=new Map,this.connection=null,this.space="",this.generation=0,this.expiryTimer=0,this.deadlines=new Map}sync(e,t){const i=this.host.hass?.connection;if(!t||!i||!this.host.isConnected)return void this.stop();if(this.unsubscribe&&this.connection===i&&this.space===e)return;this.stop(),this.connection=i,this.space=e;const n=++this.generation,r=i.subscribeMessage?.bind(i);"function"==typeof r&&Promise.resolve(r(e=>{if(n!==this.generation||!this.host.isConnected)return;const t=function(e){if(!e||"object"!=typeof e)return null;const t=e;if("string"!=typeof t.marker_id||"string"!=typeof t.server_session_id||!Number.isSafeInteger(t.seq)||"string"!=typeof t.health)return null;const i=Array.isArray(t.targets)?t.targets.slice(0,256).flatMap(e=>{if(!e||"object"!=typeof e)return[];const t=e;return"string"==typeof t.slot&&Dg(t.x)&&Dg(t.y)&&Dg(t.expires_at)&&Dg(t.reported_at)&&("bounded_latest"===t.pair_quality||"coherent"===t.pair_quality)?[{...t,included:!0===t.included,smooth:!0===t.smooth}]:[]}):[],n=Array.isArray(t.ranges)?t.ranges.slice(0,64).flatMap(e=>{if(!e||"object"!=typeof e)return[];const t=e;if(!("string"==typeof t.id&&Dg(t.x)&&Dg(t.y)&&Dg(t.radius)&&Dg(t.expires_at)&&Dg(t.reported_at)))return[];const i=Array.isArray(t.segments)?t.segments.slice(0,64).flatMap(e=>{if(!Array.isArray(e))return[];const t=e.slice(0,181).flatMap(e=>Array.isArray(e)&&2===e.length&&Dg(e[0])&&Dg(e[1])?[[e[0],e[1]]]:[]);return t.length>=2?[t]:[]}):void 0;return[{...t,...i?{segments:i}:{}}]}):[],r=Array.isArray(t.zones)?t.zones.slice(0,64).flatMap(e=>{if(!e||"object"!=typeof e)return[];const t=e;if("string"!=typeof t.id)return[];const i=t.state;if(null!==i&&"boolean"!=typeof i&&!Dg(i))return[];const n=Array.isArray(t.polygon)?t.polygon.slice(0,64).flatMap(e=>Array.isArray(e)&&2===e.length&&Dg(e[0])&&Dg(e[1])?[[e[0],e[1]]]:[]):[];return[{id:t.id,state:i,...n.length>=3?{polygon:n}:{}}]}):[];return{server_session_id:t.server_session_id,marker_id:t.marker_id,source_generation:"string"==typeof t.source_generation?t.source_generation:void 0,calibration_revision:"string"==typeof t.calibration_revision?t.calibration_revision:void 0,seq:t.seq,reported_at:Dg(t.reported_at)?t.reported_at:void 0,expires_at:Dg(t.expires_at)?t.expires_at:void 0,health:t.health,reported_presence:"boolean"==typeof t.reported_presence?t.reported_presence:null,complete:!0===t.complete,targets:i,ranges:n,zones:r}}(e);if(!t)return;if(!function(e,t){return!e||t.server_session_id!==e.server_session_id||t.source_generation!==e.source_generation||t.calibration_revision!==e.calibration_revision||t.seq>e.seq}(this.frames.get(t.marker_id),t))return;const i=function(e,t=Date.now()){if(!Dg(e.expires_at))return null;if(!Dg(e.reported_at))return Math.max(0,1e3*e.expires_at-t);const i=Math.max(0,1e3*(e.expires_at-e.reported_at)),n=Math.max(0,t-1e3*e.reported_at);return Math.max(0,i-n)}(t);"restricted"===t.health||"disabled"===t.health||0===i?(this.frames.delete(t.marker_id),this.deadlines.delete(t.marker_id)):(this.frames.set(t.marker_id,t),null==i?this.deadlines.delete(t.marker_id):this.deadlines.set(t.marker_id,this.monotonicNow()+i)),this.armExpiry(),this.host.requestUpdate()},{type:"houseplan/radar/subscribe",space_id:e})).then(e=>{n===this.generation&&this.host.isConnected?"function"==typeof e&&(this.unsubscribe=e):"function"==typeof e&&e()}).catch(()=>{n===this.generation&&this.stop()})}stop(){this.generation++,this.unsubscribe?.(),this.unsubscribe=void 0,this.connection=null,this.space="",clearTimeout(this.expiryTimer),this.expiryTimer=0,this.frames.size&&(this.frames.clear(),this.host.isConnected&&this.host.requestUpdate()),this.deadlines.clear()}armExpiry(){clearTimeout(this.expiryTimer);const e=this.monotonicNow(),t=[...this.deadlines.values()].filter(t=>t>e);if(!t.length)return;const i=Math.max(20,Math.min(...t)-e+10);this.expiryTimer=window.setTimeout(()=>{this.expiryTimer=0;let e=!1;const t=this.monotonicNow();for(const[i,n]of this.deadlines)n>t||(this.deadlines.delete(i),this.frames.delete(i),e=!0);this.armExpiry(),e&&this.host.isConnected&&this.host.requestUpdate()},i)}monotonicNow(){return globalThis.performance?.now?.()??Date.now()}}const Pg=Object.freeze({enabled:!1,z2mBaseTopics:Object.freeze([])});function Fg(e){if("string"!=typeof e)return null;const t=e.trim().replace(/^\/+|\/+$/g,"").replace(/\/{2,}/g,"/");return!t||t.length>180||/[#+\u0000-\u001f\u007f]/.test(t)?null:t}function zg(e){const t=e?.zigbee_topology;if(!t||"object"!=typeof t)return Pg;const i=t,n=Array.isArray(i.z2m_base_topics)?i.z2m_base_topics:Array.isArray(i.z2mBaseTopics)?i.z2mBaseTopics:[],r=new Set,o=[];for(const e of n){const t=Fg(e);if(t&&!r.has(t)&&(r.add(t),o.push(t),8===o.length))break}return{enabled:!0===i.enabled,z2mBaseTopics:o}}function Ig(e,t){const i={...e},n=t.z2mBaseTopics.map(Fg).filter(Boolean);return t.enabled||n.length?i.zigbee_topology={enabled:!0===t.enabled,z2m_base_topics:[...new Set(n)].slice(0,8)}:delete i.zigbee_topology,i}const Og={now:()=>performance.now(),requestFrame:e=>requestAnimationFrame(e),cancelFrame:e=>cancelAnimationFrame(e)},Eg=e=>Math.max(0,Math.min(1,e)),Ng=(e,t,i)=>e+(t-e)*i,Hg=(e,t,i)=>{const n=1-e;return 3*n*n*e*t+3*n*e*e*i+e*e*e},Lg=e=>{const t=Eg(e);if(0===t||1===t)return t;let i=0,n=1,r=t;for(let e=0;e<12;e++)r=(i+n)/2,Hg(r,.2,.2)0&&e.w>0?t/e.w:1,viewBox:{...e}}}function qg(e,t,i){const n=Math.max(1e-9,e.pixelsPerUnit),r=Math.max(1e-9,t/n),o=Math.max(1e-9,i/n);return{x:e.centerX-r/2,y:e.centerY-o/2,w:r,h:o}}function jg(e){const t=e.trim(),i=/^rgba?\(\s*([\d.]+)[, ]+([\d.]+)[, ]+([\d.]+)(?:\s*[,/]\s*([\d.]+))?\s*\)$/i.exec(t);if(i)return[Number(i[1]),Number(i[2]),Number(i[3]),null==i[4]?1:Number(i[4])];const n=/^#([0-9a-f]{6}|[0-9a-f]{8})$/i.exec(t)?.[1];return n?[parseInt(n.slice(0,2),16),parseInt(n.slice(2,4),16),parseInt(n.slice(4,6),16),8===n.length?parseInt(n.slice(6,8),16)/255:1]:null}function Wg(e,t,i){const n=jg(e),r=jg(t);if(!n||!r)return i<.5?e:t;const o=Eg(i);return`rgba(${Math.round(Ng(n[0],r[0],o))}, ${Math.round(Ng(n[1],r[1],o))}, ${Math.round(Ng(n[2],r[2],o))}, ${Ng(n[3],r[3],o).toFixed(3)})`}class Ug{constructor(e,t=Og){this._hooks=e,this._clock=t,this._token=0,this._raf=0,this._state=null}get state(){return this._state}get active(){return"running"===this._state?.phase||"preparing"===this._state?.phase}get presented(){return this._state?.presented||null}start(e,t,i,n=220){this.cancel(!1);const r=++this._token,o=this._clock.now();if(this._state={token:r,phase:n<=0?"settling":"running",from:e,to:t,presented:n<=0?t:e,startedAt:o,duration:Math.max(0,n),targetMode:i},n<=0)return this._hooks.frame(this._state),this._hooks.settled(this._state),this._state=null,r;this._hooks.frame(this._state);const s=e=>{const t=this._state;if(!t||t.token!==r)return;const i=Eg((e-t.startedAt)/t.duration);t.presented=i>=1?t.to:function(e,t,i){const n=Lg(i),r=Ng(e.stageWidth,t.stageWidth,n),o=Ng(e.stageHeight,t.stageHeight,n),s=Math.max(1e-9,e.viewport.pixelsPerUnit),a=Math.max(1e-9,t.viewport.pixelsPerUnit),l={centerX:Ng(e.viewport.centerX,t.viewport.centerX,n),centerY:Ng(e.viewport.centerY,t.viewport.centerY,n),pixelsPerUnit:Math.exp(Ng(Math.log(s),Math.log(a),n))};return{presentedMode:n<.5?e.presentedMode:t.presentedMode,editorChromeHeight:Ng(e.editorChromeHeight,t.editorChromeHeight,n),stageWidth:r,stageHeight:o,viewport:{...l,viewBox:qg(l,r,o)},stageColor:Wg(e.stageColor,t.stageColor,n),paperColor:Wg(e.paperColor,t.paperColor,n),sceneBrightness:Ng(e.sceneBrightness,t.sceneBrightness,n),architectureOpacity:Ng(e.architectureOpacity,t.architectureOpacity,n),backdropOpacity:Ng(e.backdropOpacity,t.backdropOpacity,n),viewWeight:Ng(e.viewWeight,t.viewWeight,n),editorWeight:Ng(e.editorWeight,t.editorWeight,n),toolbarContentOpacity:Ng(e.toolbarContentOpacity,t.toolbarContentOpacity,n)}}(t.from,t.to,i),t.phase=i>=1?"settling":"running",this._hooks.frame(t),i<1?this._raf=this._clock.requestFrame(s):(this._raf=0,this._hooks.settled(t),this._state?.token===r&&(this._state=null))};return this._raf=this._clock.requestFrame(s),r}cancel(e=!0){this._raf&&this._clock.cancelFrame(this._raf),this._raf=0;const t=this._state;this._state=null,this._token++,t&&e&&(t.phase="settling",t.presented=t.to,this._hooks.frame(t),this._hooks.settled(t))}dispose(){this.cancel(!1)}}const Gg={now:()=>"undefined"!=typeof performance?performance.now():Date.now(),requestFrame:e=>"function"==typeof requestAnimationFrame?requestAnimationFrame(e):null,cancelFrame:e=>{"function"==typeof cancelAnimationFrame&&cancelAnimationFrame(e)}},Vg=e=>Number.isFinite(e);function Kg(e){return!!e&&Vg(e.zoom)&&e.zoom>0&&Vg(e.viewBox.x)&&Vg(e.viewBox.y)&&Vg(e.viewBox.w)&&e.viewBox.w>0&&Vg(e.viewBox.h)&&e.viewBox.h>0}function Yg(e){return{zoom:e.zoom,viewBox:{...e.viewBox}}}function Xg(e,t){return Math.abs(e.zoom-t.zoom)<1e-9&&Math.abs(e.viewBox.x-t.viewBox.x)<1e-6&&Math.abs(e.viewBox.y-t.viewBox.y)<1e-6&&Math.abs(e.viewBox.w-t.viewBox.w)<1e-6&&Math.abs(e.viewBox.h-t.viewBox.h)<1e-6}const Zg=(e,t,i)=>e+(t-e)*i,Jg=(e,t,i)=>Math.exp(Zg(Math.log(e),Math.log(t),i));class Qg{constructor(e,t=Gg){this._hooks=e,this._clock=t,this._token=0,this._raf=null,this._state=null}get state(){return this._state}get active(){return"running"===this._state?.phase}get presented(){return this._state?.presented||null}get target(){return this._state?.to||null}start(e,t,i,n){this.cancel(!1);const r=++this._token,o=Yg(e),s=Yg(t),a=n>0&&Kg(o)&&Kg(s),l=this._clock.now(),c={token:r,phase:a?"running":"settling",from:o,to:s,presented:Yg(a?o:s),startedAt:l,duration:a?n:0,reason:i};if(this._state=c,this._hooks.frame(c),!a)return this._settle(r),r;const h=e=>{const t=this._state;if(!t||t.token!==r)return;const i=Math.max(0,Math.min(1,(e-t.startedAt)/t.duration));if(t.presented=i>=1?Yg(t.to):function(e,t,i){if(!Kg(e))return Yg(t);if(!Kg(t))return Yg(e);const n=Lg(i);if(n<=0)return Yg(e);if(n>=1)return Yg(t);const r=e.viewBox.x+e.viewBox.w/2,o=e.viewBox.y+e.viewBox.h/2,s=t.viewBox.x+t.viewBox.w/2,a=t.viewBox.y+t.viewBox.h/2,l=Jg(e.viewBox.w,t.viewBox.w,n),c=Jg(e.viewBox.h,t.viewBox.h,n),h=Zg(r,s,n),d=Zg(o,a,n);return{zoom:Jg(e.zoom,t.zoom,n),viewBox:{x:h-l/2,y:d-c/2,w:l,h:c}}}(t.from,t.to,i),t.phase=i>=1?"settling":"running",this._hooks.frame(t),i>=1)return this._raf=null,void this._settle(r);this._raf=this._clock.requestFrame(h),null===this._raf&&this._settle(r)};return this._raf=this._clock.requestFrame(h),null===this._raf&&(c.phase="settling",c.presented=Yg(s),this._hooks.frame(c),this._settle(r)),r}cancel(e=!0){null!==this._raf&&this._clock.cancelFrame(this._raf),this._raf=null;const t=this._state;this._state=null,this._token++,t&&e&&(t.phase="settling",t.presented=Yg(t.to),this._hooks.frame(t),this._hooks.settled(t))}dispose(){this.cancel(!1)}_settle(e){const t=this._state;t&&t.token===e&&(t.phase="settling",t.presented=Yg(t.to),this._hooks.settled(t),this._state?.token===e&&(this._state=null))}}function ef(e,t,i){const n=e.querySelector("ha-card");if(!n)return null;const r=n.getBoundingClientRect(),o=t.getBoundingClientRect().top-r.top,s=i?0:Math.min(Math.max(r.top,0),120),a=Math.round(o+s);return a>=0?a:null}const tf=Object.freeze({rotDeg:0,tiltDeg:20,xyScale:1,zScale:1,origin:Object.freeze([500,500])}),nf=84,rf=10,of=4,sf=4;function af(e){return[e.rotDeg,e.tiltDeg,e.xyScale,e.zScale,e.origin[0],e.origin[1]].every(Number.isFinite)&&Math.abs(e.xyScale)>1e-12&&Math.abs(Math.cos(e.tiltDeg*Math.PI/180))>1e-12}function lf(e,t,i=tf){if(!Number.isFinite(e[0])||!Number.isFinite(e[1]))throw new Error("invalid isometric projection input");return function(e,t){if(!Number.isFinite(e[0])||!Number.isFinite(e[1])||!t.every(Number.isFinite))throw new Error("invalid isometric affine input");const[i,n,r,o,s,a]=t;return[i*e[0]+r*e[1]+s,n*e[0]+o*e[1]+a]}(e,hf(t,i))}function cf(e,t=tf){if(!af(t)||!Number.isFinite(e[0])||!Number.isFinite(e[1]))throw new Error("invalid isometric projection input");const i=t.rotDeg*Math.PI/180,n=t.tiltDeg*Math.PI/180,r=(e[0]-t.origin[0])/t.xyScale,o=(e[1]-t.origin[1])/(t.xyScale*Math.cos(n));return[t.origin[0]+r*Math.cos(i)+o*Math.sin(i),t.origin[1]-r*Math.sin(i)+o*Math.cos(i)]}function hf(e=0,t=tf){if(!af(t)||!Number.isFinite(e))throw new Error("invalid isometric camera");const i=t.rotDeg*Math.PI/180,n=t.tiltDeg*Math.PI/180,r=t.xyScale*Math.cos(i),o=-t.xyScale*Math.sin(i),s=t.xyScale*Math.sin(i)*Math.cos(n),a=t.xyScale*Math.cos(i)*Math.cos(n);return[r,s,o,a,t.origin[0]-r*t.origin[0]-o*t.origin[1],t.origin[1]-s*t.origin[0]-a*t.origin[1]-e*t.zScale*Math.sin(n)]}function df(e=tf){return function(e=0,t=tf){return`matrix(${hf(e,t).map(e=>Number(e.toFixed(12))).join(" ")})`}(0,e)}function uf(e,t=tf){const{rect:i,wallHeight:n}=e,r=e.openingHeight??n,o=e.floorDepth??0,s=e.raisedHeight??n;if(!(i.w>=0)||!(i.h>=0)||!Number.isFinite(n)||!Number.isFinite(r)||!Number.isFinite(o)||!Number.isFinite(s)||n<0||r<0||o<0||s<0)throw new Error("invalid isometric frame");const a=[[i.x,i.y],[i.x+i.w,i.y],[i.x+i.w,i.y+i.h],[i.x,i.y+i.h]],l=Math.max(n,r,s),c=a.flatMap(e=>[lf(e,-o,t),lf(e,l,t)]),h=c.map(e=>e[0]),d=c.map(e=>e[1]),u=Math.min(...h),p=Math.min(...d);return{x:u,y:p,w:Math.max(...h)-u,h:Math.max(...d)-p}}const pf=[".dev",".vacpuck",".oplock",".op-hit",".opening",".rlgo","a","button","input","select","textarea",'[contenteditable]:not([contenteditable="false"])',"[data-room-fit-block]",'[role="link"]','[role="button"]'].join(","),_f=(e,t)=>{try{return"function"==typeof e?.matches&&e.matches(t)}catch{return!1}};function mf(e){for(const t of e){const e=t;if(_f(e,".roomlabel[data-id]")){const t=e.getAttribute?.("data-id");return t?{kind:"room",roomId:t}:{kind:"interactive"}}if(_f(e,pf))return{kind:"interactive"};if(_f(e,'[data-hp="room"][data-id]')){const t=e.getAttribute?.("data-id");return t?{kind:"room",roomId:t}:{kind:"interactive"}}if(_f(e,".stage"))return{kind:"background"}}return{kind:"outside"}}function gf(e){const t=mf(e);return"room"===t.kind?t.roomId:null}class ff{constructor(){this.pointer=null,this.sequence=null}clear(){this.pointer=null,this.sequence=null}clearOutside(e){let t={kind:"outside"};try{t=mf(e.composedPath())}catch{}"outside"===t.kind&&this.clear()}pointerDown(e,t,i){let n={kind:"outside"};try{n=mf(e.composedPath())}catch{}this.pointer=function(e){const t="mouse"===(i=e.pointerType)||"touch"===i||"pen"===i?i:null;var i;return t&&"view"===e.mode&&"background"===e.owner.kind&&!e.blocked&&e.isPrimary&&0===e.button&&Number.isFinite(e.x)&&Number.isFinite(e.y)?{pointerId:e.pointerId,spaceId:e.spaceId,modality:t,x:e.x,y:e.y}:null}({pointerId:e.pointerId,pointerType:e.pointerType,isPrimary:e.isPrimary,button:e.button,spaceId:t,mode:i?"view":"blocked",owner:n,blocked:!i,x:e.clientX,y:e.clientY}),this.pointer||(this.sequence=null)}pointerUp(e,t,i,n,r=Date.now()){let o={kind:"outside"};try{o=mf(e.composedPath())}catch{}const s=function(e,t,i){if(!t||"view"!==i.mode||"background"!==i.owner.kind||i.blocked||t.pointerId!==i.pointerId||t.spaceId!==i.spaceId||!Number.isFinite(i.x)||!Number.isFinite(i.y)||!Number.isFinite(i.now)||Math.abs(i.x-t.x)+Math.abs(i.y-t.y)>=8)return{sequence:null,trigger:!1};const n=e?i.now-e.at:Number.POSITIVE_INFINITY;return e&&e.spaceId===i.spaceId&&e.modality===t.modality&&n>=0&&n<=350?{sequence:null,trigger:!0}:{sequence:{at:i.now,spaceId:i.spaceId,modality:t.modality},trigger:!1}}(this.sequence,this.pointer,{pointerId:e.pointerId,spaceId:t,mode:i?"view":"blocked",owner:o,blocked:n||!i,x:e.clientX,y:e.clientY,now:r});return this.pointer=null,this.sequence=s.sequence,s.trigger}}const vf=e=>e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]);function yf(e){return!!e&&Number.isFinite(e.x)&&Number.isFinite(e.y)&&Number.isFinite(e.w)&&e.w>0&&Number.isFinite(e.h)&&e.h>0}function bf(e,t=0){if(!e.length||!Number.isFinite(t)||t<0||!e.every(vf))return null;let i=1/0,n=1/0,r=-1/0,o=-1/0;for(const t of e)i=Math.min(i,t[0]),n=Math.min(n,t[1]),r=Math.max(r,t[0]),o=Math.max(o,t[1]);const s=r-i,a=o-n;return s>0&&a>0?{x:i-t,y:n-t,w:s+2*t,h:a+2*t}:null}function wf(e,t,i){const n="string"!=typeof t||"invalid"!==t&&"no-borders"!==t&&"unverified"!==t&&!/^[a-z0-9]{1,8}$/i.test(t)?"redacted":t;return Object.freeze({kind:e,fingerprint:n,terminal:!!i})}function kf(e,t){return`${e("editor.load_failed")} ${e(t.terminal?"editor.refresh_advice":"editor.retry_advice")}`}class xf extends Error{}class Sf{constructor(e){this.options=e,this._state="idle",this._inFlight=null}get state(){return this._state}ensure(){return"ready"===this._state?Promise.resolve(!0):"failed"===this._state?Promise.resolve(!1):(this._inFlight||(this._setState("loading"),this._inFlight=this._loadWithRetry().finally(()=>{this._inFlight=null})),this._inFlight)}async _loadWithRetry(){let e=new Error("Editor runtime did not load"),t=!1;for(const i of[0,1])try{const e=await this.options.load(i);if(e.fingerprint!==this.options.expectedFingerprint)throw new xf(`Editor runtime fingerprint mismatch: expected ${this.options.expectedFingerprint}, got ${e.fingerprint}`);const t=e.create();return this.options.install(t),this._setState("ready"),!0}catch(i){e=i,i instanceof xf&&(t=!0)}return this._setState(t?"failed":"idle"),this.options.failed?.(e,{terminal:t}),!1}_setState(e){e!==this._state&&(this._state=e,this.options.stateChanged?.(e))}}const $f=(e,t)=>{if(!e.has(t))return{hit:!1};const i=e.get(t);return e.delete(t),e.set(t,i),{hit:!0,value:i}},Mf=(e,t,i,n)=>{for(e.delete(t),e.set(t,i);e.size>n;){const t=e.keys().next().value;if(void 0===t)break;e.delete(t)}},Rf=new Set(["select","draw","column","merge","split","resize","opening","wallthick","delroom"]),Cf=e=>`${window.innerWidth}x${window.innerHeight}|${location.pathname}|${JSON.stringify(e??{})}`,Tf="houseplan_card_alpha_v1",Df=Object.freeze([Object.freeze({id:"iso",issue:89,summary:"Volumetric plan renderer"})]);function Af(e){return/^[a-z][a-z0-9-]*$/.test(e.id)&&Number.isInteger(e.issue)&&e.issue>0&&!!e.summary.trim()}function Pf(e){const t=String(e||"").replace(/^#/,"");return new URLSearchParams(t)}function Ff(e){return Pf(e).get("space")||""}function zf(e,t,i=Df){const n=function(e){const t=new Set;for(const i of e){if(!Af(i)||t.has(i.id))return!1;t.add(i.id)}return!0}(i),r=function(e){let t,i=!1;const n=e=>{for(const n of e.getAll("hp_alpha"))i=!0,"1"===n?t=!0:"0"===n&&(t=!1)};return n(new URLSearchParams(String(e.search||"").replace(/^\?/,""))),n(Pf(e.hash)),{present:i,value:t}}(e),o=void 0!==r.value,s="1"===t,a=o?!0===r.value:!r.present&&s,l=n&&a;return{alpha:l,active:Object.freeze(l?i.map(e=>e.id).sort():[]),space:Ff(e.hash),persist:n&&o?l?"1":"0":void 0,knownUrlOperation:o}}let If={alpha:!1,active:Object.freeze([]),space:""},Of=!1,Ef="";const Nf=new Set;function Hf(){if("undefined"==typeof window)return If;const e=zf(window.location,function(){try{return window.localStorage.getItem(Tf)}catch{return null}}());void 0!==e.persist&&function(e){try{window.localStorage.setItem(Tf,e)}catch{}}(e.persist),If={alpha:e.alpha,active:e.active,space:e.space},window.__hpAlpha=e.alpha,window.__hpLabs=e.active;for(const e of Nf)e(If);return If}function Lf(){Hf()}function Bf(){if("undefined"==typeof window)return If;if(!Of){Of=!0,window.__hpLabsListenerCleanup?.(),window.addEventListener("hashchange",Lf),window.addEventListener("popstate",Lf);const e=()=>{window.removeEventListener("hashchange",Lf),window.removeEventListener("popstate",Lf),window.__hpLabsListenerCleanup===e&&delete window.__hpLabsListenerCleanup};window.__hpLabsListenerCleanup=e}return Hf()}const qf={window:120,door:90,passage:90,gate:300};function jf(e){return qf[e]}function Wf(e,t){return{type:e,lengthCm:jf(e),flipH:!1,flipV:!1,revision:t}}function Uf(e,t){const i=Math.max(0,e.renderedLength)/2,n=Math.max(0,e.target.physicalHalfWidth),r=n+.18*Math.max(0,t),o=e=>({x1:e,y1:-r,x2:e,y2:r});return{rect:{x:-i,y:n?-n:0,width:2*i,height:2*n},boundaries:[o(-i),o(i)]}}function Gf(e,t){const i=[e[0],e[1]],n=[t[0],t[1]];return function(e,t){return e[0]-t[0]||e[1]-t[1]}(i,n)<=0?{a:i,b:n}:{a:n,b:i}}function Vf(e){const t=new Map;return e.forEach((e,i)=>{if(!e.kind||e.open)return;const n=Gf(e.a,e.b);if(Math.hypot(n.b[0]-n.a[0],n.b[1]-n.a[1])<=1e-9)return;const r=function(e,t){const i=e=>(Math.abs(e)<=5e-10?0:Math.round(1e6*e)/1e6).toFixed(6);return`${i(e[0])},${i(e[1])}>${i(t[0])},${i(t[1])}`}(n.a,n.b),o=t.get(r);if(o)return o.physicalHalfWidth=Math.max(o.physicalHalfWidth,e.half||0),o.sourceOrder=Math.min(o.sourceOrder,i),void(e.partitionHost&&(o.partitionHost&&o.partitionHost.id!==e.partitionHost.id?o.ambiguousPartitionHost=!0:o.partitionHost=e.partitionHost));t.set(r,{segmentKey:r,a:n.a,b:n.b,physicalHalfWidth:Math.max(0,e.half||0),sourceOrder:i,...e.partitionHost?{partitionHost:e.partitionHost}:{}})}),[...t.values()]}function Kf(e,t){if(Math.abs(e.distance-t.distance)>1e-9)return e.distance-t.distance;if(Math.abs(e.perpendicular-t.perpendicular)>1e-9)return e.perpendicular-t.perpendicular;return(e.target.segmentKeyt.target.segmentKey?1:0)||e.target.sourceOrder-t.target.sourceOrder}function Yf(e){const t=Vf(e.intervals).map(t=>{const i=function(e,t){const i=t.b[0]-t.a[0],n=t.b[1]-t.a[1],r=Math.hypot(i,n),o=i/r,s=n/r,a=(e[0]-t.a[0])*o+(e[1]-t.a[1])*s,l=Math.max(0,Math.min(r,a)),c=t.a[0]+l*o,h=t.a[1]+l*s;return{along:l,length:r,x:c,y:h,distance:Math.hypot(e[0]-c,e[1]-h),perpendicular:Math.abs((e[0]-t.a[0])*s-(e[1]-t.a[1])*o)}}(e.pointer,t);return{target:t,...i,envelope:Math.max(e.baseTolerance,t.physicalHalfWidth+e.bodyPointerPadding)}}).filter(e=>e.distance<=e.envelope+1e-9).filter(t=>!function(e,t,i,n,r){const o=t.b[0]-t.a[0],s=t.b[1]-t.a[1],a=Math.hypot(o,s);if(!(a>1e-9))return!1;const l=o/a,c=s/a;for(const o of i){if(!o.open&&o.kind)continue;const i=Gf(o.a,o.b),s=i.b[0]-i.a[0],a=i.b[1]-i.a[1],h=Math.hypot(s,a);if(!(h>1e-9))continue;const d=s/h,u=a/h;if(Math.abs(l*u-c*d)>1e-6)continue;if(Math.abs((i.a[0]-t.a[0])*c-(i.a[1]-t.a[1])*l)>r)continue;const p=(e[0]-i.a[0])*d+(e[1]-i.a[1])*u,_=1e-9;if(!(p<=_||p>=h-_)&&Math.abs((e[0]-i.a[0])*u-(e[1]-i.a[1])*d)<=n+1e-9)return!0}return!1}(e.pointer,t.target,e.intervals,t.envelope,Math.max(1e-9,Math.min(e.baseTolerance,.04*e.gridStep)))),i=t.filter(t=>!!t.target.partitionHost&&e.renderedLength+2*t.target.physicalHalfWidth>t.length+1e-9).sort(Kf),n=t.filter(t=>!t.target.partitionHost||e.renderedLength+2*t.target.physicalHalfWidth<=t.length+1e-9).sort(Kf);let r=n[0];if(!r)return{candidate:null,jambBlockedTarget:i[0]?.target||null};const o=n.filter(e=>Math.abs(e.distance-r.distance)<=1e-9&&Math.abs(e.perpendicular-r.perpendicular)<=1e-9),s=o.filter(e=>e.target.partitionHost);if(s.length){if(1!==new Set(s.map(e=>e.target.partitionHost.id)).size||s.some(e=>e.target.ambiguousPartitionHost))return{candidate:null,jambBlockedTarget:null};const e=s[0],t=e.target.b[0]-e.target.a[0],i=e.target.b[1]-e.target.a[1],n=Math.hypot(t,i),a=t/n,l=i/n;if(!o.every(t=>{const i=t.target.b[0]-t.target.a[0],n=t.target.b[1]-t.target.a[1],r=Math.hypot(i,n),o=i/r,s=n/r,c=Math.abs(a*s-l*o)<=1e-6,h=Math.abs((t.target.a[0]-e.target.a[0])*l-(t.target.a[1]-e.target.a[1])*a);return c&&h<=1e-9}))return{candidate:null,jambBlockedTarget:null};r=e}if(r.target.ambiguousPartitionHost)return{candidate:null,jambBlockedTarget:null};const{target:a,length:l}=r,c=a.b[0]-a.a[0],h=a.b[1]-a.a[1],d=c/l,u=h/l,p=a.partitionHost?a.physicalHalfWidth:0,_=Math.min(Math.max(0,e.renderedLength)/2+p,l/2);let m=r.along;const g=Math.max(e.gridStep,1e-9),f=l/2;m=Math.abs(m-f)<=g/2?f:Math.round(m/g)*g,m=Math.max(_,Math.min(l-_,m));const v=a.a[0]+d*m,y=a.a[1]+u*m,b=Math.max(0,e.renderedLength)/2,w=m-b,k=m+b,x=Math.max(0,w),S=Math.max(0,l-k),$=[a.a[0]+d*(w-x/2),a.a[1]+u*(w-x/2)],M=[a.a[0]+d*(k+S/2),a.a[1]+u*(k+S/2)];let R=180*Math.atan2(h,c)/Math.PI;R>=90?R-=180:R<-90&&(R+=180);const C=Math.abs(m-f)<=1e-9;return{candidate:{presetRevision:e.preset.revision,geometryRevision:e.geometryRevision,pointer:[e.pointer[0],e.pointer[1]],type:e.preset.type,lengthCm:e.preset.lengthCm,flipH:e.preset.flipH,flipV:e.preset.flipV,x:v,y:y,angle:R,renderedLength:e.renderedLength,target:a,...a.partitionHost?{host:{...a.partitionHost,t:l>0?m/l:0}}:{},measure:{labels:[{distance:x,midpoint:$},{distance:S,midpoint:M}],guide:C?{x:v,y:y,angle:R}:null}},jambBlockedTarget:null}}function Xf(e,t,i,n,r=1e-6){return e.presetRevision===i&&e.geometryRevision===n&&Math.hypot(e.pointer[0]-t[0],e.pointer[1]-t[1])<=r}function Zf(e){return!(!e.canEdit||e.kiosk||e.fixedFloor)&&("view"!==e.mode&&("mouse"===e.pointerType&&e.spaceCount>1))}class Jf{constructor(e,t,i){this.loader=e,this.host=t,this.adopted=i,this.attachment=null}connect(){if(this.runtime)return void this.runtime.connect();this.attachment?.cancel();const e=this.loader.attach(this.host,e=>this.adopt(e));this.runtime||(this.attachment=e)}disconnect(){this.attachment?.cancel(),this.attachment=null,this.runtime?.disconnect()}adopt(e){this.attachment=null,this.runtime||(this.runtime=e,this.adopted(e))}}const Qf=new class{constructor(e){this.load=e,this.factory=null,this.pending=null}get warm(){return null!==this.factory}create(e){return this.factory?this.factory(e):null}attach(e,t){let i=!0;const n={cancel:()=>{i=!1}},r=this.create(e);return r?(t(r),n):(this.ensure().then(n=>{i&&t(n(e))},()=>{}),n)}ensure(){return this.factory?Promise.resolve(this.factory):(this.pending||(this.pending=this.load().then(e=>(this.factory=e,this.pending=null,e),e=>{throw this.pending=null,e})),this.pending)}reset(){this.factory=null,this.pending=null}}(()=>import("./summary-panel-runtime-loaded-CX2cplA1.js").then(function(e){return e.e}).then(({LoadedSummaryPanelRuntime:e})=>t=>new e(t)));function ev(e){const t=globalThis.__HP_VERSION_OVERRIDE__;return"string"==typeof t&&t.length>0?t:e}let tv=0;const iv="1.77.0-beta.2",nv="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32",rv=1500,ov=new Map;let sv=0,av=1e4;const lv="houseplan_card_layout_v1",cv="houseplan_card_cfg_v1",hv="houseplan_card_zoom_v1",dv="houseplan_card_nav_v1",uv="houseplan_card_view_v1",pv="hp-dialog, hp-help, hp-color-opacity, hp-device-preview",_v=1e3,mv=(e,t)=>{const i=Math.min(e.x,t.x),n=Math.min(e.y,t.y);return{x:i,y:n,w:Math.max(e.x+e.w,t.x+t.w)-i,h:Math.max(e.y+e.h,t.y+t.h)-n}},gv=(e,t,i)=>{const n=new Event(t,{bubbles:!0,composed:!0});n.detail=i??{},e.dispatchEvent(n)},fv=e=>{history.pushState(null,"",e),gv(window,"location-changed",{replace:!1})},vv=(e,t)=>{let i,n=null;const r=(...r)=>{clearTimeout(i),n=r,i=window.setTimeout(()=>{i=void 0;const t=n;n=null,t&&e(...t)},t)};return r.flush=()=>{if(void 0===i)return;clearTimeout(i),i=void 0;const t=n;n=null,t&&e(...t)},r.cancel=()=>{clearTimeout(i),i=void 0,n=null},r.pending=()=>void 0!==i,r},yv=e=>{try{e.target?.setPointerCapture?.(e.pointerId)}catch{}},bv=["edges","corners"];class wv extends he{constructor(){var e;super(...arguments),this._editorRuntime=null,this._liveRt=null,this._onboardingRuntime=null,this._editorRuntimeLoadingVisible=!1,this._backdropGuard=null,this._editorModeRequest=0,this._warmModeRequest=0,this._editorRuntimeLoader=new Sf({expectedFingerprint:nv,load:async e=>{const t=0===e?await import("./houseplan-editor-runtime-AzCVhtuX.js"):await import((()=>{const e=new URL("./houseplan-editor-runtime-AzCVhtuX.js",import.meta.url);return e.searchParams.set("hp_retry",`${iv}-${++tv}`),e.href})());return{fingerprint:t.EDITOR_RUNTIME_FINGERPRINT,create:()=>new t.HouseplanEditorRuntime(this)}},install:e=>{this._editorRuntime=e},stateChanged:e=>this._editorRuntimeStateChanged(e),failed:(e,t)=>{console.error("[houseplan] unable to load editor runtime",e),t.terminal&&this._versionRecovery.hasCurrentMismatchNotice||this._showToast(kf(e=>this._t(e),t))}}),this._onboardingRuntimeLoader=new Sf({expectedFingerprint:nv,load:async e=>{const t=0===e?await import("./houseplan-onboarding-runtime-Dp2b84fm.js"):await import((()=>{const e=new URL("./houseplan-onboarding-runtime-Dp2b84fm.js",import.meta.url);return e.searchParams.set("hp_retry",`${iv}-${++tv}`),e.href})());return{fingerprint:t.ONBOARDING_RUNTIME_FINGERPRINT,create:()=>new t.HouseplanOnboardingRuntime(this)}},install:e=>{this._onboardingRuntime=e},failed:(e,t)=>{console.error("[houseplan] unable to load onboarding runtime",e),t.terminal&&this._versionRecovery.hasCurrentMismatchNotice||this._showToast(kf(e=>this._t(e),t))}}),this._isoSceneRuntime=null,this._isoSceneRuntimeLoader=new Sf({expectedFingerprint:nv,load:async e=>{const t=0===e?await import("./iso-scene-render-fYqz_-Ot.js"):await import((()=>{const e=new URL("./iso-scene-render-fYqz_-Ot.js",import.meta.url);return e.searchParams.set("hp_retry",`${iv}-${++tv}`),e.href})());return{fingerprint:t.ISO_SCENE_RUNTIME_FINGERPRINT,create:()=>t}},install:e=>{const t=this._effectiveProjection();this._isoSceneRuntime=e,this._isoProjectionSnapshot=null;const i=this._effectiveProjection();this._convertProjectionView(t,i),this.isConnected&&this.requestUpdate()},failed:(e,t)=>{console.warn("[houseplan] hidden isometric runtime diagnostic",wf("runtime-load","unverified",t.terminal)),this.isConnected&&this.requestUpdate()}}),this._pdfRuntime=null,this._pdfRuntimeLoader=new Sf({expectedFingerprint:nv,load:async e=>{const t=0===e?await import("./pdf-export-D3vmqIY6.js"):await import((()=>{const e=new URL("./pdf-export-D3vmqIY6.js",import.meta.url);return e.searchParams.set("hp_retry",`${iv}-${++tv}`),e.href})());return{fingerprint:t.PDF_EXPORT_FINGERPRINT,create:()=>new t.PdfExportRuntime}},install:e=>{this._pdfRuntime=e,this.isConnected&&this.requestUpdate()},failed:(e,t)=>{if(console.error("[houseplan] unable to load PDF export runtime",e),!t.terminal||!this._versionRecovery.hasCurrentMismatchNotice){const e=kf(e=>this._t(e),t),i=this._t("editor.load_failed"),n=e.startsWith(i)?e.slice(i.length).trim():e;this._showToast(`${this._t("pdf.failed")} ${n}`.trim())}}}),this.panelHost=!1,this.narrow=null,this._space="f1",this._adoption=new qu((e,t)=>this.requestUpdate(e,t)),this._serverStorage=!1,this._loadOk=!1,this._serverCanWrite=null,this._loading=!1,this._loadTries=0,this._unsubCfg=null,this._unsubLayout=null,this._unsubVirtual=null,this._liveSyncAttempt=null,this._liveSyncGeneration=0,this._liveSyncConnection=null,this._configReloadAuthority=new Gu,this._virtualLights=Hh(null),this._canOptimizeUndo=!1,this._undoKind=null,this._devices=[],this._regSignature="",this._defPos={},this._newSyncKey="",this._areaRelocationIds=new Set,this._areaSnapshotCleanupCandidates=new Map,this._areaRelocationSyncKey="",this._areaRelocationWrite=Promise.resolve(),this._tip=null,this._hoverRoom=null,this._pointerModality=new sg(this,()=>this._syncPointerHoverTargets()),this._devicePressAnimations=new Map,this._selId=null,this._toast="",this._mode="view",this._pendingNavMode=null,this._decorTool="select",this._decorStyle={...Cr},this._decorStyleSeeded=!1,this._decorDraft=null,this._decorMove=null,this._decorSel=null,this._decorEraseConfirm=null,this._decorTextDialog=null,this._decorShapeDialog=null,this._backdropDialog=null,this._decorTextSelection={start:0,end:0},this._furnPalette=null,this._decorImagePalette=null,this._decorAssetCatalog=[],this._decorAssets=new Map,this._decorAssetBusy=!1,this._furnCategory=null,this._furnPreviewInput=null,this._furnTouchPending=null,this._dtBox=null,this._dtDrag=null,this._bdDrag=null,this._slide="",this._reducedMotion=!1,this._onMotionChange=e=>{this._reducedMotion=e.matches,this._cancelDevicePressFeedback(),e.matches&&this._cancelCameraTransition(!0),e.matches&&this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:e.matches&&this._modeTransition.active&&this._cancelModeTransition(!0),this._syncVersionRecovery(),this.requestUpdate()},this._editorChromeMode="plan",this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest=0,this._modeTransitionTargetZoom=1,this._modeTransitionEditorCamera=null,this._modeTransition=new Ug({frame:e=>this._applyModeTransitionFrame(e),settled:e=>this._settleModeTransition(e)}),this._cameraTransitionFit=null,this._cameraTransition=new Qg({frame:e=>this._applyCameraTransitionFrame(e),settled:e=>this._settleCameraTransition(e)}),this._editorSecondaryCopy={groupActive:(e,t)=>this._t("editor.group_active",{group:e,item:t}),openGroup:e=>this._t("editor.open_group",{group:e}),disabledAction:(e,t)=>this._t("editor.disabled_action",{action:e,reason:t})},this._tool="draw",this._geometryHistory=new gg(50),this._devicePositionHistory=new gg(50),this._devicePositionBusy=!1,this._wallDialog=null,this._drawWallField=null,this._activeWallChainId=null,this._activeWallChainPartitionIds=[],this._wallChainRedo=[],this._physicalSel=null,this._physicalDialog=null,this._partitionDeleteDialog=null,this._roomDeleteDialog=null,this._physicalDrag=null,this._physicalRotate=null,this._physicalLastTap=null,this._physicalPickCycle=null,this._wallUnionCacheValue=null,this._wallUnionPool=new Map,this._isoGeometryCache=new Map,this._renderIsoScene=null,this._isoProjectionSnapshot=null,this._isoStructuralBuildCount=0,this._isoFallback=new Set,this._openingTunnelCache=null,this._openingWallIndexCache=new Map,this._openingPlacementIntervalsCache=null,this._openingDimensionContextCache=null,this._planSnapGeometryCache=null,this._planStructuralGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._physicalBodiesCache=null,this._lightPhysicalBodiesCache=null,this._cleanFloorCache=new Map,this._innerContourCache=new Map,this._glowRuntimeState=bm(),this._glowRuntimeHost={window:()=>this.ownerDocument.defaultView||window,isConnected:()=>this.isConnected,requestUpdate:()=>this.requestUpdate(),reducedMotion:()=>this._reducedMotion},this._lightBarrierCache=null,this._lightBarrierPool=new Map,this._glowScreenBlend=!1,this._duplicateColumnId=null,this._duplicateColumnTimer=0,this._rszLimitViolation=null,this._path=[],this._cursorPt=null,this._planSnapHover=null,this._mergeSel=null,this._openingPreset=null,this._openingRebindId=null,this._openingPresetRevision=0,this._openingHoverCandidate=null,this._openingJambBlockCm=null,this._openingDialog=null,this._openingInfo=null,this._opDrag=null,this._opMeasure=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._wallFaceBatch=null,this._wallRepairDiagnostic=null,this._wallFaceGraphCache=[],this._areaSel="",this._nameSel="",this._roomDialog=!1,this._roomEditId=null,this._roomFill="",this._roomCustomFill=null,this._roomTempMin="",this._roomTempMax="",this._roomTempSrc="",this._roomHumSrc="",this._roomSrcOpen=null,this._roomSrcFilter="",this._roomNameScale=1,this._roomLabelScale=1,this._zoom=1,this._view=null,this._zoomBySpace={},this._viewModeSnap=null,this._roomFocus=null,this._roomPointer=null,this._doubleFit=new ff,this._deviceHits=new wc,this._pointers=new Map,this._panStart=null,this._panLock=null,this._pinchStart=null,this._safeDayCycleOutline=!1,this._suppressClick=!1,this._viewportGestureDirty=!1,this._touchContacts=new Map,this._touchClickGuard=new pc,this._connectedPath="",this._routeDepartureHandled=!1,this._onLocationChanged=()=>{this._connectedPath&&location.pathname!==this._connectedPath?this._leaveCardRoute():location.pathname===this._connectedPath&&(this._routeDepartureHandled=!1)},this._touchGestureGuard={capture:!0,handleEvent:e=>this._guardTouchGesture(e)},this._hdrH=118,this._booting=!0,this._bootFading=!1,this._bootSettling=!1,this._bootSettleRaf=0,this._bootLastH=-1,this._bootStart=0,this._bootLastChange=0,this._bootSoft=!1,this._tapConfirm=null,this._dangerConfirm=null,this._dangerConfirmController=new ze(e=>{this._dangerConfirm=e}),this._confirmDanger=e=>this._config&&this.hass?"warm"===this._syncDangerConfirmLocaleGate()||this._dangerConfirmMissingSpace()?Promise.resolve(!1):this._dangerConfirmController.confirm(e):Promise.resolve(!1),this._cancelDangerConfirm=()=>{this._dangerConfirmController.cancel()},this._onDangerConfirmDecision=e=>{this._dangerConfirmController.resolve(e.detail.token,e.detail.accepted)},this._onboardingShown=!1,this._rulesDialog=null,this._preflightClipboardFallback=null,this._haIntegrationVersion=null,this._versionRecovery=(e=this,new wg({clock:{setTimeout:(e,t)=>window.setTimeout(e,t),clearTimeout:e=>window.clearTimeout(e)},storage:()=>e.ownerDocument.defaultView?.sessionStorage??null,safety:()=>Sg(e),reload:()=>e._reloadDocument(),changed:()=>{e.requestUpdate()}})),this._haSupportApi=null,this._haDecorAssetsApi=null,this._haSummaryPanelApi=null,this._haRadarStage1Api=null,this._radarLive=new Ag(this),this._decorAssetSyncToken=0,this._alignDialog=null,this._settingsDialog=null,this._pdfDialog=!1,this._supportDialog=null,this._backupExportDialog=null,this._backupImportDialog=null,this._sunRaysCache=null,this._dayCycleTimer=0,this._dayCycleClockKey="",this._compassDrag=!1,this._importDialog=null,this._importQueue=[],this._importTotal=0,this._rulesCompiledSrc="",this._infoCard=null,this._nativeMoreInfoEntity=null,this._deviceInbox=null,this._deviceInboxReturn=null,this._deviceInboxMemo=null,this._markerDialog=null,this._spaceDialog=null,this._keyHandler=e=>this._onKey(e),this._warmVp=null,this._warmVpArmed=!1,this._warmLongReturn=!1,this._warmRevivePending=!1,this._warmGen=++sv,this._warmKey=null,this._warmSlot=null,this._hashApplied=!1,this._navApplied=!1,this._labs={alpha:!1,active:Object.freeze([]),space:""},this._viewPreference={},this._renderProjection="flat",this._kioskScale={icon:1,font:1},this._kioskDialog=!1,this._summarySlot=new Jf(Qf,this,e=>{this._summary=e,this._capturedSnapshotSequence=-1,this.isConnected&&(e.connect(),this.hasUpdated&&this.requestUpdate())}),this._activityRt=new Map,this._vacRt=new Map,this._vacViewKey="",this._vacLastView=null,this._vacRaf=0,this._vacSrvTrails={},this._vacJumpOnce=!1,this._continuity=this._newContinuityController(),this._continuityHistory=[],this._continuityEpoch=0,this._continuityDataReady=!0,this._continuityPaintToken=-1,this._continuityDisposed=!1,this._renderSnapshotAt=Date.now(),this._hassSequence=0,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotSequence=-1,this._capturedSnapshotDevices=null,this._capturedSnapshotLayout=null,this._capturedSnapshotActivity="",this._capturedSnapshotConfigEpoch=-1,this._capturedSnapshotVirtual="",this._lastValidStageSize=null,this._pendingRefitSize=null,this._refitRaf=0,this._pageVisibility=e=>{if(this._continuity.visibility(e),this._dayCycleVisibility(e),this._summary?.visibility(e.kind),"hidden"===e.kind)return this._radarLive.stop(),this._editorRuntime?._cancelRadarSetup(),this._clearRoomFocus(!0),this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._cancelCameraTransition(!0),void(this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:this._cancelModeTransition(!0));if(this._vacJumpOnce=!0,this._syncRadarLive(),!e.long){const e=Date.now();let t=!1;for(const i of this._activityRt.values())!i.flashKind||(i.expiresAt||i.flashTs+tg)>e||(i.flashTs=0,i.flashKind=null,i.expiresAt=0,t=!0);return void(t&&this.requestUpdate())}Date.now()-this._renderSnapshotAt>1e3&&this._continuity.note("device-snapshot-stale"),this._continuityDataReady=!1,this._continuityPaintToken=-1,this._resumeSettling=!0,this._loading?this.requestUpdate():this._loadFromServer()},this._resumeSettling=!1,this._viewportInvalidAt=0,this._vacFit=null,this._vacAllCamerasFor=null,this._vacAllCameraCache=null,this._vacCalConfirm=null,this._kioskDots=!1,this._cyclePausedUntil=0,this._swipeStart=null,this._tabDrag=null,this._tabDragRelease=null,this._tabSuppressClick=!1,this._tabOrderWarned=!1,this._onLabsSnapshot=e=>{const t=this._effectiveProjection();this._labs=e,this._isoProjectionSnapshot=null,this._labsIso&&this._ensureIsoSceneRuntime();const i=this._effectiveProjection();this._convertProjectionView(t,i),this.requestUpdate()},this._onHashChange=()=>{if(this._hasFixedFloor)return;const e=this._hashSpace();if(e&&this._model.find(t=>t.id===e)&&e!==this._space){if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return;this._commitSpace(e),this._selId=null,this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeWallChainId=null,this._activeWallChainPartitionIds=[],this._wallChainSegmentCms=[],this._closingWallCm=null,this._restoreZoom(),this.requestUpdate()}},this._drag=null,this._deviceDrag=null,this._rlResize=null,this._holdFired=!1,this._retryContinuity=()=>{this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.retry(this._continuity.recoveryReason||"plan"),this._loading||this._loadFromServer()},this._cfgEpoch=0,this._cfgEpochPreservedConfig=null,this._terminalFrame=0,this._modelCache=null,this._emptySpaceStateActive=!1,this._decorSnapCache=null,this._markerPreviewMemo=null,this._markerPreviewDevicesMemo=null,this._showHidden=!1,this._connHooked=null,this._connectionWasLost=!1,this._haRegistryConnection=null,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._renderLife=new $g,this._liveEditorPaintCount=0,this._onHaRegistryUpdate=()=>{const e=nd(this.hass);e.revision===this._haRegistryRev&&this._devices.length||(this._haRegistryRev=e.revision,this._renderLife.invalidate(),this._planHassMemo=null,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate())},this._onConnReady=()=>{if(this._loadTries=0,clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,id(this.hass),this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(this._onConnReady,400));!this._connectionWasLost&&this._continuity.hasCompleteFrame?this._beginContinuityCandidate("connection-ready",!1,"plan"):(this._continuityDataReady=!1,this._continuityPaintToken=-1),this._loading||this._loadFromServer()},this._onConnLost=()=>{this._booting&&!this._continuity.hasCompleteFrame||(this._connectionWasLost=!0,this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.connectionLost())},this._signer=new uc(()=>this.requestUpdate()),this._dirtyPos=new Set,this._sentPos=new Map,this._persistLayout=vv(()=>{if(this._serverStorage){const e=[...this._dirtyPos];this._dirtyPos.clear();for(const t of e){const e=xo(this._layout[t]);e&&(this._layout={...this._layout,[t]:e},this._sentPos.set(t,e),this.hass.callWS({type:"houseplan/layout/update",device_id:t,pos:e}).then(e=>this._noteLayoutRev(e)).catch(e=>this._showToast(this._t("toast.pos_save_failed",{err:this._errText(e)}))).finally(()=>{this._sentPos.get(t)===e&&this._sentPos.delete(t)}))}this._cacheSnapshot()}else this._persistLocalLayout()},600),this._frame=null,this._showFar=!1,this._writesPending=0,this._writeChain=Promise.resolve(),this._pendingPhysicalWrites=new Map,this._undoGeometry=()=>this._editorRuntimeOrThrow()._undoGeometry(),this._redoGeometry=()=>this._editorRuntimeOrThrow()._redoGeometry(),this._saveConfigDebounced=vv(()=>{this._serverCfg&&this._writeConfig().catch(e=>{const t=!0===e?.physicalGeometryRolledBack;"geometry-unsafe"!==e?.code&&("wall_model_client_outdated"===e?.code?this._showToast(this._t("toast.wall_model_client_outdated")):"conflict"===e?.code?(this._showToast(this._t("toast.conflict")),t||(this._cancelPath(),this._reloadConfigOnly(!0))):this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(e)})),t&&this._reloadRejectedPhysicalWrite())})},500),this._wallChainSegmentCms=[],this._closingWallCm=null,this._savePhysicalDialog=()=>this._editorRuntimeOrThrow()._savePhysicalDialog(),this._deletePhysicalSelection=()=>this._editorRuntimeOrThrow()._deletePhysicalSelection(),this._confirmPartitionDelete=()=>this._editorRuntimeOrThrow()._confirmPartitionDelete(),this._confirmRoomDelete=e=>this._editorRuntimeOrThrow()._confirmRoomDelete(e),this._rebindPartitionOpening=()=>this._editorRuntimeOrThrow()._rebindPartitionOpening(),this._keepClosedAsPartitions=()=>this._editorRuntimeOrThrow()._keepClosedAsPartitions(),this._toggleServerPlans=async()=>this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._toggleServerPlans():this._editorRuntimeOrThrow()._toggleServerPlans(),this._aspectJob=null,this._dayCycleTick=()=>{if(!this.isConnected||"hidden"===this.ownerDocument.visibilityState)return;const e=this._dayCycleState();if(!e)return this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),void(this._dayCycleClockKey="");const t=cr(e);t!==this._dayCycleClockKey&&(this._dayCycleClockKey=t,this.requestUpdate())},this._sunShown=!1,this._sunOut=!1,this._sunOutTimer=0,this._openSettingsDialog=()=>{if(this._editorRuntime)return this._editorRuntime._openSettingsDialog();this._ensureEditorRuntime().then(e=>{e&&this._openSettingsDialog()})},this._openSupportDialog=()=>{this._editorRuntime?this._editorRuntime._openSupportDialog():this._ensureEditorRuntime().then(e=>{e&&this._openSupportDialog()})},this._openPdfDialog=()=>{this._pdfRuntimeLoader.ensure().then(e=>{e&&(this._pdfDialog=!0,this.requestUpdate())})},this._reportedPreflightFingerprint=null,this._openAlignDialog=()=>this._editorRuntimeOrThrow()._openAlignDialog(),this._toggleOptimizeLivePositions=()=>this._editorRuntimeOrThrow()._toggleOptimizeLivePositions(),this._optimizeUndoBusy=!1,this._openBackupExport=()=>this._editorRuntimeOrThrow()._openBackupExport(),this._openRulesDialog=()=>this._editorRuntimeOrThrow()._openRulesDialog(),this._climateCache=null,this._gearPtCache=new WeakMap}requestUpdate(e,t,i){if("hass"===e&&this.hass&&this._liveRt){const e=this._visibleDeviceSnapshot||this._candidateDeviceSnapshot;if(!this._liveRt.hass(t,this.hass,e?{entityIds:e.entityIds}:null,()=>Mg(this))&&!this._summary?.observeHassComposition())return}void 0!==e&&(this._terminalFrame=0),this._editorRuntime?._routeLiveEditorUpdate(e,t)||(this._liveRt?.clear(),super.requestUpdate(e,t,i))}_editorRuntimeOrThrow(){if(!this._editorRuntime)throw new Error("Houseplan editor runtime is not loaded");return this._editorRuntime}async _ensureEditorRuntime(){return this._editorRuntimeLoader.ensure()}async _ensureOnboardingRuntime(){return this._onboardingRuntimeLoader.ensure()}async _ensureIsoSceneRuntime(){return this._isoSceneRuntimeLoader.ensure()}_editorRuntimeStateChanged(e){clearTimeout(this._editorRuntimeLoadingTimer),this._editorRuntimeLoadingTimer=void 0,"loading"!==e?(this._editorRuntimeLoadingVisible=!1,this.requestUpdate()):this._editorRuntimeLoadingTimer=window.setTimeout(()=>{this._editorRuntimeLoadingVisible=!0,this.requestUpdate()},150)}async _requestMode(e,t=!0,i=!1){const n=++this._editorModeRequest;if(i&&(this._warmModeRequest=n,this._refitRaf&&(cancelAnimationFrame(this._refitRaf),this._refitRaf=0),this._pendingRefitSize=null),"view"===e||await this._ensureEditorRuntime()){if(n===this._editorModeRequest&&this.isConnected)return i?(this._adoptMode(e),this._warmRevivePending&&(clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmReviveDialog()),this.requestUpdate(),void this.updateComplete.then(()=>requestAnimationFrame(()=>requestAnimationFrame(()=>{if(this._warmModeRequest!==n||n!==this._editorModeRequest)return;const e=this._stageEl;this._lastValidStageSize=e&&e.clientWidth>0&&e.clientHeight>0?[e.clientWidth,e.clientHeight]:null,this._pendingRefitSize=null,this._warmModeRequest=0})))):void this._setMode(e,t);this._warmModeRequest===n&&(this._warmModeRequest=0)}else this._warmModeRequest===n&&(this._warmModeRequest=0)}get _layout(){return this._adoption.layout}set _layout(e){this._adoption.stageLocalLayout(e)}get _layoutRev(){return this._adoption.layoutRev}set _layoutRev(e){this._adoption.seedIdentity({layoutRev:e})}get _layoutContentFingerprint(){return this._adoption.layoutFingerprint}set _layoutContentFingerprint(e){this._adoption.seedIdentity({layoutFingerprint:e})}get _serverCfg(){return this._adoption.config}set _serverCfg(e){this._adoption.stageLocalConfig(e)}get _cfgRev(){return this._adoption.configRev}set _cfgRev(e){this._adoption.seedIdentity({configRev:e})}get _cfgContentFingerprint(){return this._adoption.configFingerprint}set _cfgContentFingerprint(e){this._adoption.seedIdentity({configFingerprint:e})}_seedDecorStyle(e){var t,i;if(t=Ol,i=this,Fl(e,Bl)&&"pending"===t.state()&&(t.art("",i),t.ensure()),this._decorStyleSeeded||!e)return;this._decorStyleSeeded=!0;const n=e.settings?.decor_default_style;n&&(this._decorStyle=function(e,t){if(!e||"object"!=typeof e)return{...t};const i=e,n="string"==typeof i.color&&i.color?i.color:t.color,r="string"==typeof i.fill_color&&i.fill_color?i.fill_color:t.fillColor,o=Number(i.width_cm);return{color:n,opacity:Tr(i.opacity,t.opacity),widthCm:Number.isFinite(o)&&o>0?Math.max(.1,Math.min(100,o)):t.widthCm,fill:"boolean"==typeof i.fill?i.fill:t.fill,fillColor:r,fillOpacity:Tr(i.fill_opacity,t.fillOpacity)}}(n,Cr))}get _canManageConfiguration(){return null!==this._serverCanWrite?this._serverCanWrite:!0===this.hass?.user?.is_admin}get _canEdit(){return this._norm&&this._canManageConfiguration}get _kiosk(){return!!this._config?.kiosk}_showKioskDots(){this._kioskDots=!0,clearTimeout(this._kioskDotsTimer),this._kioskDotsTimer=window.setTimeout(()=>this._kioskDots=!1,2500)}get _modeTransitionBusy(){return this._modeTransitionPreparing||this._modeTransition.active}get _doubleFitEnabled(){return!("view"!==this._mode||this._vacFit||this._modeTransitionBusy||this._touchSequenceMultitouch||"steady"!==this._continuity.state||this._continuity.overlayBlocksInteraction)}_cameraState(){const e=this._viewOr(this._baseVb());return{zoom:this._zoom,viewBox:{...e}}}_normalizeCameraState(e){const t=this._cameraTransitionFit||Oi(this._baseVb(),this._stageAspect());return{zoom:Math.min(wv.ZOOM_MAX,Math.max(wv.ZOOM_MIN,e.zoom)),viewBox:this._clampView({...e.viewBox},t)}}_applyCameraTransitionFrame(e){const t=this._normalizeCameraState(e.presented);e.presented=t,this._zoom=t.zoom,this._view={...t.viewBox},this._liveVp(!0)}_settleCameraTransition(e){const t=this._normalizeCameraState(e.to);this._zoom=t.zoom,this._view={...t.viewBox},this._cameraTransitionFit=null,"room"!==e.reason&&this._saveZoom(),this.requestUpdate()}_cancelCameraTransition(e=!1,t=!1){const i=this._cameraTransition.state?.reason,n=t&&this._cameraTransition.active?this._cameraTransition.presented?.zoom:void 0;this._cameraTransition.cancel(e),this._cameraTransitionFit=null,void 0!==n&&"room"!==i&&this._saveZoom()}_prepareCameraCommand(){this._bootSoftCancel(),this._modeTransitionBusy&&this._cancelModeTransition(!0),"opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1))}_startCameraTransition(e,t,i,n){const r=this._cameraState(),o=this._cameraTransition.target;return(!o||!Xg(o,e))&&(Xg(r,e)?(this._cancelCameraTransition(!1),!1):(this._activateSafeDayCycleOutline(),this._cameraTransitionFit={...t},this._cameraTransition.start(r,e,i,this._reducedMotion?0:n),!0))}_cssColor(e,t){const i=String(e||"").trim();if(!i)return t;const n=document.createElement("span");n.style.cssText=`position:absolute;visibility:hidden;color:${i}`,this.renderRoot.append(n);const r=getComputedStyle(n).color||t;return n.remove(),r}_currentModeVisual(e=this._mode){const t=this._modeTransition.presented||this._modeTransitionVisual;if(t)return{...t,viewport:{...t.viewport,viewBox:{...t.viewport.viewBox}}};const i=this._stageEl;if(!i||i.clientWidth<=0||i.clientHeight<=0)return null;const n=this.renderRoot.querySelector(".editorchrome"),r=this._viewOr(this._baseVb()),o=this.renderRoot.querySelector(".hp-paper"),s=this.renderRoot.querySelector(".hp-backdrop"),a=this.renderRoot.querySelector(".zoomwrap"),l=a?getComputedStyle(a).filter:"",c=Number(/brightness\(([^)]+)\)/.exec(l)?.[1]);return{presentedMode:e,editorChromeHeight:"view"===e?0:n?.getBoundingClientRect().height||0,stageWidth:i.clientWidth,stageHeight:i.clientHeight,viewport:Bg(r,i.clientWidth),stageColor:getComputedStyle(i).backgroundColor||"rgb(255, 255, 255)",paperColor:o?getComputedStyle(o).fill:"rgb(255, 255, 255)",sceneBrightness:Number.isFinite(c)?c:1,architectureOpacity:"decor"===e?.35:1,backdropOpacity:s&&Number(getComputedStyle(s).opacity)||1,viewWeight:"view"===e?1:0,editorWeight:"view"===e?0:1,toolbarContentOpacity:"view"===e?0:1}}_viewForModeTarget(e,t,i,n,r){const o=Oi(this._baseVb(),n/r),s=Math.min(wv.ZOOM_MAX,Math.max(wv.ZOOM_MIN,e)),a=o.w/s,l=o.h/s,c=t??o.x+o.w/2,h=i??o.y+o.h/2;return this._clampView({x:c-a/2,y:h-l/2,w:a,h:l},o)}_targetStageColor(e){return"view"!==e?"rgb(255, 255, 255)":this._cssColor(this._stageBg(this._spaceDisplayForRender()),this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"))}_targetPaperColor(e){return"view"===e&&this._spaceModel()?.bg?this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"):"rgb(255, 255, 255)"}_targetBrightness(e){return 1}_applyModeTransitionFrame(e){e.targetMode===this._mode&&(this._modeTransitionVisual=e.presented,this._view={...e.presented.viewport.viewBox},this.requestUpdate())}_settleModeTransition(e){if(e.targetMode!==this._mode)return;const t=this._modeTransitionRequest;this._view={...e.to.viewport.viewBox},this._zoom=this._modeTransitionTargetZoom,this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._lastValidStageSize=[e.to.stageWidth,e.to.stageHeight],"view"===this._mode&&(this._saveZoom(),this._viewModeSnap=null,this._modeTransitionEditorCamera=null),this.requestUpdate(),this.updateComplete.then(()=>{if(!this.isConnected||t!==this._modeTransitionRequest||this._modeTransitionBusy||e.targetMode!==this._mode)return;const i=this._stageEl;if(i&&i.clientWidth>0&&i.clientHeight>0&&(Math.abs(i.clientWidth-e.to.stageWidth)>.5||Math.abs(i.clientHeight-e.to.stageHeight)>.5)){const e=this._view;this._lastValidStageSize=[i.clientWidth,i.clientHeight],this._applyView(this._zoom,e?e.x+e.w/2:void 0,e?e.y+e.h/2:void 0),this.requestUpdate()}const n=this.renderRoot.activeElement;(!n||!n.isConnected||!!n.closest?.(".editorchrome, .stage"))&&this.renderRoot.querySelector(".modetab.active")?.focus?.({preventScroll:!0})})}_cancelModeTransition(e=!0){this._cancelCameraTransition(!1);const t=!!this._modeTransition.state;this._modeTransitionRequest++,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransition.cancel(e),e&&t||(this._modeTransitionVisual=null)}_adoptMode(e){e!==this._mode&&(this._clearRoomFocus(!0),this._resetDeviceHitState()),this._cancelModeTransition(!1),this._mode=e,this._isoProjectionSnapshot=null,"view"!==e&&(this._editorChromeMode=e)}_commitViewModeAtomic(e,t,i,n){if(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this._zoom=t,e){const r=this._stageEl?.clientWidth||e.stageWidth,o=Math.max(1,e.stageHeight+e.editorChromeHeight);this._view=this._viewForModeTarget(t,i,n,r,o),this._lastValidStageSize=[r,o]}else this._view=null;this._viewModeSnap=null,this._modeTransitionEditorCamera=null,this._saveZoom(),this.requestUpdate()}_prepareModeTransition(e,t,i,n,r,o){this.updateComplete.then(()=>{if(!this.isConnected||e!==this._modeTransitionRequest||this._mode!==i)return void(e===this._modeTransitionRequest&&(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this.requestUpdate()));const s=this.renderRoot.querySelector(".editorchrome-inner"),a="view"===i?0:s?.scrollHeight||0,l=Math.max(1,(this.panelHost?this.clientHeight:innerHeight)-ef(this.renderRoot,this._stageEl,this.panelHost)),c=this._stageEl?.clientWidth||t.stageWidth,h=this._viewForModeTarget(n,r,o,c,l),d={presentedMode:i,editorChromeHeight:a,stageWidth:c,stageHeight:l,viewport:Bg(h,c),stageColor:this._targetStageColor(i),paperColor:this._targetPaperColor(i),sceneBrightness:this._targetBrightness(i),architectureOpacity:"decor"===i?.35:1,backdropOpacity:"decor"===i&&"backdrop"!==this._decorTool?.5:1,viewWeight:"view"===i?1:0,editorWeight:"view"===i?0:1,toolbarContentOpacity:"view"===i?0:1};this._modeTransitionPreparing=!1;const u=this._modeTransitionForceAtomic;this._modeTransitionForceAtomic=!1,this._modeTransition.start(t,d,i,this._reducedMotion||u?0:220)})}get _hasFixedFloor(){return!!this._config&&Object.prototype.hasOwnProperty.call(this._config,"floor")}_fixedFloorState(e=this._model,t=this._loadOk){const i=this._config?.floor,n=function(e){if(!e.hasFloor)return{kind:"absent"};const t=e.floor;if("string"==typeof t)return t.length?e.spaceIds.includes(t)?{kind:"valid",id:t,source:"id"}:{kind:"invalid",reason:"unknown-id",value:t}:{kind:"invalid",reason:"empty-id",value:t};if("number"==typeof t){if(!Number.isFinite(t))return{kind:"invalid",reason:"non-finite-index",value:t};if(!Number.isInteger(t))return{kind:"invalid",reason:"fractional-index",value:t};if(t<0)return{kind:"invalid",reason:"negative-index",value:t};const i=e.spaceIds[t];return void 0===i?{kind:"invalid",reason:"out-of-range-index",value:t}:{kind:"valid",id:i,source:"index"}}return{kind:"invalid",reason:"invalid-type",value:t}}({spaceIds:e.map(e=>e.id),hasFloor:this._hasFixedFloor,floor:i});return!this._hasFixedFloor||t?n:"number"==typeof i?"valid"===n.kind||"invalid"===n.kind&&"out-of-range-index"===n.reason?{kind:"pending",value:i}:n:"valid"===n.kind||"invalid"===n.kind&&"unknown-id"!==n.reason?n:{kind:"pending",value:i}}_canCommitSpace(e,t=!1){if(t||!this._hasFixedFloor)return!0;const i=this._fixedFloorState();return"valid"===i.kind&&i.id===e}_commitSpace(e,t=!1){return!!this._canCommitSpace(e,t)&&(e!==this._space&&(this._clearRoomFocus(!0),this._resetDeviceHitState(),this._cancelDangerConfirm(),this._cancelCameraTransition(!1),this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._editorRuntime?._clearFurniturePreview()),this._space=e,this._isoProjectionSnapshot=null,!0)}_slideTo(e,t){if(e===this._space)return!0;if(!this._canCommitSpace(e))return!1;if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return!1;this._cancelModeTransition(!0);const i=window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;return this._commitSpace(e),this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeWallChainId=null,this._activeWallChainPartitionIds=[],this._wallChainSegmentCms=[],this._closingWallCm=null,this._selId=null,this._physicalSel=null,this._editorSecondary?.closeForNavigation(),this._physicalDialog=null,this._physicalDrag=null,this._restoreZoom(),i||(this._slide=t,clearTimeout(this._slideTimer),this._slideTimer=window.setTimeout(()=>{this._slideTimer=void 0,this._slide="",this.requestUpdate()},190),this.requestUpdate()),!0}get _canReorderTabs(){return Zf({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:"mouse",spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})}_tabPointerDown(e,t){Zf({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:e.pointerType,spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})&&(yv(e),this._tabDragRelease=e=>this._tabPointerUp(e),window.addEventListener("pointerup",this._tabDragRelease),window.addEventListener("pointercancel",this._tabDragRelease),this._tabDrag={id:t,pointerId:e.pointerId,x:e.clientX,y:e.clientY,moved:!1,targetId:null,placement:null})}_tabDropTargetAt(e,t,i){const n=this._model.map(e=>e.id),r=n.indexOf(i);if(r<0)return null;const o=this.renderRoot.querySelectorAll('[data-hp="space-tab"]');for(const s of o){const o=s.dataset.id||"";if(!o||o===i)continue;const a=s.getBoundingClientRect();if(ea.right||ta.bottom)continue;const l=n.indexOf(o);return l<0?null:{targetId:o,placement:l=4)))return;var i,n;const r=this._tabDropTargetAt(e.clientX,e.clientY,t.id);t.moved&&t.targetId===r?.targetId&&t.placement===r?.placement||(this._tabDrag={...t,moved:!0,targetId:r?.targetId||null,placement:r?.placement||null})}_tabPointerUp(e){const t=this._tabDrag;if(t&&t.pointerId!==e.pointerId)return;const i="pointerup"===e.type&&t?.moved?this._tabDropTargetAt(e.clientX,e.clientY,t.id):null;"pointerup"===e.type&&t?.moved&&this._suppressNextTabClick(),this._endTabDrag(),t?.moved&&i&&this._commitTabOrder(t.id,i.targetId)}_endTabDrag(){this._tabDrag=null,this._tabDragRelease&&(window.removeEventListener("pointerup",this._tabDragRelease),window.removeEventListener("pointercancel",this._tabDragRelease),this._tabDragRelease=null)}_tabClick(e){if(this._tabSuppressClick)return this._tabSuppressClick=!1,clearTimeout(this._tabSuppressClickTimer),void(this._tabSuppressClickTimer=void 0);this._pickSpace(e)}_suppressNextTabClick(){this._tabSuppressClick=!0,clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=window.setTimeout(()=>{this._tabSuppressClick=!1,this._tabSuppressClickTimer=void 0},0)}_commitTabOrder(e,t){const i=this._serverCfg;if(!i||!this._canReorderTabs)return;const n=this._model.map(e=>e.id),r=function(e,t,i){const n=e.indexOf(t),r=e.indexOf(i);if(n<0||r<0||n===r)return e;const o=e.slice();return o.splice(n,1),o.splice(r,0,t),o}(n,e,t);if(r===n)return;const o=new Map(this._devices.map(e=>[String(e.id),String(e.area||"")])),s=function(e,t,i,n=()=>""){if(!i)return[];const r=[];for(const o of e){if(!o||!0===o.removed)continue;const e="string"==typeof o.id?o.id:"";if(!e)continue;if("string"==typeof o.space&&o.space)continue;const s=("string"==typeof o.area?o.area:"")||n(e)||"";s&&t[s]||r.push({id:e,space:i})}return r}(i.markers||[],Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),n[0]||"",e=>o.get(e)||"");if(s.length){const e=new Map(s.map(e=>[e.id,e.space]));for(const t of i.markers||[]){const i=e.get(String(t.id));i&&(t.space=i)}}i.spaces=function(e,t){const i=new Map(t.map((e,t)=>[e,t]));return e.map((e,t)=>({space:e,index:t})).sort((e,t)=>(i.get(String(e.space?.id))??Number.MAX_SAFE_INTEGER)-(i.get(String(t.space?.id))??Number.MAX_SAFE_INTEGER)||e.index-t.index).map(e=>e.space)}(i.spaces||[],r),this._saveConfig(),this._tabOrderWarned||(this._tabOrderWarned=!0,this._showToast(this._t("toast.space_order_changed")))}_pickSpace(e){if(this._endTabDrag(),e===this._space)return;const t=this._model.map(e=>e.id),i=t.indexOf(this._space),n=t.indexOf(e);this._navApplied=!0,this._showFar=!1,this._frame=null,this._slideTo(e,i>=0&&n0&&Date.now()>=this._cyclePausedUntil&&this._model.length>1&&this._zoom<=1.001){const e=this._model.map(e=>e.id),t=e.indexOf(this._space);this._slideTo(e[(t+1)%e.length],"left"),this._showKioskDots()}}_syncCycleTimer(){clearInterval(this._cycleTimer),this._cycleTimer=void 0,this.isConnected&&!this._hasFixedFloor&&this._config?.kiosk&&Number(this._config.cycle)>0&&(this._cycleTimer=window.setInterval(()=>this._cycleTick(),1e3*Number(this._config.cycle)))}get _editing(){return"plan"===this._mode||"devices"===this._mode||"decor"===this._mode}get _markup(){return"plan"===this._mode}get _wallUnionCache(){return this._wallUnionCacheValue}set _wallUnionCache(e){this._wallUnionCacheValue=e,null===e&&this._wallUnionPool.clear()}get _glowClipCache(){return this._glowRuntimeState.clipCache}get _glowGeometryWarnings(){return this._glowRuntimeState.geometryWarnings}get _glowFeatherUnits(){return this._glowRuntimeState.featherUnits}set _glowFeatherUnits(e){this._glowRuntimeState.featherUnits=e}get _glowRenderedSources(){return this._glowRuntimeState.renderedSources}get _glowLastAppearance(){return this._glowRuntimeState.lastAppearance}get _glowFeatherSuspendUntil(){return this._glowRuntimeState.featherSuspendUntil}set _glowFeatherSuspendUntil(e){this._glowRuntimeState.featherSuspendUntil=e}get _glowFeatherResumeTimer(){return this._glowRuntimeState.featherResumeTimer}set _glowFeatherResumeTimer(e){this._glowRuntimeState.featherResumeTimer=e}get _glowSourceSeq(){return this._glowRuntimeState.sourceSeq}set _glowSourceSeq(e){this._glowRuntimeState.sourceSeq=e}_activateSafeDayCycleOutline(){this._safeDayCycleOutline=!0,this._stageEl?.classList.add("hp-safe-daycycle-outline")}get _touchSequenceMultitouch(){return this._touchClickGuard.sequenceMultitouch}_syncDangerConfirmLocaleGate(){return this._config&&this.hass?dp(this,gp,kp(this.hass,this._config.language)):"ready"}_dangerConfirmMissingSpace(){const e=this._model;if(!e.length)return!1;const t=this._fixedFloorState(e);return"pending"!==t.kind&&"invalid"!==t.kind&&!this._spaceModel()}_syncVersionRecovery(){this._versionRecovery.update({frontendVersion:ev(iv),backendVersion:this._haIntegrationVersion,kiosk:!0===this._config?.kiosk,reducedMotion:this._reducedMotion})}_newContinuityController(){return new lc(()=>{this._resumeSettling="steady"!==this._continuity.state,this._continuityEpoch++,this.isConnected&&this.requestUpdate()})}get _labsIso(){return this._labs.active.includes("iso")}get _desiredProjection(){return"view"===this._mode&&this._labsIso&&"iso"===this._viewPreference[this._space]?"iso":"flat"}_saveViewPreference(){try{localStorage.setItem(uv,JSON.stringify(this._viewPreference))}catch{}}_logicalViewCenter(e){const t=this._view;if(!t)return null;const i=[t.x+t.w/2,t.y+t.h/2],n="iso"===e?cf(i):i;return{x:n[0],y:n[1]}}_convertProjectionView(e,t){if(e===t)return;this._clearRoomFocus(!0);const i=this._logicalViewCenter(e);this._view=null;const n=i?"iso"===t?lf([i.x,i.y],0):[i.x,i.y]:null;this._applyView(this._zoom,n?.[0],n?.[1]),this._warmPatch({vp:this._warmViewportState()}),this.requestUpdate()}_setProjection(e){if(!this._labsIso||"view"!==this._mode)return;const t=this._effectiveProjection();if(this._viewPreference={...this._viewPreference,[this._space]:e},"iso"===e){this._ensureIsoSceneRuntime();const e=this._isoSceneKey();e&&this._isoFallback.delete(e),this._isoFallback.delete(`${this._space}|no-borders`),this._clearIsoInvalidFallback()}this._saveViewPreference(),this._isoProjectionSnapshot=null;const i=this._effectiveProjection();this._convertProjectionView(t,i)}_hashSpace(){return Ff(window.location.hash||"")}connectedCallback(){this._connectedPath=location.pathname,this._routeDepartureHandled=!1,this._configReloadAuthority.observeContext(Vu(this)),window.addEventListener("location-changed",this._onLocationChanged),window.addEventListener("popstate",this._onLocationChanged),this._continuityDisposed&&(this._continuity=this._newContinuityController(),this._continuityDisposed=!1,this._continuityPaintToken=-1);const e=dg(this.ownerDocument);var t;void 0!==e&&(this._glowScreenBlend=e),this._continuityUnsub?.(),this._continuityUnsub=sc(this.ownerDocument,this._pageVisibility),this._languageFailureUnsub?.(),this._languageFailureUnsub=function(...e){return()=>{for(const t of e)t()}}((t=()=>{this._showToast(this._t("toast.locale_load_failed"))},mp.add(t),()=>mp.delete(t)),function(e){return Il.add(e),()=>{Il.delete(e)}}(()=>this._showToast(this._t("toast.furniture_art_load_failed")))),super.connectedCallback(),this._summarySlot.connect(),this._ensureLiveRuntime().catch(()=>this.requestUpdate()),this._pointerModality.connect(this.ownerDocument.defaultView);const i=this.ownerDocument.defaultView?.MutationObserver;i&&(this._pointerHoverObserver=new i(e=>{let t=!1;for(const i of e){for(const e of i.addedNodes)this._syncPointerHoverSubtree(e);const e=e=>{if(e.nodeType!==Node.ELEMENT_NODE)return!1;const t=e;return t.matches(".devlayer, .devlayer *")||!!t.querySelector?.(".devlayer")};(e(i.target)||[...i.addedNodes,...i.removedNodes].some(e))&&(t=!0)}t&&this._invalidateDeviceHitGeometry()}),this._pointerHoverObserver.observe(this.renderRoot,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["class","style","data-id"]})),this._motionMedia=window.matchMedia?.("(prefers-reduced-motion: reduce)"),this._reducedMotion=!!this._motionMedia?.matches,this._motionMedia?.addEventListener?.("change",this._onMotionChange),this._syncVersionRecovery(),this._versionRecovery.connect(),hg(this.ownerDocument).then(e=>{e!==this._glowScreenBlend&&(this._glowScreenBlend=e,this.isConnected&&this.requestUpdate())}),this.hass&&this._ensureHaRegistryAuthority(),window.addEventListener("keydown",this._keyHandler),this._signer.start(()=>this.hass,()=>this._referencedContentUrls()),this._syncCycleTimer(),window.addEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=function(e){Nf.add(e);const t=Bf();return"undefined"==typeof window&&e(t),()=>{Nf.delete(e)}}(this._onLabsSnapshot),this._labsIso&&this._ensureIsoSceneRuntime(),this._booting?this._bootWatch():this._bootFading&&(clearTimeout(this._bootTimer),this._bootTimer=window.setTimeout(()=>{this._bootFading=!1},220)),this._bootSoft&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},rv)),!this._loadOk&&this._serverCfg&&this.hass&&this._scheduleLoadRetry(),!this._warmSlot&&this._config&&this._warmAdopt(),this._loadOk&&this._ensureLiveSyncSubscriptions(),this._warmVp&&!this._warmRevivePending&&void 0===this._warmReviveTimer&&(this._warmRevivePending=!0,this._warmReviveTimer=window.setTimeout(()=>this._warmReviveDialog(),0)),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1,this.requestUpdate()}disconnectedCallback(){this._versionRecovery.disconnect(),this._configReloadAuthority.invalidateLifecycle(),this._liveRt?.dispose(),this._radarLive.stop(),this._editorRuntime?._disposeLiveEditor(),this._clearRoomFocus(!0),this._cancelDangerConfirm(),this._connectedPath&&location.pathname!==this._connectedPath&&this._leaveCardRoute(),window.removeEventListener("location-changed",this._onLocationChanged),window.removeEventListener("popstate",this._onLocationChanged),this._continuityUnsub?.(),this._continuityUnsub=void 0,this._languageFailureUnsub?.(),this._languageFailureUnsub=void 0,this._motionMedia?.removeEventListener?.("change",this._onMotionChange),this._motionMedia=void 0,this._vacRaf&&(cancelAnimationFrame(this._vacRaf),this._vacRaf=0),this._refitRaf&&(cancelAnimationFrame(this._refitRaf),this._refitRaf=0),this._warmModeRequest=0,this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),this._summarySlot.disconnect(),this._dayCycleClockKey="",this._bootSettleRaf&&(cancelAnimationFrame(this._bootSettleRaf),this._bootSettleRaf=0),this._bootSettling=!1;for(const e of this._activityRt.values())clearTimeout(e.timer);window.removeEventListener("keydown",this._keyHandler),this._endTabDrag(),clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=void 0,this._tabSuppressClick=!1,clearInterval(this._cycleTimer),clearTimeout(this._kioskDotsTimer),clearTimeout(this._kioskHoldTimer),clearTimeout(this._reloadRetry),clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),this._connHooked=null,this._haRegistryRelease?.(),this._haRegistryRelease=void 0,this._haRegistryConnection=null,this._signer.dispose(),clearTimeout(this._toastTimer),clearTimeout(this._slideTimer),clearTimeout(this._editorRuntimeLoadingTimer),this._editorRuntimeLoadingTimer=void 0,this._editorRuntimeLoadingVisible=!1,this._modeTransition.dispose(),this._cameraTransition.dispose(),this._cameraTransitionFit=null,this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest++,this._slideTimer=void 0,this._slide="",clearTimeout(this._bootTimer),this._bootTimer=void 0,clearTimeout(this._bootSoftTimer),this._saveConfigDebounced.flush(),this._cancelDeviceDrag(),window.removeEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=void 0,clearTimeout(this._holdTimer),this._roViewport?.disconnect(),this._roViewport=void 0,this._roHdr?.disconnect(),this._roHdr=void 0,this._onWinResize&&(window.removeEventListener("resize",this._onWinResize),this._onWinResize=void 0),this._unsubCfg&&(this._unsubCfg(),this._unsubCfg=null),this._unsubLayout&&(this._unsubLayout(),this._unsubLayout=null),this._unsubVirtual&&(this._unsubVirtual(),this._unsubVirtual=null),this._unsubTrail&&(this._unsubTrail(),this._unsubTrail=void 0),this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=null,clearTimeout(this._layoutSyncTimer),clearTimeout(this._duplicateColumnTimer),Fm(this._glowRuntimeState,this._glowRuntimeHost),this._warmSnapshot(),this._warmRevivePending=!1,clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmRelease(),this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._editorRuntime?._clearFurniturePreview(),this._editorRuntime?._furnShiftDetach(),this._touchContacts.clear(),this._touchClickGuard.reset(),this._resetDeviceHitState(),this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._pointerHoverObserver?.disconnect(),this._pointerHoverObserver=void 0,this._pointerModality.disconnect(),this._editorSecondary?.reset(),this._resumeSettling=!1,this._continuityHistory=[...this._continuityHistory,...this._continuity.trace].slice(-80),this._continuity.dispose(),this._continuityDisposed=!0,super.disconnectedCallback()}_onKey(e){if("Escape"===e.key&&this._vacFit){if(this._vacFit.busy)return;return this._vacFit=null,this._showToast(this._t("vac.cal_cancelled")),void e.stopPropagation()}if("Escape"===e.key){if(this._tapConfirm)return void(this._tapConfirm=null);if(this._vacCalConfirm)return void(this._vacCalConfirm.busy||(this._vacCalConfirm=null));if(this._decorEraseConfirm)return void(this._decorEraseConfirm=null);if(this._openingInfo)return void(this._openingInfo=null);if(this._infoCard)return void this._closeInfoCard();if(this._rulesDialog)return void(this._rulesDialog=null);if(this._alignDialog)return this._alignDialog=null,void(this._preflightClipboardFallback=null);if(this._backupImportDialog)return void(this._backupImportDialog=null);if(this._backupExportDialog)return void(this._backupExportDialog=null);if(this._pdfDialog)return void(this._pdfDialog=!1);if(this._supportDialog)return void this._editorRuntime?._closeSupportDialog();if(this._settingsDialog)return void(this._settingsDialog=null);if(this._summary?.closeDialogIfIdle())return;if(this._markerDialog)return void this._closeMarkerDialog();if(this._deviceInbox)return void(this._deviceInbox=null);if(this._openingDialog)return void(this._openingDialog=null);if(this._physicalDialog)return void(this._physicalDialog=null);if(this._backdropDialog)return void(this._backdropDialog=null);if(this._decorShapeDialog)return void(this._decorShapeDialog=null);if(this._decorTextDialog)return void(this._decorTextDialog=null);if(this._spaceDialog&&!this._roomDialog)return this._spaceDialog=null,this._importQueue=[],void(this._importTotal=0);if(this._editorSecondary?.hasOpenGroup)return e.preventDefault(),void this._editorSecondary?.closeGroup(!0)}const t=e.composedPath?.()||[e.target],i=t.some(e=>e?.matches?.('input, textarea, select, [contenteditable="true"]')),n=t.some(e=>e?.classList?.contains?.("editor-secondary")),r=e.ctrlKey||e.metaKey,o=e.key.toLowerCase(),s=/^[a-z]$/.test(o),a="z"===o||!s&&"KeyZ"===e.code,l="y"===o||!s&&"KeyY"===e.code,c=r&&(a&&e.shiftKey||l),h=r&&a&&!e.shiftKey;if("decor"===this._mode){if((h||c)&&i)return;if(c)return e.preventDefault(),void this._redoGeometry();if(h)return e.preventDefault(),this._decorDraft?void(this._decorDraft=null):this._decorMove||this._dtDrag||this._bdDrag?void this._cancelDecorGesture():void this._undoGeometry();if(("Delete"===e.key||"Backspace"===e.key)&&this._decorSel&&!i&&!n)return e.preventDefault(),void this._decorDeleteSel();const t="ArrowLeft"===e.key?[-this._gridPitch,0]:"ArrowRight"===e.key?[this._gridPitch,0]:"ArrowUp"===e.key?[0,-this._gridPitch]:"ArrowDown"===e.key?[0,this._gridPitch]:null;return!t||r||e.altKey||"select"!==this._decorTool||!this._decorSel||!this._decorList.some(e=>e.id===this._decorSel)||this._decorDraft||this._decorMove||this._dtDrag||this._bdDrag||i||n||this._editorSecondaryDialogBlocked?void("Escape"===e.key&&(e.preventDefault(),this._decorDraft?this._decorDraft=null:this._decorMove||this._dtDrag||this._bdDrag?this._cancelDecorGesture():"furniture"===this._decorTool?(this._editorRuntime?._clearFurniturePreview(),this._editorRuntime?._furnShiftDetach(),this._furnPalette=null,this._furnCategory=null,this._decorTool="select"):this._decorSel?this._decorSel=null:"select"!==this._decorTool?this._decorTool="select":this._setMode("view"))):(e.preventDefault(),void this._decorNudge(t[0],t[1]))}if("devices"===this._mode){if((h||c)&&i)return;return c?(e.preventDefault(),void this._redoDevicePosition()):h?(e.preventDefault(),void this._undoDevicePosition()):void("Escape"===e.key&&this._deviceDrag&&(e.preventDefault(),this._cancelDeviceDrag()))}if(this._markup&&(!h&&!c||!i)){if(("Delete"===e.key||"Backspace"===e.key)&&this._physicalSel&&!i&&!n)return e.preventDefault(),void this._deletePhysicalSelection();if(c)return e.preventDefault(),void this._redoGeometry();if(h)return e.preventDefault(),this._resize?.dragging?void this._rszCancelDrag():this._wallFaceBatch?(this._roomDialogCancel(),void(this._activeWallChainId&&this._path.length>1?this._undoActiveWallPoint():this._undoPoint())):"draw"===this._tool&&this._path.length?void(this._activeWallChainId&&this._path.length>1?this._undoActiveWallPoint():this._undoPoint()):"split"===this._tool&&this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},void(this._splitSel.pts.length||(this._cursorPt=null))):void this._undoGeometry();if("Escape"===e.key)return this._physicalDrag||this._physicalRotate?(e.preventDefault(),void this._cancelPhysicalGesture()):this._roomDialog?(e.preventDefault(),void this._roomDialogCancel()):"draw"===this._tool&&this._path.length?(e.preventDefault(),void this._finishWallChain()):this._physicalSel?(e.preventDefault(),void(this._physicalSel=null)):"resize"===this._tool?(e.preventDefault(),this._resize?.dragging?void this._rszCancelDrag():("exit-tool"===this._resize?.escapeIdle()&&(this._tool="draw"),void this.requestUpdate())):"split"===this._tool?(e.preventDefault(),void(this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},this._splitSel.pts.length||(this._cursorPt=null)):this._splitSel?this._splitSel=null:this._tool="draw")):"merge"===this._tool?(e.preventDefault(),void(this._mergeSel?this._mergeSel=null:this._tool="draw")):this._wallDialog?(e.preventDefault(),void(this._wallDialog=null)):void("opening"!==this._tool&&"wallthick"!==this._tool&&"delroom"!==this._tool&&"column"!==this._tool||(e.preventDefault(),"opening"===this._tool&&this._clearOpeningPlacement(!0),this._tool="draw"))}}_undoPoint(){if(this._path.length)return this._contourClosed?(this._path=this._path.slice(0,-1),void(this._closingWallCm=null)):void(this._activeWallChainPartitionIds.length&&this._path.length>1?this._undoActiveWallPoint():this._path=this._path.slice(0,-1))}_undoActiveWallPoint(){const e=[...this._activeWallChainPartitionIds],t=e[e.length-1],i=this._spaceModel()?.partitions.find(e=>e.id===t),n=this._path[0]?[...this._path[0]]:null,r=this._path.slice(0,-1).map(e=>[...e]),o=this._wallChainSegmentCms.slice(0,-1),s=this._geometryHistory.undo();if(!s)return this._activeWallChainPartitionIds=[],this._wallChainSegmentCms=[],this._wallChainRedo=[],void(this._path=n?[n]:[]);this._applyGeometryState(s.before,!0)?(this._activeWallChainId||=`chain-${Date.now().toString(36)}`,this._activeWallChainPartitionIds=e.slice(0,-1),this._path=r.length?r:n?[n]:[],this._wallChainSegmentCms=o,i&&this._wallChainRedo.push({id:i.id,point:[...i.b],cm:i.cm}),this._clearPlanSnapHover(),this._showToast(this._t("history.undone",{name:s.name}))):this._geometryHistory.clear()}static async getConfigElement(){return await import("./editor-C694OxAO.js"),document.createElement("houseplan-card-editor")}static getStubConfig(){return{type:"custom:houseplan-card"}}static _warmBootReset(e){for(const e of ov.values())for(const t of e)clearTimeout(t.evict);ov.clear(),av=e&&e>0?e:1e4}static _warmBootStats(){let e=0,t=0;const i=[];for(const n of ov.values())for(const r of n)e++,r.dlg&&(t++,i.push(r.dlg.kind));return{keys:ov.size,slots:e,dlgs:t,drafts:i}}setConfig(e){const t=this._config,i=!!t&&Object.prototype.hasOwnProperty.call(t,"floor");this._config={icon_size:2.5,show_temperature:!0,live_states:!0,show_signal:!0,...e};(i!==this._hasFixedFloor||t?.floor!==this._config.floor)&&(this._hashApplied=!1,this._navApplied=!1,this._warmVpArmed=!1),this._config.kiosk&&(this._booting=!1,this._bootFading=!1),!this._hasFixedFloor&&e.default_floor&&this._commitSpace(e.default_floor,!0);try{this._zoomBySpace=JSON.parse(localStorage.getItem(hv)||"{}")||{}}catch{this._zoomBySpace={}}try{const e=JSON.parse(localStorage.getItem(uv)||"{}")||{};this._viewPreference=Object.fromEntries(Object.entries(e).filter(e=>"flat"===e[1]||"iso"===e[1]))}catch{this._viewPreference={}}if(this._labs=Bf(),this.isConnected&&this._labsIso&&this._ensureIsoSceneRuntime(),!this._summary?.applyLocalScaleForCurrentIdentity())try{const e=JSON.parse(localStorage.getItem("houseplan_card_kiosk_v1")||"null");this._kioskScale={icon:jn(e?.icon),font:jn(e?.font)}}catch{}try{const e=JSON.parse(localStorage.getItem(cv)||"null");this._adoption.restoreCached(e)&&(this._seedDecorStyle(this._serverCfg),this._cfgEpoch++,this._virtualLights=Hh(e.virtual_lights,this._cfgRev),this._serverStorage=!0)}catch{}this._adoptInitialSpace(this._model,this._loadOk),"view"!==this._mode||this._view||(this._zoom=this._zoomBySpace[this._space]||1),this.isConnected&&(this._syncCycleTimer(),this._warmAdopt(),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1),this._syncVersionRecovery()}_warmAdopt(){if(this._config?.kiosk)return;const e=Cf(this._config);if(this._warmKey===e&&this._warmSlot)return;this._warmSlot&&this._warmRelease();const t=this.parentNode,i=this._warmIdx(t),n=ov.get(e);if(!n||!n.length)return;const r=n.find(e=>e.owner===this._warmGen);if(r)return this._warmLongReturn=!!r.freed&&Date.now()-r.freed>=nc,clearTimeout(r.evict),r.evict=0,r.freed=0,r.live=!0,this._warmSlot=r,this._warmKey=e,r.frameFingerprint&&this._continuity.adoptCompleteFrame(r.frameFingerprint),void(!this._devices.length&&r.devices?.length&&(this._devices=[...r.devices]));const{slot:o,sure:s}=((e,t,i,n)=>{const r=e=>{const t=!!i&&e.place?.deref()===i;return t&&e.idx===n?4:e.live?0:t?3:2};let o=null,s=0,a=0,l=null;for(const i of e){if(i.owner===t)continue;l=i;const e=r(i);e<=0||(e>s?(o=i,s=e,a=1):e===s&&a++)}return!o||a>1?{slot:o||l,sure:!1}:{slot:o,sure:!0}})(n,this._warmGen,t,i);o&&(this._warmLongReturn=!!o.freed&&Date.now()-o.freed>=nc,this._booting=!1,this._bootFading=!1,this._hdrH=o.hdrH,this._bootSoft=!0,this.isConnected&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},rv)),this._warmKey=e,s?(clearTimeout(o.evict),o.evict=0,o.owner=this._warmGen,o.place=t?new WeakRef(t):null,o.idx=i,o.live=!0,this._warmSlot=o,this._warmVp=o.vp,o.frameFingerprint&&this._continuity.adoptCompleteFrame(o.frameFingerprint),!this._devices.length&&o.devices?.length&&(this._devices=[...o.devices]),this._warmAdoptViewport(this._config)):(this._warmSlot={owner:this._warmGen,path:location.pathname,place:t?new WeakRef(t):null,idx:i,live:!0,hdrH:o.hdrH,stageH:o.stageH,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0},n.push(this._warmSlot),this._warmTrim(n)))}_warmIdx(e){const t=e?.children;if(!t)return-1;for(let e=0;e4;){const t=e.findIndex(e=>!e.live);if(t<0)break;clearTimeout(e[t].evict),e.splice(t,1)}}_warmScheduleEvict(e,t){if(clearTimeout(e.evict),!(e.dlg||e.vp&&"view"!==e.vp.mode))return;const i=e.freed,n=e.owner;e.evict=window.setTimeout(()=>{if(e.evict=0,e.freed!==i||e.owner!==n)return;var r;e.dlg=null,e.vp=(r=e.vp)&&"view"!==r.mode?{...r,mode:"view",zoom:r.snap?.space===r.space?r.snap.zoom:r.zoom,view:null,snap:null,tool:"draw",decorTool:"select",showHidden:!1,selId:null,rszSel:null,decorSel:null}:r,e.frameFingerprint="";const o=ov.get(t);if(!e.live&&o&&o.length>1){const t=o.indexOf(e);t>=0&&o.splice(t,1)}},av+250)}_warmAdoptViewport(e){const t=this._warmVp;if(!t||this._warmSlot?.path!==location.pathname)return void(this._warmVp=null);const i=this._fixedFloorState();if(this._hashApplied||!this._model.find(e=>e.id===t.space)||"valid"===i.kind&&i.id!==t.space||this._hasFixedFloor&&"valid"!==i.kind)return void(this._warmVp=null);this._commitSpace(t.space,!0),this._navApplied=!0;const n="view"!==t.mode&&this._canEdit&&!e.kiosk?t.mode:"view";this._adoptMode("view"),this._pendingNavMode="view"===t.mode||this._canEdit||e.kiosk?null:t.mode,this._zoom=t.zoom;const r=this._effectiveProjection(),o=r===t.projection&&this._labsIso===t.activeLabsIso;if(this._view=o&&t.view?{...t.view}:null,this._viewModeSnap=o&&t.snap?{...t.snap}:null,!o&&t.logicalCenter){const e="iso"===r?lf([t.logicalCenter.x,t.logicalCenter.y],0):[t.logicalCenter.x,t.logicalCenter.y];this._applyView(t.zoom,e[0],e[1])}var s;this._tool="opening"===(s=function(e){return"partition"===e?"draw":e}(s=t.tool))?"draw":"string"==typeof s&&Rf.has(s)?s:"draw",this._decorTool=t.decorTool,this._showHidden=t.showHidden,this._showFar!==t.showFar&&(this._showFar=t.showFar,this._frame=null),this._selId=t.selId,this._resize?.restoreSelection(t.rszSel),this._decorSel=t.decorSel,this._warmVpArmed=!0,"view"!==n&&this._requestMode(n,!1,!0)}_warmPatch(e,t=!1){if(this._config?.kiosk)return;const i=Cf(this._config);if(!this._warmSlot||this._warmKey===i){if(!this._warmSlot){if(!t)return;const e=this.parentNode;this._warmKey=i,this._warmSlot={owner:this._warmGen,path:location.pathname,place:e?new WeakRef(e):null,idx:this._warmIdx(e),live:!0,hdrH:this._hdrH,stageH:0,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0};const n=ov.get(i)||[];for(n.push(this._warmSlot),ov.set(i,n),this._warmTrim(n);ov.size>8;){const e=ov.keys().next().value;if(void 0===e||e===i)break;for(const t of ov.get(e)||[])clearTimeout(t.evict);ov.delete(e)}}Object.assign(this._warmSlot,e)}}_warmViewportState(){const e=this._effectiveProjection();return{space:this._space,mode:this._mode,projection:e,activeLabsIso:this._labsIso,logicalCenter:this._logicalViewCenter(e),zoom:this._zoom,view:this._view?{...this._view}:null,snap:this._viewModeSnap?{...this._viewModeSnap}:null,tool:this._tool,decorTool:this._decorTool,showHidden:this._showHidden,showFar:this._showFar,selId:this._selId,rszSel:this._resize?.selectedRoomId,decorSel:this._decorSel}}_warmDialogState(){const e=(e,t)=>({kind:e,space:this._space,mode:this._mode,data:t});return this._tapConfirm||this._alignDialog||this._mergeDialog||this._importDialog||this._backupExportDialog||this._backupImportDialog?null:this._openingInfo?e("openingInfo",this._openingInfo.id):this._infoCard?e("info",this._infoCard.id):this._rulesDialog?this._rulesDialog.busy?null:e("rules",this._rulesDialog):this._settingsDialog?this._settingsDialog.busy?null:e("settings",this._settingsDialog):this._markerDialog?this._markerDialog.busy?null:e("marker",this._markerDialog):this._openingDialog?e("opening",this._openingDialog):this._backdropDialog?e("backdrop",this._backdropDialog):this._decorShapeDialog?e("decorShape",this._decorShapeDialog):this._decorTextDialog?e("decorText",this._decorTextDialog):this._roomDialog?e("room",{editId:this._roomEditId,fill:this._roomFill,customFill:this._roomCustomFill,tempMin:this._roomTempMin,tempMax:this._roomTempMax,tempSrc:this._roomTempSrc,humSrc:this._roomHumSrc,srcOpen:this._roomSrcOpen,srcFilter:this._roomSrcFilter,nameScale:this._roomNameScale,labelScale:this._roomLabelScale,areaSel:this._areaSel,nameSel:this._nameSel,pendingSplit:this._pendingSplit,wallFaceBatch:this._wallFaceBatch,path:this._path}):this._spaceDialog?this._spaceDialog.busy?null:e("space",this._spaceDialog):null}_warmSnapshot(){if(this._booting||this._config?.kiosk||"steady"!==this._continuity.state)return;const e={vp:this._warmViewportState(),frameFingerprint:this._continuity.frameFingerprint,devices:this._devices,hdrH:this._hdrH};if(this._warmRevivePending||(e.dlg=this._warmDialogState()),this.isConnected&&this._warmSlot?.owner===this._warmGen){const t=this.parentNode;e.place=t?new WeakRef(t):null,e.idx=this._warmIdx(t)}this._warmPatch(e)}_warmReviveDialog(){const e=this._warmSlot;if(this._warmReviveTimer=void 0,!e||!e.dlg)return void(this._warmRevivePending=!1);const t=e.dlg,i=e.freed;if(t.mode===this._mode||"view"===t.mode||this._warmVp?.mode!==t.mode||this._editorRuntime){if(this._warmRevivePending=!1,e.dlg=null,e.freed=0,clearTimeout(e.evict),e.evict=0,i&&!(Date.now()-i>av)&&t.space===this._space&&t.mode===this._mode){switch(t.kind){case"space":this._spaceDialog={...t.data,busy:!1,savedBusy:!1};break;case"marker":this._markerDialog={...t.data,busy:!1};break;case"settings":this._settingsDialog={...t.data,busy:!1};break;case"rules":this._rulesDialog={...t.data,busy:!1};break;case"opening":this._openingDialog={...t.data};break;case"backdrop":this._backdropDialog={...t.data};break;case"decorShape":this._decorShapeDialog={...t.data};break;case"decorText":{this._decorTextDialog={...t.data};const e=String(this._decorTextDialog?.text??"").length;this._decorTextSelection={start:e,end:e};break}case"room":{const e=t.data;this._roomEditId=e.editId,this._roomFill=e.fill,this._roomCustomFill=e.customFill||null,this._roomTempMin=e.tempMin||"",this._roomTempMax=e.tempMax||"",this._roomTempSrc=e.tempSrc,this._roomHumSrc=e.humSrc,this._roomSrcOpen=e.srcOpen,this._roomSrcFilter=e.srcFilter,this._roomNameScale=e.nameScale,this._roomLabelScale=e.labelScale,this._areaSel=e.areaSel,this._nameSel=e.nameSel,this._pendingSplit=e.pendingSplit,this._wallFaceBatch=e.wallFaceBatch||null,this._path=e.path,this._wallFaceBatch&&(this._activeWallChainId=`chain-${Date.now().toString(36)}`,this._activeWallChainPartitionIds=[...this._wallFaceBatch.activePartitionIds],this._wallChainSegmentCms=[...this._wallFaceBatch.activeCms]),this._roomDialog=!0;break}case"info":{const e=this._devices.find(e=>e.id===t.data);e&&(this._infoCard=e);break}case"openingInfo":{const e=(this._curSpaceCfg?.openings||[]).find(e=>e.id===t.data);e&&(this._openingInfo=e);break}}this.requestUpdate()}}else this._warmRevivePending=!0}_cacheSnapshot(){if(this._serverCfg)try{this._virtualLights=function(e,t,i){if(e.configRev===i)return e;const n=new Set((Array.isArray(t?.markers)?t.markers:[]).filter(qh).map(e=>e.id));return{...e,configRev:i,off:new Set([...e.off].filter(e=>n.has(e)))}}(this._virtualLights,this._serverCfg,this._cfgRev);const e=this._adoption.snapshot(function(e){return{rev:e.rev,config_rev:e.configRev,off:[...e.off].sort()}}(this._virtualLights));e&&localStorage.setItem(cv,JSON.stringify(e))}catch{}}_beginContinuityCandidate(e,t,i="plan"){return this._booting&&!this._continuity.hasCompleteFrame?this._continuity.token:(this._continuityDataReady=t,this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._resumeSettling=!0,this._continuity.beginCandidate(e,i))}_continuityStageValid(){const e=this._stageEl;return!!e&&e.clientWidth>0&&e.clientHeight>0}_versionReloadSafetySnapshot(){return Sg(this)}_continuityAssetsReady(){if(!this._model.length)return!1;const e=this._model.length?this._spaceModel():null;return!e?.bg?.href||this._signer.isReady(this.hass,e.bg.href)}_initialSpaceSelection(e,t=this._loadOk){const i=this._fixedFloorState(e,t);return"valid"===i.kind?{id:i.id,source:"fixed"}:this._hasFixedFloor?{id:null,source:"none"}:function(e){const t=new Set(e.spaceIds.filter(e=>!!e));if(!t.size)return{id:null,source:"none"};const i=[["hash",!1===e.acceptHash?null:e.hashSpace],["current",e.preserveCurrent?e.currentSpace:null],["saved",e.savedSpace],["default",e.defaultSpace],["first",e.spaceIds[0]]];for(const[e,n]of i)if(n&&t.has(n))return{id:n,source:e};return{id:null,source:"none"}}({spaceIds:e.map(e=>e.id),hashSpace:this._hashSpace(),acceptHash:!this._hashApplied,currentSpace:this._space,preserveCurrent:this._hashApplied||this._navApplied||this._warmVpArmed,savedSpace:this._savedNav()?.space,defaultSpace:this._config?.default_floor})}_adoptInitialSpace(e,t=this._loadOk){const i=this._initialSpaceSelection(e,t);return i.id?(this._commitSpace(i.id,!0),"hash"===i.source&&(this._hashApplied=!0),"saved"===i.source&&(this._navApplied=!0),i):i}_candidateBackdrop(e,t=this._space){const i=el(e),n=this._fixedFloorState(i,!0);if(this._hasFixedFloor&&"valid"!==n.kind)return"";const r=this._initialSpaceSelection(i,!0).id||(i.some(e=>e.id===t)?t:i[0]?.id);return i.find(e=>e.id===r)?.bg?.href||""}_visualFrameFingerprint(){const e=this._stageEl,t=e?[e.clientWidth,e.clientHeight]:[0,0];return hc([this._cfgRev,this._adoption.currentConfigFingerprint(),this._layoutRev,this._adoption.currentLayoutFingerprint(),this._space,this._mode,this._view,t,this._glowScreenBlend?"screen":"normal",this.hass?.themes?.darkMode??this.hass?.themes?.default_theme??""])}_settleContinuityFrame(){if(this._booting||!this._continuityStageValid())return;if(!this._continuity.hasCompleteFrame&&"steady"===this._continuity.state)return void(this._continuityAssetsReady()&&(this._renderSnapshotAt=Date.now(),this._continuity.markCompleteFrame(this._visualFrameFingerprint())));if(!this._continuityDataReady)return;if(!["holding","offline-stale","overlay-pending","overlay-visible","candidate-ready"].includes(this._continuity.state))return;const e=this._continuity.token;if(this._candidateDeviceSnapshot&&this._candidateDeviceSnapshot!==this._visibleDeviceSnapshot&&this._stagedDeviceSnapshotToken!==e)return this._stagedDeviceSnapshotToken=e,void this.requestUpdate();this._continuityPaintToken!==e&&(this._continuityPaintToken=e,this._continuity.candidateReady(e)&&this._continuity.commitAfterPaint(e,{updateComplete:()=>this.updateComplete,stageValid:()=>this.isConnected&&this._continuityStageValid(),assetsReady:()=>this._continuityAssetsReady(),frameFingerprint:()=>this._visualFrameFingerprint()}).then(t=>{t&&e===this._continuity.token?(this._resumeSettling=!1,this._renderSnapshotAt=Date.now(),this._candidateDeviceSnapshot&&(this._visibleDeviceSnapshot=this._candidateDeviceSnapshot),this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._warmSnapshot()):e===this._continuity.token&&(this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._candidateDeviceSnapshot=null,this.requestUpdate())}))}_onBackdropLoaded(e,t){this._signer.markLoaded(this.hass,e,t),this._continuity.note("asset-ready"),this._continuityPaintToken=-1,"steady"!==this._continuity.state&&this.requestUpdate()}_renderRecoveryOverlay(){if(!this._continuity.overlayVisible&&"recovery-error"!==this._continuity.state)return G;const e="connection"===this._continuity.recoveryReason;return j`
e.stopPropagation()} @click=${e=>e.stopPropagation()} @@ -364,7 +364,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc aria-label=${this._t("editor.loading_aria")}> ${this._t("editor.loading")} -
`:G}houseplanContinuityTrace(){return[...this._continuityHistory,...this._continuity.trace].slice(-80).map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}getCardSize(){return 12}getGridOptions(){return{columns:"full"}}get _norm(){return!(!this._serverCfg||!this._serverCfg.spaces.length)}_cfgFingerprint(){const e=this._serverCfg?.spaces||[];let t=e.length+":";for(const i of e){t+=(i.id||"")+","+(i.plan_aspect||"")+","+(i.plan_url||"").length+","+(i.plan_x??"")+","+(i.plan_y??"")+","+(i.plan_scale??"")+","+(i.plan_scale_x??"")+","+(i.plan_scale_y??"")+","+(i.plan_angle??"")+","+(i.rooms?.length||0)+","+(i.openings?.length||0)+","+(i.decor?.length||0)+";";for(const e of i.rooms||[]){const i=e.poly?.[0],n=e.poly?.[e.poly.length-1];t+=(e.poly?.length||0)+"."+(e.id||"")+"."+(e.open_to||[]).join("+")+"."+(e.area||"")+"."+JSON.stringify(e.settings||0)+"."+(e.x??"")+","+(e.y??"")+","+(e.w??"")+","+(e.h??"")+","+(i?i[0]+"/"+i[1]:"")+","+(n?n[0]+"/"+n[1]:"")+";"}}return t}get _model(){if(!this._serverCfg)return[];const e=this._cfgEpoch+"|"+this._cfgFingerprint();if(this._modelCache&&this._modelCache.key===e)return this._modelCache.model;const t=this._buildModel();return this._modelCache={key:e,model:t},t}_buildModel(){if(!this._serverCfg)return[];const e=this._renderCfg;return el(e).map((t,i)=>{const n=e.spaces[i]?.plan_url;return t.bg&&n?{...t,bg:{...t.bg,href:n}}:t})}_spaceModel(){return this._hasFixedFloor?kc(this._model,this._space):(e=this._model,t=this._space,e.find(e=>e.id===t)??e[0]);var e,t}_spaceModelById(e){return kc(this._model,e)}_syncEmptySpaceState(){if(!!this._serverCfg&&0===this._serverCfg.spaces.length){if(!this._emptySpaceStateActive){this._emptySpaceStateActive=!0,this._clearRoomFocus(!0);for(const e of this._pointers.keys())for(const t of this.renderRoot.querySelectorAll("*"))try{t.hasPointerCapture?.(e)&&t.releasePointerCapture(e)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null,this._drag=null,this._deviceDrag=null,this._resetDeviceHitState(),this._rlResize=null,this._vacFit=null,this._compassDrag=!1,this._cancelModeTransition(!1),this._mode="view",this._clearGeometryGesture(),this._geometryHistory.clear(),this._devicePositionHistory.clear(),this._tip=null,this._hoverRoom=null,this._openingInfo=null,this._closeInfoCard(),this._deviceInbox=null,this._deviceInboxReturn=null,this._markerDialog=null,this._physicalDialog=null,this._backdropDialog=null,this._decorShapeDialog=null,this._decorTextDialog=null,this._roomDialog=!1,"edit"===this._spaceDialog?.mode&&(this._spaceDialog=null),this._editorSecondary?.closeForNavigation(),this._saveConfigDebounced.cancel(),this._frame=null,this._planSnapGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._decorSnapCache=null,this._commitSpace("",!0)}}else this._emptySpaceStateActive=!1}get _areaToSpace(){const e={};for(const t of this._model)for(const i of t.rooms)i.area&&(e[i.area]={space:t.id,room:i});return e}get _settings(){return this._serverCfg?.settings||{}}get _showAll(){return this._showHidden||!this._settings.filter_seeded&&!!this._settings.show_all}_seedHiddenDevices(){if(!(this._loadOk&&this._serverCfg&&this._norm&&this._canEdit))return;const e=this._serverCfg,t=eu({hass:this.hass,registry:this._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,firstSpaceId:this._model[0]?.id||"",iconRules:this._iconRules});if(!t.length&&e.settings?.filter_seeded)return;e.markers=e.markers||[];const i=[];for(const n of t){const t="h"+n.slice(n.indexOf(":")+1);e.markers.push({id:t,binding:n,hidden:!0}),i.push(n.slice(n.indexOf(":")+1))}const n={...e.settings||{},filter_seeded:!0};delete n.show_all,i.length&&Array.isArray(n.new_device_ids)&&(n.new_device_ids=n.new_device_ids.filter(e=>!i.includes(e))),e.settings=n,this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate()}get _iconRules(){const e=this._settings.icon_rules;if(!e||!Array.isArray(e)||!e.length)return;const t=JSON.stringify(e);return t!==this._rulesCompiledSrc&&(this._rulesCompiledSrc=t,this._rulesCompiled=Ee(e)),this._rulesCompiled}get _fillColors(){return vn(this._settings)}get _excluded(){return lu(this._settings)}_setAreaLifecycleConfig(e){this._cfgEpochPreservedConfig=e,this._serverCfg=e}willUpdate(e){if(this._isoProjectionSnapshot=null,this._summary?.willUpdate(),e.has("hass")&&this._configReloadAuthority.observeContext(Vu(this)),e.has("_serverCfg")){const e=this._cfgEpochPreservedConfig===this._serverCfg;this._cfgEpochPreservedConfig=null,e||this._cfgEpoch++,this._renderLife.invalidate()}if(this._syncEmptySpaceState(),this._dangerConfirm&&(this._dangerConfirmMissingSpace()||"warm"===this._syncDangerConfirmLocaleGate())&&this._cancelDangerConfirm(),e.has("hass")&&this.hass){const t=this._visibleDeviceSnapshot||this._candidateDeviceSnapshot;this._renderLife.observe(e.get("hass"),this.hass,t?{entityIds:t.entityIds}:null,()=>Mg(this))}this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._continuity.refreshCompleteFrame(this._visualFrameFingerprint()),this._captureRenderDeviceSnapshot()}updated(){this._summary?.updated(),this._liveRt?.commit(),this._editorRuntime?._commitLiveEditor(),this._pruneDevicePressFeedback(),this._syncDayCycleClock(),this._syncRadarLive(),this._warmSnapshot(),this._editorRuntime&&this._dtMeasure();const e=this._stageEl;e&&!this._roViewport&&(this._roViewport=new ResizeObserver(()=>{this._invalidateDeviceHitGeometry(),this._refitView(),requestAnimationFrame(()=>this._summary?.resized())}),this._roViewport.observe(e)),e&&this._booting&&!this._bootTimer&&this._bootWatch();const t=this.renderRoot.querySelector(".hdr");if(t&&e&&!this._roHdr){const i=()=>{const t=ef(this.renderRoot,e,this.panelHost);null!==t&&(t>=0&&t!==this._hdrH&&(this._hdrH=t),t>=0&&!this._booting&&!this._config?.kiosk&&e.clientHeight>0&&this._warmPatch({hdrH:t,stageH:e.clientHeight}))};this._roHdr=new ResizeObserver(()=>requestAnimationFrame(i)),this._roHdr.observe(t),this._onWinResize=()=>requestAnimationFrame(i),window.addEventListener("resize",this._onWinResize),i()}if(e&&!this._view&&this._refitView(),this._editorSecondary?.afterRender(),this._settleContinuityFrame(),this._serverStorage&&this._loadOk&&this._canManageConfiguration&&0===this._model.length&&!this._spaceDialog&&!this._importDialog&&!this._onboardingShown){this._onboardingShown=!0;const e=function(e){const t=e?.floors;if(!t||"object"!=typeof t)return[];const i=[];for(const e of Object.values(t))e&&e.floor_id&&i.push({id:e.floor_id,name:e.name||e.floor_id,level:e.level??null});return i.sort((e,t)=>{const i=e.level??1e9,n=t.level??1e9;return i!==n?i-n:e.name.localeCompare(t.name)}),i}(this.hass);e.length?this._importDialog={floors:e.map(e=>({...e,checked:!0}))}:this._openSpaceDialog("create")}}_adoptConfigCapabilities(e){xg(this,e)}_syncRadarLive(){const e=this._serverCfg?.settings?.radar,t=(this._serverCfg?.markers||[]).some(e=>Cg(e,this._space));this._radarLive.sync(this._space,1===this._haRadarStage1Api&&"view"===this._mode&&!1!==e?.show_live&&t&&"hidden"!==this.ownerDocument.visibilityState)}async _syncDecorAssets(e){const t=++this._decorAssetSyncToken;if(1!==this._haDecorAssetsApi||!this.hass)return void(this._decorAssets=new Map);const i=await um(this.hass,cm(e),this._cfgRev);t===this._decorAssetSyncToken&&(this._decorAssets=i,this._resign(),this.requestUpdate())}_adoptAuthoritative(e){return ju(this,e)}_rollbackOptimistic(e){const t=this._adoption.rollbackOptimistic(e);return t&&this.requestUpdate(),t}_resumePendingNavMode(){if(!this._pendingNavMode||!this._canEdit||this._config?.kiosk)return!1;const e=this._pendingNavMode;return this._pendingNavMode=null,this._setMode(e,!1),!0}_getAuthoritativeConfig(){return e=this,async function(e,t){const i=await e();return t(i),i}(()=>e.hass.callWS({type:"houseplan/config/get"}),t=>xg(e,t));var e}async _loadFromServer(){this._loading=!0,this._loadTries++;const e=this._space,t=!!this._view;let i=!1;const n=()=>{i=!0,this._regSignature="",this._maybeRebuildDevices()};try{const[i,r]=await Promise.all([this._getAuthoritativeConfig(),this.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this._adoptAuthoritative({cfgResp:i,layResp:r,reason:"structural-response",profile:"reload",beforeAdopt:()=>{this._connectionWasLost=!1,this._serverStorage=!0},afterAdopt:()=>{this._warmVpArmed&&this._space===this._warmVp?.space?this._warmVpArmed=!1:t&&this._space===e||this._restoreZoom(),this._loadOk=!0,n()}})).status)return;this.hass.callWS({type:"houseplan/trail/get"}).then(e=>{this._vacSrvTrails=e?.trails||{},this.requestUpdate()}).catch(()=>{}),this._ensureLiveSyncSubscriptions()}catch(e){if(this._serverCfg)this._scheduleLoadRetry(!0);else if(this._loadTries>=8){this._serverStorage=!1;try{this._layout=JSON.parse(localStorage.getItem(lv)||"{}")||{}}catch{this._layout={}}}}finally{this._loading=!1,this._continuityDataReady=!0,i||n(),this.requestUpdate()}}_ensureLiveSyncSubscriptions(){const e=this.hass?.connection;if(!e)return;if(e!==this._liveSyncConnection&&(this._unsubCfg?.(),this._unsubCfg=null,this._unsubLayout?.(),this._unsubLayout=null,this._unsubTrail?.(),this._unsubTrail=void 0,this._unsubVirtual?.(),this._unsubVirtual=null,this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=e),this._liveSyncAttempt)return;const t=this._liveSyncGeneration,i=[],n=(n,r,o,s)=>{n()||i.push(async()=>{const i=await e.subscribeEvents(s,o);t===this._liveSyncGeneration&&this.isConnected&&this.hass?.connection===e&&!n()?r(i):i?.()})};if(n(()=>this._unsubCfg,e=>{this._unsubCfg=e},"houseplan_config_updated",e=>{const t=Number(e?.data?.rev??-1);t!==this._cfgRev&&this._reloadConfigOnly(!1,t)}),n(()=>this._unsubTrail,e=>{this._unsubTrail=e},"houseplan_trail_updated",async()=>{try{const e=await this.hass.callWS({type:"houseplan/trail/get"});this._vacSrvTrails=e?.trails||{},this.requestUpdate()}catch{}}),n(()=>this._unsubLayout,e=>{this._unsubLayout=e},"houseplan_layout_updated",e=>this._onLayoutEvent(Number(e?.data?.rev??-1))),n(()=>this._unsubVirtual,e=>{this._unsubVirtual=e},"houseplan_virtual_light_updated",e=>{const t=Wh(this._virtualLights,e?.data);t!==this._virtualLights&&(this._virtualLights=t,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}),!i.length)return;const r=function(e){return Promise.allSettled(e.map(e=>Promise.resolve().then(e)))}(i).then(()=>{});this._liveSyncAttempt=r,r.finally(()=>{this._liveSyncAttempt===r&&(this._liveSyncAttempt=null)})}async _reloadConfigOnly(e=!1,t){return Ku(this,e,t)}_scheduleLoadRetry(e=!1){if(void 0!==this._loadRetryTimer)return;const t=Math.min(8e3,500*2**Math.min(4,Math.max(1,this._loadTries-7)));this._loadRetryTimer=window.setTimeout(()=>{this._loadRetryTimer=void 0,!e&&this._loadOk||this._loading||!this.hass||this._loadFromServer()},t)}async _ensureLiveRuntime(){if(this._liveRt)return;const e=await import("./live-interaction-runtime-CCfHOfT8.js");this._liveRt=new e.LiveRuntime(this),this.isConnected&&this.requestUpdate()}_liveVp(e=!1){this._liveRt?this._liveRt.viewport(e):this.requestUpdate()}_syncLiveHover(){this._liveRt?this._liveRt.hover():this.requestUpdate()}_flushHa(){this._liveRt?.take()&&(this._terminalFrame=2,super.requestUpdate())}_ensureHaRegistryAuthority(){const e=this.hass?.connection||null;e&&e!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=e,this._haRegistryRev=-1,this._haBindingCacheKey="",this._renderLife.invalidate(),this._areaSnapshotCleanupCandidates.clear(),this._planHassMemo=null,this._haRegistryRelease=td(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}get _haRegistry(){return nd(this.hass)}get _planHass(){const e=this._haRegistry,t=od(this.hass,e),i=this._planHassMemo;if(i&&i.hass===this.hass&&i.sig===t)return i.active;const n=ad(this.hass,e),r=ld(this.hass,e);return this._planHassMemo={hass:this.hass,sig:t,active:n,full:r},n}_captureRenderDeviceSnapshot(){if(!this.hass)return;const e=Date.now(),t=[...this._activityRt.entries()].map(([t,i])=>`${t}:${i.gen}:${i.flashTs}:`+(i.flashKind&&(i.expiresAt||i.flashTs+tg)>e?1:0)).join("|"),i=Bh(this._virtualLights);if(this._capturedSnapshotSequence===this._hassSequence&&this._capturedSnapshotDevices===this._devices&&this._capturedSnapshotLayout===this._layout&&this._capturedSnapshotConfigEpoch===this._cfgEpoch&&this._capturedSnapshotVirtual===i&&this._capturedSnapshotActivity===t)return;const n=this._planHass,r=new Map,o=new Map,s=new Set(["sun.sun"]);for(const e of this._summary?.entityIds()||[])s.add(e);this._vacFit?.source&&s.add(this._vacFit.source);const a=new Set,l=new Set,c=e=>{if(!e)return;const t=e.indexOf(":");if(t<0)return void s.add(e);const i=e.slice(0,t),n=e.slice(t+1);"device"===i?a.add(n):"entity"===i&&s.add(n)};for(const e of this._model)for(const t of e.rooms)t.area&&l.add(t.area),c(t.settings?.temp_source),c(t.settings?.hum_source);for(const e of this._serverCfg?.spaces||[])for(const t of e.openings||[])for(const e of ui(t))s.add(e);for(const e of this._serverCfg?.spaces||[])for(const t of e.decor||[])if("text"===t.kind){for(const e of String(t.text||"").matchAll(/\{([^{}\r\n]+)\}/g)){const t=Xi(e[1]);t?.entity&&s.add(t.entity)}t.entity&&s.add(t.entity),o.set(`decor:${e.id}:${t.id}`,tn(t.text,t,n,e=>!!n.entities?.[e]&&!!n.states?.[e]&&!Jd(n,e,Zd(this._markers))))}const h=Ed(n,this._devices,null,this._virtualLights);for(const e of this._devices){for(const t of[!1,!0])r.set(f_(e.id,t),p_(n,e,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:t,activityRuntime:this._activityRt.get(e.id),sourceDetails:!1,lightDevices:this._devices,lightSources:h,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion}));if(this._isVacDev(e)){const t=this._vacSource(e,n),i=t?Wc(n?.states?.[t]?.attributes):null,r=this._vacRt.get(e.id),s=lh(e.id,e.marker?.vacuum??null,e.space,t),a=hh({routes:s,observed:dh(s,[t],t=>this._vacObservedMapId(e,t,n)),spaceIds:new Set(this._model.map(e=>e.id))});o.set(`vacuum:${e.id}`,{source:t,telemetry:i,routes:s,resolution:a,mapId:i?this._vacMapId(e,i,n):null,runtime:r?{trail:r.trail,lastTs:r.lastTs,moving:r.moving,jump:r.jump}:null,server:this._vacSrvTrails[e.id]||null})}}const d=g_({sourceSequence:this._hassSequence,hass:n,devices:this._devices,presentations:r,positions:(u=this._model.length>0,p=this._devices,_=e=>this._livePos(e),u?new Map(p.map(e=>[e.id,_(e)])):new Map),facts:o,entityIds:s,deviceIds:a,areaIds:l});var u,p,_;this._capturedSnapshotSequence=this._hassSequence,this._capturedSnapshotDevices=this._devices,this._capturedSnapshotLayout=this._layout,this._capturedSnapshotActivity=t,this._capturedSnapshotConfigEpoch=this._cfgEpoch,this._capturedSnapshotVirtual=i,this._visibleDeviceSnapshot&&"steady"!==this._continuity.state?this._candidateDeviceSnapshot=d:(this._visibleDeviceSnapshot=d,this._candidateDeviceSnapshot=null)}get _renderDeviceSnapshot(){return this._stagedDeviceSnapshotToken===this._continuity.token?this._candidateDeviceSnapshot||this._visibleDeviceSnapshot:this._visibleDeviceSnapshot||this._candidateDeviceSnapshot}get _renderPlanHass(){return this._renderDeviceSnapshot?.hass||this._planHass}get _renderDevices(){return this._renderDeviceSnapshot?.devices||this._devices}get _renderVacuumDevices(){return this._renderDeviceSnapshot?.vacuumDevices||this._devices}get _fullRegistryHass(){return this._planHass,this._planHassMemo?.full||this.hass}_bindingStatus(e){return dd(this.hass,e,this._haRegistry)}houseplanDiagnostics(){const{registry:e,bindings:t}=this._renderLife.diagnostics(this.hass,this._markers,e=>this._bindingStatus(e));return{registry:{...e,lastSuccessAgeMs:e.lastSuccess?Math.max(0,Date.now()-e.lastSuccess):null},bindings:t}}_openBindingInHa(e){const[t,i]=e.split(":");if(i)if("device"!==t){if("entity"===t){const e=this._fullRegistryHass.entities?.[i];e?.device_id&&fv("/config/devices/device/"+encodeURIComponent(e.device_id))}}else fv("/config/devices/device/"+encodeURIComponent(i))}_bindingHasHaPage(e){const[t,i]=e.split(":");return!!i&&("device"===t||"entity"===t&&!!this._fullRegistryHass.entities?.[i]?.device_id)}_toggleMarkerDialogVisibility(){const e=this._markerDialog;if(!e)return;const t="ha"===e.bindingMode?this._bindingStatus(e.binding):null,i=e.hideFromPlan||"ha_disabled"===t?.kind;i&&"ha_disabled"===t?.kind?this._showToast(this._t("entity"===t.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device")):i&&"unverified"===t?.kind?this._showToast(this._t("toast.ha_binding_unverified")):this._markerDialog={...e,hideFromPlan:!i}}_hookConnection(){const e=this.hass?.connection;e&&e!==this._connHooked&&(this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),e.addEventListener?.("ready",this._onConnReady),e.addEventListener?.("disconnected",this._onConnLost),e.addEventListener?.("reconnect-error",this._onConnLost),this._connHooked=e)}_display(e){return this._signer.display(this.hass,e)}_referencedContentUrls(){const e=Nn(this._serverCfg);for(const t of this._decorAssets.values())e.add(t.url);return e}_resign(){this._signer.resign(this.hass,this._referencedContentUrls())}_onLayoutEvent(e){e<=this._layoutRev||(clearTimeout(this._layoutSyncTimer),this._layoutSyncTimer=window.setTimeout(()=>{e<=this._layoutRev||this._reloadLayoutOnly()},200))}_noteLayoutRev(e){this._adoption.noteLayoutRevision(e?.rev)}async _reloadLayoutOnly(){if(!this._serverStorage||!this.hass?.callWS)return;this._beginContinuityCandidate("layout-reload",!1);const e=new Map;for(const t of this._dirtyPos)this._layout[t]&&e.set(t,this._layout[t]);this._persistLayout.pending()&&this._persistLayout.flush();for(const[t,i]of this._sentPos)e.set(t,i);try{const t=await this.hass.callWS({type:"houseplan/layout/get"}),i={...t?.layout||{}};for(const[t,n]of e)null===n?delete i[t]:i[t]=n;this._adoption.adoptMergedLayout(i,t,()=>{this._cancelDeviceDrag(),this._devicePositionHistory.clear()}),this._canOptimizeUndo=!!t?.can_optimize_undo,this._undoKind=t?.undo_kind||null,this._cacheSnapshot(),this.requestUpdate()}catch{}finally{this._continuityDataReady=!0,this.requestUpdate()}}_persistLocalLayout(){this._layout=So(lo(this._layout)),localStorage.setItem(lv,JSON.stringify(this._layout))}_maybeRebuildDevices(){const e=this.hass;if(!e?.devices||!e?.entities||!e?.areas)return;const t=this._haRegistry,i=od(e,t)+":"+Object.keys(e.areas).length+":"+(this._norm?"n":"l")+":"+kp(e,this._config?.language);if(i===this._regSignature&&this._devices.length)return;this._regSignature=i;const n=new Map(this._devices.map(e=>[e.id,e.bindingStatus?.kind||"active"]));this._devices=iu({hass:e,registry:t,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,showAll:this._showAll,firstSpaceId:this._model[0]?.id||"",loc:e=>this._t(e),iconRules:this._iconRules});const r=this._markers.filter(e=>!e.removed&&"virtual"!==e.binding).map(e=>e.binding).sort(),o=t.revision+":"+r.join("|");if(t.authoritative&&o!==this._haBindingCacheKey){const i=new Map;for(const n of r)i.set(n,dd(e,n,t));!function(e){if("undefined"==typeof localStorage||!e.size)return;const t=hd(),i=Date.now();for(const[n,r]of e)"active"===r.kind?t[n]={kind:"active",ts:i}:"ha_disabled"===r.kind&&(t[n]={kind:"ha_disabled",reason:r.reason,ts:i});const n=Object.fromEntries(Object.entries(t).sort((e,t)=>t[1].ts-e[1].ts).slice(0,1500));Yh=n;try{localStorage.setItem(Kh,JSON.stringify(n))}catch{}}(i),this._haBindingCacheKey=o}let s=null;if(t.authoritative&&(s=this._resolveAreaRelocations(t),this._areaRelocationIds=new Set(s.relocateIds),this._areaRelocationIds.size)){this._cancelDeviceDrag();const e=this._areaRelocationIds;this._devicePositionHistory.removeWhere(({before:t,after:i})=>e.has(t.deviceId)||e.has(i.deviceId));const t=this._markerDialog;if(t?.devId&&!t.roomTouched&&this._areaRelocationIds.has(t.devId)){const e=this._devices.find(e=>e.id===t.devId);e&&(this._markerDialog={...t,room:e.marker?.room_id?`${e.space}#@${e.marker.room_id}`:e.space&&e.area?`${e.space}#${e.area}`:""})}}this._defPos=this._defaultPositions(),this._syncNewDevices(),this._seedHiddenDevices(),s&&this._syncAreaRelocations(s),this._syncActivityRuntime();const a=new Set(this._devices.filter(e=>!e.hidden).map(e=>e.id));for(const e of this._vacRt.keys())a.has(e)||this._vacRt.delete(e);if(this._infoCard){const e=this._devices.find(e=>e.id===this._infoCard.id);this._infoCard=e&&"ha_disabled"!==e.bindingStatus?.kind?e:null}const l=this._devices.some(e=>"ha_disabled"===e.bindingStatus?.kind&&"ha_disabled"!==n.get(e.id));l&&("ha_disabled"!==this._infoCard?.bindingStatus?.kind&&"ha_disabled"!==this._devices.find(e=>e.id===this._infoCard?.id)?.bindingStatus?.kind||this._closeInfoCard(),this._deviceDrag&&"ha_disabled"===this._devices.find(e=>e.id===this._deviceDrag.id)?.bindingStatus?.kind&&(this._cancelDeviceDrag(),this._devicePositionHistory.clear()),clearTimeout(this._holdTimer),this._holdFired=!1,this._tip=null,this._tapConfirm=null),this._nativeMoreInfoEntity&&!this._planEntityAvailable(this._nativeMoreInfoEntity)&&(gv(this,"hass-more-info",{entityId:null}),this._nativeMoreInfoEntity=null)}_resolveAreaRelocations(e=this._haRegistry){const t=function(e){const t=Q_(e.snapshot),i=new Set(Object.values(t).map(e=>e.binding)),n=new Map;for(const[t,r]of e.previousCandidates||[])J_(t)&&Number.isFinite(r)&&i.has(t)&&n.set(t,r);const r=new Set,o=new Set;for(const t of e.markers||[])t.removed||(Z_(t.id)&&r.add(t.id),J_(t.binding)&&o.add(t.binding));const s=new Set(Object.keys(e.registryDevices||{})),a=new Set(Object.keys(e.registryEntities||{})),l=new Set(Object.keys(e.liveStates||{})),c=new Map;for(const[e,i]of Object.entries(t)){const t=c.get(i.binding)||[];t.push(e),c.set(i.binding,t)}const h=new Set;let d=!1;for(const[t,i]of c){const[c,u]=rm(t);if(o.has(t)||i.some(e=>r.has(e))||("device"===c?s.has(u):a.has(u)||l.has(u))){n.delete(t);continue}const p="device"===c?s.size>0:a.size>0;if(!e.authoritative||!p)continue;const _=n.get(t);if(void 0!==_){if(_!==e.revision)for(const e of i)h.add(e)}else n.set(t,e.revision),d=!0}return{removeIds:h,candidates:n,needsConfirmationRefresh:d}}({snapshot:this._settings.marker_area_snapshot,authoritative:e.authoritative,revision:e.revision,registryDevices:e.devices,registryEntities:e.entities,liveStates:this.hass?.states,markers:this._markers,previousCandidates:this._areaSnapshotCleanupCandidates});return this._areaSnapshotCleanupCandidates=t.candidates,t.needsConfirmationRefresh&&this._canEdit&&id(this.hass),om({devices:this._devices,model:this._model,layout:this._layout,snapshot:this._settings.marker_area_snapshot,authoritative:e.authoritative,cleanupSnapshotIds:t.removeIds,coordinateScale:_v})}_syncNewDevices(){if(!this._norm||!this._loadOk||!this._serverCfg)return;const e=this._devices.filter(e=>!e.marker&&!e.virtual).map(e=>e.id).sort(),t=e.join(",");if(t===this._newSyncKey)return;this._newSyncKey=t;const i=this._settings,{fresh:n,known:r}=function(e,t){if(!Array.isArray(t))return{fresh:[],known:[...e]};const i=new Set(t),n=e.filter(e=>!i.has(e));return{fresh:n,known:n.length?[...t,...n]:t}}(e,i.known_devices);if(!Array.isArray(i.known_devices)||n.length){const e=[...new Set([...i.new_device_ids||[],...n])];this._serverCfg={...this._serverCfg,settings:{...i,known_devices:r,new_device_ids:e}},this._saveConfig()}}_syncAreaRelocations(e){if(!(this._loadOk&&this._serverCfg&&this._norm&&this._canEdit&&this._haRegistry.authoritative))return;const t=e.decisions.filter(e=>e.updateSnapshot||e.removeSnapshot);if(!t.length)return;const i=cc({snapshot:Q_(this._settings.marker_area_snapshot),decisions:t});i!==this._areaRelocationSyncKey&&(this._areaRelocationSyncKey=i,this._areaRelocationWrite=this._areaRelocationWrite.catch(()=>{}).then(async()=>{if(!this._serverCfg||!this._haRegistry.authoritative)return;const e=this._resolveAreaRelocations();this._areaRelocationIds=new Set(e.relocateIds);const t=new Set,i=new Map;let n=!1;for(const r of e.decisions){if(!r.relocate)continue;const e=fg(this._layout,r.id);try{await this._persistDevicePlacement(r.id,null),t.add(r.id),e&&i.set(r.id,e),this._areaRelocationIds.delete(r.id)}catch(t){n=!0,this._layout=vg(this._layout,r.id,e),this._showToast(this._t("toast.pos_save_failed",{err:this._errText(t)}))}}const r=this._settings,o=function(e,t,i=new Set){const n=Q_(e);for(const e of t.decisions)e.removeSnapshot?delete n[e.id]:e.updateSnapshot&&e.binding&&e.area&&(e.relocate&&!i.has(e.id)||(n[e.id]={binding:e.binding,area:e.area}));return n}(r.marker_area_snapshot,e,t),s=[...new Set([...Array.isArray(r.new_device_ids)?r.new_device_ids:[],...t])],a=cc(o)!==cc(Q_(r.marker_area_snapshot)),l=cc(s)!==cc(Array.isArray(r.new_device_ids)?r.new_device_ids:[]);if(a||l){const e=r.marker_area_snapshot,n=r.new_device_ids,a={...this._serverCfg,settings:{...r,marker_area_snapshot:o,...l?{new_device_ids:s}:{}}};this._setAreaLifecycleConfig(a);try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.cancel(),await this._writeConfig()}catch(r){const a=this._settings;if(cc(a.marker_area_snapshot)===cc(o)&&cc(a.new_device_ids)===cc(l?s:n)){const t={...a};void 0===e?delete t.marker_area_snapshot:t.marker_area_snapshot=e,void 0===n?delete t.new_device_ids:t.new_device_ids=n;const i={...this._serverCfg,settings:t};this._setAreaLifecycleConfig(i),this._adoption.refreshConfigFingerprint()}for(const e of t)this._areaRelocationIds.add(e);const c=new Set;for(const[e,t]of i)try{await this._persistDevicePlacement(e,t)}catch(t){c.add(e),this._showToast(this._t("toast.pos_save_failed",{err:this._errText(t)}))}this._areaRelocationSyncKey="",this._regSignature="";if("conflict"===(r&&"object"==typeof r&&"code"in r?r.code:void 0)?(this._showToast(this._t("toast.conflict")),await this._reloadConfigOnly(!0)):this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(r)})),c.size&&this._serverCfg){const e=this._settings,t=[...new Set([...Array.isArray(e.new_device_ids)?e.new_device_ids:[],...c])],i={...this._serverCfg,settings:{...e,new_device_ids:t}};this._setAreaLifecycleConfig(i);try{await this._writeConfig()}catch(e){this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(e)}))}}}}n&&(this._areaRelocationSyncKey=""),this.requestUpdate()}))}get _newIds(){const e=this._settings.new_device_ids;return new Set([...Array.isArray(e)?e:[],...this._areaRelocationIds])}_ackNewDevice(e){if(!this._newIds.has(e)||!this._serverCfg)return;const t=this._settings;this._serverCfg={...this._serverCfg,settings:{...t,new_device_ids:(t.new_device_ids||[]).filter(t=>t!==e)}},this._saveConfig(),this.requestUpdate()}get _markers(){return this._serverCfg?.markers||[]}_roomLqi(e){if(!e)return null;const t=[];for(const i of this._renderDevices){if(i.area!==e||i.virtual)continue;const n=Ld(this._renderPlanHass,i.entities);null!=n&&t.push(n)}return Ii(t)}_roomBounds(e){if(e.poly&&e.poly.length){const t=e.poly.map(e=>e[0]),i=e.poly.map(e=>e[1]),n=Math.min(...t),r=Math.min(...i);return{x:n,y:r,w:Math.max(...t)-n,h:Math.max(...i)-r}}return{x:e.x??0,y:e.y??0,w:e.w??0,h:e.h??0}}_defaultPositions(){const e={},t=this._config?.icon_size??2.5;for(const i of this._model){const n=t/100*Ml(i)*1.3;for(const t of i.rooms){if(!t.area)continue;const r=this._devices.filter(e=>e.area===t.area&&e.space===i.id);if(!r.length)continue;const o=this._roomBounds(t),s=.1*Math.min(o.w,o.h),a=o.w-2*s,l=o.h-2*s,c=Math.max(1,Math.round(Math.sqrt(r.length*a/Math.max(l,1)))),h=Math.ceil(r.length/c),d=a/c,u=l/Math.max(h,1),p=r.map((e,t)=>({x:o.x+s+d*(t%c+.5),y:o.y+s+u*(Math.floor(t/c)+.5)}));Ei(p,o,n,.5*s),r.forEach((t,i)=>e[t.id]=al(p[i]))}}return e}_pos(e){const t=this._renderDeviceSnapshot?.positions.get(e.id);return t?{x:t.x,y:t.y}:this._livePos(e)}_livePos(e){const t=this._spaceModelById(e.space),i=this._areaRelocationIds.has(e.id)?void 0:this._layout[e.id];if(i)if(this._norm){if(i.s===e.space)return{x:i.x*_v,y:i.y*_v}}else if(void 0===i.s)return{x:i.x,y:i.y};return this._defPos[e.id]?this._defPos[e.id]:t?al($l(t)):{x:500,y:500}}_devicePlacementForCanvas(e,t,i){if(!this._norm)return{x:Math.round(t),y:Math.round(i)};const n=this._gridPitch,r=Math.round(t/n)*n,o=Math.round(i/n)*n;return{s:e.space,x:cl(r/_v),y:cl(o/_v)}}_previewDevicePlacement(e,t){this._layout=vg(this._layout,e,t),this.requestUpdate()}_cancelDeviceDrag(){const e=this._deviceDrag;if(!e)return!1;this._editorRuntime?._cancelPointerMove("device"),this._deviceDrag=null,this._deviceHits.cancel(e.pointerId);try{e.source?.hasPointerCapture?.(e.pointerId)&&e.source.releasePointerCapture(e.pointerId)}catch{}return this._previewDevicePlacement(e.id,e.before),!0}async _persistDevicePlacement(e,t){if(this._layout=vg(this._layout,e,t),this._serverStorage){let i=null,n=!1;try{let r;if(null===t)i=null,this._sentPos.set(e,i),n=!0,r=await this.hass.callWS({type:"houseplan/layout/delete",device_id:e});else{const t=xo(this._layout[e]);cc(t)!==cc(this._layout[e])&&(this._layout={...this._layout,[e]:t}),i=t,this._sentPos.set(e,i),n=!0,r=await this.hass.callWS({type:"houseplan/layout/update",device_id:e,pos:t})}this._noteLayoutRev(r),this._adoption.refreshLayoutFingerprint(),this._cacheSnapshot()}finally{n&&this._sentPos.get(e)===i&&this._sentPos.delete(e)}return}this._persistLocalLayout()}_devicePositionStateValid(e){const t=this._devices.find(t=>t.id===e.deviceId);return!!t&&t.space===e.spaceId&&"ha_disabled"!==t.bindingStatus?.kind&&!!this._spaceModelById(e.spaceId)}async _runDevicePositionHistory(e){if(this._cancelDeviceDrag()||this._devicePositionBusy)return;const t="undo"===e?this._devicePositionHistory.undo():this._devicePositionHistory.redo();if(!t)return;const i="undo"===e?t.before:t.after;if(!this._devicePositionStateValid(i))return this._devicePositionHistory.clear(),this._showToast(this._t("history.device_stale")),void this.requestUpdate();const n=fg(this._layout,i.deviceId);i.spaceId!==this._space&&(this._commitSpace(i.spaceId),this._restoreZoom()),this._devicePositionBusy=!0,this._previewDevicePlacement(i.deviceId,i.placement);try{await this._persistDevicePlacement(i.deviceId,i.placement),this._showToast(this._t("undo"===e?"history.undone":"history.redone",{name:t.name}))}catch(t){this._previewDevicePlacement(i.deviceId,n),"undo"===e?this._devicePositionHistory.redo():this._devicePositionHistory.undo(),this._showToast(this._t("toast.pos_save_failed",{err:this._errText(t)}))}finally{this._devicePositionBusy=!1,this.requestUpdate()}}_undoDevicePosition(){this._runDevicePositionHistory("undo")}_redoDevicePosition(){this._runDevicePositionHistory("redo")}_savePos(e,t,i){this._spaceModelById(e.space)&&(this._layout=vg(this._layout,e.id,this._devicePlacementForCanvas(e,t,i)),this._dirtyPos.add(e.id),this._persistLayout())}_devicePresentation(e,t=!1!==this._config?.show_signal,i=!1){const n=i?null:this._renderDeviceSnapshot?.presentations.get(f_(e.id,t));return n||p_(this._renderPlanHass,e,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:t,designPreview:i,activityRuntime:this._activityRt.get(e.id),sourceDetails:!1,lightDevices:this._renderDevices,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion})}_deviceVisual(e){return this._devicePresentation(e).visual}_stateClass(e,t=this._deviceVisual(e)){const i=this._devicePresentation(e);return i.effectiveHidden?"":("icon_ripple"!==i.display||!1===this._config?.live_states||"alarm"===t.status||t.activity,u_({...i,visual:t}).join(" "))}_liveTemp(e){if(!this._config?.show_temperature)return null;if(!0===e.marker?.use_climate_temp){const t=qd(this._renderPlanHass,e.entities);if(null!=t)return t}return"mdi:thermometer"!==e.icon&&"mdi:air-filter"!==e.icon?null:Bd(this._renderPlanHass,e.entities)}_bindingEntities(e){if("virtual"===e||!e)return[];const t=this._bindingStatus(e);return"active"===t.kind?t.enabledEntityIds:t.allEntityIds}_bindingHasClimate(e){return this._bindingEntities(e).some(e=>e.startsWith("climate."))}_bindingHasAlarm(e){return this._bindingEntities(e).some(e=>{const t=this._planHass?.states?.[e]||this.hass?.states?.[e],i=this._fullRegistryHass.entities[e]||this.hass?.entities?.[e];return Yn(e.split(".")[0],t?.attributes?.device_class||i?.device_class||i?.original_device_class)})}_deviceBindingActive(e,t=!0){if(e.virtual||"virtual"===e.bindingKind)return!0;if(!e.bindingKind||!e.bindingRef)return!1;const i=this._bindingStatus(`${e.bindingKind}:${e.bindingRef}`);return"active"===i.kind||(t&&this._showToast(this._t("ha_disabled"===i.kind?"toast.ha_disabled_action":"toast.ha_binding_unverified")),!1)}_openMoreInfo(e){e?this._planEntityAvailable(e)?(this._kiosk&&(this._cyclePausedUntil=Math.max(this._cyclePausedUntil,Date.now()+6e4)),this._nativeMoreInfoEntity=e,gv(this,"hass-more-info",{entityId:e})):this._showToast(this._t("toast.ha_disabled_action")):this._showToast(this._t("toast.no_entity"))}_interruptViewGesture(e,t){if(clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),void 0!==e)for(const i of[t,this._stageEl])try{i?.hasPointerCapture?.(e)&&i.releasePointerCapture(e)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null,this._roomPointer=null,this._doubleFit.clear(),this._deviceHits.clearPointers()}_closeInfoCard(){this._interruptViewGesture(),this._holdFired=!1,this._infoCard=null}_invalidateDeviceHitGeometry(){this._deviceHits.invalidate()}_resetDeviceHitState(){this._deviceHits.reset(this.renderRoot)}_deviceHitOwnerAt(e,t){return"view"!==this._mode&&"devices"!==this._mode?null:this._deviceHits.at(this.renderRoot,this._renderDevices,this._space,e,t)}_deviceForPointerEvent(e,t){return this._deviceHits.pointer(this.renderRoot,this._renderDevices,this._space,e,t)}_deviceForClickEvent(e,t){return this._deviceHits.click(this.renderRoot,this._renderDevices,this._space,e,t)}_showDeviceTip(e,t){this._liveRt?this._liveRt.devicePointerTip(e,t):this._ensureLiveRuntime().then(()=>this._liveRt?.devicePointerTip(e,t))}_showDeviceFocusTip(e,t){const i=e.currentTarget;this._liveRt?this._liveRt.deviceFocusTip(i,t):this._ensureLiveRuntime().then(()=>this._liveRt?.deviceFocusTip(i,t))}_hideDeviceFocusTip(e){this._liveRt?.deviceBlur(e)}_clearPointerHover(){this._liveRt?this._liveRt.pointerLeave():this._clearTransientHover()}_ctxDevice(e,t){"view"===this._mode&&(t=this._deviceForPointerEvent(e,t),e.preventDefault(),e.stopPropagation(),this._deviceBindingActive(t)&&(t.primary?this._openMoreInfo(t.primary):this._infoCard=t))}_clickDevice(e,t){if("view"!==this._mode&&"devices"!==this._mode)return;if(e.stopPropagation(),t=this._deviceForClickEvent(e,t),this._deviceDrag?.moved||this._suppressClick||this._holdFired)return;if("devices"===this._mode)return void this._openMarkerDialog(t);const i=this._devices.find(e=>e.id===t.id);if(!i)return;const n=Tu(i.tapAction,i.primary?.split(".")[0]);if("none"===n)return;const r=(e,t)=>{i.marker?.tap_confirm?this._tapConfirm={kind:"run",text:e,exec:t}:t()};if("toggle"===n){const e=this._toggleIntent(i);if(!e)return;if(!Iu(e))return void this._showUnavailableToggleTargets(e);const t=e=>{const t=Iu(e);if(!t)return;if("virtual-light"===t.kind)return this._startDevicePressFeedback(i.id),void this.hass.callWS({type:"houseplan/virtual_light/toggle",marker_id:t.markerId}).then(e=>{const t=Wh(this._virtualLights,e);t!==this._virtualLights&&(this._virtualLights=t,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}).catch(e=>this._showToast(this._t("toast.virtual_light_toggle_failed",{err:this._errText(e)})));const{command:n}=t;this._startDevicePressFeedback(i.id),this.hass.callService(n.domain,n.service,n.data).catch(e=>this._showToast(this._t("toast.error",{err:this._errText(e)})))},n=((o=e).targets.length?o.targets:o.skippedTargets).map(e=>e.name||e.entityId||e.ref).join(", ")||i.name;if(i.marker?.tap_confirm){const r=this._toggleConfirmationLines(e);if(!r.length)return;this._tapConfirm={kind:"toggle",text:this._t("confirm.tap_toggle",{name:n}),lines:r,initialIntent:e,deviceId:i.id,exec:()=>{const n=this._devices.find(e=>e.id===i.id),r=n?this._toggleIntent(n):null;r&&!Iu(r)&&this._showUnavailableToggleTargets(r)||(r&&Eu(e,r)?t(r):this._showToast(this._t("toast.tap_target_changed")))}}}else t(e);return}var o;if("info"===n)return this._interruptViewGesture(),void(this._infoCard=i);if(this._deviceBindingActive(i)){if("run"===n){const e=i.marker?.tap_target||"",t=function(e){const t=String(e||"").split(".")[0];return"automation"===t?{domain:"automation",service:"trigger"}:"script"===t?{domain:"script",service:"turn_on"}:"scene"===t?{domain:"scene",service:"turn_on"}:null}(e),n=this.hass.states[e];if(!t||!n)return void this._showToast(this._t("toast.run_target_missing"));const o=n.attributes?.friendly_name||e;return void r(this._t("confirm.tap_run",{name:o}),()=>{this._deviceBindingActive(i)&&this._planEntityAvailable(e)&&(this._startDevicePressFeedback(i.id),this.hass.callService(t.domain,t.service,{entity_id:e}).then(()=>{this._stampActivity(i.id,"event",this._activitySourceKey(i)),this.requestUpdate(),this._showToast(this._t("toast.run_started",{name:o}))}).catch(e=>this._showToast(this._t("toast.error",{err:this._errText(e)}))))})}"more-info"===n&&i.primary?this._openMoreInfo(i.primary):this._infoCard=i}}_showUnavailableToggleTargets(e){const t=function(e){if(!e||"group"!==e.kind||Iu(e)||"configured-targets-missing"!==e.noneReason)return[];if(!e.skippedTargets.length||e.skippedTargets.some(e=>!Ou.has(e.reason)&&"secure"!==e.reason))return[];const t=[],i=new Set;for(const n of e.skippedTargets){if(!Ou.has(n.reason))continue;const e=String(n.name||n.entityId||n.ref||"").trim();e&&!i.has(e)&&(i.add(e),t.push(e))}return t}(e);return!!t.length&&(this._showToast(1===t.length?this._t("toast.toggle_target_unavailable",{name:t[0]}):this._t("toast.toggle_targets_unavailable",{names:t.join(", ")})),!0)}_keyDevice(e,t){"Enter"!==e.key&&" "!==e.key||"view"!==this._mode&&"devices"!==this._mode||(e.preventDefault(),this._clickDevice(e,t))}_startDevicePressFeedback(e){const t=[...this.renderRoot.querySelectorAll(".dev[data-id]")].find(t=>t.dataset.id===e),i=t?.querySelector(".device-shell");if(!i||"function"!=typeof i.animate)return;const n=Number.parseFloat(this.ownerDocument.defaultView?.getComputedStyle(i).scale||""),r=Number.isFinite(n)?Math.max(.95,Math.min(1,n)):1;this._devicePressAnimations.get(e)?.cancel();const o=this._reducedMotion?[{outlineColor:"transparent",outlineStyle:"solid",outlineWidth:"0px"},{outlineColor:"var(--hp-accent, #3ea6ff)",outlineStyle:"solid",outlineWidth:"2px",outlineOffset:"2px",offset:.5},{outlineColor:"transparent",outlineStyle:"solid",outlineWidth:"0px"}]:[{scale:String(r)},{scale:"0.95",offset:.5},{scale:"1"}],s=i.animate(o,{duration:200,easing:"cubic-bezier(.22,.61,.36,1)"});this._devicePressAnimations.set(e,s);const a=()=>{this._devicePressAnimations.get(e)===s&&this._devicePressAnimations.delete(e)};s.addEventListener("finish",a,{once:!0}),s.addEventListener("cancel",a,{once:!0})}_cancelDevicePressFeedback(){for(const e of this._devicePressAnimations.values())e.cancel();this._devicePressAnimations.clear()}_pruneDevicePressFeedback(){if(!this._devicePressAnimations.size)return;const e=new Set([...this.renderRoot.querySelectorAll(".dev[data-id]")].map(e=>e.dataset.id||""));for(const[t,i]of this._devicePressAnimations)e.has(t)||(i.cancel(),this._devicePressAnimations.delete(t))}_t(e,t){return xp(kp(this.hass,this._config?.language),e,t)}get _colorPickerLabels(){return{title:this._t("color_picker.title"),hue:this._t("color_picker.hue"),saturation:this._t("color_picker.saturation"),value:this._t("color_picker.value"),hex:this._t("color_picker.hex"),invalidHex:this._t("color_picker.invalid_hex"),confirm:this._t("color_picker.confirm")}}_help(e){return this._editorRuntimeOrThrow()._help(e)}get _stageEl(){return this.renderRoot.querySelector(".stage")}_contentItems(e){const t=[];for(const i of this._devices){if(i.space!==e.id||i.hidden)continue;const n=this._pos(i);t.push({minX:n.x,minY:n.y,maxX:n.x,maxY:n.y})}if(e.id===this._space){for(const e of this._openingsR){const i=Number(e.angle)*Math.PI/180,n=Math.cos(i)*e.rlen/2,r=Math.sin(i)*e.rlen/2,o=pl([[e.rx-n,e.ry-r],[e.rx+n,e.ry+r]]);o&&t.push(o)}const i=this._decorH;for(const e of this._decorList){if("image"===e.kind&&!this._decorAssets.has(e.asset_id)&&"decor"!==this._mode)continue;const n=pl("line"===e.kind?[[e.x1*_v,e.y1*i],[e.x2*_v,e.y2*i]]:"text"===e.kind?[[e.x*_v,e.y*i]]:Nr({x:e.x*_v,y:e.y*i,w:e.w*_v,h:e.h*i,angle:e.angle}));n&&t.push(n)}for(const i of this._physicalBodiesR(e)){const e=pl(i);e&&t.push(e)}}return vl(e,t)}_frameOf(){const e=this._spaceModel();if(!e){this._frame=null;const e={x:0,y:0,w:_v,h:_v};return{rect:e,all:e,outliers:0}}const t=this._frame,i="view"!==this._mode;if(t&&t.id===e.id&&this._bdDrag)return t;if(t&&t.id===e.id&&t.model===e&&t.layout===this._layout&&t.devs===this._devices&&t.far===this._showFar&&t.grow===i)return t;const n=kl(this._contentItems(e));let r=n.all||Sl(e),o=this._showFar?r:n.core||Sl(e);return t&&t.id===e.id&&i&&t.grow&&(o=mv(t.rect,o),r=mv(t.all,r)),this._frame={id:e.id,model:e,layout:this._layout,devs:this._devices,far:this._showFar,grow:i,rect:o,all:r,outliers:n.outliers},this._frame}_isoSource(){const e=this._isoSceneRuntime;if(!e)return null;const t=this._spaceModel();if(!t)return null;const i=this._spaceWalls,n=this._openCuts(),r=this._openingsR;return e.createIsoStructuralSource({space:t,walls:i,openCuts:n,openings:r,partitionCuts:()=>this._partitionOpeningCuts(t),roomOpenings:()=>this._roomWallOpeningInputs(r,t),cellCm:this._cellCm,gridPitch:this._gridPitch,wallKeyPitch:this._wallKeyPitch,coordinateScale:_v,onBuild:()=>{this._isoStructuralBuildCount+=1}})}_isoSceneKey(){if(!this._labsIso||"view"!==this._mode)return null;try{return this._isoSource()?.key??null}catch{return this._isoInvalidKey()}}_isoInvalidKey(){return`${this._space}|invalid|${this._cfgEpoch}`}_clearIsoInvalidFallback(e){const t=`${this._space}|invalid|`;for(const i of this._isoFallback)i.startsWith(t)&&i!==e&&this._isoFallback.delete(i)}_isoScene(e=this._isoSource()){const t=this._isoSceneRuntime;if(!t||!e)return null;let i=this._frameOf().rect;const n=this._spaceDisplayForRender(),r=this._spaceModel();if(r&&n.showNames)for(const e of r.rooms)if(e.name){const t=this._labelPos(e,r.id);i=mv(i,{x:t.x,y:t.y,w:0,h:0})}const o=t.resolveIsoScene({source:e,cache:this._isoGeometryCache,cellCm:this._cellCm,liveFrame:i});if(!r||!n.showBorders)return o;const s=this._config?.icon_size??2.5,a=s>8?2.5:s,l=this._stageEl?.getBoundingClientRect?.()??null,c=l?.height?l.width/l.height:o.frame.w/o.frame.h,h=Oi([o.frame.x,o.frame.y,o.frame.w,o.frame.h],c),d=this._isoOverlayScene(r,this._renderDevices.filter(e=>e.space===r.id&&!e.hidden),h,n,t.resolveIsoDecorationLayers(n),o,a,x_(a),n.showLqi??this._config?.show_signal??!0,!1),u=d&&t.resolveIsoOverlayFitEnvelope({baseBounds:o.frame,entries:d.entries,stageSize:l,targetView:e=>Oi([e.x,e.y,e.w,e.h],c)});return u?{...o,frame:u.bounds,overlayFitEntries:d.entries}:o}_latchIsoFallback(e,t){if(this._isoFallback.has(e))return;this._isoFallback.add(e);const i=e.includes("|invalid|")?"invalid":e.split("|").pop()||"invalid";console.warn("HOUSEPLAN ISO FALLBACK: #89/#160",wf("structural",i,!0))}_effectiveProjection(){if(this._isoProjectionSnapshot)return this._isoProjectionSnapshot;const e=e=>this._isoProjectionSnapshot=e,t=()=>("iso"===this._renderProjection&&(this._cancelCameraTransition(!1),this._view=null,this._viewModeSnap=null),e("flat"));if(this._renderIsoScene=null,"iso"!==this._desiredProjection||!this._model.length||!this._isoSceneRuntime)return e("flat");if(!this._spaceDisplayForRender().showBorders)return this._isoFallback.has(`${this._space}|no-borders`)?t():e("iso");let i=this._isoInvalidKey();if(this._clearIsoInvalidFallback(i),this._isoFallback.has(i))return t();try{const n=this._isoSource();if(!n)return e("flat");if(i=n.key,this._isoFallback.has(i))return t();const r=this._isoScene(n);return r?this._isoFallback.has(r.key)?t():(this._renderIsoScene=r,e("iso")):e("flat")}catch(e){return this._latchIsoFallback(i,e),t()}}_scenePoint(e){return"iso"===this._renderProjection?lf(e,0):e}_floorView(e){if("iso"!==this._renderProjection)return e;const t=cf([e.x,e.y]),i=cf([e.x+e.w,e.y+e.h]);return{x:t[0],y:t[1],w:i[0]-t[0],h:i[1]-t[1]}}_isoOverlayScene(e,t,i,n,r,o,s,a,l,c=!0){const h=this._isoSceneRuntime;return h&&r?.structural&&o?h.buildIsoOverlayRenderScene({space:e,devices:t,openings:this._openingsR,view:i,display:n,wallSilhouettes:o.wallSilhouettes,resolveCollisions:c,iconPct:s,deviceBasePct:a,showLqi:l,cellCm:this._cellCm,kioskIconScale:"view"===this._mode?this._kioskScale.icon:1,kioskFontScale:"view"===this._mode?this._kioskScale.font:1,stageSize:this._stageEl?.getBoundingClientRect?.(),positionOf:e=>this._pos(e),presentationOf:(e,t)=>this._devicePresentation(e,t),labelPositionOf:(e,t)=>this._labelPos(e,t),labelScaleOf:e=>this._labelScale(e),openingEntityAvailable:e=>this._renderOpeningEntityAvailable(e),openingWallIndex:()=>this._openingWallIndexFor(e,this._openCuts()).value}):null}_baseVb(e=this._effectiveProjection(),t=this._renderIsoScene){if("iso"===e){if(!this._spaceDisplayForRender().showBorders){const e=uf({rect:this._frameOf().rect,wallHeight:0});return[e.x,e.y,e.w,e.h]}const e=t?.frame??this._frameOf().rect;return[e.x,e.y,e.w,e.h]}const i=this._frameOf().rect;return[i.x,i.y,i.w,i.h]}get _outliers(){return this._showFar?0:this._frameOf().outliers}_fitFar(){this._clearRoomFocus(),this._showFar=!0,this._frame=null,this.requestUpdate(),this._resetZoom()}_clearRoomFocus(e=!1){this._doubleFit.clear(),this._roomFocus=null,e&&(this._roomPointer=null)}_roomFitBounds(e,t){const i=ni(e);if(!i||!e.id)return null;const n=this._spaceWalls,r=this._openCuts(),o=this._wallUnionGeometry(),s=n.length&&this._innerRoomContour(t,e.id,r,o?.roomGeom,o?.multiWallNodes)||i,a=this._spaceDisplayForRender();let l=[];if(a.showBorders&&n.length){const i=Fs(t.rooms,e.id,n,r,this._wallKeyPitch,this._cellCm,this._gridPitch,_v);i&&(l=aa(i.poly,i.offsets,o?.multiWallNodes)||i.poly)}const c=this._effectiveProjection();return function(e){const t=e.floor,i=e.wall||[],n=e.padding??0;if(!t.length||!t.every(vf)||!i.every(vf)||!Number.isFinite(n)||n<0)return null;if("flat"===e.projection)return bf([...t,...i],n);const r=e.wallHeight??0,o=e.floorDepth??0;if(!Number.isFinite(r)||r<0||!Number.isFinite(o)||o<0)return null;try{const e=[];for(const i of t){const t=[i[0],i[1]];e.push(lf(t,0)),o>0&&e.push(lf(t,-o))}for(const t of i){const i=[t[0],t[1]];e.push(lf(i,0)),r>0&&e.push(lf(i,r))}return bf(e,n)}catch{return null}}({floor:s,wall:l,projection:c,wallHeight:"iso"===c&&a.showBorders?Wa(84,this._cellCm):0,floorDepth:"iso"===c&&a.showBorders?Wa(10,this._cellCm):0,padding:a.showBorders?Wa(1.25,this._cellCm):0})}_fitRoom(e,t=!0){if("view"!==this._mode)return!1;this._doubleFit.clear();const i=this._spaceModel(),n=i?.rooms.find(t=>t.id===e);if(!i||!n)return this._clearRoomFocus(),!1;let r=this._roomFitBounds(n,i);if(!r)return this._clearRoomFocus(),!1;this._roomFocus={spaceId:i.id,roomId:e};const o=this._stageEl;if(!o||o.clientWidth<=0||o.clientHeight<=0)return!0;const s=Oi(this._baseVb(),o.clientWidth/o.clientHeight),a=e=>function(e){const t=e.safeFraction??.8,{bounds:i,baseFit:n,stageWidth:r,stageHeight:o,minZoom:s,maxZoom:a}=e;if(!yf(i)||!yf(n)||!Number.isFinite(r)||r<=0||!Number.isFinite(o)||o<=0||!Number.isFinite(s)||s<=0||!Number.isFinite(a)||a1)return null;const l=r/o,c=Math.max(i.w/t,i.h/t*l);if(!Number.isFinite(c)||c<=0)return null;const h=Math.min(a,Math.max(s,n.w/c)),d=n.w/h,u=d/l;return{zoom:h,viewBox:{x:i.x+i.w/2-d/2,y:i.y+i.h/2-u/2,w:d,h:u}}}({bounds:e,baseFit:s,stageWidth:o.clientWidth,stageHeight:o.clientHeight,minZoom:wv.ZOOM_MIN,maxZoom:wv.ZOOM_MAX});let l=a(r);const c=this._isoSceneRuntime,h=this._renderIsoScene?.overlayFitEntries;if(l&&"iso"===this._effectiveProjection()&&c&&h?.length){const e=c.resolveIsoOverlayFitEnvelope({baseBounds:r,entries:h,ownerId:n.id,stageSize:{width:o.clientWidth,height:o.clientHeight},targetView:e=>a(e)?.viewBox??null});e&&(r=e.bounds,l=a(r))}if(!l)return this._clearRoomFocus(),!1;const d=this._cameraState(),u=function(e,t,i,n){const r=[e,t,i,n],o=Math.min(...r.map(e=>e.x)),s=Math.min(...r.map(e=>e.y));return{x:o,y:s,w:Math.max(...r.map(e=>e.x+e.w))-o,h:Math.max(...r.map(e=>e.y+e.h))-s}}(s,d.viewBox,l.viewBox,r);return l.viewBox=this._clampView(l.viewBox,u),t?(this._prepareCameraCommand(),this._startCameraTransition(l,u,"room",220),!0):(this._cancelCameraTransition(!1),Xg(d,l)||(this._zoom=l.zoom,this._view={...l.viewBox},this.requestUpdate()),!0)}_fitAll(e="fit"){this._clearRoomFocus(),this._showFar=!0,this._frame=null,this.requestUpdate(),this._resetZoom(e)}_renderFarHint(){return this._kiosk||"view"!==this._mode||this._booting||!this._outliers?G:j`
+
`:G}houseplanContinuityTrace(){return[...this._continuityHistory,...this._continuity.trace].slice(-80).map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}getCardSize(){return 12}getGridOptions(){return{columns:"full"}}get _norm(){return!(!this._serverCfg||!this._serverCfg.spaces.length)}_cfgFingerprint(){const e=this._serverCfg?.spaces||[];let t=e.length+":";for(const i of e){t+=(i.id||"")+","+(i.plan_aspect||"")+","+(i.plan_url||"").length+","+(i.plan_x??"")+","+(i.plan_y??"")+","+(i.plan_scale??"")+","+(i.plan_scale_x??"")+","+(i.plan_scale_y??"")+","+(i.plan_angle??"")+","+(i.rooms?.length||0)+","+(i.openings?.length||0)+","+(i.decor?.length||0)+";";for(const e of i.rooms||[]){const i=e.poly?.[0],n=e.poly?.[e.poly.length-1];t+=(e.poly?.length||0)+"."+(e.id||"")+"."+(e.open_to||[]).join("+")+"."+(e.area||"")+"."+JSON.stringify(e.settings||0)+"."+(e.x??"")+","+(e.y??"")+","+(e.w??"")+","+(e.h??"")+","+(i?i[0]+"/"+i[1]:"")+","+(n?n[0]+"/"+n[1]:"")+";"}}return t}get _model(){if(!this._serverCfg)return[];const e=this._cfgEpoch+"|"+this._cfgFingerprint();if(this._modelCache&&this._modelCache.key===e)return this._modelCache.model;const t=this._buildModel();return this._modelCache={key:e,model:t},t}_buildModel(){if(!this._serverCfg)return[];const e=this._renderCfg;return el(e).map((t,i)=>{const n=e.spaces[i]?.plan_url;return t.bg&&n?{...t,bg:{...t.bg,href:n}}:t})}_spaceModel(){return this._hasFixedFloor?kc(this._model,this._space):(e=this._model,t=this._space,e.find(e=>e.id===t)??e[0]);var e,t}_spaceModelById(e){return kc(this._model,e)}_syncEmptySpaceState(){if(!!this._serverCfg&&0===this._serverCfg.spaces.length){if(!this._emptySpaceStateActive){this._emptySpaceStateActive=!0,this._clearRoomFocus(!0);for(const e of this._pointers.keys())for(const t of this.renderRoot.querySelectorAll("*"))try{t.hasPointerCapture?.(e)&&t.releasePointerCapture(e)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null,this._drag=null,this._deviceDrag=null,this._resetDeviceHitState(),this._rlResize=null,this._vacFit=null,this._compassDrag=!1,this._cancelModeTransition(!1),this._mode="view",this._clearGeometryGesture(),this._geometryHistory.clear(),this._devicePositionHistory.clear(),this._tip=null,this._hoverRoom=null,this._openingInfo=null,this._closeInfoCard(),this._deviceInbox=null,this._deviceInboxReturn=null,this._markerDialog=null,this._physicalDialog=null,this._backdropDialog=null,this._decorShapeDialog=null,this._decorTextDialog=null,this._roomDialog=!1,"edit"===this._spaceDialog?.mode&&(this._spaceDialog=null),this._editorSecondary?.closeForNavigation(),this._saveConfigDebounced.cancel(),this._frame=null,this._planSnapGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._decorSnapCache=null,this._commitSpace("",!0)}}else this._emptySpaceStateActive=!1}get _areaToSpace(){const e={};for(const t of this._model)for(const i of t.rooms)i.area&&(e[i.area]={space:t.id,room:i});return e}get _settings(){return this._serverCfg?.settings||{}}get _showAll(){return this._showHidden||!this._settings.filter_seeded&&!!this._settings.show_all}_seedHiddenDevices(){if(!(this._loadOk&&this._serverCfg&&this._norm&&this._canEdit))return;const e=this._serverCfg,t=eu({hass:this.hass,registry:this._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,firstSpaceId:this._model[0]?.id||"",iconRules:this._iconRules});if(!t.length&&e.settings?.filter_seeded)return;e.markers=e.markers||[];const i=[];for(const n of t){const t="h"+n.slice(n.indexOf(":")+1);e.markers.push({id:t,binding:n,hidden:!0}),i.push(n.slice(n.indexOf(":")+1))}const n={...e.settings||{},filter_seeded:!0};delete n.show_all,i.length&&Array.isArray(n.new_device_ids)&&(n.new_device_ids=n.new_device_ids.filter(e=>!i.includes(e))),e.settings=n,this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate()}get _iconRules(){const e=this._settings.icon_rules;if(!e||!Array.isArray(e)||!e.length)return;const t=JSON.stringify(e);return t!==this._rulesCompiledSrc&&(this._rulesCompiledSrc=t,this._rulesCompiled=Ee(e)),this._rulesCompiled}get _fillColors(){return vn(this._settings)}get _excluded(){return lu(this._settings)}_setAreaLifecycleConfig(e){this._cfgEpochPreservedConfig=e,this._serverCfg=e}willUpdate(e){if(this._isoProjectionSnapshot=null,this._summary?.willUpdate(),e.has("hass")&&this._configReloadAuthority.observeContext(Vu(this)),e.has("_serverCfg")){const e=this._cfgEpochPreservedConfig===this._serverCfg;this._cfgEpochPreservedConfig=null,e||this._cfgEpoch++,this._renderLife.invalidate()}if(this._syncEmptySpaceState(),this._dangerConfirm&&(this._dangerConfirmMissingSpace()||"warm"===this._syncDangerConfirmLocaleGate())&&this._cancelDangerConfirm(),e.has("hass")&&this.hass){const t=this._visibleDeviceSnapshot||this._candidateDeviceSnapshot;this._renderLife.observe(e.get("hass"),this.hass,t?{entityIds:t.entityIds}:null,()=>Mg(this))}this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._continuity.refreshCompleteFrame(this._visualFrameFingerprint()),this._captureRenderDeviceSnapshot()}updated(){this._summary?.updated(),this._liveRt?.commit(),this._editorRuntime?._commitLiveEditor(),this._pruneDevicePressFeedback(),this._syncDayCycleClock(),this._syncRadarLive(),this._warmSnapshot(),this._editorRuntime&&this._dtMeasure();const e=this._stageEl;e&&!this._roViewport&&(this._roViewport=new ResizeObserver(()=>{this._invalidateDeviceHitGeometry(),this._refitView(),requestAnimationFrame(()=>this._summary?.resized())}),this._roViewport.observe(e)),e&&this._booting&&!this._bootTimer&&this._bootWatch();const t=this.renderRoot.querySelector(".hdr");if(t&&e&&!this._roHdr){const i=()=>{const t=ef(this.renderRoot,e,this.panelHost);null!==t&&(t>=0&&t!==this._hdrH&&(this._hdrH=t),t>=0&&!this._booting&&!this._config?.kiosk&&e.clientHeight>0&&this._warmPatch({hdrH:t,stageH:e.clientHeight}))};this._roHdr=new ResizeObserver(()=>requestAnimationFrame(i)),this._roHdr.observe(t),this._onWinResize=()=>requestAnimationFrame(i),window.addEventListener("resize",this._onWinResize),i()}if(e&&!this._view&&this._refitView(),this._editorSecondary?.afterRender(),this._settleContinuityFrame(),this._serverStorage&&this._loadOk&&this._canManageConfiguration&&0===this._model.length&&!this._spaceDialog&&!this._importDialog&&!this._onboardingShown){this._onboardingShown=!0;const e=function(e){const t=e?.floors;if(!t||"object"!=typeof t)return[];const i=[];for(const e of Object.values(t))e&&e.floor_id&&i.push({id:e.floor_id,name:e.name||e.floor_id,level:e.level??null});return i.sort((e,t)=>{const i=e.level??1e9,n=t.level??1e9;return i!==n?i-n:e.name.localeCompare(t.name)}),i}(this.hass);e.length?this._importDialog={floors:e.map(e=>({...e,checked:!0}))}:this._openSpaceDialog("create")}}_adoptConfigCapabilities(e){xg(this,e)}_syncRadarLive(){const e=this._serverCfg?.settings?.radar,t=(this._serverCfg?.markers||[]).some(e=>Cg(e,this._space));this._radarLive.sync(this._space,1===this._haRadarStage1Api&&"view"===this._mode&&!1!==e?.show_live&&t&&"hidden"!==this.ownerDocument.visibilityState)}async _syncDecorAssets(e){const t=++this._decorAssetSyncToken;if(1!==this._haDecorAssetsApi||!this.hass)return void(this._decorAssets=new Map);const i=await um(this.hass,cm(e),this._cfgRev);t===this._decorAssetSyncToken&&(this._decorAssets=i,this._resign(),this.requestUpdate())}_adoptAuthoritative(e){return ju(this,e)}_rollbackOptimistic(e){const t=this._adoption.rollbackOptimistic(e);return t&&this.requestUpdate(),t}_resumePendingNavMode(){if(!this._pendingNavMode||!this._canEdit||this._config?.kiosk)return!1;const e=this._pendingNavMode;return this._pendingNavMode=null,this._setMode(e,!1),!0}_getAuthoritativeConfig(){return e=this,async function(e,t){const i=await e();return t(i),i}(()=>e.hass.callWS({type:"houseplan/config/get"}),t=>xg(e,t));var e}async _loadFromServer(){this._loading=!0,this._loadTries++;const e=this._space,t=!!this._view;let i=!1;const n=()=>{i=!0,this._regSignature="",this._maybeRebuildDevices()};try{const[i,r]=await Promise.all([this._getAuthoritativeConfig(),this.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this._adoptAuthoritative({cfgResp:i,layResp:r,reason:"structural-response",profile:"reload",beforeAdopt:()=>{this._connectionWasLost=!1,this._serverStorage=!0},afterAdopt:()=>{this._warmVpArmed&&this._space===this._warmVp?.space?this._warmVpArmed=!1:t&&this._space===e||this._restoreZoom(),this._loadOk=!0,n()}})).status)return;this.hass.callWS({type:"houseplan/trail/get"}).then(e=>{this._vacSrvTrails=e?.trails||{},this.requestUpdate()}).catch(()=>{}),this._ensureLiveSyncSubscriptions()}catch(e){if(this._serverCfg)this._scheduleLoadRetry(!0);else if(this._loadTries>=8){this._serverStorage=!1;try{this._layout=JSON.parse(localStorage.getItem(lv)||"{}")||{}}catch{this._layout={}}}}finally{this._loading=!1,this._continuityDataReady=!0,i||n(),this.requestUpdate()}}_ensureLiveSyncSubscriptions(){const e=this.hass?.connection;if(!e)return;if(e!==this._liveSyncConnection&&(this._unsubCfg?.(),this._unsubCfg=null,this._unsubLayout?.(),this._unsubLayout=null,this._unsubTrail?.(),this._unsubTrail=void 0,this._unsubVirtual?.(),this._unsubVirtual=null,this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=e),this._liveSyncAttempt)return;const t=this._liveSyncGeneration,i=[],n=(n,r,o,s)=>{n()||i.push(async()=>{const i=await e.subscribeEvents(s,o);t===this._liveSyncGeneration&&this.isConnected&&this.hass?.connection===e&&!n()?r(i):i?.()})};if(n(()=>this._unsubCfg,e=>{this._unsubCfg=e},"houseplan_config_updated",e=>{const t=Number(e?.data?.rev??-1);t!==this._cfgRev&&this._reloadConfigOnly(!1,t)}),n(()=>this._unsubTrail,e=>{this._unsubTrail=e},"houseplan_trail_updated",async()=>{try{const e=await this.hass.callWS({type:"houseplan/trail/get"});this._vacSrvTrails=e?.trails||{},this.requestUpdate()}catch{}}),n(()=>this._unsubLayout,e=>{this._unsubLayout=e},"houseplan_layout_updated",e=>this._onLayoutEvent(Number(e?.data?.rev??-1))),n(()=>this._unsubVirtual,e=>{this._unsubVirtual=e},"houseplan_virtual_light_updated",e=>{const t=Wh(this._virtualLights,e?.data);t!==this._virtualLights&&(this._virtualLights=t,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}),!i.length)return;const r=function(e){return Promise.allSettled(e.map(e=>Promise.resolve().then(e)))}(i).then(()=>{});this._liveSyncAttempt=r,r.finally(()=>{this._liveSyncAttempt===r&&(this._liveSyncAttempt=null)})}async _reloadConfigOnly(e=!1,t){return Ku(this,e,t)}_scheduleLoadRetry(e=!1){if(void 0!==this._loadRetryTimer)return;const t=Math.min(8e3,500*2**Math.min(4,Math.max(1,this._loadTries-7)));this._loadRetryTimer=window.setTimeout(()=>{this._loadRetryTimer=void 0,!e&&this._loadOk||this._loading||!this.hass||this._loadFromServer()},t)}async _ensureLiveRuntime(){if(this._liveRt)return;const e=await import("./live-interaction-runtime-XyTIhKAA.js");this._liveRt=new e.LiveRuntime(this),this.isConnected&&this.requestUpdate()}_liveVp(e=!1){this._liveRt?this._liveRt.viewport(e):this.requestUpdate()}_syncLiveHover(){this._liveRt?this._liveRt.hover():this.requestUpdate()}_flushHa(){this._liveRt?.take()&&(this._terminalFrame=2,super.requestUpdate())}_ensureHaRegistryAuthority(){const e=this.hass?.connection||null;e&&e!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=e,this._haRegistryRev=-1,this._haBindingCacheKey="",this._renderLife.invalidate(),this._areaSnapshotCleanupCandidates.clear(),this._planHassMemo=null,this._haRegistryRelease=td(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}get _haRegistry(){return nd(this.hass)}get _planHass(){const e=this._haRegistry,t=od(this.hass,e),i=this._planHassMemo;if(i&&i.hass===this.hass&&i.sig===t)return i.active;const n=ad(this.hass,e),r=ld(this.hass,e);return this._planHassMemo={hass:this.hass,sig:t,active:n,full:r},n}_captureRenderDeviceSnapshot(){if(!this.hass)return;const e=Date.now(),t=[...this._activityRt.entries()].map(([t,i])=>`${t}:${i.gen}:${i.flashTs}:`+(i.flashKind&&(i.expiresAt||i.flashTs+tg)>e?1:0)).join("|"),i=Bh(this._virtualLights);if(this._capturedSnapshotSequence===this._hassSequence&&this._capturedSnapshotDevices===this._devices&&this._capturedSnapshotLayout===this._layout&&this._capturedSnapshotConfigEpoch===this._cfgEpoch&&this._capturedSnapshotVirtual===i&&this._capturedSnapshotActivity===t)return;const n=this._planHass,r=new Map,o=new Map,s=new Set(["sun.sun"]);for(const e of this._summary?.entityIds()||[])s.add(e);this._vacFit?.source&&s.add(this._vacFit.source);const a=new Set,l=new Set,c=e=>{if(!e)return;const t=e.indexOf(":");if(t<0)return void s.add(e);const i=e.slice(0,t),n=e.slice(t+1);"device"===i?a.add(n):"entity"===i&&s.add(n)};for(const e of this._model)for(const t of e.rooms)t.area&&l.add(t.area),c(t.settings?.temp_source),c(t.settings?.hum_source);for(const e of this._serverCfg?.spaces||[])for(const t of e.openings||[])for(const e of ui(t))s.add(e);for(const e of this._serverCfg?.spaces||[])for(const t of e.decor||[])if("text"===t.kind){for(const e of String(t.text||"").matchAll(/\{([^{}\r\n]+)\}/g)){const t=Xi(e[1]);t?.entity&&s.add(t.entity)}t.entity&&s.add(t.entity),o.set(`decor:${e.id}:${t.id}`,tn(t.text,t,n,e=>!!n.entities?.[e]&&!!n.states?.[e]&&!Jd(n,e,Zd(this._markers))))}const h=Ed(n,this._devices,null,this._virtualLights);for(const e of this._devices){for(const t of[!1,!0])r.set(f_(e.id,t),p_(n,e,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:t,activityRuntime:this._activityRt.get(e.id),sourceDetails:!1,lightDevices:this._devices,lightSources:h,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion}));if(this._isVacDev(e)){const t=this._vacSource(e,n),i=t?Wc(n?.states?.[t]?.attributes):null,r=this._vacRt.get(e.id),s=lh(e.id,e.marker?.vacuum??null,e.space,t),a=hh({routes:s,observed:dh(s,[t],t=>this._vacObservedMapId(e,t,n)),spaceIds:new Set(this._model.map(e=>e.id))});o.set(`vacuum:${e.id}`,{source:t,telemetry:i,routes:s,resolution:a,mapId:i?this._vacMapId(e,i,n):null,runtime:r?{trail:r.trail,lastTs:r.lastTs,moving:r.moving,jump:r.jump}:null,server:this._vacSrvTrails[e.id]||null})}}const d=g_({sourceSequence:this._hassSequence,hass:n,devices:this._devices,presentations:r,positions:(u=this._model.length>0,p=this._devices,_=e=>this._livePos(e),u?new Map(p.map(e=>[e.id,_(e)])):new Map),facts:o,entityIds:s,deviceIds:a,areaIds:l});var u,p,_;this._capturedSnapshotSequence=this._hassSequence,this._capturedSnapshotDevices=this._devices,this._capturedSnapshotLayout=this._layout,this._capturedSnapshotActivity=t,this._capturedSnapshotConfigEpoch=this._cfgEpoch,this._capturedSnapshotVirtual=i,this._visibleDeviceSnapshot&&"steady"!==this._continuity.state?this._candidateDeviceSnapshot=d:(this._visibleDeviceSnapshot=d,this._candidateDeviceSnapshot=null)}get _renderDeviceSnapshot(){return this._stagedDeviceSnapshotToken===this._continuity.token?this._candidateDeviceSnapshot||this._visibleDeviceSnapshot:this._visibleDeviceSnapshot||this._candidateDeviceSnapshot}get _renderPlanHass(){return this._renderDeviceSnapshot?.hass||this._planHass}get _renderDevices(){return this._renderDeviceSnapshot?.devices||this._devices}get _renderVacuumDevices(){return this._renderDeviceSnapshot?.vacuumDevices||this._devices}get _fullRegistryHass(){return this._planHass,this._planHassMemo?.full||this.hass}_bindingStatus(e){return dd(this.hass,e,this._haRegistry)}houseplanDiagnostics(){const{registry:e,bindings:t}=this._renderLife.diagnostics(this.hass,this._markers,e=>this._bindingStatus(e));return{registry:{...e,lastSuccessAgeMs:e.lastSuccess?Math.max(0,Date.now()-e.lastSuccess):null},bindings:t}}_openBindingInHa(e){const[t,i]=e.split(":");if(i)if("device"!==t){if("entity"===t){const e=this._fullRegistryHass.entities?.[i];e?.device_id&&fv("/config/devices/device/"+encodeURIComponent(e.device_id))}}else fv("/config/devices/device/"+encodeURIComponent(i))}_bindingHasHaPage(e){const[t,i]=e.split(":");return!!i&&("device"===t||"entity"===t&&!!this._fullRegistryHass.entities?.[i]?.device_id)}_toggleMarkerDialogVisibility(){const e=this._markerDialog;if(!e)return;const t="ha"===e.bindingMode?this._bindingStatus(e.binding):null,i=e.hideFromPlan||"ha_disabled"===t?.kind;i&&"ha_disabled"===t?.kind?this._showToast(this._t("entity"===t.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device")):i&&"unverified"===t?.kind?this._showToast(this._t("toast.ha_binding_unverified")):this._markerDialog={...e,hideFromPlan:!i}}_hookConnection(){const e=this.hass?.connection;e&&e!==this._connHooked&&(this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),e.addEventListener?.("ready",this._onConnReady),e.addEventListener?.("disconnected",this._onConnLost),e.addEventListener?.("reconnect-error",this._onConnLost),this._connHooked=e)}_display(e){return this._signer.display(this.hass,e)}_referencedContentUrls(){const e=Nn(this._serverCfg);for(const t of this._decorAssets.values())e.add(t.url);return e}_resign(){this._signer.resign(this.hass,this._referencedContentUrls())}_onLayoutEvent(e){e<=this._layoutRev||(clearTimeout(this._layoutSyncTimer),this._layoutSyncTimer=window.setTimeout(()=>{e<=this._layoutRev||this._reloadLayoutOnly()},200))}_noteLayoutRev(e){this._adoption.noteLayoutRevision(e?.rev)}async _reloadLayoutOnly(){if(!this._serverStorage||!this.hass?.callWS)return;this._beginContinuityCandidate("layout-reload",!1);const e=new Map;for(const t of this._dirtyPos)this._layout[t]&&e.set(t,this._layout[t]);this._persistLayout.pending()&&this._persistLayout.flush();for(const[t,i]of this._sentPos)e.set(t,i);try{const t=await this.hass.callWS({type:"houseplan/layout/get"}),i={...t?.layout||{}};for(const[t,n]of e)null===n?delete i[t]:i[t]=n;this._adoption.adoptMergedLayout(i,t,()=>{this._cancelDeviceDrag(),this._devicePositionHistory.clear()}),this._canOptimizeUndo=!!t?.can_optimize_undo,this._undoKind=t?.undo_kind||null,this._cacheSnapshot(),this.requestUpdate()}catch{}finally{this._continuityDataReady=!0,this.requestUpdate()}}_persistLocalLayout(){this._layout=So(lo(this._layout)),localStorage.setItem(lv,JSON.stringify(this._layout))}_maybeRebuildDevices(){const e=this.hass;if(!e?.devices||!e?.entities||!e?.areas)return;const t=this._haRegistry,i=od(e,t)+":"+Object.keys(e.areas).length+":"+(this._norm?"n":"l")+":"+kp(e,this._config?.language);if(i===this._regSignature&&this._devices.length)return;this._regSignature=i;const n=new Map(this._devices.map(e=>[e.id,e.bindingStatus?.kind||"active"]));this._devices=iu({hass:e,registry:t,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,showAll:this._showAll,firstSpaceId:this._model[0]?.id||"",loc:e=>this._t(e),iconRules:this._iconRules});const r=this._markers.filter(e=>!e.removed&&"virtual"!==e.binding).map(e=>e.binding).sort(),o=t.revision+":"+r.join("|");if(t.authoritative&&o!==this._haBindingCacheKey){const i=new Map;for(const n of r)i.set(n,dd(e,n,t));!function(e){if("undefined"==typeof localStorage||!e.size)return;const t=hd(),i=Date.now();for(const[n,r]of e)"active"===r.kind?t[n]={kind:"active",ts:i}:"ha_disabled"===r.kind&&(t[n]={kind:"ha_disabled",reason:r.reason,ts:i});const n=Object.fromEntries(Object.entries(t).sort((e,t)=>t[1].ts-e[1].ts).slice(0,1500));Yh=n;try{localStorage.setItem(Kh,JSON.stringify(n))}catch{}}(i),this._haBindingCacheKey=o}let s=null;if(t.authoritative&&(s=this._resolveAreaRelocations(t),this._areaRelocationIds=new Set(s.relocateIds),this._areaRelocationIds.size)){this._cancelDeviceDrag();const e=this._areaRelocationIds;this._devicePositionHistory.removeWhere(({before:t,after:i})=>e.has(t.deviceId)||e.has(i.deviceId));const t=this._markerDialog;if(t?.devId&&!t.roomTouched&&this._areaRelocationIds.has(t.devId)){const e=this._devices.find(e=>e.id===t.devId);e&&(this._markerDialog={...t,room:e.marker?.room_id?`${e.space}#@${e.marker.room_id}`:e.space&&e.area?`${e.space}#${e.area}`:""})}}this._defPos=this._defaultPositions(),this._syncNewDevices(),this._seedHiddenDevices(),s&&this._syncAreaRelocations(s),this._syncActivityRuntime();const a=new Set(this._devices.filter(e=>!e.hidden).map(e=>e.id));for(const e of this._vacRt.keys())a.has(e)||this._vacRt.delete(e);if(this._infoCard){const e=this._devices.find(e=>e.id===this._infoCard.id);this._infoCard=e&&"ha_disabled"!==e.bindingStatus?.kind?e:null}const l=this._devices.some(e=>"ha_disabled"===e.bindingStatus?.kind&&"ha_disabled"!==n.get(e.id));l&&("ha_disabled"!==this._infoCard?.bindingStatus?.kind&&"ha_disabled"!==this._devices.find(e=>e.id===this._infoCard?.id)?.bindingStatus?.kind||this._closeInfoCard(),this._deviceDrag&&"ha_disabled"===this._devices.find(e=>e.id===this._deviceDrag.id)?.bindingStatus?.kind&&(this._cancelDeviceDrag(),this._devicePositionHistory.clear()),clearTimeout(this._holdTimer),this._holdFired=!1,this._tip=null,this._tapConfirm=null),this._nativeMoreInfoEntity&&!this._planEntityAvailable(this._nativeMoreInfoEntity)&&(gv(this,"hass-more-info",{entityId:null}),this._nativeMoreInfoEntity=null)}_resolveAreaRelocations(e=this._haRegistry){const t=function(e){const t=Q_(e.snapshot),i=new Set(Object.values(t).map(e=>e.binding)),n=new Map;for(const[t,r]of e.previousCandidates||[])J_(t)&&Number.isFinite(r)&&i.has(t)&&n.set(t,r);const r=new Set,o=new Set;for(const t of e.markers||[])t.removed||(Z_(t.id)&&r.add(t.id),J_(t.binding)&&o.add(t.binding));const s=new Set(Object.keys(e.registryDevices||{})),a=new Set(Object.keys(e.registryEntities||{})),l=new Set(Object.keys(e.liveStates||{})),c=new Map;for(const[e,i]of Object.entries(t)){const t=c.get(i.binding)||[];t.push(e),c.set(i.binding,t)}const h=new Set;let d=!1;for(const[t,i]of c){const[c,u]=rm(t);if(o.has(t)||i.some(e=>r.has(e))||("device"===c?s.has(u):a.has(u)||l.has(u))){n.delete(t);continue}const p="device"===c?s.size>0:a.size>0;if(!e.authoritative||!p)continue;const _=n.get(t);if(void 0!==_){if(_!==e.revision)for(const e of i)h.add(e)}else n.set(t,e.revision),d=!0}return{removeIds:h,candidates:n,needsConfirmationRefresh:d}}({snapshot:this._settings.marker_area_snapshot,authoritative:e.authoritative,revision:e.revision,registryDevices:e.devices,registryEntities:e.entities,liveStates:this.hass?.states,markers:this._markers,previousCandidates:this._areaSnapshotCleanupCandidates});return this._areaSnapshotCleanupCandidates=t.candidates,t.needsConfirmationRefresh&&this._canEdit&&id(this.hass),om({devices:this._devices,model:this._model,layout:this._layout,snapshot:this._settings.marker_area_snapshot,authoritative:e.authoritative,cleanupSnapshotIds:t.removeIds,coordinateScale:_v})}_syncNewDevices(){if(!this._norm||!this._loadOk||!this._serverCfg)return;const e=this._devices.filter(e=>!e.marker&&!e.virtual).map(e=>e.id).sort(),t=e.join(",");if(t===this._newSyncKey)return;this._newSyncKey=t;const i=this._settings,{fresh:n,known:r}=function(e,t){if(!Array.isArray(t))return{fresh:[],known:[...e]};const i=new Set(t),n=e.filter(e=>!i.has(e));return{fresh:n,known:n.length?[...t,...n]:t}}(e,i.known_devices);if(!Array.isArray(i.known_devices)||n.length){const e=[...new Set([...i.new_device_ids||[],...n])];this._serverCfg={...this._serverCfg,settings:{...i,known_devices:r,new_device_ids:e}},this._saveConfig()}}_syncAreaRelocations(e){if(!(this._loadOk&&this._serverCfg&&this._norm&&this._canEdit&&this._haRegistry.authoritative))return;const t=e.decisions.filter(e=>e.updateSnapshot||e.removeSnapshot);if(!t.length)return;const i=cc({snapshot:Q_(this._settings.marker_area_snapshot),decisions:t});i!==this._areaRelocationSyncKey&&(this._areaRelocationSyncKey=i,this._areaRelocationWrite=this._areaRelocationWrite.catch(()=>{}).then(async()=>{if(!this._serverCfg||!this._haRegistry.authoritative)return;const e=this._resolveAreaRelocations();this._areaRelocationIds=new Set(e.relocateIds);const t=new Set,i=new Map;let n=!1;for(const r of e.decisions){if(!r.relocate)continue;const e=fg(this._layout,r.id);try{await this._persistDevicePlacement(r.id,null),t.add(r.id),e&&i.set(r.id,e),this._areaRelocationIds.delete(r.id)}catch(t){n=!0,this._layout=vg(this._layout,r.id,e),this._showToast(this._t("toast.pos_save_failed",{err:this._errText(t)}))}}const r=this._settings,o=function(e,t,i=new Set){const n=Q_(e);for(const e of t.decisions)e.removeSnapshot?delete n[e.id]:e.updateSnapshot&&e.binding&&e.area&&(e.relocate&&!i.has(e.id)||(n[e.id]={binding:e.binding,area:e.area}));return n}(r.marker_area_snapshot,e,t),s=[...new Set([...Array.isArray(r.new_device_ids)?r.new_device_ids:[],...t])],a=cc(o)!==cc(Q_(r.marker_area_snapshot)),l=cc(s)!==cc(Array.isArray(r.new_device_ids)?r.new_device_ids:[]);if(a||l){const e=r.marker_area_snapshot,n=r.new_device_ids,a={...this._serverCfg,settings:{...r,marker_area_snapshot:o,...l?{new_device_ids:s}:{}}};this._setAreaLifecycleConfig(a);try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.cancel(),await this._writeConfig()}catch(r){const a=this._settings;if(cc(a.marker_area_snapshot)===cc(o)&&cc(a.new_device_ids)===cc(l?s:n)){const t={...a};void 0===e?delete t.marker_area_snapshot:t.marker_area_snapshot=e,void 0===n?delete t.new_device_ids:t.new_device_ids=n;const i={...this._serverCfg,settings:t};this._setAreaLifecycleConfig(i),this._adoption.refreshConfigFingerprint()}for(const e of t)this._areaRelocationIds.add(e);const c=new Set;for(const[e,t]of i)try{await this._persistDevicePlacement(e,t)}catch(t){c.add(e),this._showToast(this._t("toast.pos_save_failed",{err:this._errText(t)}))}this._areaRelocationSyncKey="",this._regSignature="";if("conflict"===(r&&"object"==typeof r&&"code"in r?r.code:void 0)?(this._showToast(this._t("toast.conflict")),await this._reloadConfigOnly(!0)):this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(r)})),c.size&&this._serverCfg){const e=this._settings,t=[...new Set([...Array.isArray(e.new_device_ids)?e.new_device_ids:[],...c])],i={...this._serverCfg,settings:{...e,new_device_ids:t}};this._setAreaLifecycleConfig(i);try{await this._writeConfig()}catch(e){this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(e)}))}}}}n&&(this._areaRelocationSyncKey=""),this.requestUpdate()}))}get _newIds(){const e=this._settings.new_device_ids;return new Set([...Array.isArray(e)?e:[],...this._areaRelocationIds])}_ackNewDevice(e){if(!this._newIds.has(e)||!this._serverCfg)return;const t=this._settings;this._serverCfg={...this._serverCfg,settings:{...t,new_device_ids:(t.new_device_ids||[]).filter(t=>t!==e)}},this._saveConfig(),this.requestUpdate()}get _markers(){return this._serverCfg?.markers||[]}_roomLqi(e){if(!e)return null;const t=[];for(const i of this._renderDevices){if(i.area!==e||i.virtual)continue;const n=Ld(this._renderPlanHass,i.entities);null!=n&&t.push(n)}return Ii(t)}_roomBounds(e){if(e.poly&&e.poly.length){const t=e.poly.map(e=>e[0]),i=e.poly.map(e=>e[1]),n=Math.min(...t),r=Math.min(...i);return{x:n,y:r,w:Math.max(...t)-n,h:Math.max(...i)-r}}return{x:e.x??0,y:e.y??0,w:e.w??0,h:e.h??0}}_defaultPositions(){const e={},t=this._config?.icon_size??2.5;for(const i of this._model){const n=t/100*Ml(i)*1.3;for(const t of i.rooms){if(!t.area)continue;const r=this._devices.filter(e=>e.area===t.area&&e.space===i.id);if(!r.length)continue;const o=this._roomBounds(t),s=.1*Math.min(o.w,o.h),a=o.w-2*s,l=o.h-2*s,c=Math.max(1,Math.round(Math.sqrt(r.length*a/Math.max(l,1)))),h=Math.ceil(r.length/c),d=a/c,u=l/Math.max(h,1),p=r.map((e,t)=>({x:o.x+s+d*(t%c+.5),y:o.y+s+u*(Math.floor(t/c)+.5)}));Ei(p,o,n,.5*s),r.forEach((t,i)=>e[t.id]=al(p[i]))}}return e}_pos(e){const t=this._renderDeviceSnapshot?.positions.get(e.id);return t?{x:t.x,y:t.y}:this._livePos(e)}_livePos(e){const t=this._spaceModelById(e.space),i=this._areaRelocationIds.has(e.id)?void 0:this._layout[e.id];if(i)if(this._norm){if(i.s===e.space)return{x:i.x*_v,y:i.y*_v}}else if(void 0===i.s)return{x:i.x,y:i.y};return this._defPos[e.id]?this._defPos[e.id]:t?al($l(t)):{x:500,y:500}}_devicePlacementForCanvas(e,t,i){if(!this._norm)return{x:Math.round(t),y:Math.round(i)};const n=this._gridPitch,r=Math.round(t/n)*n,o=Math.round(i/n)*n;return{s:e.space,x:cl(r/_v),y:cl(o/_v)}}_previewDevicePlacement(e,t){this._layout=vg(this._layout,e,t),this.requestUpdate()}_cancelDeviceDrag(){const e=this._deviceDrag;if(!e)return!1;this._editorRuntime?._cancelPointerMove("device"),this._deviceDrag=null,this._deviceHits.cancel(e.pointerId);try{e.source?.hasPointerCapture?.(e.pointerId)&&e.source.releasePointerCapture(e.pointerId)}catch{}return this._previewDevicePlacement(e.id,e.before),!0}async _persistDevicePlacement(e,t){if(this._layout=vg(this._layout,e,t),this._serverStorage){let i=null,n=!1;try{let r;if(null===t)i=null,this._sentPos.set(e,i),n=!0,r=await this.hass.callWS({type:"houseplan/layout/delete",device_id:e});else{const t=xo(this._layout[e]);cc(t)!==cc(this._layout[e])&&(this._layout={...this._layout,[e]:t}),i=t,this._sentPos.set(e,i),n=!0,r=await this.hass.callWS({type:"houseplan/layout/update",device_id:e,pos:t})}this._noteLayoutRev(r),this._adoption.refreshLayoutFingerprint(),this._cacheSnapshot()}finally{n&&this._sentPos.get(e)===i&&this._sentPos.delete(e)}return}this._persistLocalLayout()}_devicePositionStateValid(e){const t=this._devices.find(t=>t.id===e.deviceId);return!!t&&t.space===e.spaceId&&"ha_disabled"!==t.bindingStatus?.kind&&!!this._spaceModelById(e.spaceId)}async _runDevicePositionHistory(e){if(this._cancelDeviceDrag()||this._devicePositionBusy)return;const t="undo"===e?this._devicePositionHistory.undo():this._devicePositionHistory.redo();if(!t)return;const i="undo"===e?t.before:t.after;if(!this._devicePositionStateValid(i))return this._devicePositionHistory.clear(),this._showToast(this._t("history.device_stale")),void this.requestUpdate();const n=fg(this._layout,i.deviceId);i.spaceId!==this._space&&(this._commitSpace(i.spaceId),this._restoreZoom()),this._devicePositionBusy=!0,this._previewDevicePlacement(i.deviceId,i.placement);try{await this._persistDevicePlacement(i.deviceId,i.placement),this._showToast(this._t("undo"===e?"history.undone":"history.redone",{name:t.name}))}catch(t){this._previewDevicePlacement(i.deviceId,n),"undo"===e?this._devicePositionHistory.redo():this._devicePositionHistory.undo(),this._showToast(this._t("toast.pos_save_failed",{err:this._errText(t)}))}finally{this._devicePositionBusy=!1,this.requestUpdate()}}_undoDevicePosition(){this._runDevicePositionHistory("undo")}_redoDevicePosition(){this._runDevicePositionHistory("redo")}_savePos(e,t,i){this._spaceModelById(e.space)&&(this._layout=vg(this._layout,e.id,this._devicePlacementForCanvas(e,t,i)),this._dirtyPos.add(e.id),this._persistLayout())}_devicePresentation(e,t=!1!==this._config?.show_signal,i=!1){const n=i?null:this._renderDeviceSnapshot?.presentations.get(f_(e.id,t));return n||p_(this._renderPlanHass,e,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:t,designPreview:i,activityRuntime:this._activityRt.get(e.id),sourceDetails:!1,lightDevices:this._renderDevices,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion})}_deviceVisual(e){return this._devicePresentation(e).visual}_stateClass(e,t=this._deviceVisual(e)){const i=this._devicePresentation(e);return i.effectiveHidden?"":("icon_ripple"!==i.display||!1===this._config?.live_states||"alarm"===t.status||t.activity,u_({...i,visual:t}).join(" "))}_liveTemp(e){if(!this._config?.show_temperature)return null;if(!0===e.marker?.use_climate_temp){const t=qd(this._renderPlanHass,e.entities);if(null!=t)return t}return"mdi:thermometer"!==e.icon&&"mdi:air-filter"!==e.icon?null:Bd(this._renderPlanHass,e.entities)}_bindingEntities(e){if("virtual"===e||!e)return[];const t=this._bindingStatus(e);return"active"===t.kind?t.enabledEntityIds:t.allEntityIds}_bindingHasClimate(e){return this._bindingEntities(e).some(e=>e.startsWith("climate."))}_bindingHasAlarm(e){return this._bindingEntities(e).some(e=>{const t=this._planHass?.states?.[e]||this.hass?.states?.[e],i=this._fullRegistryHass.entities[e]||this.hass?.entities?.[e];return Yn(e.split(".")[0],t?.attributes?.device_class||i?.device_class||i?.original_device_class)})}_deviceBindingActive(e,t=!0){if(e.virtual||"virtual"===e.bindingKind)return!0;if(!e.bindingKind||!e.bindingRef)return!1;const i=this._bindingStatus(`${e.bindingKind}:${e.bindingRef}`);return"active"===i.kind||(t&&this._showToast(this._t("ha_disabled"===i.kind?"toast.ha_disabled_action":"toast.ha_binding_unverified")),!1)}_openMoreInfo(e){e?this._planEntityAvailable(e)?(this._kiosk&&(this._cyclePausedUntil=Math.max(this._cyclePausedUntil,Date.now()+6e4)),this._nativeMoreInfoEntity=e,gv(this,"hass-more-info",{entityId:e})):this._showToast(this._t("toast.ha_disabled_action")):this._showToast(this._t("toast.no_entity"))}_interruptViewGesture(e,t){if(clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),void 0!==e)for(const i of[t,this._stageEl])try{i?.hasPointerCapture?.(e)&&i.releasePointerCapture(e)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null,this._roomPointer=null,this._doubleFit.clear(),this._deviceHits.clearPointers()}_closeInfoCard(){this._interruptViewGesture(),this._holdFired=!1,this._infoCard=null}_invalidateDeviceHitGeometry(){this._deviceHits.invalidate()}_resetDeviceHitState(){this._deviceHits.reset(this.renderRoot)}_deviceHitOwnerAt(e,t){return"view"!==this._mode&&"devices"!==this._mode?null:this._deviceHits.at(this.renderRoot,this._renderDevices,this._space,e,t)}_deviceForPointerEvent(e,t){return this._deviceHits.pointer(this.renderRoot,this._renderDevices,this._space,e,t)}_deviceForClickEvent(e,t){return this._deviceHits.click(this.renderRoot,this._renderDevices,this._space,e,t)}_showDeviceTip(e,t){this._liveRt?this._liveRt.devicePointerTip(e,t):this._ensureLiveRuntime().then(()=>this._liveRt?.devicePointerTip(e,t))}_showDeviceFocusTip(e,t){const i=e.currentTarget;this._liveRt?this._liveRt.deviceFocusTip(i,t):this._ensureLiveRuntime().then(()=>this._liveRt?.deviceFocusTip(i,t))}_hideDeviceFocusTip(e){this._liveRt?.deviceBlur(e)}_clearPointerHover(){this._liveRt?this._liveRt.pointerLeave():this._clearTransientHover()}_ctxDevice(e,t){"view"===this._mode&&(t=this._deviceForPointerEvent(e,t),e.preventDefault(),e.stopPropagation(),this._deviceBindingActive(t)&&(t.primary?this._openMoreInfo(t.primary):this._infoCard=t))}_clickDevice(e,t){if("view"!==this._mode&&"devices"!==this._mode)return;if(e.stopPropagation(),t=this._deviceForClickEvent(e,t),this._deviceDrag?.moved||this._suppressClick||this._holdFired)return;if("devices"===this._mode)return void this._openMarkerDialog(t);const i=this._devices.find(e=>e.id===t.id);if(!i)return;const n=Tu(i.tapAction,i.primary?.split(".")[0]);if("none"===n)return;const r=(e,t)=>{i.marker?.tap_confirm?this._tapConfirm={kind:"run",text:e,exec:t}:t()};if("toggle"===n){const e=this._toggleIntent(i);if(!e)return;if(!Iu(e))return void this._showUnavailableToggleTargets(e);const t=e=>{const t=Iu(e);if(!t)return;if("virtual-light"===t.kind)return this._startDevicePressFeedback(i.id),void this.hass.callWS({type:"houseplan/virtual_light/toggle",marker_id:t.markerId}).then(e=>{const t=Wh(this._virtualLights,e);t!==this._virtualLights&&(this._virtualLights=t,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}).catch(e=>this._showToast(this._t("toast.virtual_light_toggle_failed",{err:this._errText(e)})));const{command:n}=t;this._startDevicePressFeedback(i.id),this.hass.callService(n.domain,n.service,n.data).catch(e=>this._showToast(this._t("toast.error",{err:this._errText(e)})))},n=((o=e).targets.length?o.targets:o.skippedTargets).map(e=>e.name||e.entityId||e.ref).join(", ")||i.name;if(i.marker?.tap_confirm){const r=this._toggleConfirmationLines(e);if(!r.length)return;this._tapConfirm={kind:"toggle",text:this._t("confirm.tap_toggle",{name:n}),lines:r,initialIntent:e,deviceId:i.id,exec:()=>{const n=this._devices.find(e=>e.id===i.id),r=n?this._toggleIntent(n):null;r&&!Iu(r)&&this._showUnavailableToggleTargets(r)||(r&&Eu(e,r)?t(r):this._showToast(this._t("toast.tap_target_changed")))}}}else t(e);return}var o;if("info"===n)return this._interruptViewGesture(),void(this._infoCard=i);if(this._deviceBindingActive(i)){if("run"===n){const e=i.marker?.tap_target||"",t=function(e){const t=String(e||"").split(".")[0];return"automation"===t?{domain:"automation",service:"trigger"}:"script"===t?{domain:"script",service:"turn_on"}:"scene"===t?{domain:"scene",service:"turn_on"}:null}(e),n=this.hass.states[e];if(!t||!n)return void this._showToast(this._t("toast.run_target_missing"));const o=n.attributes?.friendly_name||e;return void r(this._t("confirm.tap_run",{name:o}),()=>{this._deviceBindingActive(i)&&this._planEntityAvailable(e)&&(this._startDevicePressFeedback(i.id),this.hass.callService(t.domain,t.service,{entity_id:e}).then(()=>{this._stampActivity(i.id,"event",this._activitySourceKey(i)),this.requestUpdate(),this._showToast(this._t("toast.run_started",{name:o}))}).catch(e=>this._showToast(this._t("toast.error",{err:this._errText(e)}))))})}"more-info"===n&&i.primary?this._openMoreInfo(i.primary):this._infoCard=i}}_showUnavailableToggleTargets(e){const t=function(e){if(!e||"group"!==e.kind||Iu(e)||"configured-targets-missing"!==e.noneReason)return[];if(!e.skippedTargets.length||e.skippedTargets.some(e=>!Ou.has(e.reason)&&"secure"!==e.reason))return[];const t=[],i=new Set;for(const n of e.skippedTargets){if(!Ou.has(n.reason))continue;const e=String(n.name||n.entityId||n.ref||"").trim();e&&!i.has(e)&&(i.add(e),t.push(e))}return t}(e);return!!t.length&&(this._showToast(1===t.length?this._t("toast.toggle_target_unavailable",{name:t[0]}):this._t("toast.toggle_targets_unavailable",{names:t.join(", ")})),!0)}_keyDevice(e,t){"Enter"!==e.key&&" "!==e.key||"view"!==this._mode&&"devices"!==this._mode||(e.preventDefault(),this._clickDevice(e,t))}_startDevicePressFeedback(e){const t=[...this.renderRoot.querySelectorAll(".dev[data-id]")].find(t=>t.dataset.id===e),i=t?.querySelector(".device-shell");if(!i||"function"!=typeof i.animate)return;const n=Number.parseFloat(this.ownerDocument.defaultView?.getComputedStyle(i).scale||""),r=Number.isFinite(n)?Math.max(.95,Math.min(1,n)):1;this._devicePressAnimations.get(e)?.cancel();const o=this._reducedMotion?[{outlineColor:"transparent",outlineStyle:"solid",outlineWidth:"0px"},{outlineColor:"var(--hp-accent, #3ea6ff)",outlineStyle:"solid",outlineWidth:"2px",outlineOffset:"2px",offset:.5},{outlineColor:"transparent",outlineStyle:"solid",outlineWidth:"0px"}]:[{scale:String(r)},{scale:"0.95",offset:.5},{scale:"1"}],s=i.animate(o,{duration:200,easing:"cubic-bezier(.22,.61,.36,1)"});this._devicePressAnimations.set(e,s);const a=()=>{this._devicePressAnimations.get(e)===s&&this._devicePressAnimations.delete(e)};s.addEventListener("finish",a,{once:!0}),s.addEventListener("cancel",a,{once:!0})}_cancelDevicePressFeedback(){for(const e of this._devicePressAnimations.values())e.cancel();this._devicePressAnimations.clear()}_pruneDevicePressFeedback(){if(!this._devicePressAnimations.size)return;const e=new Set([...this.renderRoot.querySelectorAll(".dev[data-id]")].map(e=>e.dataset.id||""));for(const[t,i]of this._devicePressAnimations)e.has(t)||(i.cancel(),this._devicePressAnimations.delete(t))}_t(e,t){return xp(kp(this.hass,this._config?.language),e,t)}get _colorPickerLabels(){return{title:this._t("color_picker.title"),hue:this._t("color_picker.hue"),saturation:this._t("color_picker.saturation"),value:this._t("color_picker.value"),hex:this._t("color_picker.hex"),invalidHex:this._t("color_picker.invalid_hex"),confirm:this._t("color_picker.confirm")}}_help(e){return this._editorRuntimeOrThrow()._help(e)}get _stageEl(){return this.renderRoot.querySelector(".stage")}_contentItems(e){const t=[];for(const i of this._devices){if(i.space!==e.id||i.hidden)continue;const n=this._pos(i);t.push({minX:n.x,minY:n.y,maxX:n.x,maxY:n.y})}if(e.id===this._space){for(const e of this._openingsR){const i=Number(e.angle)*Math.PI/180,n=Math.cos(i)*e.rlen/2,r=Math.sin(i)*e.rlen/2,o=pl([[e.rx-n,e.ry-r],[e.rx+n,e.ry+r]]);o&&t.push(o)}const i=this._decorH;for(const e of this._decorList){if("image"===e.kind&&!this._decorAssets.has(e.asset_id)&&"decor"!==this._mode)continue;const n=pl("line"===e.kind?[[e.x1*_v,e.y1*i],[e.x2*_v,e.y2*i]]:"text"===e.kind?[[e.x*_v,e.y*i]]:Nr({x:e.x*_v,y:e.y*i,w:e.w*_v,h:e.h*i,angle:e.angle}));n&&t.push(n)}for(const i of this._physicalBodiesR(e)){const e=pl(i);e&&t.push(e)}}return vl(e,t)}_frameOf(){const e=this._spaceModel();if(!e){this._frame=null;const e={x:0,y:0,w:_v,h:_v};return{rect:e,all:e,outliers:0}}const t=this._frame,i="view"!==this._mode;if(t&&t.id===e.id&&this._bdDrag)return t;if(t&&t.id===e.id&&t.model===e&&t.layout===this._layout&&t.devs===this._devices&&t.far===this._showFar&&t.grow===i)return t;const n=kl(this._contentItems(e));let r=n.all||Sl(e),o=this._showFar?r:n.core||Sl(e);return t&&t.id===e.id&&i&&t.grow&&(o=mv(t.rect,o),r=mv(t.all,r)),this._frame={id:e.id,model:e,layout:this._layout,devs:this._devices,far:this._showFar,grow:i,rect:o,all:r,outliers:n.outliers},this._frame}_isoSource(){const e=this._isoSceneRuntime;if(!e)return null;const t=this._spaceModel();if(!t)return null;const i=this._spaceWalls,n=this._openCuts(),r=this._openingsR;return e.createIsoStructuralSource({space:t,walls:i,openCuts:n,openings:r,partitionCuts:()=>this._partitionOpeningCuts(t),roomOpenings:()=>this._roomWallOpeningInputs(r,t),cellCm:this._cellCm,gridPitch:this._gridPitch,wallKeyPitch:this._wallKeyPitch,coordinateScale:_v,onBuild:()=>{this._isoStructuralBuildCount+=1}})}_isoSceneKey(){if(!this._labsIso||"view"!==this._mode)return null;try{return this._isoSource()?.key??null}catch{return this._isoInvalidKey()}}_isoInvalidKey(){return`${this._space}|invalid|${this._cfgEpoch}`}_clearIsoInvalidFallback(e){const t=`${this._space}|invalid|`;for(const i of this._isoFallback)i.startsWith(t)&&i!==e&&this._isoFallback.delete(i)}_isoScene(e=this._isoSource()){const t=this._isoSceneRuntime;if(!t||!e)return null;let i=this._frameOf().rect;const n=this._spaceDisplayForRender(),r=this._spaceModel();if(r&&n.showNames)for(const e of r.rooms)if(e.name){const t=this._labelPos(e,r.id);i=mv(i,{x:t.x,y:t.y,w:0,h:0})}const o=t.resolveIsoScene({source:e,cache:this._isoGeometryCache,cellCm:this._cellCm,liveFrame:i});if(!r||!n.showBorders)return o;const s=this._config?.icon_size??2.5,a=s>8?2.5:s,l=this._stageEl?.getBoundingClientRect?.()??null,c=l?.height?l.width/l.height:o.frame.w/o.frame.h,h=Oi([o.frame.x,o.frame.y,o.frame.w,o.frame.h],c),d=this._isoOverlayScene(r,this._renderDevices.filter(e=>e.space===r.id&&!e.hidden),h,n,t.resolveIsoDecorationLayers(n),o,a,x_(a),n.showLqi??this._config?.show_signal??!0,!1),u=d&&t.resolveIsoOverlayFitEnvelope({baseBounds:o.frame,entries:d.entries,stageSize:l,targetView:e=>Oi([e.x,e.y,e.w,e.h],c)});return u?{...o,frame:u.bounds,overlayFitEntries:d.entries}:o}_latchIsoFallback(e,t){if(this._isoFallback.has(e))return;this._isoFallback.add(e);const i=e.includes("|invalid|")?"invalid":e.split("|").pop()||"invalid";console.warn("HOUSEPLAN ISO FALLBACK: #89/#160",wf("structural",i,!0))}_effectiveProjection(){if(this._isoProjectionSnapshot)return this._isoProjectionSnapshot;const e=e=>this._isoProjectionSnapshot=e,t=()=>("iso"===this._renderProjection&&(this._cancelCameraTransition(!1),this._view=null,this._viewModeSnap=null),e("flat"));if(this._renderIsoScene=null,"iso"!==this._desiredProjection||!this._model.length||!this._isoSceneRuntime)return e("flat");if(!this._spaceDisplayForRender().showBorders)return this._isoFallback.has(`${this._space}|no-borders`)?t():e("iso");let i=this._isoInvalidKey();if(this._clearIsoInvalidFallback(i),this._isoFallback.has(i))return t();try{const n=this._isoSource();if(!n)return e("flat");if(i=n.key,this._isoFallback.has(i))return t();const r=this._isoScene(n);return r?this._isoFallback.has(r.key)?t():(this._renderIsoScene=r,e("iso")):e("flat")}catch(e){return this._latchIsoFallback(i,e),t()}}_scenePoint(e){return"iso"===this._renderProjection?lf(e,0):e}_floorView(e){if("iso"!==this._renderProjection)return e;const t=cf([e.x,e.y]),i=cf([e.x+e.w,e.y+e.h]);return{x:t[0],y:t[1],w:i[0]-t[0],h:i[1]-t[1]}}_isoOverlayScene(e,t,i,n,r,o,s,a,l,c=!0){const h=this._isoSceneRuntime;return h&&r?.structural&&o?h.buildIsoOverlayRenderScene({space:e,devices:t,openings:this._openingsR,view:i,display:n,wallSilhouettes:o.wallSilhouettes,resolveCollisions:c,iconPct:s,deviceBasePct:a,showLqi:l,cellCm:this._cellCm,kioskIconScale:"view"===this._mode?this._kioskScale.icon:1,kioskFontScale:"view"===this._mode?this._kioskScale.font:1,stageSize:this._stageEl?.getBoundingClientRect?.(),positionOf:e=>this._pos(e),presentationOf:(e,t)=>this._devicePresentation(e,t),labelPositionOf:(e,t)=>this._labelPos(e,t),labelScaleOf:e=>this._labelScale(e),openingEntityAvailable:e=>this._renderOpeningEntityAvailable(e),openingWallIndex:()=>this._openingWallIndexFor(e,this._openCuts()).value}):null}_baseVb(e=this._effectiveProjection(),t=this._renderIsoScene){if("iso"===e){if(!this._spaceDisplayForRender().showBorders){const e=uf({rect:this._frameOf().rect,wallHeight:0});return[e.x,e.y,e.w,e.h]}const e=t?.frame??this._frameOf().rect;return[e.x,e.y,e.w,e.h]}const i=this._frameOf().rect;return[i.x,i.y,i.w,i.h]}get _outliers(){return this._showFar?0:this._frameOf().outliers}_fitFar(){this._clearRoomFocus(),this._showFar=!0,this._frame=null,this.requestUpdate(),this._resetZoom()}_clearRoomFocus(e=!1){this._doubleFit.clear(),this._roomFocus=null,e&&(this._roomPointer=null)}_roomFitBounds(e,t){const i=ni(e);if(!i||!e.id)return null;const n=this._spaceWalls,r=this._openCuts(),o=this._wallUnionGeometry(),s=n.length&&this._innerRoomContour(t,e.id,r,o?.roomGeom,o?.multiWallNodes)||i,a=this._spaceDisplayForRender();let l=[];if(a.showBorders&&n.length){const i=Fs(t.rooms,e.id,n,r,this._wallKeyPitch,this._cellCm,this._gridPitch,_v);i&&(l=aa(i.poly,i.offsets,o?.multiWallNodes)||i.poly)}const c=this._effectiveProjection();return function(e){const t=e.floor,i=e.wall||[],n=e.padding??0;if(!t.length||!t.every(vf)||!i.every(vf)||!Number.isFinite(n)||n<0)return null;if("flat"===e.projection)return bf([...t,...i],n);const r=e.wallHeight??0,o=e.floorDepth??0;if(!Number.isFinite(r)||r<0||!Number.isFinite(o)||o<0)return null;try{const e=[];for(const i of t){const t=[i[0],i[1]];e.push(lf(t,0)),o>0&&e.push(lf(t,-o))}for(const t of i){const i=[t[0],t[1]];e.push(lf(i,0)),r>0&&e.push(lf(i,r))}return bf(e,n)}catch{return null}}({floor:s,wall:l,projection:c,wallHeight:"iso"===c&&a.showBorders?Wa(84,this._cellCm):0,floorDepth:"iso"===c&&a.showBorders?Wa(10,this._cellCm):0,padding:a.showBorders?Wa(1.25,this._cellCm):0})}_fitRoom(e,t=!0){if("view"!==this._mode)return!1;this._doubleFit.clear();const i=this._spaceModel(),n=i?.rooms.find(t=>t.id===e);if(!i||!n)return this._clearRoomFocus(),!1;let r=this._roomFitBounds(n,i);if(!r)return this._clearRoomFocus(),!1;this._roomFocus={spaceId:i.id,roomId:e};const o=this._stageEl;if(!o||o.clientWidth<=0||o.clientHeight<=0)return!0;const s=Oi(this._baseVb(),o.clientWidth/o.clientHeight),a=e=>function(e){const t=e.safeFraction??.8,{bounds:i,baseFit:n,stageWidth:r,stageHeight:o,minZoom:s,maxZoom:a}=e;if(!yf(i)||!yf(n)||!Number.isFinite(r)||r<=0||!Number.isFinite(o)||o<=0||!Number.isFinite(s)||s<=0||!Number.isFinite(a)||a1)return null;const l=r/o,c=Math.max(i.w/t,i.h/t*l);if(!Number.isFinite(c)||c<=0)return null;const h=Math.min(a,Math.max(s,n.w/c)),d=n.w/h,u=d/l;return{zoom:h,viewBox:{x:i.x+i.w/2-d/2,y:i.y+i.h/2-u/2,w:d,h:u}}}({bounds:e,baseFit:s,stageWidth:o.clientWidth,stageHeight:o.clientHeight,minZoom:wv.ZOOM_MIN,maxZoom:wv.ZOOM_MAX});let l=a(r);const c=this._isoSceneRuntime,h=this._renderIsoScene?.overlayFitEntries;if(l&&"iso"===this._effectiveProjection()&&c&&h?.length){const e=c.resolveIsoOverlayFitEnvelope({baseBounds:r,entries:h,ownerId:n.id,stageSize:{width:o.clientWidth,height:o.clientHeight},targetView:e=>a(e)?.viewBox??null});e&&(r=e.bounds,l=a(r))}if(!l)return this._clearRoomFocus(),!1;const d=this._cameraState(),u=function(e,t,i,n){const r=[e,t,i,n],o=Math.min(...r.map(e=>e.x)),s=Math.min(...r.map(e=>e.y));return{x:o,y:s,w:Math.max(...r.map(e=>e.x+e.w))-o,h:Math.max(...r.map(e=>e.y+e.h))-s}}(s,d.viewBox,l.viewBox,r);return l.viewBox=this._clampView(l.viewBox,u),t?(this._prepareCameraCommand(),this._startCameraTransition(l,u,"room",220),!0):(this._cancelCameraTransition(!1),Xg(d,l)||(this._zoom=l.zoom,this._view={...l.viewBox},this.requestUpdate()),!0)}_fitAll(e="fit"){this._clearRoomFocus(),this._showFar=!0,this._frame=null,this.requestUpdate(),this._resetZoom(e)}_renderFarHint(){return this._kiosk||"view"!==this._mode||this._booting||!this._outliers?G:j`
${this._t("canvas.far_objects",{n:this._outliers})} @@ -816,7 +816,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${this._renderOpeningLocks(S,R?.locks)} ${g.showNames||this._markup?a.rooms.map(e=>this._renderRoomLabel(e,a,S,g,R?.rooms.get(e))):G} ${this._markup?a.rooms.map(e=>this._renderRoomGear(e,a,S)):G} - ${q={hass:this.hass,settings:this._settings,devices:this._renderDevices,registry:this._haRegistry,currentSpace:a.id,spaces:this._serverCfg?.spaces,viewKey:S,view:"view"===this._mode,kiosk:this._kiosk},q.view&&!q.kiosk&&!0===q.hass?.user?.is_admin&&zg(q.settings).enabled?(import("./hp-zigbee-topology-overlay-jGSF0zVB.js"),j``):G}
@@ -1105,4 +1105,4 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc 45% · ${this._t("roomcard.light_partial",{on:1,total:3})} -
`}_renderRoomDialog(){return this._editorRuntimeOrThrow()._renderRoomDialog()}}wv.properties={_tabDrag:{state:!0},_hdrH:{state:!0},_booting:{state:!0},_bootFading:{state:!0},_bootSoft:{state:!0},_continuityEpoch:{state:!0},_editorRuntimeLoadingVisible:{state:!0},_backdropGuard:{state:!0},_tapConfirm:{state:!0},_dangerConfirm:{state:!0},hass:{attribute:!1},panelHost:{type:Boolean,attribute:"panel-host",reflect:!0},narrow:{attribute:!1},_config:{state:!0},_space:{state:!0},_devices:{state:!0},_selId:{state:!0},_toast:{state:!0},_mode:{state:!0},_tool:{state:!0},_wallDialog:{state:!0},_drawWallField:{state:!0},_activeWallChainId:{state:!0},_physicalSel:{state:!0},_physicalDialog:{state:!0},_partitionDeleteDialog:{state:!0},_roomDeleteDialog:{state:!0},_physicalDrag:{state:!0},_physicalRotate:{state:!0},_duplicateColumnId:{state:!0},_opMeasure:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingPreset:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorEraseConfirm:{state:!0},_decorTextDialog:{state:!0},_decorShapeDialog:{state:!0},_backdropDialog:{state:!0},_furnPalette:{state:!0},_decorImagePalette:{state:!0},_decorAssetCatalog:{state:!0},_decorAssetBusy:{state:!0},_furnCategory:{state:!0},_furnPreviewInput:{state:!0},_bdDrag:{state:!0},_dtBox:{state:!0},_dtDrag:{state:!0},_kioskDialog:{state:!0},_vacFit:{state:!0},_vacAllCamerasFor:{state:!0},_vacCalConfirm:{state:!0},_kioskDots:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_roomEditId:{state:!0},_roomFill:{state:!0},_roomCustomFill:{state:!0},_roomTempMin:{state:!0},_roomTempMax:{state:!0},_roomTempSrc:{state:!0},_roomHumSrc:{state:!0},_roomSrcOpen:{state:!0},_roomSrcFilter:{state:!0},_roomNameScale:{state:!0},_roomLabelScale:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_deviceInbox:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_pdfDialog:{state:!0},_supportDialog:{state:!0},_alignDialog:{state:!0},_preflightClipboardFallback:{state:!0},_backupExportDialog:{state:!0},_backupImportDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0}},wv.ZOOM_MAX=8,wv.ZOOM_MIN=1/3,wv.styles=[ap,mg],customElements.get("houseplan-card")||customElements.define("houseplan-card",wv),window.customCards=window.customCards||[],window.customCards.find(e=>"houseplan-card"===e.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info(`%c HOUSEPLAN-CARD %c v${iv} `,"background:#3ea6ff;color:#04121f;font-weight:700","");export{T_ as $,G as A,Li as B,Ep as C,Hi as D,U as E,Ni as F,xd as G,si as H,ol as I,nl as J,ni as K,Ju as L,sp as M,zs as N,Ro as O,rp as P,Xu as Q,is as R,Os as S,ji as T,Qu as U,la as V,da as W,Oo as X,Mo as Y,Bo as Z,C_ as _,lh as a,oi as a$,Ss as a0,ao as a1,Zo as a2,_i as a3,Yo as a4,ko as a5,So as a6,no as a7,N_ as a8,Ka as a9,Kt as aA,ap as aB,xp as aC,Zp as aD,v_ as aE,b_ as aF,zp as aG,k_ as aH,Fg as aI,wi as aJ,Ur as aK,$i as aL,Mi as aM,Ut as aN,Ci as aO,q_ as aP,Ll as aQ,cl as aR,Vl as aS,Wl as aT,gs as aU,Ps as aV,ia as aW,Ls as aX,Zd as aY,Jd as aZ,ti as a_,Qo as aa,rl as ab,Xo as ac,Xa as ad,Za as ae,nn as af,rn as ag,Xi as ah,Zi as ai,el as aj,Fs as ak,cc as al,zg as am,xr as an,fn as ao,Cc as ap,Ui as aq,le as ar,W as as,sa as at,Ao as au,Fo as av,Po as aw,Wa as ax,o as ay,he as az,ih as b,Pr as b$,zn as b0,Vn as b1,pm as b2,Fr as b3,dm as b4,El as b5,ql as b6,tc as b7,tl as b8,ic as b9,$o as bA,Hu as bB,W_ as bC,yi as bD,mi as bE,Fi as bF,Ha as bG,Ma as bH,$a as bI,es as bJ,ts as bK,ra as bL,Rl as bM,Oa as bN,Ia as bO,Zn as bP,Jn as bQ,ki as bR,bs as bS,ys as bT,U_ as bU,G_ as bV,Hr as bW,jr as bX,qr as bY,zr as bZ,Dr as b_,Yl as ba,ws as bb,oa as bc,os as bd,fa as be,Ba as bf,L_ as bg,ya as bh,Is as bi,gn as bj,br as bk,kr as bl,wr as bm,yr as bn,mn as bo,Oe as bp,Sp as bq,lf as br,Io as bs,ll as bt,Qt as bu,ei as bv,Gr as bw,ba as bx,kc as by,H_ as bz,j as c,Ec as c$,Er as c0,Un as c1,Tr as c2,Ar as c3,Jl as c4,Lr as c5,Ql as c6,Kl as c7,jl as c8,ec as c9,em as cA,xo as cB,Xd as cC,Vd as cD,dn as cE,hn as cF,Ga as cG,I_ as cH,cn as cI,ln as cJ,an as cK,sn as cL,Ua as cM,Sc as cN,xc as cO,ev as cP,X_ as cQ,j_ as cR,Or as cS,Ig as cT,uo as cU,Ee as cV,qe as cW,Ne as cX,Wc as cY,Yc as cZ,rh as c_,Xl as ca,Zl as cb,sm as cc,ns as cd,Rp as ce,np as cf,Yf as cg,ip as ch,pa as ci,Wf as cj,Xf as ck,D_ as cl,li as cm,ep as cn,op as co,Di as cp,fi as cq,ai as cr,vi as cs,rs as ct,zi as cu,Cn as cv,Tu as cw,Vi as cx,qn as cy,Kd as cz,Rc as d,ua as d$,Xc as d0,Uc as d1,Gc as d2,nh as d3,eh as d4,Fc as d5,Dc as d6,jn as d7,Ac as d8,Wn as d9,il as dA,Ol as dB,Va as dC,$c as dD,Mc as dE,Wi as dF,Pc as dG,tf as dH,nf as dI,$p as dJ,of as dK,cf as dL,Ml as dM,rf as dN,sf as dO,Da as dP,Js as dQ,Mp as dR,Ri as dS,y_ as dT,$f as dU,Mf as dV,uf as dW,w_ as dX,ja as dY,Wr as dZ,Ea as d_,ci as da,Uf as db,Pp as dc,jf as dd,Tl as de,Es as df,ds as dg,us as dh,Ie as di,lu as dj,Kp as dk,Yp as dl,nu as dm,Nu as dn,Nd as dp,Ed as dq,Fd as dr,Pn as ds,kd as dt,Yd as du,Tn as dv,Co as dw,pi as dx,eu as dy,iu as dz,pe as e,Ir as e0,Nr as e1,Na as e2,Pl as e3,V_ as e4,La as e5,hm as e6,wp as e7,dp as e8,gp as e9,up as ea,Jt as eb,kg as ec,K_ as ed,Ji as ee,Qi as ef,Wt as eg,wv as eh,th as f,Rg as g,_n as h,_e as i,p_ as j,Vp as k,kp as l,Op as m,sh as n,dh as o,zd as p,Id as q,hh as r,on as s,$d as t,Md as u,Gp as v,Su as w,Xn as x,Bi as y,qi as z}; + `}_renderRoomDialog(){return this._editorRuntimeOrThrow()._renderRoomDialog()}}wv.properties={_tabDrag:{state:!0},_hdrH:{state:!0},_booting:{state:!0},_bootFading:{state:!0},_bootSoft:{state:!0},_continuityEpoch:{state:!0},_editorRuntimeLoadingVisible:{state:!0},_backdropGuard:{state:!0},_tapConfirm:{state:!0},_dangerConfirm:{state:!0},hass:{attribute:!1},panelHost:{type:Boolean,attribute:"panel-host",reflect:!0},narrow:{attribute:!1},_config:{state:!0},_space:{state:!0},_devices:{state:!0},_selId:{state:!0},_toast:{state:!0},_mode:{state:!0},_tool:{state:!0},_wallDialog:{state:!0},_drawWallField:{state:!0},_activeWallChainId:{state:!0},_physicalSel:{state:!0},_physicalDialog:{state:!0},_partitionDeleteDialog:{state:!0},_roomDeleteDialog:{state:!0},_physicalDrag:{state:!0},_physicalRotate:{state:!0},_duplicateColumnId:{state:!0},_opMeasure:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingPreset:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorEraseConfirm:{state:!0},_decorTextDialog:{state:!0},_decorShapeDialog:{state:!0},_backdropDialog:{state:!0},_furnPalette:{state:!0},_decorImagePalette:{state:!0},_decorAssetCatalog:{state:!0},_decorAssetBusy:{state:!0},_furnCategory:{state:!0},_furnPreviewInput:{state:!0},_bdDrag:{state:!0},_dtBox:{state:!0},_dtDrag:{state:!0},_kioskDialog:{state:!0},_vacFit:{state:!0},_vacAllCamerasFor:{state:!0},_vacCalConfirm:{state:!0},_kioskDots:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_roomEditId:{state:!0},_roomFill:{state:!0},_roomCustomFill:{state:!0},_roomTempMin:{state:!0},_roomTempMax:{state:!0},_roomTempSrc:{state:!0},_roomHumSrc:{state:!0},_roomSrcOpen:{state:!0},_roomSrcFilter:{state:!0},_roomNameScale:{state:!0},_roomLabelScale:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_deviceInbox:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_pdfDialog:{state:!0},_supportDialog:{state:!0},_alignDialog:{state:!0},_preflightClipboardFallback:{state:!0},_backupExportDialog:{state:!0},_backupImportDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0}},wv.ZOOM_MAX=8,wv.ZOOM_MIN=1/3,wv.styles=[ap,mg],customElements.get("houseplan-card")||customElements.define("houseplan-card",wv),window.customCards=window.customCards||[],window.customCards.find(e=>"houseplan-card"===e.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info(`%c HOUSEPLAN-CARD %c v${iv} `,"background:#3ea6ff;color:#04121f;font-weight:700","");export{Ss as $,G as A,Ep as B,Ni as C,Hi as D,U as E,xd as F,si as G,ol as H,nl as I,ni as J,Ju as K,sp as L,zs as M,Ro as N,rp as O,Xu as P,is as Q,Os as R,Qu as S,ji as T,la as U,da as V,Oo as W,Mo as X,Bo as Y,C_ as Z,T_ as _,lh as a,oi as a$,ao as a0,Zo as a1,_i as a2,Yo as a3,ko as a4,So as a5,no as a6,N_ as a7,Ka as a8,Qo as a9,Kt as aA,ap as aB,xp as aC,Zp as aD,v_ as aE,b_ as aF,zp as aG,k_ as aH,Fg as aI,wi as aJ,Ur as aK,$i as aL,Mi as aM,Ut as aN,Ci as aO,q_ as aP,Ll as aQ,cl as aR,Vl as aS,Wl as aT,gs as aU,Ps as aV,ia as aW,Ls as aX,Zd as aY,Jd as aZ,ti as a_,rl as aa,Xo as ab,Xa as ac,Za as ad,nn as ae,rn as af,Xi as ag,Zi as ah,el as ai,Fs as aj,cc as ak,zg as al,xr as am,fn as an,Rc as ao,Cc as ap,Ui as aq,le as ar,W as as,sa as at,Ao as au,Fo as av,Po as aw,Wa as ax,o as ay,he as az,ih as b,Pr as b$,zn as b0,Vn as b1,pm as b2,Fr as b3,dm as b4,El as b5,ql as b6,tc as b7,tl as b8,ic as b9,$o as bA,Hu as bB,W_ as bC,yi as bD,mi as bE,Fi as bF,Ha as bG,Ma as bH,$a as bI,es as bJ,ts as bK,ra as bL,Rl as bM,Oa as bN,Ia as bO,Zn as bP,Jn as bQ,ki as bR,bs as bS,ys as bT,U_ as bU,G_ as bV,Hr as bW,jr as bX,qr as bY,zr as bZ,Dr as b_,Yl as ba,ws as bb,oa as bc,os as bd,fa as be,Ba as bf,L_ as bg,ya as bh,Is as bi,gn as bj,br as bk,kr as bl,wr as bm,yr as bn,mn as bo,Oe as bp,Sp as bq,lf as br,Io as bs,ll as bt,Qt as bu,ei as bv,Gr as bw,ba as bx,kc as by,H_ as bz,j as c,Ec as c$,Er as c0,Un as c1,Tr as c2,Ar as c3,Jl as c4,Lr as c5,Ql as c6,Kl as c7,jl as c8,ec as c9,em as cA,xo as cB,Xd as cC,Vd as cD,dn as cE,hn as cF,Ga as cG,I_ as cH,cn as cI,ln as cJ,an as cK,sn as cL,Ua as cM,Sc as cN,xc as cO,ev as cP,X_ as cQ,j_ as cR,Or as cS,Ig as cT,uo as cU,Ee as cV,qe as cW,Ne as cX,Wc as cY,Yc as cZ,rh as c_,Xl as ca,Zl as cb,sm as cc,ns as cd,Rp as ce,np as cf,Yf as cg,ip as ch,pa as ci,Wf as cj,Xf as ck,D_ as cl,li as cm,ep as cn,op as co,Di as cp,fi as cq,ai as cr,vi as cs,rs as ct,zi as cu,Cn as cv,Tu as cw,Vi as cx,qn as cy,Kd as cz,Rg as d,ua as d$,Xc as d0,Uc as d1,Gc as d2,nh as d3,eh as d4,Fc as d5,Dc as d6,jn as d7,Ac as d8,Wn as d9,il as dA,Ol as dB,Va as dC,$c as dD,Mc as dE,Wi as dF,Pc as dG,tf as dH,nf as dI,$p as dJ,of as dK,cf as dL,Ml as dM,rf as dN,sf as dO,Da as dP,Js as dQ,Mp as dR,Ri as dS,y_ as dT,$f as dU,Mf as dV,uf as dW,w_ as dX,ja as dY,Wr as dZ,Ea as d_,ci as da,Uf as db,Pp as dc,jf as dd,Tl as de,Es as df,ds as dg,us as dh,Ie as di,lu as dj,Kp as dk,Yp as dl,nu as dm,Nu as dn,Nd as dp,Ed as dq,Fd as dr,Pn as ds,kd as dt,Yd as du,Tn as dv,Co as dw,pi as dx,eu as dy,iu as dz,pe as e,Ir as e0,Nr as e1,Na as e2,Pl as e3,V_ as e4,La as e5,hm as e6,wp as e7,dp as e8,gp as e9,up as ea,Jt as eb,kg as ec,K_ as ed,Ji as ee,Qi as ef,Wt as eg,wv as eh,th as f,_n as g,p_ as h,_e as i,Vp as j,Op as k,kp as l,zd as m,sh as n,dh as o,Id as p,$d as q,hh as r,on as s,Md as t,Su as u,Gp as v,Xn as w,Bi as x,qi as y,Li as z}; diff --git a/custom_components/houseplan/frontend/houseplan-assets/houseplan-editor-runtime-BlocE3XU.js b/custom_components/houseplan/frontend/houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js similarity index 73% rename from custom_components/houseplan/frontend/houseplan-assets/houseplan-editor-runtime-BlocE3XU.js rename to custom_components/houseplan/frontend/houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js index 427d087c..b8f8530f 100644 --- a/custom_components/houseplan/frontend/houseplan-assets/houseplan-editor-runtime-BlocE3XU.js +++ b/custom_components/houseplan/frontend/houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js @@ -1,4 +1,4 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{e as t,i as e,E as s,s as i,a as o,n as a,f as n,b as r,l,o as h,r as c,A as d,c as p,d as u,g as _,h as m,j as g,v as f,k as b,m as v,p as y,q as w,t as $,u as k,w as x,x as M,T as C,y as S,z as P,D,B as I,C as L,F as T,G as R,H as z,I as F,J as N,K as A,L as E,M as O,N as B,O as H,P as W,Q as j,R as G,S as q,U,V as K,W as V,X as J,Y as Z,Z as Y,_ as X,$ as Q,a0 as tt,a1 as et,a2 as st,a3 as it,a4 as ot,a5 as at,a6 as nt,a7 as rt,a8 as lt,a9 as ht,aa as ct,ab as dt,ac as pt,ad as ut,ae as _t,af as mt,ag as gt,ah as ft,ai as bt,aj as vt,ak as yt,al as wt,am as $t,an as kt,ao as xt,ap as Mt,aq as Ct,ar as St,as as Pt,at as Dt,au as It,av as Lt,aw as Tt,ax as Rt,ay as zt,az as Ft,aA as Nt,aB as At,aC as Et,aD as Ot,aE as Bt,aF as Ht,aG as Wt,aH as jt,aI as Gt,aJ as qt,aK as Ut,aL as Kt,aM as Vt,aN as Jt,aO as Zt,aP as Yt,aQ as Xt,aR as Qt,aS as te,aT as ee,aU as se,aV as ie,aW as oe,aX as ae,aY as ne,aZ as re,a_ as le,a$ as he,b0 as ce,b1 as de,b2 as pe,b3 as ue,b4 as _e,b5 as me,b6 as ge,b7 as fe,b8 as be,b9 as ve,ba as ye,bb as we,bc as $e,bd as ke,be as xe,bf as Me,bg as Ce,bh as Se,bi as Pe,bj as De,bk as Ie,bl as Le,bm as Te,bn as Re,bo as ze,bp as Fe,bq as Ne,br as Ae,bs as Ee,bt as Oe,bu as Be,bv as He,bw as We,bx as je,by as Ge,bz as qe,bA as Ue,bB as Ke,bC as Ve,bD as Je,bE as Ze,bF as Ye,bG as Xe,bH as Qe,bI as ts,bJ as es,bK as ss,bL as is,bM as os,bN as as,bO as ns,bP as rs,bQ as ls,bR as hs,bS as cs,bT as ds,bU as ps,bV as us,bW as _s,bX as ms,bY as gs,bZ as fs,b_ as bs,b$ as vs,c0 as ys,c1 as ws,c2 as $s,c3 as ks,c4 as xs,c5 as Ms,c6 as Cs,c7 as Ss,c8 as Ps,c9 as Ds,ca as Is,cb as Ls,cc as Ts,cd as Rs,ce as zs,cf as Fs,cg as Ns,ch as As,ci as Es,cj as Os,ck as Bs,cl as Hs,cm as Ws,cn as js,co as Gs,cp as qs,cq as Us,cr as Ks,cs as Vs,ct as Js,cu as Zs,cv as Ys,cw as Xs,cx as Qs,cy as ti,cz as ei,cA as si,cB as ii,cC as oi,cD as ai,cE as ni,cF as ri,cG as li,cH as hi,cI as ci,cJ as di,cK as pi,cL as ui,cM as _i,cN as mi,cO as gi,cP as fi,cQ as bi,cR as vi,cS as yi,cT as wi,cU as $i,cV as ki,cW as xi,cX as Mi,cY as Ci,cZ as Si,c_ as Pi,c$ as Di,d0 as Ii,d1 as Li,d2 as Ti,d3 as Ri,d4 as zi,d5 as Fi,d6 as Ni,d7 as Ai,d8 as Ei,d9 as Oi,da as Bi,db as Hi,dc as Wi,dd as ji,de as Gi,df as qi,dg as Ui,dh as Ki,di as Vi,dj as Ji,dk as Zi,dl as Yi,dm as Xi,dn as Qi,dp as to,dq as eo,dr as so,ds as io,dt as oo,du as ao,dv as no,dw as ro,dx as lo,dy as ho,dz as co,dA as po,dB as uo}from"./houseplan-card-BWAph8ZF.js";import{r as _o,s as mo,d as go,f as fo,e as bo,a as vo,c as yo,t as wo,b as $o,g as ko,h as xo,i as Mo,j as Co,k as So,l as Po,m as Do,u as Io,n as Lo,o as To,p as Ro,q as zo,v as Fo,w as No,x as Ao,y as Eo,z as Oo,F as Bo,A as Ho,B as Wo,C as jo,D as Go,E as qo,G as Uo,H as Ko,I as Vo,J as Jo,K as Zo}from"./backdrop-pick-CtZfmF4H.js";import{h as Yo,t as Xo,m as Qo,T as ta}from"./zigbee-topology-D0gydI7H.js";import{GENERATED_FURNITURE_ART as ea,FURNITURE_ART_FINGERPRINT as sa}from"./furniture-plan-art.generated-Ck1wv9qF.js";import"./form-kit.styles-DcvCvE8g.js";const ia={},oa=t(class extends e{constructor(){super(...arguments),this.ot=ia}render(t,e){return e()}update(t,[e,i]){if(Array.isArray(e)){if(Array.isArray(this.ot)&&this.ot.length===e.length&&e.every((t,e)=>t===this.ot[e]))return s}else if(this.ot===e)return s;return this.ot=Array.isArray(e)?Array.from(e):e,this.render(e,i)}});var aa={"gs.show_room_tooltip":"Show the room information window on hover","support.about_group":"About the card","support.guide_group":"Documentation","support.guide":"User guide","support.form_group":"Send a report or suggestion","support.contact":"Contact details (email/tg/WhatsApp), optional.","support.message":"Message","support.attach":"Attach anonymized information from your plan","support.attach_hint":"Includes only allowed plan geometry, settings and bounded runtime facts. Excludes names, Home Assistant IDs, live states, URLs, files, and your message/contact.","support.geometry_warning":"The package contains no names or Home Assistant IDs, but it does contain the exact geometry and dimensions of your home.","support.close_busy_title":"Stop the current operation?","support.close_busy_body":"House Plan is preparing or sending the report. Closing now stops waiting for the result.","support.building":"Preparing anonymized data…","support.preview_summary":"Package v{version} · {spaces} spaces · {size} KiB","support.prepared":"Snapshot prepared {n} min ago","support.show_data":"Show data","support.download":"Download JSON","support.refresh":"Refresh snapshot","support.privacy":"When you send, your message, optional contact and, if selected, exact geometry leave your Home Assistant through the House Plan project relay and are visible to maintainers. The project node keeps the report for up to 30 days. Network infrastructure sees your HA server address, but House Plan does not retain it raw; rate-limit and idempotency metadata is kept for up to 24 hours.","support.error_title":"The report was not sent","support.manual_recovery":"You can keep the message and attachment and continue manually:","support.copy_message":"Copy message","support.success":"Report sent: {id}. Save this number when contacting support.","support.copy_id":"Copy ID","support.sending":"Sending…","support.retry":"Retry","support.send":"Send","support.update_required":"Update the House Plan card and integration to compatible versions to send reports.","support.message_copied":"Message copied","support.id_copied":"Report ID copied","support.copy_failed":"Could not access the clipboard. Select and copy the text manually.","support.validation.message_required":"Enter a message.","support.validation.message_too_long":"The message must contain no more than 10,000 characters.","support.validation.contact_too_long":"Contact details must contain no more than 320 characters.","support.validation.preview_missing":"Wait for the attachment preview or turn the attachment off.","support.validation.preview_expired":"The attachment preview expired. Refresh the snapshot.","support.error.support_invalid_message":"Check the message and try again.","support.error.support_preview_expired":"The attachment preview expired or is no longer available. Refresh the snapshot.","support.error.support_package_too_large":"The anonymized package exceeds the 8 MiB limit.","support.error.support_rate_limited":"Too many reports or previews were requested. Try again later.","support.error.support_unavailable":"The private support service is temporarily unavailable. Your draft remains here.","support.error.support_rejected":"The report did not pass the support service validation.","support.error.unauthorized":"You do not have permission to send this report.","vac.routes_section":"Maps and floors","vac.routes_current_map":"Current map","vac.routes_no_map":"no telemetry","vac.routes_status":"Routing","vac.routes_state_ready":"map assigned and calibrated","vac.routes_state_needs_calibration":"map assigned, calibration needed","vac.routes_state_unmapped":"current map is not assigned to a floor","vac.routes_state_ambiguous":"two maps are indistinguishable — no floor is chosen","vac.routes_state_missing_space":"the map's space was deleted","vac.routes_state_none":"no map data","vac.routes_empty":"No map is assigned to a floor yet.","vac.route_map_default":"no map id","vac.route_active":"Active","vac.route_space":"Space","vac.route_space_none":"not selected","vac.route_status_ready":"ready","vac.route_status_needs_calibration":"needs calibration","vac.route_status_ambiguous":"ambiguous","vac.route_status_missing_space":"space deleted","vac.route_missing_space_group":"Deleted space","vac.route_add_current":"Add current map","vac.route_delete":"Remove map","vac.route_delete_title":"Remove the map from its floor?","vac.route_delete_body":"Calibration and saved paths for this map will be removed. Continue?","vac.route_delete_confirm":"Remove","vac.route_space_title":"Move the map to another space?","vac.route_space_body":"Calibration and saved paths for this map will be removed. Continue?","vac.route_space_confirm":"Move","vac.route_missing_space_hint":"One of the maps points at a deleted space: pick a new one or remove the map. Until then the robot is not drawn for that map.","vac.route_default_hint":"The source reports no stable map id. Several floors cannot be told apart without another source or the robot's own selected map.","vac.route_target_hint":"The dock stays in the “{space}” space regardless of the current map.","vac.route_add_source":"Add a map source","vac.route_add_source_hint":"For integrations that give each map its own camera. The “All cameras” section above widens this list.","vac.route_source_no_map":"no map reported"};const na={en:aa,ru:{"gs.show_room_tooltip":"Показывать окно с информацией при наведении на комнату","support.about_group":"О карточке","support.guide_group":"Документация","support.guide":"Руководство пользователя","support.form_group":"Отправить репорт или предложение","support.contact":"Контакт для связи (email/tg/WhatsApp), необязательно.","support.message":"Сообщение","support.attach":"Прикрепить обезличенную информацию из вашего плана","support.attach_hint":"В пакет входят только разрешённые геометрия, настройки и ограниченные сведения о среде. Не входят имена, HA id, текущие состояния, URL, файлы, сообщение и контакт.","support.geometry_warning":"Пакет не содержит имён и HA id, но содержит точную геометрию и размеры дома.","support.close_busy_title":"Прервать текущую операцию?","support.close_busy_body":"House Plan подготавливает или отправляет репорт. При закрытии ожидание результата прекратится.","support.building":"Подготавливаем обезличенные данные…","support.preview_summary":"Пакет v{version} · пространств: {spaces} · {size} КиБ","support.prepared":"Снимок подготовлен {n} мин назад","support.show_data":"Показать данные","support.download":"Скачать JSON","support.refresh":"Обновить снимок","support.privacy":"При отправке сообщение, необязательный контакт и, если выбран пакет, точная геометрия покидают ваш Home Assistant через relay проекта House Plan и доступны мейнтейнерам. Узел проекта хранит репорт до 30 дней. Сетевая инфраструктура видит адрес сервера HA, но House Plan не сохраняет его в исходном виде; метаданные лимитов и идемпотентности хранятся до 24 часов.","support.error_title":"Репорт не отправлен","support.manual_recovery":"Сообщение и вложение можно сохранить и продолжить вручную:","support.copy_message":"Копировать сообщение","support.success":"Репорт отправлен: {id}. Сохраните номер для связи с поддержкой.","support.copy_id":"Копировать ID","support.sending":"Отправляем…","support.retry":"Повторить","support.send":"Отправить","support.update_required":"Обновите карточку и интеграцию House Plan до совместимых версий, чтобы отправлять репорты.","support.message_copied":"Сообщение скопировано","support.id_copied":"ID репорта скопирован","support.copy_failed":"Не удалось получить доступ к буферу обмена. Выделите и скопируйте текст вручную.","support.validation.message_required":"Введите сообщение.","support.validation.message_too_long":"Сообщение должно содержать не более 10 000 символов.","support.validation.contact_too_long":"Контакт должен содержать не более 320 символов.","support.validation.preview_missing":"Дождитесь предпросмотра вложения или отключите его.","support.validation.preview_expired":"Предпросмотр вложения истёк. Обновите снимок.","support.error.support_invalid_message":"Проверьте сообщение и повторите попытку.","support.error.support_preview_expired":"Предпросмотр вложения истёк или больше недоступен. Обновите снимок.","support.error.support_package_too_large":"Обезличенный пакет превышает лимит 8 МиБ.","support.error.support_rate_limited":"Запрошено слишком много репортов или предпросмотров. Повторите позже.","support.error.support_unavailable":"Закрытая служба поддержки временно недоступна. Черновик сохранён в этом окне.","support.error.support_rejected":"Репорт не прошёл проверку службы поддержки.","support.error.unauthorized":"У вас нет прав на отправку этого репорта.","vac.routes_section":"Карты и этажи","vac.routes_current_map":"Текущая карта","vac.routes_no_map":"источник молчит","vac.routes_status":"Маршрутизация","vac.routes_state_ready":"карта сопоставлена и откалибрована","vac.routes_state_needs_calibration":"карта сопоставлена, нужна калибровка","vac.routes_state_unmapped":"текущая карта не сопоставлена этажу","vac.routes_state_ambiguous":"две карты неразличимы — этаж не выбирается","vac.routes_state_missing_space":"пространство карты удалено","vac.routes_state_none":"нет данных о карте","vac.routes_empty":"Ни одна карта ещё не сопоставлена этажу.","vac.route_map_default":"без идентификатора","vac.route_active":"Текущая","vac.route_space":"Пространство","vac.route_space_none":"не выбрано","vac.route_status_ready":"готова","vac.route_status_needs_calibration":"нужна калибровка","vac.route_status_ambiguous":"неоднозначна","vac.route_status_missing_space":"пространство удалено","vac.route_missing_space_group":"Пространство удалено","vac.route_add_current":"Добавить текущую карту","vac.route_delete":"Удалить карту","vac.route_delete_title":"Удалить карту с этажа?","vac.route_delete_body":"Калибровка и сохранённые пути этой карты будут удалены. Продолжить?","vac.route_delete_confirm":"Удалить","vac.route_space_title":"Перенести карту в другое пространство?","vac.route_space_body":"Калибровка и сохранённые пути этой карты будут удалены. Продолжить?","vac.route_space_confirm":"Перенести","vac.route_missing_space_hint":"Одна из карт ссылается на удалённое пространство: выберите новое или удалите карту. Пока ссылка не исправлена, робот на этой карте не рисуется.","vac.route_default_hint":"Источник не сообщает стабильный идентификатор карты. Несколько этажей нельзя различить без другого источника или собственной карты робота.","vac.route_target_hint":"Док остаётся в пространстве «{space}» независимо от текущей карты.","vac.route_add_source":"Добавить источник карты","vac.route_add_source_hint":"Для интеграций, где у каждой карты своя камера. Список расширяется разделом «Все камеры» выше.","vac.route_source_no_map":"карта не читается"},de:{"gs.show_room_tooltip":"Rauminformationen beim Darüberfahren anzeigen","support.about_group":"Über die Karte","support.guide_group":"Dokumentation","support.guide":"Benutzerhandbuch","support.form_group":"Bericht oder Vorschlag senden","support.contact":"Kontakt (E-Mail/tg/WhatsApp), optional.","support.message":"Nachricht","support.attach":"Anonymisierte Informationen aus dem Plan anhängen","support.attach_hint":"Enthält nur erlaubte Plangeometrie, Einstellungen und begrenzte Laufzeitdaten. Namen, Home-Assistant-IDs, Live-Zustände, URLs, Dateien, Nachricht und Kontakt werden ausgeschlossen.","support.geometry_warning":"Das Paket enthält keine Namen oder Home-Assistant-IDs, aber die exakte Geometrie und die Maße Ihres Hauses.","support.close_busy_title":"Aktuellen Vorgang abbrechen?","support.close_busy_body":"House Plan bereitet den Bericht vor oder sendet ihn. Beim Schließen wird nicht weiter auf das Ergebnis gewartet.","support.building":"Anonymisierte Daten werden vorbereitet…","support.preview_summary":"Paket v{version} · {spaces} Bereiche · {size} KiB","support.prepared":"Schnappschuss vor {n} Min. erstellt","support.show_data":"Daten anzeigen","support.download":"JSON herunterladen","support.refresh":"Schnappschuss aktualisieren","support.privacy":"Beim Senden verlassen Ihre Nachricht, der optionale Kontakt und, falls ausgewählt, die exakte Geometrie Ihren Home Assistant über das House-Plan-Projektrelay und sind für die Maintainer sichtbar. Der Projektserver speichert den Bericht bis zu 30 Tage. Die Netzwerkinfrastruktur sieht die Adresse Ihres HA-Servers, House Plan speichert sie jedoch nicht im Rohformat; Limit- und Idempotenzdaten bleiben bis zu 24 Stunden erhalten.","support.error_title":"Der Bericht wurde nicht gesendet","support.manual_recovery":"Nachricht und Anhang können gespeichert und manuell weitergegeben werden:","support.copy_message":"Nachricht kopieren","support.success":"Bericht gesendet: {id}. Bewahren Sie diese Nummer für den Support auf.","support.copy_id":"ID kopieren","support.sending":"Wird gesendet…","support.retry":"Erneut versuchen","support.send":"Senden","support.update_required":"Aktualisieren Sie House-Plan-Karte und Integration auf kompatible Versionen, um Berichte zu senden.","support.message_copied":"Nachricht kopiert","support.id_copied":"Berichts-ID kopiert","support.copy_failed":"Kein Zugriff auf die Zwischenablage. Markieren und kopieren Sie den Text manuell.","support.validation.message_required":"Geben Sie eine Nachricht ein.","support.validation.message_too_long":"Die Nachricht darf höchstens 10.000 Zeichen enthalten.","support.validation.contact_too_long":"Der Kontakt darf höchstens 320 Zeichen enthalten.","support.validation.preview_missing":"Warten Sie auf die Vorschau oder deaktivieren Sie den Anhang.","support.validation.preview_expired":"Die Anhangsvorschau ist abgelaufen. Aktualisieren Sie den Schnappschuss.","support.error.support_invalid_message":"Prüfen Sie die Nachricht und versuchen Sie es erneut.","support.error.support_preview_expired":"Die Anhangsvorschau ist abgelaufen oder nicht mehr verfügbar. Aktualisieren Sie den Schnappschuss.","support.error.support_package_too_large":"Das anonymisierte Paket überschreitet das Limit von 8 MiB.","support.error.support_rate_limited":"Zu viele Berichte oder Vorschauen wurden angefordert. Versuchen Sie es später erneut.","support.error.support_unavailable":"Der private Supportdienst ist vorübergehend nicht verfügbar. Der Entwurf bleibt in diesem Fenster erhalten.","support.error.support_rejected":"Der Bericht hat die Prüfung des Supportdienstes nicht bestanden.","support.error.unauthorized":"Sie dürfen diesen Bericht nicht senden.","vac.routes_section":"Karten und Etagen","vac.routes_current_map":"Aktuelle Karte","vac.routes_no_map":"keine Telemetrie","vac.routes_status":"Zuordnung","vac.routes_state_ready":"Karte zugeordnet und kalibriert","vac.routes_state_needs_calibration":"Karte zugeordnet, Kalibrierung nötig","vac.routes_state_unmapped":"aktuelle Karte keiner Etage zugeordnet","vac.routes_state_ambiguous":"zwei Karten nicht unterscheidbar — keine Etage gewählt","vac.routes_state_missing_space":"der Raum der Karte wurde gelöscht","vac.routes_state_none":"keine Kartendaten","vac.routes_empty":"Noch keine Karte einer Etage zugeordnet.","vac.route_map_default":"ohne Karten-ID","vac.route_active":"Aktiv","vac.route_space":"Raum","vac.route_space_none":"nicht gewählt","vac.route_status_ready":"bereit","vac.route_status_needs_calibration":"Kalibrierung nötig","vac.route_status_ambiguous":"mehrdeutig","vac.route_status_missing_space":"Raum gelöscht","vac.route_missing_space_group":"Gelöschter Bereich","vac.route_add_current":"Aktuelle Karte hinzufügen","vac.route_delete":"Karte entfernen","vac.route_delete_title":"Karte von der Etage entfernen?","vac.route_delete_body":"Kalibrierung und gespeicherte Pfade dieser Karte werden entfernt. Fortfahren?","vac.route_delete_confirm":"Entfernen","vac.route_space_title":"Karte in einen anderen Raum verschieben?","vac.route_space_body":"Kalibrierung und gespeicherte Pfade dieser Karte werden entfernt. Fortfahren?","vac.route_space_confirm":"Verschieben","vac.route_missing_space_hint":"Eine Karte verweist auf einen gelöschten Raum: neuen wählen oder Karte entfernen. Bis dahin wird der Roboter für diese Karte nicht gezeichnet.","vac.route_default_hint":"Die Quelle meldet keine stabile Karten-ID. Mehrere Etagen lassen sich ohne andere Quelle oder die vom Roboter gewählte Karte nicht unterscheiden.","vac.route_target_hint":"Die Station bleibt unabhängig von der aktuellen Karte im Raum „{space}“.","vac.route_add_source":"Kartenquelle hinzufügen","vac.route_add_source_hint":"Für Integrationen, die jeder Karte eine eigene Kamera geben. Der Abschnitt „Alle Kameras“ oben erweitert diese Liste.","vac.route_source_no_map":"keine Karte gemeldet"},fr:{"gs.show_room_tooltip":"Afficher les informations de la pièce au survol","support.about_group":"À propos de la carte","support.guide_group":"Documentation d’aide","support.guide":"Guide utilisateur","support.form_group":"Envoyer un rapport ou une suggestion","support.contact":"Contact (e-mail/tg/WhatsApp), facultatif.","support.message":"Votre message","support.attach":"Joindre des informations anonymisées de votre plan","support.attach_hint":"Inclut uniquement la géométrie, les réglages autorisés et des données d’exécution limitées. Exclut les noms, identifiants Home Assistant, états en direct, URL, fichiers, message et contact.","support.geometry_warning":"Le paquet ne contient ni noms ni identifiants Home Assistant, mais il contient la géométrie et les dimensions exactes de votre logement.","support.close_busy_title":"Interrompre l’opération en cours ?","support.close_busy_body":"House Plan prépare ou envoie le rapport. Fermer maintenant arrête l’attente du résultat.","support.building":"Préparation des données anonymisées…","support.preview_summary":"Paquet v{version} · {spaces} espaces · {size} Kio","support.prepared":"Instantané préparé il y a {n} min","support.show_data":"Afficher les données","support.download":"Télécharger le JSON","support.refresh":"Actualiser l’instantané","support.privacy":"Lors de l’envoi, votre message, le contact facultatif et, si elle est sélectionnée, la géométrie exacte quittent votre Home Assistant via le relais du projet House Plan et sont visibles par les mainteneurs. Le serveur du projet conserve le rapport jusqu’à 30 jours. L’infrastructure réseau voit l’adresse de votre serveur HA, mais House Plan ne la conserve pas en clair ; les métadonnées de limitation et d’idempotence sont gardées jusqu’à 24 heures.","support.error_title":"Le rapport n’a pas été envoyé","support.manual_recovery":"Vous pouvez conserver le message et la pièce jointe puis continuer manuellement :","support.copy_message":"Copier le message","support.success":"Rapport envoyé : {id}. Conservez ce numéro pour contacter l’assistance.","support.copy_id":"Copier l’ID","support.sending":"Envoi…","support.retry":"Réessayer","support.send":"Envoyer","support.update_required":"Mettez à jour la carte et l’intégration House Plan vers des versions compatibles pour envoyer des rapports.","support.message_copied":"Message copié","support.id_copied":"ID du rapport copié","support.copy_failed":"Impossible d’accéder au presse-papiers. Sélectionnez et copiez le texte manuellement.","support.validation.message_required":"Saisissez un message.","support.validation.message_too_long":"Le message ne doit pas dépasser 10 000 caractères.","support.validation.contact_too_long":"Le contact ne doit pas dépasser 320 caractères.","support.validation.preview_missing":"Attendez l’aperçu de la pièce jointe ou désactivez-la.","support.validation.preview_expired":"L’aperçu de la pièce jointe a expiré. Actualisez l’instantané.","support.error.support_invalid_message":"Vérifiez le message et réessayez.","support.error.support_preview_expired":"L’aperçu de la pièce jointe a expiré ou n’est plus disponible. Actualisez l’instantané.","support.error.support_package_too_large":"Le paquet anonymisé dépasse la limite de 8 Mio.","support.error.support_rate_limited":"Trop de rapports ou d’aperçus ont été demandés. Réessayez plus tard.","support.error.support_unavailable":"Le service d’assistance privé est temporairement indisponible. Le brouillon reste dans cette fenêtre.","support.error.support_rejected":"Le rapport n’a pas passé la validation du service d’assistance.","support.error.unauthorized":"Vous n’êtes pas autorisé à envoyer ce rapport.","vac.routes_section":"Cartes et étages","vac.routes_current_map":"Carte actuelle","vac.routes_no_map":"aucune télémétrie","vac.routes_status":"Routage","vac.routes_state_ready":"carte assignée et calibrée","vac.routes_state_needs_calibration":"carte assignée, calibrage requis","vac.routes_state_unmapped":"carte actuelle non assignée à un étage","vac.routes_state_ambiguous":"deux cartes indiscernables — aucun étage choisi","vac.routes_state_missing_space":"l'espace de la carte a été supprimé","vac.routes_state_none":"aucune donnée de carte","vac.routes_empty":"Aucune carte n'est encore assignée à un étage.","vac.route_map_default":"sans identifiant","vac.route_active":"Active","vac.route_space":"Espace","vac.route_space_none":"non sélectionné","vac.route_status_ready":"prête","vac.route_status_needs_calibration":"calibrage requis","vac.route_status_ambiguous":"ambiguë","vac.route_status_missing_space":"espace supprimé","vac.route_missing_space_group":"Espace supprimé","vac.route_add_current":"Ajouter la carte actuelle","vac.route_delete":"Supprimer la carte","vac.route_delete_title":"Retirer la carte de son étage ?","vac.route_delete_body":"Le calibrage et les trajets enregistrés de cette carte seront supprimés. Continuer ?","vac.route_delete_confirm":"Supprimer","vac.route_space_title":"Déplacer la carte vers un autre espace ?","vac.route_space_body":"Le calibrage et les trajets enregistrés de cette carte seront supprimés. Continuer ?","vac.route_space_confirm":"Déplacer","vac.route_missing_space_hint":"Une carte pointe vers un espace supprimé : choisissez-en un autre ou supprimez la carte. D'ici là, le robot n'est pas dessiné pour cette carte.","vac.route_default_hint":"La source ne fournit pas d'identifiant de carte stable. Plusieurs étages ne peuvent pas être distingués sans une autre source ou la carte sélectionnée du robot.","vac.route_target_hint":"La station reste dans l'espace « {space} » quelle que soit la carte actuelle.","vac.route_add_source":"Ajouter une source de carte","vac.route_add_source_hint":"Pour les intégrations qui donnent à chaque carte sa propre caméra. La section « Toutes les caméras » ci-dessus élargit cette liste.","vac.route_source_no_map":"aucune carte signalée"}};function ra(t,e,s){return i(na[t]?.[e]??aa[e]??e,s)}function la(t,e,s,i,o){return{markerId:t,source:i,mapId:o,space:e.length?"":s}}function ha(t,e,s){return{...t,space:s.has(e)?e:""}}function ca(t,e=Math.random){const s=new Set(t);for(let t=0;t<64;t+=1){const t="vr_"+Math.floor(16777215*e()).toString(36).padStart(5,"0");if(!s.has(t))return t}return"vr_"+Date.now().toString(36)}function da(t,e,s){return t.map(t=>t.id===e?{...t,calibration:s}:t)}const pa=new WeakMap,ua=(t,e)=>{const s=(t._serverCfg?.spaces||[]).find(t=>t?.id===e);return String(s?.name||s?.id||e)};function _a(t,e,s){const i=t.host,n=l(i.hass,i._config?.language),r=(t,e)=>ra(n,t,e),u=e.marker?.vacuum||{},_=Array.isArray(u.map_routes),m=i._vacSource(e)||"",g=o(e.id,u,e.space,m),f=(i._serverCfg?.spaces||[]).filter(t=>"string"==typeof t?.id&&!!t.id).map(t=>({id:t.id,name:String(t.name||t.id)})),b=new Set(f.map(t=>t.id)),v=h(g,[m],t=>i._vacObservedMapId(e,t)),y=c({routes:g,observed:v,spaceIds:b}),w="ready"===y.kind||"needs_calibration"===y.kind||"missing_space"===y.kind?y.route.id:"",$=m?v[m]:void 0,k=async s=>{let o=_?u.map_routes??null:null;if(!o&&(o=function(t,e,s,i){if(!s)return null;const o=t?.calibration;if(!o||"object"!=typeof o)return null;const n=new Set,r=[];for(const t of Object.keys(o)){const l=a(o[t]);if(!l)continue;const h=i(n);n.add(h),r.push({id:h,source:s,map_id:t,space:e,calibration:l})}return r.length?r:null}(u,e.space,m,t=>ca(t))??[],!m&&Object.keys(u.calibration||{}).length))return!1;const n=s(o);return!!n&&(async s=>{const o=i._serverCfg;if(!o)return!1;const a=JSON.parse(JSON.stringify(o));a.markers=a.markers||[];let n=a.markers.find(t=>t.id===e.id);if(!n){if("device"!==e.bindingKind&&"entity"!==e.bindingKind||!e.bindingRef)return!1;n={id:e.id,binding:`${e.bindingKind}:${e.bindingRef}`,space:e.space||null,area:e.area||null,hidden:!!e.hidden},a.markers.push(n)}n.vacuum={...n.vacuum||{},map_routes:s},delete n.vacuum.calibration;const r=i._adoption.beginOptimistic(o,a);i._adoption.stageLocalConfig(a),i._regSignature="",i._maybeRebuildDevices(),i.requestUpdate(),i._saveConfigDebounced.pending()&&i._saveConfigDebounced.cancel();try{return await t._saveConfigNow(),!0}catch(t){return i._rollbackOptimistic(r),i._regSignature="",i._maybeRebuildDevices(),i.requestUpdate(),i._showToast(i._t("toast.cfg_save_failed",{err:i._errText(t)})),!1}})(n)},x=s.candidates.filter(t=>t.entityId!==m&&!g.some(e=>e.source===t.entityId)),M=async(t,e)=>{if(!e||e===t.space)return;await i._confirmDanger({key:"vacuum_route_space",kind:"warning",title:r("vac.route_space_title"),message:r("vac.route_space_body"),objectName:t.map_id||r("vac.route_map_default"),confirmLabel:r("vac.route_space_confirm"),cancelLabel:i._t("btn.cancel")})&&await k(s=>function(t,e,s,i){return t.map(t=>t.id===e?{...t,id:i,space:s,calibration:null}:t)}(s,t.id,e,ca(new Set(g.map(t=>t.id)))))},C=new Map(f.map((t,e)=>[t.id,e])),S=(t,e)=>t.map_id.localeCompare(e.map_id)||t.source.localeCompare(e.source)||t.id.localeCompare(e.id),P=g.filter(t=>b.has(t.space)).sort((t,e)=>(C.get(t.space)??0)-(C.get(e.space)??0)||S(t,e)),D=g.filter(t=>!b.has(t.space)).sort(S),I=[...P,...D],L=!!m&&void 0!==$&&!g.some(t=>t.source===m&&t.map_id===$);let T=pa.get(t);const R=T?.source||"",z=T?.mapId||"",F=!!T&&g.some(t=>t.source===R&&t.map_id===z);T&&(T.markerId!==e.id||i._vacObservedMapId(e,T.source)!==T.mapId||F&&!T.saving)&&(pa.delete(t),T=void 0),T?.space&&!b.has(T.space)&&(T=ha(T,"",b),pa.set(t,T));const N=s=>p` +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{e as t,i as e,E as s,s as i,a as o,n as a,f as n,b as r,l,o as h,r as c,A as d,c as p,d as u,g as _,h as m,v as g,j as f,k as b,m as v,p as y,q as w,t as $,u as k,w as x,T as M,x as C,y as S,D as P,z as D,B as I,C as L,F as T,G as R,H as z,I as F,J as N,K as A,L as E,M as O,N as B,O as H,P as W,Q as j,R as G,S as q,U,V as K,W as V,X as J,Y as Z,Z as Y,_ as X,$ as Q,a0 as tt,a1 as et,a2 as st,a3 as it,a4 as ot,a5 as at,a6 as nt,a7 as rt,a8 as lt,a9 as ht,aa as ct,ab as dt,ac as pt,ad as ut,ae as _t,af as mt,ag as gt,ah as ft,ai as bt,aj as vt,ak as yt,al as wt,am as $t,an as kt,ao as xt,ap as Mt,aq as Ct,ar as St,as as Pt,at as Dt,au as It,av as Lt,aw as Tt,ax as Rt,ay as zt,az as Ft,aA as Nt,aB as At,aC as Et,aD as Ot,aE as Bt,aF as Ht,aG as Wt,aH as jt,aI as Gt,aJ as qt,aK as Ut,aL as Kt,aM as Vt,aN as Jt,aO as Zt,aP as Yt,aQ as Xt,aR as Qt,aS as te,aT as ee,aU as se,aV as ie,aW as oe,aX as ae,aY as ne,aZ as re,a_ as le,a$ as he,b0 as ce,b1 as de,b2 as pe,b3 as ue,b4 as _e,b5 as me,b6 as ge,b7 as fe,b8 as be,b9 as ve,ba as ye,bb as we,bc as $e,bd as ke,be as xe,bf as Me,bg as Ce,bh as Se,bi as Pe,bj as De,bk as Ie,bl as Le,bm as Te,bn as Re,bo as ze,bp as Fe,bq as Ne,br as Ae,bs as Ee,bt as Oe,bu as Be,bv as He,bw as We,bx as je,by as Ge,bz as qe,bA as Ue,bB as Ke,bC as Ve,bD as Je,bE as Ze,bF as Ye,bG as Xe,bH as Qe,bI as ts,bJ as es,bK as ss,bL as is,bM as os,bN as as,bO as ns,bP as rs,bQ as ls,bR as hs,bS as cs,bT as ds,bU as ps,bV as us,bW as _s,bX as ms,bY as gs,bZ as fs,b_ as bs,b$ as vs,c0 as ys,c1 as ws,c2 as $s,c3 as ks,c4 as xs,c5 as Ms,c6 as Cs,c7 as Ss,c8 as Ps,c9 as Ds,ca as Is,cb as Ls,cc as Ts,cd as Rs,ce as zs,cf as Fs,cg as Ns,ch as As,ci as Es,cj as Os,ck as Bs,cl as Hs,cm as Ws,cn as js,co as Gs,cp as qs,cq as Us,cr as Ks,cs as Vs,ct as Js,cu as Zs,cv as Ys,cw as Xs,cx as Qs,cy as ti,cz as ei,cA as si,cB as ii,cC as oi,cD as ai,cE as ni,cF as ri,cG as li,cH as hi,cI as ci,cJ as di,cK as pi,cL as ui,cM as _i,cN as mi,cO as gi,cP as fi,cQ as bi,cR as vi,cS as yi,cT as wi,cU as $i,cV as ki,cW as xi,cX as Mi,cY as Ci,cZ as Si,c_ as Pi,c$ as Di,d0 as Ii,d1 as Li,d2 as Ti,d3 as Ri,d4 as zi,d5 as Fi,d6 as Ni,d7 as Ai,d8 as Ei,d9 as Oi,da as Bi,db as Hi,dc as Wi,dd as ji,de as Gi,df as qi,dg as Ui,dh as Ki,di as Vi,dj as Ji,dk as Zi,dl as Yi,dm as Xi,dn as Qi,dp as to,dq as eo,dr as so,ds as io,dt as oo,du as ao,dv as no,dw as ro,dx as lo,dy as ho,dz as co,dA as po,dB as uo}from"./houseplan-card-9fMSy3y3.js";import{r as _o,s as mo,d as go,f as fo,e as bo,a as vo,c as yo,t as wo,b as $o,g as ko,h as xo,i as Mo,j as Co,k as So,l as Po,m as Do,u as Io,n as Lo,o as To,p as Ro,q as zo,v as Fo,w as No,x as Ao,y as Eo,z as Oo,F as Bo,A as Ho,B as Wo,C as jo,D as Go,E as qo,G as Uo,H as Ko,I as Vo,J as Jo,K as Zo}from"./backdrop-pick-BJOCHJxe.js";import{h as Yo,t as Xo,m as Qo,T as ta}from"./zigbee-topology-CI6PJorK.js";import{GENERATED_FURNITURE_ART as ea,FURNITURE_ART_FINGERPRINT as sa}from"./furniture-plan-art.generated-DaxkO8ol.js";import"./form-kit.styles-CKUQLdmn.js";const ia={},oa=t(class extends e{constructor(){super(...arguments),this.ot=ia}render(t,e){return e()}update(t,[e,i]){if(Array.isArray(e)){if(Array.isArray(this.ot)&&this.ot.length===e.length&&e.every((t,e)=>t===this.ot[e]))return s}else if(this.ot===e)return s;return this.ot=Array.isArray(e)?Array.from(e):e,this.render(e,i)}});var aa={"gs.show_room_tooltip":"Show the room information window on hover","support.about_group":"About the card","support.guide_group":"Documentation","support.guide":"User guide","support.form_group":"Send a report or suggestion","support.contact":"Contact details (email/tg/WhatsApp), optional.","support.message":"Message","support.attach":"Attach anonymized information from your plan","support.attach_hint":"Includes only allowed plan geometry, settings and bounded runtime facts. Excludes names, Home Assistant IDs, live states, URLs, files, and your message/contact.","support.geometry_warning":"The package contains no names or Home Assistant IDs, but it does contain the exact geometry and dimensions of your home.","support.close_busy_title":"Stop the current operation?","support.close_busy_body":"House Plan is preparing or sending the report. Closing now stops waiting for the result.","support.building":"Preparing anonymized data…","support.preview_summary":"Package v{version} · {spaces} spaces · {size} KiB","support.prepared":"Snapshot prepared {n} min ago","support.show_data":"Show data","support.download":"Download JSON","support.refresh":"Refresh snapshot","support.privacy":"When you send, your message, optional contact and, if selected, exact geometry leave your Home Assistant through the House Plan project relay and are visible to maintainers. The project node keeps the report for up to 30 days. Network infrastructure sees your HA server address, but House Plan does not retain it raw; rate-limit and idempotency metadata is kept for up to 24 hours.","support.error_title":"The report was not sent","support.manual_recovery":"You can keep the message and attachment and continue manually:","support.copy_message":"Copy message","support.success":"Report sent: {id}. Save this number when contacting support.","support.copy_id":"Copy ID","support.sending":"Sending…","support.retry":"Retry","support.send":"Send","support.update_required":"Update the House Plan card and integration to compatible versions to send reports.","support.message_copied":"Message copied","support.id_copied":"Report ID copied","support.copy_failed":"Could not access the clipboard. Select and copy the text manually.","support.validation.message_required":"Enter a message.","support.validation.message_too_long":"The message must contain no more than 10,000 characters.","support.validation.contact_too_long":"Contact details must contain no more than 320 characters.","support.validation.preview_missing":"Wait for the attachment preview or turn the attachment off.","support.validation.preview_expired":"The attachment preview expired. Refresh the snapshot.","support.error.support_invalid_message":"Check the message and try again.","support.error.support_preview_expired":"The attachment preview expired or is no longer available. Refresh the snapshot.","support.error.support_package_too_large":"The anonymized package exceeds the 8 MiB limit.","support.error.support_rate_limited":"Too many reports or previews were requested. Try again later.","support.error.support_unavailable":"The private support service is temporarily unavailable. Your draft remains here.","support.error.support_rejected":"The report did not pass the support service validation.","support.error.unauthorized":"You do not have permission to send this report.","vac.routes_section":"Maps and floors","vac.routes_current_map":"Current map","vac.routes_no_map":"no telemetry","vac.routes_status":"Routing","vac.routes_state_ready":"map assigned and calibrated","vac.routes_state_needs_calibration":"map assigned, calibration needed","vac.routes_state_unmapped":"current map is not assigned to a floor","vac.routes_state_ambiguous":"two maps are indistinguishable — no floor is chosen","vac.routes_state_missing_space":"the map's space was deleted","vac.routes_state_none":"no map data","vac.routes_empty":"No map is assigned to a floor yet.","vac.route_map_default":"no map id","vac.route_active":"Active","vac.route_space":"Space","vac.route_space_none":"not selected","vac.route_status_ready":"ready","vac.route_status_needs_calibration":"needs calibration","vac.route_status_ambiguous":"ambiguous","vac.route_status_missing_space":"space deleted","vac.route_missing_space_group":"Deleted space","vac.route_add_current":"Add current map","vac.route_delete":"Remove map","vac.route_delete_title":"Remove the map from its floor?","vac.route_delete_body":"Calibration and saved paths for this map will be removed. Continue?","vac.route_delete_confirm":"Remove","vac.route_space_title":"Move the map to another space?","vac.route_space_body":"Calibration and saved paths for this map will be removed. Continue?","vac.route_space_confirm":"Move","vac.route_missing_space_hint":"One of the maps points at a deleted space: pick a new one or remove the map. Until then the robot is not drawn for that map.","vac.route_default_hint":"The source reports no stable map id. Several floors cannot be told apart without another source or the robot's own selected map.","vac.route_target_hint":"The dock stays in the “{space}” space regardless of the current map.","vac.route_add_source":"Add a map source","vac.route_add_source_hint":"For integrations that give each map its own camera. The “All cameras” section above widens this list.","vac.route_source_no_map":"no map reported"};const na={en:aa,ru:{"gs.show_room_tooltip":"Показывать окно с информацией при наведении на комнату","support.about_group":"О карточке","support.guide_group":"Документация","support.guide":"Руководство пользователя","support.form_group":"Отправить репорт или предложение","support.contact":"Контакт для связи (email/tg/WhatsApp), необязательно.","support.message":"Сообщение","support.attach":"Прикрепить обезличенную информацию из вашего плана","support.attach_hint":"В пакет входят только разрешённые геометрия, настройки и ограниченные сведения о среде. Не входят имена, HA id, текущие состояния, URL, файлы, сообщение и контакт.","support.geometry_warning":"Пакет не содержит имён и HA id, но содержит точную геометрию и размеры дома.","support.close_busy_title":"Прервать текущую операцию?","support.close_busy_body":"House Plan подготавливает или отправляет репорт. При закрытии ожидание результата прекратится.","support.building":"Подготавливаем обезличенные данные…","support.preview_summary":"Пакет v{version} · пространств: {spaces} · {size} КиБ","support.prepared":"Снимок подготовлен {n} мин назад","support.show_data":"Показать данные","support.download":"Скачать JSON","support.refresh":"Обновить снимок","support.privacy":"При отправке сообщение, необязательный контакт и, если выбран пакет, точная геометрия покидают ваш Home Assistant через relay проекта House Plan и доступны мейнтейнерам. Узел проекта хранит репорт до 30 дней. Сетевая инфраструктура видит адрес сервера HA, но House Plan не сохраняет его в исходном виде; метаданные лимитов и идемпотентности хранятся до 24 часов.","support.error_title":"Репорт не отправлен","support.manual_recovery":"Сообщение и вложение можно сохранить и продолжить вручную:","support.copy_message":"Копировать сообщение","support.success":"Репорт отправлен: {id}. Сохраните номер для связи с поддержкой.","support.copy_id":"Копировать ID","support.sending":"Отправляем…","support.retry":"Повторить","support.send":"Отправить","support.update_required":"Обновите карточку и интеграцию House Plan до совместимых версий, чтобы отправлять репорты.","support.message_copied":"Сообщение скопировано","support.id_copied":"ID репорта скопирован","support.copy_failed":"Не удалось получить доступ к буферу обмена. Выделите и скопируйте текст вручную.","support.validation.message_required":"Введите сообщение.","support.validation.message_too_long":"Сообщение должно содержать не более 10 000 символов.","support.validation.contact_too_long":"Контакт должен содержать не более 320 символов.","support.validation.preview_missing":"Дождитесь предпросмотра вложения или отключите его.","support.validation.preview_expired":"Предпросмотр вложения истёк. Обновите снимок.","support.error.support_invalid_message":"Проверьте сообщение и повторите попытку.","support.error.support_preview_expired":"Предпросмотр вложения истёк или больше недоступен. Обновите снимок.","support.error.support_package_too_large":"Обезличенный пакет превышает лимит 8 МиБ.","support.error.support_rate_limited":"Запрошено слишком много репортов или предпросмотров. Повторите позже.","support.error.support_unavailable":"Закрытая служба поддержки временно недоступна. Черновик сохранён в этом окне.","support.error.support_rejected":"Репорт не прошёл проверку службы поддержки.","support.error.unauthorized":"У вас нет прав на отправку этого репорта.","vac.routes_section":"Карты и этажи","vac.routes_current_map":"Текущая карта","vac.routes_no_map":"источник молчит","vac.routes_status":"Маршрутизация","vac.routes_state_ready":"карта сопоставлена и откалибрована","vac.routes_state_needs_calibration":"карта сопоставлена, нужна калибровка","vac.routes_state_unmapped":"текущая карта не сопоставлена этажу","vac.routes_state_ambiguous":"две карты неразличимы — этаж не выбирается","vac.routes_state_missing_space":"пространство карты удалено","vac.routes_state_none":"нет данных о карте","vac.routes_empty":"Ни одна карта ещё не сопоставлена этажу.","vac.route_map_default":"без идентификатора","vac.route_active":"Текущая","vac.route_space":"Пространство","vac.route_space_none":"не выбрано","vac.route_status_ready":"готова","vac.route_status_needs_calibration":"нужна калибровка","vac.route_status_ambiguous":"неоднозначна","vac.route_status_missing_space":"пространство удалено","vac.route_missing_space_group":"Пространство удалено","vac.route_add_current":"Добавить текущую карту","vac.route_delete":"Удалить карту","vac.route_delete_title":"Удалить карту с этажа?","vac.route_delete_body":"Калибровка и сохранённые пути этой карты будут удалены. Продолжить?","vac.route_delete_confirm":"Удалить","vac.route_space_title":"Перенести карту в другое пространство?","vac.route_space_body":"Калибровка и сохранённые пути этой карты будут удалены. Продолжить?","vac.route_space_confirm":"Перенести","vac.route_missing_space_hint":"Одна из карт ссылается на удалённое пространство: выберите новое или удалите карту. Пока ссылка не исправлена, робот на этой карте не рисуется.","vac.route_default_hint":"Источник не сообщает стабильный идентификатор карты. Несколько этажей нельзя различить без другого источника или собственной карты робота.","vac.route_target_hint":"Док остаётся в пространстве «{space}» независимо от текущей карты.","vac.route_add_source":"Добавить источник карты","vac.route_add_source_hint":"Для интеграций, где у каждой карты своя камера. Список расширяется разделом «Все камеры» выше.","vac.route_source_no_map":"карта не читается"},de:{"gs.show_room_tooltip":"Rauminformationen beim Darüberfahren anzeigen","support.about_group":"Über die Karte","support.guide_group":"Dokumentation","support.guide":"Benutzerhandbuch","support.form_group":"Bericht oder Vorschlag senden","support.contact":"Kontakt (E-Mail/tg/WhatsApp), optional.","support.message":"Nachricht","support.attach":"Anonymisierte Informationen aus dem Plan anhängen","support.attach_hint":"Enthält nur erlaubte Plangeometrie, Einstellungen und begrenzte Laufzeitdaten. Namen, Home-Assistant-IDs, Live-Zustände, URLs, Dateien, Nachricht und Kontakt werden ausgeschlossen.","support.geometry_warning":"Das Paket enthält keine Namen oder Home-Assistant-IDs, aber die exakte Geometrie und die Maße Ihres Hauses.","support.close_busy_title":"Aktuellen Vorgang abbrechen?","support.close_busy_body":"House Plan bereitet den Bericht vor oder sendet ihn. Beim Schließen wird nicht weiter auf das Ergebnis gewartet.","support.building":"Anonymisierte Daten werden vorbereitet…","support.preview_summary":"Paket v{version} · {spaces} Bereiche · {size} KiB","support.prepared":"Schnappschuss vor {n} Min. erstellt","support.show_data":"Daten anzeigen","support.download":"JSON herunterladen","support.refresh":"Schnappschuss aktualisieren","support.privacy":"Beim Senden verlassen Ihre Nachricht, der optionale Kontakt und, falls ausgewählt, die exakte Geometrie Ihren Home Assistant über das House-Plan-Projektrelay und sind für die Maintainer sichtbar. Der Projektserver speichert den Bericht bis zu 30 Tage. Die Netzwerkinfrastruktur sieht die Adresse Ihres HA-Servers, House Plan speichert sie jedoch nicht im Rohformat; Limit- und Idempotenzdaten bleiben bis zu 24 Stunden erhalten.","support.error_title":"Der Bericht wurde nicht gesendet","support.manual_recovery":"Nachricht und Anhang können gespeichert und manuell weitergegeben werden:","support.copy_message":"Nachricht kopieren","support.success":"Bericht gesendet: {id}. Bewahren Sie diese Nummer für den Support auf.","support.copy_id":"ID kopieren","support.sending":"Wird gesendet…","support.retry":"Erneut versuchen","support.send":"Senden","support.update_required":"Aktualisieren Sie House-Plan-Karte und Integration auf kompatible Versionen, um Berichte zu senden.","support.message_copied":"Nachricht kopiert","support.id_copied":"Berichts-ID kopiert","support.copy_failed":"Kein Zugriff auf die Zwischenablage. Markieren und kopieren Sie den Text manuell.","support.validation.message_required":"Geben Sie eine Nachricht ein.","support.validation.message_too_long":"Die Nachricht darf höchstens 10.000 Zeichen enthalten.","support.validation.contact_too_long":"Der Kontakt darf höchstens 320 Zeichen enthalten.","support.validation.preview_missing":"Warten Sie auf die Vorschau oder deaktivieren Sie den Anhang.","support.validation.preview_expired":"Die Anhangsvorschau ist abgelaufen. Aktualisieren Sie den Schnappschuss.","support.error.support_invalid_message":"Prüfen Sie die Nachricht und versuchen Sie es erneut.","support.error.support_preview_expired":"Die Anhangsvorschau ist abgelaufen oder nicht mehr verfügbar. Aktualisieren Sie den Schnappschuss.","support.error.support_package_too_large":"Das anonymisierte Paket überschreitet das Limit von 8 MiB.","support.error.support_rate_limited":"Zu viele Berichte oder Vorschauen wurden angefordert. Versuchen Sie es später erneut.","support.error.support_unavailable":"Der private Supportdienst ist vorübergehend nicht verfügbar. Der Entwurf bleibt in diesem Fenster erhalten.","support.error.support_rejected":"Der Bericht hat die Prüfung des Supportdienstes nicht bestanden.","support.error.unauthorized":"Sie dürfen diesen Bericht nicht senden.","vac.routes_section":"Karten und Etagen","vac.routes_current_map":"Aktuelle Karte","vac.routes_no_map":"keine Telemetrie","vac.routes_status":"Zuordnung","vac.routes_state_ready":"Karte zugeordnet und kalibriert","vac.routes_state_needs_calibration":"Karte zugeordnet, Kalibrierung nötig","vac.routes_state_unmapped":"aktuelle Karte keiner Etage zugeordnet","vac.routes_state_ambiguous":"zwei Karten nicht unterscheidbar — keine Etage gewählt","vac.routes_state_missing_space":"der Raum der Karte wurde gelöscht","vac.routes_state_none":"keine Kartendaten","vac.routes_empty":"Noch keine Karte einer Etage zugeordnet.","vac.route_map_default":"ohne Karten-ID","vac.route_active":"Aktiv","vac.route_space":"Raum","vac.route_space_none":"nicht gewählt","vac.route_status_ready":"bereit","vac.route_status_needs_calibration":"Kalibrierung nötig","vac.route_status_ambiguous":"mehrdeutig","vac.route_status_missing_space":"Raum gelöscht","vac.route_missing_space_group":"Gelöschter Bereich","vac.route_add_current":"Aktuelle Karte hinzufügen","vac.route_delete":"Karte entfernen","vac.route_delete_title":"Karte von der Etage entfernen?","vac.route_delete_body":"Kalibrierung und gespeicherte Pfade dieser Karte werden entfernt. Fortfahren?","vac.route_delete_confirm":"Entfernen","vac.route_space_title":"Karte in einen anderen Raum verschieben?","vac.route_space_body":"Kalibrierung und gespeicherte Pfade dieser Karte werden entfernt. Fortfahren?","vac.route_space_confirm":"Verschieben","vac.route_missing_space_hint":"Eine Karte verweist auf einen gelöschten Raum: neuen wählen oder Karte entfernen. Bis dahin wird der Roboter für diese Karte nicht gezeichnet.","vac.route_default_hint":"Die Quelle meldet keine stabile Karten-ID. Mehrere Etagen lassen sich ohne andere Quelle oder die vom Roboter gewählte Karte nicht unterscheiden.","vac.route_target_hint":"Die Station bleibt unabhängig von der aktuellen Karte im Raum „{space}“.","vac.route_add_source":"Kartenquelle hinzufügen","vac.route_add_source_hint":"Für Integrationen, die jeder Karte eine eigene Kamera geben. Der Abschnitt „Alle Kameras“ oben erweitert diese Liste.","vac.route_source_no_map":"keine Karte gemeldet"},fr:{"gs.show_room_tooltip":"Afficher les informations de la pièce au survol","support.about_group":"À propos de la carte","support.guide_group":"Documentation d’aide","support.guide":"Guide utilisateur","support.form_group":"Envoyer un rapport ou une suggestion","support.contact":"Contact (e-mail/tg/WhatsApp), facultatif.","support.message":"Votre message","support.attach":"Joindre des informations anonymisées de votre plan","support.attach_hint":"Inclut uniquement la géométrie, les réglages autorisés et des données d’exécution limitées. Exclut les noms, identifiants Home Assistant, états en direct, URL, fichiers, message et contact.","support.geometry_warning":"Le paquet ne contient ni noms ni identifiants Home Assistant, mais il contient la géométrie et les dimensions exactes de votre logement.","support.close_busy_title":"Interrompre l’opération en cours ?","support.close_busy_body":"House Plan prépare ou envoie le rapport. Fermer maintenant arrête l’attente du résultat.","support.building":"Préparation des données anonymisées…","support.preview_summary":"Paquet v{version} · {spaces} espaces · {size} Kio","support.prepared":"Instantané préparé il y a {n} min","support.show_data":"Afficher les données","support.download":"Télécharger le JSON","support.refresh":"Actualiser l’instantané","support.privacy":"Lors de l’envoi, votre message, le contact facultatif et, si elle est sélectionnée, la géométrie exacte quittent votre Home Assistant via le relais du projet House Plan et sont visibles par les mainteneurs. Le serveur du projet conserve le rapport jusqu’à 30 jours. L’infrastructure réseau voit l’adresse de votre serveur HA, mais House Plan ne la conserve pas en clair ; les métadonnées de limitation et d’idempotence sont gardées jusqu’à 24 heures.","support.error_title":"Le rapport n’a pas été envoyé","support.manual_recovery":"Vous pouvez conserver le message et la pièce jointe puis continuer manuellement :","support.copy_message":"Copier le message","support.success":"Rapport envoyé : {id}. Conservez ce numéro pour contacter l’assistance.","support.copy_id":"Copier l’ID","support.sending":"Envoi…","support.retry":"Réessayer","support.send":"Envoyer","support.update_required":"Mettez à jour la carte et l’intégration House Plan vers des versions compatibles pour envoyer des rapports.","support.message_copied":"Message copié","support.id_copied":"ID du rapport copié","support.copy_failed":"Impossible d’accéder au presse-papiers. Sélectionnez et copiez le texte manuellement.","support.validation.message_required":"Saisissez un message.","support.validation.message_too_long":"Le message ne doit pas dépasser 10 000 caractères.","support.validation.contact_too_long":"Le contact ne doit pas dépasser 320 caractères.","support.validation.preview_missing":"Attendez l’aperçu de la pièce jointe ou désactivez-la.","support.validation.preview_expired":"L’aperçu de la pièce jointe a expiré. Actualisez l’instantané.","support.error.support_invalid_message":"Vérifiez le message et réessayez.","support.error.support_preview_expired":"L’aperçu de la pièce jointe a expiré ou n’est plus disponible. Actualisez l’instantané.","support.error.support_package_too_large":"Le paquet anonymisé dépasse la limite de 8 Mio.","support.error.support_rate_limited":"Trop de rapports ou d’aperçus ont été demandés. Réessayez plus tard.","support.error.support_unavailable":"Le service d’assistance privé est temporairement indisponible. Le brouillon reste dans cette fenêtre.","support.error.support_rejected":"Le rapport n’a pas passé la validation du service d’assistance.","support.error.unauthorized":"Vous n’êtes pas autorisé à envoyer ce rapport.","vac.routes_section":"Cartes et étages","vac.routes_current_map":"Carte actuelle","vac.routes_no_map":"aucune télémétrie","vac.routes_status":"Routage","vac.routes_state_ready":"carte assignée et calibrée","vac.routes_state_needs_calibration":"carte assignée, calibrage requis","vac.routes_state_unmapped":"carte actuelle non assignée à un étage","vac.routes_state_ambiguous":"deux cartes indiscernables — aucun étage choisi","vac.routes_state_missing_space":"l'espace de la carte a été supprimé","vac.routes_state_none":"aucune donnée de carte","vac.routes_empty":"Aucune carte n'est encore assignée à un étage.","vac.route_map_default":"sans identifiant","vac.route_active":"Active","vac.route_space":"Espace","vac.route_space_none":"non sélectionné","vac.route_status_ready":"prête","vac.route_status_needs_calibration":"calibrage requis","vac.route_status_ambiguous":"ambiguë","vac.route_status_missing_space":"espace supprimé","vac.route_missing_space_group":"Espace supprimé","vac.route_add_current":"Ajouter la carte actuelle","vac.route_delete":"Supprimer la carte","vac.route_delete_title":"Retirer la carte de son étage ?","vac.route_delete_body":"Le calibrage et les trajets enregistrés de cette carte seront supprimés. Continuer ?","vac.route_delete_confirm":"Supprimer","vac.route_space_title":"Déplacer la carte vers un autre espace ?","vac.route_space_body":"Le calibrage et les trajets enregistrés de cette carte seront supprimés. Continuer ?","vac.route_space_confirm":"Déplacer","vac.route_missing_space_hint":"Une carte pointe vers un espace supprimé : choisissez-en un autre ou supprimez la carte. D'ici là, le robot n'est pas dessiné pour cette carte.","vac.route_default_hint":"La source ne fournit pas d'identifiant de carte stable. Plusieurs étages ne peuvent pas être distingués sans une autre source ou la carte sélectionnée du robot.","vac.route_target_hint":"La station reste dans l'espace « {space} » quelle que soit la carte actuelle.","vac.route_add_source":"Ajouter une source de carte","vac.route_add_source_hint":"Pour les intégrations qui donnent à chaque carte sa propre caméra. La section « Toutes les caméras » ci-dessus élargit cette liste.","vac.route_source_no_map":"aucune carte signalée"}};function ra(t,e,s){return i(na[t]?.[e]??aa[e]??e,s)}function la(t,e,s,i,o){return{markerId:t,source:i,mapId:o,space:e.length?"":s}}function ha(t,e,s){return{...t,space:s.has(e)?e:""}}function ca(t,e=Math.random){const s=new Set(t);for(let t=0;t<64;t+=1){const t="vr_"+Math.floor(16777215*e()).toString(36).padStart(5,"0");if(!s.has(t))return t}return"vr_"+Date.now().toString(36)}function da(t,e,s){return t.map(t=>t.id===e?{...t,calibration:s}:t)}const pa=new WeakMap,ua=(t,e)=>{const s=(t._serverCfg?.spaces||[]).find(t=>t?.id===e);return String(s?.name||s?.id||e)};function _a(t,e,s){const i=t.host,n=l(i.hass,i._config?.language),r=(t,e)=>ra(n,t,e),u=e.marker?.vacuum||{},_=Array.isArray(u.map_routes),m=i._vacSource(e)||"",g=o(e.id,u,e.space,m),f=(i._serverCfg?.spaces||[]).filter(t=>"string"==typeof t?.id&&!!t.id).map(t=>({id:t.id,name:String(t.name||t.id)})),b=new Set(f.map(t=>t.id)),v=h(g,[m],t=>i._vacObservedMapId(e,t)),y=c({routes:g,observed:v,spaceIds:b}),w="ready"===y.kind||"needs_calibration"===y.kind||"missing_space"===y.kind?y.route.id:"",$=m?v[m]:void 0,k=async s=>{let o=_?u.map_routes??null:null;if(!o&&(o=function(t,e,s,i){if(!s)return null;const o=t?.calibration;if(!o||"object"!=typeof o)return null;const n=new Set,r=[];for(const t of Object.keys(o)){const l=a(o[t]);if(!l)continue;const h=i(n);n.add(h),r.push({id:h,source:s,map_id:t,space:e,calibration:l})}return r.length?r:null}(u,e.space,m,t=>ca(t))??[],!m&&Object.keys(u.calibration||{}).length))return!1;const n=s(o);return!!n&&(async s=>{const o=i._serverCfg;if(!o)return!1;const a=JSON.parse(JSON.stringify(o));a.markers=a.markers||[];let n=a.markers.find(t=>t.id===e.id);if(!n){if("device"!==e.bindingKind&&"entity"!==e.bindingKind||!e.bindingRef)return!1;n={id:e.id,binding:`${e.bindingKind}:${e.bindingRef}`,space:e.space||null,area:e.area||null,hidden:!!e.hidden},a.markers.push(n)}n.vacuum={...n.vacuum||{},map_routes:s},delete n.vacuum.calibration;const r=i._adoption.beginOptimistic(o,a);i._adoption.stageLocalConfig(a),i._regSignature="",i._maybeRebuildDevices(),i.requestUpdate(),i._saveConfigDebounced.pending()&&i._saveConfigDebounced.cancel();try{return await t._saveConfigNow(),!0}catch(t){return i._rollbackOptimistic(r),i._regSignature="",i._maybeRebuildDevices(),i.requestUpdate(),i._showToast(i._t("toast.cfg_save_failed",{err:i._errText(t)})),!1}})(n)},x=s.candidates.filter(t=>t.entityId!==m&&!g.some(e=>e.source===t.entityId)),M=async(t,e)=>{if(!e||e===t.space)return;await i._confirmDanger({key:"vacuum_route_space",kind:"warning",title:r("vac.route_space_title"),message:r("vac.route_space_body"),objectName:t.map_id||r("vac.route_map_default"),confirmLabel:r("vac.route_space_confirm"),cancelLabel:i._t("btn.cancel")})&&await k(s=>function(t,e,s,i){return t.map(t=>t.id===e?{...t,id:i,space:s,calibration:null}:t)}(s,t.id,e,ca(new Set(g.map(t=>t.id)))))},C=new Map(f.map((t,e)=>[t.id,e])),S=(t,e)=>t.map_id.localeCompare(e.map_id)||t.source.localeCompare(e.source)||t.id.localeCompare(e.id),P=g.filter(t=>b.has(t.space)).sort((t,e)=>(C.get(t.space)??0)-(C.get(e.space)??0)||S(t,e)),D=g.filter(t=>!b.has(t.space)).sort(S),I=[...P,...D],L=!!m&&void 0!==$&&!g.some(t=>t.source===m&&t.map_id===$);let T=pa.get(t);const R=T?.source||"",z=T?.mapId||"",F=!!T&&g.some(t=>t.source===R&&t.map_id===z);T&&(T.markerId!==e.id||i._vacObservedMapId(e,T.source)!==T.mapId||F&&!T.saving)&&(pa.delete(t),T=void 0),T?.space&&!b.has(T.space)&&(T=ha(T,"",b),pa.set(t,T));const N=s=>p`
  • ${s.map_id||r("vac.route_map_default")} @@ -81,28 +81,28 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${g.some(t=>"default"===t.map_id)?p`
    ${r("vac.route_default_hint")}
    `:d} ${I.length?p`
    ${r("vac.route_target_hint",{space:ua(i,e.space)})}
    `:d} -
    `}const ma=new Set(["bindingOpen","bindingFilter","runFilter","controlsFilter","busy","tapHintAnnouncement","uploadId","autoIcon"]);function ga(t){return mo(t,ma)}function fa(t){fo(t,"marker")}function ba(t){const e=[];return"ha"!==t.bindingMode||t.binding&&"virtual"!==t.binding||e.push({field:"marker-binding",message:"marker.error_binding"}),function(t){if(!t.trim())return!0;const e=u(t);return null!==e&&e>0}(t.glowRadius)||e.push({field:"marker-glow-radius",message:"marker.error_glow_radius"}),e}const va=new Set(["ld2450","hlkld2450","hilinkld2450"]),ya=()=>globalThis.crypto?.randomUUID?.()||`radar_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,8)}`,wa=(t,e,s)=>{const i=!!t?.original;return{radar:i?t:null,radarEligible:i,radarTouched:i?e:e||!!t,radarRemove:i?s:s||!!t}},$a=(t,e="")=>"number"==typeof t&&Number.isFinite(t)?String(t):e,ka=t=>Array.from(new Set([...t.allEntities||t.entities||[],..."entity"===t.bindingKind&&t.bindingRef?[t.bindingRef]:[]])).filter(t=>/^[a-z0-9_]+\.[a-z0-9_]+$/.test(t)),xa=(t,e,s)=>{const i=t.split(".",2)[1]||"";return new RegExp(`(?:^|_)target_?${s}_${e}(?:_|$)`).test(i)||new RegExp(`(?:^|_)target_${e}_${s}(?:_|$)`).test(i)};function Ma(t,e){if(t.marker?.radar&&"object"==typeof t.marker.radar)return _(t.marker.radar)?{eligible:!0,profile:t.marker.radar.profile,reason:"saved"}:{eligible:!0,profile:"presence_v1",reason:"saved_unsupported"};const s="entity"===t.bindingKind?e?.entities?.[t.bindingRef||""]:null,i="device"===t.bindingKind?t.bindingRef:s?.device_id,o=i?e?.devices?.[i]:null,a=ka(t);return va.has((n=o?.model||t.model,String(n||"").toLowerCase().replace(/[^a-z0-9]/g,"")))&&a.some(t=>xa(t,"x",1))&&a.some(t=>xa(t,"y",1))?{eligible:!0,profile:"esphome_ld2450_v1",reason:"ld2450"}:{eligible:!1,profile:"presence_v1",reason:"none"};var n}function Ca(t,e){return t.find(t=>e.some(e=>e.test(t)))||""}function Sa(t,e,s,i,o=!1){const a=Ma(t,i),n=_(t.marker?.radar)?t.marker.radar:null;if(!n&&!a.eligible&&!o)return null;const r=n?.profile||a.profile,l=o&&!a.eligible||"ld2450"!==a.reason?{xEntities:["","",""],yEntities:["","",""],distanceEntity:"",angleEntity:"",occupancyEntity:"",countEntity:"",zoneEntity:""}:function(t,e,s){const i=ka(t).filter(t=>!!s?.states?.[t]),o=[],a=[];for(let t=1;t<=3;t++)o.push(i.find(e=>xa(e,"x",t))||""),a.push(i.find(e=>xa(e,"y",t))||"");const n=i.filter(t=>t.startsWith("binary_sensor.")),r=i.filter(t=>t.startsWith("sensor.")),l=Ca(n,[/(?:occupancy|presence|target)(?:_|$)/]);return{xEntities:o,yEntities:a,distanceEntity:Ca(r,[/(?:target_)?distance(?:_|$)/,/distance/]),angleEntity:Ca(r,[/(?:target_)?angle(?:_|$)/,/angle/]),occupancyEntity:l,countEntity:Ca(r,[/(?:target|people|presence)_count(?:_|$)/,/target_count/]),zoneEntity:"zones_v1"===e?Ca(n,[/(?:zone|region).*(?:occupancy|presence)/,/zone/]):""}}(t,r,i),h=n?.sources||{},c=h.slots||[],d=c.filter(t=>"x_entity"in t),p=c.filter(t=>"distance_entity"in t),u=h.ranges||[],m=h.zones?.[0],g="esphome_ld2450_v1"===r?3:"cartesian_v1"===r?Math.max(1,d.length):"polar_v1"===r?Math.max(1,p.length):1,f=n?.room_id||t.marker?.room_id||e.rooms.find(e=>e.area&&e.area===t.area)?.id||"";return{original:n,enabled:!0===n?.enabled,showLive:!1!==n?.show_live,profile:r,roomId:f,installationId:n?.mount?.installation_id||ya(),mountX:$a(null==n?.mount?.x?void 0:1e3*n.mount.x,$a(s[0],"0")),mountY:$a(null==n?.mount?.y?void 0:1e3*n.mount.y,$a(s[1],"0")),heading:$a(n?.mount?.heading_deg,"0"),rangeCm:$a(n?.mount?.range_cm,"esphome_ld2450_v1"===r?"600":""),fovDeg:$a(n?.mount?.fov_deg,"esphome_ld2450_v1"===r?"120":""),mirror:!0===n?.calibration?.mirror,unit:d[0]?.unit||p[0]?.unit||u[0]?.unit||("esphome_ld2450_v1"===r?"mm":"cm"),xEntities:Array.from({length:g},(t,e)=>d[e]?.x_entity||l.xEntities[e]||""),yEntities:Array.from({length:g},(t,e)=>d[e]?.y_entity||l.yEntities[e]||""),distanceEntities:Array.from({length:g},(t,e)=>p[e]?.distance_entity||(0===e?l.distanceEntity:"")),angleEntities:Array.from({length:g},(t,e)=>p[e]?.angle_entity||(0===e?l.angleEntity:"")),rangeEntities:u.length?u.map(t=>t.entity_id):[l.distanceEntity],slotPresenceEntities:Array.from({length:g},(t,e)=>(d[e]||p[e])?.presence_entity||""),rangePresenceEntities:(u.length?u:[{}]).map(t=>"presence_entity"in t&&t.presence_entity||""),swapXY:Array.from({length:g},(t,e)=>!0===d[e]?.swap_xy),xSigns:Array.from({length:g},(t,e)=>-1===d[e]?.x_sign?-1:1),ySigns:Array.from({length:g},(t,e)=>-1===d[e]?.y_sign?-1:1),angleUnit:p[0]?.angle_unit||"degrees",angleZero:p[0]?.angle_zero||"forward",angleClockwise:!1!==p[0]?.angle_clockwise,occupancyEntity:h.occupancy_entity||l.occupancyEntity,countEntity:h.count_entity||l.countEntity,availabilityEntity:h.availability_entity||"",zoneEntity:m?.entity_id||l.zoneEntity,zoneKind:m?.kind||"occupancy"}}const Pa=t=>JSON.stringify(t,(t,e)=>e&&"object"==typeof e&&!Array.isArray(e)?Object.fromEntries(Object.entries(e).sort(([t],[e])=>te?1:0)):e),Da=t=>{if(!t.trim())return null;const e=Number(t.replace(",","."));return Number.isFinite(e)?e:null};function Ia(t,e){const s=Da(t.mountX),i=Da(t.mountY),o=Da(t.heading);if(!t.roomId||null==s||null==i||null==o)return null;const a={...t.original?.sources||{}};if(delete a.slots,delete a.ranges,delete a.zones,delete a.occupancy_entity,delete a.count_entity,"esphome_ld2450_v1"===t.profile||"cartesian_v1"===t.profile){if(a.slots=t.xEntities.flatMap((e,s)=>{const i=t.yEntities[s]||"";return e&&i?[{id:`target_${s+1}`,x_entity:e,y_entity:i,unit:"esphome_ld2450_v1"===t.profile?"mm":t.unit,..."cartesian_v1"===t.profile&&t.swapXY[s]?{swap_xy:!0}:{},..."cartesian_v1"===t.profile&&-1===t.xSigns[s]?{x_sign:-1}:{},..."cartesian_v1"===t.profile&&-1===t.ySigns[s]?{y_sign:-1}:{},...t.slotPresenceEntities[s]?{presence_entity:t.slotPresenceEntities[s]}:{}}]:[]}),!a.slots.length)return null}else if("polar_v1"===t.profile){if(a.slots=t.distanceEntities.flatMap((e,s)=>{const i=t.angleEntities[s]||"";return e&&i?[{id:`target_${s+1}`,distance_entity:e,angle_entity:i,unit:t.unit,angle_unit:t.angleUnit,angle_zero:t.angleZero,angle_clockwise:t.angleClockwise,...t.slotPresenceEntities[s]?{presence_entity:t.slotPresenceEntities[s]}:{}}]:[]}),!a.slots.length)return null}else if("range_v1"===t.profile){if(a.ranges=t.rangeEntities.flatMap((e,s)=>e?[{id:`range_${s+1}`,entity_id:e,unit:t.unit,...t.rangePresenceEntities[s]?{presence_entity:t.rangePresenceEntities[s]}:{}}]:[]),!a.ranges.length)return null}else if("zones_v1"===t.profile){if(!t.zoneEntity)return null;a.zones=[{id:"zone_1",kind:t.zoneKind,entity_id:t.zoneEntity}]}else if("presence_v1"===t.profile&&!t.occupancyEntity)return null;t.occupancyEntity&&(a.occupancy_entity=t.occupancyEntity),t.countEntity&&(a.count_entity=t.countEntity),t.availabilityEntity&&(a.availability_entity=t.availabilityEntity);const n=Da(t.rangeCm),r=Da(t.fovDeg),l=(o%360+360)%360,h={...t.original?.mount||{},installation_id:t.installationId,x:s/1e3,y:i/1e3,heading_deg:l};null!=n&&n>0?h.range_cm=n:delete h.range_cm,null!=r&&r>0?h.fov_deg=r:delete h.fov_deg;const c=t.original,d="two_point"===c?.calibration?.method&&c.profile===t.profile&&Pa(c.sources)===Pa(a)&&c.mount.installation_id===t.installationId&&Math.abs(c.mount.x-h.x)<1e-12&&Math.abs(c.mount.y-h.y)<1e-12&&Math.abs(c.mount.heading_deg-l)<1e-9&&c.calibration.mirror===t.mirror&&Math.abs(c.calibration.cell_cm-e)<1e-9,p=t.calibrationOverride?{...t.calibrationOverride}:d?{...c.calibration}:{...c?.calibration||{},method:"zones_v1"===t.profile||"presence_v1"===t.profile?"not_required":"manual",mirror:t.mirror,cell_cm:e};t.calibrationOverride||d||(delete p.refs,delete p.rms_cm);const u={...t.original||{},version:1,enabled:t.enabled,profile:t.profile,sources:a,mount:h,room_id:t.roomId,calibration:p};return t.showLive?delete u.show_live:u.show_live=!1,u}const La={badge:"display.badge",icon_ripple:"display.icon_ripple",value:"display.value",static_icon:"display.static_icon",value_static_icon:"display.value_static_icon"},Ta={badge:"marker.display_hint_badge",icon_ripple:"marker.display_hint_icon_ripple",value:"marker.display_hint_value",static_icon:"marker.display_hint_static_icon",value_static_icon:"marker.display_hint_value_static_icon"},Ra=["top","right","bottom","left"];function za(t,e,s){return p``}const ma=new Set(["bindingOpen","bindingFilter","runFilter","controlsFilter","busy","tapHintAnnouncement","uploadId","autoIcon"]);function ga(t){return mo(t,ma)}function fa(t){fo(t,"marker")}const ba=new Set(["ld2450","hlkld2450","hilinkld2450"]),va=()=>globalThis.crypto?.randomUUID?.()||`radar_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,8)}`,ya=(t,e,s)=>{const i=!!t?.original;return{radar:i?t:null,radarEligible:i,radarTouched:i?e:e||!!t,radarRemove:i?s:s||!!t}},wa=(t,e="")=>"number"==typeof t&&Number.isFinite(t)?String(t):e,$a=t=>Array.from(new Set([...t.allEntities||t.entities||[],..."entity"===t.bindingKind&&t.bindingRef?[t.bindingRef]:[]])).filter(t=>/^[a-z0-9_]+\.[a-z0-9_]+$/.test(t)),ka=(t,e,s)=>{const i=t.split(".",2)[1]||"";return new RegExp(`(?:^|_)target_?${s}_${e}(?:_|$)`).test(i)||new RegExp(`(?:^|_)target_${e}_${s}(?:_|$)`).test(i)};function xa(t,e){if(t.marker?.radar&&"object"==typeof t.marker.radar)return u(t.marker.radar)?{eligible:!0,profile:t.marker.radar.profile,reason:"saved"}:{eligible:!0,profile:"presence_v1",reason:"saved_unsupported"};const s="entity"===t.bindingKind?e?.entities?.[t.bindingRef||""]:null,i="device"===t.bindingKind?t.bindingRef:s?.device_id,o=i?e?.devices?.[i]:null,a=$a(t);return ba.has((n=o?.model||t.model,String(n||"").toLowerCase().replace(/[^a-z0-9]/g,"")))&&a.some(t=>ka(t,"x",1))&&a.some(t=>ka(t,"y",1))?{eligible:!0,profile:"esphome_ld2450_v1",reason:"ld2450"}:{eligible:!1,profile:"presence_v1",reason:"none"};var n}function Ma(t,e){return t.find(t=>e.some(e=>e.test(t)))||""}function Ca(t,e,s,i,o=!1){const a=xa(t,i),n=u(t.marker?.radar)?t.marker.radar:null;if(!n&&!a.eligible&&!o)return null;const r=n?.profile||a.profile,l=o&&!a.eligible||"ld2450"!==a.reason?{xEntities:["","",""],yEntities:["","",""],distanceEntity:"",angleEntity:"",occupancyEntity:"",countEntity:"",zoneEntity:""}:function(t,e,s){const i=$a(t).filter(t=>!!s?.states?.[t]),o=[],a=[];for(let t=1;t<=3;t++)o.push(i.find(e=>ka(e,"x",t))||""),a.push(i.find(e=>ka(e,"y",t))||"");const n=i.filter(t=>t.startsWith("binary_sensor.")),r=i.filter(t=>t.startsWith("sensor.")),l=Ma(n,[/(?:occupancy|presence|target)(?:_|$)/]);return{xEntities:o,yEntities:a,distanceEntity:Ma(r,[/(?:target_)?distance(?:_|$)/,/distance/]),angleEntity:Ma(r,[/(?:target_)?angle(?:_|$)/,/angle/]),occupancyEntity:l,countEntity:Ma(r,[/(?:target|people|presence)_count(?:_|$)/,/target_count/]),zoneEntity:"zones_v1"===e?Ma(n,[/(?:zone|region).*(?:occupancy|presence)/,/zone/]):""}}(t,r,i),h=n?.sources||{},c=h.slots||[],d=c.filter(t=>"x_entity"in t),p=c.filter(t=>"distance_entity"in t),_=h.ranges||[],m=h.zones?.[0],g="esphome_ld2450_v1"===r?3:"cartesian_v1"===r?Math.max(1,d.length):"polar_v1"===r?Math.max(1,p.length):1,f=n?.room_id||t.marker?.room_id||e.rooms.find(e=>e.area&&e.area===t.area)?.id||"";return{original:n,enabled:!0===n?.enabled,showLive:!1!==n?.show_live,profile:r,roomId:f,installationId:n?.mount?.installation_id||va(),mountX:wa(null==n?.mount?.x?void 0:1e3*n.mount.x,wa(s[0],"0")),mountY:wa(null==n?.mount?.y?void 0:1e3*n.mount.y,wa(s[1],"0")),heading:wa(n?.mount?.heading_deg,"0"),rangeCm:wa(n?.mount?.range_cm,"esphome_ld2450_v1"===r?"600":""),fovDeg:wa(n?.mount?.fov_deg,"esphome_ld2450_v1"===r?"120":""),mirror:!0===n?.calibration?.mirror,unit:d[0]?.unit||p[0]?.unit||_[0]?.unit||("esphome_ld2450_v1"===r?"mm":"cm"),xEntities:Array.from({length:g},(t,e)=>d[e]?.x_entity||l.xEntities[e]||""),yEntities:Array.from({length:g},(t,e)=>d[e]?.y_entity||l.yEntities[e]||""),distanceEntities:Array.from({length:g},(t,e)=>p[e]?.distance_entity||(0===e?l.distanceEntity:"")),angleEntities:Array.from({length:g},(t,e)=>p[e]?.angle_entity||(0===e?l.angleEntity:"")),rangeEntities:_.length?_.map(t=>t.entity_id):[l.distanceEntity],slotPresenceEntities:Array.from({length:g},(t,e)=>(d[e]||p[e])?.presence_entity||""),rangePresenceEntities:(_.length?_:[{}]).map(t=>"presence_entity"in t&&t.presence_entity||""),swapXY:Array.from({length:g},(t,e)=>!0===d[e]?.swap_xy),xSigns:Array.from({length:g},(t,e)=>-1===d[e]?.x_sign?-1:1),ySigns:Array.from({length:g},(t,e)=>-1===d[e]?.y_sign?-1:1),angleUnit:p[0]?.angle_unit||"degrees",angleZero:p[0]?.angle_zero||"forward",angleClockwise:!1!==p[0]?.angle_clockwise,occupancyEntity:h.occupancy_entity||l.occupancyEntity,countEntity:h.count_entity||l.countEntity,availabilityEntity:h.availability_entity||"",zoneEntity:m?.entity_id||l.zoneEntity,zoneKind:m?.kind||"occupancy"}}const Sa=t=>JSON.stringify(t,(t,e)=>e&&"object"==typeof e&&!Array.isArray(e)?Object.fromEntries(Object.entries(e).sort(([t],[e])=>te?1:0)):e),Pa=t=>{if(!t.trim())return null;const e=Number(t.replace(",","."));return Number.isFinite(e)?e:null};function Da(t,e){const s=Pa(t.mountX),i=Pa(t.mountY),o=Pa(t.heading);if(!t.roomId||null==s||null==i||null==o)return null;const a={...t.original?.sources||{}};if(delete a.slots,delete a.ranges,delete a.zones,delete a.occupancy_entity,delete a.count_entity,"esphome_ld2450_v1"===t.profile||"cartesian_v1"===t.profile){if(a.slots=t.xEntities.flatMap((e,s)=>{const i=t.yEntities[s]||"";return e&&i?[{id:`target_${s+1}`,x_entity:e,y_entity:i,unit:"esphome_ld2450_v1"===t.profile?"mm":t.unit,..."cartesian_v1"===t.profile&&t.swapXY[s]?{swap_xy:!0}:{},..."cartesian_v1"===t.profile&&-1===t.xSigns[s]?{x_sign:-1}:{},..."cartesian_v1"===t.profile&&-1===t.ySigns[s]?{y_sign:-1}:{},...t.slotPresenceEntities[s]?{presence_entity:t.slotPresenceEntities[s]}:{}}]:[]}),!a.slots.length)return null}else if("polar_v1"===t.profile){if(a.slots=t.distanceEntities.flatMap((e,s)=>{const i=t.angleEntities[s]||"";return e&&i?[{id:`target_${s+1}`,distance_entity:e,angle_entity:i,unit:t.unit,angle_unit:t.angleUnit,angle_zero:t.angleZero,angle_clockwise:t.angleClockwise,...t.slotPresenceEntities[s]?{presence_entity:t.slotPresenceEntities[s]}:{}}]:[]}),!a.slots.length)return null}else if("range_v1"===t.profile){if(a.ranges=t.rangeEntities.flatMap((e,s)=>e?[{id:`range_${s+1}`,entity_id:e,unit:t.unit,...t.rangePresenceEntities[s]?{presence_entity:t.rangePresenceEntities[s]}:{}}]:[]),!a.ranges.length)return null}else if("zones_v1"===t.profile){if(!t.zoneEntity)return null;a.zones=[{id:"zone_1",kind:t.zoneKind,entity_id:t.zoneEntity}]}else if("presence_v1"===t.profile&&!t.occupancyEntity)return null;t.occupancyEntity&&(a.occupancy_entity=t.occupancyEntity),t.countEntity&&(a.count_entity=t.countEntity),t.availabilityEntity&&(a.availability_entity=t.availabilityEntity);const n=Pa(t.rangeCm),r=Pa(t.fovDeg),l=(o%360+360)%360,h={...t.original?.mount||{},installation_id:t.installationId,x:s/1e3,y:i/1e3,heading_deg:l};null!=n&&n>0?h.range_cm=n:delete h.range_cm,null!=r&&r>0?h.fov_deg=r:delete h.fov_deg;const c=t.original,d="two_point"===c?.calibration?.method&&c.profile===t.profile&&Sa(c.sources)===Sa(a)&&c.mount.installation_id===t.installationId&&Math.abs(c.mount.x-h.x)<1e-12&&Math.abs(c.mount.y-h.y)<1e-12&&Math.abs(c.mount.heading_deg-l)<1e-9&&c.calibration.mirror===t.mirror&&Math.abs(c.calibration.cell_cm-e)<1e-9,p=t.calibrationOverride?{...t.calibrationOverride}:d?{...c.calibration}:{...c?.calibration||{},method:"zones_v1"===t.profile||"presence_v1"===t.profile?"not_required":"manual",mirror:t.mirror,cell_cm:e};t.calibrationOverride||d||(delete p.refs,delete p.rms_cm);const u={...t.original||{},version:1,enabled:t.enabled,profile:t.profile,sources:a,mount:h,room_id:t.roomId,calibration:p};return t.showLive?delete u.show_live:u.show_live=!1,u}const Ia={badge:"display.badge",icon_ripple:"display.icon_ripple",value:"display.value",static_icon:"display.static_icon",value_static_icon:"display.value_static_icon"},La={badge:"marker.display_hint_badge",icon_ripple:"marker.display_hint_icon_ripple",value:"marker.display_hint_value",static_icon:"marker.display_hint_static_icon",value_static_icon:"marker.display_hint_value_static_icon"},Ta=["top","right","bottom","left"];function Ra(t,e,s){return p` ${t} - `}function Fa(){bo(this.host);const t=this.host._markerDialog,e=this.host._t.bind(this.host),{st:s,shelp:i}=vo(this.host),o="virtual"===t.bindingMode,a=this._bindingCandidates(),n=o?null:this.host._bindingStatus(t.binding),r=!o&&this.host._bindingHasHaPage(t.binding),l=this._markerPreviewDevice(t),h=this._effectiveMarkerTapAction(t,l),c=l?m(this.host._serverCfg?.spaces.find(t=>t.id===l.space)):null,u=l?this._markerPreviewDevices(l):this.host._devices,_="toggle"===h&&l?this._toggleIntent(l,u):null,z=this._toggleHintLines(_),F=l?g(this.host._planHass,l,{liveStates:!1!==this.host._config?.live_states,showTemperature:!1!==this.host._config?.show_temperature,showSignal:c?.showLqi??!1!==this.host._config?.show_signal,designPreview:!0,activityRuntime:this.host._activityRt.get(l.id),lightDevices:u,registryHass:this.host._fullRegistryHass,reducedMotion:this.host._reducedMotion}):null,N=l?f(this.host._planHass,l,u):[],A=l?b(this.host._planHass,l,N):null,E=t.valueBadgeTouched?t.valueBadgeEnabled:!!F?.valueBadge,O=t.valueBadgeTouched?t.valueBadgeSource:F?.valueBadge?.source||t.valueBadgeSource,B=t.valueBadgeTouched?t.valueBadgePosition:F?.valueBadge?.position||t.valueBadgePosition,H=v(O),W=!!O&&!N.some(t=>t.key===H),j=N.find(t=>t.key===H),G=v(t.valueSource),q=!(!t.valueSource||G&&N.some(t=>t.key===G)),U=N.find(t=>t.key===G),K=F?.valueSource?.sourceKey||"",V=this._markerAutoHasSpatialSource(t),J=!!l&&y(this.host._planHass,{...l}),Z=w(t.lightRole,V,J,t.glowMode),Y=!Z.sourceExists,X=!Z.fromSourceEnabled,Q=Z.passive,tt=Z.effectiveMode,et="never"===t.lightRole?e("marker.glow_disabled_never"):"auto"!==t.lightRole||V?e(Q?"marker.glow_passive_hint":"marker.glow_disabled_no_entity"):e("marker.glow_disabled_auto"),st=l?$(l):[],it=l&&k(l)||"",ot=!!t.lightEntity&&!st.includes(t.lightEntity),at=l?x(l):[],nt=!!t.toggleEntity&&!at.includes(t.toggleEntity),rt="toggle"===h?this._toggleIntentForDialog({...t,toggleEntity:"",toggleEntityTouched:!0}):null,lt=rt?[...rt.targets,...rt.skippedTargets].map(t=>t.entityId||("ref"in t?t.ref:"")).filter(Boolean).join(", "):"",ht=(()=>{if(o)return null;const e=a.find(e=>e.value===t.binding);if(e)return e.label;const[s,i]=t.binding.split(":");return"device"===s?this.host._fullRegistryHass.devices[i]?.name_by_user||this.host._fullRegistryHass.devices[i]?.name||i:this.host._fullRegistryHass.entities[i]?.name||this.host.hass.states[i]?.attributes?.friendly_name||i})(),ct=t=>this.host.hass.states[t]?.attributes?.friendly_name||this.host._fullRegistryHass.entities[t]?.name||t,dt=this.host._imperial?e("gs.unit_ft"):e("gs.unit_m"),pt=!!t.devId,ut=ba(t),_t=t=>ut.find(e=>e.field===t),mt=function(t,e){return go(t,"marker",ga(e))}(this.host,t),gt="ha"===t.bindingMode&&!t.devId&&"active"!==n?.kind,ft=!t.busy&&!this._radarSetup.isActive()&&0===ut.length&&!gt&&(!pt||mt),bt=ut[0]?s(ut[0].message):gt&&t.binding&&"virtual"!==t.binding?e("marker.ha_registry_limited"):"",vt=async e=>{if(!pt||!mt)return fa(this.host),void this._closeMarkerDialog();const i=e.currentTarget;await this.host._confirmDanger({key:"discard-marker-dialog",kind:"warning",title:s("dialog.discard_title"),message:s("dialog.discard_message"),objectName:t.name.trim()||l?.name||void 0,confirmLabel:s("dialog.discard_confirm"),cancelLabel:s("dialog.discard_keep")})?(fa(this.host),this._closeMarkerDialog()):i?.rejectClose?.()},yt=_t("marker-binding"),wt=_t("marker-glow-radius"),$t="ha_disabled"===n?.kind?yo({kind:"warning",role:"status",icon:"mdi:power-plug-off-outline",text:e(`marker.ha_disabled_${n.reason}`),action:r?wo(e("btn.open_in_ha"),()=>this.host._openBindingInHa(t.binding)):void 0}):"unverified"===n?.kind&&t.binding?yo({kind:"warning",role:"status",icon:"mdi:shield-alert-outline",text:e("marker.ha_registry_limited")}):d,kt="ha"===t.bindingMode?$o({id:"marker-binding",open:t.bindingOpen,current:ht?{label:ht,sub:`${t.binding}${"ha_disabled"===n?.kind?` · ${e("marker.binding_disabled")}`:""}`}:null,placeholder:e("marker.pick_ph"),ariaLabel:e("marker.binding_label"),filter:t.bindingFilter,filterPlaceholder:e("marker.search_ph"),candidates:a,selected:t.binding,emptyText:e("marker.nothing_found"),onToggle:()=>this.host._markerDialog={...t,bindingOpen:!t.bindingOpen},onFilter:e=>this.host._markerDialog={...t,bindingFilter:e},onPick:e=>{if(e===t.binding)return void(this.host._markerDialog={...t,bindingOpen:!1});const s={...t,binding:e,bindingOpen:!1,controls:R(e,t.controls,this.host._bindingEntities(e)),autoIcon:this.host._autoIconForBinding(e),...wa(t.radar,t.radarTouched,t.radarRemove)};this.host._markerDialog=this._announceToggleDraft({...s,...this._valueBadgeForBinding(s,e),valueSource:null,valueSourceTouched:!0})},toolbar:p``}function za(){bo(this.host);const t=this.host._markerDialog,e=this.host._t.bind(this.host),{st:s,shelp:i}=vo(this.host),o="virtual"===t.bindingMode,a=this._bindingCandidates(),n=o?null:this.host._bindingStatus(t.binding),r=!o&&this.host._bindingHasHaPage(t.binding),l=this._markerPreviewDevice(t),h=this._effectiveMarkerTapAction(t,l),c=l?_(this.host._serverCfg?.spaces.find(t=>t.id===l.space)):null,u=l?this._markerPreviewDevices(l):this.host._devices,R="toggle"===h&&l?this._toggleIntent(l,u):null,z=this._toggleHintLines(R),F=l?m(this.host._planHass,l,{liveStates:!1!==this.host._config?.live_states,showTemperature:!1!==this.host._config?.show_temperature,showSignal:c?.showLqi??!1!==this.host._config?.show_signal,designPreview:!0,activityRuntime:this.host._activityRt.get(l.id),lightDevices:u,registryHass:this.host._fullRegistryHass,reducedMotion:this.host._reducedMotion}):null,N=l?g(this.host._planHass,l,u):[],A=l?f(this.host._planHass,l,N):null,E=t.valueBadgeTouched?t.valueBadgeEnabled:!!F?.valueBadge,O=t.valueBadgeTouched?t.valueBadgeSource:F?.valueBadge?.source||t.valueBadgeSource,B=t.valueBadgeTouched?t.valueBadgePosition:F?.valueBadge?.position||t.valueBadgePosition,H=b(O),W=!!O&&!N.some(t=>t.key===H),j=N.find(t=>t.key===H),G=b(t.valueSource),q=!(!t.valueSource||G&&N.some(t=>t.key===G)),U=N.find(t=>t.key===G),K=F?.valueSource?.sourceKey||"",V=this._markerAutoHasSpatialSource(t),J=!!l&&v(this.host._planHass,{...l}),Z=y(t.lightRole,V,J,t.glowMode),Y=!Z.sourceExists,X=!Z.fromSourceEnabled,Q=Z.passive,tt=Z.effectiveMode,et="never"===t.lightRole?e("marker.glow_disabled_never"):"auto"!==t.lightRole||V?e(Q?"marker.glow_passive_hint":"marker.glow_disabled_no_entity"):e("marker.glow_disabled_auto"),st=l?w(l):[],it=l&&$(l)||"",ot=!!t.lightEntity&&!st.includes(t.lightEntity),at=l?k(l):[],nt=!!t.toggleEntity&&!at.includes(t.toggleEntity),rt="toggle"===h?this._toggleIntentForDialog({...t,toggleEntity:"",toggleEntityTouched:!0}):null,lt=rt?[...rt.targets,...rt.skippedTargets].map(t=>t.entityId||("ref"in t?t.ref:"")).filter(Boolean).join(", "):"",ht=(()=>{if(o)return null;const e=a.find(e=>e.value===t.binding);if(e)return e.label;const[s,i]=t.binding.split(":");return"device"===s?this.host._fullRegistryHass.devices[i]?.name_by_user||this.host._fullRegistryHass.devices[i]?.name||i:this.host._fullRegistryHass.entities[i]?.name||this.host.hass.states[i]?.attributes?.friendly_name||i})(),ct=t=>this.host.hass.states[t]?.attributes?.friendly_name||this.host._fullRegistryHass.entities[t]?.name||t,dt=this.host._imperial?e("gs.unit_ft"):e("gs.unit_m"),pt=!!t.devId,ut=function(t){const e=[];return"ha"!==t.bindingMode||t.binding&&"virtual"!==t.binding||e.push({field:"marker-binding",message:"marker.error_binding"}),e}(t),_t=function(t,e){return go(t,"marker",ga(e))}(this.host,t),mt="ha"===t.bindingMode&&!t.devId&&"active"!==n?.kind,gt=!t.busy&&!this._radarSetup.isActive()&&0===ut.length&&!mt&&(!pt||_t),ft=ut[0]?s(ut[0].message):mt&&t.binding&&"virtual"!==t.binding?e("marker.ha_registry_limited"):"",bt=async e=>{if(!pt||!_t)return fa(this.host),void this._closeMarkerDialog();const i=e.currentTarget;await this.host._confirmDanger({key:"discard-marker-dialog",kind:"warning",title:s("dialog.discard_title"),message:s("dialog.discard_message"),objectName:t.name.trim()||l?.name||void 0,confirmLabel:s("dialog.discard_confirm"),cancelLabel:s("dialog.discard_keep")})?(fa(this.host),this._closeMarkerDialog()):i?.rejectClose?.()},vt=(yt="marker-binding",ut.find(t=>t.field===yt));var yt;const wt="ha_disabled"===n?.kind?yo({kind:"warning",role:"status",icon:"mdi:power-plug-off-outline",text:e(`marker.ha_disabled_${n.reason}`),action:r?wo(e("btn.open_in_ha"),()=>this.host._openBindingInHa(t.binding)):void 0}):"unverified"===n?.kind&&t.binding?yo({kind:"warning",role:"status",icon:"mdi:shield-alert-outline",text:e("marker.ha_registry_limited")}):d,$t="ha"===t.bindingMode?$o({id:"marker-binding",open:t.bindingOpen,current:ht?{label:ht,sub:`${t.binding}${"ha_disabled"===n?.kind?` · ${e("marker.binding_disabled")}`:""}`}:null,placeholder:e("marker.pick_ph"),ariaLabel:e("marker.binding_label"),filter:t.bindingFilter,filterPlaceholder:e("marker.search_ph"),candidates:a,selected:t.binding,emptyText:e("marker.nothing_found"),onToggle:()=>this.host._markerDialog={...t,bindingOpen:!t.bindingOpen},onFilter:e=>this.host._markerDialog={...t,bindingFilter:e},onPick:e=>{if(e===t.binding)return void(this.host._markerDialog={...t,bindingOpen:!1});const s={...t,binding:e,bindingOpen:!1,controls:T(e,t.controls,this.host._bindingEntities(e)),autoIcon:this.host._autoIconForBinding(e),...ya(t.radar,t.radarTouched,t.radarRemove)};this.host._markerDialog=this._announceToggleDraft({...s,...this._valueBadgeForBinding(s,e),valueSource:null,valueSourceTouched:!0})},toolbar:p``}):d,xt=ko({id:"basics",title:e("marker.card_basics"),body:p` - ${$t} + `}):d,kt=ko({id:"basics",title:e("marker.card_basics"),body:p` + ${wt} ${xo({label:e("marker.name_label"),htmlFor:"marker-name",hint:s("marker.name_hint"),control:p`this.host._markerDialog={...t,name:e.target.value}} />`})} - ${xo({label:e("marker.binding_label"),help:i("marker.binding.help"),error:yt?s(yt.message):void 0,hint:o?s("marker.binding_virtual_hint"):void 0,control:p`${Mo({name:"bmode",value:t.bindingMode,ariaLabel:e("marker.binding_label"),options:[{value:"virtual",label:e("marker.virtual_option")},{value:"ha",label:e("marker.from_ha_option")}],onChange:e=>{if("virtual"===e){const e={...t,bindingMode:"virtual",binding:"virtual",bindingOpen:!1,controls:R("virtual",t.controls),autoIcon:this.host._autoIconForBinding("virtual"),...wa(t.radar,t.radarTouched,t.radarRemove)};return void(this.host._markerDialog=this._announceToggleDraft({...e,...this._valueBadgeForBinding(e,"virtual"),valueSource:null,valueSourceTouched:!0}))}this.host._markerDialog=this._announceToggleDraft({...t,bindingMode:"ha",binding:"virtual"===t.binding?"":t.binding,bindingOpen:"virtual"===t.binding||!t.binding})}})}${kt}`})} + ${xo({label:e("marker.binding_label"),help:i("marker.binding.help"),error:vt?s(vt.message):void 0,hint:o?s("marker.binding_virtual_hint"):void 0,control:p`${Mo({name:"bmode",value:t.bindingMode,ariaLabel:e("marker.binding_label"),options:[{value:"virtual",label:e("marker.virtual_option")},{value:"ha",label:e("marker.from_ha_option")}],onChange:e=>{if("virtual"===e){const e={...t,bindingMode:"virtual",binding:"virtual",bindingOpen:!1,controls:T("virtual",t.controls),autoIcon:this.host._autoIconForBinding("virtual"),...ya(t.radar,t.radarTouched,t.radarRemove)};return void(this.host._markerDialog=this._announceToggleDraft({...e,...this._valueBadgeForBinding(e,"virtual"),valueSource:null,valueSourceTouched:!0}))}this.host._markerDialog=this._announceToggleDraft({...t,bindingMode:"ha",binding:"virtual"===t.binding?"":t.binding,bindingOpen:"virtual"===t.binding||!t.binding})}})}${$t}`})} ${xo({label:e("marker.room_label"),htmlFor:"marker-room",hint:t.room?s("marker.room_hint_override"):o?void 0:s("marker.room_hint_auto"),control:p``})} ${this._renderRadarSection(t,l)} - ${this._renderVacSection(t)}`}),Mt="toggle"===h&&(at.length>1||nt)?p`
    ${xo({label:e("marker.toggle_entity_label"),htmlFor:"marker-toggle-entity",help:this._help("marker.toggle_entity.help"),control:p`{const s={...t,toggleEntity:e.target.value,toggleEntityTouched:!0};this.host._markerDialog=this._announceToggleDraft(s)}}> `)} - `,hint:nt?za(e("marker.toggle_entity_missing",{entity:t.toggleEntity,fallback:lt||e("marker.toggle_entity_none")}),"warning"):void 0})}
    `:d,Ct="run"===h?(()=>{const s=t.runFilter.trim().toLowerCase(),i=this._runCandidates().filter(t=>!s||t.label.toLowerCase().includes(s)||t.value.includes(s)),o=t.tapTarget?this._runCandidates().find(e=>e.value===t.tapTarget):null;return xo({label:e("marker.run_target_label"),htmlFor:"marker-run-target",control:p` + `,hint:nt?Ra(e("marker.toggle_entity_missing",{entity:t.toggleEntity,fallback:lt||e("marker.toggle_entity_none")}),"warning"):void 0})}`:d,Mt="run"===h?(()=>{const s=t.runFilter.trim().toLowerCase(),i=this._runCandidates().filter(t=>!s||t.label.toLowerCase().includes(s)||t.value.includes(s)),o=t.tapTarget?this._runCandidates().find(e=>e.value===t.tapTarget):null;return xo({label:e("marker.run_target_label"),htmlFor:"marker-run-target",control:p` ${t.tapTarget&&!o?yo({kind:"warning",role:"status",text:e("marker.run_target_gone",{id:t.tapTarget})}):d} ${e("marker.nothing_found")}

    `} - `}`})})():d,St=t.controlsFilter.trim()?this._controlCandidates(t):[],Pt=ko({id:"tap",title:e("marker.card_tap"),body:p` + `}`})})():d,Ct=t.controlsFilter.trim()?this._controlCandidates(t):[],St=ko({id:"tap",title:e("marker.card_tap"),body:p` ${xo({label:e("marker.tap_label"),htmlFor:"marker-tap-action",control:p``,hint:"toggle"===h?p`${z.map(t=>p`${t}`)} ${t.tapHintAnnouncement}`:void 0})} + ${xt} ${Mt} - ${Ct} ${"run"===h||"toggle"===h?Co({id:"marker-tap-confirm",icon:"mdi:check-decagram-outline",title:e("marker.tap_confirm"),caption:e("marker.tap_confirm_tip"),checked:t.tapConfirm,onChange:e=>this.host._markerDialog={...t,tapConfirm:e}}):d} ${xo({label:e("marker.controls_label"),htmlFor:"marker-controls-filter",help:this._help("marker.controls.help"),control:p` ${t.controls.length?p`
    @@ -144,19 +144,19 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc @click=${()=>this.host._markerDialog=this._announceToggleDraft({...t,controls:t.controls.filter(t=>t!==s)})}> `})}
    `:d} -
    +
    this.host._markerDialog={...t,controlsFilter:e.target.value}} /> ${t.controlsFilter.trim()?p`
    - ${St.map(e=>p``)} - ${St.length?d:p`

    ${e("marker.nothing_found")}

    `} + ${Ct.length?d:p`

    ${e("marker.nothing_found")}

    `}
    `:d} -
    `})}`}),Dt="auto"!==tt?p`
    ${xo({label:e("marker.glow_color"),control:So({hex:t.glowColor,disabled:Y,picker:p``})}`}),Pt="auto"!==tt?p`
    ${xo({label:e("marker.glow_color"),control:So({hex:t.glowColor,disabled:Y,picker:p` ${Po({id:"marker-glow-brightness",min:1,max:100,value:Math.round(t.glowBrightness),unit:"%",ariaLabel:e("marker.glow_brightness"),disabled:Y,slider:this._rangeInput(1,100,1,t.glowBrightness,e=>{this.host._markerDialog={...t,glowMode:tt,glowBrightness:e,glowBrightnessDrafted:!0,glowTouched:!0}},Y,e("marker.glow_brightness")),onInput:e=>{this.host._markerDialog={...t,glowMode:tt,glowBrightness:e,glowBrightnessDrafted:!0,glowTouched:!0}}})} -
    `:d}
    `:d,It=ko({id:"light",title:e("marker.card_light"),body:p` +
    `:d}`:d,Dt=ko({id:"light",title:e("marker.card_light"),body:p` ${this.host._bindingHasClimate(t.binding)?Co({id:"marker-use-climate-temp",icon:"mdi:thermometer",title:e("marker.use_climate_temp"),caption:e("marker.use_climate_temp_tip"),checked:t.useClimateTemp,onChange:e=>this.host._markerDialog={...t,useClimateTemp:e}}):d} ${xo({label:e("marker.light_role_label"),help:this._help("marker.light_role.help"),control:Mo({name:"marker-light-role",value:t.lightRole,ariaLabel:e("marker.light_role_label"),options:[{value:"auto",label:s("marker.light_role_seg_auto")},{value:"always",label:s("marker.light_role_seg_always")},{value:"never",label:s("marker.light_role_seg_never")}],onChange:t=>this._setMarkerLightRole(t)}),hint:"auto"===t.lightRole?e(V?"marker.light_role_auto_yes":"marker.light_role_auto_no"):void 0})} ${"always"===t.lightRole&&(st.length>1||ot)?p`
    ${xo({label:e("marker.light_entity_label"),htmlFor:"marker-light-entity",help:this._help("marker.light_entity.help"),control:p``,hint:ot?Ra(e("marker.light_entity_missing",{entity:t.lightEntity,fallback:it||"—"}),"warning"):void 0})}
    `:d}
    ${Do({title:e("marker.glow_color_label"),help:this._help("marker.glow_mode.help")})} ${Mo({name:"marker-glow-mode",value:tt,ariaLabel:e("marker.glow_color_label"),options:[{value:"auto",label:e("marker.glow_mode_auto"),disabled:X,describedBy:X?"marker-glow-disabled-hint":void 0},{value:"color",label:e("marker.glow_mode_color"),disabled:Y,describedBy:Y?"marker-glow-disabled-hint":void 0},{value:"fixed",label:e("marker.glow_mode_fixed"),disabled:Y,describedBy:Y?"marker-glow-disabled-hint":void 0}],onChange:t=>this._setMarkerGlowMode(t)})} - ${Dt} - ${xo({label:e("marker.glow_radius_label"),htmlFor:"marker-glow-radius",help:this._help("marker.glow_radius.help"),error:wt?s(wt.message):void 0,hint:t.glowRadius.trim()?void 0:s("marker.glow_radius_empty_hint",{v:`${this.host._glowRadiusPlaceholder} ${dt}`}),control:Io({id:"marker-glow-radius",unit:dt,min:.5,step:.5,value:t.glowRadius,placeholder:this.host._glowRadiusPlaceholder,ariaLabel:e("marker.glow_radius_label"),disabled:Y,invalid:!!wt,describedBy:Y||Q?"marker-glow-disabled-hint":void 0,onInput:e=>this.host._markerDialog={...t,glowRadius:e}})})} + ${Pt} + ${xo({label:e("marker.glow_radius_label"),htmlFor:"marker-glow-radius",help:this._help("marker.glow_radius.help"),hint:t.glowRadius.trim()?void 0:s("marker.glow_radius_empty_hint",{v:`${this.host._glowRadiusPlaceholder} ${dt}`}),control:Io({id:"marker-glow-radius",unit:dt,min:.5,step:.5,value:t.glowRadius,placeholder:this.host._glowRadiusPlaceholder,ariaLabel:e("marker.glow_radius_label"),disabled:Y,describedBy:Y||Q?"marker-glow-disabled-hint":void 0,onInput:e=>this.host._markerDialog={...t,glowRadius:e}})})} ${Y||Q?yo({id:"marker-glow-disabled-hint",kind:"info",role:"note",icon:"mdi:information-outline",text:et}):d} -
    `}),Lt=customElements.get("ha-icon-picker")?p``}),It=customElements.get("ha-icon-picker")?p`{const s=e.detail.value||"";(t.icon||s!==t.autoIcon)&&(this.host._markerDialog={...t,icon:s})}}>`:p`this.host._markerDialog={...t,icon:e.target.value}} />`,Tt=S(t.display)||!N.length&&!t.valueBadgeSource,Rt=ko({id:"appearance",title:e("marker.card_appearance"),body:p` + @input=${e=>this.host._markerDialog={...t,icon:e.target.value}} />`,Lt=C(t.display)||!N.length&&!t.valueBadgeSource,Tt=ko({id:"appearance",title:e("marker.card_appearance"),body:p` ${xo({label:e("marker.icon_label"),htmlFor:"marker-icon",help:i("marker.icon.help"),control:p`
    - ${Lt} + ${It} ${t.icon?p``:d}
    `,hint:!t.icon&&t.autoIcon?p` ${e("marker.icon_auto",{icon:t.autoIcon})} ${wo(e("marker.icon_pin_auto"),()=>this.host._markerDialog={...t,icon:t.autoIcon})}`:t.icon?s("marker.icon_custom_hint"):void 0})} ${xo({label:e("marker.display_label"),htmlFor:"marker-display",help:i("marker.display.help"),control:p``,hint:e(Ta[t.display])})} + `,hint:e(La[t.display])})} ${"icon_ripple"===t.display?p`${xo({label:e("marker.activity_color"),control:p`
    ${So({hex:t.rippleColor||"#3ea6ff",picker:p`this.host._markerDialog={...t,rippleSize:e},!1,e("marker.ripple_size")),onInput:e=>this.host._markerDialog={...t,rippleSize:e}})}

    ${e("marker.activity_alarm_note")}

    `:d} - ${I(t.display)?p`
    ${xo({label:e("marker.value_source"),htmlFor:"marker-value-source",help:this._help("marker.value_source.help"),control:p`this.host._markerDialog={...t,valueSource:I(e.target.value),valueSourceTouched:!0}}> @@ -225,15 +225,15 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc title=${t.technical}> ${this._valueBadgeCandidateLabel(t)} · ${t.value} `)} - `,hint:o?za(e("marker.preview.reason.value_virtual"),"info"):q?za(e("marker.value_source_missing_hint"),"warning"):U?p`${U.technical}`:void 0})}
    `:d} - ${S(t.display)&&this.host._bindingHasAlarm(t.binding)?yo({kind:"warning",role:"note",icon:"mdi:alert-outline",text:e("marker.static_alarm_warning")}):d} + `,hint:o?Ra(e("marker.preview.reason.value_virtual"),"info"):q?Ra(e("marker.value_source_missing_hint"),"warning"):U?p`${U.technical}`:void 0})}`:d} + ${C(t.display)&&this.host._bindingHasAlarm(t.binding)?yo({kind:"warning",role:"note",icon:"mdi:alert-outline",text:e("marker.static_alarm_warning")}):d}
    ${Do({title:e("marker.value_badge_title"),help:this._help("marker.value_badge.help")})} - ${Co({id:"marker-value-badge",compact:!0,icon:S(t.display)?"mdi:eye-off-outline":"mdi:card-text-outline",title:e("marker.value_badge_enabled"),checked:E,disabled:Tt,onChange:e=>{const s=O||A;this.host._markerDialog={...t,valueBadgeEnabled:e&&!!s,valueBadgeSource:s,valueBadgeTouched:!0}}})} - ${S(t.display)?yo({kind:"info",role:"note",icon:"mdi:information-outline",text:e("marker.value_badge_static")}):N.length||t.valueBadgeSource?d:yo({kind:"info",role:"note",icon:"mdi:information-outline",text:e("marker.value_badge_empty")})} + ${Co({id:"marker-value-badge",compact:!0,icon:C(t.display)?"mdi:eye-off-outline":"mdi:card-text-outline",title:e("marker.value_badge_enabled"),checked:E,disabled:Lt,onChange:e=>{const s=O||A;this.host._markerDialog={...t,valueBadgeEnabled:e&&!!s,valueBadgeSource:s,valueBadgeTouched:!0}}})} + ${C(t.display)?yo({kind:"info",role:"note",icon:"mdi:information-outline",text:e("marker.value_badge_static")}):N.length||t.valueBadgeSource?d:yo({kind:"info",role:"note",icon:"mdi:information-outline",text:e("marker.value_badge_empty")})} ${E?p` ${xo({label:e("marker.value_badge_source"),htmlFor:"marker-value-badge-source",help:this._help("marker.value_badge_source.help"),control:p``,hint:W?za(e("marker.value_badge_missing_hint"),"warning"):I(t.display)&&H===K?za(e("marker.value_badge_duplicate"),"info"):j?p`${j.technical}`:void 0})} - ${xo({label:e("marker.value_badge_position"),help:this._help("marker.value_badge_position.help"),control:Mo({name:"marker-value-badge-position",value:B,ariaLabel:e("marker.value_badge_position"),options:Ra.map(t=>({value:t,label:e(`marker.value_badge_${t}`)})),onChange:e=>this.host._markerDialog={...t,valueBadgeEnabled:E,valueBadgeSource:O,valueBadgePosition:e,valueBadgeTouched:!0}})})} + `,hint:W?Ra(e("marker.value_badge_missing_hint"),"warning"):D(t.display)&&H===K?Ra(e("marker.value_badge_duplicate"),"info"):j?p`${j.technical}`:void 0})} + ${xo({label:e("marker.value_badge_position"),help:this._help("marker.value_badge_position.help"),control:Mo({name:"marker-value-badge-position",value:B,ariaLabel:e("marker.value_badge_position"),options:Ta.map(t=>({value:t,label:e(`marker.value_badge_${t}`)})),onChange:e=>this.host._markerDialog={...t,valueBadgeEnabled:E,valueBadgeSource:O,valueBadgePosition:e,valueBadgeTouched:!0}})})} `:d}
    ${F?p`this.host._markerDialog={...t,angle:e},!1,e("marker.angle_label")),onInput:e=>this.host._markerDialog={...t,angle:e}})} ${Ro("0°","355°")} - `])}`}),zt=ko({id:"details",title:e("marker.card_details"),body:p` + `])}`}),Rt=ko({id:"details",title:e("marker.card_details"),body:p` ${To([xo({label:e("marker.model_label"),htmlFor:"marker-model",control:p`this.host._markerDialog={...t,model:e.target.value}} />`}),xo({label:e("marker.link_label"),htmlFor:"marker-link",control:p` ${t.pdfs.map(t=>p` - ${t.name} + ${t.name} `)} `:d} @@ -288,38 +288,38 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc this._pickMarkerFiles(t)} /> `})} - ${this._renderRadarSection(t,l,"additional")}`}),Ft=t.hideFromPlan||"ha_disabled"===n?.kind;return p` + icon="mdi:shape-plus" wide @hp-close=${bt}>
    - ${xt}${Pt}${It}${Rt}${zt} + ${kt}${St}${Dt}${Tt}${Rt}
    -
    `}const Na=1e-6*F,Aa=6*F;function Ea(t){return Number.isFinite(t)?Math.round(t/F)*F:t}const Oa=(t,e,s,i)=>Math.hypot(s-t,i-e),Ba=(t,e,s,i,o,a,n,r)=>Math.hypot(Math.max(Math.abs(o-t),Math.abs(o+n-(t+s))),Math.max(Math.abs(a-e),Math.abs(a+r-(e+i)))),Ha=(t,e,s,i,o,a,n)=>{const r=Math.max(Number(i)||0,0)/2,l=Math.PI/180,h=Math.cos(s*l)*r,c=Math.sin(s*l)*r,d=Math.cos(n*l)*r,p=Math.sin(n*l)*r,u=Math.max(Oa(t+h,e+c,o+d,a+p),Oa(t-h,e-c,o-d,a-p)),_=Math.max(Oa(t+h,e+c,o-d,a-p),Oa(t-h,e-c,o+d,a+p));return Math.min(u,_)},Wa=t=>{const e=Number(t?.cell_cm);return e>0?e:5};function ja(t,e){const s=JSON.parse(JSON.stringify(t||[])),i=JSON.parse(JSON.stringify(e||{}));let o=0,a=0,n=0,r=0,l="",h=0,c=0;const d=(t,e)=>{Number.isFinite(t)&&Number.isFinite(e)&&t!==e&&Math.abs(e-t)<=Na&&c++},p=(t,e)=>{d(t[0],e[0]),d(t[1],e[1])},u={};let _=5;for(const t of s){const e=Wa(t);null!=t?.id&&(u[String(t.id)]=e),e>_&&(_=e)}const m=(t,e,s,i=!1)=>{if(!(t>Na||i))return;o++,t>n&&(n=t);const a=t*N*e;a>r&&(r=a,l=s)};for(const t of s){const e=Wa(t),s=null!=t?.id?String(t.id):"";for(const i of t.rooms||[]){a++;let t=0;if(i.poly?.length)i.poly=i.poly.map(e=>{const s=[Ea(e[0]),Ea(e[1])];return t=Math.max(t,Oa(e[0],e[1],s[0],s[1])),p(e,s),s});else if(null!=i.x&&null!=i.y){const e=i.x,s=i.y,o=i.w||0,a=i.h||0,n=Ea(e+o),r=Ea(s+a),l=Ea(e),h=Ea(s),c=Math.max(F,n-l),p=Math.max(F,r-h);t=Ba(e,s,o,a,l,h,c,p),i.x=l,i.y=h,i.w=c,i.h=p,d(e,l),d(s,h),d(e+o,l+c),d(s+a,h+p)}m(t,e,s)}for(const i of t.partitions||[]){a++;const o=[i.a[0],i.a[1]],n=[i.b[0],i.b[1]],r=[Ea(o[0]),Ea(o[1])],l=[Ea(n[0]),Ea(n[1])];let h=Math.max(Oa(o[0],o[1],r[0],r[1]),Oa(n[0],n[1],l[0],l[1]));const c=Oa(r[0],r[1],l[0],l[1]),d=(t.openings||[]).filter(t=>"partition"===t.host?.kind&&t.host.id===i.id).every(t=>{const e=Number(t.length),s=Number(t.host.t),i=s*c;return Number.isFinite(e)&&e>0&&Number.isFinite(s)&&s>=0&&s<=1&&i-e/2>=-Na&&i+e/2<=c+Na});c>Na&&d?(i.a=r,i.b=l,p(o,r),p(n,l)):h=0,m(h,e,s)}for(const i of t.wall_columns||[]){a++;const t=[i.center[0],i.center[1]],o=[Ea(t[0]),Ea(t[1])],n=Oa(t[0],t[1],o[0],o[1]);i.center=o,p(t,o),m(n,e,s)}for(const i of t.decor||[]){if("furniture"===i.kind||"image"===i.kind)continue;a++;let t=0;if("line"===i.kind){const e=[i.x1,i.y1],s=[i.x2,i.y2],o=[Ea(e[0]),Ea(e[1])],a=[Ea(s[0]),Ea(s[1])];t=Math.max(Oa(e[0],e[1],o[0],o[1]),Oa(s[0],s[1],a[0],a[1])),i.x1=o[0],i.y1=o[1],i.x2=a[0],i.y2=a[1],p(e,o),p(s,a)}else{const e=i.x,s=i.y,o=i.w,a=i.h,n=Ea(e),r=Ea(s);if(null!=i.w&&null!=i.h){const l=Ea(e+o),h=Ea(s+a),c=Math.max(F,l-n),p=Math.max(F,h-r);t=Ba(e,s,o,a,n,r,c,p),i.w=c,i.h=p,d(e+o,n+c),d(s+a,r+p)}else t=Oa(e,s,n,r);i.x=n,i.y=r,d(e,n),d(s,r)}m(t,e,s)}for(const i of t.openings||[]){if(a++,"partition"===i.host?.kind){const o=(t.partitions||[]).find(t=>t.id===i.host.id),a=Number(i.host.t);if(!o||!Number.isFinite(a)||a<0||a>1)continue;const n=o.b[0]-o.a[0],r=o.b[1]-o.a[1];if(Math.hypot(n,r)<=Na)continue;const l=o.a[0]+n*a,c=o.a[1]+r*a;let d=180*Math.atan2(r,n)/Math.PI;d>=90?d-=180:d<-90&&(d+=180);const p=Number(i.angle),u=!(Number.isFinite(p)&&p===d),_=Ha(i.x,i.y,Number.isFinite(p)?p:d,Number(i.length)||0,l,c,d);i.x=l,i.y=c,i.angle=d,u&&h++,m(_,e,s,u);continue}const o=z([i.x,i.y],t.rooms||[],Aa,{step:F,length:Number(i.length)||0});if(!o)continue;const n=Number(i.angle),r=!(Number.isFinite(n)&&n===o.angle),l=Ha(i.x,i.y,Number.isFinite(n)?n:o.angle,Number(i.length)||0,o.x,o.y,o.angle);i.x=o.x,i.y=o.y,i.angle=o.angle,r&&h++,m(l,e,s,r)}}for(const[t,e]of Object.entries(i)){if(!e||"object"!=typeof e)continue;const s=e;if("number"!=typeof s.x||"number"!=typeof s.y)continue;a++;const o=Ea(s.x),n=Ea(s.y),r=Oa(s.x,s.y,o,n);i[t]={...s,x:o,y:n},d(s.x,o),d(s.y,n);const l="string"==typeof s.s?s.s:"";m(r,u[l]??_,l)}return{spaces:s,layout:i,report:{moved:o,coordsCanonicalized:c,total:a,maxShift:n,maxShiftCm:r,maxSpace:l,rotated:h},changed:o>0||c>0}}function Ga(t,e){const s=e.base+t*e.span;return Math.min(1,Math.max(0,s))}const qa=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),Ua=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1]);function Ka(t,e,s){const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;if(a<=0)return Ua(t,e);let n=((t[0]-e[0])*i+(t[1]-e[1])*o)/a;return n=Math.max(0,Math.min(1,n)),Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))}function Va(t,e,s,i,o){for(const i of e)if(i&&!s.has(i.id)&&qa(i.a)&&qa(i.b)&&(Ua(t,i.a)<=o||Ua(t,i.b)<=o))return!0;for(const e of i?.roomPolygons||[])for(let s=0;s0&&r>0))return null;if(Math.abs(o[0]/n*(a[1]/r)-o[1]/n*(a[0]/r))>s)return null;for(const[s,o]of[[t.a,e.a],[t.a,e.b],[t.b,e.a],[t.b,e.b]])if(Ua(s,o)<=i)return[(s[0]+o[0])/2,(s[1]+o[1])/2];return null}function Za(t,e){const s=.05*(Number(e.pitch)>0?Number(e.pitch):1),i=new Map;let o=(t||[]).filter(t=>!!t&&"string"==typeof t.id&&qa(t.a)&&qa(t.b));if(o.length<2)return{partitions:[...t||[]],merged:0,openingMoves:[]};const a=e.seedIds&&e.seedIds.length?new Set(e.seedIds):null;let n=0;for(let t=0;tUa(e,t.at)>s);let c=h[0]??r.a,d=h[h.length-1]??l.b;if(h.length<2&&(c=r.a,d=l.b),d[0]0?(d[0]-c[0])/u:0,m=u>0?(d[1]-c[1])/u:0,g=t=>u>0?((t[0]-c[0])*_+(t[1]-c[1])*m)/u:0;for(const t of[r,l]){const e=g(t.a),s=g(t.b)-e;for(const[o,a]of i)a.toId===t.id&&i.set(o,{fromId:a.fromId,toId:p.id,base:e+a.base*s,span:a.span*s});i.set(t.id,{fromId:t.id,toId:p.id,base:e,span:s})}a&&a.add(p.id),o=o.filter((e,s)=>s!==t.i&&s!==t.j),o.splice(t.i,0,p),n++}return{partitions:o,merged:n,openingMoves:[...i.values()]}}function Ya(t,e,s,i){if(!t?.length||!s.length)return 0;const o=new Map(s.map(t=>[t.fromId,t]));let a=0;for(const s of t){const t=s?.host;if(!t||"partition"!==t.kind)continue;const n=o.get(t.id);if(!n)continue;s.host={...t,id:n.toId,t:Ga(t.t,n)},a++;const r=E(s,e,i.coordScale,i.cellCm,i.gridPitch).resolved;r&&Object.assign(s,O(s,r,i.coordScale))}return a}function Xa(t){return{roomPolygons:(t?.rooms||[]).map(t=>A(t)).filter(t=>!!t),columns:t?.wall_columns||[]}}const Qa=t=>!!t&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),tn=(t,e)=>t[0]-e[0]||t[1]-e[1],en=(t,e,s,i)=>[t[0]+e*i,t[1]+s*i],sn=(t,e,s,i)=>(t[0]-e[0])*s+(t[1]-e[1])*i,on=(t,e,s,i,o)=>{const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(!(r>o))return null;const l=a/r,h=n/r,c=e=>Math.abs((e[0]-t[0])*h-(e[1]-t[1])*l);if(c(s)>o||c(i)>o)return null;const d=sn(s,t,l,h),p=sn(i,t,l,h),u=Math.max(0,Math.min(d,p)),_=Math.min(r,Math.max(d,p));return _-u>o?{lo:u,hi:_}:null},an=(t,e,s)=>Math.min(t.hi,e.hi)-Math.max(t.lo,e.lo)>s,nn=t=>{const e=new Set(["id","a","b","cm"]);return Object.keys(t||{}).every(t=>e.has(t))},rn=(t,e,s,i)=>{const o=t.b[0]-t.a[0],a=t.b[1]-t.a[1],n=Math.hypot(o,a);if(!(n>i))return!0;const r=o/n,l=a/n,h=J(t.cm,s.cellCm,s.gridPitch)/2;return e.some(e=>{const o=e?.center;if(!Qa(o))return!0;const a=sn(o,t.a,r,l),c=Math.abs((o[0]-t.a[0])*l-(o[1]-t.a[1])*r),d=J(Number(e.cm),s.cellCm,s.gridPitch)*("square"===e.shape?Math.SQRT1_2:.5);return!(Number.isFinite(d)&&d>0)||a>=-d-i&&a<=n+d+i&&c<=h+d+i})},ln=(t,e,s)=>{if(t.host){const i=E(t,e,s.coordScale,s.cellCm,s.gridPitch).resolved;return i?{center:i.center,angle:i.angle,length:i.length}:null}const i=Number(t.x)*s.coordScale,o=Number(t.y)*s.coordScale,a=Number(t.angle),n=Number(t.length)*s.coordScale;return[i,o,a,n].every(Number.isFinite)&&n>0?{center:[i,o],angle:a,length:n}:null},hn=(t,e,s)=>{const i=t.angle*Math.PI/180,o=Math.cos(i),a=Math.sin(i),n=e.angle*Math.PI/180,r=Math.cos(n),l=Math.sin(n);if(Math.abs(o*l-a*r)>1e-6)return!1;const h=e.center[0]-t.center[0],c=e.center[1]-t.center[1];if(Math.abs(h*a-c*o)>s)return!1;const d=h*o+c*a;return Math.max(-t.length/2,d-e.length/2)({...t,a:[t.a[0]*e,t.a[1]*e],b:[t.b[0]*e,t.b[1]*e]}),dn=(t,e,s,i)=>{const o=`~r-${(t=>{let e=2166136261;for(let s=0;s>>0;return e.toString(36)})(`${t}|${e[0].toFixed(9)},${e[1].toFixed(9)}|${s[0].toFixed(9)},${s[1].toFixed(9)}`)}`,a=`${t.slice(0,Math.max(1,64-o.length))}${o}`;let n=a;for(let t=2;i.has(n);t++){const e=`-${t}`;n=`${a.slice(0,64-e.length)}${e}`}return i.add(n),n},pn=(t,e)=>{const s=[];for(const i of t){const t=s[s.length-1];!(t&&Math.abs(t.hi-i.lo)<=e&&t.safe===i.safe)||i.safe&&t.signature!==i.signature?s.push({lo:i.lo,hi:i.hi,a:i.a,b:i.b,safe:i.safe,signature:i.signature,roomIds:i.roomIds,finalCm:i.finalCm}):(t.hi=i.hi,t.b=i.b)}return s};function un(t,e,s,i,o){const a=s||[],n=Array.isArray(t?.partitions)?t.partitions:[],r=Array.isArray(t?.openings)?t.openings:[],l={walls:a,partitions:n,openings:r,partitionsReconciled:0,openingsRehosted:0};if(!n.length)return l;const h=Math.max(2e-4*o.gridPitch,1e-9);let c=a,d=n,p=r,u=0,_=0;const m=o.partitionIds?new Set(o.partitionIds):null,g=new Map(e.partitions.map(t=>[t.id,t]));for(const t of[...n].sort((t,e)=>t.id.localeCompare(e.id))){if(m&&!m.has(t.id))continue;if(!d.some(e=>e.id===t.id))continue;if(!nn(t))continue;const s=g.get(t.id);if(!(s&&Qa(s.a)&&Qa(s.b)&&Number.isFinite(s.cm)&&(o.allowCoincidentPartitions?!(s.cm<0):s.cm>0)))continue;const[a,n]=tn(s.a,s.b)<=0?[[s.a[0],s.a[1]],[s.b[0],s.b[1]]]:[[s.b[0],s.b[1]],[s.a[0],s.a[1]]],r=n[0]-a[0],l=n[1]-a[1],f=Math.hypot(r,l);if(!(f>h))continue;const b=r/f,v=l/f,y=B(e.rooms,c,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),w=y.flatMap(t=>{if(t.open||"outer"!==t.kind&&"shared"!==t.kind)return[];const e=on(a,n,t.a,t.b,h);return e?[{interval:t,range:e}]:[]});if(!w.length)continue;const $=p.filter(t=>"partition"===t.host?.kind&&t.host.id===s.id).map(t=>({opening:t,resolved:E(t,e.partitions,o.coordScale,o.cellCm,o.gridPitch).resolved}));if($.some(t=>!t.resolved))continue;const k=[0,f];for(const{range:t}of w)k.push(t.lo,t.hi);const x=k.slice(),M=new Map;for(const{opening:t,resolved:e}of $){const s=sn(e.center,a,b,v),i={lo:s-e.length/2,hi:s+e.length/2};M.set(t.id,i),x.push(Math.max(0,i.lo),Math.min(f,i.hi))}const C=[...new Set(x.filter(t=>Number.isFinite(t)&&t>=-h&&t<=f+h).map(t=>Math.max(0,Math.min(f,t)).toFixed(9)))].map(Number).sort((t,e)=>t-e),S=d.map(t=>cn(t,o.coordScale)).filter(t=>t.id!==s.id),P=[];for(let t=0;t+1h))continue;const r=en(a,b,v,i),l=en(a,b,v,n),c=w.filter(({range:t})=>t.lo<=i+h&&t.hi>=n-h).map(({interval:t})=>t),d=new Map;for(const t of c)d.set(t.roomId,t);const p=[...d.values()],u=new Set(p.map(t=>t.kind)),_=new Set(p.map(t=>o.allowCoincidentPartitions||t.cm>0?t.cm:H)),m=p[0]?.kind,g=[...d.keys()].sort(),f=1===u.size&&1===_.size&&("outer"===m&&1===g.length||"shared"===m&&2===g.length),y={id:s.id,a:r,b:l,cm:s.cm},$=S.some(t=>!!on(r,l,t.a,t.b,h)),k=f&&(o.allowCoincidentPartitions||!$)&&!rn(y,e.wall_columns,o,h),x=f?o.allowCoincidentPartitions||p[0].cm>0?p[0].cm:H:0,M=f?Math.max(x,s.cm):s.cm;P.push({lo:i,hi:n,a:r,b:l,safe:k,signature:k?`${m}|${g.join(",")}|${M}`:"",roomIds:g,roomCm:x,finalCm:M})}if(!P.some(t=>t.safe))continue;const D=new Map;for(const{opening:t,resolved:e}of $){const i=M.get(t.id),a=k.some(t=>t>i.lo+h&&tan(t,i,h)),r=new Set(n.filter(t=>t.safe).map(t=>t.signature));if(!a&&n.length>0&&n.every(t=>t.safe)&&1===r.size&&W(e,y,h)){D.set(t.id,{resolved:e,signature:[...r][0]});continue}const l=j(s,o.cellCm,o.gridPitch),c={lo:i.lo-l,hi:i.hi+l};for(const t of P)an(t,c,h)&&(t.safe=!1,t.signature="")}let I=!0;for(;I;){I=!1;for(const[t,e]of[...D.entries()]){const i=M.get(t),a=P.filter(t=>an(t,i,h));if(a.length>0&&a.every(t=>t.safe)&&a.every(t=>t.signature===e.signature))continue;D.delete(t);const n=j(s,o.cellCm,o.gridPitch),r={lo:i.lo-n,hi:i.hi+n};for(const t of P)an(t,r,h)&&(t.safe=!1,t.signature="");I=!0}}const L=pn(P,h),T=L.filter(t=>t.safe),R=L.filter(t=>!t.safe);if(!T.length)continue;if(d.length-1+R.length>2e3)continue;let z=c;for(const t of T){const[e,i]=tn(s.a,s.b)<=0?[t.a,t.b]:[t.b,t.a];z=G(z,e,i,t.finalCm,o.pitch,o.coordScale)}if(z=q(e.rooms,z,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),z.length>500)continue;const F=new Set(d.map(t=>t.id));F.delete(s.id);const N=R.map((t,e)=>{const i=[t.a[0]/o.coordScale,t.a[1]/o.coordScale],a=[t.b[0]/o.coordScale,t.b[1]/o.coordScale],n=0===e?s.id:dn(s.id,i,a,F);return F.add(n),{id:n,a:i,b:a,cm:s.cm}}),A=d.findIndex(t=>t.id===s.id),J=d.slice();J.splice(A,1,...N);const Z=J.map(t=>cn(t,o.coordScale)),Y=new Map;let X=!0;for(const{opening:t,resolved:e}of $){const s=D.get(t.id);if(s){const e=O(t,s.resolved,o.coordScale),{host:i,...a}=e;Y.set(t.id,a);continue}const i=M.get(t.id),a=N[R.findIndex(t=>t.lo<=i.lo+h&&t.hi>=i.hi-h)],n=a&&Z.find(t=>t.id===a.id);if(!a||!n){X=!1;break}const r=n.b[0]-n.a[0],l=n.b[1]-n.a[1],c=Math.hypot(r,l),d=sn(e.center,n.a,r/c,l/c),p={...O(t,e,o.coordScale),host:{kind:"partition",id:a.id,t:d/c}};if(!U(p,Z,o.coordScale,o.cellCm,o.gridPitch).resolved){X=!1;break}Y.set(t.id,p)}if(!X)continue;const Q=p.map(t=>Y.get(t.id)||t),tt=[...D.keys()].map(t=>Y.get(t)),et=tt.map(t=>ln(t,Z,o));if(et.some(t=>!t))continue;let st=!1;for(let t=0;tt.id));for(const t of Q){if(it.has(t.id))continue;const e=ln(t,Z,o);e&&et.some(t=>hn(t,e,h))&&(st=!0)}if(st)continue;const ot=K(e.rooms,z,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale);[...D.entries()].every(([t,e])=>{const s=Y.get(t),i=V(ot,{x:s.x*o.coordScale,y:s.y*o.coordScale,angle:s.angle,length:s.length*o.coordScale},!0),a=[i.negative,i.positive].filter(t=>!!t?.full),n=e.signature.split("|")[1].split(","),r=new Set(a.map(t=>t.roomId));return a.length===n.length&&r.size===n.length&&n.every(t=>r.has(t))})&&(c=z,d=J,p=Q,u+=T.length,_+=D.size)}return{walls:c,partitions:d,openings:p,partitionsReconciled:u,openingsRehosted:_}}const _n=t=>JSON.parse(JSON.stringify(t)),mn=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),gn=(t,e)=>e.length>0&&e.length<=35&&("space"===t?/^[a-z0-9_-]+$/.test(e):/^[A-Za-z0-9_-]+$/.test(e));function fn(t,e){let s=String(e??"");const i=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),o=new RegExp(`^${i}_(.+)_([0-9a-f]{8})$`);let a=0;for(;a<16;a++){const t=o.exec(s);if(!t)return{root:s,layers:a,bounded:!1};s=t[1]}return{root:s,layers:a,bounded:o.test(s)}}const bn=(t,e,s)=>{const i=t.get(e)||[];i.push(s),t.set(e,i)};const vn=1e-9;class yn extends Error{constructor(t,e=""){super(e?`${t}: ${e}`:t),this.reason=t,this.name="WallSegmentModelError"}}const wn=t=>JSON.parse(JSON.stringify(t)),$n=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(Number(t[0]))&&Number.isFinite(Number(t[1])),kn=t=>[Number(t[0]),Number(t[1])],xn=t=>`${Number(t[0]).toFixed(12)},${Number(t[1]).toFixed(12)}`,Mn=(t,e)=>{const s=xn(t),i=xn(e);return sxn(t)<=xn(e)?[kn(t),kn(e)]:[kn(e),kn(t)],Sn=(t,e)=>Math.hypot(e[0]-t[0],e[1]-t[1]),Pn=(t,e=[])=>{const s=new Set,i=t=>{const e=Number(t);if(!Number.isFinite(e))return;const i=e/F;Math.abs(i-Math.round(i))>=et&&s.add(e.toFixed(12))};for(const e of Array.isArray(t?.rooms)?t.rooms:[])for(const t of A(e)||[])i(t[0]),i(t[1]);for(const e of[t?.wall_segments,t?.walls])for(const t of Array.isArray(e)?e:[])i(t?.a?.[0]),i(t?.a?.[1]),i(t?.b?.[0]),i(t?.b?.[1]);for(const t of e)i(t?.[0]),i(t?.[1]);return s.size},Dn=(t,e,s)=>{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;return a>1e-18?((t[0]-e[0])*i+(t[1]-e[1])*o)/a:0},In=(t,e,s)=>{const i=Math.max(0,Math.min(1,Dn(t,e,s)));return Math.hypot(t[0]-(e[0]+(s[0]-e[0])*i),t[1]-(e[1]+(s[1]-e[1])*i))},Ln=(t,e,s,i,o=1e-9)=>{const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(r<=o)return 0;const l=e=>Math.abs((e[0]-t[0])*n-(e[1]-t[1])*a)/r;if(l(s)>o||l(i)>o)return 0;const h=Dn(s,t,e),c=Dn(i,t,e);return Math.max(0,Math.min(1,Math.max(h,c))-Math.max(0,Math.min(h,c)))*r},Tn=t=>{const e=(new TextEncoder).encode(t),s=8*e.length,i=64*Math.ceil((e.length+9)/64),o=new Uint8Array(i);o.set(e),o[e.length]=128;const a=new DataView(o.buffer);a.setUint32(i-8,Math.floor(s/4294967296),!1),a.setUint32(i-4,s>>>0,!1);const n=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),r=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),l=new Uint32Array(64),h=(t,e)=>t>>>e|t<<32-e;for(let t=0;t>>3,o=h(s,17)^h(s,19)^s>>>10;l[t]=l[t-16]+i+l[t-7]+o>>>0}let[e,s,i,o,c,d,p,u]=r;for(let t=0;t<64;t++){const a=u+(h(c,6)^h(c,11)^h(c,25))+(c&d^~c&p)+n[t]+l[t]>>>0,r=e&s^e&i^s&i;u=p,p=d,d=c,c=o+a>>>0,o=i,i=s,s=e,e=a+((h(e,2)^h(e,13)^h(e,22))+r>>>0)>>>0}r[0]=r[0]+e>>>0,r[1]=r[1]+s>>>0,r[2]=r[2]+i>>>0,r[3]=r[3]+o>>>0,r[4]=r[4]+c>>>0,r[5]=r[5]+d>>>0,r[6]=r[6]+p>>>0,r[7]=r[7]+u>>>0}const c=new Uint8Array(32),d=new DataView(c.buffer);for(let t=0;t{const e="abcdefghijklmnopqrstuvwxyz234567";let s=0,i=0,o="";for(const a of t)for(i=i<<8|a,s+=8;s>=5;)o+=e[i>>>s-5&31],s-=5;return s&&(o+=e[i<<5-s&31]),o},zn=(t,e,s,i,o="")=>{const[a,n]=Cn(e,s),r=`${t}|${xn(a)}|${xn(n)}|${[...i].sort().join(",")}${o}`;return`wall-${Rn(Tn(r)).slice(0,20)}`};let Fn=0;const Nn=t=>{for(let e=0;e<1e3;e++){const e=globalThis.crypto?.randomUUID?.(),s=`wall-${e||Rn(Tn(`${Date.now()}|${Fn++}|${Math.random()}`)).slice(0,26)}`;if(!t.has(s))return s}throw new yn("duplicate-id","id factory exhausted")},An=t=>{const e=new Map;for(const s of Array.isArray(t?.wall_segments)?t.wall_segments:[])if(s&&"string"==typeof s.id&&$n(s.a)&&$n(s.b)){if(e.has(s.id))throw new yn("duplicate-id",s.id);e.set(s.id,s)}return e},En=(t,e,s)=>{const i=(s,i)=>{const o=t[0]-s[0],a=t[1]-s[1];return Math.abs(e[0]-i[0]-o)<=vn&&Math.abs(e[1]-i[1]-a)<=vn?[o,a]:null};return i(s.a,s.b)||i(s.b,s.a)},On=(t,e)=>{const s=Array.isArray(t.rooms)?t.rooms:[],i=X(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]),o=i.length?i:Q(s,null,1,.04*F,!0),a=[];for(const t of s){const s=A(t),i=Array.isArray(t?.wall_ids)?t.wall_ids:[];if(s&&i.length===s.length)for(let t=0;t"partition"!==t.host?.kind&&[Number(t.x),Number(t.y)].every(Number.isFinite)&&Number.isFinite(Number(t.angle))&&Number(t.length)>0&&o.some(e=>In([Number(t.x),Number(t.y)],[e[0],e[1]],[e[2],e[3]])<=.04*F)):[],l=r.map(t=>{const e=Number(t.angle)*Math.PI/180,s=[Math.cos(e),Math.sin(e)],i=Number(t.length)/2,o=[Number(t.x),Number(t.y)];return{a:[o[0]-s[0]*i,o[1]-s[1]*i],b:[o[0]+s[0]*i,o[1]+s[1]*i]}}),h=(t,e)=>r.some(s=>{const i=[Number(s.x),Number(s.y)];if(!st(t,e,Number(s.angle)))return!1;if(In(i,t,e)>.02*F)return!1;const o=Sn(t,e),a=Dn(i,t,e)*o,n=Number(s.length)/2;return a+n>=-1e-9&&a-n<=o+vn}),c=new Map,d=[];for(const i of s){const r=String(i?.id||""),p=A(i);if(!r||!p||p.length<3)throw new yn("invalid-room",r);const u=tt(s,r,n,F,1,[...t.walls||[],...l]);if(!u||u.poly.length<3)throw new yn("invalid-room",r);const _=Array.isArray(i.wall_ids)?i.wall_ids:[],m=_.length===p.length;let g=null,f=m;if(f)for(let t=0;tvn||Math.abs(i[1]-g[1])>vn)){f=!1;break}g=i}const b=[];for(let t=0;t2)throw new yn("third-owner",n);const d=m?_[u.parent[t]]:void 0;if("string"==typeof d&&d){const o=e.get(d);f||!o||Ln(s,i,o.a,o.b)>vn?l.preferredIds.add(d):l.positionalIds.add(d),l.preferredCarriers.set(d,{a:kn(p[u.parent[t]]),b:kn(p[(u.parent[t]+1)%p.length])})}const g=u.parent[t];l.parentKeys.add(Y(p[g],p[(g+1)%p.length],F));const v=[(s[0]+i[0])/2,(s[1]+i[1])/2],y=t=>t.some(t=>In(v,[t[0],t[1]],[t[2],t[3]])<=.04*F);l.zeroWall||=y(a)||y(o)&&!h(s,i),b.push(n)}const v={...i};delete v.wall_ids,d.push({...v,poly:u.poly.map(t=>[t[0],t[1]]),wall_ids:b})}return{atoms:[...c.values()].sort((t,e)=>t.key.localeCompare(e.key)),rooms:d}},Bn=(t,e,s,i,o)=>{const a=new Map([...s.values()].map(t=>[Mn(t.a,t.b),t])),n=(t=>{const e=new Map;for(const s of t)"wall"===s.host?.kind&&e.set(s.host.id,(e.get(s.host.id)||0)+1);return e})(t.openings||[]),r=new Map;for(const t of e){const e=o?.get(t.key);if(e){const i=s.get(e);if(!i)throw new yn("duplicate-id",e);r.set(t,i);continue}if(t.preferredIds.size>1)throw new yn("duplicate-id",[...t.preferredIds].sort().join(","));const i=[...t.preferredIds][0],l=i?s.get(i):void 0;if(l){r.set(t,l);continue}const h=i?t.preferredCarriers.get(i):void 0;if(i&&h){r.set(t,{id:i,a:h.a,b:h.b,cm:0});continue}const c=a.get(t.key);if(c){r.set(t,c);continue}const d=[...s.values()].filter(e=>Ln(t.a,t.b,e.a,e.b)>vn),p=[...new Map(d.map(t=>[t.id,t])).values()];if(p.sort((t,e)=>(n.get(e.id)||0)-(n.get(t.id)||0)||Sn(e.a,e.b)-Sn(t.a,t.b)||t.id.localeCompare(e.id)),p[0])r.set(t,p[0]);else if(1===t.positionalIds.size){const e=s.get([...t.positionalIds][0]);e&&r.set(t,e)}}const l=new Map;for(const[t,e]of r){const s=l.get(e.id)||[];s.push(t),l.set(e.id,s)}for(const[t,e]of l){const i=s.get(t)||r.get(e[0]);if(!i)throw new yn("duplicate-id",t);const o=[(i.a[0]+i.b[0])/2,(i.a[1]+i.b[1])/2];e.sort((t,e)=>{const s=In(o,t.a,t.b)<=vn?0:1,a=In(o,e.a,e.b)<=vn?0:1;if(s!==a)return s-a;return(In(i.a,t.a,t.b)<=vn?0:1)-(In(i.a,e.a,e.b)<=vn?0:1)||t.key.localeCompare(e.key)}),e[0].id=t}const h=(t=>{const e=new Set;for(const s of[t.rooms,t.openings,t.decor,t.room_drafts,t.partitions,t.wall_columns])for(const t of Array.isArray(s)?s:[])"string"==typeof t?.id&&t.id&&e.add(t.id);for(const s of Array.isArray(t.room_drafts)?t.room_drafts:[])for(const t of Array.isArray(s?.segments)?s.segments:[])"string"==typeof t?.id&&t.id&&e.add(t.id);return e})(t);for(const t of e)if(t.id){if(h.has(t.id))throw new yn("duplicate-id",t.id);h.add(t.id)}const c=e.filter(t=>!t.id);if(i){const e=c.map(e=>{const[s,i]=Cn(e.a,e.b),o=`${String(t.id||"")}|${xn(s)}|${xn(i)}|${[...e.owners].sort().join(",")}`,a=Rn(Tn(o));return{atom:e,seed:o,digest:a,base:`wall-${a.slice(0,20)}`}}).sort((t,e)=>t.digest.localeCompare(e.digest)||t.atom.key.localeCompare(e.atom.key)),s=new Map;for(const t of e){const e=s.get(t.digest);if(e&&e!==t.seed)throw new yn("duplicate-id",t.digest);s.set(t.digest,t.seed);let i=1,o=t.base;for(;h.has(o);)o=`${t.base}-${++i}`;t.atom.id=o,h.add(o)}}else for(const t of c)t.id=Nn(h),h.add(t.id)},Hn=(t,e)=>{if("partition"===t.host?.kind)return null;const s=[Number(t.x),Number(t.y)];if(!s.every(Number.isFinite))return null;const i=e=>{if(!(Number(e.cm)>0))return!1;const i=Dn(s,e.a,e.b),o=Sn(e.a,e.b),a=Number(t.length)/2;return i>=-1e-9&&i<=1+vn&&In(s,e.a,e.b)<=.02*F&&st(e.a,e.b,Number(t.angle))&&Number.isFinite(a)&&a>=0&&i*o-a>=-1e-9&&i*o+a<=o+vn},o="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null,a=o&&i(o)?[o]:e.filter(i);if(1!==a.length)return null;const n=a[0];return{kind:"wall",id:n.id,t:Math.max(0,Math.min(1,Dn(s,n.a,n.b)))}},Wn=(t,e)=>{const s=[Number(t.x),Number(t.y)];if(!s.every(Number.isFinite))return null;const i=Number(t.length)/2,o=e.filter(e=>{if(!(Number(e.cm)>0))return!1;const o=Dn(s,e.a,e.b),a=Sn(e.a,e.b);return o>=-1e-9&&o<=1+vn&&In(s,e.a,e.b)<=.02*F&&st(e.a,e.b,Number(t.angle))&&Number.isFinite(i)&&i>=0&&o*a-i>=-1e-9&&o*a+i<=a+vn}),a=(e=>{if(!e.length)return null;const i="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null;return i||[...e].sort((t,e)=>In(s,t.a,t.b)-In(s,e.a,e.b)||Number(e.cm)-Number(t.cm)||(t.ide.id?1:0))[0]})(o);return a?{kind:"wall",id:a.id,t:Math.max(0,Math.min(1,Dn(s,a.a,a.b)))}:null},jn=/^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/,Gn=t=>{if("number"!=typeof t&&"string"!=typeof t)return null;if("string"==typeof t&&!jn.test(t.trim()))return null;const e=Number(t);return Number.isFinite(e)?e:null},qn=t=>{if(!Array.isArray(t)||t.length<2)return null;const e=Gn(t[0]),s=Gn(t[1]);return null==e||null==s?null:[e,s]},Un=t=>"string"==typeof t?t:"",Kn=t=>{if(!Object.prototype.hasOwnProperty.call(t,"room_drafts"))return{drafts:0,segments:0};const e=Array.isArray(t.room_drafts)?t.room_drafts:[];if(!e.length)return delete t.room_drafts,{drafts:0,segments:0};const s=new Set;for(const e of[t.rooms,t.openings,t.decor,t.partitions,t.wall_columns,t.wall_segments])for(const t of Array.isArray(e)?e:[])"string"==typeof t?.id&&t.id&&s.add(t.id);for(const t of e)"string"==typeof t?.id&&t.id&&s.add(t.id);const i=Array.isArray(t.partitions)?[...t.partitions]:[];let o=0;for(const a of e){const e=Un(a?.id),n=Array.isArray(a?.points)?a.points:[],r=Array.isArray(a?.segments)?a.segments:[];if(n.length<2||r.length!==n.length-1)throw new yn("zero-length",e);for(let a=0;a+1100)throw new yn("thickness-conflict",e);let p="string"==typeof c?.id&&c.id?c.id:"";if(!p||s.has(p)){const i=zn(Un(t.id),l,h,[`draft:${e}:${a}`]);p=i;for(let t=2;s.has(p);t++)p=`${i}-${t}`}s.add(p),i.push({id:p,a:kn(l),b:kn(h),cm:d}),o++}}return i.length?t.partitions=i:delete t.partitions,delete t.room_drafts,{drafts:e.length,segments:o}},Vn=t=>Kn(t),Jn=(t,e,s)=>{const i=Kn(t),o=An(t),{atoms:a,rooms:n}=On(t,o);Bn(t,a,o,e,s);const r=a.map(e=>{const s=e.id?o.get(e.id):void 0,i=((t,e,s)=>{if(e.zeroWall)return 0;const i=Array.isArray(t.walls)?t.walls:[],o=Y(e.a,e.b,F),a=i.filter(t=>Number(t.cm)>0&&(!(t.key!==o&&!e.parentKeys.has(t.key))||!(!$n(t.a)||!$n(t.b))&&Ln(e.a,e.b,t.a,t.b)>=Sn(e.a,e.b)-vn)).map(t=>Math.max(1,Math.min(100,Number(t.cm))));if(new Set(a.map(t=>t.toFixed(9))).size>1)throw new yn("thickness-conflict",e.key);if(a.length)return a[0];const n=ot(i,e.a,e.b,F,1);return n>0?n:Number(s?.cm)>0?Number(s.cm):0})(t,e,s);return{...s||{},id:e.id,a:[...e.a],b:[...e.b],cm:i}}),l=new Map(a.map(t=>[t.key,t.id]));for(const t of n)t.wall_ids=t.wall_ids.map(t=>l.get(t));t.rooms=n,t.wall_segments=r,t.walls=r.filter(t=>t.cm>0).map(t=>({key:Y(t.a,t.b,F),cm:t.cm,a:[...t.a],b:[...t.b]})),t.walls.length||delete t.walls,delete t.open_spans;for(const e of t.rooms)delete e.open_to;return((t,e,s)=>{const i=Array.isArray(t.openings)?t.openings:[];for(const t of i){if("partition"===t.host?.kind)continue;if(!t.host&&!s){const s=Hn(t,e);s&&(t.host=s);continue}const i=Hn(t,e)??(s?Wn(t,e):null);if(i)t.host=i;else{if(!s)throw new yn("opening-host",t.id);delete t.host}}})(t,r,e),{wallSegments:r.reduce((t,e)=>t+(o.has(e.id)?0:1),0),drafts:i.drafts,draftSegments:i.segments}};function Zn(t,e={}){const s=JSON.stringify(t),i=wn(t);Z(i);let o=0,a=0,n=0;const r=Number(i?.model_version||0)<10;for(const t of Array.isArray(i?.spaces)?i.spaces:[]){const s=e.lineageSpaceId===String(t?.id||"")?e.lineageHints:void 0,i=Jn(t,r,s);o+=i.wallSegments,a+=i.drafts,n+=i.draftSegments}return i.model_version=10,Z(i),{config:i,changed:s!==JSON.stringify(i),migratedSegments:o,migratedDrafts:a,migratedDraftSegments:n}}const Yn=t=>!!t&&"object"==typeof t&&!Array.isArray(t);function Xn(t,e){const s=(t,e)=>{if(Array.isArray(t)&&Array.isArray(e)){const i=new Map;for(const e of t)Yn(e)&&"string"==typeof e.id&&e.id&&i.set(e.id,e);const o=e.map((e,o)=>{if(Yn(e)&&"string"==typeof e.id&&e.id){const t=i.get(e.id);return t?s(t,e):wn(e)}return o[e,e in t?s(t[e],i):wn(i)]);for(const e of Object.keys(t))delete t[e];for(const[e,s]of i)t[e]=s;return t}return wn(e)};return s(t,e)}const Qn=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),tr=(t,e,s)=>Math.min(s,Math.max(e,t)),er=t=>vt({spaces:[t]})[0],sr=(t,e,s)=>{const i=s>0?s:1,o=t=>`${(t[0]/i).toFixed(12)},${(t[1]/i).toFixed(12)}`,a=o(t),n=o(e);return a0?n:1,l=Math.max(i*r*.02,1e-9),h=[];for(const e of t||[])for(const t of A(e)||[])h.push([t[0],t[1]]);const c=[];for(const t of s||[])Array.isArray(t)&&t.length>=4&&t.slice(0,4).every(Number.isFinite)&&c.push([t[0],t[1]],[t[2],t[3]]);const d=(t,e)=>e.some(e=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*l),p=new Map;for(const n of t||[]){if(!n?.id)continue;const u=yt(t,n.id,e,s,i,o,a,r);if(u)for(let t=0;t0&&_>0&&n===m&&_!==n))continue;const g=u.poly[i],f=u.poly[(i+1)%u.poly.length],b=Math.hypot(f[0]-g[0],f[1]-g[1]);if(!(b>l&&b<.5*a-1e-9*a))continue;if(d(g,c)||d(f,c))continue;if(d(g,h)&&d(f,h))continue;const v=sr(g,f,r),y=p.get(v);y?y.targets.add(n):p.set(v,{a:[g[0],g[1]],b:[f[0],f[1]],targets:new Set([n])})}}}let u=e.slice();const _=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*l,m=(t,e)=>{if(!Array.isArray(t.a)||!Array.isArray(t.b)||t.a.length<2||t.b.length<2)return!1;const s=[Number(t.a[0])*r,Number(t.a[1])*r],i=[Number(t.b[0])*r,Number(t.b[1])*r];return!![...s,...i].every(Number.isFinite)&&(_(s,e.a)&&_(i,e.b)||_(s,e.b)&&_(i,e.a))};for(const t of[...p.values()].filter(t=>1===t.targets.size).sort((t,e)=>sr(t.a,t.b,r).localeCompare(sr(e.a,e.b,r)))){const e=[...t.targets][0],s=u.filter(e=>m(e,t));if(new Set(s.map(t=>t.cm)).size>1)continue;let o=!1;u=u.map(s=>m(s,t)?(o=!0,s.cm===e?s:{...s,cm:e}):s),o||(u=G(u,t.a,t.b,e,i,r))}return u}const or=t=>{const e=[];for(const s of t||[]){const t=A(s);if(t?.length)for(let s=0;s"string"==typeof t?.id?t.id:"").filter(Boolean),c=new Set(h),d=new Map;for(const t of h){const e=fn("space",t);e.layers>0&&gn("space",e.root)&&bn(d,e.root,t)}const p=new Map,u=new Map,_=new Map,m=new Map;for(const t of r){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const s=new Map;for(const i of Array.isArray(t.rooms)?t.rooms:[]){const t="string"==typeof i?.id?i.id:"";if(!t)continue;const o=fn("room",t);o.layers>0&&gn("room",o.root)&&bn(s,o.root,t),u.has(t)||u.set(t,e),_.has(t)||_.set(t,String(i.name||""));const a="string"==typeof i.area?i.area:"";if(a){const s=m.get(a)||[];s.push({spaceId:e,roomId:t}),m.set(a,s)}}p.set(e,s)}const g=new Set(u.keys()),f=new Map,b=new Map;for(const t of l)"string"==typeof t?.id&&t.id&&(!0===t.removed?b.set(t.id,t):f.set(t.id,t));const v={spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,positionsUnresolved:0,nestedRefsUnresolved:0,deadSpaceIds:[],orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0,removedPositions:[],liveMissingPositions:[],unverifiedPositions:[]},y=new Set,w=t=>c.has(t)?null:(()=>{const e=fn("space",t).root;if(!gn("space",e))return null;const s=d.get(e)||[];return 1===s.length?s[0]:null})(),$=(t,e)=>{const s=fn("room",t).root;if(!gn("room",s))return null;const i=p.get(e)?.get(s)||[];return 1===i.length?i[0]:null},k=t=>{const e=s.effectiveAreaByMarker?.[t]||"",i=e&&m.get(e)||[];return 1===i.length?i[0]:null},x=(t,e,s)=>{if("string"==typeof t.room_id&&t.room_id&&!g.has(t.room_id)){const i=e?$(t.room_id,e):null;i?(t.room_id=i,v.roomRefsRemapped++):s?(t.room_id=s.roomId,v.roomRefsRemapped++):!0!==t.removed&&delete t.room_id}const i=t.vacuum?.segment_map;if(i&&"object"==typeof i&&!Array.isArray(i))for(const t of Object.keys(i)){const s=i[t];if("string"!=typeof s||!s||g.has(s))continue;const o=e?$(s,e):null;o?(i[t]=o,v.roomRefsRemapped++):v.nestedRefsUnresolved++}};for(const t of l){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const s="string"==typeof t.space?t.space:"",i=s&&!c.has(s),a=o[e],n="string"==typeof a?.s?a.s:"",r=n&&!c.has(n),l=!0===t.removed;let h=s&&c.has(s)?s:null,d=null,p=!1;if(i){const i=w(s);i?(t.space=i,h=i,p=!0,v.spaceRefsRemapped++):l||"virtual"===t.binding?l||(delete t.space,h=null,v.markersDetached++):(d=k(e),d?(t.space=d.spaceId,h=d.spaceId,v.spaceRefsRemapped++):(delete t.space,h=null,v.markersDetached++))}l&&!p||x(t,h,d),r&&p&&n===s&&h&&(o[e]={...a,s:h},v.positionsRemapped++,y.add(e))}for(const t of Object.keys(o)){if(y.has(t))continue;const e=o[t],s="string"==typeof e?.s?e.s:"";if(!s||c.has(s))continue;const i=w(s);if(i){if(t.startsWith("rl_")){const s=t.slice(3),a=$(s,i);if(a){const s=`rl_${a}`;mn(o,s)||(o[s]={...e,s:i}),delete o[t],v.roomRefsRemapped++,v.positionsRemapped++;continue}}o[t]={...e,s:i},v.positionsRemapped++}}const M=s.ownerRoster,C=!0===M?.authoritative,S=new Set(M?.deviceIds||[]),P=new Set(M?.entityIds||[]),D=new Set(Array.isArray(i.settings?.known_devices)?i.settings.known_devices.filter(t=>"string"==typeof t):[]),I=(t,e="")=>{const s=String(M?.names?.[t]||e||"").trim();return s&&s!==t?s:""},L=(t,e,s,i="",o)=>({id:t,spaceId:e,kind:s,name:I(t,i),...o?{reason:o}:{}}),T=t=>{"room_label"===t?v.orphanRoomLabelsRemoved++:"group"===t?v.orphanGroupPositionsRemoved++:v.orphanDevicePositionsRemoved++},R=new Set;for(const[t,e]of Object.entries(o)){const i="string"==typeof e?.s?e.s:"";if(!i||c.has(i))continue;let a,n;const r=f.get(t),l=b.get(t);if(r)a=L(t,i,"device",String(r.name||"")),n="live";else if(l)a=L(t,i,"device",String(l.name||"")),n="absent";else if(t.startsWith("rl_")){const e=t.slice(3);a=L(t,i,"room_label",_.get(e)||""),n=g.has(e)?"live":"absent"}else if(t.startsWith("lg_")){const e=t.slice(3);a=L(t,i,"group"),n=P.has(e)?"live":C?"absent":"unverified","unverified"===n&&(a.reason="registry_unavailable")}else S.has(t)?(a=L(t,i,"device"),n="live"):D.has(t)?(a=L(t,i,"device"),n=C?"absent":"unverified","unverified"===n&&(a.reason="registry_unavailable")):(a=L(t,i,"unknown","","unknown_owner"),n="unverified");if("absent"!==n){if("live"===n){if(v.liveMissingPositions.push(a),!0===s.removeLiveMissingPositions){delete o[t],v.liveMissingPositionsRemoved++,T(a.kind),v.removedPositions.push(a);continue}}else v.unverifiedPositions.push(a);v.positionsUnresolved++,R.add(i)}else delete o[t],T(a.kind),v.removedPositions.push(a)}return v.deadSpaceIds=[...R].sort((t,e)=>t.localeCompare(e)),{config:i,layout:o,report:v,changed:JSON.stringify(i)!==a||JSON.stringify(o)!==n}}(t,e,s),n=a.config,r=at(n,a.layout);Z(n),nt(a.layout);const l=JSON.stringify(t||{}),h=JSON.stringify(e||{}),c=Number.isInteger(Number(n.model_version))?Number(n.model_version):0,d=(t=>{let e=0,s=0,i=0;for(const s of t.markers||[]){if("ripple"===s.display&&(s.display="icon_ripple",e++),Array.isArray(s.controls)){const t="string"==typeof s.binding&&s.binding.startsWith("entity:")?s.binding.slice(7):"",i=t?s.controls.filter(e=>e!==t):s.controls;JSON.stringify(i)!==JSON.stringify(s.controls)&&(s.controls=i.length?i:null,e++)}const t=s.vacuum;t&&Qn(t,"trail")&&(["never","cleaning","always"].includes(t.trail_mode)||(t.trail_mode=!1===t.trail?"never":"cleaning"),delete t.trail,e++)}for(const o of t.spaces||[]){const t=o.settings;"glow"===t?.fill_mode&&("boolean"!=typeof t.glow_enabled&&(t.glow_enabled=!0),t.fill_mode="none",e++,s++);for(const t of o.rooms||[]){const s=t.settings;"glow"===s?.fill_mode&&("boolean"!=typeof s.glow&&(s.glow=!0),delete s.fill_mode,e++,i++)}if(Qn(o,"segments")&&(delete o.segments,e++),Qn(o,"plan_scale")){const t=Number(o.plan_scale);Number.isFinite(t)&&t>=ut&&t<=_t&&(Qn(o,"plan_scale_x")||(o.plan_scale_x=t),Qn(o,"plan_scale_y")||(o.plan_scale_y=t),delete o.plan_scale,e++)}const a=Number(o.cell_cm);Qn(o,"cell_cm")&&(!Number.isFinite(a)||a<.1||a>1e3)&&(o.cell_cm=Number.isFinite(a)&&a>0?tr(a,.1,1e3):5,e++);const n=Number(o.cell_cm),r=Number.isFinite(n)&&n>0?n:5;for(const t of o.wall_columns||[])if("circle"===t.shape)Qn(t,"angle")&&(delete t.angle,e++);else if("square"===t.shape&&Qn(t,"angle")){const s=((Number(t.angle)||0)%90+90)%90;t.angle!==s&&(t.angle=s,e++)}for(const t of o.decor||[]){if(Qn(t,"width")){const s=Number(t.width);(Qn(t,"width_cm")||Number.isFinite(s))&&(Qn(t,"width_cm")||(t.width_cm=Number(tr(s/dt*r,.1,100).toFixed(6))),delete t.width,e++)}if("rect"!==t?.kind&&"ellipse"!==t?.kind||!0!==t.fill||(Qn(t,"fill_color")||(t.fill_color=t.color||"#607d8b",e++),Qn(t,"fill_opacity")||(t.fill_opacity=.25,e++)),"text"!==t?.kind)continue;void 0===t.size_cm?(t.size_cm=Number(tr(mt*gt(t)/dt*r,.1,2e3).toFixed(6)),delete t.scale,delete t.size,e++):(Qn(t,"scale")||Qn(t,"size"))&&(delete t.scale,delete t.size,e++);let s=String(t.text??"");const i=[...s.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!ft(t[1]));if(!(Qn(t,"entity")||Qn(t,"attr")||Qn(t,"unit")))continue;const o=String(t.unit??"").trim(),a="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,n=i||o?"":bt(t.entity,a);if(i||n){if(n){const e=s.indexOf("{}");s=e>=0?s.slice(0,e)+n+s.slice(e+2):`${s}${s?" ":""}${n}`,t.text=s}delete t.entity,delete t.attr,delete t.unit,e++}}}return{total:e,glowSpaces:s,glowRooms:i}})(n);let p=d.total,u=0,_=0,m=0;if(c<10)for(const t of Array.isArray(n.spaces)?n.spaces:[]){const e=Vn(t);_+=e.drafts,m+=e.segments}const g=(f=n.spaces||[],JSON.parse(JSON.stringify(f)));var f;const b=ja(n.spaces||[],a.layout);let v=0,y=0,w=0,$="";const k=b.spaces.map(t=>{const e=rt(t);v+=e.report.wallsStraightened,y+=e.report.wallsStraightenSkipped;const s=Number(t?.cell_cm)>0?Number(t.cell_cm):5,i=e.report.maxStraightenShift/F*s;return i>w&&(w=i,$=String(t?.id||"")),e.space}),x=v?ja(k,b.layout):{...b,spaces:k};n.spaces=x.spaces;const M=v?{...b.report,moved:b.report.moved+x.report.moved,coordsCanonicalized:b.report.coordsCanonicalized+x.report.coordsCanonicalized,maxShift:Math.max(b.report.maxShift,x.report.maxShift),maxShiftCm:Math.max(b.report.maxShiftCm,x.report.maxShiftCm),maxSpace:x.report.maxShiftCm>b.report.maxShiftCm?x.report.maxSpace:b.report.maxSpace,rotated:b.report.rotated+x.report.rotated}:{...b.report};let C=0,S=0,P=0,D=0,I=0,L=0,T=0;for(let t=0;t0===Number(t.cm)),walls:e.walls||[]}),a=er(e),r=er(s);if(!a||!r)continue;const l=or(a.rooms),h=or(r.rooms),c=.02*dt,d=(e.wall_segments||[]).filter(t=>0===Number(t.cm)).map(t=>({...t,key:Y(t.a,t.b,F),cm:0})),p=new Set(d.map(t=>t.key)),u=lt(e,a.rooms,ht,c);S+=u.length;for(const t of u){const e=[t[0]/ht,t[1]/ht],s=[t[2]/ht,t[3]/ht],i=Y(e,s,F);p.has(i)||(p.add(i),d.push({key:i,a:e,b:s,cm:0}))}const _=d.length,m=ct(d,l,h,F,ht),f=(t,e,s)=>{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;if(!(a>0))return Math.hypot(t[0]-e[0],t[1]-e[1]);const n=Math.max(0,Math.min(1,((t[0]-e[0])*i+(t[1]-e[1])*o)/a));return Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))},b=m.filter(t=>{if(!Array.isArray(t.a)||!Array.isArray(t.b))return!1;const e=t.a.map(t=>t*ht),s=t.b.map(t=>t*ht);return h.some(([t,i])=>f(e,t,i)<=4*c&&f(s,t,i)<=4*c)});P+=Math.max(0,_-b.length);const v=(s.wall_segments||[]).filter(t=>Number(t.cm)>0);s.wall_segments=[...v,...b.map(({key:t,...e})=>e)];const y=b.map(t=>[t.a[0]*ht,t.a[1]*ht,t.b[0]*ht,t.b[1]*ht]),w=Array.isArray(e.walls)?e.walls.length:0;let $=ct(e.walls,l,h,F,ht);$=ir(r.rooms,$,y,F,Number(s.cell_cm)>0?Number(s.cell_cm):5,dt,ht),$=q(r.rooms,$,y,F,Number(s.cell_cm)>0?Number(s.cell_cm):5,dt,ht),$=pt($,s.rooms||[],F,1,y.map(t=>[t[0]/ht,t[1]/ht,t[2]/ht,t[3]/ht])),C+=Math.max(0,w-$.length),$.length?s.walls=$:delete s.walls;const k=Za(s.partitions||[],{pitch:F,geometry:Xa(s)});k.merged&&(D+=k.merged,s.partitions=k.partitions,Ya(s.openings,s.partitions,k.openingMoves,{coordScale:ht,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,gridPitch:dt}));const x=er(s);if(x){const t=o(s,x,s.walls||[],y,{pitch:F,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,gridPitch:dt,coordScale:ht});t.partitionsReconciled&&(I+=t.partitionsReconciled,L+=t.openingsRehosted,t.partitions.length?s.partitions=t.partitions:delete s.partitions,t.openings.length?s.openings=t.openings:delete s.openings,t.walls.length?s.walls=t.walls:delete s.walls)}JSON.stringify({zero:(s.wall_segments||[]).filter(t=>0===Number(t.cm)),walls:s.walls||[]})!==i&&T++}if(c<=10){const t=function(t){const e=Zn(t);return Xn(t,e.config),{...e,config:t}}(n);u+=t.migratedSegments,_+=t.migratedDrafts,m+=t.migratedDraftSegments}const R=Z(n),z=nt(x.layout),N=JSON.stringify(R)!==l||JSON.stringify(z)!==h;c<10&&N&&(R.model_version=10);const A=JSON.stringify(R)!==l||JSON.stringify(z)!==h,E=Number.isInteger(Number(R.model_version))?Number(R.model_version):c,O=A?M:{...M,moved:0,coordsCanonicalized:0,maxShift:0,maxShiftCm:0,maxSpace:"",rotated:0},B=A?a.report:{...a.report,spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0};return{config:R,layout:z,report:{...O,modelFrom:c,modelTo:E,migrated:A?p:0,glowSpacesMigrated:A?d.glowSpaces:0,glowRoomsMigrated:A?d.glowRooms:0,canonicalized:A?T:0,wallSegmentsMigrated:A?u:0,roomDraftsMigrated:A?_:0,roomDraftSegmentsMigrated:A?m:0,legacyZeroWallsMigrated:A?S:0,wallsMerged:A?C:0,spansMerged:A?P:0,partitionsMerged:A?D:0,partitionsReconciled:A?I:0,openingsRehosted:A?L:0,wallsStraightened:A?v:0,wallsStraightenSkipped:y,maxStraightenShiftCm:A?w:0,maxStraightenSpace:A?$:"",latticeCoordinatesCanonicalized:A?r.canonicalized:0,latticeCoordinatesFar:A?r.far:0,latticeMaxShift:A?r.maxShift:0,latticeMaxShiftCm:A?r.maxShiftCm:0,latticeSpaces:A?r.spaces:[],...B},changed:A}}async function nr(t,e,s){t._saveConfigDebounced.pending()&&t._saveConfigDebounced.flush(),await t._writeChain;const i=await t.hass.callWS({type:"houseplan/plan/optimize",config:e,layout:s,expected_config_rev:t._cfgRev,expected_layout_rev:t._layoutRev});t._adoption.acceptPairWrite(e,s,i),t._geometryHistory.clear(),t._cancelDeviceDrag(),t._devicePositionHistory.clear(),t._canOptimizeUndo=!0===i.can_undo,t._undoKind=!0===i.can_undo?"optimize":null,t._dirtyPos.clear(),t._sentPos.clear(),t._cfgEpoch++,t._modelCache=null,t._frame=null,t._regSignature="",t._maybeRebuildDevices(),t._cacheSnapshot(),t.requestUpdate()}const rr=Object.freeze({spaces:50,partitions:2e3,openings:500,decor:1e3,columns:500});class lr extends Error{constructor(t){super(t),this.code=t,this.name="SpaceCopyError"}}const hr=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),cr=t=>void 0===t?t:JSON.parse(JSON.stringify(t)),dr=t=>null===t||"object"!=typeof t||Array.isArray(t)?null:t;function pr(t,e=!1){if(void 0===t&&!e)return[];if(!Array.isArray(t))throw new lr("source_invalid");return t.map(t=>{const e=dr(t);if(!e||"string"!=typeof e.id||!e.id)throw new lr("source_invalid");return e})}const ur=t=>Array.isArray(t)&&2===t.length&&t.every(t=>Number.isFinite(t));function _r(t,e,s){const i=String(t??"").trim()||s,o=new Set(e.map(t=>{const e=dr(t);return String(e?.title??"").trim()}));let a=2;for(;o.has(`${i} (${a})`);)a++;return`${i} (${a})`}const mr=["settings","zero_wall_style","cell_cm","view_box","plan_url","plan_aspect","plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"];const gr={source_missing:"space.copy_error_source_missing",source_invalid:"space.copy_error_source_invalid",spaces_limit:"space.copy_error_spaces_limit",partitions_limit:"space.copy_error_partitions_limit",openings_limit:"space.copy_error_openings_limit",decor_limit:"space.copy_error_decor_limit",columns_limit:"space.copy_error_columns_limit",opening_host_missing:"space.copy_error_opening_host",opening_host_unknown:"space.copy_error_opening_host",geometry_unsafe:"space.copy_error_geometry"};let fr=0;function br(t,e,s){const i=t._spaceDialog;return!(!i?.copy||i.copy.token!==e)&&(t._spaceDialog={...i,busy:s,copy:{...i.copy,busy:s}},!0)}function vr(t){t._cfgEpoch++,t._modelCache=null,t._frame=null,t._regSignature="",t._maybeRebuildDevices(),t.requestUpdate()}async function yr(t,e){const s=t._spaceDialog;if(!s?.copy||"edit"!==s.mode||s.busy||s.copy.busy||!s.copy.title.trim()||!s.spaceId||!t._serverCfg)return;const i=++fr,o=s.spaceId,a=s.copy.title.trim();t._spaceDialog={...s,busy:!0,copy:{...s.copy,title:a,busy:!0,token:i}};let n=!1;try{if(t._saveConfigDebounced.pending()&&t._saveConfigDebounced.flush(),await t._writeChain,!br(t,i,!0)||!t._serverCfg)return;const s=t._cfgRev,r=t._layoutRev,l=wt(t._serverCfg),h=wt(t._layout);let c;try{c=(e.optimize??ar)(t._serverCfg,t._layout,e.optimizeReferenceContext())}catch(s){return br(t,i,!1),void e.showWallModelMigrationBlocked(s)}if(c.changed){const d=t._checkOptimizeGeometry(c.config);if(e.reportPreflightFailure(d,c.config),!d.ok)return br(t,i,!1),void t._showToast(t._t("space.copy_error_optimize_geometry"));const p=await t._confirmDanger({key:`copy-space:${o}`,kind:"warning",title:t._t("space.copy_optimize_title"),message:t._t("space.copy_optimize_body",{name:a}),objectName:a,confirmLabel:t._t("space.copy_optimize_confirm"),cancelLabel:t._t("btn.cancel"),icon:"mdi:broom"});if(!br(t,i,p))return;if(!p)return;if(t._cfgRev!==s||t._layoutRev!==r||!t._serverCfg||wt(t._serverCfg)!==l||wt(t._layout)!==h)return br(t,i,!1),void t._showToast(t._t("space.copy_error_changed"));e.clearGeometryGesture(),await nr(t,c.config,c.layout),n=!0}if(!br(t,i,!0)||!t._serverCfg)return;const d=t._serverCfg,p=function(t,e,s,i){const o=t.spaces;if(!s.trim())throw new lr("source_invalid");if(o.length>=rr.spaces)throw new lr("spaces_limit");const a=o.findIndex(t=>t.id===e);if(a<0)throw new lr("source_missing");const n=o[a];if(!Array.isArray(n.view_box))throw new lr("source_invalid");const r=pr(n.wall_segments,!0),l=pr(n.partitions),h=pr(n.openings),c=pr(n.decor),d=pr(n.wall_columns);if(r.length+l.length>rr.partitions)throw new lr("partitions_limit");if(h.length>rr.openings)throw new lr("openings_limit");if(c.length>rr.decor)throw new lr("decor_limit");if(d.length>rr.columns)throw new lr("columns_limit");let p=0;const u=t=>`${t}${i}${(p++).toString(36)}`,_=new Map,m=new Map,g=[];for(const t of r){if(_.has(t.id)||!ur(t.a)||!ur(t.b)||"number"!=typeof t.cm||!Number.isFinite(t.cm))throw new lr("source_invalid");const e=u("cw");_.set(t.id,e),g.push({id:e,a:cr(t.a),b:cr(t.b),cm:t.cm})}for(const t of l){if(m.has(t.id)||!ur(t.a)||!ur(t.b)||"number"!=typeof t.cm||!Number.isFinite(t.cm))throw new lr("source_invalid");const e=u("cp");m.set(t.id,e),g.push({id:e,a:cr(t.a),b:cr(t.b),cm:t.cm})}const f=h.map(t=>{const e=dr(t.host);if(!e||"string"!=typeof e.id||"string"!=typeof e.kind)throw new lr("opening_host_missing");const s="wall"===e.kind?_.get(e.id):"partition"===e.kind?m.get(e.id):void 0;if(!s)throw new lr("opening_host_unknown");const i={...cr(t),id:u("co"),host:{...cr(e),kind:"partition",id:s}};return delete i.contact,delete i.lock,i}),b=c.map(t=>({...cr(t),id:u("cd")})),v=d.map(t=>({...cr(t),id:u("cc")})),y=`s${i}`;if(o.some(t=>t.id===y))throw new lr("source_invalid");const w={id:y,title:s.trim(),rooms:[],wall_segments:[],view_box:cr(n.view_box)};for(const t of mr)"view_box"!==t&&hr(n,t)&&(w[t]=cr(n[t]));g.length&&(w.partitions=g),f.length&&(w.openings=f),b.length&&(w.decor=b),v.length&&(w.wall_columns=v);const $=cr(t);return $.spaces.splice(a+1,0,w),{config:$,space:w,sourceIndex:a}}(d,o,a,e.newSeed?.()??function(t=Date.now(),e=Math.random()){const s=Math.floor(16777216*Math.max(0,Math.min(.999999999,e))).toString(36).padStart(5,"0");return`${Math.max(0,Math.floor(t)).toString(36)}${s}`}());let u=!1;try{u=t._checkSpacePhysicalGeometry(p.config,p.space.id).ok}catch{u=!1}if(!u||t._junctionLimitViolations(p.config,p.space.id).length)throw new lr("geometry_unsafe");const _=t._adoption.beginOptimistic(d,p.config);t._adoption.stageLocalConfig(p.config),vr(t);try{await e.saveConfigNow(_)}catch(e){throw t._rollbackOptimistic(_)&&vr(t),"conflict"!==e?.code&&await t._reloadConfigOnly(!0),e}t._canOptimizeUndo=!1,t._undoKind=null,e.clearGeometryGesture(),t._selId=null,t._physicalSel=null,t._spaceDialog=null,t._commitSpace(p.space.id,!0),e.setMode("plan"),t._tool="draw",t._path=[],t._cursorPt=null,t._activeWallChainId=null,t._activeWallChainPartitionIds=[],t._primeDrawWallField(),t._saveNav(),t.requestUpdate(),t._showToast(t._t("toast.space_copied",{name:a}))}catch(e){"conflict"===e?.code&&await Promise.all([t._reloadConfigOnly(!0),t._reloadLayoutOnly()]),br(t,i,!1),function(t,e){if(e instanceof lr)return void t._showToast(t._t(gr[e.code]));const s=e?.code;"wall_model_client_outdated"!==s?t._showToast(t._t("toast.error",{err:t._errText(e)})):t._showToast(t._t("toast.wall_model_client_outdated"))}(t,e),n&&t.requestUpdate()}}function wr(){if(this.host._spaceDialog.copy)return function(t,e){const s=t._spaceDialog.copy,i=()=>function(t){const e=t._spaceDialog;!e?.copy||e.busy||e.copy.busy||(t._spaceDialog={...e,copy:void 0})}(t);return p``}const Fa=1e-6*z,Na=6*z;function Aa(t){return Number.isFinite(t)?Math.round(t/z)*z:t}const Ea=(t,e,s,i)=>Math.hypot(s-t,i-e),Oa=(t,e,s,i,o,a,n,r)=>Math.hypot(Math.max(Math.abs(o-t),Math.abs(o+n-(t+s))),Math.max(Math.abs(a-e),Math.abs(a+r-(e+i)))),Ba=(t,e,s,i,o,a,n)=>{const r=Math.max(Number(i)||0,0)/2,l=Math.PI/180,h=Math.cos(s*l)*r,c=Math.sin(s*l)*r,d=Math.cos(n*l)*r,p=Math.sin(n*l)*r,u=Math.max(Ea(t+h,e+c,o+d,a+p),Ea(t-h,e-c,o-d,a-p)),_=Math.max(Ea(t+h,e+c,o-d,a-p),Ea(t-h,e-c,o+d,a+p));return Math.min(u,_)},Ha=t=>{const e=Number(t?.cell_cm);return e>0?e:5};function Wa(t,e){const s=JSON.parse(JSON.stringify(t||[])),i=JSON.parse(JSON.stringify(e||{}));let o=0,a=0,n=0,r=0,l="",h=0,c=0;const d=(t,e)=>{Number.isFinite(t)&&Number.isFinite(e)&&t!==e&&Math.abs(e-t)<=Fa&&c++},p=(t,e)=>{d(t[0],e[0]),d(t[1],e[1])},u={};let _=5;for(const t of s){const e=Ha(t);null!=t?.id&&(u[String(t.id)]=e),e>_&&(_=e)}const m=(t,e,s,i=!1)=>{if(!(t>Fa||i))return;o++,t>n&&(n=t);const a=t*F*e;a>r&&(r=a,l=s)};for(const t of s){const e=Ha(t),s=null!=t?.id?String(t.id):"";for(const i of t.rooms||[]){a++;let t=0;if(i.poly?.length)i.poly=i.poly.map(e=>{const s=[Aa(e[0]),Aa(e[1])];return t=Math.max(t,Ea(e[0],e[1],s[0],s[1])),p(e,s),s});else if(null!=i.x&&null!=i.y){const e=i.x,s=i.y,o=i.w||0,a=i.h||0,n=Aa(e+o),r=Aa(s+a),l=Aa(e),h=Aa(s),c=Math.max(z,n-l),p=Math.max(z,r-h);t=Oa(e,s,o,a,l,h,c,p),i.x=l,i.y=h,i.w=c,i.h=p,d(e,l),d(s,h),d(e+o,l+c),d(s+a,h+p)}m(t,e,s)}for(const i of t.partitions||[]){a++;const o=[i.a[0],i.a[1]],n=[i.b[0],i.b[1]],r=[Aa(o[0]),Aa(o[1])],l=[Aa(n[0]),Aa(n[1])];let h=Math.max(Ea(o[0],o[1],r[0],r[1]),Ea(n[0],n[1],l[0],l[1]));const c=Ea(r[0],r[1],l[0],l[1]),d=(t.openings||[]).filter(t=>"partition"===t.host?.kind&&t.host.id===i.id).every(t=>{const e=Number(t.length),s=Number(t.host.t),i=s*c;return Number.isFinite(e)&&e>0&&Number.isFinite(s)&&s>=0&&s<=1&&i-e/2>=-Fa&&i+e/2<=c+Fa});c>Fa&&d?(i.a=r,i.b=l,p(o,r),p(n,l)):h=0,m(h,e,s)}for(const i of t.wall_columns||[]){a++;const t=[i.center[0],i.center[1]],o=[Aa(t[0]),Aa(t[1])],n=Ea(t[0],t[1],o[0],o[1]);i.center=o,p(t,o),m(n,e,s)}for(const i of t.decor||[]){if("furniture"===i.kind||"image"===i.kind)continue;a++;let t=0;if("line"===i.kind){const e=[i.x1,i.y1],s=[i.x2,i.y2],o=[Aa(e[0]),Aa(e[1])],a=[Aa(s[0]),Aa(s[1])];t=Math.max(Ea(e[0],e[1],o[0],o[1]),Ea(s[0],s[1],a[0],a[1])),i.x1=o[0],i.y1=o[1],i.x2=a[0],i.y2=a[1],p(e,o),p(s,a)}else{const e=i.x,s=i.y,o=i.w,a=i.h,n=Aa(e),r=Aa(s);if(null!=i.w&&null!=i.h){const l=Aa(e+o),h=Aa(s+a),c=Math.max(z,l-n),p=Math.max(z,h-r);t=Oa(e,s,o,a,n,r,c,p),i.w=c,i.h=p,d(e+o,n+c),d(s+a,r+p)}else t=Ea(e,s,n,r);i.x=n,i.y=r,d(e,n),d(s,r)}m(t,e,s)}for(const i of t.openings||[]){if(a++,"partition"===i.host?.kind){const o=(t.partitions||[]).find(t=>t.id===i.host.id),a=Number(i.host.t);if(!o||!Number.isFinite(a)||a<0||a>1)continue;const n=o.b[0]-o.a[0],r=o.b[1]-o.a[1];if(Math.hypot(n,r)<=Fa)continue;const l=o.a[0]+n*a,c=o.a[1]+r*a;let d=180*Math.atan2(r,n)/Math.PI;d>=90?d-=180:d<-90&&(d+=180);const p=Number(i.angle),u=!(Number.isFinite(p)&&p===d),_=Ba(i.x,i.y,Number.isFinite(p)?p:d,Number(i.length)||0,l,c,d);i.x=l,i.y=c,i.angle=d,u&&h++,m(_,e,s,u);continue}const o=R([i.x,i.y],t.rooms||[],Na,{step:z,length:Number(i.length)||0});if(!o)continue;const n=Number(i.angle),r=!(Number.isFinite(n)&&n===o.angle),l=Ba(i.x,i.y,Number.isFinite(n)?n:o.angle,Number(i.length)||0,o.x,o.y,o.angle);i.x=o.x,i.y=o.y,i.angle=o.angle,r&&h++,m(l,e,s,r)}}for(const[t,e]of Object.entries(i)){if(!e||"object"!=typeof e)continue;const s=e;if("number"!=typeof s.x||"number"!=typeof s.y)continue;a++;const o=Aa(s.x),n=Aa(s.y),r=Ea(s.x,s.y,o,n);i[t]={...s,x:o,y:n},d(s.x,o),d(s.y,n);const l="string"==typeof s.s?s.s:"";m(r,u[l]??_,l)}return{spaces:s,layout:i,report:{moved:o,coordsCanonicalized:c,total:a,maxShift:n,maxShiftCm:r,maxSpace:l,rotated:h},changed:o>0||c>0}}function ja(t,e){const s=e.base+t*e.span;return Math.min(1,Math.max(0,s))}const Ga=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),qa=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1]);function Ua(t,e,s){const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;if(a<=0)return qa(t,e);let n=((t[0]-e[0])*i+(t[1]-e[1])*o)/a;return n=Math.max(0,Math.min(1,n)),Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))}function Ka(t,e,s,i,o){for(const i of e)if(i&&!s.has(i.id)&&Ga(i.a)&&Ga(i.b)&&(qa(t,i.a)<=o||qa(t,i.b)<=o))return!0;for(const e of i?.roomPolygons||[])for(let s=0;s0&&r>0))return null;if(Math.abs(o[0]/n*(a[1]/r)-o[1]/n*(a[0]/r))>s)return null;for(const[s,o]of[[t.a,e.a],[t.a,e.b],[t.b,e.a],[t.b,e.b]])if(qa(s,o)<=i)return[(s[0]+o[0])/2,(s[1]+o[1])/2];return null}function Ja(t,e){const s=.05*(Number(e.pitch)>0?Number(e.pitch):1),i=new Map;let o=(t||[]).filter(t=>!!t&&"string"==typeof t.id&&Ga(t.a)&&Ga(t.b));if(o.length<2)return{partitions:[...t||[]],merged:0,openingMoves:[]};const a=e.seedIds&&e.seedIds.length?new Set(e.seedIds):null;let n=0;for(let t=0;tqa(e,t.at)>s);let c=h[0]??r.a,d=h[h.length-1]??l.b;if(h.length<2&&(c=r.a,d=l.b),d[0]0?(d[0]-c[0])/u:0,m=u>0?(d[1]-c[1])/u:0,g=t=>u>0?((t[0]-c[0])*_+(t[1]-c[1])*m)/u:0;for(const t of[r,l]){const e=g(t.a),s=g(t.b)-e;for(const[o,a]of i)a.toId===t.id&&i.set(o,{fromId:a.fromId,toId:p.id,base:e+a.base*s,span:a.span*s});i.set(t.id,{fromId:t.id,toId:p.id,base:e,span:s})}a&&a.add(p.id),o=o.filter((e,s)=>s!==t.i&&s!==t.j),o.splice(t.i,0,p),n++}return{partitions:o,merged:n,openingMoves:[...i.values()]}}function Za(t,e,s,i){if(!t?.length||!s.length)return 0;const o=new Map(s.map(t=>[t.fromId,t]));let a=0;for(const s of t){const t=s?.host;if(!t||"partition"!==t.kind)continue;const n=o.get(t.id);if(!n)continue;s.host={...t,id:n.toId,t:ja(t.t,n)},a++;const r=A(s,e,i.coordScale,i.cellCm,i.gridPitch).resolved;r&&Object.assign(s,E(s,r,i.coordScale))}return a}function Ya(t){return{roomPolygons:(t?.rooms||[]).map(t=>N(t)).filter(t=>!!t),columns:t?.wall_columns||[]}}const Xa=t=>!!t&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),Qa=(t,e)=>t[0]-e[0]||t[1]-e[1],tn=(t,e,s,i)=>[t[0]+e*i,t[1]+s*i],en=(t,e,s,i)=>(t[0]-e[0])*s+(t[1]-e[1])*i,sn=(t,e,s,i,o)=>{const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(!(r>o))return null;const l=a/r,h=n/r,c=e=>Math.abs((e[0]-t[0])*h-(e[1]-t[1])*l);if(c(s)>o||c(i)>o)return null;const d=en(s,t,l,h),p=en(i,t,l,h),u=Math.max(0,Math.min(d,p)),_=Math.min(r,Math.max(d,p));return _-u>o?{lo:u,hi:_}:null},on=(t,e,s)=>Math.min(t.hi,e.hi)-Math.max(t.lo,e.lo)>s,an=t=>{const e=new Set(["id","a","b","cm"]);return Object.keys(t||{}).every(t=>e.has(t))},nn=(t,e,s,i)=>{const o=t.b[0]-t.a[0],a=t.b[1]-t.a[1],n=Math.hypot(o,a);if(!(n>i))return!0;const r=o/n,l=a/n,h=V(t.cm,s.cellCm,s.gridPitch)/2;return e.some(e=>{const o=e?.center;if(!Xa(o))return!0;const a=en(o,t.a,r,l),c=Math.abs((o[0]-t.a[0])*l-(o[1]-t.a[1])*r),d=V(Number(e.cm),s.cellCm,s.gridPitch)*("square"===e.shape?Math.SQRT1_2:.5);return!(Number.isFinite(d)&&d>0)||a>=-d-i&&a<=n+d+i&&c<=h+d+i})},rn=(t,e,s)=>{if(t.host){const i=A(t,e,s.coordScale,s.cellCm,s.gridPitch).resolved;return i?{center:i.center,angle:i.angle,length:i.length}:null}const i=Number(t.x)*s.coordScale,o=Number(t.y)*s.coordScale,a=Number(t.angle),n=Number(t.length)*s.coordScale;return[i,o,a,n].every(Number.isFinite)&&n>0?{center:[i,o],angle:a,length:n}:null},ln=(t,e,s)=>{const i=t.angle*Math.PI/180,o=Math.cos(i),a=Math.sin(i),n=e.angle*Math.PI/180,r=Math.cos(n),l=Math.sin(n);if(Math.abs(o*l-a*r)>1e-6)return!1;const h=e.center[0]-t.center[0],c=e.center[1]-t.center[1];if(Math.abs(h*a-c*o)>s)return!1;const d=h*o+c*a;return Math.max(-t.length/2,d-e.length/2)({...t,a:[t.a[0]*e,t.a[1]*e],b:[t.b[0]*e,t.b[1]*e]}),cn=(t,e,s,i)=>{const o=`~r-${(t=>{let e=2166136261;for(let s=0;s>>0;return e.toString(36)})(`${t}|${e[0].toFixed(9)},${e[1].toFixed(9)}|${s[0].toFixed(9)},${s[1].toFixed(9)}`)}`,a=`${t.slice(0,Math.max(1,64-o.length))}${o}`;let n=a;for(let t=2;i.has(n);t++){const e=`-${t}`;n=`${a.slice(0,64-e.length)}${e}`}return i.add(n),n},dn=(t,e)=>{const s=[];for(const i of t){const t=s[s.length-1];!(t&&Math.abs(t.hi-i.lo)<=e&&t.safe===i.safe)||i.safe&&t.signature!==i.signature?s.push({lo:i.lo,hi:i.hi,a:i.a,b:i.b,safe:i.safe,signature:i.signature,roomIds:i.roomIds,finalCm:i.finalCm}):(t.hi=i.hi,t.b=i.b)}return s};function pn(t,e,s,i,o){const a=s||[],n=Array.isArray(t?.partitions)?t.partitions:[],r=Array.isArray(t?.openings)?t.openings:[],l={walls:a,partitions:n,openings:r,partitionsReconciled:0,openingsRehosted:0};if(!n.length)return l;const h=Math.max(2e-4*o.gridPitch,1e-9);let c=a,d=n,p=r,u=0,_=0;const m=o.partitionIds?new Set(o.partitionIds):null,g=new Map(e.partitions.map(t=>[t.id,t]));for(const t of[...n].sort((t,e)=>t.id.localeCompare(e.id))){if(m&&!m.has(t.id))continue;if(!d.some(e=>e.id===t.id))continue;if(!an(t))continue;const s=g.get(t.id);if(!(s&&Xa(s.a)&&Xa(s.b)&&Number.isFinite(s.cm)&&(o.allowCoincidentPartitions?!(s.cm<0):s.cm>0)))continue;const[a,n]=Qa(s.a,s.b)<=0?[[s.a[0],s.a[1]],[s.b[0],s.b[1]]]:[[s.b[0],s.b[1]],[s.a[0],s.a[1]]],r=n[0]-a[0],l=n[1]-a[1],f=Math.hypot(r,l);if(!(f>h))continue;const b=r/f,v=l/f,y=O(e.rooms,c,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),w=y.flatMap(t=>{if(t.open||"outer"!==t.kind&&"shared"!==t.kind)return[];const e=sn(a,n,t.a,t.b,h);return e?[{interval:t,range:e}]:[]});if(!w.length)continue;const $=p.filter(t=>"partition"===t.host?.kind&&t.host.id===s.id).map(t=>({opening:t,resolved:A(t,e.partitions,o.coordScale,o.cellCm,o.gridPitch).resolved}));if($.some(t=>!t.resolved))continue;const k=[0,f];for(const{range:t}of w)k.push(t.lo,t.hi);const x=k.slice(),M=new Map;for(const{opening:t,resolved:e}of $){const s=en(e.center,a,b,v),i={lo:s-e.length/2,hi:s+e.length/2};M.set(t.id,i),x.push(Math.max(0,i.lo),Math.min(f,i.hi))}const C=[...new Set(x.filter(t=>Number.isFinite(t)&&t>=-h&&t<=f+h).map(t=>Math.max(0,Math.min(f,t)).toFixed(9)))].map(Number).sort((t,e)=>t-e),S=d.map(t=>hn(t,o.coordScale)).filter(t=>t.id!==s.id),P=[];for(let t=0;t+1h))continue;const r=tn(a,b,v,i),l=tn(a,b,v,n),c=w.filter(({range:t})=>t.lo<=i+h&&t.hi>=n-h).map(({interval:t})=>t),d=new Map;for(const t of c)d.set(t.roomId,t);const p=[...d.values()],u=new Set(p.map(t=>t.kind)),_=new Set(p.map(t=>o.allowCoincidentPartitions||t.cm>0?t.cm:B)),m=p[0]?.kind,g=[...d.keys()].sort(),f=1===u.size&&1===_.size&&("outer"===m&&1===g.length||"shared"===m&&2===g.length),y={id:s.id,a:r,b:l,cm:s.cm},$=S.some(t=>!!sn(r,l,t.a,t.b,h)),k=f&&(o.allowCoincidentPartitions||!$)&&!nn(y,e.wall_columns,o,h),x=f?o.allowCoincidentPartitions||p[0].cm>0?p[0].cm:B:0,M=f?Math.max(x,s.cm):s.cm;P.push({lo:i,hi:n,a:r,b:l,safe:k,signature:k?`${m}|${g.join(",")}|${M}`:"",roomIds:g,roomCm:x,finalCm:M})}if(!P.some(t=>t.safe))continue;const D=new Map;for(const{opening:t,resolved:e}of $){const i=M.get(t.id),a=k.some(t=>t>i.lo+h&&ton(t,i,h)),r=new Set(n.filter(t=>t.safe).map(t=>t.signature));if(!a&&n.length>0&&n.every(t=>t.safe)&&1===r.size&&H(e,y,h)){D.set(t.id,{resolved:e,signature:[...r][0]});continue}const l=W(s,o.cellCm,o.gridPitch),c={lo:i.lo-l,hi:i.hi+l};for(const t of P)on(t,c,h)&&(t.safe=!1,t.signature="")}let I=!0;for(;I;){I=!1;for(const[t,e]of[...D.entries()]){const i=M.get(t),a=P.filter(t=>on(t,i,h));if(a.length>0&&a.every(t=>t.safe)&&a.every(t=>t.signature===e.signature))continue;D.delete(t);const n=W(s,o.cellCm,o.gridPitch),r={lo:i.lo-n,hi:i.hi+n};for(const t of P)on(t,r,h)&&(t.safe=!1,t.signature="");I=!0}}const L=dn(P,h),T=L.filter(t=>t.safe),R=L.filter(t=>!t.safe);if(!T.length)continue;if(d.length-1+R.length>2e3)continue;let z=c;for(const t of T){const[e,i]=Qa(s.a,s.b)<=0?[t.a,t.b]:[t.b,t.a];z=j(z,e,i,t.finalCm,o.pitch,o.coordScale)}if(z=G(e.rooms,z,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),z.length>500)continue;const F=new Set(d.map(t=>t.id));F.delete(s.id);const N=R.map((t,e)=>{const i=[t.a[0]/o.coordScale,t.a[1]/o.coordScale],a=[t.b[0]/o.coordScale,t.b[1]/o.coordScale],n=0===e?s.id:cn(s.id,i,a,F);return F.add(n),{id:n,a:i,b:a,cm:s.cm}}),V=d.findIndex(t=>t.id===s.id),J=d.slice();J.splice(V,1,...N);const Z=J.map(t=>hn(t,o.coordScale)),Y=new Map;let X=!0;for(const{opening:t,resolved:e}of $){const s=D.get(t.id);if(s){const e=E(t,s.resolved,o.coordScale),{host:i,...a}=e;Y.set(t.id,a);continue}const i=M.get(t.id),a=N[R.findIndex(t=>t.lo<=i.lo+h&&t.hi>=i.hi-h)],n=a&&Z.find(t=>t.id===a.id);if(!a||!n){X=!1;break}const r=n.b[0]-n.a[0],l=n.b[1]-n.a[1],c=Math.hypot(r,l),d=en(e.center,n.a,r/c,l/c),p={...E(t,e,o.coordScale),host:{kind:"partition",id:a.id,t:d/c}};if(!q(p,Z,o.coordScale,o.cellCm,o.gridPitch).resolved){X=!1;break}Y.set(t.id,p)}if(!X)continue;const Q=p.map(t=>Y.get(t.id)||t),tt=[...D.keys()].map(t=>Y.get(t)),et=tt.map(t=>rn(t,Z,o));if(et.some(t=>!t))continue;let st=!1;for(let t=0;tt.id));for(const t of Q){if(it.has(t.id))continue;const e=rn(t,Z,o);e&&et.some(t=>ln(t,e,h))&&(st=!0)}if(st)continue;const ot=U(e.rooms,z,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale);[...D.entries()].every(([t,e])=>{const s=Y.get(t),i=K(ot,{x:s.x*o.coordScale,y:s.y*o.coordScale,angle:s.angle,length:s.length*o.coordScale},!0),a=[i.negative,i.positive].filter(t=>!!t?.full),n=e.signature.split("|")[1].split(","),r=new Set(a.map(t=>t.roomId));return a.length===n.length&&r.size===n.length&&n.every(t=>r.has(t))})&&(c=z,d=J,p=Q,u+=T.length,_+=D.size)}return{walls:c,partitions:d,openings:p,partitionsReconciled:u,openingsRehosted:_}}const un=t=>JSON.parse(JSON.stringify(t)),_n=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),mn=(t,e)=>e.length>0&&e.length<=35&&("space"===t?/^[a-z0-9_-]+$/.test(e):/^[A-Za-z0-9_-]+$/.test(e));function gn(t,e){let s=String(e??"");const i=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),o=new RegExp(`^${i}_(.+)_([0-9a-f]{8})$`);let a=0;for(;a<16;a++){const t=o.exec(s);if(!t)return{root:s,layers:a,bounded:!1};s=t[1]}return{root:s,layers:a,bounded:o.test(s)}}const fn=(t,e,s)=>{const i=t.get(e)||[];i.push(s),t.set(e,i)};const bn=1e-9;class vn extends Error{constructor(t,e=""){super(e?`${t}: ${e}`:t),this.reason=t,this.name="WallSegmentModelError"}}const yn=t=>JSON.parse(JSON.stringify(t)),wn=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(Number(t[0]))&&Number.isFinite(Number(t[1])),$n=t=>[Number(t[0]),Number(t[1])],kn=t=>`${Number(t[0]).toFixed(12)},${Number(t[1]).toFixed(12)}`,xn=(t,e)=>{const s=kn(t),i=kn(e);return skn(t)<=kn(e)?[$n(t),$n(e)]:[$n(e),$n(t)],Cn=(t,e)=>Math.hypot(e[0]-t[0],e[1]-t[1]),Sn=(t,e=[])=>{const s=new Set,i=t=>{const e=Number(t);if(!Number.isFinite(e))return;const i=e/z;Math.abs(i-Math.round(i))>=tt&&s.add(e.toFixed(12))};for(const e of Array.isArray(t?.rooms)?t.rooms:[])for(const t of N(e)||[])i(t[0]),i(t[1]);for(const e of[t?.wall_segments,t?.walls])for(const t of Array.isArray(e)?e:[])i(t?.a?.[0]),i(t?.a?.[1]),i(t?.b?.[0]),i(t?.b?.[1]);for(const t of e)i(t?.[0]),i(t?.[1]);return s.size},Pn=(t,e,s)=>{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;return a>1e-18?((t[0]-e[0])*i+(t[1]-e[1])*o)/a:0},Dn=(t,e,s)=>{const i=Math.max(0,Math.min(1,Pn(t,e,s)));return Math.hypot(t[0]-(e[0]+(s[0]-e[0])*i),t[1]-(e[1]+(s[1]-e[1])*i))},In=(t,e,s,i,o=1e-9)=>{const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(r<=o)return 0;const l=e=>Math.abs((e[0]-t[0])*n-(e[1]-t[1])*a)/r;if(l(s)>o||l(i)>o)return 0;const h=Pn(s,t,e),c=Pn(i,t,e);return Math.max(0,Math.min(1,Math.max(h,c))-Math.max(0,Math.min(h,c)))*r},Ln=t=>{const e=(new TextEncoder).encode(t),s=8*e.length,i=64*Math.ceil((e.length+9)/64),o=new Uint8Array(i);o.set(e),o[e.length]=128;const a=new DataView(o.buffer);a.setUint32(i-8,Math.floor(s/4294967296),!1),a.setUint32(i-4,s>>>0,!1);const n=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),r=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),l=new Uint32Array(64),h=(t,e)=>t>>>e|t<<32-e;for(let t=0;t>>3,o=h(s,17)^h(s,19)^s>>>10;l[t]=l[t-16]+i+l[t-7]+o>>>0}let[e,s,i,o,c,d,p,u]=r;for(let t=0;t<64;t++){const a=u+(h(c,6)^h(c,11)^h(c,25))+(c&d^~c&p)+n[t]+l[t]>>>0,r=e&s^e&i^s&i;u=p,p=d,d=c,c=o+a>>>0,o=i,i=s,s=e,e=a+((h(e,2)^h(e,13)^h(e,22))+r>>>0)>>>0}r[0]=r[0]+e>>>0,r[1]=r[1]+s>>>0,r[2]=r[2]+i>>>0,r[3]=r[3]+o>>>0,r[4]=r[4]+c>>>0,r[5]=r[5]+d>>>0,r[6]=r[6]+p>>>0,r[7]=r[7]+u>>>0}const c=new Uint8Array(32),d=new DataView(c.buffer);for(let t=0;t{const e="abcdefghijklmnopqrstuvwxyz234567";let s=0,i=0,o="";for(const a of t)for(i=i<<8|a,s+=8;s>=5;)o+=e[i>>>s-5&31],s-=5;return s&&(o+=e[i<<5-s&31]),o},Rn=(t,e,s,i,o="")=>{const[a,n]=Mn(e,s),r=`${t}|${kn(a)}|${kn(n)}|${[...i].sort().join(",")}${o}`;return`wall-${Tn(Ln(r)).slice(0,20)}`};let zn=0;const Fn=t=>{for(let e=0;e<1e3;e++){const e=globalThis.crypto?.randomUUID?.(),s=`wall-${e||Tn(Ln(`${Date.now()}|${zn++}|${Math.random()}`)).slice(0,26)}`;if(!t.has(s))return s}throw new vn("duplicate-id","id factory exhausted")},Nn=t=>{const e=new Map;for(const s of Array.isArray(t?.wall_segments)?t.wall_segments:[])if(s&&"string"==typeof s.id&&wn(s.a)&&wn(s.b)){if(e.has(s.id))throw new vn("duplicate-id",s.id);e.set(s.id,s)}return e},An=(t,e,s)=>{const i=(s,i)=>{const o=t[0]-s[0],a=t[1]-s[1];return Math.abs(e[0]-i[0]-o)<=bn&&Math.abs(e[1]-i[1]-a)<=bn?[o,a]:null};return i(s.a,s.b)||i(s.b,s.a)},En=(t,e)=>{const s=Array.isArray(t.rooms)?t.rooms:[],i=Y(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]),o=i.length?i:X(s,null,1,.04*z,!0),a=[];for(const t of s){const s=N(t),i=Array.isArray(t?.wall_ids)?t.wall_ids:[];if(s&&i.length===s.length)for(let t=0;t"partition"!==t.host?.kind&&[Number(t.x),Number(t.y)].every(Number.isFinite)&&Number.isFinite(Number(t.angle))&&Number(t.length)>0&&o.some(e=>Dn([Number(t.x),Number(t.y)],[e[0],e[1]],[e[2],e[3]])<=.04*z)):[],l=r.map(t=>{const e=Number(t.angle)*Math.PI/180,s=[Math.cos(e),Math.sin(e)],i=Number(t.length)/2,o=[Number(t.x),Number(t.y)];return{a:[o[0]-s[0]*i,o[1]-s[1]*i],b:[o[0]+s[0]*i,o[1]+s[1]*i]}}),h=(t,e)=>r.some(s=>{const i=[Number(s.x),Number(s.y)];if(!et(t,e,Number(s.angle)))return!1;if(Dn(i,t,e)>.02*z)return!1;const o=Cn(t,e),a=Pn(i,t,e)*o,n=Number(s.length)/2;return a+n>=-1e-9&&a-n<=o+bn}),c=new Map,d=[];for(const i of s){const r=String(i?.id||""),p=N(i);if(!r||!p||p.length<3)throw new vn("invalid-room",r);const u=Q(s,r,n,z,1,[...t.walls||[],...l]);if(!u||u.poly.length<3)throw new vn("invalid-room",r);const _=Array.isArray(i.wall_ids)?i.wall_ids:[],m=_.length===p.length;let g=null,f=m;if(f)for(let t=0;tbn||Math.abs(i[1]-g[1])>bn)){f=!1;break}g=i}const b=[];for(let t=0;t2)throw new vn("third-owner",n);const d=m?_[u.parent[t]]:void 0;if("string"==typeof d&&d){const o=e.get(d);f||!o||In(s,i,o.a,o.b)>bn?l.preferredIds.add(d):l.positionalIds.add(d),l.preferredCarriers.set(d,{a:$n(p[u.parent[t]]),b:$n(p[(u.parent[t]+1)%p.length])})}const g=u.parent[t];l.parentKeys.add(Z(p[g],p[(g+1)%p.length],z));const v=[(s[0]+i[0])/2,(s[1]+i[1])/2],y=t=>t.some(t=>Dn(v,[t[0],t[1]],[t[2],t[3]])<=.04*z);l.zeroWall||=y(a)||y(o)&&!h(s,i),b.push(n)}const v={...i};delete v.wall_ids,d.push({...v,poly:u.poly.map(t=>[t[0],t[1]]),wall_ids:b})}return{atoms:[...c.values()].sort((t,e)=>t.key.localeCompare(e.key)),rooms:d}},On=(t,e,s,i,o)=>{const a=new Map([...s.values()].map(t=>[xn(t.a,t.b),t])),n=(t=>{const e=new Map;for(const s of t)"wall"===s.host?.kind&&e.set(s.host.id,(e.get(s.host.id)||0)+1);return e})(t.openings||[]),r=new Map;for(const t of e){const e=o?.get(t.key);if(e){const i=s.get(e);if(!i)throw new vn("duplicate-id",e);r.set(t,i);continue}if(t.preferredIds.size>1)throw new vn("duplicate-id",[...t.preferredIds].sort().join(","));const i=[...t.preferredIds][0],l=i?s.get(i):void 0;if(l){r.set(t,l);continue}const h=i?t.preferredCarriers.get(i):void 0;if(i&&h){r.set(t,{id:i,a:h.a,b:h.b,cm:0});continue}const c=a.get(t.key);if(c){r.set(t,c);continue}const d=[...s.values()].filter(e=>In(t.a,t.b,e.a,e.b)>bn),p=[...new Map(d.map(t=>[t.id,t])).values()];if(p.sort((t,e)=>(n.get(e.id)||0)-(n.get(t.id)||0)||Cn(e.a,e.b)-Cn(t.a,t.b)||t.id.localeCompare(e.id)),p[0])r.set(t,p[0]);else if(1===t.positionalIds.size){const e=s.get([...t.positionalIds][0]);e&&r.set(t,e)}}const l=new Map;for(const[t,e]of r){const s=l.get(e.id)||[];s.push(t),l.set(e.id,s)}for(const[t,e]of l){const i=s.get(t)||r.get(e[0]);if(!i)throw new vn("duplicate-id",t);const o=[(i.a[0]+i.b[0])/2,(i.a[1]+i.b[1])/2];e.sort((t,e)=>{const s=Dn(o,t.a,t.b)<=bn?0:1,a=Dn(o,e.a,e.b)<=bn?0:1;if(s!==a)return s-a;return(Dn(i.a,t.a,t.b)<=bn?0:1)-(Dn(i.a,e.a,e.b)<=bn?0:1)||t.key.localeCompare(e.key)}),e[0].id=t}const h=(t=>{const e=new Set;for(const s of[t.rooms,t.openings,t.decor,t.room_drafts,t.partitions,t.wall_columns])for(const t of Array.isArray(s)?s:[])"string"==typeof t?.id&&t.id&&e.add(t.id);for(const s of Array.isArray(t.room_drafts)?t.room_drafts:[])for(const t of Array.isArray(s?.segments)?s.segments:[])"string"==typeof t?.id&&t.id&&e.add(t.id);return e})(t);for(const t of e)if(t.id){if(h.has(t.id))throw new vn("duplicate-id",t.id);h.add(t.id)}const c=e.filter(t=>!t.id);if(i){const e=c.map(e=>{const[s,i]=Mn(e.a,e.b),o=`${String(t.id||"")}|${kn(s)}|${kn(i)}|${[...e.owners].sort().join(",")}`,a=Tn(Ln(o));return{atom:e,seed:o,digest:a,base:`wall-${a.slice(0,20)}`}}).sort((t,e)=>t.digest.localeCompare(e.digest)||t.atom.key.localeCompare(e.atom.key)),s=new Map;for(const t of e){const e=s.get(t.digest);if(e&&e!==t.seed)throw new vn("duplicate-id",t.digest);s.set(t.digest,t.seed);let i=1,o=t.base;for(;h.has(o);)o=`${t.base}-${++i}`;t.atom.id=o,h.add(o)}}else for(const t of c)t.id=Fn(h),h.add(t.id)},Bn=(t,e)=>{if("partition"===t.host?.kind)return null;const s=[Number(t.x),Number(t.y)];if(!s.every(Number.isFinite))return null;const i=e=>{if(!(Number(e.cm)>0))return!1;const i=Pn(s,e.a,e.b),o=Cn(e.a,e.b),a=Number(t.length)/2;return i>=-1e-9&&i<=1+bn&&Dn(s,e.a,e.b)<=.02*z&&et(e.a,e.b,Number(t.angle))&&Number.isFinite(a)&&a>=0&&i*o-a>=-1e-9&&i*o+a<=o+bn},o="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null,a=o&&i(o)?[o]:e.filter(i);if(1!==a.length)return null;const n=a[0];return{kind:"wall",id:n.id,t:Math.max(0,Math.min(1,Pn(s,n.a,n.b)))}},Hn=(t,e)=>{const s=[Number(t.x),Number(t.y)];if(!s.every(Number.isFinite))return null;const i=Number(t.length)/2,o=e.filter(e=>{if(!(Number(e.cm)>0))return!1;const o=Pn(s,e.a,e.b),a=Cn(e.a,e.b);return o>=-1e-9&&o<=1+bn&&Dn(s,e.a,e.b)<=.02*z&&et(e.a,e.b,Number(t.angle))&&Number.isFinite(i)&&i>=0&&o*a-i>=-1e-9&&o*a+i<=a+bn}),a=(e=>{if(!e.length)return null;const i="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null;return i||[...e].sort((t,e)=>Dn(s,t.a,t.b)-Dn(s,e.a,e.b)||Number(e.cm)-Number(t.cm)||(t.ide.id?1:0))[0]})(o);return a?{kind:"wall",id:a.id,t:Math.max(0,Math.min(1,Pn(s,a.a,a.b)))}:null},Wn=/^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/,jn=t=>{if("number"!=typeof t&&"string"!=typeof t)return null;if("string"==typeof t&&!Wn.test(t.trim()))return null;const e=Number(t);return Number.isFinite(e)?e:null},Gn=t=>{if(!Array.isArray(t)||t.length<2)return null;const e=jn(t[0]),s=jn(t[1]);return null==e||null==s?null:[e,s]},qn=t=>"string"==typeof t?t:"",Un=t=>{if(!Object.prototype.hasOwnProperty.call(t,"room_drafts"))return{drafts:0,segments:0};const e=Array.isArray(t.room_drafts)?t.room_drafts:[];if(!e.length)return delete t.room_drafts,{drafts:0,segments:0};const s=new Set;for(const e of[t.rooms,t.openings,t.decor,t.partitions,t.wall_columns,t.wall_segments])for(const t of Array.isArray(e)?e:[])"string"==typeof t?.id&&t.id&&s.add(t.id);for(const t of e)"string"==typeof t?.id&&t.id&&s.add(t.id);const i=Array.isArray(t.partitions)?[...t.partitions]:[];let o=0;for(const a of e){const e=qn(a?.id),n=Array.isArray(a?.points)?a.points:[],r=Array.isArray(a?.segments)?a.segments:[];if(n.length<2||r.length!==n.length-1)throw new vn("zero-length",e);for(let a=0;a+1100)throw new vn("thickness-conflict",e);let p="string"==typeof c?.id&&c.id?c.id:"";if(!p||s.has(p)){const i=Rn(qn(t.id),l,h,[`draft:${e}:${a}`]);p=i;for(let t=2;s.has(p);t++)p=`${i}-${t}`}s.add(p),i.push({id:p,a:$n(l),b:$n(h),cm:d}),o++}}return i.length?t.partitions=i:delete t.partitions,delete t.room_drafts,{drafts:e.length,segments:o}},Kn=t=>Un(t),Vn=(t,e,s)=>{const i=Un(t),o=Nn(t),{atoms:a,rooms:n}=En(t,o);On(t,a,o,e,s);const r=a.map(e=>{const s=e.id?o.get(e.id):void 0,i=((t,e,s)=>{if(e.zeroWall)return 0;const i=Array.isArray(t.walls)?t.walls:[],o=Z(e.a,e.b,z),a=i.filter(t=>Number(t.cm)>0&&(!(t.key!==o&&!e.parentKeys.has(t.key))||!(!wn(t.a)||!wn(t.b))&&In(e.a,e.b,t.a,t.b)>=Cn(e.a,e.b)-bn)).map(t=>Math.max(1,Math.min(100,Number(t.cm))));if(new Set(a.map(t=>t.toFixed(9))).size>1)throw new vn("thickness-conflict",e.key);if(a.length)return a[0];const n=it(i,e.a,e.b,z,1);return n>0?n:Number(s?.cm)>0?Number(s.cm):0})(t,e,s);return{...s||{},id:e.id,a:[...e.a],b:[...e.b],cm:i}}),l=new Map(a.map(t=>[t.key,t.id]));for(const t of n)t.wall_ids=t.wall_ids.map(t=>l.get(t));t.rooms=n,t.wall_segments=r,t.walls=r.filter(t=>t.cm>0).map(t=>({key:Z(t.a,t.b,z),cm:t.cm,a:[...t.a],b:[...t.b]})),t.walls.length||delete t.walls,delete t.open_spans;for(const e of t.rooms)delete e.open_to;return((t,e,s)=>{const i=Array.isArray(t.openings)?t.openings:[];for(const t of i){if("partition"===t.host?.kind)continue;if(!t.host&&!s){const s=Bn(t,e);s&&(t.host=s);continue}const i=Bn(t,e)??(s?Hn(t,e):null);if(i)t.host=i;else{if(!s)throw new vn("opening-host",t.id);delete t.host}}})(t,r,e),{wallSegments:r.reduce((t,e)=>t+(o.has(e.id)?0:1),0),drafts:i.drafts,draftSegments:i.segments}};function Jn(t,e={}){const s=JSON.stringify(t),i=yn(t);J(i);let o=0,a=0,n=0;const r=Number(i?.model_version||0)<10;for(const t of Array.isArray(i?.spaces)?i.spaces:[]){const s=e.lineageSpaceId===String(t?.id||"")?e.lineageHints:void 0,i=Vn(t,r,s);o+=i.wallSegments,a+=i.drafts,n+=i.draftSegments}return i.model_version=10,J(i),{config:i,changed:s!==JSON.stringify(i),migratedSegments:o,migratedDrafts:a,migratedDraftSegments:n}}const Zn=t=>!!t&&"object"==typeof t&&!Array.isArray(t);function Yn(t,e){const s=(t,e)=>{if(Array.isArray(t)&&Array.isArray(e)){const i=new Map;for(const e of t)Zn(e)&&"string"==typeof e.id&&e.id&&i.set(e.id,e);const o=e.map((e,o)=>{if(Zn(e)&&"string"==typeof e.id&&e.id){const t=i.get(e.id);return t?s(t,e):yn(e)}return o[e,e in t?s(t[e],i):yn(i)]);for(const e of Object.keys(t))delete t[e];for(const[e,s]of i)t[e]=s;return t}return yn(e)};return s(t,e)}const Xn=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),Qn=(t,e,s)=>Math.min(s,Math.max(e,t)),tr=t=>bt({spaces:[t]})[0],er=(t,e,s)=>{const i=s>0?s:1,o=t=>`${(t[0]/i).toFixed(12)},${(t[1]/i).toFixed(12)}`,a=o(t),n=o(e);return a0?n:1,l=Math.max(i*r*.02,1e-9),h=[];for(const e of t||[])for(const t of N(e)||[])h.push([t[0],t[1]]);const c=[];for(const t of s||[])Array.isArray(t)&&t.length>=4&&t.slice(0,4).every(Number.isFinite)&&c.push([t[0],t[1]],[t[2],t[3]]);const d=(t,e)=>e.some(e=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*l),p=new Map;for(const n of t||[]){if(!n?.id)continue;const u=vt(t,n.id,e,s,i,o,a,r);if(u)for(let t=0;t0&&_>0&&n===m&&_!==n))continue;const g=u.poly[i],f=u.poly[(i+1)%u.poly.length],b=Math.hypot(f[0]-g[0],f[1]-g[1]);if(!(b>l&&b<.5*a-1e-9*a))continue;if(d(g,c)||d(f,c))continue;if(d(g,h)&&d(f,h))continue;const v=er(g,f,r),y=p.get(v);y?y.targets.add(n):p.set(v,{a:[g[0],g[1]],b:[f[0],f[1]],targets:new Set([n])})}}}let u=e.slice();const _=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*l,m=(t,e)=>{if(!Array.isArray(t.a)||!Array.isArray(t.b)||t.a.length<2||t.b.length<2)return!1;const s=[Number(t.a[0])*r,Number(t.a[1])*r],i=[Number(t.b[0])*r,Number(t.b[1])*r];return!![...s,...i].every(Number.isFinite)&&(_(s,e.a)&&_(i,e.b)||_(s,e.b)&&_(i,e.a))};for(const t of[...p.values()].filter(t=>1===t.targets.size).sort((t,e)=>er(t.a,t.b,r).localeCompare(er(e.a,e.b,r)))){const e=[...t.targets][0],s=u.filter(e=>m(e,t));if(new Set(s.map(t=>t.cm)).size>1)continue;let o=!1;u=u.map(s=>m(s,t)?(o=!0,s.cm===e?s:{...s,cm:e}):s),o||(u=j(u,t.a,t.b,e,i,r))}return u}const ir=t=>{const e=[];for(const s of t||[]){const t=N(s);if(t?.length)for(let s=0;s"string"==typeof t?.id?t.id:"").filter(Boolean),c=new Set(h),d=new Map;for(const t of h){const e=gn("space",t);e.layers>0&&mn("space",e.root)&&fn(d,e.root,t)}const p=new Map,u=new Map,_=new Map,m=new Map;for(const t of r){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const s=new Map;for(const i of Array.isArray(t.rooms)?t.rooms:[]){const t="string"==typeof i?.id?i.id:"";if(!t)continue;const o=gn("room",t);o.layers>0&&mn("room",o.root)&&fn(s,o.root,t),u.has(t)||u.set(t,e),_.has(t)||_.set(t,String(i.name||""));const a="string"==typeof i.area?i.area:"";if(a){const s=m.get(a)||[];s.push({spaceId:e,roomId:t}),m.set(a,s)}}p.set(e,s)}const g=new Set(u.keys()),f=new Map,b=new Map;for(const t of l)"string"==typeof t?.id&&t.id&&(!0===t.removed?b.set(t.id,t):f.set(t.id,t));const v={spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,positionsUnresolved:0,nestedRefsUnresolved:0,deadSpaceIds:[],orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0,removedPositions:[],liveMissingPositions:[],unverifiedPositions:[]},y=new Set,w=t=>c.has(t)?null:(()=>{const e=gn("space",t).root;if(!mn("space",e))return null;const s=d.get(e)||[];return 1===s.length?s[0]:null})(),$=(t,e)=>{const s=gn("room",t).root;if(!mn("room",s))return null;const i=p.get(e)?.get(s)||[];return 1===i.length?i[0]:null},k=t=>{const e=s.effectiveAreaByMarker?.[t]||"",i=e&&m.get(e)||[];return 1===i.length?i[0]:null},x=(t,e,s)=>{if("string"==typeof t.room_id&&t.room_id&&!g.has(t.room_id)){const i=e?$(t.room_id,e):null;i?(t.room_id=i,v.roomRefsRemapped++):s?(t.room_id=s.roomId,v.roomRefsRemapped++):!0!==t.removed&&delete t.room_id}const i=t.vacuum?.segment_map;if(i&&"object"==typeof i&&!Array.isArray(i))for(const t of Object.keys(i)){const s=i[t];if("string"!=typeof s||!s||g.has(s))continue;const o=e?$(s,e):null;o?(i[t]=o,v.roomRefsRemapped++):v.nestedRefsUnresolved++}};for(const t of l){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const s="string"==typeof t.space?t.space:"",i=s&&!c.has(s),a=o[e],n="string"==typeof a?.s?a.s:"",r=n&&!c.has(n),l=!0===t.removed;let h=s&&c.has(s)?s:null,d=null,p=!1;if(i){const i=w(s);i?(t.space=i,h=i,p=!0,v.spaceRefsRemapped++):l||"virtual"===t.binding?l||(delete t.space,h=null,v.markersDetached++):(d=k(e),d?(t.space=d.spaceId,h=d.spaceId,v.spaceRefsRemapped++):(delete t.space,h=null,v.markersDetached++))}l&&!p||x(t,h,d),r&&p&&n===s&&h&&(o[e]={...a,s:h},v.positionsRemapped++,y.add(e))}for(const t of Object.keys(o)){if(y.has(t))continue;const e=o[t],s="string"==typeof e?.s?e.s:"";if(!s||c.has(s))continue;const i=w(s);if(i){if(t.startsWith("rl_")){const s=t.slice(3),a=$(s,i);if(a){const s=`rl_${a}`;_n(o,s)||(o[s]={...e,s:i}),delete o[t],v.roomRefsRemapped++,v.positionsRemapped++;continue}}o[t]={...e,s:i},v.positionsRemapped++}}const M=s.ownerRoster,C=!0===M?.authoritative,S=new Set(M?.deviceIds||[]),P=new Set(M?.entityIds||[]),D=new Set(Array.isArray(i.settings?.known_devices)?i.settings.known_devices.filter(t=>"string"==typeof t):[]),I=(t,e="")=>{const s=String(M?.names?.[t]||e||"").trim();return s&&s!==t?s:""},L=(t,e,s,i="",o)=>({id:t,spaceId:e,kind:s,name:I(t,i),...o?{reason:o}:{}}),T=t=>{"room_label"===t?v.orphanRoomLabelsRemoved++:"group"===t?v.orphanGroupPositionsRemoved++:v.orphanDevicePositionsRemoved++},R=new Set;for(const[t,e]of Object.entries(o)){const i="string"==typeof e?.s?e.s:"";if(!i||c.has(i))continue;let a,n;const r=f.get(t),l=b.get(t);if(r)a=L(t,i,"device",String(r.name||"")),n="live";else if(l)a=L(t,i,"device",String(l.name||"")),n="absent";else if(t.startsWith("rl_")){const e=t.slice(3);a=L(t,i,"room_label",_.get(e)||""),n=g.has(e)?"live":"absent"}else if(t.startsWith("lg_")){const e=t.slice(3);a=L(t,i,"group"),n=P.has(e)?"live":C?"absent":"unverified","unverified"===n&&(a.reason="registry_unavailable")}else S.has(t)?(a=L(t,i,"device"),n="live"):D.has(t)?(a=L(t,i,"device"),n=C?"absent":"unverified","unverified"===n&&(a.reason="registry_unavailable")):(a=L(t,i,"unknown","","unknown_owner"),n="unverified");if("absent"!==n){if("live"===n){if(v.liveMissingPositions.push(a),!0===s.removeLiveMissingPositions){delete o[t],v.liveMissingPositionsRemoved++,T(a.kind),v.removedPositions.push(a);continue}}else v.unverifiedPositions.push(a);v.positionsUnresolved++,R.add(i)}else delete o[t],T(a.kind),v.removedPositions.push(a)}return v.deadSpaceIds=[...R].sort((t,e)=>t.localeCompare(e)),{config:i,layout:o,report:v,changed:JSON.stringify(i)!==a||JSON.stringify(o)!==n}}(t,e,s),n=a.config,r=ot(n,a.layout);J(n),at(a.layout);const l=JSON.stringify(t||{}),h=JSON.stringify(e||{}),c=Number.isInteger(Number(n.model_version))?Number(n.model_version):0,d=(t=>{let e=0,s=0,i=0;for(const s of t.markers||[]){if("ripple"===s.display&&(s.display="icon_ripple",e++),Array.isArray(s.controls)){const t="string"==typeof s.binding&&s.binding.startsWith("entity:")?s.binding.slice(7):"",i=t?s.controls.filter(e=>e!==t):s.controls;JSON.stringify(i)!==JSON.stringify(s.controls)&&(s.controls=i.length?i:null,e++)}const t=s.vacuum;t&&Xn(t,"trail")&&(["never","cleaning","always"].includes(t.trail_mode)||(t.trail_mode=!1===t.trail?"never":"cleaning"),delete t.trail,e++)}for(const o of t.spaces||[]){const t=o.settings;"glow"===t?.fill_mode&&("boolean"!=typeof t.glow_enabled&&(t.glow_enabled=!0),t.fill_mode="none",e++,s++);for(const t of o.rooms||[]){const s=t.settings;"glow"===s?.fill_mode&&("boolean"!=typeof s.glow&&(s.glow=!0),delete s.fill_mode,e++,i++)}if(Xn(o,"segments")&&(delete o.segments,e++),Xn(o,"plan_scale")){const t=Number(o.plan_scale);Number.isFinite(t)&&t>=pt&&t<=ut&&(Xn(o,"plan_scale_x")||(o.plan_scale_x=t),Xn(o,"plan_scale_y")||(o.plan_scale_y=t),delete o.plan_scale,e++)}const a=Number(o.cell_cm);Xn(o,"cell_cm")&&(!Number.isFinite(a)||a<.1||a>1e3)&&(o.cell_cm=Number.isFinite(a)&&a>0?Qn(a,.1,1e3):5,e++);const n=Number(o.cell_cm),r=Number.isFinite(n)&&n>0?n:5;for(const t of o.wall_columns||[])if("circle"===t.shape)Xn(t,"angle")&&(delete t.angle,e++);else if("square"===t.shape&&Xn(t,"angle")){const s=((Number(t.angle)||0)%90+90)%90;t.angle!==s&&(t.angle=s,e++)}for(const t of o.decor||[]){if(Xn(t,"width")){const s=Number(t.width);(Xn(t,"width_cm")||Number.isFinite(s))&&(Xn(t,"width_cm")||(t.width_cm=Number(Qn(s/ct*r,.1,100).toFixed(6))),delete t.width,e++)}if("rect"!==t?.kind&&"ellipse"!==t?.kind||!0!==t.fill||(Xn(t,"fill_color")||(t.fill_color=t.color||"#607d8b",e++),Xn(t,"fill_opacity")||(t.fill_opacity=.25,e++)),"text"!==t?.kind)continue;void 0===t.size_cm?(t.size_cm=Number(Qn(_t*mt(t)/ct*r,.1,2e3).toFixed(6)),delete t.scale,delete t.size,e++):(Xn(t,"scale")||Xn(t,"size"))&&(delete t.scale,delete t.size,e++);let s=String(t.text??"");const i=[...s.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!gt(t[1]));if(!(Xn(t,"entity")||Xn(t,"attr")||Xn(t,"unit")))continue;const o=String(t.unit??"").trim(),a="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,n=i||o?"":ft(t.entity,a);if(i||n){if(n){const e=s.indexOf("{}");s=e>=0?s.slice(0,e)+n+s.slice(e+2):`${s}${s?" ":""}${n}`,t.text=s}delete t.entity,delete t.attr,delete t.unit,e++}}}return{total:e,glowSpaces:s,glowRooms:i}})(n);let p=d.total,u=0,_=0,m=0;if(c<10)for(const t of Array.isArray(n.spaces)?n.spaces:[]){const e=Kn(t);_+=e.drafts,m+=e.segments}const g=(f=n.spaces||[],JSON.parse(JSON.stringify(f)));var f;const b=Wa(n.spaces||[],a.layout);let v=0,y=0,w=0,$="";const k=b.spaces.map(t=>{const e=nt(t);v+=e.report.wallsStraightened,y+=e.report.wallsStraightenSkipped;const s=Number(t?.cell_cm)>0?Number(t.cell_cm):5,i=e.report.maxStraightenShift/z*s;return i>w&&(w=i,$=String(t?.id||"")),e.space}),x=v?Wa(k,b.layout):{...b,spaces:k};n.spaces=x.spaces;const M=v?{...b.report,moved:b.report.moved+x.report.moved,coordsCanonicalized:b.report.coordsCanonicalized+x.report.coordsCanonicalized,maxShift:Math.max(b.report.maxShift,x.report.maxShift),maxShiftCm:Math.max(b.report.maxShiftCm,x.report.maxShiftCm),maxSpace:x.report.maxShiftCm>b.report.maxShiftCm?x.report.maxSpace:b.report.maxSpace,rotated:b.report.rotated+x.report.rotated}:{...b.report};let C=0,S=0,P=0,D=0,I=0,L=0,T=0;for(let t=0;t0===Number(t.cm)),walls:e.walls||[]}),a=tr(e),r=tr(s);if(!a||!r)continue;const l=ir(a.rooms),h=ir(r.rooms),c=.02*ct,d=(e.wall_segments||[]).filter(t=>0===Number(t.cm)).map(t=>({...t,key:Z(t.a,t.b,z),cm:0})),p=new Set(d.map(t=>t.key)),u=rt(e,a.rooms,lt,c);S+=u.length;for(const t of u){const e=[t[0]/lt,t[1]/lt],s=[t[2]/lt,t[3]/lt],i=Z(e,s,z);p.has(i)||(p.add(i),d.push({key:i,a:e,b:s,cm:0}))}const _=d.length,m=ht(d,l,h,z,lt),f=(t,e,s)=>{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;if(!(a>0))return Math.hypot(t[0]-e[0],t[1]-e[1]);const n=Math.max(0,Math.min(1,((t[0]-e[0])*i+(t[1]-e[1])*o)/a));return Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))},b=m.filter(t=>{if(!Array.isArray(t.a)||!Array.isArray(t.b))return!1;const e=t.a.map(t=>t*lt),s=t.b.map(t=>t*lt);return h.some(([t,i])=>f(e,t,i)<=4*c&&f(s,t,i)<=4*c)});P+=Math.max(0,_-b.length);const v=(s.wall_segments||[]).filter(t=>Number(t.cm)>0);s.wall_segments=[...v,...b.map(({key:t,...e})=>e)];const y=b.map(t=>[t.a[0]*lt,t.a[1]*lt,t.b[0]*lt,t.b[1]*lt]),w=Array.isArray(e.walls)?e.walls.length:0;let $=ht(e.walls,l,h,z,lt);$=sr(r.rooms,$,y,z,Number(s.cell_cm)>0?Number(s.cell_cm):5,ct,lt),$=G(r.rooms,$,y,z,Number(s.cell_cm)>0?Number(s.cell_cm):5,ct,lt),$=dt($,s.rooms||[],z,1,y.map(t=>[t[0]/lt,t[1]/lt,t[2]/lt,t[3]/lt])),C+=Math.max(0,w-$.length),$.length?s.walls=$:delete s.walls;const k=Ja(s.partitions||[],{pitch:z,geometry:Ya(s)});k.merged&&(D+=k.merged,s.partitions=k.partitions,Za(s.openings,s.partitions,k.openingMoves,{coordScale:lt,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,gridPitch:ct}));const x=tr(s);if(x){const t=o(s,x,s.walls||[],y,{pitch:z,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,gridPitch:ct,coordScale:lt});t.partitionsReconciled&&(I+=t.partitionsReconciled,L+=t.openingsRehosted,t.partitions.length?s.partitions=t.partitions:delete s.partitions,t.openings.length?s.openings=t.openings:delete s.openings,t.walls.length?s.walls=t.walls:delete s.walls)}JSON.stringify({zero:(s.wall_segments||[]).filter(t=>0===Number(t.cm)),walls:s.walls||[]})!==i&&T++}if(c<=10){const t=function(t){const e=Jn(t);return Yn(t,e.config),{...e,config:t}}(n);u+=t.migratedSegments,_+=t.migratedDrafts,m+=t.migratedDraftSegments}const R=J(n),F=at(x.layout),N=JSON.stringify(R)!==l||JSON.stringify(F)!==h;c<10&&N&&(R.model_version=10);const A=JSON.stringify(R)!==l||JSON.stringify(F)!==h,E=Number.isInteger(Number(R.model_version))?Number(R.model_version):c,O=A?M:{...M,moved:0,coordsCanonicalized:0,maxShift:0,maxShiftCm:0,maxSpace:"",rotated:0},B=A?a.report:{...a.report,spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0};return{config:R,layout:F,report:{...O,modelFrom:c,modelTo:E,migrated:A?p:0,glowSpacesMigrated:A?d.glowSpaces:0,glowRoomsMigrated:A?d.glowRooms:0,canonicalized:A?T:0,wallSegmentsMigrated:A?u:0,roomDraftsMigrated:A?_:0,roomDraftSegmentsMigrated:A?m:0,legacyZeroWallsMigrated:A?S:0,wallsMerged:A?C:0,spansMerged:A?P:0,partitionsMerged:A?D:0,partitionsReconciled:A?I:0,openingsRehosted:A?L:0,wallsStraightened:A?v:0,wallsStraightenSkipped:y,maxStraightenShiftCm:A?w:0,maxStraightenSpace:A?$:"",latticeCoordinatesCanonicalized:A?r.canonicalized:0,latticeCoordinatesFar:A?r.far:0,latticeMaxShift:A?r.maxShift:0,latticeMaxShiftCm:A?r.maxShiftCm:0,latticeSpaces:A?r.spaces:[],...B},changed:A}}async function ar(t,e,s){t._saveConfigDebounced.pending()&&t._saveConfigDebounced.flush(),await t._writeChain;const i=await t.hass.callWS({type:"houseplan/plan/optimize",config:e,layout:s,expected_config_rev:t._cfgRev,expected_layout_rev:t._layoutRev});t._adoption.acceptPairWrite(e,s,i),t._geometryHistory.clear(),t._cancelDeviceDrag(),t._devicePositionHistory.clear(),t._canOptimizeUndo=!0===i.can_undo,t._undoKind=!0===i.can_undo?"optimize":null,t._dirtyPos.clear(),t._sentPos.clear(),t._cfgEpoch++,t._modelCache=null,t._frame=null,t._regSignature="",t._maybeRebuildDevices(),t._cacheSnapshot(),t.requestUpdate()}const nr=Object.freeze({spaces:50,partitions:2e3,openings:500,decor:1e3,columns:500});class rr extends Error{constructor(t){super(t),this.code=t,this.name="SpaceCopyError"}}const lr=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),hr=t=>void 0===t?t:JSON.parse(JSON.stringify(t)),cr=t=>null===t||"object"!=typeof t||Array.isArray(t)?null:t;function dr(t,e=!1){if(void 0===t&&!e)return[];if(!Array.isArray(t))throw new rr("source_invalid");return t.map(t=>{const e=cr(t);if(!e||"string"!=typeof e.id||!e.id)throw new rr("source_invalid");return e})}const pr=t=>Array.isArray(t)&&2===t.length&&t.every(t=>Number.isFinite(t));function ur(t,e,s){const i=String(t??"").trim()||s,o=new Set(e.map(t=>{const e=cr(t);return String(e?.title??"").trim()}));let a=2;for(;o.has(`${i} (${a})`);)a++;return`${i} (${a})`}const _r=["settings","zero_wall_style","cell_cm","view_box","plan_url","plan_aspect","plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"];const mr={source_missing:"space.copy_error_source_missing",source_invalid:"space.copy_error_source_invalid",spaces_limit:"space.copy_error_spaces_limit",partitions_limit:"space.copy_error_partitions_limit",openings_limit:"space.copy_error_openings_limit",decor_limit:"space.copy_error_decor_limit",columns_limit:"space.copy_error_columns_limit",opening_host_missing:"space.copy_error_opening_host",opening_host_unknown:"space.copy_error_opening_host",geometry_unsafe:"space.copy_error_geometry"};let gr=0;function fr(t,e,s){const i=t._spaceDialog;return!(!i?.copy||i.copy.token!==e)&&(t._spaceDialog={...i,busy:s,copy:{...i.copy,busy:s}},!0)}function br(t){t._cfgEpoch++,t._modelCache=null,t._frame=null,t._regSignature="",t._maybeRebuildDevices(),t.requestUpdate()}async function vr(t,e){const s=t._spaceDialog;if(!s?.copy||"edit"!==s.mode||s.busy||s.copy.busy||!s.copy.title.trim()||!s.spaceId||!t._serverCfg)return;const i=++gr,o=s.spaceId,a=s.copy.title.trim();t._spaceDialog={...s,busy:!0,copy:{...s.copy,title:a,busy:!0,token:i}};let n=!1;try{if(t._saveConfigDebounced.pending()&&t._saveConfigDebounced.flush(),await t._writeChain,!fr(t,i,!0)||!t._serverCfg)return;const s=t._cfgRev,r=t._layoutRev,l=yt(t._serverCfg),h=yt(t._layout);let c;try{c=(e.optimize??or)(t._serverCfg,t._layout,e.optimizeReferenceContext())}catch(s){return fr(t,i,!1),void e.showWallModelMigrationBlocked(s)}if(c.changed){const d=t._checkOptimizeGeometry(c.config);if(e.reportPreflightFailure(d,c.config),!d.ok)return fr(t,i,!1),void t._showToast(t._t("space.copy_error_optimize_geometry"));const p=await t._confirmDanger({key:`copy-space:${o}`,kind:"warning",title:t._t("space.copy_optimize_title"),message:t._t("space.copy_optimize_body",{name:a}),objectName:a,confirmLabel:t._t("space.copy_optimize_confirm"),cancelLabel:t._t("btn.cancel"),icon:"mdi:broom"});if(!fr(t,i,p))return;if(!p)return;if(t._cfgRev!==s||t._layoutRev!==r||!t._serverCfg||yt(t._serverCfg)!==l||yt(t._layout)!==h)return fr(t,i,!1),void t._showToast(t._t("space.copy_error_changed"));e.clearGeometryGesture(),await ar(t,c.config,c.layout),n=!0}if(!fr(t,i,!0)||!t._serverCfg)return;const d=t._serverCfg,p=function(t,e,s,i){const o=t.spaces;if(!s.trim())throw new rr("source_invalid");if(o.length>=nr.spaces)throw new rr("spaces_limit");const a=o.findIndex(t=>t.id===e);if(a<0)throw new rr("source_missing");const n=o[a];if(!Array.isArray(n.view_box))throw new rr("source_invalid");const r=dr(n.wall_segments,!0),l=dr(n.partitions),h=dr(n.openings),c=dr(n.decor),d=dr(n.wall_columns);if(r.length+l.length>nr.partitions)throw new rr("partitions_limit");if(h.length>nr.openings)throw new rr("openings_limit");if(c.length>nr.decor)throw new rr("decor_limit");if(d.length>nr.columns)throw new rr("columns_limit");let p=0;const u=t=>`${t}${i}${(p++).toString(36)}`,_=new Map,m=new Map,g=[];for(const t of r){if(_.has(t.id)||!pr(t.a)||!pr(t.b)||"number"!=typeof t.cm||!Number.isFinite(t.cm))throw new rr("source_invalid");const e=u("cw");_.set(t.id,e),g.push({id:e,a:hr(t.a),b:hr(t.b),cm:t.cm})}for(const t of l){if(m.has(t.id)||!pr(t.a)||!pr(t.b)||"number"!=typeof t.cm||!Number.isFinite(t.cm))throw new rr("source_invalid");const e=u("cp");m.set(t.id,e),g.push({id:e,a:hr(t.a),b:hr(t.b),cm:t.cm})}const f=h.map(t=>{const e=cr(t.host);if(!e||"string"!=typeof e.id||"string"!=typeof e.kind)throw new rr("opening_host_missing");const s="wall"===e.kind?_.get(e.id):"partition"===e.kind?m.get(e.id):void 0;if(!s)throw new rr("opening_host_unknown");const i={...hr(t),id:u("co"),host:{...hr(e),kind:"partition",id:s}};return delete i.contact,delete i.lock,i}),b=c.map(t=>({...hr(t),id:u("cd")})),v=d.map(t=>({...hr(t),id:u("cc")})),y=`s${i}`;if(o.some(t=>t.id===y))throw new rr("source_invalid");const w={id:y,title:s.trim(),rooms:[],wall_segments:[],view_box:hr(n.view_box)};for(const t of _r)"view_box"!==t&&lr(n,t)&&(w[t]=hr(n[t]));g.length&&(w.partitions=g),f.length&&(w.openings=f),b.length&&(w.decor=b),v.length&&(w.wall_columns=v);const $=hr(t);return $.spaces.splice(a+1,0,w),{config:$,space:w,sourceIndex:a}}(d,o,a,e.newSeed?.()??function(t=Date.now(),e=Math.random()){const s=Math.floor(16777216*Math.max(0,Math.min(.999999999,e))).toString(36).padStart(5,"0");return`${Math.max(0,Math.floor(t)).toString(36)}${s}`}());let u=!1;try{u=t._checkSpacePhysicalGeometry(p.config,p.space.id).ok}catch{u=!1}if(!u||t._junctionLimitViolations(p.config,p.space.id).length)throw new rr("geometry_unsafe");const _=t._adoption.beginOptimistic(d,p.config);t._adoption.stageLocalConfig(p.config),br(t);try{await e.saveConfigNow(_)}catch(e){throw t._rollbackOptimistic(_)&&br(t),"conflict"!==e?.code&&await t._reloadConfigOnly(!0),e}t._canOptimizeUndo=!1,t._undoKind=null,e.clearGeometryGesture(),t._selId=null,t._physicalSel=null,t._spaceDialog=null,t._commitSpace(p.space.id,!0),e.setMode("plan"),t._tool="draw",t._path=[],t._cursorPt=null,t._activeWallChainId=null,t._activeWallChainPartitionIds=[],t._primeDrawWallField(),t._saveNav(),t.requestUpdate(),t._showToast(t._t("toast.space_copied",{name:a}))}catch(e){"conflict"===e?.code&&await Promise.all([t._reloadConfigOnly(!0),t._reloadLayoutOnly()]),fr(t,i,!1),function(t,e){if(e instanceof rr)return void t._showToast(t._t(mr[e.code]));const s=e?.code;"wall_model_client_outdated"!==s?t._showToast(t._t("toast.error",{err:t._errText(e)})):t._showToast(t._t("toast.wall_model_client_outdated"))}(t,e),n&&t.requestUpdate()}}function yr(){if(this.host._spaceDialog.copy)return function(t,e){const s=t._spaceDialog.copy,i=()=>function(t){const e=t._spaceDialog;!e?.copy||e.busy||e.copy.busy||(t._spaceDialog={...e,copy:void 0})}(t);return p`
    @@ -341,32 +341,32 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${s.busy?"…":t._t("space.copy_create")}
    -
    `}(this.host,()=>{this._saveSpaceCopy()});const t=Fo({host:this.host,idPrefix:"space",help:this._help.bind(this),rangeInput:(t,e,s,i,o,a,n)=>this._rangeInput(t,e,s,i,o,a,n),pickPlanFile:t=>this._pickPlanFile(t),toggleServerPlans:()=>this._toggleServerPlans(),renderServerPlans:t=>this._renderServerPlans(t),save:()=>this._saveSpaceDialog(),skipImport:()=>this._skipImport(),deleteSpace:()=>this._deleteSpace(),copySpace:()=>function(t){const e=t._spaceDialog;if(!e||"edit"!==e.mode||e.busy||!t._serverCfg)return;const s=t._serverCfg.spaces.find(t=>t?.id===e.spaceId);s&&(t._spaceDialog={...e,copy:{title:_r(s.title,t._serverCfg.spaces,t._t("space.copy_fallback")),busy:!1,token:0}})}(this.host)});return p``}(this.host,()=>{this._saveSpaceCopy()});const t=Fo({host:this.host,idPrefix:"space",help:this._help.bind(this),rangeInput:(t,e,s,i,o,a,n)=>this._rangeInput(t,e,s,i,o,a,n),pickPlanFile:t=>this._pickPlanFile(t),toggleServerPlans:()=>this._toggleServerPlans(),renderServerPlans:t=>this._renderServerPlans(t),save:()=>this._saveSpaceDialog(),skipImport:()=>this._skipImport(),deleteSpace:()=>this._deleteSpace(),copySpace:()=>function(t){const e=t._spaceDialog;if(!e||"edit"!==e.mode||e.busy||!t._serverCfg)return;const s=t._serverCfg.spaces.find(t=>t?.id===e.spaceId);s&&(t._spaceDialog={...e,copy:{title:ur(s.title,t._serverCfg.spaces,t._t("space.copy_fallback")),busy:!1,token:0}})}(this.host)});return p` ${t.body}${t.footer} - `}const $r=new Set(["busy"]);function kr(t){return mo(t,$r)}function xr(){bo(this.host);const t=this.host,e=t._settingsDialog,s=t._t.bind(t),i=l(t.hass,t._config?.language),o=(t,e)=>Eo(i,t,e),a=e=>{t._settingsDialog={...t._settingsDialog,...e}},n=function(t){const e=[];return Number.isFinite(t.glowRadius)&&t.glowRadius>0||e.push({field:"gs-glow-radius",message:"gs.error_glow_radius"}),null===t.northDeg||Number.isInteger(t.northDeg)&&t.northDeg>=0&&t.northDeg<=359||e.push({field:"gs-north",message:"gs.error_north"}),e}(e),r=t=>n.find(e=>e.field===t),h=function(t,e){return go(t,"settings",kr(e))}(t,e),c=h&&0===n.length&&!e.busy,_=()=>{!function(t){fo(t,"settings")}(t),t._settingsDialog=null},m=async s=>{if(!h||e.busy)return void _();const i=s.currentTarget;await t._confirmDanger({key:"discard-settings-dialog",kind:"warning",title:o("dialog.discard_title"),message:o("dialog.discard_message"),confirmLabel:o("dialog.discard_confirm"),cancelLabel:o("dialog.discard_keep")})?_():i?.rejectClose?.()},g=(i,a)=>{const n=e.colors[i],r=s(a);return Oo({label:r,hex:n.c,opacity:n.a,opacityLabel:o("gs.opacity_of",{name:r}),onOpacity:t=>this._setFillColor(i,{c:n.c,a:t}),picker:p``}const wr=new Set(["busy"]);function $r(t){return mo(t,wr)}function kr(){bo(this.host);const t=this.host,e=t._settingsDialog,s=t._t.bind(t),i=l(t.hass,t._config?.language),o=(t,e)=>Eo(i,t,e),a=e=>{t._settingsDialog={...t._settingsDialog,...e}},n=function(t){const e=[];return Number.isFinite(t.glowRadius)&&t.glowRadius>0||e.push({field:"gs-glow-radius",message:"gs.error_glow_radius"}),null===t.northDeg||Number.isInteger(t.northDeg)&&t.northDeg>=0&&t.northDeg<=359||e.push({field:"gs-north",message:"gs.error_north"}),e}(e),r=t=>n.find(e=>e.field===t),h=function(t,e){return go(t,"settings",$r(e))}(t,e),c=h&&0===n.length&&!e.busy,u=()=>{!function(t){fo(t,"settings")}(t),t._settingsDialog=null},_=async s=>{if(!h||e.busy)return void u();const i=s.currentTarget;await t._confirmDanger({key:"discard-settings-dialog",kind:"warning",title:o("dialog.discard_title"),message:o("dialog.discard_message"),confirmLabel:o("dialog.discard_confirm"),cancelLabel:o("dialog.discard_keep")})?u():i?.rejectClose?.()},m=(i,a)=>{const n=e.colors[i],r=s(a);return Oo({label:r,hex:n.c,opacity:n.a,opacityLabel:o("gs.opacity_of",{name:r}),onOpacity:t=>this._setFillColor(i,{c:n.c,a:t}),picker:p`{this._setFillColor(i,{c:t.detail.color,a:t.detail.opacity})}}>`})},f=r("gs-glow-radius"),b=r("gs-north"),v=Yo(i,"help")&&Yo(i,"help_aria")?p``:d;return p` + @hp-color-opacity-change=${t=>{this._setFillColor(i,{c:t.detail.color,a:t.detail.opacity})}}>`})},g=r("gs-glow-radius"),f=r("gs-north"),b=Yo(i,"help")&&Yo(i,"help_aria")?p``:d;return p`
    ${ko({id:"display",title:s("gs.card_display"),body:p` ${Co({id:"gs-room-tooltip",icon:"mdi:tooltip-text-outline",title:ra(i,"gs.show_room_tooltip"),caption:o("gs.show_room_tooltip_hint"),checked:e.showRoomTooltip,onChange:t=>a({showRoomTooltip:t})})} ${Co({id:"gs-radar-live",icon:"mdi:radar",title:s("gs.radar_show_live"),caption:o("gs.radar_show_live_hint"),checked:e.radarShowLive,onChange:t=>a({radarShowLive:t})})}`})} - ${ko({id:"zigbee",title:s("gs.card_zigbee"),help:v,body:p`a({zigbeeTopology:t.detail})}>`})} ${ko({id:"fills",title:s("gs.card_fills"),help:this._help("gs.card_fills.help"),body:p` ${Do({title:s("gs.light_group")})} - ${No([g("light_on","gs.light_on"),g("light_off","gs.light_off"),g("light_none","gs.light_none")])} + ${No([m("light_on","gs.light_on"),m("light_off","gs.light_off"),m("light_none","gs.light_none")])} ${Do({title:s("gs.temp_group")})} - ${No([g("temp_cold","gs.temp_cold"),g("temp_ok","gs.temp_ok"),g("temp_hot","gs.temp_hot")])} + ${No([m("temp_cold","gs.temp_cold"),m("temp_ok","gs.temp_ok"),m("temp_hot","gs.temp_hot")])} ${Do({title:s("gs.lqi_group")})} - ${No([g("lqi_low","gs.lqi_low"),g("lqi_high","gs.lqi_high")])}`})} + ${No([m("lqi_low","gs.lqi_low"),m("lqi_high","gs.lqi_high")])}`})} ${ko({id:"glow",title:s("gs.glow_group"),body:p` - ${No([g("glow_base","gs.glow_base"),g("glow_light","gs.glow_light")])} - ${xo({label:s("gs.glow_radius"),htmlFor:"gs-glow-radius",help:this._help("gs.glow_radius.help"),error:f?o(f.message):void 0,control:Io({id:"gs-glow-radius",value:String(e.glowRadius),min:.5,step:.5,invalid:!!f,unit:t._imperial?s("gs.unit_ft"):s("gs.unit_m"),onInput:t=>{const e=u(t);null!=e&&e>0&&a({glowRadius:e})}})})}`})} + ${No([m("glow_base","gs.glow_base"),m("glow_light","gs.glow_light")])} + ${xo({label:s("gs.glow_radius"),htmlFor:"gs-glow-radius",help:this._help("gs.glow_radius.help"),error:g?o(g.message):void 0,control:Io({id:"gs-glow-radius",value:String(e.glowRadius),min:.5,step:.5,invalid:!!g,unit:t._imperial?s("gs.unit_ft"):s("gs.unit_m"),onInput:t=>{const e=xt(t);null!=e&&e>0&&a({glowRadius:e})}})})}`})} ${ko({id:"plan",title:s("gs.card_plan"),body:p` ${Ao({label:s("gs.wall_fill"),picker:So({hex:e.colors.wall_fill.c,opacity:e.colors.wall_fill.a,opacityLabel:s("space.opacity"),onOpacity:t=>this._setFillColor("wall_fill",{c:e.colors.wall_fill.c,a:t}),picker:p` ${this._help("gs.north.help")}
    - ${Io({id:"gs-north",value:null===e.northDeg?"":String(e.northDeg),unit:"°",min:0,max:359,step:1,placeholder:s("gs.north_ph"),invalid:!!b,onInput:t=>{const e=t.trim(),s=""===e?null:Math.round(Number(e));a({northDeg:null!==s&&Number.isFinite(s)?s:null})}})} + ${Io({id:"gs-north",value:null===e.northDeg?"":String(e.northDeg),unit:"°",min:0,max:359,step:1,placeholder:s("gs.north_ph"),invalid:!!f,onInput:t=>{const e=t.trim(),s=""===e?null:Math.round(Number(e));a({northDeg:null!==s&&Number.isFinite(s)?s:null})}})} ${null!==e.northDeg?wo(s("gs.north_clear"),()=>a({northDeg:null})):d}
    ${t._renderCompass()}
    - ${b?p``:d} + ${f?p``:d} ${Co({id:"gs-sun-rays",icon:"mdi:weather-sunny",title:s("gs.sun_rays"),caption:o("gs.sun_rays_hint"),checked:e.sunRays,onChange:t=>a({sunRays:t})})} - ${y=e.sunRayOrigin,w=t=>s(t),$=t=>a({sunRayOrigin:t}),xo({label:w("gs.sun_ray_origin"),control:Mo({name:"gs-sun-ray-origin",value:y,ariaLabel:w("gs.sun_ray_origin"),options:[{value:"inner",label:w("gs.sun_ray_origin.inner")},{value:"outer",label:w("gs.sun_ray_origin.outer")}],onChange:t=>$("outer"===t?"outer":"inner")})})}`})} + ${v=e.sunRayOrigin,y=t=>s(t),w=t=>a({sunRayOrigin:t}),xo({label:y("gs.sun_ray_origin"),control:Mo({name:"gs-sun-ray-origin",value:v,ariaLabel:y("gs.sun_ray_origin"),options:[{value:"inner",label:y("gs.sun_ray_origin.inner")},{value:"outer",label:y("gs.sun_ray_origin.outer")}],onChange:t=>w("outer"===t?"outer":"inner")})})}`})} ${ko({id:"data",title:s("gs.card_data"),body:p` ${t._canEdit?p` ${Do({title:s("gs.backup_group"),help:this._help("gs.backup_group.help")})} @@ -422,61 +422,61 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc -
    `;var y,w,$}function Mr(t){return mo({name:t._nameSel,area:t._areaSel,fill:t._roomFill,customFill:t._roomCustomFill,tempMin:t._roomTempMin,tempMax:t._roomTempMax,tempSrc:t._roomTempSrc,humSrc:t._roomHumSrc,nameScale:t._roomNameScale,labelScale:t._roomLabelScale})}function Cr(t){fo(t,"room")}function Sr(t,e){const s=t.host,i="temp"===e?s._roomTempSrc:s._roomHumSrc,o=t=>{"temp"===e?s._roomTempSrc=t:s._roomHumSrc=t,s.requestUpdate()},a=s._roomSrcOpen===e,n=s._t("temp"===e?"room.temp_src_label":"room.hum_src_label");return p`${Do({title:n})} +
    `;var v,y,w}function xr(t){return mo({name:t._nameSel,area:t._areaSel,fill:t._roomFill,customFill:t._roomCustomFill,tempMin:t._roomTempMin,tempMax:t._roomTempMax,tempSrc:t._roomTempSrc,humSrc:t._roomHumSrc,nameScale:t._roomNameScale,labelScale:t._roomLabelScale})}function Mr(t){fo(t,"room")}function Cr(t,e){const s=t.host,i="temp"===e?s._roomTempSrc:s._roomHumSrc,o=t=>{"temp"===e?s._roomTempSrc=t:s._roomHumSrc=t,s.requestUpdate()},a=s._roomSrcOpen===e,n=s._t("temp"===e?"room.temp_src_label":"room.hum_src_label");return p`${Do({title:n})} ${Mo({name:`rsrc-${e}`,value:i?"pick":"avg",ariaLabel:n,options:[{value:"avg",label:s._t("room.src_average")},{value:"pick",label:s._t("room.src_pick")}],onChange:t=>{if("avg"===t)return o(""),void(s._roomSrcOpen=null);s._roomSrcOpen=e,s._roomSrcFilter="",s.requestUpdate()}})} - ${i||a?$o({id:`room-${e}-source`,open:a,current:i?{label:t._roomSrcLabel(i),sub:i}:null,placeholder:s._t("room.src_ph"),ariaLabel:n,filter:s._roomSrcFilter,filterPlaceholder:s._t("marker.search_ph"),candidates:a?t._roomSrcCandidates():[],selected:i,emptyText:s._t("marker.nothing_found"),onToggle:()=>{s._roomSrcOpen=a?null:e,s._roomSrcFilter="",s.requestUpdate()},onFilter:t=>{s._roomSrcFilter=t,s.requestUpdate()},onPick:t=>{o(t),s._roomSrcOpen=null}}):d}`}function Pr(){bo(this.host);const t=this.host,e=t._t.bind(t),s=l(t.hass,t._config?.language),i=(t,e)=>Eo(s,t,e),o=!!t._roomEditId,a=o?null:t._wallFaceBatch,n=a&&a.candidates.length>1?e("room.queue_progress",{current:a.index+1,total:a.candidates.length}):"",r=m(t._curSpaceCfg),h=""===t._roomFill,c=t._roomFill||r.fill,_=t._roomCustomFill||r.customFill,g=Mt(t._roomTempMin,t._roomTempMax).valid,f=function(t){const e=[];return!t._roomEditId&&t._areaSel||t._nameSel.trim()||e.push({field:"room-name",message:"room.error_name"}),Mt(t._roomTempMin,t._roomTempMax).valid||e.push({field:"room-temp-min",message:"room.error_temp_range"}),e}(t),b=t=>f.find(e=>e.field===t),v=function(t){return go(t,"room",Mr(t))}(t),y=0===f.length&&g&&(!o||v),w=[...t._freeAreas];if(o&&t._areaSel&&!w.some(e=>e.area_id===t._areaSel)){const e=t.hass.areas[t._areaSel];e&&w.unshift(e)}const $=()=>{Cr(t),this._roomDialogCancel()},k=async e=>{if(!o||!v)return void $();const s=e.currentTarget;await t._confirmDanger({key:"discard-room-dialog",kind:"warning",title:i("dialog.discard_title"),message:i("dialog.discard_message"),objectName:t._nameSel.trim()||void 0,confirmLabel:i("dialog.discard_confirm"),cancelLabel:i("dialog.discard_keep")})?$():s?.rejectClose?.()},x=b("room-name"),M=b("room-temp-min"),C=e=>{t._roomFill=e,"custom"!==e&&(t._roomCustomFill=null),t.requestUpdate()},S=t=>Math.round(100*t),P=t._roomCustomFill?e("room.custom_fill_own"):e("room.custom_fill_space"),D=[["name","room.name_scale",t._roomNameScale,e=>{t._roomNameScale=e}],["label","room.label_scale",t._roomLabelScale,e=>{t._roomLabelScale=e}]];return p`{s._roomSrcOpen=a?null:e,s._roomSrcFilter="",s.requestUpdate()},onFilter:t=>{s._roomSrcFilter=t,s.requestUpdate()},onPick:t=>{o(t),s._roomSrcOpen=null}}):d}`}function Sr(){bo(this.host);const t=this.host,e=t._t.bind(t),s=l(t.hass,t._config?.language),i=(t,e)=>Eo(s,t,e),o=!!t._roomEditId,a=o?null:t._wallFaceBatch,n=a&&a.candidates.length>1?e("room.queue_progress",{current:a.index+1,total:a.candidates.length}):"",r=_(t._curSpaceCfg),h=""===t._roomFill,c=t._roomFill||r.fill,u=t._roomCustomFill||r.customFill,m=Mt(t._roomTempMin,t._roomTempMax).valid,g=function(t){const e=[];return!t._roomEditId&&t._areaSel||t._nameSel.trim()||e.push({field:"room-name",message:"room.error_name"}),Mt(t._roomTempMin,t._roomTempMax).valid||e.push({field:"room-temp-min",message:"room.error_temp_range"}),e}(t),f=t=>g.find(e=>e.field===t),b=function(t){return go(t,"room",xr(t))}(t),v=0===g.length&&m&&(!o||b),y=[...t._freeAreas];if(o&&t._areaSel&&!y.some(e=>e.area_id===t._areaSel)){const e=t.hass.areas[t._areaSel];e&&y.unshift(e)}const w=()=>{Mr(t),this._roomDialogCancel()},$=async e=>{if(!o||!b)return void w();const s=e.currentTarget;await t._confirmDanger({key:"discard-room-dialog",kind:"warning",title:i("dialog.discard_title"),message:i("dialog.discard_message"),objectName:t._nameSel.trim()||void 0,confirmLabel:i("dialog.discard_confirm"),cancelLabel:i("dialog.discard_keep")})?w():s?.rejectClose?.()},k=f("room-name"),x=f("room-temp-min"),M=e=>{t._roomFill=e,"custom"!==e&&(t._roomCustomFill=null),t.requestUpdate()},C=t=>Math.round(100*t),S=t._roomCustomFill?e("room.custom_fill_own"):e("room.custom_fill_space"),P=[["name","room.name_scale",t._roomNameScale,e=>{t._roomNameScale=e}],["label","room.label_scale",t._roomLabelScale,e=>{t._roomLabelScale=e}]];return p` + icon=${o?"mdi:cog-outline":"mdi:floor-plan"} @hp-close=${$}>
    ${n?p`

    ${n}

    `:d} - ${ko({id:"basics",title:e("room.group_basics"),body:To([xo({label:e("room.name_label"),htmlFor:"room-name",error:x?i(x.message):void 0,control:p`{t._nameSel=e.target.value,t.requestUpdate()}} />`}),xo({label:e("room.area_label"),htmlFor:"room-area",help:this._help("room.group_basics.help"),control:p``})])})} ${ko({id:"fill",title:e("room.group_fill"),help:this._help("room.group_fill.help"),body:p` - ${Co({id:"room-fill-inherit",icon:"mdi:layers-outline",title:e("fill.inherit"),caption:i("room.fill_inherit_hint"),checked:h,onChange:t=>C(t?"":Ct.includes(r.fill)?r.fill:"custom")})} - ${h?p`

    ${i("room.fill_following",{mode:e(`fill.${r.fill}`)})}

    `:xo({label:i("room.fill_mode_label"),control:Mo({name:"rfill",value:t._roomFill,ariaLabel:e("room.fill_label"),options:Ct.map(t=>({value:t,label:"lqi"===t?i("room.fill_seg_lqi"):"custom"===t?i("room.fill_seg_custom"):e(`fill.${t}`)})),onChange:t=>C(t)})})} - ${"custom"===t._roomFill?Ao({label:P,picker:So({hex:_.c,opacity:_.a,opacityLabel:e("space.opacity"),onOpacity:e=>{t._roomCustomFill={c:_.c,a:e},t.requestUpdate()},resetLabel:t._roomCustomFill?e("btn.reset"):void 0,onReset:()=>{t._roomCustomFill=null,t.requestUpdate()},picker:p`M(t?"":Ct.includes(r.fill)?r.fill:"custom")})} + ${h?p`

    ${i("room.fill_following",{mode:e(`fill.${r.fill}`)})}

    `:xo({label:i("room.fill_mode_label"),control:Mo({name:"rfill",value:t._roomFill,ariaLabel:e("room.fill_label"),options:Ct.map(t=>({value:t,label:"lqi"===t?i("room.fill_seg_lqi"):"custom"===t?i("room.fill_seg_custom"):e(`fill.${t}`)})),onChange:t=>M(t)})})} + ${"custom"===t._roomFill?Ao({label:S,picker:So({hex:u.c,opacity:u.a,opacityLabel:e("space.opacity"),onOpacity:e=>{t._roomCustomFill={c:u.c,a:e},t.requestUpdate()},resetLabel:t._roomCustomFill?e("btn.reset"):void 0,onReset:()=>{t._roomCustomFill=null,t.requestUpdate()},picker:p`{t._roomCustomFill={c:e.detail.color,a:e.detail.opacity}}}>`})}):d} ${"temp"===c?p`
    ${e("room.temp_range_label")}${this._help("room.temp_range.help")} - ${To([xo({label:i("room.temp_min_label"),htmlFor:"room-temp-min",control:Io({id:"room-temp-min",wide:!0,unit:"°C",step:.5,value:t._roomTempMin,placeholder:String(r.tempMin),ariaLabel:e("room.temp_range_min"),invalid:""!==t._roomTempMin.trim()&&null===u(t._roomTempMin),onInput:e=>{t._roomTempMin=e,t.requestUpdate()}})}),xo({label:i("room.temp_max_label"),htmlFor:"room-temp-max",control:Io({id:"room-temp-max",wide:!0,unit:"°C",step:.5,value:t._roomTempMax,placeholder:String(r.tempMax),ariaLabel:e("room.temp_range_max"),invalid:""!==t._roomTempMax.trim()&&null===u(t._roomTempMax),onInput:e=>{t._roomTempMax=e,t.requestUpdate()}})})])} - ${M?p``:d} + ${To([xo({label:i("room.temp_min_label"),htmlFor:"room-temp-min",control:Io({id:"room-temp-min",wide:!0,unit:"°C",step:.5,value:t._roomTempMin,placeholder:String(r.tempMin),ariaLabel:e("room.temp_range_min"),invalid:""!==t._roomTempMin.trim()&&null===xt(t._roomTempMin),onInput:e=>{t._roomTempMin=e,t.requestUpdate()}})}),xo({label:i("room.temp_max_label"),htmlFor:"room-temp-max",control:Io({id:"room-temp-max",wide:!0,unit:"°C",step:.5,value:t._roomTempMax,placeholder:String(r.tempMax),ariaLabel:e("room.temp_range_max"),invalid:""!==t._roomTempMax.trim()&&null===xt(t._roomTempMax),onInput:e=>{t._roomTempMax=e,t.requestUpdate()}})})])} + ${x?p``:d} ${t._roomTempMin.trim()||t._roomTempMax.trim()?wo(e("room.temp_range_reset"),()=>{t._roomTempMin="",t._roomTempMax="",t.requestUpdate()}):d}
    `:d}`})} - ${ko({id:"sources",title:e("room.group_sources"),help:this._help("room.group_sources.help"),body:p`${Sr(this,"temp")}${Sr(this,"hum")}`})} + ${ko({id:"sources",title:e("room.group_sources"),help:this._help("room.group_sources.help"),body:p`${Cr(this,"temp")}${Cr(this,"hum")}`})} ${ko({id:"sizes",title:e("room.sizes_section"),help:this._help("room.sizes_section.help"),body:p` - ${D.map(([s,o,a,n])=>p`
    + ${P.map(([s,o,a,n])=>p`
    - ${wo(i("btn.reset_100"),()=>{n(1),t.requestUpdate()},{disabled:100===S(a)})} + ${wo(i("btn.reset_100"),()=>{n(1),t.requestUpdate()},{disabled:100===C(a)})}
    - ${Po({id:`room-${s}-scale`,min:50,max:300,value:S(a),unit:"%",ariaLabel:e(o),slider:this._rangeInput(50,300,5,S(a),e=>{n(e/100),t.requestUpdate()},!1,e(o)),onInput:e=>{n(e/100),t.requestUpdate()}})} + ${Po({id:`room-${s}-scale`,min:50,max:300,value:C(a),unit:"%",ariaLabel:e(o),slider:this._rangeInput(50,300,5,C(a),e=>{n(e/100),t.requestUpdate()},!1,e(o)),onInput:e=>{n(e/100),t.requestUpdate()}})} ${Ro("50%","300%")}
    `)} -

    ${i("room.sizes_hint",{v:String(S(r.cardFontScale))})}

    +

    ${i("room.sizes_hint",{v:String(C(r.cardFontScale))})}

    ${t._renderCardPreview(r.cardFontScale,t._roomNameScale,t._roomLabelScale)}
    `})}
    `} - ${zo(f.length?{action:wo(i("dialog.review_fields",{n:String(f.length)}),()=>{const e=f[0];if(!e)return;const s=t.renderRoot.querySelector(`#${e.field}`);s?.scrollIntoView({block:"center"}),s?.focus()})}:{text:o&&v?i("dialog.unsaved"):""})} + ${zo(g.length?{action:wo(i("dialog.review_fields",{n:String(g.length)}),()=>{const e=g[0];if(!e)return;const s=t.renderRoot.querySelector(`#${e.field}`);s?.scrollIntoView({block:"center"}),s?.focus()})}:{text:o&&b?i("dialog.unsaved"):""})}
    - - ${o?p` + ${o?p``:p``:p``}
    -
    `}const Dr=new WeakMap;function Ir(t,e,s){let i=Dr.get(t);i||(i=new Map,Dr.set(t,i));const o=i.get(e);if(o)return void(o.run=s);const a={run:s};i.set(e,a),queueMicrotask(()=>{i.get(e)===a&&(i.delete(e),a.run())})}function Lr(t,e){const s=Dr.get(t),i=s?.get(e);i&&(s.delete(e),i.run())}function Tr(t,e){const s=Dr.get(t);if(!s)return;const i=e?[...s].filter(([t])=>t===e):[...s];for(const[t]of i)s.delete(t);s.size||Dr.delete(t)}const Rr=new WeakMap,zr=new Set(["_cursorPt","_opMeasure","_physicalDrag","_physicalRotate","_decorDraft","_dtBox","_dtDrag","_bdDrag","_furnPreviewInput","_layout"]),Fr=new Set(["_cursorPt","_opMeasure","_furnPreviewInput"]),Nr=new Set(["_physicalDrag","_physicalRotate","_decorDraft","_dtDrag","_bdDrag"]),Ar=t=>{let e=Rr.get(t);return e||(e={raf:0,requestedRevision:0,paintedRevision:0,waiters:[],hidden:[],transparent:[],dimmed:[]},Rr.set(t,e)),e},Er=(t,e)=>{t.paintedRevision=Math.max(t.paintedRevision,e);const s=t.waiters.filter(e=>e.revision<=t.paintedRevision);t.waiters=t.waiters.filter(e=>e.revision>t.paintedRevision);for(const t of s)t.resolve()},Or=t=>!!("view"!==t._mode&&(t._deviceDrag||t._physicalDrag||t._physicalRotate||t._decorDraft||t._decorMove||t._dtDrag||t._bdDrag||t._opDrag||t._resize?.dragging));function Br(t,e,s){const i=t;if(!i?.isConnected||"view"===i._mode)return!1;const o=void 0!==e&&zr.has(e);if("_layout"===e&&!i._deviceDrag)return!1;if("_dtBox"===e&&!i._dtDrag)return!1;if(void 0!==e&&Nr.has(e)&&null==s&&null!=i[e]&&Or(i))return!1;if(void 0!==e&&Nr.has(e)&&null==i[e])return!1;if(void 0!==e&&Fr.has(e)&&null==i[e])return!1;return!!(o&&(Fr.has(e)||Or(i))||void 0===e&&Or(i))&&(function(t){const e=Ar(t);if(e.requestedRevision++,e.raf||"function"!=typeof requestAnimationFrame)return;e.raf=requestAnimationFrame(()=>{e.raf=0;const s=e.requestedRevision;!function(t){const e=t,s=e.renderRoot;if(!s)return;const i=Ar(e);jr(i),Ur(e,s);const o=s.querySelector("[data-hp-live-editor]");if(!o)return;if(Wr(i,s,".hp-editor-only-layer:not(.hp-plan-snap-layer)"),"plan"===e._mode)e._opDrag&&Hr(i,s,".wallbodies"),e._resize?.dragging&&(Jr(i,s,".wallbodies"),Wr(i,s,".resize-layer"),Vr(i,s,e._resize.plan?.movingOpeningIds||[])),e._opDrag&&Wr(i,s,".openinglayer");else if("decor"===e._mode){const t=e._dtDrag?.id||e._decorMove?.id;t&&Kr(i,s,t),Wr(i,s,".dtframe, .backdropframe")}St(qr(e),o);const a=s.querySelector("[data-hp-live-editor-html]");if(a){const t=e._viewOr(e._baseVb());St(e._renderLiveEditorMeasurements(t),a)}e._liveEditorPaintCount=(e._liveEditorPaintCount||0)+1}(t),Er(e,s)})}(i),!0)}const Hr=(t,e,s)=>{for(const i of e.querySelectorAll(s))i.closest("[data-hp-live-editor]")||"hidden"!==i.style.visibility&&(i.style.visibility="hidden",t.hidden.push(i))},Wr=(t,e,s)=>{for(const i of e.querySelectorAll(s))i.closest("[data-hp-live-editor]")||"0"!==i.style.opacity&&(i.style.opacity="0",t.transparent.push(i))},jr=t=>{for(const e of t.hidden)e.style.removeProperty("visibility");t.hidden.length=0;for(const e of t.transparent)e.style.removeProperty("opacity");t.transparent.length=0;for(const e of t.dimmed)e.style.removeProperty("opacity");t.dimmed.length=0},Gr=(t,e,s=[])=>{if("iso"===t._renderProjection)return Pt``;const i=t._spaceModel();if(!i)return Pt``;const o=new Set(s),a=(i.rooms||[]).filter(t=>!!t.id&&o.has(t.id)).flatMap(t=>{const e=t.poly||[];return e.map((t,s)=>[t,e[(s+1)%e.length]])}),n=(t,e)=>{const[s,i]=e,o=i[0]-s[0],a=i[1]-s[1],n=o*o+a*a;if(!(n>0))return!1;const r=((t[0]-s[0])*o+(t[1]-s[1])*a)/n,l=Math.max(0,Math.min(1,r));return Math.hypot(t[0]-s[0]-o*l,t[1]-s[1]-a*l)<1e-4},r=[...t._spaceWalls.filter(t=>{const e=(t.a||[]).map(t=>t*ht),s=(t.b||[]).map(t=>t*ht);return a.some(t=>n(e,t)&&n(s,t))}).map((e,s)=>((e,s,i,o)=>{const a=Math.hypot(s[0]-e[0],s[1]-e[1]);if(!(a>1e-9&&i>0))return null;const n=J(i,t._cellCm,t._gridPitch)/2,r=-(s[1]-e[1])/a*n,l=(s[0]-e[0])/a*n;return{key:o,kind:"outer",cm:i,a:e,b:s,depthUnits:2*n,quad:[[e[0]+r,e[1]+l],[s[0]+r,s[1]+l],[s[0]-r,s[1]-l],[e[0]-r,e[1]-l]]}})((e.a||[]).map(t=>t*ht),(e.b||[]).map(t=>t*ht),e.cm,e.key||`wall-${s}`))].filter(t=>!!t),l=t._openingsR.map(t=>({x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),h=r.map(t=>Dt(t,l)).filter(Boolean);if(!h.length)return Pt``;const c=Math.max(...r.map(t=>t.depthUnits),0),d=t._viewOr(t._baseVb()),p=t._stageEl?.clientWidth&&d.w?t._stageEl.clientWidth/d.w:1,u=It(c,p)||Lt(Tt(t._cellCm),p),_=e?.color||"#607d8b",m=t._fillColors.wall_fill,g=h.join(" ");return Pt``}const Pr=new WeakMap;function Dr(t,e,s){let i=Pr.get(t);i||(i=new Map,Pr.set(t,i));const o=i.get(e);if(o)return void(o.run=s);const a={run:s};i.set(e,a),queueMicrotask(()=>{i.get(e)===a&&(i.delete(e),a.run())})}function Ir(t,e){const s=Pr.get(t),i=s?.get(e);i&&(s.delete(e),i.run())}function Lr(t,e){const s=Pr.get(t);if(!s)return;const i=e?[...s].filter(([t])=>t===e):[...s];for(const[t]of i)s.delete(t);s.size||Pr.delete(t)}const Tr=new WeakMap,Rr=new Set(["_cursorPt","_opMeasure","_physicalDrag","_physicalRotate","_decorDraft","_dtBox","_dtDrag","_bdDrag","_furnPreviewInput","_layout"]),zr=new Set(["_cursorPt","_opMeasure","_furnPreviewInput"]),Fr=new Set(["_physicalDrag","_physicalRotate","_decorDraft","_dtDrag","_bdDrag"]),Nr=t=>{let e=Tr.get(t);return e||(e={raf:0,requestedRevision:0,paintedRevision:0,waiters:[],hidden:[],transparent:[],dimmed:[]},Tr.set(t,e)),e},Ar=(t,e)=>{t.paintedRevision=Math.max(t.paintedRevision,e);const s=t.waiters.filter(e=>e.revision<=t.paintedRevision);t.waiters=t.waiters.filter(e=>e.revision>t.paintedRevision);for(const t of s)t.resolve()},Er=t=>!!("view"!==t._mode&&(t._deviceDrag||t._physicalDrag||t._physicalRotate||t._decorDraft||t._decorMove||t._dtDrag||t._bdDrag||t._opDrag||t._resize?.dragging));function Or(t,e,s){const i=t;if(!i?.isConnected||"view"===i._mode)return!1;const o=void 0!==e&&Rr.has(e);if("_layout"===e&&!i._deviceDrag)return!1;if("_dtBox"===e&&!i._dtDrag)return!1;if(void 0!==e&&Fr.has(e)&&null==s&&null!=i[e]&&Er(i))return!1;if(void 0!==e&&Fr.has(e)&&null==i[e])return!1;if(void 0!==e&&zr.has(e)&&null==i[e])return!1;return!!(o&&(zr.has(e)||Er(i))||void 0===e&&Er(i))&&(function(t){const e=Nr(t);if(e.requestedRevision++,e.raf||"function"!=typeof requestAnimationFrame)return;e.raf=requestAnimationFrame(()=>{e.raf=0;const s=e.requestedRevision;!function(t){const e=t,s=e.renderRoot;if(!s)return;const i=Nr(e);Wr(i),qr(e,s);const o=s.querySelector("[data-hp-live-editor]");if(!o)return;if(Hr(i,s,".hp-editor-only-layer:not(.hp-plan-snap-layer)"),"plan"===e._mode)e._opDrag&&Br(i,s,".wallbodies"),e._resize?.dragging&&(Vr(i,s,".wallbodies"),Hr(i,s,".resize-layer"),Kr(i,s,e._resize.plan?.movingOpeningIds||[])),e._opDrag&&Hr(i,s,".openinglayer");else if("decor"===e._mode){const t=e._dtDrag?.id||e._decorMove?.id;t&&Ur(i,s,t),Hr(i,s,".dtframe, .backdropframe")}St(Gr(e),o);const a=s.querySelector("[data-hp-live-editor-html]");if(a){const t=e._viewOr(e._baseVb());St(e._renderLiveEditorMeasurements(t),a)}e._liveEditorPaintCount=(e._liveEditorPaintCount||0)+1}(t),Ar(e,s)})}(i),!0)}const Br=(t,e,s)=>{for(const i of e.querySelectorAll(s))i.closest("[data-hp-live-editor]")||"hidden"!==i.style.visibility&&(i.style.visibility="hidden",t.hidden.push(i))},Hr=(t,e,s)=>{for(const i of e.querySelectorAll(s))i.closest("[data-hp-live-editor]")||"0"!==i.style.opacity&&(i.style.opacity="0",t.transparent.push(i))},Wr=t=>{for(const e of t.hidden)e.style.removeProperty("visibility");t.hidden.length=0;for(const e of t.transparent)e.style.removeProperty("opacity");t.transparent.length=0;for(const e of t.dimmed)e.style.removeProperty("opacity");t.dimmed.length=0},jr=(t,e,s=[])=>{if("iso"===t._renderProjection)return Pt``;const i=t._spaceModel();if(!i)return Pt``;const o=new Set(s),a=(i.rooms||[]).filter(t=>!!t.id&&o.has(t.id)).flatMap(t=>{const e=t.poly||[];return e.map((t,s)=>[t,e[(s+1)%e.length]])}),n=(t,e)=>{const[s,i]=e,o=i[0]-s[0],a=i[1]-s[1],n=o*o+a*a;if(!(n>0))return!1;const r=((t[0]-s[0])*o+(t[1]-s[1])*a)/n,l=Math.max(0,Math.min(1,r));return Math.hypot(t[0]-s[0]-o*l,t[1]-s[1]-a*l)<1e-4},r=[...t._spaceWalls.filter(t=>{const e=(t.a||[]).map(t=>t*lt),s=(t.b||[]).map(t=>t*lt);return a.some(t=>n(e,t)&&n(s,t))}).map((e,s)=>((e,s,i,o)=>{const a=Math.hypot(s[0]-e[0],s[1]-e[1]);if(!(a>1e-9&&i>0))return null;const n=V(i,t._cellCm,t._gridPitch)/2,r=-(s[1]-e[1])/a*n,l=(s[0]-e[0])/a*n;return{key:o,kind:"outer",cm:i,a:e,b:s,depthUnits:2*n,quad:[[e[0]+r,e[1]+l],[s[0]+r,s[1]+l],[s[0]-r,s[1]-l],[e[0]-r,e[1]-l]]}})((e.a||[]).map(t=>t*lt),(e.b||[]).map(t=>t*lt),e.cm,e.key||`wall-${s}`))].filter(t=>!!t),l=t._openingsR.map(t=>({x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),h=r.map(t=>Dt(t,l)).filter(Boolean);if(!h.length)return Pt``;const c=Math.max(...r.map(t=>t.depthUnits),0),d=t._viewOr(t._baseVb()),p=t._stageEl?.clientWidth&&d.w?t._stageEl.clientWidth/d.w:1,u=It(c,p)||Lt(Tt(t._cellCm),p),_=e?.color||"#607d8b",m=t._fillColors.wall_fill,g=h.join(" ");return Pt` @@ -507,8 +507,8 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc data-id="preview" data-kind="preview" d=${g} fill=${u?"none":"url(#hp-wall-hatch)"} fill-rule="nonzero" stroke=${_} stroke-width=${Rt(.6,t._cellCm)}> - `},qr=t=>{if("plan"===t._mode)return(t=>{const e=t._baseVb(),s=t._viewOr(e),i=t._opMeasureView;if(t._resize?.dragging){const e=t._spaceDisplayForRender(),i=t._resize.plan;return Pt``},Gr=t=>{if("plan"===t._mode)return(t=>{const e=t._baseVb(),s=t._viewOr(e),i=t._opMeasureView;if(t._resize?.dragging){const e=t._spaceDisplayForRender(),i=t._resize.plan;return Pt``}return Pt``},Ur=(t,e)=>{const s=t._deviceDrag;if(!s)return;const i=t._devices.find(t=>t.id===s.id),o=[...e.querySelectorAll('[data-hp="device"]')].find(t=>t.dataset.id===s.id);if(!i||!o)return;const a=t._livePos(i),n=t._scenePoint([a.x,a.y]),r=t._viewOr(t._baseVb());o.style.left=(n[0]-r.x)/r.w*100+"%",o.style.top=(n[1]-r.y)/r.h*100+"%"},Kr=(t,e,s)=>{for(const i of e.querySelectorAll('.decorlayer [data-hp="decor"]'))i.closest("[data-hp-live-editor]")||i.dataset.id!==s||"0"!==i.style.opacity&&(i.style.opacity="0",t.transparent.push(i))},Vr=(t,e,s)=>{const i=new Set(s);for(const s of e.querySelectorAll('.openinglayer [data-hp="opening"]'))!s.closest("[data-hp-live-editor]")&&i.has(s.dataset.id||"")&&(s.style.opacity="0",t.transparent.push(s))},Jr=(t,e,s)=>{for(const i of e.querySelectorAll(s))i.closest("[data-hp-live-editor]")||(i.style.opacity="0.35",t.dimmed.push(i))};const Zr=(t,e,s)=>Math.min(s,Math.max(e,Number.isFinite(t)?t:e));function Yr(t){return Number.isFinite(t)?(t%360+360)%360:0}function Xr(t){if("string"!=typeof t)return null;const e=t.trim().replace(/^#/,""),s=/^[0-9a-fA-F]{3}$/.test(e)?e.split("").map(t=>`${t}${t}`).join(""):e;return/^[0-9a-fA-F]{6}$/.test(s)?`#${s.toLowerCase()}`:null}function Qr(t){const e=Xr(t);return e?{r:Number.parseInt(e.slice(1,3),16),g:Number.parseInt(e.slice(3,5),16),b:Number.parseInt(e.slice(5,7),16)}:null}function tl(t){const e=Zr(t.r,0,255)/255,s=Zr(t.g,0,255)/255,i=Zr(t.b,0,255)/255,o=Math.max(e,s,i),a=o-Math.min(e,s,i);let n=0;return a>0&&(n=o===e?(s-i)/a%6*60:o===s?60*((i-e)/a+2):60*((e-s)/a+4)),{h:Yr(n),s:0===o?0:a/o*100,v:100*o}}function el(t){return function(t){const e=t=>Math.round(Zr(t,0,255)).toString(16).padStart(2,"0");return`#${e(t.r)}${e(t.g)}${e(t.b)}`}(function(t){const e=Yr(t.h),s=Zr(t.s,0,100)/100,i=Zr(t.v,0,100)/100,o=i*s,a=o*(1-Math.abs(e/60%2-1)),n=i-o;let r;return r=e<60?[o,a,0]:e<120?[a,o,0]:e<180?[0,o,a]:e<240?[0,a,o]:e<300?[a,0,o]:[o,0,a],{r:Math.round(255*(r[0]+n)),g:Math.round(255*(r[1]+n)),b:Math.round(255*(r[2]+n))}}(t))}const sl={title:"Color picker",hue:"Hue",saturation:"Saturation",value:"Brightness",hex:"Hex color",invalidHex:"Enter a 3- or 6-digit hex color",confirm:"OK"};class il extends Ft{constructor(){super(...arguments),this.label="",this.opacityLabel="Opacity",this.color="#607d8b",this.opacity=1,this.disabled=!1,this.showOpacity=!0,this.hideLabel=!1,this.pickerLabels=sl,this._open=!1,this._pickerRaf=0,this._emitRaf=0,this._forceFallback=!1,this._overlayDispose=null,this._hue=0,this._saturation=0,this._value=0,this._hexDraft="#607d8b",this._hexInvalid=!1,this._hexNeedsValidInput=!1,this._lastValidColor="#607d8b",this._activePointerId=null,this._outsidePointerDown=t=>{if(!this._open)return;const e=t.composedPath();this._floating.containsPath(e)||this._closePicker(!1,"outside")},this._keyDown=t=>{this._open&&"Escape"===t.key&&(t.preventDefault(),t.stopImmediatePropagation(),this._closePicker(this._floating.ownsActiveElement(),"escape"))},this._floating=new Bo(this,"color-opacity",this._keyDown),this._queuePickerPosition=()=>{if(!this._open)return;this._pickerRaf&&cancelAnimationFrame(this._pickerRaf);const t=this._window();t&&(this._pickerRaf=t.requestAnimationFrame(()=>{this._pickerRaf=0,this._positionPicker()||this._closePicker()}))}}connectedCallback(){super.connectedCallback(),this._syncFromColor(this.color,!1),this.ownerDocument.addEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.addEventListener("scroll",this._queuePickerPosition,!0);const t=this.ownerDocument.defaultView;t?.addEventListener("resize",this._queuePickerPosition),t?.addEventListener("orientationchange",this._queuePickerPosition),t?.visualViewport?.addEventListener("resize",this._queuePickerPosition),t?.visualViewport?.addEventListener("scroll",this._queuePickerPosition),this.addEventListener("keydown",this._keyDown,!0)}disconnectedCallback(){this.ownerDocument.removeEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.removeEventListener("scroll",this._queuePickerPosition,!0);const t=this.ownerDocument.defaultView;t?.removeEventListener("resize",this._queuePickerPosition),t?.removeEventListener("orientationchange",this._queuePickerPosition),t?.visualViewport?.removeEventListener("resize",this._queuePickerPosition),t?.visualViewport?.removeEventListener("scroll",this._queuePickerPosition),this.removeEventListener("keydown",this._keyDown,!0),this._pickerRaf&&cancelAnimationFrame(this._pickerRaf),this._emitRaf&&cancelAnimationFrame(this._emitRaf),this._pickerRaf=0,this._emitRaf=0,this._closePicker(!1,"disconnect"),super.disconnectedCallback()}updated(t){if(t.has("color")){const t=Xr(this.color);t&&t!==this._lastValidColor&&this._syncFromColor(t,this._open)}this.disabled&&this._open?this._closePicker():this._open&&(this._supportsPopover()||this._renderFallback(),(t.has("color")||t.has("opacity")||t.has("showOpacity")||t.has("label")||t.has("opacityLabel")||t.has("pickerLabels"))&&this._queuePickerPosition())}_window(){return this._floating.window()}_supportsPopover(){return this._floating.usesPopover(this._forceFallback)}_dialog(){return this._floating.dialog()}async _toggle(){this.disabled||(this._open?this._closePicker():(this._forceFallback=!1,this._syncFromColor(this.color,!1),this._hexInvalid=!1,this._hexNeedsValidInput=!1,this._activePointerId=null,this._open=!0,await this.updateComplete,this._open&&(this._supportsPopover()||this._renderFallback(),this._positionPicker()?this._overlayDispose=this._dialog()?.registerOverlay({owner:this,group:"transient",close:t=>this._closePicker("escape"===t&&this._floating.ownsActiveElement(),t)})||null:this._closePicker())))}_closePicker(t=!1,e="exclusive"){if(!this._open&&!this._floating.hasFallback)return;const s=this._overlayDispose;this._overlayDispose=null,s?.();const i=this.renderRoot.querySelector(".picker");if(i?.hidePopover)try{i.matches(":popover-open")&&i.hidePopover()}catch{}this._open=!1,this._cancelQueuedEmit(),this._activePointerId=null,this._floating.destroy(),t&&this.updateComplete.then(()=>this.renderRoot.querySelector(".trigger")?.focus())}_surface(){return this._floating.surface(".picker",this._supportsPopover())}_renderFallback(){const t=il.styles.cssText;this._floating.renderFallback(this._pickerTemplate(!1),t)}_positionPicker(){if(!this._open)return!1;const t=this._window(),e=this.renderRoot.querySelector(".trigger");let s=this._surface();if(!t||!e?.isConnected||!s?.isConnected)return!1;const i=Ho(t);if(s.style.maxWidth=`${Math.max(0,i.width-16)}px`,s.style.maxHeight=`${Math.max(0,i.height-16)}px`,s.style.visibility="hidden",this._supportsPopover()&&s.showPopover)try{s.matches(":popover-open")||s.showPopover()}catch{if(this._forceFallback=!0,this._renderFallback(),s=this._surface(),!s?.isConnected)return!1;s.style.maxWidth=`${Math.max(0,i.width-16)}px`,s.style.maxHeight=`${Math.max(0,i.height-16)}px`,s.style.visibility="hidden"}const o=e.getBoundingClientRect(),a=s.getBoundingClientRect();if(!(o.width&&o.height&&a.width&&a.height))return!1;const n=Wo(o,a,i);return s.style.left=`${n.left}px`,s.style.top=`${n.top}px`,s.dataset.side=n.side,s.style.visibility="",!0}_labels(){const t=this.pickerLabels||sl;return{title:t.title||sl.title,hue:t.hue||sl.hue,saturation:t.saturation||sl.saturation,value:t.value||sl.value,hex:t.hex||sl.hex,invalidHex:t.invalidHex||sl.invalidHex,confirm:t.confirm||sl.confirm}}_syncFromColor(t,e){const s=Xr(Nt(t,"#607d8b"))||"#607d8b",i=Qr(s);if(!i)return;const o=tl(i);(!e||o.s>1e-4)&&(this._hue=o.h),this._saturation=o.s,this._value=o.v,this._hexDraft=s,this._hexInvalid=!1,this._hexNeedsValidInput=!1,this._lastValidColor=s}_cancelQueuedEmit(t=!1){this._emitRaf&&cancelAnimationFrame(this._emitRaf),this._emitRaf=0,t&&this._syncFromColor(this._lastValidColor,!0)}_queueHsvEmit(){if(this._emitRaf)return;const t=this._window();t?this._emitRaf=t.requestAnimationFrame(()=>{this._emitRaf=0,this._emitHsv()}):this._emitHsv()}_emitHsv(){this._emit(el({h:this._hue,s:this._saturation,v:this._value}),this.opacity)}_setHue(t){this._hue=Math.min(359,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setSaturation(t){this._saturation=Math.min(100,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setValue(t){this._value=Math.min(100,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setOpacity(t){this._emit(this._lastValidColor,t)}_shiftRangeKey(t,e,s,i,o){if(!t.shiftKey)return;const a="ArrowRight"===t.key||"ArrowUp"===t.key?10:"ArrowLeft"===t.key||"ArrowDown"===t.key?-10:0;a&&(t.preventDefault(),t.stopPropagation(),o(Math.min(i,Math.max(s,e+a))))}_setSvFromPointer(t,e){const s=t.currentTarget.getBoundingClientRect();s.width&&s.height&&(this._saturation=Math.min(100,Math.max(0,(t.clientX-s.left)/s.width*100)),this._value=Math.min(100,Math.max(0,100*(1-(t.clientY-s.top)/s.height))),e?(this._cancelQueuedEmit(),this._emitHsv()):this._queueHsvEmit())}_svPointerDown(t){if(t.preventDefault(),t.stopPropagation(),null===this._activePointerId){this._activePointerId=t.pointerId;try{t.currentTarget.setPointerCapture(t.pointerId)}catch{}this._setSvFromPointer(t,!0)}}_svPointerMove(t){t.pointerId===this._activePointerId&&(t.preventDefault(),t.stopPropagation(),this._setSvFromPointer(t,!1))}_svPointerUp(t){if(t.pointerId===this._activePointerId){t.preventDefault(),t.stopPropagation(),this._setSvFromPointer(t,!0),this._activePointerId=null;try{t.currentTarget.releasePointerCapture(t.pointerId)}catch{}}}_svPointerCancel(t){t.pointerId===this._activePointerId&&(t.preventDefault(),t.stopPropagation(),this._activePointerId=null,this._cancelQueuedEmit(!0))}_svLostPointerCapture(t){t.pointerId===this._activePointerId&&(this._activePointerId=null,this._cancelQueuedEmit(!0))}_hexInput(t){const e=t.target.value;this._hexDraft=e;const s=Xr(e),i=s?Qr(s):null;if(!s||!i)return void(this._hexInvalid=this._hexNeedsValidInput);this._hexNeedsValidInput=!1,this._hexInvalid=!1;const o=tl(i);o.s>1e-4&&(this._hue=o.h),this._saturation=o.s,this._value=o.v,this._emit(s,this.opacity,!0)}_commitHex(){const t=Xr(this._hexDraft);if(!t)return this._hexDraft=this._lastValidColor,this._hexInvalid=!0,void(this._hexNeedsValidInput=!0);this._hexDraft=t,this._hexNeedsValidInput?this._hexInvalid=!0:(this._hexInvalid=!1,t!==this._lastValidColor&&this._emit(t,this.opacity))}_confirm(t){t.preventDefault(),t.stopPropagation(),this._commitHex(),this._hexInvalid||this._hexNeedsValidInput?this.updateComplete.then(()=>{this._surface()?.querySelector('input[type="text"]')?.focus()}):this._closePicker(!0)}_hexKeyDown(t){"Enter"===t.key&&(t.preventDefault(),t.stopPropagation(),this._commitHex())}_emit(t,e,s=!1){const i=Xr(t)||this._lastValidColor,o=Number.isFinite(e)?e:Number(this.opacity)||0,a=Math.min(1,Math.max(0,o));this.color=i,this.opacity=a,this._lastValidColor=i,s||(this._hexDraft=i),this._hexInvalid=this._hexNeedsValidInput,this.dispatchEvent(new CustomEvent("hp-color-opacity-change",{detail:{color:i,opacity:a},bubbles:!0,composed:!0}))}_pickerTemplate(t){const e=Math.round(100*Math.min(1,Math.max(0,Number(this.opacity)||0))),s=el({h:this._hue,s:this._saturation,v:this._value}),i=el({h:this._hue,s:100,v:100}),o=this._labels(),a=Math.round(this._hue),n=Math.round(this._saturation),r=Math.round(this._value);return p` + `},qr=(t,e)=>{const s=t._deviceDrag;if(!s)return;const i=t._devices.find(t=>t.id===s.id),o=[...e.querySelectorAll('[data-hp="device"]')].find(t=>t.dataset.id===s.id);if(!i||!o)return;const a=t._livePos(i),n=t._scenePoint([a.x,a.y]),r=t._viewOr(t._baseVb());o.style.left=(n[0]-r.x)/r.w*100+"%",o.style.top=(n[1]-r.y)/r.h*100+"%"},Ur=(t,e,s)=>{for(const i of e.querySelectorAll('.decorlayer [data-hp="decor"]'))i.closest("[data-hp-live-editor]")||i.dataset.id!==s||"0"!==i.style.opacity&&(i.style.opacity="0",t.transparent.push(i))},Kr=(t,e,s)=>{const i=new Set(s);for(const s of e.querySelectorAll('.openinglayer [data-hp="opening"]'))!s.closest("[data-hp-live-editor]")&&i.has(s.dataset.id||"")&&(s.style.opacity="0",t.transparent.push(s))},Vr=(t,e,s)=>{for(const i of e.querySelectorAll(s))i.closest("[data-hp-live-editor]")||(i.style.opacity="0.35",t.dimmed.push(i))};const Jr=(t,e,s)=>Math.min(s,Math.max(e,Number.isFinite(t)?t:e));function Zr(t){return Number.isFinite(t)?(t%360+360)%360:0}function Yr(t){if("string"!=typeof t)return null;const e=t.trim().replace(/^#/,""),s=/^[0-9a-fA-F]{3}$/.test(e)?e.split("").map(t=>`${t}${t}`).join(""):e;return/^[0-9a-fA-F]{6}$/.test(s)?`#${s.toLowerCase()}`:null}function Xr(t){const e=Yr(t);return e?{r:Number.parseInt(e.slice(1,3),16),g:Number.parseInt(e.slice(3,5),16),b:Number.parseInt(e.slice(5,7),16)}:null}function Qr(t){const e=Jr(t.r,0,255)/255,s=Jr(t.g,0,255)/255,i=Jr(t.b,0,255)/255,o=Math.max(e,s,i),a=o-Math.min(e,s,i);let n=0;return a>0&&(n=o===e?(s-i)/a%6*60:o===s?60*((i-e)/a+2):60*((e-s)/a+4)),{h:Zr(n),s:0===o?0:a/o*100,v:100*o}}function tl(t){return function(t){const e=t=>Math.round(Jr(t,0,255)).toString(16).padStart(2,"0");return`#${e(t.r)}${e(t.g)}${e(t.b)}`}(function(t){const e=Zr(t.h),s=Jr(t.s,0,100)/100,i=Jr(t.v,0,100)/100,o=i*s,a=o*(1-Math.abs(e/60%2-1)),n=i-o;let r;return r=e<60?[o,a,0]:e<120?[a,o,0]:e<180?[0,o,a]:e<240?[0,a,o]:e<300?[a,0,o]:[o,0,a],{r:Math.round(255*(r[0]+n)),g:Math.round(255*(r[1]+n)),b:Math.round(255*(r[2]+n))}}(t))}const el={title:"Color picker",hue:"Hue",saturation:"Saturation",value:"Brightness",hex:"Hex color",invalidHex:"Enter a 3- or 6-digit hex color",confirm:"OK"};class sl extends Ft{constructor(){super(...arguments),this.label="",this.opacityLabel="Opacity",this.color="#607d8b",this.opacity=1,this.disabled=!1,this.showOpacity=!0,this.hideLabel=!1,this.pickerLabels=el,this._open=!1,this._pickerRaf=0,this._emitRaf=0,this._forceFallback=!1,this._overlayDispose=null,this._hue=0,this._saturation=0,this._value=0,this._hexDraft="#607d8b",this._hexInvalid=!1,this._hexNeedsValidInput=!1,this._lastValidColor="#607d8b",this._activePointerId=null,this._outsidePointerDown=t=>{if(!this._open)return;const e=t.composedPath();this._floating.containsPath(e)||this._closePicker(!1,"outside")},this._keyDown=t=>{this._open&&"Escape"===t.key&&(t.preventDefault(),t.stopImmediatePropagation(),this._closePicker(this._floating.ownsActiveElement(),"escape"))},this._floating=new Bo(this,"color-opacity",this._keyDown),this._queuePickerPosition=()=>{if(!this._open)return;this._pickerRaf&&cancelAnimationFrame(this._pickerRaf);const t=this._window();t&&(this._pickerRaf=t.requestAnimationFrame(()=>{this._pickerRaf=0,this._positionPicker()||this._closePicker()}))}}connectedCallback(){super.connectedCallback(),this._syncFromColor(this.color,!1),this.ownerDocument.addEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.addEventListener("scroll",this._queuePickerPosition,!0);const t=this.ownerDocument.defaultView;t?.addEventListener("resize",this._queuePickerPosition),t?.addEventListener("orientationchange",this._queuePickerPosition),t?.visualViewport?.addEventListener("resize",this._queuePickerPosition),t?.visualViewport?.addEventListener("scroll",this._queuePickerPosition),this.addEventListener("keydown",this._keyDown,!0)}disconnectedCallback(){this.ownerDocument.removeEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.removeEventListener("scroll",this._queuePickerPosition,!0);const t=this.ownerDocument.defaultView;t?.removeEventListener("resize",this._queuePickerPosition),t?.removeEventListener("orientationchange",this._queuePickerPosition),t?.visualViewport?.removeEventListener("resize",this._queuePickerPosition),t?.visualViewport?.removeEventListener("scroll",this._queuePickerPosition),this.removeEventListener("keydown",this._keyDown,!0),this._pickerRaf&&cancelAnimationFrame(this._pickerRaf),this._emitRaf&&cancelAnimationFrame(this._emitRaf),this._pickerRaf=0,this._emitRaf=0,this._closePicker(!1,"disconnect"),super.disconnectedCallback()}updated(t){if(t.has("color")){const t=Yr(this.color);t&&t!==this._lastValidColor&&this._syncFromColor(t,this._open)}this.disabled&&this._open?this._closePicker():this._open&&(this._supportsPopover()||this._renderFallback(),(t.has("color")||t.has("opacity")||t.has("showOpacity")||t.has("label")||t.has("opacityLabel")||t.has("pickerLabels"))&&this._queuePickerPosition())}_window(){return this._floating.window()}_supportsPopover(){return this._floating.usesPopover(this._forceFallback)}_dialog(){return this._floating.dialog()}async _toggle(){this.disabled||(this._open?this._closePicker():(this._forceFallback=!1,this._syncFromColor(this.color,!1),this._hexInvalid=!1,this._hexNeedsValidInput=!1,this._activePointerId=null,this._open=!0,await this.updateComplete,this._open&&(this._supportsPopover()||this._renderFallback(),this._positionPicker()?this._overlayDispose=this._dialog()?.registerOverlay({owner:this,group:"transient",close:t=>this._closePicker("escape"===t&&this._floating.ownsActiveElement(),t)})||null:this._closePicker())))}_closePicker(t=!1,e="exclusive"){if(!this._open&&!this._floating.hasFallback)return;const s=this._overlayDispose;this._overlayDispose=null,s?.();const i=this.renderRoot.querySelector(".picker");if(i?.hidePopover)try{i.matches(":popover-open")&&i.hidePopover()}catch{}this._open=!1,this._cancelQueuedEmit(),this._activePointerId=null,this._floating.destroy(),t&&this.updateComplete.then(()=>this.renderRoot.querySelector(".trigger")?.focus())}_surface(){return this._floating.surface(".picker",this._supportsPopover())}_renderFallback(){const t=sl.styles.cssText;this._floating.renderFallback(this._pickerTemplate(!1),t)}_positionPicker(){if(!this._open)return!1;const t=this._window(),e=this.renderRoot.querySelector(".trigger");let s=this._surface();if(!t||!e?.isConnected||!s?.isConnected)return!1;const i=Ho(t);if(s.style.maxWidth=`${Math.max(0,i.width-16)}px`,s.style.maxHeight=`${Math.max(0,i.height-16)}px`,s.style.visibility="hidden",this._supportsPopover()&&s.showPopover)try{s.matches(":popover-open")||s.showPopover()}catch{if(this._forceFallback=!0,this._renderFallback(),s=this._surface(),!s?.isConnected)return!1;s.style.maxWidth=`${Math.max(0,i.width-16)}px`,s.style.maxHeight=`${Math.max(0,i.height-16)}px`,s.style.visibility="hidden"}const o=e.getBoundingClientRect(),a=s.getBoundingClientRect();if(!(o.width&&o.height&&a.width&&a.height))return!1;const n=Wo(o,a,i);return s.style.left=`${n.left}px`,s.style.top=`${n.top}px`,s.dataset.side=n.side,s.style.visibility="",!0}_labels(){const t=this.pickerLabels||el;return{title:t.title||el.title,hue:t.hue||el.hue,saturation:t.saturation||el.saturation,value:t.value||el.value,hex:t.hex||el.hex,invalidHex:t.invalidHex||el.invalidHex,confirm:t.confirm||el.confirm}}_syncFromColor(t,e){const s=Yr(Nt(t,"#607d8b"))||"#607d8b",i=Xr(s);if(!i)return;const o=Qr(i);(!e||o.s>1e-4)&&(this._hue=o.h),this._saturation=o.s,this._value=o.v,this._hexDraft=s,this._hexInvalid=!1,this._hexNeedsValidInput=!1,this._lastValidColor=s}_cancelQueuedEmit(t=!1){this._emitRaf&&cancelAnimationFrame(this._emitRaf),this._emitRaf=0,t&&this._syncFromColor(this._lastValidColor,!0)}_queueHsvEmit(){if(this._emitRaf)return;const t=this._window();t?this._emitRaf=t.requestAnimationFrame(()=>{this._emitRaf=0,this._emitHsv()}):this._emitHsv()}_emitHsv(){this._emit(tl({h:this._hue,s:this._saturation,v:this._value}),this.opacity)}_setHue(t){this._hue=Math.min(359,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setSaturation(t){this._saturation=Math.min(100,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setValue(t){this._value=Math.min(100,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setOpacity(t){this._emit(this._lastValidColor,t)}_shiftRangeKey(t,e,s,i,o){if(!t.shiftKey)return;const a="ArrowRight"===t.key||"ArrowUp"===t.key?10:"ArrowLeft"===t.key||"ArrowDown"===t.key?-10:0;a&&(t.preventDefault(),t.stopPropagation(),o(Math.min(i,Math.max(s,e+a))))}_setSvFromPointer(t,e){const s=t.currentTarget.getBoundingClientRect();s.width&&s.height&&(this._saturation=Math.min(100,Math.max(0,(t.clientX-s.left)/s.width*100)),this._value=Math.min(100,Math.max(0,100*(1-(t.clientY-s.top)/s.height))),e?(this._cancelQueuedEmit(),this._emitHsv()):this._queueHsvEmit())}_svPointerDown(t){if(t.preventDefault(),t.stopPropagation(),null===this._activePointerId){this._activePointerId=t.pointerId;try{t.currentTarget.setPointerCapture(t.pointerId)}catch{}this._setSvFromPointer(t,!0)}}_svPointerMove(t){t.pointerId===this._activePointerId&&(t.preventDefault(),t.stopPropagation(),this._setSvFromPointer(t,!1))}_svPointerUp(t){if(t.pointerId===this._activePointerId){t.preventDefault(),t.stopPropagation(),this._setSvFromPointer(t,!0),this._activePointerId=null;try{t.currentTarget.releasePointerCapture(t.pointerId)}catch{}}}_svPointerCancel(t){t.pointerId===this._activePointerId&&(t.preventDefault(),t.stopPropagation(),this._activePointerId=null,this._cancelQueuedEmit(!0))}_svLostPointerCapture(t){t.pointerId===this._activePointerId&&(this._activePointerId=null,this._cancelQueuedEmit(!0))}_hexInput(t){const e=t.target.value;this._hexDraft=e;const s=Yr(e),i=s?Xr(s):null;if(!s||!i)return void(this._hexInvalid=this._hexNeedsValidInput);this._hexNeedsValidInput=!1,this._hexInvalid=!1;const o=Qr(i);o.s>1e-4&&(this._hue=o.h),this._saturation=o.s,this._value=o.v,this._emit(s,this.opacity,!0)}_commitHex(){const t=Yr(this._hexDraft);if(!t)return this._hexDraft=this._lastValidColor,this._hexInvalid=!0,void(this._hexNeedsValidInput=!0);this._hexDraft=t,this._hexNeedsValidInput?this._hexInvalid=!0:(this._hexInvalid=!1,t!==this._lastValidColor&&this._emit(t,this.opacity))}_confirm(t){t.preventDefault(),t.stopPropagation(),this._commitHex(),this._hexInvalid||this._hexNeedsValidInput?this.updateComplete.then(()=>{this._surface()?.querySelector('input[type="text"]')?.focus()}):this._closePicker(!0)}_hexKeyDown(t){"Enter"===t.key&&(t.preventDefault(),t.stopPropagation(),this._commitHex())}_emit(t,e,s=!1){const i=Yr(t)||this._lastValidColor,o=Number.isFinite(e)?e:Number(this.opacity)||0,a=Math.min(1,Math.max(0,o));this.color=i,this.opacity=a,this._lastValidColor=i,s||(this._hexDraft=i),this._hexInvalid=this._hexNeedsValidInput,this.dispatchEvent(new CustomEvent("hp-color-opacity-change",{detail:{color:i,opacity:a},bubbles:!0,composed:!0}))}_pickerTemplate(t){const e=Math.round(100*Math.min(1,Math.max(0,Number(this.opacity)||0))),s=tl({h:this._hue,s:this._saturation,v:this._value}),i=tl({h:this._hue,s:100,v:100}),o=this._labels(),a=Math.round(this._hue),n=Math.round(this._saturation),r=Math.round(this._value);return p`
    ${this.host._t(t?"decor.image_place_hint":"decor.image_pick_hint")}
    - `}renderFurniturePalette(){const t=this.host._furnPalette,e=this.host._furnCategory,s=me.flatMap(t=>ge(t)),i=vd.filter(t=>s.some(e=>e.category===t.id)),o=i.find(t=>t.id===e)||null,a=o?s.filter(t=>t.category===o.id):[],n=this.host._t(this.host._imperial?"gs.unit_ft":"gs.unit_m");return p`
    t.stopPropagation()}> +
    `}renderFurniturePalette(){const t=this.host._furnPalette,e=this.host._furnCategory,s=me.flatMap(t=>ge(t)),i=bd.filter(t=>s.some(e=>e.category===t.id)),o=i.find(t=>t.id===e)||null,a=o?s.filter(t=>t.category===o.id):[],n=this.host._t(this.host._imperial?"gs.unit_ft":"gs.unit_m");return p`
    t.stopPropagation()}>
    ${this.host._t("furn.title")} @@ -1101,7 +1101,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc this.host._decorTextDialog={...t,sizeCm:this.host._decorTextCm(Number(e.target.value))}} /> ${this.host._t(this.host._imperial?"wallthick.unit_in":"wallthick.unit_cm")}
    @@ -1365,7 +1365,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc @change=${t=>{const e=t.target.value;e&&this._decorInsertLiveVariable("__state__"===e?null:e)}}> - ${Object.keys(s?.attributes||{}).filter(t=>!!bt(e,t)).map(t=>p``)} + ${Object.keys(s?.attributes||{}).filter(t=>!!ft(e,t)).map(t=>p``)} `:d}
    @@ -1393,7 +1393,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc -
    `}_cssPxToRender(t){const e=this.host._stageEl,s=this.host._viewOr(this.host._baseVb());return e?.clientWidth&&e.clientHeight?Math.max(s.w/e.clientWidth,s.h/e.clientHeight)*t:this.host._gridPitch/8*t}_deleteRoomClick(t){const e=this.host._spaceModel();if(!e)return;const s=[...e.rooms].reverse().find(e=>this._pointInRoom(t,e));s?s.id&&(this.host._roomDeleteDialog={roomId:s.id,name:s.name}):this.host._showToast(this.host._t("toast.delete_room_pick"))}_wallThickHit(t){const e=this.host._spaceModel();if(!e)return null;const s=6*this.host._gridPitch,i=this.host._openCuts();let o=null;const a=(t,e,i)=>{e>s||(!o||e100)return void this._showPhysicalRange(100);if("room"!==e.source.kind){const t=this._geometrySnapshot(),i=(s.partitions||[]).find(t=>t.id===e.source.id);if(!i)return;if(0===n&&Ce(s.openings,{kind:"partition",id:i.id}))return void this.host._showToast(this.host._t("toast.zero_wall_opening_conflict"));i.cm=n,this.host._wallDialog=null;return this._commitPhysicalGeometry(this.host._t("history.wall_thickness"),t)&&this.host._showToast(this.host._t("toast.wallthick_set")),void this.host.requestUpdate()}const r=this._geometrySnapshot(),l=n>0?n:null;if(0===n){const i=.02*this.host._gridPitch,o=[e.a[0],e.a[1],e.b[0],e.b[1]],a=(s.rooms||[]).find(t=>t.id===e.roomId),n=new Set(t&&a&&Array.isArray(a.wall_ids)?a.wall_ids:(s.wall_segments||[]).filter(t=>{const e=[Number(t.a?.[0])*Gd,Number(t.a?.[1])*Gd],s=[Number(t.b?.[0])*Gd,Number(t.b?.[1])*Gd];return de(e,o)<=i&&de(s,o)<=i}).map(t=>String(t.id))),r=(s.openings||[]).some(t=>{if("partition"===t.host?.kind)return!1;if("wall"===t.host?.kind&&n.has(t.host.id))return!0;if(t.host)return!1;const e=[Number(t.x)*Gd,Number(t.y)*Gd];return e.every(Number.isFinite)&&de(e,o)<=i});if(r)return void this.host._showToast(this.host._t("toast.zero_wall_opening_conflict"))}let h,c=this.host._openCuts();if(n>0&&c.length){const o=[];if(t&&e.roomId){const t=(s.rooms||[]).find(t=>t.id===e.roomId),a=new Set(Array.isArray(t?.wall_ids)?t.wall_ids:[]);for(const t of s.wall_segments||[])a.has(t.id)&&o.push([Number(t.a?.[0])*Gd,Number(t.a?.[1])*Gd,Number(t.b?.[0])*Gd,Number(t.b?.[1])*Gd]);if(!o.length){const t=i.rooms.find(t=>t.id===e.roomId),s=t?A(t):null;for(let t=0;s&&t!o.some(e=>de([t[0],t[1]],e)<=a&&de([t[2],t[3]],e)<=a&&de([e[0],e[1]],t)<=a&&de([e[2],e[3]],t)<=a))}h=t&&e.roomId?Rs(s.walls,i.rooms,e.roomId,l,this.host._wallKeyPitch,c,Gd):G(s.walls,e.a,e.b,l,this.host._wallKeyPitch,Gd),h=this.host._normalizeWalls(h,c);for(const t of s.wall_segments||[])t.cm=ot(h,t.a,t.b,F,1);h.length?s.walls=h:delete s.walls,this.host._wallDialog=null,this._commitPhysicalGeometry(this.host._t("history.wall_thickness"),r)&&this.host._showToast(this.host._t(0===n?"toast.wallthick_cleared":"toast.wallthick_set")),this.host.requestUpdate()}_wallHatchDefs(t){if(!this.host._spaceWalls.length&&!this.host._physicalBodiesR().length&&!this.host._markup)return Pt``;const e=Tt(this.host._cellCm);return Pt` +
    `}_cssPxToRender(t){const e=this.host._stageEl,s=this.host._viewOr(this.host._baseVb());return e?.clientWidth&&e.clientHeight?Math.max(s.w/e.clientWidth,s.h/e.clientHeight)*t:this.host._gridPitch/8*t}_deleteRoomClick(t){const e=this.host._spaceModel();if(!e)return;const s=[...e.rooms].reverse().find(e=>this._pointInRoom(t,e));s?s.id&&(this.host._roomDeleteDialog={roomId:s.id,name:s.name}):this.host._showToast(this.host._t("toast.delete_room_pick"))}_wallThickHit(t){const e=this.host._spaceModel();if(!e)return null;const s=6*this.host._gridPitch,i=this.host._openCuts();let o=null;const a=(t,e,i)=>{e>s||(!o||e100)return void this._showPhysicalRange(100);if("room"!==e.source.kind){const t=this._geometrySnapshot(),i=(s.partitions||[]).find(t=>t.id===e.source.id);if(!i)return;if(0===n&&Ce(s.openings,{kind:"partition",id:i.id}))return void this.host._showToast(this.host._t("toast.zero_wall_opening_conflict"));i.cm=n,this.host._wallDialog=null;return this._commitPhysicalGeometry(this.host._t("history.wall_thickness"),t)&&this.host._showToast(this.host._t("toast.wallthick_set")),void this.host.requestUpdate()}const r=this._geometrySnapshot(),l=n>0?n:null;if(0===n){const i=.02*this.host._gridPitch,o=[e.a[0],e.a[1],e.b[0],e.b[1]],a=(s.rooms||[]).find(t=>t.id===e.roomId),n=new Set(t&&a&&Array.isArray(a.wall_ids)?a.wall_ids:(s.wall_segments||[]).filter(t=>{const e=[Number(t.a?.[0])*jd,Number(t.a?.[1])*jd],s=[Number(t.b?.[0])*jd,Number(t.b?.[1])*jd];return de(e,o)<=i&&de(s,o)<=i}).map(t=>String(t.id))),r=(s.openings||[]).some(t=>{if("partition"===t.host?.kind)return!1;if("wall"===t.host?.kind&&n.has(t.host.id))return!0;if(t.host)return!1;const e=[Number(t.x)*jd,Number(t.y)*jd];return e.every(Number.isFinite)&&de(e,o)<=i});if(r)return void this.host._showToast(this.host._t("toast.zero_wall_opening_conflict"))}let h,c=this.host._openCuts();if(n>0&&c.length){const o=[];if(t&&e.roomId){const t=(s.rooms||[]).find(t=>t.id===e.roomId),a=new Set(Array.isArray(t?.wall_ids)?t.wall_ids:[]);for(const t of s.wall_segments||[])a.has(t.id)&&o.push([Number(t.a?.[0])*jd,Number(t.a?.[1])*jd,Number(t.b?.[0])*jd,Number(t.b?.[1])*jd]);if(!o.length){const t=i.rooms.find(t=>t.id===e.roomId),s=t?N(t):null;for(let t=0;s&&t!o.some(e=>de([t[0],t[1]],e)<=a&&de([t[2],t[3]],e)<=a&&de([e[0],e[1]],t)<=a&&de([e[2],e[3]],t)<=a))}h=t&&e.roomId?Rs(s.walls,i.rooms,e.roomId,l,this.host._wallKeyPitch,c,jd):j(s.walls,e.a,e.b,l,this.host._wallKeyPitch,jd),h=this.host._normalizeWalls(h,c);for(const t of s.wall_segments||[])t.cm=it(h,t.a,t.b,z,1);h.length?s.walls=h:delete s.walls,this.host._wallDialog=null,this._commitPhysicalGeometry(this.host._t("history.wall_thickness"),r)&&this.host._showToast(this.host._t(0===n?"toast.wallthick_cleared":"toast.wallthick_set")),this.host.requestUpdate()}_wallHatchDefs(t){if(!this.host._spaceWalls.length&&!this.host._physicalBodiesR().length&&!this.host._markup)return Pt``;const e=Tt(this.host._cellCm);return Pt` @@ -1418,7 +1418,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc - `:p``}_openingAt(t){if(!this.host._openingsR.length)return null;const e=this.host._openingsR.flatMap(e=>{const s=e.angle*Math.PI/180,i=t[0]-e.rx,o=t[1]-e.ry,a=i*Math.cos(s)+o*Math.sin(s);return Math.abs(a)>e.rlen/2+Rt(12,this.host._cellCm)?[]:[{o:e,localY:-i*Math.sin(s)+o*Math.cos(s)}]});if(!e.length)return null;const s=this.host._spaceModel();if(!s)return null;const i=this.host._openCuts(),o=this.host._openingWallIndexFor(s,i).value;return e.find(({o:t,localY:e})=>{const s="gate"===t.type?!t.flip_v:t.flip_v,i=t.partitionHost||this.host._spaceWalls.length||"gate"===t.type?this.host._openingFace(t,o,!!s):{ox:0,oy:0,cm:0,side:-1},a=zs({type:t.type,length:t.rlen,angle:t.angle,amount:this.host._openingAmt(t),flipH:!!t.flip_h,flipV:!!t.flip_v,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,face:i});return Math.abs(e)<=a.hitHalf})?.o||null}_resolveOpeningPlacement(t){const e=this.host._openingPreset;if("opening"!==this.host._tool||!e)return null;const s=this.host._spaceModel();if(!s)return null;const i=this.host._openCuts(),o=this.host._openingWallIndexFor(s,i),a=`${o.key}|partitions:${this.host._cfgEpoch}`;this.host._openingPlacementIntervalsCache&&this.host._openingPlacementIntervalsCache.key===a||(this.host._openingPlacementIntervalsCache={key:a,value:[...B(s.rooms,this.host._spaceWalls,i,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,Gd),...Fs(s.partitions,this.host._cellCm,this.host._gridPitch)]}),this.host._openingDimensionContextCache&&this.host._openingDimensionContextCache.key===a||(this.host._openingDimensionContextCache={key:a,value:Pd({rooms:s.rooms,walls:this.host._spaceWalls,openCuts:i,partitions:s.partitions,roomOpenings:this.host._roomWallOpeningInputs(),partitionCuts:this._partitionOpeningCuts(s),pitch:this.host._wallKeyPitch,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,coordScale:Gd,epsilon:2e-4*this.host._gridPitch})});const n=Ns({pointer:[t[0],t[1]],preset:e,geometryRevision:this.host._cfgEpoch,renderedLength:this.host._cmToUnits(e.lengthCm),intervals:this.host._openingPlacementIntervalsCache.value,baseTolerance:1.5*this.host._gridPitch,bodyPointerPadding:this._cssPxToRender("touch"===this.host._pointerModality.modality||"pen"===this.host._pointerModality.modality?10:6),gridStep:this.host._gridPitch});this.host._openingJambBlockCm=n.jambBlockedTarget?n.jambBlockedTarget.physicalHalfWidth/this.host._gridPitch*this.host._cellCm:null;const r=n.candidate;if(!r)return null;const l="gate"===r.type?!r.flipV:r.flipV;let h;if(r.host){const t=E({id:"preview",type:r.type,x:r.x/Gd,y:r.y/Gd,angle:r.angle,length:r.renderedLength/Gd,host:r.host},s.partitions,Gd,this.host._cellCm,this.host._gridPitch).resolved;h=t?As(t,l):{ox:0,oy:0,cm:0,side:-1}}else h=Es(o.value,{x:r.x,y:r.y,angle:r.angle,length:r.renderedLength,flip_v:l});const c="mi"===this.host.hass?.config?.unit_system?.length,d=Fd(r,this.host._openingDimensionContextCache.value).map(t=>({x:t.label[0],y:t.label[1],text:le(t.distance/this.host._gridPitch*this.host._cellCm,c),dimension:t}));return{...r,face:h,measure:{labels:d,guide:r.measure.guide}}}_activateOpeningPlacement(t){this._activateMarkupTool("opening"),"opening"===this.host._tool&&(this.host._openingPreset=Os(t,++this.host._openingPresetRevision),this.host._openingHoverCandidate=null,this.host._cursorPt=null)}_clearOpeningPlacement(t){this.host._openingHoverCandidate=null,this.host._openingJambBlockCm=null,t&&(this.host._openingPreset=null,this.host._openingRebindId=null)}_openingClick(t){const e=this.host._spaceModel();if(!e)return;const s=this.host._openingRebindId?null:this._openingAt(t);if(s)return void this._editOpening(s);const i=this.host._openingPreset;if(!i)return;const o=this.host._openingHoverCandidate,a=o&&Bs(o,[t[0],t[1]],i.revision,this.host._cfgEpoch)?o:this._resolveOpeningPlacement(t);if(!a){if(null!=this.host._openingJambBlockCm)return void this.host._showToast(this.host._t("opening.partition_jamb_margin",{distance:le(this.host._openingJambBlockCm,this.host._imperial)}));const s=1.5*this.host._gridPitch,i=z(t,e.rooms,s);return i&&Hs(i.x,i.y,i.angle,this.host._openCuts(),s)?void this.host._showToast(this.host._t("toast.opening_on_zero_wall")):void this.host._showToast(this.host._t("toast.opening_no_wall"))}const n=this.host._openingRebindId?this.host._curSpaceCfg?.openings?.find(t=>t.id===this.host._openingRebindId):null;this.host._openingDialog={...n?{id:n.id,type:n.type,lengthCm:Math.round(n.length*Gd/this.host._gridPitch*this.host._cellCm),lengthTouched:!1,contact:n.contact||"",lock:n.lock||"",invert:!!n.invert,flipH:!!n.flip_h,flipV:!!n.flip_v}:{type:a.type,lengthCm:a.lengthCm,contact:"",lock:"",invert:!1,flipH:a.flipH,flipV:a.flipV},...a.host?{host:a.host}:{},x:a.x,y:a.y,angle:a.angle},this.host._openingRebindId=null,this.host._openingHoverCandidate=null,this.host._cursorPt=null}_editOpening(t){this.host._openingDialog={id:t.id,type:t.type,lengthCm:Math.round(t.rlen/this.host._gridPitch*this.host._cellCm),lengthTouched:!1,contact:t.contact||"",lock:t.lock||"",invert:!!t.invert,flipH:!!t.flip_h,flipV:!!t.flip_v,..."partition"===t.host?.kind?{host:{...t.host}}:{},x:t.rx,y:t.ry,angle:t.angle}}_opPointerDown(t,e){if("plan"===this.host._mode&&this.host._spaceModel()&&"resize"!==this.host._tool){t.preventDefault(),t.stopPropagation();try{Ud(t)}catch{}this.host._opDrag={id:e.id,moved:!1,sx:t.clientX,sy:t.clientY,dirty:!1,before:this._geometrySnapshot()}}}_opPointerMove(t,e){Ir(this.host,"opening",()=>this._opPointerMoveNow(t,e))}_opPointerMoveNow(t,e){if(!this.host._opDrag||this.host._opDrag.id!==e.id)return;if(Math.abs(t.clientX-this.host._opDrag.sx)+Math.abs(t.clientY-this.host._opDrag.sy)<=3)return;const s=this.host._spaceModel();if(!s)return;const i=this._svgPoint(t),o=this.host._curSpaceCfg,a=o?.openings?.find(t=>t.id===e.id);if(!a)return;if("partition"===a.host?.kind){const t=s.partitions.find(t=>t.id===a.host.id);if(!t)return;const e=t.b[0]-t.a[0],o=t.b[1]-t.a[1],n=Math.hypot(e,o);if(!(n>1e-9))return;const r=e/n,l=o/n;if(Math.abs((i[0]-t.a[0])*l-(i[1]-t.a[1])*r)>4*this.host._gridPitch)return;const h=a.length*Gd/2+j(t,this.host._cellCm,this.host._gridPitch);let c=(i[0]-t.a[0])*r+(i[1]-t.a[1])*l;if(c=Math.round(c/this.host._gridPitch)*this.host._gridPitch,c=Math.max(h,Math.min(n-h,c)),n<2*h-1e-9)return;const d=c/n,p=(t.a[0]+r*c)/Gd,u=(t.a[1]+l*c)/this.host._spaceH;let _=180*Math.atan2(o,e)/Math.PI;_>=90?_-=180:_<-90&&(_+=180);const m=a.host.t!==d||a.x!==p||a.y!==u||a.angle!==_;return this.host._opDrag.moved=!0,m&&(this.host._opDrag.dirty=!0),a.host={...a.host,t:d},a.x=p,a.y=u,a.angle=_,this.host._opMeasure=null,m&&this.host._cfgEpoch++,void this.host.requestUpdate()}const n=z(i,s.rooms,4*this.host._gridPitch);if(!n)return;this.host._opDrag.moved=!0;const r=this._opRuler(n,a.length*Gd);this.host._opMeasure=r.measure;const l=r.x/Gd,h=r.y/this.host._spaceH,c=a.x!==l||a.y!==h||a.angle!==n.angle;if(c&&(this.host._opDrag.dirty=!0),a.x=l,a.y=h,a.angle=n.angle,Number(this.host._serverCfg?.model_version||0)>=9){const t=Hn(a,o?.wall_segments||[]);t?a.host=t:delete a.host}c&&this.host._cfgEpoch++,this.host.requestUpdate()}_opRuler(t,e){const s=this.host._spaceModel()?.rooms||[],i=this.host._gridPitch/2;let o=t.x,a=t.y,n=Ws([o,a],t.angle,e,s,i);if(n&&n.centered&&(o!==n.wallCenter[0]||a!==n.wallCenter[1]))[o,a]=n.wallCenter,n=Ws([o,a],t.angle,e,s,i);else if(n){const[r,l]=n.wallA,[h,c]=n.wallB,d=h-r,p=c-l,u=Math.hypot(d,p);if(u>0){const h=this.host._gridPitch,c=Math.min(e/2,u/2);let _=Math.round(((o-r)*d+(a-l)*p)/u/h)*h;_=Math.max(c,Math.min(u-c,_)),o=r+_/u*d,a=l+_/u*p,n=Ws([o,a],t.angle,e,s,i)||n}}if(!n)return{x:o,y:a,angle:t.angle,measure:null};const r="mi"===this.host.hass?.config?.unit_system?.length,l=(t,e)=>({x:e[0],y:e[1],text:le(t/this.host._gridPitch*this.host._cellCm,r)});return{x:o,y:a,angle:t.angle,measure:{labels:[l(n.sideA,n.midA),l(n.sideB,n.midB)],guide:n.centered?{x:n.wallCenter[0],y:n.wallCenter[1],angle:t.angle}:null}}}_opPointerUp(t,e){if(!this.host._opDrag||this.host._opDrag.id!==e.id)return;Lr(this.host,"opening");const s=this.host._opDrag,i=s.moved;this.host._opMeasure=null,i&&s.dirty&&this._commitPhysicalGeometry(this.host._t("history.move_opening"),s.before);const o=()=>{this.host._opDrag=null,this.host.requestUpdate()};i?window.setTimeout(o,0):o()}_opClick(t,e){"plan"===this.host._mode&&"resize"===this.host._tool||(t.stopPropagation(),this.host._opDrag?.moved||"plan"===this.host._mode&&this._editOpening(e))}_saveOpening(){const t=this.host._openingDialog,e=this.host._curSpaceCfg,s=this.host._spaceModel();if(!t||!e||!s)return;const i=this._geometrySnapshot(),o=this.host._spaceH,a=(e.openings||[]).find(e=>e.id===t.id),n={...a||{},id:t.id||"o"+Date.now().toString(36),type:t.type,x:t.x/Gd,y:t.y/o,angle:t.angle,length:a&&!t.lengthTouched?a.length:this.host._cmToUnits(Math.max(20,t.lengthCm))/Gd,...t.host?{host:{...t.host}}:{}};if("partition"===n.host?.kind){const t=js(a,n)?U(n,s.partitions,Gd,this.host._cellCm,this.host._gridPitch):E(n,s.partitions,Gd,this.host._cellCm,this.host._gridPitch);if(!t.resolved){const e=s.partitions.find(t=>t.id===n.host.id);if("does-not-fit-jamb"===t.reason&&e){const t=j(e,this.host._cellCm,this.host._gridPitch);this.host._showToast(this.host._t("opening.partition_jamb_margin",{distance:le(t/this.host._gridPitch*this.host._cellCm,this.host._imperial)}))}else this.host._showToast(this.host._t("opening.partition_orphan"));return}const i=(e.openings||[]).flatMap(t=>{if(!t.host||t.id===n.id)return[];const e=E(t,s.partitions,Gd,this.host._cellCm,this.host._gridPitch).resolved;return e?[e]:[]});if(Gs(t.resolved,i))return void this.host._showToast(this.host._t("toast.opening_no_wall"));Object.assign(n,O(n,t.resolved,Gd))}else if(Number(this.host._serverCfg?.model_version||0)>=9){const t=Hn(n,e.wall_segments||[]);if(!t)return void this.host._showToast(this.host._t("toast.opening_no_wall"));n.host=t}else delete n.host;"passage"===t.type?(delete n.contact,delete n.lock,delete n.invert,delete n.flip_h,delete n.flip_v):(n.contact=t.contact||null,n.lock=("door"===t.type||"gate"===t.type)&&t.lock||null,n.invert=t.invert||void 0,n.flip_h="gate"!==t.type&&t.flipH||void 0,n.flip_v=t.flipV||void 0),e.openings=e.openings||[];const r=e.openings.findIndex(t=>t.id===n.id);r>=0?e.openings[r]=n:e.openings.push(n),this._commitPhysicalGeometry(this.host._t(t.id?"history.edit_opening":"history.add_opening"),i),this.host._openingDialog=null,this.host.requestUpdate()}_deleteOpening(){const t=this.host._openingDialog,e=this.host._curSpaceCfg;if(!t?.id||!e?.openings)return;const s=this._geometrySnapshot();e.openings=e.openings.filter(e=>e.id!==t.id),this._commitPhysicalGeometry(this.host._t("history.delete_opening"),s),this.host._openingDialog=null,this.host.requestUpdate()}_contactCandidates(){const t=[];for(const e of Object.keys(this.host.hass.states)){if(!this.host._openingEntityAvailable(e))continue;const s=e.split(".")[0];if("binary_sensor"!==s&&"cover"!==s)continue;const i=this.host.hass.states[e],o=["door","window","opening","garage_door","garage"].includes(i?.attributes?.device_class||"");("cover"!==s||o)&&t.push([e,i?.attributes?.friendly_name||e,o?0:1])}return t.sort((t,e)=>t[2]-e[2]||t[1].localeCompare(e[1])).map(([t,e])=>({value:t,label:e}))}_lockCandidates(){return Object.keys(this.host.hass.states).filter(t=>t.startsWith("lock.")&&this.host._openingEntityAvailable(t)).map(t=>({value:t,label:this.host.hass.states[t]?.attributes?.friendly_name||t})).sort((t,e)=>t.label.localeCompare(e.label))}_toggleOpeningEntityPicker(t){const e=this.host._openingDialog;if(!e)return;const s="contact"===t?!e.contactOpen:!e.lockOpen;this.host._openingDialog={...e,contactOpen:"contact"===t&&s,lockOpen:"lock"===t&&s}}_filterOpeningEntities(t,e){const s=this.host._openingDialog;s&&(this.host._openingDialog="contact"===t?{...s,contactFilter:e}:{...s,lockFilter:e})}_selectOpeningEntity(t,e){const s=this.host._openingDialog;s&&(this.host._openingDialog="contact"===t?{...s,contact:e,contactOpen:!1,contactFilter:""}:{...s,lock:e,lockOpen:!1,lockFilter:""})}_mergeClick(t){const e=this.host._spaceModel();if(!e)return;const s=e.rooms,i=[...s].reverse().find(e=>this._pointInRoom(t,e));if(!i?.id)return;const o=i.id;if(!this.host._mergeSel||this.host._mergeSel===o)return void(this.host._mergeSel=this.host._mergeSel===o?null:o);const a=s.find(t=>t.id===this.host._mergeSel),n=a?A(a):null,r=A(i),l=n&&r?qs(n,r):null;if(!l)return this.host._showToast(this.host._t("toast.merge_not_adjacent")),void(this.host._mergeSel=null);this.host._mergeDialog={aId:this.host._mergeSel,bId:o,poly:l,pick:"a"},this.host._mergeSel=null}_commitMerge(){const t=this.host._mergeDialog,e=this.host._curSpaceCfg;if(!t||!e||!this.host._spaceModel())return;const s=this._geometrySnapshot(),i=this.host._spaceH,o="a"===t.pick?t.aId:t.bId,a="a"===t.pick?t.bId:t.aId,n=Bd(this.host._serverCfg?.markers||[],{kind:"merge",dropId:a,keepId:o});s&&n.changed&&(s.roomReferences=n.before);const r=e.rooms.find(t=>t.id===o);if(!r)return void(this.host._mergeDialog=null);r.poly=t.poly.map(t=>[t[0]/Gd,t[1]/i]),delete r.x,delete r.y,delete r.w,delete r.h,e.rooms=e.rooms.filter(t=>t.id!==a),n.changed&&this.host._serverCfg&&(this.host._serverCfg.markers=n.markers);const l=this._commitPhysicalGeometry(this.host._t("history.merge_rooms"),s);this.host._mergeDialog=null,this.host._regSignature="",this.host._maybeRebuildDevices(),l&&this.host._showToast(this.host._t("toast.rooms_merged",{name:r.name||""}))}_splitClick(t){const e=this.host._spaceModel();if(!e)return;const s=e.rooms;if(!this.host._splitSel){const e=[...s].reverse().find(e=>this._pointInRoom(t,e));if(!e?.id)return;return void(this.host._splitSel={roomId:e.id,pts:[]})}const i=s.find(t=>t.id===this.host._splitSel.roomId),o=i?A(i):null;if(!i||!o)return void(this.host._splitSel=null);const a=.02*this.host._gridPitch,n=6*this.host._gridPitch,r=Us(t,o),l=r&&Ks(r,o,this.host._gridPitch)||r,h=r&&l&&Math.hypot(r[0]-t[0],r[1]-t[1])<=n?l:null,c=!!h&&Vs(h,o,a),d=this.host._splitSel.pts;if(!d.length)return c?void(this.host._splitSel={...this.host._splitSel,pts:[h]}):void this.host._showToast(this.host._t("toast.split_pick_wall"));if(!c){const e=this._snap(t);return Je(e,o,a)?void(this.host._splitSel={...this.host._splitSel,pts:[...d,e]}):void this.host._showToast(this.host._t("toast.split_pick_inside"))}const p=Ye(o,[...d,h],a);if(!p)return void this.host._showToast(this.host._t("toast.split_bad_cut"));this._resetRoomDialogFields();const[u,_]=p,m=Zt(u)>=Zt(_)?u:_,g=m===u?_:u;this.host._pendingSplit={roomId:i.id,mainPoly:m,newPoly:g},this.host._cursorPt=null,this.host._nameSel="",this.host._areaSel="",this.host._roomDialog=!0}_markupMove(t){if(!this.host._markup)return;if("column"===this.host._tool)return void(this.host._cursorPt=this._snap(this._svgPoint(t)));if("opening"===this.host._tool||"wallthick"===this.host._tool)return void(this.host._cursorPt=this._svgPoint(t));const e="draw"===this.host._tool&&!this.host._contourClosed,s="split"===this.host._tool&&!!this.host._splitSel?.pts?.length;if(!e&&!s)return;const i=this._svgPoint(t);if(e){const e=this._resolvePlanDrawPoint(i,t.shiftKey);if(this.host._planSnapHover={contextKey:e.contextKey,candidate:e.candidate,conflicts:e.conflicts},this._syncPlanSnapConflictMarkers(e.conflicts),this._syncPlanSnapActiveMarker(e.candidate),!this.host._path.length)return;return void(this.host._cursorPt=e.point)}this.host._cursorPt=this._snap(i)}_saveRoom(){(this.host._areaSel||this.host._nameSel.trim())&&Mt(this.host._roomTempMin,this.host._roomTempMax).valid&&(this.host._wallFaceBatch?this._decideWallFace(!0):this._commitRoom())}_decideWallFace(t){const e=this.host._wallFaceBatch;if(!e)return;const s=e.candidates[e.index];if(!s)return;if(!t&&(s.existing||s.repair)&&1===e.candidates.length)return this.host._wallFaceBatch=null,this.host._roomDialog=!1,this.host._nameSel="",this.host._areaSel="",void this.host.requestUpdate();const i=t?{candidate:s,create:!0,name:this.host._nameSel.trim(),area:this.host._areaSel||null,settings:this._roomSettingsFromDialog()?JSON.parse(JSON.stringify(this._roomSettingsFromDialog())):null}:{candidate:s,create:!1},o=[...e.decisions,i],a=e.index+1;if(a"number"==typeof t&&Number.isFinite(t)&&t>=0?t:null,o=.02*this.host._gridPitch,a=this.host._spaceModel();if(!a)return H;for(const e of this._planSnapGeometrySnapshot().value.segments)if(!("room"===e.sourceKind||de(t,[e.a[0],e.a[1],e.b[0],e.b[1]])>o)&&"partition"===e.sourceKind)return i(a.partitions.find(t=>t.id===e.sourceId)?.cm)??H;const n=xc(Math.max(0,e.length-1),s,this.host._drawWallCm,H);for(let s=0;s+1[...t]);if(!e)return s;const i=this.host._activeWallChainPartitionIds.findIndex((t,s)=>this._activeWallSourceKey(s)===e.sourceKey),o=i>=0?i+("b"===e.endpoint?1:0):-1;return o>=0&&oe.key===t.sourceKey),a=i.find(e=>e.key===t.targetSourceKey);if(!o||!a)return!1;const n="a"===t.endpoint?o.a:o.b;return!(Math.hypot(n[0]-t.from[0],n[1]-t.from[1])>s)&&(!(de(t.to,[a.a[0],a.a[1],a.b[0],a.b[1]])>s)&&!function(t,e){if(!t.sourceKey.startsWith("static:partition|"))return!1;const s=t.sourceKey.slice(17).split("|")[0];return!!s&&e.some(t=>"partition"===t.host?.kind&&t.host.id===s)}(t,this.host._curSpaceCfg?.openings||[]))}_applyWallRepair(t,e){const s=this.host._curSpaceCfg;if(!s||!this._validateWallRepair(t,e.activePath))return!1;if(!t.sourceKey.startsWith("static:"))return!1;const[i,o]=t.sourceKey.slice(7).split("|");if("partition"===i){const i=(s.partitions||[]).find(t=>t.id===o);if(!i)return!1;const a=[i.a[0]*Gd,i.a[1]*Gd],n=[i.b[0]*Gd,i.b[1]*Gd],r=Math.hypot(a[0]-t.from[0],a[1]-t.from[1])<=2e-4*this.host._gridPitch?i.a:Math.hypot(n[0]-t.from[0],n[1]-t.from[1])<=2e-4*this.host._gridPitch?i.b:null;if(!r)return!1;(e=>{e[0]=t.to[0]/Gd,e[1]=t.to[1]/Gd})(r);const l=e.activePartitionIds.indexOf(o);if(l>=0){const s=l+("b"===t.endpoint?1:0);e.activePath[s]&&(e.activePath[s]=[...t.to])}return!0}return!1}_applyWallFaceBatch(){const t=this.host._wallFaceBatch,e=this.host._curSpaceCfg,s=this.host._spaceModel();if(!t||!e||!s)return;const i=(t,e)=>{this.host._showToast(this.host._t(t,e)),this._roomDialogCancel()},o=t.decisions.filter(t=>t.create),a=o.map(t=>t.candidate.ring),n=s.rooms;for(let t=0;ts.id!==e&&!!A(s)&&Vt(a[t],A(s)));if(s)return void i("toast.room_overlap",{name:s.name||""})}if((e.rooms||[]).length+o.length>400)return void i("toast.physical_limit");if(o.some(t=>t.candidate.split&&!e.rooms.some(e=>e.id===t.candidate.split.roomId)))return void i("toast.contour_cannot_close");const r=o.map(t=>t.candidate.repair).filter(t=>!!t);if(r.length>1||r[0]&&!this._validateWallRepair(r[0],t.activePath))return void i("toast.wall_repair_changed");if(this._activePathWithRepair(t.activePath,r[0]),!o.length){if(!this._finalizeWallChainPartitions(t.activePartitionIds))return;return this.host._path=[],this.host._activeWallChainId=null,this.host._activeWallChainPartitionIds=[],this.host._wallChainSegmentCms=[],this.host._wallChainRedo=[],this.host._closingWallCm=null,this.host._wallFaceBatch=null,this.host._roomDialog=!1,this.host._nameSel="",this.host._areaSel="",this.host.requestUpdate(),void this.host._showToast(this.host._t("toast.wall_chain_saved"))}const l=new Set(t.activePartitionIds),h=2e-4*this.host._gridPitch,c=o.map(t=>t.candidate.ring.map((t,e,i)=>{const o=i[(e+1)%i.length],a=s.partitions.filter(e=>{const s=Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1]);if(!(s>h))return!1;const i=(e.b[0]-e.a[0])/s,a=(e.b[1]-e.a[1])/s,n=t=>(t[0]-e.a[0])*i+(t[1]-e.a[1])*a;return de(t,[e.a[0],e.a[1],e.b[0],e.b[1]])<=h&&de(o,[e.a[0],e.a[1],e.b[0],e.b[1]])<=h&&n(t)>=-h&&n(t)<=s+h&&n(o)>=-h&&n(o)<=s+h});return a.sort((t,e)=>Number(l.has(e.id))-Number(l.has(t.id))||Math.hypot(t.b[0]-t.a[0],t.b[1]-t.a[1])-Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])||t.id.localeCompare(e.id)),a[0]?.id||""})),d=this._geometrySnapshot();if(!d)return void i("toast.geometry_unsafe");const p=()=>{this._restoreGeometryStateLocal(d),i("toast.geometry_unsafe")};if(r[0]&&!this._applyWallRepair(r[0],t))return void i("toast.wall_repair_changed");const u=o.some(t=>!!t.candidate.split),_=u?Pe(s.rooms,e.walls,this.host._openCuts(),this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,Gd):null,m=u&&Array.isArray(e.walls)?e.walls:null;for(const t of o){const s=t.candidate.split;if(!s)continue;const i=e.rooms.find(t=>t.id===s.roomId);if(!i)return void p();i.poly=s.mainPoly.map(t=>[t[0]/Gd,t[1]/this.host._spaceH]),delete i.x,delete i.y,delete i.w,delete i.h}const g=Date.now().toString(36),f=[];if(o.forEach((t,s)=>{const i=t.area?this.host.hass.areas[t.area]?.name:"",o={id:`r${g}-${s}`,name:t.name||i||this.host._t("room.default_name"),area:t.area||null,poly:t.candidate.ring.map(t=>[t[0]/Gd,t[1]/this.host._spaceH]),...c[s].some(Boolean)?{wall_ids:c[s]}:{},...t.settings?{settings:JSON.parse(JSON.stringify(t.settings))}:{}};e.rooms.push(o),f.push({room:o,decision:t})}),u){const t=this.host._normalizeWalls(_,this.host._openCuts());t.length?e.walls=t:m?.length?e.walls=m:delete e.walls}if(f.length){this.host._cfgEpoch++;const s=this.host._openCuts(),i=this.host._spaceModel();if(!i)return void p();let o=e.walls;for(const{room:e,decision:a}of f){const n=a.candidate.ring,r=this._wallSourceCmAt(n[0],t.activePath,t.activeCms);o=Js(o,i.rooms,e.id,r,this.host._wallKeyPitch,s,Gd);for(const a of B(i.rooms,o,s,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,Gd)){if(a.roomId!==e.id||"outer"!==a.kind)continue;const s=[(a.a[0]+a.b[0])/2,(a.a[1]+a.b[1])/2];o=G(o,a.a,a.b,this._wallSourceCmAt(s,t.activePath,t.activeCms),this.host._wallKeyPitch,Gd)}}const a=this.host._normalizeWalls(o,s);a.length?e.walls=a:delete e.walls,this.host._cfgEpoch++;const n=this.host._spaceModel();if(!n)return void p();const r=un(e,n,e.walls,s,{pitch:this.host._wallKeyPitch,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,coordScale:Gd,allowCoincidentPartitions:!0});r.walls.length?e.walls=r.walls:delete e.walls,r.partitions.length?e.partitions=r.partitions:delete e.partitions,r.openings.length?e.openings=r.openings:delete e.openings}if(!this._commitPhysicalGeometry(this.host._t("history.wall_face_batch"),d))return;this.host._path=[],this.host._activeWallChainId=null,this.host._activeWallChainPartitionIds=[],this.host._wallChainSegmentCms=[],this.host._wallChainRedo=[],this.host._closingWallCm=null,this.host._wallFaceBatch=null,this.host._roomDialog=!1,this.host._nameSel="",this.host._areaSel="",this.host._regSignature="",this.host._maybeRebuildDevices();const b=new Set(o.map(t=>t.area).filter(t=>!!t));if(b.size){const t={...this.host._layout};for(const e of this.host._devices){if(!b.has(e.area||"")||e.space!==this.host._space)continue;if(this.host._layout[e.id])continue;const s=this.host._defPos[e.id];s&&(t[e.id]={s:this.host._space,x:s.x/Gd,y:s.y/Gd},this.host._dirtyPos.add(e.id))}this.host._layout=t,this.host._persistLayout()}this.host._showToast(this.host._t(o.length?"toast.wall_rooms_saved":"toast.wall_chain_saved",{n:o.length}))}_commitRoom(){const t=this.host._curSpaceCfg,e=this.host._spaceModel();if(!t||!e)return;const s=this._geometrySnapshot();if(!s)return;const i=()=>{this._restoreGeometryStateLocal(s),this.host._showToast(this.host._t("toast.geometry_unsafe"))},o=this.host._spaceH,a=!!this.host._pendingSplit,n=a?Pe(e.rooms,t.walls,this.host._openCuts(),this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,Gd):null,r=a&&Array.isArray(t.walls)?t.walls:null;let l;if(this.host._pendingSplit){const e=t.rooms.find(t=>t.id===this.host._pendingSplit.roomId);if(!e)return this.host._pendingSplit=null,this.host._splitSel=null,void(this.host._roomDialog=!1);e.poly=this.host._pendingSplit.mainPoly.map(t=>[t[0]/Gd,t[1]/o]),delete e.x,delete e.y,delete e.w,delete e.h,l=this.host._pendingSplit.newPoly}else{if(!this.host._contourClosed)return;l=this.host._path.slice(0,-1)}const h=this.host._areaSel?this.host.hass.areas[this.host._areaSel]?.name:"",c={id:"r"+Date.now().toString(36),name:this.host._nameSel||h||this.host._t("room.default_name"),area:this.host._areaSel||null,poly:l.map(t=>[t[0]/Gd,t[1]/o]),...this._roomSettingsFromDialog()?{settings:this._roomSettingsFromDialog()}:{}};if(t.rooms.push(c),a){const e=this.host._normalizeWalls(n,this.host._openCuts());e.length?t.walls=e:r?.length?t.walls=r:delete t.walls}if(!a){const e=xc(l.length,[...this.host._wallChainSegmentCms,this.host._closingWallCm??void 0],this.host._drawWallCm,H),s=e[0];if(null!=s){this.host._cfgEpoch++;const o=this.host._openCuts(),a=this.host._spaceModel();if(!a)return void i();let n=Js(t.walls,a.rooms,c.id,s,this.host._wallKeyPitch,o,Gd);for(const t of B(a.rooms,n,o,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,Gd)){if(t.roomId!==c.id||"outer"!==t.kind)continue;const s=[(t.a[0]+t.b[0])/2,(t.a[1]+t.b[1])/2],i=l.findIndex((t,e)=>{const i=l[(e+1)%l.length];return de(s,[t[0],t[1],i[0],i[1]])<=.02*this.host._gridPitch});i>=0&&(n=G(n,t.a,t.b,e[i],this.host._wallKeyPitch,Gd))}n=this.host._normalizeWalls(n,o),n.length?t.walls=n:delete t.walls;const r=this.host._spaceModel();if(!r)return void i();const h=un(t,r,t.walls,o,{pitch:this.host._wallKeyPitch,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,coordScale:Gd,allowCoincidentPartitions:!0});h.walls.length?t.walls=h.walls:delete t.walls,h.partitions.length?t.partitions=h.partitions:delete t.partitions,h.openings.length?t.openings=h.openings:delete t.openings}}const d=this._commitPhysicalGeometry(this.host._t(a?"history.split_room":"history.add_room"),s);this.host._path=[],this.host._activeWallChainId=null,this.host._activeWallChainPartitionIds=[],this.host._wallChainSegmentCms=[],this.host._wallChainRedo=[],this.host._closingWallCm=null,this.host._pendingSplit=null,this.host._splitSel=null;const p=this.host._areaSel;if(this.host._areaSel="",this.host._nameSel="",this.host._roomDialog=!1,this.host._regSignature="",this.host._maybeRebuildDevices(),!d)return;let u=0;if(p){const t=Gd,e={...this.host._layout};for(const s of this.host._devices){if(s.area!==p||s.space!==this.host._space)continue;if(u++,this.host._layout[s.id])continue;const i=this.host._defPos[s.id];i&&(e[s.id]={s:this.host._space,x:i.x/Gd,y:i.y/t},this.host._dirtyPos.add(s.id))}this.host._layout=e,this.host._persistLayout()}const _=this.host._model.find(t=>t.id===this.host._space)?.rooms.length||0;this.host._showToast(p?this.host._t("toast.room_saved",{n:_,added:u}):this.host._t("toast.room_saved_no_area",{n:_}))}_cancelPath(){this.host._wallRepairDiagnostic=null,this.host._path=[],this.host._activeWallChainId=null,this.host._activeWallChainPartitionIds=[],this.host._wallChainSegmentCms=[],this.host._wallChainRedo=[],this.host._closingWallCm=null,this._clearPlanSnapHover(),this.host._roomDialog=!1,this.host._pendingSplit=null,this.host._wallFaceBatch=null,this.host._splitSel=null,this.host._mergeSel=null,this.host._mergeDialog=null,this.host._physicalSel=null,this.host._physicalDrag=null,this.host._physicalRotate=null,this._clearOpeningPlacement(!0)}_roomDialogCancel(){if(this.host._roomDialog=!1,this.host._roomEditId)return this.host._roomEditId=null,this.host._nameSel="",void(this.host._areaSel="");if(this.host._wallFaceBatch){const t=this.host._wallFaceBatch;return this.host._wallFaceBatch=null,this.host._path=t.activePath.map(t=>[...t]),this.host._wallChainSegmentCms=[...t.activeCms],this.host._activeWallChainPartitionIds=[...t.activePartitionIds],this.host._activeWallChainId||=`chain-${Date.now().toString(36)}`,this.host._nameSel="",this.host._areaSel="",void this.host.requestUpdate()}if(this.host._pendingSplit)return this.host._pendingSplit=null,void(this.host._splitSel=null);this.host._undoPoint()}_openDeviceInbox(){this.host._deviceInboxReturn=null,this.host._deviceInbox=this.host._deviceInbox||{tab:"on_plan",search:"",showEntities:!1,onlyNew:!1,limit:100}}_closeMarkerDialog(){this._radarSetup.isDirty()?this._closeMarkerDialogGuarded():(this._radarSetup.reset(),function(t){if(t._markerDialog=null,!t._deviceInboxReturn)return;const e={...t._deviceInboxReturn};t._deviceInbox=e,t._deviceInboxReturn=null,e.anchor&&t.updateComplete.then(()=>requestAnimationFrame(()=>{const s=`.device-inbox-row[data-binding="${CSS.escape(e.anchor)}"]`;t.renderRoot.querySelector(s)?.scrollIntoView({block:"nearest"})}))}(this.host))}async _closeMarkerDialogGuarded(){if(!await this._radarSetup.discardIfAllowed())return await this.host.updateComplete,void this.host.renderRoot.querySelector("#marker-dialog")?.rejectClose();this._closeMarkerDialog()}_deviceInboxCandidates(t){return Qh({hass:this.host._planHass,devices:this.host._devices,markers:this.host._markers,showEntities:t,labels:{device:this.host._t("marker.sub_device"),z2mGroup:this.host._t("marker.sub_z2m_group"),group:this.host._t("marker.sub_group"),helper:this.host._t("marker.sub_helper"),entity:this.host._t("marker.sub_entity")}})}_deviceInboxRows(){const t=this.host._deviceInbox||this.host._deviceInboxReturn,e=!!t?.showEntities,s=[this.host._haRegistry.revision,this.host._cfgRev,this.host._cfgEpoch,this.host._regSignature,this.host._newSyncKey,e?1:0,this.host._showAll?1:0,l(this.host.hass,this.host._config?.language)].join("|");if(this.host._deviceInboxMemo?.key===s)return this.host._deviceInboxMemo.rows;const i=this._deviceInboxCandidates(e),o=new Set(i.map(t=>t.value));for(const t of this.host._markers)t.binding&&"virtual"!==t.binding&&o.add(t.binding);for(const t of this.host._devices)t.bindingKind&&"virtual"!==t.bindingKind&&t.bindingRef&&o.add(`${t.bindingKind}:${t.bindingRef}`);const a=new Map;for(const t of o)a.set(t,this.host._bindingStatus(t));const n=this.host._areaToSpace,r={};for(const[t,e]of Object.entries(this.host.hass?.areas||{}))r[t]=n[t]?.room?.name||e?.name||t;for(const[t,e]of Object.entries(n))r[t]=e.room.name||r[t]||t;const h=Object.fromEntries(this.host._model.map(t=>[t.id,t.title])),c=Object.fromEntries(Object.entries(n).map(([t,e])=>[t,e.space])),d={},p=new Map;for(const[t,e]of Object.entries(this.host._fullRegistryHass.entities||{})){const s=String(e?.platform||"").trim();if(s&&(d[`entity:${t}`]=s),s&&e?.device_id){const t=p.get(e.device_id)||new Set;t.add(s),p.set(e.device_id,t)}}for(const[t,e]of p)d[`device:${t}`]=[...e].sort().join(", ");const u={};for(const[t,e]of Object.entries(this.host._fullRegistryHass.devices||{})){const s=`device:${t}`,i=p.get(t)||new Set,o=Array.isArray(e?.identifiers?.[0])?String(e.identifiers[0][0]||""):"";o&&!d[s]&&(d[s]=o);const a=[o,...i].some(t=>this.host._excluded.has(t));"service"===e?.entry_type?u[s]="service_entry":a?u[s]="excluded_integration":"Group"===e?.model?u[s]="grouped_light":/scene/i.test(e?.model||"")?u[s]="excluded_domain":(/bridge/i.test(`${e?.model||""}${e?.name||""}`)||"myheat"===o&&e?.via_device_id)&&(u[s]="represented_by_parent")}const _=function(t){const{devices:e,markers:s,candidates:i,statuses:o,newDeviceIds:a,showHiddenOnPlan:n,areaNames:r={},spaceNames:l={},spaceByArea:h={},integrationByBinding:c={},reasonByBinding:d={}}=t,p=new Map;for(const t of e)!t.virtual&&t.bindingKind&&"virtual"!==t.bindingKind&&t.bindingRef&&p.set(`${t.bindingKind}:${t.bindingRef}`,t);const u=new Map,_=new Map;for(const t of s)t?.binding&&"virtual"!==t.binding&&(t.removed?_.set(t.binding,t):u.set(t.binding,t));const m=new Map(i.map(t=>[t.value,t])),g=new Set([...p.keys(),...u.keys(),...m.keys(),...[..._.keys()].filter(t=>m.has(t))]),f=[];for(const t of g){const e=p.get(t),s=u.get(t),i=s?void 0:_.get(t),g=m.get(t);let b;if(i&&g)b="readd";else if(!0===s?.hidden)b="hidden";else if(e||s)b="on_plan";else{if(!g)continue;b="available"}const v=e?.bindingStatus||o.get(t)||tc,y=s||i,w=ec(t),$=e?.area||g?.areaId||y?.area||"",k=e?.space||y?.space||h[$]||"",x=e?.name||y?.name||g?.label||t,M=e?.model||y?.model||g?.model||"",C=!!g?.parentDeviceId&&p.has(`device:${g.parentDeviceId}`),S="readd"===b?"removed":"hidden"===b?s&&sc(s)?d[t]||"automatic_hidden":"manual_hidden":"on_plan"===b?s?"visible_explicit":"visible_auto":d[t]||(C?"represented_by_parent":$&&k?"available":"no_bound_room"),P=!!e&&(!e.hidden||n),D="active"===v.kind,I=P&&(D||"ha_disabled"===v.kind&&n),L=[x,M,c[t],r[$],l[k],t,g?.sub].filter(Boolean).join(" ").toLocaleLowerCase();f.push({key:t,binding:t,category:b,status:v,reason:S,deviceId:e?.id,markerId:y?.id,name:x,icon:e?.icon||y?.icon||("entity"===w?"mdi:code-braces":"mdi:devices"),model:M,integration:c[t]||"",areaId:$,areaName:r[$]||"",spaceId:k,spaceName:l[k]||"",kind:w,isNew:!!e&&a.has(e.id),searchText:L,canFind:I,canEdit:!!e||!!s,canHide:"on_plan"===b&&D,canShow:"hidden"===b&&D,canAdd:("available"===b||"readd"===b)&&D})}const b=t=>"active"===t.status.kind?1:0;return f.sort((t,e)=>t.category.localeCompare(e.category)||Number(e.isNew)-Number(t.isNew)||b(t)-b(e)||t.name.localeCompare(e.name)||t.binding.localeCompare(e.binding))}({devices:this.host._devices,markers:this.host._markers,candidates:i,statuses:a,newDeviceIds:this.host._newIds,showHiddenOnPlan:this.host._showAll,areaNames:r,spaceNames:h,spaceByArea:c,integrationByBinding:d,reasonByBinding:u});return this.host._deviceInboxMemo={key:s,rows:_},_}_deviceForInboxRow(t){const e=t.deviceId?this.host._devices.find(e=>e.id===t.deviceId):null;if(e)return e;const s=t.markerId?this.host._markers.find(e=>e.id===t.markerId):null;return!s||s.removed?null:{id:s.id,name:t.name,model:t.model,area:t.areaId,space:t.spaceId||this.host._space,hidden:!0===s.hidden||"ha_disabled"===t.status.kind,userHidden:!0===s.hidden,bindingStatus:t.status,icon:t.icon,entities:"active"===t.status.kind?t.status.enabledEntityIds:[],allEntities:t.status.allEntityIds,primary:"active"===t.status.kind?t.status.enabledEntityIds[0]:void 0,marker:s,bindingKind:t.kind,bindingRef:t.binding.slice(t.binding.indexOf(":")+1),pdfs:s.pdfs||[]}}_openInboxMarker(t,e=!1){const s=this.host._deviceInbox;if(s){if(this.host._deviceInboxReturn={...s,anchor:t.key},this.host._deviceInbox=null,!e){const e=this._deviceForInboxRow(t);return void(e?this._openMarkerDialog(e):this._closeMarkerDialog())}this._openMarkerDialog(),this.host._markerDialog?this.host._markerDialog={...this.host._markerDialog,bindingMode:"ha",binding:t.binding,bindingOpen:!1,showEntities:"entity"===t.kind,name:""}:this._closeMarkerDialog()}}async _setInboxHidden(t,e){const s=this.host._deviceInbox,i=this.host._serverCfg;if(!s||!i||s.busy||"active"!==t.status.kind)return;const o=i.markers||[],a=o.find(e=>!e.removed&&e.binding===t.binding);if(!e&&!a)return;const n=a?.id||Zs(t.binding,t.markerId,()=>`m_${Date.now().toString(36)}`),r=a?{...a,hidden:e}:{id:n,binding:t.binding,hidden:!0};i.markers=[...o.filter(e=>e.id!==n&&(e.binding!==t.binding||!0===e.removed)),r],this.host._deviceInbox={...s,busy:t.key,anchor:t.key};try{await this._saveConfigNow(),this.host._regSignature="",this.host._deviceInboxMemo=null,this.host._maybeRebuildDevices(),this.host._deviceInbox&&(this.host._deviceInbox={...this.host._deviceInbox,busy:void 0}),this.host._showToast(this.host._t("device_inbox.saved"))}catch(t){this.host._serverCfg===i&&(i.markers=o),this.host._deviceInbox&&(this.host._deviceInbox={...this.host._deviceInbox,busy:void 0}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_findInboxDevice(t){if(!t.canFind)return;const e=this._deviceForInboxRow(t);if(!e)return;if(this.host._deviceInbox=null,e.space&&e.space!==this.host._space){if(!this.host._commitSpace(e.space))return;this.host._restoreZoom()}const s=()=>{const t=this.host._devices.find(t=>t.id===e.id)||e,s=this.host._pos(t);this.host._applyView(this.host._zoom,s.x,s.y),this.host._selId=t.id,this.host.requestUpdate(),window.setTimeout(()=>{this.host._selId===t.id&&(this.host._selId=null,this.host.requestUpdate())},1500)};requestAnimationFrame(()=>requestAnimationFrame(s))}_openMarkerDialog(t){if(this.host._vacAllCamerasFor=null,this.host._vacAllCameraCache=null,t&&this.host._ackNewDevice(t.id),this.host._norm){if(t){const e=t.marker,s=Object.prototype.hasOwnProperty.call(e||{},"is_light"),i=Object.prototype.hasOwnProperty.call(e||{},"light_entity"),o=Object.prototype.hasOwnProperty.call(e||{},"glow_color"),a=Object.prototype.hasOwnProperty.call(e||{},"value_badge"),n=Object.prototype.hasOwnProperty.call(e||{},"value_source"),r=Object.prototype.hasOwnProperty.call(e||{},"tap_action"),l=Object.prototype.hasOwnProperty.call(e||{},"toggle_entity"),h=Ys(e?.glow_color),c=this.host._devicePresentation(t,!0).valueBadge,d=f(this.host._planHass,t,this.host._devices),p=b(this.host._planHass,t,d),u=Ma(t,this.host._fullRegistryHass),_=this.host._spaceModelById(t.space)||this.host._spaceModel(),m=this.host._pos(t),g=_?Sa(t,_,[m.x,m.y],this.host._fullRegistryHass):null;this.host._markerDialog={devId:t.id,name:t.name,binding:"virtual"===t.bindingKind?"virtual":t.bindingKind+":"+t.bindingRef,bindingMode:"virtual"===t.bindingKind?"virtual":"ha",bindingOpen:!1,showEntities:"entity"===t.bindingKind&&!!this.host._fullRegistryHass.entities[t.bindingRef||""]?.device_id,bindingFilter:"",icon:t.marker?.icon||"",autoIcon:t.icon||"",display:P(t.marker?.display),rippleColor:Nt(t.marker?.ripple_color,""),rippleSize:Number(t.marker?.ripple_size)>0?Number(t.marker.ripple_size):1.5,size:Number(t.marker?.size)>0?Number(t.marker.size):1,angle:Number(t.marker?.angle)||0,tapAction:Xs(t.marker?.tap_action,t.primary?.split(".")[0]),tapActionTouched:!1,originalHasTapAction:r,originalTapAction:t.marker?.tap_action,tapHintAnnouncement:"",toggleEntity:e?.toggle_entity||"",toggleEntityTouched:!1,originalHasToggleEntity:l,originalToggleEntity:e?.toggle_entity,tapTarget:t.marker?.tap_target||"",tapConfirm:!0===t.marker?.tap_confirm,runFilter:"",controls:R(t.marker?.binding,t.marker?.controls,t.entities),controlsFilter:"",lightRole:!0===e?.is_light?"always":!1===e?.is_light?"never":"auto",lightRoleTouched:!1,originalHasIsLight:s,originalIsLight:e?.is_light,lightEntity:e?.light_entity||"",lightEntityTouched:!1,originalHasLightEntity:i,originalLightEntity:e?.light_entity,glowMode:null!=h?.bri?"fixed":h?"color":"auto",glowColor:h?.c||this.host._fillColors.glow_light.c,glowBrightness:Math.max(1,Math.round(100*(h?.bri??1))),glowColorDrafted:!!h,glowBrightnessDrafted:null!=h?.bri,glowTouched:!1,originalHasGlowColor:o&&(!!h||null===e?.glow_color),originalGlowColor:h||(null===e?.glow_color?null:void 0),valueBadgeEnabled:a?!0===e?.value_badge?.enabled:!!c,valueBadgeSource:e?.value_badge?.source||c?.source||p,valueBadgePosition:e?.value_badge?.position||c?.position||"right",valueBadgeTouched:!1,originalHasValueBadge:a,originalValueBadge:e?.value_badge,valueSource:e?.value_source||null,valueSourceTouched:!1,originalHasValueSource:n,originalValueSource:e?.value_source,useClimateTemp:!0===t.marker?.use_climate_temp,glowRadius:Number(t.marker?.glow_radius_cm)>0?String(this.host._imperial?Math.round(Number(t.marker.glow_radius_cm)/30.48*10)/10:Math.round(Number(t.marker.glow_radius_cm))/100):"",model:t.model||"",link:t.link||"",description:t.description||"",pdfs:[...t.pdfs||[]],room:t.marker?.room_id?t.space+"#@"+t.marker.room_id:t.space&&t.area?t.space+"#"+t.area:"",roomTouched:!1,radar:g,radarEligible:u.eligible,radarTouched:!1,radarRemove:!1,hideFromPlan:!0===t.marker?.hidden,busy:!1}}else this.host._markerDialog={name:"",binding:"virtual",bindingMode:"virtual",bindingOpen:!1,showEntities:!1,bindingFilter:"",icon:"",autoIcon:"",display:"badge",rippleColor:"",rippleSize:1.5,size:1,angle:0,tapAction:"info",tapActionTouched:!1,originalHasTapAction:!1,originalTapAction:void 0,tapHintAnnouncement:"",toggleEntity:"",toggleEntityTouched:!1,originalHasToggleEntity:!1,originalToggleEntity:void 0,tapTarget:"",tapConfirm:!1,runFilter:"",controls:[],controlsFilter:"",lightRole:"auto",lightRoleTouched:!1,originalHasIsLight:!1,originalIsLight:void 0,lightEntity:"",lightEntityTouched:!1,originalHasLightEntity:!1,originalLightEntity:void 0,glowMode:"auto",glowColor:this.host._fillColors.glow_light.c,glowBrightness:100,glowColorDrafted:!1,glowBrightnessDrafted:!1,glowTouched:!1,originalHasGlowColor:!1,originalGlowColor:void 0,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgePosition:"right",valueBadgeTouched:!1,originalHasValueBadge:!1,originalValueBadge:void 0,valueSource:null,valueSourceTouched:!1,originalHasValueSource:!1,originalValueSource:void 0,useClimateTemp:!1,glowRadius:"",model:"",link:"",description:"",pdfs:[],room:"",roomTouched:!1,radar:null,radarEligible:!1,radarTouched:!1,radarRemove:!1,hideFromPlan:!1,busy:!1,uploadId:"up_"+Date.now().toString(36)+Math.random().toString(36).slice(2,6)};this.host._markerDialog&&function(t,e){_o(t,"marker",ga(e))}(this.host,this.host._markerDialog)}else this.host._showToast(this.host._t("toast.marker_needs_server"))}_runCandidates(){const t=[];for(const e of Qs)for(const[s,i]of Object.entries(this.host.hass.states))s.startsWith(e+".")&&this.host._planEntityAvailable(s)&&t.push({value:s,label:i?.attributes?.friendly_name||s,sub:this.host._t("run."+e)});return t.sort((t,e)=>t.sub.localeCompare(e.sub)||t.label.localeCompare(e.label))}_bindingCandidates(){const t=Qh({hass:this.host._planHass,devices:this.host._devices,markers:this.host._markers,showEntities:!!this.host._markerDialog?.showEntities,currentBinding:this.host._markerDialog?.binding,currentDeviceId:this.host._markerDialog?.devId,labels:{device:this.host._t("marker.sub_device"),z2mGroup:this.host._t("marker.sub_z2m_group"),group:this.host._t("marker.sub_group"),helper:this.host._t("marker.sub_helper"),entity:this.host._t("marker.sub_entity")}}),e=(this.host._markerDialog?.bindingFilter||"").toLowerCase().trim(),s=e?t.filter(t=>(t.label+" "+t.sub+" "+t.value).toLowerCase().includes(e)):t;return s.sort((t,e)=>t.label.localeCompare(e.label)),s.slice(0,200)}_backupErrorText(t){const e=t?.code??t?.error;if("string"==typeof e){const t=`backup.error.${e}`,s=this.host._t(t);if(s!==t)return s}return this.host._errText(t)}async _pickMarkerFiles(t){const e=t.target,s=e.files?[...e.files]:[];if(e.value="",!s.length||!this.host._markerDialog)return;const i=this.host._markerDialog.uploadId||this.host._markerDialog.devId||"new",o=[];for(const t of s)try{const e=new FormData;e.append("marker_id",i),e.append("file",t,t.name);const s=this.host.hass?.fetchWithAuth?await this.host.hass.fetchWithAuth("/api/houseplan/upload",{method:"POST",body:e}):await fetch("/api/houseplan/upload",{method:"POST",body:e,headers:this.host.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.host.hass.auth.data.access_token}`}:{}}),a=await s.json().catch(()=>({}));if(!s.ok||a.error){const t={too_large:this.host._t("err.too_large",{mb:a.max_mb||50}),bad_ext:this.host._t("err.bad_ext"),unauthorized:this.host._t("err.unauthorized")};throw new Error(t[a.error]||a.error||"HTTP "+s.status)}o.push({name:a.name||t.name,url:a.url})}catch(e){this.host._showToast(this.host._t("toast.file_failed",{name:t.name,err:this.host._errText(e)}))}o.length&&this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,pdfs:[...this.host._markerDialog.pdfs,...o]},this.host._showToast(this.host._t("toast.files_attached",{n:o.length})))}_removeMarkerPdf(t){this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,pdfs:this.host._markerDialog.pdfs.filter(e=>e.url!==t)})}_markerLightFields(t){const e={};if(t.lightRoleTouched?"always"===t.lightRole?e.is_light=!0:"never"===t.lightRole&&(e.is_light=!1):t.originalHasIsLight&&(e.is_light=t.originalIsLight??null),t.lightEntityTouched?t.lightEntity&&(e.light_entity=t.lightEntity):t.originalHasLightEntity&&(e.light_entity=t.originalLightEntity??null),t.glowTouched){if("auto"!==t.glowMode){const s={c:Nt(t.glowColor,this.host._fillColors.glow_light.c)};"fixed"===t.glowMode&&(s.bri=Math.max(.01,Math.min(1,Math.round(t.glowBrightness)/100))),e.glow_color=s}}else t.originalHasGlowColor&&(e.glow_color=t.originalGlowColor??null);return e}_markerTapActionFields(t){return t.tapActionTouched?{tap_action:t.tapAction||null}:t.originalHasTapAction?{tap_action:t.originalTapAction??null}:{}}_markerToggleEntityFields(t){return(e={touched:t.toggleEntityTouched,originalHas:t.originalHasToggleEntity,original:t.originalToggleEntity,value:t.toggleEntity}).touched?e.value?{toggle_entity:e.value}:{}:e.originalHas?{toggle_entity:e.original??null}:{};var e}async _saveMarker(){const t=this.host._markerDialog;if(!t||t.busy)return;const e=this._effectiveMarkerTapAction(t);if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return;if("virtual"===t.binding&&!t.name.trim())return void this.host._showToast(this.host._t("toast.virtual_name_required"));if("run"===e&&!t.tapTarget)return void this.host._showToast(this.host._t("toast.run_target_required"));if(t.valueBadgeTouched&&t.valueBadgeEnabled&&!t.valueBadgeSource)return void this.host._showToast(this.host._t("toast.value_badge_source_required"));if("ha"===t.bindingMode){const e=this.host._bindingStatus(t.binding),s=t.devId?this.host._markers.find(e=>e.id===t.devId):null,i=!s||s.binding!==t.binding;if("active"!==e.kind&&i)return void this.host._showToast(this.host._t("ha_disabled"===e.kind?"toast.ha_disabled_add":"toast.ha_binding_unverified"));if("ha_disabled"===e.kind&&!0===s?.hidden&&!t.hideFromPlan)return this.host._markerDialog={...t,hideFromPlan:!0},void this.host._showToast(this.host._t("entity"===e.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device"))}const s=this.host._serverCfg;if(!s)return;const i=this.host._cfgRev,o=wt(s);let a=JSON.parse(JSON.stringify(s));const n=a.markers||[],r=Zs(t.binding,t.devId,()=>"v_"+Date.now().toString(36)),l=t.devId,h=l?this.host._devices.find(t=>t.id===l):null,c=l?n.find(t=>t.id===l):null,d=!!c&&("string"==typeof c.area&&c.area.length>0||null===c.area&&!!c.space&&!!c.room_id),p="virtual"===t.binding||t.roomTouched||d,_="virtual"===t.binding||t.roomTouched?M(t.room):null;let m=d&&!t.roomTouched?c?.space||null:_?.space||null;const g=d&&!t.roomTouched?c?.area||null:_?.area||null,f=d&&!t.roomTouched?c?.room_id||null:_?.roomId||null,b=m||h?.space||null,v=b?this.host._spaceModelById(b):this.host._spaceModel();if(!v)return;const y=v.id;"virtual"!==t.binding||m||(m=y);let w={};if(t.radarTouched){if(t.radarRemove)w={radar:null};else if(t.radar){const e=Ia(t.radar,v.cellCm||5);if(!e)return void this.host._showToast(this.host._t("radar.invalid"));w={radar:e}}}else c&&Object.prototype.hasOwnProperty.call(c,"radar")&&(w={radar:c.radar});this.host._markerDialog={...t,busy:!0};let $=null,k=!1;try{const c="virtual"===t.binding?[]:n.filter(e=>e.removed&&e.binding===t.binding).map(t=>t.id),d=c.length>0,_=R(t.binding,t.controls,this.host._bindingEntities(t.binding)),b=n.find(t=>t.id===r||t.id===l)?.vacuum||null,x={id:r,vacuum:b,...w,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle?t.angle:null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===e&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:_.length?_:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),...this._markerValueSourceFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=u(t.glowRadius);return null==e||e<=0?null:Math.round(this.host._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:!!t.hideFromPlan};p&&(x.space=m,x.area=g,x.room_id=f);const M=h?.marker?.room_id??null,C=t.roomTouched&&null!=h&&(h.space!==m||h.area!==g||M!==f);let S=!1;const P=t.uploadId||l;if(P&&P!==r&&x.pdfs?.length)try{const t=await this.host.hass.callWS({type:"houseplan/files/migrate",from_id:P,to_id:r}),e=t?.mapping||{};x.pdfs=ti(x.pdfs,P,r,e),S=Object.keys(e).length>0}catch(t){this.host._showToast(this.host._t("toast.files_migrate_failed",{err:this.host._errText(t)}))}a.markers=n,l&&l!==r&&(a.markers=ei(a.markers,l,r)),l&&l!==r&&"derived_marker_state"===x.value_badge?.source?.kind&&x.value_badge.source.ref===`marker:${l}`&&(x.value_badge.source={kind:"derived_marker_state",ref:`marker:${r}`}),l&&l!==r&&"derived_marker_state"===x.value_source?.kind&&x.value_source.ref===`marker:${l}`&&(x.value_source={kind:"derived_marker_state",ref:`marker:${r}`}),a.markers=a.markers.filter(t=>t.id!==r&&t.id!==l&&("virtual"===x.binding||t.binding!==x.binding)),a.markers.push(x);const D=new Set(c);l&&l!==r&&D.add(l),D.delete(r),D.size&&a.settings?.marker_area_snapshot&&(a.settings={...a.settings,marker_area_snapshot:si(a.settings.marker_area_snapshot,D)});let I=null;const L=l?this.host._layout[l]:null,T=L?{s:L.s||h?.space||this.host._space,x:L.x,y:L.y}:l&&h&&this.host._defPos[l]?this.host._normPos(h.space,this.host._defPos[l].x,this.host._defPos[l].y):null;if(!d&&T&&T.s===y)r===l&&this.host._layout[r]&&!C||(I={s:T.s,x:T.x,y:T.y});else if(d||!this.host._layout[r]||C){let t=v.vb[0]+v.vb[2]/2,e=v.vb[1]+v.vb[3]/2;const s=f?v.rooms.find(t=>t.id===f):g?v.rooms.find(t=>t.area===g):void 0;s&&([t,e]=this.host._roomCenter(s)),I=this.host._normPos(y,t,e)}if(this.host._serverCfg!==s||this.host._cfgRev!==i||wt(s)!==o)return this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,busy:!1}),void this.host._showToast(this.host._t("toast.conflict"));if(a=this._prepareConfigCandidate(a),$=this.host._adoption.beginOptimistic(s,a),this.host._serverCfg=a,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate(),this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.cancel(),await this._saveConfigNow($),k=!0,I){const t=ii(I);this.host._layout={...this.host._layout,[r]:t},this.host._noteLayoutRev(await this.host.hass.callWS({type:"houseplan/layout/update",device_id:r,pos:t}))}const z=new Set(c);l&&l!==r&&z.add(l),z.delete(r);for(const t of z)delete this.host._layout[t],await this.host.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this.host._noteLayoutRev(t)).catch(()=>{});S&&P&&await this.host.hass.callWS({type:"houseplan/files/cleanup",marker_id:P}).catch(()=>{}),this._closeMarkerDialog(),this.host._cancelDeviceDrag(),this.host._devicePositionHistory.clear(),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.marker_saved"))}catch(t){!k&&$&&(this.host._rollbackOptimistic($),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate()),this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteMarker(){const t=this.host._markerDialog;if(!t||t.busy||!t.devId)return;const e=t.devId?this.host._devices.find(e=>e.id===t.devId):null,s=this.host._markers.find(e=>e.id===t.devId);if(!e&&!s)return;const i=e?"virtual"===e.bindingKind?"virtual":e.bindingKind&&e.bindingRef?`${e.bindingKind}:${e.bindingRef}`:"":s.binding;if(!i)return;const o=t.name||this.host._t("device.fallback"),a=t.devId,n=await this.host._confirmDanger({key:"remove-marker",kind:"destructive",title:this.host._t("confirm.remove_marker_title"),message:this.host._t("confirm.remove_marker_body"),objectName:o,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),r=this.host._markerDialog;if(!n||!r||r.busy||r.devId!==a)return;const l=this.host._devices.find(t=>t.id===a),h=this.host._markers.find(t=>t.id===a);if(!l&&!h)return;const c=this.host._serverCfg;if(!c)return;c.markers=c.markers||[];const d=c.markers,p=l?"virtual"===l.bindingKind?"virtual":l.bindingKind&&l.bindingRef?`${l.bindingKind}:${l.bindingRef}`:"":h.binding;if(!p||p!==i)return;const u=oi(c.markers,a,p,"virtual"===p);c.markers=ai(u.markers,u.cleanupIds);const _=u.cleanupIds;_.size&&c.settings?.marker_area_snapshot&&(c.settings={...c.settings,marker_area_snapshot:si(c.settings.marker_area_snapshot,_)}),this.host._markerDialog={...r,busy:!0};try{await this._saveConfigNow();for(const t of _){delete this.host._layout[t],delete this.host._defPos[t],this.host._dirtyPos.delete(t),this.host._sentPos.delete(t);const e=this.host._activityRt.get(t);e&&clearTimeout(e.timer),this.host._activityRt.delete(t),this.host._vacRt.delete(t),delete this.host._vacSrvTrails[t],await this.host.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this.host._noteLayoutRev(t)).catch(()=>{}),await this.host.hass.callWS({type:"houseplan/files/cleanup",marker_id:t}).catch(()=>{}),await this.host.hass.callWS({type:"houseplan/trail/delete",marker_id:t}).catch(()=>{})}this.host._deviceInboxReturn&&(this.host._deviceInboxReturn={...this.host._deviceInboxReturn,tab:"readd",anchor:p}),this._closeMarkerDialog(),this.host._cancelDeviceDrag(),this.host._devicePositionHistory.clear(),this.host._infoCard?.id===a&&this.host._closeInfoCard(),this.host._selId===a&&(this.host._selId=null),this.host._drag?.id===a&&(this.host._drag=null),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.marker_removed"))}catch(t){this.host._serverCfg===c&&(c.markers=d),this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_openSpaceDialog(t,e){if(this.host._serverStorage&&this.host._serverCfg){if("edit"===t){const s=this.host._serverCfg.spaces.find(t=>t.id===e);if(!s)return;const i=m(s),o=s.settings?.custom_fill&&"object"==typeof s.settings.custom_fill?ni(s.settings.custom_fill):null,a="none"===i.fill?{...o||ri,a:0}:o;this.host._spaceDialog={mode:t,spaceId:e,title:s.title,planUrl:s.plan_url||null,planFile:null,source:s.plan_url?"file":"draw",showBorders:i.showBorders,showNames:i.showNames,zeroWallStyle:hi(s),displayTouched:!0,hideDecor:i.hideDecor,hideOpenings:i.hideOpenings,roomColor:i.color,roomOpacity:i.opacity,fillMode:"none"===i.fill?"custom":i.fill,customFill:a,glowEnabled:i.glow,bgColor:i.bgColor,bgMode:"static"===s.settings?.bg_mode||"daynight"===s.settings?.bg_mode?s.settings.bg_mode:null,northDeg:Re({},s.settings),sunRays:"boolean"==typeof s.settings?.sun_rays?s.settings.sun_rays:null,tempMin:i.tempMin,tempMax:i.tempMax,showLqi:i.showLqi??this.host._config?.show_signal??!0,cardFontScale:i.cardFontScale,labelTemp:i.labelTemp,labelHum:i.labelHum,labelLqi:i.labelLqi,labelLight:i.labelLight,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,cellCmInput:li(Number(s.cell_cm)>0?Number(s.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1}}else this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...mi(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:ui,roomOpacity:pi,fillMode:"custom",customFill:{...ri,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:di,tempMax:ci,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:_i(this.host._imperial),cellCmInput:li(_i(this.host._imperial),this.host._imperial),cellCmTouched:!1,busy:!1};this.host._spaceDialog&&Go(this.host,this.host._spaceDialog)}else this.host._showToast(this.host._t("toast.integration_missing"))}async _pickPlanFile(t){const e=t.target,s=e.files?.[0];if(!s||!this.host._spaceDialog)return;e.value="",this._decorAssetGuardReplace=null;const i=await jo(s);if("reject"===i.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===i.kind)return void(this.host._backdropGuard=i.state);const o=await qo(s,i.ext,s.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:o})}_renderBackdropGuard(){const t=this._decorAssetGuardReplace;return null!==t?Uo(this.host,()=>{},()=>{this.host._backdropGuard=null,this._decorAssetGuardReplace=null},this.host.hass,(e,s)=>this._uploadDecorImage(e,s,t),(this.host._backdropGuard?.file.size||0)<=2097152)??d:Uo(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??d}_useServerPlan(t){const e=this.host._spaceDialog;e&&(this.host._spaceDialog={...e,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let e=0;e<40;e++){const e=this.host._display(t);if(e){const s=await new Promise(t=>{const s=new Image;s.onload=()=>t(s.naturalWidth&&s.naturalHeight?s.naturalWidth/s.naturalHeight:0),s.onerror=()=>t(0),s.src=e}),i=this.host._spaceDialog;return i&&i.planUrl===t&&Number.isFinite(s)&&s>0?(this.host._spaceDialog={...i,savedAspect:s},s):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const e=this.host._spaceDialog,s=e?.saved?.find(e=>e.name===t);if(!e||!s||s.used_by.length||s.url===e.planUrl)return;const i=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),o=this.host._spaceDialog,a=o?.saved?.find(e=>e.name===t);if(i&&o&&a&&a.url===s.url&&a.modified===s.modified&&!a.used_by.length&&a.url!==o.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const e=this.host._spaceDialog;e?.saved&&(this.host._spaceDialog={...e,saved:e.saved.filter(e=>e.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return p`
    ${this.host._t("space.loading")}
    `;const e=t.saved||[];if(!e.length)return p`
    ${this.host._t("space.no_saved")}
    `;return p`
    +
    `:p``}_openingAt(t){if(!this.host._openingsR.length)return null;const e=this.host._openingsR.flatMap(e=>{const s=e.angle*Math.PI/180,i=t[0]-e.rx,o=t[1]-e.ry,a=i*Math.cos(s)+o*Math.sin(s);return Math.abs(a)>e.rlen/2+Rt(12,this.host._cellCm)?[]:[{o:e,localY:-i*Math.sin(s)+o*Math.cos(s)}]});if(!e.length)return null;const s=this.host._spaceModel();if(!s)return null;const i=this.host._openCuts(),o=this.host._openingWallIndexFor(s,i).value;return e.find(({o:t,localY:e})=>{const s="gate"===t.type?!t.flip_v:t.flip_v,i=t.partitionHost||this.host._spaceWalls.length||"gate"===t.type?this.host._openingFace(t,o,!!s):{ox:0,oy:0,cm:0,side:-1},a=zs({type:t.type,length:t.rlen,angle:t.angle,amount:this.host._openingAmt(t),flipH:!!t.flip_h,flipV:!!t.flip_v,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,face:i});return Math.abs(e)<=a.hitHalf})?.o||null}_resolveOpeningPlacement(t){const e=this.host._openingPreset;if("opening"!==this.host._tool||!e)return null;const s=this.host._spaceModel();if(!s)return null;const i=this.host._openCuts(),o=this.host._openingWallIndexFor(s,i),a=`${o.key}|partitions:${this.host._cfgEpoch}`;this.host._openingPlacementIntervalsCache&&this.host._openingPlacementIntervalsCache.key===a||(this.host._openingPlacementIntervalsCache={key:a,value:[...O(s.rooms,this.host._spaceWalls,i,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,jd),...Fs(s.partitions,this.host._cellCm,this.host._gridPitch)]}),this.host._openingDimensionContextCache&&this.host._openingDimensionContextCache.key===a||(this.host._openingDimensionContextCache={key:a,value:Sd({rooms:s.rooms,walls:this.host._spaceWalls,openCuts:i,partitions:s.partitions,roomOpenings:this.host._roomWallOpeningInputs(),partitionCuts:this._partitionOpeningCuts(s),pitch:this.host._wallKeyPitch,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,coordScale:jd,epsilon:2e-4*this.host._gridPitch})});const n=Ns({pointer:[t[0],t[1]],preset:e,geometryRevision:this.host._cfgEpoch,renderedLength:this.host._cmToUnits(e.lengthCm),intervals:this.host._openingPlacementIntervalsCache.value,baseTolerance:1.5*this.host._gridPitch,bodyPointerPadding:this._cssPxToRender("touch"===this.host._pointerModality.modality||"pen"===this.host._pointerModality.modality?10:6),gridStep:this.host._gridPitch});this.host._openingJambBlockCm=n.jambBlockedTarget?n.jambBlockedTarget.physicalHalfWidth/this.host._gridPitch*this.host._cellCm:null;const r=n.candidate;if(!r)return null;const l="gate"===r.type?!r.flipV:r.flipV;let h;if(r.host){const t=A({id:"preview",type:r.type,x:r.x/jd,y:r.y/jd,angle:r.angle,length:r.renderedLength/jd,host:r.host},s.partitions,jd,this.host._cellCm,this.host._gridPitch).resolved;h=t?As(t,l):{ox:0,oy:0,cm:0,side:-1}}else h=Es(o.value,{x:r.x,y:r.y,angle:r.angle,length:r.renderedLength,flip_v:l});const c="mi"===this.host.hass?.config?.unit_system?.length,d=zd(r,this.host._openingDimensionContextCache.value).map(t=>({x:t.label[0],y:t.label[1],text:le(t.distance/this.host._gridPitch*this.host._cellCm,c),dimension:t}));return{...r,face:h,measure:{labels:d,guide:r.measure.guide}}}_activateOpeningPlacement(t){this._activateMarkupTool("opening"),"opening"===this.host._tool&&(this.host._openingPreset=Os(t,++this.host._openingPresetRevision),this.host._openingHoverCandidate=null,this.host._cursorPt=null)}_clearOpeningPlacement(t){this.host._openingHoverCandidate=null,this.host._openingJambBlockCm=null,t&&(this.host._openingPreset=null,this.host._openingRebindId=null)}_openingClick(t){const e=this.host._spaceModel();if(!e)return;const s=this.host._openingRebindId?null:this._openingAt(t);if(s)return void this._editOpening(s);const i=this.host._openingPreset;if(!i)return;const o=this.host._openingHoverCandidate,a=o&&Bs(o,[t[0],t[1]],i.revision,this.host._cfgEpoch)?o:this._resolveOpeningPlacement(t);if(!a){if(null!=this.host._openingJambBlockCm)return void this.host._showToast(this.host._t("opening.partition_jamb_margin",{distance:le(this.host._openingJambBlockCm,this.host._imperial)}));const s=1.5*this.host._gridPitch,i=R(t,e.rooms,s);return i&&Hs(i.x,i.y,i.angle,this.host._openCuts(),s)?void this.host._showToast(this.host._t("toast.opening_on_zero_wall")):void this.host._showToast(this.host._t("toast.opening_no_wall"))}const n=this.host._openingRebindId?this.host._curSpaceCfg?.openings?.find(t=>t.id===this.host._openingRebindId):null;this.host._openingDialog={...n?{id:n.id,type:n.type,lengthCm:Math.round(n.length*jd/this.host._gridPitch*this.host._cellCm),lengthTouched:!1,contact:n.contact||"",lock:n.lock||"",invert:!!n.invert,flipH:!!n.flip_h,flipV:!!n.flip_v}:{type:a.type,lengthCm:a.lengthCm,contact:"",lock:"",invert:!1,flipH:a.flipH,flipV:a.flipV},...a.host?{host:a.host}:{},x:a.x,y:a.y,angle:a.angle},this.host._openingRebindId=null,this.host._openingHoverCandidate=null,this.host._cursorPt=null}_editOpening(t){this.host._openingDialog={id:t.id,type:t.type,lengthCm:Math.round(t.rlen/this.host._gridPitch*this.host._cellCm),lengthTouched:!1,contact:t.contact||"",lock:t.lock||"",invert:!!t.invert,flipH:!!t.flip_h,flipV:!!t.flip_v,..."partition"===t.host?.kind?{host:{...t.host}}:{},x:t.rx,y:t.ry,angle:t.angle}}_opPointerDown(t,e){if("plan"===this.host._mode&&this.host._spaceModel()&&"resize"!==this.host._tool){t.preventDefault(),t.stopPropagation();try{qd(t)}catch{}this.host._opDrag={id:e.id,moved:!1,sx:t.clientX,sy:t.clientY,dirty:!1,before:this._geometrySnapshot()}}}_opPointerMove(t,e){Dr(this.host,"opening",()=>this._opPointerMoveNow(t,e))}_opPointerMoveNow(t,e){if(!this.host._opDrag||this.host._opDrag.id!==e.id)return;if(Math.abs(t.clientX-this.host._opDrag.sx)+Math.abs(t.clientY-this.host._opDrag.sy)<=3)return;const s=this.host._spaceModel();if(!s)return;const i=this._svgPoint(t),o=this.host._curSpaceCfg,a=o?.openings?.find(t=>t.id===e.id);if(!a)return;if("partition"===a.host?.kind){const t=s.partitions.find(t=>t.id===a.host.id);if(!t)return;const e=t.b[0]-t.a[0],o=t.b[1]-t.a[1],n=Math.hypot(e,o);if(!(n>1e-9))return;const r=e/n,l=o/n;if(Math.abs((i[0]-t.a[0])*l-(i[1]-t.a[1])*r)>4*this.host._gridPitch)return;const h=a.length*jd/2+W(t,this.host._cellCm,this.host._gridPitch);let c=(i[0]-t.a[0])*r+(i[1]-t.a[1])*l;if(c=Math.round(c/this.host._gridPitch)*this.host._gridPitch,c=Math.max(h,Math.min(n-h,c)),n<2*h-1e-9)return;const d=c/n,p=(t.a[0]+r*c)/jd,u=(t.a[1]+l*c)/this.host._spaceH;let _=180*Math.atan2(o,e)/Math.PI;_>=90?_-=180:_<-90&&(_+=180);const m=a.host.t!==d||a.x!==p||a.y!==u||a.angle!==_;return this.host._opDrag.moved=!0,m&&(this.host._opDrag.dirty=!0),a.host={...a.host,t:d},a.x=p,a.y=u,a.angle=_,this.host._opMeasure=null,m&&this.host._cfgEpoch++,void this.host.requestUpdate()}const n=R(i,s.rooms,4*this.host._gridPitch);if(!n)return;this.host._opDrag.moved=!0;const r=this._opRuler(n,a.length*jd);this.host._opMeasure=r.measure;const l=r.x/jd,h=r.y/this.host._spaceH,c=a.x!==l||a.y!==h||a.angle!==n.angle;if(c&&(this.host._opDrag.dirty=!0),a.x=l,a.y=h,a.angle=n.angle,Number(this.host._serverCfg?.model_version||0)>=9){const t=Bn(a,o?.wall_segments||[]);t?a.host=t:delete a.host}c&&this.host._cfgEpoch++,this.host.requestUpdate()}_opRuler(t,e){const s=this.host._spaceModel()?.rooms||[],i=this.host._gridPitch/2;let o=t.x,a=t.y,n=Ws([o,a],t.angle,e,s,i);if(n&&n.centered&&(o!==n.wallCenter[0]||a!==n.wallCenter[1]))[o,a]=n.wallCenter,n=Ws([o,a],t.angle,e,s,i);else if(n){const[r,l]=n.wallA,[h,c]=n.wallB,d=h-r,p=c-l,u=Math.hypot(d,p);if(u>0){const h=this.host._gridPitch,c=Math.min(e/2,u/2);let _=Math.round(((o-r)*d+(a-l)*p)/u/h)*h;_=Math.max(c,Math.min(u-c,_)),o=r+_/u*d,a=l+_/u*p,n=Ws([o,a],t.angle,e,s,i)||n}}if(!n)return{x:o,y:a,angle:t.angle,measure:null};const r="mi"===this.host.hass?.config?.unit_system?.length,l=(t,e)=>({x:e[0],y:e[1],text:le(t/this.host._gridPitch*this.host._cellCm,r)});return{x:o,y:a,angle:t.angle,measure:{labels:[l(n.sideA,n.midA),l(n.sideB,n.midB)],guide:n.centered?{x:n.wallCenter[0],y:n.wallCenter[1],angle:t.angle}:null}}}_opPointerUp(t,e){if(!this.host._opDrag||this.host._opDrag.id!==e.id)return;Ir(this.host,"opening");const s=this.host._opDrag,i=s.moved;this.host._opMeasure=null,i&&s.dirty&&this._commitPhysicalGeometry(this.host._t("history.move_opening"),s.before);const o=()=>{this.host._opDrag=null,this.host.requestUpdate()};i?window.setTimeout(o,0):o()}_opClick(t,e){"plan"===this.host._mode&&"resize"===this.host._tool||(t.stopPropagation(),this.host._opDrag?.moved||"plan"===this.host._mode&&this._editOpening(e))}_saveOpening(){const t=this.host._openingDialog,e=this.host._curSpaceCfg,s=this.host._spaceModel();if(!t||!e||!s)return;const i=this._geometrySnapshot(),o=this.host._spaceH,a=(e.openings||[]).find(e=>e.id===t.id),n={...a||{},id:t.id||"o"+Date.now().toString(36),type:t.type,x:t.x/jd,y:t.y/o,angle:t.angle,length:a&&!t.lengthTouched?a.length:this.host._cmToUnits(Math.max(20,t.lengthCm))/jd,...t.host?{host:{...t.host}}:{}};if("partition"===n.host?.kind){const t=js(a,n)?q(n,s.partitions,jd,this.host._cellCm,this.host._gridPitch):A(n,s.partitions,jd,this.host._cellCm,this.host._gridPitch);if(!t.resolved){const e=s.partitions.find(t=>t.id===n.host.id);if("does-not-fit-jamb"===t.reason&&e){const t=W(e,this.host._cellCm,this.host._gridPitch);this.host._showToast(this.host._t("opening.partition_jamb_margin",{distance:le(t/this.host._gridPitch*this.host._cellCm,this.host._imperial)}))}else this.host._showToast(this.host._t("opening.partition_orphan"));return}const i=(e.openings||[]).flatMap(t=>{if(!t.host||t.id===n.id)return[];const e=A(t,s.partitions,jd,this.host._cellCm,this.host._gridPitch).resolved;return e?[e]:[]});if(Gs(t.resolved,i))return void this.host._showToast(this.host._t("toast.opening_no_wall"));Object.assign(n,E(n,t.resolved,jd))}else if(Number(this.host._serverCfg?.model_version||0)>=9){const t=Bn(n,e.wall_segments||[]);if(!t)return void this.host._showToast(this.host._t("toast.opening_no_wall"));n.host=t}else delete n.host;"passage"===t.type?(delete n.contact,delete n.lock,delete n.invert,delete n.flip_h,delete n.flip_v):(n.contact=t.contact||null,n.lock=("door"===t.type||"gate"===t.type)&&t.lock||null,n.invert=t.invert||void 0,n.flip_h="gate"!==t.type&&t.flipH||void 0,n.flip_v=t.flipV||void 0),e.openings=e.openings||[];const r=e.openings.findIndex(t=>t.id===n.id);r>=0?e.openings[r]=n:e.openings.push(n),this._commitPhysicalGeometry(this.host._t(t.id?"history.edit_opening":"history.add_opening"),i),this.host._openingDialog=null,this.host.requestUpdate()}_deleteOpening(){const t=this.host._openingDialog,e=this.host._curSpaceCfg;if(!t?.id||!e?.openings)return;const s=this._geometrySnapshot();e.openings=e.openings.filter(e=>e.id!==t.id),this._commitPhysicalGeometry(this.host._t("history.delete_opening"),s),this.host._openingDialog=null,this.host.requestUpdate()}_contactCandidates(){const t=[];for(const e of Object.keys(this.host.hass.states)){if(!this.host._openingEntityAvailable(e))continue;const s=e.split(".")[0];if("binary_sensor"!==s&&"cover"!==s)continue;const i=this.host.hass.states[e],o=["door","window","opening","garage_door","garage"].includes(i?.attributes?.device_class||"");("cover"!==s||o)&&t.push([e,i?.attributes?.friendly_name||e,o?0:1])}return t.sort((t,e)=>t[2]-e[2]||t[1].localeCompare(e[1])).map(([t,e])=>({value:t,label:e}))}_lockCandidates(){return Object.keys(this.host.hass.states).filter(t=>t.startsWith("lock.")&&this.host._openingEntityAvailable(t)).map(t=>({value:t,label:this.host.hass.states[t]?.attributes?.friendly_name||t})).sort((t,e)=>t.label.localeCompare(e.label))}_toggleOpeningEntityPicker(t){const e=this.host._openingDialog;if(!e)return;const s="contact"===t?!e.contactOpen:!e.lockOpen;this.host._openingDialog={...e,contactOpen:"contact"===t&&s,lockOpen:"lock"===t&&s}}_filterOpeningEntities(t,e){const s=this.host._openingDialog;s&&(this.host._openingDialog="contact"===t?{...s,contactFilter:e}:{...s,lockFilter:e})}_selectOpeningEntity(t,e){const s=this.host._openingDialog;s&&(this.host._openingDialog="contact"===t?{...s,contact:e,contactOpen:!1,contactFilter:""}:{...s,lock:e,lockOpen:!1,lockFilter:""})}_mergeClick(t){const e=this.host._spaceModel();if(!e)return;const s=e.rooms,i=[...s].reverse().find(e=>this._pointInRoom(t,e));if(!i?.id)return;const o=i.id;if(!this.host._mergeSel||this.host._mergeSel===o)return void(this.host._mergeSel=this.host._mergeSel===o?null:o);const a=s.find(t=>t.id===this.host._mergeSel),n=a?N(a):null,r=N(i),l=n&&r?qs(n,r):null;if(!l)return this.host._showToast(this.host._t("toast.merge_not_adjacent")),void(this.host._mergeSel=null);this.host._mergeDialog={aId:this.host._mergeSel,bId:o,poly:l,pick:"a"},this.host._mergeSel=null}_commitMerge(){const t=this.host._mergeDialog,e=this.host._curSpaceCfg;if(!t||!e||!this.host._spaceModel())return;const s=this._geometrySnapshot(),i=this.host._spaceH,o="a"===t.pick?t.aId:t.bId,a="a"===t.pick?t.bId:t.aId,n=Od(this.host._serverCfg?.markers||[],{kind:"merge",dropId:a,keepId:o});s&&n.changed&&(s.roomReferences=n.before);const r=e.rooms.find(t=>t.id===o);if(!r)return void(this.host._mergeDialog=null);r.poly=t.poly.map(t=>[t[0]/jd,t[1]/i]),delete r.x,delete r.y,delete r.w,delete r.h,e.rooms=e.rooms.filter(t=>t.id!==a),n.changed&&this.host._serverCfg&&(this.host._serverCfg.markers=n.markers);const l=this._commitPhysicalGeometry(this.host._t("history.merge_rooms"),s);this.host._mergeDialog=null,this.host._regSignature="",this.host._maybeRebuildDevices(),l&&this.host._showToast(this.host._t("toast.rooms_merged",{name:r.name||""}))}_splitClick(t){const e=this.host._spaceModel();if(!e)return;const s=e.rooms;if(!this.host._splitSel){const e=[...s].reverse().find(e=>this._pointInRoom(t,e));if(!e?.id)return;return void(this.host._splitSel={roomId:e.id,pts:[]})}const i=s.find(t=>t.id===this.host._splitSel.roomId),o=i?N(i):null;if(!i||!o)return void(this.host._splitSel=null);const a=.02*this.host._gridPitch,n=6*this.host._gridPitch,r=Us(t,o),l=r&&Ks(r,o,this.host._gridPitch)||r,h=r&&l&&Math.hypot(r[0]-t[0],r[1]-t[1])<=n?l:null,c=!!h&&Vs(h,o,a),d=this.host._splitSel.pts;if(!d.length)return c?void(this.host._splitSel={...this.host._splitSel,pts:[h]}):void this.host._showToast(this.host._t("toast.split_pick_wall"));if(!c){const e=this._snap(t);return Je(e,o,a)?void(this.host._splitSel={...this.host._splitSel,pts:[...d,e]}):void this.host._showToast(this.host._t("toast.split_pick_inside"))}const p=Ye(o,[...d,h],a);if(!p)return void this.host._showToast(this.host._t("toast.split_bad_cut"));this._resetRoomDialogFields();const[u,_]=p,m=Zt(u)>=Zt(_)?u:_,g=m===u?_:u;this.host._pendingSplit={roomId:i.id,mainPoly:m,newPoly:g},this.host._cursorPt=null,this.host._nameSel="",this.host._areaSel="",this.host._roomDialog=!0}_markupMove(t){if(!this.host._markup)return;if("column"===this.host._tool)return void(this.host._cursorPt=this._snap(this._svgPoint(t)));if("opening"===this.host._tool||"wallthick"===this.host._tool)return void(this.host._cursorPt=this._svgPoint(t));const e="draw"===this.host._tool&&!this.host._contourClosed,s="split"===this.host._tool&&!!this.host._splitSel?.pts?.length;if(!e&&!s)return;const i=this._svgPoint(t);if(e){const e=this._resolvePlanDrawPoint(i,t.shiftKey);if(this.host._planSnapHover={contextKey:e.contextKey,candidate:e.candidate,conflicts:e.conflicts},this._syncPlanSnapConflictMarkers(e.conflicts),this._syncPlanSnapActiveMarker(e.candidate),!this.host._path.length)return;return void(this.host._cursorPt=e.point)}this.host._cursorPt=this._snap(i)}_saveRoom(){(this.host._areaSel||this.host._nameSel.trim())&&Mt(this.host._roomTempMin,this.host._roomTempMax).valid&&(this.host._wallFaceBatch?this._decideWallFace(!0):this._commitRoom())}_decideWallFace(t){const e=this.host._wallFaceBatch;if(!e)return;const s=e.candidates[e.index];if(!s)return;if(!t&&(s.existing||s.repair)&&1===e.candidates.length)return this.host._wallFaceBatch=null,this.host._roomDialog=!1,this.host._nameSel="",this.host._areaSel="",void this.host.requestUpdate();const i=t?{candidate:s,create:!0,name:this.host._nameSel.trim(),area:this.host._areaSel||null,settings:this._roomSettingsFromDialog()?JSON.parse(JSON.stringify(this._roomSettingsFromDialog())):null}:{candidate:s,create:!1},o=[...e.decisions,i],a=e.index+1;if(a"number"==typeof t&&Number.isFinite(t)&&t>=0?t:null,o=.02*this.host._gridPitch,a=this.host._spaceModel();if(!a)return B;for(const e of this._planSnapGeometrySnapshot().value.segments)if(!("room"===e.sourceKind||de(t,[e.a[0],e.a[1],e.b[0],e.b[1]])>o)&&"partition"===e.sourceKind)return i(a.partitions.find(t=>t.id===e.sourceId)?.cm)??B;const n=kc(Math.max(0,e.length-1),s,this.host._drawWallCm,B);for(let s=0;s+1[...t]);if(!e)return s;const i=this.host._activeWallChainPartitionIds.findIndex((t,s)=>this._activeWallSourceKey(s)===e.sourceKey),o=i>=0?i+("b"===e.endpoint?1:0):-1;return o>=0&&oe.key===t.sourceKey),a=i.find(e=>e.key===t.targetSourceKey);if(!o||!a)return!1;const n="a"===t.endpoint?o.a:o.b;return!(Math.hypot(n[0]-t.from[0],n[1]-t.from[1])>s)&&(!(de(t.to,[a.a[0],a.a[1],a.b[0],a.b[1]])>s)&&!function(t,e){if(!t.sourceKey.startsWith("static:partition|"))return!1;const s=t.sourceKey.slice(17).split("|")[0];return!!s&&e.some(t=>"partition"===t.host?.kind&&t.host.id===s)}(t,this.host._curSpaceCfg?.openings||[]))}_applyWallRepair(t,e){const s=this.host._curSpaceCfg;if(!s||!this._validateWallRepair(t,e.activePath))return!1;if(!t.sourceKey.startsWith("static:"))return!1;const[i,o]=t.sourceKey.slice(7).split("|");if("partition"===i){const i=(s.partitions||[]).find(t=>t.id===o);if(!i)return!1;const a=[i.a[0]*jd,i.a[1]*jd],n=[i.b[0]*jd,i.b[1]*jd],r=Math.hypot(a[0]-t.from[0],a[1]-t.from[1])<=2e-4*this.host._gridPitch?i.a:Math.hypot(n[0]-t.from[0],n[1]-t.from[1])<=2e-4*this.host._gridPitch?i.b:null;if(!r)return!1;(e=>{e[0]=t.to[0]/jd,e[1]=t.to[1]/jd})(r);const l=e.activePartitionIds.indexOf(o);if(l>=0){const s=l+("b"===t.endpoint?1:0);e.activePath[s]&&(e.activePath[s]=[...t.to])}return!0}return!1}_applyWallFaceBatch(){const t=this.host._wallFaceBatch,e=this.host._curSpaceCfg,s=this.host._spaceModel();if(!t||!e||!s)return;const i=(t,e)=>{this.host._showToast(this.host._t(t,e)),this._roomDialogCancel()},o=t.decisions.filter(t=>t.create),a=o.map(t=>t.candidate.ring),n=s.rooms;for(let t=0;ts.id!==e&&!!N(s)&&Vt(a[t],N(s)));if(s)return void i("toast.room_overlap",{name:s.name||""})}if((e.rooms||[]).length+o.length>400)return void i("toast.physical_limit");if(o.some(t=>t.candidate.split&&!e.rooms.some(e=>e.id===t.candidate.split.roomId)))return void i("toast.contour_cannot_close");const r=o.map(t=>t.candidate.repair).filter(t=>!!t);if(r.length>1||r[0]&&!this._validateWallRepair(r[0],t.activePath))return void i("toast.wall_repair_changed");if(this._activePathWithRepair(t.activePath,r[0]),!o.length){if(!this._finalizeWallChainPartitions(t.activePartitionIds))return;return this.host._path=[],this.host._activeWallChainId=null,this.host._activeWallChainPartitionIds=[],this.host._wallChainSegmentCms=[],this.host._wallChainRedo=[],this.host._closingWallCm=null,this.host._wallFaceBatch=null,this.host._roomDialog=!1,this.host._nameSel="",this.host._areaSel="",this.host.requestUpdate(),void this.host._showToast(this.host._t("toast.wall_chain_saved"))}const l=new Set(t.activePartitionIds),h=2e-4*this.host._gridPitch,c=o.map(t=>t.candidate.ring.map((t,e,i)=>{const o=i[(e+1)%i.length],a=s.partitions.filter(e=>{const s=Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1]);if(!(s>h))return!1;const i=(e.b[0]-e.a[0])/s,a=(e.b[1]-e.a[1])/s,n=t=>(t[0]-e.a[0])*i+(t[1]-e.a[1])*a;return de(t,[e.a[0],e.a[1],e.b[0],e.b[1]])<=h&&de(o,[e.a[0],e.a[1],e.b[0],e.b[1]])<=h&&n(t)>=-h&&n(t)<=s+h&&n(o)>=-h&&n(o)<=s+h});return a.sort((t,e)=>Number(l.has(e.id))-Number(l.has(t.id))||Math.hypot(t.b[0]-t.a[0],t.b[1]-t.a[1])-Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])||t.id.localeCompare(e.id)),a[0]?.id||""})),d=this._geometrySnapshot();if(!d)return void i("toast.geometry_unsafe");const p=()=>{this._restoreGeometryStateLocal(d),i("toast.geometry_unsafe")};if(r[0]&&!this._applyWallRepair(r[0],t))return void i("toast.wall_repair_changed");const u=o.some(t=>!!t.candidate.split),_=u?Pe(s.rooms,e.walls,this.host._openCuts(),this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,jd):null,m=u&&Array.isArray(e.walls)?e.walls:null;for(const t of o){const s=t.candidate.split;if(!s)continue;const i=e.rooms.find(t=>t.id===s.roomId);if(!i)return void p();i.poly=s.mainPoly.map(t=>[t[0]/jd,t[1]/this.host._spaceH]),delete i.x,delete i.y,delete i.w,delete i.h}const g=Date.now().toString(36),f=[];if(o.forEach((t,s)=>{const i=t.area?this.host.hass.areas[t.area]?.name:"",o={id:`r${g}-${s}`,name:t.name||i||this.host._t("room.default_name"),area:t.area||null,poly:t.candidate.ring.map(t=>[t[0]/jd,t[1]/this.host._spaceH]),...c[s].some(Boolean)?{wall_ids:c[s]}:{},...t.settings?{settings:JSON.parse(JSON.stringify(t.settings))}:{}};e.rooms.push(o),f.push({room:o,decision:t})}),u){const t=this.host._normalizeWalls(_,this.host._openCuts());t.length?e.walls=t:m?.length?e.walls=m:delete e.walls}if(f.length){this.host._cfgEpoch++;const s=this.host._openCuts(),i=this.host._spaceModel();if(!i)return void p();let o=e.walls;for(const{room:e,decision:a}of f){const n=a.candidate.ring,r=this._wallSourceCmAt(n[0],t.activePath,t.activeCms);o=Js(o,i.rooms,e.id,r,this.host._wallKeyPitch,s,jd);for(const a of O(i.rooms,o,s,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,jd)){if(a.roomId!==e.id||"outer"!==a.kind)continue;const s=[(a.a[0]+a.b[0])/2,(a.a[1]+a.b[1])/2];o=j(o,a.a,a.b,this._wallSourceCmAt(s,t.activePath,t.activeCms),this.host._wallKeyPitch,jd)}}const a=this.host._normalizeWalls(o,s);a.length?e.walls=a:delete e.walls,this.host._cfgEpoch++;const n=this.host._spaceModel();if(!n)return void p();const r=pn(e,n,e.walls,s,{pitch:this.host._wallKeyPitch,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,coordScale:jd,allowCoincidentPartitions:!0});r.walls.length?e.walls=r.walls:delete e.walls,r.partitions.length?e.partitions=r.partitions:delete e.partitions,r.openings.length?e.openings=r.openings:delete e.openings}if(!this._commitPhysicalGeometry(this.host._t("history.wall_face_batch"),d))return;this.host._path=[],this.host._activeWallChainId=null,this.host._activeWallChainPartitionIds=[],this.host._wallChainSegmentCms=[],this.host._wallChainRedo=[],this.host._closingWallCm=null,this.host._wallFaceBatch=null,this.host._roomDialog=!1,this.host._nameSel="",this.host._areaSel="",this.host._regSignature="",this.host._maybeRebuildDevices();const b=new Set(o.map(t=>t.area).filter(t=>!!t));if(b.size){const t={...this.host._layout};for(const e of this.host._devices){if(!b.has(e.area||"")||e.space!==this.host._space)continue;if(this.host._layout[e.id])continue;const s=this.host._defPos[e.id];s&&(t[e.id]={s:this.host._space,x:s.x/jd,y:s.y/jd},this.host._dirtyPos.add(e.id))}this.host._layout=t,this.host._persistLayout()}this.host._showToast(this.host._t(o.length?"toast.wall_rooms_saved":"toast.wall_chain_saved",{n:o.length}))}_commitRoom(){const t=this.host._curSpaceCfg,e=this.host._spaceModel();if(!t||!e)return;const s=this._geometrySnapshot();if(!s)return;const i=()=>{this._restoreGeometryStateLocal(s),this.host._showToast(this.host._t("toast.geometry_unsafe"))},o=this.host._spaceH,a=!!this.host._pendingSplit,n=a?Pe(e.rooms,t.walls,this.host._openCuts(),this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,jd):null,r=a&&Array.isArray(t.walls)?t.walls:null;let l;if(this.host._pendingSplit){const e=t.rooms.find(t=>t.id===this.host._pendingSplit.roomId);if(!e)return this.host._pendingSplit=null,this.host._splitSel=null,void(this.host._roomDialog=!1);e.poly=this.host._pendingSplit.mainPoly.map(t=>[t[0]/jd,t[1]/o]),delete e.x,delete e.y,delete e.w,delete e.h,l=this.host._pendingSplit.newPoly}else{if(!this.host._contourClosed)return;l=this.host._path.slice(0,-1)}const h=this.host._areaSel?this.host.hass.areas[this.host._areaSel]?.name:"",c={id:"r"+Date.now().toString(36),name:this.host._nameSel||h||this.host._t("room.default_name"),area:this.host._areaSel||null,poly:l.map(t=>[t[0]/jd,t[1]/o]),...this._roomSettingsFromDialog()?{settings:this._roomSettingsFromDialog()}:{}};if(t.rooms.push(c),a){const e=this.host._normalizeWalls(n,this.host._openCuts());e.length?t.walls=e:r?.length?t.walls=r:delete t.walls}if(!a){const e=kc(l.length,[...this.host._wallChainSegmentCms,this.host._closingWallCm??void 0],this.host._drawWallCm,B),s=e[0];if(null!=s){this.host._cfgEpoch++;const o=this.host._openCuts(),a=this.host._spaceModel();if(!a)return void i();let n=Js(t.walls,a.rooms,c.id,s,this.host._wallKeyPitch,o,jd);for(const t of O(a.rooms,n,o,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,jd)){if(t.roomId!==c.id||"outer"!==t.kind)continue;const s=[(t.a[0]+t.b[0])/2,(t.a[1]+t.b[1])/2],i=l.findIndex((t,e)=>{const i=l[(e+1)%l.length];return de(s,[t[0],t[1],i[0],i[1]])<=.02*this.host._gridPitch});i>=0&&(n=j(n,t.a,t.b,e[i],this.host._wallKeyPitch,jd))}n=this.host._normalizeWalls(n,o),n.length?t.walls=n:delete t.walls;const r=this.host._spaceModel();if(!r)return void i();const h=pn(t,r,t.walls,o,{pitch:this.host._wallKeyPitch,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,coordScale:jd,allowCoincidentPartitions:!0});h.walls.length?t.walls=h.walls:delete t.walls,h.partitions.length?t.partitions=h.partitions:delete t.partitions,h.openings.length?t.openings=h.openings:delete t.openings}}const d=this._commitPhysicalGeometry(this.host._t(a?"history.split_room":"history.add_room"),s);this.host._path=[],this.host._activeWallChainId=null,this.host._activeWallChainPartitionIds=[],this.host._wallChainSegmentCms=[],this.host._wallChainRedo=[],this.host._closingWallCm=null,this.host._pendingSplit=null,this.host._splitSel=null;const p=this.host._areaSel;if(this.host._areaSel="",this.host._nameSel="",this.host._roomDialog=!1,this.host._regSignature="",this.host._maybeRebuildDevices(),!d)return;let u=0;if(p){const t=jd,e={...this.host._layout};for(const s of this.host._devices){if(s.area!==p||s.space!==this.host._space)continue;if(u++,this.host._layout[s.id])continue;const i=this.host._defPos[s.id];i&&(e[s.id]={s:this.host._space,x:i.x/jd,y:i.y/t},this.host._dirtyPos.add(s.id))}this.host._layout=e,this.host._persistLayout()}const _=this.host._model.find(t=>t.id===this.host._space)?.rooms.length||0;this.host._showToast(p?this.host._t("toast.room_saved",{n:_,added:u}):this.host._t("toast.room_saved_no_area",{n:_}))}_cancelPath(){this.host._wallRepairDiagnostic=null,this.host._path=[],this.host._activeWallChainId=null,this.host._activeWallChainPartitionIds=[],this.host._wallChainSegmentCms=[],this.host._wallChainRedo=[],this.host._closingWallCm=null,this._clearPlanSnapHover(),this.host._roomDialog=!1,this.host._pendingSplit=null,this.host._wallFaceBatch=null,this.host._splitSel=null,this.host._mergeSel=null,this.host._mergeDialog=null,this.host._physicalSel=null,this.host._physicalDrag=null,this.host._physicalRotate=null,this._clearOpeningPlacement(!0)}_roomDialogCancel(){if(this.host._roomDialog=!1,this.host._roomEditId)return this.host._roomEditId=null,this.host._nameSel="",void(this.host._areaSel="");if(this.host._wallFaceBatch){const t=this.host._wallFaceBatch;return this.host._wallFaceBatch=null,this.host._path=t.activePath.map(t=>[...t]),this.host._wallChainSegmentCms=[...t.activeCms],this.host._activeWallChainPartitionIds=[...t.activePartitionIds],this.host._activeWallChainId||=`chain-${Date.now().toString(36)}`,this.host._nameSel="",this.host._areaSel="",void this.host.requestUpdate()}if(this.host._pendingSplit)return this.host._pendingSplit=null,void(this.host._splitSel=null);this.host._undoPoint()}_openDeviceInbox(){this.host._deviceInboxReturn=null,this.host._deviceInbox=this.host._deviceInbox||{tab:"on_plan",search:"",showEntities:!1,onlyNew:!1,limit:100}}_closeMarkerDialog(){this._radarSetup.isDirty()?this._closeMarkerDialogGuarded():(this._radarSetup.reset(),function(t){if(t._markerDialog=null,!t._deviceInboxReturn)return;const e={...t._deviceInboxReturn};t._deviceInbox=e,t._deviceInboxReturn=null,e.anchor&&t.updateComplete.then(()=>requestAnimationFrame(()=>{const s=`.device-inbox-row[data-binding="${CSS.escape(e.anchor)}"]`;t.renderRoot.querySelector(s)?.scrollIntoView({block:"nearest"})}))}(this.host))}async _closeMarkerDialogGuarded(){if(!await this._radarSetup.discardIfAllowed())return await this.host.updateComplete,void this.host.renderRoot.querySelector("#marker-dialog")?.rejectClose();this._closeMarkerDialog()}_deviceInboxCandidates(t){return Xh({hass:this.host._planHass,devices:this.host._devices,markers:this.host._markers,showEntities:t,labels:{device:this.host._t("marker.sub_device"),z2mGroup:this.host._t("marker.sub_z2m_group"),group:this.host._t("marker.sub_group"),helper:this.host._t("marker.sub_helper"),entity:this.host._t("marker.sub_entity")}})}_deviceInboxRows(){const t=this.host._deviceInbox||this.host._deviceInboxReturn,e=!!t?.showEntities,s=[this.host._haRegistry.revision,this.host._cfgRev,this.host._cfgEpoch,this.host._regSignature,this.host._newSyncKey,e?1:0,this.host._showAll?1:0,l(this.host.hass,this.host._config?.language)].join("|");if(this.host._deviceInboxMemo?.key===s)return this.host._deviceInboxMemo.rows;const i=this._deviceInboxCandidates(e),o=new Set(i.map(t=>t.value));for(const t of this.host._markers)t.binding&&"virtual"!==t.binding&&o.add(t.binding);for(const t of this.host._devices)t.bindingKind&&"virtual"!==t.bindingKind&&t.bindingRef&&o.add(`${t.bindingKind}:${t.bindingRef}`);const a=new Map;for(const t of o)a.set(t,this.host._bindingStatus(t));const n=this.host._areaToSpace,r={};for(const[t,e]of Object.entries(this.host.hass?.areas||{}))r[t]=n[t]?.room?.name||e?.name||t;for(const[t,e]of Object.entries(n))r[t]=e.room.name||r[t]||t;const h=Object.fromEntries(this.host._model.map(t=>[t.id,t.title])),c=Object.fromEntries(Object.entries(n).map(([t,e])=>[t,e.space])),d={},p=new Map;for(const[t,e]of Object.entries(this.host._fullRegistryHass.entities||{})){const s=String(e?.platform||"").trim();if(s&&(d[`entity:${t}`]=s),s&&e?.device_id){const t=p.get(e.device_id)||new Set;t.add(s),p.set(e.device_id,t)}}for(const[t,e]of p)d[`device:${t}`]=[...e].sort().join(", ");const u={};for(const[t,e]of Object.entries(this.host._fullRegistryHass.devices||{})){const s=`device:${t}`,i=p.get(t)||new Set,o=Array.isArray(e?.identifiers?.[0])?String(e.identifiers[0][0]||""):"";o&&!d[s]&&(d[s]=o);const a=[o,...i].some(t=>this.host._excluded.has(t));"service"===e?.entry_type?u[s]="service_entry":a?u[s]="excluded_integration":"Group"===e?.model?u[s]="grouped_light":/scene/i.test(e?.model||"")?u[s]="excluded_domain":(/bridge/i.test(`${e?.model||""}${e?.name||""}`)||"myheat"===o&&e?.via_device_id)&&(u[s]="represented_by_parent")}const _=function(t){const{devices:e,markers:s,candidates:i,statuses:o,newDeviceIds:a,showHiddenOnPlan:n,areaNames:r={},spaceNames:l={},spaceByArea:h={},integrationByBinding:c={},reasonByBinding:d={}}=t,p=new Map;for(const t of e)!t.virtual&&t.bindingKind&&"virtual"!==t.bindingKind&&t.bindingRef&&p.set(`${t.bindingKind}:${t.bindingRef}`,t);const u=new Map,_=new Map;for(const t of s)t?.binding&&"virtual"!==t.binding&&(t.removed?_.set(t.binding,t):u.set(t.binding,t));const m=new Map(i.map(t=>[t.value,t])),g=new Set([...p.keys(),...u.keys(),...m.keys(),...[..._.keys()].filter(t=>m.has(t))]),f=[];for(const t of g){const e=p.get(t),s=u.get(t),i=s?void 0:_.get(t),g=m.get(t);let b;if(i&&g)b="readd";else if(!0===s?.hidden)b="hidden";else if(e||s)b="on_plan";else{if(!g)continue;b="available"}const v=e?.bindingStatus||o.get(t)||Qh,y=s||i,w=tc(t),$=e?.area||g?.areaId||y?.area||"",k=e?.space||y?.space||h[$]||"",x=e?.name||y?.name||g?.label||t,M=e?.model||y?.model||g?.model||"",C=!!g?.parentDeviceId&&p.has(`device:${g.parentDeviceId}`),S="readd"===b?"removed":"hidden"===b?s&&ec(s)?d[t]||"automatic_hidden":"manual_hidden":"on_plan"===b?s?"visible_explicit":"visible_auto":d[t]||(C?"represented_by_parent":$&&k?"available":"no_bound_room"),P=!!e&&(!e.hidden||n),D="active"===v.kind,I=P&&(D||"ha_disabled"===v.kind&&n),L=[x,M,c[t],r[$],l[k],t,g?.sub].filter(Boolean).join(" ").toLocaleLowerCase();f.push({key:t,binding:t,category:b,status:v,reason:S,deviceId:e?.id,markerId:y?.id,name:x,icon:e?.icon||y?.icon||("entity"===w?"mdi:code-braces":"mdi:devices"),model:M,integration:c[t]||"",areaId:$,areaName:r[$]||"",spaceId:k,spaceName:l[k]||"",kind:w,isNew:!!e&&a.has(e.id),searchText:L,canFind:I,canEdit:!!e||!!s,canHide:"on_plan"===b&&D,canShow:"hidden"===b&&D,canAdd:("available"===b||"readd"===b)&&D})}const b=t=>"active"===t.status.kind?1:0;return f.sort((t,e)=>t.category.localeCompare(e.category)||Number(e.isNew)-Number(t.isNew)||b(t)-b(e)||t.name.localeCompare(e.name)||t.binding.localeCompare(e.binding))}({devices:this.host._devices,markers:this.host._markers,candidates:i,statuses:a,newDeviceIds:this.host._newIds,showHiddenOnPlan:this.host._showAll,areaNames:r,spaceNames:h,spaceByArea:c,integrationByBinding:d,reasonByBinding:u});return this.host._deviceInboxMemo={key:s,rows:_},_}_deviceForInboxRow(t){const e=t.deviceId?this.host._devices.find(e=>e.id===t.deviceId):null;if(e)return e;const s=t.markerId?this.host._markers.find(e=>e.id===t.markerId):null;return!s||s.removed?null:{id:s.id,name:t.name,model:t.model,area:t.areaId,space:t.spaceId||this.host._space,hidden:!0===s.hidden||"ha_disabled"===t.status.kind,userHidden:!0===s.hidden,bindingStatus:t.status,icon:t.icon,entities:"active"===t.status.kind?t.status.enabledEntityIds:[],allEntities:t.status.allEntityIds,primary:"active"===t.status.kind?t.status.enabledEntityIds[0]:void 0,marker:s,bindingKind:t.kind,bindingRef:t.binding.slice(t.binding.indexOf(":")+1),pdfs:s.pdfs||[]}}_openInboxMarker(t,e=!1){const s=this.host._deviceInbox;if(s){if(this.host._deviceInboxReturn={...s,anchor:t.key},this.host._deviceInbox=null,!e){const e=this._deviceForInboxRow(t);return void(e?this._openMarkerDialog(e):this._closeMarkerDialog())}this._openMarkerDialog(),this.host._markerDialog?this.host._markerDialog={...this.host._markerDialog,bindingMode:"ha",binding:t.binding,bindingOpen:!1,showEntities:"entity"===t.kind,name:""}:this._closeMarkerDialog()}}async _setInboxHidden(t,e){const s=this.host._deviceInbox,i=this.host._serverCfg;if(!s||!i||s.busy||"active"!==t.status.kind)return;const o=i.markers||[],a=o.find(e=>!e.removed&&e.binding===t.binding);if(!e&&!a)return;const n=a?.id||Zs(t.binding,t.markerId,()=>`m_${Date.now().toString(36)}`),r=a?{...a,hidden:e}:{id:n,binding:t.binding,hidden:!0};i.markers=[...o.filter(e=>e.id!==n&&(e.binding!==t.binding||!0===e.removed)),r],this.host._deviceInbox={...s,busy:t.key,anchor:t.key};try{await this._saveConfigNow(),this.host._regSignature="",this.host._deviceInboxMemo=null,this.host._maybeRebuildDevices(),this.host._deviceInbox&&(this.host._deviceInbox={...this.host._deviceInbox,busy:void 0}),this.host._showToast(this.host._t("device_inbox.saved"))}catch(t){this.host._serverCfg===i&&(i.markers=o),this.host._deviceInbox&&(this.host._deviceInbox={...this.host._deviceInbox,busy:void 0}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_findInboxDevice(t){if(!t.canFind)return;const e=this._deviceForInboxRow(t);if(!e)return;if(this.host._deviceInbox=null,e.space&&e.space!==this.host._space){if(!this.host._commitSpace(e.space))return;this.host._restoreZoom()}const s=()=>{const t=this.host._devices.find(t=>t.id===e.id)||e,s=this.host._pos(t);this.host._applyView(this.host._zoom,s.x,s.y),this.host._selId=t.id,this.host.requestUpdate(),window.setTimeout(()=>{this.host._selId===t.id&&(this.host._selId=null,this.host.requestUpdate())},1500)};requestAnimationFrame(()=>requestAnimationFrame(s))}_openMarkerDialog(t){if(this.host._vacAllCamerasFor=null,this.host._vacAllCameraCache=null,t&&this.host._ackNewDevice(t.id),this.host._norm){if(t){const e=t.marker,s=Object.prototype.hasOwnProperty.call(e||{},"is_light"),i=Object.prototype.hasOwnProperty.call(e||{},"light_entity"),o=Object.prototype.hasOwnProperty.call(e||{},"glow_color"),a=Object.prototype.hasOwnProperty.call(e||{},"value_badge"),n=Object.prototype.hasOwnProperty.call(e||{},"value_source"),r=Object.prototype.hasOwnProperty.call(e||{},"tap_action"),l=Object.prototype.hasOwnProperty.call(e||{},"toggle_entity"),h=Ys(e?.glow_color),c=this.host._devicePresentation(t,!0).valueBadge,d=g(this.host._planHass,t,this.host._devices),p=f(this.host._planHass,t,d),u=xa(t,this.host._fullRegistryHass),_=this.host._spaceModelById(t.space)||this.host._spaceModel(),m=this.host._pos(t),b=_?Ca(t,_,[m.x,m.y],this.host._fullRegistryHass):null;this.host._markerDialog={devId:t.id,name:t.name,binding:"virtual"===t.bindingKind?"virtual":t.bindingKind+":"+t.bindingRef,bindingMode:"virtual"===t.bindingKind?"virtual":"ha",bindingOpen:!1,showEntities:"entity"===t.bindingKind&&!!this.host._fullRegistryHass.entities[t.bindingRef||""]?.device_id,bindingFilter:"",icon:t.marker?.icon||"",autoIcon:t.icon||"",display:S(t.marker?.display),rippleColor:Nt(t.marker?.ripple_color,""),rippleSize:Number(t.marker?.ripple_size)>0?Number(t.marker.ripple_size):1.5,size:Number(t.marker?.size)>0?Number(t.marker.size):1,angle:Number(t.marker?.angle)||0,tapAction:Xs(t.marker?.tap_action,t.primary?.split(".")[0]),tapActionTouched:!1,originalHasTapAction:r,originalTapAction:t.marker?.tap_action,tapHintAnnouncement:"",toggleEntity:e?.toggle_entity||"",toggleEntityTouched:!1,originalHasToggleEntity:l,originalToggleEntity:e?.toggle_entity,tapTarget:t.marker?.tap_target||"",tapConfirm:!0===t.marker?.tap_confirm,runFilter:"",controls:T(t.marker?.binding,t.marker?.controls,t.entities),controlsFilter:"",lightRole:!0===e?.is_light?"always":!1===e?.is_light?"never":"auto",lightRoleTouched:!1,originalHasIsLight:s,originalIsLight:e?.is_light,lightEntity:e?.light_entity||"",lightEntityTouched:!1,originalHasLightEntity:i,originalLightEntity:e?.light_entity,glowMode:null!=h?.bri?"fixed":h?"color":"auto",glowColor:h?.c||this.host._fillColors.glow_light.c,glowBrightness:Math.max(1,Math.round(100*(h?.bri??1))),glowColorDrafted:!!h,glowBrightnessDrafted:null!=h?.bri,glowTouched:!1,originalHasGlowColor:o&&(!!h||null===e?.glow_color),originalGlowColor:h||(null===e?.glow_color?null:void 0),valueBadgeEnabled:a?!0===e?.value_badge?.enabled:!!c,valueBadgeSource:e?.value_badge?.source||c?.source||p,valueBadgePosition:e?.value_badge?.position||c?.position||"right",valueBadgeTouched:!1,originalHasValueBadge:a,originalValueBadge:e?.value_badge,valueSource:e?.value_source||null,valueSourceTouched:!1,originalHasValueSource:n,originalValueSource:e?.value_source,useClimateTemp:!0===t.marker?.use_climate_temp,glowRadius:Number(t.marker?.glow_radius_cm)>0?String(this.host._imperial?Math.round(Number(t.marker.glow_radius_cm)/30.48*10)/10:Math.round(Number(t.marker.glow_radius_cm))/100):"",model:t.model||"",link:t.link||"",description:t.description||"",pdfs:[...t.pdfs||[]],room:t.marker?.room_id?t.space+"#@"+t.marker.room_id:t.space&&t.area?t.space+"#"+t.area:"",roomTouched:!1,radar:b,radarEligible:u.eligible,radarTouched:!1,radarRemove:!1,hideFromPlan:!0===t.marker?.hidden,busy:!1}}else this.host._markerDialog={name:"",binding:"virtual",bindingMode:"virtual",bindingOpen:!1,showEntities:!1,bindingFilter:"",icon:"",autoIcon:"",display:"badge",rippleColor:"",rippleSize:1.5,size:1,angle:0,tapAction:"info",tapActionTouched:!1,originalHasTapAction:!1,originalTapAction:void 0,tapHintAnnouncement:"",toggleEntity:"",toggleEntityTouched:!1,originalHasToggleEntity:!1,originalToggleEntity:void 0,tapTarget:"",tapConfirm:!1,runFilter:"",controls:[],controlsFilter:"",lightRole:"auto",lightRoleTouched:!1,originalHasIsLight:!1,originalIsLight:void 0,lightEntity:"",lightEntityTouched:!1,originalHasLightEntity:!1,originalLightEntity:void 0,glowMode:"auto",glowColor:this.host._fillColors.glow_light.c,glowBrightness:100,glowColorDrafted:!1,glowBrightnessDrafted:!1,glowTouched:!1,originalHasGlowColor:!1,originalGlowColor:void 0,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgePosition:"right",valueBadgeTouched:!1,originalHasValueBadge:!1,originalValueBadge:void 0,valueSource:null,valueSourceTouched:!1,originalHasValueSource:!1,originalValueSource:void 0,useClimateTemp:!1,glowRadius:"",model:"",link:"",description:"",pdfs:[],room:"",roomTouched:!1,radar:null,radarEligible:!1,radarTouched:!1,radarRemove:!1,hideFromPlan:!1,busy:!1,uploadId:"up_"+Date.now().toString(36)+Math.random().toString(36).slice(2,6)};this.host._markerDialog&&function(t,e){_o(t,"marker",ga(e))}(this.host,this.host._markerDialog)}else this.host._showToast(this.host._t("toast.marker_needs_server"))}_runCandidates(){const t=[];for(const e of Qs)for(const[s,i]of Object.entries(this.host.hass.states))s.startsWith(e+".")&&this.host._planEntityAvailable(s)&&t.push({value:s,label:i?.attributes?.friendly_name||s,sub:this.host._t("run."+e)});return t.sort((t,e)=>t.sub.localeCompare(e.sub)||t.label.localeCompare(e.label))}_bindingCandidates(){const t=Xh({hass:this.host._planHass,devices:this.host._devices,markers:this.host._markers,showEntities:!!this.host._markerDialog?.showEntities,currentBinding:this.host._markerDialog?.binding,currentDeviceId:this.host._markerDialog?.devId,labels:{device:this.host._t("marker.sub_device"),z2mGroup:this.host._t("marker.sub_z2m_group"),group:this.host._t("marker.sub_group"),helper:this.host._t("marker.sub_helper"),entity:this.host._t("marker.sub_entity")}}),e=(this.host._markerDialog?.bindingFilter||"").toLowerCase().trim(),s=e?t.filter(t=>(t.label+" "+t.sub+" "+t.value).toLowerCase().includes(e)):t;return s.sort((t,e)=>t.label.localeCompare(e.label)),s.slice(0,200)}_backupErrorText(t){const e=t?.code??t?.error;if("string"==typeof e){const t=`backup.error.${e}`,s=this.host._t(t);if(s!==t)return s}return this.host._errText(t)}async _pickMarkerFiles(t){const e=t.target,s=e.files?[...e.files]:[];if(e.value="",!s.length||!this.host._markerDialog)return;const i=this.host._markerDialog.uploadId||this.host._markerDialog.devId||"new",o=[];for(const t of s)try{const e=new FormData;e.append("marker_id",i),e.append("file",t,t.name);const s=this.host.hass?.fetchWithAuth?await this.host.hass.fetchWithAuth("/api/houseplan/upload",{method:"POST",body:e}):await fetch("/api/houseplan/upload",{method:"POST",body:e,headers:this.host.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.host.hass.auth.data.access_token}`}:{}}),a=await s.json().catch(()=>({}));if(!s.ok||a.error){const t={too_large:this.host._t("err.too_large",{mb:a.max_mb||50}),bad_ext:this.host._t("err.bad_ext"),unauthorized:this.host._t("err.unauthorized")};throw new Error(t[a.error]||a.error||"HTTP "+s.status)}o.push({name:a.name||t.name,url:a.url})}catch(e){this.host._showToast(this.host._t("toast.file_failed",{name:t.name,err:this.host._errText(e)}))}o.length&&this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,pdfs:[...this.host._markerDialog.pdfs,...o]},this.host._showToast(this.host._t("toast.files_attached",{n:o.length})))}_removeMarkerPdf(t){this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,pdfs:this.host._markerDialog.pdfs.filter(e=>e.url!==t)})}_markerLightFields(t){const e={};if(t.lightRoleTouched?"always"===t.lightRole?e.is_light=!0:"never"===t.lightRole&&(e.is_light=!1):t.originalHasIsLight&&(e.is_light=t.originalIsLight??null),t.lightEntityTouched?t.lightEntity&&(e.light_entity=t.lightEntity):t.originalHasLightEntity&&(e.light_entity=t.originalLightEntity??null),t.glowTouched){if("auto"!==t.glowMode){const s={c:Nt(t.glowColor,this.host._fillColors.glow_light.c)};"fixed"===t.glowMode&&(s.bri=Math.max(.01,Math.min(1,Math.round(t.glowBrightness)/100))),e.glow_color=s}}else t.originalHasGlowColor&&(e.glow_color=t.originalGlowColor??null);return e}_markerTapActionFields(t){return t.tapActionTouched?{tap_action:t.tapAction||null}:t.originalHasTapAction?{tap_action:t.originalTapAction??null}:{}}_markerToggleEntityFields(t){return(e={touched:t.toggleEntityTouched,originalHas:t.originalHasToggleEntity,original:t.originalToggleEntity,value:t.toggleEntity}).touched?e.value?{toggle_entity:e.value}:{}:e.originalHas?{toggle_entity:e.original??null}:{};var e}async _saveMarker(){const t=this.host._markerDialog;if(!t||t.busy)return;const e=this._effectiveMarkerTapAction(t);if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return;if("virtual"===t.binding&&!t.name.trim())return void this.host._showToast(this.host._t("toast.virtual_name_required"));if("run"===e&&!t.tapTarget)return void this.host._showToast(this.host._t("toast.run_target_required"));if(t.valueBadgeTouched&&t.valueBadgeEnabled&&!t.valueBadgeSource)return void this.host._showToast(this.host._t("toast.value_badge_source_required"));if("ha"===t.bindingMode){const e=this.host._bindingStatus(t.binding),s=t.devId?this.host._markers.find(e=>e.id===t.devId):null,i=!s||s.binding!==t.binding;if("active"!==e.kind&&i)return void this.host._showToast(this.host._t("ha_disabled"===e.kind?"toast.ha_disabled_add":"toast.ha_binding_unverified"));if("ha_disabled"===e.kind&&!0===s?.hidden&&!t.hideFromPlan)return this.host._markerDialog={...t,hideFromPlan:!0},void this.host._showToast(this.host._t("entity"===e.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device"))}const s=this.host._serverCfg;if(!s)return;const i=this.host._cfgRev,o=yt(s);let a=JSON.parse(JSON.stringify(s));const n=a.markers||[],r=Zs(t.binding,t.devId,()=>"v_"+Date.now().toString(36)),l=t.devId,h=l?this.host._devices.find(t=>t.id===l):null,c=l?n.find(t=>t.id===l):null,d=!!c&&("string"==typeof c.area&&c.area.length>0||null===c.area&&!!c.space&&!!c.room_id),p="virtual"===t.binding||t.roomTouched||d,u="virtual"===t.binding||t.roomTouched?x(t.room):null;let _=d&&!t.roomTouched?c?.space||null:u?.space||null;const m=d&&!t.roomTouched?c?.area||null:u?.area||null,g=d&&!t.roomTouched?c?.room_id||null:u?.roomId||null,f=_||h?.space||null,b=f?this.host._spaceModelById(f):this.host._spaceModel();if(!b)return;const v=b.id;"virtual"!==t.binding||_||(_=v);let y={};if(t.radarTouched){if(t.radarRemove)y={radar:null};else if(t.radar){const e=Da(t.radar,b.cellCm||5);if(!e)return void this.host._showToast(this.host._t("radar.invalid"));y={radar:e}}}else c&&Object.prototype.hasOwnProperty.call(c,"radar")&&(y={radar:c.radar});this.host._markerDialog={...t,busy:!0};let w=null,$=!1;try{const c="virtual"===t.binding?[]:n.filter(e=>e.removed&&e.binding===t.binding).map(t=>t.id),d=c.length>0,u=T(t.binding,t.controls,this.host._bindingEntities(t.binding)),f=n.find(t=>t.id===r||t.id===l)?.vacuum||null,k={id:r,vacuum:f,...y,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle?t.angle:null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===e&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:u.length?u:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),...this._markerValueSourceFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=xt(t.glowRadius);return null==e||e<=0?null:Math.round(this.host._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:!!t.hideFromPlan};p&&(k.space=_,k.area=m,k.room_id=g);const x=h?.marker?.room_id??null,M=t.roomTouched&&null!=h&&(h.space!==_||h.area!==m||x!==g);let C=!1;const S=t.uploadId||l;if(S&&S!==r&&k.pdfs?.length)try{const t=await this.host.hass.callWS({type:"houseplan/files/migrate",from_id:S,to_id:r}),e=t?.mapping||{};k.pdfs=ti(k.pdfs,S,r,e),C=Object.keys(e).length>0}catch(t){this.host._showToast(this.host._t("toast.files_migrate_failed",{err:this.host._errText(t)}))}a.markers=n,l&&l!==r&&(a.markers=ei(a.markers,l,r)),l&&l!==r&&"derived_marker_state"===k.value_badge?.source?.kind&&k.value_badge.source.ref===`marker:${l}`&&(k.value_badge.source={kind:"derived_marker_state",ref:`marker:${r}`}),l&&l!==r&&"derived_marker_state"===k.value_source?.kind&&k.value_source.ref===`marker:${l}`&&(k.value_source={kind:"derived_marker_state",ref:`marker:${r}`}),a.markers=a.markers.filter(t=>t.id!==r&&t.id!==l&&("virtual"===k.binding||t.binding!==k.binding)),a.markers.push(k);const P=new Set(c);l&&l!==r&&P.add(l),P.delete(r),P.size&&a.settings?.marker_area_snapshot&&(a.settings={...a.settings,marker_area_snapshot:si(a.settings.marker_area_snapshot,P)});let D=null;const I=l?this.host._layout[l]:null,L=I?{s:I.s||h?.space||this.host._space,x:I.x,y:I.y}:l&&h&&this.host._defPos[l]?this.host._normPos(h.space,this.host._defPos[l].x,this.host._defPos[l].y):null;if(!d&&L&&L.s===v)r===l&&this.host._layout[r]&&!M||(D={s:L.s,x:L.x,y:L.y});else if(d||!this.host._layout[r]||M){let t=b.vb[0]+b.vb[2]/2,e=b.vb[1]+b.vb[3]/2;const s=g?b.rooms.find(t=>t.id===g):m?b.rooms.find(t=>t.area===m):void 0;s&&([t,e]=this.host._roomCenter(s)),D=this.host._normPos(v,t,e)}if(this.host._serverCfg!==s||this.host._cfgRev!==i||yt(s)!==o)return this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,busy:!1}),void this.host._showToast(this.host._t("toast.conflict"));if(a=this._prepareConfigCandidate(a),w=this.host._adoption.beginOptimistic(s,a),this.host._serverCfg=a,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate(),this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.cancel(),await this._saveConfigNow(w),$=!0,D){const t=ii(D);this.host._layout={...this.host._layout,[r]:t},this.host._noteLayoutRev(await this.host.hass.callWS({type:"houseplan/layout/update",device_id:r,pos:t}))}const R=new Set(c);l&&l!==r&&R.add(l),R.delete(r);for(const t of R)delete this.host._layout[t],await this.host.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this.host._noteLayoutRev(t)).catch(()=>{});C&&S&&await this.host.hass.callWS({type:"houseplan/files/cleanup",marker_id:S}).catch(()=>{}),this._closeMarkerDialog(),this.host._cancelDeviceDrag(),this.host._devicePositionHistory.clear(),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.marker_saved"))}catch(t){!$&&w&&(this.host._rollbackOptimistic(w),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate()),this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteMarker(){const t=this.host._markerDialog;if(!t||t.busy||!t.devId)return;const e=t.devId?this.host._devices.find(e=>e.id===t.devId):null,s=this.host._markers.find(e=>e.id===t.devId);if(!e&&!s)return;const i=e?"virtual"===e.bindingKind?"virtual":e.bindingKind&&e.bindingRef?`${e.bindingKind}:${e.bindingRef}`:"":s.binding;if(!i)return;const o=t.name||this.host._t("device.fallback"),a=t.devId,n=await this.host._confirmDanger({key:"remove-marker",kind:"destructive",title:this.host._t("confirm.remove_marker_title"),message:this.host._t("confirm.remove_marker_body"),objectName:o,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),r=this.host._markerDialog;if(!n||!r||r.busy||r.devId!==a)return;const l=this.host._devices.find(t=>t.id===a),h=this.host._markers.find(t=>t.id===a);if(!l&&!h)return;const c=this.host._serverCfg;if(!c)return;c.markers=c.markers||[];const d=c.markers,p=l?"virtual"===l.bindingKind?"virtual":l.bindingKind&&l.bindingRef?`${l.bindingKind}:${l.bindingRef}`:"":h.binding;if(!p||p!==i)return;const u=oi(c.markers,a,p,"virtual"===p);c.markers=ai(u.markers,u.cleanupIds);const _=u.cleanupIds;_.size&&c.settings?.marker_area_snapshot&&(c.settings={...c.settings,marker_area_snapshot:si(c.settings.marker_area_snapshot,_)}),this.host._markerDialog={...r,busy:!0};try{await this._saveConfigNow();for(const t of _){delete this.host._layout[t],delete this.host._defPos[t],this.host._dirtyPos.delete(t),this.host._sentPos.delete(t);const e=this.host._activityRt.get(t);e&&clearTimeout(e.timer),this.host._activityRt.delete(t),this.host._vacRt.delete(t),delete this.host._vacSrvTrails[t],await this.host.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this.host._noteLayoutRev(t)).catch(()=>{}),await this.host.hass.callWS({type:"houseplan/files/cleanup",marker_id:t}).catch(()=>{}),await this.host.hass.callWS({type:"houseplan/trail/delete",marker_id:t}).catch(()=>{})}this.host._deviceInboxReturn&&(this.host._deviceInboxReturn={...this.host._deviceInboxReturn,tab:"readd",anchor:p}),this._closeMarkerDialog(),this.host._cancelDeviceDrag(),this.host._devicePositionHistory.clear(),this.host._infoCard?.id===a&&this.host._closeInfoCard(),this.host._selId===a&&(this.host._selId=null),this.host._drag?.id===a&&(this.host._drag=null),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.marker_removed"))}catch(t){this.host._serverCfg===c&&(c.markers=d),this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_openSpaceDialog(t,e){if(this.host._serverStorage&&this.host._serverCfg){if("edit"===t){const s=this.host._serverCfg.spaces.find(t=>t.id===e);if(!s)return;const i=_(s),o=s.settings?.custom_fill&&"object"==typeof s.settings.custom_fill?ni(s.settings.custom_fill):null,a="none"===i.fill?{...o||ri,a:0}:o;this.host._spaceDialog={mode:t,spaceId:e,title:s.title,planUrl:s.plan_url||null,planFile:null,source:s.plan_url?"file":"draw",showBorders:i.showBorders,showNames:i.showNames,zeroWallStyle:hi(s),displayTouched:!0,hideDecor:i.hideDecor,hideOpenings:i.hideOpenings,roomColor:i.color,roomOpacity:i.opacity,fillMode:"none"===i.fill?"custom":i.fill,customFill:a,glowEnabled:i.glow,bgColor:i.bgColor,bgMode:"static"===s.settings?.bg_mode||"daynight"===s.settings?.bg_mode?s.settings.bg_mode:null,northDeg:Re({},s.settings),sunRays:"boolean"==typeof s.settings?.sun_rays?s.settings.sun_rays:null,tempMin:i.tempMin,tempMax:i.tempMax,showLqi:i.showLqi??this.host._config?.show_signal??!0,cardFontScale:i.cardFontScale,labelTemp:i.labelTemp,labelHum:i.labelHum,labelLqi:i.labelLqi,labelLight:i.labelLight,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,cellCmInput:li(Number(s.cell_cm)>0?Number(s.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1}}else this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...mi(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:ui,roomOpacity:pi,fillMode:"custom",customFill:{...ri,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:di,tempMax:ci,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:_i(this.host._imperial),cellCmInput:li(_i(this.host._imperial),this.host._imperial),cellCmTouched:!1,busy:!1};this.host._spaceDialog&&Go(this.host,this.host._spaceDialog)}else this.host._showToast(this.host._t("toast.integration_missing"))}async _pickPlanFile(t){const e=t.target,s=e.files?.[0];if(!s||!this.host._spaceDialog)return;e.value="",this._decorAssetGuardReplace=null;const i=await jo(s);if("reject"===i.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===i.kind)return void(this.host._backdropGuard=i.state);const o=await qo(s,i.ext,s.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:o})}_renderBackdropGuard(){const t=this._decorAssetGuardReplace;return null!==t?Uo(this.host,()=>{},()=>{this.host._backdropGuard=null,this._decorAssetGuardReplace=null},this.host.hass,(e,s)=>this._uploadDecorImage(e,s,t),(this.host._backdropGuard?.file.size||0)<=2097152)??d:Uo(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??d}_useServerPlan(t){const e=this.host._spaceDialog;e&&(this.host._spaceDialog={...e,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let e=0;e<40;e++){const e=this.host._display(t);if(e){const s=await new Promise(t=>{const s=new Image;s.onload=()=>t(s.naturalWidth&&s.naturalHeight?s.naturalWidth/s.naturalHeight:0),s.onerror=()=>t(0),s.src=e}),i=this.host._spaceDialog;return i&&i.planUrl===t&&Number.isFinite(s)&&s>0?(this.host._spaceDialog={...i,savedAspect:s},s):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const e=this.host._spaceDialog,s=e?.saved?.find(e=>e.name===t);if(!e||!s||s.used_by.length||s.url===e.planUrl)return;const i=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),o=this.host._spaceDialog,a=o?.saved?.find(e=>e.name===t);if(i&&o&&a&&a.url===s.url&&a.modified===s.modified&&!a.used_by.length&&a.url!==o.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const e=this.host._spaceDialog;e?.saved&&(this.host._spaceDialog={...e,saved:e.saved.filter(e=>e.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return p`
    ${this.host._t("space.loading")}
    `;const e=t.saved||[];if(!e.length)return p`
    ${this.host._t("space.no_saved")}
    `;return p`
    ${e.map(e=>{return p`
    @@ -1435,7 +1435,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
    `;var s})} -
    `}async _saveSpaceDialog(){const t=this.host._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this.host._showToast(this.host._t("toast.plan_required"));const e="create"===t.mode&&0===(this.host._serverCfg?.spaces.length||0);this.host._spaceDialog={...t,busy:!0};try{const s="create"===t.mode?"s"+Date.now().toString(36):t.spaceId;let i=null;if("file"===t.source&&t.planFile){i={url:(await this.host.hass.callWS({type:"houseplan/plan/set",space_id:s,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let o=t.savedAspect||null;!i&&"file"===t.source&&t.planUrl&&!o&&this.host._aspectJob&&(o=await this.host._aspectJob||null);const a=this.host._serverCfg;let n;if("create"===t.mode)n=gi(s,t.title.trim()),a.spaces.push(n);else{if(n=a.spaces.find(t=>t.id===s),!n)throw new Error("space "+s+" is gone from the config");n.title=t.title.trim()}i?(n.plan_url=i.url,n.plan_aspect=i.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==n.plan_url&&(n.plan_url=t.planUrl,n.plan_aspect=o),"draw"===t.source&&(n.plan_url=null,n.plan_aspect=null,delete n.plan_x,delete n.plan_y,delete n.plan_scale,delete n.plan_scale_x,delete n.plan_scale_y,delete n.plan_angle),n.settings={...n.settings||{},show_borders:t.showBorders,show_names:t.showNames,hide_decor:t.hideDecor||void 0,hide_openings:t.hideOpenings||void 0,room_color:t.roomColor,room_opacity:t.roomOpacity,bg_color:t.bgColor||void 0,bg_mode:t.bgMode||void 0,north_deg:t.northDeg??void 0,sun_rays:t.sunRays??void 0,fill_mode:t.fillMode,custom_fill:t.customFill||void 0,glow_enabled:t.glowEnabled,temp_min:Number.isFinite(t.tempMin)?Math.min(t.tempMin,t.tempMax):di,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):ci,show_lqi:t.showLqi,card_font_scale:1!==t.cardFontScale?t.cardFontScale:void 0,label_temp:t.labelTemp,label_hum:t.labelHum,label_lqi:t.labelLqi,label_light:t.labelLight},n.zero_wall_style=t.zeroWallStyle,n.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(Ko,Math.min(Vo,t.cellCm)):5,await this._saveConfigNow(),this.host._spaceDialog=null,"create"===t.mode&&this.host._commitSpace(n.id),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._importQueue.length?this._openNextImport():e||this.host._importTotal>0?(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this._setMode("plan"),this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this._primeDrawWallField(),this.host._showToast(this.host._t(e&&!this.host._importTotal?"toast.space_added_onboard":"import.done"))):(this.host._showToast("create"===t.mode?this.host._t("toast.space_added"):this.host._t("toast.space_saved")),"create"===t.mode&&("plan"!==this.host._mode?this._setMode("plan"):(this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this._primeDrawWallField(),this.host._saveNav())))}catch(t){"conflict"!==t?.code&&await this.host._reloadConfigOnly(!0),this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteSpace(){const t=this.host._spaceDialog;if(!t||"edit"!==t.mode)return;const e=this.host._serverCfg;if(!e)return;const s=e.spaces.find(e=>e.id===t.spaceId),i=Jo(e,this.host._layout||{},t.spaceId||""),o=1===e.spaces.length&&e.spaces[0]?.id===t.spaceId;if(i.count&&!o)return void(this.host._spaceDialog={...t,deleteBlockers:i.count});if(!s)return;const a=t.spaceId,n=await this.host._confirmDanger({key:"delete-space",kind:"destructive",title:this.host._t("confirm.delete_space_title"),message:Zo(this.host._t("confirm.delete_space_body"),this.host._t("confirm.delete_space_vac_routes"),i.routeCount),objectName:s.title,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),r=this.host._spaceDialog,l=this.host._serverCfg;if(!n||!r||"edit"!==r.mode||r.busy||r.spaceId!==a||!l)return;if(!l.spaces.find(t=>t.id===a))return;const h=Jo(l,this.host._layout||{},a),c=1===l.spaces.length&&l.spaces[0]?.id===a;if(!h.count||c){this.host._spaceDialog={...r,deleteBlockers:0,busy:!0};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),this.host._persistLayout.pending()&&this.host._persistLayout.flush(),await this.host._writeChain,await this.host.hass.callWS({type:"houseplan/space/delete",space_id:a,expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev});const[t,e]=await Promise.all([this.host._getAuthoritativeConfig(),this.host.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this.host._adoptAuthoritative({cfgResp:t,layResp:e,reason:"space-delete",profile:"post-write"})).status)return this.host._spaceDialog={...r,busy:!1},void this.host.requestUpdate();this.host._spaceDialog=null,this.host._space===a&&this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||""),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.space_deleted"))}catch(t){"conflict"!==t?.code&&"space_in_use"!==t?.code||await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]);const e=this.host._serverCfg;if(this.host._spaceDialog&&e){const t=Jo(e,this.host._layout||{},a),s=1===e.spaces.length&&e.spaces[0]?.id===a;this.host._spaceDialog={...this.host._spaceDialog,busy:!1,deleteBlockers:s?0:t.count}}this.host._showToast(this.host._t("toast.delete_failed",{err:this.host._errText(t)}))}}else this.host._spaceDialog={...r,deleteBlockers:h.count}}async _saveConfigNow(t=null){this.host._cfgEpoch++;try{await this._writeConfig(t)}catch(t){throw t?.physicalGeometryRolledBack?await this._reloadRejectedPhysicalWrite():"conflict"===t?.code&&await this.host._reloadConfigOnly(),t}}_saveSpaceCopy(){return yr(this.host,{clearGeometryGesture:()=>this._clearGeometryGesture(),optimizeReferenceContext:()=>this._optimizeReferenceContext(!1),reportPreflightFailure:(t,e)=>this._reportPreflightFailure(t,e),saveConfigNow:t=>this._saveConfigNow(t),setMode:()=>this._setMode("plan"),showWallModelMigrationBlocked:t=>this._showWallModelMigrationBlocked(t)})}_startImport(){const t=this.host._importDialog;if(!t)return;const e=t.floors.filter(t=>t.checked).map(t=>t.name);this.host._importDialog=null,e.length?(this.host._importQueue=e,this.host._importTotal=e.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this.host._importQueue.shift();void 0!==t&&(this.host._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...mi(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:ui,roomOpacity:pi,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:di,tempMax:ci,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:_i(this.host._imperial),cellCmInput:li(_i(this.host._imperial),this.host._imperial),cellCmTouched:!1,busy:!1})}_skipImport(){this.host._spaceDialog=null,this.host._importQueue.length?this._openNextImport():this.host._importTotal>0&&this.host._model.length&&(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this._setMode("plan"),this.host._showToast(this.host._t("import.done")))}_renderImportDialog(){const t=this.host._importDialog,e=t.floors.filter(t=>t.checked).length;return p``}async _saveSpaceDialog(){const t=this.host._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this.host._showToast(this.host._t("toast.plan_required"));const e="create"===t.mode&&0===(this.host._serverCfg?.spaces.length||0);this.host._spaceDialog={...t,busy:!0};try{const s="create"===t.mode?"s"+Date.now().toString(36):t.spaceId;let i=null;if("file"===t.source&&t.planFile){i={url:(await this.host.hass.callWS({type:"houseplan/plan/set",space_id:s,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let o=t.savedAspect||null;!i&&"file"===t.source&&t.planUrl&&!o&&this.host._aspectJob&&(o=await this.host._aspectJob||null);const a=this.host._serverCfg;let n;if("create"===t.mode)n=gi(s,t.title.trim()),a.spaces.push(n);else{if(n=a.spaces.find(t=>t.id===s),!n)throw new Error("space "+s+" is gone from the config");n.title=t.title.trim()}i?(n.plan_url=i.url,n.plan_aspect=i.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==n.plan_url&&(n.plan_url=t.planUrl,n.plan_aspect=o),"draw"===t.source&&(n.plan_url=null,n.plan_aspect=null,delete n.plan_x,delete n.plan_y,delete n.plan_scale,delete n.plan_scale_x,delete n.plan_scale_y,delete n.plan_angle),n.settings={...n.settings||{},show_borders:t.showBorders,show_names:t.showNames,hide_decor:t.hideDecor||void 0,hide_openings:t.hideOpenings||void 0,room_color:t.roomColor,room_opacity:t.roomOpacity,bg_color:t.bgColor||void 0,bg_mode:t.bgMode||void 0,north_deg:t.northDeg??void 0,sun_rays:t.sunRays??void 0,fill_mode:t.fillMode,custom_fill:t.customFill||void 0,glow_enabled:t.glowEnabled,temp_min:Number.isFinite(t.tempMin)?Math.min(t.tempMin,t.tempMax):di,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):ci,show_lqi:t.showLqi,card_font_scale:1!==t.cardFontScale?t.cardFontScale:void 0,label_temp:t.labelTemp,label_hum:t.labelHum,label_lqi:t.labelLqi,label_light:t.labelLight},n.zero_wall_style=t.zeroWallStyle,n.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(Ko,Math.min(Vo,t.cellCm)):5,await this._saveConfigNow(),this.host._spaceDialog=null,"create"===t.mode&&this.host._commitSpace(n.id),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._importQueue.length?this._openNextImport():e||this.host._importTotal>0?(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this._setMode("plan"),this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this._primeDrawWallField(),this.host._showToast(this.host._t(e&&!this.host._importTotal?"toast.space_added_onboard":"import.done"))):(this.host._showToast("create"===t.mode?this.host._t("toast.space_added"):this.host._t("toast.space_saved")),"create"===t.mode&&("plan"!==this.host._mode?this._setMode("plan"):(this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this._primeDrawWallField(),this.host._saveNav())))}catch(t){"conflict"!==t?.code&&await this.host._reloadConfigOnly(!0),this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteSpace(){const t=this.host._spaceDialog;if(!t||"edit"!==t.mode)return;const e=this.host._serverCfg;if(!e)return;const s=e.spaces.find(e=>e.id===t.spaceId),i=Jo(e,this.host._layout||{},t.spaceId||""),o=1===e.spaces.length&&e.spaces[0]?.id===t.spaceId;if(i.count&&!o)return void(this.host._spaceDialog={...t,deleteBlockers:i.count});if(!s)return;const a=t.spaceId,n=await this.host._confirmDanger({key:"delete-space",kind:"destructive",title:this.host._t("confirm.delete_space_title"),message:Zo(this.host._t("confirm.delete_space_body"),this.host._t("confirm.delete_space_vac_routes"),i.routeCount),objectName:s.title,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),r=this.host._spaceDialog,l=this.host._serverCfg;if(!n||!r||"edit"!==r.mode||r.busy||r.spaceId!==a||!l)return;if(!l.spaces.find(t=>t.id===a))return;const h=Jo(l,this.host._layout||{},a),c=1===l.spaces.length&&l.spaces[0]?.id===a;if(!h.count||c){this.host._spaceDialog={...r,deleteBlockers:0,busy:!0};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),this.host._persistLayout.pending()&&this.host._persistLayout.flush(),await this.host._writeChain,await this.host.hass.callWS({type:"houseplan/space/delete",space_id:a,expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev});const[t,e]=await Promise.all([this.host._getAuthoritativeConfig(),this.host.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this.host._adoptAuthoritative({cfgResp:t,layResp:e,reason:"space-delete",profile:"post-write"})).status)return this.host._spaceDialog={...r,busy:!1},void this.host.requestUpdate();this.host._spaceDialog=null,this.host._space===a&&this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||""),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.space_deleted"))}catch(t){"conflict"!==t?.code&&"space_in_use"!==t?.code||await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]);const e=this.host._serverCfg;if(this.host._spaceDialog&&e){const t=Jo(e,this.host._layout||{},a),s=1===e.spaces.length&&e.spaces[0]?.id===a;this.host._spaceDialog={...this.host._spaceDialog,busy:!1,deleteBlockers:s?0:t.count}}this.host._showToast(this.host._t("toast.delete_failed",{err:this.host._errText(t)}))}}else this.host._spaceDialog={...r,deleteBlockers:h.count}}async _saveConfigNow(t=null){this.host._cfgEpoch++;try{await this._writeConfig(t)}catch(t){throw t?.physicalGeometryRolledBack?await this._reloadRejectedPhysicalWrite():"conflict"===t?.code&&await this.host._reloadConfigOnly(),t}}_saveSpaceCopy(){return vr(this.host,{clearGeometryGesture:()=>this._clearGeometryGesture(),optimizeReferenceContext:()=>this._optimizeReferenceContext(!1),reportPreflightFailure:(t,e)=>this._reportPreflightFailure(t,e),saveConfigNow:t=>this._saveConfigNow(t),setMode:()=>this._setMode("plan"),showWallModelMigrationBlocked:t=>this._showWallModelMigrationBlocked(t)})}_startImport(){const t=this.host._importDialog;if(!t)return;const e=t.floors.filter(t=>t.checked).map(t=>t.name);this.host._importDialog=null,e.length?(this.host._importQueue=e,this.host._importTotal=e.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this.host._importQueue.shift();void 0!==t&&(this.host._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...mi(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:ui,roomOpacity:pi,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:di,tempMax:ci,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:_i(this.host._imperial),cellCmInput:li(_i(this.host._imperial),this.host._imperial),cellCmTouched:!1,busy:!1})}_skipImport(){this.host._spaceDialog=null,this.host._importQueue.length?this._openNextImport():this.host._importTotal>0&&this.host._model.length&&(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this._setMode("plan"),this.host._showToast(this.host._t("import.done")))}_renderImportDialog(){const t=this.host._importDialog,e=t.floors.filter(t=>t.checked).length;return p`this.host._importDialog=null}>
    ${this.host._t("import.hint")}
    @@ -1455,13 +1455,13 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${this.host._t("import.start",{n:e})}
    -
    `}_supportPatch(t,e){const s=this.host._supportDialog;if(!s||s.draftId!==t)return null;const i={...s,...e};return this.host._supportDialog=i,i}async _focusSupport(t){await this.host.updateComplete,this.host.renderRoot.querySelector(t)?.focus({preventScroll:!0})}_updateSupportDraft(t,e){const s=this.host._supportDialog;if(!s||"building"===s.status||"sending"===s.status||"success"===s.status)return;const i={...s,[t]:e},o=md({...i,attach:!1,preview:null});"message_required"===o&&"validation.message_required"===s.errorCode||"message_too_long"===o||"contact_too_long"===o?this._supportPatch(s.draftId,{[t]:e,status:"error",errorCode:`validation.${o}`}):i.attach&&i.preview&&i.preview.expiresAt<=Date.now()?this._supportPatch(s.draftId,{[t]:e,status:"error",errorCode:"support_preview_expired"}):this._supportPatch(s.draftId,{[t]:e,status:i.attach&&i.preview?"ready":"idle",errorCode:""})}async _discardSupportPreview(t){if(t)try{await this.host.hass.callWS({type:"houseplan/support/preview/discard",token:t})}catch{}}async _closeSupportDialog(){const t=this.host._supportDialog;if(t){if("building"===t.status||"sending"===t.status){const t=l(this.host.hass,this.host._config?.language);if(!await this.host._confirmDanger({key:"close-support-busy",kind:"warning",title:ra(t,"support.close_busy_title"),message:ra(t,"support.close_busy_body"),confirmLabel:this.host._t("btn.close"),cancelLabel:this.host._t("btn.cancel")}))return await this.host.updateComplete,void this.host.renderRoot.querySelector("#support-dialog")?.rejectClose()}clearTimeout(this._supportExpiryTimer),this._supportExpiryTimer=void 0,this.host._supportDialog=null,t.preview?.token&&"success"!==t.status&&this._discardSupportPreview(t.preview.token)}}_scheduleSupportExpiry(t,e){clearTimeout(this._supportExpiryTimer);const s=Math.max(0,e.expiresAt-Date.now());this._supportExpiryTimer=window.setTimeout(()=>{const s=this.host._supportDialog;s&&s.draftId===t&&s.preview?.token===e.token&&s.attach&&"success"!==s.status&&"sending"!==s.status&&this._supportPatch(t,{status:"error",errorCode:"support_preview_expired"})},Math.min(s+20,2147483647))}_supportFacts(){const t=this.host._haRegistry;return fd({userAgent:globalThis.navigator?.userAgent||"",language:l(this.host.hass,this.host._config?.language),registryAccess:t.access,registryLastSuccess:t.lastSuccess})}_supportPreviewRequestIsCurrent(t,e){const s=this.host._supportDialog;return e===this._supportPreviewGeneration&&s?.draftId===t&&s.attach}async _buildSupportPreview(t){const e=this.host._supportDialog;if(!e||e.draftId!==t||!e.attach||!dd(this.host._haSupportApi))return;const s=++this._supportPreviewGeneration;this._supportPatch(t,{status:"building",errorCode:""});let i="";try{const e=await this.host.hass.callWS({type:"houseplan/support/preview",card_version:fi(Hd),...this._supportFacts(),draft_id:t}),o=e&&"object"==typeof e?e:{},a=Date.now(),n="string"==typeof o.text?o.text:"",r=Number(o.size),l=Number(o.expires_in),h=Number(o.spaces),c=String(o.token||"");/^[0-9a-f]{48}$/.test(c)&&(i=c);const d=String(o.sha256||""),p=Number(o.version),u=String(o.format||""),_=(new TextEncoder).encode(n).byteLength;if(!/^[0-9a-f]{48}$/.test(c)||!/^[0-9a-f]{64}$/.test(d)||"houseplan-support-package"!==u||1!==p||!Number.isInteger(r)||r!==_||!Number.isInteger(h)||h<0||!Number.isFinite(l)||l<=0||l>600||!n.endsWith("\n"))throw{code:"support_rejected"};const m={token:c,expiresAt:a+1e3*l,size:r,sha256:d,spaces:h,format:u,version:p,text:n,preparedAt:a};if(!this._supportPreviewRequestIsCurrent(t,s))return i="",void this._discardSupportPreview(c);if(!this._supportPatch(t,{status:"ready",preview:m,errorCode:"",rawOpen:!1}))return i="",void this._discardSupportPreview(c);i="",this._scheduleSupportExpiry(t,m)}catch(e){if(i){const t=i;i="",this._discardSupportPreview(t)}if(!this._supportPreviewRequestIsCurrent(t,s))return;if(!this._supportPatch(t,{status:"error",errorCode:bd(e)}))return;this._focusSupport("#support-error")}}async _setSupportAttachment(t){const e=this.host._supportDialog;if(!e||"sending"===e.status||"success"===e.status)return;const s=e.preview?.token||"";if(!t)return this._supportPreviewGeneration+=1,clearTimeout(this._supportExpiryTimer),this._supportExpiryTimer=void 0,this._supportPatch(e.draftId,{attach:!1,status:"idle",preview:null,rawOpen:!1,errorCode:""}),void(s&&this._discardSupportPreview(s));this._supportPatch(e.draftId,{attach:!0,errorCode:""}),await this._buildSupportPreview(e.draftId)}async _refreshSupportPreview(){const t=this.host._supportDialog;t&&t.attach&&"building"!==t.status&&"sending"!==t.status&&await this._buildSupportPreview(t.draftId)}_downloadSupportPreview(){const t=this.host._supportDialog?.preview;if(!t)return;const e=new Blob([t.text],{type:"application/json;charset=utf-8"}),s=URL.createObjectURL(e),i=document.createElement("a");i.href=s,i.download=`houseplan-support-${t.sha256.slice(0,12)}.json`,i.style.display="none",document.body.append(i),i.click(),i.remove(),window.setTimeout(()=>URL.revokeObjectURL(s),0)}async _copySupportText(t,e){const s=l(this.host.hass,this.host._config?.language);try{await navigator.clipboard.writeText(t),this.host._showToast(ra(s,e))}catch{this.host._showToast(ra(s,"support.copy_failed"))}}async _submitSupport(){const t=this.host._supportDialog;if(!t||!dd(this.host._haSupportApi))return;const e=md(t);if(e)return this._supportPatch(t.draftId,{status:"error",errorCode:`validation.${e}`}),void this._focusSupport("#support-message");if(!gd(t))return;const s=ud(t),i=this._supportPatch(t.draftId,{status:"sending",errorCode:"",idempotencyKey:s.idempotencyKey,submissionFingerprint:s.fingerprint});if(i)try{const e=await this.host.hass.callWS({type:"houseplan/support/submit",message:i.message.trim(),contact:i.contact.trim(),...i.attach&&i.preview?{preview_token:i.preview.token}:{},idempotency_key:i.idempotencyKey}),s=e&&"object"==typeof e&&"report_id"in e?String(e.report_id||""):"";if(!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(s))throw{code:"support_unavailable"};if(clearTimeout(this._supportExpiryTimer),this._supportExpiryTimer=void 0,!this._supportPatch(t.draftId,{status:"success",reportId:s,errorCode:""}))return;this._focusSupport("#support-receipt")}catch(e){if(!this._supportPatch(t.draftId,{status:"error",errorCode:bd(e)}))return;this._focusSupport("#support-error")}}_supportErrorText(t){const e=l(this.host.hass,this.host._config?.language);if(t.errorCode.startsWith("validation.")){return ra(e,`support.validation.${t.errorCode.slice(11)}`)}return ra(e,`support.error.${t.errorCode||"support_unavailable"}`)}_supportMessageKeydown(t){"Enter"===t.key&&(t.ctrlKey||t.metaKey)&&(t.preventDefault(),this._submitSupport())}_renderSupportDialog(){const t=this.host._supportDialog,e=l(this.host.hass,this.host._config?.language),s="ru"===e?"https://github.com/Matysh/houseplan-card/blob/main/docs/USER-GUIDE.ru.md":"https://github.com/Matysh/houseplan-card/blob/main/docs/USER-GUIDE.md",i=dd(this.host._haSupportApi),o=(t,s)=>ra(e,t,s),a="building"===t.status||"sending"===t.status,n=md(t),r=t.preview?Math.max(0,Math.floor((Date.now()-t.preview.preparedAt)/6e4)):0,h="error"===t.status&&!t.errorCode.startsWith("validation."),c="validation.contact_too_long"===t.errorCode,u="validation.message_required"===t.errorCode||"validation.message_too_long"===t.errorCode;return p``}_supportPatch(t,e){const s=this.host._supportDialog;if(!s||s.draftId!==t)return null;const i={...s,...e};return this.host._supportDialog=i,i}async _focusSupport(t){await this.host.updateComplete,this.host.renderRoot.querySelector(t)?.focus({preventScroll:!0})}_updateSupportDraft(t,e){const s=this.host._supportDialog;if(!s||"building"===s.status||"sending"===s.status||"success"===s.status)return;const i={...s,[t]:e},o=_d({...i,attach:!1,preview:null});"message_required"===o&&"validation.message_required"===s.errorCode||"message_too_long"===o||"contact_too_long"===o?this._supportPatch(s.draftId,{[t]:e,status:"error",errorCode:`validation.${o}`}):i.attach&&i.preview&&i.preview.expiresAt<=Date.now()?this._supportPatch(s.draftId,{[t]:e,status:"error",errorCode:"support_preview_expired"}):this._supportPatch(s.draftId,{[t]:e,status:i.attach&&i.preview?"ready":"idle",errorCode:""})}async _discardSupportPreview(t){if(t)try{await this.host.hass.callWS({type:"houseplan/support/preview/discard",token:t})}catch{}}async _closeSupportDialog(){const t=this.host._supportDialog;if(t){if("building"===t.status||"sending"===t.status){const t=l(this.host.hass,this.host._config?.language);if(!await this.host._confirmDanger({key:"close-support-busy",kind:"warning",title:ra(t,"support.close_busy_title"),message:ra(t,"support.close_busy_body"),confirmLabel:this.host._t("btn.close"),cancelLabel:this.host._t("btn.cancel")}))return await this.host.updateComplete,void this.host.renderRoot.querySelector("#support-dialog")?.rejectClose()}clearTimeout(this._supportExpiryTimer),this._supportExpiryTimer=void 0,this.host._supportDialog=null,t.preview?.token&&"success"!==t.status&&this._discardSupportPreview(t.preview.token)}}_scheduleSupportExpiry(t,e){clearTimeout(this._supportExpiryTimer);const s=Math.max(0,e.expiresAt-Date.now());this._supportExpiryTimer=window.setTimeout(()=>{const s=this.host._supportDialog;s&&s.draftId===t&&s.preview?.token===e.token&&s.attach&&"success"!==s.status&&"sending"!==s.status&&this._supportPatch(t,{status:"error",errorCode:"support_preview_expired"})},Math.min(s+20,2147483647))}_supportFacts(){const t=this.host._haRegistry;return gd({userAgent:globalThis.navigator?.userAgent||"",language:l(this.host.hass,this.host._config?.language),registryAccess:t.access,registryLastSuccess:t.lastSuccess})}_supportPreviewRequestIsCurrent(t,e){const s=this.host._supportDialog;return e===this._supportPreviewGeneration&&s?.draftId===t&&s.attach}async _buildSupportPreview(t){const e=this.host._supportDialog;if(!e||e.draftId!==t||!e.attach||!cd(this.host._haSupportApi))return;const s=++this._supportPreviewGeneration;this._supportPatch(t,{status:"building",errorCode:""});let i="";try{const e=await this.host.hass.callWS({type:"houseplan/support/preview",card_version:fi(Bd),...this._supportFacts(),draft_id:t}),o=e&&"object"==typeof e?e:{},a=Date.now(),n="string"==typeof o.text?o.text:"",r=Number(o.size),l=Number(o.expires_in),h=Number(o.spaces),c=String(o.token||"");/^[0-9a-f]{48}$/.test(c)&&(i=c);const d=String(o.sha256||""),p=Number(o.version),u=String(o.format||""),_=(new TextEncoder).encode(n).byteLength;if(!/^[0-9a-f]{48}$/.test(c)||!/^[0-9a-f]{64}$/.test(d)||"houseplan-support-package"!==u||1!==p||!Number.isInteger(r)||r!==_||!Number.isInteger(h)||h<0||!Number.isFinite(l)||l<=0||l>600||!n.endsWith("\n"))throw{code:"support_rejected"};const m={token:c,expiresAt:a+1e3*l,size:r,sha256:d,spaces:h,format:u,version:p,text:n,preparedAt:a};if(!this._supportPreviewRequestIsCurrent(t,s))return i="",void this._discardSupportPreview(c);if(!this._supportPatch(t,{status:"ready",preview:m,errorCode:"",rawOpen:!1}))return i="",void this._discardSupportPreview(c);i="",this._scheduleSupportExpiry(t,m)}catch(e){if(i){const t=i;i="",this._discardSupportPreview(t)}if(!this._supportPreviewRequestIsCurrent(t,s))return;if(!this._supportPatch(t,{status:"error",errorCode:fd(e)}))return;this._focusSupport("#support-error")}}async _setSupportAttachment(t){const e=this.host._supportDialog;if(!e||"sending"===e.status||"success"===e.status)return;const s=e.preview?.token||"";if(!t)return this._supportPreviewGeneration+=1,clearTimeout(this._supportExpiryTimer),this._supportExpiryTimer=void 0,this._supportPatch(e.draftId,{attach:!1,status:"idle",preview:null,rawOpen:!1,errorCode:""}),void(s&&this._discardSupportPreview(s));this._supportPatch(e.draftId,{attach:!0,errorCode:""}),await this._buildSupportPreview(e.draftId)}async _refreshSupportPreview(){const t=this.host._supportDialog;t&&t.attach&&"building"!==t.status&&"sending"!==t.status&&await this._buildSupportPreview(t.draftId)}_downloadSupportPreview(){const t=this.host._supportDialog?.preview;if(!t)return;const e=new Blob([t.text],{type:"application/json;charset=utf-8"}),s=URL.createObjectURL(e),i=document.createElement("a");i.href=s,i.download=`houseplan-support-${t.sha256.slice(0,12)}.json`,i.style.display="none",document.body.append(i),i.click(),i.remove(),window.setTimeout(()=>URL.revokeObjectURL(s),0)}async _copySupportText(t,e){const s=l(this.host.hass,this.host._config?.language);try{await navigator.clipboard.writeText(t),this.host._showToast(ra(s,e))}catch{this.host._showToast(ra(s,"support.copy_failed"))}}async _submitSupport(){const t=this.host._supportDialog;if(!t||!cd(this.host._haSupportApi))return;const e=_d(t);if(e)return this._supportPatch(t.draftId,{status:"error",errorCode:`validation.${e}`}),void this._focusSupport("#support-message");if(!md(t))return;const s=pd(t),i=this._supportPatch(t.draftId,{status:"sending",errorCode:"",idempotencyKey:s.idempotencyKey,submissionFingerprint:s.fingerprint});if(i)try{const e=await this.host.hass.callWS({type:"houseplan/support/submit",message:i.message.trim(),contact:i.contact.trim(),...i.attach&&i.preview?{preview_token:i.preview.token}:{},idempotency_key:i.idempotencyKey}),s=e&&"object"==typeof e&&"report_id"in e?String(e.report_id||""):"";if(!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(s))throw{code:"support_unavailable"};if(clearTimeout(this._supportExpiryTimer),this._supportExpiryTimer=void 0,!this._supportPatch(t.draftId,{status:"success",reportId:s,errorCode:""}))return;this._focusSupport("#support-receipt")}catch(e){if(!this._supportPatch(t.draftId,{status:"error",errorCode:fd(e)}))return;this._focusSupport("#support-error")}}_supportErrorText(t){const e=l(this.host.hass,this.host._config?.language);if(t.errorCode.startsWith("validation.")){return ra(e,`support.validation.${t.errorCode.slice(11)}`)}return ra(e,`support.error.${t.errorCode||"support_unavailable"}`)}_supportMessageKeydown(t){"Enter"===t.key&&(t.ctrlKey||t.metaKey)&&(t.preventDefault(),this._submitSupport())}_renderSupportDialog(){const t=this.host._supportDialog,e=l(this.host.hass,this.host._config?.language),s="ru"===e?"https://github.com/Matysh/houseplan-card/blob/main/docs/USER-GUIDE.ru.md":"https://github.com/Matysh/houseplan-card/blob/main/docs/USER-GUIDE.md",i=cd(this.host._haSupportApi),o=(t,s)=>ra(e,t,s),a="building"===t.status||"sending"===t.status,n=_d(t),r=t.preview?Math.max(0,Math.floor((Date.now()-t.preview.preparedAt)/6e4)):0,h="error"===t.status&&!t.errorCode.startsWith("validation."),c="validation.contact_too_long"===t.errorCode,u="validation.message_required"===t.errorCode||"validation.message_too_long"===t.errorCode;return p`{this._closeSupportDialog()}}>

    ${o("support.about_group")}

    -
    ${this.host._t("gs.about_version",{v:fi(Hd)})}
    +
    ${this.host._t("gs.about_version",{v:fi(Bd)})}
    - `;var _}_preflightDiagnostics(t,e){const s=new Map((e?.spaces||[]).map(t=>[String(t?.id||""),t]));return{kind:"houseplan-optimize-preflight",origin:"runtime",cardVersion:fi(Hd),checkedAt:(new Date).toISOString(),preflightFingerprint:t.fingerprint,failures:t.failures.map(t=>({spaceId:t.spaceId,displayName:t.displayName,reason:t.reason,detail:t.detail??null,spaceGeometryFingerprint:s.has(t.spaceId)?Yt(s.get(t.spaceId)):null}))}}_reportPreflightFailure(t,e){t.ok||t.fingerprint===this.host._reportedPreflightFingerprint||(this.host._reportedPreflightFingerprint=t.fingerprint,console.warn("[houseplan] optimize preflight failed",this._preflightDiagnostics(t,e)))}_preflightVersionsDiffer(){const t=this.host._haIntegrationVersion;return"string"==typeof t&&t.length>0&&t!==fi(Hd)}async _copyPreflightDiagnostics(){const t=this.host._alignDialog?.preflight;if(!t||t.ok)return;const e=JSON.stringify(this._preflightDiagnostics(t,this.host._alignDialog?.config??null),null,2);try{await navigator.clipboard.writeText(e),this.host._preflightClipboardFallback=null,this.host._showToast(this.host._t("gs.preflight_copied"))}catch{this.host._preflightClipboardFallback=e}}_checkOptimizeGeometryImpl(t){return bi(t,{fallbackSpaceName:t=>this.host._t("gs.align_preflight_space",{n:String(t)})})}_checkSpacePhysicalGeometryImpl(t,e,s){return vi(t,e,{fallbackSpaceName:t=>this.host._t("gs.align_preflight_space",{n:String(t)}),captureWallGeometry:s?(t,e)=>s(e):void 0})}_optimizeReferenceContext(t){const e=this.host._haRegistry,s=this.host._fullRegistryHass,i={},o=(...t)=>{for(const e of t){const t=String(e||"").trim();if(t)return t}return""};for(const[t,s]of Object.entries(e.devices||{}))i[t]=o(s?.name_by_user,s?.name,s?.model);for(const[t,s]of Object.entries(e.entities||{}))i[`lg_${t}`]=o(this.host.hass?.states?.[t]?.attributes?.friendly_name,s?.name,s?.original_name);for(const t of this.host._devices)i[t.id]=o(t.name,i[t.id]);for(const t of this.host._serverCfg?.markers||[]){const e=String(t.binding||"").indexOf(":"),a=e>0?t.binding.slice(0,e):"",n=e>0?t.binding.slice(e+1):"",r="device"===a?s?.devices?.[n]:"entity"===a?s?.entities?.[n]:null;i[t.id]=o(t.name,"device"===a?r?.name_by_user:null,r?.name,"entity"===a?this.host.hass?.states?.[n]?.attributes?.friendly_name:null,i[t.id])}return{effectiveAreaByMarker:Object.fromEntries(this.host._devices.filter(t=>!t.virtual&&!!t.area).map(t=>[t.id,t.area])),ownerRoster:{authoritative:e.authoritative,deviceIds:Object.keys(e.devices||{}),entityIds:[...new Set([...Object.keys(e.entities||{}),...Object.keys(this.host.hass?.states||{})])],names:i},removeLiveMissingPositions:t}}_previewAlignDialog(t){if(!this.host._norm||!this.host._serverCfg)return;const e=this.host._serverCfg.spaces||[];let s;try{s=ar(this.host._serverCfg,this.host._layout||{},this._optimizeReferenceContext(t))}catch(t){return void this._showWallModelMigrationBlocked(t)}const i=s.changed?this.host._checkOptimizeGeometry(s.config):null;i&&this._reportPreflightFailure(i,s.config);const o=Math.ceil(10*s.report.maxShiftCm)/10,a=e.find(t=>null!=t?.id&&String(t.id)===s.report.maxSpace),n=e.length>1&&a?String(a.title||a.id):"";this.host._preflightClipboardFallback=null,this.host._alignDialog={report:s.report,config:s.config,layout:s.layout,cm:o,where:n,preflight:i,changed:s.changed,busy:!1,removeLiveMissingPositions:t}}async _runAlignToGrid(){let t=this.host._alignDialog;if(!t||t.busy||!this.host._serverCfg||!t.changed||!t.preflight?.ok)return;const e=wt(t.config);if(t.preflight.fingerprint!==e){const e=this.host._checkOptimizeGeometry(t.config);if(this._reportPreflightFailure(e,t.config),t={...t,preflight:e},this.host._alignDialog=t,!e.ok)return}this._clearGeometryGesture(),this.host._alignDialog={...t,busy:!0};try{await nr(this.host,t.config,t.layout),this.host._alignDialog=null,this.host._preflightClipboardFallback=null,this.host._showToast(this.host._t("gs.align_done",{n:String(t.report.moved),m:String(t.report.migrated+t.report.canonicalized+t.report.coordsCanonicalized+t.report.latticeCoordinatesCanonicalized+t.report.wallsMerged+t.report.spansMerged+t.report.partitionsMerged+t.report.partitionsReconciled+t.report.openingsRehosted+t.report.wallsStraightened),r:String(t.report.spaceRefsRemapped+t.report.roomRefsRemapped+t.report.positionsRemapped+t.report.markersDetached+t.report.orphanRoomLabelsRemoved+t.report.orphanDevicePositionsRemoved+t.report.orphanGroupPositionsRemoved)}))}catch(t){if(this.host._alignDialog&&(this.host._alignDialog={...this.host._alignDialog,busy:!1}),"wall_model_client_outdated"===t?.code)return void this.host._showToast(this.host._t("toast.wall_model_client_outdated"));"conflict"===t?.code&&await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _undoPlanOptimization(){if(!this.host._canOptimizeUndo||this.host._optimizeUndoBusy)return;const t=this.host._undoKind;this._clearGeometryGesture(),this.host._optimizeUndoBusy=!0,this.host.requestUpdate();try{await this.host.hass.callWS({type:"houseplan/plan/optimize_undo",expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev});const[e,s]=await Promise.all([this.host._getAuthoritativeConfig(),this.host.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this.host._adoptAuthoritative({cfgResp:e,layResp:s,reason:"optimize-undo",profile:"post-write"})).status)return;this.host._geometryHistory.clear(),this.host._cancelDeviceDrag(),this.host._devicePositionHistory.clear(),this.host._canOptimizeUndo=!1,this.host._undoKind=null,this.host._cfgEpoch++,this.host._modelCache=null,this.host._frame=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._cacheSnapshot(),this.host.requestUpdate(),this.host._showToast(this.host._t("import"===t?"backup.import_undone":"gs.optimize_undone"))}catch(t){this.host._canOptimizeUndo=!1,this.host._undoKind=null,this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}finally{this.host._optimizeUndoBusy=!1,this.host.requestUpdate()}}async _runBackupExport(){const t=this.host._backupExportDialog;if(t&&!t.busy){this.host._backupExportDialog={...t,busy:!0,error:""};try{const e=await this.host.hass.callWS({type:"houseplan/export/create",kind:t.kind,space_id:"space"===t.kind?this.host._space:void 0,..."space"===t.kind&&t.planOnly?{plan_only:!0}:{},card_version:fi(Hd)}),s=new Blob([JSON.stringify(e.document,null,2)+"\n"],{type:"application/json;charset=utf-8"}),i=URL.createObjectURL(s),o=document.createElement("a");o.href=i,o.download=e.filename||`houseplan-${t.kind}.json`,o.style.display="none",document.body.append(o),o.click(),o.remove(),window.setTimeout(()=>URL.revokeObjectURL(i),0),this.host._backupExportDialog=null,this.host._showToast(this.host._t("backup.export_done"))}catch(t){this.host._backupExportDialog&&(this.host._backupExportDialog={...this.host._backupExportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _pickBackupImport(t){const e=t.target,s=e.files?.[0];if(e.value="",s){this.host._settingsDialog=null,this.host._backupImportDialog={filename:s.name,size:s.size,token:"",preview:null,expectedConfigRev:this.host._cfgRev,expectedLayoutRev:this.host._layoutRev,duplicatePolicy:"skip",confirmMissing:!1,busy:!0,error:""};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),await this.host._writeChain,this.host._persistLayout.pending()&&this.host._persistLayout.flush();const t="/api/houseplan/import/preview?duplicate_policy=skip",e={method:"POST",body:s,headers:{"content-type":"application/json"}},i=this.host.hass?.fetchWithAuth?await this.host.hass.fetchWithAuth(t,e):await fetch(t,{...e,headers:{...e.headers,...this.host.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.host.hass.auth.data.access_token}`}:{}}}),o=await i.json().catch(()=>({}));if(!i.ok||o.error)throw Object.assign(new Error(o.message||o.error||`HTTP ${i.status}`),{code:o.error});this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,token:o.token,preview:o.preview,expectedConfigRev:o.expected_config_rev,expectedLayoutRev:o.expected_layout_rev,busy:!1})}catch(t){this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _setBackupDuplicatePolicy(t){const e=this.host._backupImportDialog;if(e&&!e.busy&&e.token&&t!==e.duplicatePolicy){this.host._backupImportDialog={...e,duplicatePolicy:t,busy:!0,error:""};try{const s=await this.host.hass.callWS({type:"houseplan/import/revalidate",token:e.token,duplicate_policy:t});this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,preview:{...e.preview,...s.preview},expectedConfigRev:s.expected_config_rev,expectedLayoutRev:s.expected_layout_rev,confirmMissing:!1,busy:!1})}catch(t){this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,duplicatePolicy:e.duplicatePolicy,preview:e.preview,confirmMissing:e.confirmMissing,busy:!1,error:this._backupErrorText(t)})}}}async _applyBackupImport(){const t=this.host._backupImportDialog;if(!t||t.busy||!t.token||!t.preview)return;if(t.preview.confirmation_required&&!t.confirmMissing)return;this.host._backupImportDialog={...t,busy:!0,error:""};const e=this.host._space;try{const s=await this.host.hass.callWS({type:"houseplan/import/apply",token:t.token,expected_config_rev:t.expectedConfigRev,expected_layout_rev:t.expectedLayoutRev,duplicate_policy:t.duplicatePolicy,confirm_missing_content:t.confirmMissing}),[i,o]=await Promise.all([this.host._getAuthoritativeConfig(),this.host.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this.host._adoptAuthoritative({cfgResp:i,layResp:o,reason:"import-apply",profile:"post-write"})).status)return this.host._backupImportDialog={...t,busy:!1,error:""},void this.host.requestUpdate();this.host._geometryHistory.clear(),this.host._dirtyPos.clear(),this.host._sentPos.clear(),this.host._defPos={},this.host._cfgEpoch++,this.host._modelCache=null,this.host._frame=null,this.host._visibleDeviceSnapshot=null,this.host._candidateDeviceSnapshot=null,this.host._stagedDeviceSnapshotToken=-1,this.host._capturedSnapshotConfigEpoch=-1,this.host._regSignature="",this.host._signer.invalidate(this.host.hass),this.host._resign(),this.host._maybeRebuildDevices();const a=this.host._serverCfg?.spaces||[],n="space"===s.kind&&s.space_id?s.space_id:a.some(t=>t.id===e)?e:a[0]?.id||this.host._space;this.host._hasFixedFloor?this.host._adoptInitialSpace(this.host._model,!0):this.host._commitSpace(n),this.host._backupImportDialog=null,this.host._cacheSnapshot(),this.host.requestUpdate();const r="space"===s.kind?t.preview.counts:s.counts;this.host._showToast(this.host._t("space"===s.kind?"backup.space_done":"backup.full_done",{spaces:String(r?.spaces||0),rooms:String(r?.rooms||0),markers:String(r?.markers||0),refs:String(s.repaired_target_refs||0)}))}catch(t){if("conflict"===t?.code&&this.host._backupImportDialog?.token)try{const t=this.host._backupImportDialog,e=await this.host.hass.callWS({type:"houseplan/import/revalidate",token:t.token,duplicate_policy:t.duplicatePolicy});return void(this.host._backupImportDialog={...t,preview:{...t.preview,...e.preview},expectedConfigRev:e.expected_config_rev,expectedLayoutRev:e.expected_layout_rev,confirmMissing:!1,busy:!1,error:this.host._t("backup.revalidated")})}catch(e){t=e}this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}_renderBackupExportDialog(){const t=this.host._backupExportDialog,e=(this.host._serverCfg?.spaces||[]).find(t=>t.id===this.host._space);return p``;var _}_preflightDiagnostics(t,e){const s=new Map((e?.spaces||[]).map(t=>[String(t?.id||""),t]));return{kind:"houseplan-optimize-preflight",origin:"runtime",cardVersion:fi(Bd),checkedAt:(new Date).toISOString(),preflightFingerprint:t.fingerprint,failures:t.failures.map(t=>({spaceId:t.spaceId,displayName:t.displayName,reason:t.reason,detail:t.detail??null,spaceGeometryFingerprint:s.has(t.spaceId)?Yt(s.get(t.spaceId)):null}))}}_reportPreflightFailure(t,e){t.ok||t.fingerprint===this.host._reportedPreflightFingerprint||(this.host._reportedPreflightFingerprint=t.fingerprint,console.warn("[houseplan] optimize preflight failed",this._preflightDiagnostics(t,e)))}_preflightVersionsDiffer(){const t=this.host._haIntegrationVersion;return"string"==typeof t&&t.length>0&&t!==fi(Bd)}async _copyPreflightDiagnostics(){const t=this.host._alignDialog?.preflight;if(!t||t.ok)return;const e=JSON.stringify(this._preflightDiagnostics(t,this.host._alignDialog?.config??null),null,2);try{await navigator.clipboard.writeText(e),this.host._preflightClipboardFallback=null,this.host._showToast(this.host._t("gs.preflight_copied"))}catch{this.host._preflightClipboardFallback=e}}_checkOptimizeGeometryImpl(t){return bi(t,{fallbackSpaceName:t=>this.host._t("gs.align_preflight_space",{n:String(t)})})}_checkSpacePhysicalGeometryImpl(t,e,s){return vi(t,e,{fallbackSpaceName:t=>this.host._t("gs.align_preflight_space",{n:String(t)}),captureWallGeometry:s?(t,e)=>s(e):void 0})}_optimizeReferenceContext(t){const e=this.host._haRegistry,s=this.host._fullRegistryHass,i={},o=(...t)=>{for(const e of t){const t=String(e||"").trim();if(t)return t}return""};for(const[t,s]of Object.entries(e.devices||{}))i[t]=o(s?.name_by_user,s?.name,s?.model);for(const[t,s]of Object.entries(e.entities||{}))i[`lg_${t}`]=o(this.host.hass?.states?.[t]?.attributes?.friendly_name,s?.name,s?.original_name);for(const t of this.host._devices)i[t.id]=o(t.name,i[t.id]);for(const t of this.host._serverCfg?.markers||[]){const e=String(t.binding||"").indexOf(":"),a=e>0?t.binding.slice(0,e):"",n=e>0?t.binding.slice(e+1):"",r="device"===a?s?.devices?.[n]:"entity"===a?s?.entities?.[n]:null;i[t.id]=o(t.name,"device"===a?r?.name_by_user:null,r?.name,"entity"===a?this.host.hass?.states?.[n]?.attributes?.friendly_name:null,i[t.id])}return{effectiveAreaByMarker:Object.fromEntries(this.host._devices.filter(t=>!t.virtual&&!!t.area).map(t=>[t.id,t.area])),ownerRoster:{authoritative:e.authoritative,deviceIds:Object.keys(e.devices||{}),entityIds:[...new Set([...Object.keys(e.entities||{}),...Object.keys(this.host.hass?.states||{})])],names:i},removeLiveMissingPositions:t}}_previewAlignDialog(t){if(!this.host._norm||!this.host._serverCfg)return;const e=this.host._serverCfg.spaces||[];let s;try{s=or(this.host._serverCfg,this.host._layout||{},this._optimizeReferenceContext(t))}catch(t){return void this._showWallModelMigrationBlocked(t)}const i=s.changed?this.host._checkOptimizeGeometry(s.config):null;i&&this._reportPreflightFailure(i,s.config);const o=Math.ceil(10*s.report.maxShiftCm)/10,a=e.find(t=>null!=t?.id&&String(t.id)===s.report.maxSpace),n=e.length>1&&a?String(a.title||a.id):"";this.host._preflightClipboardFallback=null,this.host._alignDialog={report:s.report,config:s.config,layout:s.layout,cm:o,where:n,preflight:i,changed:s.changed,busy:!1,removeLiveMissingPositions:t}}async _runAlignToGrid(){let t=this.host._alignDialog;if(!t||t.busy||!this.host._serverCfg||!t.changed||!t.preflight?.ok)return;const e=yt(t.config);if(t.preflight.fingerprint!==e){const e=this.host._checkOptimizeGeometry(t.config);if(this._reportPreflightFailure(e,t.config),t={...t,preflight:e},this.host._alignDialog=t,!e.ok)return}this._clearGeometryGesture(),this.host._alignDialog={...t,busy:!0};try{await ar(this.host,t.config,t.layout),this.host._alignDialog=null,this.host._preflightClipboardFallback=null,this.host._showToast(this.host._t("gs.align_done",{n:String(t.report.moved),m:String(t.report.migrated+t.report.canonicalized+t.report.coordsCanonicalized+t.report.latticeCoordinatesCanonicalized+t.report.wallsMerged+t.report.spansMerged+t.report.partitionsMerged+t.report.partitionsReconciled+t.report.openingsRehosted+t.report.wallsStraightened),r:String(t.report.spaceRefsRemapped+t.report.roomRefsRemapped+t.report.positionsRemapped+t.report.markersDetached+t.report.orphanRoomLabelsRemoved+t.report.orphanDevicePositionsRemoved+t.report.orphanGroupPositionsRemoved)}))}catch(t){if(this.host._alignDialog&&(this.host._alignDialog={...this.host._alignDialog,busy:!1}),"wall_model_client_outdated"===t?.code)return void this.host._showToast(this.host._t("toast.wall_model_client_outdated"));"conflict"===t?.code&&await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _undoPlanOptimization(){if(!this.host._canOptimizeUndo||this.host._optimizeUndoBusy)return;const t=this.host._undoKind;this._clearGeometryGesture(),this.host._optimizeUndoBusy=!0,this.host.requestUpdate();try{await this.host.hass.callWS({type:"houseplan/plan/optimize_undo",expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev});const[e,s]=await Promise.all([this.host._getAuthoritativeConfig(),this.host.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this.host._adoptAuthoritative({cfgResp:e,layResp:s,reason:"optimize-undo",profile:"post-write"})).status)return;this.host._geometryHistory.clear(),this.host._cancelDeviceDrag(),this.host._devicePositionHistory.clear(),this.host._canOptimizeUndo=!1,this.host._undoKind=null,this.host._cfgEpoch++,this.host._modelCache=null,this.host._frame=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._cacheSnapshot(),this.host.requestUpdate(),this.host._showToast(this.host._t("import"===t?"backup.import_undone":"gs.optimize_undone"))}catch(t){this.host._canOptimizeUndo=!1,this.host._undoKind=null,this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}finally{this.host._optimizeUndoBusy=!1,this.host.requestUpdate()}}async _runBackupExport(){const t=this.host._backupExportDialog;if(t&&!t.busy){this.host._backupExportDialog={...t,busy:!0,error:""};try{const e=await this.host.hass.callWS({type:"houseplan/export/create",kind:t.kind,space_id:"space"===t.kind?this.host._space:void 0,..."space"===t.kind&&t.planOnly?{plan_only:!0}:{},card_version:fi(Bd)}),s=new Blob([JSON.stringify(e.document,null,2)+"\n"],{type:"application/json;charset=utf-8"}),i=URL.createObjectURL(s),o=document.createElement("a");o.href=i,o.download=e.filename||`houseplan-${t.kind}.json`,o.style.display="none",document.body.append(o),o.click(),o.remove(),window.setTimeout(()=>URL.revokeObjectURL(i),0),this.host._backupExportDialog=null,this.host._showToast(this.host._t("backup.export_done"))}catch(t){this.host._backupExportDialog&&(this.host._backupExportDialog={...this.host._backupExportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _pickBackupImport(t){const e=t.target,s=e.files?.[0];if(e.value="",s){this.host._settingsDialog=null,this.host._backupImportDialog={filename:s.name,size:s.size,token:"",preview:null,expectedConfigRev:this.host._cfgRev,expectedLayoutRev:this.host._layoutRev,duplicatePolicy:"skip",confirmMissing:!1,busy:!0,error:""};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),await this.host._writeChain,this.host._persistLayout.pending()&&this.host._persistLayout.flush();const t="/api/houseplan/import/preview?duplicate_policy=skip",e={method:"POST",body:s,headers:{"content-type":"application/json"}},i=this.host.hass?.fetchWithAuth?await this.host.hass.fetchWithAuth(t,e):await fetch(t,{...e,headers:{...e.headers,...this.host.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.host.hass.auth.data.access_token}`}:{}}}),o=await i.json().catch(()=>({}));if(!i.ok||o.error)throw Object.assign(new Error(o.message||o.error||`HTTP ${i.status}`),{code:o.error});this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,token:o.token,preview:o.preview,expectedConfigRev:o.expected_config_rev,expectedLayoutRev:o.expected_layout_rev,busy:!1})}catch(t){this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _setBackupDuplicatePolicy(t){const e=this.host._backupImportDialog;if(e&&!e.busy&&e.token&&t!==e.duplicatePolicy){this.host._backupImportDialog={...e,duplicatePolicy:t,busy:!0,error:""};try{const s=await this.host.hass.callWS({type:"houseplan/import/revalidate",token:e.token,duplicate_policy:t});this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,preview:{...e.preview,...s.preview},expectedConfigRev:s.expected_config_rev,expectedLayoutRev:s.expected_layout_rev,confirmMissing:!1,busy:!1})}catch(t){this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,duplicatePolicy:e.duplicatePolicy,preview:e.preview,confirmMissing:e.confirmMissing,busy:!1,error:this._backupErrorText(t)})}}}async _applyBackupImport(){const t=this.host._backupImportDialog;if(!t||t.busy||!t.token||!t.preview)return;if(t.preview.confirmation_required&&!t.confirmMissing)return;this.host._backupImportDialog={...t,busy:!0,error:""};const e=this.host._space;try{const s=await this.host.hass.callWS({type:"houseplan/import/apply",token:t.token,expected_config_rev:t.expectedConfigRev,expected_layout_rev:t.expectedLayoutRev,duplicate_policy:t.duplicatePolicy,confirm_missing_content:t.confirmMissing}),[i,o]=await Promise.all([this.host._getAuthoritativeConfig(),this.host.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this.host._adoptAuthoritative({cfgResp:i,layResp:o,reason:"import-apply",profile:"post-write"})).status)return this.host._backupImportDialog={...t,busy:!1,error:""},void this.host.requestUpdate();this.host._geometryHistory.clear(),this.host._dirtyPos.clear(),this.host._sentPos.clear(),this.host._defPos={},this.host._cfgEpoch++,this.host._modelCache=null,this.host._frame=null,this.host._visibleDeviceSnapshot=null,this.host._candidateDeviceSnapshot=null,this.host._stagedDeviceSnapshotToken=-1,this.host._capturedSnapshotConfigEpoch=-1,this.host._regSignature="",this.host._signer.invalidate(this.host.hass),this.host._resign(),this.host._maybeRebuildDevices();const a=this.host._serverCfg?.spaces||[],n="space"===s.kind&&s.space_id?s.space_id:a.some(t=>t.id===e)?e:a[0]?.id||this.host._space;this.host._hasFixedFloor?this.host._adoptInitialSpace(this.host._model,!0):this.host._commitSpace(n),this.host._backupImportDialog=null,this.host._cacheSnapshot(),this.host.requestUpdate();const r="space"===s.kind?t.preview.counts:s.counts;this.host._showToast(this.host._t("space"===s.kind?"backup.space_done":"backup.full_done",{spaces:String(r?.spaces||0),rooms:String(r?.rooms||0),markers:String(r?.markers||0),refs:String(s.repaired_target_refs||0)}))}catch(t){if("conflict"===t?.code&&this.host._backupImportDialog?.token)try{const t=this.host._backupImportDialog,e=await this.host.hass.callWS({type:"houseplan/import/revalidate",token:t.token,duplicate_policy:t.duplicatePolicy});return void(this.host._backupImportDialog={...t,preview:{...t.preview,...e.preview},expectedConfigRev:e.expected_config_rev,expectedLayoutRev:e.expected_layout_rev,confirmMissing:!1,busy:!1,error:this.host._t("backup.revalidated")})}catch(e){t=e}this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}_renderBackupExportDialog(){const t=this.host._backupExportDialog,e=(this.host._serverCfg?.spaces||[]).find(t=>t.id===this.host._space);return p`this.host._backupExportDialog=null}>
    ${this.host._t("backup.export_hint")}
    @@ -1672,7 +1672,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${t.busy?"…":this.host._t("full"===e.kind?"backup.replace":"backup.add")} `:d}
    -
    `}_setFillColor(t,e){const s=this.host._settingsDialog;this.host._settingsDialog={...s,colors:{...s.colors,[t]:{...s.colors[t],...e}}}}_updateDecorStyle(t){this.host._decorStyle=t,null!==this._decorStylePersistTimer&&window.clearTimeout(this._decorStylePersistTimer),this._decorStylePersistTimer=window.setTimeout(()=>{this._decorStylePersistTimer=null,this._persistDecorStyle()},1e3)}_persistDecorStyle(){const t=this.host._serverCfg;if(!t)return;const e=yi(this.host._decorStyle),s={...t.settings},i=JSON.stringify(s.decor_default_style??null);e?s.decor_default_style=e:delete s.decor_default_style,JSON.stringify(s.decor_default_style??null)!==i&&(this.host._serverCfg={...t,settings:s},this._saveConfig())}async _saveSettingsDialog(){const t=this.host._settingsDialog;if(!t||t.busy)return;this.host._settingsDialog={...t,busy:!0};let e=null;try{const s=this.host._serverCfg,i=JSON.stringify(t.colors)===JSON.stringify(xt);let o={...s.settings};i?delete o.fill_colors:o.fill_colors=t.colors;const a=this.host._imperial?30.48*t.glowRadius:100*t.glowRadius;Number.isFinite(a)&&a>0&&300!==Math.round(a)?o.glow_radius_cm=Math.round(a):delete o.glow_radius_cm,t.bgColor?o.bg_color=t.bgColor:delete o.bg_color,null!==t.northDeg&&Number.isInteger(t.northDeg)&&t.northDeg>=0&&t.northDeg<=359?o.north_deg=t.northDeg:delete o.north_deg,o.bg_mode=t.bgMode,t.sunRays?o.sun_rays=!0:delete o.sun_rays,o.sun_ray_origin=t.sunRayOrigin,t.showRoomTooltip?delete o.show_room_tooltip:o.show_room_tooltip=!1;const n=o.radar;n&&null!=n.version&&1!==n.version||(o.radar={...n||{},version:1},t.radarShowLive?delete o.radar.show_live:o.radar.show_live=!1),o=wi(o,t.zigbeeTopology),delete o.weather_entity;const r={...s,settings:o};e=this.host._adoption.beginOptimistic(s,r),this.host._serverCfg=r,await this._saveConfigNow(e),!t.showRoomTooltip&&this.host._tip?.room&&(this.host._tip=null),this.host._settingsDialog=null,this.host.requestUpdate(),this.host._showToast(this.host._t("gs.saved"))}catch(t){e&&this.host._rollbackOptimistic(e),this.host._settingsDialog&&(this.host._settingsDialog={...this.host._settingsDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_boolInput(t,e,s=!1){const i=t=>e(!!t.target.checked);return customElements.get("ha-switch")?p``:p``}_rangeInput(t,e,s,i,o,a=!1,n){const r=t=>{const e=Number(t.target.value);Number.isFinite(e)&&o(e)};return customElements.get("ha-slider")?p``}_setFillColor(t,e){const s=this.host._settingsDialog;this.host._settingsDialog={...s,colors:{...s.colors,[t]:{...s.colors[t],...e}}}}_updateDecorStyle(t){this.host._decorStyle=t,null!==this._decorStylePersistTimer&&window.clearTimeout(this._decorStylePersistTimer),this._decorStylePersistTimer=window.setTimeout(()=>{this._decorStylePersistTimer=null,this._persistDecorStyle()},1e3)}_persistDecorStyle(){const t=this.host._serverCfg;if(!t)return;const e=yi(this.host._decorStyle),s={...t.settings},i=JSON.stringify(s.decor_default_style??null);e?s.decor_default_style=e:delete s.decor_default_style,JSON.stringify(s.decor_default_style??null)!==i&&(this.host._serverCfg={...t,settings:s},this._saveConfig())}async _saveSettingsDialog(){const t=this.host._settingsDialog;if(!t||t.busy)return;this.host._settingsDialog={...t,busy:!0};let e=null;try{const s=this.host._serverCfg,i=JSON.stringify(t.colors)===JSON.stringify(kt);let o={...s.settings};i?delete o.fill_colors:o.fill_colors=t.colors;const a=this.host._imperial?30.48*t.glowRadius:100*t.glowRadius;Number.isFinite(a)&&a>0&&300!==Math.round(a)?o.glow_radius_cm=Math.round(a):delete o.glow_radius_cm,t.bgColor?o.bg_color=t.bgColor:delete o.bg_color,null!==t.northDeg&&Number.isInteger(t.northDeg)&&t.northDeg>=0&&t.northDeg<=359?o.north_deg=t.northDeg:delete o.north_deg,o.bg_mode=t.bgMode,t.sunRays?o.sun_rays=!0:delete o.sun_rays,o.sun_ray_origin=t.sunRayOrigin,t.showRoomTooltip?delete o.show_room_tooltip:o.show_room_tooltip=!1;const n=o.radar;n&&null!=n.version&&1!==n.version||(o.radar={...n||{},version:1},t.radarShowLive?delete o.radar.show_live:o.radar.show_live=!1),o=wi(o,t.zigbeeTopology),delete o.weather_entity;const r={...s,settings:o};e=this.host._adoption.beginOptimistic(s,r),this.host._serverCfg=r,await this._saveConfigNow(e),!t.showRoomTooltip&&this.host._tip?.room&&(this.host._tip=null),this.host._settingsDialog=null,this.host.requestUpdate(),this.host._showToast(this.host._t("gs.saved"))}catch(t){e&&this.host._rollbackOptimistic(e),this.host._settingsDialog&&(this.host._settingsDialog={...this.host._settingsDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_boolInput(t,e,s=!1){const i=t=>e(!!t.target.checked);return customElements.get("ha-switch")?p``:p``}_rangeInput(t,e,s,i,o,a=!1,n){const r=t=>{const e=Number(t.target.value);Number.isFinite(e)&&o(e)};return customElements.get("ha-slider")?p``:p``}_renderAlignDialog(){const t=this.host._alignDialog,e=t.report,s=t.changed&&!t.preflight?.ok,i=t.preflight?.failures||[],o=i.slice(0,3).map(t=>t.displayName),a=o.length?o.join(", "):this.host._t("gs.align_preflight_space",{n:"1"}),n=Math.max(0,i.length-o.length),r=n?this.host._t("gs.align_preflight_more",{n:String(n)}):"",l=e.spaceRefsRemapped+e.roomRefsRemapped+e.positionsRemapped+e.markersDetached,h=e.migrated+e.canonicalized+e.coordsCanonicalized+e.wallSegmentsMigrated+e.roomDraftsMigrated+e.roomDraftSegmentsMigrated+e.wallsMerged+e.spansMerged+e.partitionsMerged+e.partitionsReconciled+e.openingsRehosted,c=e.moved+e.rotated+e.coordsCanonicalized+e.wallsStraightened,u=Math.ceil(10*e.maxStraightenShiftCm)/10,_=(this.host._serverCfg?.spaces||[]).find(t=>String(t?.id||"")===e.maxStraightenSpace),m=(this.host._serverCfg?.spaces||[]).length>1&&_?String(_.title||_.id):"",g=e.orphanRoomLabelsRemoved+e.orphanDevicePositionsRemoved+e.orphanGroupPositionsRemoved,f=e.liveMissingPositions.map(t=>t.name).filter(Boolean),b=f.slice(0,3).join(", "),v=Math.max(0,f.length-3),y=b?this.host._t("gs.optimize_live_names",{names:b,more:v?this.host._t("gs.optimize_reference_more",{n:String(v)}):""}):"",w=e.unverifiedPositions.some(t=>"registry_unavailable"===t.reason),$=t=>e.removedPositions.some(e=>e.id===t.id)?this.host._t("gs.optimize_detail_removed"):e.liveMissingPositions.some(e=>e.id===t.id)?this.host._t("gs.optimize_detail_live"):this.host._t("gs.optimize_detail_unverified"),k=t=>this.host._t("room_label"===t?"gs.optimize_detail_room_label":"group"===t?"gs.optimize_detail_group":"device"===t?"gs.optimize_detail_device":"gs.optimize_detail_unknown"),x=[...e.removedPositions,...e.liveMissingPositions.filter(t=>!e.removedPositions.some(e=>e.id===t.id)),...e.unverifiedPositions],M=x.slice(0,10),C=Math.max(0,x.length-M.length);return p`{this.host._alignDialog=null,this.host._preflightClipboardFallback=null}}> @@ -1752,7 +1752,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${t.busy?"…":this.host._t("gs.align_run")} `:d}
    -
    `}_renderSettingsDialog(){return xr.call(this)}_rulesSet(t){this.host._rulesDialog={...this.host._rulesDialog,rules:t}}async _saveRules(){const t=this.host._rulesDialog;if(!t||t.busy)return;const e=t.rules.filter(t=>t.pattern.trim()&&t.icon.trim());this.host._rulesDialog={...t,busy:!0};try{const t=this.host._serverCfg,s=JSON.stringify(e)===JSON.stringify(Fe),i={...t.settings};s?delete i.icon_rules:i.icon_rules=e,this.host._serverCfg={...t,settings:i},await this._saveConfigNow(),this.host._rulesDialog=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("rules.saved"))}catch(t){this.host._rulesDialog&&(this.host._rulesDialog={...this.host._rulesDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_renderRulesDialog(){const t=this.host._rulesDialog,e=ki(t.rules),s=t.test.trim()?xi(t.test,"",e):null,i=(e,s)=>{const i=[...t.rules],o=e+s;o<0||o>=i.length||([i[e],i[o]]=[i[o],i[e]],this._rulesSet(i))};return p``}_renderSettingsDialog(){return kr.call(this)}_rulesSet(t){this.host._rulesDialog={...this.host._rulesDialog,rules:t}}async _saveRules(){const t=this.host._rulesDialog;if(!t||t.busy)return;const e=t.rules.filter(t=>t.pattern.trim()&&t.icon.trim());this.host._rulesDialog={...t,busy:!0};try{const t=this.host._serverCfg,s=JSON.stringify(e)===JSON.stringify(Fe),i={...t.settings};s?delete i.icon_rules:i.icon_rules=e,this.host._serverCfg={...t,settings:i},await this._saveConfigNow(),this.host._rulesDialog=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("rules.saved"))}catch(t){this.host._rulesDialog&&(this.host._rulesDialog={...this.host._rulesDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_renderRulesDialog(){const t=this.host._rulesDialog,e=ki(t.rules),s=t.test.trim()?xi(t.test,"",e):null,i=(e,s)=>{const i=[...t.rules],o=e+s;o<0||o>=i.length||([i[e],i[o]]=[i[o],i[e]],this._rulesSet(i))};return p`this.host._rulesDialog=null}>
    ${this.host._t("rules.hint")}
    @@ -1873,7 +1873,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${_a(this,e,a)} `:d} -
    `}_vacMapId(t,e,s=this.host._planHass){return this.host._vacMapId(t,e,s)}_vacSaveMatrix(t,e,s,i,o=""){return cd(this,t,e,s,i,o)}_vacPlanRoomAnchors(t){return(this.host._spaceModelById(t)?.rooms||[]).map(t=>({room:t,poly:A(t)})).filter(({room:t,poly:e})=>t.name&&e).map(({room:t,poly:e})=>{const s=Di(e);return s?{name:String(t.name),cx:s[0],cy:s[1]}:null}).filter(Boolean)}async _vacAutoCalibrate(t){if(this.host._markerDialog?.busy)return;const e=this.host._vacSource(t),s=e?Ci(this.host.hass?.states[e]?.attributes):null;if(!e||!s||s.rooms.length<3)return void this.host._showToast(this.host._t("vac.autocal_no_rooms"));const i=this._vacMapId(t,s),a=function(t,e,s,i,a){const n=o(t,e,s,i).find(t=>t.source===i&&t.map_id===a);return{space:n?.space||s,routeId:n?.id||""}}(t.id,t.marker?.vacuum??null,t.space,e,i),n=Ii(s.rooms,this._vacPlanRoomAnchors(a.space));if(!n)return void this.host._showToast(this.host._t("vac.autocal_no_match"));const r=this.host._serverCfg?.spaces?.find(t=>t.id===a.space),l=Number(r?.cell_cm),h=Number.isFinite(l)&&l>0?l:5,c=Li(n.residual,this.host._gridPitch,h);c>Ti?this.host._vacCalConfirm={markerId:t.id,source:e,mapId:i,routeId:a.routeId,space:a.space,matrix:n.matrix,rooms:n.matched.length,error:le(c,"mi"===this.host.hass?.config?.unit_system?.length)}:await async function(t,e){if(ld.has(t))return;ld.add(t);const s=t.host,i=s._markerDialog,o=i?{...i,busy:!0}:null;o&&(s._markerDialog=o,s.requestUpdate());try{await cd(t,e.markerId,e.source,e.mapId,e.matrix,e.routeId)&&s._showToast(s._t("vac.autocal_done",{rooms:String(e.rooms)}))}finally{ld.delete(t),o&&s._markerDialog===o&&(s._markerDialog={...o,busy:!1},s.requestUpdate())}}(this,{markerId:t.id,source:e,mapId:i,routeId:a.routeId,space:a.space,matrix:n.matrix,rooms:n.matched.length})}_vacApplyCalibrationProposal(t){return async function(t,e){const s=t.host,i=s._vacCalConfirm;if(!i||i.busy)return;if(e){const t=s._devices.find(t=>t.id===i.markerId),e=n(i.matrix);if(!t||!e)return;const o=i.space||t.space;if(o!==s._space&&!s._commitSpace(o))return;return s._vacCalConfirm=null,s._markerDialog=null,void(s._vacFit={markerId:i.markerId,source:i.source,routeId:i.routeId,mapId:i.mapId,p:e,drag:null})}const o={...i,busy:!0};s._vacCalConfirm=o,s.requestUpdate();const a=await cd(t,i.markerId,i.source,i.mapId,i.matrix,i.routeId);s._vacCalConfirm===o&&(s._vacCalConfirm=a?null:{...i,busy:!1},s.requestUpdate()),a&&s._showToast(s._t("vac.autocal_done",{rooms:String(i.rooms)}))}(this,t)}_vacStartFit(t,e=""){if(this.host._markerDialog?.busy)return;const s=this.host._vacSource(t),i=s?Ci(this.host.hass?.states[s]?.attributes):null;if(!s||!i)return void this.host._showToast(this.host._t("vac.cal_need_pos"));const l=this._vacMapId(t,i),h=function(t,e,s){const i=o(t,e,s.dockSpace,s.source),l=i.find(t=>t.id===s.routeId)||i.find(t=>t.source===s.source&&t.map_id===s.mapId)||null,h=l?.space||s.dockSpace,c=s.viewBoxOf(h);if(!c)return null;const d=a(l?l.calibration:e?.calibration?.[s.mapId]),p=d&&n(d)||r(s.rooms,c);return{space:h,routeId:l?.id||"",params:p}}(t.id,t.marker?.vacuum??null,{routeId:e,source:s,mapId:l,dockSpace:t.space,rooms:i.rooms,viewBoxOf:t=>this.host._spaceModelById(t)?.vb??null});h&&(this.host._markerDialog=null,(h.space===this.host._space||this.host._commitSpace(h.space))&&(this.host._vacFit={markerId:t.id,source:s,mapId:l,routeId:h.routeId,p:h.params,drag:null}))}_vacFitSave(){return async function(t,e){const s=t.host,i=s._vacFit;if(!i||i.busy)return;const o={...i,busy:!0,drag:null};s._vacFit=o,s.requestUpdate();const a=await cd(t,i.markerId,i.source,i.mapId,e(i.p),i.routeId);s._vacFit===o&&(s._vacFit=a?null:{...i,busy:!1,drag:null},s.requestUpdate()),a&&s._showToast(s._t("vac.cal_done"))}(this,zi)}_vacFitTurn(t){const e=this.host._vacFit;if(!e||e.busy)return;const s=Ci(this.host.hass?.states[e.source]?.attributes),i=this._vacGhostCentre(s?.rooms||[]),o={...e.p,...t};this.host._vacFit={...e,p:Ri(o,e.p,i[0],i[1])}}_vacGhostCentre(t){const e=[],s=[];for(const i of t)e.push(i.x0??i.cx,i.x1??i.cx),s.push(i.y0??i.cy,i.y1??i.cy);return e.length?[(Math.min(...e)+Math.max(...e))/2,(Math.min(...s)+Math.max(...s))/2]:[0,0]}_vacDelta(t,e,s){const i=this.host._stageEl,o=i?.clientWidth||1,a=i?.clientHeight||1;return[e/o*t.w,s/a*t.h]}_vacFitPointer(t,e){const s=this.host._vacFit;if(!s)return;if(t.stopPropagation(),s.busy)return;if("pointerdown"===t.type){const e=t.target,i=e.getAttribute?.("data-corner");try{t.currentTarget.setPointerCapture?.(t.pointerId)}catch{}return void(this.host._vacFit={...s,drag:i?{kind:"scale",sx:t.clientX,sy:t.clientY,p0:{...s.p},fx:Number(i.split(",")[0]),fy:Number(i.split(",")[1])}:{kind:"move",sx:t.clientX,sy:t.clientY,p0:{...s.p},fx:0,fy:0}})}const i=s.drag;if(i){if("pointermove"===t.type){const[o,a]=this._vacDelta(e,t.clientX-i.sx,t.clientY-i.sy);if("move"===i.kind)this.host._vacFit={...s,p:{...i.p0,ox:i.p0.ox+o,oy:i.p0.oy+a}};else{const t=Ci(this.host.hass?.states[s.source]?.attributes),e=this._vacGhostCentre(t?.rooms||[]),n=zi(i.p0),[r,l]=Fi(n,e[0],e[1]),[h,c]=Fi(n,i.fx,i.fy),d=Math.hypot(r-h,l-c)||1,[p,u]=[2*r-h,2*l-c],_=Math.hypot(p+2*o-h,u+2*a-c)/2,m=Math.max(.05,_/d),g={...i.p0,s:i.p0.s*m};this.host._vacFit={...s,p:Ri(g,i.p0,i.fx,i.fy)}}return}"pointerup"!==t.type&&"pointercancel"!==t.type||(this.host._vacFit={...s,drag:null})}}_renderVacFit(t){const e=this.host._vacFit;if(!e)return d;const s=Ci(this.host._renderPlanHass?.states?.[e.source]?.attributes);if(!s)return d;const i=zi(e.p),o=[],a=[],n=[];for(const t of s.rooms){if(null==t.x0)continue;const e=[[t.x0,t.y0],[t.x1,t.y0],[t.x1,t.y1],[t.x0,t.y1]].map(([t,e])=>Fi(i,t,e));e.forEach(([t,e])=>{a.push(t),n.push(e)});const[s,r]=Fi(i,t.cx,t.cy);o.push(Pt` + `}_vacMapId(t,e,s=this.host._planHass){return this.host._vacMapId(t,e,s)}_vacSaveMatrix(t,e,s,i,o=""){return hd(this,t,e,s,i,o)}_vacPlanRoomAnchors(t){return(this.host._spaceModelById(t)?.rooms||[]).map(t=>({room:t,poly:N(t)})).filter(({room:t,poly:e})=>t.name&&e).map(({room:t,poly:e})=>{const s=Di(e);return s?{name:String(t.name),cx:s[0],cy:s[1]}:null}).filter(Boolean)}async _vacAutoCalibrate(t){if(this.host._markerDialog?.busy)return;const e=this.host._vacSource(t),s=e?Ci(this.host.hass?.states[e]?.attributes):null;if(!e||!s||s.rooms.length<3)return void this.host._showToast(this.host._t("vac.autocal_no_rooms"));const i=this._vacMapId(t,s),a=function(t,e,s,i,a){const n=o(t,e,s,i).find(t=>t.source===i&&t.map_id===a);return{space:n?.space||s,routeId:n?.id||""}}(t.id,t.marker?.vacuum??null,t.space,e,i),n=Ii(s.rooms,this._vacPlanRoomAnchors(a.space));if(!n)return void this.host._showToast(this.host._t("vac.autocal_no_match"));const r=this.host._serverCfg?.spaces?.find(t=>t.id===a.space),l=Number(r?.cell_cm),h=Number.isFinite(l)&&l>0?l:5,c=Li(n.residual,this.host._gridPitch,h);c>Ti?this.host._vacCalConfirm={markerId:t.id,source:e,mapId:i,routeId:a.routeId,space:a.space,matrix:n.matrix,rooms:n.matched.length,error:le(c,"mi"===this.host.hass?.config?.unit_system?.length)}:await async function(t,e){if(rd.has(t))return;rd.add(t);const s=t.host,i=s._markerDialog,o=i?{...i,busy:!0}:null;o&&(s._markerDialog=o,s.requestUpdate());try{await hd(t,e.markerId,e.source,e.mapId,e.matrix,e.routeId)&&s._showToast(s._t("vac.autocal_done",{rooms:String(e.rooms)}))}finally{rd.delete(t),o&&s._markerDialog===o&&(s._markerDialog={...o,busy:!1},s.requestUpdate())}}(this,{markerId:t.id,source:e,mapId:i,routeId:a.routeId,space:a.space,matrix:n.matrix,rooms:n.matched.length})}_vacApplyCalibrationProposal(t){return async function(t,e){const s=t.host,i=s._vacCalConfirm;if(!i||i.busy)return;if(e){const t=s._devices.find(t=>t.id===i.markerId),e=n(i.matrix);if(!t||!e)return;const o=i.space||t.space;if(o!==s._space&&!s._commitSpace(o))return;return s._vacCalConfirm=null,s._markerDialog=null,void(s._vacFit={markerId:i.markerId,source:i.source,routeId:i.routeId,mapId:i.mapId,p:e,drag:null})}const o={...i,busy:!0};s._vacCalConfirm=o,s.requestUpdate();const a=await hd(t,i.markerId,i.source,i.mapId,i.matrix,i.routeId);s._vacCalConfirm===o&&(s._vacCalConfirm=a?null:{...i,busy:!1},s.requestUpdate()),a&&s._showToast(s._t("vac.autocal_done",{rooms:String(i.rooms)}))}(this,t)}_vacStartFit(t,e=""){if(this.host._markerDialog?.busy)return;const s=this.host._vacSource(t),i=s?Ci(this.host.hass?.states[s]?.attributes):null;if(!s||!i)return void this.host._showToast(this.host._t("vac.cal_need_pos"));const l=this._vacMapId(t,i),h=function(t,e,s){const i=o(t,e,s.dockSpace,s.source),l=i.find(t=>t.id===s.routeId)||i.find(t=>t.source===s.source&&t.map_id===s.mapId)||null,h=l?.space||s.dockSpace,c=s.viewBoxOf(h);if(!c)return null;const d=a(l?l.calibration:e?.calibration?.[s.mapId]),p=d&&n(d)||r(s.rooms,c);return{space:h,routeId:l?.id||"",params:p}}(t.id,t.marker?.vacuum??null,{routeId:e,source:s,mapId:l,dockSpace:t.space,rooms:i.rooms,viewBoxOf:t=>this.host._spaceModelById(t)?.vb??null});h&&(this.host._markerDialog=null,(h.space===this.host._space||this.host._commitSpace(h.space))&&(this.host._vacFit={markerId:t.id,source:s,mapId:l,routeId:h.routeId,p:h.params,drag:null}))}_vacFitSave(){return async function(t,e){const s=t.host,i=s._vacFit;if(!i||i.busy)return;const o={...i,busy:!0,drag:null};s._vacFit=o,s.requestUpdate();const a=await hd(t,i.markerId,i.source,i.mapId,e(i.p),i.routeId);s._vacFit===o&&(s._vacFit=a?null:{...i,busy:!1,drag:null},s.requestUpdate()),a&&s._showToast(s._t("vac.cal_done"))}(this,zi)}_vacFitTurn(t){const e=this.host._vacFit;if(!e||e.busy)return;const s=Ci(this.host.hass?.states[e.source]?.attributes),i=this._vacGhostCentre(s?.rooms||[]),o={...e.p,...t};this.host._vacFit={...e,p:Ri(o,e.p,i[0],i[1])}}_vacGhostCentre(t){const e=[],s=[];for(const i of t)e.push(i.x0??i.cx,i.x1??i.cx),s.push(i.y0??i.cy,i.y1??i.cy);return e.length?[(Math.min(...e)+Math.max(...e))/2,(Math.min(...s)+Math.max(...s))/2]:[0,0]}_vacDelta(t,e,s){const i=this.host._stageEl,o=i?.clientWidth||1,a=i?.clientHeight||1;return[e/o*t.w,s/a*t.h]}_vacFitPointer(t,e){const s=this.host._vacFit;if(!s)return;if(t.stopPropagation(),s.busy)return;if("pointerdown"===t.type){const e=t.target,i=e.getAttribute?.("data-corner");try{t.currentTarget.setPointerCapture?.(t.pointerId)}catch{}return void(this.host._vacFit={...s,drag:i?{kind:"scale",sx:t.clientX,sy:t.clientY,p0:{...s.p},fx:Number(i.split(",")[0]),fy:Number(i.split(",")[1])}:{kind:"move",sx:t.clientX,sy:t.clientY,p0:{...s.p},fx:0,fy:0}})}const i=s.drag;if(i){if("pointermove"===t.type){const[o,a]=this._vacDelta(e,t.clientX-i.sx,t.clientY-i.sy);if("move"===i.kind)this.host._vacFit={...s,p:{...i.p0,ox:i.p0.ox+o,oy:i.p0.oy+a}};else{const t=Ci(this.host.hass?.states[s.source]?.attributes),e=this._vacGhostCentre(t?.rooms||[]),n=zi(i.p0),[r,l]=Fi(n,e[0],e[1]),[h,c]=Fi(n,i.fx,i.fy),d=Math.hypot(r-h,l-c)||1,[p,u]=[2*r-h,2*l-c],_=Math.hypot(p+2*o-h,u+2*a-c)/2,m=Math.max(.05,_/d),g={...i.p0,s:i.p0.s*m};this.host._vacFit={...s,p:Ri(g,i.p0,i.fx,i.fy)}}return}"pointerup"!==t.type&&"pointercancel"!==t.type||(this.host._vacFit={...s,drag:null})}}_renderVacFit(t){const e=this.host._vacFit;if(!e)return d;const s=Ci(this.host._renderPlanHass?.states?.[e.source]?.attributes);if(!s)return d;const i=zi(e.p),o=[],a=[],n=[];for(const t of s.rooms){if(null==t.x0)continue;const e=[[t.x0,t.y0],[t.x1,t.y0],[t.x1,t.y1],[t.x0,t.y1]].map(([t,e])=>Fi(i,t,e));e.forEach(([t,e])=>{a.push(t),n.push(e)});const[s,r]=Fi(i,t.cx,t.cy);o.push(Pt` ${t.name}`)}let r=d;if(s.pos){const[e,o]=Fi(i,s.pos.x,s.pos.y);r=Pt``}const l=[];if(a.length){const e=(()=>{const t=i[0]*i[4]-i[1]*i[3];return(e,s)=>[(i[4]*(e-i[2])-i[1]*(s-i[5]))/t,(-i[3]*(e-i[2])+i[0]*(s-i[5]))/t]})(),s=Math.min(...a),o=Math.max(...a),r=Math.min(...n),h=Math.max(...n),c=.022*t.w,d=c/4;for(const[t,i,a,n]of[[s,r,o,h],[o,r,s,h],[o,h,s,r],[s,h,o,r]]){const s=e(a,n);l.push(Pt` `)}}return p`t.id===this.host._roomEditId);if(!e)return this.host._roomDialog=!1,void(this.host._roomEditId=null);e.name=this.host._nameSel.trim()||e.name,e.area=this.host._areaSel||null;const s=e.settings||{},i={...s};Ei(i,this.host._roomTempMin,this.host._roomTempMax)&&(this.host._roomFill?i.fill_mode=this.host._roomFill:delete i.fill_mode,"custom"===this.host._roomFill&&this.host._roomCustomFill?i.custom_fill=this.host._roomCustomFill:delete i.custom_fill,"glow"===s.fill_mode&&"boolean"!=typeof s.glow&&(i.glow=!0),this.host._roomTempSrc?i.temp_source=this.host._roomTempSrc:delete i.temp_source,this.host._roomHumSrc?i.hum_source=this.host._roomHumSrc:delete i.hum_source,1!==this.host._roomNameScale?i.name_scale=this.host._roomNameScale:delete i.name_scale,1!==this.host._roomLabelScale?i.label_scale=this.host._roomLabelScale:delete i.label_scale,Object.keys(i).length?e.settings=i:delete e.settings,this._saveConfig(),this.host._roomDialog=!1,this.host._roomEditId=null,this.host._nameSel="",this.host._areaSel="",this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate(),this.host._showToast(this.host._t("toast.room_updated")))}_roomSrcCandidates(){const t=this.host._planHass,e=ne(this.host._markers),s=this.host._roomSrcFilter.trim().toLowerCase(),i=[];for(const o of Object.values(t.devices)){if("service"===o.entry_type)continue;if(e.devices.has(o.id))continue;const t=(o.name_by_user||o.name||o.id).trim();s&&!t.toLowerCase().includes(s)||i.push({value:"device:"+o.id,label:t,sub:o.model||this.host._t("marker.sub_device")})}for(const[o,a]of Object.entries(t.entities)){if(!o.startsWith("sensor.")||a.hidden)continue;if(re(t,o,e))continue;const n=a.name||t.states[o]?.attributes?.friendly_name||o;s&&!(n+" "+o).toLowerCase().includes(s)||i.push({value:"entity:"+o,label:n,sub:o})}return i.sort((t,e)=>t.label.localeCompare(e.label)),i.slice(0,200)}_roomSrcLabel(t){const e=t.indexOf(":"),s=t.slice(0,e),i=t.slice(e+1);return"device"===s?this.host._fullRegistryHass.devices[i]?.name_by_user||this.host._fullRegistryHass.devices[i]?.name||i:this.host._fullRegistryHass.entities[i]?.name||this.host.hass.states[i]?.attributes?.friendly_name||i}_labelPos(t,e){const s=this.host._layout["rl_"+(t.id||"")];if(s&&s.s===e)return{x:s.x*Gd,y:s.y*Gd};const i=this._snap(this.host._roomCenter(t));return{x:i[0],y:i[1]}}_labelDown(t,e,s){if("plan"!==this.host._mode)return;t.preventDefault(),t.stopPropagation();const i=this._labelPos(e,s);this.host._drag={id:"rl_"+(e.id||""),sx:t.clientX,sy:t.clientY,ox:i.x,oy:i.y,moved:!1},Ud(t),this.host._tip=null}_labelMove(t,e,s){const i="rl_"+(e.id||"");if(!this.host._drag||this.host._drag.id!==i)return;const o=this.host._stageEl;if(!o)return;const a=this.host._spaceModelById(s);if(!a)return;const n=a.vb,r=o.getBoundingClientRect(),l=this.host._viewOr(n),h=(t.clientX-this.host._drag.sx)/r.width*l.w,c=(t.clientY-this.host._drag.sy)/r.height*l.h;Math.abs(t.clientX-this.host._drag.sx)+Math.abs(t.clientY-this.host._drag.sy)>3&&(this.host._drag.moved=!0);const d=Oe(this.host._drag.ox+h),p=Oe(this.host._drag.oy+c);this.host._savePos({id:i,space:s},d,p)}_labelUp(t){const e="rl_"+(t.id||"");if(!this.host._drag||this.host._drag.id!==e)return;const s=this.host._drag.moved;this.host._drag=s?this.host._drag:null,s&&window.setTimeout(()=>this.host._drag=null,0)}_labelScale(t){const e=this.host._layout["rl_"+(t.id||"")]?.k;return"number"==typeof e&&Number.isFinite(e)?Math.min(3,Math.max(.5,e)):1}_rlResizeDown(t,e,s){if("plan"!==this.host._mode)return;t.preventDefault(),t.stopPropagation();const i=t.target.closest(".roomlabel");if(!i)return;const o=i.getBoundingClientRect(),a=o.left+o.width/2,n=o.top+o.height/2,r=Math.max(8,Math.hypot(t.clientX-a,t.clientY-n));this.host._rlResize={id:"rl_"+(e.id||""),space:s,k0:this._labelScale(e),cx:a,cy:n,d0:r},Ud(t)}_rlResizeMove(t){const e=this.host._rlResize;if(!e)return;t.stopPropagation();const s=Math.max(8,Math.hypot(t.clientX-e.cx,t.clientY-e.cy)),i=Math.min(3,Math.max(.5,e.k0*(s/e.d0))),o=this.host._layout[e.id];if(o)this.host._layout={...this.host._layout,[e.id]:{...o,k:i}};else{const t=e.id.slice(3),s=this.host._spaceModelById(e.space);if(!s)return;const o=s.rooms.find(e=>e.id===t);if(!o)return;const a=this._labelPos(o,e.space);this.host._layout={...this.host._layout,[e.id]:{s:e.space,x:a.x/Gd,y:a.y/Gd,k:i}}}this.host._dirtyPos.add(e.id)}_rlResizeUp(){this.host._rlResize&&(this.host._rlResize=null,this.host._persistLayout())}_renderRoomGear(t,e,s){if(!t.id)return d;let i=null;if(t.poly?(i=this.host._gearPtCache.get(t.poly)||null,i||(i=hs(t.poly),this.host._gearPtCache.set(t.poly,i))):null!=t.x&&null!=t.y&&(i=[t.x+(t.w||0)/2,t.y+(t.h||0)/2]),!i)return d;const o=(i[0]-s.x)/s.w*100,a=(i[1]-s.y)/s.h*100;return p``}_resetRoomDialogFields(){this.host._roomEditId=null,this.host._roomFill="",this.host._roomCustomFill=null,this.host._roomTempMin="",this.host._roomTempMax="",this.host._roomTempSrc="",this.host._roomHumSrc="",this.host._roomSrcOpen=null,this.host._roomSrcFilter="",this.host._roomNameScale=1,this.host._roomLabelScale=1}_openRoomEdit(t){if(!t.id)return;this.host._roomEditId=t.id,this.host._nameSel=t.name||"",this.host._areaSel=t.area||"",this.host._roomFill="glow"===t.settings?.fill_mode?"":t.settings?.fill_mode||"";const e="custom"===this.host._roomFill?t.settings?.custom_fill:null;var s;this.host._roomCustomFill=e&&"object"==typeof e?ni(e,_(this.host._curSpaceCfg).customFill):null,[this.host._roomTempMin,this.host._roomTempMax]=Ni(t.settings),this.host._roomTempSrc=t.settings?.temp_source||"",this.host._roomHumSrc=t.settings?.hum_source||"",this.host._roomNameScale=Ai(t.settings?.name_scale),this.host._roomLabelScale=Ai(t.settings?.label_scale),this.host._roomSrcOpen=null,this.host._roomSrcFilter="",this.host._roomDialog=!0,s=this.host,_o(s,"room",xr(s))}_roomSettingsFromDialog(){const t={};return this.host._roomFill&&(t.fill_mode=this.host._roomFill),"custom"===this.host._roomFill&&this.host._roomCustomFill&&(t.custom_fill=this.host._roomCustomFill),this.host._roomTempSrc&&(t.temp_source=this.host._roomTempSrc),this.host._roomHumSrc&&(t.hum_source=this.host._roomHumSrc),Ei(t,this.host._roomTempMin,this.host._roomTempMax),1!==this.host._roomNameScale&&(t.name_scale=this.host._roomNameScale),1!==this.host._roomLabelScale&&(t.label_scale=this.host._roomLabelScale),Object.keys(t).length?t:null}_saveRoomEdit(){const t=this.host._curSpaceCfg,e=t?.rooms.find(t=>t.id===this.host._roomEditId);if(!e)return this.host._roomDialog=!1,void(this.host._roomEditId=null);e.name=this.host._nameSel.trim()||e.name,e.area=this.host._areaSel||null;const s=e.settings||{},i={...s};Ei(i,this.host._roomTempMin,this.host._roomTempMax)&&(this.host._roomFill?i.fill_mode=this.host._roomFill:delete i.fill_mode,"custom"===this.host._roomFill&&this.host._roomCustomFill?i.custom_fill=this.host._roomCustomFill:delete i.custom_fill,"glow"===s.fill_mode&&"boolean"!=typeof s.glow&&(i.glow=!0),this.host._roomTempSrc?i.temp_source=this.host._roomTempSrc:delete i.temp_source,this.host._roomHumSrc?i.hum_source=this.host._roomHumSrc:delete i.hum_source,1!==this.host._roomNameScale?i.name_scale=this.host._roomNameScale:delete i.name_scale,1!==this.host._roomLabelScale?i.label_scale=this.host._roomLabelScale:delete i.label_scale,Object.keys(i).length?e.settings=i:delete e.settings,this._saveConfig(),this.host._roomDialog=!1,this.host._roomEditId=null,this.host._nameSel="",this.host._areaSel="",this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate(),this.host._showToast(this.host._t("toast.room_updated")))}_roomSrcCandidates(){const t=this.host._planHass,e=ne(this.host._markers),s=this.host._roomSrcFilter.trim().toLowerCase(),i=[];for(const o of Object.values(t.devices)){if("service"===o.entry_type)continue;if(e.devices.has(o.id))continue;const t=(o.name_by_user||o.name||o.id).trim();s&&!t.toLowerCase().includes(s)||i.push({value:"device:"+o.id,label:t,sub:o.model||this.host._t("marker.sub_device")})}for(const[o,a]of Object.entries(t.entities)){if(!o.startsWith("sensor.")||a.hidden)continue;if(re(t,o,e))continue;const n=a.name||t.states[o]?.attributes?.friendly_name||o;s&&!(n+" "+o).toLowerCase().includes(s)||i.push({value:"entity:"+o,label:n,sub:o})}return i.sort((t,e)=>t.label.localeCompare(e.label)),i.slice(0,200)}_roomSrcLabel(t){const e=t.indexOf(":"),s=t.slice(0,e),i=t.slice(e+1);return"device"===s?this.host._fullRegistryHass.devices[i]?.name_by_user||this.host._fullRegistryHass.devices[i]?.name||i:this.host._fullRegistryHass.entities[i]?.name||this.host.hass.states[i]?.attributes?.friendly_name||i}_labelPos(t,e){const s=this.host._layout["rl_"+(t.id||"")];if(s&&s.s===e)return{x:s.x*jd,y:s.y*jd};const i=this._snap(this.host._roomCenter(t));return{x:i[0],y:i[1]}}_labelDown(t,e,s){if("plan"!==this.host._mode)return;t.preventDefault(),t.stopPropagation();const i=this._labelPos(e,s);this.host._drag={id:"rl_"+(e.id||""),sx:t.clientX,sy:t.clientY,ox:i.x,oy:i.y,moved:!1},qd(t),this.host._tip=null}_labelMove(t,e,s){const i="rl_"+(e.id||"");if(!this.host._drag||this.host._drag.id!==i)return;const o=this.host._stageEl;if(!o)return;const a=this.host._spaceModelById(s);if(!a)return;const n=a.vb,r=o.getBoundingClientRect(),l=this.host._viewOr(n),h=(t.clientX-this.host._drag.sx)/r.width*l.w,c=(t.clientY-this.host._drag.sy)/r.height*l.h;Math.abs(t.clientX-this.host._drag.sx)+Math.abs(t.clientY-this.host._drag.sy)>3&&(this.host._drag.moved=!0);const d=Oe(this.host._drag.ox+h),p=Oe(this.host._drag.oy+c);this.host._savePos({id:i,space:s},d,p)}_labelUp(t){const e="rl_"+(t.id||"");if(!this.host._drag||this.host._drag.id!==e)return;const s=this.host._drag.moved;this.host._drag=s?this.host._drag:null,s&&window.setTimeout(()=>this.host._drag=null,0)}_labelScale(t){const e=this.host._layout["rl_"+(t.id||"")]?.k;return"number"==typeof e&&Number.isFinite(e)?Math.min(3,Math.max(.5,e)):1}_rlResizeDown(t,e,s){if("plan"!==this.host._mode)return;t.preventDefault(),t.stopPropagation();const i=t.target.closest(".roomlabel");if(!i)return;const o=i.getBoundingClientRect(),a=o.left+o.width/2,n=o.top+o.height/2,r=Math.max(8,Math.hypot(t.clientX-a,t.clientY-n));this.host._rlResize={id:"rl_"+(e.id||""),space:s,k0:this._labelScale(e),cx:a,cy:n,d0:r},qd(t)}_rlResizeMove(t){const e=this.host._rlResize;if(!e)return;t.stopPropagation();const s=Math.max(8,Math.hypot(t.clientX-e.cx,t.clientY-e.cy)),i=Math.min(3,Math.max(.5,e.k0*(s/e.d0))),o=this.host._layout[e.id];if(o)this.host._layout={...this.host._layout,[e.id]:{...o,k:i}};else{const t=e.id.slice(3),s=this.host._spaceModelById(e.space);if(!s)return;const o=s.rooms.find(e=>e.id===t);if(!o)return;const a=this._labelPos(o,e.space);this.host._layout={...this.host._layout,[e.id]:{s:e.space,x:a.x/jd,y:a.y/jd,k:i}}}this.host._dirtyPos.add(e.id)}_rlResizeUp(){this.host._rlResize&&(this.host._rlResize=null,this.host._persistLayout())}_renderRoomGear(t,e,s){if(!t.id)return d;let i=null;if(t.poly?(i=this.host._gearPtCache.get(t.poly)||null,i||(i=hs(t.poly),this.host._gearPtCache.set(t.poly,i))):null!=t.x&&null!=t.y&&(i=[t.x+(t.w||0)/2,t.y+(t.h||0)/2]),!i)return d;const o=(i[0]-s.x)/s.w*100,a=(i[1]-s.y)/s.h*100;return p``}_alignCandidates(){const t=[],e=this.host._spaceModel();if(this.host._markup){if(!e)return t;if(this.host._drag?.id.startsWith("rl_")){const s=this.host._drag.id.slice(3);for(const i of e.rooms){if(!i.name||i.id===s)continue;const e=this._labelPos(i,this.host._space);t.push([e.x,e.y])}return t}for(const s of e.rooms){const e=A(s);if(e)for(const s of e)t.push(s)}if("draw"===this.host._tool)for(const e of this.host._path)t.push(e);if("split"===this.host._tool&&this.host._splitSel?.pts)for(const e of this.host._splitSel.pts)t.push(e);return t}if("devices"===this.host._mode){const e=this.host._deviceDrag?.id??this.host._drag?.id;for(const s of this.host._devices){if(s.space!==this.host._space||s.id===e||"ha_disabled"===s.bindingStatus?.kind)continue;const i=this.host._pos(s);t.push([i.x,i.y])}return t}if("decor"===this.host._mode){const e=this.host._decorMove?.id;return t.push(...this._decorSnapGeometry(e).points),this.host._decorDraft&&t.push(this.host._decorDraft.a),t}return t}_renderAlignGuides(){const t=this.host._alignPoint;if(!t)return Pt``;const e=this.host._drag?.id.startsWith("rl_")?.5*this.host._gridPitch:.05*this.host._gridPitch,s=Oi(t,this._alignCandidates(),e);if(!s.length)return Pt``;const i=this.host._gridPitch,o=1.5*i;return Pt` + `}_alignCandidates(){const t=[],e=this.host._spaceModel();if(this.host._markup){if(!e)return t;if(this.host._drag?.id.startsWith("rl_")){const s=this.host._drag.id.slice(3);for(const i of e.rooms){if(!i.name||i.id===s)continue;const e=this._labelPos(i,this.host._space);t.push([e.x,e.y])}return t}for(const s of e.rooms){const e=N(s);if(e)for(const s of e)t.push(s)}if("draw"===this.host._tool)for(const e of this.host._path)t.push(e);if("split"===this.host._tool&&this.host._splitSel?.pts)for(const e of this.host._splitSel.pts)t.push(e);return t}if("devices"===this.host._mode){const e=this.host._deviceDrag?.id??this.host._drag?.id;for(const s of this.host._devices){if(s.space!==this.host._space||s.id===e||"ha_disabled"===s.bindingStatus?.kind)continue;const i=this.host._pos(s);t.push([i.x,i.y])}return t}if("decor"===this.host._mode){const e=this.host._decorMove?.id;return t.push(...this._decorSnapGeometry(e).points),this.host._decorDraft&&t.push(this.host._decorDraft.a),t}return t}_renderAlignGuides(){const t=this.host._alignPoint;if(!t)return Pt``;const e=this.host._drag?.id.startsWith("rl_")?.5*this.host._gridPitch:.05*this.host._gridPitch,s=Oi(t,this._alignCandidates(),e);if(!s.length)return Pt``;const i=this.host._gridPitch,o=1.5*i;return Pt` ${s.map(e=>{const[s,a,n,r]="x"===e.axis?[e.at,e.from[1],e.at,t[1]+Math.sign(t[1]-e.from[1])*o]:[e.from[0],e.at,t[0]+Math.sign(t[0]-e.from[0])*o,e.at];return Pt` `})} @@ -1920,7 +1920,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc `}_renderOpeningDialog(){const t=this.host._openingDialog,e=this.host._spaceModel()?.partitions||[],s=t.id?this.host._curSpaceCfg?.openings?.find(e=>e.id===t.id):null,i={id:t.id||"preview",type:t.type,x:t.x/Gd,y:t.y/this.host._spaceH,angle:t.angle,length:s&&!t.lengthTouched?s.length:this.host._cmToUnits(Math.max(20,t.lengthCm))/Gd,...t.host?{host:t.host}:{}},o=js(s,i),a=t.host?o?U(i,e,Gd,this.host._cellCm,this.host._gridPitch):E(i,e,Gd,this.host._cellCm,this.host._gridPitch):null,n="does-not-fit-jamb"===a?.reason,r=t.host?e.find(e=>e.id===t.host.id):null,l=r?le(r.cm/2,this.host._imperial):"",h=!!t.host&&!a?.resolved&&!n,c="gate"===t.type?"mdi:gate":"window"===t.type?"mdi:window-closed-variant":"passage"===t.type?"mdi:arch":"mdi:door",_=(e,s)=>{const i="contact"===e?t.contact:t.lock,o="contact"===e?!!t.contactOpen:!!t.lockOpen,a="contact"===e?t.contactFilter||"":t.lockFilter||"",n=s.find(t=>t.value===i),r=n?.label||this.host.hass.states[i]?.attributes?.friendly_name||this.host._fullRegistryHass.entities[i]?.name||i,l=lo(s,a);return p` + r=${Rt(.18*this.host._gridPitch,this.host._cellCm)}>`}_renderOpeningDialog(){const t=this.host._openingDialog,e=this.host._spaceModel()?.partitions||[],s=t.id?this.host._curSpaceCfg?.openings?.find(e=>e.id===t.id):null,i={id:t.id||"preview",type:t.type,x:t.x/jd,y:t.y/this.host._spaceH,angle:t.angle,length:s&&!t.lengthTouched?s.length:this.host._cmToUnits(Math.max(20,t.lengthCm))/jd,...t.host?{host:t.host}:{}},o=js(s,i),a=t.host?o?q(i,e,jd,this.host._cellCm,this.host._gridPitch):A(i,e,jd,this.host._cellCm,this.host._gridPitch):null,n="does-not-fit-jamb"===a?.reason,r=t.host?e.find(e=>e.id===t.host.id):null,l=r?le(r.cm/2,this.host._imperial):"",h=!!t.host&&!a?.resolved&&!n,c="gate"===t.type?"mdi:gate":"window"===t.type?"mdi:window-closed-variant":"passage"===t.type?"mdi:arch":"mdi:door",u=(e,s)=>{const i="contact"===e?t.contact:t.lock,o="contact"===e?!!t.contactOpen:!!t.lockOpen,a="contact"===e?t.contactFilter||"":t.lockFilter||"",n=s.find(t=>t.value===i),r=n?.label||this.host.hass.states[i]?.attributes?.friendly_name||this.host._fullRegistryHass.entities[i]?.name||i,l=lo(s,a);return p` -
    `}_markerValueBadgeFields(t){return Zi({touched:t.valueBadgeTouched,originalHas:t.originalHasValueBadge,original:t.originalValueBadge,enabled:t.valueBadgeEnabled,source:t.valueBadgeSource,position:t.valueBadgePosition})}_markerValueSourceFields(t){return Yi({touched:t.valueSourceTouched,originalHas:t.originalHasValueSource,original:t.originalValueSource,source:t.valueSource})}_markerDraft(t){if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return null;const e=M(t.room),s=Zs(t.binding,t.devId,()=>"__hp_device_preview__"),i=this.host._markers.find(e=>e.id===s||e.id===t.devId),o=R(t.binding,t.controls,this.host._bindingEntities(t.binding)),a=this._effectiveStoredTapAction(t),n={id:s,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle||null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===a&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:o.length?o:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),...this._markerValueSourceFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=u(t.glowRadius);return null==e||e<=0?null:Math.round(this.host._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:t.hideFromPlan,vacuum:i?.vacuum||null},r=!!i&&("string"==typeof i.area&&i.area.length>0||null===i.area&&!!i.space&&!!i.room_id);return"virtual"===t.binding||t.roomTouched?(n.space=e?.space||("virtual"===t.binding?this.host._space:null),n.area=e?.area||null,n.room_id=e?.roomId||null):r&&(n.space=i.space,n.area=i.area,n.room_id=i.room_id),n}_markerPreviewDevice(t){const e=this._markerDraft(t);if(!e)return null;const s=`${this.host._haRegistry.revision}\n${wt(this.host._markers)}\n${JSON.stringify(e)}`;if(this.host._markerPreviewMemo?.key===s)return this.host._markerPreviewMemo.device;const i=Xi({hass:this.host.hass,registry:this.host._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this.host._areaToSpace).map(([t,e])=>[t,e.space])),marker:e,siblingMarkers:this.host._markers,settings:this.host._settings,excluded:this.host._excluded,showAll:this.host._showAll,firstSpaceId:this.host._model[0]?.id||this.host._space,loc:t=>this.host._t(t),iconRules:this.host._iconRules});return this.host._markerPreviewMemo={key:s,device:i},i}_markerPreviewDevices(t){const e=this.host._markerPreviewDevicesMemo;if(e?.base===this.host._devices&&e.preview===t)return e.devices;const s=[...this.host._devices.filter(e=>e.id!==t.id),t];return this.host._markerPreviewDevicesMemo={base:this.host._devices,preview:t,devices:s},s}_toggleIntent(t,e=this.host._devices){return this.host._toggleIntent(t,e)}_toggleIntentForDialog(t){const e=this._markerPreviewDevice(t);if(!e)return null;const s=this._markerPreviewDevices(e);return this._toggleIntent(e,s)}_toggleStateText(t,e){return this.host._toggleStateText(t,e)}_toggleConfirmationStateText(t){return this.host._toggleConfirmationStateText(t)}_toggleConfirmationLines(t){return this.host._toggleConfirmationLines(t)}_toggleHintLines(t){if(!t)return[];const e=t=>this.host._t(`marker.toggle_effect_${t.replace("-","_")}`),s=t=>this.host._t(`marker.toggle_skip_${t.replace("-","_")}`);return Qi(t,{single:t=>{if("via"in t&&"virtual-light"===t.via)return this.host._t("marker.virtual_light_target",{name:t.name});const e=t.entityId||("ref"in t?t.ref:""),s=t.name||e;return this.host._t("marker.toggle_hint_single",{name:s,id:e})},group:t=>this.host._t("marker.toggle_hint_group",{count:t.length,names:t.map(t=>`${t.name} (${t.entityId})`).join(", ")}),currentNext:(t,s)=>"virtual-light"===t.via?this.host._t("marker.virtual_light_current",{state:this.host._t("on"===t.state?"marker.virtual_light_state_on":"marker.virtual_light_state_off"),effect:e(s)}):this.host._t("marker.toggle_hint_current",{state:this._toggleStateText(t.entityId,t.state),effect:e(s)}),groupCurrentNext:(t,s)=>this.host._t("marker.toggle_hint_group_current",{on:t.filter(t=>"on"===t.state).length,count:t.length,effect:e(s)}),skipped:t=>this.host._t("marker.toggle_hint_skipped",{count:t.length,targets:t.map(t=>{const e=t.entityId||t.ref;return`${t.name||e} (${e}: ${s(t.reason)})`}).join(", ")}),none:t=>this.host._t(`marker.toggle_none_${t.replaceAll("-","_")}`)})}_effectiveStoredTapAction(t,e){return t.tapActionTouched?t.tapAction:Xs(t.originalHasTapAction?t.originalTapAction:null,e)}_effectiveMarkerTapAction(t,e=this._markerPreviewDevice(t)){return this._effectiveStoredTapAction(t,e?.primary?.split(".")[0])}_announceToggleDraft(t){const e=this._markerPreviewDevice(t),s=t.tapActionTouched?t:{...t,tapAction:this._effectiveMarkerTapAction(t,e)},i="toggle"===s.tapAction?this._toggleHintLines(this._toggleIntentForDialog(s)).join(" "):"";return{...s,tapHintAnnouncement:i}}_valueBadgeForBinding(t,e){const s={...t,binding:e,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0},i=this._markerPreviewDevice(s);if(!i)return{valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0};const o=[...this.host._devices.filter(t=>t.id!==i.id),i],a=f(this.host._planHass,i,o),n=b(this.host._planHass,i,a);return{valueBadgeEnabled:t.valueBadgeEnabled&&!!n,valueBadgeSource:n,valueBadgeTouched:!0}}_markerSpatialSource(t){const e=this._markerPreviewDevice(t);if(!e)return null;const s={...e,hidden:!1};return to(eo(this.host._planHass,[...this.host._devices.filter(t=>t.id!==s.id),s],null,this.host._virtualLights).filter(t=>t.device.id===s.id))}_markerAutoHasSpatialSource(t){const e={...t,lightRole:"auto",lightRoleTouched:!0},s=this._markerPreviewDevice(e);return!!s&&so(this.host._planHass,{...s})}_setMarkerLightRole(t){const e=this.host._markerDialog;e&&(this.host._markerDialog={...e,lightRole:t,lightRoleTouched:!0})}_controlRefInfo(t){if(!t.startsWith("marker:"))return{label:this.host.hass.states[t]?.attributes?.friendly_name||t,sub:t,icon:t.startsWith("light.")?"mdi:lightbulb":"mdi:toggle-switch",warning:!this.host._planEntityAvailable(t)};const e=t.slice(7),s=this.host._markers.find(t=>t.id===e),i=this.host._devices.find(t=>t.id===e);if(!s||s.removed||!0!==s.is_light)return{label:this.host._t("marker.control_missing_label"),sub:`${this.host._t("marker.control_broken")} (${t})`,icon:"mdi:alert-outline",warning:!0};const o=this.host._serverCfg?.spaces.find(t=>t.id===(i?.space||s.space)),a=!!i&&$(i).length>0;return{label:s.name||i?.name||e,sub:[o?.title||i?.space||s.space,s.room_id||i?.area,a?"":this.host._t("marker.control_passive")].filter(Boolean).join(" · "),icon:s.icon||i?.icon||"mdi:lightbulb-outline",warning:!0===s.hidden||!0===i?.hidden}}_valueBadgeCandidateLabel(t){const e=t.source;if("derived_lqi"===e.kind)return this.host._t("marker.value_badge_lqi");if("derived_marker_state"===e.kind)return this.host._t("marker.value_badge_marker_state",{name:t.label});if("entity_state"===e.kind)return this.host._t("marker.value_badge_state",{name:t.label});const s=this.host.hass.states[e.entity_id]?.attributes?.friendly_name||this.host._fullRegistryHass.entities[e.entity_id]?.name||e.entity_id;return this.host._t(`marker.value_badge_attr_${e.attribute}`,{name:s})}_controlCandidates(t){const e=this._markerDraft(t)?.id||t.devId||"",s=[],i=new Set;for(const t of this.host._markers){if(t.id===e||t.removed||t.hidden||!0!==t.is_light)continue;if("virtual"!==t.binding&&"active"!==this.host._bindingStatus(t.binding).kind)continue;const o=this.host._devices.find(e=>e.id===t.id);if(!o||o.hidden)continue;const a=this._controlRefInfo(`marker:${t.id}`);for(const t of $(o))i.add(t);s.push({value:`marker:${t.id}`,label:a.label,sub:a.sub,icon:a.icon,search:`${a.label} ${a.sub} ${t.id} ${$(o).join(" ")}`.toLowerCase()})}const o=Object.keys(this.host.hass.states||{}).filter(e=>io(e)&&!i.has(e)&&oo(t.binding,[e],this.host._bindingEntities(t.binding)).length>0&&this.host._planEntityAvailable(e)).map(t=>{const e=this._controlRefInfo(t);return{value:t,label:e.label,sub:t,icon:e.icon,search:`${e.label} ${t}`.toLowerCase()}}),a=t.controlsFilter.trim().toLowerCase();return[...s,...o].filter(e=>!t.controls.includes(e.value)&&(!a||e.search.includes(a))).slice(0,12).map(({search:t,...e})=>e)}_addControlRef(t,e){if(e.startsWith("marker:")){const s=this._markerDraft(t)?.id||t.devId||"";if(!s)return void this.host._showToast(this.host._t("toast.marker_binding_required"));const i=e.slice(7),o=this._markerDraft(t),a=o?[...this.host._markers.filter(t=>t.id!==s),o]:this.host._markers;if(ao(a,s,i))return void this.host._showToast(this.host._t("toast.marker_control_cycle"))}this.host._markerDialog=this._announceToggleDraft({...t,controls:[...t.controls,e],controlsFilter:""})}_setMarkerGlowMode(t){const e=this.host._markerDialog;if(!e)return;if("auto"===t)return void(this.host._markerDialog={...e,glowMode:t,glowTouched:!0});const s=this._markerSpatialSource(e),i=no(s?this.host._planHass.states[s.eid]:void 0,null,this.host._fillColors.glow_light.c),o=!e.glowColorDrafted,a="fixed"===t&&!e.glowBrightnessDrafted;this.host._markerDialog={...e,glowMode:t,glowColor:o?i.c:e.glowColor,glowBrightness:a?Math.max(1,Math.round(100*i.bri)):e.glowBrightness,glowColorDrafted:!0,glowBrightnessDrafted:e.glowBrightnessDrafted||"fixed"===t,glowTouched:!0}}_renderRadarSection(t,e,s="main"){return ic({dialog:t,device:e,registryHass:this.host._fullRegistryHass,planHass:this.host._planHass,hass:this.host.hass,spaceModelById:t=>this.host._spaceModelById(t),currentSpace:()=>this.host._spaceModel(),position:t=>this.host._pos(t),updateDialog:t=>{this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,...t})},dialogDeviceId:()=>this.host._markerDialog?.devId,t:(t,e)=>this.host._t(t,e),help:t=>this._help(t),boolInput:(t,e)=>this._boolInput(t,e),toast:t=>this.host._showToast(t),setup:this._radarSetup,configRev:this.host._cfgRev},s)}_renderMarkerDialog(){return Fa.call(this)}_renderSpaceDialog(){return wr.call(this)}_renderMergeDialog(){const t=this.host._mergeDialog,e=this.host._spaceModel()?.rooms||[],s=(s,i)=>{const o=e.find(t=>t.id===s),a=o?.area?this.host.hass.areas[o.area]?.name:null;return p`
    `}_markerValueBadgeFields(t){return Zi({touched:t.valueBadgeTouched,originalHas:t.originalHasValueBadge,original:t.originalValueBadge,enabled:t.valueBadgeEnabled,source:t.valueBadgeSource,position:t.valueBadgePosition})}_markerValueSourceFields(t){return Yi({touched:t.valueSourceTouched,originalHas:t.originalHasValueSource,original:t.originalValueSource,source:t.valueSource})}_markerDraft(t){if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return null;const e=x(t.room),s=Zs(t.binding,t.devId,()=>"__hp_device_preview__"),i=this.host._markers.find(e=>e.id===s||e.id===t.devId),o=T(t.binding,t.controls,this.host._bindingEntities(t.binding)),a=this._effectiveStoredTapAction(t),n={id:s,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle||null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===a&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:o.length?o:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),...this._markerValueSourceFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=xt(t.glowRadius);return null==e||e<=0?null:Math.round(this.host._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:t.hideFromPlan,vacuum:i?.vacuum||null},r=!!i&&("string"==typeof i.area&&i.area.length>0||null===i.area&&!!i.space&&!!i.room_id);return"virtual"===t.binding||t.roomTouched?(n.space=e?.space||("virtual"===t.binding?this.host._space:null),n.area=e?.area||null,n.room_id=e?.roomId||null):r&&(n.space=i.space,n.area=i.area,n.room_id=i.room_id),n}_markerPreviewDevice(t){const e=this._markerDraft(t);if(!e)return null;const s=`${this.host._haRegistry.revision}\n${yt(this.host._markers)}\n${JSON.stringify(e)}`;if(this.host._markerPreviewMemo?.key===s)return this.host._markerPreviewMemo.device;const i=Xi({hass:this.host.hass,registry:this.host._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this.host._areaToSpace).map(([t,e])=>[t,e.space])),marker:e,siblingMarkers:this.host._markers,settings:this.host._settings,excluded:this.host._excluded,showAll:this.host._showAll,firstSpaceId:this.host._model[0]?.id||this.host._space,loc:t=>this.host._t(t),iconRules:this.host._iconRules});return this.host._markerPreviewMemo={key:s,device:i},i}_markerPreviewDevices(t){const e=this.host._markerPreviewDevicesMemo;if(e?.base===this.host._devices&&e.preview===t)return e.devices;const s=[...this.host._devices.filter(e=>e.id!==t.id),t];return this.host._markerPreviewDevicesMemo={base:this.host._devices,preview:t,devices:s},s}_toggleIntent(t,e=this.host._devices){return this.host._toggleIntent(t,e)}_toggleIntentForDialog(t){const e=this._markerPreviewDevice(t);if(!e)return null;const s=this._markerPreviewDevices(e);return this._toggleIntent(e,s)}_toggleStateText(t,e){return this.host._toggleStateText(t,e)}_toggleConfirmationStateText(t){return this.host._toggleConfirmationStateText(t)}_toggleConfirmationLines(t){return this.host._toggleConfirmationLines(t)}_toggleHintLines(t){if(!t)return[];const e=t=>this.host._t(`marker.toggle_effect_${t.replace("-","_")}`),s=t=>this.host._t(`marker.toggle_skip_${t.replace("-","_")}`);return Qi(t,{single:t=>{if("via"in t&&"virtual-light"===t.via)return this.host._t("marker.virtual_light_target",{name:t.name});const e=t.entityId||("ref"in t?t.ref:""),s=t.name||e;return this.host._t("marker.toggle_hint_single",{name:s,id:e})},group:t=>this.host._t("marker.toggle_hint_group",{count:t.length,names:t.map(t=>`${t.name} (${t.entityId})`).join(", ")}),currentNext:(t,s)=>"virtual-light"===t.via?this.host._t("marker.virtual_light_current",{state:this.host._t("on"===t.state?"marker.virtual_light_state_on":"marker.virtual_light_state_off"),effect:e(s)}):this.host._t("marker.toggle_hint_current",{state:this._toggleStateText(t.entityId,t.state),effect:e(s)}),groupCurrentNext:(t,s)=>this.host._t("marker.toggle_hint_group_current",{on:t.filter(t=>"on"===t.state).length,count:t.length,effect:e(s)}),skipped:t=>this.host._t("marker.toggle_hint_skipped",{count:t.length,targets:t.map(t=>{const e=t.entityId||t.ref;return`${t.name||e} (${e}: ${s(t.reason)})`}).join(", ")}),none:t=>this.host._t(`marker.toggle_none_${t.replaceAll("-","_")}`)})}_effectiveStoredTapAction(t,e){return t.tapActionTouched?t.tapAction:Xs(t.originalHasTapAction?t.originalTapAction:null,e)}_effectiveMarkerTapAction(t,e=this._markerPreviewDevice(t)){return this._effectiveStoredTapAction(t,e?.primary?.split(".")[0])}_announceToggleDraft(t){const e=this._markerPreviewDevice(t),s=t.tapActionTouched?t:{...t,tapAction:this._effectiveMarkerTapAction(t,e)},i="toggle"===s.tapAction?this._toggleHintLines(this._toggleIntentForDialog(s)).join(" "):"";return{...s,tapHintAnnouncement:i}}_valueBadgeForBinding(t,e){const s={...t,binding:e,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0},i=this._markerPreviewDevice(s);if(!i)return{valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0};const o=[...this.host._devices.filter(t=>t.id!==i.id),i],a=g(this.host._planHass,i,o),n=f(this.host._planHass,i,a);return{valueBadgeEnabled:t.valueBadgeEnabled&&!!n,valueBadgeSource:n,valueBadgeTouched:!0}}_markerSpatialSource(t){const e=this._markerPreviewDevice(t);if(!e)return null;const s={...e,hidden:!1};return to(eo(this.host._planHass,[...this.host._devices.filter(t=>t.id!==s.id),s],null,this.host._virtualLights).filter(t=>t.device.id===s.id))}_markerAutoHasSpatialSource(t){const e={...t,lightRole:"auto",lightRoleTouched:!0},s=this._markerPreviewDevice(e);return!!s&&so(this.host._planHass,{...s})}_setMarkerLightRole(t){const e=this.host._markerDialog;e&&(this.host._markerDialog={...e,lightRole:t,lightRoleTouched:!0})}_controlRefInfo(t){if(!t.startsWith("marker:"))return{label:this.host.hass.states[t]?.attributes?.friendly_name||t,sub:t,icon:t.startsWith("light.")?"mdi:lightbulb":"mdi:toggle-switch",warning:!this.host._planEntityAvailable(t)};const e=t.slice(7),s=this.host._markers.find(t=>t.id===e),i=this.host._devices.find(t=>t.id===e);if(!s||s.removed||!0!==s.is_light)return{label:this.host._t("marker.control_missing_label"),sub:`${this.host._t("marker.control_broken")} (${t})`,icon:"mdi:alert-outline",warning:!0};const o=this.host._serverCfg?.spaces.find(t=>t.id===(i?.space||s.space)),a=!!i&&w(i).length>0;return{label:s.name||i?.name||e,sub:[o?.title||i?.space||s.space,s.room_id||i?.area,a?"":this.host._t("marker.control_passive")].filter(Boolean).join(" · "),icon:s.icon||i?.icon||"mdi:lightbulb-outline",warning:!0===s.hidden||!0===i?.hidden}}_valueBadgeCandidateLabel(t){const e=t.source;if("derived_lqi"===e.kind)return this.host._t("marker.value_badge_lqi");if("derived_marker_state"===e.kind)return this.host._t("marker.value_badge_marker_state",{name:t.label});if("entity_state"===e.kind)return this.host._t("marker.value_badge_state",{name:t.label});const s=this.host.hass.states[e.entity_id]?.attributes?.friendly_name||this.host._fullRegistryHass.entities[e.entity_id]?.name||e.entity_id;return this.host._t(`marker.value_badge_attr_${e.attribute}`,{name:s})}_controlCandidates(t){const e=this._markerDraft(t)?.id||t.devId||"",s=[],i=new Set;for(const t of this.host._markers){if(t.id===e||t.removed||t.hidden||!0!==t.is_light)continue;if("virtual"!==t.binding&&"active"!==this.host._bindingStatus(t.binding).kind)continue;const o=this.host._devices.find(e=>e.id===t.id);if(!o||o.hidden)continue;const a=this._controlRefInfo(`marker:${t.id}`);for(const t of w(o))i.add(t);s.push({value:`marker:${t.id}`,label:a.label,sub:a.sub,icon:a.icon,search:`${a.label} ${a.sub} ${t.id} ${w(o).join(" ")}`.toLowerCase()})}const o=Object.keys(this.host.hass.states||{}).filter(e=>io(e)&&!i.has(e)&&oo(t.binding,[e],this.host._bindingEntities(t.binding)).length>0&&this.host._planEntityAvailable(e)).map(t=>{const e=this._controlRefInfo(t);return{value:t,label:e.label,sub:t,icon:e.icon,search:`${e.label} ${t}`.toLowerCase()}}),a=t.controlsFilter.trim().toLowerCase();return[...s,...o].filter(e=>!t.controls.includes(e.value)&&(!a||e.search.includes(a))).slice(0,12).map(({search:t,...e})=>e)}_addControlRef(t,e){if(e.startsWith("marker:")){const s=this._markerDraft(t)?.id||t.devId||"";if(!s)return void this.host._showToast(this.host._t("toast.marker_binding_required"));const i=e.slice(7),o=this._markerDraft(t),a=o?[...this.host._markers.filter(t=>t.id!==s),o]:this.host._markers;if(ao(a,s,i))return void this.host._showToast(this.host._t("toast.marker_control_cycle"))}this.host._markerDialog=this._announceToggleDraft({...t,controls:[...t.controls,e],controlsFilter:""})}_setMarkerGlowMode(t){const e=this.host._markerDialog;if(!e)return;if("auto"===t)return void(this.host._markerDialog={...e,glowMode:t,glowTouched:!0});const s=this._markerSpatialSource(e),i=no(s?this.host._planHass.states[s.eid]:void 0,null,this.host._fillColors.glow_light.c),o=!e.glowColorDrafted,a="fixed"===t&&!e.glowBrightnessDrafted;this.host._markerDialog={...e,glowMode:t,glowColor:o?i.c:e.glowColor,glowBrightness:a?Math.max(1,Math.round(100*i.bri)):e.glowBrightness,glowColorDrafted:!0,glowBrightnessDrafted:e.glowBrightnessDrafted||"fixed"===t,glowTouched:!0}}_renderRadarSection(t,e,s="main"){return sc({dialog:t,device:e,registryHass:this.host._fullRegistryHass,planHass:this.host._planHass,hass:this.host.hass,spaceModelById:t=>this.host._spaceModelById(t),currentSpace:()=>this.host._spaceModel(),position:t=>this.host._pos(t),updateDialog:t=>{this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,...t})},dialogDeviceId:()=>this.host._markerDialog?.devId,t:(t,e)=>this.host._t(t,e),help:t=>this._help(t),boolInput:(t,e)=>this._boolInput(t,e),toast:t=>this.host._showToast(t),setup:this._radarSetup,configRev:this.host._cfgRev},s)}_renderMarkerDialog(){return za.call(this)}_renderSpaceDialog(){return yr.call(this)}_renderMergeDialog(){const t=this.host._mergeDialog,e=this.host._spaceModel()?.rooms||[],s=(s,i)=>{const o=e.find(t=>t.id===s),a=o?.area?this.host.hass.areas[o.area]?.name:null;return p`
    `}_renderRoomDialog(){return Pr.call(this)}}export{Kd as EDITOR_RUNTIME_FINGERPRINT,Vd as HouseplanEditorRuntime}; +
    `}_renderRoomDialog(){return Sr.call(this)}}export{Ud as EDITOR_RUNTIME_FINGERPRINT,Kd as HouseplanEditorRuntime}; diff --git a/custom_components/houseplan/frontend/houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js b/custom_components/houseplan/frontend/houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js similarity index 95% rename from custom_components/houseplan/frontend/houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js rename to custom_components/houseplan/frontend/houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js index b7815f67..8c737236 100644 --- a/custom_components/houseplan/frontend/houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js +++ b/custom_components/houseplan/frontend/houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js @@ -1,5 +1,5 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{l as t,bq as s,A as e,aC as o,c as a,h as i,cE as l,cF as h,cG as n,bn as r,cH as c,cM as p,cI as d,cJ as _,cK as u,cL as g,cN as m,cO as b}from"./houseplan-card-BWAph8ZF.js";import{D as f,C as v,E as y,G as w,H as D,I as $,J as S,v as C}from"./backdrop-pick-CtZfmF4H.js";import"./form-kit.styles-DcvCvE8g.js";const k="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";class F{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(i){const l=`${i}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,i)&&s(h,l)?a``:e}_openSpaceDialog(t,s){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===t){const e=this.host._serverCfg.spaces.find(t=>t.id===s);if(!e)return;const o=i(e),a=e.settings?.custom_fill&&"object"==typeof e.settings.custom_fill?l(e.settings.custom_fill):null,p="none"===o.fill?{...a||h,a:0}:a;return void(this.host._spaceDialog={mode:t,spaceId:s,title:e.title,planUrl:e.plan_url||null,planFile:null,source:e.plan_url?"file":"draw",showBorders:o.showBorders,showNames:o.showNames,zeroWallStyle:c(e),displayTouched:!0,hideDecor:o.hideDecor,hideOpenings:o.hideOpenings,roomColor:o.color,roomOpacity:o.opacity,fillMode:"none"===o.fill?"custom":o.fill,customFill:p,glowEnabled:o.glow,bgColor:o.bgColor,bgMode:"static"===e.settings?.bg_mode||"daynight"===e.settings?.bg_mode?e.settings.bg_mode:null,northDeg:r({},e.settings),sunRays:"boolean"==typeof e.settings?.sun_rays?e.settings.sun_rays:null,tempMin:o.tempMin,tempMax:o.tempMax,showLqi:o.showLqi??this.host._config?.show_signal??!0,cardFontScale:o.cardFontScale,labelTemp:o.labelTemp,labelHum:o.labelHum,labelLqi:o.labelLqi,labelLight:o.labelLight,cellCm:Number(e.cell_cm)>0?Number(e.cell_cm):5,cellCmInput:n(Number(e.cell_cm)>0?Number(e.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const e=p(this.host._imperial);this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...m(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:{...h,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:_,tempMax:d,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:e,cellCmInput:n(e,this.host._imperial),cellCmTouched:!1,busy:!1},f(this.host,this.host._spaceDialog)}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;s.value="";const o=await v(e);if("reject"===o.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===o.kind)return void(this.host._backdropGuard=o.state);const a=await y(e,o.ext,e.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:a})}_renderBackdropGuard(){return w(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??e}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),o=this.host._spaceDialog;return o&&o.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...o,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const s=this.host._spaceDialog,e=s?.saved?.find(s=>s.name===t);if(!s||!e||e.used_by.length||e.url===s.planUrl)return;const o=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),a=this.host._spaceDialog,i=a?.saved?.find(s=>s.name===t);if(o&&a&&i&&i.url===e.url&&i.modified===e.modified&&!i.used_by.length&&i.url!==a.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return a`
    ${this.host._t("space.loading")}
    `;const s=t.saved||[];if(!s.length)return a`
    ${this.host._t("space.no_saved")}
    `;return a`
    +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{l as t,bq as s,A as e,aC as o,c as a,g as i,cE as l,cF as h,cG as n,bn as r,cH as c,cM as p,cI as d,cJ as _,cK as u,cL as g,cN as m,cO as f}from"./houseplan-card-9fMSy3y3.js";import{D as b,C as v,E as y,G as w,H as D,I as $,J as S,v as C}from"./backdrop-pick-BJOCHJxe.js";import"./form-kit.styles-CKUQLdmn.js";const k="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";class F{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(i){const l=`${i}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,i)&&s(h,l)?a``:e}_openSpaceDialog(t,s){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===t){const e=this.host._serverCfg.spaces.find(t=>t.id===s);if(!e)return;const o=i(e),a=e.settings?.custom_fill&&"object"==typeof e.settings.custom_fill?l(e.settings.custom_fill):null,p="none"===o.fill?{...a||h,a:0}:a;return void(this.host._spaceDialog={mode:t,spaceId:s,title:e.title,planUrl:e.plan_url||null,planFile:null,source:e.plan_url?"file":"draw",showBorders:o.showBorders,showNames:o.showNames,zeroWallStyle:c(e),displayTouched:!0,hideDecor:o.hideDecor,hideOpenings:o.hideOpenings,roomColor:o.color,roomOpacity:o.opacity,fillMode:"none"===o.fill?"custom":o.fill,customFill:p,glowEnabled:o.glow,bgColor:o.bgColor,bgMode:"static"===e.settings?.bg_mode||"daynight"===e.settings?.bg_mode?e.settings.bg_mode:null,northDeg:r({},e.settings),sunRays:"boolean"==typeof e.settings?.sun_rays?e.settings.sun_rays:null,tempMin:o.tempMin,tempMax:o.tempMax,showLqi:o.showLqi??this.host._config?.show_signal??!0,cardFontScale:o.cardFontScale,labelTemp:o.labelTemp,labelHum:o.labelHum,labelLqi:o.labelLqi,labelLight:o.labelLight,cellCm:Number(e.cell_cm)>0?Number(e.cell_cm):5,cellCmInput:n(Number(e.cell_cm)>0?Number(e.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const e=p(this.host._imperial);this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...m(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:{...h,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:_,tempMax:d,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:e,cellCmInput:n(e,this.host._imperial),cellCmTouched:!1,busy:!1},b(this.host,this.host._spaceDialog)}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;s.value="";const o=await v(e);if("reject"===o.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===o.kind)return void(this.host._backdropGuard=o.state);const a=await y(e,o.ext,e.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:a})}_renderBackdropGuard(){return w(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??e}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),o=this.host._spaceDialog;return o&&o.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...o,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const s=this.host._spaceDialog,e=s?.saved?.find(s=>s.name===t);if(!s||!e||e.used_by.length||e.url===s.planUrl)return;const o=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),a=this.host._spaceDialog,i=a?.saved?.find(s=>s.name===t);if(o&&a&&i&&i.url===e.url&&i.modified===e.modified&&!i.used_by.length&&i.url!==a.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return a`
    ${this.host._t("space.loading")}
    `;const s=t.saved||[];if(!s.length)return a`
    ${this.host._t("space.no_saved")}
    `;return a`
    ${s.map(s=>{return a`
    @@ -16,7 +16,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
    `;var e})} -
    `}async _saveConfigNow(){this.host._cfgEpoch++;try{await this.host._writeConfig()}catch(t){const s=t;throw s?.physicalGeometryRolledBack?await this.host._reloadRejectedPhysicalWrite():"conflict"===s?.code&&await this.host._reloadConfigOnly(),t}}async _saveSpaceDialog(){const t=this.host._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this.host._showToast(this.host._t("toast.plan_required"));const s="create"===t.mode&&0===(this.host._serverCfg?.spaces.length||0);this.host._spaceDialog={...t,busy:!0};try{const e="create"===t.mode?`s${Date.now().toString(36)}`:t.spaceId;let o=null;if("file"===t.source&&t.planFile){o={url:(await this.host.hass.callWS({type:"houseplan/plan/set",space_id:e,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let a=t.savedAspect||null;!o&&"file"===t.source&&t.planUrl&&!a&&this.host._aspectJob&&(a=await this.host._aspectJob||null);const i=this.host._serverCfg;let l=i.spaces.find(t=>t.id===e);if("create"===t.mode)l=b(e,t.title.trim()),i.spaces.push(l);else{if(!l)throw new Error(`space ${e} is gone from the config`);l.title=t.title.trim()}if(!l)throw new Error(`space ${e} is unavailable`);if(o?(l.plan_url=o.url,l.plan_aspect=o.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==l.plan_url&&(l.plan_url=t.planUrl,l.plan_aspect=a),"draw"===t.source&&(l.plan_url=null,l.plan_aspect=null,delete l.plan_x,delete l.plan_y,delete l.plan_scale,delete l.plan_scale_x,delete l.plan_scale_y,delete l.plan_angle),l.settings={...l.settings||{},show_borders:t.showBorders,show_names:t.showNames,hide_decor:t.hideDecor||void 0,hide_openings:t.hideOpenings||void 0,room_color:t.roomColor,room_opacity:t.roomOpacity,bg_color:t.bgColor||void 0,bg_mode:t.bgMode||void 0,north_deg:t.northDeg??void 0,sun_rays:t.sunRays??void 0,fill_mode:t.fillMode,custom_fill:t.customFill||void 0,glow_enabled:t.glowEnabled,temp_min:Number.isFinite(t.tempMin)?Math.min(t.tempMin,t.tempMax):_,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):d,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},l.zero_wall_style=t.zeroWallStyle,l.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(D,Math.min($,t.cellCm)):5,await this._saveConfigNow(),this.host._spaceDialog=null,"create"===t.mode&&this.host._commitSpace(l.id),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._importQueue.length)this._openNextImport();else if(s||this.host._importTotal>0){const t=this.host._importTotal>0;this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),await this.host._requestMode("plan"),this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this.host._primeDrawWallField(),this.host._showToast(this.host._t(s&&!t?"toast.space_added_onboard":"import.done"))}else this.host._showToast(this.host._t("create"===t.mode?"toast.space_added":"toast.space_saved")),"create"===t.mode&&("plan"!==this.host._mode?await this.host._requestMode("plan"):(this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this.host._primeDrawWallField(),this.host._saveNav()))}catch(t){const s=t;"conflict"!==s?.code&&await this.host._reloadConfigOnly(!0),this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteSpace(){const t=this.host._spaceDialog;if(!t||"edit"!==t.mode)return;const s=this.host._serverCfg;if(!s)return;const e=s.spaces.find(s=>s.id===t.spaceId);if(!e)return;const o=S(s,this.host._layout||{},t.spaceId||""),a=1===s.spaces.length&&s.spaces[0]?.id===t.spaceId;if(o.count&&!a)return void(this.host._spaceDialog={...t,deleteBlockers:o.count});const i=t.spaceId,l=await this.host._confirmDanger({key:"delete-space",kind:"destructive",title:this.host._t("confirm.delete_space_title"),message:this.host._t("confirm.delete_space_body"),objectName:e.title,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),h=this.host._spaceDialog,n=this.host._serverCfg;if(!l||!h||"edit"!==h.mode||h.busy||h.spaceId!==i||!n)return;if(!n.spaces.find(t=>t.id===i))return;const r=S(n,this.host._layout||{},i),c=1===n.spaces.length&&n.spaces[0]?.id===i;if(!r.count||c){this.host._spaceDialog={...h,deleteBlockers:0,busy:!0};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),this.host._persistLayout.pending()&&this.host._persistLayout.flush(),await this.host._writeChain,await this.host.hass.callWS({type:"houseplan/space/delete",space_id:i,expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev});const[t,s]=await Promise.all([this.host._getAuthoritativeConfig(),this.host.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this.host._adoptAuthoritative({cfgResp:t,layResp:s,reason:"space-delete",profile:"post-write"})).status)return this.host._spaceDialog={...h,busy:!1},void this.host.requestUpdate();this.host._spaceDialog=null,this.host._space===i&&this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||""),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.space_deleted"))}catch(t){const s=t;"conflict"!==s?.code&&"space_in_use"!==s?.code||await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]);const e=this.host._serverCfg;if(this.host._spaceDialog&&e){const t=S(e,this.host._layout||{},i),s=1===e.spaces.length&&e.spaces[0]?.id===i;this.host._spaceDialog={...this.host._spaceDialog,busy:!1,deleteBlockers:s?0:t.count}}this.host._showToast(this.host._t("toast.delete_failed",{err:this.host._errText(t)}))}}else this.host._spaceDialog={...h,deleteBlockers:r.count}}_startImport(){const t=this.host._importDialog;if(!t)return;const s=t.floors.filter(t=>t.checked).map(t=>t.name);this.host._importDialog=null,s.length?(this.host._importQueue=s,this.host._importTotal=s.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this.host._importQueue.shift();if(void 0===t)return;const s=p(this.host._imperial);this.host._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...m(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:_,tempMax:d,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:s,cellCmInput:n(s,this.host._imperial),cellCmTouched:!1,busy:!1},f(this.host,this.host._spaceDialog)}_skipImport(){this.host._spaceDialog=null,this.host._importQueue.length?this._openNextImport():this.host._importTotal>0&&this.host._model.length&&(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this.host._requestMode("plan").then(()=>{this.host._showToast(this.host._t("import.done"))}))}_renderImportDialog(){const t=this.host._importDialog,s=t.floors.filter(t=>t.checked).length;return a``}async _saveConfigNow(){this.host._cfgEpoch++;try{await this.host._writeConfig()}catch(t){const s=t;throw s?.physicalGeometryRolledBack?await this.host._reloadRejectedPhysicalWrite():"conflict"===s?.code&&await this.host._reloadConfigOnly(),t}}async _saveSpaceDialog(){const t=this.host._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this.host._showToast(this.host._t("toast.plan_required"));const s="create"===t.mode&&0===(this.host._serverCfg?.spaces.length||0);this.host._spaceDialog={...t,busy:!0};try{const e="create"===t.mode?`s${Date.now().toString(36)}`:t.spaceId;let o=null;if("file"===t.source&&t.planFile){o={url:(await this.host.hass.callWS({type:"houseplan/plan/set",space_id:e,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let a=t.savedAspect||null;!o&&"file"===t.source&&t.planUrl&&!a&&this.host._aspectJob&&(a=await this.host._aspectJob||null);const i=this.host._serverCfg;let l=i.spaces.find(t=>t.id===e);if("create"===t.mode)l=f(e,t.title.trim()),i.spaces.push(l);else{if(!l)throw new Error(`space ${e} is gone from the config`);l.title=t.title.trim()}if(!l)throw new Error(`space ${e} is unavailable`);if(o?(l.plan_url=o.url,l.plan_aspect=o.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==l.plan_url&&(l.plan_url=t.planUrl,l.plan_aspect=a),"draw"===t.source&&(l.plan_url=null,l.plan_aspect=null,delete l.plan_x,delete l.plan_y,delete l.plan_scale,delete l.plan_scale_x,delete l.plan_scale_y,delete l.plan_angle),l.settings={...l.settings||{},show_borders:t.showBorders,show_names:t.showNames,hide_decor:t.hideDecor||void 0,hide_openings:t.hideOpenings||void 0,room_color:t.roomColor,room_opacity:t.roomOpacity,bg_color:t.bgColor||void 0,bg_mode:t.bgMode||void 0,north_deg:t.northDeg??void 0,sun_rays:t.sunRays??void 0,fill_mode:t.fillMode,custom_fill:t.customFill||void 0,glow_enabled:t.glowEnabled,temp_min:Number.isFinite(t.tempMin)?Math.min(t.tempMin,t.tempMax):_,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):d,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},l.zero_wall_style=t.zeroWallStyle,l.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(D,Math.min($,t.cellCm)):5,await this._saveConfigNow(),this.host._spaceDialog=null,"create"===t.mode&&this.host._commitSpace(l.id),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._importQueue.length)this._openNextImport();else if(s||this.host._importTotal>0){const t=this.host._importTotal>0;this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),await this.host._requestMode("plan"),this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this.host._primeDrawWallField(),this.host._showToast(this.host._t(s&&!t?"toast.space_added_onboard":"import.done"))}else this.host._showToast(this.host._t("create"===t.mode?"toast.space_added":"toast.space_saved")),"create"===t.mode&&("plan"!==this.host._mode?await this.host._requestMode("plan"):(this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this.host._primeDrawWallField(),this.host._saveNav()))}catch(t){const s=t;"conflict"!==s?.code&&await this.host._reloadConfigOnly(!0),this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteSpace(){const t=this.host._spaceDialog;if(!t||"edit"!==t.mode)return;const s=this.host._serverCfg;if(!s)return;const e=s.spaces.find(s=>s.id===t.spaceId);if(!e)return;const o=S(s,this.host._layout||{},t.spaceId||""),a=1===s.spaces.length&&s.spaces[0]?.id===t.spaceId;if(o.count&&!a)return void(this.host._spaceDialog={...t,deleteBlockers:o.count});const i=t.spaceId,l=await this.host._confirmDanger({key:"delete-space",kind:"destructive",title:this.host._t("confirm.delete_space_title"),message:this.host._t("confirm.delete_space_body"),objectName:e.title,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),h=this.host._spaceDialog,n=this.host._serverCfg;if(!l||!h||"edit"!==h.mode||h.busy||h.spaceId!==i||!n)return;if(!n.spaces.find(t=>t.id===i))return;const r=S(n,this.host._layout||{},i),c=1===n.spaces.length&&n.spaces[0]?.id===i;if(!r.count||c){this.host._spaceDialog={...h,deleteBlockers:0,busy:!0};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),this.host._persistLayout.pending()&&this.host._persistLayout.flush(),await this.host._writeChain,await this.host.hass.callWS({type:"houseplan/space/delete",space_id:i,expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev});const[t,s]=await Promise.all([this.host._getAuthoritativeConfig(),this.host.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this.host._adoptAuthoritative({cfgResp:t,layResp:s,reason:"space-delete",profile:"post-write"})).status)return this.host._spaceDialog={...h,busy:!1},void this.host.requestUpdate();this.host._spaceDialog=null,this.host._space===i&&this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||""),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.space_deleted"))}catch(t){const s=t;"conflict"!==s?.code&&"space_in_use"!==s?.code||await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]);const e=this.host._serverCfg;if(this.host._spaceDialog&&e){const t=S(e,this.host._layout||{},i),s=1===e.spaces.length&&e.spaces[0]?.id===i;this.host._spaceDialog={...this.host._spaceDialog,busy:!1,deleteBlockers:s?0:t.count}}this.host._showToast(this.host._t("toast.delete_failed",{err:this.host._errText(t)}))}}else this.host._spaceDialog={...h,deleteBlockers:r.count}}_startImport(){const t=this.host._importDialog;if(!t)return;const s=t.floors.filter(t=>t.checked).map(t=>t.name);this.host._importDialog=null,s.length?(this.host._importQueue=s,this.host._importTotal=s.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this.host._importQueue.shift();if(void 0===t)return;const s=p(this.host._imperial);this.host._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...m(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:_,tempMax:d,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:s,cellCmInput:n(s,this.host._imperial),cellCmTouched:!1,busy:!1},b(this.host,this.host._spaceDialog)}_skipImport(){this.host._spaceDialog=null,this.host._importQueue.length?this._openNextImport():this.host._importTotal>0&&this.host._model.length&&(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this.host._requestMode("plan").then(()=>{this.host._showToast(this.host._t("import.done"))}))}_renderImportDialog(){const t=this.host._importDialog,s=t.floors.filter(t=>t.checked).length;return a`this.host._importDialog=null}>
    diff --git a/custom_components/houseplan/frontend/houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js b/custom_components/houseplan/frontend/houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js similarity index 95% rename from custom_components/houseplan/frontend/houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js rename to custom_components/houseplan/frontend/houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js index 4e572917..c2c384c1 100644 --- a/custom_components/houseplan/frontend/houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js +++ b/custom_components/houseplan/frontend/houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js @@ -1,4 +1,4 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{az as e,l as t,A as i,eb as r,as as o,c as s,ay as n}from"./houseplan-card-BWAph8ZF.js";import{t as a,a as h,r as d}from"./zigbee-topology-D0gydI7H.js";import{zigbeeTopologyRuntimeSnapshot as p,subscribeZigbeeTopology as l}from"./zigbee-topology-runtime-BXasXMdL.js";function c(e,t,i,r,o,s=9,n=4.5){const a=t.x-e.x,h=t.y-e.y,d=Math.hypot(a,h),p=d-Math.max(0,i)-Math.max(0,r);if(!Number.isFinite(d)||d<=0||p<4)return null;const l=a/d,c=h/d,_="toward-neighbor"===o,u=_?{x:t.x-l*Math.max(0,r),y:t.y-c*Math.max(0,r)}:{x:e.x+l*Math.max(0,i),y:e.y+c*Math.max(0,i)},m=Math.min(s,Math.max(4,.45*p)),v=Math.min(n,.5*m),b=_?-1:1,g=u.x+l*m*b,y=u.y+c*m*b,x=-c;return{tip:u,points:[u,{x:g+x*v,y:y+l*v},{x:g-x*v,y:y-l*v}]}}const _={revision:0,topologies:[],states:{}},u="data-hp-zigbee-topology-endpoint";class m extends e{constructor(){super(...arguments),this.devices=[],this.currentSpace="",this._runtime=_,this._hovered="",this._desiredEndpointIds=new Set,this._endpointSetDirty=!1,this._endpointElements=new Set,this._pointerOver=e=>{if(!this._mouseAllowed(e))return void this._clear();const t=this._deviceFromEvent(e),i=t?.dataset.id||"";i&&i!==this._hovered&&(this._hovered=i,this.requestUpdate())},this._pointerOut=e=>{const t=this._deviceFromEvent(e);if(!t||t.dataset.id!==this._hovered)return;const i=e.relatedTarget instanceof Element?e.relatedTarget.closest('[data-hp="device"]'):null;i?.dataset.id!==this._hovered&&this._clear()},this._pointerDown=e=>{"mouse"!==e.pointerType&&this._clear()}}connectedCallback(){super.connectedCallback();const e=this.getRootNode();e.host&&"undefined"!=typeof MutationObserver&&(this._hoverGateObserver=new MutationObserver(()=>{e.host.hasAttribute("data-pointer-hover")||this._clear()}),this._hoverGateObserver.observe(e.host,{attributes:!0,attributeFilter:["data-pointer-hover"]})),queueMicrotask(()=>this._connectParent())}disconnectedCallback(){this._release?.(),this._release=void 0,this._disconnectParent(),this._hoverGateObserver?.disconnect(),this._hoverGateObserver=void 0,this._hovered="",this._desiredEndpointIds.clear(),super.disconnectedCallback()}updated(e){e.has("hass")&&(this._release?.(),this._acceptRuntime(p(this.hass)),this._release=l(this.hass,()=>{this._acceptRuntime(p(this.hass))}));const t=e.has("currentSpace")||e.has("devices")||e.has("registry");t&&(this._mappedMemo=void 0,this.devices.some(e=>e.id===this._hovered&&e.space===this.currentSpace)||this._clear()),this._connectParent(),(this._endpointSetDirty||t)&&this._syncEndpointOwnership()}_acceptRuntime(e){e.revision===this._runtime.revision&&e.topologies===this._runtime.topologies&&e.states===this._runtime.states||(this._setDesiredEndpointIds([]),this._clearEndpointOwnership(),this._endpointSetDirty=!1,this._runtime=e,this._mappedMemo=void 0,this.requestUpdate())}_connectParent(){const e=this.parentElement;e&&e!==this._parent&&(this._disconnectParent(),this._parent=e,e.addEventListener("pointerover",this._pointerOver),e.addEventListener("pointerout",this._pointerOut),e.addEventListener("pointerdown",this._pointerDown,!0),"undefined"!=typeof MutationObserver&&(this._markerObserver=new MutationObserver(()=>this._syncEndpointOwnership()),this._markerObserver.observe(e,{childList:!0})),this._syncEndpointOwnership())}_disconnectParent(){this._parent?.removeEventListener("pointerover",this._pointerOver),this._parent?.removeEventListener("pointerout",this._pointerOut),this._parent?.removeEventListener("pointerdown",this._pointerDown,!0),this._markerObserver?.disconnect(),this._markerObserver=void 0,this._clearEndpointOwnership(),this._parent=void 0}_deviceFromEvent(e){for(const t of e.composedPath())if(t instanceof HTMLElement&&"device"===t.dataset.hp)return t;return null}_mouseAllowed(e){const t=this.getRootNode();return"mouse"===e.pointerType&&t.host?.hasAttribute?.("data-pointer-hover")}_clear(){this._setDesiredEndpointIds([]),this._clearEndpointOwnership(),this._endpointSetDirty=!1,this._hovered&&(this._hovered="",this.requestUpdate())}_setDesiredEndpointIds(e){const t=new Set(e);t.size===this._desiredEndpointIds.size&&[...t].every(e=>this._desiredEndpointIds.has(e))||(this._desiredEndpointIds=t,this._endpointSetDirty=!0)}_marker(e){return[...this._parent?.querySelectorAll('.dev[data-hp="device"][data-id]')||[]].find(t=>t.dataset.id===e)||null}_clearEndpointOwnership(){for(const e of this._endpointElements)e.removeAttribute(u);for(const e of this._parent?.querySelectorAll(`[${u}]`)||[])e.removeAttribute(u);this._endpointElements.clear()}_syncEndpointOwnership(){const e=new Set;for(const t of this._desiredEndpointIds){const i=this._marker(t);i&&e.add(i)}for(const t of this._endpointElements)e.has(t)||t.removeAttribute(u);for(const t of this._parent?.querySelectorAll(`[${u}]`)||[])e.has(t)||t.removeAttribute(u);for(const t of e)this._endpointElements.has(t)&&t.hasAttribute(u)||t.setAttribute(u,"");this._endpointElements=e,this._endpointSetDirty=!1}_position(e,t,i){const r=this._marker(e);if(!r)return null;const o=Number.parseFloat(r.style.left),s=Number.parseFloat(r.style.top),n=r.getBoundingClientRect();return Number.isFinite(o)&&Number.isFinite(s)?{x:o*t/100,y:s*i/100,width:n.width,height:n.height}:null}_targetText(e){if("remote-space"===e.kind){const i=this.spaces?.find(t=>t.id===e.spaceId)?.title;return"string"==typeof i&&i.trim()||a(t(this.hass),"route_other_space")}return a(t(this.hass),"unplaced-coordinator"===e.kind?"route_coordinator_not_on_plan":"route_device_not_on_plan")}_markerClearance(e){return.61*Math.max(e.width,e.height)+3}_points(e){return e.map(e=>`${e.x.toFixed(2)},${e.y.toFixed(2)}`).join(" ")}render(){if(!this._hovered||!this.registry||!this._runtime.topologies.length)return this._setDesiredEndpointIds([]),i;const e=this._mappedMemo,n=e&&e.runtime===this._runtime&&e.devices===this.devices&&e.registry===this.registry?e.mapped:h(this._runtime.topologies,this.devices,this.registry);e&&n===e.mapped||(this._mappedMemo={runtime:this._runtime,devices:this.devices,registry:this.registry,mapped:n});const p=d(n,this.currentSpace,this._hovered),l=this.clientWidth||this._parent?.clientWidth||1,_=this.clientHeight||this._parent?.clientHeight||1,u=this._position(this._hovered,l,_);if(!u)return this._setDesiredEndpointIds([]),i;const m=p.lines.map(e=>({...e,point:this._position(e.neighborMarkerId,l,_)})).filter(e=>!!e.point).map(e=>{const t=void 0===e.lqi?"rgba(145,155,165,.85)":r(e.lqi),i=e.routeDirection?c(u,e.point,this._markerClearance(u),this._markerClearance(e.point),e.routeDirection):null;return{...e,color:t,arrow:i}}),v=u.x>l/2,b=this._markerClearance(u)+18,g=p.parentTargets.map((e,t)=>{const i=30*(t-(p.parentTargets.length-1)/2),r={x:u.x+(v?-b:b),y:Math.max(14,Math.min(_-14,u.y+i))};return{target:e,point:r,arrow:c(u,r,this._markerClearance(u),0,"toward-neighbor")}});return this._setDesiredEndpointIds(m.length||g.length||p.remoteCount?[this._hovered,...m.map(e=>e.neighborMarkerId)]:[]),s` +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{az as e,l as t,A as i,eb as r,as as o,c as s,ay as n}from"./houseplan-card-9fMSy3y3.js";import{t as a,a as h,r as d}from"./zigbee-topology-CI6PJorK.js";import{zigbeeTopologyRuntimeSnapshot as p,subscribeZigbeeTopology as l}from"./zigbee-topology-runtime-d-S2Abll.js";function c(e,t,i,r,o,s=9,n=4.5){const a=t.x-e.x,h=t.y-e.y,d=Math.hypot(a,h),p=d-Math.max(0,i)-Math.max(0,r);if(!Number.isFinite(d)||d<=0||p<4)return null;const l=a/d,c=h/d,_="toward-neighbor"===o,u=_?{x:t.x-l*Math.max(0,r),y:t.y-c*Math.max(0,r)}:{x:e.x+l*Math.max(0,i),y:e.y+c*Math.max(0,i)},m=Math.min(s,Math.max(4,.45*p)),v=Math.min(n,.5*m),b=_?-1:1,g=u.x+l*m*b,y=u.y+c*m*b,f=-c;return{tip:u,points:[u,{x:g+f*v,y:y+l*v},{x:g-f*v,y:y-l*v}]}}const _={revision:0,topologies:[],states:{}},u="data-hp-zigbee-topology-endpoint";class m extends e{constructor(){super(...arguments),this.devices=[],this.currentSpace="",this._runtime=_,this._hovered="",this._desiredEndpointIds=new Set,this._endpointSetDirty=!1,this._endpointElements=new Set,this._pointerOver=e=>{if(!this._mouseAllowed(e))return void this._clear();const t=this._deviceFromEvent(e),i=t?.dataset.id||"";i&&i!==this._hovered&&(this._hovered=i,this.requestUpdate())},this._pointerOut=e=>{const t=this._deviceFromEvent(e);if(!t||t.dataset.id!==this._hovered)return;const i=e.relatedTarget instanceof Element?e.relatedTarget.closest('[data-hp="device"]'):null;i?.dataset.id!==this._hovered&&this._clear()},this._pointerDown=e=>{"mouse"!==e.pointerType&&this._clear()}}connectedCallback(){super.connectedCallback();const e=this.getRootNode();e.host&&"undefined"!=typeof MutationObserver&&(this._hoverGateObserver=new MutationObserver(()=>{e.host.hasAttribute("data-pointer-hover")||this._clear()}),this._hoverGateObserver.observe(e.host,{attributes:!0,attributeFilter:["data-pointer-hover"]})),queueMicrotask(()=>this._connectParent())}disconnectedCallback(){this._release?.(),this._release=void 0,this._disconnectParent(),this._hoverGateObserver?.disconnect(),this._hoverGateObserver=void 0,this._hovered="",this._desiredEndpointIds.clear(),super.disconnectedCallback()}updated(e){e.has("hass")&&(this._release?.(),this._acceptRuntime(p(this.hass)),this._release=l(this.hass,()=>{this._acceptRuntime(p(this.hass))}));const t=e.has("currentSpace")||e.has("devices")||e.has("registry");t&&(this._mappedMemo=void 0,this.devices.some(e=>e.id===this._hovered&&e.space===this.currentSpace)||this._clear()),this._connectParent(),(this._endpointSetDirty||t)&&this._syncEndpointOwnership()}_acceptRuntime(e){e.revision===this._runtime.revision&&e.topologies===this._runtime.topologies&&e.states===this._runtime.states||(this._setDesiredEndpointIds([]),this._clearEndpointOwnership(),this._endpointSetDirty=!1,this._runtime=e,this._mappedMemo=void 0,this.requestUpdate())}_connectParent(){const e=this.parentElement;e&&e!==this._parent&&(this._disconnectParent(),this._parent=e,e.addEventListener("pointerover",this._pointerOver),e.addEventListener("pointerout",this._pointerOut),e.addEventListener("pointerdown",this._pointerDown,!0),"undefined"!=typeof MutationObserver&&(this._markerObserver=new MutationObserver(()=>this._syncEndpointOwnership()),this._markerObserver.observe(e,{childList:!0})),this._syncEndpointOwnership())}_disconnectParent(){this._parent?.removeEventListener("pointerover",this._pointerOver),this._parent?.removeEventListener("pointerout",this._pointerOut),this._parent?.removeEventListener("pointerdown",this._pointerDown,!0),this._markerObserver?.disconnect(),this._markerObserver=void 0,this._clearEndpointOwnership(),this._parent=void 0}_deviceFromEvent(e){for(const t of e.composedPath())if(t instanceof HTMLElement&&"device"===t.dataset.hp)return t;return null}_mouseAllowed(e){const t=this.getRootNode();return"mouse"===e.pointerType&&t.host?.hasAttribute?.("data-pointer-hover")}_clear(){this._setDesiredEndpointIds([]),this._clearEndpointOwnership(),this._endpointSetDirty=!1,this._hovered&&(this._hovered="",this.requestUpdate())}_setDesiredEndpointIds(e){const t=new Set(e);t.size===this._desiredEndpointIds.size&&[...t].every(e=>this._desiredEndpointIds.has(e))||(this._desiredEndpointIds=t,this._endpointSetDirty=!0)}_marker(e){return[...this._parent?.querySelectorAll('.dev[data-hp="device"][data-id]')||[]].find(t=>t.dataset.id===e)||null}_clearEndpointOwnership(){for(const e of this._endpointElements)e.removeAttribute(u);for(const e of this._parent?.querySelectorAll(`[${u}]`)||[])e.removeAttribute(u);this._endpointElements.clear()}_syncEndpointOwnership(){const e=new Set;for(const t of this._desiredEndpointIds){const i=this._marker(t);i&&e.add(i)}for(const t of this._endpointElements)e.has(t)||t.removeAttribute(u);for(const t of this._parent?.querySelectorAll(`[${u}]`)||[])e.has(t)||t.removeAttribute(u);for(const t of e)this._endpointElements.has(t)&&t.hasAttribute(u)||t.setAttribute(u,"");this._endpointElements=e,this._endpointSetDirty=!1}_position(e,t,i){const r=this._marker(e);if(!r)return null;const o=Number.parseFloat(r.style.left),s=Number.parseFloat(r.style.top),n=r.getBoundingClientRect();return Number.isFinite(o)&&Number.isFinite(s)?{x:o*t/100,y:s*i/100,width:n.width,height:n.height}:null}_targetText(e){if("remote-space"===e.kind){const i=this.spaces?.find(t=>t.id===e.spaceId)?.title;return"string"==typeof i&&i.trim()||a(t(this.hass),"route_other_space")}return a(t(this.hass),"unplaced-coordinator"===e.kind?"route_coordinator_not_on_plan":"route_device_not_on_plan")}_markerClearance(e){return.61*Math.max(e.width,e.height)+3}_points(e){return e.map(e=>`${e.x.toFixed(2)},${e.y.toFixed(2)}`).join(" ")}render(){if(!this._hovered||!this.registry||!this._runtime.topologies.length)return this._setDesiredEndpointIds([]),i;const e=this._mappedMemo,n=e&&e.runtime===this._runtime&&e.devices===this.devices&&e.registry===this.registry?e.mapped:h(this._runtime.topologies,this.devices,this.registry);e&&n===e.mapped||(this._mappedMemo={runtime:this._runtime,devices:this.devices,registry:this.registry,mapped:n});const p=d(n,this.currentSpace,this._hovered),l=this.clientWidth||this._parent?.clientWidth||1,_=this.clientHeight||this._parent?.clientHeight||1,u=this._position(this._hovered,l,_);if(!u)return this._setDesiredEndpointIds([]),i;const m=p.lines.map(e=>({...e,point:this._position(e.neighborMarkerId,l,_)})).filter(e=>!!e.point).map(e=>{const t=void 0===e.lqi?"rgba(145,155,165,.85)":r(e.lqi),i=e.routeDirection?c(u,e.point,this._markerClearance(u),this._markerClearance(e.point),e.routeDirection):null;return{...e,color:t,arrow:i}}),v=u.x>l/2,b=this._markerClearance(u)+18,g=p.parentTargets.map((e,t)=>{const i=30*(t-(p.parentTargets.length-1)/2),r={x:u.x+(v?-b:b),y:Math.max(14,Math.min(_-14,u.y+i))};return{target:e,point:r,arrow:c(u,r,this._markerClearance(u),0,"toward-neighbor")}});return this._setDesiredEndpointIds(m.length||g.length||p.remoteCount?[this._hovered,...m.map(e=>e.neighborMarkerId)]:[]),s` ${m.length||g.length?o`${E} @@ -21,4 +21,4 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${this.context.t(this.busy?"pdf.saving":"pdf.save")}
    -
    `}}v.properties={context:{attribute:!1}},v.styles=A`:host{display:contents;}.body{display:grid;gap:12px;width:100%;max-width:100%;min-width:0;padding:16px 20px;box-sizing:border-box;}label{display:flex;min-width:0;min-height:44px;align-items:center;gap:12px;cursor:pointer;}label span{min-width:0;overflow-wrap:anywhere;}input{width:20px;height:20px;flex:none;accent-color:var(--hp-accent,#d89300);}.row{display:flex;align-items:center;gap:8px;width:100%;max-width:100%;min-width:0;padding:12px 16px;box-sizing:border-box;}.spacer{flex:1;}button{min-width:0;min-height:44px;max-width:100%;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--hp-line,rgb(127 127 127/.3));border-radius:12px;padding:0 18px;box-sizing:border-box;overflow-wrap:anywhere;white-space:normal;background:transparent;color:inherit;font:inherit;cursor:pointer;}button.primary{background:var(--hp-accent,#d89300);color:var(--hp-on-accent,#111);border-color:transparent;}button:disabled{opacity:.55;cursor:default;}ha-icon{flex:none;margin-right:6px;}@media (max-width:360px){.row{display:grid;grid-template-columns:minmax(0,1fr);}.spacer{display:none;}button{width:100%;}}`,customElements.get("hp-pdf-dialog")||customElements.define("hp-pdf-dialog",v);const V=(A,B,E)=>Math.hypot(A[0]-B[0],A[1]-B[1])<=E,U=A=>Number.isFinite(A)&&A>=0?A:0;function l(A){const B=Number(A);return Number.isFinite(B)&&B>0?.1/B:0}const a=(A,B)=>[...new Set([...A,...B])].sort((A,B)=>A-B),P=(A,B)=>{const E=A.points.length;if(E<=1||!V(A.points[E-1],A.points[0],B))return!1;const s=E-2;return A.edgeSources[s]=a(A.edgeSources[s],A.edgeSources[E-1]),A.points.splice(E-1,1),A.edgeSources.splice(E-1,1),!0},y=(A,B)=>{for(let E=0;E+1{let E=!1;for(;A.points.length>1;)if(P(A,B))E=!0;else{if(!y(A,B))break;E=!0}return E},N=(A,B,E)=>{const s=B[0]-A[0],w=B[1]-A[1],C=E[0]-B[0],g=E[1]-B[1],I=Math.hypot(s,w),Y=Math.hypot(C,g);if(!(I>0&&Y>0))return!1;const R=s*C+w*g;if(!(R>0))return!1;const M=s*g-w*C;return Math.abs(M)<=R*Q},K=A=>{const B=A.points.length;if(B<3)return!1;for(let E=0;E{const E=U(B),s=[],w=[];for(let B=0;B[A])};for(;Q.points.length>1;){const A=u(Q,E);if(Q.points.length<3)break;if(!K(Q)&&!A)break}return u(Q,E),Q};function J(A,B){const E=Number(A[0]),s=Number(A[1]),w=Number(B[0]),C=Number(B[1]);if(![E,s,w,C].every(Number.isFinite))return null;const g=w-E,I=C-s,Y=Math.abs(g),R=Math.abs(I),M=Math.max(Y,R),F=Math.min(Y,R);if(!(M>0)||F/M>Q)return null;const i=[(E+w)/2,(s+C)/2];if(Y>=R){return{axis:"horizontal",a:[E,i[1]],b:[w,i[1]],mid:i,projectedLength:Y,tangentInterval:[Math.min(E,w),Math.max(E,w)],normalCoordinate:i[1]}}return{axis:"vertical",a:[i[0],s],b:[i[0],C],mid:i,projectedLength:R,tangentInterval:[Math.min(s,C),Math.max(s,C)],normalCoordinate:i[0]}}function Z(A,B){const E=B.map(A=>[Number(A[0]),Number(A[1])]);if(!E.every(A=>A.every(Number.isFinite)))return!1;if(E.length<3||((A,B)=>{const E=1e-12*Math.max(1,Math.abs(A[0]),Math.abs(A[1]),...B.flatMap(A=>[Math.abs(A[0]),Math.abs(A[1])]));for(let s=0;s0))continue;const Y=(A[0]-w[0])*g-(A[1]-w[1])*C;if(Math.abs(Y)>E*I)continue;const R=(A[0]-w[0])*C+(A[1]-w[1])*g;if(R>=-E&&R<=I*I+E)return!0}return!1})(A,E))return!1;let s=!1;for(let B=0,w=E.length-1;BA[1]==C[1]>A[1])continue;const g=(C[0]-Q[0])*(A[1]-Q[1])/(C[1]-Q[1])+Q[0];A[0]Object.is(A,-0)?0:A,I=[g(-Q/C),g(w/C)],Y=[g(-I[0]),g(-I[1])],R=[(B[0]+E[0])/2,(B[1]+E[1])/2],M=Math.max(1,C,Math.abs(R[0]),Math.abs(R[1])),F=Math.max(1e-9*M,.01*U(s));for(const B of[F,4*F,16*F]){const E=Z([R[0]+I[0]*B,R[1]+I[1]*B],A);if(E!==Z([R[0]+Y[0]*B,R[1]+Y[1]*B],A))return E?I:Y}return sA(A)>=0?I:Y}function f(A,B){let E=180*Math.atan2(B[1]-A[1],B[0]-A[0])/Math.PI;return E>90&&(E-=180),E<=-90&&(E+=180),E}function k(A,B,E,s={}){const w=Number(B);if(!(w>0&&Number.isFinite(w)))return[];const Q=void 0===s.epsilon?l(w):U(s.epsilon);return z(d(A,Q),w,E,{...s,epsilon:Q})}const z=(A,B,E,s)=>{if(A.points.length<3)return[];const Q=U(s.epsilon??l(B)),C=Number.isFinite(Number(s.ringIndex))?Number(s.ringIndex):0,g=[];for(let s=0;sQ))continue;const M=[...A.edgeSources[s]||[s]].sort((A,B)=>A-B),F=M[0]??s,i=T(A.points,R.a,R.b,Q),x=("horizontal"===R.axis?i[1]:i[0])<0?-1:1,b=[R.axis,O(R.tangentInterval[0]),String(x),O(C),O(F)].join("|"),L=R.projectedLength*B;g.push({sourceA:[...I],sourceB:[...Y],a:R.a,b:R.b,text:w(L,E),short:L<30,angle:f(R.a,R.b),mid:R.mid,axis:R.axis,projectedLength:R.projectedLength,tangentInterval:R.tangentInterval,normalCoordinate:R.normalCoordinate,inwardNormal:i,normalSign:x,source:{ringIndex:C,edgeIndex:F},sourceEdgeIndices:M,stableKey:b})}return g};function p(A,B,E,s={}){const w=Number(B);if(!(w>0&&Number.isFinite(w)))return[];const Q=void 0===s.epsilon?l(w):U(s.epsilon);let C=d(A,Q);if(sA(C.points)<0&&(C=(A=>{const B=A.points.length;return{points:[...A.points].reverse().map(A=>[...A]),edgeSources:A.points.map((E,s)=>[...A.edgeSources[(B-2-s+B)%B]])}})(C)),C.points.length){let A=0;for(let B=1;B({points:[...A.points.slice(B),...A.points.slice(0,B)],edgeSources:[...A.edgeSources.slice(B),...A.edgeSources.slice(0,B)]}))(C,A)}return z(C,w,E,{...s,epsilon:Q})}function X(A,B){const E=U(B),s=[];for(const B of A){const A=s.find(A=>A.axis===B.axis&&A.normalSign===B.normalSign&&Math.abs(A.normalCoordinate-B.normalCoordinate)<=E);A?A.edges.push(B):s.push({axis:B.axis,normalSign:B.normalSign,normalCoordinate:B.normalCoordinate,edges:[B]})}return s.map(A=>A.edges)}const O=A=>Object.is(A,-0)?"0":String(A),q=A=>"horizontal"===A?0:1;function $(A,B){return q(A.axis)-q(B.axis)||A.tangentInterval[0]-B.tangentInterval[0]||A.normalSign-B.normalSign||A.source.ringIndex-B.source.ringIndex||A.source.edgeIndex-B.source.edgeIndex}function _(A,B,E,s){const w=U(s);if(A.axis!==B.axis)return!1;if(A.source.ringIndex!==B.source.ringIndex)return!1;if(A.inwardNormal[0]*B.inwardNormal[0]+A.inwardNormal[1]*B.inwardNormal[1]>=-.5)return!1;if(!((A,B,E)=>Math.abs(A[0]-B[0])<=E&&Math.abs(A[1]-B[1])<=E)(A.tangentInterval,B.tangentInterval,w))return!1;if(Math.abs(A.projectedLength-B.projectedLength)>w)return!1;return Z([(A.mid[0]+B.mid[0])/2,(A.mid[1]+B.mid[1])/2],E)}const AA=(A,B)=>{const E=B?.(A);return{hardCollisions:Number.isFinite(Number(E?.hardCollisions))?Number(E?.hardCollisions):0,normalClearance:Number.isFinite(Number(E?.normalClearance))?Number(E?.normalClearance):0}},BA=(A,B,E)=>{const s=AA(A,E),w=AA(B,E);return s.hardCollisions-w.hardCollisions||w.normalClearance-s.normalClearance||$(A,B)};function EA(A,B){if(A.length<2)return[...A];const E=U(B.epsilon),s=function(A,B=1e-7){return d(A,B).points.map(A=>[...A])}(B.ring,E),w=[];for(let B=0;B{const E=A.separation-B.separation;if(E)return E;const s=$(A.left,A.right)<=0?A.left:A.right,w=s===A.left?A.right:A.left,Q=$(B.left,B.right)<=0?B.left:B.right,C=Q===B.left?B.right:B.left;return $(s,Q)||$(w,C)});const Q=new Set,C=new Set;for(const A of w){if(Q.has(A.left)||Q.has(A.right))continue;Q.add(A.left),Q.add(A.right);const E=BA(A.left,A.right,B.score)<=0?A.left:A.right;C.add(E===A.left?A.right:A.left)}return A.filter(A=>!C.has(A))}function sA(A){let B=0;for(let E=0;E1){const A=Math.sqrt(G);Y*=A,R*=A}const o=Math.max(0,Y*Y*R*R-Y*Y*D*D-R*R*L*L),t=Y*Y*D*D+R*R*L*L||1,c=(Q===C?-1:1)*Math.sqrt(o/t),W=c*Y*D/R,m=c*-R*L/Y,n=F*W-i*m+(A+g)/2,e=i*W+F*m+(B+I)/2;let h=gA(1,0,(L-W)/Y,(D-m)/R),S=gA((L-W)/Y,(D-m)/R,(-L-W)/Y,(-D-m)/R);!C&&S>0&&(S-=2*Math.PI),C&&S<0&&(S+=2*Math.PI);const j=Math.max(1,Math.ceil(Math.abs(S)/(Math.PI/2))),r=S/j,H=A=>[n+F*Y*Math.cos(A)-i*R*Math.sin(A),e+i*Y*Math.cos(A)+F*R*Math.sin(A)],v=A=>[-F*Y*Math.sin(A)-i*R*Math.cos(A),-i*Y*Math.sin(A)+F*R*Math.cos(A)],V=[];for(let A=0;A[B.a*A+B.c*E+B.e,B.b*A+B.d*E+B.f];return function(A){const B=A.match(/[AaCcHhLlMmQqSsTtVvZz]|[-+]?(?:\d*\.\d+|\d+\.?)(?:e[-+]?\d+)?/gi)||[],E=[];let s=0,w="",Q=0,C=0,g=0,I=0,Y=null,R=null;const M=()=>Number(B[s++]);for(;sB.length||QA.test(B[s]))throw new Error(`Invalid SVG path command ${w}`);const x=Array.from({length:i},M),b=A=>A+(F?Q:0),L=A=>A+(F?C:0);if("M"===A||"L"===A)Q=b(x[0]),C=L(x[1]),E.push({op:"M"===A?"M":"L",x:Q,y:C}),"M"===A&&(g=Q,I=C,w=F?"l":"L"),Y=R=null;else if("H"===A)Q=b(x[0]),E.push({op:"L",x:Q,y:C}),Y=R=null;else if("V"===A)C=L(x[0]),E.push({op:"L",x:Q,y:C}),Y=R=null;else if("C"===A){const A=b(x[0]),B=L(x[1]),s=b(x[2]),w=L(x[3]);Q=b(x[4]),C=L(x[5]),Y=[s,w],R=null,E.push({op:"C",x1:A,y1:B,x2:s,y2:w,x:Q,y:C})}else if("S"===A){const A=Y?2*Q-Y[0]:Q,B=Y?2*C-Y[1]:C,s=b(x[0]),w=L(x[1]);Q=b(x[2]),C=L(x[3]),Y=[s,w],R=null,E.push({op:"C",x1:A,y1:B,x2:s,y2:w,x:Q,y:C})}else if("Q"===A||"T"===A){const B="Q"===A?b(x[0]):R?2*Q-R[0]:Q,s="Q"===A?L(x[1]):R?2*C-R[1]:C,w=b("Q"===A?x[2]:x[0]),g=L("Q"===A?x[3]:x[1]);E.push({op:"C",x1:Q+2/3*(B-Q),y1:C+2/3*(s-C),x2:w+2/3*(B-w),y2:g+2/3*(s-g),x:w,y:g}),Q=w,C=g,R=[B,s],Y=null}else if("A"===A){const A=b(x[5]),B=L(x[6]),s=IA(Q,C,x[0],x[1],x[2],x[3],x[4],A,B);s.length?E.push(...s):E.push({op:"L",x:A,y:B}),Q=A,C=B,Y=R=null}}return E}(A).map(A=>{if("Z"===A.op)return A;if("M"===A.op||"L"===A.op){const[B,s]=E(A.x,A.y);return{op:A.op,x:B,y:s}}if("C"!==A.op)throw new Error("Unsupported PDF vector operation");const[B,s]=E(A.x1,A.y1),[w,Q]=E(A.x2,A.y2),[C,g]=E(A.x,A.y);return{op:"C",x1:B,y1:s,x2:w,y2:Q,x:C,y:g}})}const RA=["M20.82,15.31h0L10.46,9c-.46-.26-1.11.37-.86.84l6.15,10.56,10.56,6.15a.66.66,0,0,0,.84-.86Zm-4,4,3-3,4.55,7.44Z","M18,2A16,16,0,1,0,34,18,16,16,0,0,0,18,2Zm1,29.95V29.53H17v2.42A14,14,0,0,1,4.05,19H6.47V17H4.05A14,14,0,0,1,17,4.05V6.47h2V4.05A14,14,0,0,1,31.95,17H29.53v2h2.42A14,14,0,0,1,19,31.95Z"],MA=A=>Math.abs(A)<1e-12?0:Math.abs(A-1)<1e-12?1:Math.abs(A+1)<1e-12?-1:A;function FA(A){const B=function(A){const{centerX:B,centerY:E,size:s,northDeg:w}=A;if(![B,E,s,w].every(Number.isFinite)||s<=0)throw new RangeError("PDF compass placement must contain finite coordinates and a positive size");const Q=((w%360+360)%360+45)*Math.PI/180,C=s/36,g=MA(Math.cos(Q)),I=MA(Math.sin(Q)),Y=C*g,R=C*I,M=-C*I,F=C*g;return{a:Y,b:R,c:M,d:F,e:B-18*Y-18*M,f:E-18*R-18*F}}(A);return RA.flatMap(A=>YA(A,B))}const iA=1e-8,xA=A=>A.length>=2&&Number.isFinite(A[0])&&Number.isFinite(A[1]),bA=(A,B)=>A[0]>=B.minX-iA&&A[0]<=B.maxX+iA&&A[1]>=B.minY-iA&&A[1]<=B.maxY+iA,LA=A=>[A.minX,A.minY,A.maxX,A.maxY].every(Number.isFinite)&&A.maxX>=A.minX&&A.maxY>=A.minY,DA=A=>[[A.minX,A.minY],[A.maxX,A.minY],[A.maxX,A.maxY],[A.minX,A.maxY]];const GA=(A,B,E)=>(B[0]-A[0])*(E[1]-A[1])-(B[1]-A[1])*(E[0]-A[0]),oA=(A,B,E)=>{const s=E[0]-B[0],w=E[1]-B[1],Q=Math.abs(s)>=Math.abs(w)?s:w;return Math.abs(Q)<=iA?0:(Math.abs(s)>=Math.abs(w)?A[0]-B[0]:A[1]-B[1])/Q},tA=(A,B)=>Math.hypot(B[0]-A[0],B[1]-A[1]);function cA(A,B,E){const s=tA(B,E);if(s<=iA)return tA(A,B)<=iA;if(Math.abs(GA(B,E,A))/s>iA)return!1;const w=oA(A,B,E),Q=iA/s;return w>=-Q&&w<=1+Q}function WA(A,B,E,s){const w=B[0]-A[0],Q=B[1]-A[1],C=s[0]-E[0],g=s[1]-E[1],I=Math.hypot(w,Q),Y=Math.hypot(C,g);if(I<=iA)return cA(A,E,s)?{t:0,endT:0,overlap:!1}:null;if(Y<=iA){if(!cA(E,A,B))return null;const s=Math.max(0,Math.min(1,oA(E,A,B)));return{t:s,endT:s,overlap:!1}}const R=w*g-Q*C,M=E[0]-A[0],F=E[1]-A[1],i=iA*I*Y;if(Math.abs(R)<=i){if(Math.abs(GA(A,B,E))/I>iA||Math.abs(GA(A,B,s))/I>iA)return null;const w=oA(E,A,B),Q=oA(s,A,B),C=Math.max(0,Math.min(w,Q)),g=Math.min(1,Math.max(w,Q));return giA}}const x=(M*g-F*C)/R,b=(M*Q-F*w)/R,L=iA/I,D=iA/Y;if(x<-L||x>1+L||b<-D||b>1+D)return null;const G=Math.max(0,Math.min(1,x));return{t:G,endT:G,overlap:!1}}const mA=A=>A.every(A=>A.length>=2&&A.every(xA));function nA(A,B){for(const E of A){const A=E;for(let E=0;Enull!==WA(A,B,E,s[(w+1)%s.length]))}const hA=2048,SA=2146,jA=[-1825,-555,4188,2163],rA={32:1,33:2,34:3,35:4,36:5,37:6,38:7,39:8,40:9,41:10,42:11,43:12,44:13,45:14,46:15,47:16,48:17,49:18,50:19,51:20,52:21,53:22,54:23,55:24,56:25,57:26,58:27,59:28,60:29,61:30,62:31,63:32,64:33,65:34,66:35,67:36,68:37,69:38,70:39,71:40,72:41,73:42,74:43,75:44,76:45,77:46,78:47,79:48,80:49,81:50,82:51,83:52,84:53,85:54,86:55,87:56,88:57,89:58,90:59,91:60,92:61,93:62,94:63,95:64,96:65,97:66,98:67,99:68,100:69,101:70,102:71,103:72,104:73,105:74,106:75,107:76,108:77,109:78,110:79,111:80,112:81,113:82,114:83,115:84,116:85,117:86,118:87,119:88,120:89,121:90,122:91,123:92,124:93,125:94,126:95,160:596,161:96,162:97,163:98,164:99,165:100,166:101,167:102,168:103,169:104,170:105,171:106,172:107,173:597,174:108,175:109,176:110,177:111,178:112,179:113,180:114,181:115,182:116,183:117,184:118,185:119,186:120,187:121,188:122,189:123,190:124,191:125,192:603,193:604,194:605,195:606,196:607,197:608,198:126,199:609,200:610,201:611,202:612,203:613,204:614,205:615,206:616,207:617,208:599,209:618,210:619,211:620,212:621,213:622,214:623,215:127,216:128,217:624,218:625,219:626,220:627,221:628,222:129,223:130,224:629,225:630,226:631,227:632,228:633,229:634,230:131,231:635,232:636,233:637,234:638,235:639,236:640,237:641,238:642,239:643,240:132,241:644,242:645,243:646,244:647,245:648,246:649,247:133,248:134,249:650,250:651,251:652,252:653,253:654,254:135,255:655,256:656,257:657,258:658,259:659,260:660,261:661,262:662,263:663,264:664,265:665,266:666,267:667,268:668,269:669,270:670,271:671,272:598,273:136,274:672,275:673,276:674,277:675,278:676,279:677,280:678,281:679,282:680,283:681,284:682,285:683,286:684,287:685,288:686,289:687,290:688,291:689,292:690,293:691,294:137,295:600,296:692,297:693,298:694,299:695,300:696,301:697,302:698,303:699,304:700,305:138,306:701,307:702,308:703,309:704,310:705,311:706,312:139,313:707,314:708,315:709,316:710,317:711,318:712,319:713,320:714,321:140,322:141,323:715,324:716,325:717,326:718,327:719,328:720,329:721,330:142,331:143,332:722,333:723,334:724,335:725,336:726,337:727,338:144,339:145,340:728,341:729,342:730,343:731,344:732,345:733,346:734,347:735,348:736,349:737,350:738,351:739,352:742,353:743,354:744,355:745,356:746,357:747,358:601,359:602,360:748,361:749,362:750,363:751,364:752,365:753,366:754,367:755,368:756,369:757,370:758,371:759,372:760,373:761,374:762,375:763,376:764,377:765,378:766,379:767,380:768,381:769,382:770,383:146,1024:897,1025:856,1026:165,1027:857,1028:166,1029:858,1030:859,1031:860,1032:861,1033:167,1034:168,1035:169,1036:863,1037:898,1038:864,1039:170,1040:865,1041:171,1042:866,1043:867,1044:172,1045:868,1046:173,1047:174,1048:175,1049:869,1050:862,1051:176,1052:870,1053:871,1054:872,1055:873,1056:874,1057:875,1058:876,1059:177,1060:178,1061:877,1062:179,1063:180,1064:181,1065:182,1066:183,1067:184,1068:185,1069:186,1070:187,1071:188,1072:878,1073:189,1074:190,1075:191,1076:192,1077:879,1078:193,1079:194,1080:195,1081:880,1082:196,1083:197,1084:198,1085:199,1086:881,1087:200,1088:882,1089:883,1090:201,1091:884,1092:202,1093:885,1094:203,1095:204,1096:205,1097:206,1098:207,1099:208,1100:209,1101:210,1102:211,1103:212,1104:899,1105:886,1106:213,1107:887,1108:214,1109:888,1110:889,1111:890,1112:891,1113:215,1114:216,1115:217,1116:892,1117:900,1118:893,1119:218,1120:219,1121:220,1122:965,1123:221,1124:222,1125:223,1126:224,1127:225,1128:226,1129:227,1130:228,1131:229,1132:230,1133:231,1134:232,1135:233,1136:901,1137:902,1138:234,1139:235,1140:236,1141:237,1142:903,1143:904,1144:906,1145:905,1146:238,1147:239,1148:240,1149:241,1150:242,1151:243,1152:244,1153:245,1154:246,1155:247,1156:248,1157:249,1158:250,1159:251,1160:252,1161:253,1162:254,1163:255,1164:964,1165:256,1166:257,1167:258,1168:259,1169:260,1170:966,1171:967,1172:261,1173:262,1174:263,1175:264,1176:907,1177:908,1178:265,1179:266,1180:267,1181:268,1182:968,1183:969,1184:269,1185:270,1186:271,1187:272,1188:273,1189:274,1190:275,1191:276,1192:277,1193:278,1194:909,1195:910,1196:955,1197:956,1198:911,1199:912,1200:970,1201:971,1202:279,1203:280,1204:281,1205:282,1206:283,1207:284,1208:285,1209:286,1210:287,1211:963,1212:288,1213:289,1214:961,1215:962,1216:913,1217:914,1218:915,1219:290,1220:291,1221:292,1222:293,1223:294,1224:295,1225:296,1226:297,1227:957,1228:958,1229:298,1230:299,1231:916,1232:917,1233:918,1234:919,1235:920,1236:921,1237:922,1238:923,1239:924,1240:300,1241:926,1242:925,1243:927,1244:928,1245:929,1246:930,1247:931,1248:301,1249:302,1250:932,1251:933,1252:934,1253:935,1254:936,1255:937,1256:938,1257:939,1258:940,1259:941,1260:942,1261:943,1262:944,1263:945,1264:946,1265:947,1266:948,1267:949,1268:950,1269:951,1270:959,1271:960,1272:952,1273:953,1274:303,1275:304,1276:305,1277:306,1278:972,1279:973,1280:307,1281:954,1282:308,1283:309,1284:310,1285:311,1286:312,1287:313,1288:314,1289:315,1290:316,1291:317,1292:318,1293:319,1294:320,1295:321,1296:322,1297:974,1298:323,1299:324,1300:325,1301:326,1302:327,1303:328,1304:329,1305:330,1306:982,1307:983,1308:984,1309:985,1310:331,1311:332,1312:333,1313:334,1314:335,1315:336,1316:337,1317:338,1318:339,1319:340,1320:341,1321:342,1322:343,1323:344,1324:345,1325:346,1326:347,1327:348,8192:349,8193:350,8194:351,8195:352,8196:353,8197:354,8198:355,8199:356,8200:357,8201:358,8202:360,8203:361,8204:362,8205:363,8206:364,8207:365,8208:366,8209:367,8210:368,8211:369,8212:370,8213:975,8214:371,8215:372,8216:373,8217:374,8218:375,8219:376,8220:377,8221:378,8222:379,8223:380,8224:381,8225:382,8226:383,8227:384,8228:385,8229:386,8230:387,8231:388,8239:986,8240:389,8241:390,8242:894,8243:895,8244:391,8245:392,8246:393,8247:394,8248:395,8249:396,8250:397,8251:398,8252:896,8253:399,8254:400,8255:401,8256:402,8257:403,8258:404,8259:405,8260:406,8261:407,8262:408,8263:987,8264:988,8265:989,8266:409,8267:410,8268:411,8269:412,8270:413,8271:414,8272:415,8273:416,8274:417,8275:418,8276:419,8277:420,8278:421,8279:422,8280:423,8281:424,8282:425,8283:426,8284:427,8285:428,8286:429,8287:990,8364:430,8381:431,8776:433},HA={1:507,2:527,3:655,4:1261,5:1150,6:1500,7:1273,8:357,9:700,10:712,11:882,12:1161,13:402,14:565,15:539,16:844,17:1150,18:1150,19:1150,20:1150,21:1150,22:1150,23:1150,24:1150,25:1150,26:1150,27:496,28:433,29:1041,30:1124,31:1070,32:967,33:1839,34:1336,35:1275,36:1333,37:1343,38:1164,39:1132,40:1395,41:1460,42:557,43:1130,44:1284,45:1102,46:1788,47:1460,48:1408,49:1292,50:1408,51:1261,52:1215,53:1222,54:1328,55:1303,56:1817,57:1284,58:1230,59:1226,60:543,61:840,62:543,63:856,64:924,65:633,66:1114,67:1149,68:1072,69:1155,70:1085,71:711,72:1149,73:1128,74:497,75:489,76:1038,77:497,78:1795,79:1130,80:1168,81:1149,82:1164,83:693,84:1056,85:669,86:1129,87:992,88:1539,89:1015,90:969,91:1015,92:693,93:499,94:693,95:1393,96:499,97:1120,98:1190,99:1460,100:1075,101:491,102:1256,103:856,104:1609,105:915,106:961,107:1134,108:1610,109:938,110:765,111:1094,112:751,113:751,114:642,115:1160,116:1001,117:534,118:507,119:751,120:931,121:960,122:1500,123:1589,124:1593,125:969,126:1914,127:1092,128:1408,129:1210,130:1218,131:1729,132:1200,133:1169,134:1160,135:1180,136:1223,137:1434,138:506,139:1139,140:1103,141:553,142:1419,143:1160,144:1953,145:1860,146:508,165:1535,166:1380,167:2193,168:2212,169:1666,170:1460,171:1291,172:1540,173:1859,174:1215,175:1460,176:1449,177:1287,178:1580,179:1497,180:1402,181:1927,182:1984,183:1554,184:1771,185:1285,186:1380,187:1831,188:1304,189:1132,190:1170,191:859,192:1236,193:1568,194:1040,195:1182,196:1106,197:1184,198:1519,199:1181,200:1182,201:984,202:1485,203:1213,204:1113,205:1656,206:1694,207:1271,208:1590,209:1112,210:1101,211:1671,212:1124,213:1128,214:1101,215:1737,216:1764,217:1161,218:1182,219:1800,220:1579,221:1110,222:1835,223:1528,224:1234,225:1094,226:1803,227:1547,228:1745,229:1505,230:2308,231:2001,232:1059,233:987,234:1393,235:1163,236:1290,237:1027,238:1393,239:1160,240:1793,241:1572,242:1800,243:1579,244:1330,245:1095,246:1277,247:1024,248:1024,249:1024,250:1024,251:1024,252:1024,253:1024,254:1545,255:1261,256:1110,257:1307,258:1161,259:1123,260:912,261:1243,262:1029,263:1954,264:1633,265:1434,266:1208,267:1289,268:1150,269:1676,270:1411,271:1535,272:1241,273:1999,274:1460,275:2097,276:1780,277:1518,278:1235,279:1304,280:1066,281:1836,282:1372,283:1468,284:1174,285:1391,286:1130,287:1391,288:1583,289:1213,290:1289,291:1114,292:1534,293:1263,294:1458,295:1160,296:1554,297:1260,298:1871,299:1598,300:1415,301:1192,302:1192,303:1207,304:939,305:1326,306:1088,307:1270,308:1684,309:1764,310:1622,311:1323,312:1097,313:1031,314:1985,315:1653,316:2043,317:1697,318:1270,319:1053,320:1453,321:1312,322:1380,323:1538,324:1266,325:1920,326:1549,327:1857,328:1547,329:1926,330:1774,331:1316,332:1106,333:2274,334:1832,335:2300,336:1829,337:1526,338:1242,339:1468,340:1208,341:1539,342:1273,343:2710,344:2238,345:1568,346:1240,347:1515,348:1243,349:1044,350:2089,351:1044,352:2089,353:697,354:522,355:348,356:1151,357:560,358:418,360:209,361:1024,362:1024,363:1024,364:1024,365:1024,366:564,367:564,368:1171,369:1344,370:1599,371:778,372:933,373:409,374:409,375:407,376:409,377:724,378:731,379:705,380:764,381:1129,382:1167,383:690,384:1100,385:511,386:964,387:1370,388:382,389:1962,390:2360,391:1045,392:463,393:757,394:1045,395:803,396:614,397:614,398:1241,399:919,400:952,401:1540,402:1540,403:874,404:1370,405:870,406:931,407:640,408:641,409:907,410:1001,411:1237,412:1237,413:985,414:511,415:1541,416:985,417:931,418:1366,419:1540,420:1172,421:932,422:1333,423:1215,424:1125,425:379,426:1071,427:1162,428:379,429:379,430:1150,431:1359,433:1154,596:507,597:565,598:1373,599:1373,600:1158,601:1222,602:669,603:1336,604:1336,605:1336,606:1336,607:1336,608:1336,609:1333,610:1164,611:1164,612:1164,613:1164,614:557,615:557,616:557,617:557,618:1460,619:1408,620:1408,621:1408,622:1408,623:1408,624:1328,625:1328,626:1328,627:1328,628:1230,629:1114,630:1114,631:1114,632:1114,633:1114,634:1114,635:1072,636:1085,637:1085,638:1085,639:1085,640:506,641:506,642:506,643:506,644:1130,645:1168,646:1168,647:1168,648:1168,649:1168,650:1129,651:1129,652:1129,653:1129,654:969,655:969,656:1336,657:1114,658:1336,659:1114,660:1336,661:1114,662:1333,663:1072,664:1333,665:1072,666:1333,667:1072,668:1333,669:1072,670:1343,671:1305,672:1164,673:1085,674:1164,675:1085,676:1164,677:1085,678:1164,679:1085,680:1164,681:1085,682:1395,683:1149,684:1395,685:1149,686:1395,687:1149,688:1395,689:1149,690:1460,691:1128,692:557,693:506,694:557,695:506,696:557,697:506,698:557,699:497,700:557,701:1687,702:986,703:1130,704:515,705:1284,706:1038,707:1102,708:497,709:1102,710:497,711:1102,712:647,713:1102,714:717,715:1460,716:1130,717:1460,718:1130,719:1460,720:1130,721:1130,722:1408,723:1168,724:1408,725:1168,726:1408,727:1168,728:1261,729:693,730:1261,731:693,732:1261,733:693,734:1215,735:1056,736:1215,737:1056,738:1215,739:1056,742:1215,743:1056,744:1222,745:669,746:1222,747:709,748:1328,749:1129,750:1328,751:1129,752:1328,753:1129,754:1328,755:1129,756:1328,757:1129,758:1328,759:1129,760:1817,761:1539,762:1230,763:969,764:1230,765:1226,766:1015,767:1226,768:1015,769:1226,770:1015,856:1164,857:1139,858:1215,859:557,860:557,861:1130,862:1316,863:1284,864:1287,865:1336,866:1275,867:1139,868:1164,869:1460,870:1788,871:1460,872:1408,873:1461,874:1292,875:1333,876:1222,877:1284,878:1114,879:1085,880:1182,881:1168,882:1149,883:1072,884:969,885:1015,886:1085,887:859,888:1056,889:497,890:506,891:489,892:1106,893:969,894:357,895:655,896:1054,897:1164,898:1460,899:1085,900:1182,901:1417,902:1434,903:1290,904:1027,905:2137,906:2377,907:1215,908:1040,909:1333,910:1072,911:1230,912:1026,913:557,914:1859,915:1568,916:557,917:1336,918:1114,919:1336,920:1114,921:1914,922:1729,923:1164,924:1085,925:1415,926:1079,927:1079,928:1859,929:1568,930:1215,931:1040,932:1460,933:1182,934:1460,935:1182,936:1408,937:1168,938:1393,939:1163,940:1393,941:1163,942:1380,943:1101,944:1287,945:969,946:1287,947:969,948:1287,949:969,950:1402,951:1113,952:1771,953:1590,954:1155,955:1222,956:984,957:1402,958:1113,959:1139,960:859,961:1583,962:1213,963:1128,964:1285,965:1285,966:1139,967:859,968:1336,969:1063,970:1230,971:1026,972:1284,973:1015,974:1104,975:1599,982:1408,983:1164,984:1817,985:1539,986:507,987:1934,988:1494,989:1494,990:507},vA=new TextEncoder,VA=A=>{const B=Math.round(100*A)/100;return Number.isInteger(B)?String(B):B.toFixed(2).replace(/0+$/,"")},UA=A=>{const B=Math.round(1e6*A)/1e6;return Number.isInteger(B)?String(B):B.toFixed(6).replace(/0+$/,"")},lA=A=>A.map(UA).join(" ");function aA(A){let B="",E=0;const s=new Map;for(const w of A){const A=w.codePointAt(0)||0,Q=rA[A]||rA[63];B+=Q.toString(16).padStart(4,"0"),E+=HA[Q]||1024,s.has(Q)||s.set(Q,A||63)}return{hex:B,width:E,unicode:s}}function PA(A,B){return aA(A).width*B/hA}function yA(A,B=PA(A.text,A.size)){const E=A.align||"left",s="center"===E?B/2:"right"===E?B:0,w=(A.angle||0)*Math.PI/180,Q=Math.cos(w),C=Math.sin(w);return{width:B,baselineX:A.x-Q*s,baselineY:A.y+C*s,cos:Q,sin:C}}function uA(A){const B=yA(A),E=-555*A.size/hA,s=SA*A.size/hA,w=[0,B.width].flatMap(A=>[E,s].map(E=>({x:B.baselineX+B.cos*A-B.sin*E,y:B.baselineY-B.sin*A-B.cos*E})));return{minX:Math.min(...w.map(A=>A.x)),minY:Math.min(...w.map(A=>A.y)),maxX:Math.max(...w.map(A=>A.x)),maxY:Math.max(...w.map(A=>A.y))}}function NA(A){const B=A.reduce((A,B)=>A+B.length,0),E=new Uint8Array(B);let s=0;for(const B of A)E.set(B,s),s+=B.length;return E}const KA=A=>vA.encode(A),dA=(A,B)=>NA([KA(`<< ${A} /Length ${B.length} >>\nstream\n`),B,KA("\nendstream")]);function JA(A){const B=function(A){const B=atob(A),E=new Uint8Array(B.length);for(let A=0;A"image"===A.kind&&null!=A.opacity&&A.opacity<1?[Math.max(0,Math.min(1,A.opacity))]:[]))].sort((A,B)=>A-B),s=new Map(E.map((A,B)=>[A,`GS${B+1}`])),w=function(A,B){const E=[],s=new Map,w=B=>A.height-B,Q=(A,...B)=>`${B.map(VA).join(" ")} ${A}`,C=A=>{for(const B of A)if(B.length){E.push(Q("m",B[0][0],w(B[0][1])));for(let A=1;A{let B=!1;for(const s of A)if(!(s.length<2)){B=!0,E.push(Q("m",s[0][0],w(s[0][1])));for(let A=1;A Tj`,"ET")}else{const A=(I.angle||0)*Math.PI/180,s=Math.cos(A),C=Math.sin(A),g=I.x+I.width/2,Y=w(I.y+I.height/2);E.push("q");const R=null==I.opacity?1:Math.max(0,Math.min(1,I.opacity)),M=B.get(R);M&&E.push(`/${M} gs`),E.push(Q("cm",s*I.width,C*I.width,C*I.height,-s*I.height,g-s*I.width/2-C*I.height/2,Y-C*I.width/2+s*I.height/2),`/Im${I.imageId} Do`,"Q")}return{stream:E.join("\n"),unicode:s}}(A,s),Q=Math.max(0,...Object.keys(HA).map(Number)),C=Array.from({length:Q+1},(A,B)=>Math.round(1e3*(HA[B]||1024)/hA)),g=[],I=A=>(g.push("string"==typeof A?KA(A):A),g.length),Y=I(""),R=I(""),M=I(""),F=I(dA(`/Length1 ${B.length}`,B)),i=I(`<< /Type /FontDescriptor /FontName /Roboto /Flags 32 /FontBBox [${jA.join(" ")}] /ItalicAngle 0 /Ascent 2146 /Descent -555 /CapHeight 2146 /StemV 80 /FontFile2 ${F} 0 R >>`),x=I(`<< /Type /Font /Subtype /CIDFontType2 /BaseFont /Roboto /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor ${i} 0 R /W [0 [${C.join(" ")}]] /CIDToGIDMap /Identity >>`),b=KA(function(A){const B=[...A].sort((A,B)=>A[0]-B[0]),E=B.map(([A,B])=>`<${A.toString(16).padStart(4,"0")}> <${B<=65535?B.toString(16).padStart(4,"0"):(()=>{const A=B-65536;return(55296+(A>>10)).toString(16).padStart(4,"0")+(56320+(1023&A)).toString(16).padStart(4,"0")})()}>`);return`/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def\n/CMapName /HousePlanUnicode def\n/CMapType 2 def\n1 begincodespacerange\n<0000> \nendcodespacerange\n${B.length} beginbfchar\n${E.join("\n")}\nendbfchar\nendcmap\nCMapName currentdict /CMap defineresource pop\nend\nend`}(w.unicode)),L=I(dA("",b)),D=I(`<< /Type /Font /Subtype /Type0 /BaseFont /Roboto /Encoding /Identity-H /DescendantFonts [${x} 0 R] /ToUnicode ${L} 0 R >>`),G=I(dA("",KA(w.stream))),o=[];for(const B of A.images||[]){const A=I(dA(`/Type /XObject /Subtype /Image /Width ${B.width} /Height ${B.height} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode`,B.bytes));o.push(`/Im${B.id} ${A} 0 R`)}const t=A.now.toISOString().replace(/[-:T]/g,"").slice(0,14),c=I(`<< /CreationDate (D:${t}Z) /ModDate (D:${t}Z) >>`),W=`<< /Font << /F1 ${D} 0 R >>`+(o.length?` /XObject << ${o.join(" ")} >>`:"")+(E.length?` /ExtGState << ${E.map(A=>`/${s.get(A)} << /ca ${VA(A)} /CA ${VA(A)} >>`).join(" ")} >>`:"")+" >>";g[Y-1]=KA(`<< /Type /Catalog /Pages ${R} 0 R >>`),g[R-1]=KA(`<< /Type /Pages /Kids [${M} 0 R] /Count 1 >>`),g[M-1]=KA(`<< /Type /Page /Parent ${R} 0 R /MediaBox [0 0 ${VA(A.width)} ${VA(A.height)}] /Resources ${W} /Contents ${G} 0 R >>`);const m=KA("%PDF-1.4\n%âãÏÓ\n"),n=[m],e=[0];let h=m.length;g.forEach((A,B)=>{const E=KA(`${B+1} 0 obj\n`),s=KA("\nendobj\n");e.push(h),n.push(E,A,s),h+=E.length+A.length+s.length});const S=h,j=["xref",`0 ${g.length+1}`,"0000000000 65535 f "];for(let A=1;A<=g.length;A++)j.push(`${String(e[A]).padStart(10,"0")} 00000 n `);return j.push(`trailer\n<< /Size ${g.length+1} /Root ${Y} 0 R /Info ${c} 0 R >>`,`startxref\n${S}\n%%EOF\n`),n.push(KA(j.join("\n"))),NA(n)}const ZA=A=>[A.minX,A.minY,A.maxX,A.maxY].every(Number.isFinite)&&A.maxX>=A.minX&&A.maxY>=A.minY,TA=A=>A.maxX-A.minX,fA=A=>A.maxY-A.minY;function kA(A,B,E,s=0){Number.isFinite(B)&&Number.isFinite(E)&&(A.minX=Math.min(A.minX,B-s),A.minY=Math.min(A.minY,E-s),A.maxX=Math.max(A.maxX,B+s),A.maxY=Math.max(A.maxY,E+s))}function zA(A,B,E,s,w,Q){const C=Q*Math.PI/180,g=Math.cos(C),I=Math.sin(C),Y=B+s/2,R=E+w/2;for(const[B,E]of[[-s/2,-w/2],[s/2,-w/2],[s/2,w/2],[-s/2,w/2]])kA(A,Y+g*B-I*E,R+I*B+g*E)}function pA(A,B,E){for(const s of B)"M"===s.op||"L"===s.op?kA(A,s.x,s.y,E):"C"===s.op&&(kA(A,s.x1,s.y1,E),kA(A,s.x2,s.y2,E),kA(A,s.x,s.y,E))}function XA(A){const B={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};for(const E of A)if("path"===E.kind){const A=E.stroke?(E.width||.5)/2:0;for(const s of E.rings)for(const[E,w]of s)kA(B,E,w,A)}else if("line"===E.kind)for(const[A,s]of E.points)kA(B,A,s,E.width/2);else if("vector"===E.kind)pA(B,E.ops,E.width/2);else if("text"===E.kind){const A=uA(E);kA(B,A.minX,A.minY),kA(B,A.maxX,A.maxY)}else zA(B,E.x,E.y,E.width,E.height,E.angle||0);return B}function OA(A,B,E){return!!ZA(A)&&(TA(A)<=TA(B)+E&&fA(A)<=fA(B)+E)}function qA(A){return`${A.getFullYear()}-${String(A.getMonth()+1).padStart(2,"0")}-${String(A.getDate()).padStart(2,"0")}`}const $A=72/25.4,_A=5.25,AB=[.08,.08,.08],BB=[127/255,127/255,127/255],EB=[.72,.72,.72],sB=(A,B)=>A.minXB.minX&&A.minYB.minY;function wB(A,B,E,s,w=0,Q="left"){return uA({x:A,y:B,text:E,size:s,angle:w,align:Q})}function QB(A,B,E,s,w){const Q=Math.min(...[[A.minX,A.minY],[A.maxX,A.minY],[A.maxX,A.maxY],[A.minX,A.maxY]].map(([A,w])=>(A-B)*s[0]+(w-E)*s[1]));return Math.max(0,w-Q)}const CB=(A,B)=>`${A.axis}:${B[0]<-.5||B[1]<-.5?-1:1}`,gB=(A,B)=>{A.minX=Math.min(A.minX,B[0]),A.minY=Math.min(A.minY,B[1]),A.maxX=Math.max(A.maxX,B[0]),A.maxY=Math.max(A.maxY,B[1])},IB=A=>{const B={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};for(const E of A)for(const A of E)gB(B,A);return B};function YB(A,B,E,s,w=0){const Q=w*Math.PI/180,C=Math.cos(Q),g=Math.sin(Q),I=A+E/2,Y=B+s/2;return Array.from({length:48},(A,B)=>{const w=B/48*Math.PI*2,Q=Math.cos(w)*E/2,R=Math.sin(w)*s/2;return[I+C*Q-g*R,Y+g*Q+C*R]})}function RB(A,B,E,s,w=0){const Q=w*Math.PI/180,C=Math.cos(Q),g=Math.sin(Q),I=A+E/2,Y=B+s/2;return[[-E/2,-s/2],[E/2,-s/2],[E/2,s/2],[-E/2,s/2]].map(([A,B])=>[I+C*A-g*B,Y+g*A+C*B])}function MB(A,B,E){if("passage"===A.type)return[];const s=A.rlen/2,w=B>0?B/E*Y/2:2,Q=[];if("window"===A.type)Q.push([[-s,-w],[s,-w]],[[-s,w],[s,w]],[[-s,-w],[-s,w]],[[s,-w],[s,w]]);else if("gate"===A.type){const B=10*(A.flip_v?-1:1)*Math.PI/180,E=[[[-s,0],[-s+Math.cos(B)*s,Math.sin(B)*s]],[[s,0],[s-Math.cos(B)*s,Math.sin(-B)*s]]];Q.push(...E);for(const A of E){const B=A[1][0]-A[0][0],E=A[1][1]-A[0][1],s=Math.hypot(B,E)||1,C=-E/s,g=B/s,I=Math.min(.08*s,Math.max(1,.7*w));for(const s of[.3,.5,.7]){const w=A[0][0]+B*s,Y=A[0][1]+E*s;Q.push([[w-C*I,Y-g*I],[w+C*I,Y+g*I]])}}}else{const B=A.flip_v?1:-1,E=A.flip_h?s:-s,w=[E,B*A.rlen];Q.push([[E,0],w]);const C=[];for(let s=0;s<=16;s++){const w=B*s/16*Math.PI/2,Q=A.flip_h?-1:1;C.push([E+Q*Math.cos(w)*A.rlen,Math.sin(w)*A.rlen])}Q.push(C)}const C=A.angle*Math.PI/180,g=Math.cos(C),I=Math.sin(C);return Q.map(B=>B.map(([B,E])=>[A.rx+B*g-E*I,A.ry+B*I+E*g]))}function FB(A,B){const E=IB([A]);return B.filter(A=>{const B=IB([A]);return B.maxX>=E.minX&&B.minX<=E.maxX&&B.maxY>=E.minY&&B.minY<=E.maxY})}function iB(A){const B=function(A){const{rawSpace:B,space:E}=A,s=Number(B.cell_cm)>0?Number(B.cell_cm):5,w=Array.isArray(B.walls)?B.walls:[],Q=c(B,E,I,.02*Y),C=W(B,E,s,Y,I),g=m(C),M=n(E,s,Y,2e-4*Y,g).all,F=e(C,E,w,Q.contour,R,s,Y,I);return{cellCm:s,walls:w,zero:Q,openings:C,extras:M,geometry:A.sharedWallGeometry||h(E.rooms,w,Q.contour,F,R,s,Y,I,M)}}(A),E=new Map;if(A.options.dimensions)for(const s of A.space.rooms){const w=C(s);if(!w)continue;const Q=s.id?A.resolveInnerContour?.(s.id):void 0;E.set(s,s.id&&(void 0===Q?g(A.space.rooms,s.id,B.walls,B.zero.contour,R,B.cellCm,Y,I,B.geometry.roomGeom,B.geometry.multiWallNodes):Q)||w)}const s=new Map;if(A.options.dimensions)for(const w of A.space.rooms){const Q=C(w);if(!Q)continue;const g=E.get(w)||Q,I=w.id?A.resolveRoomArea?.(w.id,g):void 0,Y=Number.isFinite(I)?[]:FB(g,B.extras),R=Y.length?M(g,Y):null,i=Number.isFinite(I)&&I>=0?I:R?F(R):Math.abs(g.reduce((A,B,E)=>{const s=g[(E+1)%g.length];return A+B[0]*s[1]-s[0]*B[1]},0)/2);s.set(w,i)}const w=[..."failed-core"===B.geometry.status?A.space.rooms.map(A=>C(A)||[]).filter(A=>A.length):B.geometry.components.flatMap(A=>i(A.geom)),...B.zero.lines.map(A=>[[A[0],A[1]],[A[2],A[3]]])];A.options.decor&&w.push(...function(A){const B=[];for(const E of A.decor||[])"line"===E.kind?B.push([[E.x1*I,E.y1*I],[E.x2*I,E.y2*I]]):"text"!==E.kind?B.push(L(E).map(([A,B])=>[A*I,B*I])):B.push([[E.x*I,E.y*I]]);return B}(A.rawSpace));for(const B of A.rasters||[])w.push(RB(B.x,B.y,B.drawWidth,B.drawHeight,B.angle));let Q=IB(w);var x;[(x=Q).minX,x.minY,x.maxX,x.maxY].every(Number.isFinite)&&x.maxX>x.minX&&x.maxY>x.minY||(Q={minX:0,minY:0,maxX:I,maxY:I});return{built:B,dimensionContours:E,roomAreas:s,bounds:Q,cmPerUnit:B.cellCm/Y}}function xB(A,B,E,s){const{built:w,dimensionContours:Q,roomAreas:g,bounds:M,cmPerUnit:F}=B,c=(s?297:210)*$A,W=(s?210:297)*$A,m=12*$A,n=18*$A,e=24*$A,h=F*(10*$A)/E,j=(M.maxX-M.minX)*h,H=(M.maxY-M.minY)*h,v=m+n,V=W-v-m-e,U=c-2*m,a=A=>[0+(A[0]-M.minX)*h,0+(A[1]-M.minY)*h],P=(A,B)=>[M.minX+(A-0)/h,M.minY+(B-0)/h],y=A=>{const B=P(A.minX,A.minY),E=P(A.maxX,A.maxY);return{minX:B[0],minY:B[1],maxX:E[0],maxY:E[1]}},u=w.geometry.components.flatMap(A=>i(A.geom)),N=A=>w.geometry.components.some(B=>S([...A],B.geom)),K=A=>function(A,B,E){if(!LA(A)||!mA(B))return!0;const s=DA(A);return!!s.some(E)||!!B.some(B=>B.some(B=>xA(B)&&bA(B,A)))||nA(B,(A,B)=>s.some((E,w)=>null!==WA(A,B,E,s[(w+1)%s.length])))}(y(function(A,B){const E=Number.isFinite(B)&&B>=0?B:0;return{minX:A.minX-E,minY:A.minY-E,maxX:A.maxX+E,maxY:A.maxY+E}}(A,$A-1e-6)),u,N),d=(A,B)=>function(A,B,E){if(!LA(A)||!mA([B]))return!1;const s=DA(A);return!!s.every(E)&&!nA([B],(A,B)=>s.some((E,w)=>null!==WA(A,B,E,s[(w+1)%s.length])))}(y(A),B,A=>Z([...A],B)),J=(A,B,E={})=>function(A,B,E,s,w={}){if(!xA(A)||!xA(B)||!mA(E))return!0;if(w.allowStartExit){const w=tA(A,B);if(w<=iA)return!0;const Q=nA(E,(B,E)=>cA(A,B,E));if(!Q)return!0;const C=[];nA(E,(E,s)=>{const w=WA(A,B,E,s);return w&&C.push(w),!1});const g=iA/w,I=[0,1,...C.flatMap(A=>[A.t,A.endT])].sort((A,B)=>A-B).filter((A,B,E)=>0===B||A-E[B-1]>g),Y=E=>[A[0]+(B[0]-A[0])*E,A[1]+(B[1]-A[1])*E],R=A=>C.some(B=>B.overlap&&A>B.t+g&&AA.t>M+g||A.endT>M+g)}const Q=[(A[0]+B[0])/2,(A[1]+B[1])/2],C=nA(E,(B,E)=>cA(A,B,E));return!((!s(A)||w.allowStartBoundary&&C)&&!s(Q)&&!s(B))||nA(E,(E,s)=>{const Q=WA(A,B,E,s);return!!Q&&(Q.overlap||!w.allowStartBoundary||!C||Q.t*tA(A,B)>iA)})}(P(A[0],A[1]),P(B[0],B[1]),u,N,E),T=(A,B,E)=>{const s=A.x*I,w=A.y*I,Q=A.w*I,C=A.h*I,g=s+Q/2,Y=w+C/2,R=s+(A.flip_h?Q:0),F=w+(A.flip_v?C:0),i=(A.flip_h?-1:1)*Q/B,x=(A.flip_v?-1:1)*C/E,b=(Number(A.angle)||0)*Math.PI/180,L=Math.cos(b),D=Math.sin(b),G=Y+D*(R-g)+L*(F-Y);return{a:h*L*i,b:h*D*i,c:-h*D*x,d:h*L*x,e:0+(g+L*(R-g)-D*(F-Y)-M.minX)*h,f:0+(G-M.minY)*h}};let f=[];const z=[],O=function(A,B){const E=3*$A*Math.SQRT2,s=[];for(let w=-B;w<=A+E;w+=E)s.push([[w,0],[w+B,B]]);return s}(c,W);for(const B of A.rasters||[])f.push({kind:"image",imageId:B.id,...a([B.x,B.y]).reduce((A,B,E)=>({...A,[E?"y":"x"]:B}),{}),width:B.drawWidth*h,height:B.drawHeight*h,angle:B.angle,opacity:B.opacity});for(const A of w.geometry.components)f.push({kind:"path",rings:i(A.geom).map(A=>A.map(a)),fill:BB,stroke:AB,width:.25*$A,hatch:{lines:O,stroke:AB,width:.18*$A}});if("failed-core"===w.geometry.status)for(const B of A.space.rooms){const A=C(B);A&&f.push({kind:"path",rings:[A.map(a)],stroke:AB,width:.25*$A})}for(const A of w.zero.lines)f.push({kind:"line",points:[a([A[0],A[1]]),a([A[2],A[3]])],stroke:AB,width:.35*$A,dash:[3*$A,2*$A]});const q=w.geometry.openingIndex;for(const B of w.openings){const E=B.partitionHost?{cm:B.partitionHost.partition.cm}:q?x(A.space.rooms,B,w.walls,R,w.cellCm,Y,I,w.zero.contour):{cm:0};for(const A of MB(B,E.cm,w.cellCm))f.push({kind:"line",points:A.map(a),stroke:AB,width:.3*$A})}if(A.options.decor)for(const B of A.rawSpace.decor||[])if("image"!==B.kind)if("line"===B.kind)f.push({kind:"line",points:[a([B.x1*I,B.y1*I]),a([B.x2*I,B.y2*I])],stroke:AB,width:Math.max(.2*$A,10*Number(B.width_cm||1)*$A/E),dash:"dashed"===B.line_style?[3*$A,2*$A]:void 0});else if("text"===B.kind)f.push({kind:"text",...(()=>{const[A,E]=a([B.x*I,B.y*I]);return{x:A,y:E}})(),text:B.text,size:Math.max(6,10*Number(B.size_cm||20)*$A/E),angle:Number(B.angle)||0});else if("furniture"===B.kind){const A=r[B.symbol];A?f.push({kind:"vector",ops:YA(A.d,T(B,A.viewW,A.viewH)),stroke:AB,width:Math.max(.2*$A,10*b(B,w.cellCm,Y)*$A/E)}):f.push({kind:"path",rings:[L(B).map(([A,B])=>a([A*I,B*I]))],stroke:AB,width:.25*$A})}else{const A="ellipse"===B.kind?YB(B.x*I,B.y*I,B.w*I,B.h*I,Number(B.angle)||0):L(B).map(([A,B])=>[A*I,B*I]);f.push({kind:"path",rings:[A.map(a)],stroke:AB,width:.25*$A})}if(A.options.dimensions&&w.geometry.roomGeom)for(const[B,E]of D(w.geometry.roomGeom).entries()){const s=l(F),w=(A,B,E)=>{const s=a(A.sourceA),w=a(A.sourceB),Q=a(A.a),C=a(A.b),g=(6+E)*$A,I=[Q[0]+B[0]*g,Q[1]+B[1]*g],Y=[C[0]+B[0]*g,C[1]+B[1]*g],R=[(I[0]+Y[0])/2,(I[1]+Y[1])/2],M=PA(A.text,7)+2*$A>Math.hypot(Y[0]-I[0],Y[1]-I[1]),F=QB(wB(R[0],R[1],A.text,7,A.angle,"center"),R[0],R[1],B,$A),i=[R[0]+B[0]*F,R[1]+B[1]*F];return{edge:A,a:s,b:w,oa:I,ob:Y,middle:R,label:i,box:wB(i[0],i[1],A.text,7,A.angle,"center"),needsShelf:M}},Q=A=>{const B=[{start:A.oa,end:A.ob},{start:A.a,end:A.oa,allowStartExit:!0},{start:A.b,end:A.ob,allowStartExit:!0}];return A.needsShelf&&B.push({start:A.middle,end:A.label,mayEnterOwnLabel:!0}),B},C=A=>K(A.box)||Q(A).some(A=>J(A.start,A.end,{allowStartBoundary:A.allowStartBoundary,allowStartExit:A.allowStartExit})),g=EA(k(E,F,A.imperial,{ringIndex:B,epsilon:s}),{ring:E,epsilon:s,score:A=>{const B=[-A.inwardNormal[0],-A.inwardNormal[1]],E=a(A.mid),s=Array.from({length:21},(A,B)=>4*B).find(E=>!C(w(A,B,E))),Q=E[0]+(U-j)/2,g=E[1]+(V-H)/2;return{hardCollisions:void 0===s?21:s/4,normalClearance:Math.abs(B[0])>.5?B[0]>0?U-Q:Q:B[1]>0?V-g:g}}});for(const A of X(g,s)){const B=A.map(A=>({edge:A,outward:[-A.inwardNormal[0],-A.inwardNormal[1]]})),E=A=>B.map(({edge:B,outward:E})=>w(B,E,A));let s=null;for(let A=0;A<=80&&!s;A+=4){const B=E(A),w=B.some((A,E)=>B.slice(0,E).some(B=>sB(A.box,B.box))),g=B.some(A=>C(A)||z.some(B=>sB(A.box,B))),I=B.some((A,E)=>Q(A).some(A=>z.some(B=>eA(A.start,A.end,B))||B.some((B,s)=>(!A.mayEnterOwnLabel||s!==E)&&eA(A.start,A.end,B.box))));w||g||I||(s=B)}if(s)for(const A of s)f.push({kind:"line",points:[A.oa,A.ob],stroke:AB,width:.2*$A},{kind:"line",points:[A.a,A.oa],stroke:AB,width:.15*$A},{kind:"line",points:[A.b,A.ob],stroke:AB,width:.15*$A}),A.needsShelf&&f.push({kind:"line",points:[A.middle,A.label],stroke:AB,width:.15*$A}),f.push({kind:"text",x:A.label[0],y:A.label[1],text:A.edge.text,size:_A,angle:A.edge.angle,align:"center"}),z.push(A.box)}}const $=[...A.space.rooms].sort((A,B)=>String(A.id||"").localeCompare(String(B.id||"")));for(const[B,E]of $.entries()){const s=C(E);if(!s)continue;const w=Q.get(E)||s,I=g.get(E)||0,Y=G(E,A.space.id,A.layout,A.config),[R,M]=a([Y.x,Y.y]),i=w.map(a),x=IB([i]);let b=!1;if(A.options.roomNames&&E.name){const A=Math.max(0,x.maxX-x.minX-4*$A),B=PA(E.name,6.75)<=A?6.75:PA(E.name,5.25)<=A?5.25:0;B&&(f.push({kind:"text",x:R,y:M-2,text:E.name,size:B,align:"center"}),z.push(wB(R,M-2,E.name,B,0,"center")),b=!0)}if(A.options.dimensions){const B=o(I*F*F/1e4,A.imperial),E=M+(b?8:0);f.push({kind:"text",x:R,y:E,text:B,size:6,align:"center"}),z.push(wB(R,E,B,8,0,"center"))}if(A.options.dimensions){const E=l(F),s=EA(p(w,F,A.imperial,{ringIndex:B,epsilon:E}),{ring:w,epsilon:E,score:A=>{const B=a(A.mid),E=QB(wB(B[0],B[1],A.text,_A,A.angle,"center"),B[0],B[1],A.inwardNormal,$A),s=wB(B[0]+A.inwardNormal[0]*E,B[1]+A.inwardNormal[1]*E,A.text,7,A.angle,"center"),w="horizontal"===A.axis?A.inwardNormal[1]>0?x.maxY-B[1]:B[1]-x.minY:A.inwardNormal[0]>0?x.maxX-B[0]:B[0]-x.minX;return{hardCollisions:Number(K(s))+z.reduce((A,B)=>A+Number(sB(s,B)),0),normalClearance:w}}});for(const A of s.filter(A=>A.short)){const B=A.inwardNormal,E=a(A.a),s=a(A.b),w=(E[0]+s[0])/2,Q=(E[1]+s[1])/2;f.push({kind:"line",points:[[w-1.5*B[0]*$A,Q-1.5*B[1]*$A],[w+1.5*B[0]*$A,Q+1.5*B[1]*$A]],stroke:AB,width:.2*$A})}const Q=new Map;for(const A of s.filter(A=>!A.short)){const B=CB(A,A.inwardNormal),E=Q.get(B)||[];E.push(A),Q.set(B,E)}for(const A of Q.values()){let B=null;for(let E=0;E<=30&&!B;E+=3){const s=A.map(A=>{const B=a(A.mid),s=QB(wB(B[0],B[1],A.text,_A,A.angle,"center"),B[0],B[1],A.inwardNormal,(1+E)*$A),w=B[0]+A.inwardNormal[0]*s,Q=B[1]+A.inwardNormal[1]*s;return{edge:A,x:w,y:Q,box:wB(w,Q,A.text,_A,A.angle,"center")}}),Q=s.some((A,B)=>s.slice(0,B).some(B=>sB(A.box,B.box))),C=s.some(A=>K(A.box)||z.some(B=>sB(A.box,B))),g=s.every(A=>d(A.box,w));Q||C||!g||(B=s)}if(B)for(const A of B)f.push({kind:"text",x:A.x,y:A.y,text:A.edge.text,size:_A,angle:A.edge.angle,align:"center"}),z.push(A.box)}}}const _={minX:m,minY:v,maxX:c-m,maxY:v+V},AA=XA(f),BA=OA(AA,{minX:0,minY:0,maxX:U,maxY:V},.5*$A),sA=function(A,B){const E=XA(A);if(!ZA(E))return{commands:[...A],bounds:E,dx:0,dy:0};const s=(B.minX+B.maxX-E.minX-E.maxX)/2,w=(B.minY+B.maxY-E.minY-E.maxY)/2,Q=function(A,B,E){return A.map(A=>"path"===A.kind?{...A,rings:A.rings.map(A=>A.map(([A,s])=>[A+B,s+E]))}:"line"===A.kind?{...A,points:A.points.map(([A,s])=>[A+B,s+E])}:"vector"===A.kind?{...A,ops:A.ops.map(A=>((A,B,E)=>"M"===A.op||"L"===A.op?{...A,x:A.x+B,y:A.y+E}:"C"===A.op?{...A,x1:A.x1+B,y1:A.y1+E,x2:A.x2+B,y2:A.y2+E,x:A.x+B,y:A.y+E}:A)(A,B,E))}:{...A,x:A.x+B,y:A.y+E})}(A,s,w);return{commands:Q,bounds:{minX:E.minX+s,minY:E.minY+w,maxX:E.maxX+s,maxY:E.maxY+w},dx:s,dy:w}}(f,_);f=sA.commands,f.push({kind:"text",x:m,y:m+10,text:A.space.title,size:14}),A.cardTitle&&f.push({kind:"text",x:c-m,y:m+10,text:A.cardTitle,size:10,align:"right"});const wA=W-m-13*$A;f.push({kind:"line",points:[[m,wA-4*$A],[c-m,wA-4*$A]],stroke:EB,width:.2*$A}),f.push({kind:"text",x:m,y:wA,text:A.t("pdf.scale",{n:E}),size:8});const QA=10*(A.imperial?152.4:100)*$A/E,CA=wA+8;f.push({kind:"line",points:[[m,CA],[m+QA,CA]],stroke:AB,width:.4*$A});for(let A=0;A<=4;A++){const B=m+QA*A/4;f.push({kind:"line",points:[[B,CA-2],[B,CA+2]],stroke:AB,width:.25*$A})}f.push({kind:"text",x:m+QA/2,y:wA+17,text:A.imperial?"5 ft":"1 m",size:7,align:"center"});const gA=t(A.config.settings,A.rawSpace.settings||{});if(null!==gA){const B=c/2,E=wA+5.5*$A;f.push({kind:"vector",ops:FA({centerX:B,centerY:E,size:11*$A,northDeg:gA}),fill:AB,width:0,fillRule:"evenodd"}),f.push({kind:"text",x:B,y:wA,text:A.t("pdf.north"),size:7,align:"center"})}f.push({kind:"text",x:c-m,y:wA+12,text:`${qA(A.now)} · House Plan v${A.version}`,size:7,align:"right"});const IA={width:c,height:W,commands:f,images:(A.rasters||[]).map(({id:A,bytes:B,width:E,height:s})=>({id:A,bytes:B,width:E,height:s})),now:A.now,scale:E,sceneBounds:sA.bounds,planField:_},RA=Math.max(0,TA(AA))*Math.max(0,fA(AA)),MA=U*V;return{page:IA,sceneBounds:sA.bounds,field:_,fits:BA,fillRatio:MA>0?RA/MA:0,landscape:s}}function bB(A,B){return A.fillRatio!==B.fillRatio?A.fillRatio>B.fillRatio?A:B:A.landscape?B:A}function LB(A,B,E){const s=12*$A,w=(E?297:210)*$A-2*s,Q=(E?210:297)*$A-2*s-18*$A-24*$A,C=A.cmPerUnit*(10*$A)/B;return(A.bounds.maxX-A.bounds.minX)*C<=w+.5*$A&&(A.bounds.maxY-A.bounds.minY)*C<=Q+.5*$A}function DB(A){let B=0;for(const E of A)if(B+=Math.max(0,Number(E)||0),B>26214400)throw new Error("pdf.too_large")}const GB="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";async function oB(A,B){if(!A)throw new Error("pdf.asset_failed");const E=await fetch(A,{credentials:"same-origin"});if(!E.ok)throw new Error("pdf.asset_failed");const s=await E.blob();let w;try{w=await createImageBitmap(s)}catch{throw new Error("pdf.asset_failed")}try{if("image/jpeg"===s.type)return{id:B,bytes:new Uint8Array(await s.arrayBuffer()),width:w.width,height:w.height};const A=document.createElement("canvas");A.width=w.width,A.height=w.height;const E=A.getContext("2d");if(!E)throw new Error("pdf.asset_failed");E.fillStyle="#fff",E.fillRect(0,0,A.width,A.height),E.drawImage(w,0,0);const Q=await new Promise(B=>A.toBlob(B,"image/jpeg",.85));if(!Q)throw new Error("pdf.asset_failed");return{id:B,bytes:new Uint8Array(await Q.arrayBuffer()),width:w.width,height:w.height}}finally{w.close()}}async function tB(A,B,E){const s=await async function(A,B){const E=[];if(B.backdrop&&A.space.bg){const B=await oB(A.backdropUrl,"backdrop");E.push({...B,x:A.space.bg.x,y:A.space.bg.y,drawWidth:A.space.bg.w,drawHeight:A.space.bg.h,angle:A.space.bg.angle,opacity:.6})}if(B.decor){let B=0;for(const s of A.rawSpace.decor||[]){if("image"!==s.kind)continue;const w=A.decorAssets.get(s.asset_id),Q=j(s,I,I);if(!w||!Q)throw new Error("pdf.asset_failed");const C=await oB(w.url,"decor"+B++);E.push({...C,x:Q[0],y:Q[1],drawWidth:Q[2],drawHeight:Q[3],opacity:Q[4],angle:Number(s.angle)||0})}}return DB(E.map(A=>A.bytes.byteLength)),E}(A,B),w=JA(function(A){const B=iB(A);let E=[];for(const s of wA){const w=[!1,!0].filter(A=>LB(B,s,A)).map(E=>xB(A,B,s,E));if(!w.length)continue;const Q=w.filter(A=>A.fits);if(Q.length)return Q.reduce(bB).page;E=w}E.length||(E=[!1,!0].map(E=>xB(A,B,500,E)));const s=E.filter(A=>A.fits);if(s.length)return s.reduce(bB).page;const w=Math.min(...E.map(A=>Math.max(TA(A.sceneBounds)/TA(A.field),fA(A.sceneBounds)/fA(A.field)))),Q=50,C=1e6,g=Number.isFinite(w)?Math.ceil(Math.min(C,500*Math.max(1,w))/Q)*Q:C;let I=500,Y=0,R=[],M=Math.max(550,g);for(;M<=C;){const E=[!1,!0].map(E=>xB(A,B,M,E)).filter(A=>A.fits);if(E.length){Y=M,R=E;break}if(I=M,M===C)break;M=Math.min(C,Math.ceil(2*M/Q)*Q)}if(!Y)throw new Error("pdf.failed");let F=Math.floor(I/Q),i=Math.floor(Y/Q);for(;i-F>1;){const E=Math.floor((F+i)/2),s=[!1,!0].map(s=>xB(A,B,E*Q,s)).filter(A=>A.fits);s.length?(i=E,R=s):F=E}const x=R.reduce(bB).page;if(!OA(x.sceneBounds,x.planField,.5*$A))throw new Error("pdf.failed");return x}({...A,options:B,now:E,rasters:s,t:A.t})),Q=new Blob([w],{type:"application/pdf"}),C=URL.createObjectURL(Q);try{const B=document.createElement("a");B.href=C,B.download=`houseplan-${g=A.space.title,g.normalize("NFKD").replace(/[^\p{L}\p{N}]+/gu,"-").replace(/^-|-$/g,"").toLowerCase()||"space"}-${qA(E)}.pdf`,B.style.display="none",document.body.append(B),B.click(),B.remove()}finally{setTimeout(()=>URL.revokeObjectURL(C),0)}var g;return w}class cB{assertRasterBudget(A){DB(A)}render(A){let B;return B={...A,save:async E=>{await tB(A,E,B.now||new Date)}},s``}}export{GB as PDF_EXPORT_FINGERPRINT,cB as PdfExportRuntime,tB as exportSpacePdf}; +
    `}}v.properties={context:{attribute:!1}},v.styles=A`:host{display:contents;}.body{display:grid;gap:12px;width:100%;max-width:100%;min-width:0;padding:16px 20px;box-sizing:border-box;}label{display:flex;min-width:0;min-height:44px;align-items:center;gap:12px;cursor:pointer;}label span{min-width:0;overflow-wrap:anywhere;}input{width:20px;height:20px;flex:none;accent-color:var(--hp-accent,#d89300);}.row{display:flex;align-items:center;gap:8px;width:100%;max-width:100%;min-width:0;padding:12px 16px;box-sizing:border-box;}.spacer{flex:1;}button{min-width:0;min-height:44px;max-width:100%;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--hp-line,rgb(127 127 127/.3));border-radius:12px;padding:0 18px;box-sizing:border-box;overflow-wrap:anywhere;white-space:normal;background:transparent;color:inherit;font:inherit;cursor:pointer;}button.primary{background:var(--hp-accent,#d89300);color:var(--hp-on-accent,#111);border-color:transparent;}button:disabled{opacity:.55;cursor:default;}ha-icon{flex:none;margin-right:6px;}@media (max-width:360px){.row{display:grid;grid-template-columns:minmax(0,1fr);}.spacer{display:none;}button{width:100%;}}`,customElements.get("hp-pdf-dialog")||customElements.define("hp-pdf-dialog",v);const V=(A,B,E)=>Math.hypot(A[0]-B[0],A[1]-B[1])<=E,U=A=>Number.isFinite(A)&&A>=0?A:0;function l(A){const B=Number(A);return Number.isFinite(B)&&B>0?.1/B:0}const a=(A,B)=>[...new Set([...A,...B])].sort((A,B)=>A-B),P=(A,B)=>{const E=A.points.length;if(E<=1||!V(A.points[E-1],A.points[0],B))return!1;const s=E-2;return A.edgeSources[s]=a(A.edgeSources[s],A.edgeSources[E-1]),A.points.splice(E-1,1),A.edgeSources.splice(E-1,1),!0},y=(A,B)=>{for(let E=0;E+1{let E=!1;for(;A.points.length>1;)if(P(A,B))E=!0;else{if(!y(A,B))break;E=!0}return E},N=(A,B,E)=>{const s=B[0]-A[0],w=B[1]-A[1],C=E[0]-B[0],g=E[1]-B[1],I=Math.hypot(s,w),Y=Math.hypot(C,g);if(!(I>0&&Y>0))return!1;const R=s*C+w*g;if(!(R>0))return!1;const M=s*g-w*C;return Math.abs(M)<=R*Q},K=A=>{const B=A.points.length;if(B<3)return!1;for(let E=0;E{const E=U(B),s=[],w=[];for(let B=0;B[A])};for(;Q.points.length>1;){const A=u(Q,E);if(Q.points.length<3)break;if(!K(Q)&&!A)break}return u(Q,E),Q};function J(A,B){const E=Number(A[0]),s=Number(A[1]),w=Number(B[0]),C=Number(B[1]);if(![E,s,w,C].every(Number.isFinite))return null;const g=w-E,I=C-s,Y=Math.abs(g),R=Math.abs(I),M=Math.max(Y,R),F=Math.min(Y,R);if(!(M>0)||F/M>Q)return null;const i=[(E+w)/2,(s+C)/2];if(Y>=R){return{axis:"horizontal",a:[E,i[1]],b:[w,i[1]],mid:i,projectedLength:Y,tangentInterval:[Math.min(E,w),Math.max(E,w)],normalCoordinate:i[1]}}return{axis:"vertical",a:[i[0],s],b:[i[0],C],mid:i,projectedLength:R,tangentInterval:[Math.min(s,C),Math.max(s,C)],normalCoordinate:i[0]}}function Z(A,B){const E=B.map(A=>[Number(A[0]),Number(A[1])]);if(!E.every(A=>A.every(Number.isFinite)))return!1;if(E.length<3||((A,B)=>{const E=1e-12*Math.max(1,Math.abs(A[0]),Math.abs(A[1]),...B.flatMap(A=>[Math.abs(A[0]),Math.abs(A[1])]));for(let s=0;s0))continue;const Y=(A[0]-w[0])*g-(A[1]-w[1])*C;if(Math.abs(Y)>E*I)continue;const R=(A[0]-w[0])*C+(A[1]-w[1])*g;if(R>=-E&&R<=I*I+E)return!0}return!1})(A,E))return!1;let s=!1;for(let B=0,w=E.length-1;BA[1]==C[1]>A[1])continue;const g=(C[0]-Q[0])*(A[1]-Q[1])/(C[1]-Q[1])+Q[0];A[0]Object.is(A,-0)?0:A,I=[g(-Q/C),g(w/C)],Y=[g(-I[0]),g(-I[1])],R=[(B[0]+E[0])/2,(B[1]+E[1])/2],M=Math.max(1,C,Math.abs(R[0]),Math.abs(R[1])),F=Math.max(1e-9*M,.01*U(s));for(const B of[F,4*F,16*F]){const E=Z([R[0]+I[0]*B,R[1]+I[1]*B],A);if(E!==Z([R[0]+Y[0]*B,R[1]+Y[1]*B],A))return E?I:Y}return sA(A)>=0?I:Y}function f(A,B){let E=180*Math.atan2(B[1]-A[1],B[0]-A[0])/Math.PI;return E>90&&(E-=180),E<=-90&&(E+=180),E}function k(A,B,E,s={}){const w=Number(B);if(!(w>0&&Number.isFinite(w)))return[];const Q=void 0===s.epsilon?l(w):U(s.epsilon);return z(d(A,Q),w,E,{...s,epsilon:Q})}const z=(A,B,E,s)=>{if(A.points.length<3)return[];const Q=U(s.epsilon??l(B)),C=Number.isFinite(Number(s.ringIndex))?Number(s.ringIndex):0,g=[];for(let s=0;sQ))continue;const M=[...A.edgeSources[s]||[s]].sort((A,B)=>A-B),F=M[0]??s,i=T(A.points,R.a,R.b,Q),x=("horizontal"===R.axis?i[1]:i[0])<0?-1:1,b=[R.axis,O(R.tangentInterval[0]),String(x),O(C),O(F)].join("|"),L=R.projectedLength*B;g.push({sourceA:[...I],sourceB:[...Y],a:R.a,b:R.b,text:w(L,E),short:L<30,angle:f(R.a,R.b),mid:R.mid,axis:R.axis,projectedLength:R.projectedLength,tangentInterval:R.tangentInterval,normalCoordinate:R.normalCoordinate,inwardNormal:i,normalSign:x,source:{ringIndex:C,edgeIndex:F},sourceEdgeIndices:M,stableKey:b})}return g};function p(A,B,E,s={}){const w=Number(B);if(!(w>0&&Number.isFinite(w)))return[];const Q=void 0===s.epsilon?l(w):U(s.epsilon);let C=d(A,Q);if(sA(C.points)<0&&(C=(A=>{const B=A.points.length;return{points:[...A.points].reverse().map(A=>[...A]),edgeSources:A.points.map((E,s)=>[...A.edgeSources[(B-2-s+B)%B]])}})(C)),C.points.length){let A=0;for(let B=1;B({points:[...A.points.slice(B),...A.points.slice(0,B)],edgeSources:[...A.edgeSources.slice(B),...A.edgeSources.slice(0,B)]}))(C,A)}return z(C,w,E,{...s,epsilon:Q})}function X(A,B){const E=U(B),s=[];for(const B of A){const A=s.find(A=>A.axis===B.axis&&A.normalSign===B.normalSign&&Math.abs(A.normalCoordinate-B.normalCoordinate)<=E);A?A.edges.push(B):s.push({axis:B.axis,normalSign:B.normalSign,normalCoordinate:B.normalCoordinate,edges:[B]})}return s.map(A=>A.edges)}const O=A=>Object.is(A,-0)?"0":String(A),q=A=>"horizontal"===A?0:1;function $(A,B){return q(A.axis)-q(B.axis)||A.tangentInterval[0]-B.tangentInterval[0]||A.normalSign-B.normalSign||A.source.ringIndex-B.source.ringIndex||A.source.edgeIndex-B.source.edgeIndex}function _(A,B,E,s){const w=U(s);if(A.axis!==B.axis)return!1;if(A.source.ringIndex!==B.source.ringIndex)return!1;if(A.inwardNormal[0]*B.inwardNormal[0]+A.inwardNormal[1]*B.inwardNormal[1]>=-.5)return!1;if(!((A,B,E)=>Math.abs(A[0]-B[0])<=E&&Math.abs(A[1]-B[1])<=E)(A.tangentInterval,B.tangentInterval,w))return!1;if(Math.abs(A.projectedLength-B.projectedLength)>w)return!1;return Z([(A.mid[0]+B.mid[0])/2,(A.mid[1]+B.mid[1])/2],E)}const AA=(A,B)=>{const E=B?.(A);return{hardCollisions:Number.isFinite(Number(E?.hardCollisions))?Number(E?.hardCollisions):0,normalClearance:Number.isFinite(Number(E?.normalClearance))?Number(E?.normalClearance):0}},BA=(A,B,E)=>{const s=AA(A,E),w=AA(B,E);return s.hardCollisions-w.hardCollisions||w.normalClearance-s.normalClearance||$(A,B)};function EA(A,B){if(A.length<2)return[...A];const E=U(B.epsilon),s=function(A,B=1e-7){return d(A,B).points.map(A=>[...A])}(B.ring,E),w=[];for(let B=0;B{const E=A.separation-B.separation;if(E)return E;const s=$(A.left,A.right)<=0?A.left:A.right,w=s===A.left?A.right:A.left,Q=$(B.left,B.right)<=0?B.left:B.right,C=Q===B.left?B.right:B.left;return $(s,Q)||$(w,C)});const Q=new Set,C=new Set;for(const A of w){if(Q.has(A.left)||Q.has(A.right))continue;Q.add(A.left),Q.add(A.right);const E=BA(A.left,A.right,B.score)<=0?A.left:A.right;C.add(E===A.left?A.right:A.left)}return A.filter(A=>!C.has(A))}function sA(A){let B=0;for(let E=0;E1){const A=Math.sqrt(G);Y*=A,R*=A}const o=Math.max(0,Y*Y*R*R-Y*Y*D*D-R*R*L*L),t=Y*Y*D*D+R*R*L*L||1,c=(Q===C?-1:1)*Math.sqrt(o/t),W=c*Y*D/R,m=c*-R*L/Y,n=F*W-i*m+(A+g)/2,e=i*W+F*m+(B+I)/2;let h=gA(1,0,(L-W)/Y,(D-m)/R),S=gA((L-W)/Y,(D-m)/R,(-L-W)/Y,(-D-m)/R);!C&&S>0&&(S-=2*Math.PI),C&&S<0&&(S+=2*Math.PI);const j=Math.max(1,Math.ceil(Math.abs(S)/(Math.PI/2))),r=S/j,H=A=>[n+F*Y*Math.cos(A)-i*R*Math.sin(A),e+i*Y*Math.cos(A)+F*R*Math.sin(A)],v=A=>[-F*Y*Math.sin(A)-i*R*Math.cos(A),-i*Y*Math.sin(A)+F*R*Math.cos(A)],V=[];for(let A=0;A[B.a*A+B.c*E+B.e,B.b*A+B.d*E+B.f];return function(A){const B=A.match(/[AaCcHhLlMmQqSsTtVvZz]|[-+]?(?:\d*\.\d+|\d+\.?)(?:e[-+]?\d+)?/gi)||[],E=[];let s=0,w="",Q=0,C=0,g=0,I=0,Y=null,R=null;const M=()=>Number(B[s++]);for(;sB.length||QA.test(B[s]))throw new Error(`Invalid SVG path command ${w}`);const x=Array.from({length:i},M),b=A=>A+(F?Q:0),L=A=>A+(F?C:0);if("M"===A||"L"===A)Q=b(x[0]),C=L(x[1]),E.push({op:"M"===A?"M":"L",x:Q,y:C}),"M"===A&&(g=Q,I=C,w=F?"l":"L"),Y=R=null;else if("H"===A)Q=b(x[0]),E.push({op:"L",x:Q,y:C}),Y=R=null;else if("V"===A)C=L(x[0]),E.push({op:"L",x:Q,y:C}),Y=R=null;else if("C"===A){const A=b(x[0]),B=L(x[1]),s=b(x[2]),w=L(x[3]);Q=b(x[4]),C=L(x[5]),Y=[s,w],R=null,E.push({op:"C",x1:A,y1:B,x2:s,y2:w,x:Q,y:C})}else if("S"===A){const A=Y?2*Q-Y[0]:Q,B=Y?2*C-Y[1]:C,s=b(x[0]),w=L(x[1]);Q=b(x[2]),C=L(x[3]),Y=[s,w],R=null,E.push({op:"C",x1:A,y1:B,x2:s,y2:w,x:Q,y:C})}else if("Q"===A||"T"===A){const B="Q"===A?b(x[0]):R?2*Q-R[0]:Q,s="Q"===A?L(x[1]):R?2*C-R[1]:C,w=b("Q"===A?x[2]:x[0]),g=L("Q"===A?x[3]:x[1]);E.push({op:"C",x1:Q+2/3*(B-Q),y1:C+2/3*(s-C),x2:w+2/3*(B-w),y2:g+2/3*(s-g),x:w,y:g}),Q=w,C=g,R=[B,s],Y=null}else if("A"===A){const A=b(x[5]),B=L(x[6]),s=IA(Q,C,x[0],x[1],x[2],x[3],x[4],A,B);s.length?E.push(...s):E.push({op:"L",x:A,y:B}),Q=A,C=B,Y=R=null}}return E}(A).map(A=>{if("Z"===A.op)return A;if("M"===A.op||"L"===A.op){const[B,s]=E(A.x,A.y);return{op:A.op,x:B,y:s}}if("C"!==A.op)throw new Error("Unsupported PDF vector operation");const[B,s]=E(A.x1,A.y1),[w,Q]=E(A.x2,A.y2),[C,g]=E(A.x,A.y);return{op:"C",x1:B,y1:s,x2:w,y2:Q,x:C,y:g}})}const RA=["M20.82,15.31h0L10.46,9c-.46-.26-1.11.37-.86.84l6.15,10.56,10.56,6.15a.66.66,0,0,0,.84-.86Zm-4,4,3-3,4.55,7.44Z","M18,2A16,16,0,1,0,34,18,16,16,0,0,0,18,2Zm1,29.95V29.53H17v2.42A14,14,0,0,1,4.05,19H6.47V17H4.05A14,14,0,0,1,17,4.05V6.47h2V4.05A14,14,0,0,1,31.95,17H29.53v2h2.42A14,14,0,0,1,19,31.95Z"],MA=A=>Math.abs(A)<1e-12?0:Math.abs(A-1)<1e-12?1:Math.abs(A+1)<1e-12?-1:A;function FA(A){const B=function(A){const{centerX:B,centerY:E,size:s,northDeg:w}=A;if(![B,E,s,w].every(Number.isFinite)||s<=0)throw new RangeError("PDF compass placement must contain finite coordinates and a positive size");const Q=((w%360+360)%360+45)*Math.PI/180,C=s/36,g=MA(Math.cos(Q)),I=MA(Math.sin(Q)),Y=C*g,R=C*I,M=-C*I,F=C*g;return{a:Y,b:R,c:M,d:F,e:B-18*Y-18*M,f:E-18*R-18*F}}(A);return RA.flatMap(A=>YA(A,B))}const iA=1e-8,xA=A=>A.length>=2&&Number.isFinite(A[0])&&Number.isFinite(A[1]),bA=(A,B)=>A[0]>=B.minX-iA&&A[0]<=B.maxX+iA&&A[1]>=B.minY-iA&&A[1]<=B.maxY+iA,LA=A=>[A.minX,A.minY,A.maxX,A.maxY].every(Number.isFinite)&&A.maxX>=A.minX&&A.maxY>=A.minY,DA=A=>[[A.minX,A.minY],[A.maxX,A.minY],[A.maxX,A.maxY],[A.minX,A.maxY]];const GA=(A,B,E)=>(B[0]-A[0])*(E[1]-A[1])-(B[1]-A[1])*(E[0]-A[0]),oA=(A,B,E)=>{const s=E[0]-B[0],w=E[1]-B[1],Q=Math.abs(s)>=Math.abs(w)?s:w;return Math.abs(Q)<=iA?0:(Math.abs(s)>=Math.abs(w)?A[0]-B[0]:A[1]-B[1])/Q},tA=(A,B)=>Math.hypot(B[0]-A[0],B[1]-A[1]);function cA(A,B,E){const s=tA(B,E);if(s<=iA)return tA(A,B)<=iA;if(Math.abs(GA(B,E,A))/s>iA)return!1;const w=oA(A,B,E),Q=iA/s;return w>=-Q&&w<=1+Q}function WA(A,B,E,s){const w=B[0]-A[0],Q=B[1]-A[1],C=s[0]-E[0],g=s[1]-E[1],I=Math.hypot(w,Q),Y=Math.hypot(C,g);if(I<=iA)return cA(A,E,s)?{t:0,endT:0,overlap:!1}:null;if(Y<=iA){if(!cA(E,A,B))return null;const s=Math.max(0,Math.min(1,oA(E,A,B)));return{t:s,endT:s,overlap:!1}}const R=w*g-Q*C,M=E[0]-A[0],F=E[1]-A[1],i=iA*I*Y;if(Math.abs(R)<=i){if(Math.abs(GA(A,B,E))/I>iA||Math.abs(GA(A,B,s))/I>iA)return null;const w=oA(E,A,B),Q=oA(s,A,B),C=Math.max(0,Math.min(w,Q)),g=Math.min(1,Math.max(w,Q));return giA}}const x=(M*g-F*C)/R,b=(M*Q-F*w)/R,L=iA/I,D=iA/Y;if(x<-L||x>1+L||b<-D||b>1+D)return null;const G=Math.max(0,Math.min(1,x));return{t:G,endT:G,overlap:!1}}const mA=A=>A.every(A=>A.length>=2&&A.every(xA));function nA(A,B){for(const E of A){const A=E;for(let E=0;Enull!==WA(A,B,E,s[(w+1)%s.length]))}const hA=2048,SA=2146,jA=[-1825,-555,4188,2163],rA={32:1,33:2,34:3,35:4,36:5,37:6,38:7,39:8,40:9,41:10,42:11,43:12,44:13,45:14,46:15,47:16,48:17,49:18,50:19,51:20,52:21,53:22,54:23,55:24,56:25,57:26,58:27,59:28,60:29,61:30,62:31,63:32,64:33,65:34,66:35,67:36,68:37,69:38,70:39,71:40,72:41,73:42,74:43,75:44,76:45,77:46,78:47,79:48,80:49,81:50,82:51,83:52,84:53,85:54,86:55,87:56,88:57,89:58,90:59,91:60,92:61,93:62,94:63,95:64,96:65,97:66,98:67,99:68,100:69,101:70,102:71,103:72,104:73,105:74,106:75,107:76,108:77,109:78,110:79,111:80,112:81,113:82,114:83,115:84,116:85,117:86,118:87,119:88,120:89,121:90,122:91,123:92,124:93,125:94,126:95,160:596,161:96,162:97,163:98,164:99,165:100,166:101,167:102,168:103,169:104,170:105,171:106,172:107,173:597,174:108,175:109,176:110,177:111,178:112,179:113,180:114,181:115,182:116,183:117,184:118,185:119,186:120,187:121,188:122,189:123,190:124,191:125,192:603,193:604,194:605,195:606,196:607,197:608,198:126,199:609,200:610,201:611,202:612,203:613,204:614,205:615,206:616,207:617,208:599,209:618,210:619,211:620,212:621,213:622,214:623,215:127,216:128,217:624,218:625,219:626,220:627,221:628,222:129,223:130,224:629,225:630,226:631,227:632,228:633,229:634,230:131,231:635,232:636,233:637,234:638,235:639,236:640,237:641,238:642,239:643,240:132,241:644,242:645,243:646,244:647,245:648,246:649,247:133,248:134,249:650,250:651,251:652,252:653,253:654,254:135,255:655,256:656,257:657,258:658,259:659,260:660,261:661,262:662,263:663,264:664,265:665,266:666,267:667,268:668,269:669,270:670,271:671,272:598,273:136,274:672,275:673,276:674,277:675,278:676,279:677,280:678,281:679,282:680,283:681,284:682,285:683,286:684,287:685,288:686,289:687,290:688,291:689,292:690,293:691,294:137,295:600,296:692,297:693,298:694,299:695,300:696,301:697,302:698,303:699,304:700,305:138,306:701,307:702,308:703,309:704,310:705,311:706,312:139,313:707,314:708,315:709,316:710,317:711,318:712,319:713,320:714,321:140,322:141,323:715,324:716,325:717,326:718,327:719,328:720,329:721,330:142,331:143,332:722,333:723,334:724,335:725,336:726,337:727,338:144,339:145,340:728,341:729,342:730,343:731,344:732,345:733,346:734,347:735,348:736,349:737,350:738,351:739,352:742,353:743,354:744,355:745,356:746,357:747,358:601,359:602,360:748,361:749,362:750,363:751,364:752,365:753,366:754,367:755,368:756,369:757,370:758,371:759,372:760,373:761,374:762,375:763,376:764,377:765,378:766,379:767,380:768,381:769,382:770,383:146,1024:897,1025:856,1026:165,1027:857,1028:166,1029:858,1030:859,1031:860,1032:861,1033:167,1034:168,1035:169,1036:863,1037:898,1038:864,1039:170,1040:865,1041:171,1042:866,1043:867,1044:172,1045:868,1046:173,1047:174,1048:175,1049:869,1050:862,1051:176,1052:870,1053:871,1054:872,1055:873,1056:874,1057:875,1058:876,1059:177,1060:178,1061:877,1062:179,1063:180,1064:181,1065:182,1066:183,1067:184,1068:185,1069:186,1070:187,1071:188,1072:878,1073:189,1074:190,1075:191,1076:192,1077:879,1078:193,1079:194,1080:195,1081:880,1082:196,1083:197,1084:198,1085:199,1086:881,1087:200,1088:882,1089:883,1090:201,1091:884,1092:202,1093:885,1094:203,1095:204,1096:205,1097:206,1098:207,1099:208,1100:209,1101:210,1102:211,1103:212,1104:899,1105:886,1106:213,1107:887,1108:214,1109:888,1110:889,1111:890,1112:891,1113:215,1114:216,1115:217,1116:892,1117:900,1118:893,1119:218,1120:219,1121:220,1122:965,1123:221,1124:222,1125:223,1126:224,1127:225,1128:226,1129:227,1130:228,1131:229,1132:230,1133:231,1134:232,1135:233,1136:901,1137:902,1138:234,1139:235,1140:236,1141:237,1142:903,1143:904,1144:906,1145:905,1146:238,1147:239,1148:240,1149:241,1150:242,1151:243,1152:244,1153:245,1154:246,1155:247,1156:248,1157:249,1158:250,1159:251,1160:252,1161:253,1162:254,1163:255,1164:964,1165:256,1166:257,1167:258,1168:259,1169:260,1170:966,1171:967,1172:261,1173:262,1174:263,1175:264,1176:907,1177:908,1178:265,1179:266,1180:267,1181:268,1182:968,1183:969,1184:269,1185:270,1186:271,1187:272,1188:273,1189:274,1190:275,1191:276,1192:277,1193:278,1194:909,1195:910,1196:955,1197:956,1198:911,1199:912,1200:970,1201:971,1202:279,1203:280,1204:281,1205:282,1206:283,1207:284,1208:285,1209:286,1210:287,1211:963,1212:288,1213:289,1214:961,1215:962,1216:913,1217:914,1218:915,1219:290,1220:291,1221:292,1222:293,1223:294,1224:295,1225:296,1226:297,1227:957,1228:958,1229:298,1230:299,1231:916,1232:917,1233:918,1234:919,1235:920,1236:921,1237:922,1238:923,1239:924,1240:300,1241:926,1242:925,1243:927,1244:928,1245:929,1246:930,1247:931,1248:301,1249:302,1250:932,1251:933,1252:934,1253:935,1254:936,1255:937,1256:938,1257:939,1258:940,1259:941,1260:942,1261:943,1262:944,1263:945,1264:946,1265:947,1266:948,1267:949,1268:950,1269:951,1270:959,1271:960,1272:952,1273:953,1274:303,1275:304,1276:305,1277:306,1278:972,1279:973,1280:307,1281:954,1282:308,1283:309,1284:310,1285:311,1286:312,1287:313,1288:314,1289:315,1290:316,1291:317,1292:318,1293:319,1294:320,1295:321,1296:322,1297:974,1298:323,1299:324,1300:325,1301:326,1302:327,1303:328,1304:329,1305:330,1306:982,1307:983,1308:984,1309:985,1310:331,1311:332,1312:333,1313:334,1314:335,1315:336,1316:337,1317:338,1318:339,1319:340,1320:341,1321:342,1322:343,1323:344,1324:345,1325:346,1326:347,1327:348,8192:349,8193:350,8194:351,8195:352,8196:353,8197:354,8198:355,8199:356,8200:357,8201:358,8202:360,8203:361,8204:362,8205:363,8206:364,8207:365,8208:366,8209:367,8210:368,8211:369,8212:370,8213:975,8214:371,8215:372,8216:373,8217:374,8218:375,8219:376,8220:377,8221:378,8222:379,8223:380,8224:381,8225:382,8226:383,8227:384,8228:385,8229:386,8230:387,8231:388,8239:986,8240:389,8241:390,8242:894,8243:895,8244:391,8245:392,8246:393,8247:394,8248:395,8249:396,8250:397,8251:398,8252:896,8253:399,8254:400,8255:401,8256:402,8257:403,8258:404,8259:405,8260:406,8261:407,8262:408,8263:987,8264:988,8265:989,8266:409,8267:410,8268:411,8269:412,8270:413,8271:414,8272:415,8273:416,8274:417,8275:418,8276:419,8277:420,8278:421,8279:422,8280:423,8281:424,8282:425,8283:426,8284:427,8285:428,8286:429,8287:990,8364:430,8381:431,8776:433},HA={1:507,2:527,3:655,4:1261,5:1150,6:1500,7:1273,8:357,9:700,10:712,11:882,12:1161,13:402,14:565,15:539,16:844,17:1150,18:1150,19:1150,20:1150,21:1150,22:1150,23:1150,24:1150,25:1150,26:1150,27:496,28:433,29:1041,30:1124,31:1070,32:967,33:1839,34:1336,35:1275,36:1333,37:1343,38:1164,39:1132,40:1395,41:1460,42:557,43:1130,44:1284,45:1102,46:1788,47:1460,48:1408,49:1292,50:1408,51:1261,52:1215,53:1222,54:1328,55:1303,56:1817,57:1284,58:1230,59:1226,60:543,61:840,62:543,63:856,64:924,65:633,66:1114,67:1149,68:1072,69:1155,70:1085,71:711,72:1149,73:1128,74:497,75:489,76:1038,77:497,78:1795,79:1130,80:1168,81:1149,82:1164,83:693,84:1056,85:669,86:1129,87:992,88:1539,89:1015,90:969,91:1015,92:693,93:499,94:693,95:1393,96:499,97:1120,98:1190,99:1460,100:1075,101:491,102:1256,103:856,104:1609,105:915,106:961,107:1134,108:1610,109:938,110:765,111:1094,112:751,113:751,114:642,115:1160,116:1001,117:534,118:507,119:751,120:931,121:960,122:1500,123:1589,124:1593,125:969,126:1914,127:1092,128:1408,129:1210,130:1218,131:1729,132:1200,133:1169,134:1160,135:1180,136:1223,137:1434,138:506,139:1139,140:1103,141:553,142:1419,143:1160,144:1953,145:1860,146:508,165:1535,166:1380,167:2193,168:2212,169:1666,170:1460,171:1291,172:1540,173:1859,174:1215,175:1460,176:1449,177:1287,178:1580,179:1497,180:1402,181:1927,182:1984,183:1554,184:1771,185:1285,186:1380,187:1831,188:1304,189:1132,190:1170,191:859,192:1236,193:1568,194:1040,195:1182,196:1106,197:1184,198:1519,199:1181,200:1182,201:984,202:1485,203:1213,204:1113,205:1656,206:1694,207:1271,208:1590,209:1112,210:1101,211:1671,212:1124,213:1128,214:1101,215:1737,216:1764,217:1161,218:1182,219:1800,220:1579,221:1110,222:1835,223:1528,224:1234,225:1094,226:1803,227:1547,228:1745,229:1505,230:2308,231:2001,232:1059,233:987,234:1393,235:1163,236:1290,237:1027,238:1393,239:1160,240:1793,241:1572,242:1800,243:1579,244:1330,245:1095,246:1277,247:1024,248:1024,249:1024,250:1024,251:1024,252:1024,253:1024,254:1545,255:1261,256:1110,257:1307,258:1161,259:1123,260:912,261:1243,262:1029,263:1954,264:1633,265:1434,266:1208,267:1289,268:1150,269:1676,270:1411,271:1535,272:1241,273:1999,274:1460,275:2097,276:1780,277:1518,278:1235,279:1304,280:1066,281:1836,282:1372,283:1468,284:1174,285:1391,286:1130,287:1391,288:1583,289:1213,290:1289,291:1114,292:1534,293:1263,294:1458,295:1160,296:1554,297:1260,298:1871,299:1598,300:1415,301:1192,302:1192,303:1207,304:939,305:1326,306:1088,307:1270,308:1684,309:1764,310:1622,311:1323,312:1097,313:1031,314:1985,315:1653,316:2043,317:1697,318:1270,319:1053,320:1453,321:1312,322:1380,323:1538,324:1266,325:1920,326:1549,327:1857,328:1547,329:1926,330:1774,331:1316,332:1106,333:2274,334:1832,335:2300,336:1829,337:1526,338:1242,339:1468,340:1208,341:1539,342:1273,343:2710,344:2238,345:1568,346:1240,347:1515,348:1243,349:1044,350:2089,351:1044,352:2089,353:697,354:522,355:348,356:1151,357:560,358:418,360:209,361:1024,362:1024,363:1024,364:1024,365:1024,366:564,367:564,368:1171,369:1344,370:1599,371:778,372:933,373:409,374:409,375:407,376:409,377:724,378:731,379:705,380:764,381:1129,382:1167,383:690,384:1100,385:511,386:964,387:1370,388:382,389:1962,390:2360,391:1045,392:463,393:757,394:1045,395:803,396:614,397:614,398:1241,399:919,400:952,401:1540,402:1540,403:874,404:1370,405:870,406:931,407:640,408:641,409:907,410:1001,411:1237,412:1237,413:985,414:511,415:1541,416:985,417:931,418:1366,419:1540,420:1172,421:932,422:1333,423:1215,424:1125,425:379,426:1071,427:1162,428:379,429:379,430:1150,431:1359,433:1154,596:507,597:565,598:1373,599:1373,600:1158,601:1222,602:669,603:1336,604:1336,605:1336,606:1336,607:1336,608:1336,609:1333,610:1164,611:1164,612:1164,613:1164,614:557,615:557,616:557,617:557,618:1460,619:1408,620:1408,621:1408,622:1408,623:1408,624:1328,625:1328,626:1328,627:1328,628:1230,629:1114,630:1114,631:1114,632:1114,633:1114,634:1114,635:1072,636:1085,637:1085,638:1085,639:1085,640:506,641:506,642:506,643:506,644:1130,645:1168,646:1168,647:1168,648:1168,649:1168,650:1129,651:1129,652:1129,653:1129,654:969,655:969,656:1336,657:1114,658:1336,659:1114,660:1336,661:1114,662:1333,663:1072,664:1333,665:1072,666:1333,667:1072,668:1333,669:1072,670:1343,671:1305,672:1164,673:1085,674:1164,675:1085,676:1164,677:1085,678:1164,679:1085,680:1164,681:1085,682:1395,683:1149,684:1395,685:1149,686:1395,687:1149,688:1395,689:1149,690:1460,691:1128,692:557,693:506,694:557,695:506,696:557,697:506,698:557,699:497,700:557,701:1687,702:986,703:1130,704:515,705:1284,706:1038,707:1102,708:497,709:1102,710:497,711:1102,712:647,713:1102,714:717,715:1460,716:1130,717:1460,718:1130,719:1460,720:1130,721:1130,722:1408,723:1168,724:1408,725:1168,726:1408,727:1168,728:1261,729:693,730:1261,731:693,732:1261,733:693,734:1215,735:1056,736:1215,737:1056,738:1215,739:1056,742:1215,743:1056,744:1222,745:669,746:1222,747:709,748:1328,749:1129,750:1328,751:1129,752:1328,753:1129,754:1328,755:1129,756:1328,757:1129,758:1328,759:1129,760:1817,761:1539,762:1230,763:969,764:1230,765:1226,766:1015,767:1226,768:1015,769:1226,770:1015,856:1164,857:1139,858:1215,859:557,860:557,861:1130,862:1316,863:1284,864:1287,865:1336,866:1275,867:1139,868:1164,869:1460,870:1788,871:1460,872:1408,873:1461,874:1292,875:1333,876:1222,877:1284,878:1114,879:1085,880:1182,881:1168,882:1149,883:1072,884:969,885:1015,886:1085,887:859,888:1056,889:497,890:506,891:489,892:1106,893:969,894:357,895:655,896:1054,897:1164,898:1460,899:1085,900:1182,901:1417,902:1434,903:1290,904:1027,905:2137,906:2377,907:1215,908:1040,909:1333,910:1072,911:1230,912:1026,913:557,914:1859,915:1568,916:557,917:1336,918:1114,919:1336,920:1114,921:1914,922:1729,923:1164,924:1085,925:1415,926:1079,927:1079,928:1859,929:1568,930:1215,931:1040,932:1460,933:1182,934:1460,935:1182,936:1408,937:1168,938:1393,939:1163,940:1393,941:1163,942:1380,943:1101,944:1287,945:969,946:1287,947:969,948:1287,949:969,950:1402,951:1113,952:1771,953:1590,954:1155,955:1222,956:984,957:1402,958:1113,959:1139,960:859,961:1583,962:1213,963:1128,964:1285,965:1285,966:1139,967:859,968:1336,969:1063,970:1230,971:1026,972:1284,973:1015,974:1104,975:1599,982:1408,983:1164,984:1817,985:1539,986:507,987:1934,988:1494,989:1494,990:507},vA=new TextEncoder,VA=A=>{const B=Math.round(100*A)/100;return Number.isInteger(B)?String(B):B.toFixed(2).replace(/0+$/,"")},UA=A=>{const B=Math.round(1e6*A)/1e6;return Number.isInteger(B)?String(B):B.toFixed(6).replace(/0+$/,"")},lA=A=>A.map(UA).join(" ");function aA(A){let B="",E=0;const s=new Map;for(const w of A){const A=w.codePointAt(0)||0,Q=rA[A]||rA[63];B+=Q.toString(16).padStart(4,"0"),E+=HA[Q]||1024,s.has(Q)||s.set(Q,A||63)}return{hex:B,width:E,unicode:s}}function PA(A,B){return aA(A).width*B/hA}function yA(A,B=PA(A.text,A.size)){const E=A.align||"left",s="center"===E?B/2:"right"===E?B:0,w=(A.angle||0)*Math.PI/180,Q=Math.cos(w),C=Math.sin(w);return{width:B,baselineX:A.x-Q*s,baselineY:A.y+C*s,cos:Q,sin:C}}function uA(A){const B=yA(A),E=-555*A.size/hA,s=SA*A.size/hA,w=[0,B.width].flatMap(A=>[E,s].map(E=>({x:B.baselineX+B.cos*A-B.sin*E,y:B.baselineY-B.sin*A-B.cos*E})));return{minX:Math.min(...w.map(A=>A.x)),minY:Math.min(...w.map(A=>A.y)),maxX:Math.max(...w.map(A=>A.x)),maxY:Math.max(...w.map(A=>A.y))}}function NA(A){const B=A.reduce((A,B)=>A+B.length,0),E=new Uint8Array(B);let s=0;for(const B of A)E.set(B,s),s+=B.length;return E}const KA=A=>vA.encode(A),dA=(A,B)=>NA([KA(`<< ${A} /Length ${B.length} >>\nstream\n`),B,KA("\nendstream")]);function JA(A){const B=function(A){const B=atob(A),E=new Uint8Array(B.length);for(let A=0;A"image"===A.kind&&null!=A.opacity&&A.opacity<1?[Math.max(0,Math.min(1,A.opacity))]:[]))].sort((A,B)=>A-B),s=new Map(E.map((A,B)=>[A,`GS${B+1}`])),w=function(A,B){const E=[],s=new Map,w=B=>A.height-B,Q=(A,...B)=>`${B.map(VA).join(" ")} ${A}`,C=A=>{for(const B of A)if(B.length){E.push(Q("m",B[0][0],w(B[0][1])));for(let A=1;A{let B=!1;for(const s of A)if(!(s.length<2)){B=!0,E.push(Q("m",s[0][0],w(s[0][1])));for(let A=1;A Tj`,"ET")}else{const A=(I.angle||0)*Math.PI/180,s=Math.cos(A),C=Math.sin(A),g=I.x+I.width/2,Y=w(I.y+I.height/2);E.push("q");const R=null==I.opacity?1:Math.max(0,Math.min(1,I.opacity)),M=B.get(R);M&&E.push(`/${M} gs`),E.push(Q("cm",s*I.width,C*I.width,C*I.height,-s*I.height,g-s*I.width/2-C*I.height/2,Y-C*I.width/2+s*I.height/2),`/Im${I.imageId} Do`,"Q")}return{stream:E.join("\n"),unicode:s}}(A,s),Q=Math.max(0,...Object.keys(HA).map(Number)),C=Array.from({length:Q+1},(A,B)=>Math.round(1e3*(HA[B]||1024)/hA)),g=[],I=A=>(g.push("string"==typeof A?KA(A):A),g.length),Y=I(""),R=I(""),M=I(""),F=I(dA(`/Length1 ${B.length}`,B)),i=I(`<< /Type /FontDescriptor /FontName /Roboto /Flags 32 /FontBBox [${jA.join(" ")}] /ItalicAngle 0 /Ascent 2146 /Descent -555 /CapHeight 2146 /StemV 80 /FontFile2 ${F} 0 R >>`),x=I(`<< /Type /Font /Subtype /CIDFontType2 /BaseFont /Roboto /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor ${i} 0 R /W [0 [${C.join(" ")}]] /CIDToGIDMap /Identity >>`),b=KA(function(A){const B=[...A].sort((A,B)=>A[0]-B[0]),E=B.map(([A,B])=>`<${A.toString(16).padStart(4,"0")}> <${B<=65535?B.toString(16).padStart(4,"0"):(()=>{const A=B-65536;return(55296+(A>>10)).toString(16).padStart(4,"0")+(56320+(1023&A)).toString(16).padStart(4,"0")})()}>`);return`/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def\n/CMapName /HousePlanUnicode def\n/CMapType 2 def\n1 begincodespacerange\n<0000> \nendcodespacerange\n${B.length} beginbfchar\n${E.join("\n")}\nendbfchar\nendcmap\nCMapName currentdict /CMap defineresource pop\nend\nend`}(w.unicode)),L=I(dA("",b)),D=I(`<< /Type /Font /Subtype /Type0 /BaseFont /Roboto /Encoding /Identity-H /DescendantFonts [${x} 0 R] /ToUnicode ${L} 0 R >>`),G=I(dA("",KA(w.stream))),o=[];for(const B of A.images||[]){const A=I(dA(`/Type /XObject /Subtype /Image /Width ${B.width} /Height ${B.height} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode`,B.bytes));o.push(`/Im${B.id} ${A} 0 R`)}const t=A.now.toISOString().replace(/[-:T]/g,"").slice(0,14),c=I(`<< /CreationDate (D:${t}Z) /ModDate (D:${t}Z) >>`),W=`<< /Font << /F1 ${D} 0 R >>`+(o.length?` /XObject << ${o.join(" ")} >>`:"")+(E.length?` /ExtGState << ${E.map(A=>`/${s.get(A)} << /ca ${VA(A)} /CA ${VA(A)} >>`).join(" ")} >>`:"")+" >>";g[Y-1]=KA(`<< /Type /Catalog /Pages ${R} 0 R >>`),g[R-1]=KA(`<< /Type /Pages /Kids [${M} 0 R] /Count 1 >>`),g[M-1]=KA(`<< /Type /Page /Parent ${R} 0 R /MediaBox [0 0 ${VA(A.width)} ${VA(A.height)}] /Resources ${W} /Contents ${G} 0 R >>`);const m=KA("%PDF-1.4\n%âãÏÓ\n"),n=[m],e=[0];let h=m.length;g.forEach((A,B)=>{const E=KA(`${B+1} 0 obj\n`),s=KA("\nendobj\n");e.push(h),n.push(E,A,s),h+=E.length+A.length+s.length});const S=h,j=["xref",`0 ${g.length+1}`,"0000000000 65535 f "];for(let A=1;A<=g.length;A++)j.push(`${String(e[A]).padStart(10,"0")} 00000 n `);return j.push(`trailer\n<< /Size ${g.length+1} /Root ${Y} 0 R /Info ${c} 0 R >>`,`startxref\n${S}\n%%EOF\n`),n.push(KA(j.join("\n"))),NA(n)}const ZA=A=>[A.minX,A.minY,A.maxX,A.maxY].every(Number.isFinite)&&A.maxX>=A.minX&&A.maxY>=A.minY,TA=A=>A.maxX-A.minX,fA=A=>A.maxY-A.minY;function kA(A,B,E,s=0){Number.isFinite(B)&&Number.isFinite(E)&&(A.minX=Math.min(A.minX,B-s),A.minY=Math.min(A.minY,E-s),A.maxX=Math.max(A.maxX,B+s),A.maxY=Math.max(A.maxY,E+s))}function zA(A,B,E,s,w,Q){const C=Q*Math.PI/180,g=Math.cos(C),I=Math.sin(C),Y=B+s/2,R=E+w/2;for(const[B,E]of[[-s/2,-w/2],[s/2,-w/2],[s/2,w/2],[-s/2,w/2]])kA(A,Y+g*B-I*E,R+I*B+g*E)}function pA(A,B,E){for(const s of B)"M"===s.op||"L"===s.op?kA(A,s.x,s.y,E):"C"===s.op&&(kA(A,s.x1,s.y1,E),kA(A,s.x2,s.y2,E),kA(A,s.x,s.y,E))}function XA(A){const B={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};for(const E of A)if("path"===E.kind){const A=E.stroke?(E.width||.5)/2:0;for(const s of E.rings)for(const[E,w]of s)kA(B,E,w,A)}else if("line"===E.kind)for(const[A,s]of E.points)kA(B,A,s,E.width/2);else if("vector"===E.kind)pA(B,E.ops,E.width/2);else if("text"===E.kind){const A=uA(E);kA(B,A.minX,A.minY),kA(B,A.maxX,A.maxY)}else zA(B,E.x,E.y,E.width,E.height,E.angle||0);return B}function OA(A,B,E){return!!ZA(A)&&(TA(A)<=TA(B)+E&&fA(A)<=fA(B)+E)}function qA(A){return`${A.getFullYear()}-${String(A.getMonth()+1).padStart(2,"0")}-${String(A.getDate()).padStart(2,"0")}`}const $A=72/25.4,_A=5.25,AB=[.08,.08,.08],BB=[127/255,127/255,127/255],EB=[.72,.72,.72],sB=(A,B)=>A.minXB.minX&&A.minYB.minY;function wB(A,B,E,s,w=0,Q="left"){return uA({x:A,y:B,text:E,size:s,angle:w,align:Q})}function QB(A,B,E,s,w){const Q=Math.min(...[[A.minX,A.minY],[A.maxX,A.minY],[A.maxX,A.maxY],[A.minX,A.maxY]].map(([A,w])=>(A-B)*s[0]+(w-E)*s[1]));return Math.max(0,w-Q)}const CB=(A,B)=>`${A.axis}:${B[0]<-.5||B[1]<-.5?-1:1}`,gB=(A,B)=>{A.minX=Math.min(A.minX,B[0]),A.minY=Math.min(A.minY,B[1]),A.maxX=Math.max(A.maxX,B[0]),A.maxY=Math.max(A.maxY,B[1])},IB=A=>{const B={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};for(const E of A)for(const A of E)gB(B,A);return B};function YB(A,B,E,s,w=0){const Q=w*Math.PI/180,C=Math.cos(Q),g=Math.sin(Q),I=A+E/2,Y=B+s/2;return Array.from({length:48},(A,B)=>{const w=B/48*Math.PI*2,Q=Math.cos(w)*E/2,R=Math.sin(w)*s/2;return[I+C*Q-g*R,Y+g*Q+C*R]})}function RB(A,B,E,s,w=0){const Q=w*Math.PI/180,C=Math.cos(Q),g=Math.sin(Q),I=A+E/2,Y=B+s/2;return[[-E/2,-s/2],[E/2,-s/2],[E/2,s/2],[-E/2,s/2]].map(([A,B])=>[I+C*A-g*B,Y+g*A+C*B])}function MB(A,B,E){if("passage"===A.type)return[];const s=A.rlen/2,w=B>0?B/E*Y/2:2,Q=[];if("window"===A.type)Q.push([[-s,-w],[s,-w]],[[-s,w],[s,w]],[[-s,-w],[-s,w]],[[s,-w],[s,w]]);else if("gate"===A.type){const B=10*(A.flip_v?-1:1)*Math.PI/180,E=[[[-s,0],[-s+Math.cos(B)*s,Math.sin(B)*s]],[[s,0],[s-Math.cos(B)*s,Math.sin(-B)*s]]];Q.push(...E);for(const A of E){const B=A[1][0]-A[0][0],E=A[1][1]-A[0][1],s=Math.hypot(B,E)||1,C=-E/s,g=B/s,I=Math.min(.08*s,Math.max(1,.7*w));for(const s of[.3,.5,.7]){const w=A[0][0]+B*s,Y=A[0][1]+E*s;Q.push([[w-C*I,Y-g*I],[w+C*I,Y+g*I]])}}}else{const B=A.flip_v?1:-1,E=A.flip_h?s:-s,w=[E,B*A.rlen];Q.push([[E,0],w]);const C=[];for(let s=0;s<=16;s++){const w=B*s/16*Math.PI/2,Q=A.flip_h?-1:1;C.push([E+Q*Math.cos(w)*A.rlen,Math.sin(w)*A.rlen])}Q.push(C)}const C=A.angle*Math.PI/180,g=Math.cos(C),I=Math.sin(C);return Q.map(B=>B.map(([B,E])=>[A.rx+B*g-E*I,A.ry+B*I+E*g]))}function FB(A,B){const E=IB([A]);return B.filter(A=>{const B=IB([A]);return B.maxX>=E.minX&&B.minX<=E.maxX&&B.maxY>=E.minY&&B.minY<=E.maxY})}function iB(A){const B=function(A){const{rawSpace:B,space:E}=A,s=Number(B.cell_cm)>0?Number(B.cell_cm):5,w=Array.isArray(B.walls)?B.walls:[],Q=c(B,E,I,.02*Y),C=W(B,E,s,Y,I),g=m(C),M=n(E,s,Y,2e-4*Y,g).all,F=e(C,E,w,Q.contour,R,s,Y,I);return{cellCm:s,walls:w,zero:Q,openings:C,extras:M,geometry:A.sharedWallGeometry||h(E.rooms,w,Q.contour,F,R,s,Y,I,M)}}(A),E=new Map;if(A.options.dimensions)for(const s of A.space.rooms){const w=C(s);if(!w)continue;const Q=s.id?A.resolveInnerContour?.(s.id):void 0;E.set(s,s.id&&(void 0===Q?g(A.space.rooms,s.id,B.walls,B.zero.contour,R,B.cellCm,Y,I,B.geometry.roomGeom,B.geometry.multiWallNodes):Q)||w)}const s=new Map;if(A.options.dimensions)for(const w of A.space.rooms){const Q=C(w);if(!Q)continue;const g=E.get(w)||Q,I=w.id?A.resolveRoomArea?.(w.id,g):void 0,Y=Number.isFinite(I)?[]:FB(g,B.extras),R=Y.length?M(g,Y):null,i=Number.isFinite(I)&&I>=0?I:R?F(R):Math.abs(g.reduce((A,B,E)=>{const s=g[(E+1)%g.length];return A+B[0]*s[1]-s[0]*B[1]},0)/2);s.set(w,i)}const w=[..."failed-core"===B.geometry.status?A.space.rooms.map(A=>C(A)||[]).filter(A=>A.length):B.geometry.components.flatMap(A=>i(A.geom)),...B.zero.lines.map(A=>[[A[0],A[1]],[A[2],A[3]]])];A.options.decor&&w.push(...function(A){const B=[];for(const E of A.decor||[])"line"===E.kind?B.push([[E.x1*I,E.y1*I],[E.x2*I,E.y2*I]]):"text"!==E.kind?B.push(L(E).map(([A,B])=>[A*I,B*I])):B.push([[E.x*I,E.y*I]]);return B}(A.rawSpace));for(const B of A.rasters||[])w.push(RB(B.x,B.y,B.drawWidth,B.drawHeight,B.angle));let Q=IB(w);var x;[(x=Q).minX,x.minY,x.maxX,x.maxY].every(Number.isFinite)&&x.maxX>x.minX&&x.maxY>x.minY||(Q={minX:0,minY:0,maxX:I,maxY:I});return{built:B,dimensionContours:E,roomAreas:s,bounds:Q,cmPerUnit:B.cellCm/Y}}function xB(A,B,E,s){const{built:w,dimensionContours:Q,roomAreas:g,bounds:M,cmPerUnit:F}=B,c=(s?297:210)*$A,W=(s?210:297)*$A,m=12*$A,n=18*$A,e=24*$A,h=F*(10*$A)/E,j=(M.maxX-M.minX)*h,H=(M.maxY-M.minY)*h,v=m+n,V=W-v-m-e,U=c-2*m,a=A=>[0+(A[0]-M.minX)*h,0+(A[1]-M.minY)*h],P=(A,B)=>[M.minX+(A-0)/h,M.minY+(B-0)/h],y=A=>{const B=P(A.minX,A.minY),E=P(A.maxX,A.maxY);return{minX:B[0],minY:B[1],maxX:E[0],maxY:E[1]}},u=w.geometry.components.flatMap(A=>i(A.geom)),N=A=>w.geometry.components.some(B=>S([...A],B.geom)),K=A=>function(A,B,E){if(!LA(A)||!mA(B))return!0;const s=DA(A);return!!s.some(E)||!!B.some(B=>B.some(B=>xA(B)&&bA(B,A)))||nA(B,(A,B)=>s.some((E,w)=>null!==WA(A,B,E,s[(w+1)%s.length])))}(y(function(A,B){const E=Number.isFinite(B)&&B>=0?B:0;return{minX:A.minX-E,minY:A.minY-E,maxX:A.maxX+E,maxY:A.maxY+E}}(A,$A-1e-6)),u,N),d=(A,B)=>function(A,B,E){if(!LA(A)||!mA([B]))return!1;const s=DA(A);return!!s.every(E)&&!nA([B],(A,B)=>s.some((E,w)=>null!==WA(A,B,E,s[(w+1)%s.length])))}(y(A),B,A=>Z([...A],B)),J=(A,B,E={})=>function(A,B,E,s,w={}){if(!xA(A)||!xA(B)||!mA(E))return!0;if(w.allowStartExit){const w=tA(A,B);if(w<=iA)return!0;const Q=nA(E,(B,E)=>cA(A,B,E));if(!Q)return!0;const C=[];nA(E,(E,s)=>{const w=WA(A,B,E,s);return w&&C.push(w),!1});const g=iA/w,I=[0,1,...C.flatMap(A=>[A.t,A.endT])].sort((A,B)=>A-B).filter((A,B,E)=>0===B||A-E[B-1]>g),Y=E=>[A[0]+(B[0]-A[0])*E,A[1]+(B[1]-A[1])*E],R=A=>C.some(B=>B.overlap&&A>B.t+g&&AA.t>M+g||A.endT>M+g)}const Q=[(A[0]+B[0])/2,(A[1]+B[1])/2],C=nA(E,(B,E)=>cA(A,B,E));return!((!s(A)||w.allowStartBoundary&&C)&&!s(Q)&&!s(B))||nA(E,(E,s)=>{const Q=WA(A,B,E,s);return!!Q&&(Q.overlap||!w.allowStartBoundary||!C||Q.t*tA(A,B)>iA)})}(P(A[0],A[1]),P(B[0],B[1]),u,N,E),T=(A,B,E)=>{const s=A.x*I,w=A.y*I,Q=A.w*I,C=A.h*I,g=s+Q/2,Y=w+C/2,R=s+(A.flip_h?Q:0),F=w+(A.flip_v?C:0),i=(A.flip_h?-1:1)*Q/B,x=(A.flip_v?-1:1)*C/E,b=(Number(A.angle)||0)*Math.PI/180,L=Math.cos(b),D=Math.sin(b),G=Y+D*(R-g)+L*(F-Y);return{a:h*L*i,b:h*D*i,c:-h*D*x,d:h*L*x,e:0+(g+L*(R-g)-D*(F-Y)-M.minX)*h,f:0+(G-M.minY)*h}};let f=[];const z=[],O=function(A,B){const E=3*$A*Math.SQRT2,s=[];for(let w=-B;w<=A+E;w+=E)s.push([[w,0],[w+B,B]]);return s}(c,W);for(const B of A.rasters||[])f.push({kind:"image",imageId:B.id,...a([B.x,B.y]).reduce((A,B,E)=>({...A,[E?"y":"x"]:B}),{}),width:B.drawWidth*h,height:B.drawHeight*h,angle:B.angle,opacity:B.opacity});for(const A of w.geometry.components)f.push({kind:"path",rings:i(A.geom).map(A=>A.map(a)),fill:BB,stroke:AB,width:.25*$A,hatch:{lines:O,stroke:AB,width:.18*$A}});if("failed-core"===w.geometry.status)for(const B of A.space.rooms){const A=C(B);A&&f.push({kind:"path",rings:[A.map(a)],stroke:AB,width:.25*$A})}for(const A of w.zero.lines)f.push({kind:"line",points:[a([A[0],A[1]]),a([A[2],A[3]])],stroke:AB,width:.35*$A,dash:[3*$A,2*$A]});const q=w.geometry.openingIndex;for(const B of w.openings){const E=B.partitionHost?{cm:B.partitionHost.partition.cm}:q?x(A.space.rooms,B,w.walls,R,w.cellCm,Y,I,w.zero.contour):{cm:0};for(const A of MB(B,E.cm,w.cellCm))f.push({kind:"line",points:A.map(a),stroke:AB,width:.3*$A})}if(A.options.decor)for(const B of A.rawSpace.decor||[])if("image"!==B.kind)if("line"===B.kind)f.push({kind:"line",points:[a([B.x1*I,B.y1*I]),a([B.x2*I,B.y2*I])],stroke:AB,width:Math.max(.2*$A,10*Number(B.width_cm||1)*$A/E),dash:"dashed"===B.line_style?[3*$A,2*$A]:void 0});else if("text"===B.kind)f.push({kind:"text",...(()=>{const[A,E]=a([B.x*I,B.y*I]);return{x:A,y:E}})(),text:B.text,size:Math.max(6,10*Number(B.size_cm||20)*$A/E),angle:Number(B.angle)||0});else if("furniture"===B.kind){const A=r[B.symbol];A?f.push({kind:"vector",ops:YA(A.d,T(B,A.viewW,A.viewH)),stroke:AB,width:Math.max(.2*$A,10*b(B,w.cellCm,Y)*$A/E)}):f.push({kind:"path",rings:[L(B).map(([A,B])=>a([A*I,B*I]))],stroke:AB,width:.25*$A})}else{const A="ellipse"===B.kind?YB(B.x*I,B.y*I,B.w*I,B.h*I,Number(B.angle)||0):L(B).map(([A,B])=>[A*I,B*I]);f.push({kind:"path",rings:[A.map(a)],stroke:AB,width:.25*$A})}if(A.options.dimensions&&w.geometry.roomGeom)for(const[B,E]of D(w.geometry.roomGeom).entries()){const s=l(F),w=(A,B,E)=>{const s=a(A.sourceA),w=a(A.sourceB),Q=a(A.a),C=a(A.b),g=(6+E)*$A,I=[Q[0]+B[0]*g,Q[1]+B[1]*g],Y=[C[0]+B[0]*g,C[1]+B[1]*g],R=[(I[0]+Y[0])/2,(I[1]+Y[1])/2],M=PA(A.text,7)+2*$A>Math.hypot(Y[0]-I[0],Y[1]-I[1]),F=QB(wB(R[0],R[1],A.text,7,A.angle,"center"),R[0],R[1],B,$A),i=[R[0]+B[0]*F,R[1]+B[1]*F];return{edge:A,a:s,b:w,oa:I,ob:Y,middle:R,label:i,box:wB(i[0],i[1],A.text,7,A.angle,"center"),needsShelf:M}},Q=A=>{const B=[{start:A.oa,end:A.ob},{start:A.a,end:A.oa,allowStartExit:!0},{start:A.b,end:A.ob,allowStartExit:!0}];return A.needsShelf&&B.push({start:A.middle,end:A.label,mayEnterOwnLabel:!0}),B},C=A=>K(A.box)||Q(A).some(A=>J(A.start,A.end,{allowStartBoundary:A.allowStartBoundary,allowStartExit:A.allowStartExit})),g=EA(k(E,F,A.imperial,{ringIndex:B,epsilon:s}),{ring:E,epsilon:s,score:A=>{const B=[-A.inwardNormal[0],-A.inwardNormal[1]],E=a(A.mid),s=Array.from({length:21},(A,B)=>4*B).find(E=>!C(w(A,B,E))),Q=E[0]+(U-j)/2,g=E[1]+(V-H)/2;return{hardCollisions:void 0===s?21:s/4,normalClearance:Math.abs(B[0])>.5?B[0]>0?U-Q:Q:B[1]>0?V-g:g}}});for(const A of X(g,s)){const B=A.map(A=>({edge:A,outward:[-A.inwardNormal[0],-A.inwardNormal[1]]})),E=A=>B.map(({edge:B,outward:E})=>w(B,E,A));let s=null;for(let A=0;A<=80&&!s;A+=4){const B=E(A),w=B.some((A,E)=>B.slice(0,E).some(B=>sB(A.box,B.box))),g=B.some(A=>C(A)||z.some(B=>sB(A.box,B))),I=B.some((A,E)=>Q(A).some(A=>z.some(B=>eA(A.start,A.end,B))||B.some((B,s)=>(!A.mayEnterOwnLabel||s!==E)&&eA(A.start,A.end,B.box))));w||g||I||(s=B)}if(s)for(const A of s)f.push({kind:"line",points:[A.oa,A.ob],stroke:AB,width:.2*$A},{kind:"line",points:[A.a,A.oa],stroke:AB,width:.15*$A},{kind:"line",points:[A.b,A.ob],stroke:AB,width:.15*$A}),A.needsShelf&&f.push({kind:"line",points:[A.middle,A.label],stroke:AB,width:.15*$A}),f.push({kind:"text",x:A.label[0],y:A.label[1],text:A.edge.text,size:_A,angle:A.edge.angle,align:"center"}),z.push(A.box)}}const $=[...A.space.rooms].sort((A,B)=>String(A.id||"").localeCompare(String(B.id||"")));for(const[B,E]of $.entries()){const s=C(E);if(!s)continue;const w=Q.get(E)||s,I=g.get(E)||0,Y=G(E,A.space.id,A.layout,A.config),[R,M]=a([Y.x,Y.y]),i=w.map(a),x=IB([i]);let b=!1;if(A.options.roomNames&&E.name){const A=Math.max(0,x.maxX-x.minX-4*$A),B=PA(E.name,6.75)<=A?6.75:PA(E.name,5.25)<=A?5.25:0;B&&(f.push({kind:"text",x:R,y:M-2,text:E.name,size:B,align:"center"}),z.push(wB(R,M-2,E.name,B,0,"center")),b=!0)}if(A.options.dimensions){const B=o(I*F*F/1e4,A.imperial),E=M+(b?8:0);f.push({kind:"text",x:R,y:E,text:B,size:6,align:"center"}),z.push(wB(R,E,B,8,0,"center"))}if(A.options.dimensions){const E=l(F),s=EA(p(w,F,A.imperial,{ringIndex:B,epsilon:E}),{ring:w,epsilon:E,score:A=>{const B=a(A.mid),E=QB(wB(B[0],B[1],A.text,_A,A.angle,"center"),B[0],B[1],A.inwardNormal,$A),s=wB(B[0]+A.inwardNormal[0]*E,B[1]+A.inwardNormal[1]*E,A.text,7,A.angle,"center"),w="horizontal"===A.axis?A.inwardNormal[1]>0?x.maxY-B[1]:B[1]-x.minY:A.inwardNormal[0]>0?x.maxX-B[0]:B[0]-x.minX;return{hardCollisions:Number(K(s))+z.reduce((A,B)=>A+Number(sB(s,B)),0),normalClearance:w}}});for(const A of s.filter(A=>A.short)){const B=A.inwardNormal,E=a(A.a),s=a(A.b),w=(E[0]+s[0])/2,Q=(E[1]+s[1])/2;f.push({kind:"line",points:[[w-1.5*B[0]*$A,Q-1.5*B[1]*$A],[w+1.5*B[0]*$A,Q+1.5*B[1]*$A]],stroke:AB,width:.2*$A})}const Q=new Map;for(const A of s.filter(A=>!A.short)){const B=CB(A,A.inwardNormal),E=Q.get(B)||[];E.push(A),Q.set(B,E)}for(const A of Q.values()){let B=null;for(let E=0;E<=30&&!B;E+=3){const s=A.map(A=>{const B=a(A.mid),s=QB(wB(B[0],B[1],A.text,_A,A.angle,"center"),B[0],B[1],A.inwardNormal,(1+E)*$A),w=B[0]+A.inwardNormal[0]*s,Q=B[1]+A.inwardNormal[1]*s;return{edge:A,x:w,y:Q,box:wB(w,Q,A.text,_A,A.angle,"center")}}),Q=s.some((A,B)=>s.slice(0,B).some(B=>sB(A.box,B.box))),C=s.some(A=>K(A.box)||z.some(B=>sB(A.box,B))),g=s.every(A=>d(A.box,w));Q||C||!g||(B=s)}if(B)for(const A of B)f.push({kind:"text",x:A.x,y:A.y,text:A.edge.text,size:_A,angle:A.edge.angle,align:"center"}),z.push(A.box)}}}const _={minX:m,minY:v,maxX:c-m,maxY:v+V},AA=XA(f),BA=OA(AA,{minX:0,minY:0,maxX:U,maxY:V},.5*$A),sA=function(A,B){const E=XA(A);if(!ZA(E))return{commands:[...A],bounds:E,dx:0,dy:0};const s=(B.minX+B.maxX-E.minX-E.maxX)/2,w=(B.minY+B.maxY-E.minY-E.maxY)/2,Q=function(A,B,E){return A.map(A=>"path"===A.kind?{...A,rings:A.rings.map(A=>A.map(([A,s])=>[A+B,s+E]))}:"line"===A.kind?{...A,points:A.points.map(([A,s])=>[A+B,s+E])}:"vector"===A.kind?{...A,ops:A.ops.map(A=>((A,B,E)=>"M"===A.op||"L"===A.op?{...A,x:A.x+B,y:A.y+E}:"C"===A.op?{...A,x1:A.x1+B,y1:A.y1+E,x2:A.x2+B,y2:A.y2+E,x:A.x+B,y:A.y+E}:A)(A,B,E))}:{...A,x:A.x+B,y:A.y+E})}(A,s,w);return{commands:Q,bounds:{minX:E.minX+s,minY:E.minY+w,maxX:E.maxX+s,maxY:E.maxY+w},dx:s,dy:w}}(f,_);f=sA.commands,f.push({kind:"text",x:m,y:m+10,text:A.space.title,size:14}),A.cardTitle&&f.push({kind:"text",x:c-m,y:m+10,text:A.cardTitle,size:10,align:"right"});const wA=W-m-13*$A;f.push({kind:"line",points:[[m,wA-4*$A],[c-m,wA-4*$A]],stroke:EB,width:.2*$A}),f.push({kind:"text",x:m,y:wA,text:A.t("pdf.scale",{n:E}),size:8});const QA=10*(A.imperial?152.4:100)*$A/E,CA=wA+8;f.push({kind:"line",points:[[m,CA],[m+QA,CA]],stroke:AB,width:.4*$A});for(let A=0;A<=4;A++){const B=m+QA*A/4;f.push({kind:"line",points:[[B,CA-2],[B,CA+2]],stroke:AB,width:.25*$A})}f.push({kind:"text",x:m+QA/2,y:wA+17,text:A.imperial?"5 ft":"1 m",size:7,align:"center"});const gA=t(A.config.settings,A.rawSpace.settings||{});if(null!==gA){const B=c/2,E=wA+5.5*$A;f.push({kind:"vector",ops:FA({centerX:B,centerY:E,size:11*$A,northDeg:gA}),fill:AB,width:0,fillRule:"evenodd"}),f.push({kind:"text",x:B,y:wA,text:A.t("pdf.north"),size:7,align:"center"})}f.push({kind:"text",x:c-m,y:wA+12,text:`${qA(A.now)} · House Plan v${A.version}`,size:7,align:"right"});const IA={width:c,height:W,commands:f,images:(A.rasters||[]).map(({id:A,bytes:B,width:E,height:s})=>({id:A,bytes:B,width:E,height:s})),now:A.now,scale:E,sceneBounds:sA.bounds,planField:_},RA=Math.max(0,TA(AA))*Math.max(0,fA(AA)),MA=U*V;return{page:IA,sceneBounds:sA.bounds,field:_,fits:BA,fillRatio:MA>0?RA/MA:0,landscape:s}}function bB(A,B){return A.fillRatio!==B.fillRatio?A.fillRatio>B.fillRatio?A:B:A.landscape?B:A}function LB(A,B,E){const s=12*$A,w=(E?297:210)*$A-2*s,Q=(E?210:297)*$A-2*s-18*$A-24*$A,C=A.cmPerUnit*(10*$A)/B;return(A.bounds.maxX-A.bounds.minX)*C<=w+.5*$A&&(A.bounds.maxY-A.bounds.minY)*C<=Q+.5*$A}function DB(A){let B=0;for(const E of A)if(B+=Math.max(0,Number(E)||0),B>26214400)throw new Error("pdf.too_large")}const GB="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";async function oB(A,B){if(!A)throw new Error("pdf.asset_failed");const E=await fetch(A,{credentials:"same-origin"});if(!E.ok)throw new Error("pdf.asset_failed");const s=await E.blob();let w;try{w=await createImageBitmap(s)}catch{throw new Error("pdf.asset_failed")}try{if("image/jpeg"===s.type)return{id:B,bytes:new Uint8Array(await s.arrayBuffer()),width:w.width,height:w.height};const A=document.createElement("canvas");A.width=w.width,A.height=w.height;const E=A.getContext("2d");if(!E)throw new Error("pdf.asset_failed");E.fillStyle="#fff",E.fillRect(0,0,A.width,A.height),E.drawImage(w,0,0);const Q=await new Promise(B=>A.toBlob(B,"image/jpeg",.85));if(!Q)throw new Error("pdf.asset_failed");return{id:B,bytes:new Uint8Array(await Q.arrayBuffer()),width:w.width,height:w.height}}finally{w.close()}}async function tB(A,B,E){const s=await async function(A,B){const E=[];if(B.backdrop&&A.space.bg){const B=await oB(A.backdropUrl,"backdrop");E.push({...B,x:A.space.bg.x,y:A.space.bg.y,drawWidth:A.space.bg.w,drawHeight:A.space.bg.h,angle:A.space.bg.angle,opacity:.6})}if(B.decor){let B=0;for(const s of A.rawSpace.decor||[]){if("image"!==s.kind)continue;const w=A.decorAssets.get(s.asset_id),Q=j(s,I,I);if(!w||!Q)throw new Error("pdf.asset_failed");const C=await oB(w.url,"decor"+B++);E.push({...C,x:Q[0],y:Q[1],drawWidth:Q[2],drawHeight:Q[3],opacity:Q[4],angle:Number(s.angle)||0})}}return DB(E.map(A=>A.bytes.byteLength)),E}(A,B),w=JA(function(A){const B=iB(A);let E=[];for(const s of wA){const w=[!1,!0].filter(A=>LB(B,s,A)).map(E=>xB(A,B,s,E));if(!w.length)continue;const Q=w.filter(A=>A.fits);if(Q.length)return Q.reduce(bB).page;E=w}E.length||(E=[!1,!0].map(E=>xB(A,B,500,E)));const s=E.filter(A=>A.fits);if(s.length)return s.reduce(bB).page;const w=Math.min(...E.map(A=>Math.max(TA(A.sceneBounds)/TA(A.field),fA(A.sceneBounds)/fA(A.field)))),Q=50,C=1e6,g=Number.isFinite(w)?Math.ceil(Math.min(C,500*Math.max(1,w))/Q)*Q:C;let I=500,Y=0,R=[],M=Math.max(550,g);for(;M<=C;){const E=[!1,!0].map(E=>xB(A,B,M,E)).filter(A=>A.fits);if(E.length){Y=M,R=E;break}if(I=M,M===C)break;M=Math.min(C,Math.ceil(2*M/Q)*Q)}if(!Y)throw new Error("pdf.failed");let F=Math.floor(I/Q),i=Math.floor(Y/Q);for(;i-F>1;){const E=Math.floor((F+i)/2),s=[!1,!0].map(s=>xB(A,B,E*Q,s)).filter(A=>A.fits);s.length?(i=E,R=s):F=E}const x=R.reduce(bB).page;if(!OA(x.sceneBounds,x.planField,.5*$A))throw new Error("pdf.failed");return x}({...A,options:B,now:E,rasters:s,t:A.t})),Q=new Blob([w],{type:"application/pdf"}),C=URL.createObjectURL(Q);try{const B=document.createElement("a");B.href=C,B.download=`houseplan-${g=A.space.title,g.normalize("NFKD").replace(/[^\p{L}\p{N}]+/gu,"-").replace(/^-|-$/g,"").toLowerCase()||"space"}-${qA(E)}.pdf`,B.style.display="none",document.body.append(B),B.click(),B.remove()}finally{setTimeout(()=>URL.revokeObjectURL(C),0)}var g;return w}class cB{assertRasterBudget(A){DB(A)}render(A){let B;return B={...A,save:async E=>{await tB(A,E,B.now||new Date)}},s``}}export{GB as PDF_EXPORT_FINGERPRINT,cB as PdfExportRuntime,tB as exportSpacePdf}; diff --git a/dist/houseplan-assets/summary-panel-editor-1TWzLmMH.js b/custom_components/houseplan/frontend/houseplan-assets/summary-panel-editor-CNT_mev4.js similarity index 75% rename from dist/houseplan-assets/summary-panel-editor-1TWzLmMH.js rename to custom_components/houseplan/frontend/houseplan-assets/summary-panel-editor-CNT_mev4.js index b83329e7..842d4c9d 100644 --- a/dist/houseplan-assets/summary-panel-editor-1TWzLmMH.js +++ b/custom_components/houseplan/frontend/houseplan-assets/summary-panel-editor-CNT_mev4.js @@ -1,4 +1,4 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{c as a,A as e}from"./houseplan-card-BWAph8ZF.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-BGIJeXIz.js";import"./form-kit.styles-DcvCvE8g.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`
    `}renderDialog(){return this.dialog&&this.editorRenderer?(this.dialog.localOnly||this.refreshEntityIndex(),this.editorRenderer({host:this.host,dialog:this.dialog,local:this.local,storageUnavailable:this.storageUnavailable,problems:this.problems(this.dialog),entityIndex:this.entityIndex||F({},null),setDialog:e=>{this.dialog=e,this.host.requestUpdate()},saveLocal:e=>this.saveLocal(e),mutate:e=>this.mutate(e),deleteBlock:e=>{this.deleteBlock(e)},dragStart:(e,t)=>this.dragStart(e,t),drop:(e,t)=>this.drop(e,t),sourceToken:e=>this.sourceToken(e),openSource:(e,t)=>this.openSource(e,t),closeSource:e=>this.closeSource(e),setSource:(e,t,s)=>this.setSource(e,t,s),save:()=>{this.saveDialog()},reload:()=>{this.reloadDialog()},close:()=>this.closeDialogIfIdle(),t:e=>this.t(e)})):t}t(e){return e.startsWith("summary.")?function(e,t){const s=e.toLowerCase().split("-")[0];return(q[s]||q.en)[t]||q.en[t]||t}(r(this.host.hass,this.host._config?.language),e):this.host._t(e)}ensureStyle(){const e=this.host.renderRoot;if(this.styleSheet&&e.adoptedStyleSheets.includes(this.styleSheet))return;const t=this.host.ownerDocument.defaultView?.CSSStyleSheet;if(t&&"adoptedStyleSheets"in e){const s=new t;return s.replaceSync(R),this.styleSheet=s,void(e.adoptedStyleSheets=[...e.adoptedStyleSheets,s])}if(e.querySelector("style[data-hp-summary]"))return;const s=this.host.ownerDocument.createElement("style");s.dataset.hpSummary="true",s.textContent=R,e.insertBefore(s,e.firstChild)}ensureDialogStyle(){const e=this.host.renderRoot.querySelector('hp-dialog[data-kind="summary"]')?.shadowRoot;if(!e||this.styledDialogRoots.has(e))return;const t=this.host.ownerDocument.defaultView?.CSSStyleSheet;if(t&&"adoptedStyleSheets"in e)this.dialogStyleSheet||(this.dialogStyleSheet=new t,this.dialogStyleSheet.replaceSync(I)),e.adoptedStyleSheets=[...e.adoptedStyleSheets,this.dialogStyleSheet];else{const t=this.host.ownerDocument.createElement("style");t.dataset.hpSummaryShell="true",t.textContent=I,e.appendChild(t)}this.styledDialogRoots.add(e)}placementSlot(){return K(this.host)}preferenceKey(){return function(e){const t=y(e.userId),s=y(e.slot);return t&&s?`houseplan.summary-panel.v1:${[t,y(e.path)||"/",y(e.host)||"card",s].map(e=>encodeURIComponent(e)).join(":")}`:null}({userId:this.host.hass?.user?.id||this.host.hass?.user?.name,path:location.pathname,host:this.host.panelHost?"panel":"lovelace",slot:this.placementSlot()})}identity(){return JSON.stringify({key:this.preferenceKey(),user:this.host.hass?.user?.id||this.host.hass?.user?.name||"",route:location.pathname,host:this.host.panelHost?"panel":"lovelace",slot:this.placementSlot(),kiosk:this.host._kiosk,canManage:this.host._canManageConfiguration})}syncLifecycle(){const e=this.identity();this.lifecycleIdentity&&e!==this.lifecycleIdentity&&this.resetLifecycle(),this.lifecycleIdentity=e}resetLifecycle(){this.presentation.reset(),this.lifecycleGeneration++,this.dialog=null,this.entityIndex=null,this.deviceMemo=null,this.areaMemo=null,this.clockContext="",this.storageKey=null,this.storageUnavailable=!1,this.local={version:1,show:!1,icon_scale:1,font_scale:1},this.clockTimer&&clearTimeout(this.clockTimer),this.clockTimer=0,this.lifecycleIdentity=this.connected?this.identity():"",this.host.requestUpdate()}current(e){return this.connected&&e===this.lifecycleGeneration&&this.lifecycleIdentity===this.identity()}refreshEntityIndex(){this.entityIndex=F(this.host.hass?.states,this.entityIndex)}syncNativeNarrow(){if(this.host.panelHost)return;let e=this.host;for(let t=0;e&&t<12;t++){const t=e.getRootNode();if(e=e.parentNode||(t instanceof ShadowRoot?t.host:null),!e||e===this.host)continue;const s=e.narrow;if("boolean"==typeof s)return void(this.host.narrow!==s&&(this.host.narrow=s))}}loadLocal(){const e=this.preferenceKey();if(!e||e===this.storageKey)return;let t=null,s=null,r=!0;try{t=JSON.parse(localStorage.getItem(e)||"null")}catch{r=!1}try{s=JSON.parse(localStorage.getItem("houseplan_card_kiosk_v1")||"null")}catch{r=!1}this.storageKey=e,this.storageUnavailable=!r,this.local=function(e,t){const s=e&&"object"==typeof e?e:{},r=t&&"object"==typeof t?t:{};return{version:1,show:!0===s.show,icon_scale:M(p(s,"icon_scale")?s.icon_scale:r.icon),font_scale:M(p(s,"font_scale")?s.font_scale:r.font)}}(t,s),this.host._kioskScale={icon:this.local.icon_scale,font:this.local.font_scale}}saveLocal(e){this.local={...this.local,...e,version:1,icon_scale:M(e.icon_scale??this.local.icon_scale),font_scale:M(e.font_scale??this.local.font_scale)},this.host._kioskScale={icon:this.local.icon_scale,font:this.local.font_scale},this.storageKey||=this.preferenceKey();let t=!1;try{this.storageKey&&(localStorage.setItem(this.storageKey,JSON.stringify(this.local)),t=!0)}catch{}this.storageUnavailable=!t,t||this.host._showToast?.(this.t("summary.storage_unavailable")),this.host.requestUpdate()}config(){return function(e,t){const s=e?.summary_panel;return void 0===s?{config:b(t),derived:!0,unsupported:!1}:v(s)?{config:s,derived:!1,unsupported:!1}:{config:null,derived:!1,unsupported:!0}}(this.host._settings,this.translate)}async openDialog(){const e=this.lifecycleGeneration;this.loadLocal();try{this.editorLoad||=import("./summary-panel-editor-1TWzLmMH.js").then(e=>e.renderSummaryPanelEditor),this.editorRenderer=await this.editorLoad}catch(t){if(this.editorLoad=null,!this.current(e))return;return void this.host._showToast?.(`${this.t("summary.load_failed")} ${this.host._errText(t)}`)}if(!this.current(e))return;const t=this.config(),s=t.config||b(this.translate),r=this.host._haSummaryPanelApi!==i,a=t.unsupported?"summary.unsupported_schema":r&&this.host._canManageConfiguration?"summary.backend_required":"summary.local_only";this.dialog={draft:_(s),base:_(s),baseRevision:this.host._cfgRev,localShow:this.local.show,baseLocalShow:this.local.show,localOnly:this.host._kiosk||!this.host._canManageConfiguration||r||t.unsupported,localOnlyHint:a,busy:!1,attempted:!1,entityFilter:"",activeSource:null,error:"",conflict:!1},this.dialog.localOnly||this.refreshEntityIndex(),this.host.requestUpdate()}problems(e=this.dialog){return!e||e.localOnly?[]:k(x(e.draft),e.base,new Set(this.host._model.map(e=>e.id)),new Set(Object.keys(this.host.hass?.states||{})))}mutate(e){if(!this.dialog||this.dialog.busy||this.dialog.localOnly)return;const t=_(this.dialog.draft);e(t);const s=this.dialog.activeSource,r=!s||t.blocks.some(e=>e.id===s.blockId&&e.values.some(e=>e.id===s.valueId));this.dialog={...this.dialog,draft:t,error:"",conflict:!1,activeSource:r?s:null,entityFilter:r?this.dialog.entityFilter:""},this.host.requestUpdate()}async deleteBlock(e){const t=this.dialog?.draft.blocks[e];if(!t)return;const s=this.lifecycleGeneration;if(t.values.length){if(!await this.host._confirmDanger({key:"summary-block",kind:"warning",title:this.t("summary.delete_block_title"),message:this.t("summary.delete_block_body"),objectName:t.title,confirmLabel:this.t("btn.delete"),cancelLabel:this.t("btn.cancel")})||!this.current(s))return}this.mutate(e=>{const s=e.blocks.findIndex(e=>e.id===t.id);s>=0&&e.blocks.splice(s,1)})}sourceToken(e){return"system"===e.type?`system:${e.key}`:`entity:${e.entity_id}`}openSource(e,t){!this.dialog||this.dialog.busy||this.dialog.localOnly||(this.refreshEntityIndex(),this.dialog={...this.dialog,activeSource:{blockId:e,valueId:t},entityFilter:""},this.host.requestUpdate(),this.host.updateComplete.then(()=>{this.dialog?.activeSource?.blockId===e&&this.dialog.activeSource.valueId===t&&this.host.renderRoot.querySelector("[data-summary-picker-search]")?.focus()}))}closeSource(e=!1){const t=this.dialog?.activeSource;this.dialog&&t&&(this.dialog={...this.dialog,activeSource:null,entityFilter:""},this.host.requestUpdate(),e&&this.focusSource(t.blockId,t.valueId))}async focusSource(e,t){await this.host.updateComplete;const s=`${e}\n${t}`,r=this.host.renderRoot.querySelectorAll("[data-summary-source-owner]");[...r].find(e=>e.dataset.summarySourceOwner===s)?.focus()}setSource(e,t,s){this.mutate(r=>{const i=r.blocks.find(t=>t.id===e)?.values.find(e=>e.id===t);if(i)if(s.startsWith("system:")){const e=s.slice(7);(e=>"device_count"===e||"total_area"===e||"datetime"===e)(e)&&(i.source={type:"system",key:e})}else i.source={type:"entity",entity_id:s.startsWith("entity:")?s.slice(7):s}}),this.dialog&&(this.dialog={...this.dialog,activeSource:null,entityFilter:""}),this.host.requestUpdate(),this.focusSource(e,t)}dragStart(e,t){e.dataTransfer?.setData("text/x-houseplan-summary",t),e.dataTransfer&&(e.dataTransfer.effectAllowed="move")}drop(e,t){e.preventDefault(),e.stopPropagation();const s=e.dataTransfer?.getData("text/x-houseplan-summary")||"",r=s.split(":").map(Number),i=t.split(":").map(Number);s.startsWith("block:")&&t.startsWith("block:")?this.mutate(e=>{e.blocks=C(e.blocks,r[1],i[1])}):s.startsWith("value:")&&t.startsWith("value:")&&r[1]===i[1]&&this.mutate(e=>{e.blocks[r[1]].values=C(e.blocks[r[1]].values,r[2],i[2])})}async saveDialog(){const e=this.dialog;if(!e||e.busy)return;const t=this.lifecycleGeneration,s=x(e.draft);if((e.localOnly?[]:k(s,e.base,new Set(this.host._model.map(e=>e.id)),new Set(Object.keys(this.host.hass?.states||{})))).some(e=>"error"===e.kind))return this.dialog={...e,draft:s,attempted:!0},this.host.requestUpdate(),await this.host.updateComplete,void this.host.renderRoot.querySelector('[data-summary-error="true"]')?.focus?.();this.dialog={...e,draft:s,busy:!0,attempted:!1,error:"",conflict:!1},this.host.requestUpdate();try{if(!e.localOnly&&!$(s,e.base)){this.host._writesPending++;const r=a(this.host._writeChain,async()=>{if(!this.current(t))return;if(!this.host._serverCfg)throw new Error(this.t("summary.save_failed"));if(this.host._cfgRev!==e.baseRevision)throw new Error(this.t("summary.conflict"));const r=o({...this.host._serverCfg,settings:{...this.host._serverCfg.settings||{},summary_panel:s}});let i=!1;try{if(await this.host._sendConfigCandidate(r),!this.current(t))return}catch(e){if(!this.current(t))throw e;try{const r=await this.host._getAuthoritativeConfig();if(!this.current(t))throw e;const a=function(e,t){if(!g(e))return null;const s=e.config,r=e.rev;if(!g(s)||!Array.isArray(s.spaces)||"number"!=typeof r||!Number.isSafeInteger(r)||r<0)return null;const i=g(s.settings)?s.settings:null,a=i?.summary_panel;return v(a)&&$(a,t)?{config:s,rev:r}:null}(r,s);if(!a)throw e;const o=await this.host._adoptAuthoritative({cfgResp:r,reason:"summary-recovery",profile:"reload"});if("adopted"!==o.status)throw e;o.spaceChanged&&this.host._restoreZoom(),this.host._regSignature="",this.host._maybeRebuildDevices(),i=!0}catch{throw e}}if(!i){if(!this.current(t))return;this.host._adoption.stageConfigCandidate(r),this.host._cacheSnapshot()}});this.host._writeChain=r,await r.finally(()=>{this.host._writesPending--})}if(!this.current(t))return;this.saveLocal({show:e.localShow}),this.dialog=null}catch(s){if(!this.current(t))return;const r="conflict"===s?.code||this.host._cfgRev!==e.baseRevision;this.dialog={...this.dialog||e,busy:!1,conflict:r,error:r?this.t("summary.conflict"):this.host._errText(s)}}this.current(t)&&this.host.requestUpdate()}async reloadDialog(){const e=this.dialog;if(!e||e.busy)return;const t=this.lifecycleGeneration;this.dialog={...e,busy:!0,error:"",conflict:!1},this.host.requestUpdate();try{if(await this.host._reloadConfigOnly(!0),!this.current(t))return;if(e.conflict&&this.host._cfgRev===e.baseRevision)throw new Error(this.t("summary.load_failed"));const s=this.config().config||b(this.translate);this.dialog={...e,draft:_(s),base:_(s),baseRevision:this.host._cfgRev,busy:!1,attempted:!1,error:"",conflict:!1}}catch(s){if(!this.current(t))return;this.dialog={...e,busy:!1,error:this.host._errText(s),conflict:!0}}this.current(t)&&this.host.requestUpdate()}metricsFresh(){return!!this.deviceMemo&&!!this.areaMemo&&this.deviceMemo.cfgEpoch===this.host._cfgEpoch&&this.deviceMemo.layoutRev===this.host._layoutRev&&this.deviceMemo.registryRev===this.host._haRegistry.revision&&this.areaMemo.cfgEpoch===this.host._cfgEpoch}scheduleMetrics(){if(this.metricsRefresh||!this.metricsModule||this.metricsFresh())return;const e=this.lifecycleGeneration,t="undefined"==typeof window?void 0:window,s=()=>{if(this.metricsRefresh=0,!this.current(e))return;const t=this.advanceMetrics(8);this.host.requestUpdate(),t||this.scheduleMetrics()};this.metricsRefresh=t?.setTimeout(()=>{"function"==typeof t.requestAnimationFrame?t.requestAnimationFrame(()=>t.setTimeout(s,0)):s()},0)||0}advanceMetrics(e=8){const t=this.metricsModule;if(!t)return!0;if(this.computeDeviceCount(),!this.host._serverCfg)return this.areaMemo={cfgEpoch:this.host._cfgEpoch,value:null},!0;if(this.areaMemo&&this.areaMemo.cfgEpoch===this.host._cfgEpoch)return!0;this.areaSteps&&this.areaStepsEpoch===this.host._cfgEpoch||(this.areaSteps=t.cleanFloorAreaSteps(this.host._serverCfg,this.host._model),this.areaStepsEpoch=this.host._cfgEpoch);const s=Date.now();let r=this.areaSteps.next();for(;!r.done&&Date.now()-s[e,t.space])),spaceIds:new Set(this.host._model.map(e=>e.id)),firstSpaceId:this.host._model[0]?.id||"",markers:this.host._markers});this.deviceMemo={cfgEpoch:this.host._cfgEpoch,layoutRev:this.host._layoutRev,registryRev:this.host._haRegistry.revision,value:t?.size??null}}}computeMetrics(){for(;!this.advanceMetrics(Number.POSITIVE_INFINITY););}metrics(){return{deviceCount:this.deviceMemo?this.deviceMemo.value:null,areaM2:this.areaMemo?this.areaMemo.value:null,now:this.clock}}valueState(e){const t=this.metricsModule;if(!t)return{kind:"pending"};if("entity"===e.source.type){const s=t.summaryEntityValue(this.host.hass,e.source.entity_id);return null===s?{kind:"unavailable"}:{kind:"ready",text:s}}const s="device_count"===e.source.key||"total_area"===e.source.key,i="device_count"===e.source.key?this.deviceMemo:this.areaMemo;if(s&&!i)return this.scheduleMetrics(),{kind:"pending"};s&&this.scheduleMetrics();const a=t.summarySystemValue(e.source,this.metrics(),this.host.hass,r(this.host.hass,this.host._config?.language));return null===a?{kind:"unavailable"}:{kind:"ready",text:a}}value(e){const t=this.valueState(e);return"ready"===t.kind?t.text:this.t("summary.unavailable")}ensureMetrics(){if(this.metricsModule||this.metricsLoad)return;const e=this.lifecycleGeneration;this.metricsLoad=import("./summary-panel-metrics-CsJSnPHD.js"),this.metricsLoad.then(t=>{this.metricsModule=t,this.current(e)&&this.host.requestUpdate()}).catch(()=>{}).finally(()=>{this.metricsLoad=null})}layout(){return function(e){const t=Math.max(0,Number(e.width)||0),s=Math.max(0,Number(e.height)||0),r=t>=s?"right":"bottom",i=Math.max(0,e.safeLeft||0)+12,a=Math.max(0,e.safeRight||0)+12,o=Math.max(Math.max(0,e.safeTop||0)+12,e.controlTop||0),n=Math.max(Math.max(0,e.safeBottom||0)+12,e.controlBottom||0),l=Math.max(0,t-i-a),m=Math.max(0,s-o-n),c="bottom"===r?Math.min(.6*s,m):m;return{side:r,fits:t>0&&s>0&&l>=280&&c>=Math.max(0,e.minimumHeight),availableWidth:l,heightCap:c,top:o,bottom:n}}({width:this.stage.width,height:this.stage.height,...this.safeInsets(),controlTop:this.host._kiosk?this.stage.controlTop:0,minimumHeight:this.stage.minimumHeight})}syncPresentation(e=!1){const t=this.config().config,s=this.layout(),r=!!t&&"view"===this.host._mode&&s.fits&&S({view:!0,localShow:!0,showOnMobile:t.show_on_mobile,narrow:this.host.narrow,fits:!0});this.presentation.sync(r&&this.local.show,s.side,e||!r||"hidden"===this.host.ownerDocument.visibilityState)}measureLayout(){const e=this.host._stageEl;if(!e)return;const t=this.host.renderRoot.querySelector(".summary-measure"),s=this.host.renderRoot.querySelector(".summary-control.kiosk"),r=e.getBoundingClientRect(),i=s?.getBoundingClientRect(),a={width:Math.round(e.clientWidth),height:Math.round(e.clientHeight),minimumHeight:Math.max(162,Math.ceil(t?.getBoundingClientRect().height||0)),controlTop:i?Math.max(0,Math.ceil(i.bottom-r.top+12)):0};a.width===this.stage.width&&a.height===this.stage.height&&a.minimumHeight===this.stage.minimumHeight&&a.controlTop===this.stage.controlTop||(this.stage=a,this.host.requestUpdate())}safeInsets(){const e=this.host.renderRoot.querySelector(".summary-safe-probe");if(!e)return{safeLeft:0,safeRight:0,safeTop:0,safeBottom:0};const t=this.host.ownerDocument.defaultView?.getComputedStyle(e);if(!t)return{safeLeft:0,safeRight:0,safeTop:0,safeBottom:0};const s=e=>Number.parseFloat(e)||0;return{safeLeft:s(t.paddingLeft),safeRight:s(t.paddingRight),safeTop:s(t.paddingTop),safeBottom:s(t.paddingBottom)}}hasVisibleClock(){const e=this.config().config;return!("hidden"===this.host.ownerDocument.visibilityState||!e)&&(!!S({view:"view"===this.host._mode,localShow:this.local.show,showOnMobile:e.show_on_mobile,narrow:this.host.narrow,fits:this.layout().fits})&&w(e,this.host._space).some(e=>e.values.some(e=>"system"===e.source.type&&"datetime"===e.source.key)))}syncClock(){const e=`${r(this.host.hass,this.host._config?.language)}\n${this.host.hass?.config?.time_zone||""}`;e!==this.clockContext&&(this.clockContext=e,this.clock=new Date);const t=this.hasVisibleClock();if(t&&!this.clockTimer){this.clock=new Date;const e=()=>{this.clock=new Date,this.clockTimer=0,this.host.requestUpdate(),this.syncClock()};this.clockTimer=window.setTimeout(e,6e4-Date.now()%6e4+25)}else!t&&this.clockTimer&&(clearTimeout(this.clockTimer),this.clockTimer=0)}}});export{A as a,G as b,z as c,D as d,V as e,C as m,x as n,$ as s}; + `}renderDialog(){return this.dialog&&this.editorRenderer?(this.dialog.localOnly||this.refreshEntityIndex(),this.editorRenderer({host:this.host,dialog:this.dialog,local:this.local,storageUnavailable:this.storageUnavailable,problems:this.problems(this.dialog),entityIndex:this.entityIndex||F({},null),setDialog:e=>{this.dialog=e,this.host.requestUpdate()},saveLocal:e=>this.saveLocal(e),mutate:e=>this.mutate(e),deleteBlock:e=>{this.deleteBlock(e)},dragStart:(e,t)=>this.dragStart(e,t),drop:(e,t)=>this.drop(e,t),sourceToken:e=>this.sourceToken(e),openSource:(e,t)=>this.openSource(e,t),closeSource:e=>this.closeSource(e),setSource:(e,t,s)=>this.setSource(e,t,s),save:()=>{this.saveDialog()},reload:()=>{this.reloadDialog()},close:()=>this.closeDialogIfIdle(),t:e=>this.t(e)})):t}t(e){return e.startsWith("summary.")?function(e,t){const s=e.toLowerCase().split("-")[0];return(q[s]||q.en)[t]||q.en[t]||t}(r(this.host.hass,this.host._config?.language),e):this.host._t(e)}ensureStyle(){const e=this.host.renderRoot;if(this.styleSheet&&e.adoptedStyleSheets.includes(this.styleSheet))return;const t=this.host.ownerDocument.defaultView?.CSSStyleSheet;if(t&&"adoptedStyleSheets"in e){const s=new t;return s.replaceSync(R),this.styleSheet=s,void(e.adoptedStyleSheets=[...e.adoptedStyleSheets,s])}if(e.querySelector("style[data-hp-summary]"))return;const s=this.host.ownerDocument.createElement("style");s.dataset.hpSummary="true",s.textContent=R,e.insertBefore(s,e.firstChild)}ensureDialogStyle(){const e=this.host.renderRoot.querySelector('hp-dialog[data-kind="summary"]')?.shadowRoot;if(!e||this.styledDialogRoots.has(e))return;const t=this.host.ownerDocument.defaultView?.CSSStyleSheet;if(t&&"adoptedStyleSheets"in e)this.dialogStyleSheet||(this.dialogStyleSheet=new t,this.dialogStyleSheet.replaceSync(I)),e.adoptedStyleSheets=[...e.adoptedStyleSheets,this.dialogStyleSheet];else{const t=this.host.ownerDocument.createElement("style");t.dataset.hpSummaryShell="true",t.textContent=I,e.appendChild(t)}this.styledDialogRoots.add(e)}placementSlot(){return K(this.host)}preferenceKey(){return function(e){const t=y(e.userId),s=y(e.slot);return t&&s?`houseplan.summary-panel.v1:${[t,y(e.path)||"/",y(e.host)||"card",s].map(e=>encodeURIComponent(e)).join(":")}`:null}({userId:this.host.hass?.user?.id||this.host.hass?.user?.name,path:location.pathname,host:this.host.panelHost?"panel":"lovelace",slot:this.placementSlot()})}identity(){return JSON.stringify({key:this.preferenceKey(),user:this.host.hass?.user?.id||this.host.hass?.user?.name||"",route:location.pathname,host:this.host.panelHost?"panel":"lovelace",slot:this.placementSlot(),kiosk:this.host._kiosk,canManage:this.host._canManageConfiguration})}syncLifecycle(){const e=this.identity();this.lifecycleIdentity&&e!==this.lifecycleIdentity&&this.resetLifecycle(),this.lifecycleIdentity=e}resetLifecycle(){this.presentation.reset(),this.lifecycleGeneration++,this.dialog=null,this.entityIndex=null,this.deviceMemo=null,this.areaMemo=null,this.clockContext="",this.storageKey=null,this.storageUnavailable=!1,this.local={version:1,show:!1,icon_scale:1,font_scale:1},this.clockTimer&&clearTimeout(this.clockTimer),this.clockTimer=0,this.lifecycleIdentity=this.connected?this.identity():"",this.host.requestUpdate()}current(e){return this.connected&&e===this.lifecycleGeneration&&this.lifecycleIdentity===this.identity()}refreshEntityIndex(){this.entityIndex=F(this.host.hass?.states,this.entityIndex)}syncNativeNarrow(){if(this.host.panelHost)return;let e=this.host;for(let t=0;e&&t<12;t++){const t=e.getRootNode();if(e=e.parentNode||(t instanceof ShadowRoot?t.host:null),!e||e===this.host)continue;const s=e.narrow;if("boolean"==typeof s)return void(this.host.narrow!==s&&(this.host.narrow=s))}}loadLocal(){const e=this.preferenceKey();if(!e||e===this.storageKey)return;let t=null,s=null,r=!0;try{t=JSON.parse(localStorage.getItem(e)||"null")}catch{r=!1}try{s=JSON.parse(localStorage.getItem("houseplan_card_kiosk_v1")||"null")}catch{r=!1}this.storageKey=e,this.storageUnavailable=!r,this.local=function(e,t){const s=e&&"object"==typeof e?e:{},r=t&&"object"==typeof t?t:{};return{version:1,show:!0===s.show,icon_scale:M(p(s,"icon_scale")?s.icon_scale:r.icon),font_scale:M(p(s,"font_scale")?s.font_scale:r.font)}}(t,s),this.host._kioskScale={icon:this.local.icon_scale,font:this.local.font_scale}}saveLocal(e){this.local={...this.local,...e,version:1,icon_scale:M(e.icon_scale??this.local.icon_scale),font_scale:M(e.font_scale??this.local.font_scale)},this.host._kioskScale={icon:this.local.icon_scale,font:this.local.font_scale},this.storageKey||=this.preferenceKey();let t=!1;try{this.storageKey&&(localStorage.setItem(this.storageKey,JSON.stringify(this.local)),t=!0)}catch{}this.storageUnavailable=!t,t||this.host._showToast?.(this.t("summary.storage_unavailable")),this.host.requestUpdate()}config(){return function(e,t){const s=e?.summary_panel;return void 0===s?{config:b(t),derived:!0,unsupported:!1}:v(s)?{config:s,derived:!1,unsupported:!1}:{config:null,derived:!1,unsupported:!0}}(this.host._settings,this.translate)}async openDialog(){const e=this.lifecycleGeneration;this.loadLocal();try{this.editorLoad||=import("./summary-panel-editor-CNT_mev4.js").then(e=>e.renderSummaryPanelEditor),this.editorRenderer=await this.editorLoad}catch(t){if(this.editorLoad=null,!this.current(e))return;return void this.host._showToast?.(`${this.t("summary.load_failed")} ${this.host._errText(t)}`)}if(!this.current(e))return;const t=this.config(),s=t.config||b(this.translate),r=this.host._haSummaryPanelApi!==i,a=t.unsupported?"summary.unsupported_schema":r&&this.host._canManageConfiguration?"summary.backend_required":"summary.local_only";this.dialog={draft:_(s),base:_(s),baseRevision:this.host._cfgRev,localShow:this.local.show,baseLocalShow:this.local.show,localOnly:this.host._kiosk||!this.host._canManageConfiguration||r||t.unsupported,localOnlyHint:a,busy:!1,attempted:!1,entityFilter:"",activeSource:null,error:"",conflict:!1},this.dialog.localOnly||this.refreshEntityIndex(),this.host.requestUpdate()}problems(e=this.dialog){return!e||e.localOnly?[]:k(x(e.draft),e.base,new Set(this.host._model.map(e=>e.id)),new Set(Object.keys(this.host.hass?.states||{})))}mutate(e){if(!this.dialog||this.dialog.busy||this.dialog.localOnly)return;const t=_(this.dialog.draft);e(t);const s=this.dialog.activeSource,r=!s||t.blocks.some(e=>e.id===s.blockId&&e.values.some(e=>e.id===s.valueId));this.dialog={...this.dialog,draft:t,error:"",conflict:!1,activeSource:r?s:null,entityFilter:r?this.dialog.entityFilter:""},this.host.requestUpdate()}async deleteBlock(e){const t=this.dialog?.draft.blocks[e];if(!t)return;const s=this.lifecycleGeneration;if(t.values.length){if(!await this.host._confirmDanger({key:"summary-block",kind:"warning",title:this.t("summary.delete_block_title"),message:this.t("summary.delete_block_body"),objectName:t.title,confirmLabel:this.t("btn.delete"),cancelLabel:this.t("btn.cancel")})||!this.current(s))return}this.mutate(e=>{const s=e.blocks.findIndex(e=>e.id===t.id);s>=0&&e.blocks.splice(s,1)})}sourceToken(e){return"system"===e.type?`system:${e.key}`:`entity:${e.entity_id}`}openSource(e,t){!this.dialog||this.dialog.busy||this.dialog.localOnly||(this.refreshEntityIndex(),this.dialog={...this.dialog,activeSource:{blockId:e,valueId:t},entityFilter:""},this.host.requestUpdate(),this.host.updateComplete.then(()=>{this.dialog?.activeSource?.blockId===e&&this.dialog.activeSource.valueId===t&&this.host.renderRoot.querySelector("[data-summary-picker-search]")?.focus()}))}closeSource(e=!1){const t=this.dialog?.activeSource;this.dialog&&t&&(this.dialog={...this.dialog,activeSource:null,entityFilter:""},this.host.requestUpdate(),e&&this.focusSource(t.blockId,t.valueId))}async focusSource(e,t){await this.host.updateComplete;const s=`${e}\n${t}`,r=this.host.renderRoot.querySelectorAll("[data-summary-source-owner]");[...r].find(e=>e.dataset.summarySourceOwner===s)?.focus()}setSource(e,t,s){this.mutate(r=>{const i=r.blocks.find(t=>t.id===e)?.values.find(e=>e.id===t);if(i)if(s.startsWith("system:")){const e=s.slice(7);(e=>"device_count"===e||"total_area"===e||"datetime"===e)(e)&&(i.source={type:"system",key:e})}else i.source={type:"entity",entity_id:s.startsWith("entity:")?s.slice(7):s}}),this.dialog&&(this.dialog={...this.dialog,activeSource:null,entityFilter:""}),this.host.requestUpdate(),this.focusSource(e,t)}dragStart(e,t){e.dataTransfer?.setData("text/x-houseplan-summary",t),e.dataTransfer&&(e.dataTransfer.effectAllowed="move")}drop(e,t){e.preventDefault(),e.stopPropagation();const s=e.dataTransfer?.getData("text/x-houseplan-summary")||"",r=s.split(":").map(Number),i=t.split(":").map(Number);s.startsWith("block:")&&t.startsWith("block:")?this.mutate(e=>{e.blocks=C(e.blocks,r[1],i[1])}):s.startsWith("value:")&&t.startsWith("value:")&&r[1]===i[1]&&this.mutate(e=>{e.blocks[r[1]].values=C(e.blocks[r[1]].values,r[2],i[2])})}async saveDialog(){const e=this.dialog;if(!e||e.busy)return;const t=this.lifecycleGeneration,s=x(e.draft);if((e.localOnly?[]:k(s,e.base,new Set(this.host._model.map(e=>e.id)),new Set(Object.keys(this.host.hass?.states||{})))).some(e=>"error"===e.kind))return this.dialog={...e,draft:s,attempted:!0},this.host.requestUpdate(),await this.host.updateComplete,void this.host.renderRoot.querySelector('[data-summary-error="true"]')?.focus?.();this.dialog={...e,draft:s,busy:!0,attempted:!1,error:"",conflict:!1},this.host.requestUpdate();try{if(!e.localOnly&&!$(s,e.base)){this.host._writesPending++;const r=a(this.host._writeChain,async()=>{if(!this.current(t))return;if(!this.host._serverCfg)throw new Error(this.t("summary.save_failed"));if(this.host._cfgRev!==e.baseRevision)throw new Error(this.t("summary.conflict"));const r=o({...this.host._serverCfg,settings:{...this.host._serverCfg.settings||{},summary_panel:s}});let i=!1;try{if(await this.host._sendConfigCandidate(r),!this.current(t))return}catch(e){if(!this.current(t))throw e;try{const r=await this.host._getAuthoritativeConfig();if(!this.current(t))throw e;const a=function(e,t){if(!g(e))return null;const s=e.config,r=e.rev;if(!g(s)||!Array.isArray(s.spaces)||"number"!=typeof r||!Number.isSafeInteger(r)||r<0)return null;const i=g(s.settings)?s.settings:null,a=i?.summary_panel;return v(a)&&$(a,t)?{config:s,rev:r}:null}(r,s);if(!a)throw e;const o=await this.host._adoptAuthoritative({cfgResp:r,reason:"summary-recovery",profile:"reload"});if("adopted"!==o.status)throw e;o.spaceChanged&&this.host._restoreZoom(),this.host._regSignature="",this.host._maybeRebuildDevices(),i=!0}catch{throw e}}if(!i){if(!this.current(t))return;this.host._adoption.stageConfigCandidate(r),this.host._cacheSnapshot()}});this.host._writeChain=r,await r.finally(()=>{this.host._writesPending--})}if(!this.current(t))return;this.saveLocal({show:e.localShow}),this.dialog=null}catch(s){if(!this.current(t))return;const r="conflict"===s?.code||this.host._cfgRev!==e.baseRevision;this.dialog={...this.dialog||e,busy:!1,conflict:r,error:r?this.t("summary.conflict"):this.host._errText(s)}}this.current(t)&&this.host.requestUpdate()}async reloadDialog(){const e=this.dialog;if(!e||e.busy)return;const t=this.lifecycleGeneration;this.dialog={...e,busy:!0,error:"",conflict:!1},this.host.requestUpdate();try{if(await this.host._reloadConfigOnly(!0),!this.current(t))return;if(e.conflict&&this.host._cfgRev===e.baseRevision)throw new Error(this.t("summary.load_failed"));const s=this.config().config||b(this.translate);this.dialog={...e,draft:_(s),base:_(s),baseRevision:this.host._cfgRev,busy:!1,attempted:!1,error:"",conflict:!1}}catch(s){if(!this.current(t))return;this.dialog={...e,busy:!1,error:this.host._errText(s),conflict:!0}}this.current(t)&&this.host.requestUpdate()}metricsFresh(){return!!this.deviceMemo&&!!this.areaMemo&&this.deviceMemo.cfgEpoch===this.host._cfgEpoch&&this.deviceMemo.layoutRev===this.host._layoutRev&&this.deviceMemo.registryRev===this.host._haRegistry.revision&&this.areaMemo.cfgEpoch===this.host._cfgEpoch}scheduleMetrics(){if(this.metricsRefresh||!this.metricsModule||this.metricsFresh())return;const e=this.lifecycleGeneration,t="undefined"==typeof window?void 0:window,s=()=>{if(this.metricsRefresh=0,!this.current(e))return;const t=this.advanceMetrics(8);this.host.requestUpdate(),t||this.scheduleMetrics()};this.metricsRefresh=t?.setTimeout(()=>{"function"==typeof t.requestAnimationFrame?t.requestAnimationFrame(()=>t.setTimeout(s,0)):s()},0)||0}advanceMetrics(e=8){const t=this.metricsModule;if(!t)return!0;if(this.computeDeviceCount(),!this.host._serverCfg)return this.areaMemo={cfgEpoch:this.host._cfgEpoch,value:null},!0;if(this.areaMemo&&this.areaMemo.cfgEpoch===this.host._cfgEpoch)return!0;this.areaSteps&&this.areaStepsEpoch===this.host._cfgEpoch||(this.areaSteps=t.cleanFloorAreaSteps(this.host._serverCfg,this.host._model),this.areaStepsEpoch=this.host._cfgEpoch);const s=Date.now();let r=this.areaSteps.next();for(;!r.done&&Date.now()-s[e,t.space])),spaceIds:new Set(this.host._model.map(e=>e.id)),firstSpaceId:this.host._model[0]?.id||"",markers:this.host._markers});this.deviceMemo={cfgEpoch:this.host._cfgEpoch,layoutRev:this.host._layoutRev,registryRev:this.host._haRegistry.revision,value:t?.size??null}}}computeMetrics(){for(;!this.advanceMetrics(Number.POSITIVE_INFINITY););}metrics(){return{deviceCount:this.deviceMemo?this.deviceMemo.value:null,areaM2:this.areaMemo?this.areaMemo.value:null,now:this.clock}}valueState(e){const t=this.metricsModule;if(!t)return{kind:"pending"};if("entity"===e.source.type){const s=t.summaryEntityValue(this.host.hass,e.source.entity_id);return null===s?{kind:"unavailable"}:{kind:"ready",text:s}}const s="device_count"===e.source.key||"total_area"===e.source.key,i="device_count"===e.source.key?this.deviceMemo:this.areaMemo;if(s&&!i)return this.scheduleMetrics(),{kind:"pending"};s&&this.scheduleMetrics();const a=t.summarySystemValue(e.source,this.metrics(),this.host.hass,r(this.host.hass,this.host._config?.language));return null===a?{kind:"unavailable"}:{kind:"ready",text:a}}value(e){const t=this.valueState(e);return"ready"===t.kind?t.text:this.t("summary.unavailable")}ensureMetrics(){if(this.metricsModule||this.metricsLoad)return;const e=this.lifecycleGeneration;this.metricsLoad=import("./summary-panel-metrics-BhoEMuKv.js"),this.metricsLoad.then(t=>{this.metricsModule=t,this.current(e)&&this.host.requestUpdate()}).catch(()=>{}).finally(()=>{this.metricsLoad=null})}layout(){return function(e){const t=Math.max(0,Number(e.width)||0),s=Math.max(0,Number(e.height)||0),r=t>=s?"right":"bottom",i=Math.max(0,e.safeLeft||0)+12,a=Math.max(0,e.safeRight||0)+12,o=Math.max(Math.max(0,e.safeTop||0)+12,e.controlTop||0),n=Math.max(Math.max(0,e.safeBottom||0)+12,e.controlBottom||0),l=Math.max(0,t-i-a),m=Math.max(0,s-o-n),c="bottom"===r?Math.min(.6*s,m):m;return{side:r,fits:t>0&&s>0&&l>=280&&c>=Math.max(0,e.minimumHeight),availableWidth:l,heightCap:c,top:o,bottom:n}}({width:this.stage.width,height:this.stage.height,...this.safeInsets(),controlTop:this.host._kiosk?this.stage.controlTop:0,minimumHeight:this.stage.minimumHeight})}syncPresentation(e=!1){const t=this.config().config,s=this.layout(),r=!!t&&"view"===this.host._mode&&s.fits&&S({view:!0,localShow:!0,showOnMobile:t.show_on_mobile,narrow:this.host.narrow,fits:!0});this.presentation.sync(r&&this.local.show,s.side,e||!r||"hidden"===this.host.ownerDocument.visibilityState)}measureLayout(){const e=this.host._stageEl;if(!e)return;const t=this.host.renderRoot.querySelector(".summary-measure"),s=this.host.renderRoot.querySelector(".summary-control.kiosk"),r=e.getBoundingClientRect(),i=s?.getBoundingClientRect(),a={width:Math.round(e.clientWidth),height:Math.round(e.clientHeight),minimumHeight:Math.max(162,Math.ceil(t?.getBoundingClientRect().height||0)),controlTop:i?Math.max(0,Math.ceil(i.bottom-r.top+12)):0};a.width===this.stage.width&&a.height===this.stage.height&&a.minimumHeight===this.stage.minimumHeight&&a.controlTop===this.stage.controlTop||(this.stage=a,this.host.requestUpdate())}safeInsets(){const e=this.host.renderRoot.querySelector(".summary-safe-probe");if(!e)return{safeLeft:0,safeRight:0,safeTop:0,safeBottom:0};const t=this.host.ownerDocument.defaultView?.getComputedStyle(e);if(!t)return{safeLeft:0,safeRight:0,safeTop:0,safeBottom:0};const s=e=>Number.parseFloat(e)||0;return{safeLeft:s(t.paddingLeft),safeRight:s(t.paddingRight),safeTop:s(t.paddingTop),safeBottom:s(t.paddingBottom)}}hasVisibleClock(){const e=this.config().config;return!("hidden"===this.host.ownerDocument.visibilityState||!e)&&(!!S({view:"view"===this.host._mode,localShow:this.local.show,showOnMobile:e.show_on_mobile,narrow:this.host.narrow,fits:this.layout().fits})&&w(e,this.host._space).some(e=>e.values.some(e=>"system"===e.source.type&&"datetime"===e.source.key)))}syncClock(){const e=`${r(this.host.hass,this.host._config?.language)}\n${this.host.hass?.config?.time_zone||""}`;e!==this.clockContext&&(this.clockContext=e,this.clock=new Date);const t=this.hasVisibleClock();if(t&&!this.clockTimer){this.clock=new Date;const e=()=>{this.clock=new Date,this.clockTimer=0,this.host.requestUpdate(),this.syncClock()};this.clockTimer=window.setTimeout(e,6e4-Date.now()%6e4+25)}else!t&&this.clockTimer&&(clearTimeout(this.clockTimer),this.clockTimer=0)}}});export{A as a,G as b,z as c,D as d,V as e,C as m,x as n,$ as s}; diff --git a/dist/houseplan-assets/zigbee-topology-D0gydI7H.js b/custom_components/houseplan/frontend/houseplan-assets/zigbee-topology-CI6PJorK.js similarity index 95% rename from dist/houseplan-assets/zigbee-topology-D0gydI7H.js rename to custom_components/houseplan/frontend/houseplan-assets/zigbee-topology-CI6PJorK.js index 3f3726b1..a8217f2e 100644 --- a/dist/houseplan-assets/zigbee-topology-D0gydI7H.js +++ b/custom_components/houseplan/frontend/houseplan-assets/zigbee-topology-CI6PJorK.js @@ -1 +1 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{s as e,aI as n}from"./houseplan-card-BWAph8ZF.js";var t={title:"Zigbee links",toggle:"Show Zigbee links when hovering over a device",hint:"Shows observed direct neighbours only. Nothing is fetched while you hover.",help:"Shows which Zigbee devices each device talks to directly. Line colour is link quality (LQI) on the same scale as the device's LQI reading: red at 40 and below, green at 180 and above. A dashed line means quality was not reported. An arrow points to the next device on the way to the coordinator: one arrow leads out, incoming arrows are the devices that route through this one. A line without an arrow is a spare neighbour. This is the route tree House Plan builds, not the path a packet takes right now: a label at the end of an arrow means its target is not on this plan, and no arrow at all means the route is unknown. Data comes from the last load and goes stale; links are shown with a mouse only.",help_aria:"Help: Zigbee links",admin_only:"Topology data is available to Home Assistant administrators only.",save_first:"Save this setting before loading topology data.",zha:"ZHA",zha_read:"Read ZHA data",zha_hint:"Reads ZHA's cached topology; it does not start a radio scan.",z2m:"Zigbee2MQTT",z2m_topics:"Base topics (one per line)",z2m_update:"Update map",z2m_warning:"A network-map scan can take 10 seconds to 2 minutes and may temporarily reduce Zigbee responsiveness.",status_idle:"Data not loaded",status_loading:"Loading…",status_ready:"Received {time}",status_stale:"Received {time} · stale",status_partial:"Received {time} · some nodes were omitted",status_no_links:"Received {time} · no observed links found",error_permission:"Administrator permission is required.",error_unsupported:"This provider or Home Assistant API is unavailable.",error_timeout:"The provider did not respond in time.",error_invalid_topic:"Check the Zigbee2MQTT base topic.",error_invalid_payload:"The provider returned unsupported topology data.",error_provider:"Topology data could not be loaded.",remote_count:"+{n} in other spaces",route_device_not_on_plan:"device is not on the plan",route_coordinator_not_on_plan:"coordinator is not on the plan",route_other_space:"another space"};const i={en:t,ru:{title:"Связи Zigbee",toggle:"Показывать связи Zigbee при наведении на устройство",hint:"Показываются только наблюдаемые прямые соседи. Наведение ничего не запрашивает.",help:"Показывает, с какими устройствами Zigbee каждое связано напрямую. Цвет линии — качество связи (LQI) по той же шкале, что у показателя LQI устройства: красный при 40 и ниже, зелёный при 180 и выше. Пунктир — качество не сообщено. Стрелка ведёт к следующему устройству по пути к координатору: исходящая одна, входящие — те, кто ходит через это устройство. Линия без стрелки — запасной сосед. Это дерево маршрутов, которое строит House Plan, а не путь пакета в эту секунду: подпись на конце стрелки значит, что цель не на этом плане, а отсутствие стрелки — что путь неизвестен. Данные из последней загрузки и устаревают, связи видны только при работе мышью.",help_aria:"Справка: связи Zigbee",admin_only:"Данные топологии доступны только администраторам Home Assistant.",save_first:"Сохраните настройку перед загрузкой данных топологии.",zha:"ZHA",zha_read:"Прочитать данные ZHA",zha_hint:"Читает сохранённую топологию ZHA и не запускает радио-сканирование.",z2m:"Zigbee2MQTT",z2m_topics:"Базовые топики (по одному в строке)",z2m_update:"Обновить карту",z2m_warning:"Сканирование карты сети занимает от 10 секунд до 2 минут и временно может снизить отзывчивость Zigbee.",status_idle:"Данные не загружены",status_loading:"Загрузка…",status_ready:"Получено: {time}",status_stale:"Получено: {time} · данные устарели",status_partial:"Получено: {time} · часть узлов не показана",status_no_links:"Получено: {time} · наблюдаемые связи не найдены",error_permission:"Нужны права администратора.",error_unsupported:"Провайдер или API Home Assistant недоступен.",error_timeout:"Провайдер не ответил вовремя.",error_invalid_topic:"Проверьте базовый топик Zigbee2MQTT.",error_invalid_payload:"Провайдер вернул неподдерживаемые данные топологии.",error_provider:"Не удалось загрузить данные топологии.",remote_count:"+{n} в других пространствах",route_device_not_on_plan:"устройства нет на плане",route_coordinator_not_on_plan:"координатора нет на плане",route_other_space:"другое пространство"},de:{title:"Zigbee-Verbindungen",toggle:"Zigbee-Verbindungen beim Darüberfahren über ein Gerät anzeigen",hint:"Es werden nur beobachtete direkte Nachbarn angezeigt. Beim Darüberfahren werden keine Daten abgerufen.",help:"Zeigt, mit welchen Zigbee-Geräten jedes Gerät direkt verbunden ist. Die Linienfarbe ist die Verbindungsqualität (LQI) auf derselben Skala wie der LQI-Wert des Geräts: rot bei 40 und darunter, grün bei 180 und darüber. Eine gestrichelte Linie bedeutet, dass die Qualität nicht gemeldet wurde. Ein Pfeil zeigt auf das nächste Gerät auf dem Weg zum Koordinator: ein Pfeil führt hinaus, eingehende Pfeile sind die Geräte, die über dieses Gerät routen. Eine Linie ohne Pfeil ist ein Ersatznachbar. Das ist der Routenbaum, den House Plan bildet, nicht der Weg eines Pakets in diesem Moment: eine Beschriftung am Pfeilende bedeutet, dass das Ziel nicht auf diesem Plan liegt, und ein fehlender Pfeil, dass die Route unbekannt ist. Die Daten stammen aus dem letzten Laden und veralten; Verbindungen sind nur mit der Maus sichtbar.",help_aria:"Hilfe: Zigbee-Verbindungen",admin_only:"Topologiedaten sind nur für Home-Assistant-Administratoren verfügbar.",save_first:"Speichere diese Einstellung, bevor Topologiedaten geladen werden.",zha:"ZHA",zha_read:"ZHA-Daten lesen",zha_hint:"Liest den ZHA-Topologiecache; es wird kein Funkscan gestartet.",z2m:"Zigbee2MQTT",z2m_topics:"Basistopics (eines pro Zeile)",z2m_update:"Karte aktualisieren",z2m_warning:"Ein Netzwerkscan kann 10 Sekunden bis 2 Minuten dauern und Zigbee vorübergehend verlangsamen.",status_idle:"Daten nicht geladen",status_loading:"Wird geladen…",status_ready:"Empfangen: {time}",status_stale:"Empfangen: {time} · veraltet",status_partial:"Empfangen: {time} · einige Knoten fehlen",status_no_links:"Empfangen: {time} · keine beobachteten Verbindungen gefunden",error_permission:"Administratorrechte sind erforderlich.",error_unsupported:"Dieser Anbieter oder die Home-Assistant-API ist nicht verfügbar.",error_timeout:"Der Anbieter hat nicht rechtzeitig geantwortet.",error_invalid_topic:"Prüfe das Zigbee2MQTT-Basistopic.",error_invalid_payload:"Der Anbieter hat nicht unterstützte Topologiedaten geliefert.",error_provider:"Topologiedaten konnten nicht geladen werden.",remote_count:"+{n} in anderen Bereichen",route_device_not_on_plan:"Gerät ist nicht im Plan",route_coordinator_not_on_plan:"Koordinator ist nicht im Plan",route_other_space:"anderer Bereich"},fr:{title:"Liens Zigbee",toggle:"Afficher les liens Zigbee au survol d’un appareil",hint:"Seuls les voisins directs observés sont affichés. Le survol ne lance aucune requête.",help:"Montre avec quels appareils Zigbee chaque appareil communique directement. La couleur de la ligne est la qualité du lien (LQI) sur la même échelle que l'indicateur LQI de l'appareil : rouge à 40 et en dessous, vert à 180 et au-dessus. Une ligne pointillée signifie que la qualité n'a pas été communiquée. Une flèche pointe vers l'appareil suivant sur le chemin du coordinateur : une flèche part, les flèches entrantes sont les appareils qui passent par celui-ci. Une ligne sans flèche est un voisin de secours. C'est l'arbre de routes que construit House Plan, pas le trajet d'un paquet à cet instant : une étiquette au bout d'une flèche signifie que sa cible n'est pas sur ce plan, et l'absence de flèche que la route est inconnue. Les données proviennent du dernier chargement et vieillissent ; les liens ne sont visibles qu'à la souris.",help_aria:"Aide : liens Zigbee",admin_only:"Les données de topologie sont réservées aux administrateurs Home Assistant.",save_first:"Enregistrez ce réglage avant de charger les données de topologie.",zha:"ZHA",zha_read:"Lire les données ZHA",zha_hint:"Lit la topologie en cache de ZHA sans lancer d’analyse radio.",z2m:"Zigbee2MQTT",z2m_topics:"Topics de base (un par ligne)",z2m_update:"Actualiser la carte",z2m_warning:"L’analyse de la carte réseau peut durer de 10 secondes à 2 minutes et réduire temporairement la réactivité de Zigbee.",status_idle:"Données non chargées",status_loading:"Chargement…",status_ready:"Reçu : {time}",status_stale:"Reçu : {time} · obsolète",status_partial:"Reçu : {time} · certains nœuds sont omis",status_no_links:"Reçu : {time} · aucun lien observé trouvé",error_permission:"Les droits administrateur sont requis.",error_unsupported:"Ce fournisseur ou l’API Home Assistant n’est pas disponible.",error_timeout:"Le fournisseur n’a pas répondu à temps.",error_invalid_topic:"Vérifiez le topic de base Zigbee2MQTT.",error_invalid_payload:"Le fournisseur a renvoyé des données de topologie non prises en charge.",error_provider:"Impossible de charger les données de topologie.",remote_count:"+{n} dans d’autres espaces",route_device_not_on_plan:"appareil absent du plan",route_coordinator_not_on_plan:"coordinateur absent du plan",route_other_space:"autre espace"}};function r(e,n){const r=i[e]?.[n]??t[n];return"string"==typeof r&&r.trim().length>0}function o(n,r,o){return e(i[n]?.[r]??t[r]??r,o)}const s=3e5,a=2097152,d=6e3;function l(e){return null!==e&&"object"==typeof e?e:null}function u(e){if("string"!=typeof e&&"number"!=typeof e)return null;let n=String(e).trim().toLowerCase();return n=/^0x[0-9a-f]{16}$/.test(n)?n.slice(2):n.replace(/[:-]/g,""),/^[0-9a-f]{16}$/.test(n)?n:null}function c(e,n,t){return`${e}:${n}:${t}`}function p(e){const n=String(e||"").toLowerCase().replace(/[ _-]/g,"");return n.includes("coordinator")?"coordinator":n.includes("router")?"router":n.includes("enddevice")||"end"===n?"end":"unknown"}const h=["parent","child","sibling","none","previous_child"];function g(e){const n=l(e),t=function(e){const n=Number(e);return Number.isFinite(n)&&n>=0&&n<=255?Math.round(n):void 0}(n?.lqi??n?.linkquality??n?.link_quality),i=function(e){if("number"==typeof e)return h[e];if("string"!=typeof e)return;const n=e.trim().toLowerCase().replace(/[\s_-]+/g,"");return"previouschild"===n?"previous_child":n.slice(0,40)||void 0}(n?.relationship);return{...void 0===t?{}:{lqi:t},...i?{relationship:i}:{}}}function f(e,n){return Array.isArray(e)&&e.length<=n?e:null}function _(e){if("string"==typeof e)return e.length<=a;try{return JSON.stringify(e).length<=a}catch{return!1}}function b(e,n,t,i,r){if(t===i)return void n.push({code:"self_link",nodeKey:t});const o=t=d){t.push({code:"invalid_payload"});break}const n=l(e),i=u(n?.ieee??n?.ieee_address);if(!i){t.push({code:"invalid_payload",nodeKey:s});continue}const a=c("zha","zha",i);r.has(a)||r.set(a,{key:a,ieee:i,role:p(n?.device_type)}),b(o,t,s,a,e)}else null!=n?.neighbors&&t.push({code:"invalid_payload",nodeKey:s})}return{provider:"zha",instanceId:"zha",obtainedAt:n,freshness:"provider-cache",nodes:[...r.values()],links:[...o.values()],warnings:t}}function v(e,n){const t=l(e),i=u(t?.ieeeAddr??t?.ieee_address??t?.ieee??e);if(i)return i;for(const i of[t?.id,t?.networkAddress,t?.network_address,e])if(null!=i){const e=n.get(String(i));if(e)return e}return null}function y(e,t,i=Date.now()){const r=[],o=n(t)||"invalid",s=_(e)?function(e){let n=e;if("string"==typeof n){if(n.length>a)return null;try{n=JSON.parse(n)}catch{return null}}const t=l(n),i=l(t?.data);if(n=i?.value??t?.value??t?.data??n,"string"==typeof n){if(n.length>a)return null;try{n=JSON.parse(n)}catch{return null}}return n}(e):null,h=l(s),g=f(h?.nodes,1e3),m=f(h?.links,d);if(!g||!m)return{provider:"z2m",instanceId:o,obtainedAt:i,freshness:"fresh-scan",nodes:[],links:[],warnings:[{code:"invalid_payload"}]};const y=new Map,k=new Map;for(const e of g){const n=l(e),t=u(n?.ieeeAddr??n?.ieee_address??n?.ieee);if(!t){r.push({code:"invalid_payload"});continue}const i=c("z2m",o,t);y.set(i,{key:i,ieee:t,role:p(n?.type??n?.device_type),..."boolean"==typeof n?.failed?{available:!n.failed}:{}});for(const e of[n?.id,n?.networkAddress,n?.network_address])null!=e&&k.set(String(e),t)}const w=new Map;for(const e of m){const n=l(e),t=u(n?.sourceIeeeAddr)??v(n?.source,k),i=u(n?.targetIeeeAddr)??v(n?.target,k);if(!t||!i){r.push({code:"invalid_payload"});continue}const s=c("z2m",o,t),a=c("z2m",o,i);y.has(s)||y.set(s,{key:s,ieee:t,role:"unknown"}),y.has(a)||y.set(a,{key:a,ieee:i,role:"unknown"}),b(w,r,s,a,e)}return{provider:"z2m",instanceId:o,obtainedAt:i,freshness:"fresh-scan",nodes:[...y.values()],links:[...w.values()],warnings:r}}function k(e){if("string"!=typeof e)return null;const n=u(e);if(n)return n;const t=e.toLowerCase().match(/^zigbee2mqtt(?:_bridge)?_(.+)$/);return t?u(t[1]):null}function w(e,n){if(e.deviceId&&n.devices[e.deviceId])return[e.deviceId];const t=new Set;for(const[i,r]of Object.entries(n.devices)){const n=l(r);(Array.isArray(n?.identifiers)?n.identifiers:[]).some(n=>Array.isArray(n)&&k(n[1])===e.ieee)&&t.add(i)}if(t.size)return[...t];for(const i of Object.values(n.entities)){const n=l(i);"string"==typeof n?.device_id&&"string"==typeof n.unique_id&&(k(n.unique_id)===e.ieee&&t.add(n.device_id))}return[...t]}function z(e){return!e.hidden&&!e.virtual&&"ha_disabled"!==e.bindingStatus?.kind&&"orphaned"!==e.bindingStatus?.kind&&"unverified"!==e.bindingStatus?.kind}function A(e){const n=new Map,t=new Map,i=e.nodes.filter(e=>"coordinator"===e.role).map(e=>e.key).sort();if(1!==i.length)return{distances:n,parents:t};const r=i[0],o=function(e){const n=new Set(e.nodes.map(e=>e.key)),t=new Map;for(const e of[...n].sort())t.set(e,[]);for(const i of[...e.links].sort((e,n)=>`${e.a}\0${e.b}`.localeCompare(`${n.a}\0${n.b}`)))n.has(i.a)&&n.has(i.b)&&(t.get(i.a).push({neighborKey:i.b,observation:i.aToB}),t.get(i.b).push({neighborKey:i.a,observation:i.bToA}));for(const e of t.values())e.sort((e,n)=>e.neighborKey.localeCompare(n.neighborKey));return t}(e);if(!o.has(r))return{distances:n,parents:t};n.set(r,0);const s=[r];for(let e=0;en.get(e)===i-1).sort((e,n)=>{const t="parent"===e.observation?.relationship?1:0,i="parent"===n.observation?.relationship?1:0;if(t!==i)return i-t;const r=e.observation?.lqi??-1;return(n.observation?.lqi??-1)-r||e.neighborKey.localeCompare(n.neighborKey)});r[0]&&t.set(e,r[0].neighborKey)}return{coordinatorKey:r,distances:n,parents:t}}function Z(e,n,t){const i=new Map,r=[];for(const o of e.nodes){if(!1===o.available){r.push({code:"provider_scan_failure",nodeKey:o.key});continue}const e=w(o,t);if(1!==e.length){r.push({code:"unmatched_device",nodeKey:o.key});continue}const s=e[0];let a=n.filter(e=>z(e)&&"device"===e.bindingKind&&e.bindingRef===s);a.length||(a=n.filter(e=>z(e)&&"entity"===e.bindingKind&&!!e.bindingRef&&t.entities[e.bindingRef]?.device_id===s)),1===a.length?i.set(o.key,{markerId:a[0].id,space:a[0].space}):r.push({code:a.length>1?"ambiguous_placement":"unmatched_device",nodeKey:o.key})}return{placements:i,warnings:r}}function T(e,n,t){return e.map(e=>({topology:e,placements:Z(e,n,t).placements,routes:A(e)}))}function I(e,n,t){const i=new Map,r=new Set,o=new Map;let s=0;for(const{topology:a,placements:d,routes:l}of e){const e=new Set([...d].filter(([,e])=>e.markerId===t&&e.space===n).map(([e])=>e));if(e.size){for(const t of e){const e=l.parents.get(t);if(!e)continue;const i=d.get(e);if(i?.space===n)continue;let r;r=i?{kind:"remote-space",spaceId:i.space}:"coordinator"===a.nodes.find(n=>n.key===e)?.role?{kind:"unplaced-coordinator"}:{kind:"unplaced-device"};const s="remote-space"===r.kind?`${r.kind}:${r.spaceId}`:r.kind;o.set(s,r)}for(const o of a.links){const a=e.has(o.a),u=e.has(o.b);if(!a&&!u)continue;const c=a?o.a:o.b,p=a?o.b:o.a,h=d.get(p);if(!h||h.markerId===t){s++;continue}const g=l.parents.get(c)===p;if(h.space!==n){g||r.add(h.markerId);continue}const f=a?o.aToB:o.bToA,_=g?"toward-neighbor":l.parents.get(p)===c?"toward-origin":void 0,b=i.get(h.markerId);b?(void 0===b.line.lqi&&void 0!==f?.lqi&&(b.line.lqi=f.lqi),_&&b.directions.add(_)):i.set(h.markerId,{line:{neighborMarkerId:h.markerId,lqi:f?.lqi},directions:new Set(_?[_]:[])})}}}return{lines:[...i.values()].map(({line:e,directions:n})=>1===n.size?{...e,routeDirection:[...n][0]}:e),remoteCount:r.size,omittedCount:s,parentTargets:[...o.values()]}}export{s as T,T as a,y as b,r as h,Z as m,m as n,I as r,o as t}; +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{s as e,aI as n}from"./houseplan-card-9fMSy3y3.js";var t={title:"Zigbee links",toggle:"Show Zigbee links when hovering over a device",hint:"Shows observed direct neighbours only. Nothing is fetched while you hover.",help:"Shows which Zigbee devices each device talks to directly. Line colour is link quality (LQI) on the same scale as the device's LQI reading: red at 40 and below, green at 180 and above. A dashed line means quality was not reported. An arrow points to the next device on the way to the coordinator: one arrow leads out, incoming arrows are the devices that route through this one. A line without an arrow is a spare neighbour. This is the route tree House Plan builds, not the path a packet takes right now: a label at the end of an arrow means its target is not on this plan, and no arrow at all means the route is unknown. Data comes from the last load and goes stale; links are shown with a mouse only.",help_aria:"Help: Zigbee links",admin_only:"Topology data is available to Home Assistant administrators only.",save_first:"Save this setting before loading topology data.",zha:"ZHA",zha_read:"Read ZHA data",zha_hint:"Reads ZHA's cached topology; it does not start a radio scan.",z2m:"Zigbee2MQTT",z2m_topics:"Base topics (one per line)",z2m_update:"Update map",z2m_warning:"A network-map scan can take 10 seconds to 2 minutes and may temporarily reduce Zigbee responsiveness.",status_idle:"Data not loaded",status_loading:"Loading…",status_ready:"Received {time}",status_stale:"Received {time} · stale",status_partial:"Received {time} · some nodes were omitted",status_no_links:"Received {time} · no observed links found",error_permission:"Administrator permission is required.",error_unsupported:"This provider or Home Assistant API is unavailable.",error_timeout:"The provider did not respond in time.",error_invalid_topic:"Check the Zigbee2MQTT base topic.",error_invalid_payload:"The provider returned unsupported topology data.",error_provider:"Topology data could not be loaded.",remote_count:"+{n} in other spaces",route_device_not_on_plan:"device is not on the plan",route_coordinator_not_on_plan:"coordinator is not on the plan",route_other_space:"another space"};const i={en:t,ru:{title:"Связи Zigbee",toggle:"Показывать связи Zigbee при наведении на устройство",hint:"Показываются только наблюдаемые прямые соседи. Наведение ничего не запрашивает.",help:"Показывает, с какими устройствами Zigbee каждое связано напрямую. Цвет линии — качество связи (LQI) по той же шкале, что у показателя LQI устройства: красный при 40 и ниже, зелёный при 180 и выше. Пунктир — качество не сообщено. Стрелка ведёт к следующему устройству по пути к координатору: исходящая одна, входящие — те, кто ходит через это устройство. Линия без стрелки — запасной сосед. Это дерево маршрутов, которое строит House Plan, а не путь пакета в эту секунду: подпись на конце стрелки значит, что цель не на этом плане, а отсутствие стрелки — что путь неизвестен. Данные из последней загрузки и устаревают, связи видны только при работе мышью.",help_aria:"Справка: связи Zigbee",admin_only:"Данные топологии доступны только администраторам Home Assistant.",save_first:"Сохраните настройку перед загрузкой данных топологии.",zha:"ZHA",zha_read:"Прочитать данные ZHA",zha_hint:"Читает сохранённую топологию ZHA и не запускает радио-сканирование.",z2m:"Zigbee2MQTT",z2m_topics:"Базовые топики (по одному в строке)",z2m_update:"Обновить карту",z2m_warning:"Сканирование карты сети занимает от 10 секунд до 2 минут и временно может снизить отзывчивость Zigbee.",status_idle:"Данные не загружены",status_loading:"Загрузка…",status_ready:"Получено: {time}",status_stale:"Получено: {time} · данные устарели",status_partial:"Получено: {time} · часть узлов не показана",status_no_links:"Получено: {time} · наблюдаемые связи не найдены",error_permission:"Нужны права администратора.",error_unsupported:"Провайдер или API Home Assistant недоступен.",error_timeout:"Провайдер не ответил вовремя.",error_invalid_topic:"Проверьте базовый топик Zigbee2MQTT.",error_invalid_payload:"Провайдер вернул неподдерживаемые данные топологии.",error_provider:"Не удалось загрузить данные топологии.",remote_count:"+{n} в других пространствах",route_device_not_on_plan:"устройства нет на плане",route_coordinator_not_on_plan:"координатора нет на плане",route_other_space:"другое пространство"},de:{title:"Zigbee-Verbindungen",toggle:"Zigbee-Verbindungen beim Darüberfahren über ein Gerät anzeigen",hint:"Es werden nur beobachtete direkte Nachbarn angezeigt. Beim Darüberfahren werden keine Daten abgerufen.",help:"Zeigt, mit welchen Zigbee-Geräten jedes Gerät direkt verbunden ist. Die Linienfarbe ist die Verbindungsqualität (LQI) auf derselben Skala wie der LQI-Wert des Geräts: rot bei 40 und darunter, grün bei 180 und darüber. Eine gestrichelte Linie bedeutet, dass die Qualität nicht gemeldet wurde. Ein Pfeil zeigt auf das nächste Gerät auf dem Weg zum Koordinator: ein Pfeil führt hinaus, eingehende Pfeile sind die Geräte, die über dieses Gerät routen. Eine Linie ohne Pfeil ist ein Ersatznachbar. Das ist der Routenbaum, den House Plan bildet, nicht der Weg eines Pakets in diesem Moment: eine Beschriftung am Pfeilende bedeutet, dass das Ziel nicht auf diesem Plan liegt, und ein fehlender Pfeil, dass die Route unbekannt ist. Die Daten stammen aus dem letzten Laden und veralten; Verbindungen sind nur mit der Maus sichtbar.",help_aria:"Hilfe: Zigbee-Verbindungen",admin_only:"Topologiedaten sind nur für Home-Assistant-Administratoren verfügbar.",save_first:"Speichere diese Einstellung, bevor Topologiedaten geladen werden.",zha:"ZHA",zha_read:"ZHA-Daten lesen",zha_hint:"Liest den ZHA-Topologiecache; es wird kein Funkscan gestartet.",z2m:"Zigbee2MQTT",z2m_topics:"Basistopics (eines pro Zeile)",z2m_update:"Karte aktualisieren",z2m_warning:"Ein Netzwerkscan kann 10 Sekunden bis 2 Minuten dauern und Zigbee vorübergehend verlangsamen.",status_idle:"Daten nicht geladen",status_loading:"Wird geladen…",status_ready:"Empfangen: {time}",status_stale:"Empfangen: {time} · veraltet",status_partial:"Empfangen: {time} · einige Knoten fehlen",status_no_links:"Empfangen: {time} · keine beobachteten Verbindungen gefunden",error_permission:"Administratorrechte sind erforderlich.",error_unsupported:"Dieser Anbieter oder die Home-Assistant-API ist nicht verfügbar.",error_timeout:"Der Anbieter hat nicht rechtzeitig geantwortet.",error_invalid_topic:"Prüfe das Zigbee2MQTT-Basistopic.",error_invalid_payload:"Der Anbieter hat nicht unterstützte Topologiedaten geliefert.",error_provider:"Topologiedaten konnten nicht geladen werden.",remote_count:"+{n} in anderen Bereichen",route_device_not_on_plan:"Gerät ist nicht im Plan",route_coordinator_not_on_plan:"Koordinator ist nicht im Plan",route_other_space:"anderer Bereich"},fr:{title:"Liens Zigbee",toggle:"Afficher les liens Zigbee au survol d’un appareil",hint:"Seuls les voisins directs observés sont affichés. Le survol ne lance aucune requête.",help:"Montre avec quels appareils Zigbee chaque appareil communique directement. La couleur de la ligne est la qualité du lien (LQI) sur la même échelle que l'indicateur LQI de l'appareil : rouge à 40 et en dessous, vert à 180 et au-dessus. Une ligne pointillée signifie que la qualité n'a pas été communiquée. Une flèche pointe vers l'appareil suivant sur le chemin du coordinateur : une flèche part, les flèches entrantes sont les appareils qui passent par celui-ci. Une ligne sans flèche est un voisin de secours. C'est l'arbre de routes que construit House Plan, pas le trajet d'un paquet à cet instant : une étiquette au bout d'une flèche signifie que sa cible n'est pas sur ce plan, et l'absence de flèche que la route est inconnue. Les données proviennent du dernier chargement et vieillissent ; les liens ne sont visibles qu'à la souris.",help_aria:"Aide : liens Zigbee",admin_only:"Les données de topologie sont réservées aux administrateurs Home Assistant.",save_first:"Enregistrez ce réglage avant de charger les données de topologie.",zha:"ZHA",zha_read:"Lire les données ZHA",zha_hint:"Lit la topologie en cache de ZHA sans lancer d’analyse radio.",z2m:"Zigbee2MQTT",z2m_topics:"Topics de base (un par ligne)",z2m_update:"Actualiser la carte",z2m_warning:"L’analyse de la carte réseau peut durer de 10 secondes à 2 minutes et réduire temporairement la réactivité de Zigbee.",status_idle:"Données non chargées",status_loading:"Chargement…",status_ready:"Reçu : {time}",status_stale:"Reçu : {time} · obsolète",status_partial:"Reçu : {time} · certains nœuds sont omis",status_no_links:"Reçu : {time} · aucun lien observé trouvé",error_permission:"Les droits administrateur sont requis.",error_unsupported:"Ce fournisseur ou l’API Home Assistant n’est pas disponible.",error_timeout:"Le fournisseur n’a pas répondu à temps.",error_invalid_topic:"Vérifiez le topic de base Zigbee2MQTT.",error_invalid_payload:"Le fournisseur a renvoyé des données de topologie non prises en charge.",error_provider:"Impossible de charger les données de topologie.",remote_count:"+{n} dans d’autres espaces",route_device_not_on_plan:"appareil absent du plan",route_coordinator_not_on_plan:"coordinateur absent du plan",route_other_space:"autre espace"}};function r(e,n){const r=i[e]?.[n]??t[n];return"string"==typeof r&&r.trim().length>0}function o(n,r,o){return e(i[n]?.[r]??t[r]??r,o)}const s=3e5,a=2097152,d=6e3;function l(e){return null!==e&&"object"==typeof e?e:null}function u(e){if("string"!=typeof e&&"number"!=typeof e)return null;let n=String(e).trim().toLowerCase();return n=/^0x[0-9a-f]{16}$/.test(n)?n.slice(2):n.replace(/[:-]/g,""),/^[0-9a-f]{16}$/.test(n)?n:null}function c(e,n,t){return`${e}:${n}:${t}`}function p(e){const n=String(e||"").toLowerCase().replace(/[ _-]/g,"");return n.includes("coordinator")?"coordinator":n.includes("router")?"router":n.includes("enddevice")||"end"===n?"end":"unknown"}const h=["parent","child","sibling","none","previous_child"];function g(e){const n=l(e),t=function(e){const n=Number(e);return Number.isFinite(n)&&n>=0&&n<=255?Math.round(n):void 0}(n?.lqi??n?.linkquality??n?.link_quality),i=function(e){if("number"==typeof e)return h[e];if("string"!=typeof e)return;const n=e.trim().toLowerCase().replace(/[\s_-]+/g,"");return"previouschild"===n?"previous_child":n.slice(0,40)||void 0}(n?.relationship);return{...void 0===t?{}:{lqi:t},...i?{relationship:i}:{}}}function f(e,n){return Array.isArray(e)&&e.length<=n?e:null}function _(e){if("string"==typeof e)return e.length<=a;try{return JSON.stringify(e).length<=a}catch{return!1}}function m(e,n,t,i,r){if(t===i)return void n.push({code:"self_link",nodeKey:t});const o=t=d){t.push({code:"invalid_payload"});break}const n=l(e),i=u(n?.ieee??n?.ieee_address);if(!i){t.push({code:"invalid_payload",nodeKey:s});continue}const a=c("zha","zha",i);r.has(a)||r.set(a,{key:a,ieee:i,role:p(n?.device_type)}),m(o,t,s,a,e)}else null!=n?.neighbors&&t.push({code:"invalid_payload",nodeKey:s})}return{provider:"zha",instanceId:"zha",obtainedAt:n,freshness:"provider-cache",nodes:[...r.values()],links:[...o.values()],warnings:t}}function v(e,n){const t=l(e),i=u(t?.ieeeAddr??t?.ieee_address??t?.ieee??e);if(i)return i;for(const i of[t?.id,t?.networkAddress,t?.network_address,e])if(null!=i){const e=n.get(String(i));if(e)return e}return null}function y(e,t,i=Date.now()){const r=[],o=n(t)||"invalid",s=_(e)?function(e){let n=e;if("string"==typeof n){if(n.length>a)return null;try{n=JSON.parse(n)}catch{return null}}const t=l(n),i=l(t?.data);if(n=i?.value??t?.value??t?.data??n,"string"==typeof n){if(n.length>a)return null;try{n=JSON.parse(n)}catch{return null}}return n}(e):null,h=l(s),g=f(h?.nodes,1e3),b=f(h?.links,d);if(!g||!b)return{provider:"z2m",instanceId:o,obtainedAt:i,freshness:"fresh-scan",nodes:[],links:[],warnings:[{code:"invalid_payload"}]};const y=new Map,k=new Map;for(const e of g){const n=l(e),t=u(n?.ieeeAddr??n?.ieee_address??n?.ieee);if(!t){r.push({code:"invalid_payload"});continue}const i=c("z2m",o,t);y.set(i,{key:i,ieee:t,role:p(n?.type??n?.device_type),..."boolean"==typeof n?.failed?{available:!n.failed}:{}});for(const e of[n?.id,n?.networkAddress,n?.network_address])null!=e&&k.set(String(e),t)}const w=new Map;for(const e of b){const n=l(e),t=u(n?.sourceIeeeAddr)??v(n?.source,k),i=u(n?.targetIeeeAddr)??v(n?.target,k);if(!t||!i){r.push({code:"invalid_payload"});continue}const s=c("z2m",o,t),a=c("z2m",o,i);y.has(s)||y.set(s,{key:s,ieee:t,role:"unknown"}),y.has(a)||y.set(a,{key:a,ieee:i,role:"unknown"}),m(w,r,s,a,e)}return{provider:"z2m",instanceId:o,obtainedAt:i,freshness:"fresh-scan",nodes:[...y.values()],links:[...w.values()],warnings:r}}function k(e){if("string"!=typeof e)return null;const n=u(e);if(n)return n;const t=e.toLowerCase().match(/^zigbee2mqtt(?:_bridge)?_(.+)$/);return t?u(t[1]):null}function w(e,n){if(e.deviceId&&n.devices[e.deviceId])return[e.deviceId];const t=new Set;for(const[i,r]of Object.entries(n.devices)){const n=l(r);(Array.isArray(n?.identifiers)?n.identifiers:[]).some(n=>Array.isArray(n)&&k(n[1])===e.ieee)&&t.add(i)}if(t.size)return[...t];for(const i of Object.values(n.entities)){const n=l(i);"string"==typeof n?.device_id&&"string"==typeof n.unique_id&&(k(n.unique_id)===e.ieee&&t.add(n.device_id))}return[...t]}function z(e){return!e.hidden&&!e.virtual&&"ha_disabled"!==e.bindingStatus?.kind&&"orphaned"!==e.bindingStatus?.kind&&"unverified"!==e.bindingStatus?.kind}function A(e){const n=new Map,t=new Map,i=e.nodes.filter(e=>"coordinator"===e.role).map(e=>e.key).sort();if(1!==i.length)return{distances:n,parents:t};const r=i[0],o=function(e){const n=new Set(e.nodes.map(e=>e.key)),t=new Map;for(const e of[...n].sort())t.set(e,[]);for(const i of[...e.links].sort((e,n)=>`${e.a}\0${e.b}`.localeCompare(`${n.a}\0${n.b}`)))n.has(i.a)&&n.has(i.b)&&(t.get(i.a).push({neighborKey:i.b,observation:i.aToB}),t.get(i.b).push({neighborKey:i.a,observation:i.bToA}));for(const e of t.values())e.sort((e,n)=>e.neighborKey.localeCompare(n.neighborKey));return t}(e);if(!o.has(r))return{distances:n,parents:t};n.set(r,0);const s=[r];for(let e=0;en.get(e)===i-1).sort((e,n)=>{const t="parent"===e.observation?.relationship?1:0,i="parent"===n.observation?.relationship?1:0;if(t!==i)return i-t;const r=e.observation?.lqi??-1;return(n.observation?.lqi??-1)-r||e.neighborKey.localeCompare(n.neighborKey)});r[0]&&t.set(e,r[0].neighborKey)}return{coordinatorKey:r,distances:n,parents:t}}function Z(e,n,t){const i=new Map,r=[];for(const o of e.nodes){if(!1===o.available){r.push({code:"provider_scan_failure",nodeKey:o.key});continue}const e=w(o,t);if(1!==e.length){r.push({code:"unmatched_device",nodeKey:o.key});continue}const s=e[0];let a=n.filter(e=>z(e)&&"device"===e.bindingKind&&e.bindingRef===s);a.length||(a=n.filter(e=>z(e)&&"entity"===e.bindingKind&&!!e.bindingRef&&t.entities[e.bindingRef]?.device_id===s)),1===a.length?i.set(o.key,{markerId:a[0].id,space:a[0].space}):r.push({code:a.length>1?"ambiguous_placement":"unmatched_device",nodeKey:o.key})}return{placements:i,warnings:r}}function T(e,n,t){return e.map(e=>({topology:e,placements:Z(e,n,t).placements,routes:A(e)}))}function I(e,n,t){const i=new Map,r=new Set,o=new Map;let s=0;for(const{topology:a,placements:d,routes:l}of e){const e=new Set([...d].filter(([,e])=>e.markerId===t&&e.space===n).map(([e])=>e));if(e.size){for(const t of e){const e=l.parents.get(t);if(!e)continue;const i=d.get(e);if(i?.space===n)continue;let r;r=i?{kind:"remote-space",spaceId:i.space}:"coordinator"===a.nodes.find(n=>n.key===e)?.role?{kind:"unplaced-coordinator"}:{kind:"unplaced-device"};const s="remote-space"===r.kind?`${r.kind}:${r.spaceId}`:r.kind;o.set(s,r)}for(const o of a.links){const a=e.has(o.a),u=e.has(o.b);if(!a&&!u)continue;const c=a?o.a:o.b,p=a?o.b:o.a,h=d.get(p);if(!h||h.markerId===t){s++;continue}const g=l.parents.get(c)===p;if(h.space!==n){g||r.add(h.markerId);continue}const f=a?o.aToB:o.bToA,_=g?"toward-neighbor":l.parents.get(p)===c?"toward-origin":void 0,m=i.get(h.markerId);m?(void 0===m.line.lqi&&void 0!==f?.lqi&&(m.line.lqi=f.lqi),_&&m.directions.add(_)):i.set(h.markerId,{line:{neighborMarkerId:h.markerId,lqi:f?.lqi},directions:new Set(_?[_]:[])})}}}return{lines:[...i.values()].map(({line:e,directions:n})=>1===n.size?{...e,routeDirection:[...n][0]}:e),remoteCount:r.size,omittedCount:s,parentTargets:[...o.values()]}}export{s as T,T as a,y as b,r as h,Z as m,b as n,I as r,o as t}; diff --git a/custom_components/houseplan/frontend/houseplan-assets/zigbee-topology-runtime-BXasXMdL.js b/custom_components/houseplan/frontend/houseplan-assets/zigbee-topology-runtime-d-S2Abll.js similarity index 93% rename from custom_components/houseplan/frontend/houseplan-assets/zigbee-topology-runtime-BXasXMdL.js rename to custom_components/houseplan/frontend/houseplan-assets/zigbee-topology-runtime-d-S2Abll.js index 105e28f5..5f755073 100644 --- a/custom_components/houseplan/frontend/houseplan-assets/zigbee-topology-runtime-BXasXMdL.js +++ b/custom_components/houseplan/frontend/houseplan-assets/zigbee-topology-runtime-d-S2Abll.js @@ -1 +1 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{n as t,b as n}from"./zigbee-topology-D0gydI7H.js";import{aI as e}from"./houseplan-card-BWAph8ZF.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function f(t){if(!0!==t?.user?.is_admin)throw a("permission")}function p(n){const e=i(n);return e?c(e,"zha",async()=>{if(f(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function m(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function g(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(f(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,p=null,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,g=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const f=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&p?.(n):c&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await m(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await m(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{p as readZhaTopology,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot}; +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{n as t,b as n}from"./zigbee-topology-CI6PJorK.js";import{aI as e}from"./houseplan-card-9fMSy3y3.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function f(t){if(!0!==t?.user?.is_admin)throw a("permission")}function p(n){const e=i(n);return e?c(e,"zha",async()=>{if(f(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function m(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function g(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(f(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,p=null,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,g=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const f=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&p?.(n):c&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await m(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await m(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{p as readZhaTopology,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot}; diff --git a/custom_components/houseplan/frontend/houseplan-card.js b/custom_components/houseplan/frontend/houseplan-card.js index a151f1cf..7ef80fee 100644 --- a/custom_components/houseplan/frontend/houseplan-card.js +++ b/custom_components/houseplan/frontend/houseplan-card.js @@ -1 +1 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";try{await import("./houseplan-assets/houseplan-card-BWAph8ZF.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)} +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";try{await import("./houseplan-assets/houseplan-card-9fMSy3y3.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)} diff --git a/custom_components/houseplan/frontend/houseplan-panel.js b/custom_components/houseplan/frontend/houseplan-panel.js index c386a019..4b698642 100644 --- a/custom_components/houseplan/frontend/houseplan-panel.js +++ b/custom_components/houseplan/frontend/houseplan-panel.js @@ -1 +1 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";try{await import("./houseplan-assets/houseplan-card-BWAph8ZF.js")}catch(e){if(!customElements.get("houseplan-panel")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-panel",class extends HTMLElement{connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;min-height:100%;background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-panel.js: the card implementation chunk is unavailable",e)}const e=["panel","hass","narrow","route"];class n extends HTMLElement{constructor(){super(),this._narrow=!1,this.attachShadow({mode:"open"}),this._adoptPreUpgradeProperties()}connectedCallback(){this._adoptPreUpgradeProperties(),this._ensureShell()}_adoptPreUpgradeProperties(){for(const n of e){if(!Object.prototype.hasOwnProperty.call(this,n))continue;const e=this[n];delete this[n],this[n]=e}}get hass(){return this._hass}set hass(e){this._hass=e,this._ensureShell(),this._card&&(this._card.hass=e),this._syncMenuLabel()}get narrow(){return this._narrow}set narrow(e){this._narrow=Boolean(e),this.toggleAttribute("narrow",this._narrow),this._card&&(this._card.narrow=this._narrow)}get route(){return this._route}set route(e){this._route=e}get panel(){return this._panel}set panel(e){this._panel=e}_ensureShell(){if(this._card||!this.shadowRoot)return;const e=document.createElement("style");e.textContent="\n :host {\n display: block;\n width: 100%;\n /* HA mounts a custom panel inside , a block with\n * safe-area padding and NO height, so a percentage here resolves to\n * auto and the stage collapses to 0 px (#488). Take the viewport\n * like HA's own iframe panels do, minus the insets HA pads with. */\n height: 100vh;\n height: calc(100dvh - var(--safe-area-inset-top, 0px) - var(--safe-area-inset-bottom, 0px));\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n color: var(--primary-text-color);\n background: var(--primary-background-color);\n }\n .page {\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n display: grid;\n grid-template-rows: auto minmax(0, 1fr);\n overflow: hidden;\n }\n .appbar {\n box-sizing: border-box;\n min-width: 0;\n min-height: var(--header-height, 56px);\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 0 16px;\n background: var(--app-header-background-color, var(--primary-background-color));\n color: var(--app-header-text-color, var(--primary-text-color));\n border-bottom: 1px solid var(--divider-color);\n z-index: 1;\n }\n .toolbar {\n min-width: 0;\n width: 100%;\n display: flex;\n align-items: center;\n gap: 12px;\n }\n .menu {\n box-sizing: border-box;\n width: 44px;\n height: 44px;\n min-width: 44px;\n min-height: 44px;\n margin: 0;\n padding: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: 0;\n border-radius: 50%;\n color: inherit;\n background: transparent;\n cursor: pointer;\n }\n .menu:focus-visible {\n outline: 2px solid var(--primary-color);\n outline-offset: 2px;\n }\n @media (hover: hover) {\n .menu:hover { background: var(--secondary-background-color); }\n }\n .menu ha-icon { --mdc-icon-size: 24px; }\n .title {\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 20px;\n font-weight: 500;\n line-height: 1.2;\n }\n .title ha-icon {\n --mdc-icon-size: 24px;\n color: var(--primary-color);\n }\n .content {\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n }\n houseplan-card {\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n }\n ";const n=document.createElement("div");n.className="page";const t=document.createElement("header");t.className="appbar";const a=document.createElement("div");a.className="toolbar",a.setAttribute("role","toolbar");const o=document.createElement("button");o.className="menu",o.dataset.hp="panel-menu",o.type="button",o.innerHTML='',o.addEventListener("click",()=>{o.dispatchEvent(new CustomEvent("hass-toggle-menu",{bubbles:!0,composed:!0}))}),this._menuButton=o;const i=document.createElement("div");i.className="title",i.dataset.hp="panel-title",i.setAttribute("role","heading"),i.setAttribute("aria-level","1"),i.innerHTML='House Plan',a.append(o,i),t.append(a);const r=document.createElement("main");r.className="content";const s=document.createElement("houseplan-card");s.panelHost=!0,s.narrow=this._narrow,s.setConfig({type:"custom:houseplan-card"}),void 0!==this._hass&&(s.hass=this._hass),r.append(s),n.append(t,r),this.shadowRoot.append(e,n),this._card=s,this._syncMenuLabel()}_syncMenuLabel(){if(!this._menuButton)return;const e=this._hass?.localize?.("ui.common.menu")||this._hass?.localize?.("ui.panel.lovelace.menu")||"Menu";this._menuButton.setAttribute("aria-label",e),this._menuButton.title=e}}customElements.get("houseplan-panel")||customElements.define("houseplan-panel",n);export{n as HouseplanPanel}; +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";try{await import("./houseplan-assets/houseplan-card-9fMSy3y3.js")}catch(e){if(!customElements.get("houseplan-panel")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-panel",class extends HTMLElement{connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;min-height:100%;background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-panel.js: the card implementation chunk is unavailable",e)}const e=["panel","hass","narrow","route"];class n extends HTMLElement{constructor(){super(),this._narrow=!1,this.attachShadow({mode:"open"}),this._adoptPreUpgradeProperties()}connectedCallback(){this._adoptPreUpgradeProperties(),this._ensureShell()}_adoptPreUpgradeProperties(){for(const n of e){if(!Object.prototype.hasOwnProperty.call(this,n))continue;const e=this[n];delete this[n],this[n]=e}}get hass(){return this._hass}set hass(e){this._hass=e,this._ensureShell(),this._card&&(this._card.hass=e),this._syncMenuLabel()}get narrow(){return this._narrow}set narrow(e){this._narrow=Boolean(e),this.toggleAttribute("narrow",this._narrow),this._card&&(this._card.narrow=this._narrow)}get route(){return this._route}set route(e){this._route=e}get panel(){return this._panel}set panel(e){this._panel=e}_ensureShell(){if(this._card||!this.shadowRoot)return;const e=document.createElement("style");e.textContent="\n :host {\n display: block;\n width: 100%;\n /* HA mounts a custom panel inside , a block with\n * safe-area padding and NO height, so a percentage here resolves to\n * auto and the stage collapses to 0 px (#488). Take the viewport\n * like HA's own iframe panels do, minus the insets HA pads with. */\n height: 100vh;\n height: calc(100dvh - var(--safe-area-inset-top, 0px) - var(--safe-area-inset-bottom, 0px));\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n color: var(--primary-text-color);\n background: var(--primary-background-color);\n }\n .page {\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n display: grid;\n grid-template-rows: auto minmax(0, 1fr);\n overflow: hidden;\n }\n .appbar {\n box-sizing: border-box;\n min-width: 0;\n min-height: var(--header-height, 56px);\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 0 16px;\n background: var(--app-header-background-color, var(--primary-background-color));\n color: var(--app-header-text-color, var(--primary-text-color));\n border-bottom: 1px solid var(--divider-color);\n z-index: 1;\n }\n .toolbar {\n min-width: 0;\n width: 100%;\n display: flex;\n align-items: center;\n gap: 12px;\n }\n .menu {\n box-sizing: border-box;\n width: 44px;\n height: 44px;\n min-width: 44px;\n min-height: 44px;\n margin: 0;\n padding: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: 0;\n border-radius: 50%;\n color: inherit;\n background: transparent;\n cursor: pointer;\n }\n .menu:focus-visible {\n outline: 2px solid var(--primary-color);\n outline-offset: 2px;\n }\n @media (hover: hover) {\n .menu:hover { background: var(--secondary-background-color); }\n }\n .menu ha-icon { --mdc-icon-size: 24px; }\n .title {\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 20px;\n font-weight: 500;\n line-height: 1.2;\n }\n .title ha-icon {\n --mdc-icon-size: 24px;\n color: var(--primary-color);\n }\n .content {\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n }\n houseplan-card {\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n }\n ";const n=document.createElement("div");n.className="page";const t=document.createElement("header");t.className="appbar";const a=document.createElement("div");a.className="toolbar",a.setAttribute("role","toolbar");const o=document.createElement("button");o.className="menu",o.dataset.hp="panel-menu",o.type="button",o.innerHTML='',o.addEventListener("click",()=>{o.dispatchEvent(new CustomEvent("hass-toggle-menu",{bubbles:!0,composed:!0}))}),this._menuButton=o;const i=document.createElement("div");i.className="title",i.dataset.hp="panel-title",i.setAttribute("role","heading"),i.setAttribute("aria-level","1"),i.innerHTML='House Plan',a.append(o,i),t.append(a);const r=document.createElement("main");r.className="content";const s=document.createElement("houseplan-card");s.panelHost=!0,s.narrow=this._narrow,s.setConfig({type:"custom:houseplan-card"}),void 0!==this._hass&&(s.hass=this._hass),r.append(s),n.append(t,r),this.shadowRoot.append(e,n),this._card=s,this._syncMenuLabel()}_syncMenuLabel(){if(!this._menuButton)return;const e=this._hass?.localize?.("ui.common.menu")||this._hass?.localize?.("ui.panel.lovelace.menu")||"Menu";this._menuButton.setAttribute("aria-label",e),this._menuButton.title=e}}customElements.get("houseplan-panel")||customElements.define("houseplan-panel",n);export{n as HouseplanPanel}; diff --git a/demo/smoke_device_settings_form.mjs b/demo/smoke_device_settings_form.mjs index ab257b01..9742cf5c 100644 --- a/demo/smoke_device_settings_form.mjs +++ b/demo/smoke_device_settings_form.mjs @@ -98,13 +98,17 @@ const out = await page.evaluate(async () => { input(q('#marker-glow-brightness'), '42'); await upd(); o.brightnessNumberWrites = c._markerDialog.glowBrightness === 42 && c._markerDialog.glowTouched === true; o.radiusHintWhenEmpty = c._markerDialog.glowRadius === '' && !!q('#marker-glow-radius')?.closest('.hpf-field')?.querySelector('.hpf-hint'); + // Ревью r1 M2: радиус — не условие Save. Нечисло или ноль, как на dev, при + // сохранении молча становится общим радиусом; поле не помечается ошибкой. c._markerDialog = { ...c._markerDialog, glowRadius: 'x' }; await upd(); - o.badRadiusBlocksSave = saveBtn().disabled === true && !!q('#marker-glow-radius[aria-invalid="true"]') - && !!q('.hpf-card[data-card="light"] .hpf-error') && !!q('.hpf-status .hpf-link'); - q('.hpf-status .hpf-link').click(); await upd(); - o.reviewLinkFocusesRadius = (sr().activeElement ?? document.activeElement)?.id === 'marker-glow-radius'; + o.badRadiusDoesNotBlockSave = saveBtn().disabled === false && !q('#marker-glow-radius[aria-invalid="true"]') + && !q('.hpf-card[data-card="light"] .hpf-error') && !q('.hpf-status .hpf-link'); input(q('#marker-glow-radius'), '2.5'); await upd(); o.radiusWrites = c._markerDialog.glowRadius === '2.5' && saveBtn().disabled === false; + // «Review N fields» ведёт к первому ошибочному полю — здесь к привязке (create-режим ниже проверяет ссылку). + input(q('#marker-glow-radius'), '0'); await upd(); + o.zeroRadiusKeepsSaveEnabled = saveBtn().disabled === false; + input(q('#marker-glow-radius'), ''); await upd(); // --- Appearance: иконка, display, бейдж, превью (Q3), размеры ---------------- o.iconFieldHasPreview = !!q('#marker-icon') && !!q('.hpf-iconfield .hpf-iconpreview ha-icon'); @@ -172,6 +176,8 @@ const out = await page.evaluate(async () => { await pickSeg('bmode', 'ha'); o.createHaWithoutBindingIsAProblem = saveBtn().disabled === true && !!q('.hpf-status .hpf-link') && !!q('.hpf-card[data-card="basics"] .hpf-error') && q('#marker-binding').getAttribute('aria-expanded') === 'true'; + q('.hpf-status .hpf-link').click(); await upd(); + o.reviewLinkFocusesBinding = (sr().activeElement ?? document.activeElement)?.id === 'marker-binding'; await pickSeg('bmode', 'virtual'); o.createVirtualHasHint = c._markerDialog.binding === 'virtual' && saveBtn().disabled === false && !!q('input[name="bmode"]')?.closest('.hpf-field')?.querySelector('.hpf-hint'); diff --git a/demo/smoke_dialog_help_clipping.mjs b/demo/smoke_dialog_help_clipping.mjs new file mode 100644 index 00000000..24ba53bc --- /dev/null +++ b/demo/smoke_dialog_help_clipping.mjs @@ -0,0 +1,134 @@ +// #600 AC8, дефект №5 («поповер «?» обрезается границей диалога комнаты»), +// ревью r1 M3: свидетель, что подсказка «?» в диалоге комнаты не режется ни +// скроллером диалога, ни поверхностью ha-dialog. +// +// Проверяется исполнением, а не чтением: подсказка открывается у карточки, +// прижатой к нижнему краю короткого окна (диалог скроллится), и каждый угол её +// прямоугольника hit-test'ом (elementsFromPoint сквозь теневые корни) попадает +// в саму подсказку — обрезанная часть элемента не hit-test'ится. Четыре +// комбинации: нативный и ветка ha-dialog × Popover API и портальный +// fallback. Ветка ha-dialog берётся заглушкой с теми же ловушками, что у +// настоящей mwc-поверхности: transform на поверхности (ловит position: fixed) и +// overflow: hidden с собственным скроллером содержимого. Настоящий ha-dialog +// (#505) требует загрузки колеса HA-frontend — это отдельная приёмка владельца. +import { launch, checkAll, finish } from './serve.mjs'; + +const { page, browser } = await launch({ width: 900, height: 620 }); + +const out = await page.evaluate(async () => { + const o = {}; + const c = window.__card; + const sr = () => c.shadowRoot || c.renderRoot; + const frame = () => new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r))); + const upd = async () => { c.requestUpdate(); await c.updateComplete; await frame(); await new Promise((r) => setTimeout(r, 40)); }; + const dlg = () => sr().querySelector('hp-dialog[data-kind="room"]'); + const helpOf = (key) => dlg()?.querySelector(`hp-help[data-help-key="${key}"]`); + const surfaceOf = (key) => helpOf(key)?.shadowRoot?.querySelector('.tooltip') + || dlg()?.shadowRoot?.querySelector('[data-hp-overlay="help"]')?.shadowRoot?.querySelector('.tooltip'); + // hit-test сквозь теневые корни: есть ли в точке именно .tooltip + const tooltipAt = (x, y) => { + const seen = new Set(); + const visit = (root) => { + for (const el of root.elementsFromPoint(x, y)) { + if (seen.has(el)) continue; seen.add(el); + if (el.classList?.contains('tooltip')) return true; + if (el.shadowRoot && visit(el.shadowRoot)) return true; + } + return false; + }; + return visit(document); + }; + const scroller = () => dlg()?.shadowRoot?.querySelector('.content') + || dlg()?.shadowRoot?.querySelector('ha-dialog')?.shadowRoot?.querySelector('.content'); + const probe = async (label, key) => { + const help = helpOf(key); + // прижать «?» к нижнему краю окна — там подсказка обязана уйти вверх, а не под срез + help.scrollIntoView({ block: 'end' }); + await frame(); + const trigger = help.shadowRoot.querySelector('.trigger'); + trigger.click(); await frame(); await new Promise((r) => setTimeout(r, 60)); + const surface = surfaceOf(key); + const r = surface?.getBoundingClientRect(); + const inViewport = !!r && r.width > 40 && r.height > 20 && r.left >= 0 && r.top >= 0 + && r.right <= innerWidth && r.bottom <= innerHeight; + // 12 px от края: у подсказки скруглённые углы (radius 9), точка в 2 px от угла — за скруглением + const corners = r ? [[r.left + 12, r.top + 12], [r.right - 12, r.top + 12], [r.left + 12, r.bottom - 12], [r.right - 12, r.bottom - 12], [(r.left + r.right) / 2, (r.top + r.bottom) / 2]] : []; + const hits = corners.map(([x, y]) => tooltipAt(x, y)); + o[`${label}_open`] = trigger.getAttribute('aria-expanded') === 'true' && !!surface; + o[`${label}_insideViewport`] = inViewport; + o[`${label}_notClipped`] = hits.length === 5 && hits.every(Boolean); + // подсказка стоит ВНЕ скроллера содержимого: её низ ниже или верх выше «?» так, что часть + // прямоугольника лежит за пределами видимой области скроллера — и всё равно hit-test'ится + const sc = scroller()?.getBoundingClientRect(); + o[`${label}_crossesScrollerEdge`] = !!r && !!sc && (r.top < sc.top || r.bottom > sc.bottom); + trigger.click(); await frame(); + }; + const openRoom = async () => { + if (c._roomDialog) { c._roomDialogCancel(); await upd(); } + c._setMode('plan'); await upd(); + c._openRoomEdit(c._curSpaceCfg.rooms[0]); await upd(); + c._roomFill = 'temp'; await upd(); + }; + const withFallback = async (fn) => { + const show = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'showPopover'); + const hide = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'hidePopover'); + Object.defineProperty(HTMLElement.prototype, 'showPopover', { configurable: true, value: undefined }); + Object.defineProperty(HTMLElement.prototype, 'hidePopover', { configurable: true, value: undefined }); + try { await fn(); } finally { + if (show) Object.defineProperty(HTMLElement.prototype, 'showPopover', show); else delete HTMLElement.prototype.showPopover; + if (hide) Object.defineProperty(HTMLElement.prototype, 'hidePopover', hide); else delete HTMLElement.prototype.hidePopover; + } + }; + + // --- нативный ------------------------------------------------------ + await openRoom(); + o.nativeBranch = !!dlg().shadowRoot.querySelector('dialog') && !dlg().shadowRoot.querySelector('ha-dialog'); + o.dialogScrolls = scroller().scrollHeight > scroller().clientHeight + 10; + await probe('native_popover_sizes', 'room.sizes_section.help'); + await probe('native_popover_fill', 'room.group_fill.help'); + await withFallback(async () => { + await probe('native_fallback_sizes', 'room.sizes_section.help'); + }); + // доказательство содержательное только если подсказка реально вышла за край скроллера + o.native_tooltipLeavesScrollerAndStaysVisible = o.native_popover_sizes_crossesScrollerEdge === true + && o.native_fallback_sizes_crossesScrollerEdge === true; + + // --- ветка ha-dialog: заглушка с ловушками настоящей mwc-поверхности -------- + customElements.define('ha-dialog', class extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: 'open' }).innerHTML = `
    +
    `; + } + connectedCallback() { queueMicrotask(() => this.dispatchEvent(new CustomEvent('opened'))); } + set open(v) { this._open = v; } get open() { return this._open; } + }); + c._roomDialogCancel(); await upd(); + await openRoom(); + o.haDialogBranch = !!dlg().shadowRoot.querySelector('ha-dialog') && !dlg().shadowRoot.querySelector('dialog'); + o.haDialogPortalOutsideSurface = (() => { + const portal = dlg().shadowRoot.querySelector('.overlay-portal'); + return !!portal && !dlg().shadowRoot.querySelector('ha-dialog').contains(portal); + })(); + o.haDialogScrolls = scroller().scrollHeight > scroller().clientHeight + 10; + await probe('ha_popover_sizes', 'room.sizes_section.help'); + await withFallback(async () => { + await probe('ha_fallback_sizes', 'room.sizes_section.help'); + await probe('ha_fallback_fill', 'room.group_fill.help'); + }); + o.ha_tooltipLeavesScrollerAndStaysVisible = o.ha_popover_sizes_crossesScrollerEdge === true + && o.ha_fallback_sizes_crossesScrollerEdge === true; + c._roomDialogCancel(); await upd(); + return o; +}); + +checkAll(Object.fromEntries(Object.entries(out).filter(([k]) => !k.endsWith('_crossesScrollerEdge')))); +await finish(browser, out); diff --git a/demo/smoke_dialog_segments_i18n.mjs b/demo/smoke_dialog_segments_i18n.mjs new file mode 100644 index 00000000..b5fb7904 --- /dev/null +++ b/demo/smoke_dialog_segments_i18n.mjs @@ -0,0 +1,71 @@ +// #600 AC2/AC9, ревью r1 M1: подписи сегментов не рвутся посреди слова ни в +// одной из четырёх локалей ни в одном из четырёх диалогов. Смок на скролл +// контейнера этого не видел: слово ломалось внутри кнопки, scrollWidth не рос. +// +// Проверка: у текстового span'а каждого варианта число клиентских прямоугольников +// (строк) не больше числа слов — однословная подпись всегда в одну строку, +// многословная переносится только по пробелам; кнопка при этом не выходит за +// границы своего сегмента. +import { launch, checkAll, finish } from './serve.mjs'; + +const { page, browser } = await launch({ width: 1280, height: 900 }); + +const out = await page.evaluate(async () => { + const o = {}; + const c = window.__card; + const sr = () => c.shadowRoot || c.renderRoot; + const upd = async () => { c.requestUpdate(); await c.updateComplete; await new Promise((r) => setTimeout(r, 40)); }; + const spId = c._space; + const closeAll = async () => { + c._settingsDialog = null; c._spaceDialog = null; c._markerDialog = null; if (c._roomDialog) c._roomDialogCancel(); + await upd(); + }; + const open = { + space: async () => { c._setMode('view'); c._openSpaceDialog('edit', spId); await upd(); c._spaceDialog = { ...c._spaceDialog, fillMode: 'temp', northMode: 'custom', northDeg: 35 }; await upd(); }, + settings: async () => { c._openSettingsDialog(); await upd(); }, + room: async () => { + c._setMode('plan'); await upd(); + c._openRoomEdit(c._curSpaceCfg.rooms[0]); await upd(); + c._roomFill = 'temp'; c._roomTempSrc = ''; c._roomSrcOpen = null; await upd(); + }, + marker: async () => { + c._setMode('devices'); await upd(); + const d = c._devices.find((x) => x.id === 'd_light1') || c._devices.find((x) => x.bindingKind === 'device') || c._devices[0]; + c._openMarkerDialog(d); await upd(); + c._markerDialog = { ...c._markerDialog, lightRole: 'always', lightRoleTouched: true, glowMode: 'fixed', glowTouched: true, valueBadgeEnabled: true, valueBadgeTouched: true }; + await upd(); + }, + }; + const wordsOf = (text) => text.trim().split(/\s+/).filter(Boolean).length; + for (const lang of ['en', 'ru', 'de', 'fr']) { + c._config = { ...c._config, language: lang }; await upd(); + for (const [kind, opener] of Object.entries(open)) { + await closeAll(); await opener(); + const dlg = sr().querySelector(`hp-dialog[data-kind="${kind}"]`); + const labels = [...(dlg?.querySelectorAll('.hpf-seg label') || [])]; + let broken = []; + let outside = []; + for (const label of labels) { + const span = [...label.querySelectorAll('span')].find((s) => !s.classList.contains('hpf-line')); + if (!span) continue; + // span — flex-элемент (блок), у блока один прямоугольник даже при переносе: + // строки считаются по текстовому узлу через Range. + const range = document.createRange(); range.selectNodeContents(span); + const lines = [...range.getClientRects()].filter((r) => r.width > 0 && r.height > 0).length; + if (lines > wordsOf(span.textContent)) broken.push(`${lang}/${kind}: «${span.textContent.trim()}» в ${lines} строк`); + const lb = label.getBoundingClientRect(); const sb = span.getBoundingClientRect(); + if (sb.left < lb.left - 0.5 || sb.right > lb.right + 0.5) outside.push(`${lang}/${kind}: «${span.textContent.trim()}» шире кнопки`); + } + o[`${lang}_${kind}_hasSegments`] = labels.length >= 2; + o[`${lang}_${kind}_noMidWordBreak`] = broken.length === 0 || broken; + o[`${lang}_${kind}_labelsInsideButtons`] = outside.length === 0 || outside; + } + } + await closeAll(); + c._config = { ...c._config, language: 'en' }; await upd(); + return o; +}); + +const normalized = Object.fromEntries(Object.entries(out).map(([k, v]) => [k, v === true])); +checkAll(normalized); +await finish(browser, out); diff --git a/dist/houseplan-assets.json b/dist/houseplan-assets.json index 416262a0..66cc11a1 100644 --- a/dist/houseplan-assets.json +++ b/dist/houseplan-assets.json @@ -1,312 +1,312 @@ { "schema": 1, - "fingerprint": "c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f", + "fingerprint": "54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32", "entry": "houseplan-card.js", "panelEntry": "houseplan-panel.js", "initialViewFiles": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js", + "houseplan-assets/houseplan-card-9fMSy3y3.js", "houseplan-card.js" ], - "initialViewGzipBytes": 289829, + "initialViewGzipBytes": 289852, "initialPanelFiles": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js", + "houseplan-assets/houseplan-card-9fMSy3y3.js", "houseplan-panel.js" ], - "initialPanelGzipBytes": 291350, + "initialPanelGzipBytes": 291374, "initialPanelOnlyFiles": [ "houseplan-panel.js" ], - "initialPanelOnlyGzipBytes": 2323, + "initialPanelOnlyGzipBytes": 2325, "lazyFiles": [ - "houseplan-assets/backdrop-pick-CtZfmF4H.js", - "houseplan-assets/de-AkOtg0jq.js", - "houseplan-assets/editor-_VTHnoKH.js", - "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "houseplan-assets/fr-Ds3OdruH.js", - "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js", - "houseplan-assets/houseplan-editor-runtime-BlocE3XU.js", - "houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js", - "houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js", - "houseplan-assets/iso-scene-render-BfrsUAJf.js", - "houseplan-assets/live-interaction-runtime-CCfHOfT8.js", - "houseplan-assets/pdf-export-Bslsp3h0.js", - "houseplan-assets/summary-panel-runtime-loaded-BGIJeXIz.js", - "houseplan-assets/zigbee-topology-D0gydI7H.js", - "houseplan-assets/zigbee-topology-runtime-BXasXMdL.js" + "houseplan-assets/backdrop-pick-BJOCHJxe.js", + "houseplan-assets/de-DVCIKwC0.js", + "houseplan-assets/editor-C694OxAO.js", + "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "houseplan-assets/fr-DHxhbm5E.js", + "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js", + "houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js", + "houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js", + "houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js", + "houseplan-assets/iso-scene-render-fYqz_-Ot.js", + "houseplan-assets/live-interaction-runtime-XyTIhKAA.js", + "houseplan-assets/pdf-export-D3vmqIY6.js", + "houseplan-assets/summary-panel-runtime-loaded-CX2cplA1.js", + "houseplan-assets/zigbee-topology-CI6PJorK.js", + "houseplan-assets/zigbee-topology-runtime-d-S2Abll.js" ], - "lazyGzipBytes": 459663, + "lazyGzipBytes": 459551, "lazyEditorFiles": [ - "houseplan-assets/backdrop-pick-CtZfmF4H.js", - "houseplan-assets/editor-_VTHnoKH.js", - "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js", - "houseplan-assets/houseplan-editor-runtime-BlocE3XU.js", - "houseplan-assets/zigbee-topology-D0gydI7H.js" + "houseplan-assets/backdrop-pick-BJOCHJxe.js", + "houseplan-assets/editor-C694OxAO.js", + "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js", + "houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js", + "houseplan-assets/zigbee-topology-CI6PJorK.js" ], - "lazyEditorGzipBytes": 243125, + "lazyEditorGzipBytes": 242989, "lazyOnboardingFiles": [ - "houseplan-assets/backdrop-pick-CtZfmF4H.js", - "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js" + "houseplan-assets/backdrop-pick-BJOCHJxe.js", + "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js" ], - "lazyOnboardingGzipBytes": 33646, + "lazyOnboardingGzipBytes": 33577, "lazyLocaleFiles": [ - "houseplan-assets/de-AkOtg0jq.js", - "houseplan-assets/fr-Ds3OdruH.js" + "houseplan-assets/de-DVCIKwC0.js", + "houseplan-assets/fr-DHxhbm5E.js" ], - "lazyLocaleGzipBytes": 55372, + "lazyLocaleGzipBytes": 55383, "lazyIsometricFiles": [ - "houseplan-assets/iso-scene-render-BfrsUAJf.js" + "houseplan-assets/iso-scene-render-fYqz_-Ot.js" ], - "lazyIsometricGzipBytes": 17644, + "lazyIsometricGzipBytes": 17643, "lazyFurnitureArtFiles": [ - "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js" + "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js" ], - "lazyFurnitureArtGzipBytes": 16945, + "lazyFurnitureArtGzipBytes": 16942, "lazyPdfFiles": [ - "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js", - "houseplan-assets/pdf-export-Bslsp3h0.js" + "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js", + "houseplan-assets/pdf-export-D3vmqIY6.js" ], - "lazyPdfGzipBytes": 126819, + "lazyPdfGzipBytes": 126817, "files": [ { - "path": "houseplan-assets/backdrop-pick-CtZfmF4H.js", - "sha256": "0318781a07d46ab4852f6ab7b0fdc44c180a1b0271935e031f9a9f885de62991", - "rawBytes": 74764, - "gzipBytes": 24114, + "path": "houseplan-assets/backdrop-pick-BJOCHJxe.js", + "sha256": "c24f2896a89f71e0a4147184f93b0e69e0c22eb705b772e644e9fc131ff879f4", + "rawBytes": 74375, + "gzipBytes": 24031, "isEntry": false, "imports": [ - "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/de-AkOtg0jq.js", - "sha256": "21cadc32b989295b913052353b5c8049b844474028e72162f8564698c0bdb9db", + "path": "houseplan-assets/de-DVCIKwC0.js", + "sha256": "6f716933e452260c6e7c0c40d7193e750b6fc443f162cca5cb814c734142dde5", "rawBytes": 92513, - "gzipBytes": 27927, + "gzipBytes": 27933, "isEntry": false, "imports": [], "dynamicImports": [] }, { - "path": "houseplan-assets/editor-_VTHnoKH.js", - "sha256": "881257f965ba340ab8367a3a0ffbfaf7e4509a38997c7b3b33281ff27b700907", + "path": "houseplan-assets/editor-C694OxAO.js", + "sha256": "f95242b8000cddf2fe1856a5518883c00a27a90c2983f228003db0189dffc1b4", "rawBytes": 3833, "gzipBytes": 1583, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "sha256": "5068cd6f5bd37792a593096b142ea5e9b729b0f85a1cf4d3c5722f714ff64eb2", - "rawBytes": 23495, - "gzipBytes": 4704, + "path": "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "sha256": "44a654e7c905948ab4bb363514532c13e67e3e54eee37e4af0ec8447f706fbc1", + "rawBytes": 23544, + "gzipBytes": 4716, "isEntry": false, "imports": [], "dynamicImports": [] }, { - "path": "houseplan-assets/fr-Ds3OdruH.js", - "sha256": "395585192b0478200785d46cb37805871bd0726088ca776e0f95150af595633c", + "path": "houseplan-assets/fr-DHxhbm5E.js", + "sha256": "f603ade3217ebe9959225379598608583ec29ab654dc257f57ae894d85ca448f", "rawBytes": 94824, - "gzipBytes": 27445, + "gzipBytes": 27450, "isEntry": false, "imports": [], "dynamicImports": [] }, { - "path": "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js", - "sha256": "2f193022979145fe8544c3c498fb8f1e9b3690fa6500fcd70a6c4f34c8a13860", + "path": "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js", + "sha256": "86d1074252f182c84d47285560a5b22c26724e21f21d03fbac4583973a9c11a7", "rawBytes": 52033, - "gzipBytes": 16945, + "gzipBytes": 16942, "isEntry": false, "imports": [], "dynamicImports": [] }, { - "path": "houseplan-assets/houseplan-card-BWAph8ZF.js", - "sha256": "ded6a4cd113062c60ed2086560b03f1cdba08884b0454c85f7140f5f51b284cb", + "path": "houseplan-assets/houseplan-card-9fMSy3y3.js", + "sha256": "e475fbae1c25540d2e349d4441bc963a4ff4181b8659fd491309dd1e578f716a", "rawBytes": 1027208, - "gzipBytes": 289027, + "gzipBytes": 289049, "isEntry": false, "imports": [], "dynamicImports": [ - "houseplan-assets/de-AkOtg0jq.js", - "houseplan-assets/editor-_VTHnoKH.js", - "houseplan-assets/fr-Ds3OdruH.js", - "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js", - "houseplan-assets/houseplan-editor-runtime-BlocE3XU.js", - "houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js", - "houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js", - "houseplan-assets/iso-scene-render-BfrsUAJf.js", - "houseplan-assets/live-interaction-runtime-CCfHOfT8.js", - "houseplan-assets/pdf-export-Bslsp3h0.js", - "houseplan-assets/summary-panel-runtime-loaded-BGIJeXIz.js" + "houseplan-assets/de-DVCIKwC0.js", + "houseplan-assets/editor-C694OxAO.js", + "houseplan-assets/fr-DHxhbm5E.js", + "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js", + "houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js", + "houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js", + "houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js", + "houseplan-assets/iso-scene-render-fYqz_-Ot.js", + "houseplan-assets/live-interaction-runtime-XyTIhKAA.js", + "houseplan-assets/pdf-export-D3vmqIY6.js", + "houseplan-assets/summary-panel-runtime-loaded-CX2cplA1.js" ] }, { - "path": "houseplan-assets/houseplan-editor-runtime-BlocE3XU.js", - "sha256": "1af11a5d027eec8d8a0793eae9be1713b6387d3a15c239e83f8623f87877f8a1", - "rawBytes": 677599, - "gzipBytes": 188352, + "path": "houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js", + "sha256": "e84feb1cf320be8297982134d45a5adceaec5a50f95aaa884e6e53cae2664edd", + "rawBytes": 677390, + "gzipBytes": 188290, "isEntry": false, "imports": [ - "houseplan-assets/backdrop-pick-CtZfmF4H.js", - "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js", - "houseplan-assets/houseplan-card-BWAph8ZF.js", - "houseplan-assets/zigbee-topology-D0gydI7H.js" + "houseplan-assets/backdrop-pick-BJOCHJxe.js", + "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js", + "houseplan-assets/houseplan-card-9fMSy3y3.js", + "houseplan-assets/zigbee-topology-CI6PJorK.js" ], "dynamicImports": [ - "houseplan-assets/zigbee-topology-runtime-BXasXMdL.js" + "houseplan-assets/zigbee-topology-runtime-d-S2Abll.js" ] }, { - "path": "houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js", - "sha256": "a30a515e61b632b90005e296b23d5cc52d3266c91ce29760fbb7358180956d1c", + "path": "houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js", + "sha256": "64367a8743ea22c4a9a350456878b7006ba01a346cc89eabb786e3c1d944ad3a", "rawBytes": 15667, - "gzipBytes": 4828, + "gzipBytes": 4830, "isEntry": false, "imports": [ - "houseplan-assets/backdrop-pick-CtZfmF4H.js", - "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/backdrop-pick-BJOCHJxe.js", + "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js", - "sha256": "780e78bbb5e04de2042497fdea47f44c31f8abeef03ad7cae3aeaf0e776f0db5", + "path": "houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js", + "sha256": "b2fa73ad0fc3353630e380abe1f63f483113c7bfc5f1e634150c2f0e12b4e0cf", "rawBytes": 10759, - "gzipBytes": 3684, + "gzipBytes": 3686, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js", - "houseplan-assets/zigbee-topology-D0gydI7H.js", - "houseplan-assets/zigbee-topology-runtime-BXasXMdL.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js", + "houseplan-assets/zigbee-topology-CI6PJorK.js", + "houseplan-assets/zigbee-topology-runtime-d-S2Abll.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/iso-scene-render-BfrsUAJf.js", - "sha256": "2806544f1906569d9613087eea4ca3b7017d0394147d6913f9e9998b8b4b456b", + "path": "houseplan-assets/iso-scene-render-fYqz_-Ot.js", + "sha256": "009a9217d1c522a5c2b6f9d5ea3450e2a77aafe52096d9c1d19902a18c6632f9", "rawBytes": 51983, - "gzipBytes": 17644, + "gzipBytes": 17643, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/live-interaction-runtime-CCfHOfT8.js", - "sha256": "5b905320a37ded5bfb1b52a4095e6a5821644d4ce0031d2ba2374b1418be2239", + "path": "houseplan-assets/live-interaction-runtime-XyTIhKAA.js", + "sha256": "0fd38fd067699ea97f11565db7c4ae86c1bcc867041e7e3377408f40e741f03f", "rawBytes": 8216, - "gzipBytes": 3205, + "gzipBytes": 3209, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/pdf-export-Bslsp3h0.js", - "sha256": "c7fc552565f6551b70366350399fbbe9bb849a588be6c293e6fb17602dabd0ae", + "path": "houseplan-assets/pdf-export-D3vmqIY6.js", + "sha256": "4c60cf0b34a17777c60c4849f1ee42841fb74b69466366adcf94cf97eec9ad2e", "rawBytes": 236247, - "gzipBytes": 109874, + "gzipBytes": 109875, "isEntry": false, "imports": [ - "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js", - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js", + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/summary-panel-editor-1TWzLmMH.js", - "sha256": "b6fad5dd728b4b6cfa4b4d54989a2d9d9dd9f37aba52301332a0bf3a4e69a66b", - "rawBytes": 14862, - "gzipBytes": 3424, + "path": "houseplan-assets/summary-panel-editor-CNT_mev4.js", + "sha256": "ef5dcf22a38fb5df834dcce277de7967303b8025167527483aab726dd30f3a2c", + "rawBytes": 14867, + "gzipBytes": 3427, "isEntry": false, "imports": [ - "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "houseplan-assets/houseplan-card-BWAph8ZF.js", - "houseplan-assets/summary-panel-runtime-loaded-BGIJeXIz.js" + "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "houseplan-assets/houseplan-card-9fMSy3y3.js", + "houseplan-assets/summary-panel-runtime-loaded-CX2cplA1.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/summary-panel-metrics-CsJSnPHD.js", - "sha256": "a9c4d54e9e1d168a3dd48fd8f09d8470eafa3b9dbc825fe6f9dda5bcb34a7029", + "path": "houseplan-assets/summary-panel-metrics-BhoEMuKv.js", + "sha256": "0b4f1816c4069cc62f20dccaeeeceb82c139dee339782833e594e46aa768fe06", "rawBytes": 2611, - "gzipBytes": 1306, + "gzipBytes": 1308, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/summary-panel-runtime-loaded-BGIJeXIz.js", - "sha256": "e3042c31f4e963a6c91fec76b05b1900e79360f60c246d8ce32291dd71201840", + "path": "houseplan-assets/summary-panel-runtime-loaded-CX2cplA1.js", + "sha256": "95e65a1d327f9d2f90796b9ae7754e0d8a64c15e44a82cefe329dca8f6115689", "rawBytes": 72733, - "gzipBytes": 20171, + "gzipBytes": 20172, "isEntry": false, "imports": [ - "houseplan-assets/form-kit.styles-DcvCvE8g.js", - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/form-kit.styles-CKUQLdmn.js", + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [ - "houseplan-assets/summary-panel-editor-1TWzLmMH.js", - "houseplan-assets/summary-panel-metrics-CsJSnPHD.js" + "houseplan-assets/summary-panel-editor-CNT_mev4.js", + "houseplan-assets/summary-panel-metrics-BhoEMuKv.js" ] }, { - "path": "houseplan-assets/zigbee-topology-D0gydI7H.js", - "sha256": "abe70ae6d783881bc6e8bdaac98a7372d1263f206103bf7110348f83f4a8dc2a", + "path": "houseplan-assets/zigbee-topology-CI6PJorK.js", + "sha256": "6e503b93a48deeda46368588fd4eebf7215aa4a2928e1162747da8b3ffe4b67a", "rawBytes": 18962, "gzipBytes": 7427, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/zigbee-topology-runtime-BXasXMdL.js", - "sha256": "c7dd23a95592651b462f8ef86d073b4aa98b6fad4ce3395b5bbeb0679bf0c76d", + "path": "houseplan-assets/zigbee-topology-runtime-d-S2Abll.js", + "sha256": "f6aad0abbf74532abc1c705d1268cce95048e7dbdc81a52a776a996c8b70f969", "rawBytes": 3942, - "gzipBytes": 1760, + "gzipBytes": 1764, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js", - "houseplan-assets/zigbee-topology-D0gydI7H.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js", + "houseplan-assets/zigbee-topology-CI6PJorK.js" ], "dynamicImports": [] }, { "path": "houseplan-card.js", - "sha256": "d5d8d4cbc7b0a71e4c6ba3f4cffb2fd412a9f8ce922200659ce96ee8f70d0bc0", + "sha256": "c796620c6d67c8fb18479291279eb410302ad541ed2b3679d59b780f74e8935b", "rawBytes": 1205, - "gzipBytes": 802, + "gzipBytes": 803, "isEntry": true, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] }, { "path": "houseplan-panel.js", - "sha256": "a34d397053df4099bce9aca317cfa95619c4e031796d77a1da09c15aab69a132", + "sha256": "c134452d829194d8d630e5859f8142d345e15348a706d7a83d5d9328b0df3faa", "rawBytes": 6165, - "gzipBytes": 2323, + "gzipBytes": 2325, "isEntry": true, "imports": [ - "houseplan-assets/houseplan-card-BWAph8ZF.js" + "houseplan-assets/houseplan-card-9fMSy3y3.js" ], "dynamicImports": [] } diff --git a/dist/houseplan-assets/backdrop-pick-CtZfmF4H.js b/dist/houseplan-assets/backdrop-pick-BJOCHJxe.js similarity index 62% rename from dist/houseplan-assets/backdrop-pick-CtZfmF4H.js rename to dist/houseplan-assets/backdrop-pick-BJOCHJxe.js index e2b1aa41..38cf624d 100644 --- a/dist/houseplan-assets/backdrop-pick-CtZfmF4H.js +++ b/dist/houseplan-assets/backdrop-pick-BJOCHJxe.js @@ -1,7 +1,7 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{A as e,c as a,s as t,l as i,cG as n,d as s,dC as r,dD as o,cF as l,dE as c,cL as d,cK as p,dF as h,bn as u,bm as m,bo as _,ar as g,ay as b,az as f,dG as v}from"./houseplan-card-BWAph8ZF.js";import{c as w,f as y,C as k}from"./form-kit.styles-DcvCvE8g.js";const $=w+y(k,{withSwitch:!1}),x=new WeakSet;let S=null;function M(e){const a=e.renderRoot;if(!a||x.has(a))return;const t=a.ownerDocument??globalThis.document,i=t?.defaultView?.CSSStyleSheet;if(i&&"adoptedStyleSheets"in a)return S||(S=new i,S.replaceSync($)),a.adoptedStyleSheets=[...a.adoptedStyleSheets,S],void x.add(a);if(a.querySelector("style[data-hp-form-kit]"))return void x.add(a);const n=t.createElement("style");n.dataset.hpFormKit="true",n.textContent=$,a.appendChild(n),x.add(a)}function C({title:t,help:i,body:n,id:s}){return a`
    +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{A as e,c as a,s as t,l as i,cG as n,ao as s,dC as r,dD as o,cF as l,dE as c,cL as d,cK as p,dF as h,bn as u,bm as m,bo as _,ar as g,ay as b,az as f,dG as v}from"./houseplan-card-9fMSy3y3.js";import{c as w,f as y,C as k}from"./form-kit.styles-CKUQLdmn.js";const $=w+y(k,{withSwitch:!1}),x=new WeakSet;let S=null;function M(e){const a=e.renderRoot;if(!a||x.has(a))return;const t=a.ownerDocument??globalThis.document,i=t?.defaultView?.CSSStyleSheet;if(i&&"adoptedStyleSheets"in a)return S||(S=new i,S.replaceSync($)),a.adoptedStyleSheets=[...a.adoptedStyleSheets,S],void x.add(a);if(a.querySelector("style[data-hp-form-kit]"))return void x.add(a);const n=t.createElement("style");n.dataset.hpFormKit="true",n.textContent=$,a.appendChild(n),x.add(a)}function C({title:t,help:i,body:n,id:s}){return a`
    ${t?a`

    ${t}

    ${i??e}
    `:e}
    ${n}
    -
    `}function z({title:t,help:i}){return a`

    ${t}

    ${i??e}
    `}function L({label:t,htmlFor:i,help:n,control:s,hint:r,error:o}){return a`
    +
    `}function L({title:t,help:i}){return a`

    ${t}

    ${i??e}
    `}function z({label:t,htmlFor:i,help:n,control:s,hint:r,error:o}){return a`
    ${i?a``:t}${n??e} ${s} ${o?a``:r?a`

    ${r}

    `:e} @@ -70,7 +70,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc `}function N({min:e,max:t,value:i,unit:n,ariaLabel:s,disabled:r,slider:o,onInput:l,id:c}){return a`
    ${o} ${I({id:c,value:String(i),unit:n,min:e,max:t,step:1,ariaLabel:s,disabled:r,onInput:a=>{const i=Number(a);Number.isFinite(i)&&l(Math.min(t,Math.max(e,i)))}})} -
    `}function O(e,t){return a``}function W(e,t,{disabled:i=!1}={}){return a``}function G({text:t,action:i}){return a`${t??""}${i??e}`}function U({title:t,tag:i,body:n}){return a`
    +
    `}function O(e,t){return a``}function W(e,t,{disabled:i=!1}={}){return a``}function U({text:t,action:i}){return a`${t??""}${i??e}`}function G({title:t,tag:i,body:n}){return a`

    ${t}

    ${i?a`${i}`:e}
    ${n}
    `}function V({open:t,current:i,placeholder:n,ariaLabel:s,filter:r,filterPlaceholder:o,candidates:l,selected:c,emptyText:d,onToggle:p,onFilter:h,onPick:u,id:m,toolbar:_,disabled:g=!1}){return a`
    @@ -92,7 +92,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc `):a`

    ${d}

    `}
    `:e} - `}const j=new WeakMap;function Z(e,a,t){const i=j.get(e)??new Map;i.set(a,t),j.set(e,i)}function K(e,a){j.get(e)?.delete(a)}function Q(e,a,t){const i=j.get(e)?.get(a);return void 0===i||i!==t}function Y(e,a=new Set){const t=Object.entries(e).filter(([e])=>!a.has(e)).sort(([e],[a])=>ea?1:0);return JSON.stringify(t)}var J={"space.title_hint":"Shown in the space tabs.","space.scale_hint":"Scale of the plan.","space.scale_changed":"Changing the scale recalculates the dimensions of the whole space when you save. Points on the plan stay where they are.","space.plan.help":"Use an image as a background to draw over. Rooms and devices stay editable on top of it. Switching to drawing by hand keeps the uploaded image available to use again.","space.plan.help.aria":"Help: floor plan","space.source_draw_hint":"Outline rooms in the plan editor.","space.source_file_hint":"Add an image to draw over.","space.plan_kept":"Your uploaded image is kept. Switch back to use it again.","space.show_borders_hint":"Show patterned outlines around the walls.","space.show_borders.help":"When off, patterned wall outlines and zero-thickness wall lines are hidden. Plain, light wall bands stay visible, so rooms remain separated. Doors, windows, room fills and lighting keep working.","space.show_borders.help.aria":"Help: room borders","space.layers_label":"Visible layers","space.layers.help":"Hiding changes only what you see on the plan. Decorative elements remain available in the background editor. Doors and windows stay in the plan editor, while their sensors, sunlight and lamp glow keep working.","space.layers.help.aria":"Help: visible layers","space.layer_decor":"Decorative layer","space.layer_openings":"Doors, windows & gates","space.fill_lqi_hint":"Uses average room LQI: low at 40 or below, high at 180 or above. Colors and opacity follow the general palette.","space.fill_light_hint":"Uses separate colors for any light on, all lights off, and no light sources. Colors and opacity follow the general palette.","space.temp_range":"Comfort range","space.temp_min":"Minimum","space.temp_max":"Maximum","space.temp_range_hint":"Below the minimum: cold. Within the range: comfort. Above the maximum: hot. Without a temperature reading, light-source glow can still add base shading.","space.show_names_hint":"Display room names and their selected values.","space.show_names.help":"Hiding room names also hides their values without clearing your selections. Room-card positions stay where you placed them.","space.show_names.help.aria":"Help: room names","space.card_values":"Values on the card","space.label_lqi_short":"Zigbee signal","space.values_hidden":"Values are saved but hidden.","space.values_hidden_action":"Show room names","space.card_font_hint":"Scales every room card in this space.","space.card_font.help":"100% is the default size. This scales every room card in this space while keeping individual card sizes and positions. Changes apply when you save.","space.card_font.help.aria":"Help: room-card font size","space.sun_inherit_short":"Use general settings","space.north_general":"Use general settings · {v}","space.north_custom":"Custom direction","space.north_deg":"North direction","space.compass_aria":"Compass: north at {v}","space.glow_enabled_hint":"Show a soft glow around lights that are on.","space.glow_enabled.help":"Lamp glow and sunlight are independent. Hiding opening symbols does not stop either effect. Window glass still lets sunlight in when the window is closed.","space.glow_enabled.help.aria":"Help: light-source glow","space.error_title":"Enter a name for the space.","space.error_plan":"Add a floor-plan image or switch to drawing by hand.","space.error_temp_range":"The maximum must be higher than the minimum.","space.error_north":"Enter a whole number between 0° and 359°.","btn.reset_100":"Reset to 100%","dialog.unsaved":"Unsaved changes","dialog.review_fields":"Review {n} field(s)","dialog.discard_title":"Discard your changes?","dialog.discard_message":"Your changes haven’t been saved.","dialog.discard_confirm":"Discard changes","dialog.discard_keep":"Keep editing","gs.show_room_tooltip_hint":"Hover a room on the plan to see its summary.","gs.radar_show_live_hint":"Hides or shows all live radar targets. This does not start or stop observation recording.","gs.bg_custom_hint":"Custom background color.","gs.bg_theme_hint":"Using the theme background.","gs.sun_rays_hint":"Draw sun rays through window openings.","gs.error_glow_radius":"Enter a radius greater than zero.","gs.error_north":"Enter a whole number between 0° and 359°.","gs.opacity_of":"{name} opacity","room.fill_inherit_hint":"Use the fill mode set for the whole space.","room.fill_following":"Following the space: {mode}.","room.fill_mode_label":"Fill mode","room.temp_min_label":"Minimum","room.temp_max_label":"Maximum","room.sizes_hint":"On top of the space-wide card size ({v}%).","room.error_temp_range":"Enter numbers for the comfort bounds.","room.error_name":"Enter a name or choose an area.","marker.name_hint":"Shown on the plan.","marker.binding.help":"A bound marker shows the live state of a Home Assistant device or entity and can act on it. A virtual device is a plain marker with no binding.","marker.binding.help.aria":"Help: binding to a Home Assistant device","marker.binding_virtual_hint":"A virtual device is a plain marker with no binding.","marker.room_hint_auto":"Placed by the device’s Home Assistant area.","marker.room_hint_override":"Overrides the placement by device area.","marker.light_role_seg_auto":"Auto","marker.light_role_seg_always":"Always","marker.light_role_seg_never":"Never","marker.glow_radius_empty_hint":"Empty: uses the general radius ({v}).","marker.icon.help":"Empty means automatic: the icon comes from the icon rules for this device. Pick one to override, or pin the automatic choice.","marker.icon.help.aria":"Help: marker icon","marker.icon_custom_hint":"Custom icon for this marker.","marker.display.help":"How the marker face reacts to state and activity. The value modes replace the icon with a Home Assistant value.","marker.display.help.aria":"Help: display mode","marker.size.help":"Scales and rotates only this marker on the plan. The tap area grows with the icon.","marker.size.help.aria":"Help: icon size and rotation","marker.size_short":"Size","marker.error_binding":"Choose a device or entity to bind.","marker.error_glow_radius":"Enter a radius greater than 0, or leave it empty.","room.fill_seg_lqi":"Zigbee","room.fill_seg_custom":"Custom"};const X={en:J,ru:{"space.title_hint":"Показывается на вкладках пространств.","space.scale_hint":"Масштаб плана.","space.scale_changed":"Смена масштаба пересчитает размеры всего пространства при сохранении. Точки на плане останутся на месте.","space.plan.help":"Изображение под планом, поверх которого рисуют. Комнаты и устройства остаются редактируемыми. При переходе на рисование вручную загруженное изображение сохраняется и доступно снова.","space.plan.help.aria":"Справка: подложка плана","space.source_draw_hint":"Обвести комнаты в редакторе плана.","space.source_file_hint":"Добавить картинку и рисовать поверх неё.","space.plan_kept":"Загруженное изображение сохранено. Переключитесь обратно, чтобы снова использовать его.","space.show_borders_hint":"Показывать узорную обводку стен.","space.show_borders.help":"Когда выключено, узорная обводка стен и линии стен нулевой толщины скрыты. Светлые полосы стен остаются видны, комнаты не сливаются. Двери, окна, заливки комнат и освещение продолжают работать.","space.show_borders.help.aria":"Справка: границы комнат","space.layers_label":"Видимые слои","space.layers.help":"Скрытие меняет только то, что видно на плане. Декоративные элементы остаются в редакторе подложки. Двери и окна остаются в редакторе плана, а их датчики, солнечный свет и свечение ламп продолжают работать.","space.layers.help.aria":"Справка: видимые слои","space.layer_decor":"Декоративный слой","space.layer_openings":"Двери, окна и ворота","space.fill_lqi_hint":"По среднему LQI комнаты: слабый — 40 и ниже, сильный — 180 и выше. Цвета и прозрачность — из общей палитры.","space.fill_light_hint":"Отдельные цвета для «горит хотя бы одна», «все выключены» и «источников нет». Цвета и прозрачность — из общей палитры.","space.temp_range":"Комфортный диапазон","space.temp_min":"Минимум","space.temp_max":"Максимум","space.temp_range_hint":"Ниже минимума — холодно. В диапазоне — комфорт. Выше максимума — жарко. Без показаний температуры свечение источников света всё равно даёт базовую заливку.","space.show_names_hint":"Названия комнат и выбранные значения на плане.","space.show_names.help":"Скрытие названий скрывает и значения, не сбрасывая выбор. Положение карточек комнат сохраняется.","space.show_names.help.aria":"Справка: названия комнат","space.card_values":"Значения на карточке","space.label_lqi_short":"Сигнал Zigbee","space.values_hidden":"Значения сохранены, но скрыты.","space.values_hidden_action":"Показать названия комнат","space.card_font_hint":"Масштабирует каждую карточку комнаты в этом пространстве.","space.card_font.help":"100 % — размер по умолчанию. Масштабирует все карточки комнат пространства, сохраняя индивидуальные размеры и положение. Применяется при сохранении.","space.card_font.help.aria":"Справка: размер шрифта карточек","space.sun_inherit_short":"Как в общих","space.north_general":"Как в общих · {v}","space.north_custom":"Своё направление","space.north_deg":"Направление на север","space.compass_aria":"Компас: север {v}","space.glow_enabled_hint":"Мягкое свечение вокруг включённых ламп.","space.glow_enabled.help":"Свечение ламп и солнечный свет независимы. Скрытие символов проёмов не отключает ни то, ни другое. Стекло окна пропускает солнце и при закрытом окне.","space.glow_enabled.help.aria":"Справка: свечение источников света","space.error_title":"Введите название пространства.","space.error_plan":"Добавьте изображение плана или переключитесь на рисование вручную.","space.error_temp_range":"Максимум должен быть больше минимума.","space.error_north":"Введите целое число от 0° до 359°.","btn.reset_100":"Сбросить до 100%","dialog.unsaved":"Есть несохранённые изменения","dialog.review_fields":"Проверьте поля: {n}","dialog.discard_title":"Отменить изменения?","dialog.discard_message":"Изменения не сохранены.","dialog.discard_confirm":"Отменить изменения","dialog.discard_keep":"Продолжить редактирование","gs.show_room_tooltip_hint":"Наведите на комнату на плане, чтобы увидеть сводку.","gs.radar_show_live_hint":"Показывает или скрывает все живые цели радаров. Запись наблюдения не запускается и не останавливается.","gs.bg_custom_hint":"Свой цвет фона.","gs.bg_theme_hint":"Используется фон темы.","gs.sun_rays_hint":"Рисовать солнечные лучи через оконные проёмы.","gs.error_glow_radius":"Введите радиус больше нуля.","gs.error_north":"Введите целое число от 0° до 359°.","gs.opacity_of":"Прозрачность: {name}","room.fill_inherit_hint":"Использовать режим заливки всего пространства.","room.fill_following":"Как у пространства: {mode}.","room.fill_mode_label":"Режим заливки","room.temp_min_label":"Минимум","room.temp_max_label":"Максимум","room.sizes_hint":"Поверх размера карточек всего пространства ({v}%).","room.error_temp_range":"Введите числа для границ комфорта.","room.error_name":"Введите название или выберите зону.","marker.name_hint":"Показывается на плане.","marker.binding.help":"Привязанный маркер показывает живое состояние устройства или сущности Home Assistant и может им управлять. Виртуальное устройство — просто маркер без привязки.","marker.binding.help.aria":"Справка: привязка к устройству Home Assistant","marker.binding_virtual_hint":"Виртуальное устройство — просто маркер без привязки.","marker.room_hint_auto":"Размещается по зоне устройства в Home Assistant.","marker.room_hint_override":"Переопределяет размещение по зоне устройства.","marker.light_role_seg_auto":"Авто","marker.light_role_seg_always":"Всегда","marker.light_role_seg_never":"Никогда","marker.glow_radius_empty_hint":"Пусто: общий радиус ({v}).","marker.icon.help":"Пусто — автоматически: иконка берётся из правил иконок для этого устройства. Выберите свою, чтобы переопределить, или закрепите автоматическую.","marker.icon.help.aria":"Справка: иконка маркера","marker.icon_custom_hint":"Своя иконка для этого маркера.","marker.display.help":"Как лицо маркера реагирует на состояние и активность. Режимы значения заменяют иконку значением из Home Assistant.","marker.display.help.aria":"Справка: режим отображения","marker.size.help":"Масштабирует и поворачивает только этот маркер на плане. Область нажатия растёт вместе с иконкой.","marker.size.help.aria":"Справка: размер и поворот иконки","marker.size_short":"Размер","marker.error_binding":"Выберите устройство или сущность для привязки.","marker.error_glow_radius":"Введите радиус больше 0 или оставьте поле пустым.","room.fill_seg_lqi":"Zigbee","room.fill_seg_custom":"Свой цвет"},de:{"space.title_hint":"Wird in den Bereichs-Tabs angezeigt.","space.scale_hint":"Maßstab des Plans.","space.scale_changed":"Eine Änderung des Maßstabs berechnet beim Speichern die Maße des gesamten Bereichs neu. Punkte auf dem Plan bleiben, wo sie sind.","space.plan.help":"Ein Bild als Hintergrund, über das gezeichnet wird. Räume und Geräte bleiben darüber bearbeitbar. Beim Wechsel zum Zeichnen von Hand bleibt das hochgeladene Bild erhalten.","space.plan.help.aria":"Hilfe: Grundriss","space.source_draw_hint":"Räume im Plan-Editor umreißen.","space.source_file_hint":"Ein Bild hinzufügen und darüber zeichnen.","space.plan_kept":"Das hochgeladene Bild bleibt erhalten. Wechseln Sie zurück, um es wieder zu nutzen.","space.show_borders_hint":"Gemusterte Umrisse um die Wände anzeigen.","space.show_borders.help":"Ausgeschaltet werden gemusterte Wandumrisse und Linien von Wänden ohne Dicke ausgeblendet. Helle Wandbänder bleiben sichtbar, Räume bleiben getrennt. Türen, Fenster, Raumfüllungen und Beleuchtung funktionieren weiter.","space.show_borders.help.aria":"Hilfe: Raumgrenzen","space.layers_label":"Sichtbare Ebenen","space.layers.help":"Ausblenden ändert nur, was auf dem Plan zu sehen ist. Dekorative Elemente bleiben im Hintergrund-Editor verfügbar. Türen und Fenster bleiben im Plan-Editor; ihre Sensoren, Sonnenlicht und Lampenschein funktionieren weiter.","space.layers.help.aria":"Hilfe: sichtbare Ebenen","space.layer_decor":"Dekorative Ebene","space.layer_openings":"Türen, Fenster & Tore","space.fill_lqi_hint":"Nach mittlerem LQI des Raums: schwach bei 40 oder weniger, stark bei 180 oder mehr. Farben und Deckkraft folgen der allgemeinen Palette.","space.fill_light_hint":"Eigene Farben für „mindestens eine Lampe an“, „alle aus“ und „keine Lichtquellen“. Farben und Deckkraft folgen der allgemeinen Palette.","space.temp_range":"Komfortbereich","space.temp_min":"Minimum","space.temp_max":"Maximum","space.temp_range_hint":"Unter dem Minimum: kalt. Im Bereich: Komfort. Über dem Maximum: heiß. Ohne Temperaturwert kann der Lampenschein weiterhin eine Grundschattierung geben.","space.show_names_hint":"Raumnamen und ausgewählte Werte anzeigen.","space.show_names.help":"Das Ausblenden der Raumnamen blendet auch ihre Werte aus, ohne die Auswahl zu löschen. Die Positionen der Raumkarten bleiben erhalten.","space.show_names.help.aria":"Hilfe: Raumnamen","space.card_values":"Werte auf der Karte","space.label_lqi_short":"Zigbee-Signal","space.values_hidden":"Werte sind gespeichert, aber ausgeblendet.","space.values_hidden_action":"Raumnamen anzeigen","space.card_font_hint":"Skaliert jede Raumkarte in diesem Bereich.","space.card_font.help":"100 % ist die Standardgröße. Skaliert alle Raumkarten dieses Bereichs, individuelle Größen und Positionen bleiben erhalten. Gilt nach dem Speichern.","space.card_font.help.aria":"Hilfe: Schriftgröße der Raumkarten","space.sun_inherit_short":"Wie allgemein","space.north_general":"Wie allgemein · {v}","space.north_custom":"Eigene Richtung","space.north_deg":"Nordrichtung","space.compass_aria":"Kompass: Norden bei {v}","space.glow_enabled_hint":"Sanftes Leuchten um eingeschaltete Lampen.","space.glow_enabled.help":"Lampenschein und Sonnenlicht sind unabhängig. Das Ausblenden von Öffnungssymbolen stoppt keinen der Effekte. Fensterglas lässt Sonnenlicht auch bei geschlossenem Fenster durch.","space.glow_enabled.help.aria":"Hilfe: Leuchten der Lichtquellen","space.error_title":"Geben Sie einen Namen für den Bereich ein.","space.error_plan":"Fügen Sie ein Grundrissbild hinzu oder wechseln Sie zum Zeichnen von Hand.","space.error_temp_range":"Das Maximum muss über dem Minimum liegen.","space.error_north":"Geben Sie eine ganze Zahl zwischen 0° und 359° ein.","btn.reset_100":"Auf 100 % zurücksetzen","dialog.unsaved":"Ungespeicherte Änderungen","dialog.review_fields":"{n} Feld(er) prüfen","dialog.discard_title":"Änderungen verwerfen?","dialog.discard_message":"Ihre Änderungen wurden nicht gespeichert.","dialog.discard_confirm":"Änderungen verwerfen","dialog.discard_keep":"Weiter bearbeiten","gs.show_room_tooltip_hint":"Zeigen Sie auf einen Raum im Plan, um seine Übersicht zu sehen.","gs.radar_show_live_hint":"Blendet alle Live-Radarziele ein oder aus. Die Beobachtungsaufzeichnung wird dadurch nicht gestartet oder gestoppt.","gs.bg_custom_hint":"Eigene Hintergrundfarbe.","gs.bg_theme_hint":"Hintergrund des Themes wird verwendet.","gs.sun_rays_hint":"Sonnenstrahlen durch Fensteröffnungen zeichnen.","gs.error_glow_radius":"Geben Sie einen Radius größer als null ein.","gs.error_north":"Geben Sie eine ganze Zahl zwischen 0° und 359° ein.","gs.opacity_of":"Deckkraft: {name}","room.fill_inherit_hint":"Den Füllmodus des gesamten Bereichs verwenden.","room.fill_following":"Wie der Bereich: {mode}.","room.fill_mode_label":"Füllmodus","room.temp_min_label":"Minimum","room.temp_max_label":"Maximum","room.sizes_hint":"Zusätzlich zur bereichsweiten Kartengröße ({v} %).","room.error_temp_range":"Geben Sie Zahlen für die Komfortgrenzen ein.","room.error_name":"Geben Sie einen Namen ein oder wählen Sie einen Bereich.","marker.name_hint":"Wird auf dem Plan angezeigt.","marker.binding.help":"Ein verknüpfter Marker zeigt den Live-Zustand eines Home-Assistant-Geräts oder einer Entität und kann darauf wirken. Ein virtuelles Gerät ist ein einfacher Marker ohne Verknüpfung.","marker.binding.help.aria":"Hilfe: Verknüpfung mit einem Home-Assistant-Gerät","marker.binding_virtual_hint":"Ein virtuelles Gerät ist ein einfacher Marker ohne Verknüpfung.","marker.room_hint_auto":"Platzierung nach dem Home-Assistant-Bereich des Geräts.","marker.room_hint_override":"Überschreibt die Platzierung nach Gerätebereich.","marker.light_role_seg_auto":"Auto","marker.light_role_seg_always":"Immer","marker.light_role_seg_never":"Nie","marker.glow_radius_empty_hint":"Leer: allgemeiner Radius ({v}).","marker.icon.help":"Leer bedeutet automatisch: Das Symbol kommt aus den Symbolregeln für dieses Gerät. Wählen Sie eines zum Überschreiben oder heften Sie die automatische Wahl an.","marker.icon.help.aria":"Hilfe: Marker-Symbol","marker.icon_custom_hint":"Eigenes Symbol für diesen Marker.","marker.display.help":"Wie das Marker-Gesicht auf Zustand und Aktivität reagiert. Die Wert-Modi ersetzen das Symbol durch einen Home-Assistant-Wert.","marker.display.help.aria":"Hilfe: Anzeigemodus","marker.size.help":"Skaliert und dreht nur diesen Marker auf dem Plan. Die Tippfläche wächst mit dem Symbol.","marker.size.help.aria":"Hilfe: Symbolgröße und Drehung","marker.size_short":"Größe","marker.error_binding":"Wählen Sie ein Gerät oder eine Entität zum Verknüpfen.","marker.error_glow_radius":"Geben Sie einen Radius größer als 0 ein oder lassen Sie das Feld leer.","room.fill_seg_lqi":"Zigbee","room.fill_seg_custom":"Eigene"},fr:{"space.title_hint":"Affiché dans les onglets des espaces.","space.scale_hint":"Échelle du plan.","space.scale_changed":"Changer l’échelle recalcule les dimensions de tout l’espace à l’enregistrement. Les points du plan restent en place.","space.plan.help":"Une image en arrière-plan sur laquelle dessiner. Les pièces et les appareils restent modifiables par-dessus. Passer au dessin à la main conserve l’image téléversée pour la réutiliser.","space.plan.help.aria":"Aide : fond de plan","space.source_draw_hint":"Tracer les pièces dans l’éditeur de plan.","space.source_file_hint":"Ajouter une image et dessiner par-dessus.","space.plan_kept":"Votre image téléversée est conservée. Revenez en arrière pour la réutiliser.","space.show_borders_hint":"Afficher les contours hachurés autour des murs.","space.show_borders.help":"Désactivé, les contours hachurés des murs et les lignes des murs sans épaisseur sont masqués. Les bandes claires des murs restent visibles, les pièces restent séparées. Portes, fenêtres, remplissages et éclairage continuent de fonctionner.","space.show_borders.help.aria":"Aide : bordures des pièces","space.layers_label":"Calques visibles","space.layers.help":"Masquer ne change que ce qui est visible sur le plan. Les éléments décoratifs restent disponibles dans l’éditeur de fond. Portes et fenêtres restent dans l’éditeur de plan ; leurs capteurs, la lumière du soleil et la lueur des lampes continuent de fonctionner.","space.layers.help.aria":"Aide : calques visibles","space.layer_decor":"Calque décoratif","space.layer_openings":"Portes, fenêtres et portails","space.fill_lqi_hint":"Selon le LQI moyen de la pièce : faible à 40 ou moins, fort à 180 ou plus. Couleurs et opacité suivent la palette générale.","space.fill_light_hint":"Couleurs distinctes pour « au moins une lampe allumée », « toutes éteintes » et « aucune source ». Couleurs et opacité suivent la palette générale.","space.temp_range":"Plage de confort","space.temp_min":"Minimum","space.temp_max":"Maximum","space.temp_range_hint":"Sous le minimum : froid. Dans la plage : confort. Au-dessus du maximum : chaud. Sans mesure de température, la lueur des sources lumineuses peut encore donner un ombrage de base.","space.show_names_hint":"Afficher les noms des pièces et les valeurs choisies.","space.show_names.help":"Masquer les noms masque aussi leurs valeurs sans effacer vos choix. La position des cartes des pièces est conservée.","space.show_names.help.aria":"Aide : noms des pièces","space.card_values":"Valeurs sur la carte","space.label_lqi_short":"Signal Zigbee","space.values_hidden":"Les valeurs sont enregistrées mais masquées.","space.values_hidden_action":"Afficher les noms des pièces","space.card_font_hint":"Met à l’échelle chaque carte de pièce de cet espace.","space.card_font.help":"100 % est la taille par défaut. Met à l’échelle toutes les cartes de pièces de cet espace en conservant tailles et positions individuelles. Appliqué à l’enregistrement.","space.card_font.help.aria":"Aide : taille de police des cartes","space.sun_inherit_short":"Comme les réglages généraux","space.north_general":"Comme les réglages généraux · {v}","space.north_custom":"Direction personnalisée","space.north_deg":"Direction du nord","space.compass_aria":"Boussole : nord à {v}","space.glow_enabled_hint":"Lueur douce autour des lampes allumées.","space.glow_enabled.help":"La lueur des lampes et la lumière du soleil sont indépendantes. Masquer les symboles d’ouvertures n’arrête aucun des deux effets. Le vitrage laisse passer le soleil même fenêtre fermée.","space.glow_enabled.help.aria":"Aide : lueur des sources lumineuses","space.error_title":"Saisissez un nom pour l’espace.","space.error_plan":"Ajoutez une image du plan ou passez au dessin à la main.","space.error_temp_range":"Le maximum doit être supérieur au minimum.","space.error_north":"Saisissez un nombre entier entre 0° et 359°.","btn.reset_100":"Réinitialiser à 100 %","dialog.unsaved":"Modifications non enregistrées","dialog.review_fields":"Vérifiez {n} champ(s)","dialog.discard_title":"Abandonner vos modifications ?","dialog.discard_message":"Vos modifications n’ont pas été enregistrées.","dialog.discard_confirm":"Abandonner","dialog.discard_keep":"Continuer la modification","gs.show_room_tooltip_hint":"Survolez une pièce sur le plan pour voir son résumé.","gs.radar_show_live_hint":"Affiche ou masque toutes les cibles radar en direct. Cela ne démarre ni n’arrête l’enregistrement d’observation.","gs.bg_custom_hint":"Couleur de fond personnalisée.","gs.bg_theme_hint":"Fond du thème utilisé.","gs.sun_rays_hint":"Tracer les rayons du soleil à travers les ouvertures des fenêtres.","gs.error_glow_radius":"Saisissez un rayon supérieur à zéro.","gs.error_north":"Saisissez un nombre entier entre 0° et 359°.","gs.opacity_of":"Opacité : {name}","room.fill_inherit_hint":"Utiliser le mode de remplissage de tout l’espace.","room.fill_following":"Comme l’espace : {mode}.","room.fill_mode_label":"Mode de remplissage","room.temp_min_label":"Minimum","room.temp_max_label":"Maximum","room.sizes_hint":"En plus de la taille des cartes de l’espace ({v} %).","room.error_temp_range":"Saisissez des nombres pour les bornes de confort.","room.error_name":"Saisissez un nom ou choisissez une zone.","marker.name_hint":"Affiché sur le plan.","marker.binding.help":"Un marqueur lié affiche l’état en direct d’un appareil ou d’une entité Home Assistant et peut agir dessus. Un appareil virtuel est un simple marqueur sans liaison.","marker.binding.help.aria":"Aide : liaison à un appareil Home Assistant","marker.binding_virtual_hint":"Un appareil virtuel est un simple marqueur sans liaison.","marker.room_hint_auto":"Placé selon la zone Home Assistant de l’appareil.","marker.room_hint_override":"Remplace le placement par zone de l’appareil.","marker.light_role_seg_auto":"Auto","marker.light_role_seg_always":"Toujours","marker.light_role_seg_never":"Jamais","marker.glow_radius_empty_hint":"Vide : rayon général ({v}).","marker.icon.help":"Vide signifie automatique : l’icône vient des règles d’icônes de cet appareil. Choisissez-en une pour remplacer, ou épinglez le choix automatique.","marker.icon.help.aria":"Aide : icône du marqueur","marker.icon_custom_hint":"Icône personnalisée pour ce marqueur.","marker.display.help":"Comment la face du marqueur réagit à l’état et à l’activité. Les modes valeur remplacent l’icône par une valeur Home Assistant.","marker.display.help.aria":"Aide : mode d’affichage","marker.size.help":"Redimensionne et fait pivoter uniquement ce marqueur sur le plan. La zone de toucher grandit avec l’icône.","marker.size.help.aria":"Aide : taille et rotation de l’icône","marker.size_short":"Taille","marker.error_binding":"Choisissez un appareil ou une entité à lier.","marker.error_glow_radius":"Saisissez un rayon supérieur à 0 ou laissez le champ vide.","room.fill_seg_lqi":"Zigbee","room.fill_seg_custom":"Perso"}};function ee(e,a){const t=X[e]?.[a]??J[a];return"string"==typeof t&&t.trim().length>0}function ae(e,a,i){return t(X[e]?.[a]??J[a]??a,i)}function te(t){const n=i(t.hass,t._config?.language);return{st:(e,a)=>ae(n,e,a),shelp:t=>{const i=`${t}.aria`;return ee(n,t)&&ee(n,i)?a``:e}}}const ie=new Set(["busy","pickSaved","saved","savedBusy","savedAspect","cellCmInput","cellCmTouched","displayTouched","deleteBlockers","copy"]);function ne(e){return Y({...e,planFile:e.planFile?e.planFile.name:null},ie)}function se(e,a){Z(e,"space",ne(a))}const re=.1,oe=1e3,le=(e,a)=>{e.host._spaceDialog=a};function ce(t){M(t.host);const{host:i}=t,n=i._spaceDialog,s=i._t.bind(i),{st:r}=te(i),o=e=>`${t.idPrefix}-${e}`,l=function(e,a){const t=[];return e.title.trim()||t.push({field:`${a}-title`,message:"space.error_title"}),"file"!==e.source||e.planFile||e.planUrl||t.push({field:`${a}-plan`,message:"space.error_plan"}),"temp"!==e.fillMode||Number.isFinite(e.tempMin)&&Number.isFinite(e.tempMax)&&e.tempMin=0&&e.northDeg<=359||t.push({field:`${a}-north-deg`,message:"space.error_north"}),t}(n,t.idPrefix),c=e=>l.find(a=>a.field===e),d=function(e,a){return Q(e,"space",ne(a))}(i,n),p=d&&0===l.length&&!n.busy,h=i._importTotal>0&&"create"===n.mode?s("import.progress",{i:i._importTotal-i._importQueue.length,n:i._importTotal}):"",u=()=>{!function(e){K(e,"space")}(i),i._spaceDialog=null,i._importQueue=[],i._importTotal=0},m=async e=>{if(!d||n.busy)return void u();const a=e.currentTarget;await i._confirmDanger({key:"discard-space-dialog",kind:"warning",title:r("dialog.discard_title"),message:r("dialog.discard_message"),objectName:n.title.trim()||void 0,confirmLabel:r("dialog.discard_confirm"),cancelLabel:r("dialog.discard_keep")})?u():a?.rejectClose?.()};return{title:`${"create"===n.mode?s("space.new"):s("space.header")}${h?` · ${h}`:""}`,badge:"edit"===n.mode?n.title.trim():"",requestClose:m,body:a`
    +
    `}const j=new WeakMap;function Z(e,a,t){const i=j.get(e)??new Map;i.set(a,t),j.set(e,i)}function K(e,a){j.get(e)?.delete(a)}function Q(e,a,t){const i=j.get(e)?.get(a);return void 0===i||i!==t}function Y(e,a=new Set){const t=Object.entries(e).filter(([e])=>!a.has(e)).sort(([e],[a])=>ea?1:0);return JSON.stringify(t)}var J={"space.title_hint":"Shown in the space tabs.","space.scale_hint":"Scale of the plan.","space.scale_changed":"Changing the scale recalculates the dimensions of the whole space when you save. Points on the plan stay where they are.","space.plan.help":"Use an image as a background to draw over. Rooms and devices stay editable on top of it. Switching to drawing by hand keeps the uploaded image available to use again.","space.plan.help.aria":"Help: floor plan","space.source_draw_hint":"Outline rooms in the plan editor.","space.source_file_hint":"Add an image to draw over.","space.plan_kept":"Your uploaded image is kept. Switch back to use it again.","space.show_borders_hint":"Show patterned outlines around the walls.","space.show_borders.help":"When off, patterned wall outlines and zero-thickness wall lines are hidden. Plain, light wall bands stay visible, so rooms remain separated. Doors, windows, room fills and lighting keep working.","space.show_borders.help.aria":"Help: room borders","space.layers_label":"Visible layers","space.layers.help":"Hiding changes only what you see on the plan. Decorative elements remain available in the background editor. Doors and windows stay in the plan editor, while their sensors, sunlight and lamp glow keep working.","space.layers.help.aria":"Help: visible layers","space.layer_decor":"Decorative layer","space.layer_openings":"Doors, windows & gates","space.fill_lqi_hint":"Uses average room LQI: low at 40 or below, high at 180 or above. Colors and opacity follow the general palette.","space.fill_light_hint":"Uses separate colors for any light on, all lights off, and no light sources. Colors and opacity follow the general palette.","space.temp_range":"Comfort range","space.temp_min":"Minimum","space.temp_max":"Maximum","space.temp_range_hint":"Below the minimum: cold. Within the range: comfort. Above the maximum: hot. Without a temperature reading, light-source glow can still add base shading.","space.show_names_hint":"Display room names and their selected values.","space.show_names.help":"Hiding room names also hides their values without clearing your selections. Room-card positions stay where you placed them.","space.show_names.help.aria":"Help: room names","space.card_values":"Values on the card","space.label_lqi_short":"Zigbee signal","space.values_hidden":"Values are saved but hidden.","space.values_hidden_action":"Show room names","space.card_font_hint":"Scales every room card in this space.","space.card_font.help":"100% is the default size. This scales every room card in this space while keeping individual card sizes and positions. Changes apply when you save.","space.card_font.help.aria":"Help: room-card font size","space.sun_inherit_short":"Use general settings","space.north_general":"Use general settings · {v}","space.north_custom":"Custom direction","space.north_deg":"North direction","space.compass_aria":"Compass: north at {v}","space.glow_enabled_hint":"Show a soft glow around lights that are on.","space.glow_enabled.help":"Lamp glow and sunlight are independent. Hiding opening symbols does not stop either effect. Window glass still lets sunlight in when the window is closed.","space.glow_enabled.help.aria":"Help: light-source glow","space.error_title":"Enter a name for the space.","space.error_plan":"Add a floor-plan image or switch to drawing by hand.","space.error_temp_range":"The maximum must be higher than the minimum.","space.error_north":"Enter a whole number between 0° and 359°.","btn.reset_100":"Reset to 100%","dialog.unsaved":"Unsaved changes","dialog.review_fields":"Review {n} field(s)","dialog.discard_title":"Discard your changes?","dialog.discard_message":"Your changes haven’t been saved.","dialog.discard_confirm":"Discard changes","dialog.discard_keep":"Keep editing","gs.show_room_tooltip_hint":"Hover a room on the plan to see its summary.","gs.radar_show_live_hint":"Hides or shows all live radar targets. This does not start or stop observation recording.","gs.bg_custom_hint":"Custom background color.","gs.bg_theme_hint":"Using the theme background.","gs.sun_rays_hint":"Draw sun rays through window openings.","gs.error_glow_radius":"Enter a radius greater than zero.","gs.error_north":"Enter a whole number between 0° and 359°.","gs.opacity_of":"{name} opacity","room.fill_inherit_hint":"Use the fill mode set for the whole space.","room.fill_following":"Following the space: {mode}.","room.fill_mode_label":"Fill mode","room.temp_min_label":"Minimum","room.temp_max_label":"Maximum","room.sizes_hint":"On top of the space-wide card size ({v}%).","room.error_temp_range":"Enter numbers for the comfort bounds.","room.error_name":"Enter a name or choose an area.","marker.name_hint":"Shown on the plan.","marker.binding.help":"A bound marker shows the live state of a Home Assistant device or entity and can act on it. A virtual device is a plain marker with no binding.","marker.binding.help.aria":"Help: binding to a Home Assistant device","marker.binding_virtual_hint":"A virtual device is a plain marker with no binding.","marker.room_hint_auto":"Placed by the device’s Home Assistant area.","marker.room_hint_override":"Overrides the placement by device area.","marker.light_role_seg_auto":"Auto","marker.light_role_seg_always":"Always","marker.light_role_seg_never":"Never","marker.glow_radius_empty_hint":"Empty: uses the general radius ({v}).","marker.icon.help":"Empty means automatic: the icon comes from the icon rules for this device. Pick one to override, or pin the automatic choice.","marker.icon.help.aria":"Help: marker icon","marker.icon_custom_hint":"Custom icon for this marker.","marker.display.help":"How the marker face reacts to state and activity. The value modes replace the icon with a Home Assistant value.","marker.display.help.aria":"Help: display mode","marker.size.help":"Scales and rotates only this marker on the plan. The tap area grows with the icon.","marker.size.help.aria":"Help: icon size and rotation","marker.size_short":"Size","marker.error_binding":"Choose a device or entity to bind.","room.fill_seg_lqi":"Zigbee","room.fill_seg_custom":"Custom"};const X={en:J,ru:{"space.title_hint":"Показывается на вкладках пространств.","space.scale_hint":"Масштаб плана.","space.scale_changed":"Смена масштаба пересчитает размеры всего пространства при сохранении. Точки на плане останутся на месте.","space.plan.help":"Изображение под планом, поверх которого рисуют. Комнаты и устройства остаются редактируемыми. При переходе на рисование вручную загруженное изображение сохраняется и доступно снова.","space.plan.help.aria":"Справка: подложка плана","space.source_draw_hint":"Обвести комнаты в редакторе плана.","space.source_file_hint":"Добавить картинку и рисовать поверх неё.","space.plan_kept":"Загруженное изображение сохранено. Переключитесь обратно, чтобы снова использовать его.","space.show_borders_hint":"Показывать узорную обводку стен.","space.show_borders.help":"Когда выключено, узорная обводка стен и линии стен нулевой толщины скрыты. Светлые полосы стен остаются видны, комнаты не сливаются. Двери, окна, заливки комнат и освещение продолжают работать.","space.show_borders.help.aria":"Справка: границы комнат","space.layers_label":"Видимые слои","space.layers.help":"Скрытие меняет только то, что видно на плане. Декоративные элементы остаются в редакторе подложки. Двери и окна остаются в редакторе плана, а их датчики, солнечный свет и свечение ламп продолжают работать.","space.layers.help.aria":"Справка: видимые слои","space.layer_decor":"Декоративный слой","space.layer_openings":"Двери, окна и ворота","space.fill_lqi_hint":"По среднему LQI комнаты: слабый — 40 и ниже, сильный — 180 и выше. Цвета и прозрачность — из общей палитры.","space.fill_light_hint":"Отдельные цвета для «горит хотя бы одна», «все выключены» и «источников нет». Цвета и прозрачность — из общей палитры.","space.temp_range":"Комфортный диапазон","space.temp_min":"Минимум","space.temp_max":"Максимум","space.temp_range_hint":"Ниже минимума — холодно. В диапазоне — комфорт. Выше максимума — жарко. Без показаний температуры свечение источников света всё равно даёт базовую заливку.","space.show_names_hint":"Названия комнат и выбранные значения на плане.","space.show_names.help":"Скрытие названий скрывает и значения, не сбрасывая выбор. Положение карточек комнат сохраняется.","space.show_names.help.aria":"Справка: названия комнат","space.card_values":"Значения на карточке","space.label_lqi_short":"Сигнал Zigbee","space.values_hidden":"Значения сохранены, но скрыты.","space.values_hidden_action":"Показать названия комнат","space.card_font_hint":"Масштабирует каждую карточку комнаты в этом пространстве.","space.card_font.help":"100 % — размер по умолчанию. Масштабирует все карточки комнат пространства, сохраняя индивидуальные размеры и положение. Применяется при сохранении.","space.card_font.help.aria":"Справка: размер шрифта карточек","space.sun_inherit_short":"Как в общих","space.north_general":"Как в общих · {v}","space.north_custom":"Своё направление","space.north_deg":"Направление на север","space.compass_aria":"Компас: север {v}","space.glow_enabled_hint":"Мягкое свечение вокруг включённых ламп.","space.glow_enabled.help":"Свечение ламп и солнечный свет независимы. Скрытие символов проёмов не отключает ни то, ни другое. Стекло окна пропускает солнце и при закрытом окне.","space.glow_enabled.help.aria":"Справка: свечение источников света","space.error_title":"Введите название пространства.","space.error_plan":"Добавьте изображение плана или переключитесь на рисование вручную.","space.error_temp_range":"Максимум должен быть больше минимума.","space.error_north":"Введите целое число от 0° до 359°.","btn.reset_100":"Сбросить до 100%","dialog.unsaved":"Есть несохранённые изменения","dialog.review_fields":"Проверьте поля: {n}","dialog.discard_title":"Отменить изменения?","dialog.discard_message":"Изменения не сохранены.","dialog.discard_confirm":"Отменить изменения","dialog.discard_keep":"Продолжить редактирование","gs.show_room_tooltip_hint":"Наведите на комнату на плане, чтобы увидеть сводку.","gs.radar_show_live_hint":"Показывает или скрывает все живые цели радаров. Запись наблюдения не запускается и не останавливается.","gs.bg_custom_hint":"Свой цвет фона.","gs.bg_theme_hint":"Используется фон темы.","gs.sun_rays_hint":"Рисовать солнечные лучи через оконные проёмы.","gs.error_glow_radius":"Введите радиус больше нуля.","gs.error_north":"Введите целое число от 0° до 359°.","gs.opacity_of":"Прозрачность: {name}","room.fill_inherit_hint":"Использовать режим заливки всего пространства.","room.fill_following":"Как у пространства: {mode}.","room.fill_mode_label":"Режим заливки","room.temp_min_label":"Минимум","room.temp_max_label":"Максимум","room.sizes_hint":"Поверх размера карточек всего пространства ({v}%).","room.error_temp_range":"Введите числа для границ комфорта.","room.error_name":"Введите название или выберите зону.","marker.name_hint":"Показывается на плане.","marker.binding.help":"Привязанный маркер показывает живое состояние устройства или сущности Home Assistant и может им управлять. Виртуальное устройство — просто маркер без привязки.","marker.binding.help.aria":"Справка: привязка к устройству Home Assistant","marker.binding_virtual_hint":"Виртуальное устройство — просто маркер без привязки.","marker.room_hint_auto":"Размещается по зоне устройства в Home Assistant.","marker.room_hint_override":"Переопределяет размещение по зоне устройства.","marker.light_role_seg_auto":"Авто","marker.light_role_seg_always":"Всегда","marker.light_role_seg_never":"Никогда","marker.glow_radius_empty_hint":"Пусто: общий радиус ({v}).","marker.icon.help":"Пусто — автоматически: иконка берётся из правил иконок для этого устройства. Выберите свою, чтобы переопределить, или закрепите автоматическую.","marker.icon.help.aria":"Справка: иконка маркера","marker.icon_custom_hint":"Своя иконка для этого маркера.","marker.display.help":"Как лицо маркера реагирует на состояние и активность. Режимы значения заменяют иконку значением из Home Assistant.","marker.display.help.aria":"Справка: режим отображения","marker.size.help":"Масштабирует и поворачивает только этот маркер на плане. Область нажатия растёт вместе с иконкой.","marker.size.help.aria":"Справка: размер и поворот иконки","marker.size_short":"Размер","marker.error_binding":"Выберите устройство или сущность для привязки.","room.fill_seg_lqi":"Zigbee","room.fill_seg_custom":"Свой цвет"},de:{"space.title_hint":"Wird in den Bereichs-Tabs angezeigt.","space.scale_hint":"Maßstab des Plans.","space.scale_changed":"Eine Änderung des Maßstabs berechnet beim Speichern die Maße des gesamten Bereichs neu. Punkte auf dem Plan bleiben, wo sie sind.","space.plan.help":"Ein Bild als Hintergrund, über das gezeichnet wird. Räume und Geräte bleiben darüber bearbeitbar. Beim Wechsel zum Zeichnen von Hand bleibt das hochgeladene Bild erhalten.","space.plan.help.aria":"Hilfe: Grundriss","space.source_draw_hint":"Räume im Plan-Editor umreißen.","space.source_file_hint":"Ein Bild hinzufügen und darüber zeichnen.","space.plan_kept":"Das hochgeladene Bild bleibt erhalten. Wechseln Sie zurück, um es wieder zu nutzen.","space.show_borders_hint":"Gemusterte Umrisse um die Wände anzeigen.","space.show_borders.help":"Ausgeschaltet werden gemusterte Wandumrisse und Linien von Wänden ohne Dicke ausgeblendet. Helle Wandbänder bleiben sichtbar, Räume bleiben getrennt. Türen, Fenster, Raumfüllungen und Beleuchtung funktionieren weiter.","space.show_borders.help.aria":"Hilfe: Raumgrenzen","space.layers_label":"Sichtbare Ebenen","space.layers.help":"Ausblenden ändert nur, was auf dem Plan zu sehen ist. Dekorative Elemente bleiben im Hintergrund-Editor verfügbar. Türen und Fenster bleiben im Plan-Editor; ihre Sensoren, Sonnenlicht und Lampenschein funktionieren weiter.","space.layers.help.aria":"Hilfe: sichtbare Ebenen","space.layer_decor":"Dekorative Ebene","space.layer_openings":"Türen, Fenster & Tore","space.fill_lqi_hint":"Nach mittlerem LQI des Raums: schwach bei 40 oder weniger, stark bei 180 oder mehr. Farben und Deckkraft folgen der allgemeinen Palette.","space.fill_light_hint":"Eigene Farben für „mindestens eine Lampe an“, „alle aus“ und „keine Lichtquellen“. Farben und Deckkraft folgen der allgemeinen Palette.","space.temp_range":"Komfortbereich","space.temp_min":"Minimum","space.temp_max":"Maximum","space.temp_range_hint":"Unter dem Minimum: kalt. Im Bereich: Komfort. Über dem Maximum: heiß. Ohne Temperaturwert kann der Lampenschein weiterhin eine Grundschattierung geben.","space.show_names_hint":"Raumnamen und ausgewählte Werte anzeigen.","space.show_names.help":"Das Ausblenden der Raumnamen blendet auch ihre Werte aus, ohne die Auswahl zu löschen. Die Positionen der Raumkarten bleiben erhalten.","space.show_names.help.aria":"Hilfe: Raumnamen","space.card_values":"Werte auf der Karte","space.label_lqi_short":"Zigbee-Signal","space.values_hidden":"Werte sind gespeichert, aber ausgeblendet.","space.values_hidden_action":"Raumnamen anzeigen","space.card_font_hint":"Skaliert jede Raumkarte in diesem Bereich.","space.card_font.help":"100 % ist die Standardgröße. Skaliert alle Raumkarten dieses Bereichs, individuelle Größen und Positionen bleiben erhalten. Gilt nach dem Speichern.","space.card_font.help.aria":"Hilfe: Schriftgröße der Raumkarten","space.sun_inherit_short":"Wie allgemein","space.north_general":"Wie allgemein · {v}","space.north_custom":"Eigene Richtung","space.north_deg":"Nordrichtung","space.compass_aria":"Kompass: Norden bei {v}","space.glow_enabled_hint":"Sanftes Leuchten um eingeschaltete Lampen.","space.glow_enabled.help":"Lampenschein und Sonnenlicht sind unabhängig. Das Ausblenden von Öffnungssymbolen stoppt keinen der Effekte. Fensterglas lässt Sonnenlicht auch bei geschlossenem Fenster durch.","space.glow_enabled.help.aria":"Hilfe: Leuchten der Lichtquellen","space.error_title":"Geben Sie einen Namen für den Bereich ein.","space.error_plan":"Fügen Sie ein Grundrissbild hinzu oder wechseln Sie zum Zeichnen von Hand.","space.error_temp_range":"Das Maximum muss über dem Minimum liegen.","space.error_north":"Geben Sie eine ganze Zahl zwischen 0° und 359° ein.","btn.reset_100":"Auf 100 % zurücksetzen","dialog.unsaved":"Ungespeicherte Änderungen","dialog.review_fields":"{n} Feld(er) prüfen","dialog.discard_title":"Änderungen verwerfen?","dialog.discard_message":"Ihre Änderungen wurden nicht gespeichert.","dialog.discard_confirm":"Änderungen verwerfen","dialog.discard_keep":"Weiter bearbeiten","gs.show_room_tooltip_hint":"Zeigen Sie auf einen Raum im Plan, um seine Übersicht zu sehen.","gs.radar_show_live_hint":"Blendet alle Live-Radarziele ein oder aus. Die Beobachtungsaufzeichnung wird dadurch nicht gestartet oder gestoppt.","gs.bg_custom_hint":"Eigene Hintergrundfarbe.","gs.bg_theme_hint":"Hintergrund des Themes wird verwendet.","gs.sun_rays_hint":"Sonnenstrahlen durch Fensteröffnungen zeichnen.","gs.error_glow_radius":"Geben Sie einen Radius größer als null ein.","gs.error_north":"Geben Sie eine ganze Zahl zwischen 0° und 359° ein.","gs.opacity_of":"Deckkraft: {name}","room.fill_inherit_hint":"Den Füllmodus des gesamten Bereichs verwenden.","room.fill_following":"Wie der Bereich: {mode}.","room.fill_mode_label":"Füllmodus","room.temp_min_label":"Minimum","room.temp_max_label":"Maximum","room.sizes_hint":"Zusätzlich zur bereichsweiten Kartengröße ({v} %).","room.error_temp_range":"Geben Sie Zahlen für die Komfortgrenzen ein.","room.error_name":"Geben Sie einen Namen ein oder wählen Sie einen Bereich.","marker.name_hint":"Wird auf dem Plan angezeigt.","marker.binding.help":"Ein verknüpfter Marker zeigt den Live-Zustand eines Home-Assistant-Geräts oder einer Entität und kann darauf wirken. Ein virtuelles Gerät ist ein einfacher Marker ohne Verknüpfung.","marker.binding.help.aria":"Hilfe: Verknüpfung mit einem Home-Assistant-Gerät","marker.binding_virtual_hint":"Ein virtuelles Gerät ist ein einfacher Marker ohne Verknüpfung.","marker.room_hint_auto":"Platzierung nach dem Home-Assistant-Bereich des Geräts.","marker.room_hint_override":"Überschreibt die Platzierung nach Gerätebereich.","marker.light_role_seg_auto":"Auto","marker.light_role_seg_always":"Immer","marker.light_role_seg_never":"Nie","marker.glow_radius_empty_hint":"Leer: allgemeiner Radius ({v}).","marker.icon.help":"Leer bedeutet automatisch: Das Symbol kommt aus den Symbolregeln für dieses Gerät. Wählen Sie eines zum Überschreiben oder heften Sie die automatische Wahl an.","marker.icon.help.aria":"Hilfe: Marker-Symbol","marker.icon_custom_hint":"Eigenes Symbol für diesen Marker.","marker.display.help":"Wie das Marker-Gesicht auf Zustand und Aktivität reagiert. Die Wert-Modi ersetzen das Symbol durch einen Home-Assistant-Wert.","marker.display.help.aria":"Hilfe: Anzeigemodus","marker.size.help":"Skaliert und dreht nur diesen Marker auf dem Plan. Die Tippfläche wächst mit dem Symbol.","marker.size.help.aria":"Hilfe: Symbolgröße und Drehung","marker.size_short":"Größe","marker.error_binding":"Wählen Sie ein Gerät oder eine Entität zum Verknüpfen.","room.fill_seg_lqi":"Zigbee","room.fill_seg_custom":"Eigene"},fr:{"space.title_hint":"Affiché dans les onglets des espaces.","space.scale_hint":"Échelle du plan.","space.scale_changed":"Changer l’échelle recalcule les dimensions de tout l’espace à l’enregistrement. Les points du plan restent en place.","space.plan.help":"Une image en arrière-plan sur laquelle dessiner. Les pièces et les appareils restent modifiables par-dessus. Passer au dessin à la main conserve l’image téléversée pour la réutiliser.","space.plan.help.aria":"Aide : fond de plan","space.source_draw_hint":"Tracer les pièces dans l’éditeur de plan.","space.source_file_hint":"Ajouter une image et dessiner par-dessus.","space.plan_kept":"Votre image téléversée est conservée. Revenez en arrière pour la réutiliser.","space.show_borders_hint":"Afficher les contours hachurés autour des murs.","space.show_borders.help":"Désactivé, les contours hachurés des murs et les lignes des murs sans épaisseur sont masqués. Les bandes claires des murs restent visibles, les pièces restent séparées. Portes, fenêtres, remplissages et éclairage continuent de fonctionner.","space.show_borders.help.aria":"Aide : bordures des pièces","space.layers_label":"Calques visibles","space.layers.help":"Masquer ne change que ce qui est visible sur le plan. Les éléments décoratifs restent disponibles dans l’éditeur de fond. Portes et fenêtres restent dans l’éditeur de plan ; leurs capteurs, la lumière du soleil et la lueur des lampes continuent de fonctionner.","space.layers.help.aria":"Aide : calques visibles","space.layer_decor":"Calque décoratif","space.layer_openings":"Portes, fenêtres et portails","space.fill_lqi_hint":"Selon le LQI moyen de la pièce : faible à 40 ou moins, fort à 180 ou plus. Couleurs et opacité suivent la palette générale.","space.fill_light_hint":"Couleurs distinctes pour « au moins une lampe allumée », « toutes éteintes » et « aucune source ». Couleurs et opacité suivent la palette générale.","space.temp_range":"Plage de confort","space.temp_min":"Minimum","space.temp_max":"Maximum","space.temp_range_hint":"Sous le minimum : froid. Dans la plage : confort. Au-dessus du maximum : chaud. Sans mesure de température, la lueur des sources lumineuses peut encore donner un ombrage de base.","space.show_names_hint":"Afficher les noms des pièces et les valeurs choisies.","space.show_names.help":"Masquer les noms masque aussi leurs valeurs sans effacer vos choix. La position des cartes des pièces est conservée.","space.show_names.help.aria":"Aide : noms des pièces","space.card_values":"Valeurs sur la carte","space.label_lqi_short":"Signal Zigbee","space.values_hidden":"Les valeurs sont enregistrées mais masquées.","space.values_hidden_action":"Afficher les noms des pièces","space.card_font_hint":"Met à l’échelle chaque carte de pièce de cet espace.","space.card_font.help":"100 % est la taille par défaut. Met à l’échelle toutes les cartes de pièces de cet espace en conservant tailles et positions individuelles. Appliqué à l’enregistrement.","space.card_font.help.aria":"Aide : taille de police des cartes","space.sun_inherit_short":"Comme les réglages généraux","space.north_general":"Comme les réglages généraux · {v}","space.north_custom":"Direction personnalisée","space.north_deg":"Direction du nord","space.compass_aria":"Boussole : nord à {v}","space.glow_enabled_hint":"Lueur douce autour des lampes allumées.","space.glow_enabled.help":"La lueur des lampes et la lumière du soleil sont indépendantes. Masquer les symboles d’ouvertures n’arrête aucun des deux effets. Le vitrage laisse passer le soleil même fenêtre fermée.","space.glow_enabled.help.aria":"Aide : lueur des sources lumineuses","space.error_title":"Saisissez un nom pour l’espace.","space.error_plan":"Ajoutez une image du plan ou passez au dessin à la main.","space.error_temp_range":"Le maximum doit être supérieur au minimum.","space.error_north":"Saisissez un nombre entier entre 0° et 359°.","btn.reset_100":"Réinitialiser à 100 %","dialog.unsaved":"Modifications non enregistrées","dialog.review_fields":"Vérifiez {n} champ(s)","dialog.discard_title":"Abandonner vos modifications ?","dialog.discard_message":"Vos modifications n’ont pas été enregistrées.","dialog.discard_confirm":"Abandonner","dialog.discard_keep":"Continuer la modification","gs.show_room_tooltip_hint":"Survolez une pièce sur le plan pour voir son résumé.","gs.radar_show_live_hint":"Affiche ou masque toutes les cibles radar en direct. Cela ne démarre ni n’arrête l’enregistrement d’observation.","gs.bg_custom_hint":"Couleur de fond personnalisée.","gs.bg_theme_hint":"Fond du thème utilisé.","gs.sun_rays_hint":"Tracer les rayons du soleil à travers les ouvertures des fenêtres.","gs.error_glow_radius":"Saisissez un rayon supérieur à zéro.","gs.error_north":"Saisissez un nombre entier entre 0° et 359°.","gs.opacity_of":"Opacité : {name}","room.fill_inherit_hint":"Utiliser le mode de remplissage de tout l’espace.","room.fill_following":"Comme l’espace : {mode}.","room.fill_mode_label":"Mode de remplissage","room.temp_min_label":"Minimum","room.temp_max_label":"Maximum","room.sizes_hint":"En plus de la taille des cartes de l’espace ({v} %).","room.error_temp_range":"Saisissez des nombres pour les bornes de confort.","room.error_name":"Saisissez un nom ou choisissez une zone.","marker.name_hint":"Affiché sur le plan.","marker.binding.help":"Un marqueur lié affiche l’état en direct d’un appareil ou d’une entité Home Assistant et peut agir dessus. Un appareil virtuel est un simple marqueur sans liaison.","marker.binding.help.aria":"Aide : liaison à un appareil Home Assistant","marker.binding_virtual_hint":"Un appareil virtuel est un simple marqueur sans liaison.","marker.room_hint_auto":"Placé selon la zone Home Assistant de l’appareil.","marker.room_hint_override":"Remplace le placement par zone de l’appareil.","marker.light_role_seg_auto":"Auto","marker.light_role_seg_always":"Toujours","marker.light_role_seg_never":"Jamais","marker.glow_radius_empty_hint":"Vide : rayon général ({v}).","marker.icon.help":"Vide signifie automatique : l’icône vient des règles d’icônes de cet appareil. Choisissez-en une pour remplacer, ou épinglez le choix automatique.","marker.icon.help.aria":"Aide : icône du marqueur","marker.icon_custom_hint":"Icône personnalisée pour ce marqueur.","marker.display.help":"Comment la face du marqueur réagit à l’état et à l’activité. Les modes valeur remplacent l’icône par une valeur Home Assistant.","marker.display.help.aria":"Aide : mode d’affichage","marker.size.help":"Redimensionne et fait pivoter uniquement ce marqueur sur le plan. La zone de toucher grandit avec l’icône.","marker.size.help.aria":"Aide : taille et rotation de l’icône","marker.size_short":"Taille","marker.error_binding":"Choisissez un appareil ou une entité à lier.","room.fill_seg_lqi":"Zigbee","room.fill_seg_custom":"Perso"}};function ee(e,a){const t=X[e]?.[a]??J[a];return"string"==typeof t&&t.trim().length>0}function ae(e,a,i){return t(X[e]?.[a]??J[a]??a,i)}function te(t){const n=i(t.hass,t._config?.language);return{st:(e,a)=>ae(n,e,a),shelp:t=>{const i=`${t}.aria`;return ee(n,t)&&ee(n,i)?a``:e}}}const ie=new Set(["busy","pickSaved","saved","savedBusy","savedAspect","cellCmInput","cellCmTouched","displayTouched","deleteBlockers","copy"]);function ne(e){return Y({...e,planFile:e.planFile?e.planFile.name:null},ie)}function se(e,a){Z(e,"space",ne(a))}const re=.1,oe=1e3,le=(e,a)=>{e.host._spaceDialog=a};function ce(t){M(t.host);const{host:i}=t,n=i._spaceDialog,s=i._t.bind(i),{st:r}=te(i),o=e=>`${t.idPrefix}-${e}`,l=function(e,a){const t=[];return e.title.trim()||t.push({field:`${a}-title`,message:"space.error_title"}),"file"!==e.source||e.planFile||e.planUrl||t.push({field:`${a}-plan`,message:"space.error_plan"}),"temp"!==e.fillMode||Number.isFinite(e.tempMin)&&Number.isFinite(e.tempMax)&&e.tempMin=0&&e.northDeg<=359||t.push({field:`${a}-north-deg`,message:"space.error_north"}),t}(n,t.idPrefix),c=e=>l.find(a=>a.field===e),d=function(e,a){return Q(e,"space",ne(a))}(i,n),p=d&&0===l.length&&!n.busy,h=i._importTotal>0&&"create"===n.mode?s("import.progress",{i:i._importTotal-i._importQueue.length,n:i._importTotal}):"",u=()=>{!function(e){K(e,"space")}(i),i._spaceDialog=null,i._importQueue=[],i._importTotal=0},m=async e=>{if(!d||n.busy)return void u();const a=e.currentTarget;await i._confirmDanger({key:"discard-space-dialog",kind:"warning",title:r("dialog.discard_title"),message:r("dialog.discard_message"),objectName:n.title.trim()||void 0,confirmLabel:r("dialog.discard_confirm"),cancelLabel:r("dialog.discard_keep")})?u():a?.rejectClose?.()};return{title:`${"create"===n.mode?s("space.new"):s("space.header")}${h?` · ${h}`:""}`,badge:"edit"===n.mode?n.title.trim():"",requestClose:m,body:a`
    ${de(t,n,o,c)} ${he(t,n,o,c)} ${ue(t,n,o)} @@ -109,7 +109,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${s("btn.delete")}
    `:e} - ${G(l.length?{action:W(r("dialog.review_fields",{n:String(l.length)}),()=>{const e=l[0];if(!e)return;const a=i.renderRoot.querySelector(`#${e.field}`);a?.scrollIntoView({block:"center"}),a?.focus()})}:{text:d?r("dialog.unsaved"):""})} + ${U(l.length?{action:W(r("dialog.review_fields",{n:String(l.length)}),()=>{const e=l[0];if(!e)return;const a=i.renderRoot.querySelector(`#${e.field}`);a?.scrollIntoView({block:"center"}),a?.focus()})}:{text:d?r("dialog.unsaved"):""})}
    ${i._importTotal>0&&"create"===n.mode?a``:e} @@ -119,12 +119,12 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
    `}}function de(t,i,l,c){const{host:d}=t,p=d._t.bind(d),{st:h,shelp:u}=te(d),m="edit"===i.mode&&i.spaceId?d._serverCfg?.spaces.find(e=>e.id===i.spaceId):void 0,_=m&&Number(m.cell_cm)>0?Number(m.cell_cm):null,g=null!==_&&Math.abs(i.cellCm-_)>1e-9,b=c(l("title")),f=c(l("plan"));return C({id:"basics",title:p("space.card_basics"),body:a` - ${P([L({label:p("space.title_label"),htmlFor:l("title"),hint:h("space.title_hint"),error:b?h(b.message):void 0,control:a`le(t,{...i,title:e.target.value})} />`}),L({label:p("space.scale_label"),htmlFor:l("cell-cm"),help:t.help("space.cell_cm.help"),hint:h("space.scale_hint"),control:I({id:l("cell-cm"),wide:!0,value:i.cellCmInput??n(i.cellCm,d._imperial),unit:p(d._imperial?"space.scale_unit_imperial":"space.scale_unit"),min:Number(n(.1,d._imperial)),max:Number(n(oe,d._imperial)),step:.1,onInput:e=>{const a=s(e),n=null==a?null:r(a,d._imperial);le(t,{...i,cellCmInput:e,cellCmTouched:!0,cellCm:null!=n&&n>0?Math.max(.1,Math.min(oe,n)):i.cellCm})}})})],{narrow:!0})} + @input=${e=>le(t,{...i,title:e.target.value})} />`}),z({label:p("space.scale_label"),htmlFor:l("cell-cm"),help:t.help("space.cell_cm.help"),hint:h("space.scale_hint"),control:I({id:l("cell-cm"),wide:!0,value:i.cellCmInput??n(i.cellCm,d._imperial),unit:p(d._imperial?"space.scale_unit_imperial":"space.scale_unit"),min:Number(n(.1,d._imperial)),max:Number(n(oe,d._imperial)),step:.1,onInput:e=>{const a=s(e),n=null==a?null:r(a,d._imperial);le(t,{...i,cellCmInput:e,cellCmTouched:!0,cellCm:null!=n&&n>0?Math.max(.1,Math.min(oe,n)):i.cellCm})}})})],{narrow:!0})} ${g?B({kind:"warning",text:h("space.scale_changed")}):e} - ${z({title:p("space.plan_label"),help:u("space.plan.help")})} + ${L({title:p("space.plan_label"),help:u("space.plan.help")})}
    ${v="plansrc",w=i.source,y=[{value:"draw",title:p("space.source_draw"),caption:h("space.source_draw_hint")},{value:"file",title:p("space.source_file"),caption:h("space.source_file_hint")}],k=e=>le(t,o(i,e)),$=p("space.plan_label"),a`
    ${y.map(e=>a`
    `})}
    `}function Rr(e,t="hp-paperg"){return W`${e.map(e=>"path"in e?W``:"poly"in e?W``:W``)}`}const Cr={color:"#607d8b",opacity:1,widthCm:3.6,fill:!1,fillColor:"#607d8b",fillOpacity:.25},Tr=(e,t=1)=>{const i=Number(e);return Number.isFinite(i)?Math.min(1,Math.max(0,i)):t},Dr=e=>{let t=Number(e);return Number.isFinite(t)?(t=(t%360+360)%360,t>180?t-360:t):0};function Ar(e,t,i){return Dr(t)?[e.x,e.y]:i([e.x,e.y])}function Pr(e,t,i,n){const r=Math.abs(i[0]-t[0]),o=Math.abs(i[1]-t[1]);return"line"===e?Math.hypot(r,o)>=n:r>=n&&o>=n}const Fr=(e,t,i)=>{const n=Number(e),r=Number.isFinite(t)&&t>0?t:5;return Number.isFinite(n)&&n>0?n/r*i:0},zr=(e,t,i)=>{const n=Number(e),r=Number.isFinite(t)&&t>0?t:5;return Number.isFinite(n)&&i>0?n/i*r:0},Ir=(e,t,i,n=Cr.widthCm)=>{const r=Number(e?.width_cm);if(Number.isFinite(r)&&r>0)return r;const o=Number(e?.width);return Number.isFinite(o)&&o>0?zr(o,t,i):n};function Or(e){const t=Cr;return e.color===t.color&&e.opacity===t.opacity&&e.widthCm===t.widthCm&&e.fill===t.fill&&e.fillColor===t.fillColor&&e.fillOpacity===t.fillOpacity?null:{color:e.color,opacity:Tr(e.opacity),width_cm:Math.max(.1,Math.min(100,Number(e.widthCm)||.1)),fill:!!e.fill,fill_color:e.fillColor,fill_opacity:Tr(e.fillOpacity,.25)}}function Er(e,t){return{color:e.color,opacity:Tr(e.opacity),width_cm:Math.max(.1,Math.min(100,Number(e.widthCm)||.1)),...t?{fill:e.fill,fill_color:e.fillColor,fill_opacity:Tr(e.fillOpacity,.25)}:{}}}function Nr(e){const t=e.x+e.w/2,i=e.y+e.h/2,n=Dr(e.angle)*Math.PI/180,r=Math.cos(n),o=Math.sin(n),s=(e,n)=>{const s=e-t,a=n-i;return[t+s*r-a*o,i+s*o+a*r]};return[s(e.x,e.y),s(e.x+e.w,e.y),s(e.x+e.w,e.y+e.h),s(e.x,e.y+e.h)]}function Hr(e){const t=Nr(e),i=(e,t)=>[(e[0]+t[0])/2,(e[1]+t[1])/2],n=[(t[0][0]+t[2][0])/2,(t[0][1]+t[2][1])/2];return{points:[...t,i(t[0],t[1]),i(t[1],t[2]),i(t[2],t[3]),i(t[3],t[0]),n],segments:t.map((e,i)=>({a:e,b:t[(i+1)%4]}))}}function Lr(e,t,i,n,r,o,s,a){const l=Dr(e.angle)*Math.PI/180,c=Math.cos(l),h=Math.sin(l),d=-Math.sin(l),u=Math.cos(l),p=e.x+e.w/2,_=e.y+e.h/2,m=t>0?-e.w/2:e.w/2,g=i>0?-e.h/2:e.h/2,f=p+m*c+g*d,v=_+m*h+g*u,y=n-f,b=r-v;let w=(y*c+b*h)*(t>0?1:-1),k=(y*d+b*u)*(i>0?1:-1),x=null;if(o){const t=w/Math.max(e.w,a),i=k/Math.max(e.h,a);x=Math.max(a/Math.max(e.w,a),a/Math.max(e.h,a),t,i),w=e.w*x,k=e.h*x}if(s>0)if(o){const t=Math.max(1,Math.round(e.w/s)),i=Math.max(1,Math.round(e.h/s));if(Math.abs(e.w-t*s)<1e-6&&Math.abs(e.h-i*s)<1e-6){const n=(e,t)=>{let i=Math.abs(e),n=Math.abs(t);for(;n;)[i,n]=[n,i%n];return Math.max(1,i)},r=1/n(t,i),o=Math.max(a/e.w,a/e.h),s=Math.max(o,Math.round((x??1)/r)*r);w=e.w*s,k=e.h*s}else{e.w>=e.h?(w=Math.round(w/s)*s,k=w*(e.h/Math.max(e.w,a))):(k=Math.round(k/s)*s,w=k*(e.w/Math.max(e.h,a)))}}else w=Math.round(w/s)*s,k=Math.round(k/s)*s;w=Math.max(a,w),k=Math.max(a,k);return{x:f+(t>0?w/2:-w/2)*c+(i>0?k/2:-k/2)*d-w/2,y:v+(t>0?w/2:-w/2)*h+(i>0?k/2:-k/2)*u-k/2,w:w,h:k,angle:Dr(e.angle)||void 0}}const Br=(e,t,i)=>{const n=i[0]-t[0],r=i[1]-t[1],o=n*n+r*r;if(o<1e-12)return[...t];const s=Math.max(0,Math.min(1,((e[0]-t[0])*n+(e[1]-t[1])*r)/o));return[t[0]+n*s,t[1]+r*s]};function qr(e,t,i,n){const r=n(e);let o=null;for(const r of t.points){const t=n(r),s=Math.hypot(t[0]-e[0],t[1]-e[1]);s<=i&&(!o||se.points),segments:e.flatMap(e=>e.segments)}}const Wr=Math.tan(.25*Math.PI/180);function Ur(e,t){const i=Math.abs(Number(t[0])-Number(e[0])),n=Math.abs(Number(t[1])-Number(e[1]));if(!([i,n].every(Number.isFinite)&&i>0&&n>0))return null;const r=i>=n?"horizontal":"vertical",o=Math.max(i,n),s=Math.min(i,n);return s/o>Wr?null:{axis:r,major:o,minor:s,angleDegrees:180*Math.atan2(s,o)/Math.PI}}function Gr(e,t){const i=Ur(e,t);return i?"horizontal"===i.axis?[Number(t[0]),Number(e[1])]:[Number(e[0]),Number(t[1])]:[Number(t[0]),Number(t[1])]}const Vr=e=>`${e[0]},${e[1]}`,Kr=(e,t)=>e[0]===t[0]&&e[1]===t[1],Yr=(e,t)=>{const i=Vr(e),n=Vr(t);return i{let t=0;for(let i=0;i{if(e.length<3)return!1;for(let t=0;t1e-12},Jr=(e,t)=>Kr(e,t.from)?[...t.to]:[...e],Qr=(e,t)=>e.map(e=>Array.isArray(e?.poly)?{...e,poly:e.poly.map(e=>Jr(e,t))}:e),eo=(e,t,i)=>{const n=e.flatMap((e,t)=>ni(e)?.some(e=>Kr(e,i.from))?[t]:[]);if(!n.length)return!1;for(const i of n){const n=ni(e[i]),r=ni(t[i]);if(!n||!r)continue;if(!Zr(r))return!1;const o=Math.sign(Xr(n)),s=Math.sign(Xr(r));if(o&&s&&o!==s)return!1}const r=new Set;for(const e of n){const i=ni(t[e]);if(i)for(let n=0;n{let i=0;for(const n of e){const e=ni(n);if(e)for(let n=0;n{const{a:i,b:n,axis:r}=e,o="horizontal"===r?{from:n,to:[n[0],i[1]]}:{from:n,to:[i[0],n[1]]},s="horizontal"===r?{from:i,to:[i[0],n[1]]}:{from:i,to:[n[0],i[1]]};return[{move:o,preservedDegree:to(t,i)},{move:s,preservedDegree:to(t,n)}].sort((e,t)=>t.preservedDegree-e.preservedDegree||Vr(e.move.to).localeCompare(Vr(t.move.to))||Vr(e.move.from).localeCompare(Vr(t.move.from))).map(e=>e.move)};function no(e){const t=JSON.parse(JSON.stringify(e||{}));let i=Array.isArray(t.rooms)?t.rooms:[];const n=new Map;for(const e of i){const t=ni(e);if(t)for(let e=0;ee.key.localeCompare(t.key))){let t=null;for(const n of io(e,i)){const e=a.get(Vr(n.from));if(e&&e!==Vr(n.to))continue;const r=Qr(i,n);if(eo(i,r,n)){t=n,i=r;break}}t?(a.set(Vr(t.from),Vr(t.to)),r++,s=Math.max(s,Math.hypot(t.to[0]-t.from[0],t.to[1]-t.from[1]))):o++}t.rooms=i;for(const e of t.partitions||[]){if(!Array.isArray(e?.a)||!Array.isArray(e?.b))continue;const i=Ur(e.a,e.b);if(!i)continue;const n={key:String(e.id||Yr(e.a,e.b)),a:[...e.a],b:[...e.b],axis:i.axis};let a=null;for(const i of io(n,[{poly:[e.a,e.b]}])){const n=Jr(e.a,i),r=Jr(e.b,i),o=Math.hypot(r[0]-n[0],r[1]-n[1]);if(!(o>0))continue;const s=(t.openings||[]).filter(t=>"partition"===t?.host?.kind&&t.host.id===e.id).every(e=>{const t=Number(e.host.t),i=Number(e.length);return Number.isFinite(t)&&t>=0&&t<=1&&Number.isFinite(i)&&i>0&&t*o-i/2>=-1e-12&&t*o+i/2<=o+1e-12});if(s){a=i,e.a=n,e.b=r;break}}a?(r++,s=Math.max(s,Math.hypot(a.to[0]-a.from[0],a.to[1]-a.from[1]))):o++}return{space:t,report:{wallsStraightened:r,wallsStraightenSkipped:o,maxStraightenShift:s},changed:r>0}}const ro=["rect","ellipse","furniture","image"],oo=10**9,so=240,ao=1e-4;function lo(e){if(Array.isArray(e))return e.map(e=>lo(e));if(null!==e&&"object"==typeof e){const t={};for(const[i,n]of Object.entries(e))t[i]=lo(n);return t}return e}function co(e){if("number"!=typeof e||!Number.isFinite(e))return e;const t=(e<0||Object.is(e,-0)?-1:1)*(Math.floor(Math.abs(e)*oo+.5)/oo);return 0===t?0:t}function ho(e){if("number"!=typeof e||!Number.isFinite(e))return e;const t=e*so,i=Math.round(t);if(Math.abs(t-i)null!==po(e)):[]}function mo(e){return"string"==typeof e&&ro.includes(e)}function go(e,t){for(const i of t)Object.prototype.hasOwnProperty.call(e,i)&&(e[i]=co(e[i]))}function fo(e,t){for(const i of t)Object.prototype.hasOwnProperty.call(e,i)&&(e[i]=ho(e[i]))}function vo(e){if(Array.isArray(e))for(let t=0;t{for(const r of n){const n=t[r];"number"==typeof n&&Number.isFinite(n)&&i(n,e)}},n=t=>{if(Array.isArray(t))for(let n=0;n{if(Array.isArray(e))for(const t of e)n(t)};for(const i of _o(e.rooms))t(i,["x","y","w","h"]),r(i.poly);for(const t of _o(e.walls))n(t.a),n(t.b);for(const t of _o(e.wall_segments))n(t.a),n(t.b);for(const i of _o(e.openings))t(i,["x","y"]);for(const i of _o(e.decor))"line"===i.kind?t(i,["x1","y1","x2","y2"]):mo(i.kind)?t(i,["x","y","w","h"]):"text"===i.kind&&t(i,["x","y"]);for(const t of _o(e.room_drafts))r(t.points);for(const t of _o(e.partitions))n(t.a),n(t.b);for(const t of _o(e.wall_columns))n(t.center);for(const t of _o(e.open_spans))n(t.a),n(t.b)}const r=po(t);if(!r)return;const o=new Map;if(n)for(const e of _o(n.spaces))null!=e.id&&o.set(String(e.id),e);for(const e of Object.values(r)){const t=po(e);if(!t)continue;const n=null!=t.s&&o.get(String(t.s))||null;for(const e of["x","y"]){const r=t[e];"number"==typeof r&&Number.isFinite(r)&&i(r,n)}}}function wo(e){const t=Number(e?.cell_cm);return t>0?t:5}function ko(e,t={}){const i={canonicalized:0,far:0,maxShift:0,maxShiftCm:0,spaces:[],bySpace:new Map},n=_o(po(e)?.spaces);let r=5;for(const e of n)r=Math.max(r,wo(e));bo(e,t,(e,t)=>{const n=e*so,o=Math.abs(n-Math.round(n)),s=ho(e),a=o>0&&o=ao))return;const l=a&&"number"==typeof s?Math.abs(s-e):0;if(a?i.canonicalized++:i.far++,i.maxShift=Math.max(i.maxShift,l),i.maxShiftCm=Math.max(i.maxShiftCm,l*so*(t?wo(t):r)),!t?.id||!a)return;const c=String(t.id);let h=i.bySpace.get(c);h||(h={spaceId:c,space:String(t.title||c),canonicalized:0,far:0,maxShift:0,maxShiftCm:0},i.bySpace.set(c,h)),h.canonicalized++,h.maxShift=Math.max(h.maxShift,l),h.maxShiftCm=Math.max(h.maxShiftCm,l*so*wo(t))}),i.bySpace.size&&bo(e,t,(e,t)=>{if(!t?.id)return;const n=i.bySpace.get(String(t.id));if(!n)return;const r=e*so;Math.abs(r-Math.round(r))>=ao&&n.far++}),i.spaces=[...i.bySpace.values()];const{bySpace:o,...s}=i;return s}function xo(e){return function(e){const t=e,i=po(t);i&&fo(i,["x","y"]);return t}(lo(e))}function So(e){const t=e,i=po(t);if(!i)return t;for(const e of Object.values(i)){const t=po(e);t&&fo(t,["x","y"])}return t}function $o(e){return Mo(lo(e))}function Mo(e){const t=e,i=po(t);if(!i)return t;for(const e of _o(i.spaces)){go(e,["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"]);for(const t of _o(e.rooms))fo(t,["x","y","w","h"]),yo(t.poly);for(const t of _o(e.walls))vo(t.a),vo(t.b);for(const t of _o(e.wall_segments))vo(t.a),vo(t.b);for(const t of _o(e.openings)){fo(t,["x","y"]),go(t,["angle","length"]);const e=po(t.host);e&&go(e,["t"])}for(const t of _o(e.decor))"line"===t.kind?fo(t,["x1","y1","x2","y2"]):mo(t.kind)?(fo(t,["x","y","w","h"]),go(t,["angle"])):"text"===t.kind&&(fo(t,["x","y"]),go(t,["scale","angle"]));for(const t of _o(e.room_drafts))yo(t.points);for(const t of _o(e.partitions))vo(t.a),vo(t.b);for(const t of _o(e.wall_columns))vo(t.center),"square"===t.shape&&go(t,["angle"]);for(const t of _o(e.open_spans))vo(t.a),vo(t.b)}for(const e of _o(i.markers))go(e,["angle"]);return t}const Ro=15,Co=8;function To(e,t,i,n,r){const o=i[0]-e[0],s=i[1]-e[1],a=Math.hypot(o,s);if(!(a>0)||a<=r+1e-9)return null;const l=o/a,c=s/a,h=t=>{const n=(t[0]-e[0])*l+(t[1]-e[1])*c,o=(r-n)/(a-n);return!Number.isFinite(o)||o<-1e-9||o>1+1e-9?null:[t[0]+(i[0]-t[0])*o,t[1]+(i[1]-t[1])*o]},d=h(t),u=h(n);return d&&u?[[e[0],e[1]],t,d,u,n]:null}const Do=Math.sin(.25*Math.PI/180);function Ao(e,t){return Number.isFinite(e)&&e>0&&Number.isFinite(t)&&t>0&&e*t<3}function Po(e){const t=Number(e)>0?Number(e):5;if(5===t)return 8;const i=5/t*8;return Math.min(80,Math.max(.5,i))}function Fo(e,t){return Number.isFinite(e)&&e>0&&Number.isFinite(t)&&t>0&&e*t<2}function zo(e){return Number.isFinite(e)?Math.max(1,Math.min(100,e)):1}function Io(e,t){return!Number.isFinite(e)||e<0?"":String(t?Math.round(e/2.54*100)/100:Math.round(100*e)/100)}function Oo(e,t,i){if(!Number.isFinite(e)||e<=0)return 0;const n=Number(t)>0?Number(t):5;return zo(e)/n*i}function Eo(e,t){return t>0&&Number.isFinite(e)?Math.round(e/t)*t:e}function No(e){return Math.max(1e-6*Math.abs(e),1e-9)}function Ho(e,t){if(!(t>0&&Number.isFinite(e)))return e;const i=Eo(e,t);return Math.abs(i-e)<=No(t)?i:e}function Lo(e,t){let i=t[0]-e[0],n=t[1]-e[1];const r=Math.hypot(i,n);return r<1e-12?[1,0]:(i/=r,n/=r,(i<-1e-12||Math.abs(i)<=1e-12&&n<0)&&(i=-i,n=-n),[i,n])}function Bo(e,t,i){const n=[Ho(e[0],i),Ho(e[1],i)],r=[Ho(t[0],i),Ho(t[1],i)],o=Eo((n[0]+r[0])/2,i),s=Eo((n[1]+r[1])/2,i),[a,l]=Lo(n,r);let c=Math.atan2(l,a);c<0&&(c+=Math.PI);const h=Math.round(1800*c)/1800,d=i>0&&i<.01?6:i<1?4:2;return`${o.toFixed(d)},${s.toFixed(d)}@${h.toFixed(4)}`}function qo(e,t,i,n){return 1===n?Bo(e,t,i):Bo([e[0]/n,e[1]/n],[t[0]/n,t[1]/n],i)}function jo(e,t){if(!Array.isArray(e.a)||!Array.isArray(e.b)||e.a.length<2||e.b.length<2)return null;const i=[Number(e.a[0]),Number(e.a[1]),Number(e.b[0]),Number(e.b[1])];if(!i.every(Number.isFinite))return null;const n=t>0?t:1;return[[i[0]*n,i[1]*n],[i[2]*n,i[3]*n]]}function Wo(e,t,i,n,r){const o=r>0?r:1;return{key:qo(e,t,n,o),cm:zo(i),a:[e[0]/o,e[1]/o],b:[t[0]/o,t[1]/o]}}function Uo(e,t){const i=t>0?t:1,n=[];for(const t of e){const e=t.key.lastIndexOf("@");if(e<0)continue;const[r,o]=t.key.slice(0,e).split(",").map(Number),s=Number(t.key.slice(e+1));[r,o,s].every(Number.isFinite)&&n.push({w:t,x:r*i,y:o*i,ang:s})}return n}function Go(e,t){const[i,n]=Lo(e,t);let r=Math.atan2(n,i);return r<0&&(r+=Math.PI),r}function Vo(e,t){let i=Math.abs(e-t);return i>Math.PI/2&&(i=Math.PI-i),i<.02}function Ko(e,t,i,n,r=1){if(!e?.length)return null;const o=qo(t,i,n,r),s=e.find(e=>e.key===o);if(s)return s;const a=r>0?r:1,l=No(n)*a,c=(e,t)=>Math.abs(e[0]-t[0])<=l&&Math.abs(e[1]-t[1])<=l;for(const n of e){const e=jo(n,a);if(e&&(c(e[0],t)&&c(e[1],i)||c(e[0],i)&&c(e[1],t)))return n}const h=(t[0]+i[0])/2,d=(t[1]+i[1])/2,u=Go(t,i),p=Math.max(.5*n,1e-9)*a;for(const t of Uo(e,a))if(Vo(t.ang,u)&&Math.hypot(t.x-h,t.y-d)<=p)return t.w;return null}function Yo(e,t,i,n,r=1){const o=Ko(e,t,i,n,r);if(o&&o.cm>0)return zo(o.cm);const s=function(e,t,i,n,r){if(!e?.length)return null;const o=r>0?r:1,s=Math.hypot(i[0]-t[0],i[1]-t[1]);if(s<1e-12)return null;const a=Go(t,i),l=Math.max(.5*n,1e-9)*o;let c=null;for(const n of e){if(!(n.cm>0))continue;const e=jo(n,o);if(!e)continue;const r=Math.hypot(e[1][0]-e[0][0],e[1][1]-e[0][1]);if(r<1e-12||!Vo(Go(e[0],e[1]),a))continue;if(Ns(t[0],t[1],e[0][0],e[0][1],e[1][0],e[1][1])>l||Ns(i[0],i[1],e[0][0],e[0][1],e[1][0],e[1][1])>l)continue;if(r+l(o.has(e.key)||(e=>{const t=jo(e,n);if(!t)return!1;const[i,o]=t,a=o[0]-i[0],c=o[1]-i[1],h=Math.hypot(a,c);if(h<=l)return!1;if(!s.some(e=>{const t=[e[0],e[1]],n=[e[2],e[3]];return Vo(Go(i,o),Go(t,n))&&Ns(i[0],i[1],t[0],t[1],n[0],n[1])<=l&&Ns(o[0],o[1],t[0],t[1],n[0],n[1])<=l}))return!1;const d=(r||[]).some(e=>{const t=[e[0],e[1]],n=[e[2],e[3]];if(!Vo(Go(i,o),Go(t,n)))return!1;const r=e=>Math.abs((e[0]-i[0])*c-(e[1]-i[1])*a)/h;if(r(t)>l||r(n)>l)return!1;const s=h*h,d=((t[0]-i[0])*a+(t[1]-i[1])*c)/s,u=((n[0]-i[0])*a+(n[1]-i[1])*c)/s;return Math.min(1,Math.max(d,u))-Math.max(0,Math.min(d,u))>l/h});return!d})(e))&&e.cm>=1&&e.cm<=100)}function Zo(e,t,i,n=8){const[r,o]=Lo(e,t);let s=Math.atan2(o,r);s<0&&(s+=Math.PI);let a=i*Math.PI/180%Math.PI;a<0&&(a+=Math.PI);let l=Math.abs(s-a);return l>Math.PI/2&&(l=Math.PI-l),l<=n*Math.PI/180}function Jo(e,t,i,n,r=1,o="affine",s){if(!e?.length)return[];if(t.length!==i.length)return"fixed-topology"===o&&s?.(),e.slice();const a=r>0?r:1,l=Math.max(.5*n,1e-9)*a,c=Math.max(n*a*1e-6,1e-9),h=[],d=new Map,u=new Map,p=(e,t,i)=>{const n=e.get(t)||new Set;n.add(i),e.set(t,n)};for(let e=0;e[e[0]+(t[0]-e[0])*i,e[1]+(t[1]-e[1])*i],m=(e,t)=>Math.hypot(e[0]-t[0],e[1]-t[1])<=c,g=(e,t)=>{if("fixed-topology"===o){const i=t.na[0]-t.oa[0],n=t.na[1]-t.oa[1],r=t.nb[0]-t.ob[0],o=t.nb[1]-t.ob[1];return Math.hypot(i-r,n-o)<=c?[e[0]+i,e[1]+n]:m(e,t.oa)?[...t.na]:m(e,t.ob)?[...t.nb]:[...e]}const i=Math.max(0,Math.min(1,((e[0]-t.oa[0])*t.dx+(e[1]-t.oa[1])*t.dy)/t.len2));return _(t.na,t.nb,i)},f=(e,t)=>{const[i,n]=Lo(e,t);return(t[0]-e[0])*i+(t[1]-e[1])*n>=0?[[...e],[...t]]:[[...t],[...e]]},v=[],y=[],b=(e,t,i)=>{if(Math.hypot(t[0]-e[0],t[1]-e[1])<=c)return;const[r,o]=f(e,t),s=zo(i);if(y.some(e=>e.entry.cm===s&&m(e.span[0],r)&&m(e.span[1],o)))return;const l=Wo(r,o,s,n,a);v.push(l),y.push({entry:l,span:[r,o]})};for(const t of e){const e=jo(t,a);if(e){const[i,n]=f(e[0],e[1]),r=n[0]-i[0],s=n[1]-i[1],a=r*r+s*s,d=Math.sqrt(a);if(d<=c){v.push({...t,cm:zo(t.cm)});continue}const u=[];for(const e of h){if(!Vo(Go(i,n),Go(e.oa,e.ob)))continue;const t=e=>Math.abs((e[0]-i[0])*s-(e[1]-i[1])*r)/d;if(t(e.oa)>l||t(e.ob)>l)continue;const o=((e.oa[0]-i[0])*r+(e.oa[1]-i[1])*s)/a,h=((e.ob[0]-i[0])*r+(e.ob[1]-i[1])*s)/a,p=Math.max(0,Math.min(o,h)),_=Math.min(1,Math.max(o,h));(_-p)*d>c&&u.push({lo:p,hi:_,move:e})}if(!u.length){"fixed-topology"===o?v.push({...t}):b(i,n,t.cm);continue}const p=[0,1,...u.flatMap(({lo:e,hi:t})=>[e,t])].sort((e,t)=>e-t).filter((e,t,i)=>0===t||Math.abs(e-i[t-1])*d>c),y=[];for(let e=0;e+1a>=e.lo-1e-12&&a<=e.hi+1e-12);if(!l.length){y.push([o,s]);continue}const h=[g(o,l[0].move),g(s,l[0].move)],f=l.slice(1).some(e=>{const t=g(o,e.move),i=g(s,e.move);return!m(h[0],t)||!m(h[1],i)});y.push(f?[o,s]:h)}const w=(e,t)=>{const i=e[1][0]-e[0][0],n=e[1][1]-e[0][1],r=t[1][0]-t[0][0],o=t[1][1]-t[0][1],s=Math.hypot(i,n);return!(s<=c||i*r+n*o<=0)&&Math.abs(i*o-n*r)/s<=c},k=[];for(const e of y){const t=k[k.length-1];t&&m(t[1],e[0])&&w(t,e)?t[1]=e[1]:k.push([[...e[0]],[...e[1]]])}if("fixed-topology"===o&&1===k.length){const[i,n]=k[0];if(m(i,e[0])&&m(n,e[1])||m(i,e[1])&&m(n,e[0])){v.push({...t});continue}}for(const[e,i]of k)b(e,i,t.cm);continue}if("fixed-topology"===o){const e=u.get(t.key);if(1===e?.size){const i=[...e][0];v.push(i===t.key?{...t}:{...t,key:i});continue}const i=[Uo([t],a)[0]];1!==a&&i.push(Uo([t],1)[0]);const n=i.filter(Boolean).some(e=>h.some(t=>{if(!Vo(e.ang,Go(t.oa,t.ob)))return!1;const i=((e.x-t.oa[0])*t.dx+(e.y-t.oa[1])*t.dy)/t.len2;return i>=-1e-6&&i<=1.000001&&Ns(e.x,e.y,t.oa[0],t.oa[1],t.ob[0],t.ob[1])<=l}));((e?.size||0)>1||n)&&s?.(),v.push({...t});continue}let i="";const r=d.get(t.key);if(1===r?.size&&(i=[...r][0]),!i){const e=Uo([t],a)[0];if(e){const t=new Set;for(const i of h){if(!Vo(e.ang,Go(i.oa,i.ob)))continue;const r=((e.x-i.oa[0])*i.dx+(e.y-i.oa[1])*i.dy)/i.len2;if(r<-1e-6||r>1.000001)continue;if(Ns(e.x,e.y,i.oa[0],i.oa[1],i.ob[0],i.ob[1])>l)continue;const o=g([e.x,e.y],i),[s,c]=Lo(i.na,i.nb),h=Math.max(n*a,1e-6);t.add(qo([o[0]-s*h,o[1]-c*h],[o[0]+s*h,o[1]+c*h],n,a))}1===t.size&&(i=[...t][0])}}v.push({...t,key:i||t.key,cm:zo(t.cm)})}return v}function Qo(e,t,i,n,r=1,o="affine"){return Jo(e,t,i,n,r,o)}function es(e,t,i,n,r=1,o="fixed-topology"){let s=!1;const a=Jo(e,t,i,n,r,o,()=>{s=!0});return{walls:s?(e||[]).map(e=>({...e})):a,rejected:s}}function ts(e,t,i,n=1,r=[]){const o=n>0?n:1,s=Math.abs(i),a=Math.max(s*o*ao,1e-9),l=(r||[]).flatMap(e=>{const t=jo(e,o);return t?t.map(e=>[...e]):[]}),c=e=>e.every((e,t)=>(e=>{if(!(s>0))return!0;const t=e/o/s;return Math.abs(t-Math.round(t))Math.abs(e-i[t])<=a)),h=[],d=e=>JSON.stringify([e.key,e.cm,e.a,e.b]);for(const i of e||[]){const e=jo(i,o);if(!e)continue;const[n,r]=e;if(![n[0],n[1],r[0],r[1]].every(Number.isFinite)||!c(n)||!c(r)){h.push(d(i));continue}const s=r[0]-n[0],l=r[1]-n[1],u=Math.hypot(s,l);if(u<=a){h.push(d(i));continue}const p=s/u,_=l/u,m=[];for(const e of t){const[t,i]=e;if(![t?.[0],t?.[1],i?.[0],i?.[1]].every(Number.isFinite))continue;const r=e=>Math.abs((e[0]-n[0])*_-(e[1]-n[1])*p);if(r(t)>a||r(i)>a)continue;const o=(t[0]-n[0])*p+(t[1]-n[1])*_,s=(i[0]-n[0])*p+(i[1]-n[1])*_,l=Math.max(0,Math.min(o,s)),c=Math.min(u,Math.max(o,s));c-l>a&&m.push([l,c])}m.sort((e,t)=>e[0]-t[0]||e[1]-t[1]);let g=0;for(const[e,t]of m){if(e>g+a)break;if(g=Math.max(g,t),g>=u-a)break}ge.key!==s);return null==n||n<1?a:[...a,Wo(t,i,n,r,o)]}function ns(e,t,i,n,r,o=[],s=1){let a=e?e.slice():[];for(const e of function(e,t,i,n,r=1,o=[]){const s=Ss(e,t,i,n,r,o);if(!s)return[];const a=[];for(let e=0;e0||(c=is(c,t,i,n,r,s)))}return c}function os(e){const{a:t,b:i,halfDepth:n}=e;if(!Array.isArray(t)||!Array.isArray(i)||t.length<2||i.length<2||![t[0],t[1],i[0],i[1]].every(Number.isFinite))return null;const r=i[0]-t[0],o=i[1]-t[1],s=Math.hypot(r,o);if(!(s>1e-9&&n>0&&Number.isFinite(n)))return null;const a=-o/s*n,l=r/s*n;return[[t[0]+a,t[1]+l],[i[0]+a,i[1]+l],[i[0]-a,i[1]-l],[t[0]-a,t[1]-l]]}function ss(e,t,i){return Math.hypot(e[0]-t[0],e[1]-t[1])<=i}function as(e,t,i){const n=t.b[0]-t.a[0],r=t.b[1]-t.a[1],o=n*n+r*r;if(!(o>i*i))return!1;const s=((e[0]-t.a[0])*n+(e[1]-t.a[1])*r)/o;if(!(s>0&&s<1))return!1;const a=[t.a[0]+n*s,t.a[1]+r*s];return Math.hypot(e[0]-a[0],e[1]-a[1])<=i}function ls(e,t,i,n){const r=Math.hypot(t,i);if(!(r>1e-9&&n>0))return;const o=[t/r,i/r],s=e.find(e=>Math.abs(e.u[0]*o[1]-e.u[1]*o[0])<1e-9&&e.u[0]*o[0]+e.u[1]*o[1]>1-1e-9);s?s.halfDepth=Math.max(s.halfDepth,n):e.push({u:o,halfDepth:n})}function cs(e,t){try{const i=Gt(Bs(e),Bs(t));let n=null,r=0;for(const e of i||[]){const t=e?.[0]||[],i=Math.abs(ms(t));t.length>=4&&i>r&&(r=i,n=t.slice(0,-1).map(e=>[e[0],e[1]]))}return n}catch{return null}}function hs(e,t=1e-6){const i=(e||[]).map((e,t)=>({segment:e,index:t})).filter(({segment:e})=>e&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&e.a.every(Number.isFinite)&&e.b.every(Number.isFinite)&&Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>1e-9);if(i.length<2)return[];const n=Math.max(Number.isFinite(t)?t:0,1e-9),r=i.flatMap(({segment:e})=>[e.a,e.b]).map(e=>[e[0],e[1]]).sort((e,t)=>e[0]-t[0]||e[1]-t[1]),o=[];for(const e of r)o.some(t=>ss(t,e,n))||o.push(e);const s=[];for(const e of o){const t=[];let r=!1;for(const{segment:o,index:s}of i){const i=Math.hypot(o.b[0]-o.a[0],o.b[1]-o.a[1]);ss(e,o.a,n)?t.push({u:[(o.b[0]-o.a[0])/i,(o.b[1]-o.a[1])/i],halfDepth:o.halfDepth,length:i,index:s}):ss(e,o.b,n)?t.push({u:[(o.a[0]-o.b[0])/i,(o.a[1]-o.b[1])/i],halfDepth:o.halfDepth,length:i,index:s}):as(e,o,n)&&(r=!0)}if(r||2!==t.length)continue;const[o,a]=t,l=o.u[0]*a.u[1]-o.u[1]*a.u[0];if(Math.abs(l)<1e-9)continue;const c=l<0?1:-1,h=[-o.u[1],o.u[0]],d=[-a.u[1],a.u[0]],u=[e[0]+h[0]*o.halfDepth*c,e[1]+h[1]*o.halfDepth*c],p=[e[0]-d[0]*a.halfDepth*c,e[1]-d[1]*a.halfDepth*c];if(!vs(u,o.u,p,a.u))continue;const _=[[o,a,p,[d[0]*-c,d[1]*-c]],[a,o,u,[h[0]*c,h[1]*c]]];for(const[t,,i,r]of _){const o=Math.min(2*t.halfDepth,t.length),a=[-t.u[1]*t.halfDepth,t.u[0]*t.halfDepth],l=[[e[0]+a[0],e[1]+a[1]],[e[0]+t.u[0]*o+a[0],e[1]+t.u[1]*o+a[1]],[e[0]+t.u[0]*o-a[0],e[1]+t.u[1]*o-a[1]],[e[0]-a[0],e[1]-a[1]]],c=e=>(e[0]-i[0])*r[0]+(e[1]-i[1])*r[1],h=[];for(let e=0;e=-1e-12&&h.push(t),n>1e-12&&r<-1e-12||n<-1e-12&&r>1e-12){const e=n/(n-r);h.push([t[0]+(i[0]-t[0])*e,t[1]+(i[1]-t[1])*e])}}h.length>=3&&Math.abs(ms(h))>n*n&&s.push({segmentIndex:t.index,wedge:h})}}return s}function ds(e,t=1e-6){const i=(e||[]).filter(e=>e&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&e.a.every(Number.isFinite)&&e.b.every(Number.isFinite)&&Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>1e-9);if(i.length<2)return[];const n=Math.max(Number.isFinite(t)?t:0,1e-9),r=i.flatMap(e=>[e.a,e.b]).map(e=>[e[0],e[1]]).sort((e,t)=>e[0]-t[0]||e[1]-t[1]),o=[];for(const e of r)o.some(t=>ss(t,e,n))||o.push(e);const s=[],a=i.map((e,t)=>({roomId:"",a:[e.a[0],e.a[1]],b:[e.b[0],e.b[1]],key:`join-${t}`,kind:"outer",cm:0,open:!1,half:e.halfDepth})),l=Ts(a,n);for(const e of Ds(l).fans)s.push(e);const c=e=>!!As(l,e);for(const e of o){if(c(e))continue;const t=[];for(const r of i)ss(e,r.a,n)?ls(t,r.b[0]-r.a[0],r.b[1]-r.a[1],r.halfDepth):ss(e,r.b,n)?ls(t,r.a[0]-r.b[0],r.a[1]-r.b[1],r.halfDepth):as(e,r,n)&&(ls(t,r.a[0]-e[0],r.a[1]-e[1],r.halfDepth),ls(t,r.b[0]-e[0],r.b[1]-e[1],r.halfDepth));if(!(t.length<2)){t.sort((e,t)=>Math.atan2(e.u[1],e.u[0])-Math.atan2(t.u[1],t.u[0])||e.halfDepth-t.halfDepth);for(let i=0;in*n&&s.push(m)}}}return s}function us(e,t,i,n){if(!(t>0)||!e||e.length<2)return"";if(i&&e.length>=3){let i=e;const r=e[e.length-1];if(e.length>=4&&Math.hypot(e[0][0]-r[0],e[0][1]-r[1])<1e-9&&(i=e.slice(0,-1)),i.length>=3){const e=i.map((e,i)=>n?.[i]||t),r=aa(i,e),o=ws(i,e);if(r&&o)return`${ks(r)} ${ks(xs(o))}`}}const r=[];for(let i=0;i=1e-9&&a>0&&r.push({a:o,b:s,halfDepth:a})}const o=r.map(os);for(const{segmentIndex:e,wedge:t}of hs(r)){const i=o[e];if(!i)continue;const n=cs(i,t);n&&(o[e]=n)}const s=[...o.filter(e=>!!e),...ds(r)],a=function(e){let t=null;try{for(const i of e){if(i.length<3)continue;const e=Bs(i);t=t?Wt(t,e):[e]}return t}catch{return null}}(s);return a?Qs(a):s.map(e=>ks(e)).join(" ")}function ps(e,t,i,n,r=1){if(!i.length)return!1;const o=_s(n,r),s=(e[0]+t[0])/2,a=(e[1]+t[1])/2,[l,c]=Lo(e,t);for(const e of i){const[t,i]=Lo([e[0],e[1]],[e[2],e[3]]);if(!(Math.abs(l*i-c*t)>.05)&&Ns(s,a,e[0],e[1],e[2],e[3])<=o)return!0}return!1}function _s(e,t){return Math.max(e*(t>0?t:1)*.04,1e-9)}function ms(e){let t=0;for(let i=0;ie[1]!=l>e[1]&&e[0]<(a-o)*(e[1]-s)/(l-s+0)+o&&(i=!i)}return i}([c[0]+.001*a,c[1]+.001*l],e)||(a=-a,l=-l),[a,l]}function fs(e,t){const i=e[0]*t[1]-e[1]*t[0],n=e[0]*t[0]+e[1]*t[1];return Math.abs(i)<1e-9&&n>0}function vs(e,t,i,n){const r=t[0]*n[1]-t[1]*n[0];if(Math.abs(r)<1e-12)return null;const o=[i[0]-e[0],i[1]-e[1]],s=(o[0]*n[1]-o[1]*n[0])/r;return[e[0]+s*t[0],e[1]+s*t[1]]}function ys(e,t,i){const n=e?.length||0;if(n<3||!Array.isArray(i)||i.length!==n)return 0;const r=(Math.trunc(t)%n+n)%n,o=e[r],s=e[(r+1)%n],a=s[0]-o[0],l=s[1]-o[1],c=Math.hypot(a,l);if(!(c>0))return 0;const h=Math.max(0,Number(i[r])||0);if(!(h>0))return c;const d=[a/c,l/c],u=gs(e,r),p=[o[0]+u[0]*h,o[1]+u[1]*h],_=t=>{const r=Math.max(0,Number(i[t])||0);if(!(r>0))return null;const s=e[t],a=e[(t+1)%n],l=a[0]-s[0],c=a[1]-s[1],h=Math.hypot(l,c);if(!(h>0))return null;const u=gs(e,t),_=vs(p,d,[s[0]+u[0]*r,s[1]+u[1]*r],[l/h,c/h]);return _?(_[0]-o[0])*d[0]+(_[1]-o[1])*d[1]:null},m=_((r-1+n)%n)??0,g=(_((r+1)%n)??c)-m;return g>0?g:0}function bs(e,t,i,n,r,o,s,a=1){const l=(e||[]).find(e=>e?.id===t),c=ni(l);if(!c||c.length<3)return null;const h=Fs(e,t,i,n,r,o,s,a);if(!h)return c.map(()=>0);const d=4*_s(r,a);return c.map((e,t)=>{const i=c[(t+1)%c.length],n=[(e[0]+i[0])/2,(e[1]+i[1])/2];for(let e=0;e!(e>0)))return e.map(e=>[e[0],e[1]]);const r=[];for(let o=0;o0||u>0)){r.push([e[o][0],e[o][1]]);continue}if(d>0!=u>0){const t=e[o],i=d>0?[t[0]+p*d,t[1]+_*d]:[t[0],t[1]],n=u>0?[t[0]+m*u,t[1]+g*u]:[t[0],t[1]];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}if(fs(w,k)){const t=e[o],i=[t[0]+p*d,t[1]+_*d],n=[t[0]+m*u,t[1]+g*u];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}const $=vs(x,w,S,k),M=Math.max(d,u,1e-9),R=As(i,e[o])?.limit??4*M;if($){const i=Math.hypot($[0]-e[o][0],$[1]-e[o][1]);if(Number.isFinite(i)&&i<=R){r.push($);continue}if(ta(e,t,o)){r.push($);continue}}d>0&&r.push([e[o][0]+p*d,e[o][1]+_*d]),u>0&&r.push([e[o][0]+m*u,e[o][1]+g*u]),d>0||u>0||r.push([e[o][0],e[o][1]])}return r.length>=3?r:null}function ks(e,t=!0){if(!e.length)return"";let i=`M ${e[0][0]} ${e[0][1]}`;for(let t=1;te?.id===t),a=ni(s);if(!a||a.length<3)return null;const l=_s(n,r),c=[];for(const i of e||[]){if(!i||i.id===t)continue;const e=ni(i);if(e)for(const t of Fn(a,e,l))c.push([t[0],t[1]],[t[2],t[3]])}for(const e of i||[])c.push([e[0],e[1]],[e[2],e[3]]);for(const e of o||[]){const t=jo(e,r);t&&c.push(t[0],t[1])}const h=[],d=[];for(let e=0;el)continue;const s=((e[0]-t[0])*(i[0]-t[0])+(e[1]-t[1])*(i[1]-t[1]))/(n*n);s<=r||s>=1-r||(o.some(e=>Math.abs(e-s)*n<=2*l)||o.push(s))}o.sort((e,t)=>e-t);for(const n of o)h.push([t[0]+(i[0]-t[0])*n,t[1]+(i[1]-t[1])*n]),d.push(e)}return{poly:h,parent:d,orig:a}}function $s(e,t,i,n){const r=t.poly.length,o=new Array(r).fill(0);if(!e?.length)return o;const s=new Set,a=[];for(let l=0;l0?(o[l]=zo(c.cm),s.add(c.key)):a.push(l)}if(!a.length)return o;const l=n>0?n:1,c=Math.max(.5*i,1e-9)*l,h=Uo(e,l).filter(e=>e.w.cm>0);for(let e=a.length-1;e>=0;e--){const i=a[e],n=t.poly[i],s=t.poly[(i+1)%r],d=Go(n,s);let u=null;for(const e of h){const t=jo(e.w,l);if(!t||!Vo(Go(t[0],t[1]),d))continue;if(Ns(n[0],n[1],t[0][0],t[0][1],t[1][0],t[1][1])>c||Ns(s[0],s[1],t[0][0],t[0][1],t[1][0],t[1][1])>c)continue;const i=Math.hypot(s[0]-n[0],s[1]-n[1]),r=Math.hypot(t[1][0]-t[0][0],t[1][1]-t[0][1]),o=Math.max(0,r-i);(!u||oc||Ns(r[0],r[1],t[0][0],t[0][1],t[1][0],t[1][1])>c)continue;i=!0,o=Math.max(0,Math.hypot(t[1][0]-t[0][0],t[1][1]-t[0][1])-_)}else{if(Ns(e.x,e.y,n[0],n[1],r[0],r[1])>c)continue;o=Math.hypot(e.x-d,e.y-u)}(!p||i&&!p.exact||i===p.exact&&o0?i:1,o=(e||[]).filter(e=>e&&!e.open&&null!==e.kind&&Number.isFinite(e.half)&&e.half>0&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&[e.a[0],e.a[1],e.b[0],e.b[1]].every(Number.isFinite)&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>n).sort((e,t)=>e.key.localeCompare(t.key)||e.a[0]-t.a[0]||e.a[1]-t.a[1]||e.b[0]-t.b[0]||e.b[1]-t.b[1]||e.half-t.half),s=new Map;for(const e of o){const t=s.get(e.key);t?e.half>t.half&&s.set(e.key,{...t,half:e.half}):s.set(e.key,e)}const a=[...s.values()].flatMap(e=>[{point:[e.a[0],e.a[1]],other:e.b,halfDepth:e.half,kind:e.kind,key:e.key},{point:[e.b[0],e.b[1]],other:e.a,halfDepth:e.half,kind:e.kind,key:e.key}]).sort((e,t)=>e.point[0]-t.point[0]||e.point[1]-t.point[1]||e.other[0]-t.other[0]||e.other[1]-t.other[1]||e.halfDepth-t.halfDepth),l=new Map;for(const e of a){const[t,i]=Ms(e.point,n),r=Rs(t,i),o=l.get(r)||[];o.push(e),l.set(r,o)}const c=[],h=new Map;for(const e of a){const t=Cs(h,e.point,n).filter(t=>Math.hypot(t.point[0]-e.point[0],t.point[1]-e.point[1])<=n).sort((t,i)=>Math.hypot(t.point[0]-e.point[0],t.point[1]-e.point[1])-Math.hypot(i.point[0]-e.point[0],i.point[1]-e.point[1])||t.point[0]-i.point[0]||t.point[1]-i.point[1]);let i=t[0];if(!i){i={point:[...e.point],rays:[]},c.push(i);const[t,r]=Ms(i.point,n),o=Rs(t,r),s=h.get(o)||[];s.push(i),h.set(o,s)}const r=e.other[0]-e.point[0],o=e.other[1]-e.point[1],s=Math.hypot(r,o);if(!(s>n))continue;const a=[r/s,o/s];let l=Math.atan2(a[1],a[0]);l<0&&(l+=2*Math.PI),i.rays.push({u:a,halfDepth:e.halfDepth,length:s,angle:l})}const d=[],u=e=>{const t=1e-9*Math.max(1,r),i=e.filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Number.isFinite(e.length)&&e.length>n);return i.filter((e,n)=>!i.some((i,r)=>r!==n&&i.halfDepth>=e.halfDepth-t&&i.length>=e.length-t&&(i.halfDepth>e.halfDepth+t||i.length>e.length+t||re.length-t.length||e.halfDepth-t.halfDepth).map(e=>({...e}))};for(const e of c){const t=e.rays.sort((e,t)=>e.angle-t.angle||e.length-t.length||e.halfDepth-t.halfDepth),i=[];for(const e of t){const t=i[i.length-1];t&&Math.abs(e.angle-t.angle)<=1e-9?t.supports.push({halfDepth:e.halfDepth,length:e.length}):i.push({u:[...e.u],angle:e.angle,supports:[{halfDepth:e.halfDepth,length:e.length}]})}if(i.length>1&&2*Math.PI-i[i.length-1].angle+i[0].angle<=1e-9){const e=i.pop();i[0].supports.push(...e.supports)}if(i.length<3)continue;const r=i.map(t=>{const i=u(t.supports),r=new Set,o=[];for(const s of i){const i=[e.point[0]+t.u[0]*s.length,e.point[1]+t.u[1]*s.length];for(const t of Cs(l,i,n)){if("shared"!==t.kind||Math.hypot(t.point[0]-i[0],t.point[1]-i[1])>n)continue;const s=t.other[0]-t.point[0],a=t.other[1]-t.point[1],l=Math.hypot(s,a);if(!(l>n))continue;const c=s/l,h=a/l;if(Math.hypot(t.other[0]-e.point[0],t.other[1]-e.point[1])<=n)continue;const d=`${t.key}|${t.point[0]}|${t.point[1]}|${t.other[0]}|${t.other[1]}|${t.halfDepth}`;r.has(d)||(r.add(d),o.push({start:[t.point[0],t.point[1]],u:[c,h],length:l,halfDepth:t.halfDepth}))}}return o.sort((e,t)=>e.start[0]-t.start[0]||e.start[1]-t.start[1]||e.u[0]-t.u[0]||e.u[1]-t.u[1]||e.length-t.length||e.halfDepth-t.halfDepth),{u:[...t.u],halfDepth:Math.max(...i.map(e=>e.halfDepth)),length:Math.max(...i.map(e=>e.length)),supports:i,continuations:o}}).filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Number.isFinite(e.length)&&e.length>n);if(r.length<3)continue;const o=Math.max(...r.map(e=>e.halfDepth));o>0&&Number.isFinite(o)&&d.push({point:[...e.point],rays:r,halfDepth:o,limit:1.25*o})}d.sort((e,t)=>e.point[0]-t.point[0]||e.point[1]-t.point[1]);const p=new Map;for(const e of d){const[t,i]=Ms(e.point,n),r=Rs(t,i),o=p.get(r)||[];o.push(e),p.set(r,o)}return{epsilon:n,coordinateScale:r,nodes:d,index:p}}function Ds(e){const t={fans:[],supports:[]};if(!e?.nodes?.length)return t;const i=Math.max(e.epsilon,1e-9)**2;for(const n of e.nodes){const e=n.rays.filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0).map(e=>({...e,thickLength:Math.max(...e.supports.filter(t=>t.halfDepth>=e.halfDepth-1e-12).map(e=>e.length),0),angle:(()=>{const t=Math.atan2(e.u[1],e.u[0]);return t<0?t+2*Math.PI:t})()})).sort((e,t)=>e.angle-t.angle);if(e.length<2)continue;const r=n.point;for(const i of e)for(const e of i.supports){if(!(e.halfDepth>0&&e.length>0))continue;const n=-i.u[1]*e.halfDepth,o=i.u[0]*e.halfDepth,s=[r[0]+i.u[0]*e.length,r[1]+i.u[1]*e.length];t.supports.push([[r[0]+n,r[1]+o],[s[0]+n,s[1]+o],[s[0]-n,s[1]-o],[r[0]-n,r[1]-o]])}for(let n=0;n{const e=s.angle-o.angle;return e>0?e:e+2*Math.PI})();if(a<1e-9)continue;const l=a>Math.PI+1e-9,c=4*Math.max(o.halfDepth,s.halfDepth),h=[r[0]-o.u[1]*o.halfDepth,r[1]+o.u[0]*o.halfDepth],d=[r[0]+s.u[1]*s.halfDepth,r[1]-s.u[0]*s.halfDepth],u=o.u[0]*s.u[1]-o.u[1]*s.u[0],p=e=>{let t=Math.atan2(e[1]-r[1],e[0]-r[0])-o.angle;for(;t<0;)t+=2*Math.PI;return t<=a+1e-9};let _=null;if(Math.abs(u)>1e-9){const e=((d[0]-h[0])*s.u[1]-(d[1]-h[1])*s.u[0])/u,t=((d[0]-h[0])*o.u[1]-(d[1]-h[1])*o.u[0])/u,i=[h[0]+o.u[0]*e,h[1]+o.u[1]*e];(l?e<=1e-9&&t<=1e-9:e>1e-9&&e<=o.thickLength&&t<=s.thickLength)&&Math.hypot(i[0]-r[0],i[1]-r[1])<=c&&p(i)&&(_=i)}const m=e=>{Math.abs(ms(e))>i&&t.fans.push(e)};if(_){const e=1.5*Math.max(o.halfDepth,s.halfDepth);m(To([r[0],r[1]],h,_,d,e)??[[r[0],r[1]],h,_,d]);continue}if(l){m([[r[0],r[1]],h,d]);continue}const g=(e,t)=>Math.min(t,Math.sqrt(Math.max(c**2-e**2,0)),2*Math.max(o.halfDepth,s.halfDepth)),f=[h[0]+o.u[0]*g(o.halfDepth,o.thickLength),h[1]+o.u[1]*g(o.halfDepth,o.thickLength)],v=[d[0]+s.u[0]*g(s.halfDepth,s.thickLength),d[1]+s.u[1]*g(s.halfDepth,s.thickLength)];m([[r[0],r[1]],h,f,v,d])}}return t}function As(e,t){return!e||!Array.isArray(t)||t.length<2||!t.slice(0,2).every(Number.isFinite)?null:Cs(e.index,t,e.epsilon).filter(i=>Math.hypot(i.point[0]-t[0],i.point[1]-t[1])<=e.epsilon).sort((e,i)=>Math.hypot(e.point[0]-t[0],e.point[1]-t[1])-Math.hypot(i.point[0]-t[0],i.point[1]-t[1])||e.point[0]-i.point[0]||e.point[1]-i.point[1])[0]||null}function Ps(e,t,i,n,r,o,s){return Ts(zs(e,t,i,n,r,o,s),4*_s(n,s),s)}function Fs(e,t,i,n,r,o,s,a=1){const l=Ss(e,t,n,r,a,i);if(!l)return null;const c=function(e,t,i){const n=(e||[]).find(e=>e?.id===t),r=ni(n);if(!r)return[];const o=[];for(const n of e||[]){if(!n||n.id===t)continue;const e=ni(n);if(e)for(const t of Fn(r,e,i))o.push(t)}return o}(e,t,_s(r,a)),h=function(e,t,i,n,r){const o=_s(n,r),s=[];for(let a=0;aNs(h,d,e[0],e[1],e[2],e[3])<=o);s.push(u?"shared":"outer")}return s}(l.poly,c,n,r,a),d=$s(i,l,r,a),u=d.map((e,t)=>h[t]&&e>0?Oo(e,o,s)/2:0);return{...l,kinds:h,cms:d,offsets:u}}function zs(e,t,i,n,r,o,s=1){const a=[];for(const l of e||[]){if(!l?.id)continue;const c=Fs(e,l.id,t,i,n,r,o,s);if(c)for(let e=0;e0&&(a=is(a,e.a,e.b,e.cm,n,s));return a}function Os(e,t,i,n,r,o,s=1){if(!t?.length)return[];const a=zs(e,t,i,n,r,o,s),l=new Map;for(const e of a){if(e.open||!e.kind||!e.roomId)continue;const t=l.get(e.key)||new Set;t.add(e.roomId),l.set(e.key,t)}const c=e=>{const t=[...l.get(e)||[]].sort();return 1!==t.length&&2!==t.length?`ambiguous:${e}`:`${1===t.length?"outer":"shared"}:${t.join("|")}`},h=[],d=new Set;for(const e of a)!e.open&&e.cm>0&&!d.has(e.key)&&(d.add(e.key),h.push({...e,ownerSignature:c(e.key)}));const u=[];for(const a of e||[]){if(!a?.id)continue;const l=Fs(e,a.id,t,i,n,r,o,s);if(l)for(let e=0;e0)||null===l.kinds[i]){e++;continue}const o=c(qo(l.poly[i],l.poly[(i+1)%l.poly.length],n,s));let a=e;for(;a+10&&u.push({a:[d[0],d[1]],b:[p[0],p[1]],key:qo(d,p,n,s),cm:r,len:_,ownerSignature:o}),e=a+1}}}u.sort((e,t)=>t.len-e.len||e.key.localeCompare(t.key));const p=[],_=new Set,m=new Set,g=4*_s(n,s);for(const e of u){const t=h.filter(t=>!m.has(t.key)&&t.cm===e.cm&&t.ownerSignature===e.ownerSignature&&Vo(Go(t.a,t.b),Go(e.a,e.b))&&Ns(t.a[0],t.a[1],e.a[0],e.a[1],e.b[0],e.b[1])<=g&&Ns(t.b[0],t.b[1],e.a[0],e.a[1],e.b[0],e.b[1])<=g);if(t.length){for(const e of t)m.add(e.key);_.has(e.key)||(_.add(e.key),p.push(Wo(e.a,e.b,e.cm,n,s)))}}for(const e of h)m.has(e.key)||_.has(e.key)||(_.add(e.key),p.push(Wo(e.a,e.b,e.cm,n,s)));return p}function Es(e,t,i,n,r,o,s,a=1){const l=_s(r,a),c=(n[0]+n[2])/2,h=(n[1]+n[3])/2,d=Go([n[0],n[1]],[n[2],n[3]]);let u=null;for(const n of zs(e,t,i,r,o,s,a)){if(!Vo(Go(n.a,n.b),d))continue;const e=Ns(c,h,n.a[0],n.a[1],n.b[0],n.b[1]);e>4*l||(!u||e[e[0],e[1]]),o=Math.abs(ms(r));r.length>=3&&o>i&&(t=r,i=o)}return t}function Ls(e,t,i,n,r,o,s,a=1,l,c){const h=(e||[]).find(e=>e?.id===t),d=ni(h);if(!d||d.length<3)return null;if(!i?.length)return d.map(e=>[e[0],e[1]]);const u=Fs(e,t,i,n,r,o,s,a);if(!u||!u.offsets.some(e=>e>0))return d.map(e=>[e[0],e[1]]);const p=c||Ps(e,i,n,r,o,s,a),_=ws(u.poly,u.offsets,p);if(!_)return d.map(e=>[e[0],e[1]]);if(!p.nodes.length)return _;const m=void 0===l?ia(e,i,n,[],r,o,s,a):null,g=l??("ok"===m?.status||"degraded-extra"===m?.status?m.roomGeom:void 0);if(g)try{const e=Hs(Gt(Bs(u.poly),g));if(e)return e}catch{}return function(e,t){try{return Hs(Ut(Bs(e),Bs(t)))}catch{return null}}(_,u.poly)||d.map(e=>[e[0],e[1]])}function Bs(e){const t=e.map(e=>[e[0],e[1]]);return t.push([e[0][0],e[0][1]]),[t]}function qs(e){return!(!Array.isArray(e)||!e.length)&&e.every(e=>Array.isArray(e)&&e.length&&e.every(e=>Array.isArray(e)&&e.length>=4&&e.every(e=>Array.isArray(e)&&e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1])))&&Math.abs(Ci(e[0]))>1e-9)}function js(e,t,i,n){const r=n?new Set(n):null;let o=null;for(let n=0;nt.epsilon))continue;const l=Ks([[e.point[0]+a[0]*n.halfDepth,e.point[1]+a[1]*n.halfDepth],[e.point[0]+s.u[0]*r+a[0]*n.halfDepth,e.point[1]+s.u[1]*r+a[1]*n.halfDepth],[e.point[0]+s.u[0]*r-a[0]*n.halfDepth,e.point[1]+s.u[1]*r-a[1]*n.halfDepth],[e.point[0]-a[0]*n.halfDepth,e.point[1]-a[1]*n.halfDepth]],t.coordinateScale);if(!l)continue;const c=Bs(l);o=o?Wt(o,c):c}}return o}function Ws(e,t,i){let n=null;for(const r of e.rays)for(const e of r.continuations){const r=[-e.u[1],e.u[0]],o=[e.start[0]+e.u[0]*e.length,e.start[1]+e.u[1]*e.length],s=Ks([[e.start[0]+r[0]*e.halfDepth,e.start[1]+r[1]*e.halfDepth],[o[0]+r[0]*e.halfDepth,o[1]+r[1]*e.halfDepth],[o[0]-r[0]*e.halfDepth,o[1]-r[1]*e.halfDepth],[e.start[0]-r[0]*e.halfDepth,e.start[1]-r[1]*e.halfDepth]],t.coordinateScale);if(!s)continue;const a=Ut(Bs(s),i);Array.isArray(a)&&0!==a.length&&(n=n?Wt(n,a):a)}return n}function Us(e,t,i=2*(4*e.halfDepth+2*t.epsilon)){const n=function(e,t=Do){const i=new Set,n=Number.isFinite(t)&&t>=0?t:Do;for(let t=0;te-t)}(e);return n.length?js(e,t,i,n):null}function Gs(e,t,i,n,r){const o=function(e){let t=null;for(const i of e){const e=Bs(i);try{t=t?Wt(t,e):e}catch{}}return t}(function(e,t,i=!1){if(!e)return[];const n=[];for(const r of e.nodes)for(let o=0;o1e-9)||h>=Math.PI-1e-9)continue;const d=[-s.u[1],s.u[0]],u=[-a.u[1],a.u[0]],p=[r.point[0]+d[0]*s.halfDepth,r.point[1]+d[1]*s.halfDepth],_=[r.point[0]-u[0]*a.halfDepth,r.point[1]-u[1]*a.halfDepth],m=vs(p,s.u,_,a.u);if(!m)continue;const g=Math.hypot(m[0]-r.point[0],m[1]-r.point[1]);if(!Number.isFinite(g)||g<=r.limit)continue;const f=t?Math.sqrt(Math.max(0,r.limit*r.limit-s.halfDepth*s.halfDepth)):0,v=t?Math.sqrt(Math.max(0,r.limit*r.limit-a.halfDepth*a.halfDepth)):0,y=Ks([[p[0]+s.u[0]*f,p[1]+s.u[1]*f],[_[0]+a.u[0]*v,_[1]+a.u[1]*v],m],e.coordinateScale);if(y&&n.push(y),i){const t=m[0]-r.point[0],i=m[1]-r.point[1],o=Math.hypot(t,i),s=g-r.limit;if(o>e.epsilon&&s>e.epsilon){const a=Math.min(Math.max(8*e.epsilon,.05*r.halfDepth),.25*s),l=t/o,c=i/o,h=-c,d=l,u=Ks([[m[0]-l*a+h*a,m[1]-c*a+d*a],[m[0]-l*a-h*a,m[1]-c*a-d*a],[m[0]+l*a,m[1]+c*a]],e.coordinateScale);u&&n.push(u)}}}return n}({...t,nodes:[e]},i,n));return o&&r?Gt(o,r):o}function Vs(e,t,i,n){if(!e||!t.nodes.length)return e;let r=null;try{r=function(e){let t=null;for(const i of e.nodes){const n=Us(i,e);n&&(t=t?Wt(t,n):n)}return t}(t)}catch{return e}let o=e;for(const e of t.nodes){const s=4*e.halfDepth+2*t.epsilon,a=2*s,l=[[e.point[0]-s,e.point[1]-s],[e.point[0]+s,e.point[1]-s],[e.point[0]+s,e.point[1]+s],[e.point[0]-s,e.point[1]+s]];try{let s=o;const c=Gs(e,t,!1,!0,r);c&&(s=Gt(s,c));let h=js(e,t,a);const d=Gs(e,t,!0,!0,r);d&&(h=Gt(h,d)),r&&(h=Wt(h,r));const u=.02*Math.min(...e.rays.map(e=>e.halfDepth));if(h=Wt(h,Bs([[e.point[0]-u,e.point[1]-u],[e.point[0]+u,e.point[1]-u],[e.point[0]+u,e.point[1]+u],[e.point[0]-u,e.point[1]+u]])),!h)continue;let p=Ut(h,Bs(l));n?p=Ut(p,n):i&&(p=Ut(p,i));const _=Bs(l),m=Gt(s,_),g=i?Gt(Ut(s,_),i):null,f=Ws(e,t,_);o=Wt(m,...g?[g]:[],...f?[f]:[],p)}catch{}}if(r)try{let e=r;n?e=Ut(e,n):i&&(e=Ut(e,i)),o=Wt(o,e)}catch{}return o}function Ks(e,t=1){if(!Array.isArray(e)||e.length<3)return null;const i=Number.isFinite(t)&&t>0?t:1,n=1e-12*Math.max(1,i),r=[];for(const t of e){if(!Array.isArray(t)||t.length<2)return null;const e=Number(t[0]),i=Number(t[1]);if(!Number.isFinite(e)||!Number.isFinite(i))return null;const o=Math.round(e/n)*n,s=Math.round(i/n)*n;if(!Number.isFinite(o)||!Number.isFinite(s))return null;r.push([Object.is(o,-0)?0:o,Object.is(s,-0)?0:s])}return Math.abs(ms(r))>n*n?r:null}function Ys(e,t,i,n){if(Ns(e[0],e[1],t[0],t[1],i[0],i[1])>n)return!1;const r=i[0]-t[0],o=i[1]-t[1],s=(e[0]-t[0])*r+(e[1]-t[1])*o,a=r*r+o*o,l=n*Math.sqrt(a);return s>=-l&&s<=a+l}function Xs(e,t,i){const n=[],r=[];for(let o=0;oi*i))continue;const d=i/Math.sqrt(h),u=[0,1];for(const e of t)for(const t of[e.a,e.b]){if(!Ys(t,s,a,i))continue;const e=((t[0]-s[0])*l+(t[1]-s[1])*c)/h;e>d&&e<1-d&&u.push(e)}u.sort((e,t)=>e-t);const p=u.filter((e,t)=>0===t||Math.abs(e-u[t-1])>d);for(let e=0;e=3&&r.length===n.length?{poly:n,offsets:r}:null}function Zs(e,t,i,n,r,o,s,a){const l=(e||[]).map(ni).filter(e=>!!e&&e.length>=3);if(!l.length)return null;let c=Wt(Bs(l[0]));for(let e=1;e"outer"===e.kind&&e.half>0),u=4*_s(n,s),p=a||Ts(h,u,s);let _=null;for(const e of function(e){const t=[];for(const i of Array.isArray(e)?e:[])if(Array.isArray(i))for(const e of i){if(!Array.isArray(e)||e.length<4)continue;const i=e.slice(0,-1).map(e=>[e[0],e[1]]);i.length>=3&&t.push(i)}return t}(c)){const t=Xs(e,d,u);if(!t||!t.offsets.some(e=>e>0))continue;const i=aa(t.poly,t.offsets,p),n=ws(t.poly,t.offsets,p);if(!i||!n)continue;const r=Gt(Bs(i),Bs(n));_=_?Wt(_,r):r}return{centre:c,shell:_||[]}}function Js(e,t,i,n,r,o,s=1){try{const a=Zs(e,t,i,n,r,o,s,Ps(e,t,i,n,r,o,s));if(!a)return[];return a.shell?.length?Wt(a.centre,a.shell):a.centre}catch{return null}}function Qs(e){if(!e)return"";let t="";for(const i of e)if(Array.isArray(i))for(const e of i){if(!Array.isArray(e)||e.length<4)continue;const i=e.slice(0,e.length-1);i.length<3||(t+=(t?" ":"")+ks(i.map(e=>[e[0],e[1]])))}return t}const ea=15;function ta(e,t,i){const n=e?.length||0;if(n<3||t?.length!==n)return!1;const r=e[(i-1+n)%n],o=e[i],s=e[(i+1)%n],a=[r[0]-o[0],r[1]-o[1]],l=[s[0]-o[0],s[1]-o[1]],c=Math.hypot(a[0],a[1]),h=Math.hypot(l[0],l[1]);if(!(c>1e-9&&h>1e-9))return!1;const d=Math.max(-1,Math.min(1,(a[0]*l[0]+a[1]*l[1])/(c*h))),u=Math.acos(d);if(!(u>1e-9))return!1;if(u>=ea*Math.PI/180)return!1;const p=Math.max(0,t[(i-1+n)%n]),_=Math.max(0,t[i]);if(!(p>0||_>0))return!1;const m=Math.sin(u);if(!(m>1e-12))return!1;const g=(_+p*d)/m,f=(p+_*d)/m;return Number.isFinite(g)&&Number.isFinite(f)&&g>0&&f>0&&ge>0))continue;for(const e of l.offsets)e>0&&(u=Math.max(u,2*e));const c=aa(l.poly,l.offsets,d),p=ws(l.poly,l.offsets,d);c&&h.push({outset:c,inset:p})}for(const e of l){const t=e.map(e=>e[0]),i=e.map(e=>e[1]);if(t.length){const n=Math.min(Math.max(...t)-Math.min(...t),Math.max(...i)-Math.min(...i)),r=Math.min(...e.map((t,i)=>{const n=e[(i+1)%e.length];return Math.hypot(n[0]-t[0],n[1]-t[1])}));u=Math.max(u,e.length>16?n:r)}}const p=function(e,t,i,n,r,o,s,a){if(!t?.length||!i?.length)return[];const l=4*_s(n,s),c=new Map;for(const a of zs(e,t,i,n,r,o,s))!a.open&&a.half>0&&!c.has(a.key)&&c.set(a.key,a);const h=[...c.values()];if(h.length<2)return[];const d=a||Ts(h,l),u=[];for(const e of i)for(const t of[[e[0],e[1]],[e[2],e[3]]])u.some(e=>Math.hypot(e[0]-t[0],e[1]-t[1])<=l)||u.push(t);const p=[],_=(e,t)=>{let i=0,n=0;if(Math.hypot(e.a[0]-t[0],e.a[1]-t[1])<=l)i=e.b[0]-e.a[0],n=e.b[1]-e.a[1];else{if(!(Math.hypot(e.b[0]-t[0],e.b[1]-t[1])<=l))return null;i=e.a[0]-e.b[0],n=e.a[1]-e.b[1]}const r=Math.hypot(i,n);return r>l?[i/r,n/r]:null};for(const e of u){const t=h.map(t=>({iv:t,u:_(t,e)})).filter(e=>!!e.u);for(let i=0;i0?[e.slice(),u,m,_]:[e.slice(),_,m,u];else{if(!f)continue;{const t=[-r.u[1],r.u[0]],i=[-o.u[1],o.u[0]],n=s<0?1:-1,a=[e[0]+t[0]*r.iv.half*n,e[1]+t[1]*r.iv.half*n],l=[e[0]-i[0]*o.iv.half*n,e[1]-i[1]*o.iv.half*n];y=s>0?[e.slice(),a,l]:[e.slice(),l,a]}}Math.abs(ms(y))>l*l&&p.push(y)}}return p}(e,t,i,r,o,s,a,d),_=n.length?la(e,t,i,r,o,s,a):null;let m="exterior";try{const v=Zs(e,t,i,r,o,s,a,d);m="paper";const y=v?v.shell?.length?Wt(v.centre,v.shell):v.centre:[],b=e=>{const t=Bs(e.outset);if(!e.inset)return t;const i=Bs(e.inset);return Gt(t,i)};m="room-rings";let w=null;for(const e of h)try{const t=b(e);w=w?Wt(w,t):t}catch{}if(m="edge-bodies",v)for(const n of oa(e,t,i,r,o,s,a))try{const e=Ut(Bs(n.quad),v.centre);w=w?Wt(w,e):e}catch{}m="junctions",w=function(e,t,i=1,n=Wt){let r=e;for(const e of t||[]){const t=Ks(e,i);if(t)try{const e=Bs(t);r=r?n(r,e):e}catch{}}return r}(w,p,a),m="facade-clip",w&&v&&(w=Ut(w,v.centre)),m="exterior-shell";const k=[];let x=0;if(v?.shell?.length)if(w)try{const e=Wt(w,v.shell);if(!qs(e))throw new Error("invalid shell union");w=e}catch{if(!qs(w)||!qs(v.shell))throw new Error("invalid shell");k.push({id:"exterior-shell",geom:v.shell}),x++}else w=v.shell;if(m="multi-wall-trim",w&&d.nodes.length){const e=e=>e.rays.some(e=>e.supports.some(e=>e.length<2*e.halfDepth)),t=d.nodes.filter(e);if(t.length){w=Vs(w,{...d,nodes:t},v?.centre,y)}}if(m="junction-corners",d.nodes.length){const n=Ds(d),l=function(e,t,i,n,r,o,s,a){try{const l=Zs(e,t,i,n,r,o,s,{epsilon:a.epsilon,coordinateScale:a.coordinateScale,nodes:[],index:new Map});return l?l.shell?.length?Wt(l.centre,l.shell):l.centre:null}catch{return null}}(e,t,i,r,o,s,a,d);for(const e of n.fans)try{let t=[Bs(e)];if(l&&(t=Ut(t,l)),!t?.length)continue;w=w?Wt(w,t):t}catch{}g=w,f=Math.max(d.epsilon,1e-9)**2,w=Array.isArray(g)?g.map(e=>{if(!Array.isArray(e)||!e.length)return e;const[t,...i]=e;return Math.abs(ms(t||[]))<=f?null:[t,...i.filter(e=>Math.abs(ms(e||[]))>f)]}).filter(e=>!!e):g}const S=w||[],$=[...qs(S)?[{id:"room-primary",geom:S}]:[],...k.map((e,t)=>({id:`room-isolated-${t}`,geom:e.geom}))];m="openings";for(const e of n){if(!(e.length>0))continue;const t=da(_,e,!0);if(!t.negative&&!t.positive)continue;const i=e.angle*Math.PI/180,n=Math.cos(i),o=Math.sin(i),s=-o,l=n,c=e.length/2,h=1.25*Math.max(u,r*a),d=[[e.x-n*c-s*h,e.y-o*c-l*h],[e.x+n*c-s*h,e.y+o*c-l*h],[e.x+n*c+s*h,e.y+o*c+l*h],[e.x-n*c+s*h,e.y-o*c+l*h]];w&&(w=Gt(w,Bs(d)));for(const e of k)e.geom=Gt(e.geom,Bs(d))}m="extras";const M=[];let R=0;const C=c.mergeExtra||((e,t)=>e?Wt(e,t):t);for(let e=0;ee.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]))||Math.abs(Ci(t))<=1e-9){R++;continue}const i=[Bs(t)];try{const t=C(w,i,e);if(!qs(t))throw new Error("invalid extra union");w=t}catch{R++,qs(i)&&M.push({id:`extra-${e}`,geom:i})}}M.push(...k),M.sort((e,t)=>Qs(e.geom).localeCompare(Qs(t.geom)));const T=w||[];return{status:R||x?"degraded-extra":"ok",geom:T,components:[...qs(T)?[{id:"primary",geom:T}]:[],...M.map((e,t)=>({...e,id:`isolated-${t}`}))],roomGeom:S,roomComponents:$,paperGeom:y,depthUnits:u,openingPadUnits:1.25*Math.max(u,r*a),openingIndex:_,multiWallNodes:d,degradedExtraCount:R+x}}catch{return c.onCoreFailure?.(m),{status:"failed-core",geom:[],components:[],roomGeom:[],paperGeom:[],roomComponents:[],depthUnits:u,openingIndex:null,multiWallNodes:d,degradedExtraCount:0}}var g,f}function na(e,t,i,n=[],r,o,s,a=1,l=[],c={}){if(!t?.length&&!l.length)return null;return ra(ia(e,t,i,n,r,o,s,a,l,c))}function ra(e){if("failed-core"===e.status||"not-applicable"===e.status)return null;const t=e.components.map(e=>({id:e.id,d:Qs(e.geom),fillRule:"evenodd"})).filter(e=>!!e.d),i=t[0]?.d||"",n=Qs(e.paperGeom);if(t.length){const r={status:e.status,d:i,paths:t,components:e.components,roomGeom:e.roomGeom,multiWallNodes:e.multiWallNodes,paperD:n,depthUnits:e.depthUnits,fillRule:"evenodd"};return Object.defineProperties(r,{roomComponents:{value:e.roomComponents||[],enumerable:!1},openingIndex:{value:e.openingIndex,enumerable:!1},openingPadUnits:{value:e.openingPadUnits,enumerable:!1}}),r}return null}function oa(e,t,i,n,r,o,s=1){if(!t?.length)return[];const a=new Set,l=[];for(const c of e||[]){if(!c?.id)continue;const h=Fs(e,c.id,t,i,n,r,o,s);if(!h)continue;const d=h.poly;for(let e=0;e0))continue;const p=qo(t,i,n,s);if(a.has(p))continue;a.add(p);const _=Oo(u,r,o),[m,g]=gs(d,e),f=-m,v=-g,y=_/2,b=[[t[0]+f*y,t[1]+v*y],[i[0]+f*y,i[1]+v*y],[i[0]+m*y,i[1]+g*y],[t[0]+m*y,t[1]+g*y]];l.push({key:p,kind:c,cm:u,quad:b,a:[t[0],t[1]],b:[i[0],i[1]],depthUnits:_})}}return l}function sa(e,t=[]){let i=ks(e.quad);const[n,r]=Lo(e.a,e.b),o=n,s=r,a=-s,l=o;for(const n of t){if(!Zo(e.a,e.b,n.angle))continue;if(Ns(n.x,n.y,e.a[0],e.a[1],e.b[0],e.b[1])>Math.max(.55*e.depthUnits,.001))continue;const t=n.length/2,r=e.depthUnits,c=n.x,h=n.y;i+=` ${ks(xs([[c-o*t-a*r,h-s*t-l*r],[c+o*t-a*r,h+s*t-l*r],[c+o*t+a*r,h+s*t+l*r],[c-o*t+a*r,h-s*t+l*r]]))}`}return i}function aa(e,t,i){const n=e?.length||0;if(n<3||t.length!==n)return null;if(t.every(e=>!(e>0)))return e.map(e=>[e[0],e[1]]);xs(e),t.slice().reverse();const r=[];for(let o=0;o0||l>0)){r.push([e[o][0],e[o][1]]);continue}if(a>0!=l>0){const t=e[o],i=a>0?[t[0]-c*a,t[1]-h*a]:[t[0],t[1]],n=l>0?[t[0]-d*l,t[1]-u*l]:[t[0],t[1]];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}if(fs(w,k)){const t=e[o],i=[t[0]-c*a,t[1]-h*a],n=[t[0]-d*l,t[1]-u*l];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}const $=vs(x,w,S,k),M=Math.max(a,l,1e-9),R=As(i,e[o])?.limit??4*M;if($){const i=Math.hypot($[0]-e[o][0],$[1]-e[o][1]);if(Number.isFinite(i)&&i<=R){r.push($);continue}if(ta(e,t,o)){r.push([e[o][0],e[o][1]]);continue}}a>0&&r.push([e[o][0]-c*a,e[o][1]-h*a]),l>0&&r.push([e[o][0]-d*l,e[o][1]-u*l])}return r.length>=3?r:null}function la(e,t,i,n,r,o,s=1){const a=[];for(const l of e||[]){if(!l?.id)continue;const c=Fs(e,l.id,t,i,n,r,o,s);if(!c)continue;const h=Math.abs(Ci(c.poly));for(let e=0;e[Math.max(t,e.x0),Math.min(i,e.x1)]).filter(e=>e[1]-e[0]>n).sort((e,t)=>e[0]-t[0]||e[1]-t[1]);if(!r.length)return{coverage:0,full:!1};let o=r[0][0],s=r[0][1],a=0,l=o<=t+n;for(let e=1;e=i-n,{coverage:a,full:l}}function ha(e,t){return Number(t.full)-Number(e.full)||e.faceDistance-t.faceDistance||e.area-t.area||e.roomId.localeCompare(t.roomId)}function da(e,t,i=!1){const n=Number(t?.x),r=Number(t?.y),o=Number(t?.angle),s=Number(t?.length);if(!([n,r,o,s].every(Number.isFinite)&&s>0))return{negative:null,positive:null};const a=o*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=-c,d=l,u=s/2,p=Math.max(1e-9,e.adjacencyEps),_=new Map;let m=0;for(const t of e.edges){if(i&&!(t.half>0))continue;if(!Zo(t.a,t.b,o))continue;const[e,s]=Lo(t.a,t.b);if(Math.abs((n-t.a[0])*s-(r-t.a[1])*e)>p)continue;const a=(t.a[0]-n)*l+(t.a[1]-r)*c,g=(t.b[0]-n)*l+(t.b[1]-r)*c,f=Math.max(-u,Math.min(a,g)),v=Math.min(u,Math.max(a,g));if(v-f<=p)continue;const y=t.inward[0]*h+t.inward[1]*d>=0?1:-1,b=((t.a[0]+t.b[0])/2-n)*h+((t.a[1]+t.b[1])/2-r)*d,w=Math.abs(b+y*t.half),k=`${y}|${t.roomId}`,x={x0:f,x1:v,half:t.half,cm:t.cm,key:t.key,axis:[e,s]},S=_.get(k);S?(S.pieces.push(x),S.faceDistance=Math.min(S.faceDistance,w)):_.set(k,{roomId:t.roomId,side:y,order:m++,pieces:[x],faceDistance:w,area:t.area,coverage:0,full:!1})}for(const e of _.values()){const t=ca(e.pieces,-u,u,p);e.coverage=t.coverage,e.full=t.full}const g=e=>{const t=[..._.values()].filter(t=>t.side===e&&t.coverage>p);return t.sort(ha),t[0]||null};return{negative:g(-1),positive:g(1)}}function ua(e,t,i,n,r,o,s=1,a=[]){return pa(la(e,i,a,n,r,o,s),t)}function pa(e,t){const i=da(e,t),n=[i.negative,i.positive].filter(e=>!!e);if(!n.length)return{ox:0,oy:0,cm:0,side:-1};const r=i.negative&&i.positive?-1:n[0].side,o=t.flip_v?-r:r,s=(-1===o?i.negative:i.positive)||n[0],a=[...s.pieces].sort((e,t)=>(e.x0<=0&&e.x1>=0?0:Math.min(Math.abs(e.x0),Math.abs(e.x1)))-(t.x0<=0&&t.x1>=0?0:Math.min(Math.abs(t.x0),Math.abs(t.x1)))||t.x1-t.x0-(e.x1-e.x0)||e.key.localeCompare(t.key))[0];if(!(a.half>0&&a.cm>0))return{ox:0,oy:0,cm:0,side:o};const l=t.angle*Math.PI/180,c=-Math.sin(l),h=Math.cos(l);return{ox:c*o*a.half,oy:h*o*a.half,cm:a.cm,side:o}}function _a(e,t){const i=1e-9,n=t.filter(e=>Number.isFinite(e.x0)&&Number.isFinite(e.x1)&&Number.isFinite(e.half)&&e.x1>e.x0&&e.half>0);if(!n.length)return"";const r=n.flatMap(e=>[e.x0,e.x1]).sort((e,t)=>e-t),o=[];for(const e of r){const t=o[o.length-1];(void 0===t||e>t+i)&&o.push(e)}const s=[];for(let e=0;e+1t+i))continue;const a=(t+r)/2,l=n.reduce((e,t)=>a>=t.x0-i&&a<=t.x1+i?Math.max(e,t.half):e,0);if(!(l>0))continue;const c=s[s.length-1];c&&t<=c.x1+i&&Math.abs(l-c.half)<=i?c.x1=r:s.push({x0:t,x1:r,half:l})}const a=[];for(const e of s){const t=a[a.length-1],n=t?.[t.length-1];n&&e.x0<=n.x1+i?(e.x0=n.x1,t.push(e)):a.push([e])}return a.map(t=>{const i=t[0],n=t[t.length-1],r=Math.min(.25*Math.min(...t.map(e=>e.half)),.75),o=-e*r,s=[];if(1===e){s.push(`M ${i.x0} ${o} L ${n.x1} ${o}`);for(let e=t.length-1;e>=0;e--){const i=t[e];s.push(`L ${i.x1} ${i.half} L ${i.x0} ${i.half}`)}}else{s.push(`M ${n.x1} ${o} L ${i.x0} ${o}`);for(const e of t)s.push(`L ${e.x0} ${-e.half} L ${e.x1} ${-e.half}`)}return s.push("Z"),s.join(" ")}).join(" ")}function ma(e,t,i,n){if(!n)return i;const r=e.angle*Math.PI/180,o=Math.cos(r),s=Math.sin(r),a=[],l=1e-9;for(const r of i){const[i,c]=r.axis,h=o*i+s*c;if(Math.abs(h)<=l)continue;const d=e.x*i+e.y*c,u=d+h*r.x0,p=d+h*r.x1,_=Math.min(u,p),m=Math.max(u,p),g=`${r.key}|${t}`,f=n.get(g)||[];let v=[[_,m]];for(const[e,t]of f){const i=[];for(const[n,r]of v)t<=n+l||e>=r-l?i.push([n,r]):(e>n+l&&i.push([n,Math.min(r,e)]),te[0]-t[0]||e[1]-t[1]),b=[];for(const e of y){const t=b[b.length-1];t&&e[0]<=t[1]+l?t[1]=Math.max(t[1],e[1]):b.push([e[0],e[1]])}n.set(g,b)}return a}function ga(e,t){const i=new Map;return t.map(t=>function(e,t,i){const n=da(e,t,!0),r=n.negative,o=n.positive;if(!r&&!o)return null;let s;if(r&&o)s=[{candidate:r,side:-1},{candidate:o,side:1}];else{const e=r||o;s=[{candidate:e,side:-1},{candidate:e,side:1}]}const a=s.map(({candidate:e,side:n})=>({candidate:e,side:n,pieces:ma(t,n,e.pieces,i)})),l=a.map(({candidate:e,side:t,pieces:i})=>({side:t,roomId:e.roomId,d:_a(t,i)})),c=a.flatMap(({pieces:e})=>e);if(!c.length)return null;const h=Math.max(...c.map(e=>e.half));return{faces:l,minY:-h,maxY:h,wallKey:[...new Set(c.map(e=>e.key))].sort().join("|")}}(e,t,i))}const fa=150,va=1e-6;function ya(e){return Number.isFinite(e)?Math.max(1,Math.min(fa,e)):1}function ba(e){return((Number.isFinite(Number(e))?Number(e):0)%90+90)%90}const wa=e=>{const t=e.map(e=>[e[0],e[1]]);return!t.length||t[0][0]===t[t.length-1][0]&&t[0][1]===t[t.length-1][1]||t.push([...t[0]]),[t]},ka=(e,t)=>e[0]===t[0]&&e[1]===t[1];function xa(e,t=1e-6){const i=Number.isFinite(t)&&t>0?t:va,n=[];for(const t of e||[]){if(!Array.isArray(t)||t.length<2)return null;const e=Number(t[0]),r=Number(t[1]);if(!Number.isFinite(e)||!Number.isFinite(r))return null;const o=Math.round(e/i)*i,s=Math.round(r/i)*i;if(!Number.isFinite(o)||!Number.isFinite(s))return null;const a=[Object.is(o,-0)?0:o,Object.is(s,-0)?0:s];n.length&&ka(n[n.length-1],a)||n.push(a)}return n.length>1&&ka(n[0],n[n.length-1])&&n.pop(),n.length<3||new Set(n.map(e=>`${e[0]},${e[1]}`)).size<3?null:Ci(n)>i*i?n:null}function Sa(e){const t=[];for(const i of e||[])for(const e of i||[]){const i=(e||[]).filter(e=>Array.isArray(e)&&e.length>=2);i.length<4||t.push(`M ${i.slice(0,-1).map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`)}return t.join(" ")}function $a(e,t,i,n,r){return os({a:e,b:t,halfDepth:Oo(i,n,r)/2})}function Ma(e,t,i){const n=Number(t)>0?Number(t):5,r=ya(e.cm)/n*i,o=e.center[0],s=e.center[1];if("circle"===e.shape){const e=r/2;return Array.from({length:96},(t,i)=>{const n=i/96*Math.PI*2;return[o+Math.cos(n)*e,s+Math.sin(n)*e]})}const a=r/2,l=ba(e.angle)*Math.PI/180,c=Math.cos(l),h=Math.sin(l);return[[-a,-a],[a,-a],[a,a],[-a,a]].map(([e,t])=>[o+e*c-t*h,s+e*h+t*c])}function Ra(e,t){const i=Number.isFinite(t)?Math.max(0,Math.min(1,t)):0,n=(e.a[0]+e.b[0])/2,r=(e.a[1]+e.b[1])/2,o=(e.b[0]-e.a[0])*i/2,s=(e.b[1]-e.a[1])*i/2;return{...e,a:[n-o,r-s],b:[n+o,r+s]}}function Ca(e,t,i=1e-9){if(!t.length)return[e];let n=[wa(e)];try{for(const e of t){const t=e.b[0]-e.a[0],r=e.b[1]-e.a[1],o=Math.hypot(t,r);if(!(o>i))continue;const s=t/o,a=r/o,l=-a,c=s,h=1.25*Math.max(Number(e.depth)||0,4*i),d=Math.max(2*i,1e-9*o),u=[[e.a[0]-s*d-l*h,e.a[1]-a*d-c*h],[e.b[0]+s*d-l*h,e.b[1]+a*d-c*h],[e.b[0]+s*d+l*h,e.b[1]+a*d+c*h],[e.a[0]-s*d+l*h,e.a[1]-a*d+c*h]];n=Gt(n,wa(u))}return Na(n)}catch{return[e]}}function Ta(e,t){try{const i=Gt([[...e.map(e=>[e[0],e[1]]),[e[0][0],e[0][1]]]],[[...t.map(e=>[e[0],e[1]]),[t[0][0],t[0][1]]]]);let n=null,r=0;for(const e of i||[]){const t=e?.[0]||[],i=Math.abs(Ci(t));t.length>=4&&i>r&&(r=i,n=t.slice(0,-1).map(e=>[e[0],e[1]]))}return n}catch{return null}}function Da(e,t,i,n=Math.max(2e-4*i,1e-9),r=[]){const o=[],s=new Map;for(const e of r){const t=s.get(e.hostId)||[];t.push(e),s.set(e.hostId,t)}const a=[],l=[],c=[];for(const n of e.partitions||[]){const e={a:n.a,b:n.b,halfDepth:Oo(n.cm,t,i)/2};if(!(e.halfDepth>0))continue;const r=os(e);r&&(o.push(e),a.push(r),c.push({id:n.id,body:r}))}const h=o;for(const{segmentIndex:e,wedge:t}of hs(h,n)){const i={list:a,at:e},n=Ta(i.list[i.at],t);n&&(i.list[i.at]=n,c[i.at].body=n)}for(const e of c)l.push(...Ca(e.body,s.get(e.id)||[],n));const d=(e.wall_columns||[]).map(e=>Ma(e,t,i)),u=ds(o,n).flatMap(e=>Ca(e,r,n));return{partitions:a,columns:d,patches:u,all:[...l,...u,...d]}}function Aa(e){try{const t=e.map(e=>xa(e)).filter(e=>!!e).map(e=>wa(e));return t.length?Wt(t[0],...t.slice(1)):null}catch{return null}}const Pa=e=>`M ${e.map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`;function Fa(e){const t=[];for(const i of e||[]){if(Oa([i])<=1e-6)continue;const e=[];for(const t of i||[]){const i=(t||[]).filter(e=>Array.isArray(e)&&e.length>=2);i.length<4||e.push(Pa(i.slice(0,-1)))}e.length&&t.push(e.join(" "))}return t}function za(e,t,i={}){const n=Aa(e.filter(e=>e.length>=3)),r=t.some(e=>!xa(e))?null:Aa(t);if(!n)return[];if(r)try{return Fa(Ut(n,r))}catch{}return function(e,t,i){let n=null;for(let r=0;r=4&&t.push(e.slice(0,-1).map(e=>[e[0],e[1]]));return t}function Na(e){const t=[];for(const i of e||[]){const e=i?.[0];e?.length>=4&&t.push(e.slice(0,-1).map(e=>[e[0],e[1]]))}return t}function Ha(e,t){let i=!1;for(let n=0,r=t.length-1;ne[1]!=l>e[1]&&e[0]<(a-o)*(e[1]-s)/(l-s||1e-12)+o&&(i=!i)}return i}function La(e,t){for(const i of t||[]){const t=i?.[0];if(!t?.length||!Ha(e,t))continue;let n=!1;for(let t=1;ti)return!1;if(Math.abs(ya(e.cm)-ya(t.cm))>1e-6)return!1;if(e.shape!==t.shape)return!0;if("circle"===e.shape||"circle"===t.shape)return!0;const n=Math.abs(ba(e.angle)-ba(t.angle));return Math.min(n,90-n)<=1e-6}const qa=2.54;function ja(e){const t="number"==typeof e?e:NaN;return!Number.isFinite(t)||t<=0||5===t?1:5/t}function Wa(e,t){return e*ja(t)}function Ua(e){return e?qa:1}function Ga(e,t){if(!t)return String(e);const i=e/qa;return String(Math.round(1e6*i)/1e6)}function Va(e,t){return t?e*qa:e}const Ka=1e3;function Ya(e,t){const i=Number(e),n=Number.isFinite(i)&&i>0?i:1,r=n>=1?t:t*n,o=n>=1?t/n:t;return{x:(t-r)/2,y:(t-o)/2,w:r,h:o}}const Xa=.01,Za=100;function Ja(e,t=1e3){const i=Ya(e?.plan_aspect,t),n=Number(e?.plan_scale),r=Number.isFinite(n)&&n>0?Math.min(Za,Math.max(Xa,n)):1,o=Number(e?.plan_scale_x),s=Number(e?.plan_scale_y),a=Number.isFinite(o)&&o>0?Math.min(Za,Math.max(Xa,o)):r,l=Number.isFinite(s)&&s>0?Math.min(Za,Math.max(Xa,s)):r,c=Number(e?.plan_x),h=Number(e?.plan_y),d=Dr(e?.plan_angle);return{x:i.x+(Number.isFinite(c)?cl(c):0)*t,y:i.y+(Number.isFinite(h)?cl(h):0)*t,w:i.w*a,h:i.h*l,...d?{angle:d}:{}}}function Qa(e){if(null==e.x||null==e.y)return{x:e.x,y:e.y,w:e.w,h:e.h};const t=Number(e.w)||0,i=Number(e.h)||0;return{x:t<0?e.x+t:e.x,y:i<0?e.y+i:e.y,w:Math.abs(t),h:Math.abs(i)}}function el(e){return e&&Array.isArray(e.spaces)?e.spaces.map(e=>{const t=Ka,i=function(e){return Array.isArray(e)&&4===e.length&&e.every(e=>Number.isFinite(e))&&e[2]>1e-6&&e[3]>1e-6?e:[0,0,1,1]}(e.view_box);return{id:e.id,title:e.title,cellCm:Number.isFinite(Number(e.cell_cm))&&Number(e.cell_cm)>0?Number(e.cell_cm):5,vb:[i[0]*Ka,i[1]*t,i[2]*Ka,i[3]*t],bg:e.plan_url?{href:Hn(e.plan_url),...Ja(e,Ka)}:null,rooms:(e.rooms||[]).map(e=>{const i={...e,...Qa(e)};return{id:i.id,name:i.name,area:i.area??null,open_to:i.open_to||void 0,settings:i.settings||void 0,x:null!=i.x?i.x*Ka:void 0,y:null!=i.y?i.y*t:void 0,w:null!=i.w?i.w*Ka:void 0,h:null!=i.h?i.h*t:void 0,poly:i.poly?i.poly.map(e=>[e[0]*Ka,e[1]*t]):void 0,wall_ids:Array.isArray(i.wall_ids)?[...i.wall_ids]:void 0}}),wall_segments:(e.wall_segments||[]).map(e=>({...e,id:String(e.id),a:[Number(e.a?.[0])*Ka,Number(e.a?.[1])*t],b:[Number(e.b?.[0])*Ka,Number(e.b?.[1])*t],cm:Number(e.cm)})),partitions:(e.partitions||[]).map(e=>({id:e.id,a:[e.a[0]*Ka,e.a[1]*t],b:[e.b[0]*Ka,e.b[1]*t],cm:Number(e.cm)})),wall_columns:(e.wall_columns||[]).map(e=>({id:e.id,shape:"circle"===e.shape?"circle":"square",center:[e.center[0]*Ka,e.center[1]*t],cm:Number(e.cm),..."circle"===e.shape?{}:{angle:ba(e.angle)}}))}}):[]}const tl=5e3,il=tl*Ka,nl=240,rl=Ka/nl,ol=1/nl;function sl(e){if(!Number.isFinite(e))return e;const t=Math.round(e*nl/Ka)*Ka/nl;return Math.abs(t-e)<=1e-9*rl?e:t}function al(e){return{x:sl(e.x),y:sl(e.y)}}function ll(e){return Number.isFinite(e)?Math.min(il,Math.max(-il,e)):0}function cl(e){return Number.isFinite(e)?Math.min(tl,Math.max(-tl,e)):0}const hl=1/3,dl=200;function ul(e){return"house"===e?"house":"content"}function pl(e){let t=1/0,i=1/0,n=-1/0,r=-1/0;for(const o of e){const e=Number(o[0]),s=Number(o[1]);Number.isFinite(e)&&Number.isFinite(s)&&(en&&(n=e),s>r&&(r=s))}return t>n?null:{minX:t,minY:i,maxX:n,maxY:r}}function _l(e){const t=[],i=e=>{if(Array.isArray(e))if(e.length>=2&&Number.isFinite(Number(e[0]))&&Number.isFinite(Number(e[1])))t.push([Number(e[0]),Number(e[1])]);else for(const t of e)i(t)};return i(e),pl(t)}function ml(e,t){const i=Number.isFinite(t)&&t>0?t:0;return{minX:e.minX-i,minY:e.minY-i,maxX:e.maxX+i,maxY:e.maxY+i}}function gl(e){return e.poly&&e.poly.length?pl(e.poly):null==e.x||null==e.y?null:pl([[e.x,e.y],[e.x+(e.w||0),e.y+(e.h||0)]])}function fl(e,t=1e3,i=1e3){const n=Number(e.x)*t,r=Number(e.y)*i,o=Number(e.w)*t,s=Number(e.h)*i;return![n,r,o,s].every(Number.isFinite)||o<=0||s<=0?null:pl(Nr({x:n,y:r,w:o,h:s,angle:Dr(e.angle)||void 0}))}function vl(e,t){const i=[];for(const t of e.rooms||[]){const e=gl(t);e&&i.push(e)}if(e.bg){const t=pl(Nr(e.bg));t&&i.push(t)}for(const e of t||[])if(Array.isArray(e)){const t=pl([e]);t&&i.push(t)}else i.push(e);return i}const yl=e=>{if(!e.length)return 0;const t=[...e].sort((e,t)=>e-t),i=t.length>>1;return t.length%2?t[i]:(t[i-1]+t[i])/2},bl=e=>{let t=1/0,i=1/0,n=-1/0,r=-1/0;for(const o of e)o.minXn&&(n=o.maxX),o.maxY>r&&(r=o.maxY);return t>n||i>r?null:{x:t,y:i,w:n-t,h:r-i}};function wl(e,t){let{x:i,y:n,w:r,h:o}=e;r<30&&(i=i+r/2-100,r=dl),o<30&&(n=n+o/2-100,o=dl);const s="number"==typeof t?{top:t,right:t,bottom:t,left:t}:t,a=Math.max(r,o),l=a*s.top,c=a*s.right,h=a*s.bottom,d=a*s.left;return{x:i-d,y:n-l,w:r+d+c,h:o+l+h}}function kl(e,t={}){const i=t.pad??.05,n=t.k??10,r=t.minSpread??50,o=e.filter(e=>Number.isFinite(e.minX)&&Number.isFinite(e.minY)&&Number.isFinite(e.maxX)&&Number.isFinite(e.maxY)&&Math.abs(e.minX)<=il&&Math.abs(e.maxX)<=il&&Math.abs(e.minY)<=il&&Math.abs(e.maxY)<=il);if(!o.length)return{core:null,all:null,outliers:0};const s=bl(o);if(o.length<4){const e=wl(s,i);return{core:e,all:e,outliers:0}}const a=o.map(e=>(e.minX+e.maxX)/2),l=o.map(e=>(e.minY+e.maxY)/2),c=yl(a),h=yl(l),d=o.map((e,t)=>Math.max(Math.abs(a[t]-c),Math.abs(l[t]-h))),u=Math.max(((e,t)=>e.length?e[Math.min(e.length-1,Math.max(0,Math.round(t*(e.length-1))))]:0)([...d].sort((e,t)=>e-t),.75),r),p=d.map(e=>e>n*u),_=p.filter(Boolean).length,m=_&&_<=o.length*hl?o.filter((e,t)=>!p[t]):o;return{core:wl(bl(m)||s,i),all:wl(s,i),outliers:m===o?0:_}}function xl(e){return kl(e,{pad:0}).all}function Sl(e,t,i=.05){const n=kl(vl(e,t),{pad:i});if(n.core)return n.core;const r=e.vb&&4===e.vb.length&&e.vb[2]>0&&e.vb[3]>0?e.vb:[0,0,Ka,Ka];return{x:r[0],y:r[1],w:r[2],h:r[3]}}function $l(e){const t=Sl(e);return{x:t.x+t.w/2,y:t.y+t.h/2}}function Ml(e){const t=[];for(const i of e.rooms||[]){const e=gl(i);e&&t.push(e)}const i=kl(t,{pad:0}).core,n=Ka*ja(e.cellCm??5);return i?Math.max(n,Math.min(il,Math.max(i.w,i.h))):n}function Rl(e,t,i,n=1){const r=Number(i),o=Number.isFinite(n)&&n>0?n:1;return!Number.isFinite(r)||r<=0?e*o:e*Ml(t)*o/r}const Cl=[1,2,5,10,20,50,100,200,500,1e3];function Tl(e,t,i=7){if(!(e>0&&t>0&&Number.isFinite(t)))return null;const n=Cl.find(n=>e*n*t>=i);if(void 0===n)return null;const r=Cl.find(e=>e>=5*n)??5*n;return{fine:n,coarse:r}}function Dl(e){if(e.poly&&e.poly.length){const t=e.poly.map(e=>e[0]),i=e.poly.map(e=>e[1]),n=Math.min(...t),r=Math.min(...i);return{x:n,y:r,w:Math.max(...t)-n,h:Math.max(...i)-r}}return{x:e.x??0,y:e.y??0,w:e.w??0,h:e.h??0}}function Al(e,t,i,n,r,o=new Set){const s=t[e.id];return!o.has(e.id)&&s&&s.s===e.space?{x:s.x*Ka,y:s.y*Ka}:n[e.id]?n[e.id]:al($l(r))}function Pl(e,t,i,n){const r=i["rl_"+(e.id||"")];if(r&&r.s===t)return{x:r.x*Ka,y:r.y*Ka};const o=function(e){if(e.poly){const t=e.poly.length;return[e.poly.reduce((e,t)=>e+t[0],0)/t,e.poly.reduce((e,t)=>e+t[1],0)/t]}return[e.x+e.w/2,e.y+.1*Math.min(e.w,e.h)]}(e);return al({x:o[0],y:o[1]})}function Fl(e,t){for(const i of e?.spaces??[])for(const e of i?.decor??[])if("furniture"===e?.kind&&"string"==typeof e.symbol&&t(e.symbol))return!0;return!1}let zl=0;const Il=new Set;const Ol=new class{constructor(e){this.options=e,this._art=null,this._failed=!1,this._terminal=!1,this._inFlight=null,this._hosts=new Set,this._settled=[]}state(){return this._art?"ready":this._failed?"fallback":"pending"}get terminal(){return this._terminal}art(e,t){if(this._art)return this._art[e];t&&!this._failed&&this._hosts.add(t)}adopt(e,t){return!!this._art||(t!==this.options.expectedFingerprint?((this.options.warn??console.warn)("[houseplan] furniture artwork from another build ignored",{fingerprint:t}),!1):(this._install(e),!0))}ensure(){return"pending"!==this.state()?Promise.resolve():(this._inFlight||(this._inFlight=this._loadWithRetry().finally(()=>{this._inFlight=null})),this._inFlight)}onSettled(e){"pending"===this.state()?this._settled.push(e):Promise.resolve().then(e)}async _loadWithRetry(){let e=new Error("furniture artwork did not load");for(const t of[0,1])try{const i=await this.options.load(t);if(i.FURNITURE_ART_FINGERPRINT!==this.options.expectedFingerprint){this._terminal=!0,e=new Error(`furniture artwork fingerprint mismatch: expected ${this.options.expectedFingerprint}, got ${i.FURNITURE_ART_FINGERPRINT}`);break}if(this._art)return;return void this._install(i.GENERATED_FURNITURE_ART)}catch(t){e=t}this._art||(this._failed=!0,(this.options.warn??console.warn)("[houseplan] furniture artwork unavailable",e),this.options.loadFailed?.(this._terminal),this._flush())}_install(e){this._art=e,this._failed=!1,this._flush()}_flush(){const e=[...this._hosts];this._hosts.clear();for(const t of e)t.isConnected&&t.requestUpdate();const t=this._settled.splice(0);for(const e of t)e()}}({expectedFingerprint:"c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f",load:async e=>0===e?await import("./furniture-plan-art.generated-Ck1wv9qF.js"):await import((()=>{const e=new URL("./furniture-plan-art.generated-Ck1wv9qF.js",import.meta.url);return e.searchParams.set("hp_retry","art-"+ ++zl),e.href})()),loadFailed:e=>{for(const t of Il)t(e)}}),El=["furniture","appliance","sanitary","other"],Nl=[{id:"coffee_table",group:"furniture",category:"coffee_table",w:120,h:60},{id:"coffee_table_round",group:"furniture",category:"coffee_table",w:80,h:80},{id:"coffee_table_oval",group:"furniture",category:"coffee_table",w:120,h:60},{id:"coffee_table_rounded",group:"furniture",category:"coffee_table",w:120,h:60},{id:"table_dining",group:"furniture",category:"dining_table",w:160,h:90},{id:"table_round",group:"furniture",category:"dining_table",w:110,h:110},{id:"table_dining_oval",group:"furniture",category:"dining_table",w:180,h:100},{id:"table_dining_rounded",group:"furniture",category:"dining_table",w:160,h:90},{id:"desk",group:"furniture",category:"work_table",w:140,h:70},{id:"desk_corner",group:"furniture",category:"work_table",w:160,h:160},{id:"chair",group:"furniture",category:"chair",w:50,h:50},{id:"chair_bar",group:"furniture",category:"chair",w:45,h:48},{id:"armchair",group:"furniture",category:"armchair",w:90,h:90},{id:"armchair_office",group:"furniture",category:"armchair",w:65,h:65},{id:"sofa",group:"furniture",category:"sofa",w:180,h:90},{id:"sofa_three_seat",group:"furniture",category:"sofa",w:240,h:90},{id:"sofa_corner_right",group:"furniture",category:"sofa",w:260,h:170},{id:"bed_single",group:"furniture",category:"bed",w:90,h:200},{id:"bed_double",group:"furniture",category:"bed",w:160,h:200},{id:"nightstand",group:"furniture",category:"nightstand",w:50,h:40},{id:"cabinet_tv",group:"furniture",category:"nightstand",w:140,h:45},{id:"cabinet_shoe",group:"furniture",category:"nightstand",w:80,h:35},{id:"cabinet_sink",group:"furniture",category:"nightstand",w:80,h:50},{id:"bookshelf",group:"furniture",category:"wardrobe",w:100,h:35},{id:"wall_unit",group:"furniture",category:"wardrobe",w:240,h:45},{id:"wardrobe",group:"furniture",category:"wardrobe",w:180,h:60},{id:"kitchen_floor",group:"furniture",category:"kitchen_cabinet",w:60,h:60},{id:"kitchen_floor_corner",group:"furniture",category:"kitchen_cabinet",w:90,h:90},{id:"kitchen_wall",group:"furniture",category:"kitchen_cabinet",w:60,h:35},{id:"kitchen_wall_corner",group:"furniture",category:"kitchen_cabinet",w:60,h:60},{id:"shelf_floor",group:"furniture",category:"shelving",w:100,h:35},{id:"shelf_wall",group:"furniture",category:"shelving",w:100,h:25},{id:"cooktop_two",group:"appliance",category:"cooktop",w:30,h:50},{id:"stove",group:"appliance",category:"cooktop",w:60,h:60},{id:"tv",group:"appliance",category:"tv",w:120,h:28},{id:"tv_wall",group:"appliance",category:"tv",w:120,h:15},{id:"toilet",group:"sanitary",category:"toilet",w:40,h:70},{id:"toilet_built_in",group:"sanitary",category:"toilet",w:40,h:55},{id:"bathtub",group:"sanitary",category:"bathtub",w:170,h:75},{id:"bathtub_corner",group:"sanitary",category:"bathtub",w:140,h:140},{id:"bidet",group:"sanitary",category:"bidet",w:40,h:60},{id:"bidet_built_in",group:"sanitary",category:"bidet",w:40,h:50},{id:"kitchen_sink",group:"sanitary",category:"kitchen_sink",w:60,h:50},{id:"kitchen_sink_double",group:"sanitary",category:"kitchen_sink",w:90,h:50},{id:"fridge",group:"appliance",category:"fridge",w:60,h:65},{id:"dishwasher",group:"appliance",category:"dishwasher",w:60,h:60},{id:"washer",group:"appliance",category:"washer",w:60,h:60},{id:"dryer",group:"appliance",category:"dryer",w:60,h:60},{id:"ac",group:"appliance",category:"air_conditioner",w:90,h:25},{id:"water_heater",group:"appliance",category:"boiler",w:45,h:45},{id:"shower",group:"sanitary",category:"shower",w:90,h:90},{id:"sink",group:"sanitary",category:"sink",w:60,h:45},{id:"stairs",group:"other",category:"stairs",w:100,h:280},{id:"fireplace",group:"other",category:"fireplace",w:120,h:40},{id:"plant",group:"other",category:"plant",w:40,h:40},{id:"rug",group:"other",category:"rug",w:200,h:140},{id:"computer",group:"appliance",category:"computer",w:120,h:60},{id:"hood",group:"appliance",category:"hood",w:60,h:50},{id:"oven",group:"appliance",category:"oven",w:60,h:60},{id:"cactus",group:"other",category:"plant",w:70,h:120}].map(e=>({id:e.id,group:e.group,category:e.category,w:e.w,h:e.h})),Hl=new Map(Nl.map(e=>[e.id,e]));function Ll(e){return e&&Hl.get(e)||null}function Bl(e){return Hl.has(e)}function ql(e){return Nl.filter(t=>t.group===e)}function jl(e){const t=Ll(e);return t?{w:t.w,h:t.h}:{w:60,h:60}}function Wl(e,t,i=rl,n=1e3){const r=Number(t)>0?Number(t):5;return(Number(e)||0)/r*i/n}const Ul=5e-4,Gl=tl;function Vl(e){return Number.isFinite(e)?Math.max(Ul,Math.min(Gl,e)):Ul}function Kl(e){return Number.isFinite(e)?Math.max(1,Math.min(1e4,e)):1}function Yl(e,t){return Ll(e)?Ol.art(e,t)??null:null}function Xl(e,t,i=1){const n=Number(e),r=Number(i),o=Number.isFinite(n)&&n>0?n:Number.isFinite(r)&&r>0?r:1,s=Number(t),a=o*(Number.isFinite(s)&&s>0?s:1);return Number.isFinite(a)&&a>0?a:o}function Zl(e,t,i,n,r){const o=e+i/2,s=t+n/2,a=(Number(r)||0)*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=(e,t)=>{const i=e-o,n=t-s;return[o+i*l-n*c,s+i*c+n*l]};return[h(e,t),h(e+i,t),h(e+i,t+n),h(e,t+n)]}function Jl(e,t,i,n,r,o,s){const a=Number.isFinite(s)&&s>0?s:1e-6,l=(Number(e.angle)||0)*Math.PI/180,c=Math.cos(l),h=Math.sin(l),d=-Math.sin(l),u=Math.cos(l),p=e.x+e.w/2,_=e.y+e.h/2,m=t>0?-e.w/2:t<0?e.w/2:0,g=i>0?-e.h/2:i<0?e.h/2:0,f=p+m*c+g*d,v=_+m*h+g*u,y=n-f,b=r-v,w=t?(y*c+b*h)*(t>0?1:-1):e.w,k=i?(y*d+b*u)*(i>0?1:-1):e.h;let x=t?Math.abs(w):e.w,S=i?Math.abs(k):e.h;if(o&&t&&i){const t=x/Math.max(e.w,a),i=S/Math.max(e.h,a),n=Math.abs(t-1)>=Math.abs(i-1)?t:i,r=Math.max(a/e.w,a/e.h),o=Math.max(r,Number.isFinite(n)?n:r);x=e.w*o,S=e.h*o}x=Math.max(a,Number.isFinite(x)?x:a),S=Math.max(a,Number.isFinite(S)?S:a);const $=!!t&&w<0,M=!!i&&k<0,R=t?(t>0?1:-1)*($?-1:1):0,C=i?(i>0?1:-1)*(M?-1:1):0,T=f+R*(x/2)*c+C*(S/2)*d,D=v+R*(x/2)*h+C*(S/2)*u,A=!!e.flip_h!==$,P=!!e.flip_v!==M;return{x:T-x/2,y:D-S/2,w:x,h:S,...Number(e.angle)?{angle:Number(e.angle)}:{},...A?{flip_h:!0}:{},...P?{flip_v:!0}:{}}}function Ql(e,t,i,n){let r=Number(e)+(Number(i)-Number(t));if([r,t,i].every(Number.isFinite)||(r=0),n){const e=r/45;r=45*(e<0?-Math.round(Math.abs(e)):Math.round(e))}return r=(r%360+360)%360,r>180?r-360:r}function ec(e,t,i,n,r){const o=e.x*t,s=e.y*i,a=e.w*t,l=e.h*i,c=o+a/2,h=s+l/2,d=o+(e.flip_h?a:0),u=s+(e.flip_v?l:0),p=(e.flip_h?-1:1)*a/n,_=(e.flip_v?-1:1)*l/r,m=Number(e.angle)||0;return(m?`rotate(${m} ${c} ${h}) `:"")+`translate(${d} ${u}) scale(${p} ${_})`}function tc(e,t,i,n=.1){if("string"==typeof e&&!e.trim())return null;const r=Number(e);if(!Number.isFinite(r)||0===r)return null;const o=r*(t?30.48:100),s=Math.abs(o);return si?null:o}function ic(e,t,i){const n=Math.abs(Number(e))/(i?30.48:100),r=Number(n.toFixed(6));return String(t?-r:r)}const nc=15e3,rc=2e3,oc=new WeakMap;function sc(e,t){let i=oc.get(e);if(!i){const t=new Set;i={hiddenAt:"hidden"===e.visibilityState?Date.now():0,token:0,subscribers:t,onVisibility:()=>{const t=oc.get(e);if(!t)return;const i=Date.now();if("hidden"===e.visibilityState){t.hiddenAt||(t.hiddenAt=i);const e={kind:"hidden",token:t.token,at:i,hiddenFor:0,long:!1};for(const i of[...t.subscribers])i(e);return}const n=t.hiddenAt?Math.max(0,i-t.hiddenAt):0;t.hiddenAt=0,t.token++;const r={kind:"visible",token:t.token,at:i,hiddenFor:n,long:n>=nc};for(const e of[...t.subscribers])e(r)},onPageShow:t=>{const i=oc.get(e);if(!i)return;const n=Date.now();i.token++;const r={kind:"pageshow",token:i.token,at:n,hiddenFor:0,long:!!t.persisted,persisted:!!t.persisted};for(const e of[...i.subscribers])e(r)}},oc.set(e,i),e.addEventListener("visibilitychange",i.onVisibility),e.defaultView?.addEventListener("pageshow",i.onPageShow)}return i.subscribers.add(t),()=>{const i=oc.get(e);i&&(i.subscribers.delete(t),i.subscribers.size||(e.removeEventListener("visibilitychange",i.onVisibility),e.defaultView?.removeEventListener("pageshow",i.onPageShow),oc.delete(e)))}}const ac={now:()=>Date.now(),setTimeout:(e,t)=>window.setTimeout(e,t),clearTimeout:e=>window.clearTimeout(e),requestAnimationFrame:e=>window.requestAnimationFrame(e),cancelAnimationFrame:e=>window.cancelAnimationFrame(e)};class lc{constructor(e,t=ac){this.onChange=e,this.clock=t,this._state="steady",this._token=0,this._frameFingerprint="",this._hasCompleteFrame=!1,this._overlayPhase="none",this._recoveryReason=null,this._overlayTimer=0,this._overlayRaf=0,this._overlayOpaqueAt=0,this._barrierRafs=new Set,this._trace=[],this._disposed=!1}get state(){return this._state}get token(){return this._token}get frameFingerprint(){return this._frameFingerprint}get hasCompleteFrame(){return this._hasCompleteFrame}get overlayPhase(){return this._overlayPhase}get overlayVisible(){return"none"!==this._overlayPhase}get overlayBlocksInteraction(){return this.overlayVisible}get recoveryReason(){return this._recoveryReason}get trace(){return this._trace.map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}note(e,t={}){this.record(e,void 0,t)}record(e,t,i={}){this._trace.push({at:this.clock.now(),token:this._token,event:e,state:this._state,...t?{reason:t}:{},...i}),this._trace.length>80&&this._trace.splice(0,this._trace.length-80)}changed(){this._disposed||this.onChange()}adoptCompleteFrame(e){e&&(this._hasCompleteFrame=!0,this._frameFingerprint=e,this._state="steady",this._recoveryReason=null,this.clearOverlay(),this.record("frame-adopted"),this.changed())}markCompleteFrame(e){e&&(this._hasCompleteFrame=!0,this._frameFingerprint=e,this._state="steady",this._recoveryReason=null,this.clearOverlay(),this.record("frame-complete"),this.changed())}refreshCompleteFrame(e){!this._disposed&&this._hasCompleteFrame&&"steady"===this._state&&e&&e!==this._frameFingerprint&&(this._frameFingerprint=e,this.record("frame-refreshed"))}visibility(e){return"hidden"===e.kind?(this.record("visibility-hidden"),this._token):e.long||"visible"!==e.kind&&"pageshow"!==e.kind?this.beginCandidate("pageshow"===e.kind?"pageshow":"long-resume"):(this.record("pageshow"===e.kind?"pageshow-noop":"visibility-visible-quick"),this._token)}beginCandidate(e,t="plan"){return this._token++,this._recoveryReason=t,this._hasCompleteFrame?(this._state="connection"===t?"offline-stale":"holding",this.clearOverlay()):this.overlayVisible?this._state="overlay-visible":(this._state="overlay-pending",this.scheduleOverlay(t)),this.record("candidate-start",e),this.changed(),this._token}connectionLost(){return this.beginCandidate("connection-lost","connection")}candidateReady(e){return!this._disposed&&e===this._token&&(this._state="candidate-ready",this.record("candidate-ready"),this.changed(),!0)}async commitAfterPaint(e,t){if(this._disposed||e!==this._token)return!1;let i=!0;const n=(async()=>{for(await t.updateComplete();i&&!this._disposed&&e===this._token;)if(t.stageValid()&&t.assetsReady()){if(await this.nextFrame(),e!==this._token||!t.stageValid()||!t.assetsReady())continue;if(await this.nextFrame(),e===this._token&&t.stageValid()&&t.assetsReady())return!0}else await this.nextFrame();return!1})();let r=0;const o=new Promise(e=>{r=this.clock.setTimeout(()=>e({ready:!1,timedOut:!0}),rc)}),s=await Promise.race([n.then(e=>({ready:e,timedOut:!1})),o]);return i=!1,this.clock.clearTimeout(r),!this._disposed&&e===this._token&&(!(!s.ready&&!s.timedOut)&&(s.ready?(this._hasCompleteFrame=!0,this._frameFingerprint=t.frameFingerprint(),this.record("paint-barrier"),this.finishOverlayAfterCommit(),!0):(this.record("paint-barrier-timeout"),this._hasCompleteFrame?(this._state="connection"===this._recoveryReason?"offline-stale":"steady",this.clearOverlay()):(this._state="recovery-error","opaque"!==this._overlayPhase&&this.showOverlayNow()),this.changed(),!1)))}retry(e=this._recoveryReason||"plan"){return this.beginCandidate("retry",e)}nextFrame(){return new Promise(e=>{const t=this.clock.requestAnimationFrame(()=>{this._barrierRafs.delete(t),e()});this._barrierRafs.add(t)})}scheduleOverlay(e){this.clearOverlayTimer(),this._recoveryReason=e,this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._hasCompleteFrame||"overlay-pending"!==this._state&&"candidate-ready"!==this._state||(this._state="overlay-visible",this._overlayPhase="entering",this.record("overlay-enter"),this.changed(),this._overlayRaf=this.clock.requestAnimationFrame(()=>{this._overlayRaf=0,"entering"===this._overlayPhase&&(this._overlayPhase="fading-in",this.changed(),this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,"fading-in"===this._overlayPhase&&(this._overlayPhase="opaque",this._overlayOpaqueAt=this.clock.now(),this.record("overlay-opaque"),this.changed())},150))}))},150)}showOverlayNow(){this.clearOverlayTimer(),this._overlayPhase="opaque",this._overlayOpaqueAt=this.clock.now(),this.record("overlay-error")}finishOverlayAfterCommit(){if(this.clearOverlayTimer(),"none"===this._overlayPhase||"entering"===this._overlayPhase||"fading-in"===this._overlayPhase)return this.clearOverlay(),this._state="steady",this._recoveryReason=null,this.record("candidate-committed"),void this.changed();const e=Math.max(0,this._overlayOpaqueAt+250-this.clock.now());this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._overlayPhase="leaving",this.record("overlay-leave"),this.changed(),this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._overlayPhase="none",this._state="steady",this._recoveryReason=null,this.record("candidate-committed"),this.changed()},180)},e)}clearOverlayTimer(){this._overlayTimer&&this.clock.clearTimeout(this._overlayTimer),this._overlayTimer=0}clearOverlay(){this.clearOverlayTimer(),this._overlayRaf&&this.clock.cancelAnimationFrame(this._overlayRaf),this._overlayRaf=0,this._overlayPhase="none",this._overlayOpaqueAt=0}dispose(){this._disposed=!0,this._token++,this.clearOverlay();for(const e of this._barrierRafs)this.clock.cancelAnimationFrame(e);this._barrierRafs.clear()}}function cc(e){let t=2166136261,i=2654435769;const n=new WeakSet,r=e=>{for(let n=0;n>>0)+(i>>>2)}},o=e=>{if(null===e)return void r("n");const t=typeof e;if("string"===t)return void r(`s${e.length}:${e}`);if("number"===t)return void r(`d${Number.isNaN(e)?"NaN":String(e)}`);if("boolean"===t)return void r(e?"t":"f");if("undefined"===t)return void r("u");if("object"!==t)return void r(`${t}:${String(e)}`);const i=e;if(n.has(i))r("[cycle]");else{if(n.add(i),Array.isArray(e)){r("[");for(const t of e)o(t);return r("]"),void n.delete(i)}r("{");for(const t of Object.keys(e).sort())r(t),o(e[t]);r("}"),n.delete(i)}};return o(e),`${(t>>>0).toString(16).padStart(8,"0")}${(i>>>0).toString(16).padStart(8,"0")}`}function hc(e){return cc(e)}const dc=new WeakMap;class uc{constructor(e,t=()=>Date.now()){this.onUpdate=e,this.now=t,this.fallbackAuthority={},this.referenceOwner={},this.referenced=new Set,this.queued=new Set,this.disposed=!1,this.sharedUpdate=()=>{this.disposed||this.onUpdate()}}bind(e){const t=((e,t)=>{const i=e?.connection||e?.callWS||t;return!i||"object"!=typeof i&&"function"!=typeof i?t:i})(e,this.fallbackAuthority);return this.shared&&this.authority===t||(this.shared&&(this.shared.listeners.delete(this.sharedUpdate),this.shared.references.delete(this.referenceOwner)),this.authority=t,this.shared=(e=>{let t=dc.get(e);return t||(t={signed:{},queued:new Set,inFlight:new Map,retry:new Map,listeners:new Set,settlers:new Set,references:new Map},dc.set(e,t)),t})(t),this.disposed||(this.shared.listeners.add(this.sharedUpdate),this.shared.references.set(this.referenceOwner,new Set(this.referenced)))),this.shared}start(e,t){this.disposed=!1,this.referenced=new Set(t());const i=this.bind(e());i.listeners.add(this.sharedUpdate),i.references.set(this.referenceOwner,new Set(this.referenced)),this.stopTimer(),this.resignTimer=setInterval(()=>this.resign(e(),t()),288e5)}dispose(){if(this.disposed=!0,this.stopTimer(),clearTimeout(this.batchTimer),this.shared){this.shared.listeners.delete(this.sharedUpdate),this.shared.references.delete(this.referenceOwner);for(const e of this.queued)this.shared.queued.delete(e)}this.queued.clear()}invalidate(e){const t=this.bind(e);clearTimeout(this.batchTimer),this.queued.clear(),t.queued.clear(),t.inFlight.clear(),t.retry.clear(),t.signed={}}stopTimer(){void 0!==this.resignTimer&&clearInterval(this.resignTimer),this.resignTimer=void 0}display(e,t){const i=Hn(t);if(!i.startsWith("/api/houseplan/content/"))return i;const n=this.bind(e);this.referenced.add(i),n.references.set(this.referenceOwner,new Set(this.referenced));const r=n.signed[i],o=r?this.now()-r.at:1/0;return o{const t=[...this.queued];this.queued.clear();for(const e of t)i.queued.delete(e);this.sign(e,t)},30))}sign(e,t){if(!t.length||!e?.callWS)return;const i=this.bind(e);for(const n of function(e,t){const i=Math.max(1,Math.floor(t)),n=[];for(let t=0;t{const n=i.inFlight.get(e);return!(void 0!==n&&t-n<15e3)&&(i.inFlight.set(e,t),!0)});r.length&&e.callWS({type:"houseplan/content/sign",paths:r}).then(e=>{const t=this.now();let n=0,o=!1;for(const s of r){const r=e?.urls?.[s];if("string"==typeof r&&r){const e=i.signed[s];e?.loaded&&e.url!==r?(e.pending={url:r,at:t},this.preloadReplacement(i,s,r,t)):(i.signed[s]={url:r,at:t,loaded:e?.url===r&&!!e.loaded},o=!0),i.retry.delete(s),n++}else this.backOff(i,s)}if(n&&(this.trimShared(i),o))for(const e of[...i.listeners])e()}).catch(()=>{for(const e of r)this.backOff(i,e)}).finally(()=>{for(const e of r)i.inFlight.get(e)===t&&i.inFlight.delete(e);for(const e of[...i.settlers])e()})}}preloadReplacement(e,t,i,n){const r=()=>{const r=e.signed[t];if(r?.pending?.url===i){e.signed[t]={url:i,at:n,loaded:!0},e.retry.delete(t),this.trimShared(e);for(const t of[...e.listeners])t()}},o=()=>{const n=e.signed[t];n?.pending?.url===i&&(delete n.pending,this.backOff(e,t))};if("undefined"==typeof Image)return void r();const s=new Image;s.onload=()=>{("function"==typeof s.decode?s.decode():Promise.resolve()).then(r).catch(o)},s.onerror=o,s.src=i}preloadCurrentImage(e,t,i){if(i.loaded)return Promise.resolve(!0);if(i.preload)return i.preload;if("undefined"==typeof Image)return i.loaded=!0,Promise.resolve(!0);const n=i.url;return i.preload=new Promise(r=>{const o=new Image;let s=!1;const a=o=>{if(s)return;s=!0,clearTimeout(l);const a=e.signed[t];if(a===i&&delete a.preload,o&&a===i&&a.url===n){a.loaded=!0;for(const t of[...e.listeners])t();r(!0)}else o||a!==i||this.backOff(e,t),r(!1)};o.onload=()=>{("function"==typeof o.decode?o.decode():Promise.resolve()).then(()=>a(!0)).catch(()=>a(!1))},o.onerror=()=>a(!1);const l=setTimeout(()=>a(!1),rc);o.src=n}),i.preload}prepareImage(e,t){const i=Hn(t);if(!i.startsWith("/api/houseplan/content/"))return Promise.resolve(!0);const n=this.bind(e),r=()=>{const t=n.signed[i];if(t&&this.now()-t.atthis.now()&&!n.inFlight.has(i)&&!n.queued.has(i)?Promise.resolve(!1):null},o=r();return o?(s=o,new Promise(e=>{let t=!1;const i=i=>{t||(t=!0,clearTimeout(n),e(i))},n=setTimeout(()=>i(!1),rc);s.then(i).catch(()=>i(!1))})):new Promise(e=>{let t=!1,i=null;const o=i=>{t||(t=!0,clearTimeout(a),n.settlers.delete(s),e(i))},s=()=>{t||i||(i=r(),i&&i.then(o).catch(()=>o(!1)))},a=setTimeout(()=>o(!1),rc);n.settlers.add(s),s()});var s}backOff(e,t){const i=e.retry.get(t)?.delay||0,n=Math.min(6e4,i?2*i:2e3);e.retry.set(t,{notBefore:this.now()+n,delay:n})}trimShared(e){const t=Object.entries(e.signed);if(t.length<=512)return;const i=new Set(e.inFlight.keys());for(const t of e.references.values())for(const e of t)i.add(e);for(const[e,n]of t)(n.pending||n.preload)&&i.add(e);t.sort((e,t)=>t[1].at-e[1].at);const n=t.filter(([e])=>i.has(e));for(const e of t){if(n.length>=512)break;i.has(e[0])||n.push(e)}e.signed=Object.fromEntries(n)}resign(e,t){const i=this.bind(e);this.referenced=new Set(t),i.references.set(this.referenceOwner,new Set(this.referenced));const n=this.now(),r=new Set;for(const e of i.references.values())for(const t of e)r.add(t);const o={};for(const[e,t]of Object.entries(i.signed))r.has(e)&&n-t.at!!o[e]&&!o[e].pending))}markLoaded(e,t,i){const n=Hn(t);if(!n.startsWith("/api/houseplan/content/"))return;const r=this.bind(e).signed[n];if(r&&(!i||r.url===i)&&!r.loaded){r.loaded=!0;for(const t of[...this.bind(e).listeners])t()}}isReady(e,t){const i=Hn(t);if(!i.startsWith("/api/houseplan/content/"))return!0;const n=this.bind(e).signed[i];return!!n&&this.now()-n.at=2&&(this._sequenceMultitouch=!0,this._postGestureClickBlocked=!0))}pointerTerminal(e,t){if("touch"!==t)return!1;const i=this._sequenceMultitouch;return this._activeTouchPointers.delete(e),0===this._activeTouchPointers.size&&(this._sequenceMultitouch=!1),i}reset(){this._activeTouchPointers.clear(),this._sequenceMultitouch=!1,this._postGestureClickBlocked=!1}}const _c=1e-7,mc=(e,t)=>{const i=e.x-t.x,n=e.y-t.y;return i*i+n*n};function gc(e){const t=Math.max(0,e.floorRadius);return{left:Math.min(e.painted.left,e.center.x-t),top:Math.min(e.painted.top,e.center.y-t),right:Math.max(e.painted.right,e.center.x+t),bottom:Math.max(e.painted.bottom,e.center.y+t)}}function fc(e,t){let i=null,n=Number.POSITIVE_INFINITY;for(const r of e){const e=mc(t,r.center);(efunction(e,t){const i=Math.max(0,t.right-t.left),n=Math.max(0,t.bottom-t.top);if(i<=0||n<=0)return!1;const r=Math.min(i,n)/2,o=Math.max(t.left+r,Math.min(t.right-r,e.x)),s=Math.max(t.top+r,Math.min(t.bottom-r,e.y));return mc(e,{x:o,y:s})<=r*r+_c}(t,e.painted));if(i.length)return fc(i,t);return fc(e.filter(e=>{const i=Math.max(0,e.floorRadius);return mc(t,e.center)<=i*i+_c}),t)}class yc{constructor(e,t=44){this.cellSize=t,this.buckets=new Map;const i=Number.isFinite(t)&&t>0?t:44;this.cellSize=i;for(const t of e){const e=gc(t),n=Math.floor(e.left/i),r=Math.floor(e.right/i),o=Math.floor(e.top/i),s=Math.floor(e.bottom/i);for(let e=n;e<=r;e++)for(let i=o;i<=s;i++){const n=`${e}:${i}`,r=this.buckets.get(n);r?r.push(t):this.buckets.set(n,[t])}}}resolve(e){const t=`${Math.floor(e.x/this.cellSize)}:${Math.floor(e.y/this.cellSize)}`;return vc(this.buckets.get(t)||[],e)}}class bc{constructor(){this.active=new Map,this.released=new Map}begin(e,t){this.released.delete(e),this.active.set(e,t)}owner(e){return this.active.get(e)||null}release(e){const t=this.active.get(e)||null;if(!t)return this.released.get(e)||null;for(this.active.delete(e),this.released.set(e,t);this.released.size>16;){const e=this.released.keys().next().value;if(void 0===e)break;this.released.delete(e)}return t}consumeClick(e){const t=this.released.get(e)||null;return this.released.delete(e),t}cancel(e){const t=this.active.get(e)||null;return this.active.delete(e),t}clear(){this.active.clear(),this.released.clear()}}class wc{constructor(){this.index=null,this.pointers=new bc,this.hoverId=null,this.hoverElement=null}invalidate(){this.index=null}reset(e){this.invalidate(),this.pointers.clear(),this.hover(e,null)}clearPointers(){this.pointers.clear()}cancel(e){return this.pointers.cancel(e)}release(e){return this.pointers.release(e)}indexFor(e){if(this.index)return this.index;const t=[];for(const i of e.querySelectorAll('.devlayer > .dev[data-hp="device"][data-id]')){const e=i.querySelector(".device-shell-frame"),n=i.getBoundingClientRect(),r=e?.getBoundingClientRect();!i.dataset.id||!i.isConnected||!r||n.width<=0||n.height<=0||r.width<=0||r.height<=0||t.push({id:i.dataset.id,center:{x:n.left+n.width/2,y:n.top+n.height/2},painted:{left:r.left,top:r.top,right:r.right,bottom:r.bottom},floorRadius:Math.max(22,Math.min(r.width,r.height)/2)})}return this.index=new yc(t),this.index}at(e,t,i,n,r){const o=this.indexFor(e).resolve({x:n,y:r})?.id;return o&&t.find(e=>e.id===o&&e.space===i)||null}byId(e,t,i){return i&&e.find(e=>e.id===i&&e.space===t)||null}begin(e,t,i,n,r){const o=this.at(e,t,i,n.clientX,n.clientY)||r;return this.pointers.begin(n.pointerId,o.id),o}pointer(e,t,i,n,r){const o=n.pointerId;return(Number.isFinite(o)?this.byId(t,i,this.pointers.owner(o)):null)||this.at(e,t,i,n.clientX,n.clientY)||r}click(e,t,i,n,r){if(!(n instanceof PointerEvent))return r;const o=n,s=Number.isFinite(o.pointerId)?this.pointers.consumeClick(o.pointerId):null;return this.byId(t,i,s)||this.at(e,t,i,o.clientX,o.clientY)||r}hover(e,t){this.hoverId===t&&this.hoverElement?.isConnected||(this.hoverElement?.removeAttribute("data-hp-device-hover"),this.hoverId=t,this.hoverElement=t&&[...e.querySelectorAll('.devlayer > .dev[data-hp="device"][data-id]')].find(e=>e.dataset.id===t)||null,this.hoverElement?.setAttribute("data-hp-device-hover",""))}}function kc(e,t){if(t)return e.find(e=>e.id===t)}function xc(e,t){return{id:e,title:t,plan_url:null,view_box:[0,0,1,1],rooms:[],wall_segments:[]}}function Sc(e="file"){const t="draw"===e;return{source:e,showBorders:t,showNames:t,displayTouched:!1}}function $c(e,t){if(e.displayTouched)return{...e,source:t};const i="draw"===t;return{...e,source:t,showBorders:i,showNames:i}}function Mc(e,t,i){return{...e,[t]:i,displayTouched:!0}}function Rc(e){const t=String(e??"").trim().replace(",",".");if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(t))return null;const i=Number(t);return Number.isFinite(i)?i:null}function Cc(e,t){const i=e=>{if(""===String(e??"").trim())return{valid:!0,value:null};const t=Rc(e);return{valid:null!==t,value:t}},n=i(e),r=i(t);return n.valid&&r.valid?null!==n.value&&null!==r.value&&n.value>r.value?{valid:!0,min:r.value,max:n.value}:{valid:!0,min:n.value,max:r.value}:{valid:!1,min:n.value,max:r.value}}function Tc(e,t,i,n,r,o){const s=Cc(n,r);return pn(e,t,o&&s.valid?{settings:{...i.settings||{},temp_min:s.min,temp_max:s.max}}:i)}function Dc(e){const t=e=>"number"==typeof e&&Number.isFinite(e)?String(e):"";return[t(e?.temp_min),t(e?.temp_max)]}function Ac(e,t,i){const n=Cc(t,i);return!!n.valid&&(null===n.min?delete e.temp_min:e.temp_min=n.min,null===n.max?delete e.temp_max:e.temp_max=n.max,!0)}var Pc="M11,18H13V16H11V18M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,6A4,4 0 0,0 8,10H10A2,2 0 0,1 12,8A2,2 0 0,1 14,10C14,12 11,11.75 11,15H13C13,12.75 16,12.5 16,10A4,4 0 0,0 12,6Z";function Fc(e,t,i){return[e[0]*t+e[1]*i+e[2],e[3]*t+e[4]*i+e[5]]}function zc(e,t){let i=0;for(const[n,r]of t){const t=Fc(e,n[0],n[1]);i=Math.max(i,Math.hypot(t[0]-r[0],t[1]-r[1]))}return i}const Ic=e=>{if(null==e||""===e)return null;const t=Number(e);return Number.isFinite(t)?t:null},Oc=e=>{const t=e,i=Ic(Array.isArray(t)?t[0]:t?.x),n=Ic(Array.isArray(t)?t[1]:t?.y);return null==i||null==n?null:[i,n]};function Ec(e){if(!Array.isArray(e))return null;const t=[];for(const i of e){const e=Oc(i);if(!e)return null;t.push(e)}if(t.length>1){const e=t[0],i=t[t.length-1];e[0]===i[0]&&e[1]===i[1]&&t.pop()}if(t.length<3)return null;let i=0,n=0,r=0;for(let e=0;ee+t[0],0)/t.length,t.reduce((e,t)=>e+t[1],0)/t.length]:[n/(3*i),r/(3*i)]}function Nc(e){if(!Array.isArray(e))return null;const t=[];for(const i of e){const e=Oc(i);if(!e)return null;t.push(e)}if(t.length>1){const e=t[0],i=t[t.length-1];e[0]===i[0]&&e[1]===i[1]&&t.pop()}const i=Ec(t);if(!i)return null;const n=t.map(e=>e[0]),r=t.map(e=>e[1]);return{centroid:i,bbox:[Math.min(...n),Math.min(...r),Math.max(...n),Math.max(...r)]}}function Hc(e){let t=e;if(t&&"object"==typeof t&&!Array.isArray(t)){const e=t;t=e.path??e.points??t}if(!Array.isArray(t)||!t.length)return[];let i=(t.some(e=>(e=>Array.isArray(e)?e.length>=2&&!Array.isArray(e[0])&&("object"!=typeof e[0]||null==e[0]):!!e&&"object"==typeof e&&("x"in e||"y"in e))(e))?[t]:t.filter(Array.isArray)).map(e=>e.map(Oc).filter(e=>null!=e)).filter(e=>e.length>=2);i.length>64&&(i=i.slice(-64));const n=i.reduce((e,t)=>e+t.length,0);if(n<=4e3)return i.map(e=>e.slice());const r=4e3-2*i.length,o=i.map(e=>e.length-2),s=o.reduce((e,t)=>e+t,0),a=o.map(e=>r*e/s),l=a.map(Math.floor);let c=r-l.reduce((e,t)=>e+t,0);const h=a.map((e,t)=>({index:t,fraction:e-Math.floor(e)})).sort((e,t)=>t.fraction-e.fraction||e.index-t.index);for(let e=0;efunction(e,t){if(t>=e.length)return e.slice();if(t<=2)return[e[0],e[e.length-1]];const i=[];for(let n=0;ne.slice()),i=t[t.length-1];return i?(i.length>2?i.pop():t.pop(),t):[]}const qc=e=>Number.isFinite(e[0])&&Number.isFinite(e[1]),jc=(e,t)=>e[0]===t[0]&&e[1]===t[1];function Wc(e){if(!e)return null;const t=e.vacuum_position||e.robot_position||null,i=t&&null!=Ic(t.x)&&null!=Ic(t.y)?{x:Ic(t.x),y:Ic(t.y),a:Ic(t.a??t.angle??t.theta)}:null,n=Hc(e.path?.path??e.path?.points??e.path),r=[],o=e.rooms,s=Array.isArray(o)?o.map((e,t)=>[String(e?.id??t),e]):o&&"object"==typeof o?Object.entries(o):[];for(const[e,t]of s){if(!t||"object"!=typeof t)continue;const i=String(t.name??t.label??"").trim(),n=[[Ic(t.cx),Ic(t.cy)],[Ic(t.center?.x),Ic(t.center?.y)],[Ic(t.x),Ic(t.y)]].find(([e,t])=>null!=e&&null!=t);let o=n?.[0]??null,s=n?.[1]??null;const a=Nc(t.outline),l=Ic(t.x0),c=Ic(t.y0),h=Ic(t.x1),d=Ic(t.y1),u=(null!=l&&null!=c&&null!=h&&null!=d?[Math.min(l,h),Math.min(c,d),Math.max(l,h),Math.max(c,d)]:null)||a?.bbox||null;if(null!=o&&null!=s||!a||([o,s]=a.centroid),null!=o&&null!=s||!u||(o=(u[0]+u[2])/2,s=(u[1]+u[3])/2),i&&null!=o&&null!=s){const t={id:e,name:i,cx:o,cy:s};u&&([t.x0,t.y0,t.x1,t.y1]=u),r.push(t)}}const a=function(e){return String(e.map_name??e.current_map??e.map_index??e.selected_map??"default")}(e);return i||r.length||n.length?{pos:i,path:n,rooms:r,mapId:a}:null}function Uc(e,t,i){return![e,t,i].every(Number.isFinite)||e<0||t<=0||i<=0?Number.POSITIVE_INFINITY:e/t*i}const Gc=40;function Vc(e,t,i){if(!e||!t)return null;const n=t.attributes||{},r=e.split(".")[0]||"",o=null!=i?.platform?String(i.platform):null,s=!!Oc(n.vacuum_position??n.robot_position),a=!(!n.rooms||"object"!=typeof n.rooms),l=Hc(n.path?.path??n.path?.points??n.path).length>0,c=[n.map_name,n.current_map,n.map_index,n.selected_map].some(e=>null!=e),h="xiaomi_cloud_map_extractor"===o,d=a||l||c;let u=null;if(s?u="compatible":h?u="known_xcme_incomplete":d?u="partial":"camera"===r&&(u="camera"),!u)return null;const p=s?"camera"===r?300:200:h?100:d?50:0;return{entityId:e,name:String(n.friendly_name||e),platform:o,category:u,hasPosition:s,hasRooms:a,hasPath:l,hasMapId:c,score:p}}const Kc=e=>e.toLowerCase().replace(/[\s_\-.,]+/g,"");function Yc(e,t){const i=new Set(t.map(Kc).filter(Boolean)),n=new Set;for(const t of e){const e=Kc(t.name||"");e&&i.has(e)&&n.add(e)}return n.size}function Xc(e,t){const i=new Map(t.map(e=>[Kc(e.name),e])),n=[],r=[];for(const t of e){const e=i.get(Kc(t.name));e&&(n.push([[t.cx,t.cy],[e.cx,e.cy]]),r.push(t.name))}if(n.length<3)return null;const o=function(e){if(e.length<3)return null;let t=0,i=0,n=0,r=0,o=0,s=0,a=0,l=0,c=0,h=0,d=0,u=0;for(const[[p,_],[m,g]]of e){if(![p,_,m,g].every(Number.isFinite))return null;t+=p*p,i+=p*_,n+=p,r+=_*_,o+=_,s+=1,a+=p*m,l+=_*m,c+=m,h+=p*g,d+=_*g,u+=g}const p=[t,i,n,i,r,o,n,o,s],_=e=>{const[t,i,n,r,o,s,a,l,c]=p,h=t*(o*c-s*l)-i*(r*c-s*a)+n*(r*l-o*a);if(!Number.isFinite(h)||Math.abs(h)<1e-9)return null;const d=[(o*c-s*l)/h,(n*l-i*c)/h,(i*s-n*o)/h,(s*a-r*c)/h,(t*c-n*a)/h,(n*r-t*s)/h,(r*l-o*a)/h,(i*a-t*l)/h,(t*o-i*r)/h];return[d[0]*e[0]+d[1]*e[1]+d[2]*e[2],d[3]*e[0]+d[4]*e[1]+d[5]*e[2],d[6]*e[0]+d[7]*e[1]+d[8]*e[2]]},m=_([a,l,c]),g=_([h,d,u]);if(!m||!g)return null;const f=[m[0],m[1],m[2],g[0],g[1],g[2]];return f.every(Number.isFinite)?f:null}(n);return o?{matrix:o,matched:r,residual:zc(o,n)}:null}function Zc(e,t,i){const n=e[e.length-1];if(n&&n[0]===t[0]&&n[1]===t[1])return e;if(e.push(t),e.length<=600)return e;let r=function(e,t){if(e.length<3)return e.slice();const i=new Uint8Array(e.length);i[0]=i[e.length-1]=1;const n=[[0,e.length-1]];for(;n.length;){const[r,o]=n.pop(),[s,a]=e[r],[l,c]=e[o],h=l-s,d=c-a,u=Math.hypot(h,d)||1e-9;let p=0,_=-1;for(let t=r+1;tp&&(p=i,_=t)}_>0&&p>t&&(i[_]=1,n.push([r,_],[_,o]))}const r=[];for(let t=0;t600&&(r=r.filter((e,t)=>t%2==0||t===r.length-1)),r}function Jc(e){return"cleaning"===e||"returning"===e||"on"===e}const Qc={0:[1,0],90:[0,1],180:[-1,0],270:[0,-1]};function eh(e){const[t,i]=Qc[e.rot]||[1,0],n=e.mir?-1:1;return[e.s*t*n,-e.s*i,e.ox,e.s*i*n,e.s*t,e.oy]}function th(e){const t=e[0]*e[4]-e[1]*e[3];if(!Number.isFinite(t)||Math.abs(t)<1e-12)return null;const i=t<0,n=Math.sqrt(Math.abs(t));let r=180*Math.atan2(-e[1],e[4])/Math.PI;return r=(90*Math.round(r/90)%360+360)%360,{ox:e[2],oy:e[5],s:n,rot:r,mir:i}}function ih(e,t){const i=[],n=[];for(const t of e)null!=t.x0?(i.push(t.x0,t.x1),n.push(t.y0,t.y1)):(i.push(t.cx),n.push(t.cy));if(!i.length)return{ox:t[0]+t[2]/2,oy:t[1]+t[3]/2,s:t[2]/1e4,rot:0,mir:!0};const r=Math.min(...i),o=Math.max(...i),s=Math.min(...n),a=Math.max(...n),l=Math.max(o-r,a-s)||1,c={ox:0,oy:0,s:.6*Math.min(t[2],t[3])/l,rot:0,mir:!0},h=eh(c),[d,u]=Fc(h,(r+o)/2,(s+a)/2);return c.ox=t[0]+t[2]/2-d,c.oy=t[1]+t[3]/2-u,c}function nh(e,t,i,n){const[r,o]=Fc(eh(t),i,n),s=eh({...e,ox:0,oy:0}),[a,l]=Fc(s,i,n);return{...e,ox:r-a,oy:o-l}}function rh(e){const t=e?.trail_mode;return"never"===t||"cleaning"===t||"always"===t?t:!1===e?.trail?"never":"cleaning"}const oh=e=>"number"==typeof e&&Number.isFinite(e);function sh(e){return Array.isArray(e)&&6===e.length&&e.every(oh)?[e[0],e[1],e[2],e[3],e[4],e[5]]:null}function ah(e,t,i){return"legacy:"+e+" "+t+" "+i}function lh(e,t,i,n){const r=t?.map_routes;if(Array.isArray(r))return r.filter(e=>e&&"string"==typeof e.id&&e.id).map(e=>({id:e.id,source:String(e.source??""),map_id:String(e.map_id??""),space:String(e.space??""),calibration:sh(e.calibration)}));const o="string"==typeof t?.source&&t.source?t.source:n||"";if(!o)return[];const s=t?.calibration;if(!s||"object"!=typeof s)return[];const a=[];for(const t of Object.keys(s)){const n=sh(s[t]);n&&a.push({id:ah(e,o,t),source:o,map_id:t,space:i,calibration:n})}return a}const ch=(e,t)=>e instanceof Map?e.get(t):e?.[t];function hh(e){const t=[];let i=!1,n="",r="";for(const o of e.routes){const s=ch(e.observed,o.source);void 0!==s&&(i=!0,n||(n=o.source,r=s),s===o.map_id&&t.push(o))}if(t.length>1)return{kind:"ambiguous",routeIds:t.map(e=>e.id).sort()};if(1===t.length){const i=t[0];if(e.spaceIds&&!e.spaceIds.has(i.space))return{kind:"missing_space",route:i};const n=sh(i.calibration);return n?{kind:"ready",route:{...i,calibration:n}}:{kind:"needs_calibration",route:i}}if(i)return{kind:"unmapped",source:n,mapId:r};const o=e.observed instanceof Map?[...e.observed.entries()]:Object.entries(e.observed||{});if(o.length){const e=o.slice().sort((e,t)=>e[0].localeCompare(t[0]))[0];return{kind:"unmapped",source:e[0],mapId:e[1]}}return{kind:"none"}}function dh(e,t,i){const n=new Set;for(const t of e)t.source&&n.add(t.source);for(const e of t)e&&n.add(e);const r={};for(const e of[...n].sort()){const t=i(e);void 0!==t&&(r[e]=t)}return r}function uh(e,t,i){if(!e)return null;const n="string"==typeof e.route_id?e.route_id:"";if(n)return t.find(e=>e.id===n)||null;const r=function(e,t,i){if(!e||"string"!=typeof e.map_id)return{kind:"orphan_run"};const n=e.map_id,r="string"==typeof i?i:"";let o=t.filter(e=>e.map_id===n);return r&&(o=o.filter(e=>e.source===r)),1===o.length?{kind:"adopted",route:o[0]}:0===o.length?{kind:"orphan_run"}:{kind:"ambiguous_run",routeIds:o.map(e=>e.id).sort()}}(e,t,i);return"adopted"===r.kind?r.route:null}function ph(e){const t="ready"===e.resolution.kind?e.resolution.route:null,i=t&&t.space===e.renderSpace?sh(t.calibration):null,n=uh(e.serverCurrent,e.routes,e.rootSource),r=!!t&&!!n&&n.id===t.id,o=uh(e.serverPrevious,e.routes,e.rootSource);return{live:i,currentRunMatches:r,previous:!!o&&o.space===e.renderSpace&&(e.explicitRoutes||!!t&&o.id===t.id)?sh(o.calibration):null}}const _h={availability:"available",status:"alarm",activity:"none"},mh=new Set(["motion","vibration","sound"]),gh=new Set(["occupancy","presence"]),fh=new Set(["door","window","garage_door","opening"]),vh=new Set(["running","power"]),yh=new Set(["smoke","gas","carbon_monoxide","moisture","safety","tamper","problem"]);const bh=new Set(["running","working","washing","rinsing","spinning","drying","heating","cooling","cleaning","cooking","playing","recording","pumping","irrigating","humidifying","dehumidifying","fan","preheating","defrosting"]),wh=new Set([...bh,"start","started","run","active","in_progress","wash","rinse","spin","dry"]),kh=new Set(["off","idle","paused","standby","docked","finished","complete","completed","stopped","ready","sleeping","stop","end","done","inactive"]),xh=new Set(["heat","cool","heat_cool","auto","dry","fan_only"]),Sh=e=>""===e||"unknown"===e||"unavailable"===e||"__missing__"===e,$h=e=>String(e??"").trim().toLowerCase(),Mh=e=>$h(e).replace(/[\s-]+/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,""),Rh=new Map([["run_state",0],["job_state",0],["operation_state",0],["activity_state",0],["machine_state",1],["running_state",1],["status",2],["device_status",2],["machine_status",2]]),Ch=new Set(["wifi","connection","signal","battery"]);function Th(e,t){const i=e?.entities?.[t]||{};if("config"===i.entity_category)return null;const n=String(t||"").split(".").slice(1).join("."),r=[i.translation_key,i.original_name,i.name],o=[...r,n];r.some(e=>$h(e))||o.push(e?.states?.[t]?.attributes?.friendly_name);const s=o.map(Mh).filter(Boolean);if(s.some(e=>e.split("_").some(e=>Ch.has(e))))return null;let a=null;for(const e of s)for(const[t,i]of Rh)(e===t||e.endsWith(`_${t}`))&&(a=null==a?i:Math.min(a,i));return a}const Dh=(e,t)=>null!=Th(e,t);function Ah(e,t){if(!t.startsWith("switch."))return!1;const i=e?.entities?.[t]||{},n=e?.states?.[t],r=t.slice(7).toLowerCase();if(/(?:^|_)(?:main_)?power$/.test(r))return!0;if([i.translation_key,i.original_name,i.name].map($h).some(e=>["power","main power","power switch","питание"].includes(e)))return!0;const o=$h(n?.attributes?.friendly_name);return/(?:^|[\s._-])(?:main[\s._-]+)?power$/.test(o)||/(?:^|[\s._-])питание$/.test(o)}function Ph(e){for(const t of["hvac_action","action","current_operation","run_state","job_state","operation","activity"]){const i=$h(e?.[t]);if(bh.has(i)||kh.has(i))return i}return""}function Fh(e,t){const i=e?.states?.[t],n=i?$h(i.state):"__missing__",r=String(t||"").split(".")[0],o=$h(i?.attributes?.device_class),s={eid:t,state:n,availability:Sh(n)?"unavailable":"available",status:"neutral",activity:"none",edge:"none"};if("unavailable"===s.availability)return s;if(function(e,t,i){return"alarm_control_panel"===e?"triggered"===i:"on"===i&&Yn(e,t)}(r,o,n))return{...s,status:"alarm"};if("binary_sensor"===r)return mh.has(o)?{...s,edge:"rising"}:gh.has(o)?{...s,activity:"on"===n?"presence":"none"}:fh.has(o)?{...s,status:"on"===n?"open":"neutral",edge:"rising"}:"moving"===o?{...s,activity:"on"===n?"transition":"none"}:vh.has(o)&&"on"===n?{...s,status:"working",activity:"running"}:s;if("cover"===r)return{...s,activity:"opening"===n||"closing"===n?"transition":"none",edge:"terminal_transition"};if("lock"===r)return{...s,status:"unlocked"===n||"open"===n?"open":"neutral",activity:"locking"===n||"unlocking"===n?"transition":"none",edge:"terminal_transition"};if("valve"===r)return{...s,status:["open","opening","closing"].includes(n)?"open":"neutral",activity:"opening"===n||"closing"===n?"transition":"none",edge:"terminal_transition"};if("climate"===r){const e=Ph(i.attributes),t=Array.isArray(i.attributes?.hvac_modes)?i.attributes.hvac_modes.map($h):[],r=!kh.has(n)&&(xh.has(n)||bh.has(n)||t.includes(n));return(e?bh.has(e):r)?{...s,status:"working",activity:"running"}:s}if(["light","switch","fan","humidifier"].includes(r))return"on"===n?{...s,status:"working",activity:"running"}:s;if("media_player"===r)return"off"===n?{...s,availability:"unavailable"}:s;if("vacuum"===r)return"cleaning"===n?{...s,status:"working",activity:"running"}:"returning"===n?{...s,status:"working",activity:"transition"}:s;if("script"===r)return"on"===n?{...s,status:"working",activity:"running"}:s;if("automation"===r)return s;if("button"===r||"event"===r)return{...s,edge:"change"};const a=Ph(i.attributes);return bh.has(a)||bh.has(n)&&!kh.has(n)?{...s,status:"working",activity:"running"}:s}function zh(e,t,i){const n=i.filter(t=>t.startsWith("switch.")&&!e?.entities?.[t]?.entity_category),r=t.find(t=>Ah(e,t));if(!(n.length>1&&!!r))return t.map(t=>Fh(e,t));const o=t.find(t=>t!==r&&Dh(e,t)),s=Fh(e,r);return"unavailable"===s.availability||"off"===s.state?t.map(t=>({eid:t,state:e?.states?.[t]?$h(e.states[t].state):"__missing__",availability:"unavailable",status:"neutral",activity:"none",edge:"none"})):t.map(t=>{if(t===o)return function(e,t){const i=e?.states?.[t],n=i?$h(i.state):"__missing__",r={eid:t,state:n,availability:Sh(n)?"unavailable":"available",status:"neutral",activity:"none",edge:"none"};if("unavailable"===r.availability)return r;const o=Ph(i?.attributes);return bh.has(o)||wh.has(n)&&!kh.has(n)?{...r,status:"working",activity:"running"}:r}(e,t);return{...t===r?s:Fh(e,t),status:"neutral",activity:"none",edge:"none"}})}function Ih(e){if(!e.length)return{availability:"available",status:"neutral",activity:"none"};const t=e.filter(e=>"available"===e.availability);if(!t.length)return{availability:"unavailable",status:"neutral",activity:"none"};if(t.some(e=>"alarm"===e.status))return _h;const i=t.some(e=>"working"===e.status)?"working":t.some(e=>"open"===e.status)?"open":"neutral",n=t.some(e=>"transition"===e.activity)?"transition":t.some(e=>"presence"===e.activity)?"presence":t.some(e=>"running"===e.activity)?"running":"none";return{availability:"available",status:i,activity:n}}function Oh(e,t){if(!(e=>!!e&&!Sh(e))(e)||"unavailable"===t.availability||e===t.state)return null;if("rising"===t.edge)return"off"===e&&"on"===t.state?"event":null;if("change"===t.edge)return"event";if("terminal_transition"===t.edge){const i=new Set([e,t.state]);if(i.has("closed")&&i.has("open")||i.has("locked")&&i.has("unlocked"))return"transition"}return null}const Eh=(e,t=0)=>{const i=Number(e);return Number.isInteger(i)&&i>=0?i:t},Nh=(e,t)=>{const i={rev:0,configRev:Eh(t),off:new Set};if(null==e)return{snapshot:i,valid:!1};const n=e.off;return!Number.isInteger(e.rev)||Number(e.rev)<0||!Number.isInteger(e.config_rev)||Number(e.config_rev)<0||!Array.isArray(n)||n.some(e=>"string"!=typeof e||!e)?{snapshot:i,valid:!1}:{snapshot:{rev:Number(e.rev),configRev:Number(e.config_rev),off:new Set(n)},valid:!0}};function Hh(e,t=0){return Nh(e,t).snapshot}function Lh(e,t,i,n){const r=Nh(t,i);return n&&r.valid&&r.snapshot.configRev===i?e.configRev===i&&r.snapshot.rev{try{const[i,n]=await Promise.all([e.callWS({type:"config/device_registry/list"}),e.callWS({type:"config/entity_registry/list"})]),r=Zh(i,"id"),o=Zh(n,"entity_id");if(!r||!o)throw new Error("invalid_registry_response");t.devices=r,t.entities=o,t.authoritative=!0,t.access="full",t.lastSuccess=Date.now(),t.error=void 0}catch(e){t.authoritative=!1,t.access="limited",t.error=function(e){if(e&&"object"==typeof e){const t=e;return String(t.message||t.code||t.error||"registry_unavailable")}return String(e||"registry_unavailable")}(e)}finally{t.revision++,t.loading=void 0,function(e){for(const t of[...e.listeners])try{t()}catch{}}(t)}})()),t.loading}function Qh(e,t){void 0===t.reloadTimer&&(t.reloadTimer=globalThis.setTimeout(()=>{t.reloadTimer=void 0,Jh(e,t)},80))}async function ed(e,t){if(t.subscribing||t.unsubDevice&&t.unsubEntity)return t.subscribing;const i=e?.connection?.subscribeEvents;return"function"==typeof i?(t.subscribing=(async()=>{try{t.unsubDevice||(t.unsubDevice=await i.call(e.connection,()=>Qh(e,t),"device_registry_updated")),t.unsubEntity||(t.unsubEntity=await i.call(e.connection,()=>Qh(e,t),"entity_registry_updated"))}catch{}finally{0===t.refs&&(t.unsubDevice?.(),t.unsubEntity?.(),t.unsubDevice=void 0,t.unsubEntity=void 0),t.subscribing=void 0}})(),t.subscribing):void 0}function td(e,t){const i=Xh(e);if(!i)return()=>{};const n=0===i.refs;i.refs++,i.listeners.add(t),("pending"===i.access||n)&&Jh(e,i),ed(e,i);let r=!1;return()=>{r||(r=!0,i.listeners.delete(t),i.refs=Math.max(0,i.refs-1),i.refs>0||(i.unsubDevice?.(),i.unsubEntity?.(),i.unsubDevice=void 0,i.unsubEntity=void 0,void 0!==i.reloadTimer&&globalThis.clearTimeout(i.reloadTimer),i.reloadTimer=void 0))}}function id(e){const t=Xh(e);t&&(Qh(e,t),ed(e,t))}function nd(e){const t=Xh(e);if(!t)return{revision:0,authoritative:!1,access:"limited",devices:e?.devices||{},entities:e?.entities||{},lastSuccess:0,error:"registry_unavailable"};let i=e?.devices||{},n=e?.entities||{};if(t.authoritative){const r=t.liveDevices!==i||t.liveEntities!==n,o=void 0!==t.liveDevices||void 0!==t.liveEntities;if(r&&(t.liveDevices=i,t.liveEntities=n,t.projectedRevision=void 0,o&&Qh(e,t)),t.projectedRevision!==t.revision||!t.projectedDevices||!t.projectedEntities){const e={...t.devices},r={...t.entities};for(const[t,n]of Object.entries(i))Object.prototype.hasOwnProperty.call(e,t)||(e[t]=n);for(const[e,t]of Object.entries(n))Object.prototype.hasOwnProperty.call(r,e)||(r[e]=t);t.projectedDevices=e,t.projectedEntities=r,t.projectedRevision=t.revision}i=t.projectedDevices,n=t.projectedEntities}return{revision:t.revision,authoritative:t.authoritative,access:t.access,devices:i,entities:n,lastSuccess:t.lastSuccess,error:t.error}}function rd(e){if(!e||"object"!=typeof e&&"function"!=typeof e)return 0;let t=Gh.get(e);return t||(t=Vh++,Gh.set(e,t)),t}function od(e,t=nd(e)){return[t.revision,t.access,rd(t.devices),rd(t.entities)].join(":")}function sd(e){return!!e&&null==e.disabled_by}function ad(e,t=nd(e)){const i={},n={},r={};for(const[e,n]of Object.entries(t.devices||{}))sd(n)&&(i[e]=n);for(const[e,i]of Object.entries(t.entities||{})){if(!sd(i))continue;const r=i.device_id?t.devices?.[i.device_id]:null;t.authoritative&&i.device_id&&!r||(r&&!sd(r)||(n[e]=i))}for(const[i,n]of Object.entries(e?.states||{})){const e=t.entities?.[i];if(e&&!sd(e))continue;const o=e?.device_id?t.devices?.[e.device_id]:null;t.authoritative&&e?.device_id&&!o||(o&&!sd(o)||(r[i]=n))}return{...e,devices:i,entities:n,states:r}}function ld(e,t=nd(e)){return{...e,devices:t.devices||{},entities:t.entities||{}}}function cd(e,t){const i=[];for(const[n,r]of Object.entries(e||{}))r?.device_id===t&&i.push(n);return i}function hd(){if(Yh)return Yh;if("undefined"==typeof localStorage)return{};try{const e=JSON.parse(localStorage.getItem(Kh)||"{}");if(!e||"object"!=typeof e||Array.isArray(e))return{};const t=Date.now(),i={};for(const[n,r]of Object.entries(e))!r||"active"!==r.kind&&"ha_disabled"!==r.kind||!Number.isFinite(r.ts)||t-r.ts>7776e6||(i[n]=r);return Yh=i,Yh}catch{return{}}}function dd(e,t,i=nd(e)){if(!t||"virtual"===t)return{kind:"active",enabledEntityIds:[],allEntityIds:[]};const n=t.indexOf(":");if(n<1)return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]};const r=t.slice(0,n),o=t.slice(n+1);if("device"!==r&&"entity"!==r||!o)return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]};const s=i.devices||{},a=i.entities||{};if(i.authoritative){if("device"===r){const e=s[o];if(!e)return{kind:"orphaned",reason:"device_missing",enabledEntityIds:[],allEntityIds:[]};const t=cd(a,o);if(!sd(e))return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:t};const i=t.filter(e=>sd(a[e]));return t.length&&!i.length?{kind:"ha_disabled",reason:"all_entities",enabledEntityIds:[],allEntityIds:t}:{kind:"active",enabledEntityIds:i,allEntityIds:t}}const t=a[o];return t&&!sd(t)?{kind:"ha_disabled",reason:"entity",enabledEntityIds:[],allEntityIds:[o]}:t?.device_id&&!s[t.device_id]?{kind:"orphaned",reason:"device_missing",enabledEntityIds:[],allEntityIds:[o]}:t?.device_id&&!sd(s[t.device_id])?{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:[o]}:t||e?.states?.[o]?{kind:"active",enabledEntityIds:[o],allEntityIds:[o]}:{kind:"orphaned",reason:"entity_missing",enabledEntityIds:[],allEntityIds:[]}}const l=function(e){return hd()[e]||null}(t);if("device"===r){const t=s[o],i=cd(a,o);if(null!=t?.disabled_by)return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:i};const n=i.filter(e=>{const t=a[e];return null==t?.disabled_by&&(!t.device_id||null==s[t.device_id]?.disabled_by)});if(i.length&&!n.length&&i.every(e=>null!=a[e]?.disabled_by))return{kind:"ha_disabled",reason:"all_entities",enabledEntityIds:[],allEntityIds:i};if("ha_disabled"===l?.kind)return{kind:"ha_disabled",reason:l.reason||"device",enabledEntityIds:[],allEntityIds:i};if(t||n.some(t=>!!e?.states?.[t]))return{kind:"active",enabledEntityIds:n,allEntityIds:i}}else{const t=a[o];if(null!=t?.disabled_by)return{kind:"ha_disabled",reason:"entity",enabledEntityIds:[],allEntityIds:[o]};if(t?.device_id&&null!=s[t.device_id]?.disabled_by)return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:[o]};if("ha_disabled"===l?.kind)return{kind:"ha_disabled",reason:l.reason||"entity",enabledEntityIds:[],allEntityIds:[o]};if(t||e?.states?.[o])return{kind:"active",enabledEntityIds:[o],allEntityIds:[o]}}return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]}}function ud(e){const t=nd(e);return{access:t.access,authoritative:t.authoritative,revision:t.revision,lastSuccess:t.lastSuccess,error:t.error}}function pd(e){const t={};for(const[i,n]of Object.entries(e.entities)){if(!n?.device_id||!sd(n))continue;const r=e.devices?.[n.device_id];r&&!sd(r)||(t[n.device_id]=t[n.device_id]||[]).push(i)}return t}function _d(e,t){const i=new Map;for(const n of e){if(!0===n?.removed)continue;const e=n?.binding||"";if(!e.startsWith("entity:"))continue;const r=e.slice(7);if(!r)continue;const o=t?.entities?.[r]?.device_id;if(!o)continue;const s=i.get(o)||new Set;s.add(r),i.set(o,s)}return{byDevice:i}}function md(e,t,i,n){const r=n.byDevice.get(t);return r?.size?{partial:!0,entityIds:i.filter(t=>!r.has(t)&&!e?.entities?.[t]?.hidden)}:{partial:!1,entityIds:[...i]}}function gd(e,t,i){if(t.identifiers?.[0]?.[0])return t.identifiers[0][0];for(const t of i){const i=e.entities[t]?.platform;if(i)return i}return""}function fd(e,t){if(/_device_temperature$/.test(t))return!1;if(e.entities?.[t]?.entity_category)return!1;const i=e.states[t];if(!i)return/_temperature$/.test(t);const n=i.attributes||{};return"temperature"===n.device_class||/°C|°F/.test(n.unit_of_measurement||"")||/_temperature$/.test(t)}const vd=["vacuum","lawn_mower","climate","media_player","light","cover","lock","valve","alarm_control_panel","water_heater","fan","humidifier","siren","camera","remote"],yd=e=>[...e.filter(e=>!e.reg?.hidden),...e.filter(e=>!!e.reg?.hidden)];function bd(e,t){const i=t.map(t=>({eid:t,reg:e?.entities?.[t]})).filter(e=>!!e.reg);if(!i.length)return[];const n=i.filter(e=>!e.reg.entity_category),r=n.length?n:i;for(const e of vd){const t=r.filter(t=>t.eid.startsWith(e+"."));if(t.length)return yd(t).map(e=>e.eid)}const o=r.filter(t=>function(e,t){if(!t.startsWith("binary_sensor."))return!1;const i=$h(e?.states?.[t]?.attributes?.device_class||e?.entities?.[t]?.device_class||e?.entities?.[t]?.original_device_class);return mh.has(i)||gh.has(i)||fh.has(i)||vh.has(i)||"moving"===i||yh.has(i)}(e,t.eid));if(o.length)return yd(o).map(e=>e.eid);const s=r.filter(e=>e.eid.startsWith("switch."));if(s.length){const t=yd(s),n=t.find(t=>Ah(e,t.eid));if(s.length>1&&n){const t=i.filter(t=>t.eid!==n.eid&&"config"!==t.reg?.entity_category&&null!=Th(e,t.eid)),r=t.filter(e=>!e.reg?.entity_category),o=r.length?r:t;for(const t of[0,1,2]){const i=yd(o.filter(i=>Th(e,i.eid)===t));if(i.length)return[i[0].eid,n.eid]}}return[(n||t[0]).eid]}const a=[];for(const e of je)a.push(...yd(r.filter(t=>t.eid.startsWith(e+"."))));return a.push(...yd(r.filter(e=>!je.includes(e.eid.split(".")[0])))),a.map(e=>e.eid)}function wd(e,t,i){const n=t.map(t=>({eid:t,reg:e.entities[t],st:e.states[t]})).filter(e=>e.reg),r=[n.filter(e=>!e.reg.hidden&&!e.reg.entity_category),n.filter(e=>!e.reg.entity_category),n.filter(e=>!e.reg.hidden),n];if("mdi:thermometer"===i||"mdi:air-filter"===i)for(const t of r){const i=t.find(t=>fd(e,t.eid));if(i)return i.eid}const o=bd(e,t);return o.find(Pn)||o[0]}function kd(e,t,i=[]){return[...new Set(xd(e,t,i))].filter(e=>Pn(e))}function xd(e,t,i=[]){const n=e?.startsWith("entity:")?new Set([e.slice(7)]):new Set(i);return(t||[]).filter(e=>"string"==typeof e&&!n.has(e))}function Sd(e,t){if("string"==typeof t)return e.area===t;const i=e.marker?.room_id;return i?!!t.id&&i===t.id:!!t.area&&e.area===t.area}function $d(e){const t=e.marker?.binding?.startsWith("entity:")?e.marker.binding.slice(7):null,i=e.entities.filter(Pn),n=e.primary&&Pn(e.primary)?e.primary:null;return[...new Set([t,n,...i].filter(e=>!!e&&Pn(e)))]}function Md(e){const t=$d(e),i=e.marker?.light_entity;return i&&t.includes(i)?i:t[0]||null}function Rd(e,t){if(!1===t.marker?.is_light)return[];if(!0===t.marker?.is_light){return[{eid:Md(t),via:"forced"}]}const i=t.primary||bd(e,t.entities)[0];return i&&!i.startsWith("light.")?[]:t.entities.filter(t=>t.startsWith("light.")&&!!e.states?.[t]).map(e=>({eid:e,via:"light"}))}const Cd=new WeakMap,Td=new WeakMap;function Dd(e){return e.map(e=>[e.id||"",!0===e.hidden?1:0,e.primary||"",[...e.entities].join(","),void 0===e.controls?"":[...e.controls].join(","),e.marker?.id||"",e.marker?.binding||"",e.marker?.is_light,e.marker?.tap_action||"",!0===e.marker?.removed?1:0,e.marker?.light_entity||"",null==e.marker?.controls?"":[...e.marker.controls].join(",")].join("")).join("")}function Ad(e){const t=Dd(e),i=Cd.get(e);if(i?.fingerprint===t)return i;const n=e.filter(e=>!e.hidden),r=new Map,o=new Map;for(const t of e){o.set(t,xd(t.marker?.binding,t.marker?.controls??t.controls,t.entities));const e=t.hidden||!0!==t.marker?.is_light?null:t.marker?.id||t.id;e&&r.set(String(e),t)}const s=new Map;for(const t of e){const e=o.get(t)||[],i=new Set(void 0===t.controls?e.filter(Pn):t.controls.filter(Pn)),n=Md(t),a=i.size?[...i]:n?[n]:[];for(const i of e){if(!i.startsWith("marker:"))continue;const e=i.slice(7);if(!e||e===String(t.marker?.id||t.id||""))continue;if(!r.has(e))continue;const n=s.get(e)||{markerId:e,controllers:[],driverEids:[]};n.controllers.push({device:t,driverEids:[...a]}),n.driverEids=[...new Set([...n.driverEids,...a])],s.set(e,n)}}const a={fingerprint:t,visible:n,markerById:r,persistedByDevice:o,incomingByMarker:s};return Cd.set(e,a),a}function Pd(e){return Ad(e).incomingByMarker}function Fd(e,t){const i=kd(t.marker?.binding,t.controls??t.marker?.controls,t.entities),n=xd(t.marker?.binding,t.marker?.controls??t.controls,t.entities);return(null!=t.marker?.is_light||!i.length&&!n.some(e=>e.startsWith("marker:")))&&Rd(e,t).length>0}function zd(e,t){return Rd(e,t).some(e=>!!e.eid)}function Id(e,t,i,n){const r="always"===e||"auto"===e&&t,o=r&&!i;return{sourceExists:r,fromSourceEnabled:r&&i,manualEnabled:r,radiusEnabled:r,passive:o,effectiveMode:o&&"auto"===n?"fixed":n}}function Od(e,t){const i=kd(t.marker?.binding,t.controls??t.marker?.controls,t.entities).map(e=>({eid:e,via:"controls"})),n=Fd(e,t)?Rd(e,t):[];for(const e of n)e.eid&&i.some(t=>t.eid===e.eid)||i.push(e);return i}function Ed(e,t,i,n){if(null!=i)return Ed(e,t,null,n).filter(e=>Sd(e.device,i));const r=Dd(t),o=function(e,t){const i=new Set;for(const e of t){for(const t of e.entities)i.add(t);for(const t of e.controls||e.marker?.controls||[])"string"!=typeof t||t.startsWith("marker:")||i.add(t)}return[...i].sort().map(t=>`${t}:${e?.states?.[t]?.state??""}`).join("|")}(e,t),s=Bh(n),a=Td.get(t);if(a?.graphFingerprint===r&&a.stateFingerprint===o&&a.virtualLightFingerprint===s&&a.registry===e?.entities)return a.sources;const{visible:l,markerById:c,persistedByDevice:h,incomingByMarker:d}=Ad(t),u=null==i?l:l.filter(e=>Sd(e,i)),p=new Map,_=new Map;for(const t of u){const i=Od(e,t).filter(e=>"controls"!==e.via);for(const n of i){const i=!0===t.marker?.is_light?String(t.marker?.id||t.id||""):"",r=i?`marker:${i}`:`entity:${n.eid}`,o=n.eid?[n.eid]:[],s={key:r,eid:n.eid||"",stateEids:o,serviceEids:o,device:t,via:n.via,castsGlow:!0,passive:!n.eid,on:!n.eid||"on"===e.states?.[n.eid]?.state};p.set(t,[...p.get(t)||[],s]),n.eid&&_.set(n.eid,s)}}const m=new Map;for(const e of t){const t=h.get(e)||[],i=new Set(void 0===e.controls?t.filter(Pn):e.controls);m.set(e,i)}for(const t of p.values())for(const i of t){if(!i.passive)continue;const t=i.key.slice(7),r=d.get(t);i.on=!r||r.driverEids.some(t=>"on"===e.states?.[t]?.state),!r&&qh(i.device.marker)&&(i.on=jh(i.device.marker,n))}const g=new Map,f=e=>{const t=g.get(e.key);(!t||e.castsGlow&&!t.castsGlow)&&g.set(e.key,e)};for(const t of l){const n=h.get(t)||[],r=null==i||Sd(t,i);for(const i of n){if(i.startsWith("marker:")){const e=c.get(i.slice(7)),t=e?p.get(e):null;if(t)for(const e of t)f(e);continue}if(!Pn(i)||!m.get(t)?.has(i))continue;const n=_.get(i);n?f(n):r&&f({key:`entity:${i}`,eid:i,stateEids:[i],serviceEids:[i],device:t,via:"controls",castsGlow:!1,passive:!1,on:"on"===e.states?.[i]?.state})}for(const e of p.get(t)||[])f(e)}const v=[...g.values()];return Td.set(t,{graphFingerprint:r,stateFingerprint:o,virtualLightFingerprint:s,registry:e?.entities,sources:v}),v}function Nd(e){const t=e.filter(e=>e.castsGlow);return t.find(e=>e.on)||t[0]||null}function Hd(e){return e.length?e.some(e=>e.on)?"on":"off":"none"}function Ld(e,t){const i=[];for(const n of t){const t=e.states[n];if(!t)continue;const r=(t.attributes?.unit_of_measurement||"").toLowerCase();if(/_(linkquality|lqi)$/.test(n)||"lqi"===r){const e=parseFloat(t.state);isNaN(e)||i.push(e);continue}const o=t.attributes?.linkquality??t.attributes?.lqi;if(null!=o){const e=parseFloat(o);isNaN(e)||i.push(e)}}return Ii(i)}function Bd(e,t){for(const i of t){if(!fd(e,i))continue;const t=e.states[i];if(!t)continue;const n=parseFloat(t.state);if(!isNaN(n))return Math.round(10*n)/10}return null}function qd(e,t){for(const i of t){if(!i.startsWith("climate."))continue;const t=e.states[i];if(!t||"unavailable"===t.state||"unknown"===t.state)continue;const n=parseFloat(t.attributes?.current_temperature);if(Number.isFinite(n))return Math.round(10*n)/10}return null}function jd(e,t){if(e.entities?.[t]?.entity_category)return!1;const i=e.states[t];if(!i)return/_humidity$/.test(t);const n=i.attributes||{};return"humidity"===n.device_class||"%"===n.unit_of_measurement&&/_humidity$/.test(t)||/_humidity$/.test(t)}function Wd(e,t){for(const i of t){if(!jd(e,i))continue;const t=e.states[i];if(!t)continue;const n=parseFloat(t.state);if(!isNaN(n))return Math.round(n)}return null}function Ud(e,t){if(!t)return[];const i=[];for(const[t,n]of Object.entries(e.entities)){if(!t.startsWith("light.")||n.hidden||!sd(n))continue;let r=null;if("group"===n.platform)r=n.area_id||null;else{if(!n.device_id)continue;{const t=e.devices[n.device_id];if(!sd(t))continue;if("Group"!==t?.model)continue;r=t.area_id||n.area_id||null}}if(!r)continue;const o=e.states[t];i.push({eid:t,name:n.name||o?.attributes?.friendly_name||t,area:r})}return i}function Gd(e,t,i,n,r){const o=qe(t,i,r);if(o!==Be)return o;const s=[];for(const t of n){const i=e.states[t]?.attributes?.device_class;i&&s.push(i)}return function(e){for(const t of e){const e=Le[t];if(e)return e}return null}(s)??Be}function Vd(e,t){return e.map(e=>{if(!Array.isArray(e.controls))return e;const i=e.controls.filter(e=>!("string"==typeof e&&e.startsWith("marker:")&&t.has(e.slice(7))));return i.length===e.controls.length?e:{...e,controls:i.length?i:null}})}function Kd(e,t,i){if(!t||!i||t===i)return[...e];const n=`marker:${t}`,r=`marker:${i}`;return e.map(e=>{const t=Array.isArray(e.controls)?e.controls.map(e=>e===n?r:e):e.controls,i="derived_marker_state"===e.value_badge?.source?.kind&&e.value_badge.source.ref===n?{...e.value_badge,source:{...e.value_badge.source,ref:r}}:e.value_badge,o="derived_marker_state"===e.value_source?.kind&&e.value_source.ref===n?{...e.value_source,ref:r}:e.value_source;return t===e.controls&&i===e.value_badge&&o===e.value_source?e:{...e,controls:t,...void 0!==i?{value_badge:i}:{},...void 0!==o?{value_source:o}:{}}})}function Yd(e,t,i){if(!t||t===i)return!0;const n=new Map;for(const t of e)n.set(t.id,(t.controls||[]).filter(e=>"string"==typeof e&&e.startsWith("marker:")).map(e=>e.slice(7)));const r=new Set,o=[i];for(;o.length;){const e=o.pop();if(e===t)return!0;r.has(e)||(r.add(e),o.push(...n.get(e)||[]))}return!1}function Xd(e,t,i,n){const r=new Set([t]),o=e.filter(e=>{const o=e.id===t||!n&&e.binding===i;return o&&r.add(e.id),!o});return{markers:n?o:[...o,{id:t,binding:i,removed:!0,hidden:!0}],cleanupIds:r}}function Zd(e){const t=new Set,i=new Set,n=new Set;for(const r of e||[]){const e=String(r.binding||"").indexOf(":");if(e<1)continue;const o=r.binding.slice(0,e),s=r.binding.slice(e+1);s&&(!0===r?.removed?"device"===o?t.add(s):"entity"===o&&i.add(s):"entity"===o&&n.add(s))}return{devices:t,entities:i,liveEntities:n}}function Jd(e,t,i){if(i.liveEntities.has(t))return!1;if(i.entities.has(t))return!0;const n=e?.entities?.[t]?.device_id;return!!n&&i.devices.has(n)}function Qd(e,t,i,n,r){const o=kd(t.binding,t.controls,e.entities).filter(e=>!Jd(i,e,n)).filter(e=>"active"===dd(i,"entity:"+e,r).kind);e.marker=t,e.controls=o,e.userHidden=!0===t.hidden,e.hidden=e.userHidden||"ha_disabled"===e.bindingStatus?.kind,t.name&&(e.name=t.name),t.icon&&(e.icon=t.icon),null!=t.model&&(e.model=t.model),e.link=t.link??null,e.description=t.description??null,e.pdfs=t.pdfs||[],e.tapAction=t.tap_action??null}function eu(e){const t=e.hass,i=e.registry||nd(t),n=ad(t,i),r=ld(t,i),{areaToSpace:o,markers:s,settings:a,excluded:l,iconRules:c}=e,h=!1!==a.group_lights,d=Zd(s),u=Ud(n,h).filter(e=>!Jd(n,e.eid,d)),p=new Set(u.map(e=>e.area)),_=pd(n),m=_d(s,r),g=new Set(s.map(e=>e.binding)),f=[];for(const e of Object.values(n.devices)){const r=e.area_id;if(!r||!o[r])continue;if("service"===e.entry_type)continue;if(g.has("device:"+e.id))continue;if("active"!==dd(t,"device:"+e.id,i).kind)continue;const s=md(n,e.id,_[e.id]||[],m);if(s.partial&&!s.entityIds.length)continue;const a=s.entityIds,d=gd(n,e,a);let u=l.has(d)||"Group"===e.model||/scene/i.test(e.model||"")||/bridge/i.test((e.model||"")+(e.name||""))||"myheat"===d&&!!e.via_device_id;if(!u&&h&&p.has(r)){const t=(e.name_by_user||e.name||"").trim();"mdi:lightbulb"===Gd(n,t,e.model,a,c)&&(u=!0)}u&&f.push("device:"+e.id)}return f}function tu(e,t,i,n){if("string"==typeof e.room_id&&e.room_id.length>0&&null===e.area)return{area:"",space:e.space||n};const r=e.area||t||"";return{area:r,space:r&&i[r]||e.space||n}}function iu(e){const t=e.hass,i=e.registry||nd(t),n=ad(t,i),r=ld(t,i),{areaToSpace:o,markers:s,settings:a,excluded:l,showAll:c,firstSpaceId:h,loc:d,iconRules:u}=e,p=!1!==a.group_lights,_=Zd(s),m=Ud(n,p).filter(e=>!Jd(n,e.eid,_)),g=new Set(m.map(e=>e.area)),f=pd(n),v=function(e){const t={};for(const[i,n]of Object.entries(e.entities||{}))n?.device_id&&(t[n.device_id]=t[n.device_id]||[]).push(i);return t}(r),y=_d(s,r),b=new Set;for(const e of s){const[t,i]=e.binding.split(":");"device"!==t&&"entity"!==t||!i||b.add(e.binding)}const w=(e,t)=>s.find(i=>i.binding===e+":"+t),k={},x=[];for(const e of Object.values(n.devices)){const r=e.area_id;if(!r||!o[r])continue;if("service"===e.entry_type)continue;if(b.has("device:"+e.id))continue;const s=dd(t,"device:"+e.id,i);if("active"!==s.kind)continue;const h=w("device",e.id);if(h&&h.hidden&&!a.filter_seeded)continue;const _=md(n,e.id,f[e.id]||[],y);if(_.partial&&!_.entityIds.length)continue;const m=_.entityIds,v=_.partial?{kind:"active",enabledEntityIds:m,allEntityIds:m}:s,S=gd(n,e,m),$=!a.filter_seeded;if($&&!c){if(l.has(S))continue;if("Group"===e.model)continue;if(/scene/i.test(e.model||""))continue;if(/bridge/i.test((e.model||"")+(e.name||"")))continue;if("myheat"===S&&e.via_device_id)continue}const M=(e.name_by_user||e.name||d("device.unnamed")).trim(),R=M+"|"+r;let C=Gd(n,M,e.model,m,u);if(m.some(e=>e.startsWith("lock."))&&(C="mdi:lock"),$&&!c&&p&&"mdi:lightbulb"===C&&g.has(r))continue;k[R]=(k[R]||0)+1;const T=k[R]>1?M+" "+k[R]:M,D={id:e.id,name:T,model:e.model||"",area:r,space:o[r],icon:C,entities:m,allEntities:v.allEntityIds,bindingStatus:v,bindingKind:"device",bindingRef:e.id,pdfs:[]};D.primary=wd(n,m,C),"mdi:thermometer"!==C&&"mdi:air-filter"!==C||(D.temp=Bd(n,m)),D.primary&&jd(n,D.primary)&&(D.hum=Wd(n,m)),x.push(D)}for(const e of m)o[e.area]&&(b.has("entity:"+e.eid)||x.push({id:"lg_"+e.eid,name:e.name,model:d("device.light_group"),area:e.area,space:o[e.area],icon:"mdi:lightbulb-group",entities:[e.eid],allEntities:[e.eid],bindingStatus:{kind:"active",enabledEntityIds:[e.eid],allEntityIds:[e.eid]},primary:e.eid,bindingKind:"entity",bindingRef:e.eid,pdfs:[]}));for(const e of s){if(e.removed)continue;const[s,l]=e.binding.split(":"),c="device"===s||"entity"===s?dd(t,e.binding,i):null;if(!e.hidden||a.filter_seeded||"ha_disabled"===c?.kind)if("device"===s){const t=c;if("unverified"===t.kind)continue;const s=r.devices[l],{area:a,space:p}=tu(e,s?.area_id,o,h),m="active"===t.kind?t.enabledEntityIds:[];let g=s?Gd(n,s.name_by_user||s.name||"",s.model,m,u):"mdi:help-circle";m.some(e=>e.startsWith("lock."))&&(g="mdi:lock");const f={id:e.id,name:s?.name_by_user||s?.name||d("device.fallback"),model:s?.model||"",area:a,space:p,icon:g,entities:m,allEntities:t.allEntityIds.length?t.allEntityIds:s&&v[s.id]||[],bindingStatus:t,bindingKind:"device",bindingRef:l};f.primary=wd(n,m,g),"mdi:thermometer"!==g&&"mdi:air-filter"!==g||(f.temp=Bd(n,m)),f.primary&&jd(n,f.primary)&&(f.hum=Wd(n,m)),Qd(f,e,r,_,i),x.push(f)}else if("entity"===s){if(Jd(r,l,_))continue;const t=c;if("unverified"===t.kind)continue;const s=r.entities[l],a=s?.area_id||s?.device_id&&r.devices[s.device_id]?.area_id||"",{area:d,space:p}=tu(e,a,o,h),m=n.states[l],g=s?.name||m?.attributes?.friendly_name||l;let f=Gd(n,g,"",[l],u);l.startsWith("lock.")&&(f="mdi:lock");const v={id:e.id,name:g,model:"",area:d,space:p,icon:f,entities:"active"===t.kind?[l]:[],allEntities:[l],bindingStatus:t,primary:"active"===t.kind?l:void 0,bindingKind:"entity",bindingRef:l};"mdi:thermometer"!==f&&"mdi:air-filter"!==f||!v.entities.length||(v.temp=Bd(n,v.entities)),v.entities.length&&jd(n,l)&&(v.hum=Wd(n,v.entities)),Qd(v,e,r,_,i),x.push(v)}else{const t=e.area||"",n=e.space||t&&o[t]||h,s={id:e.id,name:e.name||d("device.virtual"),model:e.model||"",area:t,space:n,icon:e.icon||"mdi:map-marker",entities:[],allEntities:[],bindingStatus:{kind:"active",enabledEntityIds:[],allEntityIds:[]},bindingKind:"virtual",virtual:!0};Qd(s,e,r,_,i),x.push(s)}}return x}function nu(e){const{marker:t,siblingMarkers:i=[],...n}=e;return iu({...n,markers:[...i.filter(e=>e.id!==t.id),t]}).find(e=>e.id===t.id)||null}function ru(e,t,i,n){if(!t)return null;if(function(e,t,i){if(!t)return!1;const n=t.indexOf(":");if(n<1)return!1;const r=t.slice(0,n),o=t.slice(n+1),s=Zd(i);return"device"===r?s.devices.has(o):"entity"===r&&Jd(e,o,s)}(e,t,n))return null;const r=t.indexOf(":");if(r<0)return null;const o=t.slice(0,r),s=t.slice(r+1);if(!s)return null;if("entity"===o){const t=parseFloat(e.states[s]?.state);return Number.isFinite(t)?"temp"===i?Math.round(10*t)/10:Math.round(t):null}if("device"===o){const t=Object.entries(e.entities).filter(([,e])=>e.device_id===s).map(([e])=>e);return"temp"===i?Bd(e,t):Wd(e,t)}return null}const ou=new RegExp(["water","voda","coolant","flow_?temp","return_?temp","target","setpoint","chip","cpu","processor","board","core_temp","device_temp","batter","akkum","freezer","fridge","oven","kettle","boiler"].join("|"),"i");function su(e,t){return t.area?t.area:e&&t.id?`@room/${encodeURIComponent(e)}/${encodeURIComponent(t.id)}`:null}function au(e){return null==e.area&&e.space&&e.room_id?su(e.space,{id:e.room_id,area:null}):e.area||null}function lu(e){const t=e?.exclude_integrations;return t?new Set(t):Ie}function cu(e,t,i,n=Ie){const r=new Map;if(!e?.entities)return r;const o=Zd(i),s=new Set,a=new Map,l=new Map;for(const e of i||[]){if(e?.removed)continue;const t=(e.binding||"").indexOf(":");if(t<=0)continue;const i=e.binding.slice(0,t),n=e.binding.slice(t+1);if(!n)continue;!0===e.use_climate_temp&&s.add(n);const r=au(e);r&&("entity"!==i||a.has(n)?"device"!==i||l.has(n)||l.set(n,r):a.set(n,r))}const c=new Map;for(const[t,i]of Object.entries(e.entities)){if(i.device_id&&o.devices.has(i.device_id)&&!o.liveEntities.has(t)||!i.device_id&&o.entities.has(t)&&!o.liveEntities.has(t))continue;const r=i.device_id?e.devices?.[i.device_id]:null;if(!sd(i)||r&&!sd(r))continue;const h=a.get(t)||(i.device_id?l.get(i.device_id):null)||i.area_id||r?.area_id||null;if(!h)continue;if(i.entity_category)continue;if(!(s.size>0&&t.startsWith("climate.")&&(s.has(t)||i.device_id&&s.has(i.device_id)))){if(n.has(i.platform))continue;if(ou.test(t))continue}let d=c.get(h);d||(d=new Map,c.set(h,d));const u=i.device_id||t;let p=d.get(u);if(!p){const n=e.states?.[t];p={name:(r?r.name_by_user||r.name:i.name||n?.attributes?.friendly_name||t)||t,model:r?.model,ents:[]},d.set(u,p)}p.ents.push(t)}for(const[i,n]of c){const o=[],a=[];for(const[i,r]of n){const n=Gd(e,r.name,r.model,r.ents,t),l="mdi:thermometer"===n||"mdi:air-filter"===n;if(l){const t=Bd(e,r.ents);null!=t&&o.push(t)}if(s.size>0&&(s.has(i)||r.ents.some(e=>s.has(e)))){const t=qd(e,r.ents);null!=t&&o.push(t)}if(l||"mdi:water-percent"===n){const t=Wd(e,r.ents);null!=t&&a.push(t)}}(o.length||a.length)&&r.set(i,{temp:o.length?Math.round(o.reduce((e,t)=>e+t,0)/o.length*10)/10:null,hum:a.length?Math.round(a.reduce((e,t)=>e+t,0)/a.length):null})}return r}function hu(e,t,i){const n=[];for(const r of t){if(r.area!==i||r.virtual)continue;const t=Ld(e,r.entities);null!=t&&n.push(t)}return Ii(n)}const du={offStates:["off"],unknownUsesToggle:!0},uu={light:du,switch:du,fan:du,humidifier:du,input_boolean:du,automation:du,remote:du,group:du,climate:{...du,featureMasks:{turn_on:256,turn_off:128,toggle:384}},media_player:{...du,featureMasks:{turn_on:128,turn_off:256,toggle:384}},siren:{...du,featureMasks:{turn_on:1,turn_off:2,toggle:3}},vacuum:{...du,featureMasks:{turn_on:1,turn_off:2,toggle:3}},water_heater:{...du,featureMasks:{turn_on:8,turn_off:8,toggle:8}},camera:{...du,featureMasks:{turn_on:1,turn_off:1,toggle:1}}};function pu(e){return e.slice(0,e.indexOf("."))}function _u(e,t,i){if(!e?.services||"object"!=typeof e.services)return!1;const n=e.services?.[t];return!!n&&Object.prototype.hasOwnProperty.call(n,i)}function mu(e,t,i){return _u(e,t,i)?{domain:t,service:i}:_u(e,"homeassistant",i)?{domain:"homeassistant",service:i}:null}function gu(e,t){return e?.entities?.[t]||null}function fu(e,t,i){const n=e?.states?.[i],r=gu(t,i);return n?.attributes?.friendly_name||r?.name||r?.original_name||i}function vu(e,t){const i=gu(e,t);if(null!=i?.disabled_by)return!0;const n=i?.device_id?e?.devices?.[i.device_id]:null;return null!=n?.disabled_by}function yu(e,t){const i=e?.attributes?.supported_features;if(null==i||""===i)return!1;const n=Number(i);return Number.isFinite(n)&&(n&t)===t}function bu(e,t,i){const n=pu(i);if("lock"===n||"alarm_control_panel"===n)return!0;if("cover"!==n)return!1;const r=e?.states?.[i],o=gu(t,i),s=String(r?.attributes?.device_class||o?.device_class||o?.original_device_class||"");return Gi.has(s)}function wu(e,t,i,n,r){return{ref:i,entityId:n,name:n?fu(e,t,n):null,reason:r}}function ku(e,t,i,n,r,o=null){return{target:null,skipped:wu(e,t,i,n,r),semantics:o,nextEffect:null,command:null}}function xu(e,t,i,n,r=i){const o=pu(i);if("cover"!==o&&"valve"!==o)return function(e,t,i,n,r=i){const o=pu(i),s=e?.states?.[i];if(vu(t,i))return ku(e,t,r,i,"ha-disabled","power");if(bu(e,t,i))return ku(e,t,r,i,"secure");if(!s)return ku(e,t,r,i,"missing","power");if("unavailable"===s.state)return ku(e,t,r,i,"unavailable","power");const a=uu[o];if(!a)return ku(e,t,r,i,"unsupported");let l,c;if("unknown"===s.state||""===s.state){if(!a.unknownUsesToggle)return ku(e,t,r,i,"unsupported","power");l="toggle",c="toggle"}else a.offStates.includes(String(s.state))?(l="turn-on",c="turn_on"):(l="turn-off",c="turn_off");const h=a.featureMasks?.[c];if(h&&!yu(s,h))return ku(e,t,r,i,"unsupported","power");const d=mu(e,o,c);return d?{target:{entityId:i,name:fu(e,t,i),state:String(s.state||""),via:n},skipped:null,semantics:"power",nextEffect:l,command:{...d,data:{entity_id:i}}}:ku(e,t,r,i,"unsupported","power")}(e,t,i,n,r);if(vu(t,i))return ku(e,t,r,i,"ha-disabled",o);if(bu(e,t,i))return ku(e,t,r,i,"secure",o);const s=e?.states?.[i];if(!s)return ku(e,t,r,i,"missing",o);if("unavailable"===s.state)return ku(e,t,r,i,"unavailable",o);const a=function(e,t,i){const n=String(i?.state||""),r="closed"===n?{service:`open_${t}`,effect:"open",feature:1}:"open"===n?{service:`close_${t}`,effect:"close",feature:2}:"opening"===n||"closing"===n?{service:`stop_${t}`,effect:"stop",feature:8}:null;return r&&yu(i,r.feature)&&_u(e,t,r.service)?r:yu(i,3)&&_u(e,t,"toggle")?{service:"toggle",effect:"toggle"}:null}(e,o,s);if(!a)return ku(e,t,r,i,"unsupported",o);return{target:{entityId:i,name:fu(e,t,i),state:String(s.state||""),via:n},skipped:null,semantics:o,nextEffect:a.effect,command:{domain:o,service:a.service,data:{entity_id:i}}}}function Su(e){return"entity"===e.bindingKind?e.bindingRef&&Pn(e.bindingRef)?[e.bindingRef]:[]:"virtual"===e.bindingKind?[]:$d(e)}function $u(e){const t=e.marker?.toggle_entity;return t&&Su(e).includes(t)?t:null}function Mu(e,t,i){const n=function(e,t){if("entity"===e.bindingKind&&e.bindingRef){const t=e.marker?.light_entity?Md(e):null;return[...new Set([t,e.bindingRef].filter(e=>!!e))]}const i=e.entities.length?e.entities:e.allEntities||[],n=e.marker?.light_entity||e.primary&&Pn(e.primary)?Md(e):null;return[...new Set([n,...bd(t,i)].filter(e=>!!e))]}(i,t);if(!n.length)return null;const r="entity"===i.bindingKind?"binding":"device-role";if("binding"===r)return xu(e,t,n[0],r);let o=null,s=null;for(const i of n){const n=xu(e,t,i,r);if(n.command)return n;const a=n.skipped?.reason;if("missing"===a||"unavailable"===a||"secure"===a)return n;"ha-disabled"!==a?o||=n:s||=n}return o||s}function Ru(e){const t=e.skipped?.reason;return"missing"===t?"unavailable":t||"unsupported"}function Cu(e,t){return{origin:e,kind:"none",semantics:null,targets:[],skippedTargets:[],noneReason:t,nextEffect:null,command:null}}function Tu(e,t){return"cover"===e||"toggle"===e?"toggle":"more-info"===e||"run"===e||"info"===e||"none"===e?e:(null==e||""===e)&&"light"===t?"toggle":"info"}function Du(e,t){return{origin:e,kind:"single",semantics:t.semantics,targets:t.target?[t.target]:[],skippedTargets:t.skipped?[t.skipped]:[],noneReason:t.command?null:Ru(t),nextEffect:t.nextEffect,command:t.command}}function Au(e,t,i,n=[]){const r=new Map,o=[],s=new Set,a=e=>{const t=`${e.ref}\n${e.entityId||""}\n${e.reason}`;s.has(t)||(s.add(t),o.push(e))};for(const e of n)a(e);for(const n of i){const i=xu(e,t,n.entityId,n.via,n.ref);i.target?r.set(n.entityId,r.get(n.entityId)||i.target):i.skipped&&a(i.skipped)}const l=[...r.values()];if(!l.length)return{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:l,skippedTargets:o,noneReason:o.length&&o.every(e=>"secure"===e.reason)?"secure":"configured-targets-missing",nextEffect:null,command:null};const c=l.some(e=>"on"===e.state)?"turn_off":"turn_on",h=mu(e,"homeassistant",c);return h?{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:l,skippedTargets:o,noneReason:null,nextEffect:"turn_on"===c?"turn-on":"turn-off",command:{...h,data:{entity_id:l.map(e=>e.entityId)}}}:{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:[],skippedTargets:[...o,...l.map(i=>wu(e,t,i.entityId,i.entityId,"unsupported"))],noneReason:"unsupported",nextEffect:null,command:null}}function Pu(e){return String(e.marker?.id||e.id||"")}function Fu(e){const{hass:t,device:i}=e,n=e.registryHass||t,r=function(e){return"toggle"===e.tapAction?"explicit-toggle":"cover"===e.tapAction?"legacy-cover":!e.tapAction&&e.primary?.startsWith("light.")?"default-light":null}(i);if(!r)return null;const o=i.marker;if("explicit-toggle"===r&&qh(o)){const t=String(o?.id||i.id||""),n=Pd(e.devices).get(t);if(n)return function(e,t){const i=e.registryHass||e.hass;return Au(e.hass,i,t.driverEids.map(e=>({entityId:e,via:"control-marker-driver",ref:`marker:${t.markerId}`})))}(e,n);const s=jh(o,e.virtualLights);return{origin:r,kind:"single",semantics:"power",targets:[{entityId:"",name:i.name,state:s?"on":"off",via:"virtual-light"}],skippedTargets:[],noneReason:null,nextEffect:s?"turn-off":"turn-on",command:null,operation:{kind:"virtual-light",markerId:o.id}}}if("explicit-toggle"===r){if(xd(i.marker?.binding,i.marker?.controls??i.controls,i.entities).length)return function(e,t=null){const{hass:i,device:n,devices:r}=e,o=e.registryHass||i,s=xd(n.marker?.binding,n.marker?.controls??n.controls,n.entities),a=e.lightSources||Ed(i,r,null,e.virtualLights),l=new Map;for(const e of a){if(!e.key.startsWith("marker:"))continue;const t=l.get(e.key)||[];t.push(e),l.set(e.key,t)}const c=Pd(r),h=new Map;for(const e of r){const t=String(e.marker?.id||e.id||"");t&&h.set(t,e)}const d=[],u=[];t&&d.push({entityId:t,via:"entity"===n.bindingKind?"binding":"device-role",ref:t});for(const e of s){if(!e.startsWith("marker:")){Pn(e)?d.push({entityId:e,via:"control-entity",ref:e}):u.push(wu(i,o,e,e.includes(".")?e:null,"unsupported"));continue}const t=l.get(e)||[];if(!t.length){const t=h.get(e.slice(7));if("ha_disabled"===t?.bindingStatus?.kind){const n=t.bindingStatus.allEntityIds[0]||null;u.push({ref:e,entityId:n,name:t.name||(n?fu(i,o,n):null),reason:"ha-disabled"})}else u.push(wu(i,o,e,null,"missing"));continue}const r=[...new Set(t.flatMap(e=>e.serviceEids))];if(r.length){for(const t of r)d.push({entityId:t,via:"control-entity",ref:e});continue}const s=t.some(e=>e.passive),a=e.slice(7),p=Pu(n),_=c.get(a)?.controllers.find(e=>Pu(e.device)===p);if(s&&_?.driverEids.length)for(const t of _.driverEids)d.push({entityId:t,via:"control-marker-driver",ref:e});else u.push(wu(i,o,e,null,s?"missing":"unsupported"))}return Au(i,o,d,u)}(e,$u(i))}if("legacy-cover"===r){const e=i.entities.find(e=>e.startsWith("cover."))||i.allEntities?.find(e=>e.startsWith("cover."));return e?Du(r,xu(t,n,e,"device-role")):Cu(r,"no-actionable-entity")}const s=$u(i),a=s?xu(t,n,s,"entity"===i.bindingKind?"binding":"device-role"):Mu(t,n,i);return a?Du(r,a):Cu(r,i.virtual||"virtual"===i.bindingKind?"no-actionable-entity":"no-binding")}function zu(e){if(!e)return[];const t=Array.isArray(e.data.entity_id)?e.data.entity_id:[e.data.entity_id];return[...new Set(t)].sort()}function Iu(e){return e?e.operation?e.operation:e.command?{kind:"ha-service",command:e.command}:null:null}const Ou=new Set(["missing","ha-disabled","unavailable"]);function Eu(e,t){const i=Iu(e),n=Iu(t);return!(!i||!n||i.kind!==n.kind)&&("virtual-light"===i.kind&&"virtual-light"===n.kind?i.markerId===n.markerId:"ha-service"===i.kind&&"ha-service"===n.kind&&function(e,t){const i=zu(e),n=zu(t);return i.length===n.length&&i.every((e,t)=>e===n[t])}(i.command,n.command))}function Nu(e,t){const i=e.targets[0]||e.skippedTargets[0],n=[];return"group"===e.kind?e.targets.length&&n.push(t.group(e.targets)):i&&n.push(t.single(i)),e.nextEffect&&e.targets.length&&n.push("group"===e.kind?t.groupCurrentNext(e.targets,e.nextEffect):t.currentNext(e.targets[0],e.nextEffect)),e.skippedTargets.length&&n.push(t.skipped(e.skippedTargets)),!e.command&&e.noneReason&&n.push(t.none(e.noneReason)),n}function Hu(e,t){return e.catch(()=>{}).then(t)}const Lu=e=>{const t=e?.config;return t&&Array.isArray(t.spaces)?t:null},Bu=(e,t)=>"number"==typeof e&&Number.isFinite(e)?e:t;class qu{constructor(e){this.onBodyReplaced=e,this.config=null,this.configRev=0,this.configFingerprint="",this.layout={},this.layoutRev=0,this.layoutFingerprint=""}setConfig(e){const t=this.config;e!==t&&(this.config=e,this.onBodyReplaced?.("_serverCfg",t))}setLayout(e){const t=this.layout;e!==t&&(this.layout=e,this.onBodyReplaced?.("_layout",t))}currentConfigFingerprint(){return this.configFingerprint||cc(this.config)}currentLayoutFingerprint(){return this.layoutFingerprint||cc(this.layout)}adoptResponses(e,t,i,n){const r=Lu(e),o=cc(r),s=o!==this.currentConfigFingerprint();s&&(i(),this.setConfig(r),this.configFingerprint=o),this.configRev=e?.rev??this.configRev;let a=!1;if(void 0!==t){const e=t?.layout??{},i=cc(e);a=i!==this.currentLayoutFingerprint(),a&&(n(),this.setLayout(e),this.layoutFingerprint=i),this.layoutRev=t?.rev??this.layoutRev}return{configChanged:s,layoutChanged:a}}adoptMergedLayout(e,t,i){const n=cc(e),r=n!==cc(this.layout);return r&&(i?.(),this.setLayout(e)),this.layoutFingerprint=n,this.layoutRev=t?.rev??this.layoutRev,r}stageConfigCandidate(e){const t=cc(e);t!==cc(this.config)&&this.setConfig(e),this.configFingerprint=t}acceptConfigWrite(e,t){this.configFingerprint=cc(e),this.configRev=Bu(t?.rev,this.configRev+1)}acceptPairWrite(e,t,i){this.setConfig(e),this.configFingerprint=cc(e),this.setLayout(t),this.layoutFingerprint=cc(t),this.configRev=Bu(i?.config_rev,this.configRev+1),this.layoutRev=Bu(i?.layout_rev,this.layoutRev+1)}noteLayoutRevision(e){"number"==typeof e&&e>this.layoutRev&&(this.layoutRev=e)}stageLocalConfig(e){this.setConfig(e)}stageLocalLayout(e){this.setLayout(e)}seedIdentity(e){Object.assign(this,e)}refreshConfigFingerprint(){this.configFingerprint=cc(this.config)}refreshLayoutFingerprint(){this.layoutFingerprint=cc(this.layout)}beginOptimistic(e,t){return function(e,t,i,n,r){return{previous:JSON.parse(JSON.stringify(e)),previousFingerprint:i,revision:n,attempted:t,attemptedFingerprint:r(t)}}(e,t,this.configFingerprint,this.configRev,cc)}rollbackOptimistic(e){const t=this.config;return!(!t||this.configRev!==e.revision||cc(t)!==e.attemptedFingerprint)&&(this.setConfig(e.previous),this.configFingerprint=e.previousFingerprint,!0)}restoreCached(e){const t=e?.config;return!(!t||!Array.isArray(t.spaces))&&(this.setConfig(t),this.configRev=e?.rev||0,this.configFingerprint=e?.config_fingerprint||cc(t),this.setLayout(e?.layout||{}),this.layoutRev=e?.layout_rev||0,this.layoutFingerprint=e?.layout_fingerprint||cc(this.layout),!0)}snapshot(e){return this.config?(this.refreshConfigFingerprint(),this.refreshLayoutFingerprint(),{config:this.config,rev:this.configRev,config_fingerprint:this.configFingerprint,layout:this.layout,layout_rev:this.layoutRev,layout_fingerprint:this.layoutFingerprint,virtual_lights:e}):null}}async function ju(e,t){const i=t.isCurrent??(()=>!0);if(!i())return{status:"superseded"};const{cfgResp:n,layResp:r}=t,o=e._adoption,s=Lu(n),a=null!=n&&cc(s)!==o.currentConfigFingerprint()||null!=r&&cc(r.layout??{})!==o.currentLayoutFingerprint();if(a){const t=await e._signer.prepareImage(e.hass,e._candidateBackdrop(s));if(!i())return{status:"superseded"};if(!t)return e._continuity.note("asset-failed"),e._scheduleLoadRetry(!0),{status:"asset-wait"}}if(!i())return{status:"superseded"};a&&e._continuity.hasCompleteFrame&&"steady"===e._continuity.state&&e._beginContinuityCandidate(t.reason,!0),t.beforeAdopt?.();const l=e._space;return function(e,t,i){const n=e._adoption,r=!!n.config,{configChanged:o,layoutChanged:s}=n.adoptResponses(t??{},i,()=>{e._geometryHistory.clear(),e._devicePositionHistory.clear(),e._cancelDeviceDrag(),e._pendingPhysicalWrites.clear(),e._clearRoomFocus(!0),e._cancelCameraTransition(!1),r&&e._clearGeometryGesture()},()=>{e._cancelCameraTransition(!1),e._devicePositionHistory.clear(),e._cancelDeviceDrag()});if(o&&e._seedDecorStyle(n.config),t&&("virtual_lights"in t||"config"in t)){const i=Lh(e._virtualLights,t.virtual_lights,n.configRev,"virtual_lights"in t);Bh(i)!==Bh(e._virtualLights)&&(e._virtualLights=i,e._capturedSnapshotVirtual="")}e._canOptimizeUndo=!(!t?.can_optimize_undo&&!i?.can_optimize_undo),e._adoptConfigCapabilities(t),e._undoKind=t?.undo_kind||i?.undo_kind||null,"boolean"==typeof t?.can_write&&(e._serverCanWrite=t.can_write),o&&e._continuity.note("config-candidate",{configRev:n.configRev}),s&&e._continuity.note("layout-candidate",{layoutRev:n.layoutRev})}(e,n,r),"reload"===t.profile&&(e._syncDecorAssets(s).catch(()=>{}),e._adoptInitialSpace(e._model,!0),e._resumePendingNavMode(),e._cacheSnapshot()),t.afterAdopt?.(),{status:"adopted",spaceChanged:e._space!==l}}const Wu=(e,t)=>e.connection===t.connection&&e.userId===t.userId&&e.route===t.route,Uu=e=>"number"==typeof e&&Number.isFinite(e)?e:null;class Gu{constructor(){this.sequence=0,this.currentSequence=0,this.lifecycle=0,this.observedHighWater=null,this.context=null}observeContext(e){this.context?Wu(this.context,e)||(this.context={...e},this.invalidateLifecycle()):this.context={...e}}invalidateLifecycle(){this.lifecycle+=1,this.currentSequence=++this.sequence,this.observedHighWater=null}observeRevision(e,t,i){this.observeContext(i);const n=Uu(e);if(null===n)return null;const r=Uu(t)??Number.NEGATIVE_INFINITY;return n<=Math.max(r,this.observedHighWater??Number.NEGATIVE_INFINITY)?null:(this.observedHighWater=n,Object.freeze({sequence:this.currentSequence,lifecycle:this.lifecycle,context:{...i},observedRevision:n}))}isReservationCurrent(e,t,i){this.observeContext(t);const n=Uu(i)??Number.NEGATIVE_INFINITY;return e.sequence===this.currentSequence&&e.lifecycle===this.lifecycle&&Wu(e.context,t)&&e.observedRevision===this.observedHighWater&&e.observedRevision>n}begin(e){this.observeContext(e.context),e.force&&this.invalidateLifecycle();const t=++this.sequence;return this.currentSequence=t,Object.freeze({sequence:t,lifecycle:this.lifecycle,force:e.force,context:{...e.context},baselineRevision:e.baselineRevision,baselineFingerprint:e.baselineFingerprint})}isCurrent(e){this.observeContext(e.context);const t=e.claim;return e.connected&&(t.force||!e.writePending)&&t.sequence===this.currentSequence&&t.lifecycle===this.lifecycle&&Wu(t.context,e.context)&&t.baselineRevision===e.baselineRevision&&t.baselineFingerprint===e.baselineFingerprint}}const Vu=e=>{const t=e.hass,i=t?.user?.id;return{connection:t?.connection??null,userId:"string"==typeof i?i:null,route:location.pathname}};async function Ku(e,t=!1,i){let n=null;const r=e._configReloadAuthority;if(!t){if(void 0!==i&&(n=r.observeRevision(i,e._cfgRev,Vu(e)),!n))return;if(e._saveConfigDebounced.pending()&&e._saveConfigDebounced.flush(),e._cfgWriting)return clearTimeout(e._reloadRetry),void(e._reloadRetry=window.setTimeout(()=>{n&&!r.isReservationCurrent(n,Vu(e),e._cfgRev)||Ku(e,!1)},400))}const o=r.begin({force:t,context:Vu(e),baselineRevision:e._cfgRev,baselineFingerprint:e._adoption.currentConfigFingerprint()}),s=()=>((e,t)=>e._configReloadAuthority.isCurrent({claim:t,context:Vu(e),connected:e.isConnected,baselineRevision:e._cfgRev,baselineFingerprint:e._adoption.currentConfigFingerprint(),writePending:e._saveConfigDebounced.pending()||e._cfgWriting}))(e,o);let a=!1;try{const t=await e._getAuthoritativeConfig();if(!s())return;const i=await e._adoptAuthoritative({cfgResp:t,reason:"config-reload",profile:"reload",isCurrent:s,afterAdopt:()=>{e._regSignature="",e._maybeRebuildDevices()}});if("superseded"===i.status)return;if(a=!0,"adopted"!==i.status)return;i.spaceChanged&&e._restoreZoom(),e.requestUpdate()}catch(t){if(!s())return;a=!0,e._showToast(e._t("toast.cfg_reload_failed",{err:e._errText(t)}))}finally{(a||s())&&(e._continuityDataReady=!0,e.requestUpdate())}}const Yu=e=>!!e&&e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]);function Xu(e,t=5,i=5){return Oo(e.cm,t,i)/2}function Zu(e,t,i=1,n=5,r=5,o=0){const s=e.host;if(!s||"partition"!==s.kind||"string"!=typeof s.id||!s.id)return{resolved:null,reason:"invalid-host"};const a=t.find(e=>e.id===s.id);if(!a)return{resolved:null,reason:"missing-partition"};if(!Yu(a.a)||!Yu(a.b)||!Number.isFinite(s.t)||s.t<0||s.t>1)return{resolved:null,reason:"invalid-position"};const l=a.b[0]-a.a[0],c=a.b[1]-a.a[1],h=Math.hypot(l,c),d=Number(e.length)*i;if(!(h>1e-9&&d>0&&Number.isFinite(d)))return{resolved:null,reason:"invalid-length"};const u=s.t*h;if(u-d/2h-o+1e-9)return{resolved:null,reason:"does-not-fit"};const p=l/h,_=c/h;let m=180*Math.atan2(c,l)/Math.PI;return m>=90?m-=180:m<-90&&(m+=180),{reason:null,resolved:{opening:e,host:s,partition:a,center:[a.a[0]+l*s.t,a.a[1]+c*s.t],angle:m,length:d,depth:Oo(a.cm,n,r),t:s.t,axis:{a:[a.a[0],a.a[1]],b:[a.b[0],a.b[1]],ux:p,uy:_,length:h}}}}function Ju(e,t,i=1,n=5,r=5){return Zu(e,t,i,n,r,0)}function Qu(e,t,i=1,n=5,r=5){const o=e.host,s="partition"===o?.kind?t.find(e=>e.id===o.id):void 0;if(!s)return Ju(e,t,i,n,r);const a=Zu(e,t,i,n,r,Xu(s,n,r));return"does-not-fit"===a.reason?{resolved:null,reason:"does-not-fit-jamb"}:a}function ep(e,t){return!e||(e.length!==t.length||e.host?.kind!==t.host?.kind||e.host?.id!==t.host?.id||e.host?.t!==t.host?.t)}function tp(e){const{center:t,length:i,axis:n,host:r}=e,o=i/2;return{hostId:r.id,a:[t[0]-n.ux*o,t[1]-n.uy*o],b:[t[0]+n.ux*o,t[1]+n.uy*o],depth:e.depth}}function ip(e,t=!1){const i=t?1:-1,n=e.depth/2;return{ox:-e.axis.uy*i*n,oy:e.axis.ux*i*n,cm:e.partition.cm,side:i}}function np(e,t,i){return e.flatMap(e=>!Yu(e.a)||!Yu(e.b)||Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])<=1e-9?[]:[{roomId:"",a:[e.a[0],e.a[1]],b:[e.b[0],e.b[1]],key:`partition:${e.id}`,kind:"outer",cm:e.cm,open:!1,half:Oo(e.cm,t,i)/2,partitionHost:{kind:"partition",id:e.id}}])}function rp(e,t,i){const{center:n,length:r,axis:o}=e,s=r/2,a=t.flatMap(e=>{if(!e.kind||e.open)return[];const t=e.b[0]-e.a[0],r=e.b[1]-e.a[1],a=Math.hypot(t,r);if(!(a>i))return[];const l=t/a,c=r/a;if(Math.abs(o.ux*c-o.uy*l)>1e-6)return[];if(Math.abs((n[0]-e.a[0])*c-(n[1]-e.a[1])*l)>i)return[];const h=e=>(e[0]-n[0])*o.ux+(e[1]-n[1])*o.uy,d=h(e.a),u=h(e.b),p=Math.max(-s,Math.min(d,u)),_=Math.min(s,Math.max(d,u));return _>=p-i?[[p,_]]:[]});if(!a.length)return!1;a.sort((e,t)=>e[0]-t[0]||e[1]-t[1]);let l=-s;for(const[e,t]of a){if(e>l+i)return!1;if(l=Math.max(l,t),l>=s-i)return!0}return!1}function op(e,t,i=1e-9){const n=e.length/(2*e.axis.length),r=e.t-n,o=e.t+n;return t.some(t=>{if(t.host.id!==e.host.id||t.opening.id===e.opening.id)return!1;const n=t.length/(2*t.axis.length);return Math.max(r,t.t-n)ha-icon{align-self:start;color:var(--hp-accent);}.version-recovery-copy{min-width:0;display:flex;flex-direction:column;gap:var(--sp-2);font-size:var(--fs-m);line-height:1.35;}.version-recovery-copy>span{color:var(--hp-muted);}.version-recovery-versions{display:flex;flex-wrap:wrap;gap:var(--sp-2) var(--sp-5);}.version-recovery-versions span,.version-recovery-versions b{overflow-wrap:anywhere;}.version-recovery-reload{min-height:44px;white-space:normal;}@keyframes hp-version-recovery-in{from{opacity:0;}to{opacity:1;}}@keyframes hp-version-recovery-out{from{opacity:1;}to{opacity:0;}}@media (max-width:520px){.version-recovery-card{grid-template-columns:auto minmax(0,1fr);}.version-recovery-reload{grid-column:1 / -1;width:100%;}}@keyframes fixedfloor-spin{to{transform:rotate(360deg);}}.spacer{flex:1;}.bootveil{position:absolute;inset:0;z-index:40;display:flex;align-items:center;justify-content:center;background:var(--hp-bg,#16212e);opacity:1;transition:opacity 0.15s ease;pointer-events:none;}.bootveil.off{opacity:0;}.bootveil .boothouse{position:static;width:56px;height:56px;fill:var(--hp-accent);opacity:0.85;animation:hp-boot-pulse 1.3s ease-in-out infinite;}@keyframes hp-boot-pulse{0%,100%{opacity:0.3;transform:scale(0.94);}50%{opacity:0.9;transform:scale(1);}}@media (prefers-reduced-motion:reduce){.bootveil .boothouse{animation:none;opacity:0.7;}.version-recovery.phase-visible,.version-recovery.phase-leaving{animation:none;}}@keyframes hp-pulse-short{0%{transform:scale(1);opacity:0.55;}70%{opacity:0.22;}100%{transform:scale(var(--ripple-scale,1.5));opacity:0;}}@keyframes hp-pulse-short-b{0%{transform:scale(1);opacity:0.55;}70%{opacity:0.22;}100%{transform:scale(var(--ripple-scale,1.5));opacity:0;}}@keyframes hp-pulse-continuous{0%{transform:scale(1);opacity:0.55;}65%{opacity:0.18;}100%{transform:scale(var(--ripple-scale,1.5));opacity:0;}}@keyframes hp-pulse-alarm{0%{transform:scale(1);opacity:0.72;}100%{transform:scale(1.5);opacity:0;}}@keyframes hp-slide-left{0%{transform:translateX(4%);opacity:0.72;}100%{transform:translateX(0);opacity:1;}}@keyframes hp-slide-right{0%{transform:translateX(-4%);opacity:0.72;}100%{transform:translateX(0);opacity:1;}}@keyframes hp-sunfade-in{from{opacity:0;}to{opacity:1;}}@keyframes hp-sunfade-out{from{opacity:1;}to{opacity:0;}}.sr-only{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0,0,0,0) !important;white-space:nowrap !important;border:0 !important;}.toast{position:fixed;pointer-events:none;left:50%;bottom:22px;transform:translateX(-50%);background:var(--hp-bg);border:1px solid var(--hp-accent);color:var(--hp-txt);padding:var(--sp-4) var(--sp-6);border-radius:var(--rad-l);font-size:var(--fs-m);box-shadow:var(--shadow-2);z-index:120;max-width:90vw;}`,o`.fixedfloor-loading{animation:fixedfloor-spin 1.1s linear infinite;}.fixedfloor-error p{max-width:42rem;margin:0;overflow-wrap:anywhere;}@media (prefers-reduced-motion:reduce){.fixedfloor-loading{animation:none;}.radar-target{transition:none;}}.stage.noplan{background:#ffffff;}.stage.mode-plan,.stage.mode-devices,.stage.mode-decor{background:#ffffff;}.stage{position:relative;width:100%;container-type:inline-size;overflow:hidden;touch-action:none;background:var(--ha-card-background,var(--card-background-color,#111));}.zoomwrap{position:absolute;inset:0;z-index:1;}.stage.mode-transition,.stage.mode-transition .zoomwrap{transition:none !important;}.stage.mode-transition .hp-view-only-layer,.stage.mode-transition .hp-editor-only-layer{pointer-events:none;will-change:opacity;}.stage.mode-transition .hp-paper{fill:var(--hp-mode-paper) !important;}.hp-day-cycle-env{position:absolute;inset:0;z-index:0;overflow:hidden;pointer-events:none;isolation:isolate;}.hp-day-cycle-bg{position:absolute;inset:0;opacity:0;overflow:hidden;transition:opacity 1100ms cubic-bezier(.22,.61,.36,1);}.hp-day-cycle-bg.active{opacity:1;}.hp-day-cycle-sun{position:absolute;left:var(--hp-day-cycle-sun-x);top:var(--hp-day-cycle-sun-y);width:clamp(140px,25cqw,250px);height:clamp(140px,25cqw,250px);transform:translate(-50%,-50%);border-radius:50%;filter:blur(10px);opacity:var(--hp-day-cycle-sun-opacity);transition:left 1100ms cubic-bezier(.22,.61,.36,1),top 1100ms cubic-bezier(.22,.61,.36,1),opacity 1100ms cubic-bezier(.22,.61,.36,1);}.stage.mode-transition .hp-day-cycle-env{transition:none;}.stage.daycycle .hp-paperg,.stage.daycycle.hp-safe-daycycle-outline .hp-paper-outline-svg,.hp-static-stage.daycycle .hp-paper-outline-svg{filter:drop-shadow(0 0 1px var(--hp-day-cycle-outline-near)) drop-shadow(0 0 5px var(--hp-day-cycle-outline-mid)) drop-shadow(0 0 10px var(--hp-day-cycle-outline-far));will-change:filter;transition:filter 1100ms cubic-bezier(.22,.61,.36,1);}.stage.daycycle.hp-safe-daycycle-outline .hp-paperg{filter:none;will-change:auto;transition:none;}.hp-static-stage.daycycle .hp-paperg{filter:none;will-change:auto;transition:none;}.stage.daycycle.hp-safe-daycycle-outline .hp-paper-outline-svg{transition:none;}.stage.daycycle.hp-safe-daycycle-outline .plan-svg{will-change:transform;}@media (prefers-reduced-motion:reduce){.hp-day-cycle-bg,.hp-day-cycle-sun,.stage.daycycle .hp-paperg,.stage.daycycle.hp-safe-daycycle-outline .hp-paper-outline-svg,.hp-static-stage.daycycle .hp-paper-outline-svg{transition:none;}}.sunlayer{pointer-events:none;}.compass{touch-action:none;cursor:grab;user-select:none;}.compass:active{cursor:grabbing;}.stage.hpboot .zoomwrap,.stage.hpboot .zoombadge{visibility:hidden;}.stage.hpsettle{transition:height 0.25s ease;}@media (prefers-reduced-motion:reduce){.stage.hpsettle{transition:none;}}.zoomctl{display:inline-flex;gap:var(--sp-1);background:rgba(127,127,127,0.12);border-radius:var(--rad-m);padding:var(--sp-1);}.zoomctl .zb{border:none;padding:var(--sp-3) var(--sp-4);}.zoomctl .zb[disabled]{opacity:0.4;pointer-events:none;}.projection-toggle{min-width:44px;min-height:44px;justify-content:center;padding:var(--sp-3);}.header-action{min-width:44px;min-height:44px;justify-content:center;padding:var(--sp-3);}.homearrow{position:absolute;z-index:12;transform:translate(-50%,-50%);width:40px;height:40px;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;background:var(--card-background-color,var(--hp-bg));color:var(--hp-accent);border:1px solid var(--hp-accent);opacity:0.9;padding:0;}.homearrow ha-icon{--mdc-icon-size:22px;line-height:1;}.zoombadge{position:absolute;z-index:12;left:var(--sp-4);bottom:var(--sp-4);background:var(--card-background-color,var(--hp-bg));opacity:0.92;color:var(--hp-txt);border:1px solid var(--hp-accent);border-radius:var(--rad-m);padding:var(--sp-1) var(--sp-4);font-size:var(--fs-s);font-weight:600;pointer-events:none;}.zoomwrap>svg{position:absolute;inset:0;width:100%;height:100%;display:block;}.plan-svg{z-index:1;}.hp-paper-outline-svg{z-index:0;overflow:visible;pointer-events:none;visibility:hidden;}.stage.hp-safe-daycycle-outline .hp-paper-outline-svg{visibility:visible;}.hp-static-stage .hp-paper-outline-svg{visibility:visible;}.iso-underlay-svg{z-index:0;overflow:visible;}.iso-shadows-svg{z-index:3;overflow:visible;}.iso-walls-svg{z-index:4;overflow:visible;}.iso-overlays-svg{z-index:5;overflow:visible;}.iso-underlay-svg,.iso-shadows-svg,.iso-walls-svg,.iso-overlays-svg,.iso-underlay,.iso-shadows,.iso-walls,.iso-openings{pointer-events:none;}.iso-side-hi{stop-color:#b9bdbe;}.iso-side-lo{stop-color:#969c9f;}.iso-top-hi{stop-color:#fafaf7;}.iso-top-lo{stop-color:#e2e4e2;}.iso-wall-side{fill:url(#hp-iso-wall-side) #a8acae;stroke:#92989b;stroke-width:0.7;vector-effect:non-scaling-stroke;}.iso-wall-top{fill:url(#hp-iso-wall-top) #f3f3f1;stroke:#d7d9d8;stroke-width:0.8;vector-effect:non-scaling-stroke;}.iso-material-texture{fill:url(#hp-iso-wall-texture);stroke:none;opacity:0.12;pointer-events:none;}.iso-floor-texture{fill:url(#hp-iso-floor-texture);opacity:0.1;}.iso-texture-mark{fill:rgba(36,43,47,0.34);}.iso-texture-line{fill:none;stroke:rgba(36,43,47,0.24);stroke-width:0.55;}.iso-floor-side{fill:#858b8d;stroke:#71787b;stroke-width:0.7;vector-effect:non-scaling-stroke;}.iso-opening-panel{fill:#d7d9d7;fill-opacity:0.96;stroke:#7f878b;stroke-width:0.9;vector-effect:non-scaling-stroke;}.iso-opening-panel.iso-window{fill:#dfeff4;fill-opacity:0.72;stroke:#8aa7b1;}.iso-opening-panel.iso-material-reveal{fill:#c7cbca;stroke:#8b9294;}.iso-opening-panel.iso-material-matte-leaf{fill:#a6abad;stroke:none;}.iso-opening-panel.iso-opening-leaf-edge,.iso-opening-panel.iso-opening-leaf-top{fill:#8d9497;}.iso-opening-panel.iso-material-light-frame,.iso-opening-panel.iso-material-light-sill{fill:#fffef8;fill-opacity:0.94;stroke:#b3b5ae;}.iso-opening-panel.iso-material-light-window,.iso-opening-panel.iso-material-glass-side{fill:#c9e4f3;fill-opacity:0.88;stroke:#8fb4c7;}.iso-opening-panel.iso-material-glass-top{fill:#e3f2fa;fill-opacity:0.96;stroke:#9fc4d5;}.iso-ambient-shadow{fill:rgba(15,21,25,0.22);filter:url(#hp-iso-ambient-shadow);}.stage.theme-dark .iso-side-hi{stop-color:#4c555a;}.stage.theme-dark .iso-side-lo{stop-color:#343c40;}.stage.theme-dark .iso-top-hi{stop-color:#687176;}.stage.theme-dark .iso-top-lo{stop-color:#50585d;}.stage.theme-dark .iso-wall-side{stroke:#30373b;}.stage.theme-dark .iso-wall-top{stroke:#7b858a;}.stage.theme-dark .iso-floor-side{fill:#2d3438;stroke:#20272a;}.stage.theme-dark .iso-opening-panel{fill:#626b70;stroke:#899399;}.stage.theme-dark .iso-opening-panel.iso-window{fill:#75919b;stroke:#abc6ce;}.stage.theme-dark .iso-opening-panel.iso-material-reveal{fill:#454e52;stroke:#727d82;}.stage.theme-dark .iso-opening-panel.iso-material-matte-leaf{fill:#626a6e;stroke:none;}.stage.theme-dark .iso-opening-panel.iso-opening-leaf-edge,.stage.theme-dark .iso-opening-panel.iso-opening-leaf-top{fill:#4b5458;}.stage.theme-dark .iso-opening-panel.iso-material-light-frame,.stage.theme-dark .iso-opening-panel.iso-material-light-sill{fill:#e8e7df;stroke:#a9aca7;}.stage.theme-dark .iso-opening-panel.iso-material-light-window,.stage.theme-dark .iso-opening-panel.iso-material-glass-side{fill:#8fbfd5;stroke:#bad9e6;}.stage.theme-dark .iso-opening-panel.iso-material-glass-top{fill:#c9e6f2;stroke:#d9eef6;}.stage.theme-dark .iso-ambient-shadow{fill:rgba(0,0,0,0.34);}.stage.theme-dark .iso-texture-mark{fill:rgba(255,255,255,0.24);}.stage.theme-dark .iso-texture-line{stroke:rgba(255,255,255,0.18);}@media (prefers-color-scheme:dark){.stage:not(.theme-light) .iso-side-hi{stop-color:#4c555a;}.stage:not(.theme-light) .iso-side-lo{stop-color:#343c40;}.stage:not(.theme-light) .iso-top-hi{stop-color:#687176;}.stage:not(.theme-light) .iso-top-lo{stop-color:#50585d;}.stage:not(.theme-light) .iso-wall-side{stroke:#30373b;}.stage:not(.theme-light) .iso-wall-top{stroke:#7b858a;}.stage:not(.theme-light) .iso-floor-side{fill:#2d3438;stroke:#20272a;}.stage:not(.theme-light) .iso-opening-panel{fill:#626b70;stroke:#899399;}.stage:not(.theme-light) .iso-opening-panel.iso-window{fill:#75919b;stroke:#abc6ce;}.stage:not(.theme-light) .iso-opening-panel.iso-material-reveal{fill:#454e52;stroke:#727d82;}.stage:not(.theme-light) .iso-opening-panel.iso-material-matte-leaf{fill:#626a6e;stroke:none;}.stage:not(.theme-light) .iso-opening-panel.iso-opening-leaf-edge,.stage:not(.theme-light) .iso-opening-panel.iso-opening-leaf-top{fill:#4b5458;}.stage:not(.theme-light) .iso-opening-panel.iso-material-light-frame,.stage:not(.theme-light) .iso-opening-panel.iso-material-light-sill{fill:#e8e7df;stroke:#a9aca7;}.stage:not(.theme-light) .iso-opening-panel.iso-material-light-window,.stage:not(.theme-light) .iso-opening-panel.iso-material-glass-side{fill:#8fbfd5;stroke:#bad9e6;}.stage:not(.theme-light) .iso-opening-panel.iso-material-glass-top{fill:#c9e6f2;stroke:#d9eef6;}.stage:not(.theme-light) .iso-ambient-shadow{fill:rgba(0,0,0,0.34);}.stage:not(.theme-light) .iso-texture-mark{fill:rgba(255,255,255,0.24);}.stage:not(.theme-light) .iso-texture-line{stroke:rgba(255,255,255,0.18);}}@media (forced-colors:active){.iso-wall-side,.iso-wall-top,.iso-floor-side,.iso-opening-panel{fill:Canvas;stroke:CanvasText;forced-color-adjust:auto;}.iso-ambient-shadow,.iso-material-texture{display:none;}}@supports not (filter:blur(1px)){.iso-ambient-shadow,.iso-material-texture{display:none;}}.hp-paper{fill:var(--ha-card-background,var(--card-background-color,#111));stroke:none;}.stage.noplan .hp-paper,.stage.mode-plan .hp-paper,.stage.mode-devices .hp-paper,.stage.mode-decor .hp-paper{fill:#ffffff;}.room{transition:0.12s;cursor:default;stroke-linejoin:round;stroke-linecap:round;}.stage.mode-view .room{cursor:pointer;}.room.overlay{fill:transparent;stroke:transparent;stroke-width:calc(2px * var(--hp-cell-visual-scale,1));}:host([data-pointer-hover]) .stage.mode-view .room.overlay:not(.styled):hover{stroke:var(--hp-accent);stroke-opacity:1;}.room.yard{fill:rgba(75,140,90,0.14);stroke:#4b8c5a;stroke-width:calc(2px * var(--hp-cell-visual-scale,1));}:host([data-pointer-hover]) .stage.mode-view .room.yard:not(.styled):hover{stroke:var(--hp-accent);stroke-opacity:1;}.room.styled{stroke:var(--room-stroke,transparent);stroke-opacity:var(--room-stroke-op,0);stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));fill:var(--room-fill,transparent);fill-opacity:var(--room-fill-op,0);}.glow-base-layer,.glow-base-tunnels,.glow-pools-frame,.glow-pools,.glow-spot{pointer-events:none;}.glow-pools-frame,.glow-pools,.glow-spot{isolation:isolate;}.glow-pools.blend-screen .glow-spot{mix-blend-mode:screen;}.glow-spot{opacity:1;transition:opacity 500ms ease;}.glow-spot.is-entering,.glow-spot.is-leaving{opacity:0;}@media (prefers-reduced-motion:reduce){.glow-spot{transition:none;}}:host([data-pointer-hover]) .stage.mode-view .room.styled:hover{stroke:var(--hp-accent);stroke-opacity:1;}.op-leaf{transition:transform 0.6s ease;}.op-arc{stroke-width:calc(1.5px * var(--hp-cell-visual-scale,1));transition:stroke-dashoffset 0.6s ease;}.op-outline{fill:none;stroke:var(--hp-accent);stroke-width:calc(1.5px * var(--hp-cell-visual-scale,1));opacity:0;transition:opacity 0.15s;pointer-events:none;}:host([data-pointer-hover]) .stage.markup g.opening:hover .op-outline{opacity:0.9;}.op-hit{fill:transparent;pointer-events:none;cursor:default;}.stage.markup .op-hit{pointer-events:auto;cursor:grab;touch-action:none;}.stage.markup .op-hit:active{cursor:grabbing;}.stage.markup .opening.orphan{pointer-events:auto;cursor:pointer;color:var(--error-color,#db4437);}.stage.markup .opening.orphan circle{fill:var(--hp-bg);stroke:currentColor;stroke-width:calc(2px * var(--hp-cell-visual-scale,1));}.stage.markup .opening.orphan text{fill:currentColor;font-weight:800;font-size:calc(12px * var(--hp-cell-visual-scale,1));pointer-events:none;}.stage.markup.tool-resize .op-hit{pointer-events:none;cursor:default;}.stage.mode-view .oplock{pointer-events:auto;cursor:pointer;}.stage.projection-iso.mode-view .oplock::before{content:'';position:absolute;left:50%;top:50%;width:max(44px,100%);height:max(44px,100%);transform:translate(-50%,-50%);border-radius:50%;pointer-events:auto;}@media (prefers-reduced-motion:reduce){.op-leaf,.op-arc{transition:none;}}.roomlabel{pointer-events:none;position:absolute;transform:translate(-50%,-50%);font-size:calc(var(--rl-icon-size,var(--icon-size,2.5cqw)) * 0.5 * var(--rl-scale,1) * var(--rl-font,1) * var(--rl-space,1));font-weight:700;letter-spacing:0.04em;white-space:nowrap;cursor:grab;user-select:none;z-index:1;display:flex;flex-direction:column;align-items:center;gap:0.15em;text-align:center;}.rlname{display:inline-flex;align-items:center;gap:0.25em;font-size:calc(1em * var(--rl-name,1));}.zoomwrap.slide-left{animation:hp-slide-left 0.18s cubic-bezier(0.2,0.7,0.2,1);}.zoomwrap.slide-right{animation:hp-slide-right 0.18s cubic-bezier(0.2,0.7,0.2,1);}@media (prefers-reduced-motion:reduce){.zoomwrap.slide-left,.zoomwrap.slide-right{animation:none;}}.rlgearbtn{--gear-h:calc(var(--icon-size,2.5cqw) * 0.77);position:absolute;transform:translate(-50%,-50%);display:inline-flex;align-items:center;gap:0.35em;height:var(--gear-h);padding:0 calc(var(--gear-h) * 0.38);border:0;border-radius:999px;background:var(--hp-accent);color:var(--text-primary-color,#fff);font:inherit;font-size:calc(var(--gear-h) * 0.42);font-weight:600;line-height:1;white-space:nowrap;cursor:pointer;pointer-events:auto;opacity:0.92;box-shadow:var(--shadow-1);z-index:2;}.rlgearbtn{transition:opacity 0.15s,filter 0.15s;}:host([data-pointer-hover]) .rlgearbtn:hover{opacity:1;filter:brightness(1.18);}.rlgearbtn ha-icon{--mdc-icon-size:calc(var(--gear-h) * 0.55);display:inline-flex;}.rlgear{--mdc-icon-size:0.9em;display:inline-flex;margin-right:0.2em;opacity:0.6;cursor:pointer;pointer-events:auto;}:host([data-pointer-hover]) .rlgear:hover{opacity:1;}.rlgo{--mdc-icon-size:0.85em;display:inline-flex;opacity:0.55;}.stage.mode-view .rlgo{pointer-events:auto;cursor:pointer;}:host([data-pointer-hover]) .stage.mode-view .rlgo:hover{opacity:1;}.roomlabel .rlmetrics{position:absolute;top:calc(100% + 0.15em);left:50%;transform:translateX(-50%);white-space:nowrap;display:flex;align-items:center;gap:0.55em;font-size:calc(0.75em * var(--rl-meta,1));font-weight:600;letter-spacing:0.02em;opacity:0.9;}.roomlabel .rlm{display:inline-flex;align-items:center;gap:0.12em;}.roomlabel .rlm ha-icon{--mdc-icon-size:1.05em;display:inline-flex;}.roomlabel .rlm.lit{opacity:1;}.rlhandle{display:none;position:absolute;width:9px;height:9px;border-radius:2px;background:var(--hp-accent);border:1px solid var(--card-background-color,#fff);z-index:2;}.rlhandle.tl{left:-6px;top:-6px;cursor:nwse-resize;}.rlhandle.br{right:-6px;bottom:-6px;cursor:nwse-resize;}.rlhandle.tr{right:-6px;top:-6px;cursor:nesw-resize;}.rlhandle.bl{left:-6px;bottom:-6px;cursor:nesw-resize;}:host([data-pointer-hover]) .stage.markup .roomlabel:hover .rlhandle{display:block;}.stage.markup .roomlabel{pointer-events:auto;}.stage.mode-view .roomlabel{pointer-events:auto;cursor:pointer;border-radius:0.2em;}.stage.projection-iso.mode-view .roomlabel{box-sizing:border-box;min-width:44px;min-height:44px;justify-content:center;text-shadow:none;filter:none;-webkit-text-stroke:0 transparent;color:#303936 !important;}.stage.projection-iso.mode-view .dev,.stage.projection-iso.mode-view .oplock{z-index:2;}.stage.projection-iso.theme-dark.mode-view .roomlabel{color:#f2f0e8 !important;}@media (prefers-color-scheme:dark){.stage.projection-iso:not(.theme-light).mode-view .roomlabel{color:#f2f0e8 !important;}}.stage.mode-view .roomlabel:focus-visible{outline:2px solid var(--hp-accent);outline-offset:4px;}.roomlabel:active{cursor:grabbing;}.measurelayer{position:absolute;inset:0;pointer-events:none;}.alignline{stroke:var(--hp-accent);stroke-width:calc(1.2px * var(--hp-cell-visual-scale,1));stroke-dasharray:calc(4px * var(--hp-cell-visual-scale,1)) calc(4px * var(--hp-cell-visual-scale,1));pointer-events:none;opacity:0.9;}.aligndot{fill:var(--hp-accent);pointer-events:none;}.measurelabel.on45{color:#4bd28f;border-color:#4bd28f;}.measurelabel{position:absolute;transform:translate(12px,-150%);font-size:var(--fs-s);font-weight:600;padding:1px var(--sp-3);border-radius:var(--rad-s);background:rgba(0,0,0,0.72);color:#fff;white-space:nowrap;pointer-events:none;user-select:none;z-index:3;}.measurelabel.opdimension{transform:translate(calc(-50% + var(--op-label-shift-x,0px)),calc(-50% + var(--op-label-shift-y,-12px)));border:1px solid var(--hp-open,#ff9800);}.decorlayer .dshape{pointer-events:none;}.stage.mode-decor .decorlayer .dshape{pointer-events:visiblePainted;cursor:pointer;}.stage.mode-decor.dtool-select .decorlayer .dshape{cursor:move;}.stage.mode-decor.dtool-line .decorlayer .dshape,.stage.mode-decor.dtool-rect .decorlayer .dshape,.stage.mode-decor.dtool-ellipse .decorlayer .dshape,.stage.mode-decor.dtool-text .decorlayer .dshape,.stage.mode-decor.dtool-furniture .decorlayer .dshape,.stage.mode-decor.dtool-image .decorlayer .dshape,.stage.mode-decor.dtool-backdrop .decorlayer .dshape{pointer-events:none;}.stage.mode-decor.dtool-furniture,.stage.mode-decor.dtool-image{cursor:copy;}.stage.mode-decor.dtool-select .decorlayer .dimage,.stage.mode-decor.dtool-erase .decorlayer .dimage,.stage.mode-decor.dtool-select .decorlayer .dimage-missing,.stage.mode-decor.dtool-erase .decorlayer .dimage-missing{pointer-events:bounding-box;}.decorlayer .dimage-missing rect{fill:rgba(127,127,127,0.12);stroke:var(--hp-accent);stroke-dasharray:8 5;vector-effect:non-scaling-stroke;}.decorlayer .dimage-missing path{fill:none;stroke:var(--hp-accent);vector-effect:non-scaling-stroke;}.decorlayer .decor-image-placement-preview{opacity:0.65;}.stage.mode-decor.dtool-text .decorlayer .dshape.dtext,.stage.mode-decor.dtool-select .decorlayer .dshape.dtext,.stage.mode-decor.dtool-erase .decorlayer .dshape.dtext{pointer-events:visiblePainted;pointer-events:bounding-box;}.stage.mode-decor.dtool-text .decorlayer .dshape.dtext{cursor:text;}.decorlayer .derasehit{fill:none;stroke:transparent;stroke-width:16px;stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke;pointer-events:none;}.stage.mode-decor.dtool-erase .decorlayer .derasehit{pointer-events:stroke;}.decorlayer .dselecthit{fill:none;stroke:transparent;stroke-width:16px;stroke-linecap:round;vector-effect:non-scaling-stroke;pointer-events:none;}.stage.mode-decor.dtool-select .decorlayer .dselecthit{pointer-events:stroke;cursor:move;}.stage.mode-decor .decorlayer .dshape.dfurniturehit{fill:none;stroke:transparent;pointer-events:none;}.stage.mode-decor.dtool-select .decorlayer .dshape.dfurniturehit{pointer-events:stroke;cursor:move;}.decorlayer .dsel{filter:drop-shadow(0 0 3px var(--hp-accent));}.decorlayer .ddraft{stroke-dasharray:calc(6px * var(--hp-cell-visual-scale,1)) calc(5px * var(--hp-cell-visual-scale,1));pointer-events:none;}.decorlayer .furniture-placement-preview{opacity:0.55;pointer-events:none;}.decorlayer text{font-weight:600;user-select:none;dominant-baseline:middle;text-anchor:middle;}.stage.mode-decor{outline:2px solid #26a69a;outline-offset:-2px;}.bdframe .bdbox{fill:none;stroke:var(--hp-accent);stroke-width:2;stroke-dasharray:10 7;vector-effect:non-scaling-stroke;pointer-events:none;opacity:0.9;}.bdframe .bdhandle{fill:transparent;stroke:none;pointer-events:all;touch-action:none;}.bdframe .bdknob{fill:var(--hp-accent);stroke:#fff;stroke-width:1;vector-effect:non-scaling-stroke;pointer-events:none;}:host([data-pointer-hover]) .bdframe .bdhandle:hover + .bdknob{fill:#fff;stroke:var(--hp-accent);}.bdframe .bd-nwse{cursor:nwse-resize;}.bdframe .bd-nesw{cursor:nesw-resize;}.stage.mode-decor.bdgrab{cursor:grab;}.stage.mode-decor.bdgrabbing,.stage.mode-decor.bdgrabbing .bdframe .bdhandle{cursor:grabbing;}.measurelabel.bdmeasure{transform:translate(-50%,-50%);border:1px solid var(--hp-accent);}.dtframe .dtbox{fill:none;stroke:var(--hp-accent);stroke-width:1.5;stroke-dasharray:7 5;vector-effect:non-scaling-stroke;pointer-events:none;opacity:0.85;}.dtframe .dtstem,.bdframe .dtstem{stroke:var(--hp-accent);stroke-width:1.5;vector-effect:non-scaling-stroke;pointer-events:none;opacity:0.85;}.dtframe .dthandle{fill:transparent;stroke:none;pointer-events:all;touch-action:none;}.dtframe .dtknob{fill:var(--hp-accent);stroke:#fff;stroke-width:1;vector-effect:non-scaling-stroke;pointer-events:none;}:host([data-pointer-hover]) .dtframe .dthandle:hover + .dtknob{fill:#fff;stroke:var(--hp-accent);}.dtframe .dt-nwse{cursor:nwse-resize;}.dtframe .dt-nesw{cursor:nesw-resize;}.dtframe .dtrot{cursor:grab;}.dtframe .dt-ew{cursor:ew-resize;}.dtframe .dt-ns{cursor:ns-resize;}.dtfurnitureframe .dtrot{cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M18.4 7.2A8 8 0 1 0 20 12' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'/%3E%3Cpath d='m15.5 3.8 3.2 3.5-4.6.8' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 12 12,grab;}.dtfurnitureframe .dtrot:active{cursor:grabbing;}.dtframe .dtendpoint{cursor:crosshair;}.bdframe .dtrot{cursor:grab;}.dtarea{resize:vertical;min-height:3.4em;font:inherit;line-height:1.35;}.stage.mode-decor.dtool-line,.stage.mode-decor.dtool-rect,.stage.mode-decor.dtool-ellipse,.stage.mode-decor.dtool-text{cursor:crosshair;}.stage.mode-decor.dtool-erase,.stage.mode-decor.dtool-erase .decorlayer .dshape{cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg transform='rotate(-45 12 12)'%3E%3Crect x='7' y='2' width='10' height='18' rx='2' fill='%23fff' stroke='%23111' stroke-width='1.5'/%3E%3Cpath d='M7 13h10v5a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2z' fill='%23ff9f43' stroke='%23111' stroke-width='1.5'/%3E%3C/g%3E%3C/svg%3E") 5 22,pointer;}.stage.mode-decor .room{pointer-events:none;}.stage.mode-decor .devlayer,.stage.mode-decor .devlayer *,.stage.mode-decor .dev::before{pointer-events:none;}.stage .room,.stage .devlayer,.stage .opening,.stage .room-outline,.stage .wallbodies,.stage .opening-tunnels,.stage .glow-base-layer,.stage .glow-pools-frame,.stage .zero-walls{opacity:var(--hp-mode-architecture-opacity,1);}.opening-preview{opacity:0.5;pointer-events:none;}.opening-preview[data-kind="passage"]{opacity:1;}.passage-preview-cut{fill:var(--wall-fill,#ffffff);fill-opacity:0.35;stroke:none;pointer-events:none;}.passage-preview-boundary{stroke:var(--hp-open,#ff9800);stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));pointer-events:none;}.opening-preview .op-leaf,.opening-preview .op-arc{transition:none;}.opening-preview-dot{fill:var(--hp-open,#ff9800);pointer-events:none;}.opening-dimensions,.opening-dimension{pointer-events:none;}.opening-dimension-line,.opening-dimension-tick{fill:none;stroke:var(--hp-open,#ff9800);stroke-width:1.5;vector-effect:non-scaling-stroke;pointer-events:none;}.opening-dimension-tick{stroke-width:2;}.stage.edit .room{pointer-events:none;}.stage.markup{cursor:crosshair;}.stage.markup.tool-merge,.stage.markup.tool-split.pickstage,.stage.markup.tool-delroom{cursor:pointer;}.stage.markup.tool-wallthick{cursor:default;}.stage.markup.tool-wallthick.wallhot{cursor:pointer;}.wallbody-fill{fill:var(--wall-fill,#ffffff);fill-opacity:var(--wall-fill-op,1);fill-rule:evenodd;stroke:none;pointer-events:none;}.wallbody{fill:url(#hp-wall-hatch);fill-rule:evenodd;stroke:var(--room-stroke,var(--hp-muted));stroke-width:calc(0.6px * var(--hp-cell-visual-scale,1));pointer-events:none;}.wallbody.solid{fill:none;}.wallthick-hover{fill:var(--accent-color,#03a9f4);fill-opacity:0.38;stroke:var(--accent-color,#03a9f4);stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));stroke-linejoin:round;stroke-linecap:round;pointer-events:none;}.wallthick-hover.isopen{fill:var(--error-color,#f44336);stroke:var(--error-color,#f44336);}.zero-wall{stroke:var(--zero-wall-stroke,var(--hp-muted));stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));stroke-dasharray:calc(7px * var(--hp-cell-visual-scale,1)) calc(7px * var(--hp-cell-visual-scale,1));stroke-linecap:butt;pointer-events:none;opacity:0.9;}.zero-walls.solid .zero-wall{stroke-dasharray:none;}.room.noedge{stroke-opacity:0 !important;}.room-outline{fill:none;stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));stroke-linejoin:round;stroke-linecap:round;pointer-events:none;}.room-outline.outlined{stroke:rgba(62,166,255,0.55);stroke-opacity:1;}.room-hover-fill{fill:#000;fill-opacity:0.22;pointer-events:none;}.room-hover-halo{fill:none;stroke:var(--hp-accent);stroke-opacity:0.28;stroke-width:calc(8px * var(--hp-cell-visual-scale,1));stroke-linejoin:round;stroke-linecap:round;pointer-events:none;}.room-hover-outline{fill:none;stroke:var(--hp-accent);stroke-width:calc(3px * var(--hp-cell-visual-scale,1));stroke-linejoin:round;stroke-linecap:round;pointer-events:none;}.stage.markup .room{pointer-events:none;}.stage.markup .devlayer .dev{display:none;}.stage.mode-plan{outline:2px solid #ffc14d;outline-offset:-2px;}.stage.mode-devices{outline:2px solid var(--hp-accent);outline-offset:-2px;}.room.outlined{stroke:rgba(62,166,255,0.55);fill:rgba(62,166,255,0.06);}.room.picked{stroke:#ffc14d;stroke-width:calc(3px * var(--hp-cell-visual-scale,1));fill:rgba(255,193,77,0.25);}.griddot{fill:var(--hp-accent);opacity:0.35;stroke:rgba(0,0,0,0.35);stroke-width:0.4;}.griddot.major{opacity:0.5;stroke-width:0;}.seg{stroke:var(--hp-accent);stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));stroke-linecap:round;stroke-linejoin:round;}.pathline{stroke:#ffc14d;stroke-width:calc(3px * var(--hp-cell-visual-scale,1));fill:none;stroke-linecap:round;stroke-linejoin:round;}.preview{stroke:#ffc14d;stroke-width:calc(2px * var(--hp-cell-visual-scale,1));stroke-dasharray:calc(6px * var(--hp-cell-visual-scale,1)) calc(5px * var(--hp-cell-visual-scale,1));opacity:0.7;}.active-axis{stroke:#ffc14d;stroke-width:2;stroke-linecap:round;vector-effect:non-scaling-stroke;pointer-events:none;}.active-vertex{fill:#ffc14d;stroke:#171006;stroke-width:2;vector-effect:non-scaling-stroke;pointer-events:none;}.wall-repair-preview{stroke:#d93025;stroke-width:4;stroke-linecap:round;stroke-dasharray:5 4;vector-effect:non-scaling-stroke;pointer-events:none;}.drawwall-preview-fill{fill:var(--wall-fill,#ffffff);fill-opacity:calc(var(--wall-fill-op,1) * 0.55);fill-rule:evenodd;stroke:none;pointer-events:none;}.drawwall-preview{fill:url(#hp-wall-hatch);fill-opacity:0.55;fill-rule:evenodd;stroke:var(--accent-color,#03a9f4);stroke-width:calc(0.5px * var(--hp-cell-visual-scale,1));stroke-opacity:0.7;pointer-events:none;}.drawwall-zero-preview{fill:none;stroke:var(--accent-color,#03a9f4);stroke-width:calc(3px * var(--hp-cell-visual-scale,1));stroke-linecap:butt;stroke-linejoin:round;opacity:0.72;pointer-events:none;}.drawwall-zero-preview.dashed{stroke-dasharray:calc(7px * var(--hp-cell-visual-scale,1)) calc(7px * var(--hp-cell-visual-scale,1));}.vertex{fill:#ffc14d;stroke:#4a2800;stroke-width:calc(1px * var(--hp-cell-visual-scale,1));}.vertex.first{fill:#4bd28f;stroke:#04121f;}.plan-snap-overlay,.plan-snap-overlay *,.hidden-wall-diagnostic,.hidden-wall-diagnostic *{pointer-events:none;}.plan-snap-line,.hidden-wall-line{fill:none;stroke:color-mix(in srgb,var(--hp-accent) 82%,white 18%);stroke-width:1;stroke-linecap:round;opacity:0.92;}.plan-snap-node,.hidden-wall-node{fill:var(--ha-card-background,var(--card-background-color,#fff));stroke:color-mix(in srgb,var(--hp-accent) 88%,#07131c 12%);stroke-width:1;vector-effect:non-scaling-stroke;}.plan-snap-node.active{fill:#ffc14d;stroke:#171006;stroke-width:2;}.plan-snap-node.active.dynamic{fill:#4bd28f;stroke:#04121f;}.plan-snap-node.conflict{fill:#fff;stroke:#d93025;stroke-width:3;}@media (prefers-color-scheme:dark){.plan-snap-line{stroke:color-mix(in srgb,var(--hp-accent) 72%,white 28%);}.hidden-wall-line{stroke:color-mix(in srgb,var(--hp-accent) 72%,white 28%);}.plan-snap-node,.hidden-wall-node{fill:#17242c;stroke:#9bdcf5;}.plan-snap-node.active{fill:#ffc14d;stroke:#fff4d6;}.plan-snap-node.active.dynamic{fill:#4bd28f;stroke:#eafff4;}}@media (forced-colors:active){.plan-snap-line,.hidden-wall-line{stroke:CanvasText;opacity:1;forced-color-adjust:auto;}.plan-snap-node,.hidden-wall-node{fill:Canvas;stroke:CanvasText;forced-color-adjust:auto;}.plan-snap-node.active,.plan-snap-node.active.dynamic{fill:Highlight;stroke:HighlightText;forced-color-adjust:auto;}}.sunlayer{animation:hp-sunfade-in 2s linear both;}.sunlayer.out{animation:hp-sunfade-out 2s linear both;}@media (prefers-reduced-motion:reduce){.sunlayer,.sunlayer.out{animation:none;}.sunlayer.out{opacity:0;}}.devlayer{position:absolute;inset:0;pointer-events:none;z-index:6;}.radar-target{position:absolute;width:8px;height:8px;box-sizing:border-box;transform:translate(-50%,-50%);border-radius:50%;background:var(--success-color,#43a047);border:2px solid var(--primary-text-color,#1f1f1f);box-shadow:0 0 0 1px color-mix(in srgb,var(--card-background-color,#fff) 80%,transparent);pointer-events:none;z-index:0;}.radar-target.smooth{transition:left 200ms linear,top 200ms linear;}.radar-ranges{position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none;z-index:0;}.radar-ranges path,.radar-ranges polyline{fill:none;stroke:var(--success-color,#43a047);stroke-width:2px;stroke-dasharray:5 4;vector-effect:non-scaling-stroke;opacity:0.72;}.radar-ranges .radar-zone{fill:color-mix(in srgb,var(--success-color,#43a047) 8%,transparent);stroke:var(--success-color,#43a047);stroke-width:2px;vector-effect:non-scaling-stroke;opacity:0.8;}.stage.mode-devices .dev{cursor:grab;}.stage.mode-devices .dev:active{cursor:grabbing;}.physical-hit{fill:transparent;stroke:transparent;pointer-events:none;cursor:grab;}.stage.tool-select .physical-hit{pointer-events:all;}.physical-hit:active{cursor:grabbing;}line.physical-hit{cursor:pointer;}.physical-hit.selected{fill:rgba(255,193,77,0.24);stroke:transparent;}line.physical-hit.selected{stroke:transparent;}.physical-drag{fill:rgba(255,193,77,0.38);stroke:#ffc14d;stroke-width:2.5;vector-effect:non-scaling-stroke;pointer-events:none;}.physical-chrome{pointer-events:none;}.physical-chrome .frame,.physical-chrome .stem{fill:none;stroke:#ffc14d;stroke-width:2;vector-effect:non-scaling-stroke;}.physical-chrome .frame{fill:rgba(255,193,77,0.22);}.physical-chrome polyline.frame{fill:none;}.physical-chrome .move-dot{fill:#ffc14d;stroke:#24262d;stroke-width:1.5;vector-effect:non-scaling-stroke;}.physical-chrome .rotate-handle{fill:#24262d;stroke:#ffc14d;stroke-width:2.5;vector-effect:non-scaling-stroke;pointer-events:all;cursor:crosshair;}.drawwall.invalid input{border-color:var(--error-color,#db4437);}.drawwall .rangehint{margin-inline-start:4px;font-size:0.78em;opacity:0.72;}.drawwall.invalid .rangehint{color:var(--error-color,#db4437);opacity:1;}.stage.markup.tool-partition,.stage.markup.tool-column{cursor:crosshair;}.rszhandle{fill:transparent;stroke:none;pointer-events:all;cursor:grab;touch-action:none;}.rszhandle:active{cursor:grabbing;}.rszhandle.disabled,.rszhandle.disabled:active{cursor:not-allowed;}.rszicon{pointer-events:none;}.rszicon path{fill:none;stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke;}.rszhalo{stroke:var(--hp-bg);stroke-width:6;}.rszink{stroke:var(--hp-accent);stroke-width:2;}:host([data-pointer-hover]) .rszhandle:hover + .rszicon .rszink{stroke-width:3;}.rszicon.disabled{opacity:0.38;}:host([data-pointer-hover]) .rszhandle.disabled:hover + .rszicon .rszink{stroke-width:2;}.rszmeasurelayer,.rszmeasurelayer *{pointer-events:none;}.rszmeasurehalo,.rszmeasureink,.rszleader{fill:none;stroke-linecap:round;vector-effect:non-scaling-stroke;}.rszmeasurehalo{stroke:var(--hp-bg);stroke-width:7px;opacity:0.9;}.rszmeasureink{stroke:var(--hp-accent);stroke-width:3px;}.rszleader{stroke:var(--hp-accent);stroke-width:2px;opacity:0.95;}.measurelabel.dmeasure{transform:translate(-50%,-160%);}.measurelabel.rszarea{transform:translate(calc(-50% + var(--rsz-label-x,0px)),calc(-50% + var(--rsz-label-y,0px)));background:rgba(0,0,0,0.6);border:1px solid var(--hp-accent);}.measurelabel.furnmeasure{transform:translate(-50%,-50%);border:1px solid var(--hp-accent);}.alignmsg{margin:0 0 8px;font-size:13px;line-height:1.45;}`,o`.dev ha-icon{position:relative;z-index:1;}.device-pulse{position:absolute;left:50%;top:50%;width:var(--dev-size);height:var(--dev-size);transform:translate(-50%,-50%);pointer-events:none;z-index:0;}.device-pulse i{position:absolute;inset:0;border-radius:50%;border:2px solid var(--ripple-color,var(--hp-accent));opacity:0;}.device-pulse.short i{animation:hp-pulse-short 1.1s cubic-bezier(.22,.61,.36,1) 1 forwards;}.device-pulse.short i:nth-child(2){animation-delay:1.1s;}.device-pulse.short i:nth-child(3){animation-delay:2.2s;}.device-pulse.short.gen2 i{animation-name:hp-pulse-short-b;}.device-pulse.continuous i:nth-child(n + 2),.device-pulse.alarm i:nth-child(n + 3){display:none;}.device-pulse.continuous i:first-child{animation:hp-pulse-continuous 3.6s cubic-bezier(.45,.05,.55,.95) infinite;}.device-pulse.alarm i{border-width:3px;border-color:#F0410C;animation:hp-pulse-alarm 2.4s cubic-bezier(.22,.61,.36,1) infinite;}.device-pulse.alarm i:nth-child(2){animation-delay:1.2s;}.activity-dot{position:absolute;right:8%;bottom:8%;width:18%;height:18%;min-width:4px;min-height:4px;border-radius:50%;background:var(--ripple-color,var(--hp-accent));border:1px solid color-mix(in srgb,var(--hp-bg) 82%,transparent);pointer-events:none;z-index:3;}.kioskdots{position:absolute;left:50%;bottom:var(--sp-5);transform:translateX(-50%);display:flex;gap:var(--sp-4);z-index:5;pointer-events:none;}.kdot{width:9px;height:9px;border-radius:50%;background:var(--hp-muted);opacity:0.55;}.kdot.on{background:var(--hp-accent);opacity:1;}.dev.valonly{width:var(--dev-size,var(--icon-size,2.5cqw));}.dev.valonly .device-core{width:max-content;min-width:var(--dev-size,var(--icon-size,2.5cqw));padding-inline:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.16);border-radius:calc(var(--dev-size,var(--icon-size,2.5cqw)) / 2);}.dev .valtext{overflow:visible;font-size:calc(var(--dev-size,var(--icon-size,2.5cqw)) * var(--value-font-scale,.45));font-weight:600;white-space:nowrap;}@media (prefers-reduced-motion:reduce){.device-pulse{display:none;}}.dev .newdot{position:absolute;top:calc(var(--dev-size,var(--icon-size,2.5cqw)) * -0.12);right:calc(var(--dev-size,var(--icon-size,2.5cqw)) * -0.12);width:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.34);height:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.34);border-radius:50%;background:#f0301f;border:2px solid var(--card-background-color,var(--hp-bg));pointer-events:none;z-index:2;}.dev{position:absolute;--dev-size:calc(var(--device-base-size,2.25cqw) * var(--dev-scale,1));--device-shell-size:calc(var(--dev-size) * 1.26875);--device-shell-inset:calc(var(--dev-size) * 0.134375);--device-shell-stroke-ratio:0.01875;--device-shell-border-width:max(1px,calc(var(--dev-size) * var(--device-shell-stroke-ratio)));--device-core-bg:var(--card-background-color,#fff);--device-core-fg:var(--primary-text-color,#252525);--device-core-bg:light-dark(#fff,#252525);--device-core-fg:light-dark(#252525,#fff);--device-face-bg:var(--device-core-bg);--device-face-fg:var(--device-core-fg);--device-shell-base-stroke:light-dark(#BCBCBC,rgb(37 37 37 / 75%));--device-shell-stroke:var(--device-shell-base-stroke);--device-shell-shadow:0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .05) rgb(37 40 45 / 12%),0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%);--device-core-inset-shadow:0 0 0 0 transparent;--device-ring-color:transparent;--device-ring-width:0px;width:var(--dev-size);height:var(--dev-size);margin:calc(var(--dev-size) / -2) 0 0 calc(var(--dev-size) / -2);border:0;background:transparent;display:block;color:var(--device-core-fg);cursor:pointer;pointer-events:none;transition:opacity 0.2s;box-shadow:none;outline:none;z-index:auto;}.dev.theme-light{--device-core-bg:#fff;--device-core-fg:#000;--device-shell-base-stroke:#BCBCBC;--device-shell-stroke:var(--device-shell-base-stroke);--device-shell-shadow:0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .05) rgb(37 40 45 / 12%),0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%);--device-core-inset-shadow:0 0 0 0 transparent;}.dev.theme-dark{--device-core-bg:#252525;--device-core-fg:#fff;--device-shell-base-stroke:rgb(37 37 37 / 75%);--device-shell-stroke:var(--device-shell-base-stroke);--device-shell-shadow:0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .0375) rgb(37 40 45 / 12%),0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%);--device-core-inset-shadow:inset 0 calc(var(--dev-size) * 0.0125) calc(var(--dev-size) * 0.0125) rgb(255 255 255 / 70%);}.dev::before{content:'';position:absolute;left:50%;top:50%;width:max(44px,var(--device-shell-size));height:max(44px,var(--device-shell-size));transform:translate(-50%,-50%);border-radius:50%;pointer-events:auto;z-index:1;}.device-shell{position:absolute;box-sizing:border-box;display:flex;align-items:center;gap:calc(var(--dev-size) * 0.1);padding:0;min-width:var(--dev-size);min-height:var(--dev-size);border:0;background:transparent;box-shadow:none;transition:opacity .2s;pointer-events:none;z-index:2;}.device-shell-frame{position:absolute;z-index:0;box-sizing:border-box;inset:calc(var(--device-shell-inset) / -1);border:var(--device-shell-border-width) solid var(--device-shell-stroke);border-radius:9999px;background:transparent;box-shadow:var(--device-shell-shadow);transition:border-color .15s,opacity .2s;pointer-events:auto;backdrop-filter:none;}.device-shell:not(.with-values){left:0;top:0;}.device-shell:not(.with-values):not(.text-shell) .device-shell-frame{border-radius:50%;}.device-shell.with-values.pos-right{left:0;top:50%;transform:translateY(-50%);}.device-shell.with-values.pos-left{right:0;top:50%;transform:translateY(-50%);flex-direction:row-reverse;}.device-shell.with-values.pos-bottom{left:50%;top:0;transform:translateX(-50%);flex-direction:column;}.device-shell.with-values.pos-top{left:50%;bottom:0;transform:translateX(-50%);flex-direction:column-reverse;}.device-core{position:relative;z-index:1;box-sizing:border-box;flex:0 0 auto;width:var(--dev-size);height:var(--dev-size);display:flex;align-items:center;justify-content:center;border-radius:50%;background:var(--device-face-bg);color:var(--device-face-fg);box-shadow:var(--device-core-inset-shadow),0 0 0 var(--device-ring-width) var(--device-ring-color);line-height:0;transition:background .15s,color .15s,opacity .2s;pointer-events:none;}.device-sections{display:flex;flex-direction:column;align-items:stretch;justify-content:center;gap:calc(var(--dev-size) * .08);min-width:0;pointer-events:none;}.device-shell.pos-top .device-sections,.device-shell.pos-bottom .device-sections{flex-direction:row;}.dev ha-icon{--mdc-icon-size:calc(var(--dev-size,var(--device-base-size,2.25cqw)) * 0.55);display:flex;align-items:center;justify-content:center;line-height:0;}.dev.on{--device-face-bg:#F0A00C;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:#F0A00C;}.dev.theme-light.on{--device-face-fg:#fff;}.dev.theme-dark.on{--device-face-fg:#252525;--device-shell-stroke-ratio:.0375;}.dev.open{--device-face-bg:var(--hp-open);--device-face-fg:light-dark(#fff,#252525);}.dev.theme-light.open{--device-face-fg:#fff;}.dev.theme-dark.open{--device-face-fg:#252525;}.dev.lock-locked{--device-face-bg:#66D17A;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:#66D17A;}.dev.theme-light.lock-locked{--device-face-fg:#fff;}.dev.theme-dark.lock-locked{--device-face-fg:#252525;--device-shell-stroke-ratio:.025;}.dev.lock-unlocked{--device-face-bg:#F0410C;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:#F0410C;}.dev.theme-light.lock-unlocked{--device-face-fg:#fff;}.dev.theme-dark.lock-unlocked{--device-face-fg:#252525;--device-shell-stroke-ratio:.025;}:host([data-pointer-hover]) .dev:not(.unavail)[data-hp-device-hover]{--device-face-bg:#0C82F0;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:var(--device-shell-base-stroke);}:host([data-pointer-hover]) .dev.theme-light:not(.unavail)[data-hp-device-hover]{--device-face-fg:#fff;}:host([data-pointer-hover]) .dev.theme-dark:not(.unavail)[data-hp-device-hover]{--device-face-fg:#252525;}:host([data-pointer-hover]) .dev[data-hp-device-hover],.dev:focus-visible{z-index:5;}.dev[data-hp-zigbee-topology-endpoint]{z-index:8;}:host([data-pointer-hover]) .dev[data-hp-zigbee-topology-endpoint][data-hp-device-hover]{z-index:8;}.dev.unavail{opacity:0.35;--device-face-bg:#B5BAC1;--device-shell-stroke:var(--device-shell-base-stroke);}.dev.virtual .device-shell-frame{border-style:dashed;}.dev.ghost{opacity:0.6;color:var(--hp-accent);}.dev.ghost .device-shell-frame{border-style:dashed;border-color:var(--hp-accent);box-shadow:none;}.dev.ghost .device-core{background:rgba(62,166,255,0.22);background:color-mix(in srgb,var(--hp-accent) 30%,var(--card-background-color,#1c2530));color:var(--hp-accent);}.dev.ghost.ha-disabled{opacity:0.62;color:var(--secondary-text-color,#9aa0aa);}.dev.ghost.ha-disabled .device-shell-frame{border-color:var(--secondary-text-color,#9aa0aa);}.dev.ghost.ha-disabled .device-core{background:rgba(120,124,134,0.2);background:color-mix(in srgb,var(--secondary-text-color,#9aa0aa) 24%,var(--card-background-color,#1c2530));color:var(--secondary-text-color,#9aa0aa);}.dev .habadge{position:absolute;right:-18%;bottom:-18%;display:grid;place-items:center;width:46%;height:46%;min-width:12px;min-height:12px;border-radius:50%;background:var(--card-background-color,#242832);border:1px solid currentColor;}.dev .habadge ha-icon{width:72%;height:72%;}.dev.sel{--device-ring-color:#F0A00C;--device-ring-width:calc(var(--dev-size) * 0.0375);}.dev:focus-visible{--device-ring-color:#0C82F0;--device-ring-width:calc(var(--dev-size) * 0.0375);}.dev:not(.on):not(.open):not(.alarm):not(.lock-locked):not(.lock-unlocked):not(.unavail):focus-visible{--device-face-fg:#0C82F0;}.dev.alarm,:host([data-pointer-hover]) .dev.alarm[data-hp-device-hover],.dev.alarm:focus-visible{--device-face-bg:#F0410C;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:#F0410C;}.dev.theme-light.alarm{--device-face-fg:#fff;}.dev.theme-dark.alarm{--device-face-fg:#252525;--device-shell-stroke-ratio:.025;}.dev .value-badge{position:relative;z-index:2;box-sizing:border-box;width:max-content;min-width:calc(var(--dev-size,var(--icon-size,2.5cqw)) * .7875);height:calc(var(--dev-size,var(--icon-size,2.5cqw)) * .7875);display:flex;align-items:center;justify-content:center;overflow:visible;background:var(--device-core-bg);border:0;border-radius:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.39375);padding:0 calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.14);font-size:calc(var(--dev-size,var(--icon-size,2.5cqw)) * var(--value-font-scale,.45));font-weight:600;line-height:1;color:var(--device-core-fg);white-space:nowrap;pointer-events:none;}.dev .value-badge.unavailable,.dev .value-badge.missing{opacity:0.66;}.dev .lqi{position:absolute;top:calc(50% + var(--device-shell-size) / 2 + var(--dev-size) * .05);left:50%;transform:translateX(-50%);margin-top:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.05);font-size:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.38);font-weight:600;line-height:1;text-shadow:0 0 3px rgba(0,0,0,0.9),0 0 2px rgba(0,0,0,0.9);white-space:nowrap;pointer-events:none;}.dev .lqi.below-value-badge{margin-top:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.8875);}.temprange{display:inline-flex;align-items:center;gap:var(--sp-3);margin-left:auto;color:var(--hp-muted);font-size:var(--fs-s);}.vacwarn{position:absolute;top:-12%;right:-12%;width:calc(var(--device-base-size,2.25cqw) * 0.42);height:calc(var(--device-base-size,2.25cqw) * 0.42);border-radius:50%;display:flex;align-items:center;justify-content:center;background:light-dark(#fff,#252525);border:1px solid #E5A100;color:#E5A100;z-index:7;pointer-events:none;}.vacwarn ha-icon{--mdc-icon-size:calc(var(--device-base-size,2.25cqw) * 0.32);color:inherit;}.vacpuck{position:absolute;--puck-size:calc(var(--device-base-size,2.25cqw) * 0.8);width:var(--puck-size);height:var(--puck-size);border-radius:50%;transform:translate(-50%,-50%);--vac-core-bg:light-dark(#fff,#252525);--vac-core-fg:light-dark(#252525,#fff);background:var(--vac-core-bg);border:1px solid #BCBCBC;box-shadow:0 1px 2px rgb(37 40 45 / 12%),0 4px 8px -1.07px rgb(37 40 45 / 18%);color:var(--vac-core-fg);display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:6;transition:left 1.2s linear,top 1.2s linear;animation:vacpulse 2.2s ease-out infinite;}.vacpuck.theme-light{--vac-core-bg:#fff;--vac-core-fg:#252525;}.vacpuck.theme-dark{--vac-core-bg:#252525;--vac-core-fg:#fff;}.vacpuck.jump{transition:none;}.vacpuck.stale{opacity:0.45;animation:none;}.vacpuck ha-icon{--mdc-icon-size:calc(var(--puck-size) * 0.68);color:var(--vac-core-fg);display:flex;align-items:center;justify-content:center;line-height:0;width:var(--mdc-icon-size);height:var(--mdc-icon-size);}@keyframes vacpulse{0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--hp-accent) 45%,transparent);}70%{box-shadow:0 0 0 12px transparent;}100%{box-shadow:0 0 0 0 transparent;}}@media (prefers-reduced-motion:reduce){.vacpuck{animation:none;}}.vactrail{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:5;overflow:visible;}.vactrail polyline,.vactrail path{fill:none;stroke-linejoin:round;stroke-linecap:round;vector-effect:non-scaling-stroke;}.vactrail g.prev{opacity:0.4;}.vactrail .case{stroke:rgba(0,0,0,0.4);stroke-width:2.25;}.vactrail .core{stroke:rgba(255,255,255,0.82);stroke-width:0.9;}.devicepreview-empty{min-height:82px;margin:4px 0 14px;padding:var(--sp-4);display:flex;align-items:center;justify-content:center;gap:var(--sp-3);border:1px dashed var(--hp-line);border-radius:var(--rad-m);color:var(--hp-muted);text-align:center;}`,o`.hdr{position:sticky;top:var(--header-height,56px);z-index:20;background:var(--card-background-color,var(--hp-bg));border-radius:var(--ha-card-border-radius,12px) var(--ha-card-border-radius,12px) 0 0;}.tabs{display:flex;gap:var(--sp-2);background:rgba(127,127,127,0.12);padding:var(--sp-2);border-radius:var(--rad-l);flex-wrap:wrap;}.tab{border:0;background:transparent;color:var(--hp-muted);display:inline-flex;align-items:center;padding:var(--sp-3) var(--sp-5);border-radius:var(--rad-m);font-size:var(--fs-m);font-weight:600;cursor:pointer;transition:0.15s;font-family:inherit;}:host([data-pointer-hover]) .tab:hover{color:var(--hp-txt);}.tab.active{background:var(--hp-accent);color:var(--text-primary-color,#fff);}.farhint{position:absolute;left:50%;transform:translateX(-50%);bottom:var(--sp-4);z-index:12;display:flex;align-items:center;gap:var(--sp-2);max-width:calc(100% - var(--sp-8));background:var(--card-background-color,var(--hp-bg));opacity:0.94;color:var(--hp-txt);border:1px solid var(--divider-color,#33404d);border-radius:var(--rad-m);padding:var(--sp-1) var(--sp-3);font-size:var(--fs-s);}.farhint ha-icon{--mdc-icon-size:18px;color:var(--hp-warn,#e2a03f);flex:none;}.farhint span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.dropbtn{display:flex;align-items:center;gap:var(--sp-4);width:100%;text-align:left;border:1px solid var(--hp-muted);border-radius:var(--rad-m);background:transparent;color:var(--hp-txt);padding:var(--sp-4) 10px;cursor:pointer;font-family:inherit;font-size:var(--fs-m);margin-top:var(--sp-3);}.dropbtn .ref{color:var(--hp-muted);font-size:var(--fs-s);margin-left:auto;}.dropbtn ha-icon{--mdc-icon-size:18px;margin-left:var(--sp-2);}.dropbtn.open{border-color:var(--hp-accent);}.droppanel{border:1px solid var(--hp-accent);border-top:none;border-radius:0 0 var(--rad-m) var(--rad-m);padding:var(--sp-3);margin-top:-4px;}.hdr.kioskhide{display:none;}.decorbar .dcolor{width:30px;height:26px;padding:0;border:none;background:none;cursor:pointer;}.decorbar .dwidth{font-family:inherit;font-size:var(--fs-s);border-radius:var(--rad-s);background:var(--hp-bg2,transparent);color:var(--hp-txt);border:1px solid var(--hp-muted);padding:var(--sp-2) var(--sp-3);}.decorbar .bdhint{font-size:var(--fs-s);color:var(--hp-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.decorbar .dfill{display:inline-flex;align-items:center;gap:var(--sp-2);font-size:var(--fs-s);cursor:pointer;}.decorbar .dfill input[type="checkbox"]{width:16px;height:16px;flex:none;margin:0;padding:0;}.decorbar hp-color-opacity{flex:0 0 auto;}.modes{display:inline-flex;gap:var(--sp-1);background:rgba(127,127,127,0.12);border-radius:var(--rad-l);padding:var(--sp-2);}.modetab{display:inline-flex;align-items:center;gap:var(--sp-3);border:0;background:transparent;color:var(--hp-muted);padding:var(--sp-3) 10px;border-radius:var(--rad-m);font-size:var(--fs-m);font-weight:600;cursor:pointer;font-family:inherit;transition:background-color 0.14s ease,color 0.14s ease,transform 0.14s ease;}.modetab:active{transform:scale(0.97);}.modetab ha-icon{--mdc-icon-size:15px;}.tab[data-reorderable]{cursor:grab;}.tab.dragging{cursor:grabbing;opacity:0.55;}.tab.drop-before{box-shadow:inset 2px 0 0 0 var(--primary-color,#03a9f4);}.tab.drop-after{box-shadow:inset -2px 0 0 0 var(--primary-color,#03a9f4);}.modetab .closex{--mdc-icon-size:13px;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;min-width:24px;min-height:24px;margin:-5.5px -5.5px -5.5px -3.5px;opacity:0.75;cursor:pointer;border-radius:var(--rad-s);}:host([data-pointer-hover]) .modetab .closex:hover{opacity:1;}.editbar .barclose{box-sizing:border-box;width:40px;height:40px;padding:0;margin:0;min-width:40px;min-height:40px;justify-content:center;gap:0;line-height:0;}.editbar .barclose ha-icon{flex:none;margin:0;}.modetab.active{background:var(--hp-accent);color:var(--text-primary-color,#fff);}@media (max-width:720px){.modetab .ml{display:none;}}.editbar{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:stretch;border-bottom:1px solid var(--hp-line);font-size:var(--fs-m);}.editbar-tools{display:flex;align-items:center;gap:10px;padding:var(--sp-4) var(--sp-5);flex-wrap:wrap;min-width:0;outline:none;}.editbar-end{display:flex;align-items:center;padding:var(--sp-4) var(--sp-5);border-inline-start:1px solid var(--hp-line);background:var(--card-background-color,var(--hp-bg));position:relative;z-index:2;}.tab .tabedit{--mdc-icon-size:13px;display:inline-flex;align-items:center;margin-left:var(--sp-3);opacity:0.4;}:host([data-pointer-hover]) .tab:hover .tabedit{opacity:0.9;}.tab.tabadd{padding:var(--sp-3) var(--sp-4);}.tab.tabadd ha-icon{--mdc-icon-size:15px;}.rhint{font-size:var(--fs-s);color:var(--hp-muted);margin-bottom:var(--sp-3);}.editorchrome{display:block;height:0;opacity:0;visibility:hidden;overflow:hidden;}.editorchrome:not(.open){pointer-events:none;}.editorchrome.open{height:auto;opacity:1;visibility:visible;overflow:visible;}.editorchrome.transitioning{overflow:hidden;will-change:height;pointer-events:none;}.editorchrome.transitioning .barclose{pointer-events:auto;}.editorchrome-inner{min-height:0;transform-origin:top center;}.editorchrome.transitioning .editorchrome-inner{will-change:opacity;}@media (prefers-reduced-motion:reduce){.modetab{transition:none;}}.editbar .warn{color:#ffc14d;}.editbar .sname{font-weight:600;}.editbar input{width:74px;background:transparent;border:1px solid var(--hp-line);color:var(--hp-txt);border-radius:var(--rad-s);padding:var(--sp-3) var(--sp-4);font-size:var(--fs-m);}.editbar label,.editbar .hint{color:var(--hp-muted);font-size:var(--fs-s);}.editbar .drawwall{display:inline-flex;align-items:center;gap:var(--sp-3);white-space:nowrap;}.editbar .wallsgroup{display:inline-flex;align-items:center;gap:10px;white-space:nowrap;}.editbar .drawwall input{width:4.2em;}.editbar .drawwall .opl{color:var(--hp-muted);font-size:var(--fs-s);}.menuwrap{position:fixed;inset:0;z-index:80;}.menu{position:fixed;background:var(--hp-bg);border:1px solid var(--hp-accent);border-radius:var(--rad-l);box-shadow:var(--shadow-2);min-width:210px;max-width:300px;overflow:hidden;transform:translate(0,8px);}.menu .hd{padding:var(--sp-4) var(--sp-5);font-weight:600;font-size:var(--fs-m);border-bottom:1px solid var(--hp-line);display:flex;align-items:center;gap:var(--sp-3);}.menu .hd ha-icon,.menu .it.all ha-icon{color:var(--hp-accent);--mdc-icon-size:16px;}.menu .it{padding:var(--sp-4) var(--sp-5);font-size:var(--fs-m);cursor:pointer;display:flex;align-items:center;gap:var(--sp-4);}.menu .it ha-icon{--mdc-icon-size:16px;color:var(--hp-muted);}:host([data-pointer-hover]) .menu .it:hover{background:rgba(127,127,127,0.15);}.menu .it.all{color:var(--hp-accent);font-weight:600;}.tip{position:fixed;pointer-events:none;background:var(--hp-bg);border:1px solid var(--hp-accent);color:var(--hp-txt);padding:var(--sp-3) 10px;border-radius:var(--rad-m);font-size:var(--fs-m);box-shadow:var(--shadow-2);z-index:60;max-width:260px;}.tip .m{color:var(--hp-muted);font-size:var(--fs-s);display:block;}`,o`.head{display:flex;align-items:center;gap:10px;padding:10px var(--sp-5);border-bottom:1px solid var(--hp-line);flex-wrap:wrap;}.title{font-size:var(--fs-l);font-weight:600;display:flex;align-items:center;gap:var(--sp-3);white-space:nowrap;}.title ha-icon{color:var(--hp-accent);--mdc-icon-size:18px;}@media (max-width:1100px){.head .count{display:none;}}@media (max-width:620px){.head{gap:var(--sp-3);padding:var(--sp-4) 10px;}.head .title{font-size:var(--fs-m);}}.count{font-size:var(--fs-s);color:var(--hp-muted);}.btn{display:inline-flex;align-items:center;gap:var(--sp-3);border:1px solid var(--hp-line);background:transparent;color:var(--hp-txt);padding:var(--sp-3) 10px;border-radius:var(--rad-m);cursor:pointer;transition:0.15s;font-family:inherit;font-size:var(--fs-m);}.btn ha-icon{--mdc-icon-size:17px;}:host([data-pointer-hover]) .btn:hover{border-color:var(--hp-accent);}.btn.on{background:var(--hp-accent);color:var(--text-primary-color,#fff);border-color:var(--hp-accent);}.btn.ghost{border:none;}.btn[disabled]{opacity:0.5;pointer-events:none;}.recoveryoverlay{position:absolute;inset:0;z-index:75;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--sp-4);padding:var(--sp-6);box-sizing:border-box;background:linear-gradient(var(--ha-card-background,var(--card-background-color,#111)),var(--ha-card-background,var(--card-background-color,#111))),#111;color:var(--primary-text-color,#fff);text-align:center;pointer-events:auto;transition:opacity 0.15s ease;}.recoveryoverlay.phase-entering,.recoveryoverlay.phase-leaving{opacity:0;}.recoveryoverlay.phase-fading-in,.recoveryoverlay.phase-opaque{opacity:1;}.recoveryoverlay ha-icon{--mdc-icon-size:44px;color:var(--hp-accent);}.editorloading{position:absolute;z-index:74;left:50%;top:50%;display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-5);border:1px solid color-mix(in srgb,var(--hp-accent) 45%,transparent);border-radius:999px;background:color-mix(in srgb,var(--ha-card-background,var(--card-background-color,#111)) 92%,transparent);color:var(--primary-text-color);box-shadow:0 6px 22px rgb(0 0 0 / 18%);transform:translate(-50%,-50%);pointer-events:none;animation:editor-loading-in 0.15s ease both;}.editorloading ha-icon{--mdc-icon-size:22px;color:var(--hp-accent);animation:editor-loading-spin 0.9s linear infinite;}@keyframes editor-loading-in{from{opacity:0;transform:translate(-50%,calc(-50% + 4px));}to{opacity:1;transform:translate(-50%,-50%);}}@keyframes editor-loading-spin{to{transform:rotate(360deg);}}@media (prefers-reduced-motion:reduce){.recoveryoverlay,.editorloading,.editorloading ha-icon{transition:none;animation:none;}}.oplock{--oplock-size:calc(var(--icon-size,2.5cqw) * 0.62);--oplock-core-size:calc(var(--oplock-size) / 1.26875);--oplock-stroke-ratio:0.01875;--oplock-stroke-width:max(1px,calc(var(--oplock-core-size) * var(--oplock-stroke-ratio)));--oplock-core-bg:light-dark(#fff,#252525);--oplock-core-fg:light-dark(#252525,#fff);--oplock-shell-stroke:light-dark(#BCBCBC,rgb(37 37 37 / 75%));--oplock-shell-shadow:0 calc(var(--oplock-core-size) * .025) calc(var(--oplock-core-size) * .05) rgb(37 40 45 / 12%),0 calc(var(--oplock-core-size) * .1) calc(var(--oplock-core-size) * .175) calc(var(--oplock-core-size) * -.025) rgb(37 40 45 / 18%);--oplock-core-shadow:0 0 0 0 transparent;pointer-events:none;position:absolute;transform:translate(-50%,-50%);width:var(--oplock-size);height:var(--oplock-size);display:grid;place-items:center;border:0;background:transparent;z-index:1;}.oplock.theme-light{--oplock-core-bg:#fff;--oplock-core-fg:#252525;--oplock-shell-stroke:#BCBCBC;}.oplock.theme-dark{--oplock-core-bg:#252525;--oplock-core-fg:#fff;--oplock-shell-stroke:rgb(37 37 37 / 75%);--oplock-core-shadow:inset 0 calc(var(--oplock-core-size) * .0125) calc(var(--oplock-core-size) * .0125) rgb(255 255 255 / 70%);}.oplock-shell{box-sizing:border-box;width:100%;height:100%;border:var(--oplock-stroke-width) solid var(--oplock-shell-stroke);border-radius:50%;background:transparent;box-shadow:var(--oplock-shell-shadow);display:grid;place-items:center;pointer-events:none;backdrop-filter:none;}.oplock-core{width:var(--oplock-core-size);height:var(--oplock-core-size);border-radius:50%;background:var(--oplock-core-bg);color:var(--oplock-core-fg);box-shadow:var(--oplock-core-shadow);display:grid;place-items:center;pointer-events:none;}.oplock ha-icon{--mdc-icon-size:calc(var(--oplock-core-size) * 0.55);display:flex;line-height:0;}.oplock.locked{--oplock-core-bg:#66D17A;--oplock-core-fg:light-dark(#fff,#252525);--oplock-shell-stroke:#66D17A;}.oplock.theme-light.locked{--oplock-core-fg:#fff;}.oplock.theme-dark.locked{--oplock-core-fg:#252525;--oplock-stroke-ratio:.025;}.oplock.unlocked{--oplock-core-bg:#F0410C;--oplock-core-fg:light-dark(#fff,#252525);--oplock-shell-stroke:#F0410C;}.oplock.theme-light.unlocked{--oplock-core-fg:#fff;}.oplock.theme-dark.unlocked{--oplock-core-fg:#252525;--oplock-stroke-ratio:.025;}.oplock.unknown{--oplock-core-fg:var(--hp-muted);}.btn.lockact{width:100%;justify-content:center;display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-4);}.btn.lockact.warn{color:var(--error-color,#d33);border-color:var(--error-color,#d33);}.oprow{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-3) 0;}.oprow b{margin-left:auto;}.oprow.ok b{color:#66d17a;}.oprow.warn b{color:var(--hp-open);}.ctrlstates{display:flex;flex-direction:column;gap:var(--sp-2);}.ctrlstate{display:inline-flex;align-items:center;gap:var(--sp-3);color:var(--hp-muted);}.ctrlstate.on{color:var(--hp-txt);}.ctrlstate ha-icon{--mdc-icon-size:15px;}.cardpreview{display:flex;flex-direction:column;align-items:center;gap:var(--sp-2);margin:var(--sp-4) 0 var(--sp-1);padding:10px;border:1px dashed var(--hp-muted);border-radius:var(--rad-m);}.cardpreview .cpname{font-weight:700;letter-spacing:0.04em;}.cardpreview .cpmeta{display:inline-flex;align-items:center;gap:0.3em;font-weight:600;opacity:0.85;}.cardpreview .cpmeta ha-icon{--mdc-icon-size:1.05em;}hp-dialog .dfill{display:inline-flex;align-items:center;gap:var(--sp-3);cursor:pointer;}.wallthick-dlg{position:absolute;z-index:40;min-width:200px;transform:translate(-50%,8px);padding:10px 12px;border-radius:10px;background:var(--card-background-color,#fff);box-shadow:0 8px 28px rgba(0,0,0,.22);display:flex;flex-direction:column;gap:8px;pointer-events:auto;}.wallthick-dlg .row{display:flex;align-items:center;gap:8px;}.wallthick-dlg input[type="number"]{width:5.5em;padding:4px 6px;border:1px solid var(--divider-color,#ccc);border-radius:6px;background:var(--input-fill,transparent);color:var(--primary-text-color);}.areasel,.namein{background:var(--hp-bg);border:1px solid var(--hp-line);color:var(--hp-txt);border-radius:var(--rad-s);padding:var(--sp-3) var(--sp-4);font-size:var(--fs-m);font-family:inherit;}.namein{width:130px;}.habindingbanner{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);margin-bottom:var(--sp-4);border:1px solid var(--warning-color,#ff9800);border-radius:var(--rad-m);background:color-mix(in srgb,var(--warning-color,#ff9800) 12%,transparent);color:var(--primary-text-color,#f1f3f6);}.habindingbanner>span{flex:1;min-width:0;}.habindingbanner>ha-icon{color:var(--warning-color,#ff9800);flex:0 0 auto;}.habindingbanner.limited{border-color:var(--secondary-text-color,#9aa0aa);background:color-mix(in srgb,var(--secondary-text-color,#9aa0aa) 10%,transparent);}.habindingbanner.limited>ha-icon{color:var(--secondary-text-color,#9aa0aa);}.srcrow{display:flex;align-items:center;gap:var(--sp-4);font-size:var(--fs-m);cursor:pointer;padding:var(--sp-1) 0;}.dispsection{margin-top:var(--sp-5) !important;padding-top:var(--sp-4);border-top:1px solid var(--hp-line);font-weight:600;color:var(--hp-txt) !important;}.colorrow{display:flex;align-items:center;gap:var(--sp-4);}.colorrow input[type='range']{flex:1;}.colorrow .tempin{width:70px;flex:none;}hp-dialog .body .temprange .tempin{width:56px;flex:none;padding:var(--sp-2) var(--sp-3);}hp-dialog .body .colorrow .tempin{width:72px;flex:none;}.srcrow{flex-wrap:nowrap;}.srcrow ha-switch{flex:none;}.colorrow ha-slider{flex:1;min-width:0;}.srcrow>span:first-of-type{white-space:nowrap;}.colorrow .opl{color:var(--hp-muted);font-size:var(--fs-s);}.colorrow .opv{font-size:var(--fs-s);min-width:34px;text-align:right;}.markerlightgroup{min-width:0;margin:var(--sp-5) 0 0;padding:var(--sp-4);border:1px solid var(--hp-line);border-radius:var(--rad-m);}.markerlightgroup legend{display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-1);padding:0 var(--sp-2);color:var(--hp-txt);font-weight:600;}.markerlightgroup legend>span{min-width:0;overflow-wrap:anywhere;}.markerlightgroup[disabled]>:not(legend){opacity:.62;}.radargroup{display:grid;gap:var(--sp-2);}.radargroup>p{margin:0;}.radargroup>label:not(.srcrow){margin-top:var(--sp-2);}.radarcoordinates{align-items:flex-end;flex-wrap:wrap;}.radarcoordinates>label{display:grid;flex:1 1 92px;gap:var(--sp-1);min-width:0;margin:0;}hp-dialog .body .radarcoordinates .tempin{box-sizing:border-box;width:100%;}.radarinspection{display:grid;gap:6px;padding:10px 12px;border-radius:10px;background:color-mix(in srgb,var(--primary-color) 7%,transparent);}.radarinspection code{overflow-wrap:anywhere;font-size:12px;}.radarsetup{display:grid;gap:10px;margin-top:10px;padding:12px;border:1px solid var(--hp-accent);border-radius:var(--rad-m);background:color-mix(in srgb,var(--secondary-background-color) 88%,transparent);}.radarsetup-head{display:flex;align-items:center;gap:8px;}.radarsetup-head strong{flex:1;}.radarsetup>svg{width:min(100%,460px);aspect-ratio:1;justify-self:center;border-radius:var(--rad-m);background:var(--primary-background-color);touch-action:none;cursor:crosshair;}.radarsetup .room{fill:color-mix(in srgb,var(--hp-accent) 8%,transparent);stroke:var(--divider-color);stroke-width:3;vector-effect:non-scaling-stroke;}.radarsetup .heading{stroke:var(--hp-accent);stroke-width:4;vector-effect:non-scaling-stroke;}.radarsetup .trail{fill:none;stroke:var(--success-color,#43a047);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke;opacity:.55;}.radarsetup g circle{fill:var(--hp-bg);stroke:var(--hp-accent);stroke-width:3;vector-effect:non-scaling-stroke;}.radarsetup g.pending circle{stroke-dasharray:5 4;}.radarsetup g text{fill:var(--hp-txt);font-size:22px;font-weight:700;text-anchor:middle;dominant-baseline:middle;pointer-events:none;}.help-inline-label{display:inline-flex;align-items:center;flex-wrap:wrap;gap:var(--sp-1);}hp-dialog .body .help-inline-label>label{min-width:0;margin-top:0;overflow-wrap:anywhere;}.markerlightgroup .srcrow>span:first-of-type{min-width:0;white-space:normal;overflow-wrap:anywhere;}.planrow{display:flex;align-items:center;gap:10px;}.savedplans{display:flex;flex-direction:column;gap:var(--sp-3);max-height:240px;overflow:auto;margin:var(--sp-3) 0 var(--sp-1);padding:var(--sp-3);border:1px solid var(--hp-line);border-radius:var(--rad-m);background:var(--hp-bg2,rgba(255,255,255,0.03));flex:0 0 auto;min-height:2.6em;}.savedplan{display:flex;align-items:center;gap:10px;}.savedplan.cur{outline:1px solid var(--hp-accent);border-radius:var(--rad-s);}.savedplan img{width:56px;height:40px;object-fit:contain;border:1px solid var(--hp-line);border-radius:var(--rad-s);background:#fff;flex:none;}.savedmeta{display:flex;flex-direction:column;min-width:0;flex:1;}.savedmeta b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.savedmeta .muted{font-size:var(--fs-s);}.savedplan .btn.danger ha-icon{color:#f25a4a;}.savedplan .btn[disabled]{opacity:0.4;pointer-events:none;}.planprev{max-width:120px;max-height:70px;border:1px solid var(--hp-line);border-radius:var(--rad-s);background:#fff;}.planname{font-size:var(--fs-m);max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.planname.muted{color:var(--hp-muted);}.filebtn{cursor:pointer;}.btn.danger{border-color:#b3402a;color:#ff7a5c;}hp-dialog .row .spacer{flex:1;}hp-dialog .body{max-height:66vh;overflow-y:auto;}hp-dialog[form-shell] .body{max-height:none;overflow:visible;padding:16px;box-sizing:border-box;}@media (max-width:480px){hp-dialog[form-shell] .body{padding:12px;}}hp-confirm{display:contents;}hp-dialog .danger-confirm-body{display:flex;flex-direction:column;gap:var(--sp-4);}hp-dialog .danger-confirm-body p{margin:0;line-height:1.45;}hp-dialog .danger-confirm-object{overflow-wrap:anywhere;font-size:var(--fs-l);line-height:1.3;}.curbind{display:flex;align-items:center;gap:var(--sp-3);font-size:var(--fs-m);color:var(--hp-txt);flex-wrap:wrap;}.curbind .ref{color:var(--hp-muted);font-size:var(--fs-s);}.vacbox .vacbtns{display:flex;gap:var(--sp-4);margin:var(--sp-3) 0;flex-wrap:wrap;}.vacdiag{display:grid;gap:4px;margin-bottom:var(--sp-3);}.vacdiag>div{display:flex;justify-content:space-between;gap:var(--sp-5);}.vacdiag>div>span{color:var(--secondary-text-color);}.vacdiag>div>b{text-align:right;overflow-wrap:anywhere;}.vacroute-missing-group{margin-top:var(--sp-4);padding-top:var(--sp-4);border-top:1px solid var(--hp-line);}.vacroute-group-title{margin:0 0 var(--sp-3);color:var(--secondary-text-color);font-size:var(--fs-m);font-weight:600;}.vacroute-missing-group .vacroute-list{margin-top:0;}.vacpicker{margin:var(--sp-3) 0;}.vacsource-warning{display:grid;gap:8px;}.vacsource-warning .btn{justify-self:start;}.vacpicker>summary{display:inline-flex;width:auto;list-style:none;cursor:pointer;}.vacpicker>summary::-webkit-details-marker{display:none;}.vacsource-list{display:grid;gap:6px;margin-top:8px;}.vacsource-list details{padding:6px 0 0;}.vacsource-list details>summary{cursor:pointer;font-weight:600;}.vacsource{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;min-width:0;padding:9px 10px;border:1px solid var(--divider-color);border-radius:10px;color:var(--primary-text-color);background:var(--secondary-background-color);text-align:left;cursor:pointer;}.vacsource.on{border-color:var(--accent-color);box-shadow:inset 3px 0 var(--accent-color);}.vacsource>span:first-child{min-width:0;display:grid;gap:2px;}.vacsource small{color:var(--secondary-text-color);overflow-wrap:anywhere;}.vacsource-meta{color:var(--secondary-text-color);text-align:right;font-size:0.82em;}.vacxcme pre{margin:8px 0 0;white-space:pre-wrap;user-select:text;}.vacfit{position:absolute;inset:0;width:100%;height:100%;z-index:12;overflow:visible;touch-action:none;cursor:grab;pointer-events:auto;}.vacfit:active{cursor:grabbing;}.vacfit polygon{fill:color-mix(in srgb,var(--hp-accent) 16%,transparent);stroke:var(--hp-accent);stroke-width:2;vector-effect:non-scaling-stroke;stroke-dasharray:6 4;}.vacfit text{fill:var(--hp-accent);font-size:26px;text-anchor:middle;dominant-baseline:middle;pointer-events:none;user-select:none;}.furnpalette{display:flex;flex-direction:column;max-height:38vh;border-top:1px solid var(--hp-border,rgba(255,255,255,0.12));background:var(--card-background-color,var(--hp-bg));font-size:0.85em;}.furnhd{display:flex;align-items:center;gap:6px;padding:4px 8px;font-weight:600;opacity:0.9;}.furnhd .spacer{flex:1;}.furnbody{overflow:auto;padding:0 8px 6px;}.furngroup{margin:6px 0 3px;font-size:0.85em;text-transform:uppercase;letter-spacing:0.04em;opacity:0.6;}.furnrow{display:flex;flex-wrap:wrap;gap:4px;}.furnback{min-height:34px;gap:5px;margin:2px 0 4px;}.furnitem{display:flex;flex-direction:column;align-items:center;gap:2px;width:74px;padding:4px 2px;border:1px solid transparent;border-radius:8px;background:rgba(127,127,127,0.08);color:inherit;font:inherit;font-size:0.8em;line-height:1.15;text-align:center;cursor:pointer;}:host([data-pointer-hover]) .furnitem:hover{background:rgba(127,127,127,0.18);}.furnitem.on{border-color:var(--hp-accent);background:rgba(38,166,154,0.18);}.furnprev{width:40px;height:40px;color:var(--primary-text-color,currentColor);}.furncategory{width:92px;min-height:76px;}.furncatprev{width:48px;height:48px;}.furnvariants .furnitem{min-height:74px;}.furnsize{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:6px 8px;border-top:1px solid var(--hp-border,rgba(255,255,255,0.12));}.furnsize label{display:flex;align-items:baseline;gap:3px;opacity:0.8;}.furnsize .furnunit{opacity:0.6;font-size:0.85em;}.furnsize input{width:5.5em;padding:3px 5px;}.furnhint{opacity:0.6;}.imageupload{display:inline-flex;gap:6px;margin:4px 0 8px;cursor:pointer;}.imageupload.disabled{opacity:0.55;pointer-events:none;}.imageupload input{display:none;}.imageassets{align-items:stretch;}.imageempty{padding:12px 6px;}.imageasset{position:relative;}.imageasset .furnitem{width:104px;min-height:92px;}.imageasset img{width:64px;height:54px;object-fit:contain;border-radius:4px;background:repeating-conic-gradient(#ddd 0 25%,#fff 0 50%) 50% / 12px 12px;}.imageasset .furnitem span{max-width:96px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.imageasset .furnitem small{opacity:0.65;font-size:0.72em;}.imageassetdelete{position:absolute;top:0;right:0;min-width:30px;width:30px;min-height:30px;padding:3px;}.imagepropertypreview{display:flex;align-items:center;gap:10px;min-width:0;}.imagepropertypreview img{width:72px;height:54px;object-fit:contain;border-radius:4px;background:repeating-conic-gradient(#ddd 0 25%,#fff 0 50%) 50% / 12px 12px;}.imagepropertypreview span{overflow-wrap:anywhere;}.vacfitdot{fill:var(--hp-accent);pointer-events:none;}.vacfithandle{fill:transparent;stroke:none;cursor:nwse-resize;}.vacfitknob{fill:var(--hp-bg);stroke:var(--hp-accent);stroke-width:2;vector-effect:non-scaling-stroke;pointer-events:none;}.vaccalbar{position:fixed;left:50%;bottom:24px;transform:translateX(-50%);display:flex;gap:var(--sp-5);align-items:center;background:var(--hp-bg);color:var(--hp-txt);border:1px solid var(--hp-accent);border-radius:var(--rad-l);padding:10px var(--sp-5);z-index:60;box-shadow:var(--shadow-2);}.candlist{max-height:160px;overflow-y:auto;border-top:1px solid var(--hp-line);flex:0 0 auto;min-height:2.6em;}.cand{display:flex;justify-content:space-between;gap:var(--sp-4);padding:var(--sp-3) var(--sp-4);cursor:pointer;border-radius:var(--rad-s);font-size:var(--fs-m);}:host([data-pointer-hover]) .cand:hover{background:rgba(127,127,127,0.15);}.cand.sel{background:var(--hp-accent);color:var(--text-primary-color,#fff);}.cand .cs{color:var(--hp-muted);font-size:var(--fs-s);white-space:nowrap;}.opening-entity-candidate{width:100%;border:0;background:transparent;color:inherit;font:inherit;text-align:left;}.opening-entity-candidate.sel{background:var(--hp-accent);color:var(--text-primary-color,#fff);}.opening-entity-empty{cursor:default;}.cand.sel .cs{color:var(--text-primary-color,#fff);opacity:0.85;}.cand.muted{color:var(--hp-muted);cursor:default;}.entlist{display:flex;flex-direction:column;gap:var(--sp-2);margin-bottom:10px;}.entrow{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-3) var(--sp-4);border-radius:var(--rad-m);background:var(--secondary-background-color,rgba(128,128,128,0.12));}.entrow ha-icon{--mdc-icon-size:20px;color:var(--hp-muted);}.entrow.on ha-icon{color:var(--hp-accent);}.entrow .en{flex:1;font-size:var(--fs-m);}.entrow .ev{font-size:var(--fs-m);color:var(--hp-muted);}.entbtn{min-width:74px;min-height:32px;padding:var(--sp-2) var(--sp-5);border:1px solid var(--hp-muted);border-radius:999px;background:transparent;color:var(--hp-txt);font:inherit;font-size:var(--fs-m);cursor:pointer;}.entbtn.on{background:var(--hp-accent);border-color:var(--hp-accent);color:var(--text-primary-color,#fff);font-weight:600;}.inforow{display:flex;gap:10px;font-size:var(--fs-m);margin:var(--sp-2) 0;}.inforow .k{color:var(--hp-muted);min-width:84px;}.inforow a{color:var(--hp-accent);word-break:break-all;}.infodesc{font-size:var(--fs-m);white-space:pre-wrap;margin-top:var(--sp-3);}.infodesc.muted{color:var(--hp-muted);}.pdflist{display:flex;flex-direction:column;gap:var(--sp-2);}.pdf{display:inline-flex;align-items:center;gap:var(--sp-2);color:var(--hp-accent);text-decoration:none;}ha-icon-picker{display:block;}.floorrow{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-3) var(--sp-2);font-size:var(--fs-m);cursor:pointer;}.floorrow .floorlvl{color:var(--hp-muted);font-size:var(--fs-s);border:1px solid var(--hp-line);border-radius:var(--rad-s);padding:0 var(--sp-3);}.rtest{display:flex;align-items:center;gap:var(--sp-4);margin-bottom:var(--sp-4);}.rtest .namein{flex:1;}.rtest ha-icon{color:var(--hp-accent);}.rtesticon{font-size:var(--fs-s);color:var(--hp-muted);}.rrow{display:flex;align-items:center;gap:var(--sp-3);margin:var(--sp-1) 0;}.rrow .rpat{flex:2;}.rrow .ricon{flex:1.4;}.rrow .rpat.bad{border-color:#ff7a5c;}.rrow .rprev{--mdc-icon-size:18px;color:var(--hp-txt);min-width:18px;}.rrow .ract{--mdc-icon-size:16px;color:var(--hp-muted);cursor:pointer;}:host([data-pointer-hover]) .rrow .ract:hover{color:var(--hp-txt);}:host([data-pointer-hover]) .rrow .ract.del:hover{color:#ff7a5c;}.optimize-live{display:grid;justify-items:start;gap:var(--sp-2);margin-bottom:var(--sp-3);}.optimize-live .alignmsg,.optimize-live .rhint{margin-bottom:0;}.optimize-cleanup{min-height:44px;}.optimize-selected{color:var(--hp-txt);}.optimize-details{margin-top:var(--sp-3);color:var(--hp-muted);font-size:var(--fs-s);overflow-wrap:anywhere;}.optimize-details>summary{width:fit-content;color:var(--hp-txt);cursor:pointer;font-weight:600;}.optimize-details>summary:focus-visible{outline:2px solid var(--hp-accent);outline-offset:3px;border-radius:var(--rad-s);}.optimize-details ul{margin:var(--sp-3) 0;padding-inline-start:22px;}.optimize-details li + li{margin-top:var(--sp-1);}.btn.alignall{width:100%;justify-content:center;}.backupactions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-3);}.backupactions .btn{justify-content:center;min-width:0;}.backupupload{display:inline-flex;min-width:0;}.backupupload>.btn{width:100%;justify-content:center;}.backupupload input{display:none;}.backupbody{min-width:0;}.backupplanonly{margin-inline-start:var(--sp-4) !important;align-items:flex-start !important;}.backupplanonly>span:first-of-type{display:grid;gap:2px;white-space:normal;}.backupplanonly small{color:var(--secondary-text-color);line-height:1.35;}.backupplanonlystatus{color:var(--hp-accent) !important;font-weight:700;}.backupfile,.backupsummary,.backupcontent{display:flex;flex-direction:column;min-width:0;gap:var(--sp-1);}.backupfile b,.backupcontent span{overflow-wrap:anywhere;}.backupfile span,.backupsummary span,.backupcontent span{color:var(--hp-muted);font-size:var(--fs-s);}.backupcounts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-2) var(--sp-4);font-size:var(--fs-s);}.backupwarn,.backuperror{border-radius:var(--rad-s);padding:var(--sp-3);font-size:var(--fs-s);line-height:1.45;overflow-wrap:anywhere;}.backupwarn{background:color-mix(in srgb,var(--hp-accent) 12%,transparent);}.backuperror{background:rgba(179,64,42,.16);color:#ff7a5c;}.backupdetails{border:1px solid var(--hp-line);border-radius:var(--rad-s);padding:var(--sp-2) var(--sp-3);font-size:var(--fs-s);}.backupdetails summary{cursor:pointer;font-weight:700;}.backupdetails>div{display:grid;gap:var(--sp-1);padding-block-start:var(--sp-2);}.backupdetails code{overflow-wrap:anywhere;color:var(--hp-muted);}.backupchoices{display:flex;flex-direction:column;gap:var(--sp-2);border:1px solid var(--hp-line);border-radius:var(--rad-s);min-width:0;}.backupchoices label{margin:0 !important;display:flex;gap:var(--sp-2);}.backupconfirm{align-items:flex-start !important;}.backupconfirm>span:first-of-type{min-width:0;white-space:normal;overflow-wrap:anywhere;}@media (max-width:520px){.backupactions,.backupcounts{grid-template-columns:1fr;}}.aboutver{font-size:var(--fs-s);color:var(--hp-muted);margin:var(--sp-2) 0 var(--sp-3);}.aboutlink{display:flex;align-items:center;gap:var(--sp-3);width:fit-content;color:var(--hp-accent);text-decoration:none;font-size:var(--fs-m);padding:var(--sp-1) 0;}:host([data-pointer-hover]) .aboutlink:hover{text-decoration:underline;}.aboutlink ha-icon{--mdc-icon-size:18px;line-height:1;}hp-dialog .supportbody{min-width:0;overflow-x:hidden;gap:var(--sp-5);}.supportsection{display:grid;min-width:0;gap:var(--sp-2);}.supportsection + .supportsection{padding-top:var(--sp-4);border-top:1px solid var(--hp-line);}.supportsection h3{margin:0;color:var(--hp-txt);font-size:var(--fs-m);}.supportlinks,.supportactions{display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-2) var(--sp-4);min-width:0;}.supportform>label:not(.srcrow){margin-top:var(--sp-2);color:var(--hp-muted);font-size:var(--fs-s);}.supportmessage,.supportraw{width:100%;min-width:0;box-sizing:border-box;resize:vertical;border:1px solid var(--hp-line);border-radius:var(--rad-s);padding:var(--sp-3);color:var(--hp-txt);background:color-mix(in srgb,var(--card-background-color,var(--hp-bg)) 92%,var(--hp-txt));font:inherit;}.supportmessage{min-height:120px;background:var(--hp-bg);}.supportraw{min-height:220px;margin-top:var(--sp-2);resize:none;white-space:pre;overflow:auto;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;}.supportattach{min-width:0;align-items:flex-start;margin:var(--sp-2) 0 0 !important;}.supportattach>span:first-of-type{min-width:0;white-space:normal;overflow-wrap:anywhere;}.supportwarning,.supportstatus,.supportupdate{display:flex;align-items:flex-start;gap:var(--sp-2);min-width:0;margin:0;padding:var(--sp-3);border-radius:var(--rad-s);background:color-mix(in srgb,var(--hp-accent) 14%,transparent);overflow-wrap:anywhere;font-size:var(--fs-s);line-height:1.45;}.supportwarning ha-icon,.supportstatus ha-icon,.supportupdate ha-icon{flex:none;color:var(--hp-accent);--mdc-icon-size:20px;}.supportpreview,.supportmanual,.supporterror,.supportsuccess{display:grid;min-width:0;gap:var(--sp-2);padding:var(--sp-3);border:1px solid var(--hp-line);border-radius:var(--rad-s);}.supportsummary{font-weight:600;overflow-wrap:anywhere;}.supporthash{display:grid;min-width:0;gap:var(--sp-1);color:var(--hp-muted);font-size:var(--fs-s);}.supporthash code{overflow-wrap:anywhere;color:var(--hp-txt);}.supportpreview details{min-width:0;}.supportpreview summary{cursor:pointer;color:var(--hp-accent);}.supportprivacy{margin:0 !important;line-height:1.45;}.supporterror{background:color-mix(in srgb,var(--error-color,#db4437) 12%,transparent);border-color:color-mix(in srgb,var(--error-color,#db4437) 45%,var(--hp-line));}.supportsuccess{background:color-mix(in srgb,var(--success-color,#43a047) 12%,transparent);border-color:color-mix(in srgb,var(--success-color,#43a047) 45%,var(--hp-line));}.supportfooter{flex-wrap:wrap;}@media (max-width:520px){hp-dialog .supportbody{padding-inline:var(--sp-4);}hp-dialog .supportfooter{padding-inline:var(--sp-4);}.supportactions .btn,.supportactions .aboutlink{max-width:100%;}}hp-dialog .body{padding:var(--sp-5) var(--sp-6);display:flex;flex-direction:column;gap:var(--sp-3);}hp-dialog .tapconfirm-body{min-width:0;overflow-x:hidden;}hp-dialog .tapconfirm-body p{max-width:100%;min-width:0;margin:0;overflow-wrap:anywhere;white-space:normal;}hp-dialog .tapconfirm-line{color:var(--hp-muted);}hp-dialog .body label{font-size:var(--fs-s);color:var(--hp-muted);margin-top:var(--sp-3);}hp-dialog .body .namein,hp-dialog .body .areasel{width:100%;box-sizing:border-box;}hp-dialog .row{display:flex;justify-content:flex-end;gap:var(--sp-4);width:100%;min-width:0;box-sizing:border-box;padding:var(--sp-5) var(--sp-6);border-top:1px solid var(--hp-line);}hp-dialog>.row[slot='footer'] button{min-height:44px;}hp-dialog .row.dialog-action-footer{align-items:center;justify-content:flex-start;flex-wrap:wrap;row-gap:var(--sp-4);}hp-dialog .dialog-action-group{display:flex;flex:0 1 auto;flex-wrap:wrap;align-items:center;gap:var(--sp-4);max-width:100%;min-width:0;}hp-dialog .dialog-action-group .btn{flex:0 0 auto;min-height:44px;}hp-dialog .dialog-action-danger{margin-right:auto;}hp-dialog .dialog-action-commit{margin-left:auto;justify-content:flex-end;}hp-dialog .row.infofooter{align-items:center;justify-content:flex-start;flex-wrap:wrap;gap:var(--sp-3);}hp-dialog .row.infofooter .btn{flex-shrink:0;}hp-dialog .row.infofooter .infofooter-close{margin-left:auto;}@media (max-width:480px){hp-dialog .row.infofooter{padding:var(--sp-4) var(--sp-5);}}.device-inbox{display:flex;flex-direction:column;gap:var(--sp-4);padding:var(--sp-5) var(--sp-6);min-width:0;}.device-inbox-dialog{--hp-dialog-wide-width:920px;}.device-inbox-head{display:grid;grid-template-columns:minmax(180px,1fr) auto;align-items:center;gap:var(--sp-4);}.device-inbox-search{width:100%;min-width:0;box-sizing:border-box;border:1px solid var(--hp-line);border-radius:var(--rad-m);background:transparent;color:var(--hp-txt);font:inherit;padding:11px 14px;}.device-inbox-tabs{display:flex;gap:var(--sp-2);overflow-x:auto;scrollbar-width:thin;padding-bottom:var(--sp-1);}.device-inbox-tabs button{flex:0 0 auto;border:1px solid var(--hp-line);border-radius:999px;background:transparent;color:var(--hp-txt);font:inherit;padding:8px 12px;cursor:pointer;}.device-inbox-tabs button.on{border-color:var(--hp-accent);background:color-mix(in srgb,var(--hp-accent) 18%,transparent);}.device-inbox-tabs button span{color:var(--hp-muted);margin-inline-start:4px;}.device-inbox-discovery{margin:8px 0;padding:8px 10px;border:1px solid var(--divider-color,#e0e0e0);border-radius:8px;}.device-inbox-discovery summary{cursor:pointer;font-weight:600;}.device-inbox-discovery .srcrow{display:flex;gap:6px;align-items:center;margin:8px 0;}.device-inbox-excluded{display:flex;flex-wrap:wrap;gap:6px;align-items:center;}.device-inbox-excluded>span{font-weight:500;}.device-inbox-chips{display:flex;flex-wrap:wrap;gap:4px;}.device-inbox-chips .chip{display:inline-flex;align-items:center;gap:2px;padding:1px 6px;border-radius:10px;background:var(--secondary-background-color,#f0f0f0);font-size:12px;}.device-inbox-chips .chip button{border:none;background:none;cursor:pointer;padding:0 2px;color:var(--secondary-text-color,#666);}.device-inbox-excluded input[type="text"]{flex:1 1 140px;min-width:120px;padding:4px 6px;border:1px solid var(--divider-color,#e0e0e0);border-radius:6px;background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);}.device-inbox-preview{margin:8px 0 4px;font-size:13px;opacity:0.85;}.device-inbox-filters{display:flex;flex-wrap:wrap;gap:var(--sp-4) var(--sp-6);color:var(--hp-muted);}.device-inbox-filters label{display:inline-flex;align-items:center;gap:var(--sp-2);cursor:pointer;}.device-inbox-filter-help{display:inline-flex;align-items:center;gap:var(--sp-1);min-width:0;}.device-inbox-results{display:grid;gap:var(--sp-3);min-width:0;}.device-inbox-row{display:grid;grid-template-columns:42px minmax(180px,1fr) minmax(180px,auto);align-items:center;gap:var(--sp-4);min-width:0;border:1px solid var(--hp-line);border-radius:var(--rad-m);padding:var(--sp-4);background:color-mix(in srgb,var(--hp-txt) 3%,transparent);}.device-inbox-icon{--mdc-icon-size:28px;color:var(--hp-txt);justify-self:center;}.device-inbox-copy{min-width:0;}.device-inbox-name{display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-2);}.device-inbox-new{border-radius:999px;background:var(--hp-accent);color:var(--text-primary-color,#fff);font-size:var(--fs-s);padding:2px 7px;}.device-inbox-meta,.device-inbox-reason,.device-inbox-copy code{display:block;color:var(--hp-muted);font-size:var(--fs-s);overflow-wrap:anywhere;white-space:normal;}.device-inbox-status{color:var(--error-color,#db4437);margin-inline-start:var(--sp-2);}.device-inbox-actions{display:flex;justify-content:flex-end;align-items:center;flex-wrap:wrap;gap:var(--sp-2);}.device-inbox-actions .btn{min-height:36px;padding:7px 10px;}.device-inbox-menu{position:relative;}.device-inbox-menu summary{list-style:none;cursor:pointer;}.device-inbox-menu summary::-webkit-details-marker{display:none;}.device-inbox-menu-items{position:absolute;z-index:2;inset-inline-end:0;top:calc(100% + var(--sp-1));display:grid;gap:var(--sp-1);min-width:180px;padding:var(--sp-2);border:1px solid var(--hp-line);border-radius:var(--rad-m);background:var(--hp-panel,var(--card-background-color,#fff));box-shadow:0 8px 24px rgba(0,0,0,.22);}.device-inbox-menu-items .btn{justify-content:flex-start;width:100%;}.device-inbox-empty{color:var(--hp-muted);text-align:center;padding:var(--sp-8);}.device-inbox-more{align-self:center;}@media (max-width:680px){.device-inbox{padding:var(--sp-4);}.device-inbox-head{grid-template-columns:minmax(0,1fr);}.device-inbox-head .btn{justify-self:stretch;}.device-inbox-tabs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));overflow-x:visible;}.device-inbox-tabs button{min-width:0;overflow-wrap:anywhere;}.device-inbox-row{grid-template-columns:36px minmax(0,1fr);}.device-inbox-actions{grid-column:1 / -1;justify-content:flex-start;}}`];var lp={"editor.context_actions":"Actions: {object}","editor.tool_options":"Tool options: {tool}","editor.palette":"Palette: {tool}","editor.open_group":"Tool group: {group}","editor.group_active":"{group} — active: {item}","editor.disabled_action":"{action} is unavailable: {reason}","editor.loading":"Loading…","editor.loading_aria":"The plan editor is loading","editor.load_failed":"Could not load the editor.","editor.refresh_advice":"Refresh the page and try again.","editor.retry_advice":"Check your connection and press again.","version_mismatch.title":"House Plan versions do not match","version_mismatch.body":"If Home Assistant is still restarting, let it finish, then reload this page.","version_mismatch.frontend":"Card","version_mismatch.backend":"Integration","version_mismatch.reload":"Reload page","color_picker.title":"Color picker","color_picker.hue":"Hue","color_picker.saturation":"Saturation","color_picker.value":"Brightness","color_picker.hex":"Hex color","color_picker.invalid_hex":"Enter a 3- or 6-digit hex color","color_picker.confirm":"OK","btn.properties":"Properties","btn.keep_as_walls":"Keep as walls","btn.delete_room_keep_walls":"Delete room, keep walls","btn.delete_room_with_walls":"Delete room and walls","title.markup_select":"Select and edit walls and columns","title.markup_column":"Column: click a grid point to place a square column","markup.partition":"Partition","markup.column":"Column","markup.hint_column":"click a grid point to place a square column","history.wall_segment":"Add wall segment","history.column_add":"Add column","history.physical_edit":"Change physical object","history.physical_delete":"Delete physical object","history.physical_move":"Move physical object","history.wall_face_batch":"Create rooms from walls","toast.column_duplicate":"A column with the same centre and outer size already exists","physical.partition_properties":"Partition properties","physical.column_properties":"Column properties","physical.shape":"Shape","physical.square":"Square","physical.circle":"Circle","physical.diameter":"Diameter","physical.side":"Side","physical.rotation":"Rotation angle","physical.length":"Length","physical.allowed_range":"Allowed: {min}–{max} {unit}","physical.column_size_title":"Outer side of the square column placed by the click (1–150 cm).","card.title":"House plan","count.devices":"{n} dev.","empty.no_spaces":"No spaces yet.","nav.spaces":"House Plan spaces","empty.add_first":"Add the first space and upload a floor plan.","empty.read_only":"No spaces are configured. Ask an administrator to add one.","empty.install":'Install the House Plan integration and add it in "Devices & services".',"btn.add_space":"Add space","btn.cancel":"Cancel","btn.save":"Save","btn.close":"Close","btn.delete":"Delete","btn.copy":"Copy","btn.edit":"Edit","btn.open_in_ha":"Open in HA","btn.reset":"Reset","btn.attach":"Attach…","btn.upload":"Upload…","btn.replace":"Replace…","title.zoom_in":"Zoom in","title.zoom_out":"Zoom out","title.zoom_fit":"Fit all","title.configure_space":"Configure space","title.add_space":"Add space","title.markup_add":"Walls: draw a continuous chain; each accepted segment is saved independently. Shift locks to 45°","title.markup_merge":"Merge: click one room, then the neighbour it shares a wall with","title.markup_split":"Split a room: click the room, then two points on its walls","title.markup_delroom":"Delete room: click inside a room and confirm","markup.add":"Walls","markup.merge":"Merge","markup.split":"Split","markup.resize":"Resize","title.markup_resize":"Resize rooms: drag an available horizontal or vertical wall handle","markup.hint_resize":"drag an available wall handle · the wall stops at the first unsafe position · Esc cancels · Ctrl+Z — undo","resize.disabled.diagonal":"This wall is angled; Resize supports only horizontal and vertical walls","resize.disabled.side-angle":"An adjoining wall is angled; Resize requires both adjoining walls to meet this wall at right angles","resize.disabled.duplicate-physical-wall":"A separate partition or column overlaps this wall; remove or move it before resizing","resize.disabled.partial-shared":"A neighbouring room uses only part of this wall, so it cannot be moved safely as one shared wall","resize.disabled.unequal-shared":"The neighbouring room uses different endpoints or wall length, so the walls cannot move together safely","resize.disabled.multiple-rooms":"Moving this wall would affect more than two rooms","resize.disabled.thickness-conflict":"The wall thickness cannot be preserved safely","resize.disabled.opening-conflict":"An opening on this wall cannot be moved safely","resize.disabled.invalid-geometry":"This wall cannot be resized without changing the plan structure","resize.limit_stopped":"Wall stopped: the next step would break a junction limit","resize.commit_failed":"Resize was cancelled because the final plan did not pass the geometry check","resize.preview_failed":"Resize stopped at the last safe position because the plan geometry could not be preserved","markup.opening":"Opening","markup.delete_room":"Delete room","history.undo":"Undo","history.redo":"Redo","history.undo_named":"Undo: {name} (Ctrl+Z)","history.redo_named":"Redo: {name} (Ctrl+Shift+Z / Ctrl+Y)","history.undo_empty":"Nothing to undo","history.redo_empty":"Nothing to redo","history.undone":"Undone: {name}","history.redone":"Redone: {name}","history.add_room":"Create room","history.split_room":"Split room","history.merge_rooms":"Merge rooms","history.resize_room":"Resize room","history.wall_thickness":"Change wall thickness","history.add_opening":"Add door or window opening","history.edit_opening":"Edit opening","history.move_opening":"Move opening","history.delete_opening":"Delete opening","history.delete_room_keep_walls":"Delete room, keep walls","history.delete_room_with_walls":"Delete room and walls","history.decor_add":"Add decor object","history.decor_edit":"Edit decor object","history.decor_move":"Move decor object","history.decor_transform":"Transform decor object","history.decor_delete":"Delete decor object","history.backdrop_transform":"Transform plan backdrop","history.device_move":"Move {name}","history.device_stale":"Device position history is no longer applicable and was cleared","opening.new":"New opening","opening.edit":"Opening","opening.door":"Door","opening.window":"Window","opening.gate":"Gate","opening.passage":"Open passage","opening.passage_binding_warning":"Saving will remove the open/close sensor and lock.","opening.invalid_passage_fields":"The open passage on plan “{room}” has unsupported settings: {fields}.","opening.type_label":"Type","opening.length_label":"Length, cm","opening.contact_label":"Open/close sensor","opening.lock_label":"Lock","opening.none":"— none —","opening.search_ph":"Search: name or entity id…","opening.invert":"Invert open/closed","opening.flip_h":"Hinge on the other jamb","opening.flip_v":"Opens to the other side","opening.open":"Open","opening.closed":"Closed","opening.locked":"Locked","opening.unlocked":"Unlocked","opening.state_unknown":"unavailable","opening.no_entities":"No sensors bound — a static symbol on the plan.","toast.opening_no_wall":"Click next to a room wall or independent wall","opening.host_partition":"Independent wall","opening.partition_orphan":"The independent wall for this opening no longer exists","opening.partition_jamb_margin":"Leave at least {distance} between the opening and the end of the wall","opening.rebind_partition":"Attach to another independent wall","confirm.delete_partition_openings_title":"Delete wall and openings?","confirm.delete_partition_openings_body":"This wall contains {count} opening(s). They will be deleted together.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.hint_points":"points: {n} · Shift — 45° steps · Esc — finish chain · Ctrl+Z — undo a point · closing an area offers a room","markup.hint_start":"click a grid dot to start a wall chain","tip.lqi":"average zigbee signal:","tip.area":"area: {value}","info.device_header":"Device on the plan","info.model":"Model","info.state":"State","info.link":"Link","info.manuals":"Manuals","info.none":"No additional information","marker.new_device":"New device","marker.name_label":"Name","marker.name_ph":"Name","marker.binding_label":"Bind to an HA device","marker.binding_disabled":"disabled in Home Assistant","marker.virtual_option":"Virtual device (no binding)","marker.search_ph":"Search device / group…","marker.nothing_found":"nothing found","marker.room_label":"Room","marker.room_choose":"— select a room —","marker.room_auto":"— by device area (auto) —","marker.icon_label":"Icon","marker.icon_ph":"mdi:… (empty = auto)","marker.display_label":"Display","display.badge":"Icon + state","display.icon_ripple":"Icon + state and activity","display.static_icon":"Always static icon","display.value_static_icon":"Value + static icon","marker.display_hint_badge":"The icon and dynamic plate show device state without the ordinary activity pulse. Red alarms remain visible.","marker.display_hint_icon_ripple":"The icon, dynamic plate and pulse show a short pulse for events and a continuous pulse for work, motion or presence. Red alarms have separate priority.","marker.display_hint_value":"A selected or automatically resolved Home Assistant value replaces the icon while the plate continues to show state. Red alarms remain visible.","marker.display_hint_static_icon":"The theme-aware shell and icon always stay the same. State, activity, unavailability and alarms do not change the face.","marker.display_hint_value_static_icon":"The marker shows the selected value while the shell stays theme-aware. State, activity, unavailability and alarms do not change the marker colour.","marker.static_alarm_warning":"This device can report alarms. Static display hides the marker's visual alarm indication.","marker.preview.title":"Display preview","marker.preview.actual":"Now","marker.preview.example":"Example","marker.preview.integration":"Provided by","marker.preview.source":"Display source","marker.preview.current_state":"Current state","marker.preview.result":"On the plan","marker.preview.details":"Source details","marker.preview.select_source":"Choose a Home Assistant device or entity to see its actual display.","marker.preview.unknown_provider":"Unknown integration","marker.preview.virtual_provider":"House Plan · virtual device","marker.preview.no_source":"No active source","marker.preview.no_state":"No current state","marker.preview.mixed_states":"Several different states","marker.preview.multiple_sources":"{n} sources","marker.preview.more_sources":"+{n} more","marker.preview.scaled":"The preview is scaled to {n}% to fit. The saved size is unchanged.","marker.preview.demo_short":"Show short activity","marker.preview.demo_continuous":"Show continuous activity","marker.preview.stop_continuous":"Stop continuous activity","marker.preview.demo_short_notice":"Short activity example; the actual device state is unchanged.","marker.preview.demo_continuous_notice":"Continuous activity example; the actual device state is unchanged.","marker.preview.demo_already_visible":"The current state already shows a real activity or alarm effect.","marker.preview.reduced_motion":"System reduced-motion is enabled, so ordinary activity is shown as a dot.","marker.preview.reason.neutral":"Neutral dark plate","marker.preview.reason.working":"Yellow plate: the device is working now","marker.preview.reason.working_activity":"Yellow plate and activity effect: the device is working now","marker.preview.reason.open":"Orange plate: physically open or unlocked","marker.preview.reason.cover_icon_state":"Neutral plate; the cover entity controls the displayed state and icon","marker.preview.reason.presence":"Activity effect while presence is detected","marker.preview.reason.event":"Short activity effect after a detected event","marker.preview.reason.transition":"Activity effect while the device is moving or changing state","marker.preview.reason.media_neutral":"Media devices stay on a neutral dark plate while available","marker.preview.reason.unavailable":"Subdued neutral plate: unavailable or off","marker.preview.reason.alarm":"Red alarm plate; alarm indication is always shown","marker.preview.reason.live_states_disabled":"Live-state styling is disabled for this card","marker.preview.reason.value_no_state":"No usable state value; the icon is shown instead","marker.preview.reason.value_ambiguous_sources":"Several possible value sources; the icon is shown instead","marker.preview.reason.value_non_scalar":"The source did not return a simple value; the icon is shown instead","marker.preview.reason.value_virtual":"A virtual device has no Home Assistant value; the icon is shown instead","marker.preview.reason.vacuum_live_plan_only":"Live vacuum position and trail are available only on the full plan","marker.preview.reason.hidden_design_preview":"The device is hidden on the plan; this design preview remains visible","marker.preview.reason.composite_power_source":"State comes from the device Power entity; auxiliary switches are ignored","marker.preview.reason.activity_display_disabled":"The selected display mode does not show ordinary activity effects","marker.preview.reason.ha_disabled":"The Home Assistant binding is disabled and will be hidden on the plan","marker.preview.reason.orphaned":"The saved Home Assistant binding can no longer be found","marker.preview.reason.static_icon":"Static mode: device state does not change the icon","marker.preview.reason.value_static_icon":"Static mode with a value: device state does not change the marker colour","marker.activity_color":"Activity pulse color","marker.ripple_size":"Activity pulse size","marker.activity_alarm_note":"Color and size affect ordinary activity only and do not change red alarms.","marker.pulse_a11y_alarm":"Alarm","marker.pulse_a11y_event":"Recent event","marker.pulse_a11y_presence":"Presence detected","marker.pulse_a11y_transition":"Changing state","marker.pulse_a11y_running":"Working","marker.state_a11y_neutral":"Default state","marker.state_a11y_working":"Working","marker.state_a11y_open":"Open","marker.state_a11y_locked":"Locked","marker.state_a11y_unlocked":"Unlocked","marker.state_a11y_alarm":"Alarm","marker.state_a11y_unavailable":"Unavailable","marker.lqi_a11y_low":"LQI {value}, low signal","marker.lqi_a11y_mid":"LQI {value}, medium signal","marker.lqi_a11y_high":"LQI {value}, high signal","marker.size_label":"Icon size and rotation","marker.angle_label":"Rotate","marker.model_label":"Model","marker.model_ph":"e.g. Aqara T&H","marker.link_label":"Link","marker.desc_label":"Description","marker.desc_ph":"Notes, specs…","marker.manuals_label":"Manuals (PDF etc.)","marker.sub_device":"device","marker.sub_z2m_group":" · Z2M group","marker.sub_group":"group","marker.sub_helper":"helper","space.new":"New space","space.copy_title":"Copy space","space.copy_name":"New space name","space.copy_fallback":"Space","space.copy_create":"Create copy","space.copy_optimize_title":"Optimize before copying?","space.copy_optimize_body":"Before creating “{name}”, House Plan must optimize the entire plan, including other spaces. Continue?","space.copy_optimize_confirm":"Optimize and copy","space.copy_error_changed":"The plan changed while confirmation was open. Review it and try again.","space.copy_error_source_missing":"The source space no longer exists. Reopen its settings and try again.","space.copy_error_source_invalid":"House Plan could not validate every wall in this space. Fix the source space and try again.","space.copy_error_spaces_limit":"House Plan already has the maximum number of spaces.","space.copy_error_partitions_limit":"This space has too many walls to copy.","space.copy_error_openings_limit":"This space has too many openings to copy.","space.copy_error_decor_limit":"This space has too many background objects to copy.","space.copy_error_columns_limit":"This space has too many columns to copy.","space.copy_error_opening_host":"One of the openings is no longer attached to a wall. Fix or delete it before copying.","space.copy_error_geometry":"The copy would create unsafe wall geometry. Fix the source space and try again.","space.copy_error_optimize_geometry":"Copy stopped because optimizing the entire plan is unsafe for one of the spaces.","space.header":"Space","space.title_label":"Space name","space.title_ph":"e.g. Garage","space.plan_label":"Floor plan","space.no_plan":"no plan image","space.plan_alt":"plan","room.new":"New room","room.name_label":"Display name","room.name_ph":"e.g. Terrace","room.area_label":"Home Assistant area","room.no_area_option":"— no area —","room.default_name":"Room","device.unnamed":"unnamed","device.light_group":"light group","device.fallback":"device","device.virtual":"virtual device","confirm.delete_room_title":'Delete room "{name}"?',"confirm.delete_room_body":"Choose whether the room's exclusive physical walls should remain. Walls shared with another room are always kept.","confirm.remove_marker_title":"Delete device from the plan?","confirm.remove_marker_body":"The device will disappear completely and stop contributing to plan data. You can add it again later.","confirm.erase_decor":"Erase the {kind} object? You can undo this action from the editor history.","confirm.delete_space_title":"Delete space?","confirm.delete_space_body":"The space, all its rooms and all its plan markup will be deleted.","confirm.delete_space_vac_routes":"Robot map assignments will also be removed: {count}.","space.delete_blocked":"This space is still used by {n} device(s). Move them to another space or delete them first.","toast.pos_save_failed":"Failed to save position: {err}","toast.no_entity":"The device has no suitable entity","toast.ha_disabled_action":"A Home Assistant object that is disabled cannot be used on the plan.","toast.ha_disabled_show_device":"A device disabled in Home Assistant cannot be shown on the plan. Enable it in Home Assistant first.","toast.ha_disabled_show_entity":"An entity disabled in Home Assistant cannot be shown on the plan. Enable it in Home Assistant first.","toast.ha_disabled_add":"A disabled Home Assistant object cannot be added to the plan. Enable it in Home Assistant first.","toast.ha_binding_unverified":"The object status could not be verified through the Home Assistant registry. Display and actions are temporarily unavailable.","toast.markup_needs_server":"Markup is available after the config is moved to the server","toast.space_order_changed":"Order changed. If any card pins its floor by number, check those panels.","toast.conflict":"Config was changed in another window — data refreshed, repeat your last action","toast.cfg_save_failed":"Failed to save config: {err}","toast.room_overlap":"The outline overlaps room “{name}” — rooms must not overlap","toast.contour_cannot_close":"The outline cannot close because it is degenerate or intersects itself","toast.merge_not_adjacent":"Only rooms that share a wall can be merged","toast.rooms_merged":"Rooms merged into “{name}”","toast.split_pick_wall":"Start the cut on the room’s wall","toast.split_bad_cut":"The cut must run wall to wall inside the room, without crossing walls or itself","merge.header":"Merge rooms","merge.hint":"The merged room keeps one name and one area. The other area is released — its devices leave the plan until another room claims it.","merge.keep":"Keep","merge.no_area":"no area","toast.room_saved":"Room saved ({n}). Devices added: {added}. Outline the next one or exit markup.","toast.room_saved_no_area":"Room saved ({n}, no area). Outline the next one or exit markup.","toast.marker_needs_server":"Device editing is available after the config is moved to the server","toast.virtual_name_required":"Enter a name for the virtual device","toast.marker_saved":"Device saved","toast.marker_removed":"Device deleted from the plan","toast.integration_missing":"The House Plan integration is not installed — management unavailable","toast.plan_formats":"Supported formats: SVG, PNG, JPG, WebP","toast.plan_required":"Upload a floor plan — it is required","toast.space_added_onboard":"Space added. Outline the rooms: click grid dots and close the contour.","toast.space_added":"Space added","toast.space_copied":"Space “{name}” created","toast.space_saved":"Space saved","toast.space_deleted":"Space deleted","toast.delete_failed":"Delete failed: {err}","toast.error":"Error: {err}","toast.toggle_target_unavailable":"Target “{name}” is unavailable — no action was performed","toast.toggle_targets_unavailable":"Targets are unavailable: {names}. No action was performed","toast.file_failed":'File "{name}" was not uploaded: {err}',"toast.files_attached":"Files attached: {n}","err.unknown":"unknown error","err.code":"code {code}","err.too_large":"file larger than {mb} MB","err.bad_ext":"unsupported type (PDF/image expected)","err.unauthorized":"administrator rights required","editor.title":"Title","editor.default_floor":"Initial space","editor.default_floor_missing":"Initial space “{id}” no longer exists. Choose another space.","editor.floor":"Fixed space","editor.floor_none":"— not fixed —","editor.floor_index":"YAML index {index} (preserved)","fixed_floor.loading":"Loading the fixed space…","fixed_floor.invalid_title":"The fixed space is unavailable","fixed_floor.invalid_body":"Check floor in the card configuration. The configured value is: {value}","editor.icon_size":"Icon size, % of plan width","editor.show_temperature":"Show temperature","editor.live_states":"Live states (on/off, open…)","editor.light_pools":"Light pools and wall shadows","editor.show_signal":"Show zigbee signal (LQI)","editor.language":"Interface language","editor.lang_auto":"Auto (HA profile)","title.icon_rules":"Icon rules: which MDI icon devices get by name","rules.title":"Icon rules","rules.hint":"Rules are checked top-down against “device name + model” (case-insensitive regex); the first match wins. When nothing matches, the entity device class decides, then the generic chip icon.","rules.pattern_ph":"regex, e.g. plug|socket","rules.icon_ph":"mdi:power-socket-de","rules.add":"Add rule","rules.reset":"Reset to defaults","rules.test_ph":"Try a device name…","rules.invalid":"invalid regex","rules.saved":"Icon rules saved","btn.up":"Up","btn.down":"Down","tap.info":"Device card","tap.more_info":"HA more-info dialog","tap.toggle":"Toggle state","marker.tap_label":"Tap action for this device","tap.toggle_note":"The resolved state is shown below. Secure devices are never toggled from the plan.","import.title":"Create spaces from HA floors","import.hint":"Your Home Assistant already knows these floors. Pick the ones to turn into plan spaces — you will upload a floor-plan image for each one next. Rooms are then outlined by hand on the plan.","import.start":"Create {n} space(s)","import.manual":"Start from scratch","import.progress":"Floor {i} of {n}","import.done":"Spaces created. Outline the rooms: click grid dots and close the contour.","btn.skip":"Skip","space.scale_label":"Scale (grid cell size)","space.cell_cm.help":"Links the grid to real dimensions: lengths, areas, wall thickness, opening sizes and glow radius depend on it. Changing it after drawing changes the calculated dimensions of the whole space without moving its points on the plan.","space.cell_cm.help.aria":"Help: space scale","space.scale_unit":"cm per cell","space.scale_unit_imperial":"in per cell","space.display_section":"Appearance","space.show_borders":"Always show room borders","space.zero_wall_style":"Zero-thickness walls","space.zero_wall_style.help":"Dashed zero-thickness walls pass Glow and sun rays, while solid ones block them as zero-area barriers. The choice affects every such wall in the space even when its line is hidden in View.","space.zero_wall_style.help.aria":"Help: zero-thickness wall style","space.zero_wall_dashed":"Dashed","space.zero_wall_solid":"Solid","space.show_names":"Show room names","space.room_color":"Border & name color","space.opacity":"Opacity","space.fill_label":"Room fill","space.fill_mode.help":"“Custom colour” is styling, while “Light”, “Temperature” and “LQI” use current Home Assistant data; Glow is enabled separately.","space.fill_mode.help.aria":"Help: room fill mode","fill.none":"None","fill.lqi":"Zigbee signal","fill.light":"Lights","fill.custom":"Custom color","space.custom_fill":"Fill color","space.source_file":"Use a floor-plan image","space.source_draw":"Draw it myself","fill.temp":"Temperature","tip.temp_avg":"average temperature:","tip.hum_avg":"average humidity:","space_card.button":"Open the space plan","space_card.not_found":"Space “{id}” not found","space_card.loading":"Loading…","continuity.restore_plan":"Restoring floor plan…","continuity.restore_connection":"Restoring device connection…","continuity.retry":"Try again","editor.space":"Space","editor.framing":"Framing","editor.fit_content":"All visible content","editor.fit_house":"Tight to house geometry","editor.show_button":"Show button","editor.button_label":"Button label","editor.button_target":"Target dashboard path","marker.sub_entity":"entity","title.general_settings":"General settings","title.export_pdf":"Save as PDF","pdf.title":"Save as PDF","pdf.dimensions":"Show dimensions and areas","pdf.decor":"Show furniture and other decor","pdf.room_names":"Show room names","pdf.backdrop":"Show backdrop","pdf.save":"Save","pdf.saving":"Creating…","pdf.failed":"Could not create the PDF.","pdf.too_large":"The images exceed the 25 MB PDF limit.","pdf.asset_failed":"A backdrop or decor image could not be loaded.","pdf.scale":"Scale 1:{n}","pdf.north":"North","gs.title":"General settings","gs.light_group":"Lights","gs.light_on":"Lights on","gs.light_off":"All lights off","gs.temp_group":"Temperature","gs.temp_cold":"Cold","gs.temp_ok":"Comfortable","gs.temp_hot":"Hot","gs.lqi_group":"Zigbee signal","gs.lqi_low":"Weak signal","gs.lqi_high":"Strong signal","gs.reset":"Reset to defaults","gs.saved":"General settings saved","gs.radar_show_live":"Show live presence on the plan","radar.title":"Presence on the plan","radar.help":"Connect this marker to exact Home Assistant radar entities, place the sensor and choose its coordinate profile. Live positions are clipped to the selected room.","radar.help.aria":"Help: presence radar settings","radar.enabled":"Use this presence radar","radar.show_live":"Show live targets","radar.configure":"Configure radar","radar.configure_on_plan":"Configure on plan","radar.change_installation":"Change installation","radar.no_contour":"This room has no boundary. Radar points will not be clipped.","radar.discard_setup_title":"Discard radar setup?","radar.discard_setup":"The unsaved radar setup will be lost.","radar.step_place_mount":"Mark the physical sensor position","radar.step_place_heading":"Mark a point straight ahead of the sensor","radar.step_reference":"Mark reference position {n}, then start measurement","radar.step_check_reference":"Mark an independent check position","radar.start_measure":"Start measurement","radar.countdown":"Stand at the mark in {seconds} s","radar.capturing":"Stand still and alone while measuring…","radar.fit_ready":"Calibration is ready","radar.check_third":"Check at another position","radar.check_complete":"Independent check completed","radar.error_distance":"Position difference: {distance}","radar.ambiguous_target":"More than one target was reported. Repeat the measurement alone.","radar.insufficient_samples":"Not enough current coordinates. Retry or use manual setup.","radar.bad_references":"Choose separated references in different directions from the sensor.","radar.ambiguous_sources":"The measurements allow two equally plausible directions. Choose reference points that distinguish left from right.","radar.bad_fit":"Measurements do not match. Check units, mounting point and references.","radar.desktop_hint":"Use a computer for precise setup. Editing on touch devices is best effort.","radar.detected":"House Plan recognized radar metadata for this device. Review the exact sources before saving.","radar.detected_ld2450":"House Plan found an ESPHome LD2450 coordinate set. Review the exact X/Y sources before saving.","radar.additional_actions":"Additional actions","radar.declare":"This is a presence radar","radar.profile":"Data profile","radar.profile_esphome_ld2450_v1":"ESPHome LD2450 (X/Y targets)","radar.profile_cartesian_v1":"Cartesian targets (X/Y)","radar.profile_polar_v1":"Polar target (distance/angle)","radar.profile_range_v1":"Distance only","radar.profile_zones_v1":"Zone states","radar.profile_presence_v1":"Presence only","radar.room":"Radar room","radar.room_choose":"Choose a room","radar.target":"Target {n}","radar.axis_x":"X coordinate entity","radar.axis_y":"Y coordinate entity","radar.add_target":"Add target slot","radar.range_channel":"Range channel {n}","radar.add_range":"Add range channel","radar.presence_gate":"Presence gate entity","radar.swap_axes":"Swap X and Y axes","radar.axis_x_sign":"X direction","radar.axis_y_sign":"Y direction","radar.distance_source":"Distance entity","radar.angle_source":"Angle entity","radar.angle_unit":"Angle unit","radar.degrees":"Degrees","radar.radians":"Radians","radar.angle_zero":"Zero-angle direction","radar.angle_forward":"Forward","radar.angle_right":"Right","radar.angle_clockwise":"Angles increase clockwise","radar.zone_source":"Zone entity","radar.occupancy_source":"Presence entity","radar.count_source":"Target count entity","radar.availability_source":"Availability entity","radar.source_choose":"Choose an entity","radar.source_optional":"Optional","radar.source_missing":"currently unavailable","radar.saved_unsupported":"This saved radar setup is unsupported or incomplete. It remains inactive; remove it or update House Plan before configuring it again.","radar.occupancy":"Presence (on/off)","radar.count":"Count","radar.mount":"Position and direction","radar.mount_hint":"This is the physical sensor position. Moving its decorative marker does not change it.","radar.heading":"Direction, °","radar.range_cm":"Range, cm","radar.fov_deg":"Field of view, °","radar.unit":"Source unit","radar.mirror":"Mirror the left/right axis","radar.remove":"Remove radar settings","radar.invalid":"Complete the radar room, sources and position before saving.","radar.check_sources":"Check live data","radar.checking":"Checking…","radar.health":"Connection status","radar.live_summary":"Current targets: {targets}; range arcs: {ranges}","radar.health_ok":"Current data received","radar.health_off":"No targets detected","radar.health_stale":"Some coordinate data is out of date","radar.health_partial":"Some sources are current; others are out of date","radar.health_restricted":"Access to one or more sources is restricted","radar.health_incomplete":"The current radar report is incomplete","radar.health_position_unavailable":"Presence reported; current position unavailable","radar.health_unavailable":"Sensor data unavailable","radar.health_needs_setup":"Installation needs setup","radar.health_inconsistent":"The sources report conflicting values","radar.health_unknown":"Current state is unknown","radar.health_disabled":"Radar is disabled","radar.error_invalid_radar":"Check the radar settings.","radar.error_invalid_selection":"Select an existing room and valid sources.","radar.error_source_restricted":"You do not have access to all selected sources.","radar.error_rate_limited":"Too many requests. Try again shortly.","radar.error_not_ready":"Radar processing is not ready.","radar.error_conflict":"The plan changed. Reopen the radar setup and try again.","radar.error_source_unavailable":"One or more selected radar sources are unavailable.","radar.error_unsupported_capability":"This radar capability is not supported by the installed integration.","radar.report_age":"{seconds} s ago","space.show_lqi":"Zigbee signal next to devices","gs.light_none":"No light sources","mode.plan":"Plan editor","mode.devices":"Device editor","display.value":"Value + state","marker.subarea":"no area, manual","device.new":"New device — open its editor to dismiss","opening.unlock_action":"Unlock","opening.lock_action":"Lock","opening.lock_pending":"Working…","title.close_editor":"Close editor (back to view)","title.add_device":"Add a device to the plan","devbar.add":"Add","devbar.rules":"Icon rules","device_inbox.button":"Devices","device_inbox.title":"Devices on the plan","device_inbox.search":"Search devices, entities and integrations…","device_inbox.add_virtual":"Add virtual device","device_inbox.tab_on_plan":"On plan","device_inbox.tab_available":"Available","device_inbox.tab_hidden":"Hidden","device_inbox.tab_readd":"Available again","device_inbox.only_new":"New only","device_inbox.show_entities":"Show entities","device_inbox.show_hidden":"Show hidden on plan","device_inbox.show_hidden.help":"Temporarily shows hidden and disabled markers as editor-only ghosts on the plan. Saved device visibility does not change.","device_inbox.show_hidden.help.aria":"Help: show hidden devices on the plan","device_inbox.new":"New","device_inbox.find":"Find on plan","device_inbox.edit":"Edit","device_inbox.hide":"Hide","device_inbox.show":"Show","device_inbox.add":"Add","device_inbox.readd":"Add again","device_inbox.hide_available":"Hide from list","device_inbox.show_more":"Show more","device_inbox.more_actions":"More actions","device_inbox.find_hidden_hint":"Enable “Show hidden on plan” first","device_inbox.show_disabled":"Activate this binding in Home Assistant before showing it","device_inbox.empty_on_plan":"No matching devices are on the plan yet.","device_inbox.empty_available":"No devices are available to add.","device_inbox.empty_hidden":"There are no hidden devices.","device_inbox.empty_readd":"No removed devices are available to add again.","device_inbox.reason_visible_auto":"Discovered automatically","device_inbox.reason_visible_explicit":"Added explicitly","device_inbox.reason_manual_hidden":"Hidden by user","device_inbox.reason_automatic_hidden":"Hidden automatically","device_inbox.reason_service_entry":"Service-only registry entry","device_inbox.reason_excluded_integration":"Integration “{integration}” excluded by discovery filters","device_inbox.reason_excluded_domain":"Non-spatial entity type","device_inbox.reason_grouped_light":"Represented by a room light group","device_inbox.reason_represented_by_parent":"Represented by its parent device","device_inbox.reason_removed":"Previously removed from the plan","device_inbox.reason_available":"Available to add to the plan","device_inbox.reason_no_bound_room":"HA area is not linked to a plan room","device_inbox.status_ha_disabled":"Disabled in Home Assistant","device_inbox.status_orphaned":"Binding is no longer present in Home Assistant","device_inbox.status_unverified":"Home Assistant registry is temporarily unavailable","device_inbox.saved":"Device list updated","device_inbox.filters_excluded":"Excluded integrations","device_inbox.filters_group_lights":"Group room lights into one marker","device_inbox.filters_preview_appear":"will appear: {count}","device_inbox.filters_preview_hide":"will disappear: {count}","device_inbox.filters_preview_lights":"lights affected: {count}","device_inbox.filters_reset":"Restore recommended","device_inbox.filters_save":"Save filters","device_inbox.filters_search_ph":"Add an integration…","device_inbox.filters_title":"Discovery filters","space.roomcard_section":"Room cards","space.label_temp":"Temperature","space.label_hum":"Humidity","space.label_lqi":"Average Zigbee signal","space.label_light":"Lights on/off","roomcard.light_on":"On","roomcard.light_off":"Off","roomcard.light_partial":"{on} of {total}","toast.split_pick_inside":"Intermediate cut points must be inside the room","mode.decor":"Background editor","decor.select":"Select","decor.line":"Line","decor.rect":"Rectangle","decor.ellipse":"Oval","decor.text":"Text","decor.erase":"Erase","decor.erase_confirm_title":"Erase object?","decor.color":"Color","decor.width":"Line width","decor.line_style":"Line style","decor.line_style_solid":"Solid","decor.line_style_dashed":"Dashed","decor.fill":"Fill","decor.fill_color":"Fill color","decor.length":"Length","decor.size":"Size","decor.flip_h":"Flip horizontally","decor.flip_v":"Flip vertically","decor.angle":"Rotation angle, °","decor.text_size":"Text size","decor.backdrop_properties":"Plan backdrop properties","decor.text_title":"Text label","decor.object_title":"Edit {kind}","decor.text_label":"Text","decor.live_group":"Insert HA variable","decor.live_entity":"Entity","decor.live_entity_ph":"choose an entity","decor.live_attr":"Value","decor.live_attr_ph":"choose state or attribute","decor.live_state":"State","decor.backdrop":"Backdrop image","decor.backdrop_hint":"Drag to move; pull a corner to resize; use the top handle to rotate. Shift changes proportions or frees the angle.","decor.backdrop_reset":"Reset the picture","decor.backdrop_reset_done":"The picture is back at its original place and size","marker.icon_auto":"Auto: {icon} (by icon rules; pick one to override)","marker.icon_pin_auto":"Pin","mode.plan_tip":"Plan editor — the geometry of the home: draw and split/merge rooms, bind them to HA areas, place doors, windows and gates, move room cards, set the scale","mode.devices_tip":"Device editor — everything about icons: drag to position, click to edit binding/icon/display, add virtual devices, icon rules","mode.decor_tip":"Background editor — purely visual decor under the plan: lines, rectangles, ovals and text labels that never react to clicks","space.glow_enabled":"Light-source glow","gs.glow_group":"Light-source glow","gs.glow_base":"House darkness","gs.glow_light":"Default light color / intensity","gs.wall_fill":"Wall fill","gs.glow_radius":"Glow radius","gs.glow_radius.help":"Sets the default glow radius in metres or feet; a device-specific radius overrides it.","gs.glow_radius.help.aria":"Help: default glow radius","gs.unit_m":"m","gs.unit_ft":"ft","marker.controls_label":"Controls other light sources","marker.controls.help":"With the “Toggle state” action, the listed sources toggle together with this marker. Their glow stays at their own markers, and the link alone does not turn the controlling marker into a light source.","marker.controls.help.aria":"Help: controlling other light sources","marker.controls_filter":"Search lights and switches…","info.controls":"Controls","marker.glow_radius_label":"Glow radius","marker.glow_radius.help":"Sets the glow radius in metres or feet; an empty value uses the radius from general settings.","marker.glow_radius.help.aria":"Help: glow radius","markup.wallthick":"Thickness","markup.select":"Select","title.markup_wallthick":"Thickness — click a wall to set its thickness from 0 to 100 cm.","markup.hint_wallthick":"click a wall · Esc closes without applying","wallthick.field":"Thickness","wallthick.unit_cm":"cm","wallthick.unit_in":"in","wallthick.apply_room":"Apply to all walls of this room","markup.draw_wall_title":"Thickness of each new wall segment (0–100 cm). Shared walls keep the existing value.","room.queue_progress":"Room {current} of {total}","toast.wall_rooms_saved":"Created rooms: {n}","toast.wall_chain_saved":"Wall chain saved","toast.wallthick_pick":"Click a wall","toast.wallthick_set":"Wall thickness set","toast.wallthick_cleared":"Wall thickness removed","toast.physical_range":"Enter a value from {min} to {max} {unit}","toast.zero_wall_opening_conflict":"Remove the opening on this wall segment first.","toast.zero_wall_ambiguous":"The wall segment is ambiguous. Simplify or adjust the junction.","toast.zero_wall_migration_blocked":"The space was not converted: {reason}. No data was changed.","toast.physical_angle":"Enter a rotation angle from 0° up to, but not including, 90°","toast.physical_limit":"The space has reached the limit for this type of geometry","toast.geometry_unsafe":"Change canceled: wall geometry could not be built safely.","junction.limit_angle":"The angle between walls is too sharp: {actual}°, minimum {limit}°.","junction.limit_valence":"Too many walls meet in one node: {actual}, maximum {limit}.","junction.limit_length":"The wall segment is too short: {actual} cm, minimum {limit} cm.","junction.limit_distance":"Walls and nodes are too close: {actual} cm, minimum {limit} cm.","junction.limit_clearance":"No room interior is left: {actual} cm², minimum {limit} cm².","junction.limit_check_failed":"The junction check could not run — the change was not saved","toast.wall_model_migration_blocked":"The wall model could not be updated: {reason}. The plan was not changed. Run “Optimize plans”; if the error repeats, fix the conflicting wall geometry.","toast.wall_model_client_outdated":"Update the card and reload the page before editing the plan.","wall_model.reason.invalid-room":"invalid room contour","wall_model.reason.zero-length":"zero-length wall segment","wall_model.reason.third-owner":"wall shared by more than two rooms","wall_model.reason.duplicate-id":"conflicting wall identifiers","wall_model.reason.thickness-conflict":"conflicting wall thickness values","wall_model.reason.opening-host":"opening cannot be assigned to one wall","toast.delete_room_pick":"Click inside the room you want to delete","toast.plan_snap_ambiguous":"Zoom in to choose the wall node","toast.wall_repair_ambiguous":"The room outline has more than one possible connection. Zoom in and connect it explicitly.","toast.wall_repair_too_large":"The gap is larger than 2 cm. Connect the walls before creating the room.","toast.wall_repair_changed":"The wall geometry changed. Try creating the room again.","toast.opening_on_zero_wall":"Openings cannot sit on a zero-thickness wall","marker.from_ha_option":"Pick from the HA list","marker.show_entities":"Show entities","marker.show_entities_tip":"Adds not only devices to the list, but all their entities too","marker.pick_ph":"Choose a device…","room.open_area":"Open the HA area","room.fit_action":"Fit room {name}","view.volumetric":"Volumetric view","view.flat":"Flat view","kiosk.title":"This screen's sizes","kiosk.hint":"Stored on this device only — every wall tablet or TV can have its own comfortable sizes.","kiosk.icon_scale":"Device icon size","kiosk.font_scale":"Room card text size","editor.kiosk":"Wall device (kiosk) mode","editor.cycle":"Auto-switch spaces every N seconds (kiosk, 0 = off)","room.settings_title":"Room settings","room.fill_label":"Fill in THIS room","fill.inherit":"As the space","room.custom_fill_space":"Space color","room.custom_fill_own":"Room color","room.temp_range_label":"Comfort range","room.temp_range_min":"Lower comfort-temperature bound","room.temp_range_max":"Upper comfort-temperature bound","room.temp_range_reset":"As the space","room.temp_range.help":"This range applies only to this room. Empty fields inherit the corresponding space bounds; if the bounds are reversed, House Plan uses the smaller value as the lower bound and the larger value as the upper bound.","room.temp_range.help.aria":"About the room comfort range","room.temp_src_label":"Temperature source","room.hum_src_label":"Humidity source","room.src_average":"Average of the room’s sensors","room.src_pick":"Specific device or entity","room.src_ph":"Choose a source…","toast.room_updated":"Room updated","space.card_font":"Room-card font size","room.sizes_section":"Font sizes","room.group_basics":"Basics","room.group_basics.help":"The area links the room to a Home Assistant area, which is where its sensors come from. Without one the room stays geometry.","room.group_basics.help.aria":"Help: room name and area","room.group_fill":"Fill","room.group_fill.help":"This room’s fill overrides the space one; a custom colour is kept for this room only.","room.group_fill.help.aria":"Help: room fill","room.group_sources":"Sensor sources","room.group_sources.help":"By default the room averages its own sensors. A selected sensor replaces that average everywhere: tooltip, card, fill.","room.group_sources.help.aria":"Help: temperature and humidity sources","room.sizes_section.help":"These scales apply to this room only and multiply the shared card scale from the space settings.","room.sizes_section.help.aria":"Help: room font sizes","room.name_scale":"Room name size","room.label_scale":"Metrics size","preview.room_name":"Living room","toast.cfg_reload_failed":"Could not reload the plan from the server: {err}","toast.locale_load_failed":"Could not load the language pack. English is used until the page reloads.","toast.furniture_art_load_failed":"Could not load the furniture drawings. Reload the page to show them.","room.settings_short":"Room settings","room.unnamed":"Unnamed room","marker.use_climate_temp":"Include the device temperature in the room","marker.use_climate_temp_tip":"Adds an air conditioner or thermostat current_temperature to the room average. Configure the external value badge separately below.","marker.value_badge_title":"Value badge","marker.value_badge.help":"Shows one selected value next to the icon. It does not affect room metrics, light, Glow or the tap action.","marker.value_badge.help.aria":"Help: device value badge","marker.value_badge_enabled":"Show a value badge","marker.value_badge_source":"Value","marker.value_badge_source.help":"Choose a specific state, supported attribute, or derived value of this device.","marker.value_badge_source.help.aria":"Help: value badge source","marker.value_badge_position":"Position","marker.value_badge_position.help":"The chosen side stays fixed and does not flip automatically at a plan edge.","marker.value_badge_position.help.aria":"Help: value badge position","marker.value_badge_right":"Right","marker.value_badge_bottom":"Below","marker.value_badge_left":"Left","marker.value_badge_top":"Above","marker.value_badge_empty":"This device has no available values","marker.value_badge_static":"A static icon does not show live values. The setting is preserved.","marker.value_badge_missing":"Source unavailable","marker.value_badge_missing_hint":"The saved source is currently unavailable. Keep it, disable the badge, or choose another value.","marker.value_badge_duplicate":"The same value is already shown inside the icon.","marker.value_badge_state":"State · {name}","marker.value_badge_marker_state":"Light-source state · {name}","marker.value_badge_lqi":"Average Zigbee signal quality","marker.value_badge_attr_current_temperature":"Current temperature · {name}","marker.value_badge_attr_temperature":"Target temperature · {name}","marker.value_badge_attr_current_humidity":"Current humidity · {name}","marker.value_badge_attr_humidity":"Humidity · {name}","marker.value_badge_attr_current_position":"Position · {name}","marker.value_badge_attr_percentage":"Speed · {name}","marker.value_badge_attr_brightness":"Brightness · {name}","marker.value_badge_attr_volume_level":"Volume · {name}","marker.value_badge_attr_battery_level":"Battery · {name}","marker.value_badge_attr_fan_speed":"Fan speed · {name}","marker.value_source":"Value source","marker.value_source.help":"Choose the value that replaces the icon. The tap action does not change.","marker.value_source.help.aria":"Help: value face source","marker.value_source_auto":"Automatic (as before)","marker.value_source_missing_hint":"The saved source is currently unavailable. The face shows — until it recovers or you choose another value.","marker.light_role_label":"Is this device a light source?","marker.light_role.help":"“Auto” uses the bound device's resolved role, “Always” forces its own source and “Never” excludes it; linked lights above remain independent.","marker.light_role.help.aria":"Help: whether this device is a light source","marker.light_role_auto_yes":"Auto (light source)","marker.light_role_auto_no":"Auto (not a light source)","marker.light_entity_label":"Leading light entity","marker.light_entity.help":"For a composite device, choose the entity whose state, colour and brightness represent this plan source. The automatic fallback remains compatible with older plans.","marker.light_entity.help.aria":"Help: leading light entity","marker.light_entity_auto":"Automatic ({entity})","marker.light_entity_none":"no controllable entity","marker.light_entity_missing":"The saved entity {entity} is unavailable. House Plan temporarily uses {fallback}; the saved choice will be restored if it returns.","marker.toggle_entity_label":"Entity to toggle","marker.toggle_entity.help":"For a composite device, choose the exact own light or switch operated by a tap. Automatic keeps the previous target rules and is independent from the leading light entity.","marker.toggle_entity.help.aria":"Help: entity to toggle","marker.toggle_entity_auto":"Automatic ({entity})","marker.toggle_entity_none":"no own controllable entity","marker.toggle_entity_missing":"The saved entity {entity} is no longer among this marker’s selectable channels. House Plan temporarily uses {fallback}; the saved choice will be restored if it returns.","marker.glow_color_label":"Glow colour and brightness","marker.glow_mode.help":"Use live source values, override only its colour, or fix both colour and brightness. The minimum is 1%; to disable the source, choose “Never”.","marker.glow_mode.help.aria":"Help: glow colour and brightness","marker.glow_mode_auto":"From source","marker.glow_mode_color":"Set colour","marker.glow_mode_fixed":"Colour and brightness","marker.glow_color":"Glow colour","marker.glow_brightness":"Brightness","marker.glow_disabled_never":"Glow settings are unavailable because this marker is explicitly not a light source.","marker.glow_disabled_auto":"Auto mode found no spatial light source for this marker.","marker.glow_disabled_no_entity":"No active controllable Home Assistant entity is available for this spatial source.","marker.glow_passive_hint":"This source has no own Home Assistant data. Set its colour and brightness manually; its radius remains available.","marker.control_broken":"Saved source is missing or no longer marked as a light","marker.control_missing_label":"Missing plan light","marker.control_passive":"passive source","toast.marker_control_cycle":"This link would create a circular chain of light controls.","toast.marker_binding_required":"Choose a Home Assistant device before linking another light source.","confirm.unlock_title":"Unlock?","confirm.unlock_body":"House Plan will send an unlock command to this lock.","toast.files_migrate_failed":"Attachments could not be moved to the new binding, links keep pointing at the old files: {err}","space.pick_saved":"Already uploaded","space.pick_saved_hint":"Plans stored on the server, including ones you detached earlier","space.no_saved":"No plans stored on the server yet.","space.loading":"Loading…","space.used_by":"in use: {list}","space.in_use":"A space still uses this plan — detach it first","btn.use":"Use","confirm.delete_plan_title":"Delete plan file?","confirm.delete_plan_body":"The file will be deleted from the server. This action cannot be undone.","toast.plans_list_failed":"Could not list the stored plans: {err}","toast.plan_delete_failed":"Could not delete the plan: {err}","marker.hide":"Hide","marker.hide_tip":'The device will disappear from the plan after saving but will still count toward the room signal. Restore it through the "Devices" catalog in the device editor.',"marker.show":"Show","marker.show_tip":"The device will appear on the plan again after saving.","marker.hidden_ghost":"Device hidden by the user","marker.ha_disabled_device":"The device is disabled in Home Assistant and hidden from the plan.","marker.ha_disabled_entity":"The entity is disabled in Home Assistant and hidden from the plan.","marker.ha_disabled_all_entities":"The device has no active Home Assistant entities, so it is hidden from the plan.","marker.ha_registry_limited":"The full Home Assistant registry is unavailable to this user. The unverified object cannot be shown or used for now.","marker.delete_tip":"Completely delete the device from the plan and every aggregate. You can add it again later.","tap.run":"Run automation/script/scene","tap.none":"Do nothing","marker.run_target_label":"What to run","marker.run_search_ph":"Search: automation, script or scene…","marker.run_target_gone":"Target {id} not found — pick again","marker.tap_confirm":"Ask for confirmation","marker.tap_confirm_tip":"Show a confirmation dialog before acting — a guard against accidental taps.","marker.toggle_hint_single":"Target: {name} ({id}).","marker.virtual_light_target":"Virtual light: {name}.","marker.virtual_light_current":"Manual state: {state} → {effect}.","marker.virtual_light_state_on":"on","marker.virtual_light_state_off":"off","marker.toggle_hint_group":"Will toggle {count} source(s): {names}.","marker.toggle_hint_current":"Now: {state} → {effect}.","marker.toggle_hint_group_current":"Currently on: {on} of {count} → {effect}.","marker.toggle_hint_skipped":"Will be skipped ({count}): {targets}.","marker.toggle_effect_turn_on":"will turn on","marker.toggle_effect_turn_off":"will turn off","marker.toggle_effect_open":"will open","marker.toggle_effect_close":"will close","marker.toggle_effect_stop":"will stop","marker.toggle_effect_toggle":"state will toggle","marker.toggle_skip_missing":"not found","marker.toggle_skip_ha_disabled":"disabled in HA","marker.toggle_skip_unavailable":"unavailable","marker.toggle_skip_unsupported":"toggle is unsupported","marker.toggle_skip_secure":"blocked for security","marker.toggle_none_no_binding":"This device has no binding, so there is no state to toggle. Tapping will do nothing.","marker.toggle_none_no_actionable_entity":"This device has no state that can be toggled. Tapping will do nothing.","marker.toggle_none_configured_targets_missing":"The configured targets are unavailable. The device's own entity will not be substituted for them.","marker.toggle_none_ha_disabled":"The target is disabled in Home Assistant and cannot be used on the plan.","marker.toggle_none_unavailable":"The target is currently unavailable. Tapping will do nothing.","marker.toggle_none_unsupported":"Home Assistant exposes no safe toggle operation for this entity. Tapping will do nothing.","marker.toggle_none_secure":"Toggling locks, alarms and secure gates from the plan is blocked for security.","run.automation":"automation","run.script":"script","run.scene":"scene","confirm.tap_run":'Run "{name}"?',"confirm.tap_toggle":'Toggle "{name}"?',"confirm.current_state":"Current state: {state}","confirm.expected_state":"After switching: {state}","confirm.group_current":"on {on} of {total}","confirm.group_all_on":"all are on","confirm.group_all_off":"all are off","confirm.unavailable_targets":"Unavailable: {count}","confirm.expected_by_ha":"Home Assistant will determine the state","confirm.state_on":"On","confirm.state_off":"Off","confirm.state_open":"Open","confirm.state_closed":"Closed","confirm.state_opening":"Opening","confirm.state_closing":"Closing","confirm.state_stopped":"Stopped","confirm.state_unknown":"Unknown","toast.run_started":"Started: {name}","toast.run_target_missing":"Run target not found — check the device settings","toast.run_target_required":"Pick an automation, script or scene","toast.tap_target_changed":"The action target changed. Try again.","toast.virtual_light_toggle_failed":"Could not toggle the virtual light: {err}","toast.value_badge_source_required":"Choose a value for the badge","btn.run":"Run","vac.section":"Robot vacuum: live position","vac.autocal":"Set up automatically","vac.live":"Live position on the plan","vac.trail":"Show the robot's path","vac.autocal_no_rooms":"The integration reports no room list — open “Fit manually”","vac.route_warn_unmapped":"The robot is cleaning a map that is not assigned to any floor","vac.route_warn_needs_calibration":"The map is assigned to a floor but not calibrated","vac.route_warn_ambiguous":"Two maps are indistinguishable — no floor was chosen","vac.route_warn_missing_space":"The space of this map was deleted","vac.autocal_no_match":"Room names did not match (need ≥3 in common) — open “Fit manually”","vac.autocal_done":"Done: bound via {rooms} rooms. Start a cleanup and check","vac.cal_need_pos":"The robot is not reporting coordinates — start a cleanup and pause it","vac.cal_done":"Calibration saved. Start a cleanup and check","vac.cal_cancelled":"Calibration cancelled","vac.fit":"Fit manually","vac.fit_hint":"Drag the robot map into place, stretch by the corners","vac.fit_rotate":"Rotate 90°","vac.fit_mirror":"Mirror","vac.trail_never":"Never","vac.trail_cleaning":"While cleaning","vac.trail_always":"Always","gs.bg_color":"Background around the plan","gs.bg_default":"Theme default","gs.bg_mode":"Plan background","gs.bg_mode.help":"“Follows the Sun” uses sun.sun, falling back to the browser's local clock; Static always shows the selected colour.","gs.bg_mode.help.aria":"Help: general plan background","gs.bg_static":"Static color","gs.bg_daynight":"Follows the Sun","gs.sun_group":"Sun","gs.sun_missing":"The sun.sun entity was not found — the background follows your local clock; window rays are unavailable.","gs.north":"North on the plan","gs.north.help":"The angle is measured clockwise from the plan's upward vertical; north is required for window rays, not for the “Follows the Sun” background.","gs.north.help.aria":"Help: general north direction","gs.north_ph":"not set","gs.north_clear":"Clear","gs.north_letter":"N","gs.sun_rays":"Sunlight through windows","gs.sun_ray_origin":"Sun rays","gs.sun_ray_origin.inner":"From the inner window corners","gs.sun_ray_origin.outer":"From the outer window corners","gs.about_version":"Houseplan Card v{v}","gs.about_github":"GitHub · docs & issues","gs.about_telegram":"Telegram chat","support.title":"Help & feedback","space.bg_color":"Background around the plan","space.bg_inherit":"Inherit general","space.bg_mode":"Plan background","space.bg_mode.help":"Inherit the general background or override this space with a static colour or “Follows the Sun”.","space.bg_mode.help.aria":"Help: space background","space.north":"North on the plan","space.north.help":"Overrides general north for this space; the angle is measured clockwise from the plan's upward vertical and is used by window rays.","space.north.help.aria":"Help: north for this space","space.sun_rays":"Sunlight through windows","space.sun_inherit":"General settings","space.sun_on":"On","space.sun_off":"Off","canvas.far_objects":"{n} object(s) far from the plan","canvas.show_far":"Show","canvas.home_tip":"The plan is over there — click to fit it","gs.grid_group":"Plan maintenance","gs.align_all":"Optimize plans","gs.align_title":"Optimize plans","gs.align_none":"All plans already use the current optimized data model.","gs.optimize_no_automatic_changes":"There are no automatic changes to apply. Review the items below.","gs.align_count":"{n} of {total} elements will move, by at most {cm} cm.","gs.align_where":"The largest shift is in “{s}”.","gs.align_turned":"Openings whose angle is corrected: {n}.","gs.align_preflight_failed":"Could not safely verify the geometry of the following spaces: {spaces}{more}.","gs.align_preflight_hint":"Plans were not changed. Copy the diagnostics with the button below and attach them to the bug report together with a space export.","gs.preflight_reason_prepare-exception":"Could not prepare the space geometry (exception while building the model)","gs.preflight_reason_wall-null":"The wall body did not build (the union came back empty)","gs.preflight_reason_wall-degraded-extra":"The wall body degraded with extra geometry","gs.preflight_reason_wall-failed-core":"The wall body core failed to assemble","gs.preflight_reason_wall-exception":"Wall construction threw an exception","gs.preflight_reason_floor-null":"The floor outline did not build","gs.preflight_reason_floor-exception":"Floor construction threw an exception","gs.preflight_copy":"Copy diagnostics","gs.preflight_copied":"Diagnostics copied","gs.preflight_update_hint":"The card and integration versions differ — update House Plan and retry.","gs.align_preflight_space":"Space {n}","gs.align_preflight_more":", and {n} more","gs.optimize_changes":"Model migrations: {m}; spaces updated: {c}; noisy coordinate values removed: {p}; merged real-wall fragments: {w}; merged zero-thickness wall fragments: {s}; independent walls: {i}.","gs.zero_walls_migrated":"Virtual wall spans converted: {n}.","gs.wall_segments_migrated":"Wall segments stabilised: {n}.","gs.room_drafts_migrated":"Unfinished contours converted to ordinary walls: {drafts}; wall segments: {segments}.","gs.optimize_lattice_summary":"Noisy coordinate values canonicalized: {n}; maximum movement: {cm} cm.","gs.optimize_lattice_space":"{space}: coordinate values canonicalized: {n}; off-grid values left unchanged: {far}.","gs.optimize_coincident_partitions":"Hidden independent wall sections absorbed into room walls: {n}.","gs.optimize_openings_rehosted":"Openings reattached to room walls: {n}.","gs.optimize_walls_straightened":"Walls straightened: {n}; maximum movement: {cm} cm.","gs.optimize_walls_straightened_where":"Largest wall correction: {s}.","gs.optimize_walls_straighten_skipped":"Near-axis walls left unchanged because they could not be repaired safely: {n}.","gs.optimize_glow_migration":"Legacy Glow: {spaces} spaces → no data fill + independent Glow; {rooms} rooms → inherited data fill + independent Glow.","gs.optimize_references":"References repaired: spaces — {spaces}; rooms — {rooms}; positions — {positions}; devices detached from missing spaces — {detached}.","gs.optimize_reference_more":", and {n} more","gs.optimize_orphans_removed":"Forgotten records removed: {total} — room labels: {rooms}; devices: {devices}; group markers: {groups}. They belonged to spaces deleted earlier.","gs.optimize_live_positions":"Old positions in deleted spaces belong to existing objects: {n}{names}. They will be kept.","gs.optimize_live_positions_remove":"Old positions in deleted spaces belong to existing objects: {n}{names}. They are selected for removal.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Remove old positions","gs.optimize_live_keep":"Keep old positions","gs.optimize_live_selected":"Old positions will be removed after Optimize is applied.","gs.optimize_unverified":"Could not safely verify positions: {n}. They were left unchanged.","gs.optimize_registry_limited":"Full administrator access to the Home Assistant registries is required for a safe check.","gs.optimize_vacuum_warning":"Vacuum room mappings that still need review: {n}.","gs.optimize_details":"Details","gs.optimize_details_more":"And {n} more records.","gs.optimize_detail_removed":"will be removed","gs.optimize_detail_live":"will be kept","gs.optimize_detail_unverified":"not verified","gs.optimize_detail_room_label":"room label","gs.optimize_detail_device":"device","gs.optimize_detail_group":"group marker","gs.optimize_detail_unknown":"unknown owner","gs.optimize_detail_item":"{status}: {kind} {id}; old space {space}","gs.align_warn":"Elements deliberately placed between grid nodes will move. One undo is available after the operation, only until the next plan edit.","gs.align_run":"Optimize","gs.align_done":"Plans optimized: {n} elements moved, {m} records maintained, {r} references repaired","gs.optimize_undo":"Undo last optimization","gs.optimize_undone":"The last optimization was undone","decor.furniture":"Furniture","decor.image":"Image","decor.image_title":"Custom images","decor.image_upload":"Upload image","decor.image_replace":"Replace image","decor.image_uploading":"Uploading…","decor.image_asset":"Image file","decor.image_pick_hint":"Upload an image or choose one already used in House Plan.","decor.image_place_hint":"Click on the plan to place the image.","decor.image_none":"No uploaded images yet.","decor.image_unavailable":"Image unavailable","decor.image_used":"Used in {n} objects","decor.image_upload_failed":"Could not upload the image: {err}","decor.image_error_capacity":"The custom image storage limit has been reached.","decor.image_in_use":"Remove every placed copy before deleting this image.","decor.image_delete_title":"Delete image file?","decor.image_delete_message":"Delete “{name}” from House Plan? This cannot be undone.","furn.title":"Furniture library","furn.symbol":"Symbol","furn.group_furniture":"Furniture","furn.group_appliance":"Appliances","furn.group_sanitary":"Plumbing","furn.group_other":"Other","furn.width":"Width","furn.depth":"Depth","furn.back_to_categories":"All categories","furn.pick_hint":"Choose a category, then a symbol.","furn.place_hint":"Click on the plan — the piece lands against the nearest wall. Shift places it free.","furn.cat_air_conditioner":"Air conditioners","furn.cat_armchair":"Armchairs","furn.cat_bathtub":"Bathtubs","furn.cat_bed":"Beds","furn.cat_bidet":"Bidets","furn.cat_boiler":"Water heaters","furn.cat_chair":"Chairs","furn.cat_coffee_table":"Coffee tables","furn.cat_computer":"Computer","furn.cat_cooktop":"Cooktops","furn.cat_dining_table":"Dining tables","furn.cat_dishwasher":"Dishwashers","furn.cat_dryer":"Dryers","furn.cat_fireplace":"Fireplaces","furn.cat_fridge":"Refrigerators","furn.cat_hood":"Cooker hood","furn.cat_kitchen_cabinet":"Kitchen cabinets","furn.cat_kitchen_sink":"Kitchen sinks","furn.cat_nightstand":"Cabinets","furn.cat_oven":"Oven","furn.cat_plant":"Plants","furn.cat_rug":"Rugs","furn.cat_shelving":"Shelving","furn.cat_shower":"Showers","furn.cat_sink":"Sinks","furn.cat_sofa":"Sofas","furn.cat_stairs":"Stairs","furn.cat_toilet":"Toilets","furn.cat_tv":"Televisions","furn.cat_wardrobe":"Wardrobes","furn.cat_washer":"Washing machines","furn.cat_work_table":"Desks","furn.sym_cactus":"Cactus","furn.sym_computer":"Computer","furn.sym_hood":"Cooker hood","furn.sym_oven":"Oven","furn.sym_sofa":"Two-seat sofa","furn.sym_sofa_three_seat":"Three-seat sofa","furn.sym_sofa_corner_right":"Right sectional sofa","furn.sym_armchair":"Soft armchair","furn.sym_armchair_office":"Office chair","furn.sym_coffee_table":"Rectangular coffee table","furn.sym_coffee_table_round":"Round coffee table","furn.sym_coffee_table_oval":"Oval coffee table","furn.sym_coffee_table_rounded":"Rounded coffee table","furn.sym_table_dining":"Rectangular dining table","furn.sym_table_round":"Round table","furn.sym_table_dining_oval":"Oval dining table","furn.sym_table_dining_rounded":"Rounded dining table","furn.sym_chair":"Chair","furn.sym_chair_bar":"Bar stool","furn.sym_desk":"Rectangular desk","furn.sym_desk_corner":"Corner desk","furn.sym_bed_double":"Double bed","furn.sym_bed_single":"Single bed","furn.sym_nightstand":"Bedside table","furn.sym_cabinet_tv":"TV cabinet","furn.sym_cabinet_shoe":"Shoe cabinet","furn.sym_cabinet_sink":"Sink cabinet","furn.sym_wardrobe":"Wardrobe","furn.sym_bookshelf":"Bookcase","furn.sym_wall_unit":"Wall unit","furn.sym_kitchen_floor":"Kitchen floor module","furn.sym_kitchen_floor_corner":"Kitchen floor corner module","furn.sym_kitchen_wall":"Kitchen wall module","furn.sym_kitchen_wall_corner":"Kitchen wall corner module","furn.sym_shelf_floor":"Floor shelving unit","furn.sym_shelf_wall":"Wall shelf","furn.sym_fridge":"Fridge","furn.sym_stove":"Four-burner cooktop","furn.sym_cooktop_two":"Two-burner cooktop","furn.sym_dishwasher":"Dishwasher","furn.sym_washer":"Washing machine","furn.sym_dryer":"Tumble dryer","furn.sym_tv":"TV on stand","furn.sym_tv_wall":"Wall-mounted TV","furn.sym_ac":"Air conditioner","furn.sym_water_heater":"Water heater","furn.sym_toilet":"Floor-standing toilet","furn.sym_toilet_built_in":"Built-in toilet","furn.sym_bathtub":"Rectangular bathtub","furn.sym_bathtub_corner":"Corner bathtub","furn.sym_shower":"Shower","furn.sym_sink":"Washbasin","furn.sym_kitchen_sink":"Single kitchen sink","furn.sym_kitchen_sink_double":"Double kitchen sink","furn.sym_bidet":"Floor-standing bidet","furn.sym_bidet_built_in":"Built-in bidet","furn.sym_stairs":"Stairs","furn.sym_fireplace":"Fireplace","furn.sym_plant":"Plant","furn.sym_rug":"Rug","common.yes":"Yes","common.no":"No","vac.diag_source":"Source","vac.diag_platform":"Integration","vac.diag_status":"Status","vac.diag_position":"Position","vac.diag_rooms":"Rooms","vac.diag_rooms_value":"{total} · {matched} names match · {readiness}","vac.autocal_ready":"auto-calibration available","vac.autocal_not_ready":"need 3 matching names","vac.diag_path":"Integration path","vac.diag_map":"Map ID","vac.source_none":"not selected","vac.source_status_ok":"Ready","vac.source_status_missing":"Missing","vac.source_status_disabled":"Disabled in Home Assistant","vac.source_status_unavailable":"Unavailable","vac.source_status_unverified":"Cannot verify with current permissions","vac.source_status_unsupported":"No position data","vac.source_status_none":"No source","vac.source_banner_missing":"The saved source no longer exists. It was not replaced automatically; choose another source or restore it in Home Assistant.","vac.source_banner_disabled":"The saved source is disabled in Home Assistant. Enable it there or choose another source.","vac.source_banner_unverified":"Current Home Assistant permissions cannot verify this saved source. It remains pinned and will not be replaced automatically.","vac.choose_source":"Choose source","vac.source_auto":"Automatic","vac.source_auto_hint":"Use a compatible entity from this device","vac.all_cameras":"All cameras","vac.all_cameras_warn":"A camera may not provide robot data. Choose one only if it is your vacuum map.","vac.all_cameras_empty":"No other camera entities found.","vac.platform_unknown":"unknown integration","vac.cap_position":"position","vac.cap_rooms_short":"rooms","vac.cap_path":"path","vac.cap_map":"map ID","vac.cap_none":"no robot data detected","vac.xcme_hint":"Enable these Xiaomi Cloud Map Extractor attributes:","vac.documentation":"Documentation","vac.residual_title":"Check automatic calibration","vac.residual_message":"The matched rooms disagree by up to {error}. Apply this approximate calibration, refine it manually, or cancel without changing the saved setup.","vac.apply_proposal":"Apply","gs.backup_group":"Backup and transfer","backup.export_open":"Export","backup.import_open":"Import","backup.export_title":"Export House Plan","backup.import_title":"Import House Plan","backup.export_hint":"Choose whether the backup should contain the whole House Plan configuration or only the current space.","backup.full":"Full backup","backup.current_space":"Current space","backup.current_space_title":"Current space: {title}","backup.no_current_space":"No current space","backup.plan_only":"Plan only","backup.plan_only_hint":"Keep rooms, walls, openings, decor and room-label positions without devices or Home Assistant bindings.","backup.plan_only_preview":"This file contains the plan only","backup.privacy_warning":"The archive keeps names, Home Assistant identifiers and exact coordinates. Internal plans and attachments are referenced, not embedded; runtime states and vacuum trails are not included.","backup.download":"Download JSON","backup.export_done":"Backup downloaded","backup.reading":"Checking the backup…","backup.revalidated":"The plan changed after this preview. The summary was refreshed; review it and confirm again.","backup.error.support_invalid_message":"Check the support message and try again.","backup.error.support_package_too_large":"The anonymized support package exceeds the 8 MiB limit.","backup.error.support_preview_expired":"The support attachment preview expired or is no longer available.","backup.error.support_rate_limited":"Too many support reports or previews were requested. Try again later.","backup.error.support_rejected":"The report did not pass support service validation.","backup.error.support_unavailable":"The private support service is temporarily unavailable.","backup.error.unauthorized":"You do not have permission to export or import this plan.","backup.error.not_ready":"House Plan is not ready yet. Try again in a moment.","backup.error.too_large":"The backup exceeds the 8 MiB limit.","backup.error.invalid_json":"The selected file is not valid JSON.","backup.error.invalid_format":"The selected file is not a House Plan backup.","backup.error.invalid_image":"The image is damaged or does not match its format.","backup.error.unsupported_export_version":"This backup format is not supported by the installed version.","backup.error.unsupported_image":"Use a supported PNG, JPEG, WebP or SVG image.","backup.error.future_model":"The backup was created by a newer House Plan data model.","backup.error.invalid_config":"The backup contains an invalid House Plan configuration.","backup.error.wall_model_migration_blocked":"The backup wall model could not be upgraded safely. Optimize the source plan first, then export it again.","backup.error.invalid_layout":"The backup contains invalid object positions.","backup.error.invalid_content":"The backup contains invalid or inconsistent content references.","backup.error.space_not_found":"The selected space no longer exists.","backup.error.capacity_exceeded":"Adding this backup would exceed the plan limits.","backup.error.preview_expired":"The preview expired. Select the backup file again.","backup.error.preview_owner_mismatch":"This preview belongs to another Home Assistant user.","backup.error.conflict":"The plan changed after the preview. Review the refreshed summary.","backup.error.content_confirmation_required":"Confirm that unavailable local content may be detached.","backup.error.commit_failed":"The backup could not be applied safely. The previous plan was restored or is pending recovery.","backup.error.missing_plan":"A referenced plan file disappeared after the preview. Review the backup again.","backup.error.missing_content":"A referenced local attachment disappeared after the preview. Review the backup again.","backup.error.marker_control_missing":"A linked plan light is missing from the backup.","backup.error.marker_control_not_light":"A linked plan target is no longer marked as a light source.","backup.error.marker_control_self":"A light source cannot control itself.","backup.error.marker_control_cycle":"The backup contains a circular chain of light controls.","backup.error.duplicate_marker_control":"The backup contains a duplicate plan-light link.","backup.error.no_backup":"There is no import or optimization snapshot to restore.","backup.error.in_use":"The item is still in use","backup.error.invalid_data":"The request carries invalid data","backup.error.invalid_light_entity":"The leading light must be a light.* or switch.* entity","backup.error.invalid_marker_control":"Invalid marker control reference","backup.error.invalid_name":"The name is invalid","backup.error.invalid_partition_opening_host":"The opening must keep its partition host","backup.error.invalid_partition_opening_jamb_margin":"The opening leaves no physical jamb at the wall end","backup.error.invalid_passage_fields":"An open passage cannot carry door-only settings","backup.error.invalid_space_id":"Unknown space","backup.error.invalid_toggle_entity":"The toggle entity must be light.* or switch.*","backup.error.invalid_value_badge":"Invalid value badge settings","backup.error.invalid_value_badge_attribute":"Invalid value badge attribute","backup.error.invalid_value_badge_position":"Invalid value badge position","backup.error.invalid_value_badge_source":"Invalid value badge source","backup.error.invalid_vacuum_map_route":"Check how the robot's maps are assigned to spaces.","backup.error.invalid_value_source":"Invalid value source","backup.error.invalid_value_source_attribute":"Invalid value source attribute","backup.error.io_error":"A file operation failed on the server","backup.error.not_toggleable":"This device cannot be toggled","backup.error.nothing_to_repair":"Nothing to repair","backup.error.space_in_use":"The space is still referenced","backup.error.value_badge_source_required":"The value badge needs a source","backup.error.wall_model_client_outdated":"The plan was updated elsewhere — reload the page","backup.same_source":"Created on this Home Assistant instance","backup.foreign_source":"Created on another Home Assistant instance","backup.created":"Created: {value}","backup.versions":"Card {card}; integration {integration}; data model {model}","backup.count_spaces":"Spaces: {n}","backup.count_rooms":"Rooms: {n}","backup.count_walls":"Walls: {n}","backup.count_openings":"Openings: {n}","backup.count_decor":"Decor objects: {n}","backup.count_markers":"Devices: {n}","backup.count_layout":"Positions: {n}","backup.bindings":"Bindings — devices: {device}, entities: {entity}, virtual: {virtual}; positions without a space: {legacy}","backup.binding_status":"Target status — active: {active}, disabled: {disabled}, missing: {missing}","backup.missing_areas":"Areas missing on the target: {areas}","backup.dropped_marker_links":"Plan-light links outside this transferred space were omitted: {n}.","backup.room_drafts_migrated":"Legacy unfinished contours converted to ordinary walls: {drafts}; wall segments: {segments}.","backup.repaired_target_refs":"Existing references restored by this space import: {n}.","backup.preserved_unresolved_refs":"References that could not be restored unambiguously were preserved: {n}.","backup.preserved_unresolved_hint":"No data was guessed or deleted. After the import, run Optimize plans to inspect the remaining references.","backup.import_details":"Import reference details","backup.import_detail.incoming_remapped":"References updated inside the imported copy: {n}","backup.import_detail.target_repaired":"Existing references restored: {n}","backup.import_detail.preserved_unresolved":"Unresolved references preserved: {n}","backup.import_detail.collisions":"Destination conflicts preserved safely: {n}","backup.import_detail.dropped_links":"Incoming links omitted by transfer rules: {n}","backup.import_detail.bounded_lineages":"Overly nested identifiers left bounded: {n}","backup.replace_warning":"This replaces the current configuration and layout. Uploaded files are never deleted. One undo remains available until the next plan edit.","backup.foreign_bookkeeping":"Instance-specific known/new-device bookkeeping will not be imported.","backup.final_name":"New space name","backup.target_settings":"The target instance's global settings remain unchanged.","backup.duplicates":"Bindings already present: {n}","backup.skip":"Skip duplicate devices","backup.virtual_copy":"Add safe static virtual copies","backup.content":"Referenced content","backup.decor_images_summary":"Custom images: {objects} objects, {assets} files; missing files: {missing}.","backup.content_available":"available locally","backup.content_external":"external link","backup.content_detach_required":"will be detached","backup.confirm_detach":"I understand that unavailable internal plans and attachments will be detached from the imported configuration.","backup.confirm_missing_images":"I understand that missing custom images will remain as repair placeholders and other unavailable local files will be detached.","backup.replace":"Replace","backup.add":"Add space","backup.space_done":"Space imported: {rooms} rooms, {markers} devices, {refs} existing references restored","backup.full_done":"Backup restored: {spaces} spaces, {rooms} rooms, {markers} devices","backup.undo_import":"Undo last full import","backup.import_undone":"Full import undone","backdrop.large_title":"Large image","backdrop.large_body":"This image is {w}×{h} ({fileMb} MB file) and needs about {decodedMb} MB of memory to display. On tablets this can crash the page.","backdrop.unknown_body":"The image dimensions could not be read — the file may be damaged. Continuing may crash the page on tablets.","backdrop.reduced_dimensions":"Reduced copy: {w}×{h} px.","backdrop.use_downscaled":"Upload a reduced copy","backdrop.reducing":"Reducing…","backdrop.keep_original":"Keep the original","backdrop.too_large_title":"Image is too large","backdrop.too_large_body":"This image exceeds what browsers can display ({w}×{h}, limit {limit} px per side). Please reduce it in a desktop editor and upload again.","backdrop.downscale_failed":"Could not create the reduced copy. The original plan was not changed.","gs.card_display":"Display","gs.card_zigbee":"Zigbee links","gs.card_fills":"Room fill colors","gs.card_plan":"Plan","gs.card_data":"Data","gs.card_fills.help.aria":"About room fill colors","gs.backup_group.help.aria":"About backup and transfer","gs.grid_group.help.aria":"About plan maintenance","gs.backup_group.help":"Download a portable JSON backup or preview and import a backup made by House Plan.","gs.grid_group.help":"Updates data models, aligns plan elements to the grid and merges redundant wall fragments. An exact report is shown before anything is stored.","gs.card_fills.help":"Fill colors apply to every space; each color has its own opacity. Which fill mode a space uses is set in that space's dialog.","space.card_basics":"Basics","space.card_sun":"Sun & light","marker.card_basics":"Basics","marker.card_tap":"Tap action","marker.card_light":"Light and glow","marker.card_appearance":"Appearance","marker.card_details":"Details"};const cp=new WeakSet,hp=new WeakSet;function dp(e,t,i){const n=i?t.state(i):"ready";return i&&"pending"===n?(hp.has(e)||(e.inert=!0,e.setAttribute("aria-busy","true"),hp.add(e)),t.ensure(i).then(()=>{e.isConnected&&e.requestUpdate()}),cp.has(e)?"warm":"cold"):(hp.delete(e)&&(e.inert=!1,e.removeAttribute("aria-busy")),i&&(e.setAttribute("lang","fallback"===n?"en":i),cp.add(e)),"ready")}function up(){return j``}const pp=[{code:"en",nativeLabel:"English",dictionary:lp},{code:"ru",nativeLabel:"Русский",dictionary:{"editor.context_actions":"Действия: {object}","editor.tool_options":"Параметры инструмента: {tool}","editor.palette":"Палитра: {tool}","editor.open_group":"Группа инструментов: {group}","editor.group_active":"{group} — активно: {item}","editor.disabled_action":"{action} недоступно: {reason}","editor.loading":"Загрузка…","editor.loading_aria":"Редактор плана загружается","editor.load_failed":"Не удалось загрузить редактор.","editor.refresh_advice":"Обновите страницу и повторите попытку.","editor.retry_advice":"Проверьте сеть и нажмите ещё раз.","version_mismatch.title":"Версии House Plan не совпадают","version_mismatch.body":"Если Home Assistant ещё перезапускается, дождитесь завершения, затем перезагрузите эту страницу.","version_mismatch.frontend":"Карточка","version_mismatch.backend":"Интеграция","version_mismatch.reload":"Перезагрузить страницу","color_picker.title":"Выбор цвета","color_picker.hue":"Оттенок","color_picker.saturation":"Насыщенность","color_picker.value":"Яркость","color_picker.hex":"Цвет HEX","color_picker.invalid_hex":"Введите цвет HEX из 3 или 6 цифр","color_picker.confirm":"ОК","btn.properties":"Свойства","btn.keep_as_walls":"Оставить стенами","btn.delete_room_keep_walls":"Удалить комнату, оставить стены","btn.delete_room_with_walls":"Удалить комнату и стены","title.markup_select":"Выбор и редактирование стен и колонн","title.markup_column":"Колонна: кликните точку сетки для квадратной колонны","markup.partition":"Перегородка","markup.column":"Колонна","markup.hint_column":"кликните точку сетки, чтобы поставить квадратную колонну","history.wall_segment":"Добавление отрезка стены","history.column_add":"Добавление колонны","history.physical_edit":"Изменение физического объекта","history.physical_delete":"Удаление физического объекта","history.physical_move":"Перемещение физического объекта","history.wall_face_batch":"Создание комнат из стен","toast.column_duplicate":"Колонна с тем же центром и внешним размером уже существует","physical.partition_properties":"Свойства перегородки","physical.column_properties":"Свойства колонны","physical.shape":"Форма","physical.square":"Квадрат","physical.circle":"Круг","physical.diameter":"Диаметр","physical.side":"Сторона","physical.rotation":"Угол поворота","physical.length":"Длина","physical.allowed_range":"Допустимо: {min}–{max} {unit}","physical.column_size_title":"Внешняя сторона квадратной колонны, создаваемой кликом (1–150 см).","card.title":"План дома","count.devices":"{n} устр.","empty.no_spaces":"Пространств пока нет.","nav.spaces":"Пространства House Plan","empty.add_first":"Добавьте первое пространство и загрузите план этажа.","empty.read_only":"Пространства не настроены. Попросите администратора добавить первое.","empty.install":"Установите интеграцию House Plan и добавьте запись в «Устройства и службы».","btn.add_space":"Добавить пространство","btn.cancel":"Отмена","btn.save":"Сохранить","btn.close":"Закрыть","btn.delete":"Удалить","btn.copy":"Копировать","btn.edit":"Редактировать","btn.open_in_ha":"Открыть в HA","btn.reset":"Сброс","btn.attach":"Прикрепить…","btn.upload":"Загрузить…","btn.replace":"Заменить…","title.zoom_in":"Приблизить","title.zoom_out":"Отдалить","title.zoom_fit":"Вписать всё","title.configure_space":"Настроить пространство","title.add_space":"Добавить пространство","title.markup_add":"Стены: рисуйте непрерывную цепочку; каждый принятый отрезок сохраняется отдельно. Shift фиксирует 45°","title.markup_merge":"Объединить: клик по одной комнате, затем по соседней с общей стеной","title.markup_split":"Разделить комнату: клик по комнате, затем две точки на её стенах","title.markup_delroom":"Удалить комнату: кликните внутри комнаты и подтвердите удаление","markup.add":"Стены","markup.merge":"Объединить","markup.split":"Разделить","markup.resize":"Размер","title.markup_resize":"Изменение размера комнат: тяните доступную ручку горизонтальной или вертикальной стены","markup.hint_resize":"тяните доступную ручку стены · стена упирается в первую небезопасную позицию · Esc — отмена · Ctrl+Z — отмена шага","resize.disabled.diagonal":"Стена расположена под углом: Resize поддерживает только горизонтальные и вертикальные стены","resize.disabled.side-angle":"Примыкающая стена расположена под углом: для Resize обе примыкающие стены должны образовывать прямой угол","resize.disabled.duplicate-physical-wall":"Стену перекрывает отдельная перегородка или колонна; удалите или переместите её перед изменением размера","resize.disabled.partial-shared":"Соседняя комната использует только часть этой стены, поэтому её нельзя безопасно двигать как одну общую стену","resize.disabled.unequal-shared":"У соседней комнаты другие конечные точки или длина стены, поэтому стены нельзя безопасно двигать вместе","resize.disabled.multiple-rooms":"Перемещение затронуло бы больше двух комнат","resize.disabled.thickness-conflict":"Толщину стены нельзя безопасно сохранить","resize.disabled.opening-conflict":"Проём на этой стене нельзя безопасно переместить","resize.disabled.invalid-geometry":"Эту стену нельзя переместить без изменения структуры плана","resize.limit_stopped":"Стена остановлена: дальше нарушается ограничение стыков","resize.commit_failed":"Изменение размера отменено: итоговый план не прошёл проверку геометрии","resize.preview_failed":"Стена остановлена в последней безопасной позиции: геометрию плана нельзя сохранить без потерь","markup.opening":"Проём","markup.delete_room":"Удалить комнату","history.undo":"Отменить","history.redo":"Повторить","history.undo_named":"Отменить: {name} (Ctrl+Z)","history.redo_named":"Повторить: {name} (Ctrl+Shift+Z / Ctrl+Y)","history.undo_empty":"Нет операций для отмены","history.redo_empty":"Нет операций для повтора","history.undone":"Отменено: {name}","history.redone":"Повторено: {name}","history.add_room":"Создание комнаты","history.split_room":"Разделение комнаты","history.merge_rooms":"Объединение комнат","history.resize_room":"Изменение размера комнаты","history.wall_thickness":"Изменение толщины стены","history.add_opening":"Добавление дверного или оконного проёма","history.edit_opening":"Изменение проёма","history.move_opening":"Перемещение проёма","history.delete_opening":"Удаление проёма","history.delete_room_keep_walls":"Удаление комнаты с сохранением стен","history.delete_room_with_walls":"Удаление комнаты и её стен","history.decor_add":"Добавление объекта декора","history.decor_edit":"Изменение объекта декора","history.decor_move":"Перемещение объекта декора","history.decor_transform":"Трансформация объекта декора","history.decor_delete":"Удаление объекта декора","history.backdrop_transform":"Трансформация подложки плана","history.device_move":"Перемещение: {name}","history.device_stale":"История позиций больше неприменима и была очищена","opening.new":"Новый проём","opening.edit":"Проём","opening.door":"Дверь","opening.window":"Окно","opening.gate":"Ворота","opening.passage":"Открытый проём","opening.passage_binding_warning":"При сохранении датчик открытия и замок будут удалены.","opening.invalid_passage_fields":"У открытого проёма на плане «{room}» есть недопустимые параметры: {fields}.","opening.type_label":"Тип","opening.length_label":"Длина, см","opening.contact_label":"Датчик открытия","opening.lock_label":"Замок","opening.none":"— нет —","opening.search_ph":"Поиск: имя или entity_id…","opening.invert":"Инвертировать открыто/закрыто","opening.flip_h":"Петли с другой стороны","opening.flip_v":"Открывается в другую сторону","opening.open":"Открыто","opening.closed":"Закрыто","opening.locked":"Заперто","opening.unlocked":"Не заперто","opening.state_unknown":"недоступно","opening.no_entities":"Датчики не привязаны — статичный символ на плане.","toast.opening_no_wall":"Кликните рядом со стеной комнаты или независимой стеной","opening.host_partition":"Независимая стена","opening.partition_orphan":"Независимая стена этого проёма больше не существует","opening.partition_jamb_margin":"Оставьте от края проёма до торца стены минимум {distance}","opening.rebind_partition":"Привязать к другой независимой стене","confirm.delete_partition_openings_title":"Удалить стену и проёмы?","confirm.delete_partition_openings_body":"В стене есть проёмы: {count}. Они будут удалены вместе со стеной.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.hint_points":"точек: {n} · Shift — шаг 45° · Esc — завершить цепочку · Ctrl+Z — убрать точку · при замыкании будет предложена комната","markup.hint_start":"кликните точку сетки, чтобы начать цепочку стен","tip.lqi":"средний сигнал zigbee:","tip.area":"площадь: {value}","info.device_header":"Устройство на плане","info.model":"Модель","info.state":"Состояние","info.link":"Ссылка","info.manuals":"Инструкции","info.none":"Нет дополнительной информации","marker.new_device":"Новое устройство","marker.name_label":"Название","marker.name_ph":"Название","marker.binding_label":"Привязка к устройству HA","marker.binding_disabled":"деактивировано в Home Assistant","marker.virtual_option":"Виртуальное устройство (без привязки)","marker.search_ph":"Поиск устройства / группы…","marker.nothing_found":"ничего не найдено","marker.room_label":"Комната","marker.room_choose":"— выберите комнату —","marker.room_auto":"— по зоне устройства (авто) —","marker.icon_label":"Иконка","marker.icon_ph":"mdi:… (пусто = авто)","marker.display_label":"Отображение","display.badge":"Значок + состояние","display.icon_ripple":"Значок + состояние и активность","display.static_icon":"Всегда статичный значок","display.value_static_icon":"Значение + статичный значок","marker.display_hint_badge":"Значок и динамическая подложка показывают состояние устройства без обычной пульсации активности. Красная тревога сохраняется.","marker.display_hint_icon_ripple":"Значок, динамическая подложка и пульсация: короткая — для событий, постоянная — для работы, движения или присутствия. Красная тревога имеет отдельный приоритет.","marker.display_hint_value":"Значок заменяется выбранным или автоматически найденным значением Home Assistant; подложка продолжает показывать состояние. Красная тревога сохраняется.","marker.display_hint_static_icon":"Подложка в цветах темы и значок всегда остаются одинаковыми. Состояния, активность, недоступность и тревоги не меняют отображение.","marker.display_hint_value_static_icon":"Маркер показывает выбранное значение, а подложка остаётся в цветах темы. Состояния, активность, недоступность и тревоги не меняют цвет маркера.","marker.static_alarm_warning":"Это устройство может сообщать о тревогах. Статичный режим скрывает визуальную тревогу маркера.","marker.preview.title":"Предпросмотр отображения","marker.preview.actual":"Сейчас","marker.preview.example":"Пример","marker.preview.integration":"Интеграция","marker.preview.source":"Источник отображения","marker.preview.current_state":"Текущее состояние","marker.preview.result":"На плане","marker.preview.details":"Подробнее об источниках","marker.preview.select_source":"Выберите устройство или сущность Home Assistant, чтобы увидеть фактическое отображение.","marker.preview.unknown_provider":"Интеграция неизвестна","marker.preview.virtual_provider":"House Plan · виртуальное устройство","marker.preview.no_source":"Нет активного источника","marker.preview.no_state":"Нет текущего состояния","marker.preview.mixed_states":"Несколько разных состояний","marker.preview.multiple_sources":"Источников: {n}","marker.preview.more_sources":"ещё {n}","marker.preview.scaled":"Предпросмотр уменьшен до {n}%, чтобы поместиться. Сохранённый размер не изменится.","marker.preview.demo_short":"Показать краткую активность","marker.preview.demo_continuous":"Показать постоянную активность","marker.preview.stop_continuous":"Остановить постоянную активность","marker.preview.demo_short_notice":"Пример краткой активности; фактическое состояние устройства не меняется.","marker.preview.demo_continuous_notice":"Пример постоянной активности; фактическое состояние устройства не меняется.","marker.preview.demo_already_visible":"Текущее состояние уже показывает реальную активность или тревогу.","marker.preview.reduced_motion":"В системе включено уменьшение движения, поэтому обычная активность показана точкой.","marker.preview.reason.neutral":"Нейтральная тёмная подложка","marker.preview.reason.working":"Жёлтая подложка: устройство сейчас работает","marker.preview.reason.working_activity":"Жёлтая подложка и эффект активности: устройство сейчас работает","marker.preview.reason.open":"Оранжевая подложка: физически открыто или разблокировано","marker.preview.reason.cover_icon_state":"Нейтральная подложка; состояние и значок определяет сущность шторы или заслонки","marker.preview.reason.presence":"Эффект активности, пока обнаружено присутствие","marker.preview.reason.event":"Короткий эффект активности после события","marker.preview.reason.transition":"Эффект активности во время движения или смены состояния","marker.preview.reason.media_neutral":"Медиаустройство остаётся на нейтральной тёмной подложке, пока доступно","marker.preview.reason.unavailable":"Приглушённая нейтральная подложка: отключено или недоступно","marker.preview.reason.alarm":"Красная тревожная подложка; тревога отображается всегда","marker.preview.reason.live_states_disabled":"Оформление по живым состояниям отключено в настройках карточки","marker.preview.reason.value_no_state":"Нет подходящего значения состояния — вместо него показан значок","marker.preview.reason.value_ambiguous_sources":"Подходит несколько источников значения — вместо него показан значок","marker.preview.reason.value_non_scalar":"Источник вернул не простое значение — вместо него показан значок","marker.preview.reason.value_virtual":"У виртуального устройства нет значения HA — вместо него показан значок","marker.preview.reason.vacuum_live_plan_only":"Живая позиция и след пылесоса доступны только на полном плане","marker.preview.reason.hidden_design_preview":"Устройство скрыто на плане, но его оформление видно в предпросмотре","marker.preview.reason.composite_power_source":"Состояние берётся из сущности питания устройства; вспомогательные переключатели не учитываются","marker.preview.reason.activity_display_disabled":"Выбранный режим отображения не показывает обычные эффекты активности","marker.preview.reason.ha_disabled":"Привязка отключена в Home Assistant, поэтому устройство будет скрыто на плане","marker.preview.reason.orphaned":"Сохранённая привязка Home Assistant больше не найдена","marker.preview.reason.static_icon":"Статичный режим: состояние устройства не меняет значок","marker.preview.reason.value_static_icon":"Статичный режим со значением: состояние устройства не меняет цвет маркера","marker.activity_color":"Цвет пульсации активности","marker.ripple_size":"Размер пульсации активности","marker.activity_alarm_note":"Цвет и размер относятся только к обычной активности и не влияют на красную тревогу.","marker.pulse_a11y_alarm":"Тревога","marker.pulse_a11y_event":"Недавнее событие","marker.pulse_a11y_presence":"Обнаружено присутствие","marker.pulse_a11y_transition":"Изменение состояния","marker.pulse_a11y_running":"Работает","marker.state_a11y_neutral":"Обычное состояние","marker.state_a11y_working":"Работает","marker.state_a11y_open":"Открыто","marker.state_a11y_locked":"Заблокировано","marker.state_a11y_unlocked":"Разблокировано","marker.state_a11y_alarm":"Тревога","marker.state_a11y_unavailable":"Недоступно","marker.lqi_a11y_low":"LQI {value}, слабый сигнал","marker.lqi_a11y_mid":"LQI {value}, средний сигнал","marker.lqi_a11y_high":"LQI {value}, сильный сигнал","marker.size_label":"Размер и поворот иконки","marker.angle_label":"Поворот","marker.model_label":"Модель","marker.model_ph":"напр. Aqara T&H","marker.link_label":"Ссылка","marker.desc_label":"Описание","marker.desc_ph":"Заметки, характеристики…","marker.manuals_label":"Инструкции (PDF и т.п.)","marker.sub_device":"устройство","marker.sub_z2m_group":" · Z2M-группа","marker.sub_group":"группа","marker.sub_helper":"хелпер","space.new":"Новое пространство","space.copy_title":"Копирование пространства","space.copy_name":"Название нового пространства","space.copy_fallback":"Пространство","space.copy_create":"Создать копию","space.copy_optimize_title":"Оптимизировать перед копированием?","space.copy_optimize_body":"Перед созданием «{name}» House Plan должен оптимизировать весь план, включая другие пространства. Продолжить?","space.copy_optimize_confirm":"Оптимизировать и скопировать","space.copy_error_changed":"План изменился, пока было открыто подтверждение. Проверьте его и повторите попытку.","space.copy_error_source_missing":"Исходного пространства больше нет. Снова откройте его настройки и повторите попытку.","space.copy_error_source_invalid":"House Plan не смог проверить все стены этого пространства. Исправьте исходное пространство и повторите попытку.","space.copy_error_spaces_limit":"В House Plan уже создано максимальное число пространств.","space.copy_error_partitions_limit":"В этом пространстве слишком много стен для копирования.","space.copy_error_openings_limit":"В этом пространстве слишком много проёмов для копирования.","space.copy_error_decor_limit":"В этом пространстве слишком много элементов подложки для копирования.","space.copy_error_columns_limit":"В этом пространстве слишком много колонн для копирования.","space.copy_error_opening_host":"Один из проёмов больше не привязан к стене. Исправьте или удалите его перед копированием.","space.copy_error_geometry":"Копия создаст небезопасную геометрию стен. Исправьте исходное пространство и повторите попытку.","space.copy_error_optimize_geometry":"Копирование остановлено: оптимизация всего плана небезопасна для одного из пространств.","space.header":"Пространство","space.title_label":"Название пространства","space.title_ph":"Например: Гараж","space.plan_label":"Подложка","space.no_plan":"нет подложки","space.plan_alt":"план","room.new":"Новая комната","room.name_label":"Отображаемое имя","room.name_ph":"Например: Терраса","room.area_label":"Зона Home Assistant","room.no_area_option":"— без зоны —","room.default_name":"Комната","device.unnamed":"без имени","device.light_group":"группа света","device.fallback":"устройство","device.virtual":"виртуальное устройство","confirm.delete_room_title":"Удалить комнату «{name}»?","confirm.delete_room_body":"Выберите, нужно ли оставить физические стены, принадлежащие только этой комнате. Общие с другой комнатой стены сохраняются всегда.","confirm.remove_marker_title":"Удалить устройство с плана?","confirm.remove_marker_body":"Устройство исчезнет полностью и перестанет участвовать в данных плана. Позже его можно будет добавить заново.","confirm.erase_decor":"Стереть объект «{kind}»? Действие можно отменить из истории редактора.","confirm.delete_space_title":"Удалить пространство?","confirm.delete_space_body":"Пространство, все его комнаты и вся разметка плана будут удалены.","confirm.delete_space_vac_routes":"Также будет снято сопоставление карт роботов: {count}.","space.delete_blocked":"Это пространство всё ещё используется устройствами: {n}. Сначала перенесите их в другое пространство или удалите.","toast.pos_save_failed":"Не удалось сохранить позицию: {err}","toast.no_entity":"У устройства нет подходящей сущности","toast.ha_disabled_action":"Деактивированный объект Home Assistant нельзя использовать на плане.","toast.ha_disabled_show_device":"Деактивированное в Home Assistant устройство нельзя показать на плане. Сначала активируйте его в Home Assistant.","toast.ha_disabled_show_entity":"Деактивированную в Home Assistant сущность нельзя показать на плане. Сначала активируйте её в Home Assistant.","toast.ha_disabled_add":"Деактивированный объект Home Assistant нельзя добавить на план. Сначала активируйте его в Home Assistant.","toast.ha_binding_unverified":"Статус объекта не удалось подтвердить по реестру Home Assistant. Отображение и действия временно недоступны.","toast.markup_needs_server":"Разметка доступна после переноса конфига на сервер","toast.space_order_changed":"Порядок изменён. Если где-то этаж карточки задан номером, проверьте такие панели.","toast.conflict":"Конфиг изменён в другом окне — данные обновлены, повторите последнее действие","toast.cfg_save_failed":"Не удалось сохранить конфиг: {err}","toast.room_overlap":"Контур накладывается на комнату «{name}» — комнаты не должны накладываться","toast.contour_cannot_close":"Контур нельзя замкнуть: он вырожден или пересекает сам себя","toast.merge_not_adjacent":"Объединять можно только комнаты с общей стеной","toast.rooms_merged":"Комнаты объединены в «{name}»","toast.split_pick_wall":"Начните разрез на стене комнаты","toast.split_bad_cut":"Разрез — от стены до стены внутри комнаты, без пересечения стен и самого себя","merge.header":"Объединение комнат","merge.hint":"У объединённой комнаты одно имя и одна зона. Вторая зона освобождается — её устройства уйдут с плана, пока их не заберёт другая комната.","merge.keep":"Оставить","merge.no_area":"без зоны","toast.room_saved":"Комната сохранена ({n}). Устройств добавлено: {added}. Обведите следующую или выйдите из разметки.","toast.room_saved_no_area":"Комната сохранена ({n}, без зоны). Обведите следующую или выйдите из разметки.","toast.marker_needs_server":"Редактирование устройств доступно после переноса конфига на сервер","toast.virtual_name_required":"Укажите имя виртуального устройства","toast.marker_saved":"Устройство сохранено","toast.marker_removed":"Устройство удалено с плана","toast.integration_missing":"Интеграция House Plan не установлена — управление недоступно","toast.plan_formats":"Поддерживаются SVG, PNG, JPG, WebP","toast.plan_required":"Загрузите подложку — план этажа обязателен","toast.space_added_onboard":"Пространство добавлено. Обведите комнаты: кликайте по точкам сетки и замкните контур.","toast.space_added":"Пространство добавлено","toast.space_copied":"Пространство «{name}» создано","toast.space_saved":"Пространство сохранено","toast.space_deleted":"Пространство удалено","toast.delete_failed":"Ошибка удаления: {err}","toast.error":"Ошибка: {err}","toast.toggle_target_unavailable":"Цель «{name}» недоступна — действие не выполнено","toast.toggle_targets_unavailable":"Цели недоступны: {names}. Действие не выполнено","toast.file_failed":"Файл «{name}» не загружен: {err}","toast.files_attached":"Прикреплено файлов: {n}","err.unknown":"неизвестная ошибка","err.code":"код {code}","err.too_large":"файл больше {mb} МБ","err.bad_ext":"недопустимый тип (нужен PDF/изображение)","err.unauthorized":"нужны права администратора","editor.title":"Заголовок","editor.default_floor":"Стартовое пространство","editor.default_floor_missing":"Стартовое пространство «{id}» больше не существует. Выберите другое.","editor.floor":"Закреплённое пространство","editor.floor_none":"— не закреплять —","editor.floor_index":"YAML-индекс {index} (сохранён)","fixed_floor.loading":"Загружаем закреплённое пространство…","fixed_floor.invalid_title":"Закреплённое пространство недоступно","fixed_floor.invalid_body":"Проверьте floor в конфигурации карточки. Настроенное значение: {value}","editor.icon_size":"Размер иконок, % ширины плана","editor.show_temperature":"Показывать температуру","editor.live_states":"Живые состояния (вкл/выкл, открыто…)","editor.light_pools":"Световые пулы и тени от стен","editor.show_signal":"Показывать сигнал zigbee (LQI)","editor.language":"Язык интерфейса","editor.lang_auto":"Авто (профиль HA)","title.icon_rules":"Правила иконок: какая MDI-иконка достаётся устройству по имени","rules.title":"Правила иконок","rules.hint":"Правила проверяются сверху вниз по строке «имя устройства + модель» (regex без учёта регистра); срабатывает первое совпадение. Если ничего не подошло — решает device class сущности, затем — иконка-заглушка.","rules.pattern_ph":"regex, напр. розетк|plug","rules.icon_ph":"mdi:power-socket-de","rules.add":"Добавить правило","rules.reset":"Сбросить к умолчаниям","rules.test_ph":"Проверьте имя устройства…","rules.invalid":"некорректный regex","rules.saved":"Правила иконок сохранены","btn.up":"Вверх","btn.down":"Вниз","tap.info":"Карточка устройства","tap.more_info":"Диалог HA (more-info)","tap.toggle":"Переключить состояние","marker.tap_label":"Действие по нажатию для этого устройства","tap.toggle_note":"Под селектором показано, какое состояние изменится. Защищённые устройства не переключаются с плана.","import.title":"Создать пространства из этажей HA","import.hint":"Home Assistant уже знает эти этажи. Отметьте, какие превратить в пространства плана — далее для каждого попросим картинку плана. Комнаты затем обводятся вручную по плану.","import.start":"Создать: {n}","import.manual":"Начать с нуля","import.progress":"Этаж {i} из {n}","import.done":"Пространства созданы. Обведите комнаты: кликайте по точкам сетки и замкните контур.","btn.skip":"Пропустить","space.scale_label":"Масштаб (размер клетки сетки)","space.cell_cm.help":"Связывает сетку с реальными размерами: от значения зависят длины и площади, толщина стен, размеры проёмов и радиус свечения. Изменение после разметки меняет расчётные размеры всего пространства, но не двигает его точки на плане.","space.cell_cm.help.aria":"Подсказка: масштаб пространства","space.scale_unit":"см на клетку","space.scale_unit_imperial":"дюйм на клетку","space.display_section":"Внешний вид","space.show_borders":"Всегда отображать границы комнат","space.zero_wall_style":"Стены нулевой толщины","space.zero_wall_style.help":"Пунктирные стены нулевой толщины пропускают Glow и солнечные лучи, сплошные блокируют их как барьер нулевой площади. Выбор меняет все такие стены пространства, даже когда их линии скрыты в просмотре.","space.zero_wall_style.help.aria":"Подсказка: вид стен нулевой толщины","space.zero_wall_dashed":"Пунктирные","space.zero_wall_solid":"Сплошные","space.show_names":"Показывать названия комнат","space.room_color":"Цвет границ и названий","space.opacity":"Прозрачность","space.fill_label":"Заливка комнат","space.fill_mode.help":"«Свой цвет» задаёт оформление, а «Свет», «Температура» и «LQI» используют текущие данные Home Assistant; Glow включается отдельно.","space.fill_mode.help.aria":"Подсказка: режим заливки комнат","fill.none":"Нет","fill.lqi":"По силе зигби-сигнала","fill.light":"По освещению","fill.custom":"Свой цвет","space.custom_fill":"Цвет заливки","space.source_file":"Использовать изображение плана","space.source_draw":"Нарисовать вручную","fill.temp":"По температуре","tip.temp_avg":"средняя температура:","tip.hum_avg":"средняя влажность:","space_card.button":"Перейти к пространству","space_card.not_found":"Пространство «{id}» не найдено","space_card.loading":"Загрузка…","continuity.restore_plan":"Восстанавливаем план…","continuity.restore_connection":"Восстанавливаем подключение к устройствам…","continuity.retry":"Повторить","editor.space":"Пространство","editor.framing":"Кадрирование","editor.fit_content":"Всё видимое содержимое","editor.fit_house":"Плотно по геометрии дома","editor.show_button":"Показывать кнопку","editor.button_label":"Текст кнопки","editor.button_target":"Путь дашборда (куда вести)","marker.sub_entity":"сущность","title.general_settings":"Общие настройки","title.export_pdf":"Сохранить в PDF","pdf.title":"Сохранение в PDF","pdf.dimensions":"Отображать размеры и площади","pdf.decor":"Отображать мебель и другой декор","pdf.room_names":"Отображать названия комнат","pdf.backdrop":"Отображать подложку","pdf.save":"Сохранить","pdf.saving":"Формируем…","pdf.failed":"Не удалось создать PDF.","pdf.too_large":"Размер изображений превышает лимит PDF 25 МБ.","pdf.asset_failed":"Не удалось загрузить подложку или изображение декора.","pdf.scale":"Масштаб 1:{n}","pdf.north":"Север","gs.title":"Общие настройки","gs.light_group":"Освещение","gs.light_on":"Свет включён","gs.light_off":"Весь свет выключен","gs.temp_group":"Температура","gs.temp_cold":"Холодно","gs.temp_ok":"Комфорт","gs.temp_hot":"Жарко","gs.lqi_group":"Сигнал Zigbee","gs.lqi_low":"Слабый сигнал","gs.lqi_high":"Сильный сигнал","gs.reset":"Сбросить к умолчаниям","gs.saved":"Общие настройки сохранены","gs.radar_show_live":"Показывать текущее присутствие на плане","radar.title":"Присутствие на плане","radar.help":"Свяжите маркер с точными сущностями радара Home Assistant, укажите положение датчика и профиль координат. Живые позиции обрезаются по выбранной комнате.","radar.help.aria":"Подсказка: настройки радара присутствия","radar.enabled":"Использовать этот радар присутствия","radar.show_live":"Показывать живые цели","radar.configure":"Настроить радар","radar.configure_on_plan":"Настроить на плане","radar.change_installation":"Сменить установку","radar.no_contour":"У комнаты нет контура. Точки радара не будут обрезаться по комнате.","radar.discard_setup_title":"Отменить настройку радара?","radar.discard_setup":"Несохранённая настройка радара будет потеряна.","radar.step_place_mount":"Укажите физическое положение датчика","radar.step_place_heading":"Укажите точку прямо перед датчиком","radar.step_reference":"Укажите контрольное положение {n}, затем начните измерение","radar.step_check_reference":"Укажите независимое проверочное положение","radar.start_measure":"Начать измерение","radar.countdown":"Встаньте в отмеченное место через {seconds} с","radar.capturing":"Стойте неподвижно и в одиночестве…","radar.fit_ready":"Калибровка готова","radar.check_third":"Проверить в другом положении","radar.check_complete":"Независимая проверка завершена","radar.error_distance":"Расхождение положения: {distance}","radar.ambiguous_target":"Обнаружено несколько целей. Повторите измерение в одиночестве.","radar.insufficient_samples":"Недостаточно актуальных координат. Повторите или настройте вручную.","radar.bad_references":"Выберите разнесённые положения в разных направлениях от датчика.","radar.ambiguous_sources":"Измерения допускают два одинаково вероятных направления. Выберите точки, по которым можно различить левую и правую стороны.","radar.bad_fit":"Измерения не совпадают. Проверьте единицы, положение датчика и контрольные точки.","radar.desktop_hint":"Для точной настройки используйте компьютер. Редактирование на тач-устройствах поддерживается по остаточному принципу.","radar.detected":"House Plan распознал признаки радара у этого устройства. Перед сохранением проверьте точные источники.","radar.detected_ld2450":"House Plan нашёл набор координат ESPHome LD2450. Перед сохранением проверьте точные источники X/Y.","radar.additional_actions":"Дополнительные действия","radar.declare":"Это радар присутствия","radar.profile":"Профиль данных","radar.profile_esphome_ld2450_v1":"ESPHome LD2450 (цели X/Y)","radar.profile_cartesian_v1":"Декартовы цели (X/Y)","radar.profile_polar_v1":"Полярная цель (дальность/угол)","radar.profile_range_v1":"Только дальность","radar.profile_zones_v1":"Состояния зон","radar.profile_presence_v1":"Только присутствие","radar.room":"Комната радара","radar.room_choose":"Выберите комнату","radar.target":"Цель {n}","radar.axis_x":"Сущность координаты X","radar.axis_y":"Сущность координаты Y","radar.add_target":"Добавить слот цели","radar.range_channel":"Канал дальности {n}","radar.add_range":"Добавить канал дальности","radar.presence_gate":"Сущность присутствия для слота","radar.swap_axes":"Поменять оси X и Y местами","radar.axis_x_sign":"Направление X","radar.axis_y_sign":"Направление Y","radar.distance_source":"Сущность дальности","radar.angle_source":"Сущность угла","radar.angle_unit":"Единица угла","radar.degrees":"Градусы","radar.radians":"Радианы","radar.angle_zero":"Направление нулевого угла","radar.angle_forward":"Вперёд","radar.angle_right":"Вправо","radar.angle_clockwise":"Угол растёт по часовой стрелке","radar.zone_source":"Сущность зоны","radar.occupancy_source":"Сущность присутствия","radar.count_source":"Сущность количества целей","radar.availability_source":"Сущность доступности","radar.source_choose":"Выберите сущность","radar.source_optional":"Необязательно","radar.source_missing":"сейчас недоступна","radar.saved_unsupported":"Сохранённая настройка радара не поддерживается или неполна. Она неактивна; удалите её либо обновите House Plan перед повторной настройкой.","radar.occupancy":"Присутствие (вкл/выкл)","radar.count":"Количество","radar.mount":"Положение и направление","radar.mount_hint":"Это физическое положение датчика. Перемещение его декоративного маркера не меняет установку.","radar.heading":"Направление, °","radar.range_cm":"Дальность, см","radar.fov_deg":"Угол обзора, °","radar.unit":"Единица источника","radar.mirror":"Отразить ось влево/вправо","radar.remove":"Удалить настройки радара","radar.invalid":"Перед сохранением заполните комнату, источники и положение радара.","radar.check_sources":"Проверить живые данные","radar.checking":"Проверяем…","radar.health":"Состояние подключения","radar.live_summary":"Текущих целей: {targets}; дуг дальности: {ranges}","radar.health_ok":"Актуальные данные получены","radar.health_off":"Цели не обнаружены","radar.health_stale":"Часть координат устарела","radar.health_partial":"Часть источников актуальна, часть устарела","radar.health_restricted":"Нет доступа к одному или нескольким источникам","radar.health_incomplete":"Текущий отчёт радара неполон","radar.health_position_unavailable":"Есть присутствие, но актуальное положение недоступно","radar.health_unavailable":"Данные датчика недоступны","radar.health_needs_setup":"Требуется настроить установку","radar.health_inconsistent":"Источники передают противоречивые данные","radar.health_unknown":"Текущее состояние неизвестно","radar.health_disabled":"Радар отключён","radar.error_invalid_radar":"Проверьте настройки радара.","radar.error_invalid_selection":"Выберите существующую комнату и допустимые источники.","radar.error_source_restricted":"Нет доступа ко всем выбранным источникам.","radar.error_rate_limited":"Слишком много запросов. Повторите чуть позже.","radar.error_not_ready":"Обработка данных радара ещё не готова.","radar.error_conflict":"План изменился. Откройте настройку радара заново и повторите попытку.","radar.error_source_unavailable":"Один или несколько выбранных источников радара недоступны.","radar.error_unsupported_capability":"Установленная интеграция не поддерживает эту возможность радара.","radar.report_age":"{seconds} с назад","space.show_lqi":"Сигнал Zigbee рядом с устройствами","gs.light_none":"Нет источников света","mode.plan":"Редактор плана","mode.devices":"Редактор устройств","display.value":"Значение + состояние","marker.subarea":"без зоны, вручную","device.new":"Новое устройство — откройте его редактор, чтобы снять отметку","opening.unlock_action":"Открыть замок","opening.lock_action":"Закрыть замок","opening.lock_pending":"Выполняется…","title.close_editor":"Закрыть редактор (вернуться к просмотру)","title.add_device":"Добавить устройство на план","devbar.add":"Добавить","devbar.rules":"Правила иконок","device_inbox.button":"Устройства","device_inbox.title":"Устройства на плане","device_inbox.search":"Поиск по устройствам, сущностям и интеграциям…","device_inbox.add_virtual":"Добавить виртуальное устройство","device_inbox.tab_on_plan":"На плане","device_inbox.tab_available":"Доступны","device_inbox.tab_hidden":"Скрытые","device_inbox.tab_readd":"Доступны снова","device_inbox.only_new":"Только новые","device_inbox.show_entities":"Показывать сущности","device_inbox.show_hidden":"Показывать скрытые на плане","device_inbox.show_hidden.help":"Временно показывает на плане скрытые и деактивированные маркеры служебными призраками только в редакторе устройств. Сохранённая видимость устройств не меняется.","device_inbox.show_hidden.help.aria":"Подсказка: показывать скрытые устройства на плане","device_inbox.new":"Новое","device_inbox.find":"Найти на плане","device_inbox.edit":"Настроить","device_inbox.hide":"Скрыть","device_inbox.show":"Показать","device_inbox.add":"Добавить","device_inbox.readd":"Добавить заново","device_inbox.hide_available":"Скрыть из списка","device_inbox.show_more":"Показать ещё","device_inbox.more_actions":"Другие действия","device_inbox.find_hidden_hint":"Сначала включите «Показывать скрытые на плане»","device_inbox.show_disabled":"Перед показом активируйте эту привязку в Home Assistant","device_inbox.empty_on_plan":"На плане пока нет подходящих устройств.","device_inbox.empty_available":"Нет доступных устройств для добавления.","device_inbox.empty_hidden":"Скрытых устройств нет.","device_inbox.empty_readd":"Нет удалённых устройств, доступных для повторного добавления.","device_inbox.reason_visible_auto":"Найдено автоматически","device_inbox.reason_visible_explicit":"Добавлено явно","device_inbox.reason_manual_hidden":"Скрыто пользователем","device_inbox.reason_automatic_hidden":"Скрыто автоматически","device_inbox.reason_service_entry":"Служебная запись реестра","device_inbox.reason_excluded_integration":"Исключена интеграция «{integration}»","device_inbox.reason_excluded_domain":"Непространственный тип сущности","device_inbox.reason_grouped_light":"Представлено группой света комнаты","device_inbox.reason_represented_by_parent":"Представлено родительским устройством","device_inbox.reason_removed":"Ранее удалено с плана","device_inbox.reason_available":"Можно добавить на план","device_inbox.reason_no_bound_room":"Зона HA не связана с комнатой плана","device_inbox.status_ha_disabled":"Отключено в Home Assistant","device_inbox.status_orphaned":"Привязка больше не найдена в Home Assistant","device_inbox.status_unverified":"Реестр Home Assistant временно недоступен","device_inbox.saved":"Список устройств обновлён","device_inbox.filters_excluded":"Исключённые интеграции","device_inbox.filters_group_lights":"Объединять светильники комнаты в один маркер","device_inbox.filters_preview_appear":"появится: {count}","device_inbox.filters_preview_hide":"скроется: {count}","device_inbox.filters_preview_lights":"затронет светильников: {count}","device_inbox.filters_reset":"Вернуть рекомендуемые","device_inbox.filters_save":"Сохранить фильтры","device_inbox.filters_search_ph":"Добавить интеграцию…","device_inbox.filters_title":"Фильтры обнаружения","space.roomcard_section":"Карточки комнат","space.label_temp":"Температура","space.label_hum":"Влажность","space.label_lqi":"Средний Zigbee-сигнал","space.label_light":"Свет вкл/выкл","roomcard.light_on":"Вкл","roomcard.light_off":"Выкл","roomcard.light_partial":"{on} из {total}","toast.split_pick_inside":"Промежуточные точки разреза — внутри комнаты","mode.decor":"Редактор подложки","decor.select":"Выбрать","decor.line":"Линия","decor.rect":"Прямоугольник","decor.ellipse":"Овал","decor.text":"Надпись","decor.erase":"Стереть","decor.erase_confirm_title":"Стереть объект?","decor.color":"Цвет","decor.width":"Толщина линии","decor.line_style":"Стиль линии","decor.line_style_solid":"Сплошная","decor.line_style_dashed":"Пунктирная","decor.fill":"Заливка","decor.fill_color":"Цвет заливки","decor.length":"Длина","decor.size":"Размер","decor.flip_h":"Отзеркалить по горизонтали","decor.flip_v":"Отзеркалить по вертикали","decor.angle":"Угол поворота, °","decor.text_size":"Размер текста","decor.backdrop_properties":"Свойства картинки-подложки","decor.text_title":"Надпись","decor.object_title":"Редактирование: {kind}","decor.text_label":"Текст","decor.live_group":"Вставить переменную HA","decor.live_entity":"Сущность","decor.live_entity_ph":"выберите сущность","decor.live_attr":"Значение","decor.live_attr_ph":"выберите состояние или атрибут","decor.live_state":"Состояние","decor.backdrop":"Картинка-подложка","decor.backdrop_hint":"Тяните картинку — перемещение; угол — размер; верхнюю ручку — поворот. Shift меняет пропорции или снимает шаг угла.","decor.backdrop_reset":"Вернуть картинку","decor.backdrop_reset_done":"Картинка вернулась на своё место и в свой размер","marker.icon_auto":"Авто: {icon} (по правилам иконок; выберите свою, чтобы заменить)","marker.icon_pin_auto":"Закрепить","mode.plan_tip":"Редактор плана — геометрия дома: рисование и объединение/разделение комнат, привязка к зонам HA, двери, окна и ворота, карточки комнат, масштаб","mode.devices_tip":"Редактор устройств — всё про значки: перетаскивание, клик — настройка привязки/иконки/отображения, виртуальные устройства, правила иконок","mode.decor_tip":"Редактор подложки — чисто визуальный декор под планом: линии, прямоугольники, овалы и надписи, не реагирующие на клики","space.glow_enabled":"Свечение источников света","gs.glow_group":"Свечение источников света","gs.glow_base":"Темнота дома","gs.glow_light":"Цвет света по умолчанию / интенсивность","gs.wall_fill":"Цвет заливки стен","gs.glow_radius":"Радиус свечения","gs.glow_radius.help":"Задаёт общий радиус светового пятна в метрах или футах; персональный радиус устройства заменяет это значение.","gs.glow_radius.help.aria":"Подсказка: общий радиус свечения","gs.unit_m":"м","gs.unit_ft":"фут","marker.controls_label":"Управляет другими источниками света","marker.controls.help":"При действии «Переключить состояние» перечисленные источники переключаются вместе с этим маркером. Их световые пятна остаются у собственных маркеров, а эта связь сама по себе не делает управляющий маркер источником света.","marker.controls.help.aria":"Подсказка: управление другими источниками света","marker.controls_filter":"Поиск ламп и выключателей…","info.controls":"Управляет","marker.glow_radius_label":"Радиус свечения","marker.glow_radius.help":"Задаёт радиус свечения в метрах или футах; пустое значение использует радиус из общих настроек.","marker.glow_radius.help.aria":"Подсказка: радиус свечения","markup.wallthick":"Толщина","markup.select":"Выбрать","title.markup_wallthick":"Толщина — клик по стене задаёт толщину от 0 до 100 см.","markup.hint_wallthick":"клик по стене · Esc закрывает без применения","wallthick.field":"Толщина","wallthick.unit_cm":"см","wallthick.unit_in":"дюйм","wallthick.apply_room":"Применить ко всем стенам комнаты","markup.draw_wall_title":"Толщина каждого нового сегмента стены (0–100 см). Общие стены сохраняют существующее значение.","room.queue_progress":"Комната {current} из {total}","toast.wall_rooms_saved":"Создано комнат: {n}","toast.wall_chain_saved":"Цепочка стен сохранена","toast.wallthick_pick":"Кликните по стене","toast.wallthick_set":"Толщина стены задана","toast.wallthick_cleared":"Толщина стены убрана","toast.physical_range":"Введите значение от {min} до {max} {unit}","toast.zero_wall_opening_conflict":"Сначала удалите проём на этом участке стены.","toast.zero_wall_ambiguous":"Не удалось однозначно выбрать участок стены. Уточните геометрию узла.","toast.zero_wall_migration_blocked":"Пространство не преобразовано: {reason}. Данные не изменены.","toast.physical_angle":"Введите угол поворота от 0° до 90°, не включая 90°","toast.physical_limit":"В пространстве достигнут лимит объектов этого типа","toast.geometry_unsafe":"Изменение отменено: геометрию стен нельзя безопасно построить.","junction.limit_angle":"Слишком острый угол между стенами: {actual}°, минимум {limit}°.","junction.limit_valence":"Слишком много стен в одном узле: {actual}, максимум {limit}.","junction.limit_length":"Слишком короткий участок стены: {actual} см, минимум {limit} см.","junction.limit_distance":"Стены и узлы слишком близко: {actual} см, минимум {limit} см.","junction.limit_clearance":"Внутри комнаты не остаётся места: {actual} см², минимум {limit} см².","junction.limit_check_failed":"Проверку стыков выполнить не удалось — изменение не сохранено","toast.wall_model_migration_blocked":"Не удалось обновить модель стен: {reason}. План не изменён. Запустите «Оптимизировать планы»; если ошибка повторится, исправьте конфликтующую геометрию стен.","toast.wall_model_client_outdated":"Обновите карточку и перезагрузите страницу перед редактированием плана.","wall_model.reason.invalid-room":"некорректный контур комнаты","wall_model.reason.zero-length":"отрезок стены нулевой длины","wall_model.reason.third-owner":"стена принадлежит более чем двум комнатам","wall_model.reason.duplicate-id":"конфликт идентификаторов стен","wall_model.reason.thickness-conflict":"конфликт значений толщины стены","wall_model.reason.opening-host":"проём нельзя однозначно привязать к стене","toast.delete_room_pick":"Кликните внутри комнаты, которую нужно удалить","toast.plan_snap_ambiguous":"Увеличьте масштаб, чтобы выбрать узел стены","toast.wall_repair_ambiguous":"У контура несколько возможных соединений. Увеличьте масштаб и соедините стены явно.","toast.wall_repair_too_large":"Разрыв больше 2 см. Соедините стены перед созданием комнаты.","toast.wall_repair_changed":"Геометрия стен изменилась. Попробуйте создать комнату ещё раз.","toast.opening_on_zero_wall":"Проёмы на стене нулевой толщины запрещены","marker.from_ha_option":"Выбрать из списка HA","marker.show_entities":"Показывать сущности","marker.show_entities_tip":"Добавляет в список не только устройства, но и все их сущности","marker.pick_ph":"Выберите устройство…","room.open_area":"Открыть зону в HA","room.fit_action":"Вписать комнату {name}","view.volumetric":"Объёмный вид","view.flat":"Плоский вид","kiosk.title":"Размеры на этом экране","kiosk.hint":"Хранится только на этом устройстве — у каждого настенного планшета или ТВ свои удобные размеры.","kiosk.icon_scale":"Размер значков устройств","kiosk.font_scale":"Размер текста карточек комнат","editor.kiosk":"Режим настенного устройства (киоск)","editor.cycle":"Автосмена пространств каждые N секунд (киоск, 0 = выкл)","room.settings_title":"Настройки комнаты","room.fill_label":"Заливка в ЭТОЙ комнате","fill.inherit":"Как у пространства","room.custom_fill_space":"Цвет пространства","room.custom_fill_own":"Цвет комнаты","room.temp_range_label":"Диапазон комфорта","room.temp_range_min":"Нижняя граница комфортной температуры","room.temp_range_max":"Верхняя граница комфортной температуры","room.temp_range_reset":"Как у пространства","room.temp_range.help":"Диапазон применяется только к этой комнате. Пустое поле наследует соответствующую границу пространства; если границы поменялись местами, House Plan использует меньшую как нижнюю, а большую как верхнюю.","room.temp_range.help.aria":"О диапазоне комфорта комнаты","room.temp_src_label":"Источник температуры","room.hum_src_label":"Источник влажности","room.src_average":"Среднее по датчикам комнаты","room.src_pick":"Конкретное устройство или сущность","room.src_ph":"Выберите источник…","toast.room_updated":"Комната обновлена","space.card_font":"Размер шрифта карточек","room.sizes_section":"Размеры шрифтов","room.group_basics":"Основное","room.group_basics.help":"Область связывает комнату с зоной Home Assistant: из неё берутся датчики. Без области комната остаётся геометрией.","room.group_basics.help.aria":"Подсказка: имя и область комнаты","room.group_fill":"Заливка","room.group_fill.help":"Заливка этой комнаты перекрывает выбранную для пространства; «Свой цвет» хранится только здесь.","room.group_fill.help.aria":"Подсказка: заливка комнаты","room.group_sources":"Источники","room.group_sources.help":"По умолчанию комната усредняет свои датчики. Выбранный датчик заменяет среднее везде: подсказка, карточка, заливка.","room.group_sources.help.aria":"Подсказка: источники температуры и влажности","room.sizes_section.help":"Масштабы действуют только в этой комнате и умножаются на общий масштаб карточки из настроек пространства.","room.sizes_section.help.aria":"Подсказка: размеры шрифтов комнаты","room.name_scale":"Размер названия","room.label_scale":"Размер подписей","preview.room_name":"Гостиная","toast.cfg_reload_failed":"Не удалось перечитать план с сервера: {err}","toast.locale_load_failed":"Не удалось загрузить языковой пакет. До перезагрузки страницы используется английский.","toast.furniture_art_load_failed":"Не удалось загрузить изображения мебели. Обновите страницу, чтобы их показать.","room.settings_short":"Настройки комнаты","room.unnamed":"Комната без имени","marker.use_climate_temp":"Учитывать температуру устройства в комнате","marker.use_climate_temp_tip":"Добавляет current_temperature кондиционера или термостата в среднюю температуру комнаты. Внешний бейдж со значением настраивается отдельно ниже.","marker.value_badge_title":"Бейдж со значением","marker.value_badge.help":"Показывает одно выбранное значение рядом со значком. Не влияет на комнатные показатели, свет, Glow и действие по нажатию.","marker.value_badge.help.aria":"Подсказка: бейдж со значением устройства","marker.value_badge_enabled":"Отображать бейдж со значением","marker.value_badge_source":"Значение","marker.value_badge_source.help":"Выберите конкретное состояние, поддерживаемый атрибут или производное значение этого устройства.","marker.value_badge_source.help.aria":"Подсказка: источник значения бейджа","marker.value_badge_position":"Расположение","marker.value_badge_position.help":"Выбранная сторона сохраняется постоянно и не переворачивается автоматически у края плана.","marker.value_badge_position.help.aria":"Подсказка: расположение бейджа","marker.value_badge_right":"Справа","marker.value_badge_bottom":"Снизу","marker.value_badge_left":"Слева","marker.value_badge_top":"Сверху","marker.value_badge_empty":"У этого устройства нет доступных значений","marker.value_badge_static":"Статичный значок не показывает живые значения. Настройка сохранится.","marker.value_badge_missing":"Источник недоступен","marker.value_badge_missing_hint":"Сохранённый источник сейчас недоступен. Можно сохранить его, отключить бейдж или выбрать другой.","marker.value_badge_duplicate":"То же значение уже показано внутри значка.","marker.value_badge_state":"Состояние · {name}","marker.value_badge_marker_state":"Состояние источника света · {name}","marker.value_badge_lqi":"Качество Zigbee-сигнала (среднее)","marker.value_badge_attr_current_temperature":"Текущая температура · {name}","marker.value_badge_attr_temperature":"Целевая температура · {name}","marker.value_badge_attr_current_humidity":"Текущая влажность · {name}","marker.value_badge_attr_humidity":"Влажность · {name}","marker.value_badge_attr_current_position":"Положение · {name}","marker.value_badge_attr_percentage":"Скорость · {name}","marker.value_badge_attr_brightness":"Яркость · {name}","marker.value_badge_attr_volume_level":"Громкость · {name}","marker.value_badge_attr_battery_level":"Заряд батареи · {name}","marker.value_badge_attr_fan_speed":"Скорость вентилятора · {name}","marker.value_source":"Источник значения","marker.value_source.help":"Выберите, что заменит значок. Действие по нажатию не изменится.","marker.value_source.help.aria":"Подсказка: источник значения внутри значка","marker.value_source_auto":"Автоматически (как раньше)","marker.value_source_missing_hint":"Сохранённый источник сейчас недоступен. До его восстановления или выбора другого значения внутри будет показано —.","marker.light_role_label":"Является источником света","marker.light_role.help":"«Авто» использует фактическую роль привязанного устройства, «Всегда» принудительно создаёт собственный источник, а «Никогда» исключает его; связанные лампы выше остаются независимыми.","marker.light_role.help.aria":"Подсказка: является ли устройство источником света","marker.light_role_auto_yes":"Автоматически (источник света)","marker.light_role_auto_no":"Автоматически (не источник света)","marker.light_entity_label":"Ведущая сущность света","marker.light_entity.help":"Для составного устройства выберите сущность, состояние, цвет и яркость которой представляют этот источник на плане. Автоматический вариант сохраняет совместимость со старыми планами.","marker.light_entity.help.aria":"Подсказка: ведущая сущность света","marker.light_entity_auto":"Автоматически ({entity})","marker.light_entity_none":"нет управляемой сущности","marker.light_entity_missing":"Сохранённая сущность {entity} недоступна. Временно используется {fallback}; выбор восстановится, если сущность вернётся.","marker.toggle_entity_label":"Переключаемая сущность","marker.toggle_entity.help":"Для составного устройства выберите собственную лампу или переключатель, которой управляет нажатие. Автоматический вариант сохраняет прежние правила цели и не зависит от ведущей сущности света.","marker.toggle_entity.help.aria":"Подсказка: переключаемая сущность","marker.toggle_entity_auto":"Автоматически ({entity})","marker.toggle_entity_none":"нет собственной управляемой сущности","marker.toggle_entity_missing":"Сохранённой сущности {entity} больше нет среди выбираемых каналов этого маркера. Временно используется {fallback}; выбор восстановится, если сущность вернётся.","marker.glow_color_label":"Цвет и яркость свечения","marker.glow_mode.help":"Используйте данные источника, задайте только цвет или зафиксируйте цвет и яркость. Минимум — 1%; чтобы отключить источник, выберите «Никогда».","marker.glow_mode.help.aria":"Подсказка: цвет и яркость свечения","marker.glow_mode_auto":"Из источника","marker.glow_mode_color":"Задать цвет","marker.glow_mode_fixed":"Цвет и яркость","marker.glow_color":"Цвет свечения","marker.glow_brightness":"Яркость","marker.glow_disabled_never":"Настройки свечения недоступны: маркер явно исключён из источников света.","marker.glow_disabled_auto":"В автоматическом режиме у этого маркера не найден пространственный источник света.","marker.glow_disabled_no_entity":"Для пространственного источника нет активной управляемой сущности Home Assistant.","marker.glow_passive_hint":"У источника нет собственных данных Home Assistant. Задайте цвет и яркость вручную; радиус остаётся доступным.","marker.control_broken":"Сохранённый источник отсутствует или больше не отмечен как источник света","marker.control_missing_label":"Отсутствующий источник на плане","marker.control_passive":"пассивный источник","toast.marker_control_cycle":"Такая связь создаст циклическую цепочку управления светом.","toast.marker_binding_required":"Сначала выберите устройство Home Assistant, затем добавьте управляемый источник света.","confirm.unlock_title":"Открыть замок?","confirm.unlock_body":"House Plan отправит этому замку команду открытия.","toast.files_migrate_failed":"Не удалось перенести вложения к новой привязке, ссылки остались на старые файлы: {err}","space.pick_saved":"Уже загруженные","space.pick_saved_hint":"Планы, сохранённые на сервере, включая отцеплённые ранее","space.no_saved":"На сервере пока нет сохранённых планов.","space.loading":"Загрузка…","space.used_by":"используется: {list}","space.in_use":"План используется пространством — сначала отцепите его","btn.use":"Выбрать","confirm.delete_plan_title":"Удалить файл плана?","confirm.delete_plan_body":"Файл будет удалён с сервера. Это действие нельзя отменить.","toast.plans_list_failed":"Не удалось получить список планов: {err}","toast.plan_delete_failed":"Не удалось удалить план: {err}","marker.hide":"Скрыть","marker.hide_tip":"Устройство исчезнет с плана после сохранения, но продолжит участвовать в расчёте сигнала комнаты. Вернуть его можно через каталог «Устройства» в редакторе устройств.","marker.show":"Показать","marker.show_tip":"Устройство снова появится на плане после сохранения.","marker.hidden_ghost":"Устройство скрыто пользователем","marker.ha_disabled_device":"Устройство деактивировано в Home Assistant и скрыто с плана.","marker.ha_disabled_entity":"Сущность деактивирована в Home Assistant и скрыта с плана.","marker.ha_disabled_all_entities":"У устройства нет активных сущностей Home Assistant, поэтому оно скрыто с плана.","marker.ha_registry_limited":"Полный реестр Home Assistant недоступен этому пользователю. Неподтверждённый объект временно нельзя показывать или использовать.","marker.delete_tip":"Полностью удалить устройство с плана и из всех расчётов. Позже его можно добавить заново.","tap.run":"Запустить автоматизацию/скрипт/сцену","tap.none":"Ничего не делать","marker.run_target_label":"Что запускать","marker.run_search_ph":"Поиск: автоматизация, скрипт или сцена…","marker.run_target_gone":"Цель {id} не найдена — выберите заново","marker.tap_confirm":"Спрашивать подтверждение","marker.tap_confirm_tip":"Перед выполнением показать диалог подтверждения — защита от случайных нажатий.","marker.toggle_hint_single":"Цель: {name} ({id}).","marker.virtual_light_target":"Виртуальный свет: {name}.","marker.virtual_light_current":"Ручное состояние: {state} → {effect}.","marker.virtual_light_state_on":"включён","marker.virtual_light_state_off":"выключен","marker.toggle_hint_group":"Переключатся источники ({count}): {names}.","marker.toggle_hint_current":"Сейчас: {state} → {effect}.","marker.toggle_hint_group_current":"Сейчас включено {on} из {count} → {effect}.","marker.toggle_hint_skipped":"Не будут затронуты ({count}): {targets}.","marker.toggle_effect_turn_on":"включится","marker.toggle_effect_turn_off":"выключится","marker.toggle_effect_open":"откроется","marker.toggle_effect_close":"закроется","marker.toggle_effect_stop":"остановится","marker.toggle_effect_toggle":"состояние переключится","marker.toggle_skip_missing":"не найдено","marker.toggle_skip_ha_disabled":"деактивировано в HA","marker.toggle_skip_unavailable":"недоступно","marker.toggle_skip_unsupported":"переключение не поддерживается","marker.toggle_skip_secure":"заблокировано из соображений безопасности","marker.toggle_none_no_binding":"У устройства нет привязки, состояние переключать нечем. По нажатию ничего не произойдёт.","marker.toggle_none_no_actionable_entity":"У устройства нет состояния, которое можно переключить. По нажатию ничего не произойдёт.","marker.toggle_none_configured_targets_missing":"Настроенные цели сейчас недоступны. Собственная сущность устройства не будет подставлена вместо них.","marker.toggle_none_ha_disabled":"Цель деактивирована в Home Assistant и не может использоваться на плане.","marker.toggle_none_unavailable":"Цель сейчас недоступна. По нажатию ничего не произойдёт.","marker.toggle_none_unsupported":"Для этой сущности Home Assistant не предоставляет безопасного переключения. По нажатию ничего не произойдёт.","marker.toggle_none_secure":"Переключение замков, сигнализации и защитных ворот с плана заблокировано из соображений безопасности.","run.automation":"автоматизация","run.script":"скрипт","run.scene":"сцена","confirm.tap_run":"Запустить «{name}»?","confirm.tap_toggle":"Переключить «{name}»?","confirm.current_state":"Текущее состояние: {state}","confirm.expected_state":"После переключения: {state}","confirm.group_current":"включено {on} из {total}","confirm.group_all_on":"все включены","confirm.group_all_off":"все выключены","confirm.unavailable_targets":"Недоступно: {count}","confirm.expected_by_ha":"Состояние определит Home Assistant","confirm.state_on":"Включено","confirm.state_off":"Выключено","confirm.state_open":"Открыто","confirm.state_closed":"Закрыто","confirm.state_opening":"Открывается","confirm.state_closing":"Закрывается","confirm.state_stopped":"Остановлено","confirm.state_unknown":"Неизвестно","toast.run_started":"Запущено: {name}","toast.run_target_missing":"Цель запуска не найдена — проверьте настройки устройства","toast.run_target_required":"Выберите автоматизацию, скрипт или сцену","toast.tap_target_changed":"Цель действия изменилась. Повторите попытку.","toast.virtual_light_toggle_failed":"Не удалось переключить виртуальный свет: {err}","toast.value_badge_source_required":"Выберите значение для бейджа","btn.run":"Выполнить","vac.section":"Робот-пылесос: живая позиция","vac.autocal":"Настроить автоматически","vac.live":"Живая позиция на плане","vac.trail":"Показывать путь робота","vac.autocal_no_rooms":"Интеграция не отдаёт список комнат — откройте «Подогнать вручную»","vac.route_warn_unmapped":"Робот убирает на карте, которая не сопоставлена ни одному этажу","vac.route_warn_needs_calibration":"Карта сопоставлена этажу, но не откалибрована","vac.route_warn_ambiguous":"Две карты неразличимы — этаж не выбран","vac.route_warn_missing_space":"Пространство этой карты удалено","vac.autocal_no_match":"Не совпали имена комнат (нужно ≥3 общих) — откройте «Подогнать вручную»","vac.autocal_done":"Готово: привязка по {rooms} комнатам. Запустите уборку и проверьте","vac.cal_need_pos":"Робот сейчас не отдаёт координаты — запустите уборку и поставьте на паузу","vac.cal_done":"Калибровка сохранена. Запустите уборку и проверьте","vac.cal_cancelled":"Калибровка отменена","vac.fit":"Подогнать вручную","vac.fit_hint":"Перетащите карту робота на место, растяните за уголки","vac.fit_rotate":"Повернуть 90°","vac.fit_mirror":"Отразить","vac.trail_never":"Не показывать никогда","vac.trail_cleaning":"Во время уборки","vac.trail_always":"Показывать всегда","gs.bg_color":"Цвет фона вокруг плана","gs.bg_default":"Как в теме","gs.bg_mode":"Фон плана","gs.bg_mode.help":"«Следует за Солнцем» использует sun.sun, а при недоступности — локальные часы браузера; статичный режим всегда показывает выбранный цвет.","gs.bg_mode.help.aria":"Подсказка: общий фон плана","gs.bg_static":"Статичный цвет","gs.bg_daynight":"Следует за Солнцем","gs.sun_group":"Солнце","gs.sun_missing":"Сущность sun.sun не найдена — фон следует локальным часам, а оконные лучи недоступны.","gs.north":"Север на плане","gs.north.help":"Угол отсчитывается по часовой стрелке от верхней вертикали плана; север нужен для оконных лучей, а не для фона «Следует за Солнцем».","gs.north.help.aria":"Подсказка: общее направление севера","gs.north_ph":"не задан","gs.north_clear":"Сбросить","gs.north_letter":"С","gs.sun_rays":"Солнце в окнах","gs.sun_ray_origin":"Лучи солнца","gs.sun_ray_origin.inner":"От внутренних углов окон","gs.sun_ray_origin.outer":"От внешних углов окон","gs.about_version":"Houseplan Card v{v}","gs.about_github":"GitHub · документация и issues","gs.about_telegram":"Чат в Telegram","support.title":"Помощь и обратная связь","space.bg_color":"Цвет фона вокруг плана","space.bg_inherit":"Наследовать общий","space.bg_mode":"Фон плана","space.bg_mode.help":"Выберите наследование общего фона либо переопределите это пространство статичным цветом или режимом «Следует за Солнцем».","space.bg_mode.help.aria":"Подсказка: фон пространства","space.north":"Север на плане","space.north.help":"Переопределяет общий север для этого пространства; угол отсчитывается по часовой стрелке от верхней вертикали плана и используется оконными лучами.","space.north.help.aria":"Подсказка: север для пространства","space.sun_rays":"Солнце в окнах","space.sun_inherit":"Общие настройки","space.sun_on":"Вкл","space.sun_off":"Выкл","canvas.far_objects":"Объектов далеко от плана: {n}","canvas.show_far":"Показать","canvas.home_tip":"План там — нажмите, чтобы вписать","gs.grid_group":"Обслуживание планов","gs.align_all":"Оптимизировать планы","gs.align_title":"Оптимизировать планы","gs.align_none":"Все планы уже используют актуальную и оптимальную модель данных.","gs.optimize_no_automatic_changes":"Автоматических изменений нет. Проверьте пункты ниже.","gs.align_count":"Сдвинется элементов: {n} из {total}, максимум на {cm} см.","gs.align_where":"Наибольший сдвиг — в пространстве «{s}».","gs.align_turned":"Проёмов с исправлением угла: {n}.","gs.align_preflight_failed":"Не удалось безопасно проверить геометрию следующих пространств: {spaces}{more}.","gs.align_preflight_hint":"Планы не изменены. Скопируйте диагностику кнопкой ниже и приложите её к отчёту об ошибке вместе с экспортом пространства.","gs.preflight_reason_prepare-exception":"Не удалось подготовить геометрию пространства (исключение при сборке модели)","gs.preflight_reason_wall-null":"Тело стен не построилось (объединение вернуло пустоту)","gs.preflight_reason_wall-degraded-extra":"Тело стен деградировало с лишней геометрией","gs.preflight_reason_wall-failed-core":"Ядро тела стен не собралось","gs.preflight_reason_wall-exception":"Построение стен упало с исключением","gs.preflight_reason_floor-null":"Контур пола не построился","gs.preflight_reason_floor-exception":"Построение пола упало с исключением","gs.preflight_copy":"Скопировать диагностику","gs.preflight_copied":"Диагностика скопирована","gs.preflight_update_hint":"Версии карточки и интеграции различаются — обновите House Plan и повторите.","gs.align_preflight_space":"Пространство {n}","gs.align_preflight_more":" и ещё {n}","gs.optimize_changes":"Миграций модели: {m}; обновлено пространств: {c}; устранён шум координат: {p}; объединено отрезков реальных стен: {w}; объединено отрезков стен нулевой толщины: {s}; независимых: {i}.","gs.zero_walls_migrated":"Преобразовано виртуальных участков: {n}.","gs.wall_segments_migrated":"Стабилизировано сегментов стен: {n}.","gs.room_drafts_migrated":"Незавершённые контуры преобразованы в обычные стены: {drafts}; отрезков: {segments}.","gs.optimize_lattice_summary":"Канонизировано шумовых значений координат: {n}; максимальный сдвиг: {cm} см.","gs.optimize_lattice_space":"{space}: канонизировано значений координат: {n}; оставлено значений вне сетки: {far}.","gs.optimize_coincident_partitions":"Скрытые участки независимых стен поглощены стенами комнат: {n}.","gs.optimize_openings_rehosted":"Проёмы перепривязаны к стенам комнат: {n}.","gs.optimize_walls_straightened":"Выпрямлено стен: {n}; максимальное перемещение: {cm} см.","gs.optimize_walls_straightened_where":"Максимальная правка стены: {s}.","gs.optimize_walls_straighten_skipped":"Оставлено почти осевых стен, которые нельзя безопасно выпрямить: {n}.","gs.optimize_glow_migration":"Старый Glow: пространств — {spaces} → без заливки данных + независимый Glow; комнат — {rooms} → наследуемая заливка + независимый Glow.","gs.optimize_references":"Исправлено ссылок: пространства — {spaces}; комнаты — {rooms}; позиции — {positions}; устройств отвязано от отсутствующих пространств — {detached}.","gs.optimize_reference_more":", и ещё {n}","gs.optimize_orphans_removed":"Убрано забытых записей: {total} — подписи комнат: {rooms}; устройства: {devices}; групповые метки: {groups}. Все они принадлежали пространствам, удалённым ранее.","gs.optimize_live_positions":"Старые позиции в удалённых пространствах принадлежат существующим объектам: {n}{names}. Они будут сохранены.","gs.optimize_live_positions_remove":"Старые позиции в удалённых пространствах принадлежат существующим объектам: {n}{names}. Они выбраны для удаления.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Убрать старые позиции","gs.optimize_live_keep":"Сохранить старые позиции","gs.optimize_live_selected":"Старые позиции будут убраны после применения оптимизации.","gs.optimize_unverified":"Не удалось безопасно проверить позиций: {n}. Они оставлены без изменений.","gs.optimize_registry_limited":"Для безопасной проверки нужен полный доступ администратора к реестрам Home Assistant.","gs.optimize_vacuum_warning":"Сопоставления комнат пылесоса требуют проверки: {n}.","gs.optimize_details":"Подробности","gs.optimize_details_more":"И ещё записей: {n}.","gs.optimize_detail_removed":"будет удалено","gs.optimize_detail_live":"будет сохранено","gs.optimize_detail_unverified":"не проверено","gs.optimize_detail_room_label":"подпись комнаты","gs.optimize_detail_device":"устройство","gs.optimize_detail_group":"групповая метка","gs.optimize_detail_unknown":"неизвестный владелец","gs.optimize_detail_item":"{status}: {kind} {id}; прежнее пространство {space}","gs.align_warn":"Элементы, намеренно поставленные между узлами, будут сдвинуты. После операции доступна одна отмена — только до следующего изменения плана.","gs.align_run":"Оптимизировать","gs.align_done":"Планы оптимизированы: сдвинуто элементов — {n}, обслужено записей — {m}, исправлено ссылок — {r}","gs.optimize_undo":"Отменить последнюю оптимизацию","gs.optimize_undone":"Последняя оптимизация отменена","decor.furniture":"Мебель","decor.image":"Изображение","decor.image_title":"Свои изображения","decor.image_upload":"Загрузить изображение","decor.image_replace":"Заменить изображение","decor.image_uploading":"Загрузка…","decor.image_asset":"Файл изображения","decor.image_pick_hint":"Загрузите изображение или выберите уже используемое в House Plan.","decor.image_place_hint":"Кликните по плану, чтобы разместить изображение.","decor.image_none":"Загруженных изображений пока нет.","decor.image_unavailable":"Изображение недоступно","decor.image_used":"Используется в объектах: {n}","decor.image_upload_failed":"Не удалось загрузить изображение: {err}","decor.image_error_capacity":"Хранилище пользовательских изображений заполнено.","decor.image_in_use":"Перед удалением файла удалите все размещённые копии.","decor.image_delete_title":"Удалить файл изображения?","decor.image_delete_message":"Удалить «{name}» из House Plan? Это действие нельзя отменить.","furn.title":"Библиотека мебели","furn.symbol":"Символ","furn.group_furniture":"Мебель","furn.group_appliance":"Техника","furn.group_sanitary":"Сантехника","furn.group_other":"Прочее","furn.width":"Ширина","furn.depth":"Глубина","furn.back_to_categories":"Все категории","furn.pick_hint":"Выберите категорию, затем символ.","furn.place_hint":"Кликните по плану — предмет встанет к ближайшей стене. Shift — свободно.","furn.cat_air_conditioner":"Кондиционеры","furn.cat_armchair":"Кресла","furn.cat_bathtub":"Ванны","furn.cat_bed":"Кровати","furn.cat_bidet":"Биде","furn.cat_boiler":"Бойлеры","furn.cat_chair":"Стулья","furn.cat_coffee_table":"Журнальные столы","furn.cat_computer":"Компьютер","furn.cat_cooktop":"Варочные панели","furn.cat_dining_table":"Обеденные столы","furn.cat_dishwasher":"Посудомоечные машины","furn.cat_dryer":"Сушильные машины","furn.cat_fireplace":"Камины","furn.cat_fridge":"Холодильники","furn.cat_hood":"Вытяжка","furn.cat_kitchen_cabinet":"Кухонные шкафы","furn.cat_kitchen_sink":"Кухонные мойки","furn.cat_nightstand":"Тумбы","furn.cat_oven":"Духовка","furn.cat_plant":"Растения","furn.cat_rug":"Ковры","furn.cat_shelving":"Стеллажи","furn.cat_shower":"Душевые","furn.cat_sink":"Раковины","furn.cat_sofa":"Диваны","furn.cat_stairs":"Лестницы","furn.cat_toilet":"Унитазы","furn.cat_tv":"Телевизоры","furn.cat_wardrobe":"Шкафы","furn.cat_washer":"Стиральные машины","furn.cat_work_table":"Рабочие столы","furn.sym_cactus":"Кактус","furn.sym_computer":"Компьютер","furn.sym_hood":"Вытяжка","furn.sym_oven":"Духовка","furn.sym_sofa":"Диван двухместный","furn.sym_sofa_three_seat":"Диван трёхместный","furn.sym_sofa_corner_right":"Угловой диван, правый","furn.sym_armchair":"Кресло мягкое","furn.sym_armchair_office":"Кресло офисное","furn.sym_coffee_table":"Журнальный стол, прямоугольный","furn.sym_coffee_table_round":"Журнальный стол, круглый","furn.sym_coffee_table_oval":"Журнальный стол, овальный","furn.sym_coffee_table_rounded":"Журнальный стол, скруглённый","furn.sym_table_dining":"Обеденный стол, прямоугольный","furn.sym_table_round":"Круглый стол","furn.sym_table_dining_oval":"Обеденный стол, овальный","furn.sym_table_dining_rounded":"Обеденный стол, скруглённый","furn.sym_chair":"Стул","furn.sym_chair_bar":"Барный стул","furn.sym_desk":"Рабочий стол, прямоугольный","furn.sym_desk_corner":"Рабочий стол, угловой","furn.sym_bed_double":"Двуспальная кровать","furn.sym_bed_single":"Односпальная кровать","furn.sym_nightstand":"Тумба прикроватная","furn.sym_cabinet_tv":"Тумба под телевизор","furn.sym_cabinet_shoe":"Тумба для обуви","furn.sym_cabinet_sink":"Тумба под раковину","furn.sym_wardrobe":"Шкаф гардеробный","furn.sym_bookshelf":"Шкаф книжный","furn.sym_wall_unit":"Шкаф-стенка","furn.sym_kitchen_floor":"Кухонный напольный модуль","furn.sym_kitchen_floor_corner":"Кухонный напольный угловой модуль","furn.sym_kitchen_wall":"Кухонный навесной модуль","furn.sym_kitchen_wall_corner":"Кухонный навесной угловой модуль","furn.sym_shelf_floor":"Стеллаж напольный","furn.sym_shelf_wall":"Полка настенная","furn.sym_fridge":"Холодильник","furn.sym_stove":"Варочная панель, 4 конфорки","furn.sym_cooktop_two":"Варочная панель, 2 конфорки","furn.sym_dishwasher":"Посудомоечная машина","furn.sym_washer":"Стиральная машина","furn.sym_dryer":"Сушильная машина","furn.sym_tv":"Телевизор на подставке","furn.sym_tv_wall":"Телевизор на кронштейне","furn.sym_ac":"Кондиционер","furn.sym_water_heater":"Бойлер","furn.sym_toilet":"Унитаз напольный","furn.sym_toilet_built_in":"Унитаз встроенный","furn.sym_bathtub":"Ванна прямоугольная","furn.sym_bathtub_corner":"Ванна угловая","furn.sym_shower":"Душ","furn.sym_sink":"Раковина","furn.sym_kitchen_sink":"Кухонная мойка одинарная","furn.sym_kitchen_sink_double":"Кухонная мойка двойная","furn.sym_bidet":"Биде напольное","furn.sym_bidet_built_in":"Биде встроенное","furn.sym_stairs":"Лестница","furn.sym_fireplace":"Камин","furn.sym_plant":"Растение","furn.sym_rug":"Ковёр","common.yes":"Да","common.no":"Нет","vac.diag_source":"Источник","vac.diag_platform":"Интеграция","vac.diag_status":"Статус","vac.diag_position":"Позиция","vac.diag_rooms":"Комнаты","vac.diag_rooms_value":"{total} · совпало имён: {matched} · {readiness}","vac.autocal_ready":"автокалибровка доступна","vac.autocal_not_ready":"нужно 3 совпавших имени","vac.diag_path":"Путь интеграции","vac.diag_map":"ID карты","vac.source_none":"не выбран","vac.source_status_ok":"Готов","vac.source_status_missing":"Не найден","vac.source_status_disabled":"Деактивирован в Home Assistant","vac.source_status_unavailable":"Недоступен","vac.source_status_unverified":"Нельзя проверить с текущими правами","vac.source_status_unsupported":"Нет данных позиции","vac.source_status_none":"Нет источника","vac.source_banner_missing":"Сохранённый источник больше не существует. Он не заменён автоматически: выберите другой или восстановите его в Home Assistant.","vac.source_banner_disabled":"Сохранённый источник деактивирован в Home Assistant. Активируйте его там или выберите другой.","vac.source_banner_unverified":"Текущих прав Home Assistant недостаточно для проверки источника. Привязка сохранена и не будет заменена автоматически.","vac.choose_source":"Выбрать источник","vac.source_auto":"Автоматически","vac.source_auto_hint":"Использовать совместимую сущность этого устройства","vac.all_cameras":"Все камеры","vac.all_cameras_warn":"Камера может не отдавать данные робота. Выбирайте её только если это карта вашего пылесоса.","vac.all_cameras_empty":"Других сущностей камеры не найдено.","vac.platform_unknown":"интеграция неизвестна","vac.cap_position":"позиция","vac.cap_rooms_short":"комнаты","vac.cap_path":"путь","vac.cap_map":"ID карты","vac.cap_none":"данные робота не обнаружены","vac.xcme_hint":"Включите атрибуты Xiaomi Cloud Map Extractor:","vac.documentation":"Документация","vac.residual_title":"Проверьте автокалибровку","vac.residual_message":"Совпавшие комнаты расходятся максимум на {error}. Примените приблизительную калибровку, подгоните её вручную либо отмените без изменения сохранённых настроек.","vac.apply_proposal":"Применить","gs.backup_group":"Резервная копия и перенос","backup.export_open":"Экспорт","backup.import_open":"Импорт","backup.export_title":"Экспорт House Plan","backup.import_title":"Импорт House Plan","backup.export_hint":"Выберите, должна ли копия содержать всю конфигурацию House Plan или только текущее пространство.","backup.full":"Полная копия","backup.current_space":"Текущее пространство","backup.current_space_title":"Текущее пространство: {title}","backup.no_current_space":"Нет текущего пространства","backup.plan_only":"Только планировка","backup.plan_only_hint":"Сохранить комнаты, стены, проёмы, декор и позиции подписей комнат без устройств и привязок Home Assistant.","backup.plan_only_preview":"Файл содержит только планировку","backup.privacy_warning":"Архив сохраняет названия, идентификаторы Home Assistant и точные координаты. Внутренние планы и вложения указываются ссылками, но не вкладываются; текущие состояния и маршруты пылесосов не включаются.","backup.download":"Скачать JSON","backup.export_done":"Резервная копия скачана","backup.reading":"Проверяем резервную копию…","backup.revalidated":"После предпросмотра план изменился. Сводка обновлена — проверьте её и подтвердите ещё раз.","backup.error.support_invalid_message":"Проверьте сообщение для поддержки и повторите попытку.","backup.error.support_package_too_large":"Обезличенный пакет для поддержки превышает лимит 8 МиБ.","backup.error.support_preview_expired":"Предпросмотр вложения для поддержки истёк или больше недоступен.","backup.error.support_rate_limited":"Запрошено слишком много репортов или предпросмотров. Повторите позже.","backup.error.support_rejected":"Репорт не прошёл проверку службы поддержки.","backup.error.support_unavailable":"Закрытая служба поддержки временно недоступна.","backup.error.unauthorized":"У вас нет прав на экспорт или импорт этого плана.","backup.error.not_ready":"House Plan ещё не готов. Повторите попытку через несколько секунд.","backup.error.too_large":"Размер резервной копии превышает 8 МиБ.","backup.error.invalid_json":"Выбранный файл не является корректным JSON.","backup.error.invalid_format":"Выбранный файл не является резервной копией House Plan.","backup.error.invalid_image":"Изображение повреждено или не соответствует своему формату.","backup.error.unsupported_export_version":"Эта версия формата резервной копии не поддерживается установленной версией.","backup.error.unsupported_image":"Используйте поддерживаемое изображение PNG, JPEG, WebP или SVG.","backup.error.future_model":"Резервная копия создана в более новой версии модели данных House Plan.","backup.error.invalid_config":"Резервная копия содержит некорректную конфигурацию House Plan.","backup.error.wall_model_migration_blocked":"Не удалось безопасно обновить модель стен из резервной копии. Сначала оптимизируйте исходный план и повторите экспорт.","backup.error.invalid_layout":"Резервная копия содержит некорректные позиции объектов.","backup.error.invalid_content":"Резервная копия содержит некорректные или несогласованные ссылки на файлы.","backup.error.space_not_found":"Выбранное пространство больше не существует.","backup.error.capacity_exceeded":"Добавление этой копии превысит ограничения размера плана.","backup.error.preview_expired":"Время предпросмотра истекло. Выберите файл резервной копии заново.","backup.error.preview_owner_mismatch":"Этот предпросмотр принадлежит другому пользователю Home Assistant.","backup.error.conflict":"После предпросмотра план изменился. Проверьте обновлённую сводку.","backup.error.content_confirmation_required":"Подтвердите отсоединение недоступных локальных файлов.","backup.error.commit_failed":"Не удалось безопасно применить копию. Предыдущий план восстановлен или ожидает восстановления.","backup.error.missing_plan":"После предпросмотра исчез связанный файл плана. Проверьте копию ещё раз.","backup.error.missing_content":"После предпросмотра исчез связанный локальный файл. Проверьте копию ещё раз.","backup.error.marker_control_missing":"В резервной копии отсутствует связанный источник света на плане.","backup.error.marker_control_not_light":"Связанная цель больше не отмечена как источник света.","backup.error.marker_control_self":"Источник света не может управлять самим собой.","backup.error.marker_control_cycle":"Резервная копия содержит циклическую цепочку управления светом.","backup.error.duplicate_marker_control":"Резервная копия содержит повторяющуюся связь с источником света.","backup.error.no_backup":"Нет снимка импорта или оптимизации, который можно восстановить.","backup.error.in_use":"Элемент ещё используется","backup.error.invalid_data":"Запрос содержит некорректные данные","backup.error.invalid_light_entity":"Ведущий свет должен быть сущностью light.* или switch.*","backup.error.invalid_marker_control":"Некорректная ссылка управления маркером","backup.error.invalid_name":"Некорректное имя","backup.error.invalid_partition_opening_host":"Проём должен сохранить свою перегородку-носитель","backup.error.invalid_partition_opening_jamb_margin":"Проём не оставляет физического простенка у края стены","backup.error.invalid_passage_fields":"Открытый проход не может нести настройки двери","backup.error.invalid_space_id":"Неизвестное пространство","backup.error.invalid_toggle_entity":"Сущность переключения должна быть light.* или switch.*","backup.error.invalid_value_badge":"Некорректные настройки бейджа значения","backup.error.invalid_value_badge_attribute":"Некорректный атрибут бейджа значения","backup.error.invalid_value_badge_position":"Некорректная позиция бейджа значения","backup.error.invalid_value_badge_source":"Некорректный источник бейджа значения","backup.error.invalid_vacuum_map_route":"Проверьте сопоставление карт робота пространствам.","backup.error.invalid_value_source":"Некорректный источник значения","backup.error.invalid_value_source_attribute":"Некорректный атрибут источника значения","backup.error.io_error":"Файловая операция на сервере не удалась","backup.error.not_toggleable":"Это устройство нельзя переключить","backup.error.nothing_to_repair":"Нечего чинить","backup.error.space_in_use":"На пространство ещё есть ссылки","backup.error.value_badge_source_required":"Бейджу значения нужен источник","backup.error.wall_model_client_outdated":"План обновлён в другом месте — перезагрузите страницу","backup.same_source":"Создано на этом экземпляре Home Assistant","backup.foreign_source":"Создано на другом экземпляре Home Assistant","backup.created":"Создано: {value}","backup.versions":"Карточка {card}; интеграция {integration}; модель данных {model}","backup.count_spaces":"Пространств: {n}","backup.count_rooms":"Комнат: {n}","backup.count_walls":"Стен: {n}","backup.count_openings":"Проёмов: {n}","backup.count_decor":"Объектов декора: {n}","backup.count_markers":"Устройств: {n}","backup.count_layout":"Позиций: {n}","backup.bindings":"Привязки — устройства: {device}, сущности: {entity}, виртуальные: {virtual}; позиций без пространства: {legacy}","backup.binding_status":"Статус на целевом экземпляре — активных: {active}, деактивированных: {disabled}, отсутствующих: {missing}","backup.missing_areas":"На целевом экземпляре отсутствуют зоны: {areas}","backup.dropped_marker_links":"Связи с источниками света вне переносимого пространства пропущены: {n}.","backup.room_drafts_migrated":"Старые незавершённые контуры преобразованы в обычные стены: {drafts}; отрезков: {segments}.","backup.repaired_target_refs":"Существующих ссылок восстановлено этим импортом: {n}.","backup.preserved_unresolved_refs":"Неоднозначные ссылки сохранены без изменений: {n}.","backup.preserved_unresolved_hint":"House Plan ничего не угадывал и не удалял. После импорта запустите «Оптимизировать планы», чтобы проверить оставшиеся ссылки.","backup.import_details":"Подробности восстановления ссылок","backup.import_detail.incoming_remapped":"Ссылок обновлено внутри импортируемой копии: {n}","backup.import_detail.target_repaired":"Существующих ссылок восстановлено: {n}","backup.import_detail.preserved_unresolved":"Неразрешимых ссылок сохранено: {n}","backup.import_detail.collisions":"Конфликтов назначения безопасно сохранено: {n}","backup.import_detail.dropped_links":"Входящих связей пропущено по правилам переноса: {n}","backup.import_detail.bounded_lineages":"Чрезмерно вложенных идентификаторов ограничено: {n}","backup.replace_warning":"Текущая конфигурация и расположение будут заменены. Загруженные файлы не удаляются. Одну отмену можно выполнить до следующего изменения плана.","backup.foreign_bookkeeping":"Служебные списки известных и новых устройств другого экземпляра импортированы не будут.","backup.final_name":"Название нового пространства","backup.target_settings":"Глобальные настройки целевого экземпляра не изменятся.","backup.duplicates":"Уже существующих привязок: {n}","backup.skip":"Пропустить повторяющиеся устройства","backup.virtual_copy":"Добавить безопасные статичные виртуальные копии","backup.content":"Связанное содержимое","backup.decor_images_summary":"Свои изображения: объектов — {objects}, файлов — {assets}; отсутствует файлов — {missing}.","backup.content_available":"доступно локально","backup.content_external":"внешняя ссылка","backup.content_detach_required":"будет отвязано","backup.confirm_detach":"Я понимаю, что недоступные внутренние планы и вложения будут отвязаны от импортируемой конфигурации.","backup.confirm_missing_images":"Я понимаю, что отсутствующие свои изображения останутся восстанавливаемыми заглушками, а остальные недоступные локальные файлы будут отвязаны.","backup.replace":"Заменить","backup.add":"Добавить пространство","backup.space_done":"Пространство импортировано: комнат — {rooms}, устройств — {markers}, существующих ссылок восстановлено — {refs}","backup.full_done":"Копия восстановлена: пространств — {spaces}, комнат — {rooms}, устройств — {markers}","backup.undo_import":"Отменить последний полный импорт","backup.import_undone":"Полный импорт отменён","backdrop.large_title":"Большое изображение","backdrop.large_body":"Изображение {w}×{h} ({fileMb} МБ), для показа потребуется около {decodedMb} МБ памяти. На планшетах это может привести к падению страницы.","backdrop.unknown_body":"Не удалось прочитать размеры изображения — файл может быть повреждён. Продолжение может привести к падению страницы на планшете.","backdrop.reduced_dimensions":"Уменьшенная копия: {w}×{h} px.","backdrop.use_downscaled":"Загрузить уменьшенную копию","backdrop.reducing":"Уменьшаем…","backdrop.keep_original":"Оставить оригинал","backdrop.too_large_title":"Изображение слишком большое","backdrop.too_large_body":"Изображение превышает возможности браузера ({w}×{h}, предел {limit} px по стороне). Уменьшите его в редакторе на компьютере и загрузите снова.","backdrop.downscale_failed":"Не удалось создать уменьшенную копию. Текущий план не изменён.","gs.card_display":"Отображение","gs.card_zigbee":"Связи Zigbee","gs.card_fills":"Цвета заливки комнат","gs.card_plan":"План","gs.card_data":"Данные","gs.card_fills.help.aria":"О цветах заливки комнат","gs.backup_group.help.aria":"О резервной копии и переносе","gs.grid_group.help.aria":"Об обслуживании плана","gs.backup_group.help":"Скачайте переносимую JSON-копию или проверьте и импортируйте копию, созданную House Plan.","gs.grid_group.help":"Обновляет модели данных, выравнивает элементы по сетке и объединяет лишние фрагменты стен. Перед записью будет показан точный отчёт.","gs.card_fills.help":"Цвета заливок действуют на все пространства; у каждого цвета своя прозрачность. Какой режим заливки использует пространство — задаётся в его диалоге.","space.card_basics":"Основное","space.card_sun":"Солнце и свет","marker.card_basics":"Основное","marker.card_tap":"Действие по нажатию","marker.card_light":"Свет и свечение","marker.card_appearance":"Внешний вид","marker.card_details":"Подробности"}},{code:"de",nativeLabel:"Deutsch",loadDictionary:async function(e){const t=0===e?await import("./de-AkOtg0jq.js"):await import(new URL("./de-AkOtg0jq.js?retry",import.meta.url).href);return{dictionary:t.dictionary,fingerprint:t.fingerprint}}},{code:"fr",nativeLabel:"Français",loadDictionary:async function(e){const t=0===e?await import("./fr-Ds3OdruH.js"):await import(new URL("./fr-Ds3OdruH.js?retry",import.meta.url).href);return{dictionary:t.dictionary,fingerprint:t.fingerprint}}}],_p=lp,mp=new Set;const gp=new class{constructor(e,t,i=console.warn,n){this.entries=e,this.expectedFingerprint=t,this.warn=i,this.loadFailed=n,this.dictionaries=new Map,this.pending=new Map,this.failed=new Set;for(const t of e)t.dictionary&&this.dictionaries.set(t.code,t.dictionary)}state(e){return this.dictionaries.has(e)?"ready":this.failed.has(e)?"fallback":"pending"}dictionary(e){return this.dictionaries.get(e)}ensure(e){if("pending"!==this.state(e))return Promise.resolve();const t=this.pending.get(e);if(t)return t;const i=this.entries.find(t=>t.code===e),n=this.load(i).finally(()=>this.pending.delete(e));return this.pending.set(e,n),n}async load(e){if(!e?.loadDictionary)return void(e&&this.failed.add(e.code));let t;for(const i of[0,1])try{const t=await e.loadDictionary(i);if(t.fingerprint!==this.expectedFingerprint)throw new Error(`locale fingerprint mismatch for ${e.code}`);return this.dictionaries.set(e.code,t.dictionary),void this.failed.delete(e.code)}catch(e){t=e}this.failed.add(e.code),this.warn(`[houseplan] unable to load ${e.code} locale; using English`,t),this.loadFailed?.(e.code)}}(pp,"c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f",console.warn,function(e){for(const t of mp)t(e)});function fp(e){const t=bp(e)?.code??"en";return gp.dictionary(t)??_p}function vp(e){return"string"==typeof e?e.trim().replaceAll("_","-").toLowerCase():""}const yp=new Map(pp.map(e=>[vp(e.code),e]));function bp(e){return yp.get(vp(e))}function wp(e,t){const i=[{value:"",label:e},...pp.map(({code:e,nativeLabel:t})=>({value:e,label:t}))],n="string"==typeof t?t:"";return n&&!i.some(e=>e.value===n)&&i.push({value:n,label:bp(n)?.nativeLabel??n}),i}function kp(e,t){return function(e,t,i,n){const r=new Map(i.map(e=>[vp(e),e])),o=r.get(vp(e));if(o)return o;const s=vp(t),a=r.get(s);return a||(r.get(s.split("-")[0]||"")??n)}(t,e?.locale?.language||e?.language,pp.map(({code:e})=>e),"en")}function xp(e,t,i){return on(fp(e)[t]??_p[t]??t,i)}function Sp(e,t){const i=fp(e)[t]??_p[t];return"string"==typeof i&&i.trim().length>0}function $p(e,t,i,n){return{ox:0,oy:0}}function Mp(e,t){const i=(e.angle+90)*Math.PI/180,n=Wa(16,t),r=e.gateFace?-n*e.gateFace.side:n*(e.flipV?-1:1);return[[e.x+Math.cos(i)*r,e.y+Math.sin(i)*r],r<0]}function Rp(e){const t=e.length/2,i=e.face.cm>0?e.face.cm/e.cellCm*e.gridPitch/2:Wa(4,e.cellCm),n="gate"===e.type?Math.sin(10*Math.PI/180)*t:0;return{half:t,jambHalf:i,gateDepth:n,outlineHalf:Math.max(Wa(16,e.cellCm),i+Wa(8,e.cellCm),n+Wa(8,e.cellCm)),hitHalf:Math.max(Wa(20,e.cellCm),i+Wa(10,e.cellCm),n+Wa(12,e.cellCm))}}function Cp(e,t,i){e.minX=Math.min(e.minX,t),e.minY=Math.min(e.minY,i),e.maxX=Math.max(e.maxX,t),e.maxY=Math.max(e.maxY,i)}function Tp(e,t,i,n,r,o,s,a){const l=Math.min(s,a)*Math.PI/180,c=Math.max(s,a)*Math.PI/180,h=(e,t)=>{const i=Math.atan2(t,e),n=[l,c];for(let e=-3;e<=3;e++){const t=e*Math.PI-i,r=Math.PI/2+e*Math.PI-i;t>l&&tl&&r0&&[e.length,e.angle,t[0],t[1]].every(Number.isFinite)))return null;const{half:i,jambHalf:n}=Rp(e),r=ja(e.cellCm),o=1.75*r,s=1.25*r,a=.75*r,l={minX:-i-s,minY:-n-s,maxX:i+s,maxY:n+s},c={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};if("window"===e.type)Tp(c,-i,0,i,-o,o,-90,0),Tp(c,i,-i,0,-o,o,0,90),Cp(c,-i-a,-i-a),Cp(c,i+a,a);else if("gate"===e.type){const t=10*e.face.side;Tp(c,-i,0,i,-o,o,0,t),Tp(c,i,-i,0,-o,o,-t,0)}else Tp(c,-i,0,e.length,-o,o,-90,0),Cp(c,-i-a,-e.length-a),Cp(c,i+a,a);const[h,d]=Dp(e),u={...l};Cp(u,c.minX+h,c.minY+d),Cp(u,c.maxX+h,c.maxY+d);const p=e.flipH?-1:1,_="gate"===e.type?1:e.flipV?-1:1,m=e.angle*Math.PI/180,g=Math.cos(m),f=Math.sin(m),v={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};for(const e of[u.minX,u.maxX])for(const i of[u.minY,u.maxY]){const n=e*p,r=i*_;Cp(v,t[0]+n*g-r*f,t[1]+n*f+r*g)}return v}function Pp(e){if("passage"===e.type)return W``;const t=Math.max(0,Math.min(1,e.amount)),{half:i,jambHalf:n}=Rp(e),r=ja(e.cellCm),o=1.75*r,s=e.flipH?-1:1,a=e.flipV?-1:1,l="gate"===e.type?1:a,[c,h]=Dp(e);let d;if("window"===e.type){const o=Math.PI/2*i,s=e.face.cm>0?W``)}`}const Cr={color:"#607d8b",opacity:1,widthCm:3.6,fill:!1,fillColor:"#607d8b",fillOpacity:.25},Tr=(e,t=1)=>{const i=Number(e);return Number.isFinite(i)?Math.min(1,Math.max(0,i)):t},Dr=e=>{let t=Number(e);return Number.isFinite(t)?(t=(t%360+360)%360,t>180?t-360:t):0};function Ar(e,t,i){return Dr(t)?[e.x,e.y]:i([e.x,e.y])}function Pr(e,t,i,n){const r=Math.abs(i[0]-t[0]),o=Math.abs(i[1]-t[1]);return"line"===e?Math.hypot(r,o)>=n:r>=n&&o>=n}const Fr=(e,t,i)=>{const n=Number(e),r=Number.isFinite(t)&&t>0?t:5;return Number.isFinite(n)&&n>0?n/r*i:0},zr=(e,t,i)=>{const n=Number(e),r=Number.isFinite(t)&&t>0?t:5;return Number.isFinite(n)&&i>0?n/i*r:0},Ir=(e,t,i,n=Cr.widthCm)=>{const r=Number(e?.width_cm);if(Number.isFinite(r)&&r>0)return r;const o=Number(e?.width);return Number.isFinite(o)&&o>0?zr(o,t,i):n};function Or(e){const t=Cr;return e.color===t.color&&e.opacity===t.opacity&&e.widthCm===t.widthCm&&e.fill===t.fill&&e.fillColor===t.fillColor&&e.fillOpacity===t.fillOpacity?null:{color:e.color,opacity:Tr(e.opacity),width_cm:Math.max(.1,Math.min(100,Number(e.widthCm)||.1)),fill:!!e.fill,fill_color:e.fillColor,fill_opacity:Tr(e.fillOpacity,.25)}}function Er(e,t){return{color:e.color,opacity:Tr(e.opacity),width_cm:Math.max(.1,Math.min(100,Number(e.widthCm)||.1)),...t?{fill:e.fill,fill_color:e.fillColor,fill_opacity:Tr(e.fillOpacity,.25)}:{}}}function Nr(e){const t=e.x+e.w/2,i=e.y+e.h/2,n=Dr(e.angle)*Math.PI/180,r=Math.cos(n),o=Math.sin(n),s=(e,n)=>{const s=e-t,a=n-i;return[t+s*r-a*o,i+s*o+a*r]};return[s(e.x,e.y),s(e.x+e.w,e.y),s(e.x+e.w,e.y+e.h),s(e.x,e.y+e.h)]}function Hr(e){const t=Nr(e),i=(e,t)=>[(e[0]+t[0])/2,(e[1]+t[1])/2],n=[(t[0][0]+t[2][0])/2,(t[0][1]+t[2][1])/2];return{points:[...t,i(t[0],t[1]),i(t[1],t[2]),i(t[2],t[3]),i(t[3],t[0]),n],segments:t.map((e,i)=>({a:e,b:t[(i+1)%4]}))}}function Lr(e,t,i,n,r,o,s,a){const l=Dr(e.angle)*Math.PI/180,c=Math.cos(l),h=Math.sin(l),d=-Math.sin(l),u=Math.cos(l),p=e.x+e.w/2,_=e.y+e.h/2,m=t>0?-e.w/2:e.w/2,g=i>0?-e.h/2:e.h/2,f=p+m*c+g*d,v=_+m*h+g*u,y=n-f,b=r-v;let w=(y*c+b*h)*(t>0?1:-1),k=(y*d+b*u)*(i>0?1:-1),x=null;if(o){const t=w/Math.max(e.w,a),i=k/Math.max(e.h,a);x=Math.max(a/Math.max(e.w,a),a/Math.max(e.h,a),t,i),w=e.w*x,k=e.h*x}if(s>0)if(o){const t=Math.max(1,Math.round(e.w/s)),i=Math.max(1,Math.round(e.h/s));if(Math.abs(e.w-t*s)<1e-6&&Math.abs(e.h-i*s)<1e-6){const n=(e,t)=>{let i=Math.abs(e),n=Math.abs(t);for(;n;)[i,n]=[n,i%n];return Math.max(1,i)},r=1/n(t,i),o=Math.max(a/e.w,a/e.h),s=Math.max(o,Math.round((x??1)/r)*r);w=e.w*s,k=e.h*s}else{e.w>=e.h?(w=Math.round(w/s)*s,k=w*(e.h/Math.max(e.w,a))):(k=Math.round(k/s)*s,w=k*(e.w/Math.max(e.h,a)))}}else w=Math.round(w/s)*s,k=Math.round(k/s)*s;w=Math.max(a,w),k=Math.max(a,k);return{x:f+(t>0?w/2:-w/2)*c+(i>0?k/2:-k/2)*d-w/2,y:v+(t>0?w/2:-w/2)*h+(i>0?k/2:-k/2)*u-k/2,w:w,h:k,angle:Dr(e.angle)||void 0}}const Br=(e,t,i)=>{const n=i[0]-t[0],r=i[1]-t[1],o=n*n+r*r;if(o<1e-12)return[...t];const s=Math.max(0,Math.min(1,((e[0]-t[0])*n+(e[1]-t[1])*r)/o));return[t[0]+n*s,t[1]+r*s]};function qr(e,t,i,n){const r=n(e);let o=null;for(const r of t.points){const t=n(r),s=Math.hypot(t[0]-e[0],t[1]-e[1]);s<=i&&(!o||se.points),segments:e.flatMap(e=>e.segments)}}const Wr=Math.tan(.25*Math.PI/180);function Ur(e,t){const i=Math.abs(Number(t[0])-Number(e[0])),n=Math.abs(Number(t[1])-Number(e[1]));if(!([i,n].every(Number.isFinite)&&i>0&&n>0))return null;const r=i>=n?"horizontal":"vertical",o=Math.max(i,n),s=Math.min(i,n);return s/o>Wr?null:{axis:r,major:o,minor:s,angleDegrees:180*Math.atan2(s,o)/Math.PI}}function Gr(e,t){const i=Ur(e,t);return i?"horizontal"===i.axis?[Number(t[0]),Number(e[1])]:[Number(e[0]),Number(t[1])]:[Number(t[0]),Number(t[1])]}const Vr=e=>`${e[0]},${e[1]}`,Kr=(e,t)=>e[0]===t[0]&&e[1]===t[1],Yr=(e,t)=>{const i=Vr(e),n=Vr(t);return i{let t=0;for(let i=0;i{if(e.length<3)return!1;for(let t=0;t1e-12},Jr=(e,t)=>Kr(e,t.from)?[...t.to]:[...e],Qr=(e,t)=>e.map(e=>Array.isArray(e?.poly)?{...e,poly:e.poly.map(e=>Jr(e,t))}:e),eo=(e,t,i)=>{const n=e.flatMap((e,t)=>ni(e)?.some(e=>Kr(e,i.from))?[t]:[]);if(!n.length)return!1;for(const i of n){const n=ni(e[i]),r=ni(t[i]);if(!n||!r)continue;if(!Zr(r))return!1;const o=Math.sign(Xr(n)),s=Math.sign(Xr(r));if(o&&s&&o!==s)return!1}const r=new Set;for(const e of n){const i=ni(t[e]);if(i)for(let n=0;n{let i=0;for(const n of e){const e=ni(n);if(e)for(let n=0;n{const{a:i,b:n,axis:r}=e,o="horizontal"===r?{from:n,to:[n[0],i[1]]}:{from:n,to:[i[0],n[1]]},s="horizontal"===r?{from:i,to:[i[0],n[1]]}:{from:i,to:[n[0],i[1]]};return[{move:o,preservedDegree:to(t,i)},{move:s,preservedDegree:to(t,n)}].sort((e,t)=>t.preservedDegree-e.preservedDegree||Vr(e.move.to).localeCompare(Vr(t.move.to))||Vr(e.move.from).localeCompare(Vr(t.move.from))).map(e=>e.move)};function no(e){const t=JSON.parse(JSON.stringify(e||{}));let i=Array.isArray(t.rooms)?t.rooms:[];const n=new Map;for(const e of i){const t=ni(e);if(t)for(let e=0;ee.key.localeCompare(t.key))){let t=null;for(const n of io(e,i)){const e=a.get(Vr(n.from));if(e&&e!==Vr(n.to))continue;const r=Qr(i,n);if(eo(i,r,n)){t=n,i=r;break}}t?(a.set(Vr(t.from),Vr(t.to)),r++,s=Math.max(s,Math.hypot(t.to[0]-t.from[0],t.to[1]-t.from[1]))):o++}t.rooms=i;for(const e of t.partitions||[]){if(!Array.isArray(e?.a)||!Array.isArray(e?.b))continue;const i=Ur(e.a,e.b);if(!i)continue;const n={key:String(e.id||Yr(e.a,e.b)),a:[...e.a],b:[...e.b],axis:i.axis};let a=null;for(const i of io(n,[{poly:[e.a,e.b]}])){const n=Jr(e.a,i),r=Jr(e.b,i),o=Math.hypot(r[0]-n[0],r[1]-n[1]);if(!(o>0))continue;const s=(t.openings||[]).filter(t=>"partition"===t?.host?.kind&&t.host.id===e.id).every(e=>{const t=Number(e.host.t),i=Number(e.length);return Number.isFinite(t)&&t>=0&&t<=1&&Number.isFinite(i)&&i>0&&t*o-i/2>=-1e-12&&t*o+i/2<=o+1e-12});if(s){a=i,e.a=n,e.b=r;break}}a?(r++,s=Math.max(s,Math.hypot(a.to[0]-a.from[0],a.to[1]-a.from[1]))):o++}return{space:t,report:{wallsStraightened:r,wallsStraightenSkipped:o,maxStraightenShift:s},changed:r>0}}const ro=["rect","ellipse","furniture","image"],oo=10**9,so=240,ao=1e-4;function lo(e){if(Array.isArray(e))return e.map(e=>lo(e));if(null!==e&&"object"==typeof e){const t={};for(const[i,n]of Object.entries(e))t[i]=lo(n);return t}return e}function co(e){if("number"!=typeof e||!Number.isFinite(e))return e;const t=(e<0||Object.is(e,-0)?-1:1)*(Math.floor(Math.abs(e)*oo+.5)/oo);return 0===t?0:t}function ho(e){if("number"!=typeof e||!Number.isFinite(e))return e;const t=e*so,i=Math.round(t);if(Math.abs(t-i)null!==po(e)):[]}function mo(e){return"string"==typeof e&&ro.includes(e)}function go(e,t){for(const i of t)Object.prototype.hasOwnProperty.call(e,i)&&(e[i]=co(e[i]))}function fo(e,t){for(const i of t)Object.prototype.hasOwnProperty.call(e,i)&&(e[i]=ho(e[i]))}function vo(e){if(Array.isArray(e))for(let t=0;t{for(const r of n){const n=t[r];"number"==typeof n&&Number.isFinite(n)&&i(n,e)}},n=t=>{if(Array.isArray(t))for(let n=0;n{if(Array.isArray(e))for(const t of e)n(t)};for(const i of _o(e.rooms))t(i,["x","y","w","h"]),r(i.poly);for(const t of _o(e.walls))n(t.a),n(t.b);for(const t of _o(e.wall_segments))n(t.a),n(t.b);for(const i of _o(e.openings))t(i,["x","y"]);for(const i of _o(e.decor))"line"===i.kind?t(i,["x1","y1","x2","y2"]):mo(i.kind)?t(i,["x","y","w","h"]):"text"===i.kind&&t(i,["x","y"]);for(const t of _o(e.room_drafts))r(t.points);for(const t of _o(e.partitions))n(t.a),n(t.b);for(const t of _o(e.wall_columns))n(t.center);for(const t of _o(e.open_spans))n(t.a),n(t.b)}const r=po(t);if(!r)return;const o=new Map;if(n)for(const e of _o(n.spaces))null!=e.id&&o.set(String(e.id),e);for(const e of Object.values(r)){const t=po(e);if(!t)continue;const n=null!=t.s&&o.get(String(t.s))||null;for(const e of["x","y"]){const r=t[e];"number"==typeof r&&Number.isFinite(r)&&i(r,n)}}}function wo(e){const t=Number(e?.cell_cm);return t>0?t:5}function ko(e,t={}){const i={canonicalized:0,far:0,maxShift:0,maxShiftCm:0,spaces:[],bySpace:new Map},n=_o(po(e)?.spaces);let r=5;for(const e of n)r=Math.max(r,wo(e));bo(e,t,(e,t)=>{const n=e*so,o=Math.abs(n-Math.round(n)),s=ho(e),a=o>0&&o=ao))return;const l=a&&"number"==typeof s?Math.abs(s-e):0;if(a?i.canonicalized++:i.far++,i.maxShift=Math.max(i.maxShift,l),i.maxShiftCm=Math.max(i.maxShiftCm,l*so*(t?wo(t):r)),!t?.id||!a)return;const c=String(t.id);let h=i.bySpace.get(c);h||(h={spaceId:c,space:String(t.title||c),canonicalized:0,far:0,maxShift:0,maxShiftCm:0},i.bySpace.set(c,h)),h.canonicalized++,h.maxShift=Math.max(h.maxShift,l),h.maxShiftCm=Math.max(h.maxShiftCm,l*so*wo(t))}),i.bySpace.size&&bo(e,t,(e,t)=>{if(!t?.id)return;const n=i.bySpace.get(String(t.id));if(!n)return;const r=e*so;Math.abs(r-Math.round(r))>=ao&&n.far++}),i.spaces=[...i.bySpace.values()];const{bySpace:o,...s}=i;return s}function xo(e){return function(e){const t=e,i=po(t);i&&fo(i,["x","y"]);return t}(lo(e))}function So(e){const t=e,i=po(t);if(!i)return t;for(const e of Object.values(i)){const t=po(e);t&&fo(t,["x","y"])}return t}function $o(e){return Mo(lo(e))}function Mo(e){const t=e,i=po(t);if(!i)return t;for(const e of _o(i.spaces)){go(e,["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"]);for(const t of _o(e.rooms))fo(t,["x","y","w","h"]),yo(t.poly);for(const t of _o(e.walls))vo(t.a),vo(t.b);for(const t of _o(e.wall_segments))vo(t.a),vo(t.b);for(const t of _o(e.openings)){fo(t,["x","y"]),go(t,["angle","length"]);const e=po(t.host);e&&go(e,["t"])}for(const t of _o(e.decor))"line"===t.kind?fo(t,["x1","y1","x2","y2"]):mo(t.kind)?(fo(t,["x","y","w","h"]),go(t,["angle"])):"text"===t.kind&&(fo(t,["x","y"]),go(t,["scale","angle"]));for(const t of _o(e.room_drafts))yo(t.points);for(const t of _o(e.partitions))vo(t.a),vo(t.b);for(const t of _o(e.wall_columns))vo(t.center),"square"===t.shape&&go(t,["angle"]);for(const t of _o(e.open_spans))vo(t.a),vo(t.b)}for(const e of _o(i.markers))go(e,["angle"]);return t}const Ro=15,Co=8;function To(e,t,i,n,r){const o=i[0]-e[0],s=i[1]-e[1],a=Math.hypot(o,s);if(!(a>0)||a<=r+1e-9)return null;const l=o/a,c=s/a,h=t=>{const n=(t[0]-e[0])*l+(t[1]-e[1])*c,o=(r-n)/(a-n);return!Number.isFinite(o)||o<-1e-9||o>1+1e-9?null:[t[0]+(i[0]-t[0])*o,t[1]+(i[1]-t[1])*o]},d=h(t),u=h(n);return d&&u?[[e[0],e[1]],t,d,u,n]:null}const Do=Math.sin(.25*Math.PI/180);function Ao(e,t){return Number.isFinite(e)&&e>0&&Number.isFinite(t)&&t>0&&e*t<3}function Po(e){const t=Number(e)>0?Number(e):5;if(5===t)return 8;const i=5/t*8;return Math.min(80,Math.max(.5,i))}function Fo(e,t){return Number.isFinite(e)&&e>0&&Number.isFinite(t)&&t>0&&e*t<2}function zo(e){return Number.isFinite(e)?Math.max(1,Math.min(100,e)):1}function Io(e,t){return!Number.isFinite(e)||e<0?"":String(t?Math.round(e/2.54*100)/100:Math.round(100*e)/100)}function Oo(e,t,i){if(!Number.isFinite(e)||e<=0)return 0;const n=Number(t)>0?Number(t):5;return zo(e)/n*i}function Eo(e,t){return t>0&&Number.isFinite(e)?Math.round(e/t)*t:e}function No(e){return Math.max(1e-6*Math.abs(e),1e-9)}function Ho(e,t){if(!(t>0&&Number.isFinite(e)))return e;const i=Eo(e,t);return Math.abs(i-e)<=No(t)?i:e}function Lo(e,t){let i=t[0]-e[0],n=t[1]-e[1];const r=Math.hypot(i,n);return r<1e-12?[1,0]:(i/=r,n/=r,(i<-1e-12||Math.abs(i)<=1e-12&&n<0)&&(i=-i,n=-n),[i,n])}function Bo(e,t,i){const n=[Ho(e[0],i),Ho(e[1],i)],r=[Ho(t[0],i),Ho(t[1],i)],o=Eo((n[0]+r[0])/2,i),s=Eo((n[1]+r[1])/2,i),[a,l]=Lo(n,r);let c=Math.atan2(l,a);c<0&&(c+=Math.PI);const h=Math.round(1800*c)/1800,d=i>0&&i<.01?6:i<1?4:2;return`${o.toFixed(d)},${s.toFixed(d)}@${h.toFixed(4)}`}function qo(e,t,i,n){return 1===n?Bo(e,t,i):Bo([e[0]/n,e[1]/n],[t[0]/n,t[1]/n],i)}function jo(e,t){if(!Array.isArray(e.a)||!Array.isArray(e.b)||e.a.length<2||e.b.length<2)return null;const i=[Number(e.a[0]),Number(e.a[1]),Number(e.b[0]),Number(e.b[1])];if(!i.every(Number.isFinite))return null;const n=t>0?t:1;return[[i[0]*n,i[1]*n],[i[2]*n,i[3]*n]]}function Wo(e,t,i,n,r){const o=r>0?r:1;return{key:qo(e,t,n,o),cm:zo(i),a:[e[0]/o,e[1]/o],b:[t[0]/o,t[1]/o]}}function Uo(e,t){const i=t>0?t:1,n=[];for(const t of e){const e=t.key.lastIndexOf("@");if(e<0)continue;const[r,o]=t.key.slice(0,e).split(",").map(Number),s=Number(t.key.slice(e+1));[r,o,s].every(Number.isFinite)&&n.push({w:t,x:r*i,y:o*i,ang:s})}return n}function Go(e,t){const[i,n]=Lo(e,t);let r=Math.atan2(n,i);return r<0&&(r+=Math.PI),r}function Vo(e,t){let i=Math.abs(e-t);return i>Math.PI/2&&(i=Math.PI-i),i<.02}function Ko(e,t,i,n,r=1){if(!e?.length)return null;const o=qo(t,i,n,r),s=e.find(e=>e.key===o);if(s)return s;const a=r>0?r:1,l=No(n)*a,c=(e,t)=>Math.abs(e[0]-t[0])<=l&&Math.abs(e[1]-t[1])<=l;for(const n of e){const e=jo(n,a);if(e&&(c(e[0],t)&&c(e[1],i)||c(e[0],i)&&c(e[1],t)))return n}const h=(t[0]+i[0])/2,d=(t[1]+i[1])/2,u=Go(t,i),p=Math.max(.5*n,1e-9)*a;for(const t of Uo(e,a))if(Vo(t.ang,u)&&Math.hypot(t.x-h,t.y-d)<=p)return t.w;return null}function Yo(e,t,i,n,r=1){const o=Ko(e,t,i,n,r);if(o&&o.cm>0)return zo(o.cm);const s=function(e,t,i,n,r){if(!e?.length)return null;const o=r>0?r:1,s=Math.hypot(i[0]-t[0],i[1]-t[1]);if(s<1e-12)return null;const a=Go(t,i),l=Math.max(.5*n,1e-9)*o;let c=null;for(const n of e){if(!(n.cm>0))continue;const e=jo(n,o);if(!e)continue;const r=Math.hypot(e[1][0]-e[0][0],e[1][1]-e[0][1]);if(r<1e-12||!Vo(Go(e[0],e[1]),a))continue;if(Ns(t[0],t[1],e[0][0],e[0][1],e[1][0],e[1][1])>l||Ns(i[0],i[1],e[0][0],e[0][1],e[1][0],e[1][1])>l)continue;if(r+l(o.has(e.key)||(e=>{const t=jo(e,n);if(!t)return!1;const[i,o]=t,a=o[0]-i[0],c=o[1]-i[1],h=Math.hypot(a,c);if(h<=l)return!1;if(!s.some(e=>{const t=[e[0],e[1]],n=[e[2],e[3]];return Vo(Go(i,o),Go(t,n))&&Ns(i[0],i[1],t[0],t[1],n[0],n[1])<=l&&Ns(o[0],o[1],t[0],t[1],n[0],n[1])<=l}))return!1;const d=(r||[]).some(e=>{const t=[e[0],e[1]],n=[e[2],e[3]];if(!Vo(Go(i,o),Go(t,n)))return!1;const r=e=>Math.abs((e[0]-i[0])*c-(e[1]-i[1])*a)/h;if(r(t)>l||r(n)>l)return!1;const s=h*h,d=((t[0]-i[0])*a+(t[1]-i[1])*c)/s,u=((n[0]-i[0])*a+(n[1]-i[1])*c)/s;return Math.min(1,Math.max(d,u))-Math.max(0,Math.min(d,u))>l/h});return!d})(e))&&e.cm>=1&&e.cm<=100)}function Zo(e,t,i,n=8){const[r,o]=Lo(e,t);let s=Math.atan2(o,r);s<0&&(s+=Math.PI);let a=i*Math.PI/180%Math.PI;a<0&&(a+=Math.PI);let l=Math.abs(s-a);return l>Math.PI/2&&(l=Math.PI-l),l<=n*Math.PI/180}function Jo(e,t,i,n,r=1,o="affine",s){if(!e?.length)return[];if(t.length!==i.length)return"fixed-topology"===o&&s?.(),e.slice();const a=r>0?r:1,l=Math.max(.5*n,1e-9)*a,c=Math.max(n*a*1e-6,1e-9),h=[],d=new Map,u=new Map,p=(e,t,i)=>{const n=e.get(t)||new Set;n.add(i),e.set(t,n)};for(let e=0;e[e[0]+(t[0]-e[0])*i,e[1]+(t[1]-e[1])*i],m=(e,t)=>Math.hypot(e[0]-t[0],e[1]-t[1])<=c,g=(e,t)=>{if("fixed-topology"===o){const i=t.na[0]-t.oa[0],n=t.na[1]-t.oa[1],r=t.nb[0]-t.ob[0],o=t.nb[1]-t.ob[1];return Math.hypot(i-r,n-o)<=c?[e[0]+i,e[1]+n]:m(e,t.oa)?[...t.na]:m(e,t.ob)?[...t.nb]:[...e]}const i=Math.max(0,Math.min(1,((e[0]-t.oa[0])*t.dx+(e[1]-t.oa[1])*t.dy)/t.len2));return _(t.na,t.nb,i)},f=(e,t)=>{const[i,n]=Lo(e,t);return(t[0]-e[0])*i+(t[1]-e[1])*n>=0?[[...e],[...t]]:[[...t],[...e]]},v=[],y=[],b=(e,t,i)=>{if(Math.hypot(t[0]-e[0],t[1]-e[1])<=c)return;const[r,o]=f(e,t),s=zo(i);if(y.some(e=>e.entry.cm===s&&m(e.span[0],r)&&m(e.span[1],o)))return;const l=Wo(r,o,s,n,a);v.push(l),y.push({entry:l,span:[r,o]})};for(const t of e){const e=jo(t,a);if(e){const[i,n]=f(e[0],e[1]),r=n[0]-i[0],s=n[1]-i[1],a=r*r+s*s,d=Math.sqrt(a);if(d<=c){v.push({...t,cm:zo(t.cm)});continue}const u=[];for(const e of h){if(!Vo(Go(i,n),Go(e.oa,e.ob)))continue;const t=e=>Math.abs((e[0]-i[0])*s-(e[1]-i[1])*r)/d;if(t(e.oa)>l||t(e.ob)>l)continue;const o=((e.oa[0]-i[0])*r+(e.oa[1]-i[1])*s)/a,h=((e.ob[0]-i[0])*r+(e.ob[1]-i[1])*s)/a,p=Math.max(0,Math.min(o,h)),_=Math.min(1,Math.max(o,h));(_-p)*d>c&&u.push({lo:p,hi:_,move:e})}if(!u.length){"fixed-topology"===o?v.push({...t}):b(i,n,t.cm);continue}const p=[0,1,...u.flatMap(({lo:e,hi:t})=>[e,t])].sort((e,t)=>e-t).filter((e,t,i)=>0===t||Math.abs(e-i[t-1])*d>c),y=[];for(let e=0;e+1a>=e.lo-1e-12&&a<=e.hi+1e-12);if(!l.length){y.push([o,s]);continue}const h=[g(o,l[0].move),g(s,l[0].move)],f=l.slice(1).some(e=>{const t=g(o,e.move),i=g(s,e.move);return!m(h[0],t)||!m(h[1],i)});y.push(f?[o,s]:h)}const w=(e,t)=>{const i=e[1][0]-e[0][0],n=e[1][1]-e[0][1],r=t[1][0]-t[0][0],o=t[1][1]-t[0][1],s=Math.hypot(i,n);return!(s<=c||i*r+n*o<=0)&&Math.abs(i*o-n*r)/s<=c},k=[];for(const e of y){const t=k[k.length-1];t&&m(t[1],e[0])&&w(t,e)?t[1]=e[1]:k.push([[...e[0]],[...e[1]]])}if("fixed-topology"===o&&1===k.length){const[i,n]=k[0];if(m(i,e[0])&&m(n,e[1])||m(i,e[1])&&m(n,e[0])){v.push({...t});continue}}for(const[e,i]of k)b(e,i,t.cm);continue}if("fixed-topology"===o){const e=u.get(t.key);if(1===e?.size){const i=[...e][0];v.push(i===t.key?{...t}:{...t,key:i});continue}const i=[Uo([t],a)[0]];1!==a&&i.push(Uo([t],1)[0]);const n=i.filter(Boolean).some(e=>h.some(t=>{if(!Vo(e.ang,Go(t.oa,t.ob)))return!1;const i=((e.x-t.oa[0])*t.dx+(e.y-t.oa[1])*t.dy)/t.len2;return i>=-1e-6&&i<=1.000001&&Ns(e.x,e.y,t.oa[0],t.oa[1],t.ob[0],t.ob[1])<=l}));((e?.size||0)>1||n)&&s?.(),v.push({...t});continue}let i="";const r=d.get(t.key);if(1===r?.size&&(i=[...r][0]),!i){const e=Uo([t],a)[0];if(e){const t=new Set;for(const i of h){if(!Vo(e.ang,Go(i.oa,i.ob)))continue;const r=((e.x-i.oa[0])*i.dx+(e.y-i.oa[1])*i.dy)/i.len2;if(r<-1e-6||r>1.000001)continue;if(Ns(e.x,e.y,i.oa[0],i.oa[1],i.ob[0],i.ob[1])>l)continue;const o=g([e.x,e.y],i),[s,c]=Lo(i.na,i.nb),h=Math.max(n*a,1e-6);t.add(qo([o[0]-s*h,o[1]-c*h],[o[0]+s*h,o[1]+c*h],n,a))}1===t.size&&(i=[...t][0])}}v.push({...t,key:i||t.key,cm:zo(t.cm)})}return v}function Qo(e,t,i,n,r=1,o="affine"){return Jo(e,t,i,n,r,o)}function es(e,t,i,n,r=1,o="fixed-topology"){let s=!1;const a=Jo(e,t,i,n,r,o,()=>{s=!0});return{walls:s?(e||[]).map(e=>({...e})):a,rejected:s}}function ts(e,t,i,n=1,r=[]){const o=n>0?n:1,s=Math.abs(i),a=Math.max(s*o*ao,1e-9),l=(r||[]).flatMap(e=>{const t=jo(e,o);return t?t.map(e=>[...e]):[]}),c=e=>e.every((e,t)=>(e=>{if(!(s>0))return!0;const t=e/o/s;return Math.abs(t-Math.round(t))Math.abs(e-i[t])<=a)),h=[],d=e=>JSON.stringify([e.key,e.cm,e.a,e.b]);for(const i of e||[]){const e=jo(i,o);if(!e)continue;const[n,r]=e;if(![n[0],n[1],r[0],r[1]].every(Number.isFinite)||!c(n)||!c(r)){h.push(d(i));continue}const s=r[0]-n[0],l=r[1]-n[1],u=Math.hypot(s,l);if(u<=a){h.push(d(i));continue}const p=s/u,_=l/u,m=[];for(const e of t){const[t,i]=e;if(![t?.[0],t?.[1],i?.[0],i?.[1]].every(Number.isFinite))continue;const r=e=>Math.abs((e[0]-n[0])*_-(e[1]-n[1])*p);if(r(t)>a||r(i)>a)continue;const o=(t[0]-n[0])*p+(t[1]-n[1])*_,s=(i[0]-n[0])*p+(i[1]-n[1])*_,l=Math.max(0,Math.min(o,s)),c=Math.min(u,Math.max(o,s));c-l>a&&m.push([l,c])}m.sort((e,t)=>e[0]-t[0]||e[1]-t[1]);let g=0;for(const[e,t]of m){if(e>g+a)break;if(g=Math.max(g,t),g>=u-a)break}ge.key!==s);return null==n||n<1?a:[...a,Wo(t,i,n,r,o)]}function ns(e,t,i,n,r,o=[],s=1){let a=e?e.slice():[];for(const e of function(e,t,i,n,r=1,o=[]){const s=Ss(e,t,i,n,r,o);if(!s)return[];const a=[];for(let e=0;e0||(c=is(c,t,i,n,r,s)))}return c}function os(e){const{a:t,b:i,halfDepth:n}=e;if(!Array.isArray(t)||!Array.isArray(i)||t.length<2||i.length<2||![t[0],t[1],i[0],i[1]].every(Number.isFinite))return null;const r=i[0]-t[0],o=i[1]-t[1],s=Math.hypot(r,o);if(!(s>1e-9&&n>0&&Number.isFinite(n)))return null;const a=-o/s*n,l=r/s*n;return[[t[0]+a,t[1]+l],[i[0]+a,i[1]+l],[i[0]-a,i[1]-l],[t[0]-a,t[1]-l]]}function ss(e,t,i){return Math.hypot(e[0]-t[0],e[1]-t[1])<=i}function as(e,t,i){const n=t.b[0]-t.a[0],r=t.b[1]-t.a[1],o=n*n+r*r;if(!(o>i*i))return!1;const s=((e[0]-t.a[0])*n+(e[1]-t.a[1])*r)/o;if(!(s>0&&s<1))return!1;const a=[t.a[0]+n*s,t.a[1]+r*s];return Math.hypot(e[0]-a[0],e[1]-a[1])<=i}function ls(e,t,i,n){const r=Math.hypot(t,i);if(!(r>1e-9&&n>0))return;const o=[t/r,i/r],s=e.find(e=>Math.abs(e.u[0]*o[1]-e.u[1]*o[0])<1e-9&&e.u[0]*o[0]+e.u[1]*o[1]>1-1e-9);s?s.halfDepth=Math.max(s.halfDepth,n):e.push({u:o,halfDepth:n})}function cs(e,t){try{const i=Gt(Bs(e),Bs(t));let n=null,r=0;for(const e of i||[]){const t=e?.[0]||[],i=Math.abs(ms(t));t.length>=4&&i>r&&(r=i,n=t.slice(0,-1).map(e=>[e[0],e[1]]))}return n}catch{return null}}function hs(e,t=1e-6){const i=(e||[]).map((e,t)=>({segment:e,index:t})).filter(({segment:e})=>e&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&e.a.every(Number.isFinite)&&e.b.every(Number.isFinite)&&Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>1e-9);if(i.length<2)return[];const n=Math.max(Number.isFinite(t)?t:0,1e-9),r=i.flatMap(({segment:e})=>[e.a,e.b]).map(e=>[e[0],e[1]]).sort((e,t)=>e[0]-t[0]||e[1]-t[1]),o=[];for(const e of r)o.some(t=>ss(t,e,n))||o.push(e);const s=[];for(const e of o){const t=[];let r=!1;for(const{segment:o,index:s}of i){const i=Math.hypot(o.b[0]-o.a[0],o.b[1]-o.a[1]);ss(e,o.a,n)?t.push({u:[(o.b[0]-o.a[0])/i,(o.b[1]-o.a[1])/i],halfDepth:o.halfDepth,length:i,index:s}):ss(e,o.b,n)?t.push({u:[(o.a[0]-o.b[0])/i,(o.a[1]-o.b[1])/i],halfDepth:o.halfDepth,length:i,index:s}):as(e,o,n)&&(r=!0)}if(r||2!==t.length)continue;const[o,a]=t,l=o.u[0]*a.u[1]-o.u[1]*a.u[0];if(Math.abs(l)<1e-9)continue;const c=l<0?1:-1,h=[-o.u[1],o.u[0]],d=[-a.u[1],a.u[0]],u=[e[0]+h[0]*o.halfDepth*c,e[1]+h[1]*o.halfDepth*c],p=[e[0]-d[0]*a.halfDepth*c,e[1]-d[1]*a.halfDepth*c];if(!vs(u,o.u,p,a.u))continue;const _=[[o,a,p,[d[0]*-c,d[1]*-c]],[a,o,u,[h[0]*c,h[1]*c]]];for(const[t,,i,r]of _){const o=Math.min(2*t.halfDepth,t.length),a=[-t.u[1]*t.halfDepth,t.u[0]*t.halfDepth],l=[[e[0]+a[0],e[1]+a[1]],[e[0]+t.u[0]*o+a[0],e[1]+t.u[1]*o+a[1]],[e[0]+t.u[0]*o-a[0],e[1]+t.u[1]*o-a[1]],[e[0]-a[0],e[1]-a[1]]],c=e=>(e[0]-i[0])*r[0]+(e[1]-i[1])*r[1],h=[];for(let e=0;e=-1e-12&&h.push(t),n>1e-12&&r<-1e-12||n<-1e-12&&r>1e-12){const e=n/(n-r);h.push([t[0]+(i[0]-t[0])*e,t[1]+(i[1]-t[1])*e])}}h.length>=3&&Math.abs(ms(h))>n*n&&s.push({segmentIndex:t.index,wedge:h})}}return s}function ds(e,t=1e-6){const i=(e||[]).filter(e=>e&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&e.a.every(Number.isFinite)&&e.b.every(Number.isFinite)&&Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>1e-9);if(i.length<2)return[];const n=Math.max(Number.isFinite(t)?t:0,1e-9),r=i.flatMap(e=>[e.a,e.b]).map(e=>[e[0],e[1]]).sort((e,t)=>e[0]-t[0]||e[1]-t[1]),o=[];for(const e of r)o.some(t=>ss(t,e,n))||o.push(e);const s=[],a=i.map((e,t)=>({roomId:"",a:[e.a[0],e.a[1]],b:[e.b[0],e.b[1]],key:`join-${t}`,kind:"outer",cm:0,open:!1,half:e.halfDepth})),l=Ts(a,n);for(const e of Ds(l).fans)s.push(e);const c=e=>!!As(l,e);for(const e of o){if(c(e))continue;const t=[];for(const r of i)ss(e,r.a,n)?ls(t,r.b[0]-r.a[0],r.b[1]-r.a[1],r.halfDepth):ss(e,r.b,n)?ls(t,r.a[0]-r.b[0],r.a[1]-r.b[1],r.halfDepth):as(e,r,n)&&(ls(t,r.a[0]-e[0],r.a[1]-e[1],r.halfDepth),ls(t,r.b[0]-e[0],r.b[1]-e[1],r.halfDepth));if(!(t.length<2)){t.sort((e,t)=>Math.atan2(e.u[1],e.u[0])-Math.atan2(t.u[1],t.u[0])||e.halfDepth-t.halfDepth);for(let i=0;in*n&&s.push(m)}}}return s}function us(e,t,i,n){if(!(t>0)||!e||e.length<2)return"";if(i&&e.length>=3){let i=e;const r=e[e.length-1];if(e.length>=4&&Math.hypot(e[0][0]-r[0],e[0][1]-r[1])<1e-9&&(i=e.slice(0,-1)),i.length>=3){const e=i.map((e,i)=>n?.[i]||t),r=aa(i,e),o=ws(i,e);if(r&&o)return`${ks(r)} ${ks(xs(o))}`}}const r=[];for(let i=0;i=1e-9&&a>0&&r.push({a:o,b:s,halfDepth:a})}const o=r.map(os);for(const{segmentIndex:e,wedge:t}of hs(r)){const i=o[e];if(!i)continue;const n=cs(i,t);n&&(o[e]=n)}const s=[...o.filter(e=>!!e),...ds(r)],a=function(e){let t=null;try{for(const i of e){if(i.length<3)continue;const e=Bs(i);t=t?Wt(t,e):[e]}return t}catch{return null}}(s);return a?Qs(a):s.map(e=>ks(e)).join(" ")}function ps(e,t,i,n,r=1){if(!i.length)return!1;const o=_s(n,r),s=(e[0]+t[0])/2,a=(e[1]+t[1])/2,[l,c]=Lo(e,t);for(const e of i){const[t,i]=Lo([e[0],e[1]],[e[2],e[3]]);if(!(Math.abs(l*i-c*t)>.05)&&Ns(s,a,e[0],e[1],e[2],e[3])<=o)return!0}return!1}function _s(e,t){return Math.max(e*(t>0?t:1)*.04,1e-9)}function ms(e){let t=0;for(let i=0;ie[1]!=l>e[1]&&e[0]<(a-o)*(e[1]-s)/(l-s+0)+o&&(i=!i)}return i}([c[0]+.001*a,c[1]+.001*l],e)||(a=-a,l=-l),[a,l]}function fs(e,t){const i=e[0]*t[1]-e[1]*t[0],n=e[0]*t[0]+e[1]*t[1];return Math.abs(i)<1e-9&&n>0}function vs(e,t,i,n){const r=t[0]*n[1]-t[1]*n[0];if(Math.abs(r)<1e-12)return null;const o=[i[0]-e[0],i[1]-e[1]],s=(o[0]*n[1]-o[1]*n[0])/r;return[e[0]+s*t[0],e[1]+s*t[1]]}function ys(e,t,i){const n=e?.length||0;if(n<3||!Array.isArray(i)||i.length!==n)return 0;const r=(Math.trunc(t)%n+n)%n,o=e[r],s=e[(r+1)%n],a=s[0]-o[0],l=s[1]-o[1],c=Math.hypot(a,l);if(!(c>0))return 0;const h=Math.max(0,Number(i[r])||0);if(!(h>0))return c;const d=[a/c,l/c],u=gs(e,r),p=[o[0]+u[0]*h,o[1]+u[1]*h],_=t=>{const r=Math.max(0,Number(i[t])||0);if(!(r>0))return null;const s=e[t],a=e[(t+1)%n],l=a[0]-s[0],c=a[1]-s[1],h=Math.hypot(l,c);if(!(h>0))return null;const u=gs(e,t),_=vs(p,d,[s[0]+u[0]*r,s[1]+u[1]*r],[l/h,c/h]);return _?(_[0]-o[0])*d[0]+(_[1]-o[1])*d[1]:null},m=_((r-1+n)%n)??0,g=(_((r+1)%n)??c)-m;return g>0?g:0}function bs(e,t,i,n,r,o,s,a=1){const l=(e||[]).find(e=>e?.id===t),c=ni(l);if(!c||c.length<3)return null;const h=Fs(e,t,i,n,r,o,s,a);if(!h)return c.map(()=>0);const d=4*_s(r,a);return c.map((e,t)=>{const i=c[(t+1)%c.length],n=[(e[0]+i[0])/2,(e[1]+i[1])/2];for(let e=0;e!(e>0)))return e.map(e=>[e[0],e[1]]);const r=[];for(let o=0;o0||u>0)){r.push([e[o][0],e[o][1]]);continue}if(d>0!=u>0){const t=e[o],i=d>0?[t[0]+p*d,t[1]+_*d]:[t[0],t[1]],n=u>0?[t[0]+m*u,t[1]+g*u]:[t[0],t[1]];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}if(fs(w,k)){const t=e[o],i=[t[0]+p*d,t[1]+_*d],n=[t[0]+m*u,t[1]+g*u];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}const $=vs(x,w,S,k),M=Math.max(d,u,1e-9),R=As(i,e[o])?.limit??4*M;if($){const i=Math.hypot($[0]-e[o][0],$[1]-e[o][1]);if(Number.isFinite(i)&&i<=R){r.push($);continue}if(ta(e,t,o)){r.push($);continue}}d>0&&r.push([e[o][0]+p*d,e[o][1]+_*d]),u>0&&r.push([e[o][0]+m*u,e[o][1]+g*u]),d>0||u>0||r.push([e[o][0],e[o][1]])}return r.length>=3?r:null}function ks(e,t=!0){if(!e.length)return"";let i=`M ${e[0][0]} ${e[0][1]}`;for(let t=1;te?.id===t),a=ni(s);if(!a||a.length<3)return null;const l=_s(n,r),c=[];for(const i of e||[]){if(!i||i.id===t)continue;const e=ni(i);if(e)for(const t of Fn(a,e,l))c.push([t[0],t[1]],[t[2],t[3]])}for(const e of i||[])c.push([e[0],e[1]],[e[2],e[3]]);for(const e of o||[]){const t=jo(e,r);t&&c.push(t[0],t[1])}const h=[],d=[];for(let e=0;el)continue;const s=((e[0]-t[0])*(i[0]-t[0])+(e[1]-t[1])*(i[1]-t[1]))/(n*n);s<=r||s>=1-r||(o.some(e=>Math.abs(e-s)*n<=2*l)||o.push(s))}o.sort((e,t)=>e-t);for(const n of o)h.push([t[0]+(i[0]-t[0])*n,t[1]+(i[1]-t[1])*n]),d.push(e)}return{poly:h,parent:d,orig:a}}function $s(e,t,i,n){const r=t.poly.length,o=new Array(r).fill(0);if(!e?.length)return o;const s=new Set,a=[];for(let l=0;l0?(o[l]=zo(c.cm),s.add(c.key)):a.push(l)}if(!a.length)return o;const l=n>0?n:1,c=Math.max(.5*i,1e-9)*l,h=Uo(e,l).filter(e=>e.w.cm>0);for(let e=a.length-1;e>=0;e--){const i=a[e],n=t.poly[i],s=t.poly[(i+1)%r],d=Go(n,s);let u=null;for(const e of h){const t=jo(e.w,l);if(!t||!Vo(Go(t[0],t[1]),d))continue;if(Ns(n[0],n[1],t[0][0],t[0][1],t[1][0],t[1][1])>c||Ns(s[0],s[1],t[0][0],t[0][1],t[1][0],t[1][1])>c)continue;const i=Math.hypot(s[0]-n[0],s[1]-n[1]),r=Math.hypot(t[1][0]-t[0][0],t[1][1]-t[0][1]),o=Math.max(0,r-i);(!u||oc||Ns(r[0],r[1],t[0][0],t[0][1],t[1][0],t[1][1])>c)continue;i=!0,o=Math.max(0,Math.hypot(t[1][0]-t[0][0],t[1][1]-t[0][1])-_)}else{if(Ns(e.x,e.y,n[0],n[1],r[0],r[1])>c)continue;o=Math.hypot(e.x-d,e.y-u)}(!p||i&&!p.exact||i===p.exact&&o0?i:1,o=(e||[]).filter(e=>e&&!e.open&&null!==e.kind&&Number.isFinite(e.half)&&e.half>0&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&[e.a[0],e.a[1],e.b[0],e.b[1]].every(Number.isFinite)&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>n).sort((e,t)=>e.key.localeCompare(t.key)||e.a[0]-t.a[0]||e.a[1]-t.a[1]||e.b[0]-t.b[0]||e.b[1]-t.b[1]||e.half-t.half),s=new Map;for(const e of o){const t=s.get(e.key);t?e.half>t.half&&s.set(e.key,{...t,half:e.half}):s.set(e.key,e)}const a=[...s.values()].flatMap(e=>[{point:[e.a[0],e.a[1]],other:e.b,halfDepth:e.half,kind:e.kind,key:e.key},{point:[e.b[0],e.b[1]],other:e.a,halfDepth:e.half,kind:e.kind,key:e.key}]).sort((e,t)=>e.point[0]-t.point[0]||e.point[1]-t.point[1]||e.other[0]-t.other[0]||e.other[1]-t.other[1]||e.halfDepth-t.halfDepth),l=new Map;for(const e of a){const[t,i]=Ms(e.point,n),r=Rs(t,i),o=l.get(r)||[];o.push(e),l.set(r,o)}const c=[],h=new Map;for(const e of a){const t=Cs(h,e.point,n).filter(t=>Math.hypot(t.point[0]-e.point[0],t.point[1]-e.point[1])<=n).sort((t,i)=>Math.hypot(t.point[0]-e.point[0],t.point[1]-e.point[1])-Math.hypot(i.point[0]-e.point[0],i.point[1]-e.point[1])||t.point[0]-i.point[0]||t.point[1]-i.point[1]);let i=t[0];if(!i){i={point:[...e.point],rays:[]},c.push(i);const[t,r]=Ms(i.point,n),o=Rs(t,r),s=h.get(o)||[];s.push(i),h.set(o,s)}const r=e.other[0]-e.point[0],o=e.other[1]-e.point[1],s=Math.hypot(r,o);if(!(s>n))continue;const a=[r/s,o/s];let l=Math.atan2(a[1],a[0]);l<0&&(l+=2*Math.PI),i.rays.push({u:a,halfDepth:e.halfDepth,length:s,angle:l})}const d=[],u=e=>{const t=1e-9*Math.max(1,r),i=e.filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Number.isFinite(e.length)&&e.length>n);return i.filter((e,n)=>!i.some((i,r)=>r!==n&&i.halfDepth>=e.halfDepth-t&&i.length>=e.length-t&&(i.halfDepth>e.halfDepth+t||i.length>e.length+t||re.length-t.length||e.halfDepth-t.halfDepth).map(e=>({...e}))};for(const e of c){const t=e.rays.sort((e,t)=>e.angle-t.angle||e.length-t.length||e.halfDepth-t.halfDepth),i=[];for(const e of t){const t=i[i.length-1];t&&Math.abs(e.angle-t.angle)<=1e-9?t.supports.push({halfDepth:e.halfDepth,length:e.length}):i.push({u:[...e.u],angle:e.angle,supports:[{halfDepth:e.halfDepth,length:e.length}]})}if(i.length>1&&2*Math.PI-i[i.length-1].angle+i[0].angle<=1e-9){const e=i.pop();i[0].supports.push(...e.supports)}if(i.length<3)continue;const r=i.map(t=>{const i=u(t.supports),r=new Set,o=[];for(const s of i){const i=[e.point[0]+t.u[0]*s.length,e.point[1]+t.u[1]*s.length];for(const t of Cs(l,i,n)){if("shared"!==t.kind||Math.hypot(t.point[0]-i[0],t.point[1]-i[1])>n)continue;const s=t.other[0]-t.point[0],a=t.other[1]-t.point[1],l=Math.hypot(s,a);if(!(l>n))continue;const c=s/l,h=a/l;if(Math.hypot(t.other[0]-e.point[0],t.other[1]-e.point[1])<=n)continue;const d=`${t.key}|${t.point[0]}|${t.point[1]}|${t.other[0]}|${t.other[1]}|${t.halfDepth}`;r.has(d)||(r.add(d),o.push({start:[t.point[0],t.point[1]],u:[c,h],length:l,halfDepth:t.halfDepth}))}}return o.sort((e,t)=>e.start[0]-t.start[0]||e.start[1]-t.start[1]||e.u[0]-t.u[0]||e.u[1]-t.u[1]||e.length-t.length||e.halfDepth-t.halfDepth),{u:[...t.u],halfDepth:Math.max(...i.map(e=>e.halfDepth)),length:Math.max(...i.map(e=>e.length)),supports:i,continuations:o}}).filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Number.isFinite(e.length)&&e.length>n);if(r.length<3)continue;const o=Math.max(...r.map(e=>e.halfDepth));o>0&&Number.isFinite(o)&&d.push({point:[...e.point],rays:r,halfDepth:o,limit:1.25*o})}d.sort((e,t)=>e.point[0]-t.point[0]||e.point[1]-t.point[1]);const p=new Map;for(const e of d){const[t,i]=Ms(e.point,n),r=Rs(t,i),o=p.get(r)||[];o.push(e),p.set(r,o)}return{epsilon:n,coordinateScale:r,nodes:d,index:p}}function Ds(e){const t={fans:[],supports:[]};if(!e?.nodes?.length)return t;const i=Math.max(e.epsilon,1e-9)**2;for(const n of e.nodes){const e=n.rays.filter(e=>Number.isFinite(e.halfDepth)&&e.halfDepth>0).map(e=>({...e,thickLength:Math.max(...e.supports.filter(t=>t.halfDepth>=e.halfDepth-1e-12).map(e=>e.length),0),angle:(()=>{const t=Math.atan2(e.u[1],e.u[0]);return t<0?t+2*Math.PI:t})()})).sort((e,t)=>e.angle-t.angle);if(e.length<2)continue;const r=n.point;for(const i of e)for(const e of i.supports){if(!(e.halfDepth>0&&e.length>0))continue;const n=-i.u[1]*e.halfDepth,o=i.u[0]*e.halfDepth,s=[r[0]+i.u[0]*e.length,r[1]+i.u[1]*e.length];t.supports.push([[r[0]+n,r[1]+o],[s[0]+n,s[1]+o],[s[0]-n,s[1]-o],[r[0]-n,r[1]-o]])}for(let n=0;n{const e=s.angle-o.angle;return e>0?e:e+2*Math.PI})();if(a<1e-9)continue;const l=a>Math.PI+1e-9,c=4*Math.max(o.halfDepth,s.halfDepth),h=[r[0]-o.u[1]*o.halfDepth,r[1]+o.u[0]*o.halfDepth],d=[r[0]+s.u[1]*s.halfDepth,r[1]-s.u[0]*s.halfDepth],u=o.u[0]*s.u[1]-o.u[1]*s.u[0],p=e=>{let t=Math.atan2(e[1]-r[1],e[0]-r[0])-o.angle;for(;t<0;)t+=2*Math.PI;return t<=a+1e-9};let _=null;if(Math.abs(u)>1e-9){const e=((d[0]-h[0])*s.u[1]-(d[1]-h[1])*s.u[0])/u,t=((d[0]-h[0])*o.u[1]-(d[1]-h[1])*o.u[0])/u,i=[h[0]+o.u[0]*e,h[1]+o.u[1]*e];(l?e<=1e-9&&t<=1e-9:e>1e-9&&e<=o.thickLength&&t<=s.thickLength)&&Math.hypot(i[0]-r[0],i[1]-r[1])<=c&&p(i)&&(_=i)}const m=e=>{Math.abs(ms(e))>i&&t.fans.push(e)};if(_){const e=1.5*Math.max(o.halfDepth,s.halfDepth);m(To([r[0],r[1]],h,_,d,e)??[[r[0],r[1]],h,_,d]);continue}if(l){m([[r[0],r[1]],h,d]);continue}const g=(e,t)=>Math.min(t,Math.sqrt(Math.max(c**2-e**2,0)),2*Math.max(o.halfDepth,s.halfDepth)),f=[h[0]+o.u[0]*g(o.halfDepth,o.thickLength),h[1]+o.u[1]*g(o.halfDepth,o.thickLength)],v=[d[0]+s.u[0]*g(s.halfDepth,s.thickLength),d[1]+s.u[1]*g(s.halfDepth,s.thickLength)];m([[r[0],r[1]],h,f,v,d])}}return t}function As(e,t){return!e||!Array.isArray(t)||t.length<2||!t.slice(0,2).every(Number.isFinite)?null:Cs(e.index,t,e.epsilon).filter(i=>Math.hypot(i.point[0]-t[0],i.point[1]-t[1])<=e.epsilon).sort((e,i)=>Math.hypot(e.point[0]-t[0],e.point[1]-t[1])-Math.hypot(i.point[0]-t[0],i.point[1]-t[1])||e.point[0]-i.point[0]||e.point[1]-i.point[1])[0]||null}function Ps(e,t,i,n,r,o,s){return Ts(zs(e,t,i,n,r,o,s),4*_s(n,s),s)}function Fs(e,t,i,n,r,o,s,a=1){const l=Ss(e,t,n,r,a,i);if(!l)return null;const c=function(e,t,i){const n=(e||[]).find(e=>e?.id===t),r=ni(n);if(!r)return[];const o=[];for(const n of e||[]){if(!n||n.id===t)continue;const e=ni(n);if(e)for(const t of Fn(r,e,i))o.push(t)}return o}(e,t,_s(r,a)),h=function(e,t,i,n,r){const o=_s(n,r),s=[];for(let a=0;aNs(h,d,e[0],e[1],e[2],e[3])<=o);s.push(u?"shared":"outer")}return s}(l.poly,c,n,r,a),d=$s(i,l,r,a),u=d.map((e,t)=>h[t]&&e>0?Oo(e,o,s)/2:0);return{...l,kinds:h,cms:d,offsets:u}}function zs(e,t,i,n,r,o,s=1){const a=[];for(const l of e||[]){if(!l?.id)continue;const c=Fs(e,l.id,t,i,n,r,o,s);if(c)for(let e=0;e0&&(a=is(a,e.a,e.b,e.cm,n,s));return a}function Os(e,t,i,n,r,o,s=1){if(!t?.length)return[];const a=zs(e,t,i,n,r,o,s),l=new Map;for(const e of a){if(e.open||!e.kind||!e.roomId)continue;const t=l.get(e.key)||new Set;t.add(e.roomId),l.set(e.key,t)}const c=e=>{const t=[...l.get(e)||[]].sort();return 1!==t.length&&2!==t.length?`ambiguous:${e}`:`${1===t.length?"outer":"shared"}:${t.join("|")}`},h=[],d=new Set;for(const e of a)!e.open&&e.cm>0&&!d.has(e.key)&&(d.add(e.key),h.push({...e,ownerSignature:c(e.key)}));const u=[];for(const a of e||[]){if(!a?.id)continue;const l=Fs(e,a.id,t,i,n,r,o,s);if(l)for(let e=0;e0)||null===l.kinds[i]){e++;continue}const o=c(qo(l.poly[i],l.poly[(i+1)%l.poly.length],n,s));let a=e;for(;a+10&&u.push({a:[d[0],d[1]],b:[p[0],p[1]],key:qo(d,p,n,s),cm:r,len:_,ownerSignature:o}),e=a+1}}}u.sort((e,t)=>t.len-e.len||e.key.localeCompare(t.key));const p=[],_=new Set,m=new Set,g=4*_s(n,s);for(const e of u){const t=h.filter(t=>!m.has(t.key)&&t.cm===e.cm&&t.ownerSignature===e.ownerSignature&&Vo(Go(t.a,t.b),Go(e.a,e.b))&&Ns(t.a[0],t.a[1],e.a[0],e.a[1],e.b[0],e.b[1])<=g&&Ns(t.b[0],t.b[1],e.a[0],e.a[1],e.b[0],e.b[1])<=g);if(t.length){for(const e of t)m.add(e.key);_.has(e.key)||(_.add(e.key),p.push(Wo(e.a,e.b,e.cm,n,s)))}}for(const e of h)m.has(e.key)||_.has(e.key)||(_.add(e.key),p.push(Wo(e.a,e.b,e.cm,n,s)));return p}function Es(e,t,i,n,r,o,s,a=1){const l=_s(r,a),c=(n[0]+n[2])/2,h=(n[1]+n[3])/2,d=Go([n[0],n[1]],[n[2],n[3]]);let u=null;for(const n of zs(e,t,i,r,o,s,a)){if(!Vo(Go(n.a,n.b),d))continue;const e=Ns(c,h,n.a[0],n.a[1],n.b[0],n.b[1]);e>4*l||(!u||e[e[0],e[1]]),o=Math.abs(ms(r));r.length>=3&&o>i&&(t=r,i=o)}return t}function Ls(e,t,i,n,r,o,s,a=1,l,c){const h=(e||[]).find(e=>e?.id===t),d=ni(h);if(!d||d.length<3)return null;if(!i?.length)return d.map(e=>[e[0],e[1]]);const u=Fs(e,t,i,n,r,o,s,a);if(!u||!u.offsets.some(e=>e>0))return d.map(e=>[e[0],e[1]]);const p=c||Ps(e,i,n,r,o,s,a),_=ws(u.poly,u.offsets,p);if(!_)return d.map(e=>[e[0],e[1]]);if(!p.nodes.length)return _;const m=void 0===l?ia(e,i,n,[],r,o,s,a):null,g=l??("ok"===m?.status||"degraded-extra"===m?.status?m.roomGeom:void 0);if(g)try{const e=Hs(Gt(Bs(u.poly),g));if(e)return e}catch{}return function(e,t){try{return Hs(Ut(Bs(e),Bs(t)))}catch{return null}}(_,u.poly)||d.map(e=>[e[0],e[1]])}function Bs(e){const t=e.map(e=>[e[0],e[1]]);return t.push([e[0][0],e[0][1]]),[t]}function qs(e){return!(!Array.isArray(e)||!e.length)&&e.every(e=>Array.isArray(e)&&e.length&&e.every(e=>Array.isArray(e)&&e.length>=4&&e.every(e=>Array.isArray(e)&&e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1])))&&Math.abs(Ci(e[0]))>1e-9)}function js(e,t,i,n){const r=n?new Set(n):null;let o=null;for(let n=0;nt.epsilon))continue;const l=Ks([[e.point[0]+a[0]*n.halfDepth,e.point[1]+a[1]*n.halfDepth],[e.point[0]+s.u[0]*r+a[0]*n.halfDepth,e.point[1]+s.u[1]*r+a[1]*n.halfDepth],[e.point[0]+s.u[0]*r-a[0]*n.halfDepth,e.point[1]+s.u[1]*r-a[1]*n.halfDepth],[e.point[0]-a[0]*n.halfDepth,e.point[1]-a[1]*n.halfDepth]],t.coordinateScale);if(!l)continue;const c=Bs(l);o=o?Wt(o,c):c}}return o}function Ws(e,t,i){let n=null;for(const r of e.rays)for(const e of r.continuations){const r=[-e.u[1],e.u[0]],o=[e.start[0]+e.u[0]*e.length,e.start[1]+e.u[1]*e.length],s=Ks([[e.start[0]+r[0]*e.halfDepth,e.start[1]+r[1]*e.halfDepth],[o[0]+r[0]*e.halfDepth,o[1]+r[1]*e.halfDepth],[o[0]-r[0]*e.halfDepth,o[1]-r[1]*e.halfDepth],[e.start[0]-r[0]*e.halfDepth,e.start[1]-r[1]*e.halfDepth]],t.coordinateScale);if(!s)continue;const a=Ut(Bs(s),i);Array.isArray(a)&&0!==a.length&&(n=n?Wt(n,a):a)}return n}function Us(e,t,i=2*(4*e.halfDepth+2*t.epsilon)){const n=function(e,t=Do){const i=new Set,n=Number.isFinite(t)&&t>=0?t:Do;for(let t=0;te-t)}(e);return n.length?js(e,t,i,n):null}function Gs(e,t,i,n,r){const o=function(e){let t=null;for(const i of e){const e=Bs(i);try{t=t?Wt(t,e):e}catch{}}return t}(function(e,t,i=!1){if(!e)return[];const n=[];for(const r of e.nodes)for(let o=0;o1e-9)||h>=Math.PI-1e-9)continue;const d=[-s.u[1],s.u[0]],u=[-a.u[1],a.u[0]],p=[r.point[0]+d[0]*s.halfDepth,r.point[1]+d[1]*s.halfDepth],_=[r.point[0]-u[0]*a.halfDepth,r.point[1]-u[1]*a.halfDepth],m=vs(p,s.u,_,a.u);if(!m)continue;const g=Math.hypot(m[0]-r.point[0],m[1]-r.point[1]);if(!Number.isFinite(g)||g<=r.limit)continue;const f=t?Math.sqrt(Math.max(0,r.limit*r.limit-s.halfDepth*s.halfDepth)):0,v=t?Math.sqrt(Math.max(0,r.limit*r.limit-a.halfDepth*a.halfDepth)):0,y=Ks([[p[0]+s.u[0]*f,p[1]+s.u[1]*f],[_[0]+a.u[0]*v,_[1]+a.u[1]*v],m],e.coordinateScale);if(y&&n.push(y),i){const t=m[0]-r.point[0],i=m[1]-r.point[1],o=Math.hypot(t,i),s=g-r.limit;if(o>e.epsilon&&s>e.epsilon){const a=Math.min(Math.max(8*e.epsilon,.05*r.halfDepth),.25*s),l=t/o,c=i/o,h=-c,d=l,u=Ks([[m[0]-l*a+h*a,m[1]-c*a+d*a],[m[0]-l*a-h*a,m[1]-c*a-d*a],[m[0]+l*a,m[1]+c*a]],e.coordinateScale);u&&n.push(u)}}}return n}({...t,nodes:[e]},i,n));return o&&r?Gt(o,r):o}function Vs(e,t,i,n){if(!e||!t.nodes.length)return e;let r=null;try{r=function(e){let t=null;for(const i of e.nodes){const n=Us(i,e);n&&(t=t?Wt(t,n):n)}return t}(t)}catch{return e}let o=e;for(const e of t.nodes){const s=4*e.halfDepth+2*t.epsilon,a=2*s,l=[[e.point[0]-s,e.point[1]-s],[e.point[0]+s,e.point[1]-s],[e.point[0]+s,e.point[1]+s],[e.point[0]-s,e.point[1]+s]];try{let s=o;const c=Gs(e,t,!1,!0,r);c&&(s=Gt(s,c));let h=js(e,t,a);const d=Gs(e,t,!0,!0,r);d&&(h=Gt(h,d)),r&&(h=Wt(h,r));const u=.02*Math.min(...e.rays.map(e=>e.halfDepth));if(h=Wt(h,Bs([[e.point[0]-u,e.point[1]-u],[e.point[0]+u,e.point[1]-u],[e.point[0]+u,e.point[1]+u],[e.point[0]-u,e.point[1]+u]])),!h)continue;let p=Ut(h,Bs(l));n?p=Ut(p,n):i&&(p=Ut(p,i));const _=Bs(l),m=Gt(s,_),g=i?Gt(Ut(s,_),i):null,f=Ws(e,t,_);o=Wt(m,...g?[g]:[],...f?[f]:[],p)}catch{}}if(r)try{let e=r;n?e=Ut(e,n):i&&(e=Ut(e,i)),o=Wt(o,e)}catch{}return o}function Ks(e,t=1){if(!Array.isArray(e)||e.length<3)return null;const i=Number.isFinite(t)&&t>0?t:1,n=1e-12*Math.max(1,i),r=[];for(const t of e){if(!Array.isArray(t)||t.length<2)return null;const e=Number(t[0]),i=Number(t[1]);if(!Number.isFinite(e)||!Number.isFinite(i))return null;const o=Math.round(e/n)*n,s=Math.round(i/n)*n;if(!Number.isFinite(o)||!Number.isFinite(s))return null;r.push([Object.is(o,-0)?0:o,Object.is(s,-0)?0:s])}return Math.abs(ms(r))>n*n?r:null}function Ys(e,t,i,n){if(Ns(e[0],e[1],t[0],t[1],i[0],i[1])>n)return!1;const r=i[0]-t[0],o=i[1]-t[1],s=(e[0]-t[0])*r+(e[1]-t[1])*o,a=r*r+o*o,l=n*Math.sqrt(a);return s>=-l&&s<=a+l}function Xs(e,t,i){const n=[],r=[];for(let o=0;oi*i))continue;const d=i/Math.sqrt(h),u=[0,1];for(const e of t)for(const t of[e.a,e.b]){if(!Ys(t,s,a,i))continue;const e=((t[0]-s[0])*l+(t[1]-s[1])*c)/h;e>d&&e<1-d&&u.push(e)}u.sort((e,t)=>e-t);const p=u.filter((e,t)=>0===t||Math.abs(e-u[t-1])>d);for(let e=0;e=3&&r.length===n.length?{poly:n,offsets:r}:null}function Zs(e,t,i,n,r,o,s,a){const l=(e||[]).map(ni).filter(e=>!!e&&e.length>=3);if(!l.length)return null;let c=Wt(Bs(l[0]));for(let e=1;e"outer"===e.kind&&e.half>0),u=4*_s(n,s),p=a||Ts(h,u,s);let _=null;for(const e of function(e){const t=[];for(const i of Array.isArray(e)?e:[])if(Array.isArray(i))for(const e of i){if(!Array.isArray(e)||e.length<4)continue;const i=e.slice(0,-1).map(e=>[e[0],e[1]]);i.length>=3&&t.push(i)}return t}(c)){const t=Xs(e,d,u);if(!t||!t.offsets.some(e=>e>0))continue;const i=aa(t.poly,t.offsets,p),n=ws(t.poly,t.offsets,p);if(!i||!n)continue;const r=Gt(Bs(i),Bs(n));_=_?Wt(_,r):r}return{centre:c,shell:_||[]}}function Js(e,t,i,n,r,o,s=1){try{const a=Zs(e,t,i,n,r,o,s,Ps(e,t,i,n,r,o,s));if(!a)return[];return a.shell?.length?Wt(a.centre,a.shell):a.centre}catch{return null}}function Qs(e){if(!e)return"";let t="";for(const i of e)if(Array.isArray(i))for(const e of i){if(!Array.isArray(e)||e.length<4)continue;const i=e.slice(0,e.length-1);i.length<3||(t+=(t?" ":"")+ks(i.map(e=>[e[0],e[1]])))}return t}const ea=15;function ta(e,t,i){const n=e?.length||0;if(n<3||t?.length!==n)return!1;const r=e[(i-1+n)%n],o=e[i],s=e[(i+1)%n],a=[r[0]-o[0],r[1]-o[1]],l=[s[0]-o[0],s[1]-o[1]],c=Math.hypot(a[0],a[1]),h=Math.hypot(l[0],l[1]);if(!(c>1e-9&&h>1e-9))return!1;const d=Math.max(-1,Math.min(1,(a[0]*l[0]+a[1]*l[1])/(c*h))),u=Math.acos(d);if(!(u>1e-9))return!1;if(u>=ea*Math.PI/180)return!1;const p=Math.max(0,t[(i-1+n)%n]),_=Math.max(0,t[i]);if(!(p>0||_>0))return!1;const m=Math.sin(u);if(!(m>1e-12))return!1;const g=(_+p*d)/m,f=(p+_*d)/m;return Number.isFinite(g)&&Number.isFinite(f)&&g>0&&f>0&&ge>0))continue;for(const e of l.offsets)e>0&&(u=Math.max(u,2*e));const c=aa(l.poly,l.offsets,d),p=ws(l.poly,l.offsets,d);c&&h.push({outset:c,inset:p})}for(const e of l){const t=e.map(e=>e[0]),i=e.map(e=>e[1]);if(t.length){const n=Math.min(Math.max(...t)-Math.min(...t),Math.max(...i)-Math.min(...i)),r=Math.min(...e.map((t,i)=>{const n=e[(i+1)%e.length];return Math.hypot(n[0]-t[0],n[1]-t[1])}));u=Math.max(u,e.length>16?n:r)}}const p=function(e,t,i,n,r,o,s,a){if(!t?.length||!i?.length)return[];const l=4*_s(n,s),c=new Map;for(const a of zs(e,t,i,n,r,o,s))!a.open&&a.half>0&&!c.has(a.key)&&c.set(a.key,a);const h=[...c.values()];if(h.length<2)return[];const d=a||Ts(h,l),u=[];for(const e of i)for(const t of[[e[0],e[1]],[e[2],e[3]]])u.some(e=>Math.hypot(e[0]-t[0],e[1]-t[1])<=l)||u.push(t);const p=[],_=(e,t)=>{let i=0,n=0;if(Math.hypot(e.a[0]-t[0],e.a[1]-t[1])<=l)i=e.b[0]-e.a[0],n=e.b[1]-e.a[1];else{if(!(Math.hypot(e.b[0]-t[0],e.b[1]-t[1])<=l))return null;i=e.a[0]-e.b[0],n=e.a[1]-e.b[1]}const r=Math.hypot(i,n);return r>l?[i/r,n/r]:null};for(const e of u){const t=h.map(t=>({iv:t,u:_(t,e)})).filter(e=>!!e.u);for(let i=0;i0?[e.slice(),u,m,_]:[e.slice(),_,m,u];else{if(!f)continue;{const t=[-r.u[1],r.u[0]],i=[-o.u[1],o.u[0]],n=s<0?1:-1,a=[e[0]+t[0]*r.iv.half*n,e[1]+t[1]*r.iv.half*n],l=[e[0]-i[0]*o.iv.half*n,e[1]-i[1]*o.iv.half*n];y=s>0?[e.slice(),a,l]:[e.slice(),l,a]}}Math.abs(ms(y))>l*l&&p.push(y)}}return p}(e,t,i,r,o,s,a,d),_=n.length?la(e,t,i,r,o,s,a):null;let m="exterior";try{const v=Zs(e,t,i,r,o,s,a,d);m="paper";const y=v?v.shell?.length?Wt(v.centre,v.shell):v.centre:[],b=e=>{const t=Bs(e.outset);if(!e.inset)return t;const i=Bs(e.inset);return Gt(t,i)};m="room-rings";let w=null;for(const e of h)try{const t=b(e);w=w?Wt(w,t):t}catch{}if(m="edge-bodies",v)for(const n of oa(e,t,i,r,o,s,a))try{const e=Ut(Bs(n.quad),v.centre);w=w?Wt(w,e):e}catch{}m="junctions",w=function(e,t,i=1,n=Wt){let r=e;for(const e of t||[]){const t=Ks(e,i);if(t)try{const e=Bs(t);r=r?n(r,e):e}catch{}}return r}(w,p,a),m="facade-clip",w&&v&&(w=Ut(w,v.centre)),m="exterior-shell";const k=[];let x=0;if(v?.shell?.length)if(w)try{const e=Wt(w,v.shell);if(!qs(e))throw new Error("invalid shell union");w=e}catch{if(!qs(w)||!qs(v.shell))throw new Error("invalid shell");k.push({id:"exterior-shell",geom:v.shell}),x++}else w=v.shell;if(m="multi-wall-trim",w&&d.nodes.length){const e=e=>e.rays.some(e=>e.supports.some(e=>e.length<2*e.halfDepth)),t=d.nodes.filter(e);if(t.length){w=Vs(w,{...d,nodes:t},v?.centre,y)}}if(m="junction-corners",d.nodes.length){const n=Ds(d),l=function(e,t,i,n,r,o,s,a){try{const l=Zs(e,t,i,n,r,o,s,{epsilon:a.epsilon,coordinateScale:a.coordinateScale,nodes:[],index:new Map});return l?l.shell?.length?Wt(l.centre,l.shell):l.centre:null}catch{return null}}(e,t,i,r,o,s,a,d);for(const e of n.fans)try{let t=[Bs(e)];if(l&&(t=Ut(t,l)),!t?.length)continue;w=w?Wt(w,t):t}catch{}g=w,f=Math.max(d.epsilon,1e-9)**2,w=Array.isArray(g)?g.map(e=>{if(!Array.isArray(e)||!e.length)return e;const[t,...i]=e;return Math.abs(ms(t||[]))<=f?null:[t,...i.filter(e=>Math.abs(ms(e||[]))>f)]}).filter(e=>!!e):g}const S=w||[],$=[...qs(S)?[{id:"room-primary",geom:S}]:[],...k.map((e,t)=>({id:`room-isolated-${t}`,geom:e.geom}))];m="openings";for(const e of n){if(!(e.length>0))continue;const t=da(_,e,!0);if(!t.negative&&!t.positive)continue;const i=e.angle*Math.PI/180,n=Math.cos(i),o=Math.sin(i),s=-o,l=n,c=e.length/2,h=1.25*Math.max(u,r*a),d=[[e.x-n*c-s*h,e.y-o*c-l*h],[e.x+n*c-s*h,e.y+o*c-l*h],[e.x+n*c+s*h,e.y+o*c+l*h],[e.x-n*c+s*h,e.y-o*c+l*h]];w&&(w=Gt(w,Bs(d)));for(const e of k)e.geom=Gt(e.geom,Bs(d))}m="extras";const M=[];let R=0;const C=c.mergeExtra||((e,t)=>e?Wt(e,t):t);for(let e=0;ee.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]))||Math.abs(Ci(t))<=1e-9){R++;continue}const i=[Bs(t)];try{const t=C(w,i,e);if(!qs(t))throw new Error("invalid extra union");w=t}catch{R++,qs(i)&&M.push({id:`extra-${e}`,geom:i})}}M.push(...k),M.sort((e,t)=>Qs(e.geom).localeCompare(Qs(t.geom)));const T=w||[];return{status:R||x?"degraded-extra":"ok",geom:T,components:[...qs(T)?[{id:"primary",geom:T}]:[],...M.map((e,t)=>({...e,id:`isolated-${t}`}))],roomGeom:S,roomComponents:$,paperGeom:y,depthUnits:u,openingPadUnits:1.25*Math.max(u,r*a),openingIndex:_,multiWallNodes:d,degradedExtraCount:R+x}}catch{return c.onCoreFailure?.(m),{status:"failed-core",geom:[],components:[],roomGeom:[],paperGeom:[],roomComponents:[],depthUnits:u,openingIndex:null,multiWallNodes:d,degradedExtraCount:0}}var g,f}function na(e,t,i,n=[],r,o,s,a=1,l=[],c={}){if(!t?.length&&!l.length)return null;return ra(ia(e,t,i,n,r,o,s,a,l,c))}function ra(e){if("failed-core"===e.status||"not-applicable"===e.status)return null;const t=e.components.map(e=>({id:e.id,d:Qs(e.geom),fillRule:"evenodd"})).filter(e=>!!e.d),i=t[0]?.d||"",n=Qs(e.paperGeom);if(t.length){const r={status:e.status,d:i,paths:t,components:e.components,roomGeom:e.roomGeom,multiWallNodes:e.multiWallNodes,paperD:n,depthUnits:e.depthUnits,fillRule:"evenodd"};return Object.defineProperties(r,{roomComponents:{value:e.roomComponents||[],enumerable:!1},openingIndex:{value:e.openingIndex,enumerable:!1},openingPadUnits:{value:e.openingPadUnits,enumerable:!1}}),r}return null}function oa(e,t,i,n,r,o,s=1){if(!t?.length)return[];const a=new Set,l=[];for(const c of e||[]){if(!c?.id)continue;const h=Fs(e,c.id,t,i,n,r,o,s);if(!h)continue;const d=h.poly;for(let e=0;e0))continue;const p=qo(t,i,n,s);if(a.has(p))continue;a.add(p);const _=Oo(u,r,o),[m,g]=gs(d,e),f=-m,v=-g,y=_/2,b=[[t[0]+f*y,t[1]+v*y],[i[0]+f*y,i[1]+v*y],[i[0]+m*y,i[1]+g*y],[t[0]+m*y,t[1]+g*y]];l.push({key:p,kind:c,cm:u,quad:b,a:[t[0],t[1]],b:[i[0],i[1]],depthUnits:_})}}return l}function sa(e,t=[]){let i=ks(e.quad);const[n,r]=Lo(e.a,e.b),o=n,s=r,a=-s,l=o;for(const n of t){if(!Zo(e.a,e.b,n.angle))continue;if(Ns(n.x,n.y,e.a[0],e.a[1],e.b[0],e.b[1])>Math.max(.55*e.depthUnits,.001))continue;const t=n.length/2,r=e.depthUnits,c=n.x,h=n.y;i+=` ${ks(xs([[c-o*t-a*r,h-s*t-l*r],[c+o*t-a*r,h+s*t-l*r],[c+o*t+a*r,h+s*t+l*r],[c-o*t+a*r,h-s*t+l*r]]))}`}return i}function aa(e,t,i){const n=e?.length||0;if(n<3||t.length!==n)return null;if(t.every(e=>!(e>0)))return e.map(e=>[e[0],e[1]]);xs(e),t.slice().reverse();const r=[];for(let o=0;o0||l>0)){r.push([e[o][0],e[o][1]]);continue}if(a>0!=l>0){const t=e[o],i=a>0?[t[0]-c*a,t[1]-h*a]:[t[0],t[1]],n=l>0?[t[0]-d*l,t[1]-u*l]:[t[0],t[1]];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}if(fs(w,k)){const t=e[o],i=[t[0]-c*a,t[1]-h*a],n=[t[0]-d*l,t[1]-u*l];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}const $=vs(x,w,S,k),M=Math.max(a,l,1e-9),R=As(i,e[o])?.limit??4*M;if($){const i=Math.hypot($[0]-e[o][0],$[1]-e[o][1]);if(Number.isFinite(i)&&i<=R){r.push($);continue}if(ta(e,t,o)){r.push([e[o][0],e[o][1]]);continue}}a>0&&r.push([e[o][0]-c*a,e[o][1]-h*a]),l>0&&r.push([e[o][0]-d*l,e[o][1]-u*l])}return r.length>=3?r:null}function la(e,t,i,n,r,o,s=1){const a=[];for(const l of e||[]){if(!l?.id)continue;const c=Fs(e,l.id,t,i,n,r,o,s);if(!c)continue;const h=Math.abs(Ci(c.poly));for(let e=0;e[Math.max(t,e.x0),Math.min(i,e.x1)]).filter(e=>e[1]-e[0]>n).sort((e,t)=>e[0]-t[0]||e[1]-t[1]);if(!r.length)return{coverage:0,full:!1};let o=r[0][0],s=r[0][1],a=0,l=o<=t+n;for(let e=1;e=i-n,{coverage:a,full:l}}function ha(e,t){return Number(t.full)-Number(e.full)||e.faceDistance-t.faceDistance||e.area-t.area||e.roomId.localeCompare(t.roomId)}function da(e,t,i=!1){const n=Number(t?.x),r=Number(t?.y),o=Number(t?.angle),s=Number(t?.length);if(!([n,r,o,s].every(Number.isFinite)&&s>0))return{negative:null,positive:null};const a=o*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=-c,d=l,u=s/2,p=Math.max(1e-9,e.adjacencyEps),_=new Map;let m=0;for(const t of e.edges){if(i&&!(t.half>0))continue;if(!Zo(t.a,t.b,o))continue;const[e,s]=Lo(t.a,t.b);if(Math.abs((n-t.a[0])*s-(r-t.a[1])*e)>p)continue;const a=(t.a[0]-n)*l+(t.a[1]-r)*c,g=(t.b[0]-n)*l+(t.b[1]-r)*c,f=Math.max(-u,Math.min(a,g)),v=Math.min(u,Math.max(a,g));if(v-f<=p)continue;const y=t.inward[0]*h+t.inward[1]*d>=0?1:-1,b=((t.a[0]+t.b[0])/2-n)*h+((t.a[1]+t.b[1])/2-r)*d,w=Math.abs(b+y*t.half),k=`${y}|${t.roomId}`,x={x0:f,x1:v,half:t.half,cm:t.cm,key:t.key,axis:[e,s]},S=_.get(k);S?(S.pieces.push(x),S.faceDistance=Math.min(S.faceDistance,w)):_.set(k,{roomId:t.roomId,side:y,order:m++,pieces:[x],faceDistance:w,area:t.area,coverage:0,full:!1})}for(const e of _.values()){const t=ca(e.pieces,-u,u,p);e.coverage=t.coverage,e.full=t.full}const g=e=>{const t=[..._.values()].filter(t=>t.side===e&&t.coverage>p);return t.sort(ha),t[0]||null};return{negative:g(-1),positive:g(1)}}function ua(e,t,i,n,r,o,s=1,a=[]){return pa(la(e,i,a,n,r,o,s),t)}function pa(e,t){const i=da(e,t),n=[i.negative,i.positive].filter(e=>!!e);if(!n.length)return{ox:0,oy:0,cm:0,side:-1};const r=i.negative&&i.positive?-1:n[0].side,o=t.flip_v?-r:r,s=(-1===o?i.negative:i.positive)||n[0],a=[...s.pieces].sort((e,t)=>(e.x0<=0&&e.x1>=0?0:Math.min(Math.abs(e.x0),Math.abs(e.x1)))-(t.x0<=0&&t.x1>=0?0:Math.min(Math.abs(t.x0),Math.abs(t.x1)))||t.x1-t.x0-(e.x1-e.x0)||e.key.localeCompare(t.key))[0];if(!(a.half>0&&a.cm>0))return{ox:0,oy:0,cm:0,side:o};const l=t.angle*Math.PI/180,c=-Math.sin(l),h=Math.cos(l);return{ox:c*o*a.half,oy:h*o*a.half,cm:a.cm,side:o}}function _a(e,t){const i=1e-9,n=t.filter(e=>Number.isFinite(e.x0)&&Number.isFinite(e.x1)&&Number.isFinite(e.half)&&e.x1>e.x0&&e.half>0);if(!n.length)return"";const r=n.flatMap(e=>[e.x0,e.x1]).sort((e,t)=>e-t),o=[];for(const e of r){const t=o[o.length-1];(void 0===t||e>t+i)&&o.push(e)}const s=[];for(let e=0;e+1t+i))continue;const a=(t+r)/2,l=n.reduce((e,t)=>a>=t.x0-i&&a<=t.x1+i?Math.max(e,t.half):e,0);if(!(l>0))continue;const c=s[s.length-1];c&&t<=c.x1+i&&Math.abs(l-c.half)<=i?c.x1=r:s.push({x0:t,x1:r,half:l})}const a=[];for(const e of s){const t=a[a.length-1],n=t?.[t.length-1];n&&e.x0<=n.x1+i?(e.x0=n.x1,t.push(e)):a.push([e])}return a.map(t=>{const i=t[0],n=t[t.length-1],r=Math.min(.25*Math.min(...t.map(e=>e.half)),.75),o=-e*r,s=[];if(1===e){s.push(`M ${i.x0} ${o} L ${n.x1} ${o}`);for(let e=t.length-1;e>=0;e--){const i=t[e];s.push(`L ${i.x1} ${i.half} L ${i.x0} ${i.half}`)}}else{s.push(`M ${n.x1} ${o} L ${i.x0} ${o}`);for(const e of t)s.push(`L ${e.x0} ${-e.half} L ${e.x1} ${-e.half}`)}return s.push("Z"),s.join(" ")}).join(" ")}function ma(e,t,i,n){if(!n)return i;const r=e.angle*Math.PI/180,o=Math.cos(r),s=Math.sin(r),a=[],l=1e-9;for(const r of i){const[i,c]=r.axis,h=o*i+s*c;if(Math.abs(h)<=l)continue;const d=e.x*i+e.y*c,u=d+h*r.x0,p=d+h*r.x1,_=Math.min(u,p),m=Math.max(u,p),g=`${r.key}|${t}`,f=n.get(g)||[];let v=[[_,m]];for(const[e,t]of f){const i=[];for(const[n,r]of v)t<=n+l||e>=r-l?i.push([n,r]):(e>n+l&&i.push([n,Math.min(r,e)]),te[0]-t[0]||e[1]-t[1]),b=[];for(const e of y){const t=b[b.length-1];t&&e[0]<=t[1]+l?t[1]=Math.max(t[1],e[1]):b.push([e[0],e[1]])}n.set(g,b)}return a}function ga(e,t){const i=new Map;return t.map(t=>function(e,t,i){const n=da(e,t,!0),r=n.negative,o=n.positive;if(!r&&!o)return null;let s;if(r&&o)s=[{candidate:r,side:-1},{candidate:o,side:1}];else{const e=r||o;s=[{candidate:e,side:-1},{candidate:e,side:1}]}const a=s.map(({candidate:e,side:n})=>({candidate:e,side:n,pieces:ma(t,n,e.pieces,i)})),l=a.map(({candidate:e,side:t,pieces:i})=>({side:t,roomId:e.roomId,d:_a(t,i)})),c=a.flatMap(({pieces:e})=>e);if(!c.length)return null;const h=Math.max(...c.map(e=>e.half));return{faces:l,minY:-h,maxY:h,wallKey:[...new Set(c.map(e=>e.key))].sort().join("|")}}(e,t,i))}const fa=150,va=1e-6;function ya(e){return Number.isFinite(e)?Math.max(1,Math.min(fa,e)):1}function ba(e){return((Number.isFinite(Number(e))?Number(e):0)%90+90)%90}const wa=e=>{const t=e.map(e=>[e[0],e[1]]);return!t.length||t[0][0]===t[t.length-1][0]&&t[0][1]===t[t.length-1][1]||t.push([...t[0]]),[t]},ka=(e,t)=>e[0]===t[0]&&e[1]===t[1];function xa(e,t=1e-6){const i=Number.isFinite(t)&&t>0?t:va,n=[];for(const t of e||[]){if(!Array.isArray(t)||t.length<2)return null;const e=Number(t[0]),r=Number(t[1]);if(!Number.isFinite(e)||!Number.isFinite(r))return null;const o=Math.round(e/i)*i,s=Math.round(r/i)*i;if(!Number.isFinite(o)||!Number.isFinite(s))return null;const a=[Object.is(o,-0)?0:o,Object.is(s,-0)?0:s];n.length&&ka(n[n.length-1],a)||n.push(a)}return n.length>1&&ka(n[0],n[n.length-1])&&n.pop(),n.length<3||new Set(n.map(e=>`${e[0]},${e[1]}`)).size<3?null:Ci(n)>i*i?n:null}function Sa(e){const t=[];for(const i of e||[])for(const e of i||[]){const i=(e||[]).filter(e=>Array.isArray(e)&&e.length>=2);i.length<4||t.push(`M ${i.slice(0,-1).map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`)}return t.join(" ")}function $a(e,t,i,n,r){return os({a:e,b:t,halfDepth:Oo(i,n,r)/2})}function Ma(e,t,i){const n=Number(t)>0?Number(t):5,r=ya(e.cm)/n*i,o=e.center[0],s=e.center[1];if("circle"===e.shape){const e=r/2;return Array.from({length:96},(t,i)=>{const n=i/96*Math.PI*2;return[o+Math.cos(n)*e,s+Math.sin(n)*e]})}const a=r/2,l=ba(e.angle)*Math.PI/180,c=Math.cos(l),h=Math.sin(l);return[[-a,-a],[a,-a],[a,a],[-a,a]].map(([e,t])=>[o+e*c-t*h,s+e*h+t*c])}function Ra(e,t){const i=Number.isFinite(t)?Math.max(0,Math.min(1,t)):0,n=(e.a[0]+e.b[0])/2,r=(e.a[1]+e.b[1])/2,o=(e.b[0]-e.a[0])*i/2,s=(e.b[1]-e.a[1])*i/2;return{...e,a:[n-o,r-s],b:[n+o,r+s]}}function Ca(e,t,i=1e-9){if(!t.length)return[e];let n=[wa(e)];try{for(const e of t){const t=e.b[0]-e.a[0],r=e.b[1]-e.a[1],o=Math.hypot(t,r);if(!(o>i))continue;const s=t/o,a=r/o,l=-a,c=s,h=1.25*Math.max(Number(e.depth)||0,4*i),d=Math.max(2*i,1e-9*o),u=[[e.a[0]-s*d-l*h,e.a[1]-a*d-c*h],[e.b[0]+s*d-l*h,e.b[1]+a*d-c*h],[e.b[0]+s*d+l*h,e.b[1]+a*d+c*h],[e.a[0]-s*d+l*h,e.a[1]-a*d+c*h]];n=Gt(n,wa(u))}return Na(n)}catch{return[e]}}function Ta(e,t){try{const i=Gt([[...e.map(e=>[e[0],e[1]]),[e[0][0],e[0][1]]]],[[...t.map(e=>[e[0],e[1]]),[t[0][0],t[0][1]]]]);let n=null,r=0;for(const e of i||[]){const t=e?.[0]||[],i=Math.abs(Ci(t));t.length>=4&&i>r&&(r=i,n=t.slice(0,-1).map(e=>[e[0],e[1]]))}return n}catch{return null}}function Da(e,t,i,n=Math.max(2e-4*i,1e-9),r=[]){const o=[],s=new Map;for(const e of r){const t=s.get(e.hostId)||[];t.push(e),s.set(e.hostId,t)}const a=[],l=[],c=[];for(const n of e.partitions||[]){const e={a:n.a,b:n.b,halfDepth:Oo(n.cm,t,i)/2};if(!(e.halfDepth>0))continue;const r=os(e);r&&(o.push(e),a.push(r),c.push({id:n.id,body:r}))}const h=o;for(const{segmentIndex:e,wedge:t}of hs(h,n)){const i={list:a,at:e},n=Ta(i.list[i.at],t);n&&(i.list[i.at]=n,c[i.at].body=n)}for(const e of c)l.push(...Ca(e.body,s.get(e.id)||[],n));const d=(e.wall_columns||[]).map(e=>Ma(e,t,i)),u=ds(o,n).flatMap(e=>Ca(e,r,n));return{partitions:a,columns:d,patches:u,all:[...l,...u,...d]}}function Aa(e){try{const t=e.map(e=>xa(e)).filter(e=>!!e).map(e=>wa(e));return t.length?Wt(t[0],...t.slice(1)):null}catch{return null}}const Pa=e=>`M ${e.map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`;function Fa(e){const t=[];for(const i of e||[]){if(Oa([i])<=1e-6)continue;const e=[];for(const t of i||[]){const i=(t||[]).filter(e=>Array.isArray(e)&&e.length>=2);i.length<4||e.push(Pa(i.slice(0,-1)))}e.length&&t.push(e.join(" "))}return t}function za(e,t,i={}){const n=Aa(e.filter(e=>e.length>=3)),r=t.some(e=>!xa(e))?null:Aa(t);if(!n)return[];if(r)try{return Fa(Ut(n,r))}catch{}return function(e,t,i){let n=null;for(let r=0;r=4&&t.push(e.slice(0,-1).map(e=>[e[0],e[1]]));return t}function Na(e){const t=[];for(const i of e||[]){const e=i?.[0];e?.length>=4&&t.push(e.slice(0,-1).map(e=>[e[0],e[1]]))}return t}function Ha(e,t){let i=!1;for(let n=0,r=t.length-1;ne[1]!=l>e[1]&&e[0]<(a-o)*(e[1]-s)/(l-s||1e-12)+o&&(i=!i)}return i}function La(e,t){for(const i of t||[]){const t=i?.[0];if(!t?.length||!Ha(e,t))continue;let n=!1;for(let t=1;ti)return!1;if(Math.abs(ya(e.cm)-ya(t.cm))>1e-6)return!1;if(e.shape!==t.shape)return!0;if("circle"===e.shape||"circle"===t.shape)return!0;const n=Math.abs(ba(e.angle)-ba(t.angle));return Math.min(n,90-n)<=1e-6}const qa=2.54;function ja(e){const t="number"==typeof e?e:NaN;return!Number.isFinite(t)||t<=0||5===t?1:5/t}function Wa(e,t){return e*ja(t)}function Ua(e){return e?qa:1}function Ga(e,t){if(!t)return String(e);const i=e/qa;return String(Math.round(1e6*i)/1e6)}function Va(e,t){return t?e*qa:e}const Ka=1e3;function Ya(e,t){const i=Number(e),n=Number.isFinite(i)&&i>0?i:1,r=n>=1?t:t*n,o=n>=1?t/n:t;return{x:(t-r)/2,y:(t-o)/2,w:r,h:o}}const Xa=.01,Za=100;function Ja(e,t=1e3){const i=Ya(e?.plan_aspect,t),n=Number(e?.plan_scale),r=Number.isFinite(n)&&n>0?Math.min(Za,Math.max(Xa,n)):1,o=Number(e?.plan_scale_x),s=Number(e?.plan_scale_y),a=Number.isFinite(o)&&o>0?Math.min(Za,Math.max(Xa,o)):r,l=Number.isFinite(s)&&s>0?Math.min(Za,Math.max(Xa,s)):r,c=Number(e?.plan_x),h=Number(e?.plan_y),d=Dr(e?.plan_angle);return{x:i.x+(Number.isFinite(c)?cl(c):0)*t,y:i.y+(Number.isFinite(h)?cl(h):0)*t,w:i.w*a,h:i.h*l,...d?{angle:d}:{}}}function Qa(e){if(null==e.x||null==e.y)return{x:e.x,y:e.y,w:e.w,h:e.h};const t=Number(e.w)||0,i=Number(e.h)||0;return{x:t<0?e.x+t:e.x,y:i<0?e.y+i:e.y,w:Math.abs(t),h:Math.abs(i)}}function el(e){return e&&Array.isArray(e.spaces)?e.spaces.map(e=>{const t=Ka,i=function(e){return Array.isArray(e)&&4===e.length&&e.every(e=>Number.isFinite(e))&&e[2]>1e-6&&e[3]>1e-6?e:[0,0,1,1]}(e.view_box);return{id:e.id,title:e.title,cellCm:Number.isFinite(Number(e.cell_cm))&&Number(e.cell_cm)>0?Number(e.cell_cm):5,vb:[i[0]*Ka,i[1]*t,i[2]*Ka,i[3]*t],bg:e.plan_url?{href:Hn(e.plan_url),...Ja(e,Ka)}:null,rooms:(e.rooms||[]).map(e=>{const i={...e,...Qa(e)};return{id:i.id,name:i.name,area:i.area??null,open_to:i.open_to||void 0,settings:i.settings||void 0,x:null!=i.x?i.x*Ka:void 0,y:null!=i.y?i.y*t:void 0,w:null!=i.w?i.w*Ka:void 0,h:null!=i.h?i.h*t:void 0,poly:i.poly?i.poly.map(e=>[e[0]*Ka,e[1]*t]):void 0,wall_ids:Array.isArray(i.wall_ids)?[...i.wall_ids]:void 0}}),wall_segments:(e.wall_segments||[]).map(e=>({...e,id:String(e.id),a:[Number(e.a?.[0])*Ka,Number(e.a?.[1])*t],b:[Number(e.b?.[0])*Ka,Number(e.b?.[1])*t],cm:Number(e.cm)})),partitions:(e.partitions||[]).map(e=>({id:e.id,a:[e.a[0]*Ka,e.a[1]*t],b:[e.b[0]*Ka,e.b[1]*t],cm:Number(e.cm)})),wall_columns:(e.wall_columns||[]).map(e=>({id:e.id,shape:"circle"===e.shape?"circle":"square",center:[e.center[0]*Ka,e.center[1]*t],cm:Number(e.cm),..."circle"===e.shape?{}:{angle:ba(e.angle)}}))}}):[]}const tl=5e3,il=tl*Ka,nl=240,rl=Ka/nl,ol=1/nl;function sl(e){if(!Number.isFinite(e))return e;const t=Math.round(e*nl/Ka)*Ka/nl;return Math.abs(t-e)<=1e-9*rl?e:t}function al(e){return{x:sl(e.x),y:sl(e.y)}}function ll(e){return Number.isFinite(e)?Math.min(il,Math.max(-il,e)):0}function cl(e){return Number.isFinite(e)?Math.min(tl,Math.max(-tl,e)):0}const hl=1/3,dl=200;function ul(e){return"house"===e?"house":"content"}function pl(e){let t=1/0,i=1/0,n=-1/0,r=-1/0;for(const o of e){const e=Number(o[0]),s=Number(o[1]);Number.isFinite(e)&&Number.isFinite(s)&&(en&&(n=e),s>r&&(r=s))}return t>n?null:{minX:t,minY:i,maxX:n,maxY:r}}function _l(e){const t=[],i=e=>{if(Array.isArray(e))if(e.length>=2&&Number.isFinite(Number(e[0]))&&Number.isFinite(Number(e[1])))t.push([Number(e[0]),Number(e[1])]);else for(const t of e)i(t)};return i(e),pl(t)}function ml(e,t){const i=Number.isFinite(t)&&t>0?t:0;return{minX:e.minX-i,minY:e.minY-i,maxX:e.maxX+i,maxY:e.maxY+i}}function gl(e){return e.poly&&e.poly.length?pl(e.poly):null==e.x||null==e.y?null:pl([[e.x,e.y],[e.x+(e.w||0),e.y+(e.h||0)]])}function fl(e,t=1e3,i=1e3){const n=Number(e.x)*t,r=Number(e.y)*i,o=Number(e.w)*t,s=Number(e.h)*i;return![n,r,o,s].every(Number.isFinite)||o<=0||s<=0?null:pl(Nr({x:n,y:r,w:o,h:s,angle:Dr(e.angle)||void 0}))}function vl(e,t){const i=[];for(const t of e.rooms||[]){const e=gl(t);e&&i.push(e)}if(e.bg){const t=pl(Nr(e.bg));t&&i.push(t)}for(const e of t||[])if(Array.isArray(e)){const t=pl([e]);t&&i.push(t)}else i.push(e);return i}const yl=e=>{if(!e.length)return 0;const t=[...e].sort((e,t)=>e-t),i=t.length>>1;return t.length%2?t[i]:(t[i-1]+t[i])/2},bl=e=>{let t=1/0,i=1/0,n=-1/0,r=-1/0;for(const o of e)o.minXn&&(n=o.maxX),o.maxY>r&&(r=o.maxY);return t>n||i>r?null:{x:t,y:i,w:n-t,h:r-i}};function wl(e,t){let{x:i,y:n,w:r,h:o}=e;r<30&&(i=i+r/2-100,r=dl),o<30&&(n=n+o/2-100,o=dl);const s="number"==typeof t?{top:t,right:t,bottom:t,left:t}:t,a=Math.max(r,o),l=a*s.top,c=a*s.right,h=a*s.bottom,d=a*s.left;return{x:i-d,y:n-l,w:r+d+c,h:o+l+h}}function kl(e,t={}){const i=t.pad??.05,n=t.k??10,r=t.minSpread??50,o=e.filter(e=>Number.isFinite(e.minX)&&Number.isFinite(e.minY)&&Number.isFinite(e.maxX)&&Number.isFinite(e.maxY)&&Math.abs(e.minX)<=il&&Math.abs(e.maxX)<=il&&Math.abs(e.minY)<=il&&Math.abs(e.maxY)<=il);if(!o.length)return{core:null,all:null,outliers:0};const s=bl(o);if(o.length<4){const e=wl(s,i);return{core:e,all:e,outliers:0}}const a=o.map(e=>(e.minX+e.maxX)/2),l=o.map(e=>(e.minY+e.maxY)/2),c=yl(a),h=yl(l),d=o.map((e,t)=>Math.max(Math.abs(a[t]-c),Math.abs(l[t]-h))),u=Math.max(((e,t)=>e.length?e[Math.min(e.length-1,Math.max(0,Math.round(t*(e.length-1))))]:0)([...d].sort((e,t)=>e-t),.75),r),p=d.map(e=>e>n*u),_=p.filter(Boolean).length,m=_&&_<=o.length*hl?o.filter((e,t)=>!p[t]):o;return{core:wl(bl(m)||s,i),all:wl(s,i),outliers:m===o?0:_}}function xl(e){return kl(e,{pad:0}).all}function Sl(e,t,i=.05){const n=kl(vl(e,t),{pad:i});if(n.core)return n.core;const r=e.vb&&4===e.vb.length&&e.vb[2]>0&&e.vb[3]>0?e.vb:[0,0,Ka,Ka];return{x:r[0],y:r[1],w:r[2],h:r[3]}}function $l(e){const t=Sl(e);return{x:t.x+t.w/2,y:t.y+t.h/2}}function Ml(e){const t=[];for(const i of e.rooms||[]){const e=gl(i);e&&t.push(e)}const i=kl(t,{pad:0}).core,n=Ka*ja(e.cellCm??5);return i?Math.max(n,Math.min(il,Math.max(i.w,i.h))):n}function Rl(e,t,i,n=1){const r=Number(i),o=Number.isFinite(n)&&n>0?n:1;return!Number.isFinite(r)||r<=0?e*o:e*Ml(t)*o/r}const Cl=[1,2,5,10,20,50,100,200,500,1e3];function Tl(e,t,i=7){if(!(e>0&&t>0&&Number.isFinite(t)))return null;const n=Cl.find(n=>e*n*t>=i);if(void 0===n)return null;const r=Cl.find(e=>e>=5*n)??5*n;return{fine:n,coarse:r}}function Dl(e){if(e.poly&&e.poly.length){const t=e.poly.map(e=>e[0]),i=e.poly.map(e=>e[1]),n=Math.min(...t),r=Math.min(...i);return{x:n,y:r,w:Math.max(...t)-n,h:Math.max(...i)-r}}return{x:e.x??0,y:e.y??0,w:e.w??0,h:e.h??0}}function Al(e,t,i,n,r,o=new Set){const s=t[e.id];return!o.has(e.id)&&s&&s.s===e.space?{x:s.x*Ka,y:s.y*Ka}:n[e.id]?n[e.id]:al($l(r))}function Pl(e,t,i,n){const r=i["rl_"+(e.id||"")];if(r&&r.s===t)return{x:r.x*Ka,y:r.y*Ka};const o=function(e){if(e.poly){const t=e.poly.length;return[e.poly.reduce((e,t)=>e+t[0],0)/t,e.poly.reduce((e,t)=>e+t[1],0)/t]}return[e.x+e.w/2,e.y+.1*Math.min(e.w,e.h)]}(e);return al({x:o[0],y:o[1]})}function Fl(e,t){for(const i of e?.spaces??[])for(const e of i?.decor??[])if("furniture"===e?.kind&&"string"==typeof e.symbol&&t(e.symbol))return!0;return!1}let zl=0;const Il=new Set;const Ol=new class{constructor(e){this.options=e,this._art=null,this._failed=!1,this._terminal=!1,this._inFlight=null,this._hosts=new Set,this._settled=[]}state(){return this._art?"ready":this._failed?"fallback":"pending"}get terminal(){return this._terminal}art(e,t){if(this._art)return this._art[e];t&&!this._failed&&this._hosts.add(t)}adopt(e,t){return!!this._art||(t!==this.options.expectedFingerprint?((this.options.warn??console.warn)("[houseplan] furniture artwork from another build ignored",{fingerprint:t}),!1):(this._install(e),!0))}ensure(){return"pending"!==this.state()?Promise.resolve():(this._inFlight||(this._inFlight=this._loadWithRetry().finally(()=>{this._inFlight=null})),this._inFlight)}onSettled(e){"pending"===this.state()?this._settled.push(e):Promise.resolve().then(e)}async _loadWithRetry(){let e=new Error("furniture artwork did not load");for(const t of[0,1])try{const i=await this.options.load(t);if(i.FURNITURE_ART_FINGERPRINT!==this.options.expectedFingerprint){this._terminal=!0,e=new Error(`furniture artwork fingerprint mismatch: expected ${this.options.expectedFingerprint}, got ${i.FURNITURE_ART_FINGERPRINT}`);break}if(this._art)return;return void this._install(i.GENERATED_FURNITURE_ART)}catch(t){e=t}this._art||(this._failed=!0,(this.options.warn??console.warn)("[houseplan] furniture artwork unavailable",e),this.options.loadFailed?.(this._terminal),this._flush())}_install(e){this._art=e,this._failed=!1,this._flush()}_flush(){const e=[...this._hosts];this._hosts.clear();for(const t of e)t.isConnected&&t.requestUpdate();const t=this._settled.splice(0);for(const e of t)e()}}({expectedFingerprint:"54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32",load:async e=>0===e?await import("./furniture-plan-art.generated-DaxkO8ol.js"):await import((()=>{const e=new URL("./furniture-plan-art.generated-DaxkO8ol.js",import.meta.url);return e.searchParams.set("hp_retry","art-"+ ++zl),e.href})()),loadFailed:e=>{for(const t of Il)t(e)}}),El=["furniture","appliance","sanitary","other"],Nl=[{id:"coffee_table",group:"furniture",category:"coffee_table",w:120,h:60},{id:"coffee_table_round",group:"furniture",category:"coffee_table",w:80,h:80},{id:"coffee_table_oval",group:"furniture",category:"coffee_table",w:120,h:60},{id:"coffee_table_rounded",group:"furniture",category:"coffee_table",w:120,h:60},{id:"table_dining",group:"furniture",category:"dining_table",w:160,h:90},{id:"table_round",group:"furniture",category:"dining_table",w:110,h:110},{id:"table_dining_oval",group:"furniture",category:"dining_table",w:180,h:100},{id:"table_dining_rounded",group:"furniture",category:"dining_table",w:160,h:90},{id:"desk",group:"furniture",category:"work_table",w:140,h:70},{id:"desk_corner",group:"furniture",category:"work_table",w:160,h:160},{id:"chair",group:"furniture",category:"chair",w:50,h:50},{id:"chair_bar",group:"furniture",category:"chair",w:45,h:48},{id:"armchair",group:"furniture",category:"armchair",w:90,h:90},{id:"armchair_office",group:"furniture",category:"armchair",w:65,h:65},{id:"sofa",group:"furniture",category:"sofa",w:180,h:90},{id:"sofa_three_seat",group:"furniture",category:"sofa",w:240,h:90},{id:"sofa_corner_right",group:"furniture",category:"sofa",w:260,h:170},{id:"bed_single",group:"furniture",category:"bed",w:90,h:200},{id:"bed_double",group:"furniture",category:"bed",w:160,h:200},{id:"nightstand",group:"furniture",category:"nightstand",w:50,h:40},{id:"cabinet_tv",group:"furniture",category:"nightstand",w:140,h:45},{id:"cabinet_shoe",group:"furniture",category:"nightstand",w:80,h:35},{id:"cabinet_sink",group:"furniture",category:"nightstand",w:80,h:50},{id:"bookshelf",group:"furniture",category:"wardrobe",w:100,h:35},{id:"wall_unit",group:"furniture",category:"wardrobe",w:240,h:45},{id:"wardrobe",group:"furniture",category:"wardrobe",w:180,h:60},{id:"kitchen_floor",group:"furniture",category:"kitchen_cabinet",w:60,h:60},{id:"kitchen_floor_corner",group:"furniture",category:"kitchen_cabinet",w:90,h:90},{id:"kitchen_wall",group:"furniture",category:"kitchen_cabinet",w:60,h:35},{id:"kitchen_wall_corner",group:"furniture",category:"kitchen_cabinet",w:60,h:60},{id:"shelf_floor",group:"furniture",category:"shelving",w:100,h:35},{id:"shelf_wall",group:"furniture",category:"shelving",w:100,h:25},{id:"cooktop_two",group:"appliance",category:"cooktop",w:30,h:50},{id:"stove",group:"appliance",category:"cooktop",w:60,h:60},{id:"tv",group:"appliance",category:"tv",w:120,h:28},{id:"tv_wall",group:"appliance",category:"tv",w:120,h:15},{id:"toilet",group:"sanitary",category:"toilet",w:40,h:70},{id:"toilet_built_in",group:"sanitary",category:"toilet",w:40,h:55},{id:"bathtub",group:"sanitary",category:"bathtub",w:170,h:75},{id:"bathtub_corner",group:"sanitary",category:"bathtub",w:140,h:140},{id:"bidet",group:"sanitary",category:"bidet",w:40,h:60},{id:"bidet_built_in",group:"sanitary",category:"bidet",w:40,h:50},{id:"kitchen_sink",group:"sanitary",category:"kitchen_sink",w:60,h:50},{id:"kitchen_sink_double",group:"sanitary",category:"kitchen_sink",w:90,h:50},{id:"fridge",group:"appliance",category:"fridge",w:60,h:65},{id:"dishwasher",group:"appliance",category:"dishwasher",w:60,h:60},{id:"washer",group:"appliance",category:"washer",w:60,h:60},{id:"dryer",group:"appliance",category:"dryer",w:60,h:60},{id:"ac",group:"appliance",category:"air_conditioner",w:90,h:25},{id:"water_heater",group:"appliance",category:"boiler",w:45,h:45},{id:"shower",group:"sanitary",category:"shower",w:90,h:90},{id:"sink",group:"sanitary",category:"sink",w:60,h:45},{id:"stairs",group:"other",category:"stairs",w:100,h:280},{id:"fireplace",group:"other",category:"fireplace",w:120,h:40},{id:"plant",group:"other",category:"plant",w:40,h:40},{id:"rug",group:"other",category:"rug",w:200,h:140},{id:"computer",group:"appliance",category:"computer",w:120,h:60},{id:"hood",group:"appliance",category:"hood",w:60,h:50},{id:"oven",group:"appliance",category:"oven",w:60,h:60},{id:"cactus",group:"other",category:"plant",w:70,h:120}].map(e=>({id:e.id,group:e.group,category:e.category,w:e.w,h:e.h})),Hl=new Map(Nl.map(e=>[e.id,e]));function Ll(e){return e&&Hl.get(e)||null}function Bl(e){return Hl.has(e)}function ql(e){return Nl.filter(t=>t.group===e)}function jl(e){const t=Ll(e);return t?{w:t.w,h:t.h}:{w:60,h:60}}function Wl(e,t,i=rl,n=1e3){const r=Number(t)>0?Number(t):5;return(Number(e)||0)/r*i/n}const Ul=5e-4,Gl=tl;function Vl(e){return Number.isFinite(e)?Math.max(Ul,Math.min(Gl,e)):Ul}function Kl(e){return Number.isFinite(e)?Math.max(1,Math.min(1e4,e)):1}function Yl(e,t){return Ll(e)?Ol.art(e,t)??null:null}function Xl(e,t,i=1){const n=Number(e),r=Number(i),o=Number.isFinite(n)&&n>0?n:Number.isFinite(r)&&r>0?r:1,s=Number(t),a=o*(Number.isFinite(s)&&s>0?s:1);return Number.isFinite(a)&&a>0?a:o}function Zl(e,t,i,n,r){const o=e+i/2,s=t+n/2,a=(Number(r)||0)*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=(e,t)=>{const i=e-o,n=t-s;return[o+i*l-n*c,s+i*c+n*l]};return[h(e,t),h(e+i,t),h(e+i,t+n),h(e,t+n)]}function Jl(e,t,i,n,r,o,s){const a=Number.isFinite(s)&&s>0?s:1e-6,l=(Number(e.angle)||0)*Math.PI/180,c=Math.cos(l),h=Math.sin(l),d=-Math.sin(l),u=Math.cos(l),p=e.x+e.w/2,_=e.y+e.h/2,m=t>0?-e.w/2:t<0?e.w/2:0,g=i>0?-e.h/2:i<0?e.h/2:0,f=p+m*c+g*d,v=_+m*h+g*u,y=n-f,b=r-v,w=t?(y*c+b*h)*(t>0?1:-1):e.w,k=i?(y*d+b*u)*(i>0?1:-1):e.h;let x=t?Math.abs(w):e.w,S=i?Math.abs(k):e.h;if(o&&t&&i){const t=x/Math.max(e.w,a),i=S/Math.max(e.h,a),n=Math.abs(t-1)>=Math.abs(i-1)?t:i,r=Math.max(a/e.w,a/e.h),o=Math.max(r,Number.isFinite(n)?n:r);x=e.w*o,S=e.h*o}x=Math.max(a,Number.isFinite(x)?x:a),S=Math.max(a,Number.isFinite(S)?S:a);const $=!!t&&w<0,M=!!i&&k<0,R=t?(t>0?1:-1)*($?-1:1):0,C=i?(i>0?1:-1)*(M?-1:1):0,T=f+R*(x/2)*c+C*(S/2)*d,D=v+R*(x/2)*h+C*(S/2)*u,A=!!e.flip_h!==$,P=!!e.flip_v!==M;return{x:T-x/2,y:D-S/2,w:x,h:S,...Number(e.angle)?{angle:Number(e.angle)}:{},...A?{flip_h:!0}:{},...P?{flip_v:!0}:{}}}function Ql(e,t,i,n){let r=Number(e)+(Number(i)-Number(t));if([r,t,i].every(Number.isFinite)||(r=0),n){const e=r/45;r=45*(e<0?-Math.round(Math.abs(e)):Math.round(e))}return r=(r%360+360)%360,r>180?r-360:r}function ec(e,t,i,n,r){const o=e.x*t,s=e.y*i,a=e.w*t,l=e.h*i,c=o+a/2,h=s+l/2,d=o+(e.flip_h?a:0),u=s+(e.flip_v?l:0),p=(e.flip_h?-1:1)*a/n,_=(e.flip_v?-1:1)*l/r,m=Number(e.angle)||0;return(m?`rotate(${m} ${c} ${h}) `:"")+`translate(${d} ${u}) scale(${p} ${_})`}function tc(e,t,i,n=.1){if("string"==typeof e&&!e.trim())return null;const r=Number(e);if(!Number.isFinite(r)||0===r)return null;const o=r*(t?30.48:100),s=Math.abs(o);return si?null:o}function ic(e,t,i){const n=Math.abs(Number(e))/(i?30.48:100),r=Number(n.toFixed(6));return String(t?-r:r)}const nc=15e3,rc=2e3,oc=new WeakMap;function sc(e,t){let i=oc.get(e);if(!i){const t=new Set;i={hiddenAt:"hidden"===e.visibilityState?Date.now():0,token:0,subscribers:t,onVisibility:()=>{const t=oc.get(e);if(!t)return;const i=Date.now();if("hidden"===e.visibilityState){t.hiddenAt||(t.hiddenAt=i);const e={kind:"hidden",token:t.token,at:i,hiddenFor:0,long:!1};for(const i of[...t.subscribers])i(e);return}const n=t.hiddenAt?Math.max(0,i-t.hiddenAt):0;t.hiddenAt=0,t.token++;const r={kind:"visible",token:t.token,at:i,hiddenFor:n,long:n>=nc};for(const e of[...t.subscribers])e(r)},onPageShow:t=>{const i=oc.get(e);if(!i)return;const n=Date.now();i.token++;const r={kind:"pageshow",token:i.token,at:n,hiddenFor:0,long:!!t.persisted,persisted:!!t.persisted};for(const e of[...i.subscribers])e(r)}},oc.set(e,i),e.addEventListener("visibilitychange",i.onVisibility),e.defaultView?.addEventListener("pageshow",i.onPageShow)}return i.subscribers.add(t),()=>{const i=oc.get(e);i&&(i.subscribers.delete(t),i.subscribers.size||(e.removeEventListener("visibilitychange",i.onVisibility),e.defaultView?.removeEventListener("pageshow",i.onPageShow),oc.delete(e)))}}const ac={now:()=>Date.now(),setTimeout:(e,t)=>window.setTimeout(e,t),clearTimeout:e=>window.clearTimeout(e),requestAnimationFrame:e=>window.requestAnimationFrame(e),cancelAnimationFrame:e=>window.cancelAnimationFrame(e)};class lc{constructor(e,t=ac){this.onChange=e,this.clock=t,this._state="steady",this._token=0,this._frameFingerprint="",this._hasCompleteFrame=!1,this._overlayPhase="none",this._recoveryReason=null,this._overlayTimer=0,this._overlayRaf=0,this._overlayOpaqueAt=0,this._barrierRafs=new Set,this._trace=[],this._disposed=!1}get state(){return this._state}get token(){return this._token}get frameFingerprint(){return this._frameFingerprint}get hasCompleteFrame(){return this._hasCompleteFrame}get overlayPhase(){return this._overlayPhase}get overlayVisible(){return"none"!==this._overlayPhase}get overlayBlocksInteraction(){return this.overlayVisible}get recoveryReason(){return this._recoveryReason}get trace(){return this._trace.map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}note(e,t={}){this.record(e,void 0,t)}record(e,t,i={}){this._trace.push({at:this.clock.now(),token:this._token,event:e,state:this._state,...t?{reason:t}:{},...i}),this._trace.length>80&&this._trace.splice(0,this._trace.length-80)}changed(){this._disposed||this.onChange()}adoptCompleteFrame(e){e&&(this._hasCompleteFrame=!0,this._frameFingerprint=e,this._state="steady",this._recoveryReason=null,this.clearOverlay(),this.record("frame-adopted"),this.changed())}markCompleteFrame(e){e&&(this._hasCompleteFrame=!0,this._frameFingerprint=e,this._state="steady",this._recoveryReason=null,this.clearOverlay(),this.record("frame-complete"),this.changed())}refreshCompleteFrame(e){!this._disposed&&this._hasCompleteFrame&&"steady"===this._state&&e&&e!==this._frameFingerprint&&(this._frameFingerprint=e,this.record("frame-refreshed"))}visibility(e){return"hidden"===e.kind?(this.record("visibility-hidden"),this._token):e.long||"visible"!==e.kind&&"pageshow"!==e.kind?this.beginCandidate("pageshow"===e.kind?"pageshow":"long-resume"):(this.record("pageshow"===e.kind?"pageshow-noop":"visibility-visible-quick"),this._token)}beginCandidate(e,t="plan"){return this._token++,this._recoveryReason=t,this._hasCompleteFrame?(this._state="connection"===t?"offline-stale":"holding",this.clearOverlay()):this.overlayVisible?this._state="overlay-visible":(this._state="overlay-pending",this.scheduleOverlay(t)),this.record("candidate-start",e),this.changed(),this._token}connectionLost(){return this.beginCandidate("connection-lost","connection")}candidateReady(e){return!this._disposed&&e===this._token&&(this._state="candidate-ready",this.record("candidate-ready"),this.changed(),!0)}async commitAfterPaint(e,t){if(this._disposed||e!==this._token)return!1;let i=!0;const n=(async()=>{for(await t.updateComplete();i&&!this._disposed&&e===this._token;)if(t.stageValid()&&t.assetsReady()){if(await this.nextFrame(),e!==this._token||!t.stageValid()||!t.assetsReady())continue;if(await this.nextFrame(),e===this._token&&t.stageValid()&&t.assetsReady())return!0}else await this.nextFrame();return!1})();let r=0;const o=new Promise(e=>{r=this.clock.setTimeout(()=>e({ready:!1,timedOut:!0}),rc)}),s=await Promise.race([n.then(e=>({ready:e,timedOut:!1})),o]);return i=!1,this.clock.clearTimeout(r),!this._disposed&&e===this._token&&(!(!s.ready&&!s.timedOut)&&(s.ready?(this._hasCompleteFrame=!0,this._frameFingerprint=t.frameFingerprint(),this.record("paint-barrier"),this.finishOverlayAfterCommit(),!0):(this.record("paint-barrier-timeout"),this._hasCompleteFrame?(this._state="connection"===this._recoveryReason?"offline-stale":"steady",this.clearOverlay()):(this._state="recovery-error","opaque"!==this._overlayPhase&&this.showOverlayNow()),this.changed(),!1)))}retry(e=this._recoveryReason||"plan"){return this.beginCandidate("retry",e)}nextFrame(){return new Promise(e=>{const t=this.clock.requestAnimationFrame(()=>{this._barrierRafs.delete(t),e()});this._barrierRafs.add(t)})}scheduleOverlay(e){this.clearOverlayTimer(),this._recoveryReason=e,this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._hasCompleteFrame||"overlay-pending"!==this._state&&"candidate-ready"!==this._state||(this._state="overlay-visible",this._overlayPhase="entering",this.record("overlay-enter"),this.changed(),this._overlayRaf=this.clock.requestAnimationFrame(()=>{this._overlayRaf=0,"entering"===this._overlayPhase&&(this._overlayPhase="fading-in",this.changed(),this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,"fading-in"===this._overlayPhase&&(this._overlayPhase="opaque",this._overlayOpaqueAt=this.clock.now(),this.record("overlay-opaque"),this.changed())},150))}))},150)}showOverlayNow(){this.clearOverlayTimer(),this._overlayPhase="opaque",this._overlayOpaqueAt=this.clock.now(),this.record("overlay-error")}finishOverlayAfterCommit(){if(this.clearOverlayTimer(),"none"===this._overlayPhase||"entering"===this._overlayPhase||"fading-in"===this._overlayPhase)return this.clearOverlay(),this._state="steady",this._recoveryReason=null,this.record("candidate-committed"),void this.changed();const e=Math.max(0,this._overlayOpaqueAt+250-this.clock.now());this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._overlayPhase="leaving",this.record("overlay-leave"),this.changed(),this._overlayTimer=this.clock.setTimeout(()=>{this._overlayTimer=0,this._overlayPhase="none",this._state="steady",this._recoveryReason=null,this.record("candidate-committed"),this.changed()},180)},e)}clearOverlayTimer(){this._overlayTimer&&this.clock.clearTimeout(this._overlayTimer),this._overlayTimer=0}clearOverlay(){this.clearOverlayTimer(),this._overlayRaf&&this.clock.cancelAnimationFrame(this._overlayRaf),this._overlayRaf=0,this._overlayPhase="none",this._overlayOpaqueAt=0}dispose(){this._disposed=!0,this._token++,this.clearOverlay();for(const e of this._barrierRafs)this.clock.cancelAnimationFrame(e);this._barrierRafs.clear()}}function cc(e){let t=2166136261,i=2654435769;const n=new WeakSet,r=e=>{for(let n=0;n>>0)+(i>>>2)}},o=e=>{if(null===e)return void r("n");const t=typeof e;if("string"===t)return void r(`s${e.length}:${e}`);if("number"===t)return void r(`d${Number.isNaN(e)?"NaN":String(e)}`);if("boolean"===t)return void r(e?"t":"f");if("undefined"===t)return void r("u");if("object"!==t)return void r(`${t}:${String(e)}`);const i=e;if(n.has(i))r("[cycle]");else{if(n.add(i),Array.isArray(e)){r("[");for(const t of e)o(t);return r("]"),void n.delete(i)}r("{");for(const t of Object.keys(e).sort())r(t),o(e[t]);r("}"),n.delete(i)}};return o(e),`${(t>>>0).toString(16).padStart(8,"0")}${(i>>>0).toString(16).padStart(8,"0")}`}function hc(e){return cc(e)}const dc=new WeakMap;class uc{constructor(e,t=()=>Date.now()){this.onUpdate=e,this.now=t,this.fallbackAuthority={},this.referenceOwner={},this.referenced=new Set,this.queued=new Set,this.disposed=!1,this.sharedUpdate=()=>{this.disposed||this.onUpdate()}}bind(e){const t=((e,t)=>{const i=e?.connection||e?.callWS||t;return!i||"object"!=typeof i&&"function"!=typeof i?t:i})(e,this.fallbackAuthority);return this.shared&&this.authority===t||(this.shared&&(this.shared.listeners.delete(this.sharedUpdate),this.shared.references.delete(this.referenceOwner)),this.authority=t,this.shared=(e=>{let t=dc.get(e);return t||(t={signed:{},queued:new Set,inFlight:new Map,retry:new Map,listeners:new Set,settlers:new Set,references:new Map},dc.set(e,t)),t})(t),this.disposed||(this.shared.listeners.add(this.sharedUpdate),this.shared.references.set(this.referenceOwner,new Set(this.referenced)))),this.shared}start(e,t){this.disposed=!1,this.referenced=new Set(t());const i=this.bind(e());i.listeners.add(this.sharedUpdate),i.references.set(this.referenceOwner,new Set(this.referenced)),this.stopTimer(),this.resignTimer=setInterval(()=>this.resign(e(),t()),288e5)}dispose(){if(this.disposed=!0,this.stopTimer(),clearTimeout(this.batchTimer),this.shared){this.shared.listeners.delete(this.sharedUpdate),this.shared.references.delete(this.referenceOwner);for(const e of this.queued)this.shared.queued.delete(e)}this.queued.clear()}invalidate(e){const t=this.bind(e);clearTimeout(this.batchTimer),this.queued.clear(),t.queued.clear(),t.inFlight.clear(),t.retry.clear(),t.signed={}}stopTimer(){void 0!==this.resignTimer&&clearInterval(this.resignTimer),this.resignTimer=void 0}display(e,t){const i=Hn(t);if(!i.startsWith("/api/houseplan/content/"))return i;const n=this.bind(e);this.referenced.add(i),n.references.set(this.referenceOwner,new Set(this.referenced));const r=n.signed[i],o=r?this.now()-r.at:1/0;return o{const t=[...this.queued];this.queued.clear();for(const e of t)i.queued.delete(e);this.sign(e,t)},30))}sign(e,t){if(!t.length||!e?.callWS)return;const i=this.bind(e);for(const n of function(e,t){const i=Math.max(1,Math.floor(t)),n=[];for(let t=0;t{const n=i.inFlight.get(e);return!(void 0!==n&&t-n<15e3)&&(i.inFlight.set(e,t),!0)});r.length&&e.callWS({type:"houseplan/content/sign",paths:r}).then(e=>{const t=this.now();let n=0,o=!1;for(const s of r){const r=e?.urls?.[s];if("string"==typeof r&&r){const e=i.signed[s];e?.loaded&&e.url!==r?(e.pending={url:r,at:t},this.preloadReplacement(i,s,r,t)):(i.signed[s]={url:r,at:t,loaded:e?.url===r&&!!e.loaded},o=!0),i.retry.delete(s),n++}else this.backOff(i,s)}if(n&&(this.trimShared(i),o))for(const e of[...i.listeners])e()}).catch(()=>{for(const e of r)this.backOff(i,e)}).finally(()=>{for(const e of r)i.inFlight.get(e)===t&&i.inFlight.delete(e);for(const e of[...i.settlers])e()})}}preloadReplacement(e,t,i,n){const r=()=>{const r=e.signed[t];if(r?.pending?.url===i){e.signed[t]={url:i,at:n,loaded:!0},e.retry.delete(t),this.trimShared(e);for(const t of[...e.listeners])t()}},o=()=>{const n=e.signed[t];n?.pending?.url===i&&(delete n.pending,this.backOff(e,t))};if("undefined"==typeof Image)return void r();const s=new Image;s.onload=()=>{("function"==typeof s.decode?s.decode():Promise.resolve()).then(r).catch(o)},s.onerror=o,s.src=i}preloadCurrentImage(e,t,i){if(i.loaded)return Promise.resolve(!0);if(i.preload)return i.preload;if("undefined"==typeof Image)return i.loaded=!0,Promise.resolve(!0);const n=i.url;return i.preload=new Promise(r=>{const o=new Image;let s=!1;const a=o=>{if(s)return;s=!0,clearTimeout(l);const a=e.signed[t];if(a===i&&delete a.preload,o&&a===i&&a.url===n){a.loaded=!0;for(const t of[...e.listeners])t();r(!0)}else o||a!==i||this.backOff(e,t),r(!1)};o.onload=()=>{("function"==typeof o.decode?o.decode():Promise.resolve()).then(()=>a(!0)).catch(()=>a(!1))},o.onerror=()=>a(!1);const l=setTimeout(()=>a(!1),rc);o.src=n}),i.preload}prepareImage(e,t){const i=Hn(t);if(!i.startsWith("/api/houseplan/content/"))return Promise.resolve(!0);const n=this.bind(e),r=()=>{const t=n.signed[i];if(t&&this.now()-t.atthis.now()&&!n.inFlight.has(i)&&!n.queued.has(i)?Promise.resolve(!1):null},o=r();return o?(s=o,new Promise(e=>{let t=!1;const i=i=>{t||(t=!0,clearTimeout(n),e(i))},n=setTimeout(()=>i(!1),rc);s.then(i).catch(()=>i(!1))})):new Promise(e=>{let t=!1,i=null;const o=i=>{t||(t=!0,clearTimeout(a),n.settlers.delete(s),e(i))},s=()=>{t||i||(i=r(),i&&i.then(o).catch(()=>o(!1)))},a=setTimeout(()=>o(!1),rc);n.settlers.add(s),s()});var s}backOff(e,t){const i=e.retry.get(t)?.delay||0,n=Math.min(6e4,i?2*i:2e3);e.retry.set(t,{notBefore:this.now()+n,delay:n})}trimShared(e){const t=Object.entries(e.signed);if(t.length<=512)return;const i=new Set(e.inFlight.keys());for(const t of e.references.values())for(const e of t)i.add(e);for(const[e,n]of t)(n.pending||n.preload)&&i.add(e);t.sort((e,t)=>t[1].at-e[1].at);const n=t.filter(([e])=>i.has(e));for(const e of t){if(n.length>=512)break;i.has(e[0])||n.push(e)}e.signed=Object.fromEntries(n)}resign(e,t){const i=this.bind(e);this.referenced=new Set(t),i.references.set(this.referenceOwner,new Set(this.referenced));const n=this.now(),r=new Set;for(const e of i.references.values())for(const t of e)r.add(t);const o={};for(const[e,t]of Object.entries(i.signed))r.has(e)&&n-t.at!!o[e]&&!o[e].pending))}markLoaded(e,t,i){const n=Hn(t);if(!n.startsWith("/api/houseplan/content/"))return;const r=this.bind(e).signed[n];if(r&&(!i||r.url===i)&&!r.loaded){r.loaded=!0;for(const t of[...this.bind(e).listeners])t()}}isReady(e,t){const i=Hn(t);if(!i.startsWith("/api/houseplan/content/"))return!0;const n=this.bind(e).signed[i];return!!n&&this.now()-n.at=2&&(this._sequenceMultitouch=!0,this._postGestureClickBlocked=!0))}pointerTerminal(e,t){if("touch"!==t)return!1;const i=this._sequenceMultitouch;return this._activeTouchPointers.delete(e),0===this._activeTouchPointers.size&&(this._sequenceMultitouch=!1),i}reset(){this._activeTouchPointers.clear(),this._sequenceMultitouch=!1,this._postGestureClickBlocked=!1}}const _c=1e-7,mc=(e,t)=>{const i=e.x-t.x,n=e.y-t.y;return i*i+n*n};function gc(e){const t=Math.max(0,e.floorRadius);return{left:Math.min(e.painted.left,e.center.x-t),top:Math.min(e.painted.top,e.center.y-t),right:Math.max(e.painted.right,e.center.x+t),bottom:Math.max(e.painted.bottom,e.center.y+t)}}function fc(e,t){let i=null,n=Number.POSITIVE_INFINITY;for(const r of e){const e=mc(t,r.center);(efunction(e,t){const i=Math.max(0,t.right-t.left),n=Math.max(0,t.bottom-t.top);if(i<=0||n<=0)return!1;const r=Math.min(i,n)/2,o=Math.max(t.left+r,Math.min(t.right-r,e.x)),s=Math.max(t.top+r,Math.min(t.bottom-r,e.y));return mc(e,{x:o,y:s})<=r*r+_c}(t,e.painted));if(i.length)return fc(i,t);return fc(e.filter(e=>{const i=Math.max(0,e.floorRadius);return mc(t,e.center)<=i*i+_c}),t)}class yc{constructor(e,t=44){this.cellSize=t,this.buckets=new Map;const i=Number.isFinite(t)&&t>0?t:44;this.cellSize=i;for(const t of e){const e=gc(t),n=Math.floor(e.left/i),r=Math.floor(e.right/i),o=Math.floor(e.top/i),s=Math.floor(e.bottom/i);for(let e=n;e<=r;e++)for(let i=o;i<=s;i++){const n=`${e}:${i}`,r=this.buckets.get(n);r?r.push(t):this.buckets.set(n,[t])}}}resolve(e){const t=`${Math.floor(e.x/this.cellSize)}:${Math.floor(e.y/this.cellSize)}`;return vc(this.buckets.get(t)||[],e)}}class bc{constructor(){this.active=new Map,this.released=new Map}begin(e,t){this.released.delete(e),this.active.set(e,t)}owner(e){return this.active.get(e)||null}release(e){const t=this.active.get(e)||null;if(!t)return this.released.get(e)||null;for(this.active.delete(e),this.released.set(e,t);this.released.size>16;){const e=this.released.keys().next().value;if(void 0===e)break;this.released.delete(e)}return t}consumeClick(e){const t=this.released.get(e)||null;return this.released.delete(e),t}cancel(e){const t=this.active.get(e)||null;return this.active.delete(e),t}clear(){this.active.clear(),this.released.clear()}}class wc{constructor(){this.index=null,this.pointers=new bc,this.hoverId=null,this.hoverElement=null}invalidate(){this.index=null}reset(e){this.invalidate(),this.pointers.clear(),this.hover(e,null)}clearPointers(){this.pointers.clear()}cancel(e){return this.pointers.cancel(e)}release(e){return this.pointers.release(e)}indexFor(e){if(this.index)return this.index;const t=[];for(const i of e.querySelectorAll('.devlayer > .dev[data-hp="device"][data-id]')){const e=i.querySelector(".device-shell-frame"),n=i.getBoundingClientRect(),r=e?.getBoundingClientRect();!i.dataset.id||!i.isConnected||!r||n.width<=0||n.height<=0||r.width<=0||r.height<=0||t.push({id:i.dataset.id,center:{x:n.left+n.width/2,y:n.top+n.height/2},painted:{left:r.left,top:r.top,right:r.right,bottom:r.bottom},floorRadius:Math.max(22,Math.min(r.width,r.height)/2)})}return this.index=new yc(t),this.index}at(e,t,i,n,r){const o=this.indexFor(e).resolve({x:n,y:r})?.id;return o&&t.find(e=>e.id===o&&e.space===i)||null}byId(e,t,i){return i&&e.find(e=>e.id===i&&e.space===t)||null}begin(e,t,i,n,r){const o=this.at(e,t,i,n.clientX,n.clientY)||r;return this.pointers.begin(n.pointerId,o.id),o}pointer(e,t,i,n,r){const o=n.pointerId;return(Number.isFinite(o)?this.byId(t,i,this.pointers.owner(o)):null)||this.at(e,t,i,n.clientX,n.clientY)||r}click(e,t,i,n,r){if(!(n instanceof PointerEvent))return r;const o=n,s=Number.isFinite(o.pointerId)?this.pointers.consumeClick(o.pointerId):null;return this.byId(t,i,s)||this.at(e,t,i,o.clientX,o.clientY)||r}hover(e,t){this.hoverId===t&&this.hoverElement?.isConnected||(this.hoverElement?.removeAttribute("data-hp-device-hover"),this.hoverId=t,this.hoverElement=t&&[...e.querySelectorAll('.devlayer > .dev[data-hp="device"][data-id]')].find(e=>e.dataset.id===t)||null,this.hoverElement?.setAttribute("data-hp-device-hover",""))}}function kc(e,t){if(t)return e.find(e=>e.id===t)}function xc(e,t){return{id:e,title:t,plan_url:null,view_box:[0,0,1,1],rooms:[],wall_segments:[]}}function Sc(e="file"){const t="draw"===e;return{source:e,showBorders:t,showNames:t,displayTouched:!1}}function $c(e,t){if(e.displayTouched)return{...e,source:t};const i="draw"===t;return{...e,source:t,showBorders:i,showNames:i}}function Mc(e,t,i){return{...e,[t]:i,displayTouched:!0}}function Rc(e){const t=String(e??"").trim().replace(",",".");if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(t))return null;const i=Number(t);return Number.isFinite(i)?i:null}function Cc(e,t){const i=e=>{if(""===String(e??"").trim())return{valid:!0,value:null};const t=Rc(e);return{valid:null!==t,value:t}},n=i(e),r=i(t);return n.valid&&r.valid?null!==n.value&&null!==r.value&&n.value>r.value?{valid:!0,min:r.value,max:n.value}:{valid:!0,min:n.value,max:r.value}:{valid:!1,min:n.value,max:r.value}}function Tc(e,t,i,n,r,o){const s=Cc(n,r);return pn(e,t,o&&s.valid?{settings:{...i.settings||{},temp_min:s.min,temp_max:s.max}}:i)}function Dc(e){const t=e=>"number"==typeof e&&Number.isFinite(e)?String(e):"";return[t(e?.temp_min),t(e?.temp_max)]}function Ac(e,t,i){const n=Cc(t,i);return!!n.valid&&(null===n.min?delete e.temp_min:e.temp_min=n.min,null===n.max?delete e.temp_max:e.temp_max=n.max,!0)}var Pc="M11,18H13V16H11V18M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,6A4,4 0 0,0 8,10H10A2,2 0 0,1 12,8A2,2 0 0,1 14,10C14,12 11,11.75 11,15H13C13,12.75 16,12.5 16,10A4,4 0 0,0 12,6Z";function Fc(e,t,i){return[e[0]*t+e[1]*i+e[2],e[3]*t+e[4]*i+e[5]]}function zc(e,t){let i=0;for(const[n,r]of t){const t=Fc(e,n[0],n[1]);i=Math.max(i,Math.hypot(t[0]-r[0],t[1]-r[1]))}return i}const Ic=e=>{if(null==e||""===e)return null;const t=Number(e);return Number.isFinite(t)?t:null},Oc=e=>{const t=e,i=Ic(Array.isArray(t)?t[0]:t?.x),n=Ic(Array.isArray(t)?t[1]:t?.y);return null==i||null==n?null:[i,n]};function Ec(e){if(!Array.isArray(e))return null;const t=[];for(const i of e){const e=Oc(i);if(!e)return null;t.push(e)}if(t.length>1){const e=t[0],i=t[t.length-1];e[0]===i[0]&&e[1]===i[1]&&t.pop()}if(t.length<3)return null;let i=0,n=0,r=0;for(let e=0;ee+t[0],0)/t.length,t.reduce((e,t)=>e+t[1],0)/t.length]:[n/(3*i),r/(3*i)]}function Nc(e){if(!Array.isArray(e))return null;const t=[];for(const i of e){const e=Oc(i);if(!e)return null;t.push(e)}if(t.length>1){const e=t[0],i=t[t.length-1];e[0]===i[0]&&e[1]===i[1]&&t.pop()}const i=Ec(t);if(!i)return null;const n=t.map(e=>e[0]),r=t.map(e=>e[1]);return{centroid:i,bbox:[Math.min(...n),Math.min(...r),Math.max(...n),Math.max(...r)]}}function Hc(e){let t=e;if(t&&"object"==typeof t&&!Array.isArray(t)){const e=t;t=e.path??e.points??t}if(!Array.isArray(t)||!t.length)return[];let i=(t.some(e=>(e=>Array.isArray(e)?e.length>=2&&!Array.isArray(e[0])&&("object"!=typeof e[0]||null==e[0]):!!e&&"object"==typeof e&&("x"in e||"y"in e))(e))?[t]:t.filter(Array.isArray)).map(e=>e.map(Oc).filter(e=>null!=e)).filter(e=>e.length>=2);i.length>64&&(i=i.slice(-64));const n=i.reduce((e,t)=>e+t.length,0);if(n<=4e3)return i.map(e=>e.slice());const r=4e3-2*i.length,o=i.map(e=>e.length-2),s=o.reduce((e,t)=>e+t,0),a=o.map(e=>r*e/s),l=a.map(Math.floor);let c=r-l.reduce((e,t)=>e+t,0);const h=a.map((e,t)=>({index:t,fraction:e-Math.floor(e)})).sort((e,t)=>t.fraction-e.fraction||e.index-t.index);for(let e=0;efunction(e,t){if(t>=e.length)return e.slice();if(t<=2)return[e[0],e[e.length-1]];const i=[];for(let n=0;ne.slice()),i=t[t.length-1];return i?(i.length>2?i.pop():t.pop(),t):[]}const qc=e=>Number.isFinite(e[0])&&Number.isFinite(e[1]),jc=(e,t)=>e[0]===t[0]&&e[1]===t[1];function Wc(e){if(!e)return null;const t=e.vacuum_position||e.robot_position||null,i=t&&null!=Ic(t.x)&&null!=Ic(t.y)?{x:Ic(t.x),y:Ic(t.y),a:Ic(t.a??t.angle??t.theta)}:null,n=Hc(e.path?.path??e.path?.points??e.path),r=[],o=e.rooms,s=Array.isArray(o)?o.map((e,t)=>[String(e?.id??t),e]):o&&"object"==typeof o?Object.entries(o):[];for(const[e,t]of s){if(!t||"object"!=typeof t)continue;const i=String(t.name??t.label??"").trim(),n=[[Ic(t.cx),Ic(t.cy)],[Ic(t.center?.x),Ic(t.center?.y)],[Ic(t.x),Ic(t.y)]].find(([e,t])=>null!=e&&null!=t);let o=n?.[0]??null,s=n?.[1]??null;const a=Nc(t.outline),l=Ic(t.x0),c=Ic(t.y0),h=Ic(t.x1),d=Ic(t.y1),u=(null!=l&&null!=c&&null!=h&&null!=d?[Math.min(l,h),Math.min(c,d),Math.max(l,h),Math.max(c,d)]:null)||a?.bbox||null;if(null!=o&&null!=s||!a||([o,s]=a.centroid),null!=o&&null!=s||!u||(o=(u[0]+u[2])/2,s=(u[1]+u[3])/2),i&&null!=o&&null!=s){const t={id:e,name:i,cx:o,cy:s};u&&([t.x0,t.y0,t.x1,t.y1]=u),r.push(t)}}const a=function(e){return String(e.map_name??e.current_map??e.map_index??e.selected_map??"default")}(e);return i||r.length||n.length?{pos:i,path:n,rooms:r,mapId:a}:null}function Uc(e,t,i){return![e,t,i].every(Number.isFinite)||e<0||t<=0||i<=0?Number.POSITIVE_INFINITY:e/t*i}const Gc=40;function Vc(e,t,i){if(!e||!t)return null;const n=t.attributes||{},r=e.split(".")[0]||"",o=null!=i?.platform?String(i.platform):null,s=!!Oc(n.vacuum_position??n.robot_position),a=!(!n.rooms||"object"!=typeof n.rooms),l=Hc(n.path?.path??n.path?.points??n.path).length>0,c=[n.map_name,n.current_map,n.map_index,n.selected_map].some(e=>null!=e),h="xiaomi_cloud_map_extractor"===o,d=a||l||c;let u=null;if(s?u="compatible":h?u="known_xcme_incomplete":d?u="partial":"camera"===r&&(u="camera"),!u)return null;const p=s?"camera"===r?300:200:h?100:d?50:0;return{entityId:e,name:String(n.friendly_name||e),platform:o,category:u,hasPosition:s,hasRooms:a,hasPath:l,hasMapId:c,score:p}}const Kc=e=>e.toLowerCase().replace(/[\s_\-.,]+/g,"");function Yc(e,t){const i=new Set(t.map(Kc).filter(Boolean)),n=new Set;for(const t of e){const e=Kc(t.name||"");e&&i.has(e)&&n.add(e)}return n.size}function Xc(e,t){const i=new Map(t.map(e=>[Kc(e.name),e])),n=[],r=[];for(const t of e){const e=i.get(Kc(t.name));e&&(n.push([[t.cx,t.cy],[e.cx,e.cy]]),r.push(t.name))}if(n.length<3)return null;const o=function(e){if(e.length<3)return null;let t=0,i=0,n=0,r=0,o=0,s=0,a=0,l=0,c=0,h=0,d=0,u=0;for(const[[p,_],[m,g]]of e){if(![p,_,m,g].every(Number.isFinite))return null;t+=p*p,i+=p*_,n+=p,r+=_*_,o+=_,s+=1,a+=p*m,l+=_*m,c+=m,h+=p*g,d+=_*g,u+=g}const p=[t,i,n,i,r,o,n,o,s],_=e=>{const[t,i,n,r,o,s,a,l,c]=p,h=t*(o*c-s*l)-i*(r*c-s*a)+n*(r*l-o*a);if(!Number.isFinite(h)||Math.abs(h)<1e-9)return null;const d=[(o*c-s*l)/h,(n*l-i*c)/h,(i*s-n*o)/h,(s*a-r*c)/h,(t*c-n*a)/h,(n*r-t*s)/h,(r*l-o*a)/h,(i*a-t*l)/h,(t*o-i*r)/h];return[d[0]*e[0]+d[1]*e[1]+d[2]*e[2],d[3]*e[0]+d[4]*e[1]+d[5]*e[2],d[6]*e[0]+d[7]*e[1]+d[8]*e[2]]},m=_([a,l,c]),g=_([h,d,u]);if(!m||!g)return null;const f=[m[0],m[1],m[2],g[0],g[1],g[2]];return f.every(Number.isFinite)?f:null}(n);return o?{matrix:o,matched:r,residual:zc(o,n)}:null}function Zc(e,t,i){const n=e[e.length-1];if(n&&n[0]===t[0]&&n[1]===t[1])return e;if(e.push(t),e.length<=600)return e;let r=function(e,t){if(e.length<3)return e.slice();const i=new Uint8Array(e.length);i[0]=i[e.length-1]=1;const n=[[0,e.length-1]];for(;n.length;){const[r,o]=n.pop(),[s,a]=e[r],[l,c]=e[o],h=l-s,d=c-a,u=Math.hypot(h,d)||1e-9;let p=0,_=-1;for(let t=r+1;tp&&(p=i,_=t)}_>0&&p>t&&(i[_]=1,n.push([r,_],[_,o]))}const r=[];for(let t=0;t600&&(r=r.filter((e,t)=>t%2==0||t===r.length-1)),r}function Jc(e){return"cleaning"===e||"returning"===e||"on"===e}const Qc={0:[1,0],90:[0,1],180:[-1,0],270:[0,-1]};function eh(e){const[t,i]=Qc[e.rot]||[1,0],n=e.mir?-1:1;return[e.s*t*n,-e.s*i,e.ox,e.s*i*n,e.s*t,e.oy]}function th(e){const t=e[0]*e[4]-e[1]*e[3];if(!Number.isFinite(t)||Math.abs(t)<1e-12)return null;const i=t<0,n=Math.sqrt(Math.abs(t));let r=180*Math.atan2(-e[1],e[4])/Math.PI;return r=(90*Math.round(r/90)%360+360)%360,{ox:e[2],oy:e[5],s:n,rot:r,mir:i}}function ih(e,t){const i=[],n=[];for(const t of e)null!=t.x0?(i.push(t.x0,t.x1),n.push(t.y0,t.y1)):(i.push(t.cx),n.push(t.cy));if(!i.length)return{ox:t[0]+t[2]/2,oy:t[1]+t[3]/2,s:t[2]/1e4,rot:0,mir:!0};const r=Math.min(...i),o=Math.max(...i),s=Math.min(...n),a=Math.max(...n),l=Math.max(o-r,a-s)||1,c={ox:0,oy:0,s:.6*Math.min(t[2],t[3])/l,rot:0,mir:!0},h=eh(c),[d,u]=Fc(h,(r+o)/2,(s+a)/2);return c.ox=t[0]+t[2]/2-d,c.oy=t[1]+t[3]/2-u,c}function nh(e,t,i,n){const[r,o]=Fc(eh(t),i,n),s=eh({...e,ox:0,oy:0}),[a,l]=Fc(s,i,n);return{...e,ox:r-a,oy:o-l}}function rh(e){const t=e?.trail_mode;return"never"===t||"cleaning"===t||"always"===t?t:!1===e?.trail?"never":"cleaning"}const oh=e=>"number"==typeof e&&Number.isFinite(e);function sh(e){return Array.isArray(e)&&6===e.length&&e.every(oh)?[e[0],e[1],e[2],e[3],e[4],e[5]]:null}function ah(e,t,i){return"legacy:"+e+" "+t+" "+i}function lh(e,t,i,n){const r=t?.map_routes;if(Array.isArray(r))return r.filter(e=>e&&"string"==typeof e.id&&e.id).map(e=>({id:e.id,source:String(e.source??""),map_id:String(e.map_id??""),space:String(e.space??""),calibration:sh(e.calibration)}));const o="string"==typeof t?.source&&t.source?t.source:n||"";if(!o)return[];const s=t?.calibration;if(!s||"object"!=typeof s)return[];const a=[];for(const t of Object.keys(s)){const n=sh(s[t]);n&&a.push({id:ah(e,o,t),source:o,map_id:t,space:i,calibration:n})}return a}const ch=(e,t)=>e instanceof Map?e.get(t):e?.[t];function hh(e){const t=[];let i=!1,n="",r="";for(const o of e.routes){const s=ch(e.observed,o.source);void 0!==s&&(i=!0,n||(n=o.source,r=s),s===o.map_id&&t.push(o))}if(t.length>1)return{kind:"ambiguous",routeIds:t.map(e=>e.id).sort()};if(1===t.length){const i=t[0];if(e.spaceIds&&!e.spaceIds.has(i.space))return{kind:"missing_space",route:i};const n=sh(i.calibration);return n?{kind:"ready",route:{...i,calibration:n}}:{kind:"needs_calibration",route:i}}if(i)return{kind:"unmapped",source:n,mapId:r};const o=e.observed instanceof Map?[...e.observed.entries()]:Object.entries(e.observed||{});if(o.length){const e=o.slice().sort((e,t)=>e[0].localeCompare(t[0]))[0];return{kind:"unmapped",source:e[0],mapId:e[1]}}return{kind:"none"}}function dh(e,t,i){const n=new Set;for(const t of e)t.source&&n.add(t.source);for(const e of t)e&&n.add(e);const r={};for(const e of[...n].sort()){const t=i(e);void 0!==t&&(r[e]=t)}return r}function uh(e,t,i){if(!e)return null;const n="string"==typeof e.route_id?e.route_id:"";if(n)return t.find(e=>e.id===n)||null;const r=function(e,t,i){if(!e||"string"!=typeof e.map_id)return{kind:"orphan_run"};const n=e.map_id,r="string"==typeof i?i:"";let o=t.filter(e=>e.map_id===n);return r&&(o=o.filter(e=>e.source===r)),1===o.length?{kind:"adopted",route:o[0]}:0===o.length?{kind:"orphan_run"}:{kind:"ambiguous_run",routeIds:o.map(e=>e.id).sort()}}(e,t,i);return"adopted"===r.kind?r.route:null}function ph(e){const t="ready"===e.resolution.kind?e.resolution.route:null,i=t&&t.space===e.renderSpace?sh(t.calibration):null,n=uh(e.serverCurrent,e.routes,e.rootSource),r=!!t&&!!n&&n.id===t.id,o=uh(e.serverPrevious,e.routes,e.rootSource);return{live:i,currentRunMatches:r,previous:!!o&&o.space===e.renderSpace&&(e.explicitRoutes||!!t&&o.id===t.id)?sh(o.calibration):null}}const _h={availability:"available",status:"alarm",activity:"none"},mh=new Set(["motion","vibration","sound"]),gh=new Set(["occupancy","presence"]),fh=new Set(["door","window","garage_door","opening"]),vh=new Set(["running","power"]),yh=new Set(["smoke","gas","carbon_monoxide","moisture","safety","tamper","problem"]);const bh=new Set(["running","working","washing","rinsing","spinning","drying","heating","cooling","cleaning","cooking","playing","recording","pumping","irrigating","humidifying","dehumidifying","fan","preheating","defrosting"]),wh=new Set([...bh,"start","started","run","active","in_progress","wash","rinse","spin","dry"]),kh=new Set(["off","idle","paused","standby","docked","finished","complete","completed","stopped","ready","sleeping","stop","end","done","inactive"]),xh=new Set(["heat","cool","heat_cool","auto","dry","fan_only"]),Sh=e=>""===e||"unknown"===e||"unavailable"===e||"__missing__"===e,$h=e=>String(e??"").trim().toLowerCase(),Mh=e=>$h(e).replace(/[\s-]+/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,""),Rh=new Map([["run_state",0],["job_state",0],["operation_state",0],["activity_state",0],["machine_state",1],["running_state",1],["status",2],["device_status",2],["machine_status",2]]),Ch=new Set(["wifi","connection","signal","battery"]);function Th(e,t){const i=e?.entities?.[t]||{};if("config"===i.entity_category)return null;const n=String(t||"").split(".").slice(1).join("."),r=[i.translation_key,i.original_name,i.name],o=[...r,n];r.some(e=>$h(e))||o.push(e?.states?.[t]?.attributes?.friendly_name);const s=o.map(Mh).filter(Boolean);if(s.some(e=>e.split("_").some(e=>Ch.has(e))))return null;let a=null;for(const e of s)for(const[t,i]of Rh)(e===t||e.endsWith(`_${t}`))&&(a=null==a?i:Math.min(a,i));return a}const Dh=(e,t)=>null!=Th(e,t);function Ah(e,t){if(!t.startsWith("switch."))return!1;const i=e?.entities?.[t]||{},n=e?.states?.[t],r=t.slice(7).toLowerCase();if(/(?:^|_)(?:main_)?power$/.test(r))return!0;if([i.translation_key,i.original_name,i.name].map($h).some(e=>["power","main power","power switch","питание"].includes(e)))return!0;const o=$h(n?.attributes?.friendly_name);return/(?:^|[\s._-])(?:main[\s._-]+)?power$/.test(o)||/(?:^|[\s._-])питание$/.test(o)}function Ph(e){for(const t of["hvac_action","action","current_operation","run_state","job_state","operation","activity"]){const i=$h(e?.[t]);if(bh.has(i)||kh.has(i))return i}return""}function Fh(e,t){const i=e?.states?.[t],n=i?$h(i.state):"__missing__",r=String(t||"").split(".")[0],o=$h(i?.attributes?.device_class),s={eid:t,state:n,availability:Sh(n)?"unavailable":"available",status:"neutral",activity:"none",edge:"none"};if("unavailable"===s.availability)return s;if(function(e,t,i){return"alarm_control_panel"===e?"triggered"===i:"on"===i&&Yn(e,t)}(r,o,n))return{...s,status:"alarm"};if("binary_sensor"===r)return mh.has(o)?{...s,edge:"rising"}:gh.has(o)?{...s,activity:"on"===n?"presence":"none"}:fh.has(o)?{...s,status:"on"===n?"open":"neutral",edge:"rising"}:"moving"===o?{...s,activity:"on"===n?"transition":"none"}:vh.has(o)&&"on"===n?{...s,status:"working",activity:"running"}:s;if("cover"===r)return{...s,activity:"opening"===n||"closing"===n?"transition":"none",edge:"terminal_transition"};if("lock"===r)return{...s,status:"unlocked"===n||"open"===n?"open":"neutral",activity:"locking"===n||"unlocking"===n?"transition":"none",edge:"terminal_transition"};if("valve"===r)return{...s,status:["open","opening","closing"].includes(n)?"open":"neutral",activity:"opening"===n||"closing"===n?"transition":"none",edge:"terminal_transition"};if("climate"===r){const e=Ph(i.attributes),t=Array.isArray(i.attributes?.hvac_modes)?i.attributes.hvac_modes.map($h):[],r=!kh.has(n)&&(xh.has(n)||bh.has(n)||t.includes(n));return(e?bh.has(e):r)?{...s,status:"working",activity:"running"}:s}if(["light","switch","fan","humidifier"].includes(r))return"on"===n?{...s,status:"working",activity:"running"}:s;if("media_player"===r)return"off"===n?{...s,availability:"unavailable"}:s;if("vacuum"===r)return"cleaning"===n?{...s,status:"working",activity:"running"}:"returning"===n?{...s,status:"working",activity:"transition"}:s;if("script"===r)return"on"===n?{...s,status:"working",activity:"running"}:s;if("automation"===r)return s;if("button"===r||"event"===r)return{...s,edge:"change"};const a=Ph(i.attributes);return bh.has(a)||bh.has(n)&&!kh.has(n)?{...s,status:"working",activity:"running"}:s}function zh(e,t,i){const n=i.filter(t=>t.startsWith("switch.")&&!e?.entities?.[t]?.entity_category),r=t.find(t=>Ah(e,t));if(!(n.length>1&&!!r))return t.map(t=>Fh(e,t));const o=t.find(t=>t!==r&&Dh(e,t)),s=Fh(e,r);return"unavailable"===s.availability||"off"===s.state?t.map(t=>({eid:t,state:e?.states?.[t]?$h(e.states[t].state):"__missing__",availability:"unavailable",status:"neutral",activity:"none",edge:"none"})):t.map(t=>{if(t===o)return function(e,t){const i=e?.states?.[t],n=i?$h(i.state):"__missing__",r={eid:t,state:n,availability:Sh(n)?"unavailable":"available",status:"neutral",activity:"none",edge:"none"};if("unavailable"===r.availability)return r;const o=Ph(i?.attributes);return bh.has(o)||wh.has(n)&&!kh.has(n)?{...r,status:"working",activity:"running"}:r}(e,t);return{...t===r?s:Fh(e,t),status:"neutral",activity:"none",edge:"none"}})}function Ih(e){if(!e.length)return{availability:"available",status:"neutral",activity:"none"};const t=e.filter(e=>"available"===e.availability);if(!t.length)return{availability:"unavailable",status:"neutral",activity:"none"};if(t.some(e=>"alarm"===e.status))return _h;const i=t.some(e=>"working"===e.status)?"working":t.some(e=>"open"===e.status)?"open":"neutral",n=t.some(e=>"transition"===e.activity)?"transition":t.some(e=>"presence"===e.activity)?"presence":t.some(e=>"running"===e.activity)?"running":"none";return{availability:"available",status:i,activity:n}}function Oh(e,t){if(!(e=>!!e&&!Sh(e))(e)||"unavailable"===t.availability||e===t.state)return null;if("rising"===t.edge)return"off"===e&&"on"===t.state?"event":null;if("change"===t.edge)return"event";if("terminal_transition"===t.edge){const i=new Set([e,t.state]);if(i.has("closed")&&i.has("open")||i.has("locked")&&i.has("unlocked"))return"transition"}return null}const Eh=(e,t=0)=>{const i=Number(e);return Number.isInteger(i)&&i>=0?i:t},Nh=(e,t)=>{const i={rev:0,configRev:Eh(t),off:new Set};if(null==e)return{snapshot:i,valid:!1};const n=e.off;return!Number.isInteger(e.rev)||Number(e.rev)<0||!Number.isInteger(e.config_rev)||Number(e.config_rev)<0||!Array.isArray(n)||n.some(e=>"string"!=typeof e||!e)?{snapshot:i,valid:!1}:{snapshot:{rev:Number(e.rev),configRev:Number(e.config_rev),off:new Set(n)},valid:!0}};function Hh(e,t=0){return Nh(e,t).snapshot}function Lh(e,t,i,n){const r=Nh(t,i);return n&&r.valid&&r.snapshot.configRev===i?e.configRev===i&&r.snapshot.rev{try{const[i,n]=await Promise.all([e.callWS({type:"config/device_registry/list"}),e.callWS({type:"config/entity_registry/list"})]),r=Zh(i,"id"),o=Zh(n,"entity_id");if(!r||!o)throw new Error("invalid_registry_response");t.devices=r,t.entities=o,t.authoritative=!0,t.access="full",t.lastSuccess=Date.now(),t.error=void 0}catch(e){t.authoritative=!1,t.access="limited",t.error=function(e){if(e&&"object"==typeof e){const t=e;return String(t.message||t.code||t.error||"registry_unavailable")}return String(e||"registry_unavailable")}(e)}finally{t.revision++,t.loading=void 0,function(e){for(const t of[...e.listeners])try{t()}catch{}}(t)}})()),t.loading}function Qh(e,t){void 0===t.reloadTimer&&(t.reloadTimer=globalThis.setTimeout(()=>{t.reloadTimer=void 0,Jh(e,t)},80))}async function ed(e,t){if(t.subscribing||t.unsubDevice&&t.unsubEntity)return t.subscribing;const i=e?.connection?.subscribeEvents;return"function"==typeof i?(t.subscribing=(async()=>{try{t.unsubDevice||(t.unsubDevice=await i.call(e.connection,()=>Qh(e,t),"device_registry_updated")),t.unsubEntity||(t.unsubEntity=await i.call(e.connection,()=>Qh(e,t),"entity_registry_updated"))}catch{}finally{0===t.refs&&(t.unsubDevice?.(),t.unsubEntity?.(),t.unsubDevice=void 0,t.unsubEntity=void 0),t.subscribing=void 0}})(),t.subscribing):void 0}function td(e,t){const i=Xh(e);if(!i)return()=>{};const n=0===i.refs;i.refs++,i.listeners.add(t),("pending"===i.access||n)&&Jh(e,i),ed(e,i);let r=!1;return()=>{r||(r=!0,i.listeners.delete(t),i.refs=Math.max(0,i.refs-1),i.refs>0||(i.unsubDevice?.(),i.unsubEntity?.(),i.unsubDevice=void 0,i.unsubEntity=void 0,void 0!==i.reloadTimer&&globalThis.clearTimeout(i.reloadTimer),i.reloadTimer=void 0))}}function id(e){const t=Xh(e);t&&(Qh(e,t),ed(e,t))}function nd(e){const t=Xh(e);if(!t)return{revision:0,authoritative:!1,access:"limited",devices:e?.devices||{},entities:e?.entities||{},lastSuccess:0,error:"registry_unavailable"};let i=e?.devices||{},n=e?.entities||{};if(t.authoritative){const r=t.liveDevices!==i||t.liveEntities!==n,o=void 0!==t.liveDevices||void 0!==t.liveEntities;if(r&&(t.liveDevices=i,t.liveEntities=n,t.projectedRevision=void 0,o&&Qh(e,t)),t.projectedRevision!==t.revision||!t.projectedDevices||!t.projectedEntities){const e={...t.devices},r={...t.entities};for(const[t,n]of Object.entries(i))Object.prototype.hasOwnProperty.call(e,t)||(e[t]=n);for(const[e,t]of Object.entries(n))Object.prototype.hasOwnProperty.call(r,e)||(r[e]=t);t.projectedDevices=e,t.projectedEntities=r,t.projectedRevision=t.revision}i=t.projectedDevices,n=t.projectedEntities}return{revision:t.revision,authoritative:t.authoritative,access:t.access,devices:i,entities:n,lastSuccess:t.lastSuccess,error:t.error}}function rd(e){if(!e||"object"!=typeof e&&"function"!=typeof e)return 0;let t=Gh.get(e);return t||(t=Vh++,Gh.set(e,t)),t}function od(e,t=nd(e)){return[t.revision,t.access,rd(t.devices),rd(t.entities)].join(":")}function sd(e){return!!e&&null==e.disabled_by}function ad(e,t=nd(e)){const i={},n={},r={};for(const[e,n]of Object.entries(t.devices||{}))sd(n)&&(i[e]=n);for(const[e,i]of Object.entries(t.entities||{})){if(!sd(i))continue;const r=i.device_id?t.devices?.[i.device_id]:null;t.authoritative&&i.device_id&&!r||(r&&!sd(r)||(n[e]=i))}for(const[i,n]of Object.entries(e?.states||{})){const e=t.entities?.[i];if(e&&!sd(e))continue;const o=e?.device_id?t.devices?.[e.device_id]:null;t.authoritative&&e?.device_id&&!o||(o&&!sd(o)||(r[i]=n))}return{...e,devices:i,entities:n,states:r}}function ld(e,t=nd(e)){return{...e,devices:t.devices||{},entities:t.entities||{}}}function cd(e,t){const i=[];for(const[n,r]of Object.entries(e||{}))r?.device_id===t&&i.push(n);return i}function hd(){if(Yh)return Yh;if("undefined"==typeof localStorage)return{};try{const e=JSON.parse(localStorage.getItem(Kh)||"{}");if(!e||"object"!=typeof e||Array.isArray(e))return{};const t=Date.now(),i={};for(const[n,r]of Object.entries(e))!r||"active"!==r.kind&&"ha_disabled"!==r.kind||!Number.isFinite(r.ts)||t-r.ts>7776e6||(i[n]=r);return Yh=i,Yh}catch{return{}}}function dd(e,t,i=nd(e)){if(!t||"virtual"===t)return{kind:"active",enabledEntityIds:[],allEntityIds:[]};const n=t.indexOf(":");if(n<1)return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]};const r=t.slice(0,n),o=t.slice(n+1);if("device"!==r&&"entity"!==r||!o)return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]};const s=i.devices||{},a=i.entities||{};if(i.authoritative){if("device"===r){const e=s[o];if(!e)return{kind:"orphaned",reason:"device_missing",enabledEntityIds:[],allEntityIds:[]};const t=cd(a,o);if(!sd(e))return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:t};const i=t.filter(e=>sd(a[e]));return t.length&&!i.length?{kind:"ha_disabled",reason:"all_entities",enabledEntityIds:[],allEntityIds:t}:{kind:"active",enabledEntityIds:i,allEntityIds:t}}const t=a[o];return t&&!sd(t)?{kind:"ha_disabled",reason:"entity",enabledEntityIds:[],allEntityIds:[o]}:t?.device_id&&!s[t.device_id]?{kind:"orphaned",reason:"device_missing",enabledEntityIds:[],allEntityIds:[o]}:t?.device_id&&!sd(s[t.device_id])?{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:[o]}:t||e?.states?.[o]?{kind:"active",enabledEntityIds:[o],allEntityIds:[o]}:{kind:"orphaned",reason:"entity_missing",enabledEntityIds:[],allEntityIds:[]}}const l=function(e){return hd()[e]||null}(t);if("device"===r){const t=s[o],i=cd(a,o);if(null!=t?.disabled_by)return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:i};const n=i.filter(e=>{const t=a[e];return null==t?.disabled_by&&(!t.device_id||null==s[t.device_id]?.disabled_by)});if(i.length&&!n.length&&i.every(e=>null!=a[e]?.disabled_by))return{kind:"ha_disabled",reason:"all_entities",enabledEntityIds:[],allEntityIds:i};if("ha_disabled"===l?.kind)return{kind:"ha_disabled",reason:l.reason||"device",enabledEntityIds:[],allEntityIds:i};if(t||n.some(t=>!!e?.states?.[t]))return{kind:"active",enabledEntityIds:n,allEntityIds:i}}else{const t=a[o];if(null!=t?.disabled_by)return{kind:"ha_disabled",reason:"entity",enabledEntityIds:[],allEntityIds:[o]};if(t?.device_id&&null!=s[t.device_id]?.disabled_by)return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:[o]};if("ha_disabled"===l?.kind)return{kind:"ha_disabled",reason:l.reason||"entity",enabledEntityIds:[],allEntityIds:[o]};if(t||e?.states?.[o])return{kind:"active",enabledEntityIds:[o],allEntityIds:[o]}}return{kind:"unverified",reason:"registry_unavailable",enabledEntityIds:[],allEntityIds:[]}}function ud(e){const t=nd(e);return{access:t.access,authoritative:t.authoritative,revision:t.revision,lastSuccess:t.lastSuccess,error:t.error}}function pd(e){const t={};for(const[i,n]of Object.entries(e.entities)){if(!n?.device_id||!sd(n))continue;const r=e.devices?.[n.device_id];r&&!sd(r)||(t[n.device_id]=t[n.device_id]||[]).push(i)}return t}function _d(e,t){const i=new Map;for(const n of e){if(!0===n?.removed)continue;const e=n?.binding||"";if(!e.startsWith("entity:"))continue;const r=e.slice(7);if(!r)continue;const o=t?.entities?.[r]?.device_id;if(!o)continue;const s=i.get(o)||new Set;s.add(r),i.set(o,s)}return{byDevice:i}}function md(e,t,i,n){const r=n.byDevice.get(t);return r?.size?{partial:!0,entityIds:i.filter(t=>!r.has(t)&&!e?.entities?.[t]?.hidden)}:{partial:!1,entityIds:[...i]}}function gd(e,t,i){if(t.identifiers?.[0]?.[0])return t.identifiers[0][0];for(const t of i){const i=e.entities[t]?.platform;if(i)return i}return""}function fd(e,t){if(/_device_temperature$/.test(t))return!1;if(e.entities?.[t]?.entity_category)return!1;const i=e.states[t];if(!i)return/_temperature$/.test(t);const n=i.attributes||{};return"temperature"===n.device_class||/°C|°F/.test(n.unit_of_measurement||"")||/_temperature$/.test(t)}const vd=["vacuum","lawn_mower","climate","media_player","light","cover","lock","valve","alarm_control_panel","water_heater","fan","humidifier","siren","camera","remote"],yd=e=>[...e.filter(e=>!e.reg?.hidden),...e.filter(e=>!!e.reg?.hidden)];function bd(e,t){const i=t.map(t=>({eid:t,reg:e?.entities?.[t]})).filter(e=>!!e.reg);if(!i.length)return[];const n=i.filter(e=>!e.reg.entity_category),r=n.length?n:i;for(const e of vd){const t=r.filter(t=>t.eid.startsWith(e+"."));if(t.length)return yd(t).map(e=>e.eid)}const o=r.filter(t=>function(e,t){if(!t.startsWith("binary_sensor."))return!1;const i=$h(e?.states?.[t]?.attributes?.device_class||e?.entities?.[t]?.device_class||e?.entities?.[t]?.original_device_class);return mh.has(i)||gh.has(i)||fh.has(i)||vh.has(i)||"moving"===i||yh.has(i)}(e,t.eid));if(o.length)return yd(o).map(e=>e.eid);const s=r.filter(e=>e.eid.startsWith("switch."));if(s.length){const t=yd(s),n=t.find(t=>Ah(e,t.eid));if(s.length>1&&n){const t=i.filter(t=>t.eid!==n.eid&&"config"!==t.reg?.entity_category&&null!=Th(e,t.eid)),r=t.filter(e=>!e.reg?.entity_category),o=r.length?r:t;for(const t of[0,1,2]){const i=yd(o.filter(i=>Th(e,i.eid)===t));if(i.length)return[i[0].eid,n.eid]}}return[(n||t[0]).eid]}const a=[];for(const e of je)a.push(...yd(r.filter(t=>t.eid.startsWith(e+"."))));return a.push(...yd(r.filter(e=>!je.includes(e.eid.split(".")[0])))),a.map(e=>e.eid)}function wd(e,t,i){const n=t.map(t=>({eid:t,reg:e.entities[t],st:e.states[t]})).filter(e=>e.reg),r=[n.filter(e=>!e.reg.hidden&&!e.reg.entity_category),n.filter(e=>!e.reg.entity_category),n.filter(e=>!e.reg.hidden),n];if("mdi:thermometer"===i||"mdi:air-filter"===i)for(const t of r){const i=t.find(t=>fd(e,t.eid));if(i)return i.eid}const o=bd(e,t);return o.find(Pn)||o[0]}function kd(e,t,i=[]){return[...new Set(xd(e,t,i))].filter(e=>Pn(e))}function xd(e,t,i=[]){const n=e?.startsWith("entity:")?new Set([e.slice(7)]):new Set(i);return(t||[]).filter(e=>"string"==typeof e&&!n.has(e))}function Sd(e,t){if("string"==typeof t)return e.area===t;const i=e.marker?.room_id;return i?!!t.id&&i===t.id:!!t.area&&e.area===t.area}function $d(e){const t=e.marker?.binding?.startsWith("entity:")?e.marker.binding.slice(7):null,i=e.entities.filter(Pn),n=e.primary&&Pn(e.primary)?e.primary:null;return[...new Set([t,n,...i].filter(e=>!!e&&Pn(e)))]}function Md(e){const t=$d(e),i=e.marker?.light_entity;return i&&t.includes(i)?i:t[0]||null}function Rd(e,t){if(!1===t.marker?.is_light)return[];if(!0===t.marker?.is_light){return[{eid:Md(t),via:"forced"}]}const i=t.primary||bd(e,t.entities)[0];return i&&!i.startsWith("light.")?[]:t.entities.filter(t=>t.startsWith("light.")&&!!e.states?.[t]).map(e=>({eid:e,via:"light"}))}const Cd=new WeakMap,Td=new WeakMap;function Dd(e){return e.map(e=>[e.id||"",!0===e.hidden?1:0,e.primary||"",[...e.entities].join(","),void 0===e.controls?"":[...e.controls].join(","),e.marker?.id||"",e.marker?.binding||"",e.marker?.is_light,e.marker?.tap_action||"",!0===e.marker?.removed?1:0,e.marker?.light_entity||"",null==e.marker?.controls?"":[...e.marker.controls].join(",")].join("")).join("")}function Ad(e){const t=Dd(e),i=Cd.get(e);if(i?.fingerprint===t)return i;const n=e.filter(e=>!e.hidden),r=new Map,o=new Map;for(const t of e){o.set(t,xd(t.marker?.binding,t.marker?.controls??t.controls,t.entities));const e=t.hidden||!0!==t.marker?.is_light?null:t.marker?.id||t.id;e&&r.set(String(e),t)}const s=new Map;for(const t of e){const e=o.get(t)||[],i=new Set(void 0===t.controls?e.filter(Pn):t.controls.filter(Pn)),n=Md(t),a=i.size?[...i]:n?[n]:[];for(const i of e){if(!i.startsWith("marker:"))continue;const e=i.slice(7);if(!e||e===String(t.marker?.id||t.id||""))continue;if(!r.has(e))continue;const n=s.get(e)||{markerId:e,controllers:[],driverEids:[]};n.controllers.push({device:t,driverEids:[...a]}),n.driverEids=[...new Set([...n.driverEids,...a])],s.set(e,n)}}const a={fingerprint:t,visible:n,markerById:r,persistedByDevice:o,incomingByMarker:s};return Cd.set(e,a),a}function Pd(e){return Ad(e).incomingByMarker}function Fd(e,t){const i=kd(t.marker?.binding,t.controls??t.marker?.controls,t.entities),n=xd(t.marker?.binding,t.marker?.controls??t.controls,t.entities);return(null!=t.marker?.is_light||!i.length&&!n.some(e=>e.startsWith("marker:")))&&Rd(e,t).length>0}function zd(e,t){return Rd(e,t).some(e=>!!e.eid)}function Id(e,t,i,n){const r="always"===e||"auto"===e&&t,o=r&&!i;return{sourceExists:r,fromSourceEnabled:r&&i,manualEnabled:r,radiusEnabled:r,passive:o,effectiveMode:o&&"auto"===n?"fixed":n}}function Od(e,t){const i=kd(t.marker?.binding,t.controls??t.marker?.controls,t.entities).map(e=>({eid:e,via:"controls"})),n=Fd(e,t)?Rd(e,t):[];for(const e of n)e.eid&&i.some(t=>t.eid===e.eid)||i.push(e);return i}function Ed(e,t,i,n){if(null!=i)return Ed(e,t,null,n).filter(e=>Sd(e.device,i));const r=Dd(t),o=function(e,t){const i=new Set;for(const e of t){for(const t of e.entities)i.add(t);for(const t of e.controls||e.marker?.controls||[])"string"!=typeof t||t.startsWith("marker:")||i.add(t)}return[...i].sort().map(t=>`${t}:${e?.states?.[t]?.state??""}`).join("|")}(e,t),s=Bh(n),a=Td.get(t);if(a?.graphFingerprint===r&&a.stateFingerprint===o&&a.virtualLightFingerprint===s&&a.registry===e?.entities)return a.sources;const{visible:l,markerById:c,persistedByDevice:h,incomingByMarker:d}=Ad(t),u=null==i?l:l.filter(e=>Sd(e,i)),p=new Map,_=new Map;for(const t of u){const i=Od(e,t).filter(e=>"controls"!==e.via);for(const n of i){const i=!0===t.marker?.is_light?String(t.marker?.id||t.id||""):"",r=i?`marker:${i}`:`entity:${n.eid}`,o=n.eid?[n.eid]:[],s={key:r,eid:n.eid||"",stateEids:o,serviceEids:o,device:t,via:n.via,castsGlow:!0,passive:!n.eid,on:!n.eid||"on"===e.states?.[n.eid]?.state};p.set(t,[...p.get(t)||[],s]),n.eid&&_.set(n.eid,s)}}const m=new Map;for(const e of t){const t=h.get(e)||[],i=new Set(void 0===e.controls?t.filter(Pn):e.controls);m.set(e,i)}for(const t of p.values())for(const i of t){if(!i.passive)continue;const t=i.key.slice(7),r=d.get(t);i.on=!r||r.driverEids.some(t=>"on"===e.states?.[t]?.state),!r&&qh(i.device.marker)&&(i.on=jh(i.device.marker,n))}const g=new Map,f=e=>{const t=g.get(e.key);(!t||e.castsGlow&&!t.castsGlow)&&g.set(e.key,e)};for(const t of l){const n=h.get(t)||[],r=null==i||Sd(t,i);for(const i of n){if(i.startsWith("marker:")){const e=c.get(i.slice(7)),t=e?p.get(e):null;if(t)for(const e of t)f(e);continue}if(!Pn(i)||!m.get(t)?.has(i))continue;const n=_.get(i);n?f(n):r&&f({key:`entity:${i}`,eid:i,stateEids:[i],serviceEids:[i],device:t,via:"controls",castsGlow:!1,passive:!1,on:"on"===e.states?.[i]?.state})}for(const e of p.get(t)||[])f(e)}const v=[...g.values()];return Td.set(t,{graphFingerprint:r,stateFingerprint:o,virtualLightFingerprint:s,registry:e?.entities,sources:v}),v}function Nd(e){const t=e.filter(e=>e.castsGlow);return t.find(e=>e.on)||t[0]||null}function Hd(e){return e.length?e.some(e=>e.on)?"on":"off":"none"}function Ld(e,t){const i=[];for(const n of t){const t=e.states[n];if(!t)continue;const r=(t.attributes?.unit_of_measurement||"").toLowerCase();if(/_(linkquality|lqi)$/.test(n)||"lqi"===r){const e=parseFloat(t.state);isNaN(e)||i.push(e);continue}const o=t.attributes?.linkquality??t.attributes?.lqi;if(null!=o){const e=parseFloat(o);isNaN(e)||i.push(e)}}return Ii(i)}function Bd(e,t){for(const i of t){if(!fd(e,i))continue;const t=e.states[i];if(!t)continue;const n=parseFloat(t.state);if(!isNaN(n))return Math.round(10*n)/10}return null}function qd(e,t){for(const i of t){if(!i.startsWith("climate."))continue;const t=e.states[i];if(!t||"unavailable"===t.state||"unknown"===t.state)continue;const n=parseFloat(t.attributes?.current_temperature);if(Number.isFinite(n))return Math.round(10*n)/10}return null}function jd(e,t){if(e.entities?.[t]?.entity_category)return!1;const i=e.states[t];if(!i)return/_humidity$/.test(t);const n=i.attributes||{};return"humidity"===n.device_class||"%"===n.unit_of_measurement&&/_humidity$/.test(t)||/_humidity$/.test(t)}function Wd(e,t){for(const i of t){if(!jd(e,i))continue;const t=e.states[i];if(!t)continue;const n=parseFloat(t.state);if(!isNaN(n))return Math.round(n)}return null}function Ud(e,t){if(!t)return[];const i=[];for(const[t,n]of Object.entries(e.entities)){if(!t.startsWith("light.")||n.hidden||!sd(n))continue;let r=null;if("group"===n.platform)r=n.area_id||null;else{if(!n.device_id)continue;{const t=e.devices[n.device_id];if(!sd(t))continue;if("Group"!==t?.model)continue;r=t.area_id||n.area_id||null}}if(!r)continue;const o=e.states[t];i.push({eid:t,name:n.name||o?.attributes?.friendly_name||t,area:r})}return i}function Gd(e,t,i,n,r){const o=qe(t,i,r);if(o!==Be)return o;const s=[];for(const t of n){const i=e.states[t]?.attributes?.device_class;i&&s.push(i)}return function(e){for(const t of e){const e=Le[t];if(e)return e}return null}(s)??Be}function Vd(e,t){return e.map(e=>{if(!Array.isArray(e.controls))return e;const i=e.controls.filter(e=>!("string"==typeof e&&e.startsWith("marker:")&&t.has(e.slice(7))));return i.length===e.controls.length?e:{...e,controls:i.length?i:null}})}function Kd(e,t,i){if(!t||!i||t===i)return[...e];const n=`marker:${t}`,r=`marker:${i}`;return e.map(e=>{const t=Array.isArray(e.controls)?e.controls.map(e=>e===n?r:e):e.controls,i="derived_marker_state"===e.value_badge?.source?.kind&&e.value_badge.source.ref===n?{...e.value_badge,source:{...e.value_badge.source,ref:r}}:e.value_badge,o="derived_marker_state"===e.value_source?.kind&&e.value_source.ref===n?{...e.value_source,ref:r}:e.value_source;return t===e.controls&&i===e.value_badge&&o===e.value_source?e:{...e,controls:t,...void 0!==i?{value_badge:i}:{},...void 0!==o?{value_source:o}:{}}})}function Yd(e,t,i){if(!t||t===i)return!0;const n=new Map;for(const t of e)n.set(t.id,(t.controls||[]).filter(e=>"string"==typeof e&&e.startsWith("marker:")).map(e=>e.slice(7)));const r=new Set,o=[i];for(;o.length;){const e=o.pop();if(e===t)return!0;r.has(e)||(r.add(e),o.push(...n.get(e)||[]))}return!1}function Xd(e,t,i,n){const r=new Set([t]),o=e.filter(e=>{const o=e.id===t||!n&&e.binding===i;return o&&r.add(e.id),!o});return{markers:n?o:[...o,{id:t,binding:i,removed:!0,hidden:!0}],cleanupIds:r}}function Zd(e){const t=new Set,i=new Set,n=new Set;for(const r of e||[]){const e=String(r.binding||"").indexOf(":");if(e<1)continue;const o=r.binding.slice(0,e),s=r.binding.slice(e+1);s&&(!0===r?.removed?"device"===o?t.add(s):"entity"===o&&i.add(s):"entity"===o&&n.add(s))}return{devices:t,entities:i,liveEntities:n}}function Jd(e,t,i){if(i.liveEntities.has(t))return!1;if(i.entities.has(t))return!0;const n=e?.entities?.[t]?.device_id;return!!n&&i.devices.has(n)}function Qd(e,t,i,n,r){const o=kd(t.binding,t.controls,e.entities).filter(e=>!Jd(i,e,n)).filter(e=>"active"===dd(i,"entity:"+e,r).kind);e.marker=t,e.controls=o,e.userHidden=!0===t.hidden,e.hidden=e.userHidden||"ha_disabled"===e.bindingStatus?.kind,t.name&&(e.name=t.name),t.icon&&(e.icon=t.icon),null!=t.model&&(e.model=t.model),e.link=t.link??null,e.description=t.description??null,e.pdfs=t.pdfs||[],e.tapAction=t.tap_action??null}function eu(e){const t=e.hass,i=e.registry||nd(t),n=ad(t,i),r=ld(t,i),{areaToSpace:o,markers:s,settings:a,excluded:l,iconRules:c}=e,h=!1!==a.group_lights,d=Zd(s),u=Ud(n,h).filter(e=>!Jd(n,e.eid,d)),p=new Set(u.map(e=>e.area)),_=pd(n),m=_d(s,r),g=new Set(s.map(e=>e.binding)),f=[];for(const e of Object.values(n.devices)){const r=e.area_id;if(!r||!o[r])continue;if("service"===e.entry_type)continue;if(g.has("device:"+e.id))continue;if("active"!==dd(t,"device:"+e.id,i).kind)continue;const s=md(n,e.id,_[e.id]||[],m);if(s.partial&&!s.entityIds.length)continue;const a=s.entityIds,d=gd(n,e,a);let u=l.has(d)||"Group"===e.model||/scene/i.test(e.model||"")||/bridge/i.test((e.model||"")+(e.name||""))||"myheat"===d&&!!e.via_device_id;if(!u&&h&&p.has(r)){const t=(e.name_by_user||e.name||"").trim();"mdi:lightbulb"===Gd(n,t,e.model,a,c)&&(u=!0)}u&&f.push("device:"+e.id)}return f}function tu(e,t,i,n){if("string"==typeof e.room_id&&e.room_id.length>0&&null===e.area)return{area:"",space:e.space||n};const r=e.area||t||"";return{area:r,space:r&&i[r]||e.space||n}}function iu(e){const t=e.hass,i=e.registry||nd(t),n=ad(t,i),r=ld(t,i),{areaToSpace:o,markers:s,settings:a,excluded:l,showAll:c,firstSpaceId:h,loc:d,iconRules:u}=e,p=!1!==a.group_lights,_=Zd(s),m=Ud(n,p).filter(e=>!Jd(n,e.eid,_)),g=new Set(m.map(e=>e.area)),f=pd(n),v=function(e){const t={};for(const[i,n]of Object.entries(e.entities||{}))n?.device_id&&(t[n.device_id]=t[n.device_id]||[]).push(i);return t}(r),y=_d(s,r),b=new Set;for(const e of s){const[t,i]=e.binding.split(":");"device"!==t&&"entity"!==t||!i||b.add(e.binding)}const w=(e,t)=>s.find(i=>i.binding===e+":"+t),k={},x=[];for(const e of Object.values(n.devices)){const r=e.area_id;if(!r||!o[r])continue;if("service"===e.entry_type)continue;if(b.has("device:"+e.id))continue;const s=dd(t,"device:"+e.id,i);if("active"!==s.kind)continue;const h=w("device",e.id);if(h&&h.hidden&&!a.filter_seeded)continue;const _=md(n,e.id,f[e.id]||[],y);if(_.partial&&!_.entityIds.length)continue;const m=_.entityIds,v=_.partial?{kind:"active",enabledEntityIds:m,allEntityIds:m}:s,S=gd(n,e,m),$=!a.filter_seeded;if($&&!c){if(l.has(S))continue;if("Group"===e.model)continue;if(/scene/i.test(e.model||""))continue;if(/bridge/i.test((e.model||"")+(e.name||"")))continue;if("myheat"===S&&e.via_device_id)continue}const M=(e.name_by_user||e.name||d("device.unnamed")).trim(),R=M+"|"+r;let C=Gd(n,M,e.model,m,u);if(m.some(e=>e.startsWith("lock."))&&(C="mdi:lock"),$&&!c&&p&&"mdi:lightbulb"===C&&g.has(r))continue;k[R]=(k[R]||0)+1;const T=k[R]>1?M+" "+k[R]:M,D={id:e.id,name:T,model:e.model||"",area:r,space:o[r],icon:C,entities:m,allEntities:v.allEntityIds,bindingStatus:v,bindingKind:"device",bindingRef:e.id,pdfs:[]};D.primary=wd(n,m,C),"mdi:thermometer"!==C&&"mdi:air-filter"!==C||(D.temp=Bd(n,m)),D.primary&&jd(n,D.primary)&&(D.hum=Wd(n,m)),x.push(D)}for(const e of m)o[e.area]&&(b.has("entity:"+e.eid)||x.push({id:"lg_"+e.eid,name:e.name,model:d("device.light_group"),area:e.area,space:o[e.area],icon:"mdi:lightbulb-group",entities:[e.eid],allEntities:[e.eid],bindingStatus:{kind:"active",enabledEntityIds:[e.eid],allEntityIds:[e.eid]},primary:e.eid,bindingKind:"entity",bindingRef:e.eid,pdfs:[]}));for(const e of s){if(e.removed)continue;const[s,l]=e.binding.split(":"),c="device"===s||"entity"===s?dd(t,e.binding,i):null;if(!e.hidden||a.filter_seeded||"ha_disabled"===c?.kind)if("device"===s){const t=c;if("unverified"===t.kind)continue;const s=r.devices[l],{area:a,space:p}=tu(e,s?.area_id,o,h),m="active"===t.kind?t.enabledEntityIds:[];let g=s?Gd(n,s.name_by_user||s.name||"",s.model,m,u):"mdi:help-circle";m.some(e=>e.startsWith("lock."))&&(g="mdi:lock");const f={id:e.id,name:s?.name_by_user||s?.name||d("device.fallback"),model:s?.model||"",area:a,space:p,icon:g,entities:m,allEntities:t.allEntityIds.length?t.allEntityIds:s&&v[s.id]||[],bindingStatus:t,bindingKind:"device",bindingRef:l};f.primary=wd(n,m,g),"mdi:thermometer"!==g&&"mdi:air-filter"!==g||(f.temp=Bd(n,m)),f.primary&&jd(n,f.primary)&&(f.hum=Wd(n,m)),Qd(f,e,r,_,i),x.push(f)}else if("entity"===s){if(Jd(r,l,_))continue;const t=c;if("unverified"===t.kind)continue;const s=r.entities[l],a=s?.area_id||s?.device_id&&r.devices[s.device_id]?.area_id||"",{area:d,space:p}=tu(e,a,o,h),m=n.states[l],g=s?.name||m?.attributes?.friendly_name||l;let f=Gd(n,g,"",[l],u);l.startsWith("lock.")&&(f="mdi:lock");const v={id:e.id,name:g,model:"",area:d,space:p,icon:f,entities:"active"===t.kind?[l]:[],allEntities:[l],bindingStatus:t,primary:"active"===t.kind?l:void 0,bindingKind:"entity",bindingRef:l};"mdi:thermometer"!==f&&"mdi:air-filter"!==f||!v.entities.length||(v.temp=Bd(n,v.entities)),v.entities.length&&jd(n,l)&&(v.hum=Wd(n,v.entities)),Qd(v,e,r,_,i),x.push(v)}else{const t=e.area||"",n=e.space||t&&o[t]||h,s={id:e.id,name:e.name||d("device.virtual"),model:e.model||"",area:t,space:n,icon:e.icon||"mdi:map-marker",entities:[],allEntities:[],bindingStatus:{kind:"active",enabledEntityIds:[],allEntityIds:[]},bindingKind:"virtual",virtual:!0};Qd(s,e,r,_,i),x.push(s)}}return x}function nu(e){const{marker:t,siblingMarkers:i=[],...n}=e;return iu({...n,markers:[...i.filter(e=>e.id!==t.id),t]}).find(e=>e.id===t.id)||null}function ru(e,t,i,n){if(!t)return null;if(function(e,t,i){if(!t)return!1;const n=t.indexOf(":");if(n<1)return!1;const r=t.slice(0,n),o=t.slice(n+1),s=Zd(i);return"device"===r?s.devices.has(o):"entity"===r&&Jd(e,o,s)}(e,t,n))return null;const r=t.indexOf(":");if(r<0)return null;const o=t.slice(0,r),s=t.slice(r+1);if(!s)return null;if("entity"===o){const t=parseFloat(e.states[s]?.state);return Number.isFinite(t)?"temp"===i?Math.round(10*t)/10:Math.round(t):null}if("device"===o){const t=Object.entries(e.entities).filter(([,e])=>e.device_id===s).map(([e])=>e);return"temp"===i?Bd(e,t):Wd(e,t)}return null}const ou=new RegExp(["water","voda","coolant","flow_?temp","return_?temp","target","setpoint","chip","cpu","processor","board","core_temp","device_temp","batter","akkum","freezer","fridge","oven","kettle","boiler"].join("|"),"i");function su(e,t){return t.area?t.area:e&&t.id?`@room/${encodeURIComponent(e)}/${encodeURIComponent(t.id)}`:null}function au(e){return null==e.area&&e.space&&e.room_id?su(e.space,{id:e.room_id,area:null}):e.area||null}function lu(e){const t=e?.exclude_integrations;return t?new Set(t):Ie}function cu(e,t,i,n=Ie){const r=new Map;if(!e?.entities)return r;const o=Zd(i),s=new Set,a=new Map,l=new Map;for(const e of i||[]){if(e?.removed)continue;const t=(e.binding||"").indexOf(":");if(t<=0)continue;const i=e.binding.slice(0,t),n=e.binding.slice(t+1);if(!n)continue;!0===e.use_climate_temp&&s.add(n);const r=au(e);r&&("entity"!==i||a.has(n)?"device"!==i||l.has(n)||l.set(n,r):a.set(n,r))}const c=new Map;for(const[t,i]of Object.entries(e.entities)){if(i.device_id&&o.devices.has(i.device_id)&&!o.liveEntities.has(t)||!i.device_id&&o.entities.has(t)&&!o.liveEntities.has(t))continue;const r=i.device_id?e.devices?.[i.device_id]:null;if(!sd(i)||r&&!sd(r))continue;const h=a.get(t)||(i.device_id?l.get(i.device_id):null)||i.area_id||r?.area_id||null;if(!h)continue;if(i.entity_category)continue;if(!(s.size>0&&t.startsWith("climate.")&&(s.has(t)||i.device_id&&s.has(i.device_id)))){if(n.has(i.platform))continue;if(ou.test(t))continue}let d=c.get(h);d||(d=new Map,c.set(h,d));const u=i.device_id||t;let p=d.get(u);if(!p){const n=e.states?.[t];p={name:(r?r.name_by_user||r.name:i.name||n?.attributes?.friendly_name||t)||t,model:r?.model,ents:[]},d.set(u,p)}p.ents.push(t)}for(const[i,n]of c){const o=[],a=[];for(const[i,r]of n){const n=Gd(e,r.name,r.model,r.ents,t),l="mdi:thermometer"===n||"mdi:air-filter"===n;if(l){const t=Bd(e,r.ents);null!=t&&o.push(t)}if(s.size>0&&(s.has(i)||r.ents.some(e=>s.has(e)))){const t=qd(e,r.ents);null!=t&&o.push(t)}if(l||"mdi:water-percent"===n){const t=Wd(e,r.ents);null!=t&&a.push(t)}}(o.length||a.length)&&r.set(i,{temp:o.length?Math.round(o.reduce((e,t)=>e+t,0)/o.length*10)/10:null,hum:a.length?Math.round(a.reduce((e,t)=>e+t,0)/a.length):null})}return r}function hu(e,t,i){const n=[];for(const r of t){if(r.area!==i||r.virtual)continue;const t=Ld(e,r.entities);null!=t&&n.push(t)}return Ii(n)}const du={offStates:["off"],unknownUsesToggle:!0},uu={light:du,switch:du,fan:du,humidifier:du,input_boolean:du,automation:du,remote:du,group:du,climate:{...du,featureMasks:{turn_on:256,turn_off:128,toggle:384}},media_player:{...du,featureMasks:{turn_on:128,turn_off:256,toggle:384}},siren:{...du,featureMasks:{turn_on:1,turn_off:2,toggle:3}},vacuum:{...du,featureMasks:{turn_on:1,turn_off:2,toggle:3}},water_heater:{...du,featureMasks:{turn_on:8,turn_off:8,toggle:8}},camera:{...du,featureMasks:{turn_on:1,turn_off:1,toggle:1}}};function pu(e){return e.slice(0,e.indexOf("."))}function _u(e,t,i){if(!e?.services||"object"!=typeof e.services)return!1;const n=e.services?.[t];return!!n&&Object.prototype.hasOwnProperty.call(n,i)}function mu(e,t,i){return _u(e,t,i)?{domain:t,service:i}:_u(e,"homeassistant",i)?{domain:"homeassistant",service:i}:null}function gu(e,t){return e?.entities?.[t]||null}function fu(e,t,i){const n=e?.states?.[i],r=gu(t,i);return n?.attributes?.friendly_name||r?.name||r?.original_name||i}function vu(e,t){const i=gu(e,t);if(null!=i?.disabled_by)return!0;const n=i?.device_id?e?.devices?.[i.device_id]:null;return null!=n?.disabled_by}function yu(e,t){const i=e?.attributes?.supported_features;if(null==i||""===i)return!1;const n=Number(i);return Number.isFinite(n)&&(n&t)===t}function bu(e,t,i){const n=pu(i);if("lock"===n||"alarm_control_panel"===n)return!0;if("cover"!==n)return!1;const r=e?.states?.[i],o=gu(t,i),s=String(r?.attributes?.device_class||o?.device_class||o?.original_device_class||"");return Gi.has(s)}function wu(e,t,i,n,r){return{ref:i,entityId:n,name:n?fu(e,t,n):null,reason:r}}function ku(e,t,i,n,r,o=null){return{target:null,skipped:wu(e,t,i,n,r),semantics:o,nextEffect:null,command:null}}function xu(e,t,i,n,r=i){const o=pu(i);if("cover"!==o&&"valve"!==o)return function(e,t,i,n,r=i){const o=pu(i),s=e?.states?.[i];if(vu(t,i))return ku(e,t,r,i,"ha-disabled","power");if(bu(e,t,i))return ku(e,t,r,i,"secure");if(!s)return ku(e,t,r,i,"missing","power");if("unavailable"===s.state)return ku(e,t,r,i,"unavailable","power");const a=uu[o];if(!a)return ku(e,t,r,i,"unsupported");let l,c;if("unknown"===s.state||""===s.state){if(!a.unknownUsesToggle)return ku(e,t,r,i,"unsupported","power");l="toggle",c="toggle"}else a.offStates.includes(String(s.state))?(l="turn-on",c="turn_on"):(l="turn-off",c="turn_off");const h=a.featureMasks?.[c];if(h&&!yu(s,h))return ku(e,t,r,i,"unsupported","power");const d=mu(e,o,c);return d?{target:{entityId:i,name:fu(e,t,i),state:String(s.state||""),via:n},skipped:null,semantics:"power",nextEffect:l,command:{...d,data:{entity_id:i}}}:ku(e,t,r,i,"unsupported","power")}(e,t,i,n,r);if(vu(t,i))return ku(e,t,r,i,"ha-disabled",o);if(bu(e,t,i))return ku(e,t,r,i,"secure",o);const s=e?.states?.[i];if(!s)return ku(e,t,r,i,"missing",o);if("unavailable"===s.state)return ku(e,t,r,i,"unavailable",o);const a=function(e,t,i){const n=String(i?.state||""),r="closed"===n?{service:`open_${t}`,effect:"open",feature:1}:"open"===n?{service:`close_${t}`,effect:"close",feature:2}:"opening"===n||"closing"===n?{service:`stop_${t}`,effect:"stop",feature:8}:null;return r&&yu(i,r.feature)&&_u(e,t,r.service)?r:yu(i,3)&&_u(e,t,"toggle")?{service:"toggle",effect:"toggle"}:null}(e,o,s);if(!a)return ku(e,t,r,i,"unsupported",o);return{target:{entityId:i,name:fu(e,t,i),state:String(s.state||""),via:n},skipped:null,semantics:o,nextEffect:a.effect,command:{domain:o,service:a.service,data:{entity_id:i}}}}function Su(e){return"entity"===e.bindingKind?e.bindingRef&&Pn(e.bindingRef)?[e.bindingRef]:[]:"virtual"===e.bindingKind?[]:$d(e)}function $u(e){const t=e.marker?.toggle_entity;return t&&Su(e).includes(t)?t:null}function Mu(e,t,i){const n=function(e,t){if("entity"===e.bindingKind&&e.bindingRef){const t=e.marker?.light_entity?Md(e):null;return[...new Set([t,e.bindingRef].filter(e=>!!e))]}const i=e.entities.length?e.entities:e.allEntities||[],n=e.marker?.light_entity||e.primary&&Pn(e.primary)?Md(e):null;return[...new Set([n,...bd(t,i)].filter(e=>!!e))]}(i,t);if(!n.length)return null;const r="entity"===i.bindingKind?"binding":"device-role";if("binding"===r)return xu(e,t,n[0],r);let o=null,s=null;for(const i of n){const n=xu(e,t,i,r);if(n.command)return n;const a=n.skipped?.reason;if("missing"===a||"unavailable"===a||"secure"===a)return n;"ha-disabled"!==a?o||=n:s||=n}return o||s}function Ru(e){const t=e.skipped?.reason;return"missing"===t?"unavailable":t||"unsupported"}function Cu(e,t){return{origin:e,kind:"none",semantics:null,targets:[],skippedTargets:[],noneReason:t,nextEffect:null,command:null}}function Tu(e,t){return"cover"===e||"toggle"===e?"toggle":"more-info"===e||"run"===e||"info"===e||"none"===e?e:(null==e||""===e)&&"light"===t?"toggle":"info"}function Du(e,t){return{origin:e,kind:"single",semantics:t.semantics,targets:t.target?[t.target]:[],skippedTargets:t.skipped?[t.skipped]:[],noneReason:t.command?null:Ru(t),nextEffect:t.nextEffect,command:t.command}}function Au(e,t,i,n=[]){const r=new Map,o=[],s=new Set,a=e=>{const t=`${e.ref}\n${e.entityId||""}\n${e.reason}`;s.has(t)||(s.add(t),o.push(e))};for(const e of n)a(e);for(const n of i){const i=xu(e,t,n.entityId,n.via,n.ref);i.target?r.set(n.entityId,r.get(n.entityId)||i.target):i.skipped&&a(i.skipped)}const l=[...r.values()];if(!l.length)return{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:l,skippedTargets:o,noneReason:o.length&&o.every(e=>"secure"===e.reason)?"secure":"configured-targets-missing",nextEffect:null,command:null};const c=l.some(e=>"on"===e.state)?"turn_off":"turn_on",h=mu(e,"homeassistant",c);return h?{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:l,skippedTargets:o,noneReason:null,nextEffect:"turn_on"===c?"turn-on":"turn-off",command:{...h,data:{entity_id:l.map(e=>e.entityId)}}}:{origin:"explicit-toggle",kind:"group",semantics:"group-power",targets:[],skippedTargets:[...o,...l.map(i=>wu(e,t,i.entityId,i.entityId,"unsupported"))],noneReason:"unsupported",nextEffect:null,command:null}}function Pu(e){return String(e.marker?.id||e.id||"")}function Fu(e){const{hass:t,device:i}=e,n=e.registryHass||t,r=function(e){return"toggle"===e.tapAction?"explicit-toggle":"cover"===e.tapAction?"legacy-cover":!e.tapAction&&e.primary?.startsWith("light.")?"default-light":null}(i);if(!r)return null;const o=i.marker;if("explicit-toggle"===r&&qh(o)){const t=String(o?.id||i.id||""),n=Pd(e.devices).get(t);if(n)return function(e,t){const i=e.registryHass||e.hass;return Au(e.hass,i,t.driverEids.map(e=>({entityId:e,via:"control-marker-driver",ref:`marker:${t.markerId}`})))}(e,n);const s=jh(o,e.virtualLights);return{origin:r,kind:"single",semantics:"power",targets:[{entityId:"",name:i.name,state:s?"on":"off",via:"virtual-light"}],skippedTargets:[],noneReason:null,nextEffect:s?"turn-off":"turn-on",command:null,operation:{kind:"virtual-light",markerId:o.id}}}if("explicit-toggle"===r){if(xd(i.marker?.binding,i.marker?.controls??i.controls,i.entities).length)return function(e,t=null){const{hass:i,device:n,devices:r}=e,o=e.registryHass||i,s=xd(n.marker?.binding,n.marker?.controls??n.controls,n.entities),a=e.lightSources||Ed(i,r,null,e.virtualLights),l=new Map;for(const e of a){if(!e.key.startsWith("marker:"))continue;const t=l.get(e.key)||[];t.push(e),l.set(e.key,t)}const c=Pd(r),h=new Map;for(const e of r){const t=String(e.marker?.id||e.id||"");t&&h.set(t,e)}const d=[],u=[];t&&d.push({entityId:t,via:"entity"===n.bindingKind?"binding":"device-role",ref:t});for(const e of s){if(!e.startsWith("marker:")){Pn(e)?d.push({entityId:e,via:"control-entity",ref:e}):u.push(wu(i,o,e,e.includes(".")?e:null,"unsupported"));continue}const t=l.get(e)||[];if(!t.length){const t=h.get(e.slice(7));if("ha_disabled"===t?.bindingStatus?.kind){const n=t.bindingStatus.allEntityIds[0]||null;u.push({ref:e,entityId:n,name:t.name||(n?fu(i,o,n):null),reason:"ha-disabled"})}else u.push(wu(i,o,e,null,"missing"));continue}const r=[...new Set(t.flatMap(e=>e.serviceEids))];if(r.length){for(const t of r)d.push({entityId:t,via:"control-entity",ref:e});continue}const s=t.some(e=>e.passive),a=e.slice(7),p=Pu(n),_=c.get(a)?.controllers.find(e=>Pu(e.device)===p);if(s&&_?.driverEids.length)for(const t of _.driverEids)d.push({entityId:t,via:"control-marker-driver",ref:e});else u.push(wu(i,o,e,null,s?"missing":"unsupported"))}return Au(i,o,d,u)}(e,$u(i))}if("legacy-cover"===r){const e=i.entities.find(e=>e.startsWith("cover."))||i.allEntities?.find(e=>e.startsWith("cover."));return e?Du(r,xu(t,n,e,"device-role")):Cu(r,"no-actionable-entity")}const s=$u(i),a=s?xu(t,n,s,"entity"===i.bindingKind?"binding":"device-role"):Mu(t,n,i);return a?Du(r,a):Cu(r,i.virtual||"virtual"===i.bindingKind?"no-actionable-entity":"no-binding")}function zu(e){if(!e)return[];const t=Array.isArray(e.data.entity_id)?e.data.entity_id:[e.data.entity_id];return[...new Set(t)].sort()}function Iu(e){return e?e.operation?e.operation:e.command?{kind:"ha-service",command:e.command}:null:null}const Ou=new Set(["missing","ha-disabled","unavailable"]);function Eu(e,t){const i=Iu(e),n=Iu(t);return!(!i||!n||i.kind!==n.kind)&&("virtual-light"===i.kind&&"virtual-light"===n.kind?i.markerId===n.markerId:"ha-service"===i.kind&&"ha-service"===n.kind&&function(e,t){const i=zu(e),n=zu(t);return i.length===n.length&&i.every((e,t)=>e===n[t])}(i.command,n.command))}function Nu(e,t){const i=e.targets[0]||e.skippedTargets[0],n=[];return"group"===e.kind?e.targets.length&&n.push(t.group(e.targets)):i&&n.push(t.single(i)),e.nextEffect&&e.targets.length&&n.push("group"===e.kind?t.groupCurrentNext(e.targets,e.nextEffect):t.currentNext(e.targets[0],e.nextEffect)),e.skippedTargets.length&&n.push(t.skipped(e.skippedTargets)),!e.command&&e.noneReason&&n.push(t.none(e.noneReason)),n}function Hu(e,t){return e.catch(()=>{}).then(t)}const Lu=e=>{const t=e?.config;return t&&Array.isArray(t.spaces)?t:null},Bu=(e,t)=>"number"==typeof e&&Number.isFinite(e)?e:t;class qu{constructor(e){this.onBodyReplaced=e,this.config=null,this.configRev=0,this.configFingerprint="",this.layout={},this.layoutRev=0,this.layoutFingerprint=""}setConfig(e){const t=this.config;e!==t&&(this.config=e,this.onBodyReplaced?.("_serverCfg",t))}setLayout(e){const t=this.layout;e!==t&&(this.layout=e,this.onBodyReplaced?.("_layout",t))}currentConfigFingerprint(){return this.configFingerprint||cc(this.config)}currentLayoutFingerprint(){return this.layoutFingerprint||cc(this.layout)}adoptResponses(e,t,i,n){const r=Lu(e),o=cc(r),s=o!==this.currentConfigFingerprint();s&&(i(),this.setConfig(r),this.configFingerprint=o),this.configRev=e?.rev??this.configRev;let a=!1;if(void 0!==t){const e=t?.layout??{},i=cc(e);a=i!==this.currentLayoutFingerprint(),a&&(n(),this.setLayout(e),this.layoutFingerprint=i),this.layoutRev=t?.rev??this.layoutRev}return{configChanged:s,layoutChanged:a}}adoptMergedLayout(e,t,i){const n=cc(e),r=n!==cc(this.layout);return r&&(i?.(),this.setLayout(e)),this.layoutFingerprint=n,this.layoutRev=t?.rev??this.layoutRev,r}stageConfigCandidate(e){const t=cc(e);t!==cc(this.config)&&this.setConfig(e),this.configFingerprint=t}acceptConfigWrite(e,t){this.configFingerprint=cc(e),this.configRev=Bu(t?.rev,this.configRev+1)}acceptPairWrite(e,t,i){this.setConfig(e),this.configFingerprint=cc(e),this.setLayout(t),this.layoutFingerprint=cc(t),this.configRev=Bu(i?.config_rev,this.configRev+1),this.layoutRev=Bu(i?.layout_rev,this.layoutRev+1)}noteLayoutRevision(e){"number"==typeof e&&e>this.layoutRev&&(this.layoutRev=e)}stageLocalConfig(e){this.setConfig(e)}stageLocalLayout(e){this.setLayout(e)}seedIdentity(e){Object.assign(this,e)}refreshConfigFingerprint(){this.configFingerprint=cc(this.config)}refreshLayoutFingerprint(){this.layoutFingerprint=cc(this.layout)}beginOptimistic(e,t){return function(e,t,i,n,r){return{previous:JSON.parse(JSON.stringify(e)),previousFingerprint:i,revision:n,attempted:t,attemptedFingerprint:r(t)}}(e,t,this.configFingerprint,this.configRev,cc)}rollbackOptimistic(e){const t=this.config;return!(!t||this.configRev!==e.revision||cc(t)!==e.attemptedFingerprint)&&(this.setConfig(e.previous),this.configFingerprint=e.previousFingerprint,!0)}restoreCached(e){const t=e?.config;return!(!t||!Array.isArray(t.spaces))&&(this.setConfig(t),this.configRev=e?.rev||0,this.configFingerprint=e?.config_fingerprint||cc(t),this.setLayout(e?.layout||{}),this.layoutRev=e?.layout_rev||0,this.layoutFingerprint=e?.layout_fingerprint||cc(this.layout),!0)}snapshot(e){return this.config?(this.refreshConfigFingerprint(),this.refreshLayoutFingerprint(),{config:this.config,rev:this.configRev,config_fingerprint:this.configFingerprint,layout:this.layout,layout_rev:this.layoutRev,layout_fingerprint:this.layoutFingerprint,virtual_lights:e}):null}}async function ju(e,t){const i=t.isCurrent??(()=>!0);if(!i())return{status:"superseded"};const{cfgResp:n,layResp:r}=t,o=e._adoption,s=Lu(n),a=null!=n&&cc(s)!==o.currentConfigFingerprint()||null!=r&&cc(r.layout??{})!==o.currentLayoutFingerprint();if(a){const t=await e._signer.prepareImage(e.hass,e._candidateBackdrop(s));if(!i())return{status:"superseded"};if(!t)return e._continuity.note("asset-failed"),e._scheduleLoadRetry(!0),{status:"asset-wait"}}if(!i())return{status:"superseded"};a&&e._continuity.hasCompleteFrame&&"steady"===e._continuity.state&&e._beginContinuityCandidate(t.reason,!0),t.beforeAdopt?.();const l=e._space;return function(e,t,i){const n=e._adoption,r=!!n.config,{configChanged:o,layoutChanged:s}=n.adoptResponses(t??{},i,()=>{e._geometryHistory.clear(),e._devicePositionHistory.clear(),e._cancelDeviceDrag(),e._pendingPhysicalWrites.clear(),e._clearRoomFocus(!0),e._cancelCameraTransition(!1),r&&e._clearGeometryGesture()},()=>{e._cancelCameraTransition(!1),e._devicePositionHistory.clear(),e._cancelDeviceDrag()});if(o&&e._seedDecorStyle(n.config),t&&("virtual_lights"in t||"config"in t)){const i=Lh(e._virtualLights,t.virtual_lights,n.configRev,"virtual_lights"in t);Bh(i)!==Bh(e._virtualLights)&&(e._virtualLights=i,e._capturedSnapshotVirtual="")}e._canOptimizeUndo=!(!t?.can_optimize_undo&&!i?.can_optimize_undo),e._adoptConfigCapabilities(t),e._undoKind=t?.undo_kind||i?.undo_kind||null,"boolean"==typeof t?.can_write&&(e._serverCanWrite=t.can_write),o&&e._continuity.note("config-candidate",{configRev:n.configRev}),s&&e._continuity.note("layout-candidate",{layoutRev:n.layoutRev})}(e,n,r),"reload"===t.profile&&(e._syncDecorAssets(s).catch(()=>{}),e._adoptInitialSpace(e._model,!0),e._resumePendingNavMode(),e._cacheSnapshot()),t.afterAdopt?.(),{status:"adopted",spaceChanged:e._space!==l}}const Wu=(e,t)=>e.connection===t.connection&&e.userId===t.userId&&e.route===t.route,Uu=e=>"number"==typeof e&&Number.isFinite(e)?e:null;class Gu{constructor(){this.sequence=0,this.currentSequence=0,this.lifecycle=0,this.observedHighWater=null,this.context=null}observeContext(e){this.context?Wu(this.context,e)||(this.context={...e},this.invalidateLifecycle()):this.context={...e}}invalidateLifecycle(){this.lifecycle+=1,this.currentSequence=++this.sequence,this.observedHighWater=null}observeRevision(e,t,i){this.observeContext(i);const n=Uu(e);if(null===n)return null;const r=Uu(t)??Number.NEGATIVE_INFINITY;return n<=Math.max(r,this.observedHighWater??Number.NEGATIVE_INFINITY)?null:(this.observedHighWater=n,Object.freeze({sequence:this.currentSequence,lifecycle:this.lifecycle,context:{...i},observedRevision:n}))}isReservationCurrent(e,t,i){this.observeContext(t);const n=Uu(i)??Number.NEGATIVE_INFINITY;return e.sequence===this.currentSequence&&e.lifecycle===this.lifecycle&&Wu(e.context,t)&&e.observedRevision===this.observedHighWater&&e.observedRevision>n}begin(e){this.observeContext(e.context),e.force&&this.invalidateLifecycle();const t=++this.sequence;return this.currentSequence=t,Object.freeze({sequence:t,lifecycle:this.lifecycle,force:e.force,context:{...e.context},baselineRevision:e.baselineRevision,baselineFingerprint:e.baselineFingerprint})}isCurrent(e){this.observeContext(e.context);const t=e.claim;return e.connected&&(t.force||!e.writePending)&&t.sequence===this.currentSequence&&t.lifecycle===this.lifecycle&&Wu(t.context,e.context)&&t.baselineRevision===e.baselineRevision&&t.baselineFingerprint===e.baselineFingerprint}}const Vu=e=>{const t=e.hass,i=t?.user?.id;return{connection:t?.connection??null,userId:"string"==typeof i?i:null,route:location.pathname}};async function Ku(e,t=!1,i){let n=null;const r=e._configReloadAuthority;if(!t){if(void 0!==i&&(n=r.observeRevision(i,e._cfgRev,Vu(e)),!n))return;if(e._saveConfigDebounced.pending()&&e._saveConfigDebounced.flush(),e._cfgWriting)return clearTimeout(e._reloadRetry),void(e._reloadRetry=window.setTimeout(()=>{n&&!r.isReservationCurrent(n,Vu(e),e._cfgRev)||Ku(e,!1)},400))}const o=r.begin({force:t,context:Vu(e),baselineRevision:e._cfgRev,baselineFingerprint:e._adoption.currentConfigFingerprint()}),s=()=>((e,t)=>e._configReloadAuthority.isCurrent({claim:t,context:Vu(e),connected:e.isConnected,baselineRevision:e._cfgRev,baselineFingerprint:e._adoption.currentConfigFingerprint(),writePending:e._saveConfigDebounced.pending()||e._cfgWriting}))(e,o);let a=!1;try{const t=await e._getAuthoritativeConfig();if(!s())return;const i=await e._adoptAuthoritative({cfgResp:t,reason:"config-reload",profile:"reload",isCurrent:s,afterAdopt:()=>{e._regSignature="",e._maybeRebuildDevices()}});if("superseded"===i.status)return;if(a=!0,"adopted"!==i.status)return;i.spaceChanged&&e._restoreZoom(),e.requestUpdate()}catch(t){if(!s())return;a=!0,e._showToast(e._t("toast.cfg_reload_failed",{err:e._errText(t)}))}finally{(a||s())&&(e._continuityDataReady=!0,e.requestUpdate())}}const Yu=e=>!!e&&e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]);function Xu(e,t=5,i=5){return Oo(e.cm,t,i)/2}function Zu(e,t,i=1,n=5,r=5,o=0){const s=e.host;if(!s||"partition"!==s.kind||"string"!=typeof s.id||!s.id)return{resolved:null,reason:"invalid-host"};const a=t.find(e=>e.id===s.id);if(!a)return{resolved:null,reason:"missing-partition"};if(!Yu(a.a)||!Yu(a.b)||!Number.isFinite(s.t)||s.t<0||s.t>1)return{resolved:null,reason:"invalid-position"};const l=a.b[0]-a.a[0],c=a.b[1]-a.a[1],h=Math.hypot(l,c),d=Number(e.length)*i;if(!(h>1e-9&&d>0&&Number.isFinite(d)))return{resolved:null,reason:"invalid-length"};const u=s.t*h;if(u-d/2h-o+1e-9)return{resolved:null,reason:"does-not-fit"};const p=l/h,_=c/h;let m=180*Math.atan2(c,l)/Math.PI;return m>=90?m-=180:m<-90&&(m+=180),{reason:null,resolved:{opening:e,host:s,partition:a,center:[a.a[0]+l*s.t,a.a[1]+c*s.t],angle:m,length:d,depth:Oo(a.cm,n,r),t:s.t,axis:{a:[a.a[0],a.a[1]],b:[a.b[0],a.b[1]],ux:p,uy:_,length:h}}}}function Ju(e,t,i=1,n=5,r=5){return Zu(e,t,i,n,r,0)}function Qu(e,t,i=1,n=5,r=5){const o=e.host,s="partition"===o?.kind?t.find(e=>e.id===o.id):void 0;if(!s)return Ju(e,t,i,n,r);const a=Zu(e,t,i,n,r,Xu(s,n,r));return"does-not-fit"===a.reason?{resolved:null,reason:"does-not-fit-jamb"}:a}function ep(e,t){return!e||(e.length!==t.length||e.host?.kind!==t.host?.kind||e.host?.id!==t.host?.id||e.host?.t!==t.host?.t)}function tp(e){const{center:t,length:i,axis:n,host:r}=e,o=i/2;return{hostId:r.id,a:[t[0]-n.ux*o,t[1]-n.uy*o],b:[t[0]+n.ux*o,t[1]+n.uy*o],depth:e.depth}}function ip(e,t=!1){const i=t?1:-1,n=e.depth/2;return{ox:-e.axis.uy*i*n,oy:e.axis.ux*i*n,cm:e.partition.cm,side:i}}function np(e,t,i){return e.flatMap(e=>!Yu(e.a)||!Yu(e.b)||Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])<=1e-9?[]:[{roomId:"",a:[e.a[0],e.a[1]],b:[e.b[0],e.b[1]],key:`partition:${e.id}`,kind:"outer",cm:e.cm,open:!1,half:Oo(e.cm,t,i)/2,partitionHost:{kind:"partition",id:e.id}}])}function rp(e,t,i){const{center:n,length:r,axis:o}=e,s=r/2,a=t.flatMap(e=>{if(!e.kind||e.open)return[];const t=e.b[0]-e.a[0],r=e.b[1]-e.a[1],a=Math.hypot(t,r);if(!(a>i))return[];const l=t/a,c=r/a;if(Math.abs(o.ux*c-o.uy*l)>1e-6)return[];if(Math.abs((n[0]-e.a[0])*c-(n[1]-e.a[1])*l)>i)return[];const h=e=>(e[0]-n[0])*o.ux+(e[1]-n[1])*o.uy,d=h(e.a),u=h(e.b),p=Math.max(-s,Math.min(d,u)),_=Math.min(s,Math.max(d,u));return _>=p-i?[[p,_]]:[]});if(!a.length)return!1;a.sort((e,t)=>e[0]-t[0]||e[1]-t[1]);let l=-s;for(const[e,t]of a){if(e>l+i)return!1;if(l=Math.max(l,t),l>=s-i)return!0}return!1}function op(e,t,i=1e-9){const n=e.length/(2*e.axis.length),r=e.t-n,o=e.t+n;return t.some(t=>{if(t.host.id!==e.host.id||t.opening.id===e.opening.id)return!1;const n=t.length/(2*t.axis.length);return Math.max(r,t.t-n)ha-icon{align-self:start;color:var(--hp-accent);}.version-recovery-copy{min-width:0;display:flex;flex-direction:column;gap:var(--sp-2);font-size:var(--fs-m);line-height:1.35;}.version-recovery-copy>span{color:var(--hp-muted);}.version-recovery-versions{display:flex;flex-wrap:wrap;gap:var(--sp-2) var(--sp-5);}.version-recovery-versions span,.version-recovery-versions b{overflow-wrap:anywhere;}.version-recovery-reload{min-height:44px;white-space:normal;}@keyframes hp-version-recovery-in{from{opacity:0;}to{opacity:1;}}@keyframes hp-version-recovery-out{from{opacity:1;}to{opacity:0;}}@media (max-width:520px){.version-recovery-card{grid-template-columns:auto minmax(0,1fr);}.version-recovery-reload{grid-column:1 / -1;width:100%;}}@keyframes fixedfloor-spin{to{transform:rotate(360deg);}}.spacer{flex:1;}.bootveil{position:absolute;inset:0;z-index:40;display:flex;align-items:center;justify-content:center;background:var(--hp-bg,#16212e);opacity:1;transition:opacity 0.15s ease;pointer-events:none;}.bootveil.off{opacity:0;}.bootveil .boothouse{position:static;width:56px;height:56px;fill:var(--hp-accent);opacity:0.85;animation:hp-boot-pulse 1.3s ease-in-out infinite;}@keyframes hp-boot-pulse{0%,100%{opacity:0.3;transform:scale(0.94);}50%{opacity:0.9;transform:scale(1);}}@media (prefers-reduced-motion:reduce){.bootveil .boothouse{animation:none;opacity:0.7;}.version-recovery.phase-visible,.version-recovery.phase-leaving{animation:none;}}@keyframes hp-pulse-short{0%{transform:scale(1);opacity:0.55;}70%{opacity:0.22;}100%{transform:scale(var(--ripple-scale,1.5));opacity:0;}}@keyframes hp-pulse-short-b{0%{transform:scale(1);opacity:0.55;}70%{opacity:0.22;}100%{transform:scale(var(--ripple-scale,1.5));opacity:0;}}@keyframes hp-pulse-continuous{0%{transform:scale(1);opacity:0.55;}65%{opacity:0.18;}100%{transform:scale(var(--ripple-scale,1.5));opacity:0;}}@keyframes hp-pulse-alarm{0%{transform:scale(1);opacity:0.72;}100%{transform:scale(1.5);opacity:0;}}@keyframes hp-slide-left{0%{transform:translateX(4%);opacity:0.72;}100%{transform:translateX(0);opacity:1;}}@keyframes hp-slide-right{0%{transform:translateX(-4%);opacity:0.72;}100%{transform:translateX(0);opacity:1;}}@keyframes hp-sunfade-in{from{opacity:0;}to{opacity:1;}}@keyframes hp-sunfade-out{from{opacity:1;}to{opacity:0;}}.sr-only{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0,0,0,0) !important;white-space:nowrap !important;border:0 !important;}.toast{position:fixed;pointer-events:none;left:50%;bottom:22px;transform:translateX(-50%);background:var(--hp-bg);border:1px solid var(--hp-accent);color:var(--hp-txt);padding:var(--sp-4) var(--sp-6);border-radius:var(--rad-l);font-size:var(--fs-m);box-shadow:var(--shadow-2);z-index:120;max-width:90vw;}`,o`.fixedfloor-loading{animation:fixedfloor-spin 1.1s linear infinite;}.fixedfloor-error p{max-width:42rem;margin:0;overflow-wrap:anywhere;}@media (prefers-reduced-motion:reduce){.fixedfloor-loading{animation:none;}.radar-target{transition:none;}}.stage.noplan{background:#ffffff;}.stage.mode-plan,.stage.mode-devices,.stage.mode-decor{background:#ffffff;}.stage{position:relative;width:100%;container-type:inline-size;overflow:hidden;touch-action:none;background:var(--ha-card-background,var(--card-background-color,#111));}.zoomwrap{position:absolute;inset:0;z-index:1;}.stage.mode-transition,.stage.mode-transition .zoomwrap{transition:none !important;}.stage.mode-transition .hp-view-only-layer,.stage.mode-transition .hp-editor-only-layer{pointer-events:none;will-change:opacity;}.stage.mode-transition .hp-paper{fill:var(--hp-mode-paper) !important;}.hp-day-cycle-env{position:absolute;inset:0;z-index:0;overflow:hidden;pointer-events:none;isolation:isolate;}.hp-day-cycle-bg{position:absolute;inset:0;opacity:0;overflow:hidden;transition:opacity 1100ms cubic-bezier(.22,.61,.36,1);}.hp-day-cycle-bg.active{opacity:1;}.hp-day-cycle-sun{position:absolute;left:var(--hp-day-cycle-sun-x);top:var(--hp-day-cycle-sun-y);width:clamp(140px,25cqw,250px);height:clamp(140px,25cqw,250px);transform:translate(-50%,-50%);border-radius:50%;filter:blur(10px);opacity:var(--hp-day-cycle-sun-opacity);transition:left 1100ms cubic-bezier(.22,.61,.36,1),top 1100ms cubic-bezier(.22,.61,.36,1),opacity 1100ms cubic-bezier(.22,.61,.36,1);}.stage.mode-transition .hp-day-cycle-env{transition:none;}.stage.daycycle .hp-paperg,.stage.daycycle.hp-safe-daycycle-outline .hp-paper-outline-svg,.hp-static-stage.daycycle .hp-paper-outline-svg{filter:drop-shadow(0 0 1px var(--hp-day-cycle-outline-near)) drop-shadow(0 0 5px var(--hp-day-cycle-outline-mid)) drop-shadow(0 0 10px var(--hp-day-cycle-outline-far));will-change:filter;transition:filter 1100ms cubic-bezier(.22,.61,.36,1);}.stage.daycycle.hp-safe-daycycle-outline .hp-paperg{filter:none;will-change:auto;transition:none;}.hp-static-stage.daycycle .hp-paperg{filter:none;will-change:auto;transition:none;}.stage.daycycle.hp-safe-daycycle-outline .hp-paper-outline-svg{transition:none;}.stage.daycycle.hp-safe-daycycle-outline .plan-svg{will-change:transform;}@media (prefers-reduced-motion:reduce){.hp-day-cycle-bg,.hp-day-cycle-sun,.stage.daycycle .hp-paperg,.stage.daycycle.hp-safe-daycycle-outline .hp-paper-outline-svg,.hp-static-stage.daycycle .hp-paper-outline-svg{transition:none;}}.sunlayer{pointer-events:none;}.compass{touch-action:none;cursor:grab;user-select:none;}.compass:active{cursor:grabbing;}.stage.hpboot .zoomwrap,.stage.hpboot .zoombadge{visibility:hidden;}.stage.hpsettle{transition:height 0.25s ease;}@media (prefers-reduced-motion:reduce){.stage.hpsettle{transition:none;}}.zoomctl{display:inline-flex;gap:var(--sp-1);background:rgba(127,127,127,0.12);border-radius:var(--rad-m);padding:var(--sp-1);}.zoomctl .zb{border:none;padding:var(--sp-3) var(--sp-4);}.zoomctl .zb[disabled]{opacity:0.4;pointer-events:none;}.projection-toggle{min-width:44px;min-height:44px;justify-content:center;padding:var(--sp-3);}.header-action{min-width:44px;min-height:44px;justify-content:center;padding:var(--sp-3);}.homearrow{position:absolute;z-index:12;transform:translate(-50%,-50%);width:40px;height:40px;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;background:var(--card-background-color,var(--hp-bg));color:var(--hp-accent);border:1px solid var(--hp-accent);opacity:0.9;padding:0;}.homearrow ha-icon{--mdc-icon-size:22px;line-height:1;}.zoombadge{position:absolute;z-index:12;left:var(--sp-4);bottom:var(--sp-4);background:var(--card-background-color,var(--hp-bg));opacity:0.92;color:var(--hp-txt);border:1px solid var(--hp-accent);border-radius:var(--rad-m);padding:var(--sp-1) var(--sp-4);font-size:var(--fs-s);font-weight:600;pointer-events:none;}.zoomwrap>svg{position:absolute;inset:0;width:100%;height:100%;display:block;}.plan-svg{z-index:1;}.hp-paper-outline-svg{z-index:0;overflow:visible;pointer-events:none;visibility:hidden;}.stage.hp-safe-daycycle-outline .hp-paper-outline-svg{visibility:visible;}.hp-static-stage .hp-paper-outline-svg{visibility:visible;}.iso-underlay-svg{z-index:0;overflow:visible;}.iso-shadows-svg{z-index:3;overflow:visible;}.iso-walls-svg{z-index:4;overflow:visible;}.iso-overlays-svg{z-index:5;overflow:visible;}.iso-underlay-svg,.iso-shadows-svg,.iso-walls-svg,.iso-overlays-svg,.iso-underlay,.iso-shadows,.iso-walls,.iso-openings{pointer-events:none;}.iso-side-hi{stop-color:#b9bdbe;}.iso-side-lo{stop-color:#969c9f;}.iso-top-hi{stop-color:#fafaf7;}.iso-top-lo{stop-color:#e2e4e2;}.iso-wall-side{fill:url(#hp-iso-wall-side) #a8acae;stroke:#92989b;stroke-width:0.7;vector-effect:non-scaling-stroke;}.iso-wall-top{fill:url(#hp-iso-wall-top) #f3f3f1;stroke:#d7d9d8;stroke-width:0.8;vector-effect:non-scaling-stroke;}.iso-material-texture{fill:url(#hp-iso-wall-texture);stroke:none;opacity:0.12;pointer-events:none;}.iso-floor-texture{fill:url(#hp-iso-floor-texture);opacity:0.1;}.iso-texture-mark{fill:rgba(36,43,47,0.34);}.iso-texture-line{fill:none;stroke:rgba(36,43,47,0.24);stroke-width:0.55;}.iso-floor-side{fill:#858b8d;stroke:#71787b;stroke-width:0.7;vector-effect:non-scaling-stroke;}.iso-opening-panel{fill:#d7d9d7;fill-opacity:0.96;stroke:#7f878b;stroke-width:0.9;vector-effect:non-scaling-stroke;}.iso-opening-panel.iso-window{fill:#dfeff4;fill-opacity:0.72;stroke:#8aa7b1;}.iso-opening-panel.iso-material-reveal{fill:#c7cbca;stroke:#8b9294;}.iso-opening-panel.iso-material-matte-leaf{fill:#a6abad;stroke:none;}.iso-opening-panel.iso-opening-leaf-edge,.iso-opening-panel.iso-opening-leaf-top{fill:#8d9497;}.iso-opening-panel.iso-material-light-frame,.iso-opening-panel.iso-material-light-sill{fill:#fffef8;fill-opacity:0.94;stroke:#b3b5ae;}.iso-opening-panel.iso-material-light-window,.iso-opening-panel.iso-material-glass-side{fill:#c9e4f3;fill-opacity:0.88;stroke:#8fb4c7;}.iso-opening-panel.iso-material-glass-top{fill:#e3f2fa;fill-opacity:0.96;stroke:#9fc4d5;}.iso-ambient-shadow{fill:rgba(15,21,25,0.22);filter:url(#hp-iso-ambient-shadow);}.stage.theme-dark .iso-side-hi{stop-color:#4c555a;}.stage.theme-dark .iso-side-lo{stop-color:#343c40;}.stage.theme-dark .iso-top-hi{stop-color:#687176;}.stage.theme-dark .iso-top-lo{stop-color:#50585d;}.stage.theme-dark .iso-wall-side{stroke:#30373b;}.stage.theme-dark .iso-wall-top{stroke:#7b858a;}.stage.theme-dark .iso-floor-side{fill:#2d3438;stroke:#20272a;}.stage.theme-dark .iso-opening-panel{fill:#626b70;stroke:#899399;}.stage.theme-dark .iso-opening-panel.iso-window{fill:#75919b;stroke:#abc6ce;}.stage.theme-dark .iso-opening-panel.iso-material-reveal{fill:#454e52;stroke:#727d82;}.stage.theme-dark .iso-opening-panel.iso-material-matte-leaf{fill:#626a6e;stroke:none;}.stage.theme-dark .iso-opening-panel.iso-opening-leaf-edge,.stage.theme-dark .iso-opening-panel.iso-opening-leaf-top{fill:#4b5458;}.stage.theme-dark .iso-opening-panel.iso-material-light-frame,.stage.theme-dark .iso-opening-panel.iso-material-light-sill{fill:#e8e7df;stroke:#a9aca7;}.stage.theme-dark .iso-opening-panel.iso-material-light-window,.stage.theme-dark .iso-opening-panel.iso-material-glass-side{fill:#8fbfd5;stroke:#bad9e6;}.stage.theme-dark .iso-opening-panel.iso-material-glass-top{fill:#c9e6f2;stroke:#d9eef6;}.stage.theme-dark .iso-ambient-shadow{fill:rgba(0,0,0,0.34);}.stage.theme-dark .iso-texture-mark{fill:rgba(255,255,255,0.24);}.stage.theme-dark .iso-texture-line{stroke:rgba(255,255,255,0.18);}@media (prefers-color-scheme:dark){.stage:not(.theme-light) .iso-side-hi{stop-color:#4c555a;}.stage:not(.theme-light) .iso-side-lo{stop-color:#343c40;}.stage:not(.theme-light) .iso-top-hi{stop-color:#687176;}.stage:not(.theme-light) .iso-top-lo{stop-color:#50585d;}.stage:not(.theme-light) .iso-wall-side{stroke:#30373b;}.stage:not(.theme-light) .iso-wall-top{stroke:#7b858a;}.stage:not(.theme-light) .iso-floor-side{fill:#2d3438;stroke:#20272a;}.stage:not(.theme-light) .iso-opening-panel{fill:#626b70;stroke:#899399;}.stage:not(.theme-light) .iso-opening-panel.iso-window{fill:#75919b;stroke:#abc6ce;}.stage:not(.theme-light) .iso-opening-panel.iso-material-reveal{fill:#454e52;stroke:#727d82;}.stage:not(.theme-light) .iso-opening-panel.iso-material-matte-leaf{fill:#626a6e;stroke:none;}.stage:not(.theme-light) .iso-opening-panel.iso-opening-leaf-edge,.stage:not(.theme-light) .iso-opening-panel.iso-opening-leaf-top{fill:#4b5458;}.stage:not(.theme-light) .iso-opening-panel.iso-material-light-frame,.stage:not(.theme-light) .iso-opening-panel.iso-material-light-sill{fill:#e8e7df;stroke:#a9aca7;}.stage:not(.theme-light) .iso-opening-panel.iso-material-light-window,.stage:not(.theme-light) .iso-opening-panel.iso-material-glass-side{fill:#8fbfd5;stroke:#bad9e6;}.stage:not(.theme-light) .iso-opening-panel.iso-material-glass-top{fill:#c9e6f2;stroke:#d9eef6;}.stage:not(.theme-light) .iso-ambient-shadow{fill:rgba(0,0,0,0.34);}.stage:not(.theme-light) .iso-texture-mark{fill:rgba(255,255,255,0.24);}.stage:not(.theme-light) .iso-texture-line{stroke:rgba(255,255,255,0.18);}}@media (forced-colors:active){.iso-wall-side,.iso-wall-top,.iso-floor-side,.iso-opening-panel{fill:Canvas;stroke:CanvasText;forced-color-adjust:auto;}.iso-ambient-shadow,.iso-material-texture{display:none;}}@supports not (filter:blur(1px)){.iso-ambient-shadow,.iso-material-texture{display:none;}}.hp-paper{fill:var(--ha-card-background,var(--card-background-color,#111));stroke:none;}.stage.noplan .hp-paper,.stage.mode-plan .hp-paper,.stage.mode-devices .hp-paper,.stage.mode-decor .hp-paper{fill:#ffffff;}.room{transition:0.12s;cursor:default;stroke-linejoin:round;stroke-linecap:round;}.stage.mode-view .room{cursor:pointer;}.room.overlay{fill:transparent;stroke:transparent;stroke-width:calc(2px * var(--hp-cell-visual-scale,1));}:host([data-pointer-hover]) .stage.mode-view .room.overlay:not(.styled):hover{stroke:var(--hp-accent);stroke-opacity:1;}.room.yard{fill:rgba(75,140,90,0.14);stroke:#4b8c5a;stroke-width:calc(2px * var(--hp-cell-visual-scale,1));}:host([data-pointer-hover]) .stage.mode-view .room.yard:not(.styled):hover{stroke:var(--hp-accent);stroke-opacity:1;}.room.styled{stroke:var(--room-stroke,transparent);stroke-opacity:var(--room-stroke-op,0);stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));fill:var(--room-fill,transparent);fill-opacity:var(--room-fill-op,0);}.glow-base-layer,.glow-base-tunnels,.glow-pools-frame,.glow-pools,.glow-spot{pointer-events:none;}.glow-pools-frame,.glow-pools,.glow-spot{isolation:isolate;}.glow-pools.blend-screen .glow-spot{mix-blend-mode:screen;}.glow-spot{opacity:1;transition:opacity 500ms ease;}.glow-spot.is-entering,.glow-spot.is-leaving{opacity:0;}@media (prefers-reduced-motion:reduce){.glow-spot{transition:none;}}:host([data-pointer-hover]) .stage.mode-view .room.styled:hover{stroke:var(--hp-accent);stroke-opacity:1;}.op-leaf{transition:transform 0.6s ease;}.op-arc{stroke-width:calc(1.5px * var(--hp-cell-visual-scale,1));transition:stroke-dashoffset 0.6s ease;}.op-outline{fill:none;stroke:var(--hp-accent);stroke-width:calc(1.5px * var(--hp-cell-visual-scale,1));opacity:0;transition:opacity 0.15s;pointer-events:none;}:host([data-pointer-hover]) .stage.markup g.opening:hover .op-outline{opacity:0.9;}.op-hit{fill:transparent;pointer-events:none;cursor:default;}.stage.markup .op-hit{pointer-events:auto;cursor:grab;touch-action:none;}.stage.markup .op-hit:active{cursor:grabbing;}.stage.markup .opening.orphan{pointer-events:auto;cursor:pointer;color:var(--error-color,#db4437);}.stage.markup .opening.orphan circle{fill:var(--hp-bg);stroke:currentColor;stroke-width:calc(2px * var(--hp-cell-visual-scale,1));}.stage.markup .opening.orphan text{fill:currentColor;font-weight:800;font-size:calc(12px * var(--hp-cell-visual-scale,1));pointer-events:none;}.stage.markup.tool-resize .op-hit{pointer-events:none;cursor:default;}.stage.mode-view .oplock{pointer-events:auto;cursor:pointer;}.stage.projection-iso.mode-view .oplock::before{content:'';position:absolute;left:50%;top:50%;width:max(44px,100%);height:max(44px,100%);transform:translate(-50%,-50%);border-radius:50%;pointer-events:auto;}@media (prefers-reduced-motion:reduce){.op-leaf,.op-arc{transition:none;}}.roomlabel{pointer-events:none;position:absolute;transform:translate(-50%,-50%);font-size:calc(var(--rl-icon-size,var(--icon-size,2.5cqw)) * 0.5 * var(--rl-scale,1) * var(--rl-font,1) * var(--rl-space,1));font-weight:700;letter-spacing:0.04em;white-space:nowrap;cursor:grab;user-select:none;z-index:1;display:flex;flex-direction:column;align-items:center;gap:0.15em;text-align:center;}.rlname{display:inline-flex;align-items:center;gap:0.25em;font-size:calc(1em * var(--rl-name,1));}.zoomwrap.slide-left{animation:hp-slide-left 0.18s cubic-bezier(0.2,0.7,0.2,1);}.zoomwrap.slide-right{animation:hp-slide-right 0.18s cubic-bezier(0.2,0.7,0.2,1);}@media (prefers-reduced-motion:reduce){.zoomwrap.slide-left,.zoomwrap.slide-right{animation:none;}}.rlgearbtn{--gear-h:calc(var(--icon-size,2.5cqw) * 0.77);position:absolute;transform:translate(-50%,-50%);display:inline-flex;align-items:center;gap:0.35em;height:var(--gear-h);padding:0 calc(var(--gear-h) * 0.38);border:0;border-radius:999px;background:var(--hp-accent);color:var(--text-primary-color,#fff);font:inherit;font-size:calc(var(--gear-h) * 0.42);font-weight:600;line-height:1;white-space:nowrap;cursor:pointer;pointer-events:auto;opacity:0.92;box-shadow:var(--shadow-1);z-index:2;}.rlgearbtn{transition:opacity 0.15s,filter 0.15s;}:host([data-pointer-hover]) .rlgearbtn:hover{opacity:1;filter:brightness(1.18);}.rlgearbtn ha-icon{--mdc-icon-size:calc(var(--gear-h) * 0.55);display:inline-flex;}.rlgear{--mdc-icon-size:0.9em;display:inline-flex;margin-right:0.2em;opacity:0.6;cursor:pointer;pointer-events:auto;}:host([data-pointer-hover]) .rlgear:hover{opacity:1;}.rlgo{--mdc-icon-size:0.85em;display:inline-flex;opacity:0.55;}.stage.mode-view .rlgo{pointer-events:auto;cursor:pointer;}:host([data-pointer-hover]) .stage.mode-view .rlgo:hover{opacity:1;}.roomlabel .rlmetrics{position:absolute;top:calc(100% + 0.15em);left:50%;transform:translateX(-50%);white-space:nowrap;display:flex;align-items:center;gap:0.55em;font-size:calc(0.75em * var(--rl-meta,1));font-weight:600;letter-spacing:0.02em;opacity:0.9;}.roomlabel .rlm{display:inline-flex;align-items:center;gap:0.12em;}.roomlabel .rlm ha-icon{--mdc-icon-size:1.05em;display:inline-flex;}.roomlabel .rlm.lit{opacity:1;}.rlhandle{display:none;position:absolute;width:9px;height:9px;border-radius:2px;background:var(--hp-accent);border:1px solid var(--card-background-color,#fff);z-index:2;}.rlhandle.tl{left:-6px;top:-6px;cursor:nwse-resize;}.rlhandle.br{right:-6px;bottom:-6px;cursor:nwse-resize;}.rlhandle.tr{right:-6px;top:-6px;cursor:nesw-resize;}.rlhandle.bl{left:-6px;bottom:-6px;cursor:nesw-resize;}:host([data-pointer-hover]) .stage.markup .roomlabel:hover .rlhandle{display:block;}.stage.markup .roomlabel{pointer-events:auto;}.stage.mode-view .roomlabel{pointer-events:auto;cursor:pointer;border-radius:0.2em;}.stage.projection-iso.mode-view .roomlabel{box-sizing:border-box;min-width:44px;min-height:44px;justify-content:center;text-shadow:none;filter:none;-webkit-text-stroke:0 transparent;color:#303936 !important;}.stage.projection-iso.mode-view .dev,.stage.projection-iso.mode-view .oplock{z-index:2;}.stage.projection-iso.theme-dark.mode-view .roomlabel{color:#f2f0e8 !important;}@media (prefers-color-scheme:dark){.stage.projection-iso:not(.theme-light).mode-view .roomlabel{color:#f2f0e8 !important;}}.stage.mode-view .roomlabel:focus-visible{outline:2px solid var(--hp-accent);outline-offset:4px;}.roomlabel:active{cursor:grabbing;}.measurelayer{position:absolute;inset:0;pointer-events:none;}.alignline{stroke:var(--hp-accent);stroke-width:calc(1.2px * var(--hp-cell-visual-scale,1));stroke-dasharray:calc(4px * var(--hp-cell-visual-scale,1)) calc(4px * var(--hp-cell-visual-scale,1));pointer-events:none;opacity:0.9;}.aligndot{fill:var(--hp-accent);pointer-events:none;}.measurelabel.on45{color:#4bd28f;border-color:#4bd28f;}.measurelabel{position:absolute;transform:translate(12px,-150%);font-size:var(--fs-s);font-weight:600;padding:1px var(--sp-3);border-radius:var(--rad-s);background:rgba(0,0,0,0.72);color:#fff;white-space:nowrap;pointer-events:none;user-select:none;z-index:3;}.measurelabel.opdimension{transform:translate(calc(-50% + var(--op-label-shift-x,0px)),calc(-50% + var(--op-label-shift-y,-12px)));border:1px solid var(--hp-open,#ff9800);}.decorlayer .dshape{pointer-events:none;}.stage.mode-decor .decorlayer .dshape{pointer-events:visiblePainted;cursor:pointer;}.stage.mode-decor.dtool-select .decorlayer .dshape{cursor:move;}.stage.mode-decor.dtool-line .decorlayer .dshape,.stage.mode-decor.dtool-rect .decorlayer .dshape,.stage.mode-decor.dtool-ellipse .decorlayer .dshape,.stage.mode-decor.dtool-text .decorlayer .dshape,.stage.mode-decor.dtool-furniture .decorlayer .dshape,.stage.mode-decor.dtool-image .decorlayer .dshape,.stage.mode-decor.dtool-backdrop .decorlayer .dshape{pointer-events:none;}.stage.mode-decor.dtool-furniture,.stage.mode-decor.dtool-image{cursor:copy;}.stage.mode-decor.dtool-select .decorlayer .dimage,.stage.mode-decor.dtool-erase .decorlayer .dimage,.stage.mode-decor.dtool-select .decorlayer .dimage-missing,.stage.mode-decor.dtool-erase .decorlayer .dimage-missing{pointer-events:bounding-box;}.decorlayer .dimage-missing rect{fill:rgba(127,127,127,0.12);stroke:var(--hp-accent);stroke-dasharray:8 5;vector-effect:non-scaling-stroke;}.decorlayer .dimage-missing path{fill:none;stroke:var(--hp-accent);vector-effect:non-scaling-stroke;}.decorlayer .decor-image-placement-preview{opacity:0.65;}.stage.mode-decor.dtool-text .decorlayer .dshape.dtext,.stage.mode-decor.dtool-select .decorlayer .dshape.dtext,.stage.mode-decor.dtool-erase .decorlayer .dshape.dtext{pointer-events:visiblePainted;pointer-events:bounding-box;}.stage.mode-decor.dtool-text .decorlayer .dshape.dtext{cursor:text;}.decorlayer .derasehit{fill:none;stroke:transparent;stroke-width:16px;stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke;pointer-events:none;}.stage.mode-decor.dtool-erase .decorlayer .derasehit{pointer-events:stroke;}.decorlayer .dselecthit{fill:none;stroke:transparent;stroke-width:16px;stroke-linecap:round;vector-effect:non-scaling-stroke;pointer-events:none;}.stage.mode-decor.dtool-select .decorlayer .dselecthit{pointer-events:stroke;cursor:move;}.stage.mode-decor .decorlayer .dshape.dfurniturehit{fill:none;stroke:transparent;pointer-events:none;}.stage.mode-decor.dtool-select .decorlayer .dshape.dfurniturehit{pointer-events:stroke;cursor:move;}.decorlayer .dsel{filter:drop-shadow(0 0 3px var(--hp-accent));}.decorlayer .ddraft{stroke-dasharray:calc(6px * var(--hp-cell-visual-scale,1)) calc(5px * var(--hp-cell-visual-scale,1));pointer-events:none;}.decorlayer .furniture-placement-preview{opacity:0.55;pointer-events:none;}.decorlayer text{font-weight:600;user-select:none;dominant-baseline:middle;text-anchor:middle;}.stage.mode-decor{outline:2px solid #26a69a;outline-offset:-2px;}.bdframe .bdbox{fill:none;stroke:var(--hp-accent);stroke-width:2;stroke-dasharray:10 7;vector-effect:non-scaling-stroke;pointer-events:none;opacity:0.9;}.bdframe .bdhandle{fill:transparent;stroke:none;pointer-events:all;touch-action:none;}.bdframe .bdknob{fill:var(--hp-accent);stroke:#fff;stroke-width:1;vector-effect:non-scaling-stroke;pointer-events:none;}:host([data-pointer-hover]) .bdframe .bdhandle:hover + .bdknob{fill:#fff;stroke:var(--hp-accent);}.bdframe .bd-nwse{cursor:nwse-resize;}.bdframe .bd-nesw{cursor:nesw-resize;}.stage.mode-decor.bdgrab{cursor:grab;}.stage.mode-decor.bdgrabbing,.stage.mode-decor.bdgrabbing .bdframe .bdhandle{cursor:grabbing;}.measurelabel.bdmeasure{transform:translate(-50%,-50%);border:1px solid var(--hp-accent);}.dtframe .dtbox{fill:none;stroke:var(--hp-accent);stroke-width:1.5;stroke-dasharray:7 5;vector-effect:non-scaling-stroke;pointer-events:none;opacity:0.85;}.dtframe .dtstem,.bdframe .dtstem{stroke:var(--hp-accent);stroke-width:1.5;vector-effect:non-scaling-stroke;pointer-events:none;opacity:0.85;}.dtframe .dthandle{fill:transparent;stroke:none;pointer-events:all;touch-action:none;}.dtframe .dtknob{fill:var(--hp-accent);stroke:#fff;stroke-width:1;vector-effect:non-scaling-stroke;pointer-events:none;}:host([data-pointer-hover]) .dtframe .dthandle:hover + .dtknob{fill:#fff;stroke:var(--hp-accent);}.dtframe .dt-nwse{cursor:nwse-resize;}.dtframe .dt-nesw{cursor:nesw-resize;}.dtframe .dtrot{cursor:grab;}.dtframe .dt-ew{cursor:ew-resize;}.dtframe .dt-ns{cursor:ns-resize;}.dtfurnitureframe .dtrot{cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M18.4 7.2A8 8 0 1 0 20 12' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'/%3E%3Cpath d='m15.5 3.8 3.2 3.5-4.6.8' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 12 12,grab;}.dtfurnitureframe .dtrot:active{cursor:grabbing;}.dtframe .dtendpoint{cursor:crosshair;}.bdframe .dtrot{cursor:grab;}.dtarea{resize:vertical;min-height:3.4em;font:inherit;line-height:1.35;}.stage.mode-decor.dtool-line,.stage.mode-decor.dtool-rect,.stage.mode-decor.dtool-ellipse,.stage.mode-decor.dtool-text{cursor:crosshair;}.stage.mode-decor.dtool-erase,.stage.mode-decor.dtool-erase .decorlayer .dshape{cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg transform='rotate(-45 12 12)'%3E%3Crect x='7' y='2' width='10' height='18' rx='2' fill='%23fff' stroke='%23111' stroke-width='1.5'/%3E%3Cpath d='M7 13h10v5a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2z' fill='%23ff9f43' stroke='%23111' stroke-width='1.5'/%3E%3C/g%3E%3C/svg%3E") 5 22,pointer;}.stage.mode-decor .room{pointer-events:none;}.stage.mode-decor .devlayer,.stage.mode-decor .devlayer *,.stage.mode-decor .dev::before{pointer-events:none;}.stage .room,.stage .devlayer,.stage .opening,.stage .room-outline,.stage .wallbodies,.stage .opening-tunnels,.stage .glow-base-layer,.stage .glow-pools-frame,.stage .zero-walls{opacity:var(--hp-mode-architecture-opacity,1);}.opening-preview{opacity:0.5;pointer-events:none;}.opening-preview[data-kind="passage"]{opacity:1;}.passage-preview-cut{fill:var(--wall-fill,#ffffff);fill-opacity:0.35;stroke:none;pointer-events:none;}.passage-preview-boundary{stroke:var(--hp-open,#ff9800);stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));pointer-events:none;}.opening-preview .op-leaf,.opening-preview .op-arc{transition:none;}.opening-preview-dot{fill:var(--hp-open,#ff9800);pointer-events:none;}.opening-dimensions,.opening-dimension{pointer-events:none;}.opening-dimension-line,.opening-dimension-tick{fill:none;stroke:var(--hp-open,#ff9800);stroke-width:1.5;vector-effect:non-scaling-stroke;pointer-events:none;}.opening-dimension-tick{stroke-width:2;}.stage.edit .room{pointer-events:none;}.stage.markup{cursor:crosshair;}.stage.markup.tool-merge,.stage.markup.tool-split.pickstage,.stage.markup.tool-delroom{cursor:pointer;}.stage.markup.tool-wallthick{cursor:default;}.stage.markup.tool-wallthick.wallhot{cursor:pointer;}.wallbody-fill{fill:var(--wall-fill,#ffffff);fill-opacity:var(--wall-fill-op,1);fill-rule:evenodd;stroke:none;pointer-events:none;}.wallbody{fill:url(#hp-wall-hatch);fill-rule:evenodd;stroke:var(--room-stroke,var(--hp-muted));stroke-width:calc(0.6px * var(--hp-cell-visual-scale,1));pointer-events:none;}.wallbody.solid{fill:none;}.wallthick-hover{fill:var(--accent-color,#03a9f4);fill-opacity:0.38;stroke:var(--accent-color,#03a9f4);stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));stroke-linejoin:round;stroke-linecap:round;pointer-events:none;}.wallthick-hover.isopen{fill:var(--error-color,#f44336);stroke:var(--error-color,#f44336);}.zero-wall{stroke:var(--zero-wall-stroke,var(--hp-muted));stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));stroke-dasharray:calc(7px * var(--hp-cell-visual-scale,1)) calc(7px * var(--hp-cell-visual-scale,1));stroke-linecap:butt;pointer-events:none;opacity:0.9;}.zero-walls.solid .zero-wall{stroke-dasharray:none;}.room.noedge{stroke-opacity:0 !important;}.room-outline{fill:none;stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));stroke-linejoin:round;stroke-linecap:round;pointer-events:none;}.room-outline.outlined{stroke:rgba(62,166,255,0.55);stroke-opacity:1;}.room-hover-fill{fill:#000;fill-opacity:0.22;pointer-events:none;}.room-hover-halo{fill:none;stroke:var(--hp-accent);stroke-opacity:0.28;stroke-width:calc(8px * var(--hp-cell-visual-scale,1));stroke-linejoin:round;stroke-linecap:round;pointer-events:none;}.room-hover-outline{fill:none;stroke:var(--hp-accent);stroke-width:calc(3px * var(--hp-cell-visual-scale,1));stroke-linejoin:round;stroke-linecap:round;pointer-events:none;}.stage.markup .room{pointer-events:none;}.stage.markup .devlayer .dev{display:none;}.stage.mode-plan{outline:2px solid #ffc14d;outline-offset:-2px;}.stage.mode-devices{outline:2px solid var(--hp-accent);outline-offset:-2px;}.room.outlined{stroke:rgba(62,166,255,0.55);fill:rgba(62,166,255,0.06);}.room.picked{stroke:#ffc14d;stroke-width:calc(3px * var(--hp-cell-visual-scale,1));fill:rgba(255,193,77,0.25);}.griddot{fill:var(--hp-accent);opacity:0.35;stroke:rgba(0,0,0,0.35);stroke-width:0.4;}.griddot.major{opacity:0.5;stroke-width:0;}.seg{stroke:var(--hp-accent);stroke-width:calc(2.5px * var(--hp-cell-visual-scale,1));stroke-linecap:round;stroke-linejoin:round;}.pathline{stroke:#ffc14d;stroke-width:calc(3px * var(--hp-cell-visual-scale,1));fill:none;stroke-linecap:round;stroke-linejoin:round;}.preview{stroke:#ffc14d;stroke-width:calc(2px * var(--hp-cell-visual-scale,1));stroke-dasharray:calc(6px * var(--hp-cell-visual-scale,1)) calc(5px * var(--hp-cell-visual-scale,1));opacity:0.7;}.active-axis{stroke:#ffc14d;stroke-width:2;stroke-linecap:round;vector-effect:non-scaling-stroke;pointer-events:none;}.active-vertex{fill:#ffc14d;stroke:#171006;stroke-width:2;vector-effect:non-scaling-stroke;pointer-events:none;}.wall-repair-preview{stroke:#d93025;stroke-width:4;stroke-linecap:round;stroke-dasharray:5 4;vector-effect:non-scaling-stroke;pointer-events:none;}.drawwall-preview-fill{fill:var(--wall-fill,#ffffff);fill-opacity:calc(var(--wall-fill-op,1) * 0.55);fill-rule:evenodd;stroke:none;pointer-events:none;}.drawwall-preview{fill:url(#hp-wall-hatch);fill-opacity:0.55;fill-rule:evenodd;stroke:var(--accent-color,#03a9f4);stroke-width:calc(0.5px * var(--hp-cell-visual-scale,1));stroke-opacity:0.7;pointer-events:none;}.drawwall-zero-preview{fill:none;stroke:var(--accent-color,#03a9f4);stroke-width:calc(3px * var(--hp-cell-visual-scale,1));stroke-linecap:butt;stroke-linejoin:round;opacity:0.72;pointer-events:none;}.drawwall-zero-preview.dashed{stroke-dasharray:calc(7px * var(--hp-cell-visual-scale,1)) calc(7px * var(--hp-cell-visual-scale,1));}.vertex{fill:#ffc14d;stroke:#4a2800;stroke-width:calc(1px * var(--hp-cell-visual-scale,1));}.vertex.first{fill:#4bd28f;stroke:#04121f;}.plan-snap-overlay,.plan-snap-overlay *,.hidden-wall-diagnostic,.hidden-wall-diagnostic *{pointer-events:none;}.plan-snap-line,.hidden-wall-line{fill:none;stroke:color-mix(in srgb,var(--hp-accent) 82%,white 18%);stroke-width:1;stroke-linecap:round;opacity:0.92;}.plan-snap-node,.hidden-wall-node{fill:var(--ha-card-background,var(--card-background-color,#fff));stroke:color-mix(in srgb,var(--hp-accent) 88%,#07131c 12%);stroke-width:1;vector-effect:non-scaling-stroke;}.plan-snap-node.active{fill:#ffc14d;stroke:#171006;stroke-width:2;}.plan-snap-node.active.dynamic{fill:#4bd28f;stroke:#04121f;}.plan-snap-node.conflict{fill:#fff;stroke:#d93025;stroke-width:3;}@media (prefers-color-scheme:dark){.plan-snap-line{stroke:color-mix(in srgb,var(--hp-accent) 72%,white 28%);}.hidden-wall-line{stroke:color-mix(in srgb,var(--hp-accent) 72%,white 28%);}.plan-snap-node,.hidden-wall-node{fill:#17242c;stroke:#9bdcf5;}.plan-snap-node.active{fill:#ffc14d;stroke:#fff4d6;}.plan-snap-node.active.dynamic{fill:#4bd28f;stroke:#eafff4;}}@media (forced-colors:active){.plan-snap-line,.hidden-wall-line{stroke:CanvasText;opacity:1;forced-color-adjust:auto;}.plan-snap-node,.hidden-wall-node{fill:Canvas;stroke:CanvasText;forced-color-adjust:auto;}.plan-snap-node.active,.plan-snap-node.active.dynamic{fill:Highlight;stroke:HighlightText;forced-color-adjust:auto;}}.sunlayer{animation:hp-sunfade-in 2s linear both;}.sunlayer.out{animation:hp-sunfade-out 2s linear both;}@media (prefers-reduced-motion:reduce){.sunlayer,.sunlayer.out{animation:none;}.sunlayer.out{opacity:0;}}.devlayer{position:absolute;inset:0;pointer-events:none;z-index:6;}.radar-target{position:absolute;width:8px;height:8px;box-sizing:border-box;transform:translate(-50%,-50%);border-radius:50%;background:var(--success-color,#43a047);border:2px solid var(--primary-text-color,#1f1f1f);box-shadow:0 0 0 1px color-mix(in srgb,var(--card-background-color,#fff) 80%,transparent);pointer-events:none;z-index:0;}.radar-target.smooth{transition:left 200ms linear,top 200ms linear;}.radar-ranges{position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none;z-index:0;}.radar-ranges path,.radar-ranges polyline{fill:none;stroke:var(--success-color,#43a047);stroke-width:2px;stroke-dasharray:5 4;vector-effect:non-scaling-stroke;opacity:0.72;}.radar-ranges .radar-zone{fill:color-mix(in srgb,var(--success-color,#43a047) 8%,transparent);stroke:var(--success-color,#43a047);stroke-width:2px;vector-effect:non-scaling-stroke;opacity:0.8;}.stage.mode-devices .dev{cursor:grab;}.stage.mode-devices .dev:active{cursor:grabbing;}.physical-hit{fill:transparent;stroke:transparent;pointer-events:none;cursor:grab;}.stage.tool-select .physical-hit{pointer-events:all;}.physical-hit:active{cursor:grabbing;}line.physical-hit{cursor:pointer;}.physical-hit.selected{fill:rgba(255,193,77,0.24);stroke:transparent;}line.physical-hit.selected{stroke:transparent;}.physical-drag{fill:rgba(255,193,77,0.38);stroke:#ffc14d;stroke-width:2.5;vector-effect:non-scaling-stroke;pointer-events:none;}.physical-chrome{pointer-events:none;}.physical-chrome .frame,.physical-chrome .stem{fill:none;stroke:#ffc14d;stroke-width:2;vector-effect:non-scaling-stroke;}.physical-chrome .frame{fill:rgba(255,193,77,0.22);}.physical-chrome polyline.frame{fill:none;}.physical-chrome .move-dot{fill:#ffc14d;stroke:#24262d;stroke-width:1.5;vector-effect:non-scaling-stroke;}.physical-chrome .rotate-handle{fill:#24262d;stroke:#ffc14d;stroke-width:2.5;vector-effect:non-scaling-stroke;pointer-events:all;cursor:crosshair;}.drawwall.invalid input{border-color:var(--error-color,#db4437);}.drawwall .rangehint{margin-inline-start:4px;font-size:0.78em;opacity:0.72;}.drawwall.invalid .rangehint{color:var(--error-color,#db4437);opacity:1;}.stage.markup.tool-partition,.stage.markup.tool-column{cursor:crosshair;}.rszhandle{fill:transparent;stroke:none;pointer-events:all;cursor:grab;touch-action:none;}.rszhandle:active{cursor:grabbing;}.rszhandle.disabled,.rszhandle.disabled:active{cursor:not-allowed;}.rszicon{pointer-events:none;}.rszicon path{fill:none;stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke;}.rszhalo{stroke:var(--hp-bg);stroke-width:6;}.rszink{stroke:var(--hp-accent);stroke-width:2;}:host([data-pointer-hover]) .rszhandle:hover + .rszicon .rszink{stroke-width:3;}.rszicon.disabled{opacity:0.38;}:host([data-pointer-hover]) .rszhandle.disabled:hover + .rszicon .rszink{stroke-width:2;}.rszmeasurelayer,.rszmeasurelayer *{pointer-events:none;}.rszmeasurehalo,.rszmeasureink,.rszleader{fill:none;stroke-linecap:round;vector-effect:non-scaling-stroke;}.rszmeasurehalo{stroke:var(--hp-bg);stroke-width:7px;opacity:0.9;}.rszmeasureink{stroke:var(--hp-accent);stroke-width:3px;}.rszleader{stroke:var(--hp-accent);stroke-width:2px;opacity:0.95;}.measurelabel.dmeasure{transform:translate(-50%,-160%);}.measurelabel.rszarea{transform:translate(calc(-50% + var(--rsz-label-x,0px)),calc(-50% + var(--rsz-label-y,0px)));background:rgba(0,0,0,0.6);border:1px solid var(--hp-accent);}.measurelabel.furnmeasure{transform:translate(-50%,-50%);border:1px solid var(--hp-accent);}.alignmsg{margin:0 0 8px;font-size:13px;line-height:1.45;}`,o`.dev ha-icon{position:relative;z-index:1;}.device-pulse{position:absolute;left:50%;top:50%;width:var(--dev-size);height:var(--dev-size);transform:translate(-50%,-50%);pointer-events:none;z-index:0;}.device-pulse i{position:absolute;inset:0;border-radius:50%;border:2px solid var(--ripple-color,var(--hp-accent));opacity:0;}.device-pulse.short i{animation:hp-pulse-short 1.1s cubic-bezier(.22,.61,.36,1) 1 forwards;}.device-pulse.short i:nth-child(2){animation-delay:1.1s;}.device-pulse.short i:nth-child(3){animation-delay:2.2s;}.device-pulse.short.gen2 i{animation-name:hp-pulse-short-b;}.device-pulse.continuous i:nth-child(n + 2),.device-pulse.alarm i:nth-child(n + 3){display:none;}.device-pulse.continuous i:first-child{animation:hp-pulse-continuous 3.6s cubic-bezier(.45,.05,.55,.95) infinite;}.device-pulse.alarm i{border-width:3px;border-color:#F0410C;animation:hp-pulse-alarm 2.4s cubic-bezier(.22,.61,.36,1) infinite;}.device-pulse.alarm i:nth-child(2){animation-delay:1.2s;}.activity-dot{position:absolute;right:8%;bottom:8%;width:18%;height:18%;min-width:4px;min-height:4px;border-radius:50%;background:var(--ripple-color,var(--hp-accent));border:1px solid color-mix(in srgb,var(--hp-bg) 82%,transparent);pointer-events:none;z-index:3;}.kioskdots{position:absolute;left:50%;bottom:var(--sp-5);transform:translateX(-50%);display:flex;gap:var(--sp-4);z-index:5;pointer-events:none;}.kdot{width:9px;height:9px;border-radius:50%;background:var(--hp-muted);opacity:0.55;}.kdot.on{background:var(--hp-accent);opacity:1;}.dev.valonly{width:var(--dev-size,var(--icon-size,2.5cqw));}.dev.valonly .device-core{width:max-content;min-width:var(--dev-size,var(--icon-size,2.5cqw));padding-inline:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.16);border-radius:calc(var(--dev-size,var(--icon-size,2.5cqw)) / 2);}.dev .valtext{overflow:visible;font-size:calc(var(--dev-size,var(--icon-size,2.5cqw)) * var(--value-font-scale,.45));font-weight:600;white-space:nowrap;}@media (prefers-reduced-motion:reduce){.device-pulse{display:none;}}.dev .newdot{position:absolute;top:calc(var(--dev-size,var(--icon-size,2.5cqw)) * -0.12);right:calc(var(--dev-size,var(--icon-size,2.5cqw)) * -0.12);width:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.34);height:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.34);border-radius:50%;background:#f0301f;border:2px solid var(--card-background-color,var(--hp-bg));pointer-events:none;z-index:2;}.dev{position:absolute;--dev-size:calc(var(--device-base-size,2.25cqw) * var(--dev-scale,1));--device-shell-size:calc(var(--dev-size) * 1.26875);--device-shell-inset:calc(var(--dev-size) * 0.134375);--device-shell-stroke-ratio:0.01875;--device-shell-border-width:max(1px,calc(var(--dev-size) * var(--device-shell-stroke-ratio)));--device-core-bg:var(--card-background-color,#fff);--device-core-fg:var(--primary-text-color,#252525);--device-core-bg:light-dark(#fff,#252525);--device-core-fg:light-dark(#252525,#fff);--device-face-bg:var(--device-core-bg);--device-face-fg:var(--device-core-fg);--device-shell-base-stroke:light-dark(#BCBCBC,rgb(37 37 37 / 75%));--device-shell-stroke:var(--device-shell-base-stroke);--device-shell-shadow:0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .05) rgb(37 40 45 / 12%),0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%);--device-core-inset-shadow:0 0 0 0 transparent;--device-ring-color:transparent;--device-ring-width:0px;width:var(--dev-size);height:var(--dev-size);margin:calc(var(--dev-size) / -2) 0 0 calc(var(--dev-size) / -2);border:0;background:transparent;display:block;color:var(--device-core-fg);cursor:pointer;pointer-events:none;transition:opacity 0.2s;box-shadow:none;outline:none;z-index:auto;}.dev.theme-light{--device-core-bg:#fff;--device-core-fg:#000;--device-shell-base-stroke:#BCBCBC;--device-shell-stroke:var(--device-shell-base-stroke);--device-shell-shadow:0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .05) rgb(37 40 45 / 12%),0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%);--device-core-inset-shadow:0 0 0 0 transparent;}.dev.theme-dark{--device-core-bg:#252525;--device-core-fg:#fff;--device-shell-base-stroke:rgb(37 37 37 / 75%);--device-shell-stroke:var(--device-shell-base-stroke);--device-shell-shadow:0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .0375) rgb(37 40 45 / 12%),0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%);--device-core-inset-shadow:inset 0 calc(var(--dev-size) * 0.0125) calc(var(--dev-size) * 0.0125) rgb(255 255 255 / 70%);}.dev::before{content:'';position:absolute;left:50%;top:50%;width:max(44px,var(--device-shell-size));height:max(44px,var(--device-shell-size));transform:translate(-50%,-50%);border-radius:50%;pointer-events:auto;z-index:1;}.device-shell{position:absolute;box-sizing:border-box;display:flex;align-items:center;gap:calc(var(--dev-size) * 0.1);padding:0;min-width:var(--dev-size);min-height:var(--dev-size);border:0;background:transparent;box-shadow:none;transition:opacity .2s;pointer-events:none;z-index:2;}.device-shell-frame{position:absolute;z-index:0;box-sizing:border-box;inset:calc(var(--device-shell-inset) / -1);border:var(--device-shell-border-width) solid var(--device-shell-stroke);border-radius:9999px;background:transparent;box-shadow:var(--device-shell-shadow);transition:border-color .15s,opacity .2s;pointer-events:auto;backdrop-filter:none;}.device-shell:not(.with-values){left:0;top:0;}.device-shell:not(.with-values):not(.text-shell) .device-shell-frame{border-radius:50%;}.device-shell.with-values.pos-right{left:0;top:50%;transform:translateY(-50%);}.device-shell.with-values.pos-left{right:0;top:50%;transform:translateY(-50%);flex-direction:row-reverse;}.device-shell.with-values.pos-bottom{left:50%;top:0;transform:translateX(-50%);flex-direction:column;}.device-shell.with-values.pos-top{left:50%;bottom:0;transform:translateX(-50%);flex-direction:column-reverse;}.device-core{position:relative;z-index:1;box-sizing:border-box;flex:0 0 auto;width:var(--dev-size);height:var(--dev-size);display:flex;align-items:center;justify-content:center;border-radius:50%;background:var(--device-face-bg);color:var(--device-face-fg);box-shadow:var(--device-core-inset-shadow),0 0 0 var(--device-ring-width) var(--device-ring-color);line-height:0;transition:background .15s,color .15s,opacity .2s;pointer-events:none;}.device-sections{display:flex;flex-direction:column;align-items:stretch;justify-content:center;gap:calc(var(--dev-size) * .08);min-width:0;pointer-events:none;}.device-shell.pos-top .device-sections,.device-shell.pos-bottom .device-sections{flex-direction:row;}.dev ha-icon{--mdc-icon-size:calc(var(--dev-size,var(--device-base-size,2.25cqw)) * 0.55);display:flex;align-items:center;justify-content:center;line-height:0;}.dev.on{--device-face-bg:#F0A00C;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:#F0A00C;}.dev.theme-light.on{--device-face-fg:#fff;}.dev.theme-dark.on{--device-face-fg:#252525;--device-shell-stroke-ratio:.0375;}.dev.open{--device-face-bg:var(--hp-open);--device-face-fg:light-dark(#fff,#252525);}.dev.theme-light.open{--device-face-fg:#fff;}.dev.theme-dark.open{--device-face-fg:#252525;}.dev.lock-locked{--device-face-bg:#66D17A;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:#66D17A;}.dev.theme-light.lock-locked{--device-face-fg:#fff;}.dev.theme-dark.lock-locked{--device-face-fg:#252525;--device-shell-stroke-ratio:.025;}.dev.lock-unlocked{--device-face-bg:#F0410C;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:#F0410C;}.dev.theme-light.lock-unlocked{--device-face-fg:#fff;}.dev.theme-dark.lock-unlocked{--device-face-fg:#252525;--device-shell-stroke-ratio:.025;}:host([data-pointer-hover]) .dev:not(.unavail)[data-hp-device-hover]{--device-face-bg:#0C82F0;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:var(--device-shell-base-stroke);}:host([data-pointer-hover]) .dev.theme-light:not(.unavail)[data-hp-device-hover]{--device-face-fg:#fff;}:host([data-pointer-hover]) .dev.theme-dark:not(.unavail)[data-hp-device-hover]{--device-face-fg:#252525;}:host([data-pointer-hover]) .dev[data-hp-device-hover],.dev:focus-visible{z-index:5;}.dev[data-hp-zigbee-topology-endpoint]{z-index:8;}:host([data-pointer-hover]) .dev[data-hp-zigbee-topology-endpoint][data-hp-device-hover]{z-index:8;}.dev.unavail{opacity:0.35;--device-face-bg:#B5BAC1;--device-shell-stroke:var(--device-shell-base-stroke);}.dev.virtual .device-shell-frame{border-style:dashed;}.dev.ghost{opacity:0.6;color:var(--hp-accent);}.dev.ghost .device-shell-frame{border-style:dashed;border-color:var(--hp-accent);box-shadow:none;}.dev.ghost .device-core{background:rgba(62,166,255,0.22);background:color-mix(in srgb,var(--hp-accent) 30%,var(--card-background-color,#1c2530));color:var(--hp-accent);}.dev.ghost.ha-disabled{opacity:0.62;color:var(--secondary-text-color,#9aa0aa);}.dev.ghost.ha-disabled .device-shell-frame{border-color:var(--secondary-text-color,#9aa0aa);}.dev.ghost.ha-disabled .device-core{background:rgba(120,124,134,0.2);background:color-mix(in srgb,var(--secondary-text-color,#9aa0aa) 24%,var(--card-background-color,#1c2530));color:var(--secondary-text-color,#9aa0aa);}.dev .habadge{position:absolute;right:-18%;bottom:-18%;display:grid;place-items:center;width:46%;height:46%;min-width:12px;min-height:12px;border-radius:50%;background:var(--card-background-color,#242832);border:1px solid currentColor;}.dev .habadge ha-icon{width:72%;height:72%;}.dev.sel{--device-ring-color:#F0A00C;--device-ring-width:calc(var(--dev-size) * 0.0375);}.dev:focus-visible{--device-ring-color:#0C82F0;--device-ring-width:calc(var(--dev-size) * 0.0375);}.dev:not(.on):not(.open):not(.alarm):not(.lock-locked):not(.lock-unlocked):not(.unavail):focus-visible{--device-face-fg:#0C82F0;}.dev.alarm,:host([data-pointer-hover]) .dev.alarm[data-hp-device-hover],.dev.alarm:focus-visible{--device-face-bg:#F0410C;--device-face-fg:light-dark(#fff,#252525);--device-shell-stroke:#F0410C;}.dev.theme-light.alarm{--device-face-fg:#fff;}.dev.theme-dark.alarm{--device-face-fg:#252525;--device-shell-stroke-ratio:.025;}.dev .value-badge{position:relative;z-index:2;box-sizing:border-box;width:max-content;min-width:calc(var(--dev-size,var(--icon-size,2.5cqw)) * .7875);height:calc(var(--dev-size,var(--icon-size,2.5cqw)) * .7875);display:flex;align-items:center;justify-content:center;overflow:visible;background:var(--device-core-bg);border:0;border-radius:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.39375);padding:0 calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.14);font-size:calc(var(--dev-size,var(--icon-size,2.5cqw)) * var(--value-font-scale,.45));font-weight:600;line-height:1;color:var(--device-core-fg);white-space:nowrap;pointer-events:none;}.dev .value-badge.unavailable,.dev .value-badge.missing{opacity:0.66;}.dev .lqi{position:absolute;top:calc(50% + var(--device-shell-size) / 2 + var(--dev-size) * .05);left:50%;transform:translateX(-50%);margin-top:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.05);font-size:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.38);font-weight:600;line-height:1;text-shadow:0 0 3px rgba(0,0,0,0.9),0 0 2px rgba(0,0,0,0.9);white-space:nowrap;pointer-events:none;}.dev .lqi.below-value-badge{margin-top:calc(var(--dev-size,var(--icon-size,2.5cqw)) * 0.8875);}.temprange{display:inline-flex;align-items:center;gap:var(--sp-3);margin-left:auto;color:var(--hp-muted);font-size:var(--fs-s);}.vacwarn{position:absolute;top:-12%;right:-12%;width:calc(var(--device-base-size,2.25cqw) * 0.42);height:calc(var(--device-base-size,2.25cqw) * 0.42);border-radius:50%;display:flex;align-items:center;justify-content:center;background:light-dark(#fff,#252525);border:1px solid #E5A100;color:#E5A100;z-index:7;pointer-events:none;}.vacwarn ha-icon{--mdc-icon-size:calc(var(--device-base-size,2.25cqw) * 0.32);color:inherit;}.vacpuck{position:absolute;--puck-size:calc(var(--device-base-size,2.25cqw) * 0.8);width:var(--puck-size);height:var(--puck-size);border-radius:50%;transform:translate(-50%,-50%);--vac-core-bg:light-dark(#fff,#252525);--vac-core-fg:light-dark(#252525,#fff);background:var(--vac-core-bg);border:1px solid #BCBCBC;box-shadow:0 1px 2px rgb(37 40 45 / 12%),0 4px 8px -1.07px rgb(37 40 45 / 18%);color:var(--vac-core-fg);display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:6;transition:left 1.2s linear,top 1.2s linear;animation:vacpulse 2.2s ease-out infinite;}.vacpuck.theme-light{--vac-core-bg:#fff;--vac-core-fg:#252525;}.vacpuck.theme-dark{--vac-core-bg:#252525;--vac-core-fg:#fff;}.vacpuck.jump{transition:none;}.vacpuck.stale{opacity:0.45;animation:none;}.vacpuck ha-icon{--mdc-icon-size:calc(var(--puck-size) * 0.68);color:var(--vac-core-fg);display:flex;align-items:center;justify-content:center;line-height:0;width:var(--mdc-icon-size);height:var(--mdc-icon-size);}@keyframes vacpulse{0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--hp-accent) 45%,transparent);}70%{box-shadow:0 0 0 12px transparent;}100%{box-shadow:0 0 0 0 transparent;}}@media (prefers-reduced-motion:reduce){.vacpuck{animation:none;}}.vactrail{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:5;overflow:visible;}.vactrail polyline,.vactrail path{fill:none;stroke-linejoin:round;stroke-linecap:round;vector-effect:non-scaling-stroke;}.vactrail g.prev{opacity:0.4;}.vactrail .case{stroke:rgba(0,0,0,0.4);stroke-width:2.25;}.vactrail .core{stroke:rgba(255,255,255,0.82);stroke-width:0.9;}.devicepreview-empty{min-height:82px;margin:4px 0 14px;padding:var(--sp-4);display:flex;align-items:center;justify-content:center;gap:var(--sp-3);border:1px dashed var(--hp-line);border-radius:var(--rad-m);color:var(--hp-muted);text-align:center;}`,o`.hdr{position:sticky;top:var(--header-height,56px);z-index:20;background:var(--card-background-color,var(--hp-bg));border-radius:var(--ha-card-border-radius,12px) var(--ha-card-border-radius,12px) 0 0;}.tabs{display:flex;gap:var(--sp-2);background:rgba(127,127,127,0.12);padding:var(--sp-2);border-radius:var(--rad-l);flex-wrap:wrap;}.tab{border:0;background:transparent;color:var(--hp-muted);display:inline-flex;align-items:center;padding:var(--sp-3) var(--sp-5);border-radius:var(--rad-m);font-size:var(--fs-m);font-weight:600;cursor:pointer;transition:0.15s;font-family:inherit;}:host([data-pointer-hover]) .tab:hover{color:var(--hp-txt);}.tab.active{background:var(--hp-accent);color:var(--text-primary-color,#fff);}.farhint{position:absolute;left:50%;transform:translateX(-50%);bottom:var(--sp-4);z-index:12;display:flex;align-items:center;gap:var(--sp-2);max-width:calc(100% - var(--sp-8));background:var(--card-background-color,var(--hp-bg));opacity:0.94;color:var(--hp-txt);border:1px solid var(--divider-color,#33404d);border-radius:var(--rad-m);padding:var(--sp-1) var(--sp-3);font-size:var(--fs-s);}.farhint ha-icon{--mdc-icon-size:18px;color:var(--hp-warn,#e2a03f);flex:none;}.farhint span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.dropbtn{display:flex;align-items:center;gap:var(--sp-4);width:100%;text-align:left;border:1px solid var(--hp-muted);border-radius:var(--rad-m);background:transparent;color:var(--hp-txt);padding:var(--sp-4) 10px;cursor:pointer;font-family:inherit;font-size:var(--fs-m);margin-top:var(--sp-3);}.dropbtn .ref{color:var(--hp-muted);font-size:var(--fs-s);margin-left:auto;}.dropbtn ha-icon{--mdc-icon-size:18px;margin-left:var(--sp-2);}.dropbtn.open{border-color:var(--hp-accent);}.droppanel{border:1px solid var(--hp-accent);border-top:none;border-radius:0 0 var(--rad-m) var(--rad-m);padding:var(--sp-3);margin-top:-4px;}.hdr.kioskhide{display:none;}.decorbar .dcolor{width:30px;height:26px;padding:0;border:none;background:none;cursor:pointer;}.decorbar .dwidth{font-family:inherit;font-size:var(--fs-s);border-radius:var(--rad-s);background:var(--hp-bg2,transparent);color:var(--hp-txt);border:1px solid var(--hp-muted);padding:var(--sp-2) var(--sp-3);}.decorbar .bdhint{font-size:var(--fs-s);color:var(--hp-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.decorbar .dfill{display:inline-flex;align-items:center;gap:var(--sp-2);font-size:var(--fs-s);cursor:pointer;}.decorbar .dfill input[type="checkbox"]{width:16px;height:16px;flex:none;margin:0;padding:0;}.decorbar hp-color-opacity{flex:0 0 auto;}.modes{display:inline-flex;gap:var(--sp-1);background:rgba(127,127,127,0.12);border-radius:var(--rad-l);padding:var(--sp-2);}.modetab{display:inline-flex;align-items:center;gap:var(--sp-3);border:0;background:transparent;color:var(--hp-muted);padding:var(--sp-3) 10px;border-radius:var(--rad-m);font-size:var(--fs-m);font-weight:600;cursor:pointer;font-family:inherit;transition:background-color 0.14s ease,color 0.14s ease,transform 0.14s ease;}.modetab:active{transform:scale(0.97);}.modetab ha-icon{--mdc-icon-size:15px;}.tab[data-reorderable]{cursor:grab;}.tab.dragging{cursor:grabbing;opacity:0.55;}.tab.drop-before{box-shadow:inset 2px 0 0 0 var(--primary-color,#03a9f4);}.tab.drop-after{box-shadow:inset -2px 0 0 0 var(--primary-color,#03a9f4);}.modetab .closex{--mdc-icon-size:13px;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;min-width:24px;min-height:24px;margin:-5.5px -5.5px -5.5px -3.5px;opacity:0.75;cursor:pointer;border-radius:var(--rad-s);}:host([data-pointer-hover]) .modetab .closex:hover{opacity:1;}.editbar .barclose{box-sizing:border-box;width:40px;height:40px;padding:0;margin:0;min-width:40px;min-height:40px;justify-content:center;gap:0;line-height:0;}.editbar .barclose ha-icon{flex:none;margin:0;}.modetab.active{background:var(--hp-accent);color:var(--text-primary-color,#fff);}@media (max-width:720px){.modetab .ml{display:none;}}.editbar{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:stretch;border-bottom:1px solid var(--hp-line);font-size:var(--fs-m);}.editbar-tools{display:flex;align-items:center;gap:10px;padding:var(--sp-4) var(--sp-5);flex-wrap:wrap;min-width:0;outline:none;}.editbar-end{display:flex;align-items:center;padding:var(--sp-4) var(--sp-5);border-inline-start:1px solid var(--hp-line);background:var(--card-background-color,var(--hp-bg));position:relative;z-index:2;}.tab .tabedit{--mdc-icon-size:13px;display:inline-flex;align-items:center;margin-left:var(--sp-3);opacity:0.4;}:host([data-pointer-hover]) .tab:hover .tabedit{opacity:0.9;}.tab.tabadd{padding:var(--sp-3) var(--sp-4);}.tab.tabadd ha-icon{--mdc-icon-size:15px;}.rhint{font-size:var(--fs-s);color:var(--hp-muted);margin-bottom:var(--sp-3);}.editorchrome{display:block;height:0;opacity:0;visibility:hidden;overflow:hidden;}.editorchrome:not(.open){pointer-events:none;}.editorchrome.open{height:auto;opacity:1;visibility:visible;overflow:visible;}.editorchrome.transitioning{overflow:hidden;will-change:height;pointer-events:none;}.editorchrome.transitioning .barclose{pointer-events:auto;}.editorchrome-inner{min-height:0;transform-origin:top center;}.editorchrome.transitioning .editorchrome-inner{will-change:opacity;}@media (prefers-reduced-motion:reduce){.modetab{transition:none;}}.editbar .warn{color:#ffc14d;}.editbar .sname{font-weight:600;}.editbar input{width:74px;background:transparent;border:1px solid var(--hp-line);color:var(--hp-txt);border-radius:var(--rad-s);padding:var(--sp-3) var(--sp-4);font-size:var(--fs-m);}.editbar label,.editbar .hint{color:var(--hp-muted);font-size:var(--fs-s);}.editbar .drawwall{display:inline-flex;align-items:center;gap:var(--sp-3);white-space:nowrap;}.editbar .wallsgroup{display:inline-flex;align-items:center;gap:10px;white-space:nowrap;}.editbar .drawwall input{width:4.2em;}.editbar .drawwall .opl{color:var(--hp-muted);font-size:var(--fs-s);}.menuwrap{position:fixed;inset:0;z-index:80;}.menu{position:fixed;background:var(--hp-bg);border:1px solid var(--hp-accent);border-radius:var(--rad-l);box-shadow:var(--shadow-2);min-width:210px;max-width:300px;overflow:hidden;transform:translate(0,8px);}.menu .hd{padding:var(--sp-4) var(--sp-5);font-weight:600;font-size:var(--fs-m);border-bottom:1px solid var(--hp-line);display:flex;align-items:center;gap:var(--sp-3);}.menu .hd ha-icon,.menu .it.all ha-icon{color:var(--hp-accent);--mdc-icon-size:16px;}.menu .it{padding:var(--sp-4) var(--sp-5);font-size:var(--fs-m);cursor:pointer;display:flex;align-items:center;gap:var(--sp-4);}.menu .it ha-icon{--mdc-icon-size:16px;color:var(--hp-muted);}:host([data-pointer-hover]) .menu .it:hover{background:rgba(127,127,127,0.15);}.menu .it.all{color:var(--hp-accent);font-weight:600;}.tip{position:fixed;pointer-events:none;background:var(--hp-bg);border:1px solid var(--hp-accent);color:var(--hp-txt);padding:var(--sp-3) 10px;border-radius:var(--rad-m);font-size:var(--fs-m);box-shadow:var(--shadow-2);z-index:60;max-width:260px;}.tip .m{color:var(--hp-muted);font-size:var(--fs-s);display:block;}`,o`.head{display:flex;align-items:center;gap:10px;padding:10px var(--sp-5);border-bottom:1px solid var(--hp-line);flex-wrap:wrap;}.title{font-size:var(--fs-l);font-weight:600;display:flex;align-items:center;gap:var(--sp-3);white-space:nowrap;}.title ha-icon{color:var(--hp-accent);--mdc-icon-size:18px;}@media (max-width:1100px){.head .count{display:none;}}@media (max-width:620px){.head{gap:var(--sp-3);padding:var(--sp-4) 10px;}.head .title{font-size:var(--fs-m);}}.count{font-size:var(--fs-s);color:var(--hp-muted);}.btn{display:inline-flex;align-items:center;gap:var(--sp-3);border:1px solid var(--hp-line);background:transparent;color:var(--hp-txt);padding:var(--sp-3) 10px;border-radius:var(--rad-m);cursor:pointer;transition:0.15s;font-family:inherit;font-size:var(--fs-m);}.btn ha-icon{--mdc-icon-size:17px;}:host([data-pointer-hover]) .btn:hover{border-color:var(--hp-accent);}.btn.on{background:var(--hp-accent);color:var(--text-primary-color,#fff);border-color:var(--hp-accent);}.btn.ghost{border:none;}.btn[disabled]{opacity:0.5;pointer-events:none;}.recoveryoverlay{position:absolute;inset:0;z-index:75;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--sp-4);padding:var(--sp-6);box-sizing:border-box;background:linear-gradient(var(--ha-card-background,var(--card-background-color,#111)),var(--ha-card-background,var(--card-background-color,#111))),#111;color:var(--primary-text-color,#fff);text-align:center;pointer-events:auto;transition:opacity 0.15s ease;}.recoveryoverlay.phase-entering,.recoveryoverlay.phase-leaving{opacity:0;}.recoveryoverlay.phase-fading-in,.recoveryoverlay.phase-opaque{opacity:1;}.recoveryoverlay ha-icon{--mdc-icon-size:44px;color:var(--hp-accent);}.editorloading{position:absolute;z-index:74;left:50%;top:50%;display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-5);border:1px solid color-mix(in srgb,var(--hp-accent) 45%,transparent);border-radius:999px;background:color-mix(in srgb,var(--ha-card-background,var(--card-background-color,#111)) 92%,transparent);color:var(--primary-text-color);box-shadow:0 6px 22px rgb(0 0 0 / 18%);transform:translate(-50%,-50%);pointer-events:none;animation:editor-loading-in 0.15s ease both;}.editorloading ha-icon{--mdc-icon-size:22px;color:var(--hp-accent);animation:editor-loading-spin 0.9s linear infinite;}@keyframes editor-loading-in{from{opacity:0;transform:translate(-50%,calc(-50% + 4px));}to{opacity:1;transform:translate(-50%,-50%);}}@keyframes editor-loading-spin{to{transform:rotate(360deg);}}@media (prefers-reduced-motion:reduce){.recoveryoverlay,.editorloading,.editorloading ha-icon{transition:none;animation:none;}}.oplock{--oplock-size:calc(var(--icon-size,2.5cqw) * 0.62);--oplock-core-size:calc(var(--oplock-size) / 1.26875);--oplock-stroke-ratio:0.01875;--oplock-stroke-width:max(1px,calc(var(--oplock-core-size) * var(--oplock-stroke-ratio)));--oplock-core-bg:light-dark(#fff,#252525);--oplock-core-fg:light-dark(#252525,#fff);--oplock-shell-stroke:light-dark(#BCBCBC,rgb(37 37 37 / 75%));--oplock-shell-shadow:0 calc(var(--oplock-core-size) * .025) calc(var(--oplock-core-size) * .05) rgb(37 40 45 / 12%),0 calc(var(--oplock-core-size) * .1) calc(var(--oplock-core-size) * .175) calc(var(--oplock-core-size) * -.025) rgb(37 40 45 / 18%);--oplock-core-shadow:0 0 0 0 transparent;pointer-events:none;position:absolute;transform:translate(-50%,-50%);width:var(--oplock-size);height:var(--oplock-size);display:grid;place-items:center;border:0;background:transparent;z-index:1;}.oplock.theme-light{--oplock-core-bg:#fff;--oplock-core-fg:#252525;--oplock-shell-stroke:#BCBCBC;}.oplock.theme-dark{--oplock-core-bg:#252525;--oplock-core-fg:#fff;--oplock-shell-stroke:rgb(37 37 37 / 75%);--oplock-core-shadow:inset 0 calc(var(--oplock-core-size) * .0125) calc(var(--oplock-core-size) * .0125) rgb(255 255 255 / 70%);}.oplock-shell{box-sizing:border-box;width:100%;height:100%;border:var(--oplock-stroke-width) solid var(--oplock-shell-stroke);border-radius:50%;background:transparent;box-shadow:var(--oplock-shell-shadow);display:grid;place-items:center;pointer-events:none;backdrop-filter:none;}.oplock-core{width:var(--oplock-core-size);height:var(--oplock-core-size);border-radius:50%;background:var(--oplock-core-bg);color:var(--oplock-core-fg);box-shadow:var(--oplock-core-shadow);display:grid;place-items:center;pointer-events:none;}.oplock ha-icon{--mdc-icon-size:calc(var(--oplock-core-size) * 0.55);display:flex;line-height:0;}.oplock.locked{--oplock-core-bg:#66D17A;--oplock-core-fg:light-dark(#fff,#252525);--oplock-shell-stroke:#66D17A;}.oplock.theme-light.locked{--oplock-core-fg:#fff;}.oplock.theme-dark.locked{--oplock-core-fg:#252525;--oplock-stroke-ratio:.025;}.oplock.unlocked{--oplock-core-bg:#F0410C;--oplock-core-fg:light-dark(#fff,#252525);--oplock-shell-stroke:#F0410C;}.oplock.theme-light.unlocked{--oplock-core-fg:#fff;}.oplock.theme-dark.unlocked{--oplock-core-fg:#252525;--oplock-stroke-ratio:.025;}.oplock.unknown{--oplock-core-fg:var(--hp-muted);}.btn.lockact{width:100%;justify-content:center;display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-4);}.btn.lockact.warn{color:var(--error-color,#d33);border-color:var(--error-color,#d33);}.oprow{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-3) 0;}.oprow b{margin-left:auto;}.oprow.ok b{color:#66d17a;}.oprow.warn b{color:var(--hp-open);}.ctrlstates{display:flex;flex-direction:column;gap:var(--sp-2);}.ctrlstate{display:inline-flex;align-items:center;gap:var(--sp-3);color:var(--hp-muted);}.ctrlstate.on{color:var(--hp-txt);}.ctrlstate ha-icon{--mdc-icon-size:15px;}.cardpreview{display:flex;flex-direction:column;align-items:center;gap:var(--sp-2);margin:var(--sp-4) 0 var(--sp-1);padding:10px;border:1px dashed var(--hp-muted);border-radius:var(--rad-m);}.cardpreview .cpname{font-weight:700;letter-spacing:0.04em;}.cardpreview .cpmeta{display:inline-flex;align-items:center;gap:0.3em;font-weight:600;opacity:0.85;}.cardpreview .cpmeta ha-icon{--mdc-icon-size:1.05em;}hp-dialog .dfill{display:inline-flex;align-items:center;gap:var(--sp-3);cursor:pointer;}.wallthick-dlg{position:absolute;z-index:40;min-width:200px;transform:translate(-50%,8px);padding:10px 12px;border-radius:10px;background:var(--card-background-color,#fff);box-shadow:0 8px 28px rgba(0,0,0,.22);display:flex;flex-direction:column;gap:8px;pointer-events:auto;}.wallthick-dlg .row{display:flex;align-items:center;gap:8px;}.wallthick-dlg input[type="number"]{width:5.5em;padding:4px 6px;border:1px solid var(--divider-color,#ccc);border-radius:6px;background:var(--input-fill,transparent);color:var(--primary-text-color);}.areasel,.namein{background:var(--hp-bg);border:1px solid var(--hp-line);color:var(--hp-txt);border-radius:var(--rad-s);padding:var(--sp-3) var(--sp-4);font-size:var(--fs-m);font-family:inherit;}.namein{width:130px;}.habindingbanner{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);margin-bottom:var(--sp-4);border:1px solid var(--warning-color,#ff9800);border-radius:var(--rad-m);background:color-mix(in srgb,var(--warning-color,#ff9800) 12%,transparent);color:var(--primary-text-color,#f1f3f6);}.habindingbanner>span{flex:1;min-width:0;}.habindingbanner>ha-icon{color:var(--warning-color,#ff9800);flex:0 0 auto;}.habindingbanner.limited{border-color:var(--secondary-text-color,#9aa0aa);background:color-mix(in srgb,var(--secondary-text-color,#9aa0aa) 10%,transparent);}.habindingbanner.limited>ha-icon{color:var(--secondary-text-color,#9aa0aa);}.srcrow{display:flex;align-items:center;gap:var(--sp-4);font-size:var(--fs-m);cursor:pointer;padding:var(--sp-1) 0;}.dispsection{margin-top:var(--sp-5) !important;padding-top:var(--sp-4);border-top:1px solid var(--hp-line);font-weight:600;color:var(--hp-txt) !important;}.colorrow{display:flex;align-items:center;gap:var(--sp-4);}.colorrow input[type='range']{flex:1;}.colorrow .tempin{width:70px;flex:none;}hp-dialog .body .temprange .tempin{width:56px;flex:none;padding:var(--sp-2) var(--sp-3);}hp-dialog .body .colorrow .tempin{width:72px;flex:none;}.srcrow{flex-wrap:nowrap;}.srcrow ha-switch{flex:none;}.colorrow ha-slider{flex:1;min-width:0;}.srcrow>span:first-of-type{white-space:nowrap;}.colorrow .opl{color:var(--hp-muted);font-size:var(--fs-s);}.colorrow .opv{font-size:var(--fs-s);min-width:34px;text-align:right;}.markerlightgroup{min-width:0;margin:var(--sp-5) 0 0;padding:var(--sp-4);border:1px solid var(--hp-line);border-radius:var(--rad-m);}.markerlightgroup legend{display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-1);padding:0 var(--sp-2);color:var(--hp-txt);font-weight:600;}.markerlightgroup legend>span{min-width:0;overflow-wrap:anywhere;}.markerlightgroup[disabled]>:not(legend){opacity:.62;}.radargroup{display:grid;gap:var(--sp-2);}.radargroup>p{margin:0;}.radargroup>label:not(.srcrow){margin-top:var(--sp-2);}.radarcoordinates{align-items:flex-end;flex-wrap:wrap;}.radarcoordinates>label{display:grid;flex:1 1 92px;gap:var(--sp-1);min-width:0;margin:0;}hp-dialog .body .radarcoordinates .tempin{box-sizing:border-box;width:100%;}.radarinspection{display:grid;gap:6px;padding:10px 12px;border-radius:10px;background:color-mix(in srgb,var(--primary-color) 7%,transparent);}.radarinspection code{overflow-wrap:anywhere;font-size:12px;}.radarsetup{display:grid;gap:10px;margin-top:10px;padding:12px;border:1px solid var(--hp-accent);border-radius:var(--rad-m);background:color-mix(in srgb,var(--secondary-background-color) 88%,transparent);}.radarsetup-head{display:flex;align-items:center;gap:8px;}.radarsetup-head strong{flex:1;}.radarsetup>svg{width:min(100%,460px);aspect-ratio:1;justify-self:center;border-radius:var(--rad-m);background:var(--primary-background-color);touch-action:none;cursor:crosshair;}.radarsetup .room{fill:color-mix(in srgb,var(--hp-accent) 8%,transparent);stroke:var(--divider-color);stroke-width:3;vector-effect:non-scaling-stroke;}.radarsetup .heading{stroke:var(--hp-accent);stroke-width:4;vector-effect:non-scaling-stroke;}.radarsetup .trail{fill:none;stroke:var(--success-color,#43a047);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke;opacity:.55;}.radarsetup g circle{fill:var(--hp-bg);stroke:var(--hp-accent);stroke-width:3;vector-effect:non-scaling-stroke;}.radarsetup g.pending circle{stroke-dasharray:5 4;}.radarsetup g text{fill:var(--hp-txt);font-size:22px;font-weight:700;text-anchor:middle;dominant-baseline:middle;pointer-events:none;}.help-inline-label{display:inline-flex;align-items:center;flex-wrap:wrap;gap:var(--sp-1);}hp-dialog .body .help-inline-label>label{min-width:0;margin-top:0;overflow-wrap:anywhere;}.markerlightgroup .srcrow>span:first-of-type{min-width:0;white-space:normal;overflow-wrap:anywhere;}.planrow{display:flex;align-items:center;gap:10px;}.savedplans{display:flex;flex-direction:column;gap:var(--sp-3);max-height:240px;overflow:auto;margin:var(--sp-3) 0 var(--sp-1);padding:var(--sp-3);border:1px solid var(--hp-line);border-radius:var(--rad-m);background:var(--hp-bg2,rgba(255,255,255,0.03));flex:0 0 auto;min-height:2.6em;}.savedplan{display:flex;align-items:center;gap:10px;}.savedplan.cur{outline:1px solid var(--hp-accent);border-radius:var(--rad-s);}.savedplan img{width:56px;height:40px;object-fit:contain;border:1px solid var(--hp-line);border-radius:var(--rad-s);background:#fff;flex:none;}.savedmeta{display:flex;flex-direction:column;min-width:0;flex:1;}.savedmeta b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.savedmeta .muted{font-size:var(--fs-s);}.savedplan .btn.danger ha-icon{color:#f25a4a;}.savedplan .btn[disabled]{opacity:0.4;pointer-events:none;}.planprev{max-width:120px;max-height:70px;border:1px solid var(--hp-line);border-radius:var(--rad-s);background:#fff;}.planname{font-size:var(--fs-m);max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.planname.muted{color:var(--hp-muted);}.filebtn{cursor:pointer;}.btn.danger{border-color:#b3402a;color:#ff7a5c;}hp-dialog .row .spacer{flex:1;}hp-dialog .body{max-height:66vh;overflow-y:auto;}hp-dialog[form-shell] .body{max-height:none;overflow:visible;padding:16px;box-sizing:border-box;}@media (max-width:480px){hp-dialog[form-shell] .body{padding:12px;}}hp-confirm{display:contents;}hp-dialog .danger-confirm-body{display:flex;flex-direction:column;gap:var(--sp-4);}hp-dialog .danger-confirm-body p{margin:0;line-height:1.45;}hp-dialog .danger-confirm-object{overflow-wrap:anywhere;font-size:var(--fs-l);line-height:1.3;}.curbind{display:flex;align-items:center;gap:var(--sp-3);font-size:var(--fs-m);color:var(--hp-txt);flex-wrap:wrap;}.curbind .ref{color:var(--hp-muted);font-size:var(--fs-s);}.vacbox .vacbtns{display:flex;gap:var(--sp-4);margin:var(--sp-3) 0;flex-wrap:wrap;}.vacdiag{display:grid;gap:4px;margin-bottom:var(--sp-3);}.vacdiag>div{display:flex;justify-content:space-between;gap:var(--sp-5);}.vacdiag>div>span{color:var(--secondary-text-color);}.vacdiag>div>b{text-align:right;overflow-wrap:anywhere;}.vacroute-missing-group{margin-top:var(--sp-4);padding-top:var(--sp-4);border-top:1px solid var(--hp-line);}.vacroute-group-title{margin:0 0 var(--sp-3);color:var(--secondary-text-color);font-size:var(--fs-m);font-weight:600;}.vacroute-missing-group .vacroute-list{margin-top:0;}.vacpicker{margin:var(--sp-3) 0;}.vacsource-warning{display:grid;gap:8px;}.vacsource-warning .btn{justify-self:start;}.vacpicker>summary{display:inline-flex;width:auto;list-style:none;cursor:pointer;}.vacpicker>summary::-webkit-details-marker{display:none;}.vacsource-list{display:grid;gap:6px;margin-top:8px;}.vacsource-list details{padding:6px 0 0;}.vacsource-list details>summary{cursor:pointer;font-weight:600;}.vacsource{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;min-width:0;padding:9px 10px;border:1px solid var(--divider-color);border-radius:10px;color:var(--primary-text-color);background:var(--secondary-background-color);text-align:left;cursor:pointer;}.vacsource.on{border-color:var(--accent-color);box-shadow:inset 3px 0 var(--accent-color);}.vacsource>span:first-child{min-width:0;display:grid;gap:2px;}.vacsource small{color:var(--secondary-text-color);overflow-wrap:anywhere;}.vacsource-meta{color:var(--secondary-text-color);text-align:right;font-size:0.82em;}.vacxcme pre{margin:8px 0 0;white-space:pre-wrap;user-select:text;}.vacfit{position:absolute;inset:0;width:100%;height:100%;z-index:12;overflow:visible;touch-action:none;cursor:grab;pointer-events:auto;}.vacfit:active{cursor:grabbing;}.vacfit polygon{fill:color-mix(in srgb,var(--hp-accent) 16%,transparent);stroke:var(--hp-accent);stroke-width:2;vector-effect:non-scaling-stroke;stroke-dasharray:6 4;}.vacfit text{fill:var(--hp-accent);font-size:26px;text-anchor:middle;dominant-baseline:middle;pointer-events:none;user-select:none;}.furnpalette{display:flex;flex-direction:column;max-height:38vh;border-top:1px solid var(--hp-border,rgba(255,255,255,0.12));background:var(--card-background-color,var(--hp-bg));font-size:0.85em;}.furnhd{display:flex;align-items:center;gap:6px;padding:4px 8px;font-weight:600;opacity:0.9;}.furnhd .spacer{flex:1;}.furnbody{overflow:auto;padding:0 8px 6px;}.furngroup{margin:6px 0 3px;font-size:0.85em;text-transform:uppercase;letter-spacing:0.04em;opacity:0.6;}.furnrow{display:flex;flex-wrap:wrap;gap:4px;}.furnback{min-height:34px;gap:5px;margin:2px 0 4px;}.furnitem{display:flex;flex-direction:column;align-items:center;gap:2px;width:74px;padding:4px 2px;border:1px solid transparent;border-radius:8px;background:rgba(127,127,127,0.08);color:inherit;font:inherit;font-size:0.8em;line-height:1.15;text-align:center;cursor:pointer;}:host([data-pointer-hover]) .furnitem:hover{background:rgba(127,127,127,0.18);}.furnitem.on{border-color:var(--hp-accent);background:rgba(38,166,154,0.18);}.furnprev{width:40px;height:40px;color:var(--primary-text-color,currentColor);}.furncategory{width:92px;min-height:76px;}.furncatprev{width:48px;height:48px;}.furnvariants .furnitem{min-height:74px;}.furnsize{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:6px 8px;border-top:1px solid var(--hp-border,rgba(255,255,255,0.12));}.furnsize label{display:flex;align-items:baseline;gap:3px;opacity:0.8;}.furnsize .furnunit{opacity:0.6;font-size:0.85em;}.furnsize input{width:5.5em;padding:3px 5px;}.furnhint{opacity:0.6;}.imageupload{display:inline-flex;gap:6px;margin:4px 0 8px;cursor:pointer;}.imageupload.disabled{opacity:0.55;pointer-events:none;}.imageupload input{display:none;}.imageassets{align-items:stretch;}.imageempty{padding:12px 6px;}.imageasset{position:relative;}.imageasset .furnitem{width:104px;min-height:92px;}.imageasset img{width:64px;height:54px;object-fit:contain;border-radius:4px;background:repeating-conic-gradient(#ddd 0 25%,#fff 0 50%) 50% / 12px 12px;}.imageasset .furnitem span{max-width:96px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.imageasset .furnitem small{opacity:0.65;font-size:0.72em;}.imageassetdelete{position:absolute;top:0;right:0;min-width:30px;width:30px;min-height:30px;padding:3px;}.imagepropertypreview{display:flex;align-items:center;gap:10px;min-width:0;}.imagepropertypreview img{width:72px;height:54px;object-fit:contain;border-radius:4px;background:repeating-conic-gradient(#ddd 0 25%,#fff 0 50%) 50% / 12px 12px;}.imagepropertypreview span{overflow-wrap:anywhere;}.vacfitdot{fill:var(--hp-accent);pointer-events:none;}.vacfithandle{fill:transparent;stroke:none;cursor:nwse-resize;}.vacfitknob{fill:var(--hp-bg);stroke:var(--hp-accent);stroke-width:2;vector-effect:non-scaling-stroke;pointer-events:none;}.vaccalbar{position:fixed;left:50%;bottom:24px;transform:translateX(-50%);display:flex;gap:var(--sp-5);align-items:center;background:var(--hp-bg);color:var(--hp-txt);border:1px solid var(--hp-accent);border-radius:var(--rad-l);padding:10px var(--sp-5);z-index:60;box-shadow:var(--shadow-2);}.candlist{max-height:160px;overflow-y:auto;border-top:1px solid var(--hp-line);flex:0 0 auto;min-height:2.6em;}.cand{display:flex;justify-content:space-between;gap:var(--sp-4);padding:var(--sp-3) var(--sp-4);cursor:pointer;border-radius:var(--rad-s);font-size:var(--fs-m);}:host([data-pointer-hover]) .cand:hover{background:rgba(127,127,127,0.15);}.cand.sel{background:var(--hp-accent);color:var(--text-primary-color,#fff);}.cand .cs{color:var(--hp-muted);font-size:var(--fs-s);white-space:nowrap;}.opening-entity-candidate{width:100%;border:0;background:transparent;color:inherit;font:inherit;text-align:left;}.opening-entity-candidate.sel{background:var(--hp-accent);color:var(--text-primary-color,#fff);}.opening-entity-empty{cursor:default;}.cand.sel .cs{color:var(--text-primary-color,#fff);opacity:0.85;}.cand.muted{color:var(--hp-muted);cursor:default;}.entlist{display:flex;flex-direction:column;gap:var(--sp-2);margin-bottom:10px;}.entrow{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-3) var(--sp-4);border-radius:var(--rad-m);background:var(--secondary-background-color,rgba(128,128,128,0.12));}.entrow ha-icon{--mdc-icon-size:20px;color:var(--hp-muted);}.entrow.on ha-icon{color:var(--hp-accent);}.entrow .en{flex:1;font-size:var(--fs-m);}.entrow .ev{font-size:var(--fs-m);color:var(--hp-muted);}.entbtn{min-width:74px;min-height:32px;padding:var(--sp-2) var(--sp-5);border:1px solid var(--hp-muted);border-radius:999px;background:transparent;color:var(--hp-txt);font:inherit;font-size:var(--fs-m);cursor:pointer;}.entbtn.on{background:var(--hp-accent);border-color:var(--hp-accent);color:var(--text-primary-color,#fff);font-weight:600;}.inforow{display:flex;gap:10px;font-size:var(--fs-m);margin:var(--sp-2) 0;}.inforow .k{color:var(--hp-muted);min-width:84px;}.inforow a{color:var(--hp-accent);word-break:break-all;}.infodesc{font-size:var(--fs-m);white-space:pre-wrap;margin-top:var(--sp-3);}.infodesc.muted{color:var(--hp-muted);}.pdflist{display:flex;flex-direction:column;gap:var(--sp-2);}.pdf{display:inline-flex;align-items:center;gap:var(--sp-2);color:var(--hp-accent);text-decoration:none;}ha-icon-picker{display:block;}.floorrow{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-3) var(--sp-2);font-size:var(--fs-m);cursor:pointer;}.floorrow .floorlvl{color:var(--hp-muted);font-size:var(--fs-s);border:1px solid var(--hp-line);border-radius:var(--rad-s);padding:0 var(--sp-3);}.rtest{display:flex;align-items:center;gap:var(--sp-4);margin-bottom:var(--sp-4);}.rtest .namein{flex:1;}.rtest ha-icon{color:var(--hp-accent);}.rtesticon{font-size:var(--fs-s);color:var(--hp-muted);}.rrow{display:flex;align-items:center;gap:var(--sp-3);margin:var(--sp-1) 0;}.rrow .rpat{flex:2;}.rrow .ricon{flex:1.4;}.rrow .rpat.bad{border-color:#ff7a5c;}.rrow .rprev{--mdc-icon-size:18px;color:var(--hp-txt);min-width:18px;}.rrow .ract{--mdc-icon-size:16px;color:var(--hp-muted);cursor:pointer;}:host([data-pointer-hover]) .rrow .ract:hover{color:var(--hp-txt);}:host([data-pointer-hover]) .rrow .ract.del:hover{color:#ff7a5c;}.optimize-live{display:grid;justify-items:start;gap:var(--sp-2);margin-bottom:var(--sp-3);}.optimize-live .alignmsg,.optimize-live .rhint{margin-bottom:0;}.optimize-cleanup{min-height:44px;}.optimize-selected{color:var(--hp-txt);}.optimize-details{margin-top:var(--sp-3);color:var(--hp-muted);font-size:var(--fs-s);overflow-wrap:anywhere;}.optimize-details>summary{width:fit-content;color:var(--hp-txt);cursor:pointer;font-weight:600;}.optimize-details>summary:focus-visible{outline:2px solid var(--hp-accent);outline-offset:3px;border-radius:var(--rad-s);}.optimize-details ul{margin:var(--sp-3) 0;padding-inline-start:22px;}.optimize-details li + li{margin-top:var(--sp-1);}.btn.alignall{width:100%;justify-content:center;}.backupactions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-3);}.backupactions .btn{justify-content:center;min-width:0;}.backupupload{display:inline-flex;min-width:0;}.backupupload>.btn{width:100%;justify-content:center;}.backupupload input{display:none;}.backupbody{min-width:0;}.backupplanonly{margin-inline-start:var(--sp-4) !important;align-items:flex-start !important;}.backupplanonly>span:first-of-type{display:grid;gap:2px;white-space:normal;}.backupplanonly small{color:var(--secondary-text-color);line-height:1.35;}.backupplanonlystatus{color:var(--hp-accent) !important;font-weight:700;}.backupfile,.backupsummary,.backupcontent{display:flex;flex-direction:column;min-width:0;gap:var(--sp-1);}.backupfile b,.backupcontent span{overflow-wrap:anywhere;}.backupfile span,.backupsummary span,.backupcontent span{color:var(--hp-muted);font-size:var(--fs-s);}.backupcounts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-2) var(--sp-4);font-size:var(--fs-s);}.backupwarn,.backuperror{border-radius:var(--rad-s);padding:var(--sp-3);font-size:var(--fs-s);line-height:1.45;overflow-wrap:anywhere;}.backupwarn{background:color-mix(in srgb,var(--hp-accent) 12%,transparent);}.backuperror{background:rgba(179,64,42,.16);color:#ff7a5c;}.backupdetails{border:1px solid var(--hp-line);border-radius:var(--rad-s);padding:var(--sp-2) var(--sp-3);font-size:var(--fs-s);}.backupdetails summary{cursor:pointer;font-weight:700;}.backupdetails>div{display:grid;gap:var(--sp-1);padding-block-start:var(--sp-2);}.backupdetails code{overflow-wrap:anywhere;color:var(--hp-muted);}.backupchoices{display:flex;flex-direction:column;gap:var(--sp-2);border:1px solid var(--hp-line);border-radius:var(--rad-s);min-width:0;}.backupchoices label{margin:0 !important;display:flex;gap:var(--sp-2);}.backupconfirm{align-items:flex-start !important;}.backupconfirm>span:first-of-type{min-width:0;white-space:normal;overflow-wrap:anywhere;}@media (max-width:520px){.backupactions,.backupcounts{grid-template-columns:1fr;}}.aboutver{font-size:var(--fs-s);color:var(--hp-muted);margin:var(--sp-2) 0 var(--sp-3);}.aboutlink{display:flex;align-items:center;gap:var(--sp-3);width:fit-content;color:var(--hp-accent);text-decoration:none;font-size:var(--fs-m);padding:var(--sp-1) 0;}:host([data-pointer-hover]) .aboutlink:hover{text-decoration:underline;}.aboutlink ha-icon{--mdc-icon-size:18px;line-height:1;}hp-dialog .supportbody{min-width:0;overflow-x:hidden;gap:var(--sp-5);}.supportsection{display:grid;min-width:0;gap:var(--sp-2);}.supportsection + .supportsection{padding-top:var(--sp-4);border-top:1px solid var(--hp-line);}.supportsection h3{margin:0;color:var(--hp-txt);font-size:var(--fs-m);}.supportlinks,.supportactions{display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-2) var(--sp-4);min-width:0;}.supportform>label:not(.srcrow){margin-top:var(--sp-2);color:var(--hp-muted);font-size:var(--fs-s);}.supportmessage,.supportraw{width:100%;min-width:0;box-sizing:border-box;resize:vertical;border:1px solid var(--hp-line);border-radius:var(--rad-s);padding:var(--sp-3);color:var(--hp-txt);background:color-mix(in srgb,var(--card-background-color,var(--hp-bg)) 92%,var(--hp-txt));font:inherit;}.supportmessage{min-height:120px;background:var(--hp-bg);}.supportraw{min-height:220px;margin-top:var(--sp-2);resize:none;white-space:pre;overflow:auto;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;}.supportattach{min-width:0;align-items:flex-start;margin:var(--sp-2) 0 0 !important;}.supportattach>span:first-of-type{min-width:0;white-space:normal;overflow-wrap:anywhere;}.supportwarning,.supportstatus,.supportupdate{display:flex;align-items:flex-start;gap:var(--sp-2);min-width:0;margin:0;padding:var(--sp-3);border-radius:var(--rad-s);background:color-mix(in srgb,var(--hp-accent) 14%,transparent);overflow-wrap:anywhere;font-size:var(--fs-s);line-height:1.45;}.supportwarning ha-icon,.supportstatus ha-icon,.supportupdate ha-icon{flex:none;color:var(--hp-accent);--mdc-icon-size:20px;}.supportpreview,.supportmanual,.supporterror,.supportsuccess{display:grid;min-width:0;gap:var(--sp-2);padding:var(--sp-3);border:1px solid var(--hp-line);border-radius:var(--rad-s);}.supportsummary{font-weight:600;overflow-wrap:anywhere;}.supporthash{display:grid;min-width:0;gap:var(--sp-1);color:var(--hp-muted);font-size:var(--fs-s);}.supporthash code{overflow-wrap:anywhere;color:var(--hp-txt);}.supportpreview details{min-width:0;}.supportpreview summary{cursor:pointer;color:var(--hp-accent);}.supportprivacy{margin:0 !important;line-height:1.45;}.supporterror{background:color-mix(in srgb,var(--error-color,#db4437) 12%,transparent);border-color:color-mix(in srgb,var(--error-color,#db4437) 45%,var(--hp-line));}.supportsuccess{background:color-mix(in srgb,var(--success-color,#43a047) 12%,transparent);border-color:color-mix(in srgb,var(--success-color,#43a047) 45%,var(--hp-line));}.supportfooter{flex-wrap:wrap;}@media (max-width:520px){hp-dialog .supportbody{padding-inline:var(--sp-4);}hp-dialog .supportfooter{padding-inline:var(--sp-4);}.supportactions .btn,.supportactions .aboutlink{max-width:100%;}}hp-dialog .body{padding:var(--sp-5) var(--sp-6);display:flex;flex-direction:column;gap:var(--sp-3);}hp-dialog .tapconfirm-body{min-width:0;overflow-x:hidden;}hp-dialog .tapconfirm-body p{max-width:100%;min-width:0;margin:0;overflow-wrap:anywhere;white-space:normal;}hp-dialog .tapconfirm-line{color:var(--hp-muted);}hp-dialog .body label{font-size:var(--fs-s);color:var(--hp-muted);margin-top:var(--sp-3);}hp-dialog .body .namein,hp-dialog .body .areasel{width:100%;box-sizing:border-box;}hp-dialog .row{display:flex;justify-content:flex-end;gap:var(--sp-4);width:100%;min-width:0;box-sizing:border-box;padding:var(--sp-5) var(--sp-6);border-top:1px solid var(--hp-line);}hp-dialog>.row[slot='footer'] button{min-height:44px;}hp-dialog .row.dialog-action-footer{align-items:center;justify-content:flex-start;flex-wrap:wrap;row-gap:var(--sp-4);}hp-dialog .dialog-action-group{display:flex;flex:0 1 auto;flex-wrap:wrap;align-items:center;gap:var(--sp-4);max-width:100%;min-width:0;}hp-dialog .dialog-action-group .btn{flex:0 0 auto;min-height:44px;}hp-dialog .dialog-action-danger{margin-right:auto;}hp-dialog .dialog-action-commit{margin-left:auto;justify-content:flex-end;}hp-dialog .row.infofooter{align-items:center;justify-content:flex-start;flex-wrap:wrap;gap:var(--sp-3);}hp-dialog .row.infofooter .btn{flex-shrink:0;}hp-dialog .row.infofooter .infofooter-close{margin-left:auto;}@media (max-width:480px){hp-dialog .row.infofooter{padding:var(--sp-4) var(--sp-5);}}.device-inbox{display:flex;flex-direction:column;gap:var(--sp-4);padding:var(--sp-5) var(--sp-6);min-width:0;}.device-inbox-dialog{--hp-dialog-wide-width:920px;}.device-inbox-head{display:grid;grid-template-columns:minmax(180px,1fr) auto;align-items:center;gap:var(--sp-4);}.device-inbox-search{width:100%;min-width:0;box-sizing:border-box;border:1px solid var(--hp-line);border-radius:var(--rad-m);background:transparent;color:var(--hp-txt);font:inherit;padding:11px 14px;}.device-inbox-tabs{display:flex;gap:var(--sp-2);overflow-x:auto;scrollbar-width:thin;padding-bottom:var(--sp-1);}.device-inbox-tabs button{flex:0 0 auto;border:1px solid var(--hp-line);border-radius:999px;background:transparent;color:var(--hp-txt);font:inherit;padding:8px 12px;cursor:pointer;}.device-inbox-tabs button.on{border-color:var(--hp-accent);background:color-mix(in srgb,var(--hp-accent) 18%,transparent);}.device-inbox-tabs button span{color:var(--hp-muted);margin-inline-start:4px;}.device-inbox-discovery{margin:8px 0;padding:8px 10px;border:1px solid var(--divider-color,#e0e0e0);border-radius:8px;}.device-inbox-discovery summary{cursor:pointer;font-weight:600;}.device-inbox-discovery .srcrow{display:flex;gap:6px;align-items:center;margin:8px 0;}.device-inbox-excluded{display:flex;flex-wrap:wrap;gap:6px;align-items:center;}.device-inbox-excluded>span{font-weight:500;}.device-inbox-chips{display:flex;flex-wrap:wrap;gap:4px;}.device-inbox-chips .chip{display:inline-flex;align-items:center;gap:2px;padding:1px 6px;border-radius:10px;background:var(--secondary-background-color,#f0f0f0);font-size:12px;}.device-inbox-chips .chip button{border:none;background:none;cursor:pointer;padding:0 2px;color:var(--secondary-text-color,#666);}.device-inbox-excluded input[type="text"]{flex:1 1 140px;min-width:120px;padding:4px 6px;border:1px solid var(--divider-color,#e0e0e0);border-radius:6px;background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);}.device-inbox-preview{margin:8px 0 4px;font-size:13px;opacity:0.85;}.device-inbox-filters{display:flex;flex-wrap:wrap;gap:var(--sp-4) var(--sp-6);color:var(--hp-muted);}.device-inbox-filters label{display:inline-flex;align-items:center;gap:var(--sp-2);cursor:pointer;}.device-inbox-filter-help{display:inline-flex;align-items:center;gap:var(--sp-1);min-width:0;}.device-inbox-results{display:grid;gap:var(--sp-3);min-width:0;}.device-inbox-row{display:grid;grid-template-columns:42px minmax(180px,1fr) minmax(180px,auto);align-items:center;gap:var(--sp-4);min-width:0;border:1px solid var(--hp-line);border-radius:var(--rad-m);padding:var(--sp-4);background:color-mix(in srgb,var(--hp-txt) 3%,transparent);}.device-inbox-icon{--mdc-icon-size:28px;color:var(--hp-txt);justify-self:center;}.device-inbox-copy{min-width:0;}.device-inbox-name{display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-2);}.device-inbox-new{border-radius:999px;background:var(--hp-accent);color:var(--text-primary-color,#fff);font-size:var(--fs-s);padding:2px 7px;}.device-inbox-meta,.device-inbox-reason,.device-inbox-copy code{display:block;color:var(--hp-muted);font-size:var(--fs-s);overflow-wrap:anywhere;white-space:normal;}.device-inbox-status{color:var(--error-color,#db4437);margin-inline-start:var(--sp-2);}.device-inbox-actions{display:flex;justify-content:flex-end;align-items:center;flex-wrap:wrap;gap:var(--sp-2);}.device-inbox-actions .btn{min-height:36px;padding:7px 10px;}.device-inbox-menu{position:relative;}.device-inbox-menu summary{list-style:none;cursor:pointer;}.device-inbox-menu summary::-webkit-details-marker{display:none;}.device-inbox-menu-items{position:absolute;z-index:2;inset-inline-end:0;top:calc(100% + var(--sp-1));display:grid;gap:var(--sp-1);min-width:180px;padding:var(--sp-2);border:1px solid var(--hp-line);border-radius:var(--rad-m);background:var(--hp-panel,var(--card-background-color,#fff));box-shadow:0 8px 24px rgba(0,0,0,.22);}.device-inbox-menu-items .btn{justify-content:flex-start;width:100%;}.device-inbox-empty{color:var(--hp-muted);text-align:center;padding:var(--sp-8);}.device-inbox-more{align-self:center;}@media (max-width:680px){.device-inbox{padding:var(--sp-4);}.device-inbox-head{grid-template-columns:minmax(0,1fr);}.device-inbox-head .btn{justify-self:stretch;}.device-inbox-tabs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));overflow-x:visible;}.device-inbox-tabs button{min-width:0;overflow-wrap:anywhere;}.device-inbox-row{grid-template-columns:36px minmax(0,1fr);}.device-inbox-actions{grid-column:1 / -1;justify-content:flex-start;}}`];var lp={"editor.context_actions":"Actions: {object}","editor.tool_options":"Tool options: {tool}","editor.palette":"Palette: {tool}","editor.open_group":"Tool group: {group}","editor.group_active":"{group} — active: {item}","editor.disabled_action":"{action} is unavailable: {reason}","editor.loading":"Loading…","editor.loading_aria":"The plan editor is loading","editor.load_failed":"Could not load the editor.","editor.refresh_advice":"Refresh the page and try again.","editor.retry_advice":"Check your connection and press again.","version_mismatch.title":"House Plan versions do not match","version_mismatch.body":"If Home Assistant is still restarting, let it finish, then reload this page.","version_mismatch.frontend":"Card","version_mismatch.backend":"Integration","version_mismatch.reload":"Reload page","color_picker.title":"Color picker","color_picker.hue":"Hue","color_picker.saturation":"Saturation","color_picker.value":"Brightness","color_picker.hex":"Hex color","color_picker.invalid_hex":"Enter a 3- or 6-digit hex color","color_picker.confirm":"OK","btn.properties":"Properties","btn.keep_as_walls":"Keep as walls","btn.delete_room_keep_walls":"Delete room, keep walls","btn.delete_room_with_walls":"Delete room and walls","title.markup_select":"Select and edit walls and columns","title.markup_column":"Column: click a grid point to place a square column","markup.partition":"Partition","markup.column":"Column","markup.hint_column":"click a grid point to place a square column","history.wall_segment":"Add wall segment","history.column_add":"Add column","history.physical_edit":"Change physical object","history.physical_delete":"Delete physical object","history.physical_move":"Move physical object","history.wall_face_batch":"Create rooms from walls","toast.column_duplicate":"A column with the same centre and outer size already exists","physical.partition_properties":"Partition properties","physical.column_properties":"Column properties","physical.shape":"Shape","physical.square":"Square","physical.circle":"Circle","physical.diameter":"Diameter","physical.side":"Side","physical.rotation":"Rotation angle","physical.length":"Length","physical.allowed_range":"Allowed: {min}–{max} {unit}","physical.column_size_title":"Outer side of the square column placed by the click (1–150 cm).","card.title":"House plan","count.devices":"{n} dev.","empty.no_spaces":"No spaces yet.","nav.spaces":"House Plan spaces","empty.add_first":"Add the first space and upload a floor plan.","empty.read_only":"No spaces are configured. Ask an administrator to add one.","empty.install":'Install the House Plan integration and add it in "Devices & services".',"btn.add_space":"Add space","btn.cancel":"Cancel","btn.save":"Save","btn.close":"Close","btn.delete":"Delete","btn.copy":"Copy","btn.edit":"Edit","btn.open_in_ha":"Open in HA","btn.reset":"Reset","btn.attach":"Attach…","btn.upload":"Upload…","btn.replace":"Replace…","title.zoom_in":"Zoom in","title.zoom_out":"Zoom out","title.zoom_fit":"Fit all","title.configure_space":"Configure space","title.add_space":"Add space","title.markup_add":"Walls: draw a continuous chain; each accepted segment is saved independently. Shift locks to 45°","title.markup_merge":"Merge: click one room, then the neighbour it shares a wall with","title.markup_split":"Split a room: click the room, then two points on its walls","title.markup_delroom":"Delete room: click inside a room and confirm","markup.add":"Walls","markup.merge":"Merge","markup.split":"Split","markup.resize":"Resize","title.markup_resize":"Resize rooms: drag an available horizontal or vertical wall handle","markup.hint_resize":"drag an available wall handle · the wall stops at the first unsafe position · Esc cancels · Ctrl+Z — undo","resize.disabled.diagonal":"This wall is angled; Resize supports only horizontal and vertical walls","resize.disabled.side-angle":"An adjoining wall is angled; Resize requires both adjoining walls to meet this wall at right angles","resize.disabled.duplicate-physical-wall":"A separate partition or column overlaps this wall; remove or move it before resizing","resize.disabled.partial-shared":"A neighbouring room uses only part of this wall, so it cannot be moved safely as one shared wall","resize.disabled.unequal-shared":"The neighbouring room uses different endpoints or wall length, so the walls cannot move together safely","resize.disabled.multiple-rooms":"Moving this wall would affect more than two rooms","resize.disabled.thickness-conflict":"The wall thickness cannot be preserved safely","resize.disabled.opening-conflict":"An opening on this wall cannot be moved safely","resize.disabled.invalid-geometry":"This wall cannot be resized without changing the plan structure","resize.limit_stopped":"Wall stopped: the next step would break a junction limit","resize.commit_failed":"Resize was cancelled because the final plan did not pass the geometry check","resize.preview_failed":"Resize stopped at the last safe position because the plan geometry could not be preserved","markup.opening":"Opening","markup.delete_room":"Delete room","history.undo":"Undo","history.redo":"Redo","history.undo_named":"Undo: {name} (Ctrl+Z)","history.redo_named":"Redo: {name} (Ctrl+Shift+Z / Ctrl+Y)","history.undo_empty":"Nothing to undo","history.redo_empty":"Nothing to redo","history.undone":"Undone: {name}","history.redone":"Redone: {name}","history.add_room":"Create room","history.split_room":"Split room","history.merge_rooms":"Merge rooms","history.resize_room":"Resize room","history.wall_thickness":"Change wall thickness","history.add_opening":"Add door or window opening","history.edit_opening":"Edit opening","history.move_opening":"Move opening","history.delete_opening":"Delete opening","history.delete_room_keep_walls":"Delete room, keep walls","history.delete_room_with_walls":"Delete room and walls","history.decor_add":"Add decor object","history.decor_edit":"Edit decor object","history.decor_move":"Move decor object","history.decor_transform":"Transform decor object","history.decor_delete":"Delete decor object","history.backdrop_transform":"Transform plan backdrop","history.device_move":"Move {name}","history.device_stale":"Device position history is no longer applicable and was cleared","opening.new":"New opening","opening.edit":"Opening","opening.door":"Door","opening.window":"Window","opening.gate":"Gate","opening.passage":"Open passage","opening.passage_binding_warning":"Saving will remove the open/close sensor and lock.","opening.invalid_passage_fields":"The open passage on plan “{room}” has unsupported settings: {fields}.","opening.type_label":"Type","opening.length_label":"Length, cm","opening.contact_label":"Open/close sensor","opening.lock_label":"Lock","opening.none":"— none —","opening.search_ph":"Search: name or entity id…","opening.invert":"Invert open/closed","opening.flip_h":"Hinge on the other jamb","opening.flip_v":"Opens to the other side","opening.open":"Open","opening.closed":"Closed","opening.locked":"Locked","opening.unlocked":"Unlocked","opening.state_unknown":"unavailable","opening.no_entities":"No sensors bound — a static symbol on the plan.","toast.opening_no_wall":"Click next to a room wall or independent wall","opening.host_partition":"Independent wall","opening.partition_orphan":"The independent wall for this opening no longer exists","opening.partition_jamb_margin":"Leave at least {distance} between the opening and the end of the wall","opening.rebind_partition":"Attach to another independent wall","confirm.delete_partition_openings_title":"Delete wall and openings?","confirm.delete_partition_openings_body":"This wall contains {count} opening(s). They will be deleted together.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.hint_points":"points: {n} · Shift — 45° steps · Esc — finish chain · Ctrl+Z — undo a point · closing an area offers a room","markup.hint_start":"click a grid dot to start a wall chain","tip.lqi":"average zigbee signal:","tip.area":"area: {value}","info.device_header":"Device on the plan","info.model":"Model","info.state":"State","info.link":"Link","info.manuals":"Manuals","info.none":"No additional information","marker.new_device":"New device","marker.name_label":"Name","marker.name_ph":"Name","marker.binding_label":"Bind to an HA device","marker.binding_disabled":"disabled in Home Assistant","marker.virtual_option":"Virtual device (no binding)","marker.search_ph":"Search device / group…","marker.nothing_found":"nothing found","marker.room_label":"Room","marker.room_choose":"— select a room —","marker.room_auto":"— by device area (auto) —","marker.icon_label":"Icon","marker.icon_ph":"mdi:… (empty = auto)","marker.display_label":"Display","display.badge":"Icon + state","display.icon_ripple":"Icon + state and activity","display.static_icon":"Always static icon","display.value_static_icon":"Value + static icon","marker.display_hint_badge":"The icon and dynamic plate show device state without the ordinary activity pulse. Red alarms remain visible.","marker.display_hint_icon_ripple":"The icon, dynamic plate and pulse show a short pulse for events and a continuous pulse for work, motion or presence. Red alarms have separate priority.","marker.display_hint_value":"A selected or automatically resolved Home Assistant value replaces the icon while the plate continues to show state. Red alarms remain visible.","marker.display_hint_static_icon":"The theme-aware shell and icon always stay the same. State, activity, unavailability and alarms do not change the face.","marker.display_hint_value_static_icon":"The marker shows the selected value while the shell stays theme-aware. State, activity, unavailability and alarms do not change the marker colour.","marker.static_alarm_warning":"This device can report alarms. Static display hides the marker's visual alarm indication.","marker.preview.title":"Display preview","marker.preview.actual":"Now","marker.preview.example":"Example","marker.preview.integration":"Provided by","marker.preview.source":"Display source","marker.preview.current_state":"Current state","marker.preview.result":"On the plan","marker.preview.details":"Source details","marker.preview.select_source":"Choose a Home Assistant device or entity to see its actual display.","marker.preview.unknown_provider":"Unknown integration","marker.preview.virtual_provider":"House Plan · virtual device","marker.preview.no_source":"No active source","marker.preview.no_state":"No current state","marker.preview.mixed_states":"Several different states","marker.preview.multiple_sources":"{n} sources","marker.preview.more_sources":"+{n} more","marker.preview.scaled":"The preview is scaled to {n}% to fit. The saved size is unchanged.","marker.preview.demo_short":"Show short activity","marker.preview.demo_continuous":"Show continuous activity","marker.preview.stop_continuous":"Stop continuous activity","marker.preview.demo_short_notice":"Short activity example; the actual device state is unchanged.","marker.preview.demo_continuous_notice":"Continuous activity example; the actual device state is unchanged.","marker.preview.demo_already_visible":"The current state already shows a real activity or alarm effect.","marker.preview.reduced_motion":"System reduced-motion is enabled, so ordinary activity is shown as a dot.","marker.preview.reason.neutral":"Neutral dark plate","marker.preview.reason.working":"Yellow plate: the device is working now","marker.preview.reason.working_activity":"Yellow plate and activity effect: the device is working now","marker.preview.reason.open":"Orange plate: physically open or unlocked","marker.preview.reason.cover_icon_state":"Neutral plate; the cover entity controls the displayed state and icon","marker.preview.reason.presence":"Activity effect while presence is detected","marker.preview.reason.event":"Short activity effect after a detected event","marker.preview.reason.transition":"Activity effect while the device is moving or changing state","marker.preview.reason.media_neutral":"Media devices stay on a neutral dark plate while available","marker.preview.reason.unavailable":"Subdued neutral plate: unavailable or off","marker.preview.reason.alarm":"Red alarm plate; alarm indication is always shown","marker.preview.reason.live_states_disabled":"Live-state styling is disabled for this card","marker.preview.reason.value_no_state":"No usable state value; the icon is shown instead","marker.preview.reason.value_ambiguous_sources":"Several possible value sources; the icon is shown instead","marker.preview.reason.value_non_scalar":"The source did not return a simple value; the icon is shown instead","marker.preview.reason.value_virtual":"A virtual device has no Home Assistant value; the icon is shown instead","marker.preview.reason.vacuum_live_plan_only":"Live vacuum position and trail are available only on the full plan","marker.preview.reason.hidden_design_preview":"The device is hidden on the plan; this design preview remains visible","marker.preview.reason.composite_power_source":"State comes from the device Power entity; auxiliary switches are ignored","marker.preview.reason.activity_display_disabled":"The selected display mode does not show ordinary activity effects","marker.preview.reason.ha_disabled":"The Home Assistant binding is disabled and will be hidden on the plan","marker.preview.reason.orphaned":"The saved Home Assistant binding can no longer be found","marker.preview.reason.static_icon":"Static mode: device state does not change the icon","marker.preview.reason.value_static_icon":"Static mode with a value: device state does not change the marker colour","marker.activity_color":"Activity pulse color","marker.ripple_size":"Activity pulse size","marker.activity_alarm_note":"Color and size affect ordinary activity only and do not change red alarms.","marker.pulse_a11y_alarm":"Alarm","marker.pulse_a11y_event":"Recent event","marker.pulse_a11y_presence":"Presence detected","marker.pulse_a11y_transition":"Changing state","marker.pulse_a11y_running":"Working","marker.state_a11y_neutral":"Default state","marker.state_a11y_working":"Working","marker.state_a11y_open":"Open","marker.state_a11y_locked":"Locked","marker.state_a11y_unlocked":"Unlocked","marker.state_a11y_alarm":"Alarm","marker.state_a11y_unavailable":"Unavailable","marker.lqi_a11y_low":"LQI {value}, low signal","marker.lqi_a11y_mid":"LQI {value}, medium signal","marker.lqi_a11y_high":"LQI {value}, high signal","marker.size_label":"Icon size and rotation","marker.angle_label":"Rotate","marker.model_label":"Model","marker.model_ph":"e.g. Aqara T&H","marker.link_label":"Link","marker.desc_label":"Description","marker.desc_ph":"Notes, specs…","marker.manuals_label":"Manuals (PDF etc.)","marker.sub_device":"device","marker.sub_z2m_group":" · Z2M group","marker.sub_group":"group","marker.sub_helper":"helper","space.new":"New space","space.copy_title":"Copy space","space.copy_name":"New space name","space.copy_fallback":"Space","space.copy_create":"Create copy","space.copy_optimize_title":"Optimize before copying?","space.copy_optimize_body":"Before creating “{name}”, House Plan must optimize the entire plan, including other spaces. Continue?","space.copy_optimize_confirm":"Optimize and copy","space.copy_error_changed":"The plan changed while confirmation was open. Review it and try again.","space.copy_error_source_missing":"The source space no longer exists. Reopen its settings and try again.","space.copy_error_source_invalid":"House Plan could not validate every wall in this space. Fix the source space and try again.","space.copy_error_spaces_limit":"House Plan already has the maximum number of spaces.","space.copy_error_partitions_limit":"This space has too many walls to copy.","space.copy_error_openings_limit":"This space has too many openings to copy.","space.copy_error_decor_limit":"This space has too many background objects to copy.","space.copy_error_columns_limit":"This space has too many columns to copy.","space.copy_error_opening_host":"One of the openings is no longer attached to a wall. Fix or delete it before copying.","space.copy_error_geometry":"The copy would create unsafe wall geometry. Fix the source space and try again.","space.copy_error_optimize_geometry":"Copy stopped because optimizing the entire plan is unsafe for one of the spaces.","space.header":"Space","space.title_label":"Space name","space.title_ph":"e.g. Garage","space.plan_label":"Floor plan","space.no_plan":"no plan image","space.plan_alt":"plan","room.new":"New room","room.name_label":"Display name","room.name_ph":"e.g. Terrace","room.area_label":"Home Assistant area","room.no_area_option":"— no area —","room.default_name":"Room","device.unnamed":"unnamed","device.light_group":"light group","device.fallback":"device","device.virtual":"virtual device","confirm.delete_room_title":'Delete room "{name}"?',"confirm.delete_room_body":"Choose whether the room's exclusive physical walls should remain. Walls shared with another room are always kept.","confirm.remove_marker_title":"Delete device from the plan?","confirm.remove_marker_body":"The device will disappear completely and stop contributing to plan data. You can add it again later.","confirm.erase_decor":"Erase the {kind} object? You can undo this action from the editor history.","confirm.delete_space_title":"Delete space?","confirm.delete_space_body":"The space, all its rooms and all its plan markup will be deleted.","confirm.delete_space_vac_routes":"Robot map assignments will also be removed: {count}.","space.delete_blocked":"This space is still used by {n} device(s). Move them to another space or delete them first.","toast.pos_save_failed":"Failed to save position: {err}","toast.no_entity":"The device has no suitable entity","toast.ha_disabled_action":"A Home Assistant object that is disabled cannot be used on the plan.","toast.ha_disabled_show_device":"A device disabled in Home Assistant cannot be shown on the plan. Enable it in Home Assistant first.","toast.ha_disabled_show_entity":"An entity disabled in Home Assistant cannot be shown on the plan. Enable it in Home Assistant first.","toast.ha_disabled_add":"A disabled Home Assistant object cannot be added to the plan. Enable it in Home Assistant first.","toast.ha_binding_unverified":"The object status could not be verified through the Home Assistant registry. Display and actions are temporarily unavailable.","toast.markup_needs_server":"Markup is available after the config is moved to the server","toast.space_order_changed":"Order changed. If any card pins its floor by number, check those panels.","toast.conflict":"Config was changed in another window — data refreshed, repeat your last action","toast.cfg_save_failed":"Failed to save config: {err}","toast.room_overlap":"The outline overlaps room “{name}” — rooms must not overlap","toast.contour_cannot_close":"The outline cannot close because it is degenerate or intersects itself","toast.merge_not_adjacent":"Only rooms that share a wall can be merged","toast.rooms_merged":"Rooms merged into “{name}”","toast.split_pick_wall":"Start the cut on the room’s wall","toast.split_bad_cut":"The cut must run wall to wall inside the room, without crossing walls or itself","merge.header":"Merge rooms","merge.hint":"The merged room keeps one name and one area. The other area is released — its devices leave the plan until another room claims it.","merge.keep":"Keep","merge.no_area":"no area","toast.room_saved":"Room saved ({n}). Devices added: {added}. Outline the next one or exit markup.","toast.room_saved_no_area":"Room saved ({n}, no area). Outline the next one or exit markup.","toast.marker_needs_server":"Device editing is available after the config is moved to the server","toast.virtual_name_required":"Enter a name for the virtual device","toast.marker_saved":"Device saved","toast.marker_removed":"Device deleted from the plan","toast.integration_missing":"The House Plan integration is not installed — management unavailable","toast.plan_formats":"Supported formats: SVG, PNG, JPG, WebP","toast.plan_required":"Upload a floor plan — it is required","toast.space_added_onboard":"Space added. Outline the rooms: click grid dots and close the contour.","toast.space_added":"Space added","toast.space_copied":"Space “{name}” created","toast.space_saved":"Space saved","toast.space_deleted":"Space deleted","toast.delete_failed":"Delete failed: {err}","toast.error":"Error: {err}","toast.toggle_target_unavailable":"Target “{name}” is unavailable — no action was performed","toast.toggle_targets_unavailable":"Targets are unavailable: {names}. No action was performed","toast.file_failed":'File "{name}" was not uploaded: {err}',"toast.files_attached":"Files attached: {n}","err.unknown":"unknown error","err.code":"code {code}","err.too_large":"file larger than {mb} MB","err.bad_ext":"unsupported type (PDF/image expected)","err.unauthorized":"administrator rights required","editor.title":"Title","editor.default_floor":"Initial space","editor.default_floor_missing":"Initial space “{id}” no longer exists. Choose another space.","editor.floor":"Fixed space","editor.floor_none":"— not fixed —","editor.floor_index":"YAML index {index} (preserved)","fixed_floor.loading":"Loading the fixed space…","fixed_floor.invalid_title":"The fixed space is unavailable","fixed_floor.invalid_body":"Check floor in the card configuration. The configured value is: {value}","editor.icon_size":"Icon size, % of plan width","editor.show_temperature":"Show temperature","editor.live_states":"Live states (on/off, open…)","editor.light_pools":"Light pools and wall shadows","editor.show_signal":"Show zigbee signal (LQI)","editor.language":"Interface language","editor.lang_auto":"Auto (HA profile)","title.icon_rules":"Icon rules: which MDI icon devices get by name","rules.title":"Icon rules","rules.hint":"Rules are checked top-down against “device name + model” (case-insensitive regex); the first match wins. When nothing matches, the entity device class decides, then the generic chip icon.","rules.pattern_ph":"regex, e.g. plug|socket","rules.icon_ph":"mdi:power-socket-de","rules.add":"Add rule","rules.reset":"Reset to defaults","rules.test_ph":"Try a device name…","rules.invalid":"invalid regex","rules.saved":"Icon rules saved","btn.up":"Up","btn.down":"Down","tap.info":"Device card","tap.more_info":"HA more-info dialog","tap.toggle":"Toggle state","marker.tap_label":"Tap action for this device","tap.toggle_note":"The resolved state is shown below. Secure devices are never toggled from the plan.","import.title":"Create spaces from HA floors","import.hint":"Your Home Assistant already knows these floors. Pick the ones to turn into plan spaces — you will upload a floor-plan image for each one next. Rooms are then outlined by hand on the plan.","import.start":"Create {n} space(s)","import.manual":"Start from scratch","import.progress":"Floor {i} of {n}","import.done":"Spaces created. Outline the rooms: click grid dots and close the contour.","btn.skip":"Skip","space.scale_label":"Scale (grid cell size)","space.cell_cm.help":"Links the grid to real dimensions: lengths, areas, wall thickness, opening sizes and glow radius depend on it. Changing it after drawing changes the calculated dimensions of the whole space without moving its points on the plan.","space.cell_cm.help.aria":"Help: space scale","space.scale_unit":"cm per cell","space.scale_unit_imperial":"in per cell","space.display_section":"Appearance","space.show_borders":"Always show room borders","space.zero_wall_style":"Zero-thickness walls","space.zero_wall_style.help":"Dashed zero-thickness walls pass Glow and sun rays, while solid ones block them as zero-area barriers. The choice affects every such wall in the space even when its line is hidden in View.","space.zero_wall_style.help.aria":"Help: zero-thickness wall style","space.zero_wall_dashed":"Dashed","space.zero_wall_solid":"Solid","space.show_names":"Show room names","space.room_color":"Border & name color","space.opacity":"Opacity","space.fill_label":"Room fill","space.fill_mode.help":"“Custom colour” is styling, while “Light”, “Temperature” and “LQI” use current Home Assistant data; Glow is enabled separately.","space.fill_mode.help.aria":"Help: room fill mode","fill.none":"None","fill.lqi":"Zigbee signal","fill.light":"Lights","fill.custom":"Custom color","space.custom_fill":"Fill color","space.source_file":"Use a floor-plan image","space.source_draw":"Draw it myself","fill.temp":"Temperature","tip.temp_avg":"average temperature:","tip.hum_avg":"average humidity:","space_card.button":"Open the space plan","space_card.not_found":"Space “{id}” not found","space_card.loading":"Loading…","continuity.restore_plan":"Restoring floor plan…","continuity.restore_connection":"Restoring device connection…","continuity.retry":"Try again","editor.space":"Space","editor.framing":"Framing","editor.fit_content":"All visible content","editor.fit_house":"Tight to house geometry","editor.show_button":"Show button","editor.button_label":"Button label","editor.button_target":"Target dashboard path","marker.sub_entity":"entity","title.general_settings":"General settings","title.export_pdf":"Save as PDF","pdf.title":"Save as PDF","pdf.dimensions":"Show dimensions and areas","pdf.decor":"Show furniture and other decor","pdf.room_names":"Show room names","pdf.backdrop":"Show backdrop","pdf.save":"Save","pdf.saving":"Creating…","pdf.failed":"Could not create the PDF.","pdf.too_large":"The images exceed the 25 MB PDF limit.","pdf.asset_failed":"A backdrop or decor image could not be loaded.","pdf.scale":"Scale 1:{n}","pdf.north":"North","gs.title":"General settings","gs.light_group":"Lights","gs.light_on":"Lights on","gs.light_off":"All lights off","gs.temp_group":"Temperature","gs.temp_cold":"Cold","gs.temp_ok":"Comfortable","gs.temp_hot":"Hot","gs.lqi_group":"Zigbee signal","gs.lqi_low":"Weak signal","gs.lqi_high":"Strong signal","gs.reset":"Reset to defaults","gs.saved":"General settings saved","gs.radar_show_live":"Show live presence on the plan","radar.title":"Presence on the plan","radar.help":"Connect this marker to exact Home Assistant radar entities, place the sensor and choose its coordinate profile. Live positions are clipped to the selected room.","radar.help.aria":"Help: presence radar settings","radar.enabled":"Use this presence radar","radar.show_live":"Show live targets","radar.configure":"Configure radar","radar.configure_on_plan":"Configure on plan","radar.change_installation":"Change installation","radar.no_contour":"This room has no boundary. Radar points will not be clipped.","radar.discard_setup_title":"Discard radar setup?","radar.discard_setup":"The unsaved radar setup will be lost.","radar.step_place_mount":"Mark the physical sensor position","radar.step_place_heading":"Mark a point straight ahead of the sensor","radar.step_reference":"Mark reference position {n}, then start measurement","radar.step_check_reference":"Mark an independent check position","radar.start_measure":"Start measurement","radar.countdown":"Stand at the mark in {seconds} s","radar.capturing":"Stand still and alone while measuring…","radar.fit_ready":"Calibration is ready","radar.check_third":"Check at another position","radar.check_complete":"Independent check completed","radar.error_distance":"Position difference: {distance}","radar.ambiguous_target":"More than one target was reported. Repeat the measurement alone.","radar.insufficient_samples":"Not enough current coordinates. Retry or use manual setup.","radar.bad_references":"Choose separated references in different directions from the sensor.","radar.ambiguous_sources":"The measurements allow two equally plausible directions. Choose reference points that distinguish left from right.","radar.bad_fit":"Measurements do not match. Check units, mounting point and references.","radar.desktop_hint":"Use a computer for precise setup. Editing on touch devices is best effort.","radar.detected":"House Plan recognized radar metadata for this device. Review the exact sources before saving.","radar.detected_ld2450":"House Plan found an ESPHome LD2450 coordinate set. Review the exact X/Y sources before saving.","radar.additional_actions":"Additional actions","radar.declare":"This is a presence radar","radar.profile":"Data profile","radar.profile_esphome_ld2450_v1":"ESPHome LD2450 (X/Y targets)","radar.profile_cartesian_v1":"Cartesian targets (X/Y)","radar.profile_polar_v1":"Polar target (distance/angle)","radar.profile_range_v1":"Distance only","radar.profile_zones_v1":"Zone states","radar.profile_presence_v1":"Presence only","radar.room":"Radar room","radar.room_choose":"Choose a room","radar.target":"Target {n}","radar.axis_x":"X coordinate entity","radar.axis_y":"Y coordinate entity","radar.add_target":"Add target slot","radar.range_channel":"Range channel {n}","radar.add_range":"Add range channel","radar.presence_gate":"Presence gate entity","radar.swap_axes":"Swap X and Y axes","radar.axis_x_sign":"X direction","radar.axis_y_sign":"Y direction","radar.distance_source":"Distance entity","radar.angle_source":"Angle entity","radar.angle_unit":"Angle unit","radar.degrees":"Degrees","radar.radians":"Radians","radar.angle_zero":"Zero-angle direction","radar.angle_forward":"Forward","radar.angle_right":"Right","radar.angle_clockwise":"Angles increase clockwise","radar.zone_source":"Zone entity","radar.occupancy_source":"Presence entity","radar.count_source":"Target count entity","radar.availability_source":"Availability entity","radar.source_choose":"Choose an entity","radar.source_optional":"Optional","radar.source_missing":"currently unavailable","radar.saved_unsupported":"This saved radar setup is unsupported or incomplete. It remains inactive; remove it or update House Plan before configuring it again.","radar.occupancy":"Presence (on/off)","radar.count":"Count","radar.mount":"Position and direction","radar.mount_hint":"This is the physical sensor position. Moving its decorative marker does not change it.","radar.heading":"Direction, °","radar.range_cm":"Range, cm","radar.fov_deg":"Field of view, °","radar.unit":"Source unit","radar.mirror":"Mirror the left/right axis","radar.remove":"Remove radar settings","radar.invalid":"Complete the radar room, sources and position before saving.","radar.check_sources":"Check live data","radar.checking":"Checking…","radar.health":"Connection status","radar.live_summary":"Current targets: {targets}; range arcs: {ranges}","radar.health_ok":"Current data received","radar.health_off":"No targets detected","radar.health_stale":"Some coordinate data is out of date","radar.health_partial":"Some sources are current; others are out of date","radar.health_restricted":"Access to one or more sources is restricted","radar.health_incomplete":"The current radar report is incomplete","radar.health_position_unavailable":"Presence reported; current position unavailable","radar.health_unavailable":"Sensor data unavailable","radar.health_needs_setup":"Installation needs setup","radar.health_inconsistent":"The sources report conflicting values","radar.health_unknown":"Current state is unknown","radar.health_disabled":"Radar is disabled","radar.error_invalid_radar":"Check the radar settings.","radar.error_invalid_selection":"Select an existing room and valid sources.","radar.error_source_restricted":"You do not have access to all selected sources.","radar.error_rate_limited":"Too many requests. Try again shortly.","radar.error_not_ready":"Radar processing is not ready.","radar.error_conflict":"The plan changed. Reopen the radar setup and try again.","radar.error_source_unavailable":"One or more selected radar sources are unavailable.","radar.error_unsupported_capability":"This radar capability is not supported by the installed integration.","radar.report_age":"{seconds} s ago","space.show_lqi":"Zigbee signal next to devices","gs.light_none":"No light sources","mode.plan":"Plan editor","mode.devices":"Device editor","display.value":"Value + state","marker.subarea":"no area, manual","device.new":"New device — open its editor to dismiss","opening.unlock_action":"Unlock","opening.lock_action":"Lock","opening.lock_pending":"Working…","title.close_editor":"Close editor (back to view)","title.add_device":"Add a device to the plan","devbar.add":"Add","devbar.rules":"Icon rules","device_inbox.button":"Devices","device_inbox.title":"Devices on the plan","device_inbox.search":"Search devices, entities and integrations…","device_inbox.add_virtual":"Add virtual device","device_inbox.tab_on_plan":"On plan","device_inbox.tab_available":"Available","device_inbox.tab_hidden":"Hidden","device_inbox.tab_readd":"Available again","device_inbox.only_new":"New only","device_inbox.show_entities":"Show entities","device_inbox.show_hidden":"Show hidden on plan","device_inbox.show_hidden.help":"Temporarily shows hidden and disabled markers as editor-only ghosts on the plan. Saved device visibility does not change.","device_inbox.show_hidden.help.aria":"Help: show hidden devices on the plan","device_inbox.new":"New","device_inbox.find":"Find on plan","device_inbox.edit":"Edit","device_inbox.hide":"Hide","device_inbox.show":"Show","device_inbox.add":"Add","device_inbox.readd":"Add again","device_inbox.hide_available":"Hide from list","device_inbox.show_more":"Show more","device_inbox.more_actions":"More actions","device_inbox.find_hidden_hint":"Enable “Show hidden on plan” first","device_inbox.show_disabled":"Activate this binding in Home Assistant before showing it","device_inbox.empty_on_plan":"No matching devices are on the plan yet.","device_inbox.empty_available":"No devices are available to add.","device_inbox.empty_hidden":"There are no hidden devices.","device_inbox.empty_readd":"No removed devices are available to add again.","device_inbox.reason_visible_auto":"Discovered automatically","device_inbox.reason_visible_explicit":"Added explicitly","device_inbox.reason_manual_hidden":"Hidden by user","device_inbox.reason_automatic_hidden":"Hidden automatically","device_inbox.reason_service_entry":"Service-only registry entry","device_inbox.reason_excluded_integration":"Integration “{integration}” excluded by discovery filters","device_inbox.reason_excluded_domain":"Non-spatial entity type","device_inbox.reason_grouped_light":"Represented by a room light group","device_inbox.reason_represented_by_parent":"Represented by its parent device","device_inbox.reason_removed":"Previously removed from the plan","device_inbox.reason_available":"Available to add to the plan","device_inbox.reason_no_bound_room":"HA area is not linked to a plan room","device_inbox.status_ha_disabled":"Disabled in Home Assistant","device_inbox.status_orphaned":"Binding is no longer present in Home Assistant","device_inbox.status_unverified":"Home Assistant registry is temporarily unavailable","device_inbox.saved":"Device list updated","device_inbox.filters_excluded":"Excluded integrations","device_inbox.filters_group_lights":"Group room lights into one marker","device_inbox.filters_preview_appear":"will appear: {count}","device_inbox.filters_preview_hide":"will disappear: {count}","device_inbox.filters_preview_lights":"lights affected: {count}","device_inbox.filters_reset":"Restore recommended","device_inbox.filters_save":"Save filters","device_inbox.filters_search_ph":"Add an integration…","device_inbox.filters_title":"Discovery filters","space.roomcard_section":"Room cards","space.label_temp":"Temperature","space.label_hum":"Humidity","space.label_lqi":"Average Zigbee signal","space.label_light":"Lights on/off","roomcard.light_on":"On","roomcard.light_off":"Off","roomcard.light_partial":"{on} of {total}","toast.split_pick_inside":"Intermediate cut points must be inside the room","mode.decor":"Background editor","decor.select":"Select","decor.line":"Line","decor.rect":"Rectangle","decor.ellipse":"Oval","decor.text":"Text","decor.erase":"Erase","decor.erase_confirm_title":"Erase object?","decor.color":"Color","decor.width":"Line width","decor.line_style":"Line style","decor.line_style_solid":"Solid","decor.line_style_dashed":"Dashed","decor.fill":"Fill","decor.fill_color":"Fill color","decor.length":"Length","decor.size":"Size","decor.flip_h":"Flip horizontally","decor.flip_v":"Flip vertically","decor.angle":"Rotation angle, °","decor.text_size":"Text size","decor.backdrop_properties":"Plan backdrop properties","decor.text_title":"Text label","decor.object_title":"Edit {kind}","decor.text_label":"Text","decor.live_group":"Insert HA variable","decor.live_entity":"Entity","decor.live_entity_ph":"choose an entity","decor.live_attr":"Value","decor.live_attr_ph":"choose state or attribute","decor.live_state":"State","decor.backdrop":"Backdrop image","decor.backdrop_hint":"Drag to move; pull a corner to resize; use the top handle to rotate. Shift changes proportions or frees the angle.","decor.backdrop_reset":"Reset the picture","decor.backdrop_reset_done":"The picture is back at its original place and size","marker.icon_auto":"Auto: {icon} (by icon rules; pick one to override)","marker.icon_pin_auto":"Pin","mode.plan_tip":"Plan editor — the geometry of the home: draw and split/merge rooms, bind them to HA areas, place doors, windows and gates, move room cards, set the scale","mode.devices_tip":"Device editor — everything about icons: drag to position, click to edit binding/icon/display, add virtual devices, icon rules","mode.decor_tip":"Background editor — purely visual decor under the plan: lines, rectangles, ovals and text labels that never react to clicks","space.glow_enabled":"Light-source glow","gs.glow_group":"Light-source glow","gs.glow_base":"House darkness","gs.glow_light":"Default light color / intensity","gs.wall_fill":"Wall fill","gs.glow_radius":"Glow radius","gs.glow_radius.help":"Sets the default glow radius in metres or feet; a device-specific radius overrides it.","gs.glow_radius.help.aria":"Help: default glow radius","gs.unit_m":"m","gs.unit_ft":"ft","marker.controls_label":"Controls other light sources","marker.controls.help":"With the “Toggle state” action, the listed sources toggle together with this marker. Their glow stays at their own markers, and the link alone does not turn the controlling marker into a light source.","marker.controls.help.aria":"Help: controlling other light sources","marker.controls_filter":"Search lights and switches…","info.controls":"Controls","marker.glow_radius_label":"Glow radius","marker.glow_radius.help":"Sets the glow radius in metres or feet; an empty value uses the radius from general settings.","marker.glow_radius.help.aria":"Help: glow radius","markup.wallthick":"Thickness","markup.select":"Select","title.markup_wallthick":"Thickness — click a wall to set its thickness from 0 to 100 cm.","markup.hint_wallthick":"click a wall · Esc closes without applying","wallthick.field":"Thickness","wallthick.unit_cm":"cm","wallthick.unit_in":"in","wallthick.apply_room":"Apply to all walls of this room","markup.draw_wall_title":"Thickness of each new wall segment (0–100 cm). Shared walls keep the existing value.","room.queue_progress":"Room {current} of {total}","toast.wall_rooms_saved":"Created rooms: {n}","toast.wall_chain_saved":"Wall chain saved","toast.wallthick_pick":"Click a wall","toast.wallthick_set":"Wall thickness set","toast.wallthick_cleared":"Wall thickness removed","toast.physical_range":"Enter a value from {min} to {max} {unit}","toast.zero_wall_opening_conflict":"Remove the opening on this wall segment first.","toast.zero_wall_ambiguous":"The wall segment is ambiguous. Simplify or adjust the junction.","toast.zero_wall_migration_blocked":"The space was not converted: {reason}. No data was changed.","toast.physical_angle":"Enter a rotation angle from 0° up to, but not including, 90°","toast.physical_limit":"The space has reached the limit for this type of geometry","toast.geometry_unsafe":"Change canceled: wall geometry could not be built safely.","junction.limit_angle":"The angle between walls is too sharp: {actual}°, minimum {limit}°.","junction.limit_valence":"Too many walls meet in one node: {actual}, maximum {limit}.","junction.limit_length":"The wall segment is too short: {actual} cm, minimum {limit} cm.","junction.limit_distance":"Walls and nodes are too close: {actual} cm, minimum {limit} cm.","junction.limit_clearance":"No room interior is left: {actual} cm², minimum {limit} cm².","junction.limit_check_failed":"The junction check could not run — the change was not saved","toast.wall_model_migration_blocked":"The wall model could not be updated: {reason}. The plan was not changed. Run “Optimize plans”; if the error repeats, fix the conflicting wall geometry.","toast.wall_model_client_outdated":"Update the card and reload the page before editing the plan.","wall_model.reason.invalid-room":"invalid room contour","wall_model.reason.zero-length":"zero-length wall segment","wall_model.reason.third-owner":"wall shared by more than two rooms","wall_model.reason.duplicate-id":"conflicting wall identifiers","wall_model.reason.thickness-conflict":"conflicting wall thickness values","wall_model.reason.opening-host":"opening cannot be assigned to one wall","toast.delete_room_pick":"Click inside the room you want to delete","toast.plan_snap_ambiguous":"Zoom in to choose the wall node","toast.wall_repair_ambiguous":"The room outline has more than one possible connection. Zoom in and connect it explicitly.","toast.wall_repair_too_large":"The gap is larger than 2 cm. Connect the walls before creating the room.","toast.wall_repair_changed":"The wall geometry changed. Try creating the room again.","toast.opening_on_zero_wall":"Openings cannot sit on a zero-thickness wall","marker.from_ha_option":"Pick from the HA list","marker.show_entities":"Show entities","marker.show_entities_tip":"Adds not only devices to the list, but all their entities too","marker.pick_ph":"Choose a device…","room.open_area":"Open the HA area","room.fit_action":"Fit room {name}","view.volumetric":"Volumetric view","view.flat":"Flat view","kiosk.title":"This screen's sizes","kiosk.hint":"Stored on this device only — every wall tablet or TV can have its own comfortable sizes.","kiosk.icon_scale":"Device icon size","kiosk.font_scale":"Room card text size","editor.kiosk":"Wall device (kiosk) mode","editor.cycle":"Auto-switch spaces every N seconds (kiosk, 0 = off)","room.settings_title":"Room settings","room.fill_label":"Fill in THIS room","fill.inherit":"As the space","room.custom_fill_space":"Space color","room.custom_fill_own":"Room color","room.temp_range_label":"Comfort range","room.temp_range_min":"Lower comfort-temperature bound","room.temp_range_max":"Upper comfort-temperature bound","room.temp_range_reset":"As the space","room.temp_range.help":"This range applies only to this room. Empty fields inherit the corresponding space bounds; if the bounds are reversed, House Plan uses the smaller value as the lower bound and the larger value as the upper bound.","room.temp_range.help.aria":"About the room comfort range","room.temp_src_label":"Temperature source","room.hum_src_label":"Humidity source","room.src_average":"Average of the room’s sensors","room.src_pick":"Specific device or entity","room.src_ph":"Choose a source…","toast.room_updated":"Room updated","space.card_font":"Room-card font size","room.sizes_section":"Font sizes","room.group_basics":"Basics","room.group_basics.help":"The area links the room to a Home Assistant area, which is where its sensors come from. Without one the room stays geometry.","room.group_basics.help.aria":"Help: room name and area","room.group_fill":"Fill","room.group_fill.help":"This room’s fill overrides the space one; a custom colour is kept for this room only.","room.group_fill.help.aria":"Help: room fill","room.group_sources":"Sensor sources","room.group_sources.help":"By default the room averages its own sensors. A selected sensor replaces that average everywhere: tooltip, card, fill.","room.group_sources.help.aria":"Help: temperature and humidity sources","room.sizes_section.help":"These scales apply to this room only and multiply the shared card scale from the space settings.","room.sizes_section.help.aria":"Help: room font sizes","room.name_scale":"Room name size","room.label_scale":"Metrics size","preview.room_name":"Living room","toast.cfg_reload_failed":"Could not reload the plan from the server: {err}","toast.locale_load_failed":"Could not load the language pack. English is used until the page reloads.","toast.furniture_art_load_failed":"Could not load the furniture drawings. Reload the page to show them.","room.settings_short":"Room settings","room.unnamed":"Unnamed room","marker.use_climate_temp":"Include the device temperature in the room","marker.use_climate_temp_tip":"Adds an air conditioner or thermostat current_temperature to the room average. Configure the external value badge separately below.","marker.value_badge_title":"Value badge","marker.value_badge.help":"Shows one selected value next to the icon. It does not affect room metrics, light, Glow or the tap action.","marker.value_badge.help.aria":"Help: device value badge","marker.value_badge_enabled":"Show a value badge","marker.value_badge_source":"Value","marker.value_badge_source.help":"Choose a specific state, supported attribute, or derived value of this device.","marker.value_badge_source.help.aria":"Help: value badge source","marker.value_badge_position":"Position","marker.value_badge_position.help":"The chosen side stays fixed and does not flip automatically at a plan edge.","marker.value_badge_position.help.aria":"Help: value badge position","marker.value_badge_right":"Right","marker.value_badge_bottom":"Below","marker.value_badge_left":"Left","marker.value_badge_top":"Above","marker.value_badge_empty":"This device has no available values","marker.value_badge_static":"A static icon does not show live values. The setting is preserved.","marker.value_badge_missing":"Source unavailable","marker.value_badge_missing_hint":"The saved source is currently unavailable. Keep it, disable the badge, or choose another value.","marker.value_badge_duplicate":"The same value is already shown inside the icon.","marker.value_badge_state":"State · {name}","marker.value_badge_marker_state":"Light-source state · {name}","marker.value_badge_lqi":"Average Zigbee signal quality","marker.value_badge_attr_current_temperature":"Current temperature · {name}","marker.value_badge_attr_temperature":"Target temperature · {name}","marker.value_badge_attr_current_humidity":"Current humidity · {name}","marker.value_badge_attr_humidity":"Humidity · {name}","marker.value_badge_attr_current_position":"Position · {name}","marker.value_badge_attr_percentage":"Speed · {name}","marker.value_badge_attr_brightness":"Brightness · {name}","marker.value_badge_attr_volume_level":"Volume · {name}","marker.value_badge_attr_battery_level":"Battery · {name}","marker.value_badge_attr_fan_speed":"Fan speed · {name}","marker.value_source":"Value source","marker.value_source.help":"Choose the value that replaces the icon. The tap action does not change.","marker.value_source.help.aria":"Help: value face source","marker.value_source_auto":"Automatic (as before)","marker.value_source_missing_hint":"The saved source is currently unavailable. The face shows — until it recovers or you choose another value.","marker.light_role_label":"Is this device a light source?","marker.light_role.help":"“Auto” uses the bound device's resolved role, “Always” forces its own source and “Never” excludes it; linked lights above remain independent.","marker.light_role.help.aria":"Help: whether this device is a light source","marker.light_role_auto_yes":"Auto (light source)","marker.light_role_auto_no":"Auto (not a light source)","marker.light_entity_label":"Leading light entity","marker.light_entity.help":"For a composite device, choose the entity whose state, colour and brightness represent this plan source. The automatic fallback remains compatible with older plans.","marker.light_entity.help.aria":"Help: leading light entity","marker.light_entity_auto":"Automatic ({entity})","marker.light_entity_none":"no controllable entity","marker.light_entity_missing":"The saved entity {entity} is unavailable. House Plan temporarily uses {fallback}; the saved choice will be restored if it returns.","marker.toggle_entity_label":"Entity to toggle","marker.toggle_entity.help":"For a composite device, choose the exact own light or switch operated by a tap. Automatic keeps the previous target rules and is independent from the leading light entity.","marker.toggle_entity.help.aria":"Help: entity to toggle","marker.toggle_entity_auto":"Automatic ({entity})","marker.toggle_entity_none":"no own controllable entity","marker.toggle_entity_missing":"The saved entity {entity} is no longer among this marker’s selectable channels. House Plan temporarily uses {fallback}; the saved choice will be restored if it returns.","marker.glow_color_label":"Glow colour and brightness","marker.glow_mode.help":"Use live source values, override only its colour, or fix both colour and brightness. The minimum is 1%; to disable the source, choose “Never”.","marker.glow_mode.help.aria":"Help: glow colour and brightness","marker.glow_mode_auto":"From source","marker.glow_mode_color":"Set colour","marker.glow_mode_fixed":"Colour and brightness","marker.glow_color":"Glow colour","marker.glow_brightness":"Brightness","marker.glow_disabled_never":"Glow settings are unavailable because this marker is explicitly not a light source.","marker.glow_disabled_auto":"Auto mode found no spatial light source for this marker.","marker.glow_disabled_no_entity":"No active controllable Home Assistant entity is available for this spatial source.","marker.glow_passive_hint":"This source has no own Home Assistant data. Set its colour and brightness manually; its radius remains available.","marker.control_broken":"Saved source is missing or no longer marked as a light","marker.control_missing_label":"Missing plan light","marker.control_passive":"passive source","toast.marker_control_cycle":"This link would create a circular chain of light controls.","toast.marker_binding_required":"Choose a Home Assistant device before linking another light source.","confirm.unlock_title":"Unlock?","confirm.unlock_body":"House Plan will send an unlock command to this lock.","toast.files_migrate_failed":"Attachments could not be moved to the new binding, links keep pointing at the old files: {err}","space.pick_saved":"Already uploaded","space.pick_saved_hint":"Plans stored on the server, including ones you detached earlier","space.no_saved":"No plans stored on the server yet.","space.loading":"Loading…","space.used_by":"in use: {list}","space.in_use":"A space still uses this plan — detach it first","btn.use":"Use","confirm.delete_plan_title":"Delete plan file?","confirm.delete_plan_body":"The file will be deleted from the server. This action cannot be undone.","toast.plans_list_failed":"Could not list the stored plans: {err}","toast.plan_delete_failed":"Could not delete the plan: {err}","marker.hide":"Hide","marker.hide_tip":'The device will disappear from the plan after saving but will still count toward the room signal. Restore it through the "Devices" catalog in the device editor.',"marker.show":"Show","marker.show_tip":"The device will appear on the plan again after saving.","marker.hidden_ghost":"Device hidden by the user","marker.ha_disabled_device":"The device is disabled in Home Assistant and hidden from the plan.","marker.ha_disabled_entity":"The entity is disabled in Home Assistant and hidden from the plan.","marker.ha_disabled_all_entities":"The device has no active Home Assistant entities, so it is hidden from the plan.","marker.ha_registry_limited":"The full Home Assistant registry is unavailable to this user. The unverified object cannot be shown or used for now.","marker.delete_tip":"Completely delete the device from the plan and every aggregate. You can add it again later.","tap.run":"Run automation/script/scene","tap.none":"Do nothing","marker.run_target_label":"What to run","marker.run_search_ph":"Search: automation, script or scene…","marker.run_target_gone":"Target {id} not found — pick again","marker.tap_confirm":"Ask for confirmation","marker.tap_confirm_tip":"Show a confirmation dialog before acting — a guard against accidental taps.","marker.toggle_hint_single":"Target: {name} ({id}).","marker.virtual_light_target":"Virtual light: {name}.","marker.virtual_light_current":"Manual state: {state} → {effect}.","marker.virtual_light_state_on":"on","marker.virtual_light_state_off":"off","marker.toggle_hint_group":"Will toggle {count} source(s): {names}.","marker.toggle_hint_current":"Now: {state} → {effect}.","marker.toggle_hint_group_current":"Currently on: {on} of {count} → {effect}.","marker.toggle_hint_skipped":"Will be skipped ({count}): {targets}.","marker.toggle_effect_turn_on":"will turn on","marker.toggle_effect_turn_off":"will turn off","marker.toggle_effect_open":"will open","marker.toggle_effect_close":"will close","marker.toggle_effect_stop":"will stop","marker.toggle_effect_toggle":"state will toggle","marker.toggle_skip_missing":"not found","marker.toggle_skip_ha_disabled":"disabled in HA","marker.toggle_skip_unavailable":"unavailable","marker.toggle_skip_unsupported":"toggle is unsupported","marker.toggle_skip_secure":"blocked for security","marker.toggle_none_no_binding":"This device has no binding, so there is no state to toggle. Tapping will do nothing.","marker.toggle_none_no_actionable_entity":"This device has no state that can be toggled. Tapping will do nothing.","marker.toggle_none_configured_targets_missing":"The configured targets are unavailable. The device's own entity will not be substituted for them.","marker.toggle_none_ha_disabled":"The target is disabled in Home Assistant and cannot be used on the plan.","marker.toggle_none_unavailable":"The target is currently unavailable. Tapping will do nothing.","marker.toggle_none_unsupported":"Home Assistant exposes no safe toggle operation for this entity. Tapping will do nothing.","marker.toggle_none_secure":"Toggling locks, alarms and secure gates from the plan is blocked for security.","run.automation":"automation","run.script":"script","run.scene":"scene","confirm.tap_run":'Run "{name}"?',"confirm.tap_toggle":'Toggle "{name}"?',"confirm.current_state":"Current state: {state}","confirm.expected_state":"After switching: {state}","confirm.group_current":"on {on} of {total}","confirm.group_all_on":"all are on","confirm.group_all_off":"all are off","confirm.unavailable_targets":"Unavailable: {count}","confirm.expected_by_ha":"Home Assistant will determine the state","confirm.state_on":"On","confirm.state_off":"Off","confirm.state_open":"Open","confirm.state_closed":"Closed","confirm.state_opening":"Opening","confirm.state_closing":"Closing","confirm.state_stopped":"Stopped","confirm.state_unknown":"Unknown","toast.run_started":"Started: {name}","toast.run_target_missing":"Run target not found — check the device settings","toast.run_target_required":"Pick an automation, script or scene","toast.tap_target_changed":"The action target changed. Try again.","toast.virtual_light_toggle_failed":"Could not toggle the virtual light: {err}","toast.value_badge_source_required":"Choose a value for the badge","btn.run":"Run","vac.section":"Robot vacuum: live position","vac.autocal":"Set up automatically","vac.live":"Live position on the plan","vac.trail":"Show the robot's path","vac.autocal_no_rooms":"The integration reports no room list — open “Fit manually”","vac.route_warn_unmapped":"The robot is cleaning a map that is not assigned to any floor","vac.route_warn_needs_calibration":"The map is assigned to a floor but not calibrated","vac.route_warn_ambiguous":"Two maps are indistinguishable — no floor was chosen","vac.route_warn_missing_space":"The space of this map was deleted","vac.autocal_no_match":"Room names did not match (need ≥3 in common) — open “Fit manually”","vac.autocal_done":"Done: bound via {rooms} rooms. Start a cleanup and check","vac.cal_need_pos":"The robot is not reporting coordinates — start a cleanup and pause it","vac.cal_done":"Calibration saved. Start a cleanup and check","vac.cal_cancelled":"Calibration cancelled","vac.fit":"Fit manually","vac.fit_hint":"Drag the robot map into place, stretch by the corners","vac.fit_rotate":"Rotate 90°","vac.fit_mirror":"Mirror","vac.trail_never":"Never","vac.trail_cleaning":"While cleaning","vac.trail_always":"Always","gs.bg_color":"Background around the plan","gs.bg_default":"Theme default","gs.bg_mode":"Plan background","gs.bg_mode.help":"“Follows the Sun” uses sun.sun, falling back to the browser's local clock; Static always shows the selected colour.","gs.bg_mode.help.aria":"Help: general plan background","gs.bg_static":"Static color","gs.bg_daynight":"Follows the Sun","gs.sun_group":"Sun","gs.sun_missing":"The sun.sun entity was not found — the background follows your local clock; window rays are unavailable.","gs.north":"North on the plan","gs.north.help":"The angle is measured clockwise from the plan's upward vertical; north is required for window rays, not for the “Follows the Sun” background.","gs.north.help.aria":"Help: general north direction","gs.north_ph":"not set","gs.north_clear":"Clear","gs.north_letter":"N","gs.sun_rays":"Sunlight through windows","gs.sun_ray_origin":"Sun rays","gs.sun_ray_origin.inner":"From the inner window corners","gs.sun_ray_origin.outer":"From the outer window corners","gs.about_version":"Houseplan Card v{v}","gs.about_github":"GitHub · docs & issues","gs.about_telegram":"Telegram chat","support.title":"Help & feedback","space.bg_color":"Background around the plan","space.bg_inherit":"Inherit general","space.bg_mode":"Plan background","space.bg_mode.help":"Inherit the general background or override this space with a static colour or “Follows the Sun”.","space.bg_mode.help.aria":"Help: space background","space.north":"North on the plan","space.north.help":"Overrides general north for this space; the angle is measured clockwise from the plan's upward vertical and is used by window rays.","space.north.help.aria":"Help: north for this space","space.sun_rays":"Sunlight through windows","space.sun_inherit":"General settings","space.sun_on":"On","space.sun_off":"Off","canvas.far_objects":"{n} object(s) far from the plan","canvas.show_far":"Show","canvas.home_tip":"The plan is over there — click to fit it","gs.grid_group":"Plan maintenance","gs.align_all":"Optimize plans","gs.align_title":"Optimize plans","gs.align_none":"All plans already use the current optimized data model.","gs.optimize_no_automatic_changes":"There are no automatic changes to apply. Review the items below.","gs.align_count":"{n} of {total} elements will move, by at most {cm} cm.","gs.align_where":"The largest shift is in “{s}”.","gs.align_turned":"Openings whose angle is corrected: {n}.","gs.align_preflight_failed":"Could not safely verify the geometry of the following spaces: {spaces}{more}.","gs.align_preflight_hint":"Plans were not changed. Copy the diagnostics with the button below and attach them to the bug report together with a space export.","gs.preflight_reason_prepare-exception":"Could not prepare the space geometry (exception while building the model)","gs.preflight_reason_wall-null":"The wall body did not build (the union came back empty)","gs.preflight_reason_wall-degraded-extra":"The wall body degraded with extra geometry","gs.preflight_reason_wall-failed-core":"The wall body core failed to assemble","gs.preflight_reason_wall-exception":"Wall construction threw an exception","gs.preflight_reason_floor-null":"The floor outline did not build","gs.preflight_reason_floor-exception":"Floor construction threw an exception","gs.preflight_copy":"Copy diagnostics","gs.preflight_copied":"Diagnostics copied","gs.preflight_update_hint":"The card and integration versions differ — update House Plan and retry.","gs.align_preflight_space":"Space {n}","gs.align_preflight_more":", and {n} more","gs.optimize_changes":"Model migrations: {m}; spaces updated: {c}; noisy coordinate values removed: {p}; merged real-wall fragments: {w}; merged zero-thickness wall fragments: {s}; independent walls: {i}.","gs.zero_walls_migrated":"Virtual wall spans converted: {n}.","gs.wall_segments_migrated":"Wall segments stabilised: {n}.","gs.room_drafts_migrated":"Unfinished contours converted to ordinary walls: {drafts}; wall segments: {segments}.","gs.optimize_lattice_summary":"Noisy coordinate values canonicalized: {n}; maximum movement: {cm} cm.","gs.optimize_lattice_space":"{space}: coordinate values canonicalized: {n}; off-grid values left unchanged: {far}.","gs.optimize_coincident_partitions":"Hidden independent wall sections absorbed into room walls: {n}.","gs.optimize_openings_rehosted":"Openings reattached to room walls: {n}.","gs.optimize_walls_straightened":"Walls straightened: {n}; maximum movement: {cm} cm.","gs.optimize_walls_straightened_where":"Largest wall correction: {s}.","gs.optimize_walls_straighten_skipped":"Near-axis walls left unchanged because they could not be repaired safely: {n}.","gs.optimize_glow_migration":"Legacy Glow: {spaces} spaces → no data fill + independent Glow; {rooms} rooms → inherited data fill + independent Glow.","gs.optimize_references":"References repaired: spaces — {spaces}; rooms — {rooms}; positions — {positions}; devices detached from missing spaces — {detached}.","gs.optimize_reference_more":", and {n} more","gs.optimize_orphans_removed":"Forgotten records removed: {total} — room labels: {rooms}; devices: {devices}; group markers: {groups}. They belonged to spaces deleted earlier.","gs.optimize_live_positions":"Old positions in deleted spaces belong to existing objects: {n}{names}. They will be kept.","gs.optimize_live_positions_remove":"Old positions in deleted spaces belong to existing objects: {n}{names}. They are selected for removal.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Remove old positions","gs.optimize_live_keep":"Keep old positions","gs.optimize_live_selected":"Old positions will be removed after Optimize is applied.","gs.optimize_unverified":"Could not safely verify positions: {n}. They were left unchanged.","gs.optimize_registry_limited":"Full administrator access to the Home Assistant registries is required for a safe check.","gs.optimize_vacuum_warning":"Vacuum room mappings that still need review: {n}.","gs.optimize_details":"Details","gs.optimize_details_more":"And {n} more records.","gs.optimize_detail_removed":"will be removed","gs.optimize_detail_live":"will be kept","gs.optimize_detail_unverified":"not verified","gs.optimize_detail_room_label":"room label","gs.optimize_detail_device":"device","gs.optimize_detail_group":"group marker","gs.optimize_detail_unknown":"unknown owner","gs.optimize_detail_item":"{status}: {kind} {id}; old space {space}","gs.align_warn":"Elements deliberately placed between grid nodes will move. One undo is available after the operation, only until the next plan edit.","gs.align_run":"Optimize","gs.align_done":"Plans optimized: {n} elements moved, {m} records maintained, {r} references repaired","gs.optimize_undo":"Undo last optimization","gs.optimize_undone":"The last optimization was undone","decor.furniture":"Furniture","decor.image":"Image","decor.image_title":"Custom images","decor.image_upload":"Upload image","decor.image_replace":"Replace image","decor.image_uploading":"Uploading…","decor.image_asset":"Image file","decor.image_pick_hint":"Upload an image or choose one already used in House Plan.","decor.image_place_hint":"Click on the plan to place the image.","decor.image_none":"No uploaded images yet.","decor.image_unavailable":"Image unavailable","decor.image_used":"Used in {n} objects","decor.image_upload_failed":"Could not upload the image: {err}","decor.image_error_capacity":"The custom image storage limit has been reached.","decor.image_in_use":"Remove every placed copy before deleting this image.","decor.image_delete_title":"Delete image file?","decor.image_delete_message":"Delete “{name}” from House Plan? This cannot be undone.","furn.title":"Furniture library","furn.symbol":"Symbol","furn.group_furniture":"Furniture","furn.group_appliance":"Appliances","furn.group_sanitary":"Plumbing","furn.group_other":"Other","furn.width":"Width","furn.depth":"Depth","furn.back_to_categories":"All categories","furn.pick_hint":"Choose a category, then a symbol.","furn.place_hint":"Click on the plan — the piece lands against the nearest wall. Shift places it free.","furn.cat_air_conditioner":"Air conditioners","furn.cat_armchair":"Armchairs","furn.cat_bathtub":"Bathtubs","furn.cat_bed":"Beds","furn.cat_bidet":"Bidets","furn.cat_boiler":"Water heaters","furn.cat_chair":"Chairs","furn.cat_coffee_table":"Coffee tables","furn.cat_computer":"Computer","furn.cat_cooktop":"Cooktops","furn.cat_dining_table":"Dining tables","furn.cat_dishwasher":"Dishwashers","furn.cat_dryer":"Dryers","furn.cat_fireplace":"Fireplaces","furn.cat_fridge":"Refrigerators","furn.cat_hood":"Cooker hood","furn.cat_kitchen_cabinet":"Kitchen cabinets","furn.cat_kitchen_sink":"Kitchen sinks","furn.cat_nightstand":"Cabinets","furn.cat_oven":"Oven","furn.cat_plant":"Plants","furn.cat_rug":"Rugs","furn.cat_shelving":"Shelving","furn.cat_shower":"Showers","furn.cat_sink":"Sinks","furn.cat_sofa":"Sofas","furn.cat_stairs":"Stairs","furn.cat_toilet":"Toilets","furn.cat_tv":"Televisions","furn.cat_wardrobe":"Wardrobes","furn.cat_washer":"Washing machines","furn.cat_work_table":"Desks","furn.sym_cactus":"Cactus","furn.sym_computer":"Computer","furn.sym_hood":"Cooker hood","furn.sym_oven":"Oven","furn.sym_sofa":"Two-seat sofa","furn.sym_sofa_three_seat":"Three-seat sofa","furn.sym_sofa_corner_right":"Right sectional sofa","furn.sym_armchair":"Soft armchair","furn.sym_armchair_office":"Office chair","furn.sym_coffee_table":"Rectangular coffee table","furn.sym_coffee_table_round":"Round coffee table","furn.sym_coffee_table_oval":"Oval coffee table","furn.sym_coffee_table_rounded":"Rounded coffee table","furn.sym_table_dining":"Rectangular dining table","furn.sym_table_round":"Round table","furn.sym_table_dining_oval":"Oval dining table","furn.sym_table_dining_rounded":"Rounded dining table","furn.sym_chair":"Chair","furn.sym_chair_bar":"Bar stool","furn.sym_desk":"Rectangular desk","furn.sym_desk_corner":"Corner desk","furn.sym_bed_double":"Double bed","furn.sym_bed_single":"Single bed","furn.sym_nightstand":"Bedside table","furn.sym_cabinet_tv":"TV cabinet","furn.sym_cabinet_shoe":"Shoe cabinet","furn.sym_cabinet_sink":"Sink cabinet","furn.sym_wardrobe":"Wardrobe","furn.sym_bookshelf":"Bookcase","furn.sym_wall_unit":"Wall unit","furn.sym_kitchen_floor":"Kitchen floor module","furn.sym_kitchen_floor_corner":"Kitchen floor corner module","furn.sym_kitchen_wall":"Kitchen wall module","furn.sym_kitchen_wall_corner":"Kitchen wall corner module","furn.sym_shelf_floor":"Floor shelving unit","furn.sym_shelf_wall":"Wall shelf","furn.sym_fridge":"Fridge","furn.sym_stove":"Four-burner cooktop","furn.sym_cooktop_two":"Two-burner cooktop","furn.sym_dishwasher":"Dishwasher","furn.sym_washer":"Washing machine","furn.sym_dryer":"Tumble dryer","furn.sym_tv":"TV on stand","furn.sym_tv_wall":"Wall-mounted TV","furn.sym_ac":"Air conditioner","furn.sym_water_heater":"Water heater","furn.sym_toilet":"Floor-standing toilet","furn.sym_toilet_built_in":"Built-in toilet","furn.sym_bathtub":"Rectangular bathtub","furn.sym_bathtub_corner":"Corner bathtub","furn.sym_shower":"Shower","furn.sym_sink":"Washbasin","furn.sym_kitchen_sink":"Single kitchen sink","furn.sym_kitchen_sink_double":"Double kitchen sink","furn.sym_bidet":"Floor-standing bidet","furn.sym_bidet_built_in":"Built-in bidet","furn.sym_stairs":"Stairs","furn.sym_fireplace":"Fireplace","furn.sym_plant":"Plant","furn.sym_rug":"Rug","common.yes":"Yes","common.no":"No","vac.diag_source":"Source","vac.diag_platform":"Integration","vac.diag_status":"Status","vac.diag_position":"Position","vac.diag_rooms":"Rooms","vac.diag_rooms_value":"{total} · {matched} names match · {readiness}","vac.autocal_ready":"auto-calibration available","vac.autocal_not_ready":"need 3 matching names","vac.diag_path":"Integration path","vac.diag_map":"Map ID","vac.source_none":"not selected","vac.source_status_ok":"Ready","vac.source_status_missing":"Missing","vac.source_status_disabled":"Disabled in Home Assistant","vac.source_status_unavailable":"Unavailable","vac.source_status_unverified":"Cannot verify with current permissions","vac.source_status_unsupported":"No position data","vac.source_status_none":"No source","vac.source_banner_missing":"The saved source no longer exists. It was not replaced automatically; choose another source or restore it in Home Assistant.","vac.source_banner_disabled":"The saved source is disabled in Home Assistant. Enable it there or choose another source.","vac.source_banner_unverified":"Current Home Assistant permissions cannot verify this saved source. It remains pinned and will not be replaced automatically.","vac.choose_source":"Choose source","vac.source_auto":"Automatic","vac.source_auto_hint":"Use a compatible entity from this device","vac.all_cameras":"All cameras","vac.all_cameras_warn":"A camera may not provide robot data. Choose one only if it is your vacuum map.","vac.all_cameras_empty":"No other camera entities found.","vac.platform_unknown":"unknown integration","vac.cap_position":"position","vac.cap_rooms_short":"rooms","vac.cap_path":"path","vac.cap_map":"map ID","vac.cap_none":"no robot data detected","vac.xcme_hint":"Enable these Xiaomi Cloud Map Extractor attributes:","vac.documentation":"Documentation","vac.residual_title":"Check automatic calibration","vac.residual_message":"The matched rooms disagree by up to {error}. Apply this approximate calibration, refine it manually, or cancel without changing the saved setup.","vac.apply_proposal":"Apply","gs.backup_group":"Backup and transfer","backup.export_open":"Export","backup.import_open":"Import","backup.export_title":"Export House Plan","backup.import_title":"Import House Plan","backup.export_hint":"Choose whether the backup should contain the whole House Plan configuration or only the current space.","backup.full":"Full backup","backup.current_space":"Current space","backup.current_space_title":"Current space: {title}","backup.no_current_space":"No current space","backup.plan_only":"Plan only","backup.plan_only_hint":"Keep rooms, walls, openings, decor and room-label positions without devices or Home Assistant bindings.","backup.plan_only_preview":"This file contains the plan only","backup.privacy_warning":"The archive keeps names, Home Assistant identifiers and exact coordinates. Internal plans and attachments are referenced, not embedded; runtime states and vacuum trails are not included.","backup.download":"Download JSON","backup.export_done":"Backup downloaded","backup.reading":"Checking the backup…","backup.revalidated":"The plan changed after this preview. The summary was refreshed; review it and confirm again.","backup.error.support_invalid_message":"Check the support message and try again.","backup.error.support_package_too_large":"The anonymized support package exceeds the 8 MiB limit.","backup.error.support_preview_expired":"The support attachment preview expired or is no longer available.","backup.error.support_rate_limited":"Too many support reports or previews were requested. Try again later.","backup.error.support_rejected":"The report did not pass support service validation.","backup.error.support_unavailable":"The private support service is temporarily unavailable.","backup.error.unauthorized":"You do not have permission to export or import this plan.","backup.error.not_ready":"House Plan is not ready yet. Try again in a moment.","backup.error.too_large":"The backup exceeds the 8 MiB limit.","backup.error.invalid_json":"The selected file is not valid JSON.","backup.error.invalid_format":"The selected file is not a House Plan backup.","backup.error.invalid_image":"The image is damaged or does not match its format.","backup.error.unsupported_export_version":"This backup format is not supported by the installed version.","backup.error.unsupported_image":"Use a supported PNG, JPEG, WebP or SVG image.","backup.error.future_model":"The backup was created by a newer House Plan data model.","backup.error.invalid_config":"The backup contains an invalid House Plan configuration.","backup.error.wall_model_migration_blocked":"The backup wall model could not be upgraded safely. Optimize the source plan first, then export it again.","backup.error.invalid_layout":"The backup contains invalid object positions.","backup.error.invalid_content":"The backup contains invalid or inconsistent content references.","backup.error.space_not_found":"The selected space no longer exists.","backup.error.capacity_exceeded":"Adding this backup would exceed the plan limits.","backup.error.preview_expired":"The preview expired. Select the backup file again.","backup.error.preview_owner_mismatch":"This preview belongs to another Home Assistant user.","backup.error.conflict":"The plan changed after the preview. Review the refreshed summary.","backup.error.content_confirmation_required":"Confirm that unavailable local content may be detached.","backup.error.commit_failed":"The backup could not be applied safely. The previous plan was restored or is pending recovery.","backup.error.missing_plan":"A referenced plan file disappeared after the preview. Review the backup again.","backup.error.missing_content":"A referenced local attachment disappeared after the preview. Review the backup again.","backup.error.marker_control_missing":"A linked plan light is missing from the backup.","backup.error.marker_control_not_light":"A linked plan target is no longer marked as a light source.","backup.error.marker_control_self":"A light source cannot control itself.","backup.error.marker_control_cycle":"The backup contains a circular chain of light controls.","backup.error.duplicate_marker_control":"The backup contains a duplicate plan-light link.","backup.error.no_backup":"There is no import or optimization snapshot to restore.","backup.error.in_use":"The item is still in use","backup.error.invalid_data":"The request carries invalid data","backup.error.invalid_light_entity":"The leading light must be a light.* or switch.* entity","backup.error.invalid_marker_control":"Invalid marker control reference","backup.error.invalid_name":"The name is invalid","backup.error.invalid_partition_opening_host":"The opening must keep its partition host","backup.error.invalid_partition_opening_jamb_margin":"The opening leaves no physical jamb at the wall end","backup.error.invalid_passage_fields":"An open passage cannot carry door-only settings","backup.error.invalid_space_id":"Unknown space","backup.error.invalid_toggle_entity":"The toggle entity must be light.* or switch.*","backup.error.invalid_value_badge":"Invalid value badge settings","backup.error.invalid_value_badge_attribute":"Invalid value badge attribute","backup.error.invalid_value_badge_position":"Invalid value badge position","backup.error.invalid_value_badge_source":"Invalid value badge source","backup.error.invalid_vacuum_map_route":"Check how the robot's maps are assigned to spaces.","backup.error.invalid_value_source":"Invalid value source","backup.error.invalid_value_source_attribute":"Invalid value source attribute","backup.error.io_error":"A file operation failed on the server","backup.error.not_toggleable":"This device cannot be toggled","backup.error.nothing_to_repair":"Nothing to repair","backup.error.space_in_use":"The space is still referenced","backup.error.value_badge_source_required":"The value badge needs a source","backup.error.wall_model_client_outdated":"The plan was updated elsewhere — reload the page","backup.same_source":"Created on this Home Assistant instance","backup.foreign_source":"Created on another Home Assistant instance","backup.created":"Created: {value}","backup.versions":"Card {card}; integration {integration}; data model {model}","backup.count_spaces":"Spaces: {n}","backup.count_rooms":"Rooms: {n}","backup.count_walls":"Walls: {n}","backup.count_openings":"Openings: {n}","backup.count_decor":"Decor objects: {n}","backup.count_markers":"Devices: {n}","backup.count_layout":"Positions: {n}","backup.bindings":"Bindings — devices: {device}, entities: {entity}, virtual: {virtual}; positions without a space: {legacy}","backup.binding_status":"Target status — active: {active}, disabled: {disabled}, missing: {missing}","backup.missing_areas":"Areas missing on the target: {areas}","backup.dropped_marker_links":"Plan-light links outside this transferred space were omitted: {n}.","backup.room_drafts_migrated":"Legacy unfinished contours converted to ordinary walls: {drafts}; wall segments: {segments}.","backup.repaired_target_refs":"Existing references restored by this space import: {n}.","backup.preserved_unresolved_refs":"References that could not be restored unambiguously were preserved: {n}.","backup.preserved_unresolved_hint":"No data was guessed or deleted. After the import, run Optimize plans to inspect the remaining references.","backup.import_details":"Import reference details","backup.import_detail.incoming_remapped":"References updated inside the imported copy: {n}","backup.import_detail.target_repaired":"Existing references restored: {n}","backup.import_detail.preserved_unresolved":"Unresolved references preserved: {n}","backup.import_detail.collisions":"Destination conflicts preserved safely: {n}","backup.import_detail.dropped_links":"Incoming links omitted by transfer rules: {n}","backup.import_detail.bounded_lineages":"Overly nested identifiers left bounded: {n}","backup.replace_warning":"This replaces the current configuration and layout. Uploaded files are never deleted. One undo remains available until the next plan edit.","backup.foreign_bookkeeping":"Instance-specific known/new-device bookkeeping will not be imported.","backup.final_name":"New space name","backup.target_settings":"The target instance's global settings remain unchanged.","backup.duplicates":"Bindings already present: {n}","backup.skip":"Skip duplicate devices","backup.virtual_copy":"Add safe static virtual copies","backup.content":"Referenced content","backup.decor_images_summary":"Custom images: {objects} objects, {assets} files; missing files: {missing}.","backup.content_available":"available locally","backup.content_external":"external link","backup.content_detach_required":"will be detached","backup.confirm_detach":"I understand that unavailable internal plans and attachments will be detached from the imported configuration.","backup.confirm_missing_images":"I understand that missing custom images will remain as repair placeholders and other unavailable local files will be detached.","backup.replace":"Replace","backup.add":"Add space","backup.space_done":"Space imported: {rooms} rooms, {markers} devices, {refs} existing references restored","backup.full_done":"Backup restored: {spaces} spaces, {rooms} rooms, {markers} devices","backup.undo_import":"Undo last full import","backup.import_undone":"Full import undone","backdrop.large_title":"Large image","backdrop.large_body":"This image is {w}×{h} ({fileMb} MB file) and needs about {decodedMb} MB of memory to display. On tablets this can crash the page.","backdrop.unknown_body":"The image dimensions could not be read — the file may be damaged. Continuing may crash the page on tablets.","backdrop.reduced_dimensions":"Reduced copy: {w}×{h} px.","backdrop.use_downscaled":"Upload a reduced copy","backdrop.reducing":"Reducing…","backdrop.keep_original":"Keep the original","backdrop.too_large_title":"Image is too large","backdrop.too_large_body":"This image exceeds what browsers can display ({w}×{h}, limit {limit} px per side). Please reduce it in a desktop editor and upload again.","backdrop.downscale_failed":"Could not create the reduced copy. The original plan was not changed.","gs.card_display":"Display","gs.card_zigbee":"Zigbee links","gs.card_fills":"Room fill colors","gs.card_plan":"Plan","gs.card_data":"Data","gs.card_fills.help.aria":"About room fill colors","gs.backup_group.help.aria":"About backup and transfer","gs.grid_group.help.aria":"About plan maintenance","gs.backup_group.help":"Download a portable JSON backup or preview and import a backup made by House Plan.","gs.grid_group.help":"Updates data models, aligns plan elements to the grid and merges redundant wall fragments. An exact report is shown before anything is stored.","gs.card_fills.help":"Fill colors apply to every space; each color has its own opacity. Which fill mode a space uses is set in that space's dialog.","space.card_basics":"Basics","space.card_sun":"Sun & light","marker.card_basics":"Basics","marker.card_tap":"Tap action","marker.card_light":"Light and glow","marker.card_appearance":"Appearance","marker.card_details":"Details"};const cp=new WeakSet,hp=new WeakSet;function dp(e,t,i){const n=i?t.state(i):"ready";return i&&"pending"===n?(hp.has(e)||(e.inert=!0,e.setAttribute("aria-busy","true"),hp.add(e)),t.ensure(i).then(()=>{e.isConnected&&e.requestUpdate()}),cp.has(e)?"warm":"cold"):(hp.delete(e)&&(e.inert=!1,e.removeAttribute("aria-busy")),i&&(e.setAttribute("lang","fallback"===n?"en":i),cp.add(e)),"ready")}function up(){return j``}const pp=[{code:"en",nativeLabel:"English",dictionary:lp},{code:"ru",nativeLabel:"Русский",dictionary:{"editor.context_actions":"Действия: {object}","editor.tool_options":"Параметры инструмента: {tool}","editor.palette":"Палитра: {tool}","editor.open_group":"Группа инструментов: {group}","editor.group_active":"{group} — активно: {item}","editor.disabled_action":"{action} недоступно: {reason}","editor.loading":"Загрузка…","editor.loading_aria":"Редактор плана загружается","editor.load_failed":"Не удалось загрузить редактор.","editor.refresh_advice":"Обновите страницу и повторите попытку.","editor.retry_advice":"Проверьте сеть и нажмите ещё раз.","version_mismatch.title":"Версии House Plan не совпадают","version_mismatch.body":"Если Home Assistant ещё перезапускается, дождитесь завершения, затем перезагрузите эту страницу.","version_mismatch.frontend":"Карточка","version_mismatch.backend":"Интеграция","version_mismatch.reload":"Перезагрузить страницу","color_picker.title":"Выбор цвета","color_picker.hue":"Оттенок","color_picker.saturation":"Насыщенность","color_picker.value":"Яркость","color_picker.hex":"Цвет HEX","color_picker.invalid_hex":"Введите цвет HEX из 3 или 6 цифр","color_picker.confirm":"ОК","btn.properties":"Свойства","btn.keep_as_walls":"Оставить стенами","btn.delete_room_keep_walls":"Удалить комнату, оставить стены","btn.delete_room_with_walls":"Удалить комнату и стены","title.markup_select":"Выбор и редактирование стен и колонн","title.markup_column":"Колонна: кликните точку сетки для квадратной колонны","markup.partition":"Перегородка","markup.column":"Колонна","markup.hint_column":"кликните точку сетки, чтобы поставить квадратную колонну","history.wall_segment":"Добавление отрезка стены","history.column_add":"Добавление колонны","history.physical_edit":"Изменение физического объекта","history.physical_delete":"Удаление физического объекта","history.physical_move":"Перемещение физического объекта","history.wall_face_batch":"Создание комнат из стен","toast.column_duplicate":"Колонна с тем же центром и внешним размером уже существует","physical.partition_properties":"Свойства перегородки","physical.column_properties":"Свойства колонны","physical.shape":"Форма","physical.square":"Квадрат","physical.circle":"Круг","physical.diameter":"Диаметр","physical.side":"Сторона","physical.rotation":"Угол поворота","physical.length":"Длина","physical.allowed_range":"Допустимо: {min}–{max} {unit}","physical.column_size_title":"Внешняя сторона квадратной колонны, создаваемой кликом (1–150 см).","card.title":"План дома","count.devices":"{n} устр.","empty.no_spaces":"Пространств пока нет.","nav.spaces":"Пространства House Plan","empty.add_first":"Добавьте первое пространство и загрузите план этажа.","empty.read_only":"Пространства не настроены. Попросите администратора добавить первое.","empty.install":"Установите интеграцию House Plan и добавьте запись в «Устройства и службы».","btn.add_space":"Добавить пространство","btn.cancel":"Отмена","btn.save":"Сохранить","btn.close":"Закрыть","btn.delete":"Удалить","btn.copy":"Копировать","btn.edit":"Редактировать","btn.open_in_ha":"Открыть в HA","btn.reset":"Сброс","btn.attach":"Прикрепить…","btn.upload":"Загрузить…","btn.replace":"Заменить…","title.zoom_in":"Приблизить","title.zoom_out":"Отдалить","title.zoom_fit":"Вписать всё","title.configure_space":"Настроить пространство","title.add_space":"Добавить пространство","title.markup_add":"Стены: рисуйте непрерывную цепочку; каждый принятый отрезок сохраняется отдельно. Shift фиксирует 45°","title.markup_merge":"Объединить: клик по одной комнате, затем по соседней с общей стеной","title.markup_split":"Разделить комнату: клик по комнате, затем две точки на её стенах","title.markup_delroom":"Удалить комнату: кликните внутри комнаты и подтвердите удаление","markup.add":"Стены","markup.merge":"Объединить","markup.split":"Разделить","markup.resize":"Размер","title.markup_resize":"Изменение размера комнат: тяните доступную ручку горизонтальной или вертикальной стены","markup.hint_resize":"тяните доступную ручку стены · стена упирается в первую небезопасную позицию · Esc — отмена · Ctrl+Z — отмена шага","resize.disabled.diagonal":"Стена расположена под углом: Resize поддерживает только горизонтальные и вертикальные стены","resize.disabled.side-angle":"Примыкающая стена расположена под углом: для Resize обе примыкающие стены должны образовывать прямой угол","resize.disabled.duplicate-physical-wall":"Стену перекрывает отдельная перегородка или колонна; удалите или переместите её перед изменением размера","resize.disabled.partial-shared":"Соседняя комната использует только часть этой стены, поэтому её нельзя безопасно двигать как одну общую стену","resize.disabled.unequal-shared":"У соседней комнаты другие конечные точки или длина стены, поэтому стены нельзя безопасно двигать вместе","resize.disabled.multiple-rooms":"Перемещение затронуло бы больше двух комнат","resize.disabled.thickness-conflict":"Толщину стены нельзя безопасно сохранить","resize.disabled.opening-conflict":"Проём на этой стене нельзя безопасно переместить","resize.disabled.invalid-geometry":"Эту стену нельзя переместить без изменения структуры плана","resize.limit_stopped":"Стена остановлена: дальше нарушается ограничение стыков","resize.commit_failed":"Изменение размера отменено: итоговый план не прошёл проверку геометрии","resize.preview_failed":"Стена остановлена в последней безопасной позиции: геометрию плана нельзя сохранить без потерь","markup.opening":"Проём","markup.delete_room":"Удалить комнату","history.undo":"Отменить","history.redo":"Повторить","history.undo_named":"Отменить: {name} (Ctrl+Z)","history.redo_named":"Повторить: {name} (Ctrl+Shift+Z / Ctrl+Y)","history.undo_empty":"Нет операций для отмены","history.redo_empty":"Нет операций для повтора","history.undone":"Отменено: {name}","history.redone":"Повторено: {name}","history.add_room":"Создание комнаты","history.split_room":"Разделение комнаты","history.merge_rooms":"Объединение комнат","history.resize_room":"Изменение размера комнаты","history.wall_thickness":"Изменение толщины стены","history.add_opening":"Добавление дверного или оконного проёма","history.edit_opening":"Изменение проёма","history.move_opening":"Перемещение проёма","history.delete_opening":"Удаление проёма","history.delete_room_keep_walls":"Удаление комнаты с сохранением стен","history.delete_room_with_walls":"Удаление комнаты и её стен","history.decor_add":"Добавление объекта декора","history.decor_edit":"Изменение объекта декора","history.decor_move":"Перемещение объекта декора","history.decor_transform":"Трансформация объекта декора","history.decor_delete":"Удаление объекта декора","history.backdrop_transform":"Трансформация подложки плана","history.device_move":"Перемещение: {name}","history.device_stale":"История позиций больше неприменима и была очищена","opening.new":"Новый проём","opening.edit":"Проём","opening.door":"Дверь","opening.window":"Окно","opening.gate":"Ворота","opening.passage":"Открытый проём","opening.passage_binding_warning":"При сохранении датчик открытия и замок будут удалены.","opening.invalid_passage_fields":"У открытого проёма на плане «{room}» есть недопустимые параметры: {fields}.","opening.type_label":"Тип","opening.length_label":"Длина, см","opening.contact_label":"Датчик открытия","opening.lock_label":"Замок","opening.none":"— нет —","opening.search_ph":"Поиск: имя или entity_id…","opening.invert":"Инвертировать открыто/закрыто","opening.flip_h":"Петли с другой стороны","opening.flip_v":"Открывается в другую сторону","opening.open":"Открыто","opening.closed":"Закрыто","opening.locked":"Заперто","opening.unlocked":"Не заперто","opening.state_unknown":"недоступно","opening.no_entities":"Датчики не привязаны — статичный символ на плане.","toast.opening_no_wall":"Кликните рядом со стеной комнаты или независимой стеной","opening.host_partition":"Независимая стена","opening.partition_orphan":"Независимая стена этого проёма больше не существует","opening.partition_jamb_margin":"Оставьте от края проёма до торца стены минимум {distance}","opening.rebind_partition":"Привязать к другой независимой стене","confirm.delete_partition_openings_title":"Удалить стену и проёмы?","confirm.delete_partition_openings_body":"В стене есть проёмы: {count}. Они будут удалены вместе со стеной.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.hint_points":"точек: {n} · Shift — шаг 45° · Esc — завершить цепочку · Ctrl+Z — убрать точку · при замыкании будет предложена комната","markup.hint_start":"кликните точку сетки, чтобы начать цепочку стен","tip.lqi":"средний сигнал zigbee:","tip.area":"площадь: {value}","info.device_header":"Устройство на плане","info.model":"Модель","info.state":"Состояние","info.link":"Ссылка","info.manuals":"Инструкции","info.none":"Нет дополнительной информации","marker.new_device":"Новое устройство","marker.name_label":"Название","marker.name_ph":"Название","marker.binding_label":"Привязка к устройству HA","marker.binding_disabled":"деактивировано в Home Assistant","marker.virtual_option":"Виртуальное устройство (без привязки)","marker.search_ph":"Поиск устройства / группы…","marker.nothing_found":"ничего не найдено","marker.room_label":"Комната","marker.room_choose":"— выберите комнату —","marker.room_auto":"— по зоне устройства (авто) —","marker.icon_label":"Иконка","marker.icon_ph":"mdi:… (пусто = авто)","marker.display_label":"Отображение","display.badge":"Значок + состояние","display.icon_ripple":"Значок + состояние и активность","display.static_icon":"Всегда статичный значок","display.value_static_icon":"Значение + статичный значок","marker.display_hint_badge":"Значок и динамическая подложка показывают состояние устройства без обычной пульсации активности. Красная тревога сохраняется.","marker.display_hint_icon_ripple":"Значок, динамическая подложка и пульсация: короткая — для событий, постоянная — для работы, движения или присутствия. Красная тревога имеет отдельный приоритет.","marker.display_hint_value":"Значок заменяется выбранным или автоматически найденным значением Home Assistant; подложка продолжает показывать состояние. Красная тревога сохраняется.","marker.display_hint_static_icon":"Подложка в цветах темы и значок всегда остаются одинаковыми. Состояния, активность, недоступность и тревоги не меняют отображение.","marker.display_hint_value_static_icon":"Маркер показывает выбранное значение, а подложка остаётся в цветах темы. Состояния, активность, недоступность и тревоги не меняют цвет маркера.","marker.static_alarm_warning":"Это устройство может сообщать о тревогах. Статичный режим скрывает визуальную тревогу маркера.","marker.preview.title":"Предпросмотр отображения","marker.preview.actual":"Сейчас","marker.preview.example":"Пример","marker.preview.integration":"Интеграция","marker.preview.source":"Источник отображения","marker.preview.current_state":"Текущее состояние","marker.preview.result":"На плане","marker.preview.details":"Подробнее об источниках","marker.preview.select_source":"Выберите устройство или сущность Home Assistant, чтобы увидеть фактическое отображение.","marker.preview.unknown_provider":"Интеграция неизвестна","marker.preview.virtual_provider":"House Plan · виртуальное устройство","marker.preview.no_source":"Нет активного источника","marker.preview.no_state":"Нет текущего состояния","marker.preview.mixed_states":"Несколько разных состояний","marker.preview.multiple_sources":"Источников: {n}","marker.preview.more_sources":"ещё {n}","marker.preview.scaled":"Предпросмотр уменьшен до {n}%, чтобы поместиться. Сохранённый размер не изменится.","marker.preview.demo_short":"Показать краткую активность","marker.preview.demo_continuous":"Показать постоянную активность","marker.preview.stop_continuous":"Остановить постоянную активность","marker.preview.demo_short_notice":"Пример краткой активности; фактическое состояние устройства не меняется.","marker.preview.demo_continuous_notice":"Пример постоянной активности; фактическое состояние устройства не меняется.","marker.preview.demo_already_visible":"Текущее состояние уже показывает реальную активность или тревогу.","marker.preview.reduced_motion":"В системе включено уменьшение движения, поэтому обычная активность показана точкой.","marker.preview.reason.neutral":"Нейтральная тёмная подложка","marker.preview.reason.working":"Жёлтая подложка: устройство сейчас работает","marker.preview.reason.working_activity":"Жёлтая подложка и эффект активности: устройство сейчас работает","marker.preview.reason.open":"Оранжевая подложка: физически открыто или разблокировано","marker.preview.reason.cover_icon_state":"Нейтральная подложка; состояние и значок определяет сущность шторы или заслонки","marker.preview.reason.presence":"Эффект активности, пока обнаружено присутствие","marker.preview.reason.event":"Короткий эффект активности после события","marker.preview.reason.transition":"Эффект активности во время движения или смены состояния","marker.preview.reason.media_neutral":"Медиаустройство остаётся на нейтральной тёмной подложке, пока доступно","marker.preview.reason.unavailable":"Приглушённая нейтральная подложка: отключено или недоступно","marker.preview.reason.alarm":"Красная тревожная подложка; тревога отображается всегда","marker.preview.reason.live_states_disabled":"Оформление по живым состояниям отключено в настройках карточки","marker.preview.reason.value_no_state":"Нет подходящего значения состояния — вместо него показан значок","marker.preview.reason.value_ambiguous_sources":"Подходит несколько источников значения — вместо него показан значок","marker.preview.reason.value_non_scalar":"Источник вернул не простое значение — вместо него показан значок","marker.preview.reason.value_virtual":"У виртуального устройства нет значения HA — вместо него показан значок","marker.preview.reason.vacuum_live_plan_only":"Живая позиция и след пылесоса доступны только на полном плане","marker.preview.reason.hidden_design_preview":"Устройство скрыто на плане, но его оформление видно в предпросмотре","marker.preview.reason.composite_power_source":"Состояние берётся из сущности питания устройства; вспомогательные переключатели не учитываются","marker.preview.reason.activity_display_disabled":"Выбранный режим отображения не показывает обычные эффекты активности","marker.preview.reason.ha_disabled":"Привязка отключена в Home Assistant, поэтому устройство будет скрыто на плане","marker.preview.reason.orphaned":"Сохранённая привязка Home Assistant больше не найдена","marker.preview.reason.static_icon":"Статичный режим: состояние устройства не меняет значок","marker.preview.reason.value_static_icon":"Статичный режим со значением: состояние устройства не меняет цвет маркера","marker.activity_color":"Цвет пульсации активности","marker.ripple_size":"Размер пульсации активности","marker.activity_alarm_note":"Цвет и размер относятся только к обычной активности и не влияют на красную тревогу.","marker.pulse_a11y_alarm":"Тревога","marker.pulse_a11y_event":"Недавнее событие","marker.pulse_a11y_presence":"Обнаружено присутствие","marker.pulse_a11y_transition":"Изменение состояния","marker.pulse_a11y_running":"Работает","marker.state_a11y_neutral":"Обычное состояние","marker.state_a11y_working":"Работает","marker.state_a11y_open":"Открыто","marker.state_a11y_locked":"Заблокировано","marker.state_a11y_unlocked":"Разблокировано","marker.state_a11y_alarm":"Тревога","marker.state_a11y_unavailable":"Недоступно","marker.lqi_a11y_low":"LQI {value}, слабый сигнал","marker.lqi_a11y_mid":"LQI {value}, средний сигнал","marker.lqi_a11y_high":"LQI {value}, сильный сигнал","marker.size_label":"Размер и поворот иконки","marker.angle_label":"Поворот","marker.model_label":"Модель","marker.model_ph":"напр. Aqara T&H","marker.link_label":"Ссылка","marker.desc_label":"Описание","marker.desc_ph":"Заметки, характеристики…","marker.manuals_label":"Инструкции (PDF и т.п.)","marker.sub_device":"устройство","marker.sub_z2m_group":" · Z2M-группа","marker.sub_group":"группа","marker.sub_helper":"хелпер","space.new":"Новое пространство","space.copy_title":"Копирование пространства","space.copy_name":"Название нового пространства","space.copy_fallback":"Пространство","space.copy_create":"Создать копию","space.copy_optimize_title":"Оптимизировать перед копированием?","space.copy_optimize_body":"Перед созданием «{name}» House Plan должен оптимизировать весь план, включая другие пространства. Продолжить?","space.copy_optimize_confirm":"Оптимизировать и скопировать","space.copy_error_changed":"План изменился, пока было открыто подтверждение. Проверьте его и повторите попытку.","space.copy_error_source_missing":"Исходного пространства больше нет. Снова откройте его настройки и повторите попытку.","space.copy_error_source_invalid":"House Plan не смог проверить все стены этого пространства. Исправьте исходное пространство и повторите попытку.","space.copy_error_spaces_limit":"В House Plan уже создано максимальное число пространств.","space.copy_error_partitions_limit":"В этом пространстве слишком много стен для копирования.","space.copy_error_openings_limit":"В этом пространстве слишком много проёмов для копирования.","space.copy_error_decor_limit":"В этом пространстве слишком много элементов подложки для копирования.","space.copy_error_columns_limit":"В этом пространстве слишком много колонн для копирования.","space.copy_error_opening_host":"Один из проёмов больше не привязан к стене. Исправьте или удалите его перед копированием.","space.copy_error_geometry":"Копия создаст небезопасную геометрию стен. Исправьте исходное пространство и повторите попытку.","space.copy_error_optimize_geometry":"Копирование остановлено: оптимизация всего плана небезопасна для одного из пространств.","space.header":"Пространство","space.title_label":"Название пространства","space.title_ph":"Например: Гараж","space.plan_label":"Подложка","space.no_plan":"нет подложки","space.plan_alt":"план","room.new":"Новая комната","room.name_label":"Отображаемое имя","room.name_ph":"Например: Терраса","room.area_label":"Зона Home Assistant","room.no_area_option":"— без зоны —","room.default_name":"Комната","device.unnamed":"без имени","device.light_group":"группа света","device.fallback":"устройство","device.virtual":"виртуальное устройство","confirm.delete_room_title":"Удалить комнату «{name}»?","confirm.delete_room_body":"Выберите, нужно ли оставить физические стены, принадлежащие только этой комнате. Общие с другой комнатой стены сохраняются всегда.","confirm.remove_marker_title":"Удалить устройство с плана?","confirm.remove_marker_body":"Устройство исчезнет полностью и перестанет участвовать в данных плана. Позже его можно будет добавить заново.","confirm.erase_decor":"Стереть объект «{kind}»? Действие можно отменить из истории редактора.","confirm.delete_space_title":"Удалить пространство?","confirm.delete_space_body":"Пространство, все его комнаты и вся разметка плана будут удалены.","confirm.delete_space_vac_routes":"Также будет снято сопоставление карт роботов: {count}.","space.delete_blocked":"Это пространство всё ещё используется устройствами: {n}. Сначала перенесите их в другое пространство или удалите.","toast.pos_save_failed":"Не удалось сохранить позицию: {err}","toast.no_entity":"У устройства нет подходящей сущности","toast.ha_disabled_action":"Деактивированный объект Home Assistant нельзя использовать на плане.","toast.ha_disabled_show_device":"Деактивированное в Home Assistant устройство нельзя показать на плане. Сначала активируйте его в Home Assistant.","toast.ha_disabled_show_entity":"Деактивированную в Home Assistant сущность нельзя показать на плане. Сначала активируйте её в Home Assistant.","toast.ha_disabled_add":"Деактивированный объект Home Assistant нельзя добавить на план. Сначала активируйте его в Home Assistant.","toast.ha_binding_unverified":"Статус объекта не удалось подтвердить по реестру Home Assistant. Отображение и действия временно недоступны.","toast.markup_needs_server":"Разметка доступна после переноса конфига на сервер","toast.space_order_changed":"Порядок изменён. Если где-то этаж карточки задан номером, проверьте такие панели.","toast.conflict":"Конфиг изменён в другом окне — данные обновлены, повторите последнее действие","toast.cfg_save_failed":"Не удалось сохранить конфиг: {err}","toast.room_overlap":"Контур накладывается на комнату «{name}» — комнаты не должны накладываться","toast.contour_cannot_close":"Контур нельзя замкнуть: он вырожден или пересекает сам себя","toast.merge_not_adjacent":"Объединять можно только комнаты с общей стеной","toast.rooms_merged":"Комнаты объединены в «{name}»","toast.split_pick_wall":"Начните разрез на стене комнаты","toast.split_bad_cut":"Разрез — от стены до стены внутри комнаты, без пересечения стен и самого себя","merge.header":"Объединение комнат","merge.hint":"У объединённой комнаты одно имя и одна зона. Вторая зона освобождается — её устройства уйдут с плана, пока их не заберёт другая комната.","merge.keep":"Оставить","merge.no_area":"без зоны","toast.room_saved":"Комната сохранена ({n}). Устройств добавлено: {added}. Обведите следующую или выйдите из разметки.","toast.room_saved_no_area":"Комната сохранена ({n}, без зоны). Обведите следующую или выйдите из разметки.","toast.marker_needs_server":"Редактирование устройств доступно после переноса конфига на сервер","toast.virtual_name_required":"Укажите имя виртуального устройства","toast.marker_saved":"Устройство сохранено","toast.marker_removed":"Устройство удалено с плана","toast.integration_missing":"Интеграция House Plan не установлена — управление недоступно","toast.plan_formats":"Поддерживаются SVG, PNG, JPG, WebP","toast.plan_required":"Загрузите подложку — план этажа обязателен","toast.space_added_onboard":"Пространство добавлено. Обведите комнаты: кликайте по точкам сетки и замкните контур.","toast.space_added":"Пространство добавлено","toast.space_copied":"Пространство «{name}» создано","toast.space_saved":"Пространство сохранено","toast.space_deleted":"Пространство удалено","toast.delete_failed":"Ошибка удаления: {err}","toast.error":"Ошибка: {err}","toast.toggle_target_unavailable":"Цель «{name}» недоступна — действие не выполнено","toast.toggle_targets_unavailable":"Цели недоступны: {names}. Действие не выполнено","toast.file_failed":"Файл «{name}» не загружен: {err}","toast.files_attached":"Прикреплено файлов: {n}","err.unknown":"неизвестная ошибка","err.code":"код {code}","err.too_large":"файл больше {mb} МБ","err.bad_ext":"недопустимый тип (нужен PDF/изображение)","err.unauthorized":"нужны права администратора","editor.title":"Заголовок","editor.default_floor":"Стартовое пространство","editor.default_floor_missing":"Стартовое пространство «{id}» больше не существует. Выберите другое.","editor.floor":"Закреплённое пространство","editor.floor_none":"— не закреплять —","editor.floor_index":"YAML-индекс {index} (сохранён)","fixed_floor.loading":"Загружаем закреплённое пространство…","fixed_floor.invalid_title":"Закреплённое пространство недоступно","fixed_floor.invalid_body":"Проверьте floor в конфигурации карточки. Настроенное значение: {value}","editor.icon_size":"Размер иконок, % ширины плана","editor.show_temperature":"Показывать температуру","editor.live_states":"Живые состояния (вкл/выкл, открыто…)","editor.light_pools":"Световые пулы и тени от стен","editor.show_signal":"Показывать сигнал zigbee (LQI)","editor.language":"Язык интерфейса","editor.lang_auto":"Авто (профиль HA)","title.icon_rules":"Правила иконок: какая MDI-иконка достаётся устройству по имени","rules.title":"Правила иконок","rules.hint":"Правила проверяются сверху вниз по строке «имя устройства + модель» (regex без учёта регистра); срабатывает первое совпадение. Если ничего не подошло — решает device class сущности, затем — иконка-заглушка.","rules.pattern_ph":"regex, напр. розетк|plug","rules.icon_ph":"mdi:power-socket-de","rules.add":"Добавить правило","rules.reset":"Сбросить к умолчаниям","rules.test_ph":"Проверьте имя устройства…","rules.invalid":"некорректный regex","rules.saved":"Правила иконок сохранены","btn.up":"Вверх","btn.down":"Вниз","tap.info":"Карточка устройства","tap.more_info":"Диалог HA (more-info)","tap.toggle":"Переключить состояние","marker.tap_label":"Действие по нажатию для этого устройства","tap.toggle_note":"Под селектором показано, какое состояние изменится. Защищённые устройства не переключаются с плана.","import.title":"Создать пространства из этажей HA","import.hint":"Home Assistant уже знает эти этажи. Отметьте, какие превратить в пространства плана — далее для каждого попросим картинку плана. Комнаты затем обводятся вручную по плану.","import.start":"Создать: {n}","import.manual":"Начать с нуля","import.progress":"Этаж {i} из {n}","import.done":"Пространства созданы. Обведите комнаты: кликайте по точкам сетки и замкните контур.","btn.skip":"Пропустить","space.scale_label":"Масштаб (размер клетки сетки)","space.cell_cm.help":"Связывает сетку с реальными размерами: от значения зависят длины и площади, толщина стен, размеры проёмов и радиус свечения. Изменение после разметки меняет расчётные размеры всего пространства, но не двигает его точки на плане.","space.cell_cm.help.aria":"Подсказка: масштаб пространства","space.scale_unit":"см на клетку","space.scale_unit_imperial":"дюйм на клетку","space.display_section":"Внешний вид","space.show_borders":"Всегда отображать границы комнат","space.zero_wall_style":"Стены нулевой толщины","space.zero_wall_style.help":"Пунктирные стены нулевой толщины пропускают Glow и солнечные лучи, сплошные блокируют их как барьер нулевой площади. Выбор меняет все такие стены пространства, даже когда их линии скрыты в просмотре.","space.zero_wall_style.help.aria":"Подсказка: вид стен нулевой толщины","space.zero_wall_dashed":"Пунктирные","space.zero_wall_solid":"Сплошные","space.show_names":"Показывать названия комнат","space.room_color":"Цвет границ и названий","space.opacity":"Прозрачность","space.fill_label":"Заливка комнат","space.fill_mode.help":"«Свой цвет» задаёт оформление, а «Свет», «Температура» и «LQI» используют текущие данные Home Assistant; Glow включается отдельно.","space.fill_mode.help.aria":"Подсказка: режим заливки комнат","fill.none":"Нет","fill.lqi":"По силе зигби-сигнала","fill.light":"По освещению","fill.custom":"Свой цвет","space.custom_fill":"Цвет заливки","space.source_file":"Использовать изображение плана","space.source_draw":"Нарисовать вручную","fill.temp":"По температуре","tip.temp_avg":"средняя температура:","tip.hum_avg":"средняя влажность:","space_card.button":"Перейти к пространству","space_card.not_found":"Пространство «{id}» не найдено","space_card.loading":"Загрузка…","continuity.restore_plan":"Восстанавливаем план…","continuity.restore_connection":"Восстанавливаем подключение к устройствам…","continuity.retry":"Повторить","editor.space":"Пространство","editor.framing":"Кадрирование","editor.fit_content":"Всё видимое содержимое","editor.fit_house":"Плотно по геометрии дома","editor.show_button":"Показывать кнопку","editor.button_label":"Текст кнопки","editor.button_target":"Путь дашборда (куда вести)","marker.sub_entity":"сущность","title.general_settings":"Общие настройки","title.export_pdf":"Сохранить в PDF","pdf.title":"Сохранение в PDF","pdf.dimensions":"Отображать размеры и площади","pdf.decor":"Отображать мебель и другой декор","pdf.room_names":"Отображать названия комнат","pdf.backdrop":"Отображать подложку","pdf.save":"Сохранить","pdf.saving":"Формируем…","pdf.failed":"Не удалось создать PDF.","pdf.too_large":"Размер изображений превышает лимит PDF 25 МБ.","pdf.asset_failed":"Не удалось загрузить подложку или изображение декора.","pdf.scale":"Масштаб 1:{n}","pdf.north":"Север","gs.title":"Общие настройки","gs.light_group":"Освещение","gs.light_on":"Свет включён","gs.light_off":"Весь свет выключен","gs.temp_group":"Температура","gs.temp_cold":"Холодно","gs.temp_ok":"Комфорт","gs.temp_hot":"Жарко","gs.lqi_group":"Сигнал Zigbee","gs.lqi_low":"Слабый сигнал","gs.lqi_high":"Сильный сигнал","gs.reset":"Сбросить к умолчаниям","gs.saved":"Общие настройки сохранены","gs.radar_show_live":"Показывать текущее присутствие на плане","radar.title":"Присутствие на плане","radar.help":"Свяжите маркер с точными сущностями радара Home Assistant, укажите положение датчика и профиль координат. Живые позиции обрезаются по выбранной комнате.","radar.help.aria":"Подсказка: настройки радара присутствия","radar.enabled":"Использовать этот радар присутствия","radar.show_live":"Показывать живые цели","radar.configure":"Настроить радар","radar.configure_on_plan":"Настроить на плане","radar.change_installation":"Сменить установку","radar.no_contour":"У комнаты нет контура. Точки радара не будут обрезаться по комнате.","radar.discard_setup_title":"Отменить настройку радара?","radar.discard_setup":"Несохранённая настройка радара будет потеряна.","radar.step_place_mount":"Укажите физическое положение датчика","radar.step_place_heading":"Укажите точку прямо перед датчиком","radar.step_reference":"Укажите контрольное положение {n}, затем начните измерение","radar.step_check_reference":"Укажите независимое проверочное положение","radar.start_measure":"Начать измерение","radar.countdown":"Встаньте в отмеченное место через {seconds} с","radar.capturing":"Стойте неподвижно и в одиночестве…","radar.fit_ready":"Калибровка готова","radar.check_third":"Проверить в другом положении","radar.check_complete":"Независимая проверка завершена","radar.error_distance":"Расхождение положения: {distance}","radar.ambiguous_target":"Обнаружено несколько целей. Повторите измерение в одиночестве.","radar.insufficient_samples":"Недостаточно актуальных координат. Повторите или настройте вручную.","radar.bad_references":"Выберите разнесённые положения в разных направлениях от датчика.","radar.ambiguous_sources":"Измерения допускают два одинаково вероятных направления. Выберите точки, по которым можно различить левую и правую стороны.","radar.bad_fit":"Измерения не совпадают. Проверьте единицы, положение датчика и контрольные точки.","radar.desktop_hint":"Для точной настройки используйте компьютер. Редактирование на тач-устройствах поддерживается по остаточному принципу.","radar.detected":"House Plan распознал признаки радара у этого устройства. Перед сохранением проверьте точные источники.","radar.detected_ld2450":"House Plan нашёл набор координат ESPHome LD2450. Перед сохранением проверьте точные источники X/Y.","radar.additional_actions":"Дополнительные действия","radar.declare":"Это радар присутствия","radar.profile":"Профиль данных","radar.profile_esphome_ld2450_v1":"ESPHome LD2450 (цели X/Y)","radar.profile_cartesian_v1":"Декартовы цели (X/Y)","radar.profile_polar_v1":"Полярная цель (дальность/угол)","radar.profile_range_v1":"Только дальность","radar.profile_zones_v1":"Состояния зон","radar.profile_presence_v1":"Только присутствие","radar.room":"Комната радара","radar.room_choose":"Выберите комнату","radar.target":"Цель {n}","radar.axis_x":"Сущность координаты X","radar.axis_y":"Сущность координаты Y","radar.add_target":"Добавить слот цели","radar.range_channel":"Канал дальности {n}","radar.add_range":"Добавить канал дальности","radar.presence_gate":"Сущность присутствия для слота","radar.swap_axes":"Поменять оси X и Y местами","radar.axis_x_sign":"Направление X","radar.axis_y_sign":"Направление Y","radar.distance_source":"Сущность дальности","radar.angle_source":"Сущность угла","radar.angle_unit":"Единица угла","radar.degrees":"Градусы","radar.radians":"Радианы","radar.angle_zero":"Направление нулевого угла","radar.angle_forward":"Вперёд","radar.angle_right":"Вправо","radar.angle_clockwise":"Угол растёт по часовой стрелке","radar.zone_source":"Сущность зоны","radar.occupancy_source":"Сущность присутствия","radar.count_source":"Сущность количества целей","radar.availability_source":"Сущность доступности","radar.source_choose":"Выберите сущность","radar.source_optional":"Необязательно","radar.source_missing":"сейчас недоступна","radar.saved_unsupported":"Сохранённая настройка радара не поддерживается или неполна. Она неактивна; удалите её либо обновите House Plan перед повторной настройкой.","radar.occupancy":"Присутствие (вкл/выкл)","radar.count":"Количество","radar.mount":"Положение и направление","radar.mount_hint":"Это физическое положение датчика. Перемещение его декоративного маркера не меняет установку.","radar.heading":"Направление, °","radar.range_cm":"Дальность, см","radar.fov_deg":"Угол обзора, °","radar.unit":"Единица источника","radar.mirror":"Отразить ось влево/вправо","radar.remove":"Удалить настройки радара","radar.invalid":"Перед сохранением заполните комнату, источники и положение радара.","radar.check_sources":"Проверить живые данные","radar.checking":"Проверяем…","radar.health":"Состояние подключения","radar.live_summary":"Текущих целей: {targets}; дуг дальности: {ranges}","radar.health_ok":"Актуальные данные получены","radar.health_off":"Цели не обнаружены","radar.health_stale":"Часть координат устарела","radar.health_partial":"Часть источников актуальна, часть устарела","radar.health_restricted":"Нет доступа к одному или нескольким источникам","radar.health_incomplete":"Текущий отчёт радара неполон","radar.health_position_unavailable":"Есть присутствие, но актуальное положение недоступно","radar.health_unavailable":"Данные датчика недоступны","radar.health_needs_setup":"Требуется настроить установку","radar.health_inconsistent":"Источники передают противоречивые данные","radar.health_unknown":"Текущее состояние неизвестно","radar.health_disabled":"Радар отключён","radar.error_invalid_radar":"Проверьте настройки радара.","radar.error_invalid_selection":"Выберите существующую комнату и допустимые источники.","radar.error_source_restricted":"Нет доступа ко всем выбранным источникам.","radar.error_rate_limited":"Слишком много запросов. Повторите чуть позже.","radar.error_not_ready":"Обработка данных радара ещё не готова.","radar.error_conflict":"План изменился. Откройте настройку радара заново и повторите попытку.","radar.error_source_unavailable":"Один или несколько выбранных источников радара недоступны.","radar.error_unsupported_capability":"Установленная интеграция не поддерживает эту возможность радара.","radar.report_age":"{seconds} с назад","space.show_lqi":"Сигнал Zigbee рядом с устройствами","gs.light_none":"Нет источников света","mode.plan":"Редактор плана","mode.devices":"Редактор устройств","display.value":"Значение + состояние","marker.subarea":"без зоны, вручную","device.new":"Новое устройство — откройте его редактор, чтобы снять отметку","opening.unlock_action":"Открыть замок","opening.lock_action":"Закрыть замок","opening.lock_pending":"Выполняется…","title.close_editor":"Закрыть редактор (вернуться к просмотру)","title.add_device":"Добавить устройство на план","devbar.add":"Добавить","devbar.rules":"Правила иконок","device_inbox.button":"Устройства","device_inbox.title":"Устройства на плане","device_inbox.search":"Поиск по устройствам, сущностям и интеграциям…","device_inbox.add_virtual":"Добавить виртуальное устройство","device_inbox.tab_on_plan":"На плане","device_inbox.tab_available":"Доступны","device_inbox.tab_hidden":"Скрытые","device_inbox.tab_readd":"Доступны снова","device_inbox.only_new":"Только новые","device_inbox.show_entities":"Показывать сущности","device_inbox.show_hidden":"Показывать скрытые на плане","device_inbox.show_hidden.help":"Временно показывает на плане скрытые и деактивированные маркеры служебными призраками только в редакторе устройств. Сохранённая видимость устройств не меняется.","device_inbox.show_hidden.help.aria":"Подсказка: показывать скрытые устройства на плане","device_inbox.new":"Новое","device_inbox.find":"Найти на плане","device_inbox.edit":"Настроить","device_inbox.hide":"Скрыть","device_inbox.show":"Показать","device_inbox.add":"Добавить","device_inbox.readd":"Добавить заново","device_inbox.hide_available":"Скрыть из списка","device_inbox.show_more":"Показать ещё","device_inbox.more_actions":"Другие действия","device_inbox.find_hidden_hint":"Сначала включите «Показывать скрытые на плане»","device_inbox.show_disabled":"Перед показом активируйте эту привязку в Home Assistant","device_inbox.empty_on_plan":"На плане пока нет подходящих устройств.","device_inbox.empty_available":"Нет доступных устройств для добавления.","device_inbox.empty_hidden":"Скрытых устройств нет.","device_inbox.empty_readd":"Нет удалённых устройств, доступных для повторного добавления.","device_inbox.reason_visible_auto":"Найдено автоматически","device_inbox.reason_visible_explicit":"Добавлено явно","device_inbox.reason_manual_hidden":"Скрыто пользователем","device_inbox.reason_automatic_hidden":"Скрыто автоматически","device_inbox.reason_service_entry":"Служебная запись реестра","device_inbox.reason_excluded_integration":"Исключена интеграция «{integration}»","device_inbox.reason_excluded_domain":"Непространственный тип сущности","device_inbox.reason_grouped_light":"Представлено группой света комнаты","device_inbox.reason_represented_by_parent":"Представлено родительским устройством","device_inbox.reason_removed":"Ранее удалено с плана","device_inbox.reason_available":"Можно добавить на план","device_inbox.reason_no_bound_room":"Зона HA не связана с комнатой плана","device_inbox.status_ha_disabled":"Отключено в Home Assistant","device_inbox.status_orphaned":"Привязка больше не найдена в Home Assistant","device_inbox.status_unverified":"Реестр Home Assistant временно недоступен","device_inbox.saved":"Список устройств обновлён","device_inbox.filters_excluded":"Исключённые интеграции","device_inbox.filters_group_lights":"Объединять светильники комнаты в один маркер","device_inbox.filters_preview_appear":"появится: {count}","device_inbox.filters_preview_hide":"скроется: {count}","device_inbox.filters_preview_lights":"затронет светильников: {count}","device_inbox.filters_reset":"Вернуть рекомендуемые","device_inbox.filters_save":"Сохранить фильтры","device_inbox.filters_search_ph":"Добавить интеграцию…","device_inbox.filters_title":"Фильтры обнаружения","space.roomcard_section":"Карточки комнат","space.label_temp":"Температура","space.label_hum":"Влажность","space.label_lqi":"Средний Zigbee-сигнал","space.label_light":"Свет вкл/выкл","roomcard.light_on":"Вкл","roomcard.light_off":"Выкл","roomcard.light_partial":"{on} из {total}","toast.split_pick_inside":"Промежуточные точки разреза — внутри комнаты","mode.decor":"Редактор подложки","decor.select":"Выбрать","decor.line":"Линия","decor.rect":"Прямоугольник","decor.ellipse":"Овал","decor.text":"Надпись","decor.erase":"Стереть","decor.erase_confirm_title":"Стереть объект?","decor.color":"Цвет","decor.width":"Толщина линии","decor.line_style":"Стиль линии","decor.line_style_solid":"Сплошная","decor.line_style_dashed":"Пунктирная","decor.fill":"Заливка","decor.fill_color":"Цвет заливки","decor.length":"Длина","decor.size":"Размер","decor.flip_h":"Отзеркалить по горизонтали","decor.flip_v":"Отзеркалить по вертикали","decor.angle":"Угол поворота, °","decor.text_size":"Размер текста","decor.backdrop_properties":"Свойства картинки-подложки","decor.text_title":"Надпись","decor.object_title":"Редактирование: {kind}","decor.text_label":"Текст","decor.live_group":"Вставить переменную HA","decor.live_entity":"Сущность","decor.live_entity_ph":"выберите сущность","decor.live_attr":"Значение","decor.live_attr_ph":"выберите состояние или атрибут","decor.live_state":"Состояние","decor.backdrop":"Картинка-подложка","decor.backdrop_hint":"Тяните картинку — перемещение; угол — размер; верхнюю ручку — поворот. Shift меняет пропорции или снимает шаг угла.","decor.backdrop_reset":"Вернуть картинку","decor.backdrop_reset_done":"Картинка вернулась на своё место и в свой размер","marker.icon_auto":"Авто: {icon} (по правилам иконок; выберите свою, чтобы заменить)","marker.icon_pin_auto":"Закрепить","mode.plan_tip":"Редактор плана — геометрия дома: рисование и объединение/разделение комнат, привязка к зонам HA, двери, окна и ворота, карточки комнат, масштаб","mode.devices_tip":"Редактор устройств — всё про значки: перетаскивание, клик — настройка привязки/иконки/отображения, виртуальные устройства, правила иконок","mode.decor_tip":"Редактор подложки — чисто визуальный декор под планом: линии, прямоугольники, овалы и надписи, не реагирующие на клики","space.glow_enabled":"Свечение источников света","gs.glow_group":"Свечение источников света","gs.glow_base":"Темнота дома","gs.glow_light":"Цвет света по умолчанию / интенсивность","gs.wall_fill":"Цвет заливки стен","gs.glow_radius":"Радиус свечения","gs.glow_radius.help":"Задаёт общий радиус светового пятна в метрах или футах; персональный радиус устройства заменяет это значение.","gs.glow_radius.help.aria":"Подсказка: общий радиус свечения","gs.unit_m":"м","gs.unit_ft":"фут","marker.controls_label":"Управляет другими источниками света","marker.controls.help":"При действии «Переключить состояние» перечисленные источники переключаются вместе с этим маркером. Их световые пятна остаются у собственных маркеров, а эта связь сама по себе не делает управляющий маркер источником света.","marker.controls.help.aria":"Подсказка: управление другими источниками света","marker.controls_filter":"Поиск ламп и выключателей…","info.controls":"Управляет","marker.glow_radius_label":"Радиус свечения","marker.glow_radius.help":"Задаёт радиус свечения в метрах или футах; пустое значение использует радиус из общих настроек.","marker.glow_radius.help.aria":"Подсказка: радиус свечения","markup.wallthick":"Толщина","markup.select":"Выбрать","title.markup_wallthick":"Толщина — клик по стене задаёт толщину от 0 до 100 см.","markup.hint_wallthick":"клик по стене · Esc закрывает без применения","wallthick.field":"Толщина","wallthick.unit_cm":"см","wallthick.unit_in":"дюйм","wallthick.apply_room":"Применить ко всем стенам комнаты","markup.draw_wall_title":"Толщина каждого нового сегмента стены (0–100 см). Общие стены сохраняют существующее значение.","room.queue_progress":"Комната {current} из {total}","toast.wall_rooms_saved":"Создано комнат: {n}","toast.wall_chain_saved":"Цепочка стен сохранена","toast.wallthick_pick":"Кликните по стене","toast.wallthick_set":"Толщина стены задана","toast.wallthick_cleared":"Толщина стены убрана","toast.physical_range":"Введите значение от {min} до {max} {unit}","toast.zero_wall_opening_conflict":"Сначала удалите проём на этом участке стены.","toast.zero_wall_ambiguous":"Не удалось однозначно выбрать участок стены. Уточните геометрию узла.","toast.zero_wall_migration_blocked":"Пространство не преобразовано: {reason}. Данные не изменены.","toast.physical_angle":"Введите угол поворота от 0° до 90°, не включая 90°","toast.physical_limit":"В пространстве достигнут лимит объектов этого типа","toast.geometry_unsafe":"Изменение отменено: геометрию стен нельзя безопасно построить.","junction.limit_angle":"Слишком острый угол между стенами: {actual}°, минимум {limit}°.","junction.limit_valence":"Слишком много стен в одном узле: {actual}, максимум {limit}.","junction.limit_length":"Слишком короткий участок стены: {actual} см, минимум {limit} см.","junction.limit_distance":"Стены и узлы слишком близко: {actual} см, минимум {limit} см.","junction.limit_clearance":"Внутри комнаты не остаётся места: {actual} см², минимум {limit} см².","junction.limit_check_failed":"Проверку стыков выполнить не удалось — изменение не сохранено","toast.wall_model_migration_blocked":"Не удалось обновить модель стен: {reason}. План не изменён. Запустите «Оптимизировать планы»; если ошибка повторится, исправьте конфликтующую геометрию стен.","toast.wall_model_client_outdated":"Обновите карточку и перезагрузите страницу перед редактированием плана.","wall_model.reason.invalid-room":"некорректный контур комнаты","wall_model.reason.zero-length":"отрезок стены нулевой длины","wall_model.reason.third-owner":"стена принадлежит более чем двум комнатам","wall_model.reason.duplicate-id":"конфликт идентификаторов стен","wall_model.reason.thickness-conflict":"конфликт значений толщины стены","wall_model.reason.opening-host":"проём нельзя однозначно привязать к стене","toast.delete_room_pick":"Кликните внутри комнаты, которую нужно удалить","toast.plan_snap_ambiguous":"Увеличьте масштаб, чтобы выбрать узел стены","toast.wall_repair_ambiguous":"У контура несколько возможных соединений. Увеличьте масштаб и соедините стены явно.","toast.wall_repair_too_large":"Разрыв больше 2 см. Соедините стены перед созданием комнаты.","toast.wall_repair_changed":"Геометрия стен изменилась. Попробуйте создать комнату ещё раз.","toast.opening_on_zero_wall":"Проёмы на стене нулевой толщины запрещены","marker.from_ha_option":"Выбрать из списка HA","marker.show_entities":"Показывать сущности","marker.show_entities_tip":"Добавляет в список не только устройства, но и все их сущности","marker.pick_ph":"Выберите устройство…","room.open_area":"Открыть зону в HA","room.fit_action":"Вписать комнату {name}","view.volumetric":"Объёмный вид","view.flat":"Плоский вид","kiosk.title":"Размеры на этом экране","kiosk.hint":"Хранится только на этом устройстве — у каждого настенного планшета или ТВ свои удобные размеры.","kiosk.icon_scale":"Размер значков устройств","kiosk.font_scale":"Размер текста карточек комнат","editor.kiosk":"Режим настенного устройства (киоск)","editor.cycle":"Автосмена пространств каждые N секунд (киоск, 0 = выкл)","room.settings_title":"Настройки комнаты","room.fill_label":"Заливка в ЭТОЙ комнате","fill.inherit":"Как у пространства","room.custom_fill_space":"Цвет пространства","room.custom_fill_own":"Цвет комнаты","room.temp_range_label":"Диапазон комфорта","room.temp_range_min":"Нижняя граница комфортной температуры","room.temp_range_max":"Верхняя граница комфортной температуры","room.temp_range_reset":"Как у пространства","room.temp_range.help":"Диапазон применяется только к этой комнате. Пустое поле наследует соответствующую границу пространства; если границы поменялись местами, House Plan использует меньшую как нижнюю, а большую как верхнюю.","room.temp_range.help.aria":"О диапазоне комфорта комнаты","room.temp_src_label":"Источник температуры","room.hum_src_label":"Источник влажности","room.src_average":"Среднее по датчикам комнаты","room.src_pick":"Конкретное устройство или сущность","room.src_ph":"Выберите источник…","toast.room_updated":"Комната обновлена","space.card_font":"Размер шрифта карточек","room.sizes_section":"Размеры шрифтов","room.group_basics":"Основное","room.group_basics.help":"Область связывает комнату с зоной Home Assistant: из неё берутся датчики. Без области комната остаётся геометрией.","room.group_basics.help.aria":"Подсказка: имя и область комнаты","room.group_fill":"Заливка","room.group_fill.help":"Заливка этой комнаты перекрывает выбранную для пространства; «Свой цвет» хранится только здесь.","room.group_fill.help.aria":"Подсказка: заливка комнаты","room.group_sources":"Источники","room.group_sources.help":"По умолчанию комната усредняет свои датчики. Выбранный датчик заменяет среднее везде: подсказка, карточка, заливка.","room.group_sources.help.aria":"Подсказка: источники температуры и влажности","room.sizes_section.help":"Масштабы действуют только в этой комнате и умножаются на общий масштаб карточки из настроек пространства.","room.sizes_section.help.aria":"Подсказка: размеры шрифтов комнаты","room.name_scale":"Размер названия","room.label_scale":"Размер подписей","preview.room_name":"Гостиная","toast.cfg_reload_failed":"Не удалось перечитать план с сервера: {err}","toast.locale_load_failed":"Не удалось загрузить языковой пакет. До перезагрузки страницы используется английский.","toast.furniture_art_load_failed":"Не удалось загрузить изображения мебели. Обновите страницу, чтобы их показать.","room.settings_short":"Настройки комнаты","room.unnamed":"Комната без имени","marker.use_climate_temp":"Учитывать температуру устройства в комнате","marker.use_climate_temp_tip":"Добавляет current_temperature кондиционера или термостата в среднюю температуру комнаты. Внешний бейдж со значением настраивается отдельно ниже.","marker.value_badge_title":"Бейдж со значением","marker.value_badge.help":"Показывает одно выбранное значение рядом со значком. Не влияет на комнатные показатели, свет, Glow и действие по нажатию.","marker.value_badge.help.aria":"Подсказка: бейдж со значением устройства","marker.value_badge_enabled":"Отображать бейдж со значением","marker.value_badge_source":"Значение","marker.value_badge_source.help":"Выберите конкретное состояние, поддерживаемый атрибут или производное значение этого устройства.","marker.value_badge_source.help.aria":"Подсказка: источник значения бейджа","marker.value_badge_position":"Расположение","marker.value_badge_position.help":"Выбранная сторона сохраняется постоянно и не переворачивается автоматически у края плана.","marker.value_badge_position.help.aria":"Подсказка: расположение бейджа","marker.value_badge_right":"Справа","marker.value_badge_bottom":"Снизу","marker.value_badge_left":"Слева","marker.value_badge_top":"Сверху","marker.value_badge_empty":"У этого устройства нет доступных значений","marker.value_badge_static":"Статичный значок не показывает живые значения. Настройка сохранится.","marker.value_badge_missing":"Источник недоступен","marker.value_badge_missing_hint":"Сохранённый источник сейчас недоступен. Можно сохранить его, отключить бейдж или выбрать другой.","marker.value_badge_duplicate":"То же значение уже показано внутри значка.","marker.value_badge_state":"Состояние · {name}","marker.value_badge_marker_state":"Состояние источника света · {name}","marker.value_badge_lqi":"Качество Zigbee-сигнала (среднее)","marker.value_badge_attr_current_temperature":"Текущая температура · {name}","marker.value_badge_attr_temperature":"Целевая температура · {name}","marker.value_badge_attr_current_humidity":"Текущая влажность · {name}","marker.value_badge_attr_humidity":"Влажность · {name}","marker.value_badge_attr_current_position":"Положение · {name}","marker.value_badge_attr_percentage":"Скорость · {name}","marker.value_badge_attr_brightness":"Яркость · {name}","marker.value_badge_attr_volume_level":"Громкость · {name}","marker.value_badge_attr_battery_level":"Заряд батареи · {name}","marker.value_badge_attr_fan_speed":"Скорость вентилятора · {name}","marker.value_source":"Источник значения","marker.value_source.help":"Выберите, что заменит значок. Действие по нажатию не изменится.","marker.value_source.help.aria":"Подсказка: источник значения внутри значка","marker.value_source_auto":"Автоматически (как раньше)","marker.value_source_missing_hint":"Сохранённый источник сейчас недоступен. До его восстановления или выбора другого значения внутри будет показано —.","marker.light_role_label":"Является источником света","marker.light_role.help":"«Авто» использует фактическую роль привязанного устройства, «Всегда» принудительно создаёт собственный источник, а «Никогда» исключает его; связанные лампы выше остаются независимыми.","marker.light_role.help.aria":"Подсказка: является ли устройство источником света","marker.light_role_auto_yes":"Автоматически (источник света)","marker.light_role_auto_no":"Автоматически (не источник света)","marker.light_entity_label":"Ведущая сущность света","marker.light_entity.help":"Для составного устройства выберите сущность, состояние, цвет и яркость которой представляют этот источник на плане. Автоматический вариант сохраняет совместимость со старыми планами.","marker.light_entity.help.aria":"Подсказка: ведущая сущность света","marker.light_entity_auto":"Автоматически ({entity})","marker.light_entity_none":"нет управляемой сущности","marker.light_entity_missing":"Сохранённая сущность {entity} недоступна. Временно используется {fallback}; выбор восстановится, если сущность вернётся.","marker.toggle_entity_label":"Переключаемая сущность","marker.toggle_entity.help":"Для составного устройства выберите собственную лампу или переключатель, которой управляет нажатие. Автоматический вариант сохраняет прежние правила цели и не зависит от ведущей сущности света.","marker.toggle_entity.help.aria":"Подсказка: переключаемая сущность","marker.toggle_entity_auto":"Автоматически ({entity})","marker.toggle_entity_none":"нет собственной управляемой сущности","marker.toggle_entity_missing":"Сохранённой сущности {entity} больше нет среди выбираемых каналов этого маркера. Временно используется {fallback}; выбор восстановится, если сущность вернётся.","marker.glow_color_label":"Цвет и яркость свечения","marker.glow_mode.help":"Используйте данные источника, задайте только цвет или зафиксируйте цвет и яркость. Минимум — 1%; чтобы отключить источник, выберите «Никогда».","marker.glow_mode.help.aria":"Подсказка: цвет и яркость свечения","marker.glow_mode_auto":"Из источника","marker.glow_mode_color":"Задать цвет","marker.glow_mode_fixed":"Цвет и яркость","marker.glow_color":"Цвет свечения","marker.glow_brightness":"Яркость","marker.glow_disabled_never":"Настройки свечения недоступны: маркер явно исключён из источников света.","marker.glow_disabled_auto":"В автоматическом режиме у этого маркера не найден пространственный источник света.","marker.glow_disabled_no_entity":"Для пространственного источника нет активной управляемой сущности Home Assistant.","marker.glow_passive_hint":"У источника нет собственных данных Home Assistant. Задайте цвет и яркость вручную; радиус остаётся доступным.","marker.control_broken":"Сохранённый источник отсутствует или больше не отмечен как источник света","marker.control_missing_label":"Отсутствующий источник на плане","marker.control_passive":"пассивный источник","toast.marker_control_cycle":"Такая связь создаст циклическую цепочку управления светом.","toast.marker_binding_required":"Сначала выберите устройство Home Assistant, затем добавьте управляемый источник света.","confirm.unlock_title":"Открыть замок?","confirm.unlock_body":"House Plan отправит этому замку команду открытия.","toast.files_migrate_failed":"Не удалось перенести вложения к новой привязке, ссылки остались на старые файлы: {err}","space.pick_saved":"Уже загруженные","space.pick_saved_hint":"Планы, сохранённые на сервере, включая отцеплённые ранее","space.no_saved":"На сервере пока нет сохранённых планов.","space.loading":"Загрузка…","space.used_by":"используется: {list}","space.in_use":"План используется пространством — сначала отцепите его","btn.use":"Выбрать","confirm.delete_plan_title":"Удалить файл плана?","confirm.delete_plan_body":"Файл будет удалён с сервера. Это действие нельзя отменить.","toast.plans_list_failed":"Не удалось получить список планов: {err}","toast.plan_delete_failed":"Не удалось удалить план: {err}","marker.hide":"Скрыть","marker.hide_tip":"Устройство исчезнет с плана после сохранения, но продолжит участвовать в расчёте сигнала комнаты. Вернуть его можно через каталог «Устройства» в редакторе устройств.","marker.show":"Показать","marker.show_tip":"Устройство снова появится на плане после сохранения.","marker.hidden_ghost":"Устройство скрыто пользователем","marker.ha_disabled_device":"Устройство деактивировано в Home Assistant и скрыто с плана.","marker.ha_disabled_entity":"Сущность деактивирована в Home Assistant и скрыта с плана.","marker.ha_disabled_all_entities":"У устройства нет активных сущностей Home Assistant, поэтому оно скрыто с плана.","marker.ha_registry_limited":"Полный реестр Home Assistant недоступен этому пользователю. Неподтверждённый объект временно нельзя показывать или использовать.","marker.delete_tip":"Полностью удалить устройство с плана и из всех расчётов. Позже его можно добавить заново.","tap.run":"Запустить автоматизацию/скрипт/сцену","tap.none":"Ничего не делать","marker.run_target_label":"Что запускать","marker.run_search_ph":"Поиск: автоматизация, скрипт или сцена…","marker.run_target_gone":"Цель {id} не найдена — выберите заново","marker.tap_confirm":"Спрашивать подтверждение","marker.tap_confirm_tip":"Перед выполнением показать диалог подтверждения — защита от случайных нажатий.","marker.toggle_hint_single":"Цель: {name} ({id}).","marker.virtual_light_target":"Виртуальный свет: {name}.","marker.virtual_light_current":"Ручное состояние: {state} → {effect}.","marker.virtual_light_state_on":"включён","marker.virtual_light_state_off":"выключен","marker.toggle_hint_group":"Переключатся источники ({count}): {names}.","marker.toggle_hint_current":"Сейчас: {state} → {effect}.","marker.toggle_hint_group_current":"Сейчас включено {on} из {count} → {effect}.","marker.toggle_hint_skipped":"Не будут затронуты ({count}): {targets}.","marker.toggle_effect_turn_on":"включится","marker.toggle_effect_turn_off":"выключится","marker.toggle_effect_open":"откроется","marker.toggle_effect_close":"закроется","marker.toggle_effect_stop":"остановится","marker.toggle_effect_toggle":"состояние переключится","marker.toggle_skip_missing":"не найдено","marker.toggle_skip_ha_disabled":"деактивировано в HA","marker.toggle_skip_unavailable":"недоступно","marker.toggle_skip_unsupported":"переключение не поддерживается","marker.toggle_skip_secure":"заблокировано из соображений безопасности","marker.toggle_none_no_binding":"У устройства нет привязки, состояние переключать нечем. По нажатию ничего не произойдёт.","marker.toggle_none_no_actionable_entity":"У устройства нет состояния, которое можно переключить. По нажатию ничего не произойдёт.","marker.toggle_none_configured_targets_missing":"Настроенные цели сейчас недоступны. Собственная сущность устройства не будет подставлена вместо них.","marker.toggle_none_ha_disabled":"Цель деактивирована в Home Assistant и не может использоваться на плане.","marker.toggle_none_unavailable":"Цель сейчас недоступна. По нажатию ничего не произойдёт.","marker.toggle_none_unsupported":"Для этой сущности Home Assistant не предоставляет безопасного переключения. По нажатию ничего не произойдёт.","marker.toggle_none_secure":"Переключение замков, сигнализации и защитных ворот с плана заблокировано из соображений безопасности.","run.automation":"автоматизация","run.script":"скрипт","run.scene":"сцена","confirm.tap_run":"Запустить «{name}»?","confirm.tap_toggle":"Переключить «{name}»?","confirm.current_state":"Текущее состояние: {state}","confirm.expected_state":"После переключения: {state}","confirm.group_current":"включено {on} из {total}","confirm.group_all_on":"все включены","confirm.group_all_off":"все выключены","confirm.unavailable_targets":"Недоступно: {count}","confirm.expected_by_ha":"Состояние определит Home Assistant","confirm.state_on":"Включено","confirm.state_off":"Выключено","confirm.state_open":"Открыто","confirm.state_closed":"Закрыто","confirm.state_opening":"Открывается","confirm.state_closing":"Закрывается","confirm.state_stopped":"Остановлено","confirm.state_unknown":"Неизвестно","toast.run_started":"Запущено: {name}","toast.run_target_missing":"Цель запуска не найдена — проверьте настройки устройства","toast.run_target_required":"Выберите автоматизацию, скрипт или сцену","toast.tap_target_changed":"Цель действия изменилась. Повторите попытку.","toast.virtual_light_toggle_failed":"Не удалось переключить виртуальный свет: {err}","toast.value_badge_source_required":"Выберите значение для бейджа","btn.run":"Выполнить","vac.section":"Робот-пылесос: живая позиция","vac.autocal":"Настроить автоматически","vac.live":"Живая позиция на плане","vac.trail":"Показывать путь робота","vac.autocal_no_rooms":"Интеграция не отдаёт список комнат — откройте «Подогнать вручную»","vac.route_warn_unmapped":"Робот убирает на карте, которая не сопоставлена ни одному этажу","vac.route_warn_needs_calibration":"Карта сопоставлена этажу, но не откалибрована","vac.route_warn_ambiguous":"Две карты неразличимы — этаж не выбран","vac.route_warn_missing_space":"Пространство этой карты удалено","vac.autocal_no_match":"Не совпали имена комнат (нужно ≥3 общих) — откройте «Подогнать вручную»","vac.autocal_done":"Готово: привязка по {rooms} комнатам. Запустите уборку и проверьте","vac.cal_need_pos":"Робот сейчас не отдаёт координаты — запустите уборку и поставьте на паузу","vac.cal_done":"Калибровка сохранена. Запустите уборку и проверьте","vac.cal_cancelled":"Калибровка отменена","vac.fit":"Подогнать вручную","vac.fit_hint":"Перетащите карту робота на место, растяните за уголки","vac.fit_rotate":"Повернуть 90°","vac.fit_mirror":"Отразить","vac.trail_never":"Не показывать никогда","vac.trail_cleaning":"Во время уборки","vac.trail_always":"Показывать всегда","gs.bg_color":"Цвет фона вокруг плана","gs.bg_default":"Как в теме","gs.bg_mode":"Фон плана","gs.bg_mode.help":"«Следует за Солнцем» использует sun.sun, а при недоступности — локальные часы браузера; статичный режим всегда показывает выбранный цвет.","gs.bg_mode.help.aria":"Подсказка: общий фон плана","gs.bg_static":"Статичный цвет","gs.bg_daynight":"Следует за Солнцем","gs.sun_group":"Солнце","gs.sun_missing":"Сущность sun.sun не найдена — фон следует локальным часам, а оконные лучи недоступны.","gs.north":"Север на плане","gs.north.help":"Угол отсчитывается по часовой стрелке от верхней вертикали плана; север нужен для оконных лучей, а не для фона «Следует за Солнцем».","gs.north.help.aria":"Подсказка: общее направление севера","gs.north_ph":"не задан","gs.north_clear":"Сбросить","gs.north_letter":"С","gs.sun_rays":"Солнце в окнах","gs.sun_ray_origin":"Лучи солнца","gs.sun_ray_origin.inner":"От внутренних углов окон","gs.sun_ray_origin.outer":"От внешних углов окон","gs.about_version":"Houseplan Card v{v}","gs.about_github":"GitHub · документация и issues","gs.about_telegram":"Чат в Telegram","support.title":"Помощь и обратная связь","space.bg_color":"Цвет фона вокруг плана","space.bg_inherit":"Наследовать общий","space.bg_mode":"Фон плана","space.bg_mode.help":"Выберите наследование общего фона либо переопределите это пространство статичным цветом или режимом «Следует за Солнцем».","space.bg_mode.help.aria":"Подсказка: фон пространства","space.north":"Север на плане","space.north.help":"Переопределяет общий север для этого пространства; угол отсчитывается по часовой стрелке от верхней вертикали плана и используется оконными лучами.","space.north.help.aria":"Подсказка: север для пространства","space.sun_rays":"Солнце в окнах","space.sun_inherit":"Общие настройки","space.sun_on":"Вкл","space.sun_off":"Выкл","canvas.far_objects":"Объектов далеко от плана: {n}","canvas.show_far":"Показать","canvas.home_tip":"План там — нажмите, чтобы вписать","gs.grid_group":"Обслуживание планов","gs.align_all":"Оптимизировать планы","gs.align_title":"Оптимизировать планы","gs.align_none":"Все планы уже используют актуальную и оптимальную модель данных.","gs.optimize_no_automatic_changes":"Автоматических изменений нет. Проверьте пункты ниже.","gs.align_count":"Сдвинется элементов: {n} из {total}, максимум на {cm} см.","gs.align_where":"Наибольший сдвиг — в пространстве «{s}».","gs.align_turned":"Проёмов с исправлением угла: {n}.","gs.align_preflight_failed":"Не удалось безопасно проверить геометрию следующих пространств: {spaces}{more}.","gs.align_preflight_hint":"Планы не изменены. Скопируйте диагностику кнопкой ниже и приложите её к отчёту об ошибке вместе с экспортом пространства.","gs.preflight_reason_prepare-exception":"Не удалось подготовить геометрию пространства (исключение при сборке модели)","gs.preflight_reason_wall-null":"Тело стен не построилось (объединение вернуло пустоту)","gs.preflight_reason_wall-degraded-extra":"Тело стен деградировало с лишней геометрией","gs.preflight_reason_wall-failed-core":"Ядро тела стен не собралось","gs.preflight_reason_wall-exception":"Построение стен упало с исключением","gs.preflight_reason_floor-null":"Контур пола не построился","gs.preflight_reason_floor-exception":"Построение пола упало с исключением","gs.preflight_copy":"Скопировать диагностику","gs.preflight_copied":"Диагностика скопирована","gs.preflight_update_hint":"Версии карточки и интеграции различаются — обновите House Plan и повторите.","gs.align_preflight_space":"Пространство {n}","gs.align_preflight_more":" и ещё {n}","gs.optimize_changes":"Миграций модели: {m}; обновлено пространств: {c}; устранён шум координат: {p}; объединено отрезков реальных стен: {w}; объединено отрезков стен нулевой толщины: {s}; независимых: {i}.","gs.zero_walls_migrated":"Преобразовано виртуальных участков: {n}.","gs.wall_segments_migrated":"Стабилизировано сегментов стен: {n}.","gs.room_drafts_migrated":"Незавершённые контуры преобразованы в обычные стены: {drafts}; отрезков: {segments}.","gs.optimize_lattice_summary":"Канонизировано шумовых значений координат: {n}; максимальный сдвиг: {cm} см.","gs.optimize_lattice_space":"{space}: канонизировано значений координат: {n}; оставлено значений вне сетки: {far}.","gs.optimize_coincident_partitions":"Скрытые участки независимых стен поглощены стенами комнат: {n}.","gs.optimize_openings_rehosted":"Проёмы перепривязаны к стенам комнат: {n}.","gs.optimize_walls_straightened":"Выпрямлено стен: {n}; максимальное перемещение: {cm} см.","gs.optimize_walls_straightened_where":"Максимальная правка стены: {s}.","gs.optimize_walls_straighten_skipped":"Оставлено почти осевых стен, которые нельзя безопасно выпрямить: {n}.","gs.optimize_glow_migration":"Старый Glow: пространств — {spaces} → без заливки данных + независимый Glow; комнат — {rooms} → наследуемая заливка + независимый Glow.","gs.optimize_references":"Исправлено ссылок: пространства — {spaces}; комнаты — {rooms}; позиции — {positions}; устройств отвязано от отсутствующих пространств — {detached}.","gs.optimize_reference_more":", и ещё {n}","gs.optimize_orphans_removed":"Убрано забытых записей: {total} — подписи комнат: {rooms}; устройства: {devices}; групповые метки: {groups}. Все они принадлежали пространствам, удалённым ранее.","gs.optimize_live_positions":"Старые позиции в удалённых пространствах принадлежат существующим объектам: {n}{names}. Они будут сохранены.","gs.optimize_live_positions_remove":"Старые позиции в удалённых пространствах принадлежат существующим объектам: {n}{names}. Они выбраны для удаления.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Убрать старые позиции","gs.optimize_live_keep":"Сохранить старые позиции","gs.optimize_live_selected":"Старые позиции будут убраны после применения оптимизации.","gs.optimize_unverified":"Не удалось безопасно проверить позиций: {n}. Они оставлены без изменений.","gs.optimize_registry_limited":"Для безопасной проверки нужен полный доступ администратора к реестрам Home Assistant.","gs.optimize_vacuum_warning":"Сопоставления комнат пылесоса требуют проверки: {n}.","gs.optimize_details":"Подробности","gs.optimize_details_more":"И ещё записей: {n}.","gs.optimize_detail_removed":"будет удалено","gs.optimize_detail_live":"будет сохранено","gs.optimize_detail_unverified":"не проверено","gs.optimize_detail_room_label":"подпись комнаты","gs.optimize_detail_device":"устройство","gs.optimize_detail_group":"групповая метка","gs.optimize_detail_unknown":"неизвестный владелец","gs.optimize_detail_item":"{status}: {kind} {id}; прежнее пространство {space}","gs.align_warn":"Элементы, намеренно поставленные между узлами, будут сдвинуты. После операции доступна одна отмена — только до следующего изменения плана.","gs.align_run":"Оптимизировать","gs.align_done":"Планы оптимизированы: сдвинуто элементов — {n}, обслужено записей — {m}, исправлено ссылок — {r}","gs.optimize_undo":"Отменить последнюю оптимизацию","gs.optimize_undone":"Последняя оптимизация отменена","decor.furniture":"Мебель","decor.image":"Изображение","decor.image_title":"Свои изображения","decor.image_upload":"Загрузить изображение","decor.image_replace":"Заменить изображение","decor.image_uploading":"Загрузка…","decor.image_asset":"Файл изображения","decor.image_pick_hint":"Загрузите изображение или выберите уже используемое в House Plan.","decor.image_place_hint":"Кликните по плану, чтобы разместить изображение.","decor.image_none":"Загруженных изображений пока нет.","decor.image_unavailable":"Изображение недоступно","decor.image_used":"Используется в объектах: {n}","decor.image_upload_failed":"Не удалось загрузить изображение: {err}","decor.image_error_capacity":"Хранилище пользовательских изображений заполнено.","decor.image_in_use":"Перед удалением файла удалите все размещённые копии.","decor.image_delete_title":"Удалить файл изображения?","decor.image_delete_message":"Удалить «{name}» из House Plan? Это действие нельзя отменить.","furn.title":"Библиотека мебели","furn.symbol":"Символ","furn.group_furniture":"Мебель","furn.group_appliance":"Техника","furn.group_sanitary":"Сантехника","furn.group_other":"Прочее","furn.width":"Ширина","furn.depth":"Глубина","furn.back_to_categories":"Все категории","furn.pick_hint":"Выберите категорию, затем символ.","furn.place_hint":"Кликните по плану — предмет встанет к ближайшей стене. Shift — свободно.","furn.cat_air_conditioner":"Кондиционеры","furn.cat_armchair":"Кресла","furn.cat_bathtub":"Ванны","furn.cat_bed":"Кровати","furn.cat_bidet":"Биде","furn.cat_boiler":"Бойлеры","furn.cat_chair":"Стулья","furn.cat_coffee_table":"Журнальные столы","furn.cat_computer":"Компьютер","furn.cat_cooktop":"Варочные панели","furn.cat_dining_table":"Обеденные столы","furn.cat_dishwasher":"Посудомоечные машины","furn.cat_dryer":"Сушильные машины","furn.cat_fireplace":"Камины","furn.cat_fridge":"Холодильники","furn.cat_hood":"Вытяжка","furn.cat_kitchen_cabinet":"Кухонные шкафы","furn.cat_kitchen_sink":"Кухонные мойки","furn.cat_nightstand":"Тумбы","furn.cat_oven":"Духовка","furn.cat_plant":"Растения","furn.cat_rug":"Ковры","furn.cat_shelving":"Стеллажи","furn.cat_shower":"Душевые","furn.cat_sink":"Раковины","furn.cat_sofa":"Диваны","furn.cat_stairs":"Лестницы","furn.cat_toilet":"Унитазы","furn.cat_tv":"Телевизоры","furn.cat_wardrobe":"Шкафы","furn.cat_washer":"Стиральные машины","furn.cat_work_table":"Рабочие столы","furn.sym_cactus":"Кактус","furn.sym_computer":"Компьютер","furn.sym_hood":"Вытяжка","furn.sym_oven":"Духовка","furn.sym_sofa":"Диван двухместный","furn.sym_sofa_three_seat":"Диван трёхместный","furn.sym_sofa_corner_right":"Угловой диван, правый","furn.sym_armchair":"Кресло мягкое","furn.sym_armchair_office":"Кресло офисное","furn.sym_coffee_table":"Журнальный стол, прямоугольный","furn.sym_coffee_table_round":"Журнальный стол, круглый","furn.sym_coffee_table_oval":"Журнальный стол, овальный","furn.sym_coffee_table_rounded":"Журнальный стол, скруглённый","furn.sym_table_dining":"Обеденный стол, прямоугольный","furn.sym_table_round":"Круглый стол","furn.sym_table_dining_oval":"Обеденный стол, овальный","furn.sym_table_dining_rounded":"Обеденный стол, скруглённый","furn.sym_chair":"Стул","furn.sym_chair_bar":"Барный стул","furn.sym_desk":"Рабочий стол, прямоугольный","furn.sym_desk_corner":"Рабочий стол, угловой","furn.sym_bed_double":"Двуспальная кровать","furn.sym_bed_single":"Односпальная кровать","furn.sym_nightstand":"Тумба прикроватная","furn.sym_cabinet_tv":"Тумба под телевизор","furn.sym_cabinet_shoe":"Тумба для обуви","furn.sym_cabinet_sink":"Тумба под раковину","furn.sym_wardrobe":"Шкаф гардеробный","furn.sym_bookshelf":"Шкаф книжный","furn.sym_wall_unit":"Шкаф-стенка","furn.sym_kitchen_floor":"Кухонный напольный модуль","furn.sym_kitchen_floor_corner":"Кухонный напольный угловой модуль","furn.sym_kitchen_wall":"Кухонный навесной модуль","furn.sym_kitchen_wall_corner":"Кухонный навесной угловой модуль","furn.sym_shelf_floor":"Стеллаж напольный","furn.sym_shelf_wall":"Полка настенная","furn.sym_fridge":"Холодильник","furn.sym_stove":"Варочная панель, 4 конфорки","furn.sym_cooktop_two":"Варочная панель, 2 конфорки","furn.sym_dishwasher":"Посудомоечная машина","furn.sym_washer":"Стиральная машина","furn.sym_dryer":"Сушильная машина","furn.sym_tv":"Телевизор на подставке","furn.sym_tv_wall":"Телевизор на кронштейне","furn.sym_ac":"Кондиционер","furn.sym_water_heater":"Бойлер","furn.sym_toilet":"Унитаз напольный","furn.sym_toilet_built_in":"Унитаз встроенный","furn.sym_bathtub":"Ванна прямоугольная","furn.sym_bathtub_corner":"Ванна угловая","furn.sym_shower":"Душ","furn.sym_sink":"Раковина","furn.sym_kitchen_sink":"Кухонная мойка одинарная","furn.sym_kitchen_sink_double":"Кухонная мойка двойная","furn.sym_bidet":"Биде напольное","furn.sym_bidet_built_in":"Биде встроенное","furn.sym_stairs":"Лестница","furn.sym_fireplace":"Камин","furn.sym_plant":"Растение","furn.sym_rug":"Ковёр","common.yes":"Да","common.no":"Нет","vac.diag_source":"Источник","vac.diag_platform":"Интеграция","vac.diag_status":"Статус","vac.diag_position":"Позиция","vac.diag_rooms":"Комнаты","vac.diag_rooms_value":"{total} · совпало имён: {matched} · {readiness}","vac.autocal_ready":"автокалибровка доступна","vac.autocal_not_ready":"нужно 3 совпавших имени","vac.diag_path":"Путь интеграции","vac.diag_map":"ID карты","vac.source_none":"не выбран","vac.source_status_ok":"Готов","vac.source_status_missing":"Не найден","vac.source_status_disabled":"Деактивирован в Home Assistant","vac.source_status_unavailable":"Недоступен","vac.source_status_unverified":"Нельзя проверить с текущими правами","vac.source_status_unsupported":"Нет данных позиции","vac.source_status_none":"Нет источника","vac.source_banner_missing":"Сохранённый источник больше не существует. Он не заменён автоматически: выберите другой или восстановите его в Home Assistant.","vac.source_banner_disabled":"Сохранённый источник деактивирован в Home Assistant. Активируйте его там или выберите другой.","vac.source_banner_unverified":"Текущих прав Home Assistant недостаточно для проверки источника. Привязка сохранена и не будет заменена автоматически.","vac.choose_source":"Выбрать источник","vac.source_auto":"Автоматически","vac.source_auto_hint":"Использовать совместимую сущность этого устройства","vac.all_cameras":"Все камеры","vac.all_cameras_warn":"Камера может не отдавать данные робота. Выбирайте её только если это карта вашего пылесоса.","vac.all_cameras_empty":"Других сущностей камеры не найдено.","vac.platform_unknown":"интеграция неизвестна","vac.cap_position":"позиция","vac.cap_rooms_short":"комнаты","vac.cap_path":"путь","vac.cap_map":"ID карты","vac.cap_none":"данные робота не обнаружены","vac.xcme_hint":"Включите атрибуты Xiaomi Cloud Map Extractor:","vac.documentation":"Документация","vac.residual_title":"Проверьте автокалибровку","vac.residual_message":"Совпавшие комнаты расходятся максимум на {error}. Примените приблизительную калибровку, подгоните её вручную либо отмените без изменения сохранённых настроек.","vac.apply_proposal":"Применить","gs.backup_group":"Резервная копия и перенос","backup.export_open":"Экспорт","backup.import_open":"Импорт","backup.export_title":"Экспорт House Plan","backup.import_title":"Импорт House Plan","backup.export_hint":"Выберите, должна ли копия содержать всю конфигурацию House Plan или только текущее пространство.","backup.full":"Полная копия","backup.current_space":"Текущее пространство","backup.current_space_title":"Текущее пространство: {title}","backup.no_current_space":"Нет текущего пространства","backup.plan_only":"Только планировка","backup.plan_only_hint":"Сохранить комнаты, стены, проёмы, декор и позиции подписей комнат без устройств и привязок Home Assistant.","backup.plan_only_preview":"Файл содержит только планировку","backup.privacy_warning":"Архив сохраняет названия, идентификаторы Home Assistant и точные координаты. Внутренние планы и вложения указываются ссылками, но не вкладываются; текущие состояния и маршруты пылесосов не включаются.","backup.download":"Скачать JSON","backup.export_done":"Резервная копия скачана","backup.reading":"Проверяем резервную копию…","backup.revalidated":"После предпросмотра план изменился. Сводка обновлена — проверьте её и подтвердите ещё раз.","backup.error.support_invalid_message":"Проверьте сообщение для поддержки и повторите попытку.","backup.error.support_package_too_large":"Обезличенный пакет для поддержки превышает лимит 8 МиБ.","backup.error.support_preview_expired":"Предпросмотр вложения для поддержки истёк или больше недоступен.","backup.error.support_rate_limited":"Запрошено слишком много репортов или предпросмотров. Повторите позже.","backup.error.support_rejected":"Репорт не прошёл проверку службы поддержки.","backup.error.support_unavailable":"Закрытая служба поддержки временно недоступна.","backup.error.unauthorized":"У вас нет прав на экспорт или импорт этого плана.","backup.error.not_ready":"House Plan ещё не готов. Повторите попытку через несколько секунд.","backup.error.too_large":"Размер резервной копии превышает 8 МиБ.","backup.error.invalid_json":"Выбранный файл не является корректным JSON.","backup.error.invalid_format":"Выбранный файл не является резервной копией House Plan.","backup.error.invalid_image":"Изображение повреждено или не соответствует своему формату.","backup.error.unsupported_export_version":"Эта версия формата резервной копии не поддерживается установленной версией.","backup.error.unsupported_image":"Используйте поддерживаемое изображение PNG, JPEG, WebP или SVG.","backup.error.future_model":"Резервная копия создана в более новой версии модели данных House Plan.","backup.error.invalid_config":"Резервная копия содержит некорректную конфигурацию House Plan.","backup.error.wall_model_migration_blocked":"Не удалось безопасно обновить модель стен из резервной копии. Сначала оптимизируйте исходный план и повторите экспорт.","backup.error.invalid_layout":"Резервная копия содержит некорректные позиции объектов.","backup.error.invalid_content":"Резервная копия содержит некорректные или несогласованные ссылки на файлы.","backup.error.space_not_found":"Выбранное пространство больше не существует.","backup.error.capacity_exceeded":"Добавление этой копии превысит ограничения размера плана.","backup.error.preview_expired":"Время предпросмотра истекло. Выберите файл резервной копии заново.","backup.error.preview_owner_mismatch":"Этот предпросмотр принадлежит другому пользователю Home Assistant.","backup.error.conflict":"После предпросмотра план изменился. Проверьте обновлённую сводку.","backup.error.content_confirmation_required":"Подтвердите отсоединение недоступных локальных файлов.","backup.error.commit_failed":"Не удалось безопасно применить копию. Предыдущий план восстановлен или ожидает восстановления.","backup.error.missing_plan":"После предпросмотра исчез связанный файл плана. Проверьте копию ещё раз.","backup.error.missing_content":"После предпросмотра исчез связанный локальный файл. Проверьте копию ещё раз.","backup.error.marker_control_missing":"В резервной копии отсутствует связанный источник света на плане.","backup.error.marker_control_not_light":"Связанная цель больше не отмечена как источник света.","backup.error.marker_control_self":"Источник света не может управлять самим собой.","backup.error.marker_control_cycle":"Резервная копия содержит циклическую цепочку управления светом.","backup.error.duplicate_marker_control":"Резервная копия содержит повторяющуюся связь с источником света.","backup.error.no_backup":"Нет снимка импорта или оптимизации, который можно восстановить.","backup.error.in_use":"Элемент ещё используется","backup.error.invalid_data":"Запрос содержит некорректные данные","backup.error.invalid_light_entity":"Ведущий свет должен быть сущностью light.* или switch.*","backup.error.invalid_marker_control":"Некорректная ссылка управления маркером","backup.error.invalid_name":"Некорректное имя","backup.error.invalid_partition_opening_host":"Проём должен сохранить свою перегородку-носитель","backup.error.invalid_partition_opening_jamb_margin":"Проём не оставляет физического простенка у края стены","backup.error.invalid_passage_fields":"Открытый проход не может нести настройки двери","backup.error.invalid_space_id":"Неизвестное пространство","backup.error.invalid_toggle_entity":"Сущность переключения должна быть light.* или switch.*","backup.error.invalid_value_badge":"Некорректные настройки бейджа значения","backup.error.invalid_value_badge_attribute":"Некорректный атрибут бейджа значения","backup.error.invalid_value_badge_position":"Некорректная позиция бейджа значения","backup.error.invalid_value_badge_source":"Некорректный источник бейджа значения","backup.error.invalid_vacuum_map_route":"Проверьте сопоставление карт робота пространствам.","backup.error.invalid_value_source":"Некорректный источник значения","backup.error.invalid_value_source_attribute":"Некорректный атрибут источника значения","backup.error.io_error":"Файловая операция на сервере не удалась","backup.error.not_toggleable":"Это устройство нельзя переключить","backup.error.nothing_to_repair":"Нечего чинить","backup.error.space_in_use":"На пространство ещё есть ссылки","backup.error.value_badge_source_required":"Бейджу значения нужен источник","backup.error.wall_model_client_outdated":"План обновлён в другом месте — перезагрузите страницу","backup.same_source":"Создано на этом экземпляре Home Assistant","backup.foreign_source":"Создано на другом экземпляре Home Assistant","backup.created":"Создано: {value}","backup.versions":"Карточка {card}; интеграция {integration}; модель данных {model}","backup.count_spaces":"Пространств: {n}","backup.count_rooms":"Комнат: {n}","backup.count_walls":"Стен: {n}","backup.count_openings":"Проёмов: {n}","backup.count_decor":"Объектов декора: {n}","backup.count_markers":"Устройств: {n}","backup.count_layout":"Позиций: {n}","backup.bindings":"Привязки — устройства: {device}, сущности: {entity}, виртуальные: {virtual}; позиций без пространства: {legacy}","backup.binding_status":"Статус на целевом экземпляре — активных: {active}, деактивированных: {disabled}, отсутствующих: {missing}","backup.missing_areas":"На целевом экземпляре отсутствуют зоны: {areas}","backup.dropped_marker_links":"Связи с источниками света вне переносимого пространства пропущены: {n}.","backup.room_drafts_migrated":"Старые незавершённые контуры преобразованы в обычные стены: {drafts}; отрезков: {segments}.","backup.repaired_target_refs":"Существующих ссылок восстановлено этим импортом: {n}.","backup.preserved_unresolved_refs":"Неоднозначные ссылки сохранены без изменений: {n}.","backup.preserved_unresolved_hint":"House Plan ничего не угадывал и не удалял. После импорта запустите «Оптимизировать планы», чтобы проверить оставшиеся ссылки.","backup.import_details":"Подробности восстановления ссылок","backup.import_detail.incoming_remapped":"Ссылок обновлено внутри импортируемой копии: {n}","backup.import_detail.target_repaired":"Существующих ссылок восстановлено: {n}","backup.import_detail.preserved_unresolved":"Неразрешимых ссылок сохранено: {n}","backup.import_detail.collisions":"Конфликтов назначения безопасно сохранено: {n}","backup.import_detail.dropped_links":"Входящих связей пропущено по правилам переноса: {n}","backup.import_detail.bounded_lineages":"Чрезмерно вложенных идентификаторов ограничено: {n}","backup.replace_warning":"Текущая конфигурация и расположение будут заменены. Загруженные файлы не удаляются. Одну отмену можно выполнить до следующего изменения плана.","backup.foreign_bookkeeping":"Служебные списки известных и новых устройств другого экземпляра импортированы не будут.","backup.final_name":"Название нового пространства","backup.target_settings":"Глобальные настройки целевого экземпляра не изменятся.","backup.duplicates":"Уже существующих привязок: {n}","backup.skip":"Пропустить повторяющиеся устройства","backup.virtual_copy":"Добавить безопасные статичные виртуальные копии","backup.content":"Связанное содержимое","backup.decor_images_summary":"Свои изображения: объектов — {objects}, файлов — {assets}; отсутствует файлов — {missing}.","backup.content_available":"доступно локально","backup.content_external":"внешняя ссылка","backup.content_detach_required":"будет отвязано","backup.confirm_detach":"Я понимаю, что недоступные внутренние планы и вложения будут отвязаны от импортируемой конфигурации.","backup.confirm_missing_images":"Я понимаю, что отсутствующие свои изображения останутся восстанавливаемыми заглушками, а остальные недоступные локальные файлы будут отвязаны.","backup.replace":"Заменить","backup.add":"Добавить пространство","backup.space_done":"Пространство импортировано: комнат — {rooms}, устройств — {markers}, существующих ссылок восстановлено — {refs}","backup.full_done":"Копия восстановлена: пространств — {spaces}, комнат — {rooms}, устройств — {markers}","backup.undo_import":"Отменить последний полный импорт","backup.import_undone":"Полный импорт отменён","backdrop.large_title":"Большое изображение","backdrop.large_body":"Изображение {w}×{h} ({fileMb} МБ), для показа потребуется около {decodedMb} МБ памяти. На планшетах это может привести к падению страницы.","backdrop.unknown_body":"Не удалось прочитать размеры изображения — файл может быть повреждён. Продолжение может привести к падению страницы на планшете.","backdrop.reduced_dimensions":"Уменьшенная копия: {w}×{h} px.","backdrop.use_downscaled":"Загрузить уменьшенную копию","backdrop.reducing":"Уменьшаем…","backdrop.keep_original":"Оставить оригинал","backdrop.too_large_title":"Изображение слишком большое","backdrop.too_large_body":"Изображение превышает возможности браузера ({w}×{h}, предел {limit} px по стороне). Уменьшите его в редакторе на компьютере и загрузите снова.","backdrop.downscale_failed":"Не удалось создать уменьшенную копию. Текущий план не изменён.","gs.card_display":"Отображение","gs.card_zigbee":"Связи Zigbee","gs.card_fills":"Цвета заливки комнат","gs.card_plan":"План","gs.card_data":"Данные","gs.card_fills.help.aria":"О цветах заливки комнат","gs.backup_group.help.aria":"О резервной копии и переносе","gs.grid_group.help.aria":"Об обслуживании плана","gs.backup_group.help":"Скачайте переносимую JSON-копию или проверьте и импортируйте копию, созданную House Plan.","gs.grid_group.help":"Обновляет модели данных, выравнивает элементы по сетке и объединяет лишние фрагменты стен. Перед записью будет показан точный отчёт.","gs.card_fills.help":"Цвета заливок действуют на все пространства; у каждого цвета своя прозрачность. Какой режим заливки использует пространство — задаётся в его диалоге.","space.card_basics":"Основное","space.card_sun":"Солнце и свет","marker.card_basics":"Основное","marker.card_tap":"Действие по нажатию","marker.card_light":"Свет и свечение","marker.card_appearance":"Внешний вид","marker.card_details":"Подробности"}},{code:"de",nativeLabel:"Deutsch",loadDictionary:async function(e){const t=0===e?await import("./de-DVCIKwC0.js"):await import(new URL("./de-DVCIKwC0.js?retry",import.meta.url).href);return{dictionary:t.dictionary,fingerprint:t.fingerprint}}},{code:"fr",nativeLabel:"Français",loadDictionary:async function(e){const t=0===e?await import("./fr-DHxhbm5E.js"):await import(new URL("./fr-DHxhbm5E.js?retry",import.meta.url).href);return{dictionary:t.dictionary,fingerprint:t.fingerprint}}}],_p=lp,mp=new Set;const gp=new class{constructor(e,t,i=console.warn,n){this.entries=e,this.expectedFingerprint=t,this.warn=i,this.loadFailed=n,this.dictionaries=new Map,this.pending=new Map,this.failed=new Set;for(const t of e)t.dictionary&&this.dictionaries.set(t.code,t.dictionary)}state(e){return this.dictionaries.has(e)?"ready":this.failed.has(e)?"fallback":"pending"}dictionary(e){return this.dictionaries.get(e)}ensure(e){if("pending"!==this.state(e))return Promise.resolve();const t=this.pending.get(e);if(t)return t;const i=this.entries.find(t=>t.code===e),n=this.load(i).finally(()=>this.pending.delete(e));return this.pending.set(e,n),n}async load(e){if(!e?.loadDictionary)return void(e&&this.failed.add(e.code));let t;for(const i of[0,1])try{const t=await e.loadDictionary(i);if(t.fingerprint!==this.expectedFingerprint)throw new Error(`locale fingerprint mismatch for ${e.code}`);return this.dictionaries.set(e.code,t.dictionary),void this.failed.delete(e.code)}catch(e){t=e}this.failed.add(e.code),this.warn(`[houseplan] unable to load ${e.code} locale; using English`,t),this.loadFailed?.(e.code)}}(pp,"54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32",console.warn,function(e){for(const t of mp)t(e)});function fp(e){const t=bp(e)?.code??"en";return gp.dictionary(t)??_p}function vp(e){return"string"==typeof e?e.trim().replaceAll("_","-").toLowerCase():""}const yp=new Map(pp.map(e=>[vp(e.code),e]));function bp(e){return yp.get(vp(e))}function wp(e,t){const i=[{value:"",label:e},...pp.map(({code:e,nativeLabel:t})=>({value:e,label:t}))],n="string"==typeof t?t:"";return n&&!i.some(e=>e.value===n)&&i.push({value:n,label:bp(n)?.nativeLabel??n}),i}function kp(e,t){return function(e,t,i,n){const r=new Map(i.map(e=>[vp(e),e])),o=r.get(vp(e));if(o)return o;const s=vp(t),a=r.get(s);return a||(r.get(s.split("-")[0]||"")??n)}(t,e?.locale?.language||e?.language,pp.map(({code:e})=>e),"en")}function xp(e,t,i){return on(fp(e)[t]??_p[t]??t,i)}function Sp(e,t){const i=fp(e)[t]??_p[t];return"string"==typeof i&&i.trim().length>0}function $p(e,t,i,n){return{ox:0,oy:0}}function Mp(e,t){const i=(e.angle+90)*Math.PI/180,n=Wa(16,t),r=e.gateFace?-n*e.gateFace.side:n*(e.flipV?-1:1);return[[e.x+Math.cos(i)*r,e.y+Math.sin(i)*r],r<0]}function Rp(e){const t=e.length/2,i=e.face.cm>0?e.face.cm/e.cellCm*e.gridPitch/2:Wa(4,e.cellCm),n="gate"===e.type?Math.sin(10*Math.PI/180)*t:0;return{half:t,jambHalf:i,gateDepth:n,outlineHalf:Math.max(Wa(16,e.cellCm),i+Wa(8,e.cellCm),n+Wa(8,e.cellCm)),hitHalf:Math.max(Wa(20,e.cellCm),i+Wa(10,e.cellCm),n+Wa(12,e.cellCm))}}function Cp(e,t,i){e.minX=Math.min(e.minX,t),e.minY=Math.min(e.minY,i),e.maxX=Math.max(e.maxX,t),e.maxY=Math.max(e.maxY,i)}function Tp(e,t,i,n,r,o,s,a){const l=Math.min(s,a)*Math.PI/180,c=Math.max(s,a)*Math.PI/180,h=(e,t)=>{const i=Math.atan2(t,e),n=[l,c];for(let e=-3;e<=3;e++){const t=e*Math.PI-i,r=Math.PI/2+e*Math.PI-i;t>l&&tl&&r0&&[e.length,e.angle,t[0],t[1]].every(Number.isFinite)))return null;const{half:i,jambHalf:n}=Rp(e),r=ja(e.cellCm),o=1.75*r,s=1.25*r,a=.75*r,l={minX:-i-s,minY:-n-s,maxX:i+s,maxY:n+s},c={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};if("window"===e.type)Tp(c,-i,0,i,-o,o,-90,0),Tp(c,i,-i,0,-o,o,0,90),Cp(c,-i-a,-i-a),Cp(c,i+a,a);else if("gate"===e.type){const t=10*e.face.side;Tp(c,-i,0,i,-o,o,0,t),Tp(c,i,-i,0,-o,o,-t,0)}else Tp(c,-i,0,e.length,-o,o,-90,0),Cp(c,-i-a,-e.length-a),Cp(c,i+a,a);const[h,d]=Dp(e),u={...l};Cp(u,c.minX+h,c.minY+d),Cp(u,c.maxX+h,c.maxY+d);const p=e.flipH?-1:1,_="gate"===e.type?1:e.flipV?-1:1,m=e.angle*Math.PI/180,g=Math.cos(m),f=Math.sin(m),v={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};for(const e of[u.minX,u.maxX])for(const i of[u.minY,u.maxY]){const n=e*p,r=i*_;Cp(v,t[0]+n*g-r*f,t[1]+n*f+r*g)}return v}function Pp(e){if("passage"===e.type)return W``;const t=Math.max(0,Math.min(1,e.amount)),{half:i,jambHalf:n}=Rp(e),r=ja(e.cellCm),o=1.75*r,s=e.flipH?-1:1,a=e.flipV?-1:1,l="gate"===e.type?1:a,[c,h]=Dp(e);let d;if("window"===e.type){const o=Math.PI/2*i,s=e.face.cm>0?W``:W``;d=W` ${l} `:G} - `}}_g.properties={hass:{attribute:!1},_config:{state:!0},_snap:{state:!0},_continuityEpoch:{state:!0}},_g.styles=[ap,o`.hp-static-title{font-weight:700;padding:10px 14px 6px;font-size:16px;color:var(--primary-text-color);}.hp-static-body{position:relative;}.hp-static-stage{position:relative;width:100%;container-type:inline-size;overflow:hidden;pointer-events:none;background:var(--ha-card-background,var(--card-background-color,#111));}.hp-static-stage>svg{position:absolute;inset:0;width:100%;height:100%;display:block;z-index:1;}.hp-static-stage>.hp-paper-outline-svg{z-index:0;overflow:visible;}.hp-paper{fill:var(--ha-card-background,var(--card-background-color,#111));stroke:none;}.wallbody-fill{fill:var(--wall-fill,#ffffff);fill-opacity:var(--wall-fill-op,1);fill-rule:evenodd;stroke:none;pointer-events:none;}.wallbody{fill:url(#hp-wall-hatch);fill-rule:evenodd;stroke:var(--room-stroke,var(--hp-muted,#607d8b));stroke-width:calc(0.6px * var(--hp-cell-visual-scale,1));pointer-events:none;}.wallbody.solid{fill:none;}.hp-static-stage .devlayer{position:absolute;inset:0;z-index:2;}.hp-static-foot{padding:8px 12px 12px;pointer-events:auto;}.hp-static-btn{width:100%;padding:9px 14px;border:none;border-radius:10px;background:var(--primary-color,#3ea6ff);color:var(--text-primary-color,#fff);font-size:14px;font-weight:600;cursor:pointer;}:host([data-pointer-hover]) .hp-static-btn:hover{filter:brightness(1.08);}.hp-static-error{padding:24px;text-align:center;color:var(--secondary-text-color,#9aa4ad);}`],customElements.get("houseplan-space-card")||customElements.define("houseplan-space-card",_g),window.customCards=window.customCards||[],window.customCards.find(e=>"houseplan-space-card"===e.type)||window.customCards.push({type:"houseplan-space-card",name:"House Plan — Space (static)",description:"Read-only live schematic of a single houseplan space, with a deep-link button.",preview:!1,documentation:"https://github.com/Matysh/houseplan-card"});const mg=o`:host{--hp-editor-tray-bg-fallback:color-mix(in srgb,var(--card-background-color,var(--hp-bg)) 94%,var(--hp-line));--hp-editor-tray-bg:color-mix(in srgb,var(--card-background-color,var(--hp-bg)) 86%,transparent);--hp-editor-tray-border:color-mix(in srgb,var(--hp-line) 82%,var(--hp-accent));--hp-editor-tray-blur:8px;--hp-editor-tray-shadow:var(--shadow-2);}.editor-secondary-host{position:absolute;inset:var(--sp-2) var(--sp-4) auto;z-index:70;display:flex;justify-content:flex-end;pointer-events:none;}.editor-secondary-host.kind-palette,.editor-secondary-host.kind-group{justify-content:flex-start;}.editor-secondary{pointer-events:none;max-width:100%;display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);color:var(--hp-txt);background:var(--card-background-color,var(--hp-bg));background:var(--hp-editor-tray-bg-fallback);border:1px solid var(--hp-line);border-color:var(--hp-editor-tray-border);border-radius:var(--rad-l);box-shadow:var(--hp-editor-tray-shadow);opacity:0;visibility:hidden;transform:translateY(-4px);transition:opacity 0.1s ease,transform 0.1s cubic-bezier(0.2,0.7,0.2,1),visibility 0s linear 0.1s;touch-action:auto;}.editor-secondary-host.open .editor-secondary{pointer-events:auto;opacity:1;visibility:visible;transform:translateY(0);transition-duration:0.14s,0.14s,0s;transition-delay:0s;}.editor-secondary-host.blocked .editor-secondary{pointer-events:none;}@supports ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){.editor-secondary{background:var(--hp-editor-tray-bg);-webkit-backdrop-filter:blur(var(--hp-editor-tray-blur));backdrop-filter:blur(var(--hp-editor-tray-blur));}}.editor-secondary-content,.editor-group-items{display:flex;align-items:center;gap:var(--sp-3);min-width:0;}.editor-context-label{max-width:14rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding-inline-end:var(--sp-4);border-inline-end:1px solid var(--hp-line);color:var(--hp-muted);font-size:var(--fs-s);}.editor-secondary.kind-palette{width:min(760px,100%);align-items:stretch;padding:0;overflow:hidden;}.editor-secondary.kind-palette .editor-secondary-content,.editor-secondary.kind-palette .furnpalette{width:100%;}.editor-secondary.kind-palette .furnpalette{max-height:38vh;border:0;background:transparent;}.editor-group-launcher .group-chevron{--mdc-icon-size:16px;transition:transform 0.14s ease;}.editor-group-launcher[aria-expanded="true"] .group-chevron{transform:rotate(180deg);}.editor-secondary .bdhint{font-size:var(--fs-s);color:var(--hp-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.editor-secondary .dfill{display:inline-flex;align-items:center;gap:var(--sp-2);font-size:var(--fs-s);cursor:pointer;}.editor-secondary .dfill input[type="checkbox"]{width:16px;height:16px;flex:none;margin:0;padding:0;}.editor-secondary hp-color-opacity{flex:0 0 auto;}.editor-secondary input{width:74px;background:transparent;border:1px solid var(--hp-line);color:var(--hp-txt);border-radius:var(--rad-s);padding:var(--sp-3) var(--sp-4);font-size:var(--fs-m);}.editor-secondary label,.editor-secondary .hint{color:var(--hp-muted);font-size:var(--fs-s);}.editor-secondary .drawwall{display:inline-flex;align-items:center;gap:var(--sp-3);white-space:nowrap;}.editor-secondary .drawwall input{width:4.2em;}.editor-secondary .drawwall .opl{color:var(--hp-muted);font-size:var(--fs-s);}@container (min-width:560px) and (max-width:899px){.editor-secondary-content,.editor-group-items{flex-wrap:wrap;justify-content:flex-end;}}@container (max-width:559px){.editor-secondary-host{inset-inline:var(--sp-4);}.editor-secondary{max-width:100%;}.editor-secondary-content,.editor-group-items{overflow-x:auto;scrollbar-width:thin;}.editor-secondary-content>*,.editor-group-items>*{flex:none;}.editor-context-label{display:none;}}@media (prefers-reduced-motion:reduce){.editor-secondary{transition:none;}.editor-group-launcher .group-chevron{transition:none;}}`;class gg{constructor(e=50){this._undo=[],this._redo=[],this._limit=Math.max(30,Math.floor(e))}get canUndo(){return this._undo.length>0}get canRedo(){return this._redo.length>0}get undoName(){return this._undo[this._undo.length-1]?.name??null}get redoName(){return this._redo[this._redo.length-1]?.name??null}get size(){return this._undo.length}push(e){this._undo.push(e),this._undo.length>this._limit&&this._undo.splice(0,this._undo.length-this._limit),this._redo=[]}undo(){const e=this._undo.pop()??null;return e&&this._redo.push(e),e}redo(){const e=this._redo.pop()??null;return e&&this._undo.push(e),e}removeWhere(e){const t=this._undo.length,i=this._redo.length;return this._undo=this._undo.filter(t=>!e(t)),this._redo=this._redo.filter(t=>!e(t)),t+i-this._undo.length-this._redo.length}clear(){this._undo=[],this._redo=[]}}function fg(e,t){const i=e[t];return i&&Number.isFinite(i.x)&&Number.isFinite(i.y)?{x:i.x,y:i.y,..."string"==typeof i.s?{s:i.s}:{}}:null}function vg(e,t,i){if(null===i){if(!(t in e))return e;const i={...e};return delete i[t],i}const n={...e[t]||{}};delete n.x,delete n.y,delete n.s;const r={...n,x:i.x,y:i.y,...void 0!==i.s?{s:i.s}:{}};return{...e,[t]:r}}const yg="houseplan-card:version-reload-target:v1";function bg(e){if("string"!=typeof e)return null;return e.trim()||null}class wg{constructor(e){this.hooks=e,this._input={frontendVersion:null,backendVersion:null,kiosk:!1,reducedMotion:!1},this._relation={kind:"unknown"},this._banner=null,this._connected=!1,this._attemptTarget=null,this._attemptState=null,this._noticeToken=0}get relation(){return this._relation}get banner(){return this._banner}get hasCurrentMismatchNotice(){return"mismatch"===this._relation.kind&&"visible"===this._banner?.phase}connect(){this._connected||(this._connected=!0,this._attemptTarget=null,this._attemptState=null,this._reconcile())}disconnect(){(this._connected||this._banner)&&(this._connected=!1,this._cancelTimer(),this._banner&&(this._banner=null,this.hooks.changed()))}update(e){const t={frontendVersion:bg(e.frontendVersion),backendVersion:bg(e.backendVersion),kiosk:!0===e.kiosk,reducedMotion:!0===e.reducedMotion},i=function(e,t){const i=bg(e),n=bg(t);return i&&n?i===n?{kind:"equal",frontend:i,backend:n}:{kind:"mismatch",frontend:i,backend:n}:{kind:"unknown"}}(t.frontendVersion,t.backendVersion),n=!((e,t)=>e.frontendVersion===t.frontendVersion&&e.backendVersion===t.backendVersion&&e.kiosk===t.kiosk&&e.reducedMotion===t.reducedMotion)(this._input,t)||!((e,t)=>e.kind===t.kind&&("unknown"===e.kind||"unknown"!==t.kind&&e.frontend===t.frontend&&e.backend===t.backend))(this._relation,i);this._input=t,this._relation=i,n&&this._reconcile()}finishBannerExit(e){this._banner&&"leaving"===this._banner.phase&&this._banner.token===e&&(this._banner=null,this.hooks.changed())}_reconcile(){if(this._cancelTimer(),!this._connected||"mismatch"!==this._relation.kind)return this._attemptTarget=null,this._attemptState=null,void this._hideBanner();if(!this._input.kiosk)return this._attemptTarget=null,this._attemptState=null,void this._showBanner(this._relation.frontend,this._relation.backend);const e=this._relation.backend;if(this._attemptTarget===e&&null!==this._attemptState||(this._attemptTarget=e,this._attemptState=function(e,t){try{const i=e();return i?i.getItem(yg)===t?"attempted":"fresh":"unavailable"}catch{return"unavailable"}}(this.hooks.storage,e)),"fresh"===this._attemptState)return this._hideBanner(),void this._armTimer();this._showBanner(this._relation.frontend,e)}_armTimer(){this._connected&&void 0===this._timer&&"mismatch"===this._relation.kind&&this._input.kiosk&&"fresh"===this._attemptState&&(this._timer=this.hooks.clock.setTimeout(()=>{this._timer=void 0,this._tick()},250))}_cancelTimer(){void 0!==this._timer&&(this.hooks.clock.clearTimeout(this._timer),this._timer=void 0)}_tick(){if(!this._connected||"mismatch"!==this._relation.kind||!this._input.kiosk||"fresh"!==this._attemptState)return;if(!function(e){return e.connected&&e.initialFrameSettled&&e.viewOnly&&e.surfacesIdle&&e.configWritesIdle&&e.physicalWritesIdle&&e.layoutWritesIdle&&e.gesturesIdle&&e.interactionPauseElapsed&&e.baseZoom}(this.hooks.safety()))return void this._armTimer();const e=this._relation.backend,t=function(e,t){try{const i=e();return i?i.getItem(yg)===t?"attempted":(i.setItem(yg,t),"claimed"):"unavailable"}catch{return"unavailable"}}(this.hooks.storage,e);if(this._attemptTarget=e,this._attemptState="claimed"===t?"attempted":t,"claimed"===t){this._showBanner(this._relation.frontend,e);try{this.hooks.reload()}catch{}}else this._showBanner(this._relation.frontend,e)}_showBanner(e,t){"visible"===this._banner?.phase&&this._banner.frontend===e&&this._banner.backend===t||(this._banner={frontend:e,backend:t,phase:"visible",token:++this._noticeToken},this.hooks.changed())}_hideBanner(){if(this._banner)return this._input.reducedMotion?(this._banner=null,void this.hooks.changed()):void("leaving"!==this._banner.phase&&(this._banner={...this._banner,phase:"leaving",token:++this._noticeToken},this.hooks.changed()))}}const kg=1;function xg(e,t){const i=t&&"object"==typeof t?t:{};e._haIntegrationVersion=bg(i.integration_version);const n=i.support_api;e._haSupportApi="number"==typeof n&&Number.isSafeInteger(n)?n:null,e._haDecorAssetsApi=1===i.decor_assets_api?1:null,e._haSummaryPanelApi=1===i.summary_panel_api?1:null,e._haRadarStage1Api=1===i.radar_stage1_api?1:null,e._syncVersionRecovery()}function Sg(e){const t=e._stageEl,i=e._loadOk&&!e._loading&&e._continuityDataReady&&!e._resumeSettling&&!e._connectionWasLost&&!e._booting&&!e._bootFading&&!e._bootSettling&&!e._bootSoft&&e._continuity.hasCompleteFrame&&"steady"===e._continuity.state&&!e._continuity.overlayBlocksInteraction&&!!t&&t.clientWidth>0&&t.clientHeight>0,n=!(0!==e._pointers.size||0!==e._touchContacts.size||e._touchSequenceMultitouch||e._roomPointer||e._panStart||e._panLock||e._pinchStart||e._swipeStart||e._tabDrag||e._tabDragRelease||e._drag||e._deviceDrag||e._rlResize||e._resize?.dragging||e._physicalDrag||e._physicalRotate||e._opDrag||e._decorDraft||e._decorMove||e._dtDrag||e._bdDrag||e._furnTouchPending||e._compassDrag||e._viewportGestureDirty||e._devicePositionBusy||e._modeTransitionBusy||e._cameraTransition.active||e._slide||0!==e._warmModeRequest),r=!(e._editorSecondaryDialogBlocked||e._partitionDeleteDialog||e._roomDeleteDialog||e._backdropGuard||e._vacFit||e._editorSecondary?.hasOpenGroup||e._furnPalette||e._decorImagePalette);return{connected:e.isConnected,initialFrameSettled:i,viewOnly:!0===e._config?.kiosk&&"view"===e._mode&&!e._editing,surfacesIdle:r,configWritesIdle:0===e._writesPending&&!e._saveConfigDebounced.pending(),physicalWritesIdle:0===e._pendingPhysicalWrites.size,layoutWritesIdle:!e._persistLayout.pending()&&0===e._dirtyPos.size&&0===e._sentPos.size&&!e._devicePositionBusy,gesturesIdle:n,interactionPauseElapsed:Date.now()>=e._cyclePausedUntil,baseZoom:e._zoom<=1.001}}class $g{constructor(){this.seen=null,this.diagnosticsCache=null}observe(e,t,i,n){this.invalidateDiagnosticsForHass(e,t,i),this.intake(t,n)}intake(e,t){e&&this.seen!==e&&(this.seen=e,t())}invalidate(){this.diagnosticsCache=null}invalidateDiagnosticsForHass(e,t,i){this.diagnosticsCache&&(e?.entities!==t?.entities||e?.devices!==t?.devices||[...i?.entityIds||[]].some(i=>!!e?.states?.[i]!=!!t?.states?.[i]))&&this.invalidate()}diagnostics(e,t,i){if(this.diagnosticsCache)return this.diagnosticsCache;const n={active:0,ha_disabled:0,orphaned:0,unverified:0};for(const e of t)e.removed||"virtual"===e.binding||n[i(e.binding).kind]++;return this.diagnosticsCache={registry:ud(e),bindings:n},this.diagnosticsCache}}function Mg(e){const t=e;t._hassSequence++,t._renderSnapshotAt=Date.now(),t._continuity.note("hass-snapshot"),t._ensureHaRegistryAuthority(),t._planHassMemo=null,t._hookConnection(),!t._loadOk&&!t._loading&&t._loadTries<8&&t._loadFromServer(),t._maybeRebuildDevices(),t._vacTick(),t._activityTick()}function Rg(e){return!!e&&"object"==typeof e&&1===e.version}function Cg(e,t){const i=e.radar;return e.space===t&&!0!==e.hidden&&!0!==e.removed&&Rg(i)&&!0===i.enabled&&!1!==i.show_live}const Tg={ok:"radar.health_ok",off:"radar.health_off",stale:"radar.health_stale",partial:"radar.health_partial",restricted:"radar.health_restricted",incomplete:"radar.health_incomplete",position_unavailable:"radar.health_position_unavailable",unavailable:"radar.health_unavailable",needs_setup:"radar.health_needs_setup",inconsistent:"radar.health_inconsistent",unknown:"radar.health_unknown"};const Dg=e=>"number"==typeof e&&Number.isFinite(e);class Ag{constructor(e){this.host=e,this.frames=new Map,this.connection=null,this.space="",this.generation=0,this.expiryTimer=0,this.deadlines=new Map}sync(e,t){const i=this.host.hass?.connection;if(!t||!i||!this.host.isConnected)return void this.stop();if(this.unsubscribe&&this.connection===i&&this.space===e)return;this.stop(),this.connection=i,this.space=e;const n=++this.generation,r=i.subscribeMessage?.bind(i);"function"==typeof r&&Promise.resolve(r(e=>{if(n!==this.generation||!this.host.isConnected)return;const t=function(e){if(!e||"object"!=typeof e)return null;const t=e;if("string"!=typeof t.marker_id||"string"!=typeof t.server_session_id||!Number.isSafeInteger(t.seq)||"string"!=typeof t.health)return null;const i=Array.isArray(t.targets)?t.targets.slice(0,256).flatMap(e=>{if(!e||"object"!=typeof e)return[];const t=e;return"string"==typeof t.slot&&Dg(t.x)&&Dg(t.y)&&Dg(t.expires_at)&&Dg(t.reported_at)&&("bounded_latest"===t.pair_quality||"coherent"===t.pair_quality)?[{...t,included:!0===t.included,smooth:!0===t.smooth}]:[]}):[],n=Array.isArray(t.ranges)?t.ranges.slice(0,64).flatMap(e=>{if(!e||"object"!=typeof e)return[];const t=e;if(!("string"==typeof t.id&&Dg(t.x)&&Dg(t.y)&&Dg(t.radius)&&Dg(t.expires_at)&&Dg(t.reported_at)))return[];const i=Array.isArray(t.segments)?t.segments.slice(0,64).flatMap(e=>{if(!Array.isArray(e))return[];const t=e.slice(0,181).flatMap(e=>Array.isArray(e)&&2===e.length&&Dg(e[0])&&Dg(e[1])?[[e[0],e[1]]]:[]);return t.length>=2?[t]:[]}):void 0;return[{...t,...i?{segments:i}:{}}]}):[],r=Array.isArray(t.zones)?t.zones.slice(0,64).flatMap(e=>{if(!e||"object"!=typeof e)return[];const t=e;if("string"!=typeof t.id)return[];const i=t.state;if(null!==i&&"boolean"!=typeof i&&!Dg(i))return[];const n=Array.isArray(t.polygon)?t.polygon.slice(0,64).flatMap(e=>Array.isArray(e)&&2===e.length&&Dg(e[0])&&Dg(e[1])?[[e[0],e[1]]]:[]):[];return[{id:t.id,state:i,...n.length>=3?{polygon:n}:{}}]}):[];return{server_session_id:t.server_session_id,marker_id:t.marker_id,source_generation:"string"==typeof t.source_generation?t.source_generation:void 0,calibration_revision:"string"==typeof t.calibration_revision?t.calibration_revision:void 0,seq:t.seq,reported_at:Dg(t.reported_at)?t.reported_at:void 0,expires_at:Dg(t.expires_at)?t.expires_at:void 0,health:t.health,reported_presence:"boolean"==typeof t.reported_presence?t.reported_presence:null,complete:!0===t.complete,targets:i,ranges:n,zones:r}}(e);if(!t)return;if(!function(e,t){return!e||t.server_session_id!==e.server_session_id||t.source_generation!==e.source_generation||t.calibration_revision!==e.calibration_revision||t.seq>e.seq}(this.frames.get(t.marker_id),t))return;const i=function(e,t=Date.now()){if(!Dg(e.expires_at))return null;if(!Dg(e.reported_at))return Math.max(0,1e3*e.expires_at-t);const i=Math.max(0,1e3*(e.expires_at-e.reported_at)),n=Math.max(0,t-1e3*e.reported_at);return Math.max(0,i-n)}(t);"restricted"===t.health||"disabled"===t.health||0===i?(this.frames.delete(t.marker_id),this.deadlines.delete(t.marker_id)):(this.frames.set(t.marker_id,t),null==i?this.deadlines.delete(t.marker_id):this.deadlines.set(t.marker_id,this.monotonicNow()+i)),this.armExpiry(),this.host.requestUpdate()},{type:"houseplan/radar/subscribe",space_id:e})).then(e=>{n===this.generation&&this.host.isConnected?"function"==typeof e&&(this.unsubscribe=e):"function"==typeof e&&e()}).catch(()=>{n===this.generation&&this.stop()})}stop(){this.generation++,this.unsubscribe?.(),this.unsubscribe=void 0,this.connection=null,this.space="",clearTimeout(this.expiryTimer),this.expiryTimer=0,this.frames.size&&(this.frames.clear(),this.host.isConnected&&this.host.requestUpdate()),this.deadlines.clear()}armExpiry(){clearTimeout(this.expiryTimer);const e=this.monotonicNow(),t=[...this.deadlines.values()].filter(t=>t>e);if(!t.length)return;const i=Math.max(20,Math.min(...t)-e+10);this.expiryTimer=window.setTimeout(()=>{this.expiryTimer=0;let e=!1;const t=this.monotonicNow();for(const[i,n]of this.deadlines)n>t||(this.deadlines.delete(i),this.frames.delete(i),e=!0);this.armExpiry(),e&&this.host.isConnected&&this.host.requestUpdate()},i)}monotonicNow(){return globalThis.performance?.now?.()??Date.now()}}const Pg=Object.freeze({enabled:!1,z2mBaseTopics:Object.freeze([])});function Fg(e){if("string"!=typeof e)return null;const t=e.trim().replace(/^\/+|\/+$/g,"").replace(/\/{2,}/g,"/");return!t||t.length>180||/[#+\u0000-\u001f\u007f]/.test(t)?null:t}function zg(e){const t=e?.zigbee_topology;if(!t||"object"!=typeof t)return Pg;const i=t,n=Array.isArray(i.z2m_base_topics)?i.z2m_base_topics:Array.isArray(i.z2mBaseTopics)?i.z2mBaseTopics:[],r=new Set,o=[];for(const e of n){const t=Fg(e);if(t&&!r.has(t)&&(r.add(t),o.push(t),8===o.length))break}return{enabled:!0===i.enabled,z2mBaseTopics:o}}function Ig(e,t){const i={...e},n=t.z2mBaseTopics.map(Fg).filter(Boolean);return t.enabled||n.length?i.zigbee_topology={enabled:!0===t.enabled,z2m_base_topics:[...new Set(n)].slice(0,8)}:delete i.zigbee_topology,i}const Og={now:()=>performance.now(),requestFrame:e=>requestAnimationFrame(e),cancelFrame:e=>cancelAnimationFrame(e)},Eg=e=>Math.max(0,Math.min(1,e)),Ng=(e,t,i)=>e+(t-e)*i,Hg=(e,t,i)=>{const n=1-e;return 3*n*n*e*t+3*n*e*e*i+e*e*e},Lg=e=>{const t=Eg(e);if(0===t||1===t)return t;let i=0,n=1,r=t;for(let e=0;e<12;e++)r=(i+n)/2,Hg(r,.2,.2)0&&e.w>0?t/e.w:1,viewBox:{...e}}}function qg(e,t,i){const n=Math.max(1e-9,e.pixelsPerUnit),r=Math.max(1e-9,t/n),o=Math.max(1e-9,i/n);return{x:e.centerX-r/2,y:e.centerY-o/2,w:r,h:o}}function jg(e){const t=e.trim(),i=/^rgba?\(\s*([\d.]+)[, ]+([\d.]+)[, ]+([\d.]+)(?:\s*[,/]\s*([\d.]+))?\s*\)$/i.exec(t);if(i)return[Number(i[1]),Number(i[2]),Number(i[3]),null==i[4]?1:Number(i[4])];const n=/^#([0-9a-f]{6}|[0-9a-f]{8})$/i.exec(t)?.[1];return n?[parseInt(n.slice(0,2),16),parseInt(n.slice(2,4),16),parseInt(n.slice(4,6),16),8===n.length?parseInt(n.slice(6,8),16)/255:1]:null}function Wg(e,t,i){const n=jg(e),r=jg(t);if(!n||!r)return i<.5?e:t;const o=Eg(i);return`rgba(${Math.round(Ng(n[0],r[0],o))}, ${Math.round(Ng(n[1],r[1],o))}, ${Math.round(Ng(n[2],r[2],o))}, ${Ng(n[3],r[3],o).toFixed(3)})`}class Ug{constructor(e,t=Og){this._hooks=e,this._clock=t,this._token=0,this._raf=0,this._state=null}get state(){return this._state}get active(){return"running"===this._state?.phase||"preparing"===this._state?.phase}get presented(){return this._state?.presented||null}start(e,t,i,n=220){this.cancel(!1);const r=++this._token,o=this._clock.now();if(this._state={token:r,phase:n<=0?"settling":"running",from:e,to:t,presented:n<=0?t:e,startedAt:o,duration:Math.max(0,n),targetMode:i},n<=0)return this._hooks.frame(this._state),this._hooks.settled(this._state),this._state=null,r;this._hooks.frame(this._state);const s=e=>{const t=this._state;if(!t||t.token!==r)return;const i=Eg((e-t.startedAt)/t.duration);t.presented=i>=1?t.to:function(e,t,i){const n=Lg(i),r=Ng(e.stageWidth,t.stageWidth,n),o=Ng(e.stageHeight,t.stageHeight,n),s=Math.max(1e-9,e.viewport.pixelsPerUnit),a=Math.max(1e-9,t.viewport.pixelsPerUnit),l={centerX:Ng(e.viewport.centerX,t.viewport.centerX,n),centerY:Ng(e.viewport.centerY,t.viewport.centerY,n),pixelsPerUnit:Math.exp(Ng(Math.log(s),Math.log(a),n))};return{presentedMode:n<.5?e.presentedMode:t.presentedMode,editorChromeHeight:Ng(e.editorChromeHeight,t.editorChromeHeight,n),stageWidth:r,stageHeight:o,viewport:{...l,viewBox:qg(l,r,o)},stageColor:Wg(e.stageColor,t.stageColor,n),paperColor:Wg(e.paperColor,t.paperColor,n),sceneBrightness:Ng(e.sceneBrightness,t.sceneBrightness,n),architectureOpacity:Ng(e.architectureOpacity,t.architectureOpacity,n),backdropOpacity:Ng(e.backdropOpacity,t.backdropOpacity,n),viewWeight:Ng(e.viewWeight,t.viewWeight,n),editorWeight:Ng(e.editorWeight,t.editorWeight,n),toolbarContentOpacity:Ng(e.toolbarContentOpacity,t.toolbarContentOpacity,n)}}(t.from,t.to,i),t.phase=i>=1?"settling":"running",this._hooks.frame(t),i<1?this._raf=this._clock.requestFrame(s):(this._raf=0,this._hooks.settled(t),this._state?.token===r&&(this._state=null))};return this._raf=this._clock.requestFrame(s),r}cancel(e=!0){this._raf&&this._clock.cancelFrame(this._raf),this._raf=0;const t=this._state;this._state=null,this._token++,t&&e&&(t.phase="settling",t.presented=t.to,this._hooks.frame(t),this._hooks.settled(t))}dispose(){this.cancel(!1)}}const Gg={now:()=>"undefined"!=typeof performance?performance.now():Date.now(),requestFrame:e=>"function"==typeof requestAnimationFrame?requestAnimationFrame(e):null,cancelFrame:e=>{"function"==typeof cancelAnimationFrame&&cancelAnimationFrame(e)}},Vg=e=>Number.isFinite(e);function Kg(e){return!!e&&Vg(e.zoom)&&e.zoom>0&&Vg(e.viewBox.x)&&Vg(e.viewBox.y)&&Vg(e.viewBox.w)&&e.viewBox.w>0&&Vg(e.viewBox.h)&&e.viewBox.h>0}function Yg(e){return{zoom:e.zoom,viewBox:{...e.viewBox}}}function Xg(e,t){return Math.abs(e.zoom-t.zoom)<1e-9&&Math.abs(e.viewBox.x-t.viewBox.x)<1e-6&&Math.abs(e.viewBox.y-t.viewBox.y)<1e-6&&Math.abs(e.viewBox.w-t.viewBox.w)<1e-6&&Math.abs(e.viewBox.h-t.viewBox.h)<1e-6}const Zg=(e,t,i)=>e+(t-e)*i,Jg=(e,t,i)=>Math.exp(Zg(Math.log(e),Math.log(t),i));class Qg{constructor(e,t=Gg){this._hooks=e,this._clock=t,this._token=0,this._raf=null,this._state=null}get state(){return this._state}get active(){return"running"===this._state?.phase}get presented(){return this._state?.presented||null}get target(){return this._state?.to||null}start(e,t,i,n){this.cancel(!1);const r=++this._token,o=Yg(e),s=Yg(t),a=n>0&&Kg(o)&&Kg(s),l=this._clock.now(),c={token:r,phase:a?"running":"settling",from:o,to:s,presented:Yg(a?o:s),startedAt:l,duration:a?n:0,reason:i};if(this._state=c,this._hooks.frame(c),!a)return this._settle(r),r;const h=e=>{const t=this._state;if(!t||t.token!==r)return;const i=Math.max(0,Math.min(1,(e-t.startedAt)/t.duration));if(t.presented=i>=1?Yg(t.to):function(e,t,i){if(!Kg(e))return Yg(t);if(!Kg(t))return Yg(e);const n=Lg(i);if(n<=0)return Yg(e);if(n>=1)return Yg(t);const r=e.viewBox.x+e.viewBox.w/2,o=e.viewBox.y+e.viewBox.h/2,s=t.viewBox.x+t.viewBox.w/2,a=t.viewBox.y+t.viewBox.h/2,l=Jg(e.viewBox.w,t.viewBox.w,n),c=Jg(e.viewBox.h,t.viewBox.h,n),h=Zg(r,s,n),d=Zg(o,a,n);return{zoom:Jg(e.zoom,t.zoom,n),viewBox:{x:h-l/2,y:d-c/2,w:l,h:c}}}(t.from,t.to,i),t.phase=i>=1?"settling":"running",this._hooks.frame(t),i>=1)return this._raf=null,void this._settle(r);this._raf=this._clock.requestFrame(h),null===this._raf&&this._settle(r)};return this._raf=this._clock.requestFrame(h),null===this._raf&&(c.phase="settling",c.presented=Yg(s),this._hooks.frame(c),this._settle(r)),r}cancel(e=!0){null!==this._raf&&this._clock.cancelFrame(this._raf),this._raf=null;const t=this._state;this._state=null,this._token++,t&&e&&(t.phase="settling",t.presented=Yg(t.to),this._hooks.frame(t),this._hooks.settled(t))}dispose(){this.cancel(!1)}_settle(e){const t=this._state;t&&t.token===e&&(t.phase="settling",t.presented=Yg(t.to),this._hooks.settled(t),this._state?.token===e&&(this._state=null))}}function ef(e,t,i){const n=e.querySelector("ha-card");if(!n)return null;const r=n.getBoundingClientRect(),o=t.getBoundingClientRect().top-r.top,s=i?0:Math.min(Math.max(r.top,0),120),a=Math.round(o+s);return a>=0?a:null}const tf=Object.freeze({rotDeg:0,tiltDeg:20,xyScale:1,zScale:1,origin:Object.freeze([500,500])}),nf=84,rf=10,of=4,sf=4;function af(e){return[e.rotDeg,e.tiltDeg,e.xyScale,e.zScale,e.origin[0],e.origin[1]].every(Number.isFinite)&&Math.abs(e.xyScale)>1e-12&&Math.abs(Math.cos(e.tiltDeg*Math.PI/180))>1e-12}function lf(e,t,i=tf){if(!Number.isFinite(e[0])||!Number.isFinite(e[1]))throw new Error("invalid isometric projection input");return function(e,t){if(!Number.isFinite(e[0])||!Number.isFinite(e[1])||!t.every(Number.isFinite))throw new Error("invalid isometric affine input");const[i,n,r,o,s,a]=t;return[i*e[0]+r*e[1]+s,n*e[0]+o*e[1]+a]}(e,hf(t,i))}function cf(e,t=tf){if(!af(t)||!Number.isFinite(e[0])||!Number.isFinite(e[1]))throw new Error("invalid isometric projection input");const i=t.rotDeg*Math.PI/180,n=t.tiltDeg*Math.PI/180,r=(e[0]-t.origin[0])/t.xyScale,o=(e[1]-t.origin[1])/(t.xyScale*Math.cos(n));return[t.origin[0]+r*Math.cos(i)+o*Math.sin(i),t.origin[1]-r*Math.sin(i)+o*Math.cos(i)]}function hf(e=0,t=tf){if(!af(t)||!Number.isFinite(e))throw new Error("invalid isometric camera");const i=t.rotDeg*Math.PI/180,n=t.tiltDeg*Math.PI/180,r=t.xyScale*Math.cos(i),o=-t.xyScale*Math.sin(i),s=t.xyScale*Math.sin(i)*Math.cos(n),a=t.xyScale*Math.cos(i)*Math.cos(n);return[r,s,o,a,t.origin[0]-r*t.origin[0]-o*t.origin[1],t.origin[1]-s*t.origin[0]-a*t.origin[1]-e*t.zScale*Math.sin(n)]}function df(e=tf){return function(e=0,t=tf){return`matrix(${hf(e,t).map(e=>Number(e.toFixed(12))).join(" ")})`}(0,e)}function uf(e,t=tf){const{rect:i,wallHeight:n}=e,r=e.openingHeight??n,o=e.floorDepth??0,s=e.raisedHeight??n;if(!(i.w>=0)||!(i.h>=0)||!Number.isFinite(n)||!Number.isFinite(r)||!Number.isFinite(o)||!Number.isFinite(s)||n<0||r<0||o<0||s<0)throw new Error("invalid isometric frame");const a=[[i.x,i.y],[i.x+i.w,i.y],[i.x+i.w,i.y+i.h],[i.x,i.y+i.h]],l=Math.max(n,r,s),c=a.flatMap(e=>[lf(e,-o,t),lf(e,l,t)]),h=c.map(e=>e[0]),d=c.map(e=>e[1]),u=Math.min(...h),p=Math.min(...d);return{x:u,y:p,w:Math.max(...h)-u,h:Math.max(...d)-p}}const pf=[".dev",".vacpuck",".oplock",".op-hit",".opening",".rlgo","a","button","input","select","textarea",'[contenteditable]:not([contenteditable="false"])',"[data-room-fit-block]",'[role="link"]','[role="button"]'].join(","),_f=(e,t)=>{try{return"function"==typeof e?.matches&&e.matches(t)}catch{return!1}};function mf(e){for(const t of e){const e=t;if(_f(e,".roomlabel[data-id]")){const t=e.getAttribute?.("data-id");return t?{kind:"room",roomId:t}:{kind:"interactive"}}if(_f(e,pf))return{kind:"interactive"};if(_f(e,'[data-hp="room"][data-id]')){const t=e.getAttribute?.("data-id");return t?{kind:"room",roomId:t}:{kind:"interactive"}}if(_f(e,".stage"))return{kind:"background"}}return{kind:"outside"}}function gf(e){const t=mf(e);return"room"===t.kind?t.roomId:null}class ff{constructor(){this.pointer=null,this.sequence=null}clear(){this.pointer=null,this.sequence=null}clearOutside(e){let t={kind:"outside"};try{t=mf(e.composedPath())}catch{}"outside"===t.kind&&this.clear()}pointerDown(e,t,i){let n={kind:"outside"};try{n=mf(e.composedPath())}catch{}this.pointer=function(e){const t="mouse"===(i=e.pointerType)||"touch"===i||"pen"===i?i:null;var i;return t&&"view"===e.mode&&"background"===e.owner.kind&&!e.blocked&&e.isPrimary&&0===e.button&&Number.isFinite(e.x)&&Number.isFinite(e.y)?{pointerId:e.pointerId,spaceId:e.spaceId,modality:t,x:e.x,y:e.y}:null}({pointerId:e.pointerId,pointerType:e.pointerType,isPrimary:e.isPrimary,button:e.button,spaceId:t,mode:i?"view":"blocked",owner:n,blocked:!i,x:e.clientX,y:e.clientY}),this.pointer||(this.sequence=null)}pointerUp(e,t,i,n,r=Date.now()){let o={kind:"outside"};try{o=mf(e.composedPath())}catch{}const s=function(e,t,i){if(!t||"view"!==i.mode||"background"!==i.owner.kind||i.blocked||t.pointerId!==i.pointerId||t.spaceId!==i.spaceId||!Number.isFinite(i.x)||!Number.isFinite(i.y)||!Number.isFinite(i.now)||Math.abs(i.x-t.x)+Math.abs(i.y-t.y)>=8)return{sequence:null,trigger:!1};const n=e?i.now-e.at:Number.POSITIVE_INFINITY;return e&&e.spaceId===i.spaceId&&e.modality===t.modality&&n>=0&&n<=350?{sequence:null,trigger:!0}:{sequence:{at:i.now,spaceId:i.spaceId,modality:t.modality},trigger:!1}}(this.sequence,this.pointer,{pointerId:e.pointerId,spaceId:t,mode:i?"view":"blocked",owner:o,blocked:n||!i,x:e.clientX,y:e.clientY,now:r});return this.pointer=null,this.sequence=s.sequence,s.trigger}}const vf=e=>e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]);function yf(e){return!!e&&Number.isFinite(e.x)&&Number.isFinite(e.y)&&Number.isFinite(e.w)&&e.w>0&&Number.isFinite(e.h)&&e.h>0}function bf(e,t=0){if(!e.length||!Number.isFinite(t)||t<0||!e.every(vf))return null;let i=1/0,n=1/0,r=-1/0,o=-1/0;for(const t of e)i=Math.min(i,t[0]),n=Math.min(n,t[1]),r=Math.max(r,t[0]),o=Math.max(o,t[1]);const s=r-i,a=o-n;return s>0&&a>0?{x:i-t,y:n-t,w:s+2*t,h:a+2*t}:null}function wf(e,t,i){const n="string"!=typeof t||"invalid"!==t&&"no-borders"!==t&&"unverified"!==t&&!/^[a-z0-9]{1,8}$/i.test(t)?"redacted":t;return Object.freeze({kind:e,fingerprint:n,terminal:!!i})}function kf(e,t){return`${e("editor.load_failed")} ${e(t.terminal?"editor.refresh_advice":"editor.retry_advice")}`}class xf extends Error{}class Sf{constructor(e){this.options=e,this._state="idle",this._inFlight=null}get state(){return this._state}ensure(){return"ready"===this._state?Promise.resolve(!0):"failed"===this._state?Promise.resolve(!1):(this._inFlight||(this._setState("loading"),this._inFlight=this._loadWithRetry().finally(()=>{this._inFlight=null})),this._inFlight)}async _loadWithRetry(){let e=new Error("Editor runtime did not load"),t=!1;for(const i of[0,1])try{const e=await this.options.load(i);if(e.fingerprint!==this.options.expectedFingerprint)throw new xf(`Editor runtime fingerprint mismatch: expected ${this.options.expectedFingerprint}, got ${e.fingerprint}`);const t=e.create();return this.options.install(t),this._setState("ready"),!0}catch(i){e=i,i instanceof xf&&(t=!0)}return this._setState(t?"failed":"idle"),this.options.failed?.(e,{terminal:t}),!1}_setState(e){e!==this._state&&(this._state=e,this.options.stateChanged?.(e))}}const $f=(e,t)=>{if(!e.has(t))return{hit:!1};const i=e.get(t);return e.delete(t),e.set(t,i),{hit:!0,value:i}},Mf=(e,t,i,n)=>{for(e.delete(t),e.set(t,i);e.size>n;){const t=e.keys().next().value;if(void 0===t)break;e.delete(t)}},Rf=new Set(["select","draw","column","merge","split","resize","opening","wallthick","delroom"]),Cf=e=>`${window.innerWidth}x${window.innerHeight}|${location.pathname}|${JSON.stringify(e??{})}`,Tf="houseplan_card_alpha_v1",Df=Object.freeze([Object.freeze({id:"iso",issue:89,summary:"Volumetric plan renderer"})]);function Af(e){return/^[a-z][a-z0-9-]*$/.test(e.id)&&Number.isInteger(e.issue)&&e.issue>0&&!!e.summary.trim()}function Pf(e){const t=String(e||"").replace(/^#/,"");return new URLSearchParams(t)}function Ff(e){return Pf(e).get("space")||""}function zf(e,t,i=Df){const n=function(e){const t=new Set;for(const i of e){if(!Af(i)||t.has(i.id))return!1;t.add(i.id)}return!0}(i),r=function(e){let t,i=!1;const n=e=>{for(const n of e.getAll("hp_alpha"))i=!0,"1"===n?t=!0:"0"===n&&(t=!1)};return n(new URLSearchParams(String(e.search||"").replace(/^\?/,""))),n(Pf(e.hash)),{present:i,value:t}}(e),o=void 0!==r.value,s="1"===t,a=o?!0===r.value:!r.present&&s,l=n&&a;return{alpha:l,active:Object.freeze(l?i.map(e=>e.id).sort():[]),space:Ff(e.hash),persist:n&&o?l?"1":"0":void 0,knownUrlOperation:o}}let If={alpha:!1,active:Object.freeze([]),space:""},Of=!1,Ef="";const Nf=new Set;function Hf(){if("undefined"==typeof window)return If;const e=zf(window.location,function(){try{return window.localStorage.getItem(Tf)}catch{return null}}());void 0!==e.persist&&function(e){try{window.localStorage.setItem(Tf,e)}catch{}}(e.persist),If={alpha:e.alpha,active:e.active,space:e.space},window.__hpAlpha=e.alpha,window.__hpLabs=e.active;for(const e of Nf)e(If);return If}function Lf(){Hf()}function Bf(){if("undefined"==typeof window)return If;if(!Of){Of=!0,window.__hpLabsListenerCleanup?.(),window.addEventListener("hashchange",Lf),window.addEventListener("popstate",Lf);const e=()=>{window.removeEventListener("hashchange",Lf),window.removeEventListener("popstate",Lf),window.__hpLabsListenerCleanup===e&&delete window.__hpLabsListenerCleanup};window.__hpLabsListenerCleanup=e}return Hf()}const qf={window:120,door:90,passage:90,gate:300};function jf(e){return qf[e]}function Wf(e,t){return{type:e,lengthCm:jf(e),flipH:!1,flipV:!1,revision:t}}function Uf(e,t){const i=Math.max(0,e.renderedLength)/2,n=Math.max(0,e.target.physicalHalfWidth),r=n+.18*Math.max(0,t),o=e=>({x1:e,y1:-r,x2:e,y2:r});return{rect:{x:-i,y:n?-n:0,width:2*i,height:2*n},boundaries:[o(-i),o(i)]}}function Gf(e,t){const i=[e[0],e[1]],n=[t[0],t[1]];return function(e,t){return e[0]-t[0]||e[1]-t[1]}(i,n)<=0?{a:i,b:n}:{a:n,b:i}}function Vf(e){const t=new Map;return e.forEach((e,i)=>{if(!e.kind||e.open)return;const n=Gf(e.a,e.b);if(Math.hypot(n.b[0]-n.a[0],n.b[1]-n.a[1])<=1e-9)return;const r=function(e,t){const i=e=>(Math.abs(e)<=5e-10?0:Math.round(1e6*e)/1e6).toFixed(6);return`${i(e[0])},${i(e[1])}>${i(t[0])},${i(t[1])}`}(n.a,n.b),o=t.get(r);if(o)return o.physicalHalfWidth=Math.max(o.physicalHalfWidth,e.half||0),o.sourceOrder=Math.min(o.sourceOrder,i),void(e.partitionHost&&(o.partitionHost&&o.partitionHost.id!==e.partitionHost.id?o.ambiguousPartitionHost=!0:o.partitionHost=e.partitionHost));t.set(r,{segmentKey:r,a:n.a,b:n.b,physicalHalfWidth:Math.max(0,e.half||0),sourceOrder:i,...e.partitionHost?{partitionHost:e.partitionHost}:{}})}),[...t.values()]}function Kf(e,t){if(Math.abs(e.distance-t.distance)>1e-9)return e.distance-t.distance;if(Math.abs(e.perpendicular-t.perpendicular)>1e-9)return e.perpendicular-t.perpendicular;return(e.target.segmentKeyt.target.segmentKey?1:0)||e.target.sourceOrder-t.target.sourceOrder}function Yf(e){const t=Vf(e.intervals).map(t=>{const i=function(e,t){const i=t.b[0]-t.a[0],n=t.b[1]-t.a[1],r=Math.hypot(i,n),o=i/r,s=n/r,a=(e[0]-t.a[0])*o+(e[1]-t.a[1])*s,l=Math.max(0,Math.min(r,a)),c=t.a[0]+l*o,h=t.a[1]+l*s;return{along:l,length:r,x:c,y:h,distance:Math.hypot(e[0]-c,e[1]-h),perpendicular:Math.abs((e[0]-t.a[0])*s-(e[1]-t.a[1])*o)}}(e.pointer,t);return{target:t,...i,envelope:Math.max(e.baseTolerance,t.physicalHalfWidth+e.bodyPointerPadding)}}).filter(e=>e.distance<=e.envelope+1e-9).filter(t=>!function(e,t,i,n,r){const o=t.b[0]-t.a[0],s=t.b[1]-t.a[1],a=Math.hypot(o,s);if(!(a>1e-9))return!1;const l=o/a,c=s/a;for(const o of i){if(!o.open&&o.kind)continue;const i=Gf(o.a,o.b),s=i.b[0]-i.a[0],a=i.b[1]-i.a[1],h=Math.hypot(s,a);if(!(h>1e-9))continue;const d=s/h,u=a/h;if(Math.abs(l*u-c*d)>1e-6)continue;if(Math.abs((i.a[0]-t.a[0])*c-(i.a[1]-t.a[1])*l)>r)continue;const p=(e[0]-i.a[0])*d+(e[1]-i.a[1])*u,_=1e-9;if(!(p<=_||p>=h-_)&&Math.abs((e[0]-i.a[0])*u-(e[1]-i.a[1])*d)<=n+1e-9)return!0}return!1}(e.pointer,t.target,e.intervals,t.envelope,Math.max(1e-9,Math.min(e.baseTolerance,.04*e.gridStep)))),i=t.filter(t=>!!t.target.partitionHost&&e.renderedLength+2*t.target.physicalHalfWidth>t.length+1e-9).sort(Kf),n=t.filter(t=>!t.target.partitionHost||e.renderedLength+2*t.target.physicalHalfWidth<=t.length+1e-9).sort(Kf);let r=n[0];if(!r)return{candidate:null,jambBlockedTarget:i[0]?.target||null};const o=n.filter(e=>Math.abs(e.distance-r.distance)<=1e-9&&Math.abs(e.perpendicular-r.perpendicular)<=1e-9),s=o.filter(e=>e.target.partitionHost);if(s.length){if(1!==new Set(s.map(e=>e.target.partitionHost.id)).size||s.some(e=>e.target.ambiguousPartitionHost))return{candidate:null,jambBlockedTarget:null};const e=s[0],t=e.target.b[0]-e.target.a[0],i=e.target.b[1]-e.target.a[1],n=Math.hypot(t,i),a=t/n,l=i/n;if(!o.every(t=>{const i=t.target.b[0]-t.target.a[0],n=t.target.b[1]-t.target.a[1],r=Math.hypot(i,n),o=i/r,s=n/r,c=Math.abs(a*s-l*o)<=1e-6,h=Math.abs((t.target.a[0]-e.target.a[0])*l-(t.target.a[1]-e.target.a[1])*a);return c&&h<=1e-9}))return{candidate:null,jambBlockedTarget:null};r=e}if(r.target.ambiguousPartitionHost)return{candidate:null,jambBlockedTarget:null};const{target:a,length:l}=r,c=a.b[0]-a.a[0],h=a.b[1]-a.a[1],d=c/l,u=h/l,p=a.partitionHost?a.physicalHalfWidth:0,_=Math.min(Math.max(0,e.renderedLength)/2+p,l/2);let m=r.along;const g=Math.max(e.gridStep,1e-9),f=l/2;m=Math.abs(m-f)<=g/2?f:Math.round(m/g)*g,m=Math.max(_,Math.min(l-_,m));const v=a.a[0]+d*m,y=a.a[1]+u*m,b=Math.max(0,e.renderedLength)/2,w=m-b,k=m+b,x=Math.max(0,w),S=Math.max(0,l-k),$=[a.a[0]+d*(w-x/2),a.a[1]+u*(w-x/2)],M=[a.a[0]+d*(k+S/2),a.a[1]+u*(k+S/2)];let R=180*Math.atan2(h,c)/Math.PI;R>=90?R-=180:R<-90&&(R+=180);const C=Math.abs(m-f)<=1e-9;return{candidate:{presetRevision:e.preset.revision,geometryRevision:e.geometryRevision,pointer:[e.pointer[0],e.pointer[1]],type:e.preset.type,lengthCm:e.preset.lengthCm,flipH:e.preset.flipH,flipV:e.preset.flipV,x:v,y:y,angle:R,renderedLength:e.renderedLength,target:a,...a.partitionHost?{host:{...a.partitionHost,t:l>0?m/l:0}}:{},measure:{labels:[{distance:x,midpoint:$},{distance:S,midpoint:M}],guide:C?{x:v,y:y,angle:R}:null}},jambBlockedTarget:null}}function Xf(e,t,i,n,r=1e-6){return e.presetRevision===i&&e.geometryRevision===n&&Math.hypot(e.pointer[0]-t[0],e.pointer[1]-t[1])<=r}function Zf(e){return!(!e.canEdit||e.kiosk||e.fixedFloor)&&("view"!==e.mode&&("mouse"===e.pointerType&&e.spaceCount>1))}class Jf{constructor(e,t,i){this.loader=e,this.host=t,this.adopted=i,this.attachment=null}connect(){if(this.runtime)return void this.runtime.connect();this.attachment?.cancel();const e=this.loader.attach(this.host,e=>this.adopt(e));this.runtime||(this.attachment=e)}disconnect(){this.attachment?.cancel(),this.attachment=null,this.runtime?.disconnect()}adopt(e){this.attachment=null,this.runtime||(this.runtime=e,this.adopted(e))}}const Qf=new class{constructor(e){this.load=e,this.factory=null,this.pending=null}get warm(){return null!==this.factory}create(e){return this.factory?this.factory(e):null}attach(e,t){let i=!0;const n={cancel:()=>{i=!1}},r=this.create(e);return r?(t(r),n):(this.ensure().then(n=>{i&&t(n(e))},()=>{}),n)}ensure(){return this.factory?Promise.resolve(this.factory):(this.pending||(this.pending=this.load().then(e=>(this.factory=e,this.pending=null,e),e=>{throw this.pending=null,e})),this.pending)}reset(){this.factory=null,this.pending=null}}(()=>import("./summary-panel-runtime-loaded-BGIJeXIz.js").then(function(e){return e.e}).then(({LoadedSummaryPanelRuntime:e})=>t=>new e(t)));function ev(e){const t=globalThis.__HP_VERSION_OVERRIDE__;return"string"==typeof t&&t.length>0?t:e}let tv=0;const iv="1.77.0-beta.2",nv="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f",rv=1500,ov=new Map;let sv=0,av=1e4;const lv="houseplan_card_layout_v1",cv="houseplan_card_cfg_v1",hv="houseplan_card_zoom_v1",dv="houseplan_card_nav_v1",uv="houseplan_card_view_v1",pv="hp-dialog, hp-help, hp-color-opacity, hp-device-preview",_v=1e3,mv=(e,t)=>{const i=Math.min(e.x,t.x),n=Math.min(e.y,t.y);return{x:i,y:n,w:Math.max(e.x+e.w,t.x+t.w)-i,h:Math.max(e.y+e.h,t.y+t.h)-n}},gv=(e,t,i)=>{const n=new Event(t,{bubbles:!0,composed:!0});n.detail=i??{},e.dispatchEvent(n)},fv=e=>{history.pushState(null,"",e),gv(window,"location-changed",{replace:!1})},vv=(e,t)=>{let i,n=null;const r=(...r)=>{clearTimeout(i),n=r,i=window.setTimeout(()=>{i=void 0;const t=n;n=null,t&&e(...t)},t)};return r.flush=()=>{if(void 0===i)return;clearTimeout(i),i=void 0;const t=n;n=null,t&&e(...t)},r.cancel=()=>{clearTimeout(i),i=void 0,n=null},r.pending=()=>void 0!==i,r},yv=e=>{try{e.target?.setPointerCapture?.(e.pointerId)}catch{}},bv=["edges","corners"];class wv extends he{constructor(){var e;super(...arguments),this._editorRuntime=null,this._liveRt=null,this._onboardingRuntime=null,this._editorRuntimeLoadingVisible=!1,this._backdropGuard=null,this._editorModeRequest=0,this._warmModeRequest=0,this._editorRuntimeLoader=new Sf({expectedFingerprint:nv,load:async e=>{const t=0===e?await import("./houseplan-editor-runtime-BlocE3XU.js"):await import((()=>{const e=new URL("./houseplan-editor-runtime-BlocE3XU.js",import.meta.url);return e.searchParams.set("hp_retry",`${iv}-${++tv}`),e.href})());return{fingerprint:t.EDITOR_RUNTIME_FINGERPRINT,create:()=>new t.HouseplanEditorRuntime(this)}},install:e=>{this._editorRuntime=e},stateChanged:e=>this._editorRuntimeStateChanged(e),failed:(e,t)=>{console.error("[houseplan] unable to load editor runtime",e),t.terminal&&this._versionRecovery.hasCurrentMismatchNotice||this._showToast(kf(e=>this._t(e),t))}}),this._onboardingRuntimeLoader=new Sf({expectedFingerprint:nv,load:async e=>{const t=0===e?await import("./houseplan-onboarding-runtime-DYojoXE_.js"):await import((()=>{const e=new URL("./houseplan-onboarding-runtime-DYojoXE_.js",import.meta.url);return e.searchParams.set("hp_retry",`${iv}-${++tv}`),e.href})());return{fingerprint:t.ONBOARDING_RUNTIME_FINGERPRINT,create:()=>new t.HouseplanOnboardingRuntime(this)}},install:e=>{this._onboardingRuntime=e},failed:(e,t)=>{console.error("[houseplan] unable to load onboarding runtime",e),t.terminal&&this._versionRecovery.hasCurrentMismatchNotice||this._showToast(kf(e=>this._t(e),t))}}),this._isoSceneRuntime=null,this._isoSceneRuntimeLoader=new Sf({expectedFingerprint:nv,load:async e=>{const t=0===e?await import("./iso-scene-render-BfrsUAJf.js"):await import((()=>{const e=new URL("./iso-scene-render-BfrsUAJf.js",import.meta.url);return e.searchParams.set("hp_retry",`${iv}-${++tv}`),e.href})());return{fingerprint:t.ISO_SCENE_RUNTIME_FINGERPRINT,create:()=>t}},install:e=>{const t=this._effectiveProjection();this._isoSceneRuntime=e,this._isoProjectionSnapshot=null;const i=this._effectiveProjection();this._convertProjectionView(t,i),this.isConnected&&this.requestUpdate()},failed:(e,t)=>{console.warn("[houseplan] hidden isometric runtime diagnostic",wf("runtime-load","unverified",t.terminal)),this.isConnected&&this.requestUpdate()}}),this._pdfRuntime=null,this._pdfRuntimeLoader=new Sf({expectedFingerprint:nv,load:async e=>{const t=0===e?await import("./pdf-export-Bslsp3h0.js"):await import((()=>{const e=new URL("./pdf-export-Bslsp3h0.js",import.meta.url);return e.searchParams.set("hp_retry",`${iv}-${++tv}`),e.href})());return{fingerprint:t.PDF_EXPORT_FINGERPRINT,create:()=>new t.PdfExportRuntime}},install:e=>{this._pdfRuntime=e,this.isConnected&&this.requestUpdate()},failed:(e,t)=>{if(console.error("[houseplan] unable to load PDF export runtime",e),!t.terminal||!this._versionRecovery.hasCurrentMismatchNotice){const e=kf(e=>this._t(e),t),i=this._t("editor.load_failed"),n=e.startsWith(i)?e.slice(i.length).trim():e;this._showToast(`${this._t("pdf.failed")} ${n}`.trim())}}}),this.panelHost=!1,this.narrow=null,this._space="f1",this._adoption=new qu((e,t)=>this.requestUpdate(e,t)),this._serverStorage=!1,this._loadOk=!1,this._serverCanWrite=null,this._loading=!1,this._loadTries=0,this._unsubCfg=null,this._unsubLayout=null,this._unsubVirtual=null,this._liveSyncAttempt=null,this._liveSyncGeneration=0,this._liveSyncConnection=null,this._configReloadAuthority=new Gu,this._virtualLights=Hh(null),this._canOptimizeUndo=!1,this._undoKind=null,this._devices=[],this._regSignature="",this._defPos={},this._newSyncKey="",this._areaRelocationIds=new Set,this._areaSnapshotCleanupCandidates=new Map,this._areaRelocationSyncKey="",this._areaRelocationWrite=Promise.resolve(),this._tip=null,this._hoverRoom=null,this._pointerModality=new sg(this,()=>this._syncPointerHoverTargets()),this._devicePressAnimations=new Map,this._selId=null,this._toast="",this._mode="view",this._pendingNavMode=null,this._decorTool="select",this._decorStyle={...Cr},this._decorStyleSeeded=!1,this._decorDraft=null,this._decorMove=null,this._decorSel=null,this._decorEraseConfirm=null,this._decorTextDialog=null,this._decorShapeDialog=null,this._backdropDialog=null,this._decorTextSelection={start:0,end:0},this._furnPalette=null,this._decorImagePalette=null,this._decorAssetCatalog=[],this._decorAssets=new Map,this._decorAssetBusy=!1,this._furnCategory=null,this._furnPreviewInput=null,this._furnTouchPending=null,this._dtBox=null,this._dtDrag=null,this._bdDrag=null,this._slide="",this._reducedMotion=!1,this._onMotionChange=e=>{this._reducedMotion=e.matches,this._cancelDevicePressFeedback(),e.matches&&this._cancelCameraTransition(!0),e.matches&&this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:e.matches&&this._modeTransition.active&&this._cancelModeTransition(!0),this._syncVersionRecovery(),this.requestUpdate()},this._editorChromeMode="plan",this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest=0,this._modeTransitionTargetZoom=1,this._modeTransitionEditorCamera=null,this._modeTransition=new Ug({frame:e=>this._applyModeTransitionFrame(e),settled:e=>this._settleModeTransition(e)}),this._cameraTransitionFit=null,this._cameraTransition=new Qg({frame:e=>this._applyCameraTransitionFrame(e),settled:e=>this._settleCameraTransition(e)}),this._editorSecondaryCopy={groupActive:(e,t)=>this._t("editor.group_active",{group:e,item:t}),openGroup:e=>this._t("editor.open_group",{group:e}),disabledAction:(e,t)=>this._t("editor.disabled_action",{action:e,reason:t})},this._tool="draw",this._geometryHistory=new gg(50),this._devicePositionHistory=new gg(50),this._devicePositionBusy=!1,this._wallDialog=null,this._drawWallField=null,this._activeWallChainId=null,this._activeWallChainPartitionIds=[],this._wallChainRedo=[],this._physicalSel=null,this._physicalDialog=null,this._partitionDeleteDialog=null,this._roomDeleteDialog=null,this._physicalDrag=null,this._physicalRotate=null,this._physicalLastTap=null,this._physicalPickCycle=null,this._wallUnionCacheValue=null,this._wallUnionPool=new Map,this._isoGeometryCache=new Map,this._renderIsoScene=null,this._isoProjectionSnapshot=null,this._isoStructuralBuildCount=0,this._isoFallback=new Set,this._openingTunnelCache=null,this._openingWallIndexCache=new Map,this._openingPlacementIntervalsCache=null,this._openingDimensionContextCache=null,this._planSnapGeometryCache=null,this._planStructuralGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._physicalBodiesCache=null,this._lightPhysicalBodiesCache=null,this._cleanFloorCache=new Map,this._innerContourCache=new Map,this._glowRuntimeState=bm(),this._glowRuntimeHost={window:()=>this.ownerDocument.defaultView||window,isConnected:()=>this.isConnected,requestUpdate:()=>this.requestUpdate(),reducedMotion:()=>this._reducedMotion},this._lightBarrierCache=null,this._lightBarrierPool=new Map,this._glowScreenBlend=!1,this._duplicateColumnId=null,this._duplicateColumnTimer=0,this._rszLimitViolation=null,this._path=[],this._cursorPt=null,this._planSnapHover=null,this._mergeSel=null,this._openingPreset=null,this._openingRebindId=null,this._openingPresetRevision=0,this._openingHoverCandidate=null,this._openingJambBlockCm=null,this._openingDialog=null,this._openingInfo=null,this._opDrag=null,this._opMeasure=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._wallFaceBatch=null,this._wallRepairDiagnostic=null,this._wallFaceGraphCache=[],this._areaSel="",this._nameSel="",this._roomDialog=!1,this._roomEditId=null,this._roomFill="",this._roomCustomFill=null,this._roomTempMin="",this._roomTempMax="",this._roomTempSrc="",this._roomHumSrc="",this._roomSrcOpen=null,this._roomSrcFilter="",this._roomNameScale=1,this._roomLabelScale=1,this._zoom=1,this._view=null,this._zoomBySpace={},this._viewModeSnap=null,this._roomFocus=null,this._roomPointer=null,this._doubleFit=new ff,this._deviceHits=new wc,this._pointers=new Map,this._panStart=null,this._panLock=null,this._pinchStart=null,this._safeDayCycleOutline=!1,this._suppressClick=!1,this._viewportGestureDirty=!1,this._touchContacts=new Map,this._touchClickGuard=new pc,this._connectedPath="",this._routeDepartureHandled=!1,this._onLocationChanged=()=>{this._connectedPath&&location.pathname!==this._connectedPath?this._leaveCardRoute():location.pathname===this._connectedPath&&(this._routeDepartureHandled=!1)},this._touchGestureGuard={capture:!0,handleEvent:e=>this._guardTouchGesture(e)},this._hdrH=118,this._booting=!0,this._bootFading=!1,this._bootSettling=!1,this._bootSettleRaf=0,this._bootLastH=-1,this._bootStart=0,this._bootLastChange=0,this._bootSoft=!1,this._tapConfirm=null,this._dangerConfirm=null,this._dangerConfirmController=new ze(e=>{this._dangerConfirm=e}),this._confirmDanger=e=>this._config&&this.hass?"warm"===this._syncDangerConfirmLocaleGate()||this._dangerConfirmMissingSpace()?Promise.resolve(!1):this._dangerConfirmController.confirm(e):Promise.resolve(!1),this._cancelDangerConfirm=()=>{this._dangerConfirmController.cancel()},this._onDangerConfirmDecision=e=>{this._dangerConfirmController.resolve(e.detail.token,e.detail.accepted)},this._onboardingShown=!1,this._rulesDialog=null,this._preflightClipboardFallback=null,this._haIntegrationVersion=null,this._versionRecovery=(e=this,new wg({clock:{setTimeout:(e,t)=>window.setTimeout(e,t),clearTimeout:e=>window.clearTimeout(e)},storage:()=>e.ownerDocument.defaultView?.sessionStorage??null,safety:()=>Sg(e),reload:()=>e._reloadDocument(),changed:()=>{e.requestUpdate()}})),this._haSupportApi=null,this._haDecorAssetsApi=null,this._haSummaryPanelApi=null,this._haRadarStage1Api=null,this._radarLive=new Ag(this),this._decorAssetSyncToken=0,this._alignDialog=null,this._settingsDialog=null,this._pdfDialog=!1,this._supportDialog=null,this._backupExportDialog=null,this._backupImportDialog=null,this._sunRaysCache=null,this._dayCycleTimer=0,this._dayCycleClockKey="",this._compassDrag=!1,this._importDialog=null,this._importQueue=[],this._importTotal=0,this._rulesCompiledSrc="",this._infoCard=null,this._nativeMoreInfoEntity=null,this._deviceInbox=null,this._deviceInboxReturn=null,this._deviceInboxMemo=null,this._markerDialog=null,this._spaceDialog=null,this._keyHandler=e=>this._onKey(e),this._warmVp=null,this._warmVpArmed=!1,this._warmLongReturn=!1,this._warmRevivePending=!1,this._warmGen=++sv,this._warmKey=null,this._warmSlot=null,this._hashApplied=!1,this._navApplied=!1,this._labs={alpha:!1,active:Object.freeze([]),space:""},this._viewPreference={},this._renderProjection="flat",this._kioskScale={icon:1,font:1},this._kioskDialog=!1,this._summarySlot=new Jf(Qf,this,e=>{this._summary=e,this._capturedSnapshotSequence=-1,this.isConnected&&(e.connect(),this.hasUpdated&&this.requestUpdate())}),this._activityRt=new Map,this._vacRt=new Map,this._vacViewKey="",this._vacLastView=null,this._vacRaf=0,this._vacSrvTrails={},this._vacJumpOnce=!1,this._continuity=this._newContinuityController(),this._continuityHistory=[],this._continuityEpoch=0,this._continuityDataReady=!0,this._continuityPaintToken=-1,this._continuityDisposed=!1,this._renderSnapshotAt=Date.now(),this._hassSequence=0,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotSequence=-1,this._capturedSnapshotDevices=null,this._capturedSnapshotLayout=null,this._capturedSnapshotActivity="",this._capturedSnapshotConfigEpoch=-1,this._capturedSnapshotVirtual="",this._lastValidStageSize=null,this._pendingRefitSize=null,this._refitRaf=0,this._pageVisibility=e=>{if(this._continuity.visibility(e),this._dayCycleVisibility(e),this._summary?.visibility(e.kind),"hidden"===e.kind)return this._radarLive.stop(),this._editorRuntime?._cancelRadarSetup(),this._clearRoomFocus(!0),this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._cancelCameraTransition(!0),void(this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:this._cancelModeTransition(!0));if(this._vacJumpOnce=!0,this._syncRadarLive(),!e.long){const e=Date.now();let t=!1;for(const i of this._activityRt.values())!i.flashKind||(i.expiresAt||i.flashTs+tg)>e||(i.flashTs=0,i.flashKind=null,i.expiresAt=0,t=!0);return void(t&&this.requestUpdate())}Date.now()-this._renderSnapshotAt>1e3&&this._continuity.note("device-snapshot-stale"),this._continuityDataReady=!1,this._continuityPaintToken=-1,this._resumeSettling=!0,this._loading?this.requestUpdate():this._loadFromServer()},this._resumeSettling=!1,this._viewportInvalidAt=0,this._vacFit=null,this._vacAllCamerasFor=null,this._vacAllCameraCache=null,this._vacCalConfirm=null,this._kioskDots=!1,this._cyclePausedUntil=0,this._swipeStart=null,this._tabDrag=null,this._tabDragRelease=null,this._tabSuppressClick=!1,this._tabOrderWarned=!1,this._onLabsSnapshot=e=>{const t=this._effectiveProjection();this._labs=e,this._isoProjectionSnapshot=null,this._labsIso&&this._ensureIsoSceneRuntime();const i=this._effectiveProjection();this._convertProjectionView(t,i),this.requestUpdate()},this._onHashChange=()=>{if(this._hasFixedFloor)return;const e=this._hashSpace();if(e&&this._model.find(t=>t.id===e)&&e!==this._space){if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return;this._commitSpace(e),this._selId=null,this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeWallChainId=null,this._activeWallChainPartitionIds=[],this._wallChainSegmentCms=[],this._closingWallCm=null,this._restoreZoom(),this.requestUpdate()}},this._drag=null,this._deviceDrag=null,this._rlResize=null,this._holdFired=!1,this._retryContinuity=()=>{this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.retry(this._continuity.recoveryReason||"plan"),this._loading||this._loadFromServer()},this._cfgEpoch=0,this._cfgEpochPreservedConfig=null,this._terminalFrame=0,this._modelCache=null,this._emptySpaceStateActive=!1,this._decorSnapCache=null,this._markerPreviewMemo=null,this._markerPreviewDevicesMemo=null,this._showHidden=!1,this._connHooked=null,this._connectionWasLost=!1,this._haRegistryConnection=null,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._renderLife=new $g,this._liveEditorPaintCount=0,this._onHaRegistryUpdate=()=>{const e=nd(this.hass);e.revision===this._haRegistryRev&&this._devices.length||(this._haRegistryRev=e.revision,this._renderLife.invalidate(),this._planHassMemo=null,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate())},this._onConnReady=()=>{if(this._loadTries=0,clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,id(this.hass),this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(this._onConnReady,400));!this._connectionWasLost&&this._continuity.hasCompleteFrame?this._beginContinuityCandidate("connection-ready",!1,"plan"):(this._continuityDataReady=!1,this._continuityPaintToken=-1),this._loading||this._loadFromServer()},this._onConnLost=()=>{this._booting&&!this._continuity.hasCompleteFrame||(this._connectionWasLost=!0,this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.connectionLost())},this._signer=new uc(()=>this.requestUpdate()),this._dirtyPos=new Set,this._sentPos=new Map,this._persistLayout=vv(()=>{if(this._serverStorage){const e=[...this._dirtyPos];this._dirtyPos.clear();for(const t of e){const e=xo(this._layout[t]);e&&(this._layout={...this._layout,[t]:e},this._sentPos.set(t,e),this.hass.callWS({type:"houseplan/layout/update",device_id:t,pos:e}).then(e=>this._noteLayoutRev(e)).catch(e=>this._showToast(this._t("toast.pos_save_failed",{err:this._errText(e)}))).finally(()=>{this._sentPos.get(t)===e&&this._sentPos.delete(t)}))}this._cacheSnapshot()}else this._persistLocalLayout()},600),this._frame=null,this._showFar=!1,this._writesPending=0,this._writeChain=Promise.resolve(),this._pendingPhysicalWrites=new Map,this._undoGeometry=()=>this._editorRuntimeOrThrow()._undoGeometry(),this._redoGeometry=()=>this._editorRuntimeOrThrow()._redoGeometry(),this._saveConfigDebounced=vv(()=>{this._serverCfg&&this._writeConfig().catch(e=>{const t=!0===e?.physicalGeometryRolledBack;"geometry-unsafe"!==e?.code&&("wall_model_client_outdated"===e?.code?this._showToast(this._t("toast.wall_model_client_outdated")):"conflict"===e?.code?(this._showToast(this._t("toast.conflict")),t||(this._cancelPath(),this._reloadConfigOnly(!0))):this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(e)})),t&&this._reloadRejectedPhysicalWrite())})},500),this._wallChainSegmentCms=[],this._closingWallCm=null,this._savePhysicalDialog=()=>this._editorRuntimeOrThrow()._savePhysicalDialog(),this._deletePhysicalSelection=()=>this._editorRuntimeOrThrow()._deletePhysicalSelection(),this._confirmPartitionDelete=()=>this._editorRuntimeOrThrow()._confirmPartitionDelete(),this._confirmRoomDelete=e=>this._editorRuntimeOrThrow()._confirmRoomDelete(e),this._rebindPartitionOpening=()=>this._editorRuntimeOrThrow()._rebindPartitionOpening(),this._keepClosedAsPartitions=()=>this._editorRuntimeOrThrow()._keepClosedAsPartitions(),this._toggleServerPlans=async()=>this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._toggleServerPlans():this._editorRuntimeOrThrow()._toggleServerPlans(),this._aspectJob=null,this._dayCycleTick=()=>{if(!this.isConnected||"hidden"===this.ownerDocument.visibilityState)return;const e=this._dayCycleState();if(!e)return this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),void(this._dayCycleClockKey="");const t=cr(e);t!==this._dayCycleClockKey&&(this._dayCycleClockKey=t,this.requestUpdate())},this._sunShown=!1,this._sunOut=!1,this._sunOutTimer=0,this._openSettingsDialog=()=>{if(this._editorRuntime)return this._editorRuntime._openSettingsDialog();this._ensureEditorRuntime().then(e=>{e&&this._openSettingsDialog()})},this._openSupportDialog=()=>{this._editorRuntime?this._editorRuntime._openSupportDialog():this._ensureEditorRuntime().then(e=>{e&&this._openSupportDialog()})},this._openPdfDialog=()=>{this._pdfRuntimeLoader.ensure().then(e=>{e&&(this._pdfDialog=!0,this.requestUpdate())})},this._reportedPreflightFingerprint=null,this._openAlignDialog=()=>this._editorRuntimeOrThrow()._openAlignDialog(),this._toggleOptimizeLivePositions=()=>this._editorRuntimeOrThrow()._toggleOptimizeLivePositions(),this._optimizeUndoBusy=!1,this._openBackupExport=()=>this._editorRuntimeOrThrow()._openBackupExport(),this._openRulesDialog=()=>this._editorRuntimeOrThrow()._openRulesDialog(),this._climateCache=null,this._gearPtCache=new WeakMap}requestUpdate(e,t,i){if("hass"===e&&this.hass&&this._liveRt){const e=this._visibleDeviceSnapshot||this._candidateDeviceSnapshot;if(!this._liveRt.hass(t,this.hass,e?{entityIds:e.entityIds}:null,()=>Mg(this))&&!this._summary?.observeHassComposition())return}void 0!==e&&(this._terminalFrame=0),this._editorRuntime?._routeLiveEditorUpdate(e,t)||(this._liveRt?.clear(),super.requestUpdate(e,t,i))}_editorRuntimeOrThrow(){if(!this._editorRuntime)throw new Error("Houseplan editor runtime is not loaded");return this._editorRuntime}async _ensureEditorRuntime(){return this._editorRuntimeLoader.ensure()}async _ensureOnboardingRuntime(){return this._onboardingRuntimeLoader.ensure()}async _ensureIsoSceneRuntime(){return this._isoSceneRuntimeLoader.ensure()}_editorRuntimeStateChanged(e){clearTimeout(this._editorRuntimeLoadingTimer),this._editorRuntimeLoadingTimer=void 0,"loading"!==e?(this._editorRuntimeLoadingVisible=!1,this.requestUpdate()):this._editorRuntimeLoadingTimer=window.setTimeout(()=>{this._editorRuntimeLoadingVisible=!0,this.requestUpdate()},150)}async _requestMode(e,t=!0,i=!1){const n=++this._editorModeRequest;if(i&&(this._warmModeRequest=n,this._refitRaf&&(cancelAnimationFrame(this._refitRaf),this._refitRaf=0),this._pendingRefitSize=null),"view"===e||await this._ensureEditorRuntime()){if(n===this._editorModeRequest&&this.isConnected)return i?(this._adoptMode(e),this._warmRevivePending&&(clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmReviveDialog()),this.requestUpdate(),void this.updateComplete.then(()=>requestAnimationFrame(()=>requestAnimationFrame(()=>{if(this._warmModeRequest!==n||n!==this._editorModeRequest)return;const e=this._stageEl;this._lastValidStageSize=e&&e.clientWidth>0&&e.clientHeight>0?[e.clientWidth,e.clientHeight]:null,this._pendingRefitSize=null,this._warmModeRequest=0})))):void this._setMode(e,t);this._warmModeRequest===n&&(this._warmModeRequest=0)}else this._warmModeRequest===n&&(this._warmModeRequest=0)}get _layout(){return this._adoption.layout}set _layout(e){this._adoption.stageLocalLayout(e)}get _layoutRev(){return this._adoption.layoutRev}set _layoutRev(e){this._adoption.seedIdentity({layoutRev:e})}get _layoutContentFingerprint(){return this._adoption.layoutFingerprint}set _layoutContentFingerprint(e){this._adoption.seedIdentity({layoutFingerprint:e})}get _serverCfg(){return this._adoption.config}set _serverCfg(e){this._adoption.stageLocalConfig(e)}get _cfgRev(){return this._adoption.configRev}set _cfgRev(e){this._adoption.seedIdentity({configRev:e})}get _cfgContentFingerprint(){return this._adoption.configFingerprint}set _cfgContentFingerprint(e){this._adoption.seedIdentity({configFingerprint:e})}_seedDecorStyle(e){var t,i;if(t=Ol,i=this,Fl(e,Bl)&&"pending"===t.state()&&(t.art("",i),t.ensure()),this._decorStyleSeeded||!e)return;this._decorStyleSeeded=!0;const n=e.settings?.decor_default_style;n&&(this._decorStyle=function(e,t){if(!e||"object"!=typeof e)return{...t};const i=e,n="string"==typeof i.color&&i.color?i.color:t.color,r="string"==typeof i.fill_color&&i.fill_color?i.fill_color:t.fillColor,o=Number(i.width_cm);return{color:n,opacity:Tr(i.opacity,t.opacity),widthCm:Number.isFinite(o)&&o>0?Math.max(.1,Math.min(100,o)):t.widthCm,fill:"boolean"==typeof i.fill?i.fill:t.fill,fillColor:r,fillOpacity:Tr(i.fill_opacity,t.fillOpacity)}}(n,Cr))}get _canManageConfiguration(){return null!==this._serverCanWrite?this._serverCanWrite:!0===this.hass?.user?.is_admin}get _canEdit(){return this._norm&&this._canManageConfiguration}get _kiosk(){return!!this._config?.kiosk}_showKioskDots(){this._kioskDots=!0,clearTimeout(this._kioskDotsTimer),this._kioskDotsTimer=window.setTimeout(()=>this._kioskDots=!1,2500)}get _modeTransitionBusy(){return this._modeTransitionPreparing||this._modeTransition.active}get _doubleFitEnabled(){return!("view"!==this._mode||this._vacFit||this._modeTransitionBusy||this._touchSequenceMultitouch||"steady"!==this._continuity.state||this._continuity.overlayBlocksInteraction)}_cameraState(){const e=this._viewOr(this._baseVb());return{zoom:this._zoom,viewBox:{...e}}}_normalizeCameraState(e){const t=this._cameraTransitionFit||Oi(this._baseVb(),this._stageAspect());return{zoom:Math.min(wv.ZOOM_MAX,Math.max(wv.ZOOM_MIN,e.zoom)),viewBox:this._clampView({...e.viewBox},t)}}_applyCameraTransitionFrame(e){const t=this._normalizeCameraState(e.presented);e.presented=t,this._zoom=t.zoom,this._view={...t.viewBox},this._liveVp(!0)}_settleCameraTransition(e){const t=this._normalizeCameraState(e.to);this._zoom=t.zoom,this._view={...t.viewBox},this._cameraTransitionFit=null,"room"!==e.reason&&this._saveZoom(),this.requestUpdate()}_cancelCameraTransition(e=!1,t=!1){const i=this._cameraTransition.state?.reason,n=t&&this._cameraTransition.active?this._cameraTransition.presented?.zoom:void 0;this._cameraTransition.cancel(e),this._cameraTransitionFit=null,void 0!==n&&"room"!==i&&this._saveZoom()}_prepareCameraCommand(){this._bootSoftCancel(),this._modeTransitionBusy&&this._cancelModeTransition(!0),"opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1))}_startCameraTransition(e,t,i,n){const r=this._cameraState(),o=this._cameraTransition.target;return(!o||!Xg(o,e))&&(Xg(r,e)?(this._cancelCameraTransition(!1),!1):(this._activateSafeDayCycleOutline(),this._cameraTransitionFit={...t},this._cameraTransition.start(r,e,i,this._reducedMotion?0:n),!0))}_cssColor(e,t){const i=String(e||"").trim();if(!i)return t;const n=document.createElement("span");n.style.cssText=`position:absolute;visibility:hidden;color:${i}`,this.renderRoot.append(n);const r=getComputedStyle(n).color||t;return n.remove(),r}_currentModeVisual(e=this._mode){const t=this._modeTransition.presented||this._modeTransitionVisual;if(t)return{...t,viewport:{...t.viewport,viewBox:{...t.viewport.viewBox}}};const i=this._stageEl;if(!i||i.clientWidth<=0||i.clientHeight<=0)return null;const n=this.renderRoot.querySelector(".editorchrome"),r=this._viewOr(this._baseVb()),o=this.renderRoot.querySelector(".hp-paper"),s=this.renderRoot.querySelector(".hp-backdrop"),a=this.renderRoot.querySelector(".zoomwrap"),l=a?getComputedStyle(a).filter:"",c=Number(/brightness\(([^)]+)\)/.exec(l)?.[1]);return{presentedMode:e,editorChromeHeight:"view"===e?0:n?.getBoundingClientRect().height||0,stageWidth:i.clientWidth,stageHeight:i.clientHeight,viewport:Bg(r,i.clientWidth),stageColor:getComputedStyle(i).backgroundColor||"rgb(255, 255, 255)",paperColor:o?getComputedStyle(o).fill:"rgb(255, 255, 255)",sceneBrightness:Number.isFinite(c)?c:1,architectureOpacity:"decor"===e?.35:1,backdropOpacity:s&&Number(getComputedStyle(s).opacity)||1,viewWeight:"view"===e?1:0,editorWeight:"view"===e?0:1,toolbarContentOpacity:"view"===e?0:1}}_viewForModeTarget(e,t,i,n,r){const o=Oi(this._baseVb(),n/r),s=Math.min(wv.ZOOM_MAX,Math.max(wv.ZOOM_MIN,e)),a=o.w/s,l=o.h/s,c=t??o.x+o.w/2,h=i??o.y+o.h/2;return this._clampView({x:c-a/2,y:h-l/2,w:a,h:l},o)}_targetStageColor(e){return"view"!==e?"rgb(255, 255, 255)":this._cssColor(this._stageBg(this._spaceDisplayForRender()),this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"))}_targetPaperColor(e){return"view"===e&&this._spaceModel()?.bg?this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"):"rgb(255, 255, 255)"}_targetBrightness(e){return 1}_applyModeTransitionFrame(e){e.targetMode===this._mode&&(this._modeTransitionVisual=e.presented,this._view={...e.presented.viewport.viewBox},this.requestUpdate())}_settleModeTransition(e){if(e.targetMode!==this._mode)return;const t=this._modeTransitionRequest;this._view={...e.to.viewport.viewBox},this._zoom=this._modeTransitionTargetZoom,this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._lastValidStageSize=[e.to.stageWidth,e.to.stageHeight],"view"===this._mode&&(this._saveZoom(),this._viewModeSnap=null,this._modeTransitionEditorCamera=null),this.requestUpdate(),this.updateComplete.then(()=>{if(!this.isConnected||t!==this._modeTransitionRequest||this._modeTransitionBusy||e.targetMode!==this._mode)return;const i=this._stageEl;if(i&&i.clientWidth>0&&i.clientHeight>0&&(Math.abs(i.clientWidth-e.to.stageWidth)>.5||Math.abs(i.clientHeight-e.to.stageHeight)>.5)){const e=this._view;this._lastValidStageSize=[i.clientWidth,i.clientHeight],this._applyView(this._zoom,e?e.x+e.w/2:void 0,e?e.y+e.h/2:void 0),this.requestUpdate()}const n=this.renderRoot.activeElement;(!n||!n.isConnected||!!n.closest?.(".editorchrome, .stage"))&&this.renderRoot.querySelector(".modetab.active")?.focus?.({preventScroll:!0})})}_cancelModeTransition(e=!0){this._cancelCameraTransition(!1);const t=!!this._modeTransition.state;this._modeTransitionRequest++,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransition.cancel(e),e&&t||(this._modeTransitionVisual=null)}_adoptMode(e){e!==this._mode&&(this._clearRoomFocus(!0),this._resetDeviceHitState()),this._cancelModeTransition(!1),this._mode=e,this._isoProjectionSnapshot=null,"view"!==e&&(this._editorChromeMode=e)}_commitViewModeAtomic(e,t,i,n){if(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this._zoom=t,e){const r=this._stageEl?.clientWidth||e.stageWidth,o=Math.max(1,e.stageHeight+e.editorChromeHeight);this._view=this._viewForModeTarget(t,i,n,r,o),this._lastValidStageSize=[r,o]}else this._view=null;this._viewModeSnap=null,this._modeTransitionEditorCamera=null,this._saveZoom(),this.requestUpdate()}_prepareModeTransition(e,t,i,n,r,o){this.updateComplete.then(()=>{if(!this.isConnected||e!==this._modeTransitionRequest||this._mode!==i)return void(e===this._modeTransitionRequest&&(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this.requestUpdate()));const s=this.renderRoot.querySelector(".editorchrome-inner"),a="view"===i?0:s?.scrollHeight||0,l=Math.max(1,(this.panelHost?this.clientHeight:innerHeight)-ef(this.renderRoot,this._stageEl,this.panelHost)),c=this._stageEl?.clientWidth||t.stageWidth,h=this._viewForModeTarget(n,r,o,c,l),d={presentedMode:i,editorChromeHeight:a,stageWidth:c,stageHeight:l,viewport:Bg(h,c),stageColor:this._targetStageColor(i),paperColor:this._targetPaperColor(i),sceneBrightness:this._targetBrightness(i),architectureOpacity:"decor"===i?.35:1,backdropOpacity:"decor"===i&&"backdrop"!==this._decorTool?.5:1,viewWeight:"view"===i?1:0,editorWeight:"view"===i?0:1,toolbarContentOpacity:"view"===i?0:1};this._modeTransitionPreparing=!1;const u=this._modeTransitionForceAtomic;this._modeTransitionForceAtomic=!1,this._modeTransition.start(t,d,i,this._reducedMotion||u?0:220)})}get _hasFixedFloor(){return!!this._config&&Object.prototype.hasOwnProperty.call(this._config,"floor")}_fixedFloorState(e=this._model,t=this._loadOk){const i=this._config?.floor,n=function(e){if(!e.hasFloor)return{kind:"absent"};const t=e.floor;if("string"==typeof t)return t.length?e.spaceIds.includes(t)?{kind:"valid",id:t,source:"id"}:{kind:"invalid",reason:"unknown-id",value:t}:{kind:"invalid",reason:"empty-id",value:t};if("number"==typeof t){if(!Number.isFinite(t))return{kind:"invalid",reason:"non-finite-index",value:t};if(!Number.isInteger(t))return{kind:"invalid",reason:"fractional-index",value:t};if(t<0)return{kind:"invalid",reason:"negative-index",value:t};const i=e.spaceIds[t];return void 0===i?{kind:"invalid",reason:"out-of-range-index",value:t}:{kind:"valid",id:i,source:"index"}}return{kind:"invalid",reason:"invalid-type",value:t}}({spaceIds:e.map(e=>e.id),hasFloor:this._hasFixedFloor,floor:i});return!this._hasFixedFloor||t?n:"number"==typeof i?"valid"===n.kind||"invalid"===n.kind&&"out-of-range-index"===n.reason?{kind:"pending",value:i}:n:"valid"===n.kind||"invalid"===n.kind&&"unknown-id"!==n.reason?n:{kind:"pending",value:i}}_canCommitSpace(e,t=!1){if(t||!this._hasFixedFloor)return!0;const i=this._fixedFloorState();return"valid"===i.kind&&i.id===e}_commitSpace(e,t=!1){return!!this._canCommitSpace(e,t)&&(e!==this._space&&(this._clearRoomFocus(!0),this._resetDeviceHitState(),this._cancelDangerConfirm(),this._cancelCameraTransition(!1),this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._editorRuntime?._clearFurniturePreview()),this._space=e,this._isoProjectionSnapshot=null,!0)}_slideTo(e,t){if(e===this._space)return!0;if(!this._canCommitSpace(e))return!1;if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return!1;this._cancelModeTransition(!0);const i=window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;return this._commitSpace(e),this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeWallChainId=null,this._activeWallChainPartitionIds=[],this._wallChainSegmentCms=[],this._closingWallCm=null,this._selId=null,this._physicalSel=null,this._editorSecondary?.closeForNavigation(),this._physicalDialog=null,this._physicalDrag=null,this._restoreZoom(),i||(this._slide=t,clearTimeout(this._slideTimer),this._slideTimer=window.setTimeout(()=>{this._slideTimer=void 0,this._slide="",this.requestUpdate()},190),this.requestUpdate()),!0}get _canReorderTabs(){return Zf({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:"mouse",spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})}_tabPointerDown(e,t){Zf({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:e.pointerType,spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})&&(yv(e),this._tabDragRelease=e=>this._tabPointerUp(e),window.addEventListener("pointerup",this._tabDragRelease),window.addEventListener("pointercancel",this._tabDragRelease),this._tabDrag={id:t,pointerId:e.pointerId,x:e.clientX,y:e.clientY,moved:!1,targetId:null,placement:null})}_tabDropTargetAt(e,t,i){const n=this._model.map(e=>e.id),r=n.indexOf(i);if(r<0)return null;const o=this.renderRoot.querySelectorAll('[data-hp="space-tab"]');for(const s of o){const o=s.dataset.id||"";if(!o||o===i)continue;const a=s.getBoundingClientRect();if(ea.right||ta.bottom)continue;const l=n.indexOf(o);return l<0?null:{targetId:o,placement:l=4)))return;var i,n;const r=this._tabDropTargetAt(e.clientX,e.clientY,t.id);t.moved&&t.targetId===r?.targetId&&t.placement===r?.placement||(this._tabDrag={...t,moved:!0,targetId:r?.targetId||null,placement:r?.placement||null})}_tabPointerUp(e){const t=this._tabDrag;if(t&&t.pointerId!==e.pointerId)return;const i="pointerup"===e.type&&t?.moved?this._tabDropTargetAt(e.clientX,e.clientY,t.id):null;"pointerup"===e.type&&t?.moved&&this._suppressNextTabClick(),this._endTabDrag(),t?.moved&&i&&this._commitTabOrder(t.id,i.targetId)}_endTabDrag(){this._tabDrag=null,this._tabDragRelease&&(window.removeEventListener("pointerup",this._tabDragRelease),window.removeEventListener("pointercancel",this._tabDragRelease),this._tabDragRelease=null)}_tabClick(e){if(this._tabSuppressClick)return this._tabSuppressClick=!1,clearTimeout(this._tabSuppressClickTimer),void(this._tabSuppressClickTimer=void 0);this._pickSpace(e)}_suppressNextTabClick(){this._tabSuppressClick=!0,clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=window.setTimeout(()=>{this._tabSuppressClick=!1,this._tabSuppressClickTimer=void 0},0)}_commitTabOrder(e,t){const i=this._serverCfg;if(!i||!this._canReorderTabs)return;const n=this._model.map(e=>e.id),r=function(e,t,i){const n=e.indexOf(t),r=e.indexOf(i);if(n<0||r<0||n===r)return e;const o=e.slice();return o.splice(n,1),o.splice(r,0,t),o}(n,e,t);if(r===n)return;const o=new Map(this._devices.map(e=>[String(e.id),String(e.area||"")])),s=function(e,t,i,n=()=>""){if(!i)return[];const r=[];for(const o of e){if(!o||!0===o.removed)continue;const e="string"==typeof o.id?o.id:"";if(!e)continue;if("string"==typeof o.space&&o.space)continue;const s=("string"==typeof o.area?o.area:"")||n(e)||"";s&&t[s]||r.push({id:e,space:i})}return r}(i.markers||[],Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),n[0]||"",e=>o.get(e)||"");if(s.length){const e=new Map(s.map(e=>[e.id,e.space]));for(const t of i.markers||[]){const i=e.get(String(t.id));i&&(t.space=i)}}i.spaces=function(e,t){const i=new Map(t.map((e,t)=>[e,t]));return e.map((e,t)=>({space:e,index:t})).sort((e,t)=>(i.get(String(e.space?.id))??Number.MAX_SAFE_INTEGER)-(i.get(String(t.space?.id))??Number.MAX_SAFE_INTEGER)||e.index-t.index).map(e=>e.space)}(i.spaces||[],r),this._saveConfig(),this._tabOrderWarned||(this._tabOrderWarned=!0,this._showToast(this._t("toast.space_order_changed")))}_pickSpace(e){if(this._endTabDrag(),e===this._space)return;const t=this._model.map(e=>e.id),i=t.indexOf(this._space),n=t.indexOf(e);this._navApplied=!0,this._showFar=!1,this._frame=null,this._slideTo(e,i>=0&&n0&&Date.now()>=this._cyclePausedUntil&&this._model.length>1&&this._zoom<=1.001){const e=this._model.map(e=>e.id),t=e.indexOf(this._space);this._slideTo(e[(t+1)%e.length],"left"),this._showKioskDots()}}_syncCycleTimer(){clearInterval(this._cycleTimer),this._cycleTimer=void 0,this.isConnected&&!this._hasFixedFloor&&this._config?.kiosk&&Number(this._config.cycle)>0&&(this._cycleTimer=window.setInterval(()=>this._cycleTick(),1e3*Number(this._config.cycle)))}get _editing(){return"plan"===this._mode||"devices"===this._mode||"decor"===this._mode}get _markup(){return"plan"===this._mode}get _wallUnionCache(){return this._wallUnionCacheValue}set _wallUnionCache(e){this._wallUnionCacheValue=e,null===e&&this._wallUnionPool.clear()}get _glowClipCache(){return this._glowRuntimeState.clipCache}get _glowGeometryWarnings(){return this._glowRuntimeState.geometryWarnings}get _glowFeatherUnits(){return this._glowRuntimeState.featherUnits}set _glowFeatherUnits(e){this._glowRuntimeState.featherUnits=e}get _glowRenderedSources(){return this._glowRuntimeState.renderedSources}get _glowLastAppearance(){return this._glowRuntimeState.lastAppearance}get _glowFeatherSuspendUntil(){return this._glowRuntimeState.featherSuspendUntil}set _glowFeatherSuspendUntil(e){this._glowRuntimeState.featherSuspendUntil=e}get _glowFeatherResumeTimer(){return this._glowRuntimeState.featherResumeTimer}set _glowFeatherResumeTimer(e){this._glowRuntimeState.featherResumeTimer=e}get _glowSourceSeq(){return this._glowRuntimeState.sourceSeq}set _glowSourceSeq(e){this._glowRuntimeState.sourceSeq=e}_activateSafeDayCycleOutline(){this._safeDayCycleOutline=!0,this._stageEl?.classList.add("hp-safe-daycycle-outline")}get _touchSequenceMultitouch(){return this._touchClickGuard.sequenceMultitouch}_syncDangerConfirmLocaleGate(){return this._config&&this.hass?dp(this,gp,kp(this.hass,this._config.language)):"ready"}_dangerConfirmMissingSpace(){const e=this._model;if(!e.length)return!1;const t=this._fixedFloorState(e);return"pending"!==t.kind&&"invalid"!==t.kind&&!this._spaceModel()}_syncVersionRecovery(){this._versionRecovery.update({frontendVersion:ev(iv),backendVersion:this._haIntegrationVersion,kiosk:!0===this._config?.kiosk,reducedMotion:this._reducedMotion})}_newContinuityController(){return new lc(()=>{this._resumeSettling="steady"!==this._continuity.state,this._continuityEpoch++,this.isConnected&&this.requestUpdate()})}get _labsIso(){return this._labs.active.includes("iso")}get _desiredProjection(){return"view"===this._mode&&this._labsIso&&"iso"===this._viewPreference[this._space]?"iso":"flat"}_saveViewPreference(){try{localStorage.setItem(uv,JSON.stringify(this._viewPreference))}catch{}}_logicalViewCenter(e){const t=this._view;if(!t)return null;const i=[t.x+t.w/2,t.y+t.h/2],n="iso"===e?cf(i):i;return{x:n[0],y:n[1]}}_convertProjectionView(e,t){if(e===t)return;this._clearRoomFocus(!0);const i=this._logicalViewCenter(e);this._view=null;const n=i?"iso"===t?lf([i.x,i.y],0):[i.x,i.y]:null;this._applyView(this._zoom,n?.[0],n?.[1]),this._warmPatch({vp:this._warmViewportState()}),this.requestUpdate()}_setProjection(e){if(!this._labsIso||"view"!==this._mode)return;const t=this._effectiveProjection();if(this._viewPreference={...this._viewPreference,[this._space]:e},"iso"===e){this._ensureIsoSceneRuntime();const e=this._isoSceneKey();e&&this._isoFallback.delete(e),this._isoFallback.delete(`${this._space}|no-borders`),this._clearIsoInvalidFallback()}this._saveViewPreference(),this._isoProjectionSnapshot=null;const i=this._effectiveProjection();this._convertProjectionView(t,i)}_hashSpace(){return Ff(window.location.hash||"")}connectedCallback(){this._connectedPath=location.pathname,this._routeDepartureHandled=!1,this._configReloadAuthority.observeContext(Vu(this)),window.addEventListener("location-changed",this._onLocationChanged),window.addEventListener("popstate",this._onLocationChanged),this._continuityDisposed&&(this._continuity=this._newContinuityController(),this._continuityDisposed=!1,this._continuityPaintToken=-1);const e=dg(this.ownerDocument);var t;void 0!==e&&(this._glowScreenBlend=e),this._continuityUnsub?.(),this._continuityUnsub=sc(this.ownerDocument,this._pageVisibility),this._languageFailureUnsub?.(),this._languageFailureUnsub=function(...e){return()=>{for(const t of e)t()}}((t=()=>{this._showToast(this._t("toast.locale_load_failed"))},mp.add(t),()=>mp.delete(t)),function(e){return Il.add(e),()=>{Il.delete(e)}}(()=>this._showToast(this._t("toast.furniture_art_load_failed")))),super.connectedCallback(),this._summarySlot.connect(),this._ensureLiveRuntime().catch(()=>this.requestUpdate()),this._pointerModality.connect(this.ownerDocument.defaultView);const i=this.ownerDocument.defaultView?.MutationObserver;i&&(this._pointerHoverObserver=new i(e=>{let t=!1;for(const i of e){for(const e of i.addedNodes)this._syncPointerHoverSubtree(e);const e=e=>{if(e.nodeType!==Node.ELEMENT_NODE)return!1;const t=e;return t.matches(".devlayer, .devlayer *")||!!t.querySelector?.(".devlayer")};(e(i.target)||[...i.addedNodes,...i.removedNodes].some(e))&&(t=!0)}t&&this._invalidateDeviceHitGeometry()}),this._pointerHoverObserver.observe(this.renderRoot,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["class","style","data-id"]})),this._motionMedia=window.matchMedia?.("(prefers-reduced-motion: reduce)"),this._reducedMotion=!!this._motionMedia?.matches,this._motionMedia?.addEventListener?.("change",this._onMotionChange),this._syncVersionRecovery(),this._versionRecovery.connect(),hg(this.ownerDocument).then(e=>{e!==this._glowScreenBlend&&(this._glowScreenBlend=e,this.isConnected&&this.requestUpdate())}),this.hass&&this._ensureHaRegistryAuthority(),window.addEventListener("keydown",this._keyHandler),this._signer.start(()=>this.hass,()=>this._referencedContentUrls()),this._syncCycleTimer(),window.addEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=function(e){Nf.add(e);const t=Bf();return"undefined"==typeof window&&e(t),()=>{Nf.delete(e)}}(this._onLabsSnapshot),this._labsIso&&this._ensureIsoSceneRuntime(),this._booting?this._bootWatch():this._bootFading&&(clearTimeout(this._bootTimer),this._bootTimer=window.setTimeout(()=>{this._bootFading=!1},220)),this._bootSoft&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},rv)),!this._loadOk&&this._serverCfg&&this.hass&&this._scheduleLoadRetry(),!this._warmSlot&&this._config&&this._warmAdopt(),this._loadOk&&this._ensureLiveSyncSubscriptions(),this._warmVp&&!this._warmRevivePending&&void 0===this._warmReviveTimer&&(this._warmRevivePending=!0,this._warmReviveTimer=window.setTimeout(()=>this._warmReviveDialog(),0)),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1,this.requestUpdate()}disconnectedCallback(){this._versionRecovery.disconnect(),this._configReloadAuthority.invalidateLifecycle(),this._liveRt?.dispose(),this._radarLive.stop(),this._editorRuntime?._disposeLiveEditor(),this._clearRoomFocus(!0),this._cancelDangerConfirm(),this._connectedPath&&location.pathname!==this._connectedPath&&this._leaveCardRoute(),window.removeEventListener("location-changed",this._onLocationChanged),window.removeEventListener("popstate",this._onLocationChanged),this._continuityUnsub?.(),this._continuityUnsub=void 0,this._languageFailureUnsub?.(),this._languageFailureUnsub=void 0,this._motionMedia?.removeEventListener?.("change",this._onMotionChange),this._motionMedia=void 0,this._vacRaf&&(cancelAnimationFrame(this._vacRaf),this._vacRaf=0),this._refitRaf&&(cancelAnimationFrame(this._refitRaf),this._refitRaf=0),this._warmModeRequest=0,this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),this._summarySlot.disconnect(),this._dayCycleClockKey="",this._bootSettleRaf&&(cancelAnimationFrame(this._bootSettleRaf),this._bootSettleRaf=0),this._bootSettling=!1;for(const e of this._activityRt.values())clearTimeout(e.timer);window.removeEventListener("keydown",this._keyHandler),this._endTabDrag(),clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=void 0,this._tabSuppressClick=!1,clearInterval(this._cycleTimer),clearTimeout(this._kioskDotsTimer),clearTimeout(this._kioskHoldTimer),clearTimeout(this._reloadRetry),clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),this._connHooked=null,this._haRegistryRelease?.(),this._haRegistryRelease=void 0,this._haRegistryConnection=null,this._signer.dispose(),clearTimeout(this._toastTimer),clearTimeout(this._slideTimer),clearTimeout(this._editorRuntimeLoadingTimer),this._editorRuntimeLoadingTimer=void 0,this._editorRuntimeLoadingVisible=!1,this._modeTransition.dispose(),this._cameraTransition.dispose(),this._cameraTransitionFit=null,this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest++,this._slideTimer=void 0,this._slide="",clearTimeout(this._bootTimer),this._bootTimer=void 0,clearTimeout(this._bootSoftTimer),this._saveConfigDebounced.flush(),this._cancelDeviceDrag(),window.removeEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=void 0,clearTimeout(this._holdTimer),this._roViewport?.disconnect(),this._roViewport=void 0,this._roHdr?.disconnect(),this._roHdr=void 0,this._onWinResize&&(window.removeEventListener("resize",this._onWinResize),this._onWinResize=void 0),this._unsubCfg&&(this._unsubCfg(),this._unsubCfg=null),this._unsubLayout&&(this._unsubLayout(),this._unsubLayout=null),this._unsubVirtual&&(this._unsubVirtual(),this._unsubVirtual=null),this._unsubTrail&&(this._unsubTrail(),this._unsubTrail=void 0),this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=null,clearTimeout(this._layoutSyncTimer),clearTimeout(this._duplicateColumnTimer),Fm(this._glowRuntimeState,this._glowRuntimeHost),this._warmSnapshot(),this._warmRevivePending=!1,clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmRelease(),this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._editorRuntime?._clearFurniturePreview(),this._editorRuntime?._furnShiftDetach(),this._touchContacts.clear(),this._touchClickGuard.reset(),this._resetDeviceHitState(),this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._pointerHoverObserver?.disconnect(),this._pointerHoverObserver=void 0,this._pointerModality.disconnect(),this._editorSecondary?.reset(),this._resumeSettling=!1,this._continuityHistory=[...this._continuityHistory,...this._continuity.trace].slice(-80),this._continuity.dispose(),this._continuityDisposed=!0,super.disconnectedCallback()}_onKey(e){if("Escape"===e.key&&this._vacFit){if(this._vacFit.busy)return;return this._vacFit=null,this._showToast(this._t("vac.cal_cancelled")),void e.stopPropagation()}if("Escape"===e.key){if(this._tapConfirm)return void(this._tapConfirm=null);if(this._vacCalConfirm)return void(this._vacCalConfirm.busy||(this._vacCalConfirm=null));if(this._decorEraseConfirm)return void(this._decorEraseConfirm=null);if(this._openingInfo)return void(this._openingInfo=null);if(this._infoCard)return void this._closeInfoCard();if(this._rulesDialog)return void(this._rulesDialog=null);if(this._alignDialog)return this._alignDialog=null,void(this._preflightClipboardFallback=null);if(this._backupImportDialog)return void(this._backupImportDialog=null);if(this._backupExportDialog)return void(this._backupExportDialog=null);if(this._pdfDialog)return void(this._pdfDialog=!1);if(this._supportDialog)return void this._editorRuntime?._closeSupportDialog();if(this._settingsDialog)return void(this._settingsDialog=null);if(this._summary?.closeDialogIfIdle())return;if(this._markerDialog)return void this._closeMarkerDialog();if(this._deviceInbox)return void(this._deviceInbox=null);if(this._openingDialog)return void(this._openingDialog=null);if(this._physicalDialog)return void(this._physicalDialog=null);if(this._backdropDialog)return void(this._backdropDialog=null);if(this._decorShapeDialog)return void(this._decorShapeDialog=null);if(this._decorTextDialog)return void(this._decorTextDialog=null);if(this._spaceDialog&&!this._roomDialog)return this._spaceDialog=null,this._importQueue=[],void(this._importTotal=0);if(this._editorSecondary?.hasOpenGroup)return e.preventDefault(),void this._editorSecondary?.closeGroup(!0)}const t=e.composedPath?.()||[e.target],i=t.some(e=>e?.matches?.('input, textarea, select, [contenteditable="true"]')),n=t.some(e=>e?.classList?.contains?.("editor-secondary")),r=e.ctrlKey||e.metaKey,o=e.key.toLowerCase(),s=/^[a-z]$/.test(o),a="z"===o||!s&&"KeyZ"===e.code,l="y"===o||!s&&"KeyY"===e.code,c=r&&(a&&e.shiftKey||l),h=r&&a&&!e.shiftKey;if("decor"===this._mode){if((h||c)&&i)return;if(c)return e.preventDefault(),void this._redoGeometry();if(h)return e.preventDefault(),this._decorDraft?void(this._decorDraft=null):this._decorMove||this._dtDrag||this._bdDrag?void this._cancelDecorGesture():void this._undoGeometry();if(("Delete"===e.key||"Backspace"===e.key)&&this._decorSel&&!i&&!n)return e.preventDefault(),void this._decorDeleteSel();const t="ArrowLeft"===e.key?[-this._gridPitch,0]:"ArrowRight"===e.key?[this._gridPitch,0]:"ArrowUp"===e.key?[0,-this._gridPitch]:"ArrowDown"===e.key?[0,this._gridPitch]:null;return!t||r||e.altKey||"select"!==this._decorTool||!this._decorSel||!this._decorList.some(e=>e.id===this._decorSel)||this._decorDraft||this._decorMove||this._dtDrag||this._bdDrag||i||n||this._editorSecondaryDialogBlocked?void("Escape"===e.key&&(e.preventDefault(),this._decorDraft?this._decorDraft=null:this._decorMove||this._dtDrag||this._bdDrag?this._cancelDecorGesture():"furniture"===this._decorTool?(this._editorRuntime?._clearFurniturePreview(),this._editorRuntime?._furnShiftDetach(),this._furnPalette=null,this._furnCategory=null,this._decorTool="select"):this._decorSel?this._decorSel=null:"select"!==this._decorTool?this._decorTool="select":this._setMode("view"))):(e.preventDefault(),void this._decorNudge(t[0],t[1]))}if("devices"===this._mode){if((h||c)&&i)return;return c?(e.preventDefault(),void this._redoDevicePosition()):h?(e.preventDefault(),void this._undoDevicePosition()):void("Escape"===e.key&&this._deviceDrag&&(e.preventDefault(),this._cancelDeviceDrag()))}if(this._markup&&(!h&&!c||!i)){if(("Delete"===e.key||"Backspace"===e.key)&&this._physicalSel&&!i&&!n)return e.preventDefault(),void this._deletePhysicalSelection();if(c)return e.preventDefault(),void this._redoGeometry();if(h)return e.preventDefault(),this._resize?.dragging?void this._rszCancelDrag():this._wallFaceBatch?(this._roomDialogCancel(),void(this._activeWallChainId&&this._path.length>1?this._undoActiveWallPoint():this._undoPoint())):"draw"===this._tool&&this._path.length?void(this._activeWallChainId&&this._path.length>1?this._undoActiveWallPoint():this._undoPoint()):"split"===this._tool&&this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},void(this._splitSel.pts.length||(this._cursorPt=null))):void this._undoGeometry();if("Escape"===e.key)return this._physicalDrag||this._physicalRotate?(e.preventDefault(),void this._cancelPhysicalGesture()):this._roomDialog?(e.preventDefault(),void this._roomDialogCancel()):"draw"===this._tool&&this._path.length?(e.preventDefault(),void this._finishWallChain()):this._physicalSel?(e.preventDefault(),void(this._physicalSel=null)):"resize"===this._tool?(e.preventDefault(),this._resize?.dragging?void this._rszCancelDrag():("exit-tool"===this._resize?.escapeIdle()&&(this._tool="draw"),void this.requestUpdate())):"split"===this._tool?(e.preventDefault(),void(this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},this._splitSel.pts.length||(this._cursorPt=null)):this._splitSel?this._splitSel=null:this._tool="draw")):"merge"===this._tool?(e.preventDefault(),void(this._mergeSel?this._mergeSel=null:this._tool="draw")):this._wallDialog?(e.preventDefault(),void(this._wallDialog=null)):void("opening"!==this._tool&&"wallthick"!==this._tool&&"delroom"!==this._tool&&"column"!==this._tool||(e.preventDefault(),"opening"===this._tool&&this._clearOpeningPlacement(!0),this._tool="draw"))}}_undoPoint(){if(this._path.length)return this._contourClosed?(this._path=this._path.slice(0,-1),void(this._closingWallCm=null)):void(this._activeWallChainPartitionIds.length&&this._path.length>1?this._undoActiveWallPoint():this._path=this._path.slice(0,-1))}_undoActiveWallPoint(){const e=[...this._activeWallChainPartitionIds],t=e[e.length-1],i=this._spaceModel()?.partitions.find(e=>e.id===t),n=this._path[0]?[...this._path[0]]:null,r=this._path.slice(0,-1).map(e=>[...e]),o=this._wallChainSegmentCms.slice(0,-1),s=this._geometryHistory.undo();if(!s)return this._activeWallChainPartitionIds=[],this._wallChainSegmentCms=[],this._wallChainRedo=[],void(this._path=n?[n]:[]);this._applyGeometryState(s.before,!0)?(this._activeWallChainId||=`chain-${Date.now().toString(36)}`,this._activeWallChainPartitionIds=e.slice(0,-1),this._path=r.length?r:n?[n]:[],this._wallChainSegmentCms=o,i&&this._wallChainRedo.push({id:i.id,point:[...i.b],cm:i.cm}),this._clearPlanSnapHover(),this._showToast(this._t("history.undone",{name:s.name}))):this._geometryHistory.clear()}static async getConfigElement(){return await import("./editor-_VTHnoKH.js"),document.createElement("houseplan-card-editor")}static getStubConfig(){return{type:"custom:houseplan-card"}}static _warmBootReset(e){for(const e of ov.values())for(const t of e)clearTimeout(t.evict);ov.clear(),av=e&&e>0?e:1e4}static _warmBootStats(){let e=0,t=0;const i=[];for(const n of ov.values())for(const r of n)e++,r.dlg&&(t++,i.push(r.dlg.kind));return{keys:ov.size,slots:e,dlgs:t,drafts:i}}setConfig(e){const t=this._config,i=!!t&&Object.prototype.hasOwnProperty.call(t,"floor");this._config={icon_size:2.5,show_temperature:!0,live_states:!0,show_signal:!0,...e};(i!==this._hasFixedFloor||t?.floor!==this._config.floor)&&(this._hashApplied=!1,this._navApplied=!1,this._warmVpArmed=!1),this._config.kiosk&&(this._booting=!1,this._bootFading=!1),!this._hasFixedFloor&&e.default_floor&&this._commitSpace(e.default_floor,!0);try{this._zoomBySpace=JSON.parse(localStorage.getItem(hv)||"{}")||{}}catch{this._zoomBySpace={}}try{const e=JSON.parse(localStorage.getItem(uv)||"{}")||{};this._viewPreference=Object.fromEntries(Object.entries(e).filter(e=>"flat"===e[1]||"iso"===e[1]))}catch{this._viewPreference={}}if(this._labs=Bf(),this.isConnected&&this._labsIso&&this._ensureIsoSceneRuntime(),!this._summary?.applyLocalScaleForCurrentIdentity())try{const e=JSON.parse(localStorage.getItem("houseplan_card_kiosk_v1")||"null");this._kioskScale={icon:jn(e?.icon),font:jn(e?.font)}}catch{}try{const e=JSON.parse(localStorage.getItem(cv)||"null");this._adoption.restoreCached(e)&&(this._seedDecorStyle(this._serverCfg),this._cfgEpoch++,this._virtualLights=Hh(e.virtual_lights,this._cfgRev),this._serverStorage=!0)}catch{}this._adoptInitialSpace(this._model,this._loadOk),"view"!==this._mode||this._view||(this._zoom=this._zoomBySpace[this._space]||1),this.isConnected&&(this._syncCycleTimer(),this._warmAdopt(),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1),this._syncVersionRecovery()}_warmAdopt(){if(this._config?.kiosk)return;const e=Cf(this._config);if(this._warmKey===e&&this._warmSlot)return;this._warmSlot&&this._warmRelease();const t=this.parentNode,i=this._warmIdx(t),n=ov.get(e);if(!n||!n.length)return;const r=n.find(e=>e.owner===this._warmGen);if(r)return this._warmLongReturn=!!r.freed&&Date.now()-r.freed>=nc,clearTimeout(r.evict),r.evict=0,r.freed=0,r.live=!0,this._warmSlot=r,this._warmKey=e,r.frameFingerprint&&this._continuity.adoptCompleteFrame(r.frameFingerprint),void(!this._devices.length&&r.devices?.length&&(this._devices=[...r.devices]));const{slot:o,sure:s}=((e,t,i,n)=>{const r=e=>{const t=!!i&&e.place?.deref()===i;return t&&e.idx===n?4:e.live?0:t?3:2};let o=null,s=0,a=0,l=null;for(const i of e){if(i.owner===t)continue;l=i;const e=r(i);e<=0||(e>s?(o=i,s=e,a=1):e===s&&a++)}return!o||a>1?{slot:o||l,sure:!1}:{slot:o,sure:!0}})(n,this._warmGen,t,i);o&&(this._warmLongReturn=!!o.freed&&Date.now()-o.freed>=nc,this._booting=!1,this._bootFading=!1,this._hdrH=o.hdrH,this._bootSoft=!0,this.isConnected&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},rv)),this._warmKey=e,s?(clearTimeout(o.evict),o.evict=0,o.owner=this._warmGen,o.place=t?new WeakRef(t):null,o.idx=i,o.live=!0,this._warmSlot=o,this._warmVp=o.vp,o.frameFingerprint&&this._continuity.adoptCompleteFrame(o.frameFingerprint),!this._devices.length&&o.devices?.length&&(this._devices=[...o.devices]),this._warmAdoptViewport(this._config)):(this._warmSlot={owner:this._warmGen,path:location.pathname,place:t?new WeakRef(t):null,idx:i,live:!0,hdrH:o.hdrH,stageH:o.stageH,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0},n.push(this._warmSlot),this._warmTrim(n)))}_warmIdx(e){const t=e?.children;if(!t)return-1;for(let e=0;e4;){const t=e.findIndex(e=>!e.live);if(t<0)break;clearTimeout(e[t].evict),e.splice(t,1)}}_warmScheduleEvict(e,t){if(clearTimeout(e.evict),!(e.dlg||e.vp&&"view"!==e.vp.mode))return;const i=e.freed,n=e.owner;e.evict=window.setTimeout(()=>{if(e.evict=0,e.freed!==i||e.owner!==n)return;var r;e.dlg=null,e.vp=(r=e.vp)&&"view"!==r.mode?{...r,mode:"view",zoom:r.snap?.space===r.space?r.snap.zoom:r.zoom,view:null,snap:null,tool:"draw",decorTool:"select",showHidden:!1,selId:null,rszSel:null,decorSel:null}:r,e.frameFingerprint="";const o=ov.get(t);if(!e.live&&o&&o.length>1){const t=o.indexOf(e);t>=0&&o.splice(t,1)}},av+250)}_warmAdoptViewport(e){const t=this._warmVp;if(!t||this._warmSlot?.path!==location.pathname)return void(this._warmVp=null);const i=this._fixedFloorState();if(this._hashApplied||!this._model.find(e=>e.id===t.space)||"valid"===i.kind&&i.id!==t.space||this._hasFixedFloor&&"valid"!==i.kind)return void(this._warmVp=null);this._commitSpace(t.space,!0),this._navApplied=!0;const n="view"!==t.mode&&this._canEdit&&!e.kiosk?t.mode:"view";this._adoptMode("view"),this._pendingNavMode="view"===t.mode||this._canEdit||e.kiosk?null:t.mode,this._zoom=t.zoom;const r=this._effectiveProjection(),o=r===t.projection&&this._labsIso===t.activeLabsIso;if(this._view=o&&t.view?{...t.view}:null,this._viewModeSnap=o&&t.snap?{...t.snap}:null,!o&&t.logicalCenter){const e="iso"===r?lf([t.logicalCenter.x,t.logicalCenter.y],0):[t.logicalCenter.x,t.logicalCenter.y];this._applyView(t.zoom,e[0],e[1])}var s;this._tool="opening"===(s=function(e){return"partition"===e?"draw":e}(s=t.tool))?"draw":"string"==typeof s&&Rf.has(s)?s:"draw",this._decorTool=t.decorTool,this._showHidden=t.showHidden,this._showFar!==t.showFar&&(this._showFar=t.showFar,this._frame=null),this._selId=t.selId,this._resize?.restoreSelection(t.rszSel),this._decorSel=t.decorSel,this._warmVpArmed=!0,"view"!==n&&this._requestMode(n,!1,!0)}_warmPatch(e,t=!1){if(this._config?.kiosk)return;const i=Cf(this._config);if(!this._warmSlot||this._warmKey===i){if(!this._warmSlot){if(!t)return;const e=this.parentNode;this._warmKey=i,this._warmSlot={owner:this._warmGen,path:location.pathname,place:e?new WeakRef(e):null,idx:this._warmIdx(e),live:!0,hdrH:this._hdrH,stageH:0,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0};const n=ov.get(i)||[];for(n.push(this._warmSlot),ov.set(i,n),this._warmTrim(n);ov.size>8;){const e=ov.keys().next().value;if(void 0===e||e===i)break;for(const t of ov.get(e)||[])clearTimeout(t.evict);ov.delete(e)}}Object.assign(this._warmSlot,e)}}_warmViewportState(){const e=this._effectiveProjection();return{space:this._space,mode:this._mode,projection:e,activeLabsIso:this._labsIso,logicalCenter:this._logicalViewCenter(e),zoom:this._zoom,view:this._view?{...this._view}:null,snap:this._viewModeSnap?{...this._viewModeSnap}:null,tool:this._tool,decorTool:this._decorTool,showHidden:this._showHidden,showFar:this._showFar,selId:this._selId,rszSel:this._resize?.selectedRoomId,decorSel:this._decorSel}}_warmDialogState(){const e=(e,t)=>({kind:e,space:this._space,mode:this._mode,data:t});return this._tapConfirm||this._alignDialog||this._mergeDialog||this._importDialog||this._backupExportDialog||this._backupImportDialog?null:this._openingInfo?e("openingInfo",this._openingInfo.id):this._infoCard?e("info",this._infoCard.id):this._rulesDialog?this._rulesDialog.busy?null:e("rules",this._rulesDialog):this._settingsDialog?this._settingsDialog.busy?null:e("settings",this._settingsDialog):this._markerDialog?this._markerDialog.busy?null:e("marker",this._markerDialog):this._openingDialog?e("opening",this._openingDialog):this._backdropDialog?e("backdrop",this._backdropDialog):this._decorShapeDialog?e("decorShape",this._decorShapeDialog):this._decorTextDialog?e("decorText",this._decorTextDialog):this._roomDialog?e("room",{editId:this._roomEditId,fill:this._roomFill,customFill:this._roomCustomFill,tempMin:this._roomTempMin,tempMax:this._roomTempMax,tempSrc:this._roomTempSrc,humSrc:this._roomHumSrc,srcOpen:this._roomSrcOpen,srcFilter:this._roomSrcFilter,nameScale:this._roomNameScale,labelScale:this._roomLabelScale,areaSel:this._areaSel,nameSel:this._nameSel,pendingSplit:this._pendingSplit,wallFaceBatch:this._wallFaceBatch,path:this._path}):this._spaceDialog?this._spaceDialog.busy?null:e("space",this._spaceDialog):null}_warmSnapshot(){if(this._booting||this._config?.kiosk||"steady"!==this._continuity.state)return;const e={vp:this._warmViewportState(),frameFingerprint:this._continuity.frameFingerprint,devices:this._devices,hdrH:this._hdrH};if(this._warmRevivePending||(e.dlg=this._warmDialogState()),this.isConnected&&this._warmSlot?.owner===this._warmGen){const t=this.parentNode;e.place=t?new WeakRef(t):null,e.idx=this._warmIdx(t)}this._warmPatch(e)}_warmReviveDialog(){const e=this._warmSlot;if(this._warmReviveTimer=void 0,!e||!e.dlg)return void(this._warmRevivePending=!1);const t=e.dlg,i=e.freed;if(t.mode===this._mode||"view"===t.mode||this._warmVp?.mode!==t.mode||this._editorRuntime){if(this._warmRevivePending=!1,e.dlg=null,e.freed=0,clearTimeout(e.evict),e.evict=0,i&&!(Date.now()-i>av)&&t.space===this._space&&t.mode===this._mode){switch(t.kind){case"space":this._spaceDialog={...t.data,busy:!1,savedBusy:!1};break;case"marker":this._markerDialog={...t.data,busy:!1};break;case"settings":this._settingsDialog={...t.data,busy:!1};break;case"rules":this._rulesDialog={...t.data,busy:!1};break;case"opening":this._openingDialog={...t.data};break;case"backdrop":this._backdropDialog={...t.data};break;case"decorShape":this._decorShapeDialog={...t.data};break;case"decorText":{this._decorTextDialog={...t.data};const e=String(this._decorTextDialog?.text??"").length;this._decorTextSelection={start:e,end:e};break}case"room":{const e=t.data;this._roomEditId=e.editId,this._roomFill=e.fill,this._roomCustomFill=e.customFill||null,this._roomTempMin=e.tempMin||"",this._roomTempMax=e.tempMax||"",this._roomTempSrc=e.tempSrc,this._roomHumSrc=e.humSrc,this._roomSrcOpen=e.srcOpen,this._roomSrcFilter=e.srcFilter,this._roomNameScale=e.nameScale,this._roomLabelScale=e.labelScale,this._areaSel=e.areaSel,this._nameSel=e.nameSel,this._pendingSplit=e.pendingSplit,this._wallFaceBatch=e.wallFaceBatch||null,this._path=e.path,this._wallFaceBatch&&(this._activeWallChainId=`chain-${Date.now().toString(36)}`,this._activeWallChainPartitionIds=[...this._wallFaceBatch.activePartitionIds],this._wallChainSegmentCms=[...this._wallFaceBatch.activeCms]),this._roomDialog=!0;break}case"info":{const e=this._devices.find(e=>e.id===t.data);e&&(this._infoCard=e);break}case"openingInfo":{const e=(this._curSpaceCfg?.openings||[]).find(e=>e.id===t.data);e&&(this._openingInfo=e);break}}this.requestUpdate()}}else this._warmRevivePending=!0}_cacheSnapshot(){if(this._serverCfg)try{this._virtualLights=function(e,t,i){if(e.configRev===i)return e;const n=new Set((Array.isArray(t?.markers)?t.markers:[]).filter(qh).map(e=>e.id));return{...e,configRev:i,off:new Set([...e.off].filter(e=>n.has(e)))}}(this._virtualLights,this._serverCfg,this._cfgRev);const e=this._adoption.snapshot(function(e){return{rev:e.rev,config_rev:e.configRev,off:[...e.off].sort()}}(this._virtualLights));e&&localStorage.setItem(cv,JSON.stringify(e))}catch{}}_beginContinuityCandidate(e,t,i="plan"){return this._booting&&!this._continuity.hasCompleteFrame?this._continuity.token:(this._continuityDataReady=t,this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._resumeSettling=!0,this._continuity.beginCandidate(e,i))}_continuityStageValid(){const e=this._stageEl;return!!e&&e.clientWidth>0&&e.clientHeight>0}_versionReloadSafetySnapshot(){return Sg(this)}_continuityAssetsReady(){if(!this._model.length)return!1;const e=this._model.length?this._spaceModel():null;return!e?.bg?.href||this._signer.isReady(this.hass,e.bg.href)}_initialSpaceSelection(e,t=this._loadOk){const i=this._fixedFloorState(e,t);return"valid"===i.kind?{id:i.id,source:"fixed"}:this._hasFixedFloor?{id:null,source:"none"}:function(e){const t=new Set(e.spaceIds.filter(e=>!!e));if(!t.size)return{id:null,source:"none"};const i=[["hash",!1===e.acceptHash?null:e.hashSpace],["current",e.preserveCurrent?e.currentSpace:null],["saved",e.savedSpace],["default",e.defaultSpace],["first",e.spaceIds[0]]];for(const[e,n]of i)if(n&&t.has(n))return{id:n,source:e};return{id:null,source:"none"}}({spaceIds:e.map(e=>e.id),hashSpace:this._hashSpace(),acceptHash:!this._hashApplied,currentSpace:this._space,preserveCurrent:this._hashApplied||this._navApplied||this._warmVpArmed,savedSpace:this._savedNav()?.space,defaultSpace:this._config?.default_floor})}_adoptInitialSpace(e,t=this._loadOk){const i=this._initialSpaceSelection(e,t);return i.id?(this._commitSpace(i.id,!0),"hash"===i.source&&(this._hashApplied=!0),"saved"===i.source&&(this._navApplied=!0),i):i}_candidateBackdrop(e,t=this._space){const i=el(e),n=this._fixedFloorState(i,!0);if(this._hasFixedFloor&&"valid"!==n.kind)return"";const r=this._initialSpaceSelection(i,!0).id||(i.some(e=>e.id===t)?t:i[0]?.id);return i.find(e=>e.id===r)?.bg?.href||""}_visualFrameFingerprint(){const e=this._stageEl,t=e?[e.clientWidth,e.clientHeight]:[0,0];return hc([this._cfgRev,this._adoption.currentConfigFingerprint(),this._layoutRev,this._adoption.currentLayoutFingerprint(),this._space,this._mode,this._view,t,this._glowScreenBlend?"screen":"normal",this.hass?.themes?.darkMode??this.hass?.themes?.default_theme??""])}_settleContinuityFrame(){if(this._booting||!this._continuityStageValid())return;if(!this._continuity.hasCompleteFrame&&"steady"===this._continuity.state)return void(this._continuityAssetsReady()&&(this._renderSnapshotAt=Date.now(),this._continuity.markCompleteFrame(this._visualFrameFingerprint())));if(!this._continuityDataReady)return;if(!["holding","offline-stale","overlay-pending","overlay-visible","candidate-ready"].includes(this._continuity.state))return;const e=this._continuity.token;if(this._candidateDeviceSnapshot&&this._candidateDeviceSnapshot!==this._visibleDeviceSnapshot&&this._stagedDeviceSnapshotToken!==e)return this._stagedDeviceSnapshotToken=e,void this.requestUpdate();this._continuityPaintToken!==e&&(this._continuityPaintToken=e,this._continuity.candidateReady(e)&&this._continuity.commitAfterPaint(e,{updateComplete:()=>this.updateComplete,stageValid:()=>this.isConnected&&this._continuityStageValid(),assetsReady:()=>this._continuityAssetsReady(),frameFingerprint:()=>this._visualFrameFingerprint()}).then(t=>{t&&e===this._continuity.token?(this._resumeSettling=!1,this._renderSnapshotAt=Date.now(),this._candidateDeviceSnapshot&&(this._visibleDeviceSnapshot=this._candidateDeviceSnapshot),this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._warmSnapshot()):e===this._continuity.token&&(this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._candidateDeviceSnapshot=null,this.requestUpdate())}))}_onBackdropLoaded(e,t){this._signer.markLoaded(this.hass,e,t),this._continuity.note("asset-ready"),this._continuityPaintToken=-1,"steady"!==this._continuity.state&&this.requestUpdate()}_renderRecoveryOverlay(){if(!this._continuity.overlayVisible&&"recovery-error"!==this._continuity.state)return G;const e="connection"===this._continuity.recoveryReason;return j`
    svg{position:absolute;inset:0;width:100%;height:100%;display:block;z-index:1;}.hp-static-stage>.hp-paper-outline-svg{z-index:0;overflow:visible;}.hp-paper{fill:var(--ha-card-background,var(--card-background-color,#111));stroke:none;}.wallbody-fill{fill:var(--wall-fill,#ffffff);fill-opacity:var(--wall-fill-op,1);fill-rule:evenodd;stroke:none;pointer-events:none;}.wallbody{fill:url(#hp-wall-hatch);fill-rule:evenodd;stroke:var(--room-stroke,var(--hp-muted,#607d8b));stroke-width:calc(0.6px * var(--hp-cell-visual-scale,1));pointer-events:none;}.wallbody.solid{fill:none;}.hp-static-stage .devlayer{position:absolute;inset:0;z-index:2;}.hp-static-foot{padding:8px 12px 12px;pointer-events:auto;}.hp-static-btn{width:100%;padding:9px 14px;border:none;border-radius:10px;background:var(--primary-color,#3ea6ff);color:var(--text-primary-color,#fff);font-size:14px;font-weight:600;cursor:pointer;}:host([data-pointer-hover]) .hp-static-btn:hover{filter:brightness(1.08);}.hp-static-error{padding:24px;text-align:center;color:var(--secondary-text-color,#9aa4ad);}`],customElements.get("houseplan-space-card")||customElements.define("houseplan-space-card",_g),window.customCards=window.customCards||[],window.customCards.find(e=>"houseplan-space-card"===e.type)||window.customCards.push({type:"houseplan-space-card",name:"House Plan — Space (static)",description:"Read-only live schematic of a single houseplan space, with a deep-link button.",preview:!1,documentation:"https://github.com/Matysh/houseplan-card"});const mg=o`:host{--hp-editor-tray-bg-fallback:color-mix(in srgb,var(--card-background-color,var(--hp-bg)) 94%,var(--hp-line));--hp-editor-tray-bg:color-mix(in srgb,var(--card-background-color,var(--hp-bg)) 86%,transparent);--hp-editor-tray-border:color-mix(in srgb,var(--hp-line) 82%,var(--hp-accent));--hp-editor-tray-blur:8px;--hp-editor-tray-shadow:var(--shadow-2);}.editor-secondary-host{position:absolute;inset:var(--sp-2) var(--sp-4) auto;z-index:70;display:flex;justify-content:flex-end;pointer-events:none;}.editor-secondary-host.kind-palette,.editor-secondary-host.kind-group{justify-content:flex-start;}.editor-secondary{pointer-events:none;max-width:100%;display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);color:var(--hp-txt);background:var(--card-background-color,var(--hp-bg));background:var(--hp-editor-tray-bg-fallback);border:1px solid var(--hp-line);border-color:var(--hp-editor-tray-border);border-radius:var(--rad-l);box-shadow:var(--hp-editor-tray-shadow);opacity:0;visibility:hidden;transform:translateY(-4px);transition:opacity 0.1s ease,transform 0.1s cubic-bezier(0.2,0.7,0.2,1),visibility 0s linear 0.1s;touch-action:auto;}.editor-secondary-host.open .editor-secondary{pointer-events:auto;opacity:1;visibility:visible;transform:translateY(0);transition-duration:0.14s,0.14s,0s;transition-delay:0s;}.editor-secondary-host.blocked .editor-secondary{pointer-events:none;}@supports ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){.editor-secondary{background:var(--hp-editor-tray-bg);-webkit-backdrop-filter:blur(var(--hp-editor-tray-blur));backdrop-filter:blur(var(--hp-editor-tray-blur));}}.editor-secondary-content,.editor-group-items{display:flex;align-items:center;gap:var(--sp-3);min-width:0;}.editor-context-label{max-width:14rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding-inline-end:var(--sp-4);border-inline-end:1px solid var(--hp-line);color:var(--hp-muted);font-size:var(--fs-s);}.editor-secondary.kind-palette{width:min(760px,100%);align-items:stretch;padding:0;overflow:hidden;}.editor-secondary.kind-palette .editor-secondary-content,.editor-secondary.kind-palette .furnpalette{width:100%;}.editor-secondary.kind-palette .furnpalette{max-height:38vh;border:0;background:transparent;}.editor-group-launcher .group-chevron{--mdc-icon-size:16px;transition:transform 0.14s ease;}.editor-group-launcher[aria-expanded="true"] .group-chevron{transform:rotate(180deg);}.editor-secondary .bdhint{font-size:var(--fs-s);color:var(--hp-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.editor-secondary .dfill{display:inline-flex;align-items:center;gap:var(--sp-2);font-size:var(--fs-s);cursor:pointer;}.editor-secondary .dfill input[type="checkbox"]{width:16px;height:16px;flex:none;margin:0;padding:0;}.editor-secondary hp-color-opacity{flex:0 0 auto;}.editor-secondary input{width:74px;background:transparent;border:1px solid var(--hp-line);color:var(--hp-txt);border-radius:var(--rad-s);padding:var(--sp-3) var(--sp-4);font-size:var(--fs-m);}.editor-secondary label,.editor-secondary .hint{color:var(--hp-muted);font-size:var(--fs-s);}.editor-secondary .drawwall{display:inline-flex;align-items:center;gap:var(--sp-3);white-space:nowrap;}.editor-secondary .drawwall input{width:4.2em;}.editor-secondary .drawwall .opl{color:var(--hp-muted);font-size:var(--fs-s);}@container (min-width:560px) and (max-width:899px){.editor-secondary-content,.editor-group-items{flex-wrap:wrap;justify-content:flex-end;}}@container (max-width:559px){.editor-secondary-host{inset-inline:var(--sp-4);}.editor-secondary{max-width:100%;}.editor-secondary-content,.editor-group-items{overflow-x:auto;scrollbar-width:thin;}.editor-secondary-content>*,.editor-group-items>*{flex:none;}.editor-context-label{display:none;}}@media (prefers-reduced-motion:reduce){.editor-secondary{transition:none;}.editor-group-launcher .group-chevron{transition:none;}}`;class gg{constructor(e=50){this._undo=[],this._redo=[],this._limit=Math.max(30,Math.floor(e))}get canUndo(){return this._undo.length>0}get canRedo(){return this._redo.length>0}get undoName(){return this._undo[this._undo.length-1]?.name??null}get redoName(){return this._redo[this._redo.length-1]?.name??null}get size(){return this._undo.length}push(e){this._undo.push(e),this._undo.length>this._limit&&this._undo.splice(0,this._undo.length-this._limit),this._redo=[]}undo(){const e=this._undo.pop()??null;return e&&this._redo.push(e),e}redo(){const e=this._redo.pop()??null;return e&&this._undo.push(e),e}removeWhere(e){const t=this._undo.length,i=this._redo.length;return this._undo=this._undo.filter(t=>!e(t)),this._redo=this._redo.filter(t=>!e(t)),t+i-this._undo.length-this._redo.length}clear(){this._undo=[],this._redo=[]}}function fg(e,t){const i=e[t];return i&&Number.isFinite(i.x)&&Number.isFinite(i.y)?{x:i.x,y:i.y,..."string"==typeof i.s?{s:i.s}:{}}:null}function vg(e,t,i){if(null===i){if(!(t in e))return e;const i={...e};return delete i[t],i}const n={...e[t]||{}};delete n.x,delete n.y,delete n.s;const r={...n,x:i.x,y:i.y,...void 0!==i.s?{s:i.s}:{}};return{...e,[t]:r}}const yg="houseplan-card:version-reload-target:v1";function bg(e){if("string"!=typeof e)return null;return e.trim()||null}class wg{constructor(e){this.hooks=e,this._input={frontendVersion:null,backendVersion:null,kiosk:!1,reducedMotion:!1},this._relation={kind:"unknown"},this._banner=null,this._connected=!1,this._attemptTarget=null,this._attemptState=null,this._noticeToken=0}get relation(){return this._relation}get banner(){return this._banner}get hasCurrentMismatchNotice(){return"mismatch"===this._relation.kind&&"visible"===this._banner?.phase}connect(){this._connected||(this._connected=!0,this._attemptTarget=null,this._attemptState=null,this._reconcile())}disconnect(){(this._connected||this._banner)&&(this._connected=!1,this._cancelTimer(),this._banner&&(this._banner=null,this.hooks.changed()))}update(e){const t={frontendVersion:bg(e.frontendVersion),backendVersion:bg(e.backendVersion),kiosk:!0===e.kiosk,reducedMotion:!0===e.reducedMotion},i=function(e,t){const i=bg(e),n=bg(t);return i&&n?i===n?{kind:"equal",frontend:i,backend:n}:{kind:"mismatch",frontend:i,backend:n}:{kind:"unknown"}}(t.frontendVersion,t.backendVersion),n=!((e,t)=>e.frontendVersion===t.frontendVersion&&e.backendVersion===t.backendVersion&&e.kiosk===t.kiosk&&e.reducedMotion===t.reducedMotion)(this._input,t)||!((e,t)=>e.kind===t.kind&&("unknown"===e.kind||"unknown"!==t.kind&&e.frontend===t.frontend&&e.backend===t.backend))(this._relation,i);this._input=t,this._relation=i,n&&this._reconcile()}finishBannerExit(e){this._banner&&"leaving"===this._banner.phase&&this._banner.token===e&&(this._banner=null,this.hooks.changed())}_reconcile(){if(this._cancelTimer(),!this._connected||"mismatch"!==this._relation.kind)return this._attemptTarget=null,this._attemptState=null,void this._hideBanner();if(!this._input.kiosk)return this._attemptTarget=null,this._attemptState=null,void this._showBanner(this._relation.frontend,this._relation.backend);const e=this._relation.backend;if(this._attemptTarget===e&&null!==this._attemptState||(this._attemptTarget=e,this._attemptState=function(e,t){try{const i=e();return i?i.getItem(yg)===t?"attempted":"fresh":"unavailable"}catch{return"unavailable"}}(this.hooks.storage,e)),"fresh"===this._attemptState)return this._hideBanner(),void this._armTimer();this._showBanner(this._relation.frontend,e)}_armTimer(){this._connected&&void 0===this._timer&&"mismatch"===this._relation.kind&&this._input.kiosk&&"fresh"===this._attemptState&&(this._timer=this.hooks.clock.setTimeout(()=>{this._timer=void 0,this._tick()},250))}_cancelTimer(){void 0!==this._timer&&(this.hooks.clock.clearTimeout(this._timer),this._timer=void 0)}_tick(){if(!this._connected||"mismatch"!==this._relation.kind||!this._input.kiosk||"fresh"!==this._attemptState)return;if(!function(e){return e.connected&&e.initialFrameSettled&&e.viewOnly&&e.surfacesIdle&&e.configWritesIdle&&e.physicalWritesIdle&&e.layoutWritesIdle&&e.gesturesIdle&&e.interactionPauseElapsed&&e.baseZoom}(this.hooks.safety()))return void this._armTimer();const e=this._relation.backend,t=function(e,t){try{const i=e();return i?i.getItem(yg)===t?"attempted":(i.setItem(yg,t),"claimed"):"unavailable"}catch{return"unavailable"}}(this.hooks.storage,e);if(this._attemptTarget=e,this._attemptState="claimed"===t?"attempted":t,"claimed"===t){this._showBanner(this._relation.frontend,e);try{this.hooks.reload()}catch{}}else this._showBanner(this._relation.frontend,e)}_showBanner(e,t){"visible"===this._banner?.phase&&this._banner.frontend===e&&this._banner.backend===t||(this._banner={frontend:e,backend:t,phase:"visible",token:++this._noticeToken},this.hooks.changed())}_hideBanner(){if(this._banner)return this._input.reducedMotion?(this._banner=null,void this.hooks.changed()):void("leaving"!==this._banner.phase&&(this._banner={...this._banner,phase:"leaving",token:++this._noticeToken},this.hooks.changed()))}}const kg=1;function xg(e,t){const i=t&&"object"==typeof t?t:{};e._haIntegrationVersion=bg(i.integration_version);const n=i.support_api;e._haSupportApi="number"==typeof n&&Number.isSafeInteger(n)?n:null,e._haDecorAssetsApi=1===i.decor_assets_api?1:null,e._haSummaryPanelApi=1===i.summary_panel_api?1:null,e._haRadarStage1Api=1===i.radar_stage1_api?1:null,e._syncVersionRecovery()}function Sg(e){const t=e._stageEl,i=e._loadOk&&!e._loading&&e._continuityDataReady&&!e._resumeSettling&&!e._connectionWasLost&&!e._booting&&!e._bootFading&&!e._bootSettling&&!e._bootSoft&&e._continuity.hasCompleteFrame&&"steady"===e._continuity.state&&!e._continuity.overlayBlocksInteraction&&!!t&&t.clientWidth>0&&t.clientHeight>0,n=!(0!==e._pointers.size||0!==e._touchContacts.size||e._touchSequenceMultitouch||e._roomPointer||e._panStart||e._panLock||e._pinchStart||e._swipeStart||e._tabDrag||e._tabDragRelease||e._drag||e._deviceDrag||e._rlResize||e._resize?.dragging||e._physicalDrag||e._physicalRotate||e._opDrag||e._decorDraft||e._decorMove||e._dtDrag||e._bdDrag||e._furnTouchPending||e._compassDrag||e._viewportGestureDirty||e._devicePositionBusy||e._modeTransitionBusy||e._cameraTransition.active||e._slide||0!==e._warmModeRequest),r=!(e._editorSecondaryDialogBlocked||e._partitionDeleteDialog||e._roomDeleteDialog||e._backdropGuard||e._vacFit||e._editorSecondary?.hasOpenGroup||e._furnPalette||e._decorImagePalette);return{connected:e.isConnected,initialFrameSettled:i,viewOnly:!0===e._config?.kiosk&&"view"===e._mode&&!e._editing,surfacesIdle:r,configWritesIdle:0===e._writesPending&&!e._saveConfigDebounced.pending(),physicalWritesIdle:0===e._pendingPhysicalWrites.size,layoutWritesIdle:!e._persistLayout.pending()&&0===e._dirtyPos.size&&0===e._sentPos.size&&!e._devicePositionBusy,gesturesIdle:n,interactionPauseElapsed:Date.now()>=e._cyclePausedUntil,baseZoom:e._zoom<=1.001}}class $g{constructor(){this.seen=null,this.diagnosticsCache=null}observe(e,t,i,n){this.invalidateDiagnosticsForHass(e,t,i),this.intake(t,n)}intake(e,t){e&&this.seen!==e&&(this.seen=e,t())}invalidate(){this.diagnosticsCache=null}invalidateDiagnosticsForHass(e,t,i){this.diagnosticsCache&&(e?.entities!==t?.entities||e?.devices!==t?.devices||[...i?.entityIds||[]].some(i=>!!e?.states?.[i]!=!!t?.states?.[i]))&&this.invalidate()}diagnostics(e,t,i){if(this.diagnosticsCache)return this.diagnosticsCache;const n={active:0,ha_disabled:0,orphaned:0,unverified:0};for(const e of t)e.removed||"virtual"===e.binding||n[i(e.binding).kind]++;return this.diagnosticsCache={registry:ud(e),bindings:n},this.diagnosticsCache}}function Mg(e){const t=e;t._hassSequence++,t._renderSnapshotAt=Date.now(),t._continuity.note("hass-snapshot"),t._ensureHaRegistryAuthority(),t._planHassMemo=null,t._hookConnection(),!t._loadOk&&!t._loading&&t._loadTries<8&&t._loadFromServer(),t._maybeRebuildDevices(),t._vacTick(),t._activityTick()}function Rg(e){return!!e&&"object"==typeof e&&1===e.version}function Cg(e,t){const i=e.radar;return e.space===t&&!0!==e.hidden&&!0!==e.removed&&Rg(i)&&!0===i.enabled&&!1!==i.show_live}const Tg={ok:"radar.health_ok",off:"radar.health_off",stale:"radar.health_stale",partial:"radar.health_partial",restricted:"radar.health_restricted",incomplete:"radar.health_incomplete",position_unavailable:"radar.health_position_unavailable",unavailable:"radar.health_unavailable",needs_setup:"radar.health_needs_setup",inconsistent:"radar.health_inconsistent",unknown:"radar.health_unknown"};const Dg=e=>"number"==typeof e&&Number.isFinite(e);class Ag{constructor(e){this.host=e,this.frames=new Map,this.connection=null,this.space="",this.generation=0,this.expiryTimer=0,this.deadlines=new Map}sync(e,t){const i=this.host.hass?.connection;if(!t||!i||!this.host.isConnected)return void this.stop();if(this.unsubscribe&&this.connection===i&&this.space===e)return;this.stop(),this.connection=i,this.space=e;const n=++this.generation,r=i.subscribeMessage?.bind(i);"function"==typeof r&&Promise.resolve(r(e=>{if(n!==this.generation||!this.host.isConnected)return;const t=function(e){if(!e||"object"!=typeof e)return null;const t=e;if("string"!=typeof t.marker_id||"string"!=typeof t.server_session_id||!Number.isSafeInteger(t.seq)||"string"!=typeof t.health)return null;const i=Array.isArray(t.targets)?t.targets.slice(0,256).flatMap(e=>{if(!e||"object"!=typeof e)return[];const t=e;return"string"==typeof t.slot&&Dg(t.x)&&Dg(t.y)&&Dg(t.expires_at)&&Dg(t.reported_at)&&("bounded_latest"===t.pair_quality||"coherent"===t.pair_quality)?[{...t,included:!0===t.included,smooth:!0===t.smooth}]:[]}):[],n=Array.isArray(t.ranges)?t.ranges.slice(0,64).flatMap(e=>{if(!e||"object"!=typeof e)return[];const t=e;if(!("string"==typeof t.id&&Dg(t.x)&&Dg(t.y)&&Dg(t.radius)&&Dg(t.expires_at)&&Dg(t.reported_at)))return[];const i=Array.isArray(t.segments)?t.segments.slice(0,64).flatMap(e=>{if(!Array.isArray(e))return[];const t=e.slice(0,181).flatMap(e=>Array.isArray(e)&&2===e.length&&Dg(e[0])&&Dg(e[1])?[[e[0],e[1]]]:[]);return t.length>=2?[t]:[]}):void 0;return[{...t,...i?{segments:i}:{}}]}):[],r=Array.isArray(t.zones)?t.zones.slice(0,64).flatMap(e=>{if(!e||"object"!=typeof e)return[];const t=e;if("string"!=typeof t.id)return[];const i=t.state;if(null!==i&&"boolean"!=typeof i&&!Dg(i))return[];const n=Array.isArray(t.polygon)?t.polygon.slice(0,64).flatMap(e=>Array.isArray(e)&&2===e.length&&Dg(e[0])&&Dg(e[1])?[[e[0],e[1]]]:[]):[];return[{id:t.id,state:i,...n.length>=3?{polygon:n}:{}}]}):[];return{server_session_id:t.server_session_id,marker_id:t.marker_id,source_generation:"string"==typeof t.source_generation?t.source_generation:void 0,calibration_revision:"string"==typeof t.calibration_revision?t.calibration_revision:void 0,seq:t.seq,reported_at:Dg(t.reported_at)?t.reported_at:void 0,expires_at:Dg(t.expires_at)?t.expires_at:void 0,health:t.health,reported_presence:"boolean"==typeof t.reported_presence?t.reported_presence:null,complete:!0===t.complete,targets:i,ranges:n,zones:r}}(e);if(!t)return;if(!function(e,t){return!e||t.server_session_id!==e.server_session_id||t.source_generation!==e.source_generation||t.calibration_revision!==e.calibration_revision||t.seq>e.seq}(this.frames.get(t.marker_id),t))return;const i=function(e,t=Date.now()){if(!Dg(e.expires_at))return null;if(!Dg(e.reported_at))return Math.max(0,1e3*e.expires_at-t);const i=Math.max(0,1e3*(e.expires_at-e.reported_at)),n=Math.max(0,t-1e3*e.reported_at);return Math.max(0,i-n)}(t);"restricted"===t.health||"disabled"===t.health||0===i?(this.frames.delete(t.marker_id),this.deadlines.delete(t.marker_id)):(this.frames.set(t.marker_id,t),null==i?this.deadlines.delete(t.marker_id):this.deadlines.set(t.marker_id,this.monotonicNow()+i)),this.armExpiry(),this.host.requestUpdate()},{type:"houseplan/radar/subscribe",space_id:e})).then(e=>{n===this.generation&&this.host.isConnected?"function"==typeof e&&(this.unsubscribe=e):"function"==typeof e&&e()}).catch(()=>{n===this.generation&&this.stop()})}stop(){this.generation++,this.unsubscribe?.(),this.unsubscribe=void 0,this.connection=null,this.space="",clearTimeout(this.expiryTimer),this.expiryTimer=0,this.frames.size&&(this.frames.clear(),this.host.isConnected&&this.host.requestUpdate()),this.deadlines.clear()}armExpiry(){clearTimeout(this.expiryTimer);const e=this.monotonicNow(),t=[...this.deadlines.values()].filter(t=>t>e);if(!t.length)return;const i=Math.max(20,Math.min(...t)-e+10);this.expiryTimer=window.setTimeout(()=>{this.expiryTimer=0;let e=!1;const t=this.monotonicNow();for(const[i,n]of this.deadlines)n>t||(this.deadlines.delete(i),this.frames.delete(i),e=!0);this.armExpiry(),e&&this.host.isConnected&&this.host.requestUpdate()},i)}monotonicNow(){return globalThis.performance?.now?.()??Date.now()}}const Pg=Object.freeze({enabled:!1,z2mBaseTopics:Object.freeze([])});function Fg(e){if("string"!=typeof e)return null;const t=e.trim().replace(/^\/+|\/+$/g,"").replace(/\/{2,}/g,"/");return!t||t.length>180||/[#+\u0000-\u001f\u007f]/.test(t)?null:t}function zg(e){const t=e?.zigbee_topology;if(!t||"object"!=typeof t)return Pg;const i=t,n=Array.isArray(i.z2m_base_topics)?i.z2m_base_topics:Array.isArray(i.z2mBaseTopics)?i.z2mBaseTopics:[],r=new Set,o=[];for(const e of n){const t=Fg(e);if(t&&!r.has(t)&&(r.add(t),o.push(t),8===o.length))break}return{enabled:!0===i.enabled,z2mBaseTopics:o}}function Ig(e,t){const i={...e},n=t.z2mBaseTopics.map(Fg).filter(Boolean);return t.enabled||n.length?i.zigbee_topology={enabled:!0===t.enabled,z2m_base_topics:[...new Set(n)].slice(0,8)}:delete i.zigbee_topology,i}const Og={now:()=>performance.now(),requestFrame:e=>requestAnimationFrame(e),cancelFrame:e=>cancelAnimationFrame(e)},Eg=e=>Math.max(0,Math.min(1,e)),Ng=(e,t,i)=>e+(t-e)*i,Hg=(e,t,i)=>{const n=1-e;return 3*n*n*e*t+3*n*e*e*i+e*e*e},Lg=e=>{const t=Eg(e);if(0===t||1===t)return t;let i=0,n=1,r=t;for(let e=0;e<12;e++)r=(i+n)/2,Hg(r,.2,.2)0&&e.w>0?t/e.w:1,viewBox:{...e}}}function qg(e,t,i){const n=Math.max(1e-9,e.pixelsPerUnit),r=Math.max(1e-9,t/n),o=Math.max(1e-9,i/n);return{x:e.centerX-r/2,y:e.centerY-o/2,w:r,h:o}}function jg(e){const t=e.trim(),i=/^rgba?\(\s*([\d.]+)[, ]+([\d.]+)[, ]+([\d.]+)(?:\s*[,/]\s*([\d.]+))?\s*\)$/i.exec(t);if(i)return[Number(i[1]),Number(i[2]),Number(i[3]),null==i[4]?1:Number(i[4])];const n=/^#([0-9a-f]{6}|[0-9a-f]{8})$/i.exec(t)?.[1];return n?[parseInt(n.slice(0,2),16),parseInt(n.slice(2,4),16),parseInt(n.slice(4,6),16),8===n.length?parseInt(n.slice(6,8),16)/255:1]:null}function Wg(e,t,i){const n=jg(e),r=jg(t);if(!n||!r)return i<.5?e:t;const o=Eg(i);return`rgba(${Math.round(Ng(n[0],r[0],o))}, ${Math.round(Ng(n[1],r[1],o))}, ${Math.round(Ng(n[2],r[2],o))}, ${Ng(n[3],r[3],o).toFixed(3)})`}class Ug{constructor(e,t=Og){this._hooks=e,this._clock=t,this._token=0,this._raf=0,this._state=null}get state(){return this._state}get active(){return"running"===this._state?.phase||"preparing"===this._state?.phase}get presented(){return this._state?.presented||null}start(e,t,i,n=220){this.cancel(!1);const r=++this._token,o=this._clock.now();if(this._state={token:r,phase:n<=0?"settling":"running",from:e,to:t,presented:n<=0?t:e,startedAt:o,duration:Math.max(0,n),targetMode:i},n<=0)return this._hooks.frame(this._state),this._hooks.settled(this._state),this._state=null,r;this._hooks.frame(this._state);const s=e=>{const t=this._state;if(!t||t.token!==r)return;const i=Eg((e-t.startedAt)/t.duration);t.presented=i>=1?t.to:function(e,t,i){const n=Lg(i),r=Ng(e.stageWidth,t.stageWidth,n),o=Ng(e.stageHeight,t.stageHeight,n),s=Math.max(1e-9,e.viewport.pixelsPerUnit),a=Math.max(1e-9,t.viewport.pixelsPerUnit),l={centerX:Ng(e.viewport.centerX,t.viewport.centerX,n),centerY:Ng(e.viewport.centerY,t.viewport.centerY,n),pixelsPerUnit:Math.exp(Ng(Math.log(s),Math.log(a),n))};return{presentedMode:n<.5?e.presentedMode:t.presentedMode,editorChromeHeight:Ng(e.editorChromeHeight,t.editorChromeHeight,n),stageWidth:r,stageHeight:o,viewport:{...l,viewBox:qg(l,r,o)},stageColor:Wg(e.stageColor,t.stageColor,n),paperColor:Wg(e.paperColor,t.paperColor,n),sceneBrightness:Ng(e.sceneBrightness,t.sceneBrightness,n),architectureOpacity:Ng(e.architectureOpacity,t.architectureOpacity,n),backdropOpacity:Ng(e.backdropOpacity,t.backdropOpacity,n),viewWeight:Ng(e.viewWeight,t.viewWeight,n),editorWeight:Ng(e.editorWeight,t.editorWeight,n),toolbarContentOpacity:Ng(e.toolbarContentOpacity,t.toolbarContentOpacity,n)}}(t.from,t.to,i),t.phase=i>=1?"settling":"running",this._hooks.frame(t),i<1?this._raf=this._clock.requestFrame(s):(this._raf=0,this._hooks.settled(t),this._state?.token===r&&(this._state=null))};return this._raf=this._clock.requestFrame(s),r}cancel(e=!0){this._raf&&this._clock.cancelFrame(this._raf),this._raf=0;const t=this._state;this._state=null,this._token++,t&&e&&(t.phase="settling",t.presented=t.to,this._hooks.frame(t),this._hooks.settled(t))}dispose(){this.cancel(!1)}}const Gg={now:()=>"undefined"!=typeof performance?performance.now():Date.now(),requestFrame:e=>"function"==typeof requestAnimationFrame?requestAnimationFrame(e):null,cancelFrame:e=>{"function"==typeof cancelAnimationFrame&&cancelAnimationFrame(e)}},Vg=e=>Number.isFinite(e);function Kg(e){return!!e&&Vg(e.zoom)&&e.zoom>0&&Vg(e.viewBox.x)&&Vg(e.viewBox.y)&&Vg(e.viewBox.w)&&e.viewBox.w>0&&Vg(e.viewBox.h)&&e.viewBox.h>0}function Yg(e){return{zoom:e.zoom,viewBox:{...e.viewBox}}}function Xg(e,t){return Math.abs(e.zoom-t.zoom)<1e-9&&Math.abs(e.viewBox.x-t.viewBox.x)<1e-6&&Math.abs(e.viewBox.y-t.viewBox.y)<1e-6&&Math.abs(e.viewBox.w-t.viewBox.w)<1e-6&&Math.abs(e.viewBox.h-t.viewBox.h)<1e-6}const Zg=(e,t,i)=>e+(t-e)*i,Jg=(e,t,i)=>Math.exp(Zg(Math.log(e),Math.log(t),i));class Qg{constructor(e,t=Gg){this._hooks=e,this._clock=t,this._token=0,this._raf=null,this._state=null}get state(){return this._state}get active(){return"running"===this._state?.phase}get presented(){return this._state?.presented||null}get target(){return this._state?.to||null}start(e,t,i,n){this.cancel(!1);const r=++this._token,o=Yg(e),s=Yg(t),a=n>0&&Kg(o)&&Kg(s),l=this._clock.now(),c={token:r,phase:a?"running":"settling",from:o,to:s,presented:Yg(a?o:s),startedAt:l,duration:a?n:0,reason:i};if(this._state=c,this._hooks.frame(c),!a)return this._settle(r),r;const h=e=>{const t=this._state;if(!t||t.token!==r)return;const i=Math.max(0,Math.min(1,(e-t.startedAt)/t.duration));if(t.presented=i>=1?Yg(t.to):function(e,t,i){if(!Kg(e))return Yg(t);if(!Kg(t))return Yg(e);const n=Lg(i);if(n<=0)return Yg(e);if(n>=1)return Yg(t);const r=e.viewBox.x+e.viewBox.w/2,o=e.viewBox.y+e.viewBox.h/2,s=t.viewBox.x+t.viewBox.w/2,a=t.viewBox.y+t.viewBox.h/2,l=Jg(e.viewBox.w,t.viewBox.w,n),c=Jg(e.viewBox.h,t.viewBox.h,n),h=Zg(r,s,n),d=Zg(o,a,n);return{zoom:Jg(e.zoom,t.zoom,n),viewBox:{x:h-l/2,y:d-c/2,w:l,h:c}}}(t.from,t.to,i),t.phase=i>=1?"settling":"running",this._hooks.frame(t),i>=1)return this._raf=null,void this._settle(r);this._raf=this._clock.requestFrame(h),null===this._raf&&this._settle(r)};return this._raf=this._clock.requestFrame(h),null===this._raf&&(c.phase="settling",c.presented=Yg(s),this._hooks.frame(c),this._settle(r)),r}cancel(e=!0){null!==this._raf&&this._clock.cancelFrame(this._raf),this._raf=null;const t=this._state;this._state=null,this._token++,t&&e&&(t.phase="settling",t.presented=Yg(t.to),this._hooks.frame(t),this._hooks.settled(t))}dispose(){this.cancel(!1)}_settle(e){const t=this._state;t&&t.token===e&&(t.phase="settling",t.presented=Yg(t.to),this._hooks.settled(t),this._state?.token===e&&(this._state=null))}}function ef(e,t,i){const n=e.querySelector("ha-card");if(!n)return null;const r=n.getBoundingClientRect(),o=t.getBoundingClientRect().top-r.top,s=i?0:Math.min(Math.max(r.top,0),120),a=Math.round(o+s);return a>=0?a:null}const tf=Object.freeze({rotDeg:0,tiltDeg:20,xyScale:1,zScale:1,origin:Object.freeze([500,500])}),nf=84,rf=10,of=4,sf=4;function af(e){return[e.rotDeg,e.tiltDeg,e.xyScale,e.zScale,e.origin[0],e.origin[1]].every(Number.isFinite)&&Math.abs(e.xyScale)>1e-12&&Math.abs(Math.cos(e.tiltDeg*Math.PI/180))>1e-12}function lf(e,t,i=tf){if(!Number.isFinite(e[0])||!Number.isFinite(e[1]))throw new Error("invalid isometric projection input");return function(e,t){if(!Number.isFinite(e[0])||!Number.isFinite(e[1])||!t.every(Number.isFinite))throw new Error("invalid isometric affine input");const[i,n,r,o,s,a]=t;return[i*e[0]+r*e[1]+s,n*e[0]+o*e[1]+a]}(e,hf(t,i))}function cf(e,t=tf){if(!af(t)||!Number.isFinite(e[0])||!Number.isFinite(e[1]))throw new Error("invalid isometric projection input");const i=t.rotDeg*Math.PI/180,n=t.tiltDeg*Math.PI/180,r=(e[0]-t.origin[0])/t.xyScale,o=(e[1]-t.origin[1])/(t.xyScale*Math.cos(n));return[t.origin[0]+r*Math.cos(i)+o*Math.sin(i),t.origin[1]-r*Math.sin(i)+o*Math.cos(i)]}function hf(e=0,t=tf){if(!af(t)||!Number.isFinite(e))throw new Error("invalid isometric camera");const i=t.rotDeg*Math.PI/180,n=t.tiltDeg*Math.PI/180,r=t.xyScale*Math.cos(i),o=-t.xyScale*Math.sin(i),s=t.xyScale*Math.sin(i)*Math.cos(n),a=t.xyScale*Math.cos(i)*Math.cos(n);return[r,s,o,a,t.origin[0]-r*t.origin[0]-o*t.origin[1],t.origin[1]-s*t.origin[0]-a*t.origin[1]-e*t.zScale*Math.sin(n)]}function df(e=tf){return function(e=0,t=tf){return`matrix(${hf(e,t).map(e=>Number(e.toFixed(12))).join(" ")})`}(0,e)}function uf(e,t=tf){const{rect:i,wallHeight:n}=e,r=e.openingHeight??n,o=e.floorDepth??0,s=e.raisedHeight??n;if(!(i.w>=0)||!(i.h>=0)||!Number.isFinite(n)||!Number.isFinite(r)||!Number.isFinite(o)||!Number.isFinite(s)||n<0||r<0||o<0||s<0)throw new Error("invalid isometric frame");const a=[[i.x,i.y],[i.x+i.w,i.y],[i.x+i.w,i.y+i.h],[i.x,i.y+i.h]],l=Math.max(n,r,s),c=a.flatMap(e=>[lf(e,-o,t),lf(e,l,t)]),h=c.map(e=>e[0]),d=c.map(e=>e[1]),u=Math.min(...h),p=Math.min(...d);return{x:u,y:p,w:Math.max(...h)-u,h:Math.max(...d)-p}}const pf=[".dev",".vacpuck",".oplock",".op-hit",".opening",".rlgo","a","button","input","select","textarea",'[contenteditable]:not([contenteditable="false"])',"[data-room-fit-block]",'[role="link"]','[role="button"]'].join(","),_f=(e,t)=>{try{return"function"==typeof e?.matches&&e.matches(t)}catch{return!1}};function mf(e){for(const t of e){const e=t;if(_f(e,".roomlabel[data-id]")){const t=e.getAttribute?.("data-id");return t?{kind:"room",roomId:t}:{kind:"interactive"}}if(_f(e,pf))return{kind:"interactive"};if(_f(e,'[data-hp="room"][data-id]')){const t=e.getAttribute?.("data-id");return t?{kind:"room",roomId:t}:{kind:"interactive"}}if(_f(e,".stage"))return{kind:"background"}}return{kind:"outside"}}function gf(e){const t=mf(e);return"room"===t.kind?t.roomId:null}class ff{constructor(){this.pointer=null,this.sequence=null}clear(){this.pointer=null,this.sequence=null}clearOutside(e){let t={kind:"outside"};try{t=mf(e.composedPath())}catch{}"outside"===t.kind&&this.clear()}pointerDown(e,t,i){let n={kind:"outside"};try{n=mf(e.composedPath())}catch{}this.pointer=function(e){const t="mouse"===(i=e.pointerType)||"touch"===i||"pen"===i?i:null;var i;return t&&"view"===e.mode&&"background"===e.owner.kind&&!e.blocked&&e.isPrimary&&0===e.button&&Number.isFinite(e.x)&&Number.isFinite(e.y)?{pointerId:e.pointerId,spaceId:e.spaceId,modality:t,x:e.x,y:e.y}:null}({pointerId:e.pointerId,pointerType:e.pointerType,isPrimary:e.isPrimary,button:e.button,spaceId:t,mode:i?"view":"blocked",owner:n,blocked:!i,x:e.clientX,y:e.clientY}),this.pointer||(this.sequence=null)}pointerUp(e,t,i,n,r=Date.now()){let o={kind:"outside"};try{o=mf(e.composedPath())}catch{}const s=function(e,t,i){if(!t||"view"!==i.mode||"background"!==i.owner.kind||i.blocked||t.pointerId!==i.pointerId||t.spaceId!==i.spaceId||!Number.isFinite(i.x)||!Number.isFinite(i.y)||!Number.isFinite(i.now)||Math.abs(i.x-t.x)+Math.abs(i.y-t.y)>=8)return{sequence:null,trigger:!1};const n=e?i.now-e.at:Number.POSITIVE_INFINITY;return e&&e.spaceId===i.spaceId&&e.modality===t.modality&&n>=0&&n<=350?{sequence:null,trigger:!0}:{sequence:{at:i.now,spaceId:i.spaceId,modality:t.modality},trigger:!1}}(this.sequence,this.pointer,{pointerId:e.pointerId,spaceId:t,mode:i?"view":"blocked",owner:o,blocked:n||!i,x:e.clientX,y:e.clientY,now:r});return this.pointer=null,this.sequence=s.sequence,s.trigger}}const vf=e=>e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]);function yf(e){return!!e&&Number.isFinite(e.x)&&Number.isFinite(e.y)&&Number.isFinite(e.w)&&e.w>0&&Number.isFinite(e.h)&&e.h>0}function bf(e,t=0){if(!e.length||!Number.isFinite(t)||t<0||!e.every(vf))return null;let i=1/0,n=1/0,r=-1/0,o=-1/0;for(const t of e)i=Math.min(i,t[0]),n=Math.min(n,t[1]),r=Math.max(r,t[0]),o=Math.max(o,t[1]);const s=r-i,a=o-n;return s>0&&a>0?{x:i-t,y:n-t,w:s+2*t,h:a+2*t}:null}function wf(e,t,i){const n="string"!=typeof t||"invalid"!==t&&"no-borders"!==t&&"unverified"!==t&&!/^[a-z0-9]{1,8}$/i.test(t)?"redacted":t;return Object.freeze({kind:e,fingerprint:n,terminal:!!i})}function kf(e,t){return`${e("editor.load_failed")} ${e(t.terminal?"editor.refresh_advice":"editor.retry_advice")}`}class xf extends Error{}class Sf{constructor(e){this.options=e,this._state="idle",this._inFlight=null}get state(){return this._state}ensure(){return"ready"===this._state?Promise.resolve(!0):"failed"===this._state?Promise.resolve(!1):(this._inFlight||(this._setState("loading"),this._inFlight=this._loadWithRetry().finally(()=>{this._inFlight=null})),this._inFlight)}async _loadWithRetry(){let e=new Error("Editor runtime did not load"),t=!1;for(const i of[0,1])try{const e=await this.options.load(i);if(e.fingerprint!==this.options.expectedFingerprint)throw new xf(`Editor runtime fingerprint mismatch: expected ${this.options.expectedFingerprint}, got ${e.fingerprint}`);const t=e.create();return this.options.install(t),this._setState("ready"),!0}catch(i){e=i,i instanceof xf&&(t=!0)}return this._setState(t?"failed":"idle"),this.options.failed?.(e,{terminal:t}),!1}_setState(e){e!==this._state&&(this._state=e,this.options.stateChanged?.(e))}}const $f=(e,t)=>{if(!e.has(t))return{hit:!1};const i=e.get(t);return e.delete(t),e.set(t,i),{hit:!0,value:i}},Mf=(e,t,i,n)=>{for(e.delete(t),e.set(t,i);e.size>n;){const t=e.keys().next().value;if(void 0===t)break;e.delete(t)}},Rf=new Set(["select","draw","column","merge","split","resize","opening","wallthick","delroom"]),Cf=e=>`${window.innerWidth}x${window.innerHeight}|${location.pathname}|${JSON.stringify(e??{})}`,Tf="houseplan_card_alpha_v1",Df=Object.freeze([Object.freeze({id:"iso",issue:89,summary:"Volumetric plan renderer"})]);function Af(e){return/^[a-z][a-z0-9-]*$/.test(e.id)&&Number.isInteger(e.issue)&&e.issue>0&&!!e.summary.trim()}function Pf(e){const t=String(e||"").replace(/^#/,"");return new URLSearchParams(t)}function Ff(e){return Pf(e).get("space")||""}function zf(e,t,i=Df){const n=function(e){const t=new Set;for(const i of e){if(!Af(i)||t.has(i.id))return!1;t.add(i.id)}return!0}(i),r=function(e){let t,i=!1;const n=e=>{for(const n of e.getAll("hp_alpha"))i=!0,"1"===n?t=!0:"0"===n&&(t=!1)};return n(new URLSearchParams(String(e.search||"").replace(/^\?/,""))),n(Pf(e.hash)),{present:i,value:t}}(e),o=void 0!==r.value,s="1"===t,a=o?!0===r.value:!r.present&&s,l=n&&a;return{alpha:l,active:Object.freeze(l?i.map(e=>e.id).sort():[]),space:Ff(e.hash),persist:n&&o?l?"1":"0":void 0,knownUrlOperation:o}}let If={alpha:!1,active:Object.freeze([]),space:""},Of=!1,Ef="";const Nf=new Set;function Hf(){if("undefined"==typeof window)return If;const e=zf(window.location,function(){try{return window.localStorage.getItem(Tf)}catch{return null}}());void 0!==e.persist&&function(e){try{window.localStorage.setItem(Tf,e)}catch{}}(e.persist),If={alpha:e.alpha,active:e.active,space:e.space},window.__hpAlpha=e.alpha,window.__hpLabs=e.active;for(const e of Nf)e(If);return If}function Lf(){Hf()}function Bf(){if("undefined"==typeof window)return If;if(!Of){Of=!0,window.__hpLabsListenerCleanup?.(),window.addEventListener("hashchange",Lf),window.addEventListener("popstate",Lf);const e=()=>{window.removeEventListener("hashchange",Lf),window.removeEventListener("popstate",Lf),window.__hpLabsListenerCleanup===e&&delete window.__hpLabsListenerCleanup};window.__hpLabsListenerCleanup=e}return Hf()}const qf={window:120,door:90,passage:90,gate:300};function jf(e){return qf[e]}function Wf(e,t){return{type:e,lengthCm:jf(e),flipH:!1,flipV:!1,revision:t}}function Uf(e,t){const i=Math.max(0,e.renderedLength)/2,n=Math.max(0,e.target.physicalHalfWidth),r=n+.18*Math.max(0,t),o=e=>({x1:e,y1:-r,x2:e,y2:r});return{rect:{x:-i,y:n?-n:0,width:2*i,height:2*n},boundaries:[o(-i),o(i)]}}function Gf(e,t){const i=[e[0],e[1]],n=[t[0],t[1]];return function(e,t){return e[0]-t[0]||e[1]-t[1]}(i,n)<=0?{a:i,b:n}:{a:n,b:i}}function Vf(e){const t=new Map;return e.forEach((e,i)=>{if(!e.kind||e.open)return;const n=Gf(e.a,e.b);if(Math.hypot(n.b[0]-n.a[0],n.b[1]-n.a[1])<=1e-9)return;const r=function(e,t){const i=e=>(Math.abs(e)<=5e-10?0:Math.round(1e6*e)/1e6).toFixed(6);return`${i(e[0])},${i(e[1])}>${i(t[0])},${i(t[1])}`}(n.a,n.b),o=t.get(r);if(o)return o.physicalHalfWidth=Math.max(o.physicalHalfWidth,e.half||0),o.sourceOrder=Math.min(o.sourceOrder,i),void(e.partitionHost&&(o.partitionHost&&o.partitionHost.id!==e.partitionHost.id?o.ambiguousPartitionHost=!0:o.partitionHost=e.partitionHost));t.set(r,{segmentKey:r,a:n.a,b:n.b,physicalHalfWidth:Math.max(0,e.half||0),sourceOrder:i,...e.partitionHost?{partitionHost:e.partitionHost}:{}})}),[...t.values()]}function Kf(e,t){if(Math.abs(e.distance-t.distance)>1e-9)return e.distance-t.distance;if(Math.abs(e.perpendicular-t.perpendicular)>1e-9)return e.perpendicular-t.perpendicular;return(e.target.segmentKeyt.target.segmentKey?1:0)||e.target.sourceOrder-t.target.sourceOrder}function Yf(e){const t=Vf(e.intervals).map(t=>{const i=function(e,t){const i=t.b[0]-t.a[0],n=t.b[1]-t.a[1],r=Math.hypot(i,n),o=i/r,s=n/r,a=(e[0]-t.a[0])*o+(e[1]-t.a[1])*s,l=Math.max(0,Math.min(r,a)),c=t.a[0]+l*o,h=t.a[1]+l*s;return{along:l,length:r,x:c,y:h,distance:Math.hypot(e[0]-c,e[1]-h),perpendicular:Math.abs((e[0]-t.a[0])*s-(e[1]-t.a[1])*o)}}(e.pointer,t);return{target:t,...i,envelope:Math.max(e.baseTolerance,t.physicalHalfWidth+e.bodyPointerPadding)}}).filter(e=>e.distance<=e.envelope+1e-9).filter(t=>!function(e,t,i,n,r){const o=t.b[0]-t.a[0],s=t.b[1]-t.a[1],a=Math.hypot(o,s);if(!(a>1e-9))return!1;const l=o/a,c=s/a;for(const o of i){if(!o.open&&o.kind)continue;const i=Gf(o.a,o.b),s=i.b[0]-i.a[0],a=i.b[1]-i.a[1],h=Math.hypot(s,a);if(!(h>1e-9))continue;const d=s/h,u=a/h;if(Math.abs(l*u-c*d)>1e-6)continue;if(Math.abs((i.a[0]-t.a[0])*c-(i.a[1]-t.a[1])*l)>r)continue;const p=(e[0]-i.a[0])*d+(e[1]-i.a[1])*u,_=1e-9;if(!(p<=_||p>=h-_)&&Math.abs((e[0]-i.a[0])*u-(e[1]-i.a[1])*d)<=n+1e-9)return!0}return!1}(e.pointer,t.target,e.intervals,t.envelope,Math.max(1e-9,Math.min(e.baseTolerance,.04*e.gridStep)))),i=t.filter(t=>!!t.target.partitionHost&&e.renderedLength+2*t.target.physicalHalfWidth>t.length+1e-9).sort(Kf),n=t.filter(t=>!t.target.partitionHost||e.renderedLength+2*t.target.physicalHalfWidth<=t.length+1e-9).sort(Kf);let r=n[0];if(!r)return{candidate:null,jambBlockedTarget:i[0]?.target||null};const o=n.filter(e=>Math.abs(e.distance-r.distance)<=1e-9&&Math.abs(e.perpendicular-r.perpendicular)<=1e-9),s=o.filter(e=>e.target.partitionHost);if(s.length){if(1!==new Set(s.map(e=>e.target.partitionHost.id)).size||s.some(e=>e.target.ambiguousPartitionHost))return{candidate:null,jambBlockedTarget:null};const e=s[0],t=e.target.b[0]-e.target.a[0],i=e.target.b[1]-e.target.a[1],n=Math.hypot(t,i),a=t/n,l=i/n;if(!o.every(t=>{const i=t.target.b[0]-t.target.a[0],n=t.target.b[1]-t.target.a[1],r=Math.hypot(i,n),o=i/r,s=n/r,c=Math.abs(a*s-l*o)<=1e-6,h=Math.abs((t.target.a[0]-e.target.a[0])*l-(t.target.a[1]-e.target.a[1])*a);return c&&h<=1e-9}))return{candidate:null,jambBlockedTarget:null};r=e}if(r.target.ambiguousPartitionHost)return{candidate:null,jambBlockedTarget:null};const{target:a,length:l}=r,c=a.b[0]-a.a[0],h=a.b[1]-a.a[1],d=c/l,u=h/l,p=a.partitionHost?a.physicalHalfWidth:0,_=Math.min(Math.max(0,e.renderedLength)/2+p,l/2);let m=r.along;const g=Math.max(e.gridStep,1e-9),f=l/2;m=Math.abs(m-f)<=g/2?f:Math.round(m/g)*g,m=Math.max(_,Math.min(l-_,m));const v=a.a[0]+d*m,y=a.a[1]+u*m,b=Math.max(0,e.renderedLength)/2,w=m-b,k=m+b,x=Math.max(0,w),S=Math.max(0,l-k),$=[a.a[0]+d*(w-x/2),a.a[1]+u*(w-x/2)],M=[a.a[0]+d*(k+S/2),a.a[1]+u*(k+S/2)];let R=180*Math.atan2(h,c)/Math.PI;R>=90?R-=180:R<-90&&(R+=180);const C=Math.abs(m-f)<=1e-9;return{candidate:{presetRevision:e.preset.revision,geometryRevision:e.geometryRevision,pointer:[e.pointer[0],e.pointer[1]],type:e.preset.type,lengthCm:e.preset.lengthCm,flipH:e.preset.flipH,flipV:e.preset.flipV,x:v,y:y,angle:R,renderedLength:e.renderedLength,target:a,...a.partitionHost?{host:{...a.partitionHost,t:l>0?m/l:0}}:{},measure:{labels:[{distance:x,midpoint:$},{distance:S,midpoint:M}],guide:C?{x:v,y:y,angle:R}:null}},jambBlockedTarget:null}}function Xf(e,t,i,n,r=1e-6){return e.presetRevision===i&&e.geometryRevision===n&&Math.hypot(e.pointer[0]-t[0],e.pointer[1]-t[1])<=r}function Zf(e){return!(!e.canEdit||e.kiosk||e.fixedFloor)&&("view"!==e.mode&&("mouse"===e.pointerType&&e.spaceCount>1))}class Jf{constructor(e,t,i){this.loader=e,this.host=t,this.adopted=i,this.attachment=null}connect(){if(this.runtime)return void this.runtime.connect();this.attachment?.cancel();const e=this.loader.attach(this.host,e=>this.adopt(e));this.runtime||(this.attachment=e)}disconnect(){this.attachment?.cancel(),this.attachment=null,this.runtime?.disconnect()}adopt(e){this.attachment=null,this.runtime||(this.runtime=e,this.adopted(e))}}const Qf=new class{constructor(e){this.load=e,this.factory=null,this.pending=null}get warm(){return null!==this.factory}create(e){return this.factory?this.factory(e):null}attach(e,t){let i=!0;const n={cancel:()=>{i=!1}},r=this.create(e);return r?(t(r),n):(this.ensure().then(n=>{i&&t(n(e))},()=>{}),n)}ensure(){return this.factory?Promise.resolve(this.factory):(this.pending||(this.pending=this.load().then(e=>(this.factory=e,this.pending=null,e),e=>{throw this.pending=null,e})),this.pending)}reset(){this.factory=null,this.pending=null}}(()=>import("./summary-panel-runtime-loaded-CX2cplA1.js").then(function(e){return e.e}).then(({LoadedSummaryPanelRuntime:e})=>t=>new e(t)));function ev(e){const t=globalThis.__HP_VERSION_OVERRIDE__;return"string"==typeof t&&t.length>0?t:e}let tv=0;const iv="1.77.0-beta.2",nv="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32",rv=1500,ov=new Map;let sv=0,av=1e4;const lv="houseplan_card_layout_v1",cv="houseplan_card_cfg_v1",hv="houseplan_card_zoom_v1",dv="houseplan_card_nav_v1",uv="houseplan_card_view_v1",pv="hp-dialog, hp-help, hp-color-opacity, hp-device-preview",_v=1e3,mv=(e,t)=>{const i=Math.min(e.x,t.x),n=Math.min(e.y,t.y);return{x:i,y:n,w:Math.max(e.x+e.w,t.x+t.w)-i,h:Math.max(e.y+e.h,t.y+t.h)-n}},gv=(e,t,i)=>{const n=new Event(t,{bubbles:!0,composed:!0});n.detail=i??{},e.dispatchEvent(n)},fv=e=>{history.pushState(null,"",e),gv(window,"location-changed",{replace:!1})},vv=(e,t)=>{let i,n=null;const r=(...r)=>{clearTimeout(i),n=r,i=window.setTimeout(()=>{i=void 0;const t=n;n=null,t&&e(...t)},t)};return r.flush=()=>{if(void 0===i)return;clearTimeout(i),i=void 0;const t=n;n=null,t&&e(...t)},r.cancel=()=>{clearTimeout(i),i=void 0,n=null},r.pending=()=>void 0!==i,r},yv=e=>{try{e.target?.setPointerCapture?.(e.pointerId)}catch{}},bv=["edges","corners"];class wv extends he{constructor(){var e;super(...arguments),this._editorRuntime=null,this._liveRt=null,this._onboardingRuntime=null,this._editorRuntimeLoadingVisible=!1,this._backdropGuard=null,this._editorModeRequest=0,this._warmModeRequest=0,this._editorRuntimeLoader=new Sf({expectedFingerprint:nv,load:async e=>{const t=0===e?await import("./houseplan-editor-runtime-AzCVhtuX.js"):await import((()=>{const e=new URL("./houseplan-editor-runtime-AzCVhtuX.js",import.meta.url);return e.searchParams.set("hp_retry",`${iv}-${++tv}`),e.href})());return{fingerprint:t.EDITOR_RUNTIME_FINGERPRINT,create:()=>new t.HouseplanEditorRuntime(this)}},install:e=>{this._editorRuntime=e},stateChanged:e=>this._editorRuntimeStateChanged(e),failed:(e,t)=>{console.error("[houseplan] unable to load editor runtime",e),t.terminal&&this._versionRecovery.hasCurrentMismatchNotice||this._showToast(kf(e=>this._t(e),t))}}),this._onboardingRuntimeLoader=new Sf({expectedFingerprint:nv,load:async e=>{const t=0===e?await import("./houseplan-onboarding-runtime-Dp2b84fm.js"):await import((()=>{const e=new URL("./houseplan-onboarding-runtime-Dp2b84fm.js",import.meta.url);return e.searchParams.set("hp_retry",`${iv}-${++tv}`),e.href})());return{fingerprint:t.ONBOARDING_RUNTIME_FINGERPRINT,create:()=>new t.HouseplanOnboardingRuntime(this)}},install:e=>{this._onboardingRuntime=e},failed:(e,t)=>{console.error("[houseplan] unable to load onboarding runtime",e),t.terminal&&this._versionRecovery.hasCurrentMismatchNotice||this._showToast(kf(e=>this._t(e),t))}}),this._isoSceneRuntime=null,this._isoSceneRuntimeLoader=new Sf({expectedFingerprint:nv,load:async e=>{const t=0===e?await import("./iso-scene-render-fYqz_-Ot.js"):await import((()=>{const e=new URL("./iso-scene-render-fYqz_-Ot.js",import.meta.url);return e.searchParams.set("hp_retry",`${iv}-${++tv}`),e.href})());return{fingerprint:t.ISO_SCENE_RUNTIME_FINGERPRINT,create:()=>t}},install:e=>{const t=this._effectiveProjection();this._isoSceneRuntime=e,this._isoProjectionSnapshot=null;const i=this._effectiveProjection();this._convertProjectionView(t,i),this.isConnected&&this.requestUpdate()},failed:(e,t)=>{console.warn("[houseplan] hidden isometric runtime diagnostic",wf("runtime-load","unverified",t.terminal)),this.isConnected&&this.requestUpdate()}}),this._pdfRuntime=null,this._pdfRuntimeLoader=new Sf({expectedFingerprint:nv,load:async e=>{const t=0===e?await import("./pdf-export-D3vmqIY6.js"):await import((()=>{const e=new URL("./pdf-export-D3vmqIY6.js",import.meta.url);return e.searchParams.set("hp_retry",`${iv}-${++tv}`),e.href})());return{fingerprint:t.PDF_EXPORT_FINGERPRINT,create:()=>new t.PdfExportRuntime}},install:e=>{this._pdfRuntime=e,this.isConnected&&this.requestUpdate()},failed:(e,t)=>{if(console.error("[houseplan] unable to load PDF export runtime",e),!t.terminal||!this._versionRecovery.hasCurrentMismatchNotice){const e=kf(e=>this._t(e),t),i=this._t("editor.load_failed"),n=e.startsWith(i)?e.slice(i.length).trim():e;this._showToast(`${this._t("pdf.failed")} ${n}`.trim())}}}),this.panelHost=!1,this.narrow=null,this._space="f1",this._adoption=new qu((e,t)=>this.requestUpdate(e,t)),this._serverStorage=!1,this._loadOk=!1,this._serverCanWrite=null,this._loading=!1,this._loadTries=0,this._unsubCfg=null,this._unsubLayout=null,this._unsubVirtual=null,this._liveSyncAttempt=null,this._liveSyncGeneration=0,this._liveSyncConnection=null,this._configReloadAuthority=new Gu,this._virtualLights=Hh(null),this._canOptimizeUndo=!1,this._undoKind=null,this._devices=[],this._regSignature="",this._defPos={},this._newSyncKey="",this._areaRelocationIds=new Set,this._areaSnapshotCleanupCandidates=new Map,this._areaRelocationSyncKey="",this._areaRelocationWrite=Promise.resolve(),this._tip=null,this._hoverRoom=null,this._pointerModality=new sg(this,()=>this._syncPointerHoverTargets()),this._devicePressAnimations=new Map,this._selId=null,this._toast="",this._mode="view",this._pendingNavMode=null,this._decorTool="select",this._decorStyle={...Cr},this._decorStyleSeeded=!1,this._decorDraft=null,this._decorMove=null,this._decorSel=null,this._decorEraseConfirm=null,this._decorTextDialog=null,this._decorShapeDialog=null,this._backdropDialog=null,this._decorTextSelection={start:0,end:0},this._furnPalette=null,this._decorImagePalette=null,this._decorAssetCatalog=[],this._decorAssets=new Map,this._decorAssetBusy=!1,this._furnCategory=null,this._furnPreviewInput=null,this._furnTouchPending=null,this._dtBox=null,this._dtDrag=null,this._bdDrag=null,this._slide="",this._reducedMotion=!1,this._onMotionChange=e=>{this._reducedMotion=e.matches,this._cancelDevicePressFeedback(),e.matches&&this._cancelCameraTransition(!0),e.matches&&this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:e.matches&&this._modeTransition.active&&this._cancelModeTransition(!0),this._syncVersionRecovery(),this.requestUpdate()},this._editorChromeMode="plan",this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest=0,this._modeTransitionTargetZoom=1,this._modeTransitionEditorCamera=null,this._modeTransition=new Ug({frame:e=>this._applyModeTransitionFrame(e),settled:e=>this._settleModeTransition(e)}),this._cameraTransitionFit=null,this._cameraTransition=new Qg({frame:e=>this._applyCameraTransitionFrame(e),settled:e=>this._settleCameraTransition(e)}),this._editorSecondaryCopy={groupActive:(e,t)=>this._t("editor.group_active",{group:e,item:t}),openGroup:e=>this._t("editor.open_group",{group:e}),disabledAction:(e,t)=>this._t("editor.disabled_action",{action:e,reason:t})},this._tool="draw",this._geometryHistory=new gg(50),this._devicePositionHistory=new gg(50),this._devicePositionBusy=!1,this._wallDialog=null,this._drawWallField=null,this._activeWallChainId=null,this._activeWallChainPartitionIds=[],this._wallChainRedo=[],this._physicalSel=null,this._physicalDialog=null,this._partitionDeleteDialog=null,this._roomDeleteDialog=null,this._physicalDrag=null,this._physicalRotate=null,this._physicalLastTap=null,this._physicalPickCycle=null,this._wallUnionCacheValue=null,this._wallUnionPool=new Map,this._isoGeometryCache=new Map,this._renderIsoScene=null,this._isoProjectionSnapshot=null,this._isoStructuralBuildCount=0,this._isoFallback=new Set,this._openingTunnelCache=null,this._openingWallIndexCache=new Map,this._openingPlacementIntervalsCache=null,this._openingDimensionContextCache=null,this._planSnapGeometryCache=null,this._planStructuralGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._physicalBodiesCache=null,this._lightPhysicalBodiesCache=null,this._cleanFloorCache=new Map,this._innerContourCache=new Map,this._glowRuntimeState=bm(),this._glowRuntimeHost={window:()=>this.ownerDocument.defaultView||window,isConnected:()=>this.isConnected,requestUpdate:()=>this.requestUpdate(),reducedMotion:()=>this._reducedMotion},this._lightBarrierCache=null,this._lightBarrierPool=new Map,this._glowScreenBlend=!1,this._duplicateColumnId=null,this._duplicateColumnTimer=0,this._rszLimitViolation=null,this._path=[],this._cursorPt=null,this._planSnapHover=null,this._mergeSel=null,this._openingPreset=null,this._openingRebindId=null,this._openingPresetRevision=0,this._openingHoverCandidate=null,this._openingJambBlockCm=null,this._openingDialog=null,this._openingInfo=null,this._opDrag=null,this._opMeasure=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._wallFaceBatch=null,this._wallRepairDiagnostic=null,this._wallFaceGraphCache=[],this._areaSel="",this._nameSel="",this._roomDialog=!1,this._roomEditId=null,this._roomFill="",this._roomCustomFill=null,this._roomTempMin="",this._roomTempMax="",this._roomTempSrc="",this._roomHumSrc="",this._roomSrcOpen=null,this._roomSrcFilter="",this._roomNameScale=1,this._roomLabelScale=1,this._zoom=1,this._view=null,this._zoomBySpace={},this._viewModeSnap=null,this._roomFocus=null,this._roomPointer=null,this._doubleFit=new ff,this._deviceHits=new wc,this._pointers=new Map,this._panStart=null,this._panLock=null,this._pinchStart=null,this._safeDayCycleOutline=!1,this._suppressClick=!1,this._viewportGestureDirty=!1,this._touchContacts=new Map,this._touchClickGuard=new pc,this._connectedPath="",this._routeDepartureHandled=!1,this._onLocationChanged=()=>{this._connectedPath&&location.pathname!==this._connectedPath?this._leaveCardRoute():location.pathname===this._connectedPath&&(this._routeDepartureHandled=!1)},this._touchGestureGuard={capture:!0,handleEvent:e=>this._guardTouchGesture(e)},this._hdrH=118,this._booting=!0,this._bootFading=!1,this._bootSettling=!1,this._bootSettleRaf=0,this._bootLastH=-1,this._bootStart=0,this._bootLastChange=0,this._bootSoft=!1,this._tapConfirm=null,this._dangerConfirm=null,this._dangerConfirmController=new ze(e=>{this._dangerConfirm=e}),this._confirmDanger=e=>this._config&&this.hass?"warm"===this._syncDangerConfirmLocaleGate()||this._dangerConfirmMissingSpace()?Promise.resolve(!1):this._dangerConfirmController.confirm(e):Promise.resolve(!1),this._cancelDangerConfirm=()=>{this._dangerConfirmController.cancel()},this._onDangerConfirmDecision=e=>{this._dangerConfirmController.resolve(e.detail.token,e.detail.accepted)},this._onboardingShown=!1,this._rulesDialog=null,this._preflightClipboardFallback=null,this._haIntegrationVersion=null,this._versionRecovery=(e=this,new wg({clock:{setTimeout:(e,t)=>window.setTimeout(e,t),clearTimeout:e=>window.clearTimeout(e)},storage:()=>e.ownerDocument.defaultView?.sessionStorage??null,safety:()=>Sg(e),reload:()=>e._reloadDocument(),changed:()=>{e.requestUpdate()}})),this._haSupportApi=null,this._haDecorAssetsApi=null,this._haSummaryPanelApi=null,this._haRadarStage1Api=null,this._radarLive=new Ag(this),this._decorAssetSyncToken=0,this._alignDialog=null,this._settingsDialog=null,this._pdfDialog=!1,this._supportDialog=null,this._backupExportDialog=null,this._backupImportDialog=null,this._sunRaysCache=null,this._dayCycleTimer=0,this._dayCycleClockKey="",this._compassDrag=!1,this._importDialog=null,this._importQueue=[],this._importTotal=0,this._rulesCompiledSrc="",this._infoCard=null,this._nativeMoreInfoEntity=null,this._deviceInbox=null,this._deviceInboxReturn=null,this._deviceInboxMemo=null,this._markerDialog=null,this._spaceDialog=null,this._keyHandler=e=>this._onKey(e),this._warmVp=null,this._warmVpArmed=!1,this._warmLongReturn=!1,this._warmRevivePending=!1,this._warmGen=++sv,this._warmKey=null,this._warmSlot=null,this._hashApplied=!1,this._navApplied=!1,this._labs={alpha:!1,active:Object.freeze([]),space:""},this._viewPreference={},this._renderProjection="flat",this._kioskScale={icon:1,font:1},this._kioskDialog=!1,this._summarySlot=new Jf(Qf,this,e=>{this._summary=e,this._capturedSnapshotSequence=-1,this.isConnected&&(e.connect(),this.hasUpdated&&this.requestUpdate())}),this._activityRt=new Map,this._vacRt=new Map,this._vacViewKey="",this._vacLastView=null,this._vacRaf=0,this._vacSrvTrails={},this._vacJumpOnce=!1,this._continuity=this._newContinuityController(),this._continuityHistory=[],this._continuityEpoch=0,this._continuityDataReady=!0,this._continuityPaintToken=-1,this._continuityDisposed=!1,this._renderSnapshotAt=Date.now(),this._hassSequence=0,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotSequence=-1,this._capturedSnapshotDevices=null,this._capturedSnapshotLayout=null,this._capturedSnapshotActivity="",this._capturedSnapshotConfigEpoch=-1,this._capturedSnapshotVirtual="",this._lastValidStageSize=null,this._pendingRefitSize=null,this._refitRaf=0,this._pageVisibility=e=>{if(this._continuity.visibility(e),this._dayCycleVisibility(e),this._summary?.visibility(e.kind),"hidden"===e.kind)return this._radarLive.stop(),this._editorRuntime?._cancelRadarSetup(),this._clearRoomFocus(!0),this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._cancelCameraTransition(!0),void(this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:this._cancelModeTransition(!0));if(this._vacJumpOnce=!0,this._syncRadarLive(),!e.long){const e=Date.now();let t=!1;for(const i of this._activityRt.values())!i.flashKind||(i.expiresAt||i.flashTs+tg)>e||(i.flashTs=0,i.flashKind=null,i.expiresAt=0,t=!0);return void(t&&this.requestUpdate())}Date.now()-this._renderSnapshotAt>1e3&&this._continuity.note("device-snapshot-stale"),this._continuityDataReady=!1,this._continuityPaintToken=-1,this._resumeSettling=!0,this._loading?this.requestUpdate():this._loadFromServer()},this._resumeSettling=!1,this._viewportInvalidAt=0,this._vacFit=null,this._vacAllCamerasFor=null,this._vacAllCameraCache=null,this._vacCalConfirm=null,this._kioskDots=!1,this._cyclePausedUntil=0,this._swipeStart=null,this._tabDrag=null,this._tabDragRelease=null,this._tabSuppressClick=!1,this._tabOrderWarned=!1,this._onLabsSnapshot=e=>{const t=this._effectiveProjection();this._labs=e,this._isoProjectionSnapshot=null,this._labsIso&&this._ensureIsoSceneRuntime();const i=this._effectiveProjection();this._convertProjectionView(t,i),this.requestUpdate()},this._onHashChange=()=>{if(this._hasFixedFloor)return;const e=this._hashSpace();if(e&&this._model.find(t=>t.id===e)&&e!==this._space){if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return;this._commitSpace(e),this._selId=null,this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeWallChainId=null,this._activeWallChainPartitionIds=[],this._wallChainSegmentCms=[],this._closingWallCm=null,this._restoreZoom(),this.requestUpdate()}},this._drag=null,this._deviceDrag=null,this._rlResize=null,this._holdFired=!1,this._retryContinuity=()=>{this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.retry(this._continuity.recoveryReason||"plan"),this._loading||this._loadFromServer()},this._cfgEpoch=0,this._cfgEpochPreservedConfig=null,this._terminalFrame=0,this._modelCache=null,this._emptySpaceStateActive=!1,this._decorSnapCache=null,this._markerPreviewMemo=null,this._markerPreviewDevicesMemo=null,this._showHidden=!1,this._connHooked=null,this._connectionWasLost=!1,this._haRegistryConnection=null,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._renderLife=new $g,this._liveEditorPaintCount=0,this._onHaRegistryUpdate=()=>{const e=nd(this.hass);e.revision===this._haRegistryRev&&this._devices.length||(this._haRegistryRev=e.revision,this._renderLife.invalidate(),this._planHassMemo=null,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate())},this._onConnReady=()=>{if(this._loadTries=0,clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,id(this.hass),this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(this._onConnReady,400));!this._connectionWasLost&&this._continuity.hasCompleteFrame?this._beginContinuityCandidate("connection-ready",!1,"plan"):(this._continuityDataReady=!1,this._continuityPaintToken=-1),this._loading||this._loadFromServer()},this._onConnLost=()=>{this._booting&&!this._continuity.hasCompleteFrame||(this._connectionWasLost=!0,this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.connectionLost())},this._signer=new uc(()=>this.requestUpdate()),this._dirtyPos=new Set,this._sentPos=new Map,this._persistLayout=vv(()=>{if(this._serverStorage){const e=[...this._dirtyPos];this._dirtyPos.clear();for(const t of e){const e=xo(this._layout[t]);e&&(this._layout={...this._layout,[t]:e},this._sentPos.set(t,e),this.hass.callWS({type:"houseplan/layout/update",device_id:t,pos:e}).then(e=>this._noteLayoutRev(e)).catch(e=>this._showToast(this._t("toast.pos_save_failed",{err:this._errText(e)}))).finally(()=>{this._sentPos.get(t)===e&&this._sentPos.delete(t)}))}this._cacheSnapshot()}else this._persistLocalLayout()},600),this._frame=null,this._showFar=!1,this._writesPending=0,this._writeChain=Promise.resolve(),this._pendingPhysicalWrites=new Map,this._undoGeometry=()=>this._editorRuntimeOrThrow()._undoGeometry(),this._redoGeometry=()=>this._editorRuntimeOrThrow()._redoGeometry(),this._saveConfigDebounced=vv(()=>{this._serverCfg&&this._writeConfig().catch(e=>{const t=!0===e?.physicalGeometryRolledBack;"geometry-unsafe"!==e?.code&&("wall_model_client_outdated"===e?.code?this._showToast(this._t("toast.wall_model_client_outdated")):"conflict"===e?.code?(this._showToast(this._t("toast.conflict")),t||(this._cancelPath(),this._reloadConfigOnly(!0))):this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(e)})),t&&this._reloadRejectedPhysicalWrite())})},500),this._wallChainSegmentCms=[],this._closingWallCm=null,this._savePhysicalDialog=()=>this._editorRuntimeOrThrow()._savePhysicalDialog(),this._deletePhysicalSelection=()=>this._editorRuntimeOrThrow()._deletePhysicalSelection(),this._confirmPartitionDelete=()=>this._editorRuntimeOrThrow()._confirmPartitionDelete(),this._confirmRoomDelete=e=>this._editorRuntimeOrThrow()._confirmRoomDelete(e),this._rebindPartitionOpening=()=>this._editorRuntimeOrThrow()._rebindPartitionOpening(),this._keepClosedAsPartitions=()=>this._editorRuntimeOrThrow()._keepClosedAsPartitions(),this._toggleServerPlans=async()=>this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._toggleServerPlans():this._editorRuntimeOrThrow()._toggleServerPlans(),this._aspectJob=null,this._dayCycleTick=()=>{if(!this.isConnected||"hidden"===this.ownerDocument.visibilityState)return;const e=this._dayCycleState();if(!e)return this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),void(this._dayCycleClockKey="");const t=cr(e);t!==this._dayCycleClockKey&&(this._dayCycleClockKey=t,this.requestUpdate())},this._sunShown=!1,this._sunOut=!1,this._sunOutTimer=0,this._openSettingsDialog=()=>{if(this._editorRuntime)return this._editorRuntime._openSettingsDialog();this._ensureEditorRuntime().then(e=>{e&&this._openSettingsDialog()})},this._openSupportDialog=()=>{this._editorRuntime?this._editorRuntime._openSupportDialog():this._ensureEditorRuntime().then(e=>{e&&this._openSupportDialog()})},this._openPdfDialog=()=>{this._pdfRuntimeLoader.ensure().then(e=>{e&&(this._pdfDialog=!0,this.requestUpdate())})},this._reportedPreflightFingerprint=null,this._openAlignDialog=()=>this._editorRuntimeOrThrow()._openAlignDialog(),this._toggleOptimizeLivePositions=()=>this._editorRuntimeOrThrow()._toggleOptimizeLivePositions(),this._optimizeUndoBusy=!1,this._openBackupExport=()=>this._editorRuntimeOrThrow()._openBackupExport(),this._openRulesDialog=()=>this._editorRuntimeOrThrow()._openRulesDialog(),this._climateCache=null,this._gearPtCache=new WeakMap}requestUpdate(e,t,i){if("hass"===e&&this.hass&&this._liveRt){const e=this._visibleDeviceSnapshot||this._candidateDeviceSnapshot;if(!this._liveRt.hass(t,this.hass,e?{entityIds:e.entityIds}:null,()=>Mg(this))&&!this._summary?.observeHassComposition())return}void 0!==e&&(this._terminalFrame=0),this._editorRuntime?._routeLiveEditorUpdate(e,t)||(this._liveRt?.clear(),super.requestUpdate(e,t,i))}_editorRuntimeOrThrow(){if(!this._editorRuntime)throw new Error("Houseplan editor runtime is not loaded");return this._editorRuntime}async _ensureEditorRuntime(){return this._editorRuntimeLoader.ensure()}async _ensureOnboardingRuntime(){return this._onboardingRuntimeLoader.ensure()}async _ensureIsoSceneRuntime(){return this._isoSceneRuntimeLoader.ensure()}_editorRuntimeStateChanged(e){clearTimeout(this._editorRuntimeLoadingTimer),this._editorRuntimeLoadingTimer=void 0,"loading"!==e?(this._editorRuntimeLoadingVisible=!1,this.requestUpdate()):this._editorRuntimeLoadingTimer=window.setTimeout(()=>{this._editorRuntimeLoadingVisible=!0,this.requestUpdate()},150)}async _requestMode(e,t=!0,i=!1){const n=++this._editorModeRequest;if(i&&(this._warmModeRequest=n,this._refitRaf&&(cancelAnimationFrame(this._refitRaf),this._refitRaf=0),this._pendingRefitSize=null),"view"===e||await this._ensureEditorRuntime()){if(n===this._editorModeRequest&&this.isConnected)return i?(this._adoptMode(e),this._warmRevivePending&&(clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmReviveDialog()),this.requestUpdate(),void this.updateComplete.then(()=>requestAnimationFrame(()=>requestAnimationFrame(()=>{if(this._warmModeRequest!==n||n!==this._editorModeRequest)return;const e=this._stageEl;this._lastValidStageSize=e&&e.clientWidth>0&&e.clientHeight>0?[e.clientWidth,e.clientHeight]:null,this._pendingRefitSize=null,this._warmModeRequest=0})))):void this._setMode(e,t);this._warmModeRequest===n&&(this._warmModeRequest=0)}else this._warmModeRequest===n&&(this._warmModeRequest=0)}get _layout(){return this._adoption.layout}set _layout(e){this._adoption.stageLocalLayout(e)}get _layoutRev(){return this._adoption.layoutRev}set _layoutRev(e){this._adoption.seedIdentity({layoutRev:e})}get _layoutContentFingerprint(){return this._adoption.layoutFingerprint}set _layoutContentFingerprint(e){this._adoption.seedIdentity({layoutFingerprint:e})}get _serverCfg(){return this._adoption.config}set _serverCfg(e){this._adoption.stageLocalConfig(e)}get _cfgRev(){return this._adoption.configRev}set _cfgRev(e){this._adoption.seedIdentity({configRev:e})}get _cfgContentFingerprint(){return this._adoption.configFingerprint}set _cfgContentFingerprint(e){this._adoption.seedIdentity({configFingerprint:e})}_seedDecorStyle(e){var t,i;if(t=Ol,i=this,Fl(e,Bl)&&"pending"===t.state()&&(t.art("",i),t.ensure()),this._decorStyleSeeded||!e)return;this._decorStyleSeeded=!0;const n=e.settings?.decor_default_style;n&&(this._decorStyle=function(e,t){if(!e||"object"!=typeof e)return{...t};const i=e,n="string"==typeof i.color&&i.color?i.color:t.color,r="string"==typeof i.fill_color&&i.fill_color?i.fill_color:t.fillColor,o=Number(i.width_cm);return{color:n,opacity:Tr(i.opacity,t.opacity),widthCm:Number.isFinite(o)&&o>0?Math.max(.1,Math.min(100,o)):t.widthCm,fill:"boolean"==typeof i.fill?i.fill:t.fill,fillColor:r,fillOpacity:Tr(i.fill_opacity,t.fillOpacity)}}(n,Cr))}get _canManageConfiguration(){return null!==this._serverCanWrite?this._serverCanWrite:!0===this.hass?.user?.is_admin}get _canEdit(){return this._norm&&this._canManageConfiguration}get _kiosk(){return!!this._config?.kiosk}_showKioskDots(){this._kioskDots=!0,clearTimeout(this._kioskDotsTimer),this._kioskDotsTimer=window.setTimeout(()=>this._kioskDots=!1,2500)}get _modeTransitionBusy(){return this._modeTransitionPreparing||this._modeTransition.active}get _doubleFitEnabled(){return!("view"!==this._mode||this._vacFit||this._modeTransitionBusy||this._touchSequenceMultitouch||"steady"!==this._continuity.state||this._continuity.overlayBlocksInteraction)}_cameraState(){const e=this._viewOr(this._baseVb());return{zoom:this._zoom,viewBox:{...e}}}_normalizeCameraState(e){const t=this._cameraTransitionFit||Oi(this._baseVb(),this._stageAspect());return{zoom:Math.min(wv.ZOOM_MAX,Math.max(wv.ZOOM_MIN,e.zoom)),viewBox:this._clampView({...e.viewBox},t)}}_applyCameraTransitionFrame(e){const t=this._normalizeCameraState(e.presented);e.presented=t,this._zoom=t.zoom,this._view={...t.viewBox},this._liveVp(!0)}_settleCameraTransition(e){const t=this._normalizeCameraState(e.to);this._zoom=t.zoom,this._view={...t.viewBox},this._cameraTransitionFit=null,"room"!==e.reason&&this._saveZoom(),this.requestUpdate()}_cancelCameraTransition(e=!1,t=!1){const i=this._cameraTransition.state?.reason,n=t&&this._cameraTransition.active?this._cameraTransition.presented?.zoom:void 0;this._cameraTransition.cancel(e),this._cameraTransitionFit=null,void 0!==n&&"room"!==i&&this._saveZoom()}_prepareCameraCommand(){this._bootSoftCancel(),this._modeTransitionBusy&&this._cancelModeTransition(!0),"opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1))}_startCameraTransition(e,t,i,n){const r=this._cameraState(),o=this._cameraTransition.target;return(!o||!Xg(o,e))&&(Xg(r,e)?(this._cancelCameraTransition(!1),!1):(this._activateSafeDayCycleOutline(),this._cameraTransitionFit={...t},this._cameraTransition.start(r,e,i,this._reducedMotion?0:n),!0))}_cssColor(e,t){const i=String(e||"").trim();if(!i)return t;const n=document.createElement("span");n.style.cssText=`position:absolute;visibility:hidden;color:${i}`,this.renderRoot.append(n);const r=getComputedStyle(n).color||t;return n.remove(),r}_currentModeVisual(e=this._mode){const t=this._modeTransition.presented||this._modeTransitionVisual;if(t)return{...t,viewport:{...t.viewport,viewBox:{...t.viewport.viewBox}}};const i=this._stageEl;if(!i||i.clientWidth<=0||i.clientHeight<=0)return null;const n=this.renderRoot.querySelector(".editorchrome"),r=this._viewOr(this._baseVb()),o=this.renderRoot.querySelector(".hp-paper"),s=this.renderRoot.querySelector(".hp-backdrop"),a=this.renderRoot.querySelector(".zoomwrap"),l=a?getComputedStyle(a).filter:"",c=Number(/brightness\(([^)]+)\)/.exec(l)?.[1]);return{presentedMode:e,editorChromeHeight:"view"===e?0:n?.getBoundingClientRect().height||0,stageWidth:i.clientWidth,stageHeight:i.clientHeight,viewport:Bg(r,i.clientWidth),stageColor:getComputedStyle(i).backgroundColor||"rgb(255, 255, 255)",paperColor:o?getComputedStyle(o).fill:"rgb(255, 255, 255)",sceneBrightness:Number.isFinite(c)?c:1,architectureOpacity:"decor"===e?.35:1,backdropOpacity:s&&Number(getComputedStyle(s).opacity)||1,viewWeight:"view"===e?1:0,editorWeight:"view"===e?0:1,toolbarContentOpacity:"view"===e?0:1}}_viewForModeTarget(e,t,i,n,r){const o=Oi(this._baseVb(),n/r),s=Math.min(wv.ZOOM_MAX,Math.max(wv.ZOOM_MIN,e)),a=o.w/s,l=o.h/s,c=t??o.x+o.w/2,h=i??o.y+o.h/2;return this._clampView({x:c-a/2,y:h-l/2,w:a,h:l},o)}_targetStageColor(e){return"view"!==e?"rgb(255, 255, 255)":this._cssColor(this._stageBg(this._spaceDisplayForRender()),this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"))}_targetPaperColor(e){return"view"===e&&this._spaceModel()?.bg?this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"):"rgb(255, 255, 255)"}_targetBrightness(e){return 1}_applyModeTransitionFrame(e){e.targetMode===this._mode&&(this._modeTransitionVisual=e.presented,this._view={...e.presented.viewport.viewBox},this.requestUpdate())}_settleModeTransition(e){if(e.targetMode!==this._mode)return;const t=this._modeTransitionRequest;this._view={...e.to.viewport.viewBox},this._zoom=this._modeTransitionTargetZoom,this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._lastValidStageSize=[e.to.stageWidth,e.to.stageHeight],"view"===this._mode&&(this._saveZoom(),this._viewModeSnap=null,this._modeTransitionEditorCamera=null),this.requestUpdate(),this.updateComplete.then(()=>{if(!this.isConnected||t!==this._modeTransitionRequest||this._modeTransitionBusy||e.targetMode!==this._mode)return;const i=this._stageEl;if(i&&i.clientWidth>0&&i.clientHeight>0&&(Math.abs(i.clientWidth-e.to.stageWidth)>.5||Math.abs(i.clientHeight-e.to.stageHeight)>.5)){const e=this._view;this._lastValidStageSize=[i.clientWidth,i.clientHeight],this._applyView(this._zoom,e?e.x+e.w/2:void 0,e?e.y+e.h/2:void 0),this.requestUpdate()}const n=this.renderRoot.activeElement;(!n||!n.isConnected||!!n.closest?.(".editorchrome, .stage"))&&this.renderRoot.querySelector(".modetab.active")?.focus?.({preventScroll:!0})})}_cancelModeTransition(e=!0){this._cancelCameraTransition(!1);const t=!!this._modeTransition.state;this._modeTransitionRequest++,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransition.cancel(e),e&&t||(this._modeTransitionVisual=null)}_adoptMode(e){e!==this._mode&&(this._clearRoomFocus(!0),this._resetDeviceHitState()),this._cancelModeTransition(!1),this._mode=e,this._isoProjectionSnapshot=null,"view"!==e&&(this._editorChromeMode=e)}_commitViewModeAtomic(e,t,i,n){if(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this._zoom=t,e){const r=this._stageEl?.clientWidth||e.stageWidth,o=Math.max(1,e.stageHeight+e.editorChromeHeight);this._view=this._viewForModeTarget(t,i,n,r,o),this._lastValidStageSize=[r,o]}else this._view=null;this._viewModeSnap=null,this._modeTransitionEditorCamera=null,this._saveZoom(),this.requestUpdate()}_prepareModeTransition(e,t,i,n,r,o){this.updateComplete.then(()=>{if(!this.isConnected||e!==this._modeTransitionRequest||this._mode!==i)return void(e===this._modeTransitionRequest&&(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this.requestUpdate()));const s=this.renderRoot.querySelector(".editorchrome-inner"),a="view"===i?0:s?.scrollHeight||0,l=Math.max(1,(this.panelHost?this.clientHeight:innerHeight)-ef(this.renderRoot,this._stageEl,this.panelHost)),c=this._stageEl?.clientWidth||t.stageWidth,h=this._viewForModeTarget(n,r,o,c,l),d={presentedMode:i,editorChromeHeight:a,stageWidth:c,stageHeight:l,viewport:Bg(h,c),stageColor:this._targetStageColor(i),paperColor:this._targetPaperColor(i),sceneBrightness:this._targetBrightness(i),architectureOpacity:"decor"===i?.35:1,backdropOpacity:"decor"===i&&"backdrop"!==this._decorTool?.5:1,viewWeight:"view"===i?1:0,editorWeight:"view"===i?0:1,toolbarContentOpacity:"view"===i?0:1};this._modeTransitionPreparing=!1;const u=this._modeTransitionForceAtomic;this._modeTransitionForceAtomic=!1,this._modeTransition.start(t,d,i,this._reducedMotion||u?0:220)})}get _hasFixedFloor(){return!!this._config&&Object.prototype.hasOwnProperty.call(this._config,"floor")}_fixedFloorState(e=this._model,t=this._loadOk){const i=this._config?.floor,n=function(e){if(!e.hasFloor)return{kind:"absent"};const t=e.floor;if("string"==typeof t)return t.length?e.spaceIds.includes(t)?{kind:"valid",id:t,source:"id"}:{kind:"invalid",reason:"unknown-id",value:t}:{kind:"invalid",reason:"empty-id",value:t};if("number"==typeof t){if(!Number.isFinite(t))return{kind:"invalid",reason:"non-finite-index",value:t};if(!Number.isInteger(t))return{kind:"invalid",reason:"fractional-index",value:t};if(t<0)return{kind:"invalid",reason:"negative-index",value:t};const i=e.spaceIds[t];return void 0===i?{kind:"invalid",reason:"out-of-range-index",value:t}:{kind:"valid",id:i,source:"index"}}return{kind:"invalid",reason:"invalid-type",value:t}}({spaceIds:e.map(e=>e.id),hasFloor:this._hasFixedFloor,floor:i});return!this._hasFixedFloor||t?n:"number"==typeof i?"valid"===n.kind||"invalid"===n.kind&&"out-of-range-index"===n.reason?{kind:"pending",value:i}:n:"valid"===n.kind||"invalid"===n.kind&&"unknown-id"!==n.reason?n:{kind:"pending",value:i}}_canCommitSpace(e,t=!1){if(t||!this._hasFixedFloor)return!0;const i=this._fixedFloorState();return"valid"===i.kind&&i.id===e}_commitSpace(e,t=!1){return!!this._canCommitSpace(e,t)&&(e!==this._space&&(this._clearRoomFocus(!0),this._resetDeviceHitState(),this._cancelDangerConfirm(),this._cancelCameraTransition(!1),this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._editorRuntime?._clearFurniturePreview()),this._space=e,this._isoProjectionSnapshot=null,!0)}_slideTo(e,t){if(e===this._space)return!0;if(!this._canCommitSpace(e))return!1;if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return!1;this._cancelModeTransition(!0);const i=window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;return this._commitSpace(e),this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeWallChainId=null,this._activeWallChainPartitionIds=[],this._wallChainSegmentCms=[],this._closingWallCm=null,this._selId=null,this._physicalSel=null,this._editorSecondary?.closeForNavigation(),this._physicalDialog=null,this._physicalDrag=null,this._restoreZoom(),i||(this._slide=t,clearTimeout(this._slideTimer),this._slideTimer=window.setTimeout(()=>{this._slideTimer=void 0,this._slide="",this.requestUpdate()},190),this.requestUpdate()),!0}get _canReorderTabs(){return Zf({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:"mouse",spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})}_tabPointerDown(e,t){Zf({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:e.pointerType,spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})&&(yv(e),this._tabDragRelease=e=>this._tabPointerUp(e),window.addEventListener("pointerup",this._tabDragRelease),window.addEventListener("pointercancel",this._tabDragRelease),this._tabDrag={id:t,pointerId:e.pointerId,x:e.clientX,y:e.clientY,moved:!1,targetId:null,placement:null})}_tabDropTargetAt(e,t,i){const n=this._model.map(e=>e.id),r=n.indexOf(i);if(r<0)return null;const o=this.renderRoot.querySelectorAll('[data-hp="space-tab"]');for(const s of o){const o=s.dataset.id||"";if(!o||o===i)continue;const a=s.getBoundingClientRect();if(ea.right||ta.bottom)continue;const l=n.indexOf(o);return l<0?null:{targetId:o,placement:l=4)))return;var i,n;const r=this._tabDropTargetAt(e.clientX,e.clientY,t.id);t.moved&&t.targetId===r?.targetId&&t.placement===r?.placement||(this._tabDrag={...t,moved:!0,targetId:r?.targetId||null,placement:r?.placement||null})}_tabPointerUp(e){const t=this._tabDrag;if(t&&t.pointerId!==e.pointerId)return;const i="pointerup"===e.type&&t?.moved?this._tabDropTargetAt(e.clientX,e.clientY,t.id):null;"pointerup"===e.type&&t?.moved&&this._suppressNextTabClick(),this._endTabDrag(),t?.moved&&i&&this._commitTabOrder(t.id,i.targetId)}_endTabDrag(){this._tabDrag=null,this._tabDragRelease&&(window.removeEventListener("pointerup",this._tabDragRelease),window.removeEventListener("pointercancel",this._tabDragRelease),this._tabDragRelease=null)}_tabClick(e){if(this._tabSuppressClick)return this._tabSuppressClick=!1,clearTimeout(this._tabSuppressClickTimer),void(this._tabSuppressClickTimer=void 0);this._pickSpace(e)}_suppressNextTabClick(){this._tabSuppressClick=!0,clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=window.setTimeout(()=>{this._tabSuppressClick=!1,this._tabSuppressClickTimer=void 0},0)}_commitTabOrder(e,t){const i=this._serverCfg;if(!i||!this._canReorderTabs)return;const n=this._model.map(e=>e.id),r=function(e,t,i){const n=e.indexOf(t),r=e.indexOf(i);if(n<0||r<0||n===r)return e;const o=e.slice();return o.splice(n,1),o.splice(r,0,t),o}(n,e,t);if(r===n)return;const o=new Map(this._devices.map(e=>[String(e.id),String(e.area||"")])),s=function(e,t,i,n=()=>""){if(!i)return[];const r=[];for(const o of e){if(!o||!0===o.removed)continue;const e="string"==typeof o.id?o.id:"";if(!e)continue;if("string"==typeof o.space&&o.space)continue;const s=("string"==typeof o.area?o.area:"")||n(e)||"";s&&t[s]||r.push({id:e,space:i})}return r}(i.markers||[],Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),n[0]||"",e=>o.get(e)||"");if(s.length){const e=new Map(s.map(e=>[e.id,e.space]));for(const t of i.markers||[]){const i=e.get(String(t.id));i&&(t.space=i)}}i.spaces=function(e,t){const i=new Map(t.map((e,t)=>[e,t]));return e.map((e,t)=>({space:e,index:t})).sort((e,t)=>(i.get(String(e.space?.id))??Number.MAX_SAFE_INTEGER)-(i.get(String(t.space?.id))??Number.MAX_SAFE_INTEGER)||e.index-t.index).map(e=>e.space)}(i.spaces||[],r),this._saveConfig(),this._tabOrderWarned||(this._tabOrderWarned=!0,this._showToast(this._t("toast.space_order_changed")))}_pickSpace(e){if(this._endTabDrag(),e===this._space)return;const t=this._model.map(e=>e.id),i=t.indexOf(this._space),n=t.indexOf(e);this._navApplied=!0,this._showFar=!1,this._frame=null,this._slideTo(e,i>=0&&n0&&Date.now()>=this._cyclePausedUntil&&this._model.length>1&&this._zoom<=1.001){const e=this._model.map(e=>e.id),t=e.indexOf(this._space);this._slideTo(e[(t+1)%e.length],"left"),this._showKioskDots()}}_syncCycleTimer(){clearInterval(this._cycleTimer),this._cycleTimer=void 0,this.isConnected&&!this._hasFixedFloor&&this._config?.kiosk&&Number(this._config.cycle)>0&&(this._cycleTimer=window.setInterval(()=>this._cycleTick(),1e3*Number(this._config.cycle)))}get _editing(){return"plan"===this._mode||"devices"===this._mode||"decor"===this._mode}get _markup(){return"plan"===this._mode}get _wallUnionCache(){return this._wallUnionCacheValue}set _wallUnionCache(e){this._wallUnionCacheValue=e,null===e&&this._wallUnionPool.clear()}get _glowClipCache(){return this._glowRuntimeState.clipCache}get _glowGeometryWarnings(){return this._glowRuntimeState.geometryWarnings}get _glowFeatherUnits(){return this._glowRuntimeState.featherUnits}set _glowFeatherUnits(e){this._glowRuntimeState.featherUnits=e}get _glowRenderedSources(){return this._glowRuntimeState.renderedSources}get _glowLastAppearance(){return this._glowRuntimeState.lastAppearance}get _glowFeatherSuspendUntil(){return this._glowRuntimeState.featherSuspendUntil}set _glowFeatherSuspendUntil(e){this._glowRuntimeState.featherSuspendUntil=e}get _glowFeatherResumeTimer(){return this._glowRuntimeState.featherResumeTimer}set _glowFeatherResumeTimer(e){this._glowRuntimeState.featherResumeTimer=e}get _glowSourceSeq(){return this._glowRuntimeState.sourceSeq}set _glowSourceSeq(e){this._glowRuntimeState.sourceSeq=e}_activateSafeDayCycleOutline(){this._safeDayCycleOutline=!0,this._stageEl?.classList.add("hp-safe-daycycle-outline")}get _touchSequenceMultitouch(){return this._touchClickGuard.sequenceMultitouch}_syncDangerConfirmLocaleGate(){return this._config&&this.hass?dp(this,gp,kp(this.hass,this._config.language)):"ready"}_dangerConfirmMissingSpace(){const e=this._model;if(!e.length)return!1;const t=this._fixedFloorState(e);return"pending"!==t.kind&&"invalid"!==t.kind&&!this._spaceModel()}_syncVersionRecovery(){this._versionRecovery.update({frontendVersion:ev(iv),backendVersion:this._haIntegrationVersion,kiosk:!0===this._config?.kiosk,reducedMotion:this._reducedMotion})}_newContinuityController(){return new lc(()=>{this._resumeSettling="steady"!==this._continuity.state,this._continuityEpoch++,this.isConnected&&this.requestUpdate()})}get _labsIso(){return this._labs.active.includes("iso")}get _desiredProjection(){return"view"===this._mode&&this._labsIso&&"iso"===this._viewPreference[this._space]?"iso":"flat"}_saveViewPreference(){try{localStorage.setItem(uv,JSON.stringify(this._viewPreference))}catch{}}_logicalViewCenter(e){const t=this._view;if(!t)return null;const i=[t.x+t.w/2,t.y+t.h/2],n="iso"===e?cf(i):i;return{x:n[0],y:n[1]}}_convertProjectionView(e,t){if(e===t)return;this._clearRoomFocus(!0);const i=this._logicalViewCenter(e);this._view=null;const n=i?"iso"===t?lf([i.x,i.y],0):[i.x,i.y]:null;this._applyView(this._zoom,n?.[0],n?.[1]),this._warmPatch({vp:this._warmViewportState()}),this.requestUpdate()}_setProjection(e){if(!this._labsIso||"view"!==this._mode)return;const t=this._effectiveProjection();if(this._viewPreference={...this._viewPreference,[this._space]:e},"iso"===e){this._ensureIsoSceneRuntime();const e=this._isoSceneKey();e&&this._isoFallback.delete(e),this._isoFallback.delete(`${this._space}|no-borders`),this._clearIsoInvalidFallback()}this._saveViewPreference(),this._isoProjectionSnapshot=null;const i=this._effectiveProjection();this._convertProjectionView(t,i)}_hashSpace(){return Ff(window.location.hash||"")}connectedCallback(){this._connectedPath=location.pathname,this._routeDepartureHandled=!1,this._configReloadAuthority.observeContext(Vu(this)),window.addEventListener("location-changed",this._onLocationChanged),window.addEventListener("popstate",this._onLocationChanged),this._continuityDisposed&&(this._continuity=this._newContinuityController(),this._continuityDisposed=!1,this._continuityPaintToken=-1);const e=dg(this.ownerDocument);var t;void 0!==e&&(this._glowScreenBlend=e),this._continuityUnsub?.(),this._continuityUnsub=sc(this.ownerDocument,this._pageVisibility),this._languageFailureUnsub?.(),this._languageFailureUnsub=function(...e){return()=>{for(const t of e)t()}}((t=()=>{this._showToast(this._t("toast.locale_load_failed"))},mp.add(t),()=>mp.delete(t)),function(e){return Il.add(e),()=>{Il.delete(e)}}(()=>this._showToast(this._t("toast.furniture_art_load_failed")))),super.connectedCallback(),this._summarySlot.connect(),this._ensureLiveRuntime().catch(()=>this.requestUpdate()),this._pointerModality.connect(this.ownerDocument.defaultView);const i=this.ownerDocument.defaultView?.MutationObserver;i&&(this._pointerHoverObserver=new i(e=>{let t=!1;for(const i of e){for(const e of i.addedNodes)this._syncPointerHoverSubtree(e);const e=e=>{if(e.nodeType!==Node.ELEMENT_NODE)return!1;const t=e;return t.matches(".devlayer, .devlayer *")||!!t.querySelector?.(".devlayer")};(e(i.target)||[...i.addedNodes,...i.removedNodes].some(e))&&(t=!0)}t&&this._invalidateDeviceHitGeometry()}),this._pointerHoverObserver.observe(this.renderRoot,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["class","style","data-id"]})),this._motionMedia=window.matchMedia?.("(prefers-reduced-motion: reduce)"),this._reducedMotion=!!this._motionMedia?.matches,this._motionMedia?.addEventListener?.("change",this._onMotionChange),this._syncVersionRecovery(),this._versionRecovery.connect(),hg(this.ownerDocument).then(e=>{e!==this._glowScreenBlend&&(this._glowScreenBlend=e,this.isConnected&&this.requestUpdate())}),this.hass&&this._ensureHaRegistryAuthority(),window.addEventListener("keydown",this._keyHandler),this._signer.start(()=>this.hass,()=>this._referencedContentUrls()),this._syncCycleTimer(),window.addEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=function(e){Nf.add(e);const t=Bf();return"undefined"==typeof window&&e(t),()=>{Nf.delete(e)}}(this._onLabsSnapshot),this._labsIso&&this._ensureIsoSceneRuntime(),this._booting?this._bootWatch():this._bootFading&&(clearTimeout(this._bootTimer),this._bootTimer=window.setTimeout(()=>{this._bootFading=!1},220)),this._bootSoft&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},rv)),!this._loadOk&&this._serverCfg&&this.hass&&this._scheduleLoadRetry(),!this._warmSlot&&this._config&&this._warmAdopt(),this._loadOk&&this._ensureLiveSyncSubscriptions(),this._warmVp&&!this._warmRevivePending&&void 0===this._warmReviveTimer&&(this._warmRevivePending=!0,this._warmReviveTimer=window.setTimeout(()=>this._warmReviveDialog(),0)),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1,this.requestUpdate()}disconnectedCallback(){this._versionRecovery.disconnect(),this._configReloadAuthority.invalidateLifecycle(),this._liveRt?.dispose(),this._radarLive.stop(),this._editorRuntime?._disposeLiveEditor(),this._clearRoomFocus(!0),this._cancelDangerConfirm(),this._connectedPath&&location.pathname!==this._connectedPath&&this._leaveCardRoute(),window.removeEventListener("location-changed",this._onLocationChanged),window.removeEventListener("popstate",this._onLocationChanged),this._continuityUnsub?.(),this._continuityUnsub=void 0,this._languageFailureUnsub?.(),this._languageFailureUnsub=void 0,this._motionMedia?.removeEventListener?.("change",this._onMotionChange),this._motionMedia=void 0,this._vacRaf&&(cancelAnimationFrame(this._vacRaf),this._vacRaf=0),this._refitRaf&&(cancelAnimationFrame(this._refitRaf),this._refitRaf=0),this._warmModeRequest=0,this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),this._summarySlot.disconnect(),this._dayCycleClockKey="",this._bootSettleRaf&&(cancelAnimationFrame(this._bootSettleRaf),this._bootSettleRaf=0),this._bootSettling=!1;for(const e of this._activityRt.values())clearTimeout(e.timer);window.removeEventListener("keydown",this._keyHandler),this._endTabDrag(),clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=void 0,this._tabSuppressClick=!1,clearInterval(this._cycleTimer),clearTimeout(this._kioskDotsTimer),clearTimeout(this._kioskHoldTimer),clearTimeout(this._reloadRetry),clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),this._connHooked=null,this._haRegistryRelease?.(),this._haRegistryRelease=void 0,this._haRegistryConnection=null,this._signer.dispose(),clearTimeout(this._toastTimer),clearTimeout(this._slideTimer),clearTimeout(this._editorRuntimeLoadingTimer),this._editorRuntimeLoadingTimer=void 0,this._editorRuntimeLoadingVisible=!1,this._modeTransition.dispose(),this._cameraTransition.dispose(),this._cameraTransitionFit=null,this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest++,this._slideTimer=void 0,this._slide="",clearTimeout(this._bootTimer),this._bootTimer=void 0,clearTimeout(this._bootSoftTimer),this._saveConfigDebounced.flush(),this._cancelDeviceDrag(),window.removeEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=void 0,clearTimeout(this._holdTimer),this._roViewport?.disconnect(),this._roViewport=void 0,this._roHdr?.disconnect(),this._roHdr=void 0,this._onWinResize&&(window.removeEventListener("resize",this._onWinResize),this._onWinResize=void 0),this._unsubCfg&&(this._unsubCfg(),this._unsubCfg=null),this._unsubLayout&&(this._unsubLayout(),this._unsubLayout=null),this._unsubVirtual&&(this._unsubVirtual(),this._unsubVirtual=null),this._unsubTrail&&(this._unsubTrail(),this._unsubTrail=void 0),this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=null,clearTimeout(this._layoutSyncTimer),clearTimeout(this._duplicateColumnTimer),Fm(this._glowRuntimeState,this._glowRuntimeHost),this._warmSnapshot(),this._warmRevivePending=!1,clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmRelease(),this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._editorRuntime?._clearFurniturePreview(),this._editorRuntime?._furnShiftDetach(),this._touchContacts.clear(),this._touchClickGuard.reset(),this._resetDeviceHitState(),this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._pointerHoverObserver?.disconnect(),this._pointerHoverObserver=void 0,this._pointerModality.disconnect(),this._editorSecondary?.reset(),this._resumeSettling=!1,this._continuityHistory=[...this._continuityHistory,...this._continuity.trace].slice(-80),this._continuity.dispose(),this._continuityDisposed=!0,super.disconnectedCallback()}_onKey(e){if("Escape"===e.key&&this._vacFit){if(this._vacFit.busy)return;return this._vacFit=null,this._showToast(this._t("vac.cal_cancelled")),void e.stopPropagation()}if("Escape"===e.key){if(this._tapConfirm)return void(this._tapConfirm=null);if(this._vacCalConfirm)return void(this._vacCalConfirm.busy||(this._vacCalConfirm=null));if(this._decorEraseConfirm)return void(this._decorEraseConfirm=null);if(this._openingInfo)return void(this._openingInfo=null);if(this._infoCard)return void this._closeInfoCard();if(this._rulesDialog)return void(this._rulesDialog=null);if(this._alignDialog)return this._alignDialog=null,void(this._preflightClipboardFallback=null);if(this._backupImportDialog)return void(this._backupImportDialog=null);if(this._backupExportDialog)return void(this._backupExportDialog=null);if(this._pdfDialog)return void(this._pdfDialog=!1);if(this._supportDialog)return void this._editorRuntime?._closeSupportDialog();if(this._settingsDialog)return void(this._settingsDialog=null);if(this._summary?.closeDialogIfIdle())return;if(this._markerDialog)return void this._closeMarkerDialog();if(this._deviceInbox)return void(this._deviceInbox=null);if(this._openingDialog)return void(this._openingDialog=null);if(this._physicalDialog)return void(this._physicalDialog=null);if(this._backdropDialog)return void(this._backdropDialog=null);if(this._decorShapeDialog)return void(this._decorShapeDialog=null);if(this._decorTextDialog)return void(this._decorTextDialog=null);if(this._spaceDialog&&!this._roomDialog)return this._spaceDialog=null,this._importQueue=[],void(this._importTotal=0);if(this._editorSecondary?.hasOpenGroup)return e.preventDefault(),void this._editorSecondary?.closeGroup(!0)}const t=e.composedPath?.()||[e.target],i=t.some(e=>e?.matches?.('input, textarea, select, [contenteditable="true"]')),n=t.some(e=>e?.classList?.contains?.("editor-secondary")),r=e.ctrlKey||e.metaKey,o=e.key.toLowerCase(),s=/^[a-z]$/.test(o),a="z"===o||!s&&"KeyZ"===e.code,l="y"===o||!s&&"KeyY"===e.code,c=r&&(a&&e.shiftKey||l),h=r&&a&&!e.shiftKey;if("decor"===this._mode){if((h||c)&&i)return;if(c)return e.preventDefault(),void this._redoGeometry();if(h)return e.preventDefault(),this._decorDraft?void(this._decorDraft=null):this._decorMove||this._dtDrag||this._bdDrag?void this._cancelDecorGesture():void this._undoGeometry();if(("Delete"===e.key||"Backspace"===e.key)&&this._decorSel&&!i&&!n)return e.preventDefault(),void this._decorDeleteSel();const t="ArrowLeft"===e.key?[-this._gridPitch,0]:"ArrowRight"===e.key?[this._gridPitch,0]:"ArrowUp"===e.key?[0,-this._gridPitch]:"ArrowDown"===e.key?[0,this._gridPitch]:null;return!t||r||e.altKey||"select"!==this._decorTool||!this._decorSel||!this._decorList.some(e=>e.id===this._decorSel)||this._decorDraft||this._decorMove||this._dtDrag||this._bdDrag||i||n||this._editorSecondaryDialogBlocked?void("Escape"===e.key&&(e.preventDefault(),this._decorDraft?this._decorDraft=null:this._decorMove||this._dtDrag||this._bdDrag?this._cancelDecorGesture():"furniture"===this._decorTool?(this._editorRuntime?._clearFurniturePreview(),this._editorRuntime?._furnShiftDetach(),this._furnPalette=null,this._furnCategory=null,this._decorTool="select"):this._decorSel?this._decorSel=null:"select"!==this._decorTool?this._decorTool="select":this._setMode("view"))):(e.preventDefault(),void this._decorNudge(t[0],t[1]))}if("devices"===this._mode){if((h||c)&&i)return;return c?(e.preventDefault(),void this._redoDevicePosition()):h?(e.preventDefault(),void this._undoDevicePosition()):void("Escape"===e.key&&this._deviceDrag&&(e.preventDefault(),this._cancelDeviceDrag()))}if(this._markup&&(!h&&!c||!i)){if(("Delete"===e.key||"Backspace"===e.key)&&this._physicalSel&&!i&&!n)return e.preventDefault(),void this._deletePhysicalSelection();if(c)return e.preventDefault(),void this._redoGeometry();if(h)return e.preventDefault(),this._resize?.dragging?void this._rszCancelDrag():this._wallFaceBatch?(this._roomDialogCancel(),void(this._activeWallChainId&&this._path.length>1?this._undoActiveWallPoint():this._undoPoint())):"draw"===this._tool&&this._path.length?void(this._activeWallChainId&&this._path.length>1?this._undoActiveWallPoint():this._undoPoint()):"split"===this._tool&&this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},void(this._splitSel.pts.length||(this._cursorPt=null))):void this._undoGeometry();if("Escape"===e.key)return this._physicalDrag||this._physicalRotate?(e.preventDefault(),void this._cancelPhysicalGesture()):this._roomDialog?(e.preventDefault(),void this._roomDialogCancel()):"draw"===this._tool&&this._path.length?(e.preventDefault(),void this._finishWallChain()):this._physicalSel?(e.preventDefault(),void(this._physicalSel=null)):"resize"===this._tool?(e.preventDefault(),this._resize?.dragging?void this._rszCancelDrag():("exit-tool"===this._resize?.escapeIdle()&&(this._tool="draw"),void this.requestUpdate())):"split"===this._tool?(e.preventDefault(),void(this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},this._splitSel.pts.length||(this._cursorPt=null)):this._splitSel?this._splitSel=null:this._tool="draw")):"merge"===this._tool?(e.preventDefault(),void(this._mergeSel?this._mergeSel=null:this._tool="draw")):this._wallDialog?(e.preventDefault(),void(this._wallDialog=null)):void("opening"!==this._tool&&"wallthick"!==this._tool&&"delroom"!==this._tool&&"column"!==this._tool||(e.preventDefault(),"opening"===this._tool&&this._clearOpeningPlacement(!0),this._tool="draw"))}}_undoPoint(){if(this._path.length)return this._contourClosed?(this._path=this._path.slice(0,-1),void(this._closingWallCm=null)):void(this._activeWallChainPartitionIds.length&&this._path.length>1?this._undoActiveWallPoint():this._path=this._path.slice(0,-1))}_undoActiveWallPoint(){const e=[...this._activeWallChainPartitionIds],t=e[e.length-1],i=this._spaceModel()?.partitions.find(e=>e.id===t),n=this._path[0]?[...this._path[0]]:null,r=this._path.slice(0,-1).map(e=>[...e]),o=this._wallChainSegmentCms.slice(0,-1),s=this._geometryHistory.undo();if(!s)return this._activeWallChainPartitionIds=[],this._wallChainSegmentCms=[],this._wallChainRedo=[],void(this._path=n?[n]:[]);this._applyGeometryState(s.before,!0)?(this._activeWallChainId||=`chain-${Date.now().toString(36)}`,this._activeWallChainPartitionIds=e.slice(0,-1),this._path=r.length?r:n?[n]:[],this._wallChainSegmentCms=o,i&&this._wallChainRedo.push({id:i.id,point:[...i.b],cm:i.cm}),this._clearPlanSnapHover(),this._showToast(this._t("history.undone",{name:s.name}))):this._geometryHistory.clear()}static async getConfigElement(){return await import("./editor-C694OxAO.js"),document.createElement("houseplan-card-editor")}static getStubConfig(){return{type:"custom:houseplan-card"}}static _warmBootReset(e){for(const e of ov.values())for(const t of e)clearTimeout(t.evict);ov.clear(),av=e&&e>0?e:1e4}static _warmBootStats(){let e=0,t=0;const i=[];for(const n of ov.values())for(const r of n)e++,r.dlg&&(t++,i.push(r.dlg.kind));return{keys:ov.size,slots:e,dlgs:t,drafts:i}}setConfig(e){const t=this._config,i=!!t&&Object.prototype.hasOwnProperty.call(t,"floor");this._config={icon_size:2.5,show_temperature:!0,live_states:!0,show_signal:!0,...e};(i!==this._hasFixedFloor||t?.floor!==this._config.floor)&&(this._hashApplied=!1,this._navApplied=!1,this._warmVpArmed=!1),this._config.kiosk&&(this._booting=!1,this._bootFading=!1),!this._hasFixedFloor&&e.default_floor&&this._commitSpace(e.default_floor,!0);try{this._zoomBySpace=JSON.parse(localStorage.getItem(hv)||"{}")||{}}catch{this._zoomBySpace={}}try{const e=JSON.parse(localStorage.getItem(uv)||"{}")||{};this._viewPreference=Object.fromEntries(Object.entries(e).filter(e=>"flat"===e[1]||"iso"===e[1]))}catch{this._viewPreference={}}if(this._labs=Bf(),this.isConnected&&this._labsIso&&this._ensureIsoSceneRuntime(),!this._summary?.applyLocalScaleForCurrentIdentity())try{const e=JSON.parse(localStorage.getItem("houseplan_card_kiosk_v1")||"null");this._kioskScale={icon:jn(e?.icon),font:jn(e?.font)}}catch{}try{const e=JSON.parse(localStorage.getItem(cv)||"null");this._adoption.restoreCached(e)&&(this._seedDecorStyle(this._serverCfg),this._cfgEpoch++,this._virtualLights=Hh(e.virtual_lights,this._cfgRev),this._serverStorage=!0)}catch{}this._adoptInitialSpace(this._model,this._loadOk),"view"!==this._mode||this._view||(this._zoom=this._zoomBySpace[this._space]||1),this.isConnected&&(this._syncCycleTimer(),this._warmAdopt(),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1),this._syncVersionRecovery()}_warmAdopt(){if(this._config?.kiosk)return;const e=Cf(this._config);if(this._warmKey===e&&this._warmSlot)return;this._warmSlot&&this._warmRelease();const t=this.parentNode,i=this._warmIdx(t),n=ov.get(e);if(!n||!n.length)return;const r=n.find(e=>e.owner===this._warmGen);if(r)return this._warmLongReturn=!!r.freed&&Date.now()-r.freed>=nc,clearTimeout(r.evict),r.evict=0,r.freed=0,r.live=!0,this._warmSlot=r,this._warmKey=e,r.frameFingerprint&&this._continuity.adoptCompleteFrame(r.frameFingerprint),void(!this._devices.length&&r.devices?.length&&(this._devices=[...r.devices]));const{slot:o,sure:s}=((e,t,i,n)=>{const r=e=>{const t=!!i&&e.place?.deref()===i;return t&&e.idx===n?4:e.live?0:t?3:2};let o=null,s=0,a=0,l=null;for(const i of e){if(i.owner===t)continue;l=i;const e=r(i);e<=0||(e>s?(o=i,s=e,a=1):e===s&&a++)}return!o||a>1?{slot:o||l,sure:!1}:{slot:o,sure:!0}})(n,this._warmGen,t,i);o&&(this._warmLongReturn=!!o.freed&&Date.now()-o.freed>=nc,this._booting=!1,this._bootFading=!1,this._hdrH=o.hdrH,this._bootSoft=!0,this.isConnected&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},rv)),this._warmKey=e,s?(clearTimeout(o.evict),o.evict=0,o.owner=this._warmGen,o.place=t?new WeakRef(t):null,o.idx=i,o.live=!0,this._warmSlot=o,this._warmVp=o.vp,o.frameFingerprint&&this._continuity.adoptCompleteFrame(o.frameFingerprint),!this._devices.length&&o.devices?.length&&(this._devices=[...o.devices]),this._warmAdoptViewport(this._config)):(this._warmSlot={owner:this._warmGen,path:location.pathname,place:t?new WeakRef(t):null,idx:i,live:!0,hdrH:o.hdrH,stageH:o.stageH,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0},n.push(this._warmSlot),this._warmTrim(n)))}_warmIdx(e){const t=e?.children;if(!t)return-1;for(let e=0;e4;){const t=e.findIndex(e=>!e.live);if(t<0)break;clearTimeout(e[t].evict),e.splice(t,1)}}_warmScheduleEvict(e,t){if(clearTimeout(e.evict),!(e.dlg||e.vp&&"view"!==e.vp.mode))return;const i=e.freed,n=e.owner;e.evict=window.setTimeout(()=>{if(e.evict=0,e.freed!==i||e.owner!==n)return;var r;e.dlg=null,e.vp=(r=e.vp)&&"view"!==r.mode?{...r,mode:"view",zoom:r.snap?.space===r.space?r.snap.zoom:r.zoom,view:null,snap:null,tool:"draw",decorTool:"select",showHidden:!1,selId:null,rszSel:null,decorSel:null}:r,e.frameFingerprint="";const o=ov.get(t);if(!e.live&&o&&o.length>1){const t=o.indexOf(e);t>=0&&o.splice(t,1)}},av+250)}_warmAdoptViewport(e){const t=this._warmVp;if(!t||this._warmSlot?.path!==location.pathname)return void(this._warmVp=null);const i=this._fixedFloorState();if(this._hashApplied||!this._model.find(e=>e.id===t.space)||"valid"===i.kind&&i.id!==t.space||this._hasFixedFloor&&"valid"!==i.kind)return void(this._warmVp=null);this._commitSpace(t.space,!0),this._navApplied=!0;const n="view"!==t.mode&&this._canEdit&&!e.kiosk?t.mode:"view";this._adoptMode("view"),this._pendingNavMode="view"===t.mode||this._canEdit||e.kiosk?null:t.mode,this._zoom=t.zoom;const r=this._effectiveProjection(),o=r===t.projection&&this._labsIso===t.activeLabsIso;if(this._view=o&&t.view?{...t.view}:null,this._viewModeSnap=o&&t.snap?{...t.snap}:null,!o&&t.logicalCenter){const e="iso"===r?lf([t.logicalCenter.x,t.logicalCenter.y],0):[t.logicalCenter.x,t.logicalCenter.y];this._applyView(t.zoom,e[0],e[1])}var s;this._tool="opening"===(s=function(e){return"partition"===e?"draw":e}(s=t.tool))?"draw":"string"==typeof s&&Rf.has(s)?s:"draw",this._decorTool=t.decorTool,this._showHidden=t.showHidden,this._showFar!==t.showFar&&(this._showFar=t.showFar,this._frame=null),this._selId=t.selId,this._resize?.restoreSelection(t.rszSel),this._decorSel=t.decorSel,this._warmVpArmed=!0,"view"!==n&&this._requestMode(n,!1,!0)}_warmPatch(e,t=!1){if(this._config?.kiosk)return;const i=Cf(this._config);if(!this._warmSlot||this._warmKey===i){if(!this._warmSlot){if(!t)return;const e=this.parentNode;this._warmKey=i,this._warmSlot={owner:this._warmGen,path:location.pathname,place:e?new WeakRef(e):null,idx:this._warmIdx(e),live:!0,hdrH:this._hdrH,stageH:0,vp:null,frameFingerprint:"",devices:null,dlg:null,freed:0,evict:0};const n=ov.get(i)||[];for(n.push(this._warmSlot),ov.set(i,n),this._warmTrim(n);ov.size>8;){const e=ov.keys().next().value;if(void 0===e||e===i)break;for(const t of ov.get(e)||[])clearTimeout(t.evict);ov.delete(e)}}Object.assign(this._warmSlot,e)}}_warmViewportState(){const e=this._effectiveProjection();return{space:this._space,mode:this._mode,projection:e,activeLabsIso:this._labsIso,logicalCenter:this._logicalViewCenter(e),zoom:this._zoom,view:this._view?{...this._view}:null,snap:this._viewModeSnap?{...this._viewModeSnap}:null,tool:this._tool,decorTool:this._decorTool,showHidden:this._showHidden,showFar:this._showFar,selId:this._selId,rszSel:this._resize?.selectedRoomId,decorSel:this._decorSel}}_warmDialogState(){const e=(e,t)=>({kind:e,space:this._space,mode:this._mode,data:t});return this._tapConfirm||this._alignDialog||this._mergeDialog||this._importDialog||this._backupExportDialog||this._backupImportDialog?null:this._openingInfo?e("openingInfo",this._openingInfo.id):this._infoCard?e("info",this._infoCard.id):this._rulesDialog?this._rulesDialog.busy?null:e("rules",this._rulesDialog):this._settingsDialog?this._settingsDialog.busy?null:e("settings",this._settingsDialog):this._markerDialog?this._markerDialog.busy?null:e("marker",this._markerDialog):this._openingDialog?e("opening",this._openingDialog):this._backdropDialog?e("backdrop",this._backdropDialog):this._decorShapeDialog?e("decorShape",this._decorShapeDialog):this._decorTextDialog?e("decorText",this._decorTextDialog):this._roomDialog?e("room",{editId:this._roomEditId,fill:this._roomFill,customFill:this._roomCustomFill,tempMin:this._roomTempMin,tempMax:this._roomTempMax,tempSrc:this._roomTempSrc,humSrc:this._roomHumSrc,srcOpen:this._roomSrcOpen,srcFilter:this._roomSrcFilter,nameScale:this._roomNameScale,labelScale:this._roomLabelScale,areaSel:this._areaSel,nameSel:this._nameSel,pendingSplit:this._pendingSplit,wallFaceBatch:this._wallFaceBatch,path:this._path}):this._spaceDialog?this._spaceDialog.busy?null:e("space",this._spaceDialog):null}_warmSnapshot(){if(this._booting||this._config?.kiosk||"steady"!==this._continuity.state)return;const e={vp:this._warmViewportState(),frameFingerprint:this._continuity.frameFingerprint,devices:this._devices,hdrH:this._hdrH};if(this._warmRevivePending||(e.dlg=this._warmDialogState()),this.isConnected&&this._warmSlot?.owner===this._warmGen){const t=this.parentNode;e.place=t?new WeakRef(t):null,e.idx=this._warmIdx(t)}this._warmPatch(e)}_warmReviveDialog(){const e=this._warmSlot;if(this._warmReviveTimer=void 0,!e||!e.dlg)return void(this._warmRevivePending=!1);const t=e.dlg,i=e.freed;if(t.mode===this._mode||"view"===t.mode||this._warmVp?.mode!==t.mode||this._editorRuntime){if(this._warmRevivePending=!1,e.dlg=null,e.freed=0,clearTimeout(e.evict),e.evict=0,i&&!(Date.now()-i>av)&&t.space===this._space&&t.mode===this._mode){switch(t.kind){case"space":this._spaceDialog={...t.data,busy:!1,savedBusy:!1};break;case"marker":this._markerDialog={...t.data,busy:!1};break;case"settings":this._settingsDialog={...t.data,busy:!1};break;case"rules":this._rulesDialog={...t.data,busy:!1};break;case"opening":this._openingDialog={...t.data};break;case"backdrop":this._backdropDialog={...t.data};break;case"decorShape":this._decorShapeDialog={...t.data};break;case"decorText":{this._decorTextDialog={...t.data};const e=String(this._decorTextDialog?.text??"").length;this._decorTextSelection={start:e,end:e};break}case"room":{const e=t.data;this._roomEditId=e.editId,this._roomFill=e.fill,this._roomCustomFill=e.customFill||null,this._roomTempMin=e.tempMin||"",this._roomTempMax=e.tempMax||"",this._roomTempSrc=e.tempSrc,this._roomHumSrc=e.humSrc,this._roomSrcOpen=e.srcOpen,this._roomSrcFilter=e.srcFilter,this._roomNameScale=e.nameScale,this._roomLabelScale=e.labelScale,this._areaSel=e.areaSel,this._nameSel=e.nameSel,this._pendingSplit=e.pendingSplit,this._wallFaceBatch=e.wallFaceBatch||null,this._path=e.path,this._wallFaceBatch&&(this._activeWallChainId=`chain-${Date.now().toString(36)}`,this._activeWallChainPartitionIds=[...this._wallFaceBatch.activePartitionIds],this._wallChainSegmentCms=[...this._wallFaceBatch.activeCms]),this._roomDialog=!0;break}case"info":{const e=this._devices.find(e=>e.id===t.data);e&&(this._infoCard=e);break}case"openingInfo":{const e=(this._curSpaceCfg?.openings||[]).find(e=>e.id===t.data);e&&(this._openingInfo=e);break}}this.requestUpdate()}}else this._warmRevivePending=!0}_cacheSnapshot(){if(this._serverCfg)try{this._virtualLights=function(e,t,i){if(e.configRev===i)return e;const n=new Set((Array.isArray(t?.markers)?t.markers:[]).filter(qh).map(e=>e.id));return{...e,configRev:i,off:new Set([...e.off].filter(e=>n.has(e)))}}(this._virtualLights,this._serverCfg,this._cfgRev);const e=this._adoption.snapshot(function(e){return{rev:e.rev,config_rev:e.configRev,off:[...e.off].sort()}}(this._virtualLights));e&&localStorage.setItem(cv,JSON.stringify(e))}catch{}}_beginContinuityCandidate(e,t,i="plan"){return this._booting&&!this._continuity.hasCompleteFrame?this._continuity.token:(this._continuityDataReady=t,this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._resumeSettling=!0,this._continuity.beginCandidate(e,i))}_continuityStageValid(){const e=this._stageEl;return!!e&&e.clientWidth>0&&e.clientHeight>0}_versionReloadSafetySnapshot(){return Sg(this)}_continuityAssetsReady(){if(!this._model.length)return!1;const e=this._model.length?this._spaceModel():null;return!e?.bg?.href||this._signer.isReady(this.hass,e.bg.href)}_initialSpaceSelection(e,t=this._loadOk){const i=this._fixedFloorState(e,t);return"valid"===i.kind?{id:i.id,source:"fixed"}:this._hasFixedFloor?{id:null,source:"none"}:function(e){const t=new Set(e.spaceIds.filter(e=>!!e));if(!t.size)return{id:null,source:"none"};const i=[["hash",!1===e.acceptHash?null:e.hashSpace],["current",e.preserveCurrent?e.currentSpace:null],["saved",e.savedSpace],["default",e.defaultSpace],["first",e.spaceIds[0]]];for(const[e,n]of i)if(n&&t.has(n))return{id:n,source:e};return{id:null,source:"none"}}({spaceIds:e.map(e=>e.id),hashSpace:this._hashSpace(),acceptHash:!this._hashApplied,currentSpace:this._space,preserveCurrent:this._hashApplied||this._navApplied||this._warmVpArmed,savedSpace:this._savedNav()?.space,defaultSpace:this._config?.default_floor})}_adoptInitialSpace(e,t=this._loadOk){const i=this._initialSpaceSelection(e,t);return i.id?(this._commitSpace(i.id,!0),"hash"===i.source&&(this._hashApplied=!0),"saved"===i.source&&(this._navApplied=!0),i):i}_candidateBackdrop(e,t=this._space){const i=el(e),n=this._fixedFloorState(i,!0);if(this._hasFixedFloor&&"valid"!==n.kind)return"";const r=this._initialSpaceSelection(i,!0).id||(i.some(e=>e.id===t)?t:i[0]?.id);return i.find(e=>e.id===r)?.bg?.href||""}_visualFrameFingerprint(){const e=this._stageEl,t=e?[e.clientWidth,e.clientHeight]:[0,0];return hc([this._cfgRev,this._adoption.currentConfigFingerprint(),this._layoutRev,this._adoption.currentLayoutFingerprint(),this._space,this._mode,this._view,t,this._glowScreenBlend?"screen":"normal",this.hass?.themes?.darkMode??this.hass?.themes?.default_theme??""])}_settleContinuityFrame(){if(this._booting||!this._continuityStageValid())return;if(!this._continuity.hasCompleteFrame&&"steady"===this._continuity.state)return void(this._continuityAssetsReady()&&(this._renderSnapshotAt=Date.now(),this._continuity.markCompleteFrame(this._visualFrameFingerprint())));if(!this._continuityDataReady)return;if(!["holding","offline-stale","overlay-pending","overlay-visible","candidate-ready"].includes(this._continuity.state))return;const e=this._continuity.token;if(this._candidateDeviceSnapshot&&this._candidateDeviceSnapshot!==this._visibleDeviceSnapshot&&this._stagedDeviceSnapshotToken!==e)return this._stagedDeviceSnapshotToken=e,void this.requestUpdate();this._continuityPaintToken!==e&&(this._continuityPaintToken=e,this._continuity.candidateReady(e)&&this._continuity.commitAfterPaint(e,{updateComplete:()=>this.updateComplete,stageValid:()=>this.isConnected&&this._continuityStageValid(),assetsReady:()=>this._continuityAssetsReady(),frameFingerprint:()=>this._visualFrameFingerprint()}).then(t=>{t&&e===this._continuity.token?(this._resumeSettling=!1,this._renderSnapshotAt=Date.now(),this._candidateDeviceSnapshot&&(this._visibleDeviceSnapshot=this._candidateDeviceSnapshot),this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._warmSnapshot()):e===this._continuity.token&&(this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._candidateDeviceSnapshot=null,this.requestUpdate())}))}_onBackdropLoaded(e,t){this._signer.markLoaded(this.hass,e,t),this._continuity.note("asset-ready"),this._continuityPaintToken=-1,"steady"!==this._continuity.state&&this.requestUpdate()}_renderRecoveryOverlay(){if(!this._continuity.overlayVisible&&"recovery-error"!==this._continuity.state)return G;const e="connection"===this._continuity.recoveryReason;return j`
    e.stopPropagation()} @click=${e=>e.stopPropagation()} @@ -364,7 +364,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc aria-label=${this._t("editor.loading_aria")}> ${this._t("editor.loading")} -
    `:G}houseplanContinuityTrace(){return[...this._continuityHistory,...this._continuity.trace].slice(-80).map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}getCardSize(){return 12}getGridOptions(){return{columns:"full"}}get _norm(){return!(!this._serverCfg||!this._serverCfg.spaces.length)}_cfgFingerprint(){const e=this._serverCfg?.spaces||[];let t=e.length+":";for(const i of e){t+=(i.id||"")+","+(i.plan_aspect||"")+","+(i.plan_url||"").length+","+(i.plan_x??"")+","+(i.plan_y??"")+","+(i.plan_scale??"")+","+(i.plan_scale_x??"")+","+(i.plan_scale_y??"")+","+(i.plan_angle??"")+","+(i.rooms?.length||0)+","+(i.openings?.length||0)+","+(i.decor?.length||0)+";";for(const e of i.rooms||[]){const i=e.poly?.[0],n=e.poly?.[e.poly.length-1];t+=(e.poly?.length||0)+"."+(e.id||"")+"."+(e.open_to||[]).join("+")+"."+(e.area||"")+"."+JSON.stringify(e.settings||0)+"."+(e.x??"")+","+(e.y??"")+","+(e.w??"")+","+(e.h??"")+","+(i?i[0]+"/"+i[1]:"")+","+(n?n[0]+"/"+n[1]:"")+";"}}return t}get _model(){if(!this._serverCfg)return[];const e=this._cfgEpoch+"|"+this._cfgFingerprint();if(this._modelCache&&this._modelCache.key===e)return this._modelCache.model;const t=this._buildModel();return this._modelCache={key:e,model:t},t}_buildModel(){if(!this._serverCfg)return[];const e=this._renderCfg;return el(e).map((t,i)=>{const n=e.spaces[i]?.plan_url;return t.bg&&n?{...t,bg:{...t.bg,href:n}}:t})}_spaceModel(){return this._hasFixedFloor?kc(this._model,this._space):(e=this._model,t=this._space,e.find(e=>e.id===t)??e[0]);var e,t}_spaceModelById(e){return kc(this._model,e)}_syncEmptySpaceState(){if(!!this._serverCfg&&0===this._serverCfg.spaces.length){if(!this._emptySpaceStateActive){this._emptySpaceStateActive=!0,this._clearRoomFocus(!0);for(const e of this._pointers.keys())for(const t of this.renderRoot.querySelectorAll("*"))try{t.hasPointerCapture?.(e)&&t.releasePointerCapture(e)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null,this._drag=null,this._deviceDrag=null,this._resetDeviceHitState(),this._rlResize=null,this._vacFit=null,this._compassDrag=!1,this._cancelModeTransition(!1),this._mode="view",this._clearGeometryGesture(),this._geometryHistory.clear(),this._devicePositionHistory.clear(),this._tip=null,this._hoverRoom=null,this._openingInfo=null,this._closeInfoCard(),this._deviceInbox=null,this._deviceInboxReturn=null,this._markerDialog=null,this._physicalDialog=null,this._backdropDialog=null,this._decorShapeDialog=null,this._decorTextDialog=null,this._roomDialog=!1,"edit"===this._spaceDialog?.mode&&(this._spaceDialog=null),this._editorSecondary?.closeForNavigation(),this._saveConfigDebounced.cancel(),this._frame=null,this._planSnapGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._decorSnapCache=null,this._commitSpace("",!0)}}else this._emptySpaceStateActive=!1}get _areaToSpace(){const e={};for(const t of this._model)for(const i of t.rooms)i.area&&(e[i.area]={space:t.id,room:i});return e}get _settings(){return this._serverCfg?.settings||{}}get _showAll(){return this._showHidden||!this._settings.filter_seeded&&!!this._settings.show_all}_seedHiddenDevices(){if(!(this._loadOk&&this._serverCfg&&this._norm&&this._canEdit))return;const e=this._serverCfg,t=eu({hass:this.hass,registry:this._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,firstSpaceId:this._model[0]?.id||"",iconRules:this._iconRules});if(!t.length&&e.settings?.filter_seeded)return;e.markers=e.markers||[];const i=[];for(const n of t){const t="h"+n.slice(n.indexOf(":")+1);e.markers.push({id:t,binding:n,hidden:!0}),i.push(n.slice(n.indexOf(":")+1))}const n={...e.settings||{},filter_seeded:!0};delete n.show_all,i.length&&Array.isArray(n.new_device_ids)&&(n.new_device_ids=n.new_device_ids.filter(e=>!i.includes(e))),e.settings=n,this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate()}get _iconRules(){const e=this._settings.icon_rules;if(!e||!Array.isArray(e)||!e.length)return;const t=JSON.stringify(e);return t!==this._rulesCompiledSrc&&(this._rulesCompiledSrc=t,this._rulesCompiled=Ee(e)),this._rulesCompiled}get _fillColors(){return vn(this._settings)}get _excluded(){return lu(this._settings)}_setAreaLifecycleConfig(e){this._cfgEpochPreservedConfig=e,this._serverCfg=e}willUpdate(e){if(this._isoProjectionSnapshot=null,this._summary?.willUpdate(),e.has("hass")&&this._configReloadAuthority.observeContext(Vu(this)),e.has("_serverCfg")){const e=this._cfgEpochPreservedConfig===this._serverCfg;this._cfgEpochPreservedConfig=null,e||this._cfgEpoch++,this._renderLife.invalidate()}if(this._syncEmptySpaceState(),this._dangerConfirm&&(this._dangerConfirmMissingSpace()||"warm"===this._syncDangerConfirmLocaleGate())&&this._cancelDangerConfirm(),e.has("hass")&&this.hass){const t=this._visibleDeviceSnapshot||this._candidateDeviceSnapshot;this._renderLife.observe(e.get("hass"),this.hass,t?{entityIds:t.entityIds}:null,()=>Mg(this))}this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._continuity.refreshCompleteFrame(this._visualFrameFingerprint()),this._captureRenderDeviceSnapshot()}updated(){this._summary?.updated(),this._liveRt?.commit(),this._editorRuntime?._commitLiveEditor(),this._pruneDevicePressFeedback(),this._syncDayCycleClock(),this._syncRadarLive(),this._warmSnapshot(),this._editorRuntime&&this._dtMeasure();const e=this._stageEl;e&&!this._roViewport&&(this._roViewport=new ResizeObserver(()=>{this._invalidateDeviceHitGeometry(),this._refitView(),requestAnimationFrame(()=>this._summary?.resized())}),this._roViewport.observe(e)),e&&this._booting&&!this._bootTimer&&this._bootWatch();const t=this.renderRoot.querySelector(".hdr");if(t&&e&&!this._roHdr){const i=()=>{const t=ef(this.renderRoot,e,this.panelHost);null!==t&&(t>=0&&t!==this._hdrH&&(this._hdrH=t),t>=0&&!this._booting&&!this._config?.kiosk&&e.clientHeight>0&&this._warmPatch({hdrH:t,stageH:e.clientHeight}))};this._roHdr=new ResizeObserver(()=>requestAnimationFrame(i)),this._roHdr.observe(t),this._onWinResize=()=>requestAnimationFrame(i),window.addEventListener("resize",this._onWinResize),i()}if(e&&!this._view&&this._refitView(),this._editorSecondary?.afterRender(),this._settleContinuityFrame(),this._serverStorage&&this._loadOk&&this._canManageConfiguration&&0===this._model.length&&!this._spaceDialog&&!this._importDialog&&!this._onboardingShown){this._onboardingShown=!0;const e=function(e){const t=e?.floors;if(!t||"object"!=typeof t)return[];const i=[];for(const e of Object.values(t))e&&e.floor_id&&i.push({id:e.floor_id,name:e.name||e.floor_id,level:e.level??null});return i.sort((e,t)=>{const i=e.level??1e9,n=t.level??1e9;return i!==n?i-n:e.name.localeCompare(t.name)}),i}(this.hass);e.length?this._importDialog={floors:e.map(e=>({...e,checked:!0}))}:this._openSpaceDialog("create")}}_adoptConfigCapabilities(e){xg(this,e)}_syncRadarLive(){const e=this._serverCfg?.settings?.radar,t=(this._serverCfg?.markers||[]).some(e=>Cg(e,this._space));this._radarLive.sync(this._space,1===this._haRadarStage1Api&&"view"===this._mode&&!1!==e?.show_live&&t&&"hidden"!==this.ownerDocument.visibilityState)}async _syncDecorAssets(e){const t=++this._decorAssetSyncToken;if(1!==this._haDecorAssetsApi||!this.hass)return void(this._decorAssets=new Map);const i=await um(this.hass,cm(e),this._cfgRev);t===this._decorAssetSyncToken&&(this._decorAssets=i,this._resign(),this.requestUpdate())}_adoptAuthoritative(e){return ju(this,e)}_rollbackOptimistic(e){const t=this._adoption.rollbackOptimistic(e);return t&&this.requestUpdate(),t}_resumePendingNavMode(){if(!this._pendingNavMode||!this._canEdit||this._config?.kiosk)return!1;const e=this._pendingNavMode;return this._pendingNavMode=null,this._setMode(e,!1),!0}_getAuthoritativeConfig(){return e=this,async function(e,t){const i=await e();return t(i),i}(()=>e.hass.callWS({type:"houseplan/config/get"}),t=>xg(e,t));var e}async _loadFromServer(){this._loading=!0,this._loadTries++;const e=this._space,t=!!this._view;let i=!1;const n=()=>{i=!0,this._regSignature="",this._maybeRebuildDevices()};try{const[i,r]=await Promise.all([this._getAuthoritativeConfig(),this.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this._adoptAuthoritative({cfgResp:i,layResp:r,reason:"structural-response",profile:"reload",beforeAdopt:()=>{this._connectionWasLost=!1,this._serverStorage=!0},afterAdopt:()=>{this._warmVpArmed&&this._space===this._warmVp?.space?this._warmVpArmed=!1:t&&this._space===e||this._restoreZoom(),this._loadOk=!0,n()}})).status)return;this.hass.callWS({type:"houseplan/trail/get"}).then(e=>{this._vacSrvTrails=e?.trails||{},this.requestUpdate()}).catch(()=>{}),this._ensureLiveSyncSubscriptions()}catch(e){if(this._serverCfg)this._scheduleLoadRetry(!0);else if(this._loadTries>=8){this._serverStorage=!1;try{this._layout=JSON.parse(localStorage.getItem(lv)||"{}")||{}}catch{this._layout={}}}}finally{this._loading=!1,this._continuityDataReady=!0,i||n(),this.requestUpdate()}}_ensureLiveSyncSubscriptions(){const e=this.hass?.connection;if(!e)return;if(e!==this._liveSyncConnection&&(this._unsubCfg?.(),this._unsubCfg=null,this._unsubLayout?.(),this._unsubLayout=null,this._unsubTrail?.(),this._unsubTrail=void 0,this._unsubVirtual?.(),this._unsubVirtual=null,this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=e),this._liveSyncAttempt)return;const t=this._liveSyncGeneration,i=[],n=(n,r,o,s)=>{n()||i.push(async()=>{const i=await e.subscribeEvents(s,o);t===this._liveSyncGeneration&&this.isConnected&&this.hass?.connection===e&&!n()?r(i):i?.()})};if(n(()=>this._unsubCfg,e=>{this._unsubCfg=e},"houseplan_config_updated",e=>{const t=Number(e?.data?.rev??-1);t!==this._cfgRev&&this._reloadConfigOnly(!1,t)}),n(()=>this._unsubTrail,e=>{this._unsubTrail=e},"houseplan_trail_updated",async()=>{try{const e=await this.hass.callWS({type:"houseplan/trail/get"});this._vacSrvTrails=e?.trails||{},this.requestUpdate()}catch{}}),n(()=>this._unsubLayout,e=>{this._unsubLayout=e},"houseplan_layout_updated",e=>this._onLayoutEvent(Number(e?.data?.rev??-1))),n(()=>this._unsubVirtual,e=>{this._unsubVirtual=e},"houseplan_virtual_light_updated",e=>{const t=Wh(this._virtualLights,e?.data);t!==this._virtualLights&&(this._virtualLights=t,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}),!i.length)return;const r=function(e){return Promise.allSettled(e.map(e=>Promise.resolve().then(e)))}(i).then(()=>{});this._liveSyncAttempt=r,r.finally(()=>{this._liveSyncAttempt===r&&(this._liveSyncAttempt=null)})}async _reloadConfigOnly(e=!1,t){return Ku(this,e,t)}_scheduleLoadRetry(e=!1){if(void 0!==this._loadRetryTimer)return;const t=Math.min(8e3,500*2**Math.min(4,Math.max(1,this._loadTries-7)));this._loadRetryTimer=window.setTimeout(()=>{this._loadRetryTimer=void 0,!e&&this._loadOk||this._loading||!this.hass||this._loadFromServer()},t)}async _ensureLiveRuntime(){if(this._liveRt)return;const e=await import("./live-interaction-runtime-CCfHOfT8.js");this._liveRt=new e.LiveRuntime(this),this.isConnected&&this.requestUpdate()}_liveVp(e=!1){this._liveRt?this._liveRt.viewport(e):this.requestUpdate()}_syncLiveHover(){this._liveRt?this._liveRt.hover():this.requestUpdate()}_flushHa(){this._liveRt?.take()&&(this._terminalFrame=2,super.requestUpdate())}_ensureHaRegistryAuthority(){const e=this.hass?.connection||null;e&&e!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=e,this._haRegistryRev=-1,this._haBindingCacheKey="",this._renderLife.invalidate(),this._areaSnapshotCleanupCandidates.clear(),this._planHassMemo=null,this._haRegistryRelease=td(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}get _haRegistry(){return nd(this.hass)}get _planHass(){const e=this._haRegistry,t=od(this.hass,e),i=this._planHassMemo;if(i&&i.hass===this.hass&&i.sig===t)return i.active;const n=ad(this.hass,e),r=ld(this.hass,e);return this._planHassMemo={hass:this.hass,sig:t,active:n,full:r},n}_captureRenderDeviceSnapshot(){if(!this.hass)return;const e=Date.now(),t=[...this._activityRt.entries()].map(([t,i])=>`${t}:${i.gen}:${i.flashTs}:`+(i.flashKind&&(i.expiresAt||i.flashTs+tg)>e?1:0)).join("|"),i=Bh(this._virtualLights);if(this._capturedSnapshotSequence===this._hassSequence&&this._capturedSnapshotDevices===this._devices&&this._capturedSnapshotLayout===this._layout&&this._capturedSnapshotConfigEpoch===this._cfgEpoch&&this._capturedSnapshotVirtual===i&&this._capturedSnapshotActivity===t)return;const n=this._planHass,r=new Map,o=new Map,s=new Set(["sun.sun"]);for(const e of this._summary?.entityIds()||[])s.add(e);this._vacFit?.source&&s.add(this._vacFit.source);const a=new Set,l=new Set,c=e=>{if(!e)return;const t=e.indexOf(":");if(t<0)return void s.add(e);const i=e.slice(0,t),n=e.slice(t+1);"device"===i?a.add(n):"entity"===i&&s.add(n)};for(const e of this._model)for(const t of e.rooms)t.area&&l.add(t.area),c(t.settings?.temp_source),c(t.settings?.hum_source);for(const e of this._serverCfg?.spaces||[])for(const t of e.openings||[])for(const e of ui(t))s.add(e);for(const e of this._serverCfg?.spaces||[])for(const t of e.decor||[])if("text"===t.kind){for(const e of String(t.text||"").matchAll(/\{([^{}\r\n]+)\}/g)){const t=Xi(e[1]);t?.entity&&s.add(t.entity)}t.entity&&s.add(t.entity),o.set(`decor:${e.id}:${t.id}`,tn(t.text,t,n,e=>!!n.entities?.[e]&&!!n.states?.[e]&&!Jd(n,e,Zd(this._markers))))}const h=Ed(n,this._devices,null,this._virtualLights);for(const e of this._devices){for(const t of[!1,!0])r.set(f_(e.id,t),p_(n,e,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:t,activityRuntime:this._activityRt.get(e.id),sourceDetails:!1,lightDevices:this._devices,lightSources:h,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion}));if(this._isVacDev(e)){const t=this._vacSource(e,n),i=t?Wc(n?.states?.[t]?.attributes):null,r=this._vacRt.get(e.id),s=lh(e.id,e.marker?.vacuum??null,e.space,t),a=hh({routes:s,observed:dh(s,[t],t=>this._vacObservedMapId(e,t,n)),spaceIds:new Set(this._model.map(e=>e.id))});o.set(`vacuum:${e.id}`,{source:t,telemetry:i,routes:s,resolution:a,mapId:i?this._vacMapId(e,i,n):null,runtime:r?{trail:r.trail,lastTs:r.lastTs,moving:r.moving,jump:r.jump}:null,server:this._vacSrvTrails[e.id]||null})}}const d=g_({sourceSequence:this._hassSequence,hass:n,devices:this._devices,presentations:r,positions:(u=this._model.length>0,p=this._devices,_=e=>this._livePos(e),u?new Map(p.map(e=>[e.id,_(e)])):new Map),facts:o,entityIds:s,deviceIds:a,areaIds:l});var u,p,_;this._capturedSnapshotSequence=this._hassSequence,this._capturedSnapshotDevices=this._devices,this._capturedSnapshotLayout=this._layout,this._capturedSnapshotActivity=t,this._capturedSnapshotConfigEpoch=this._cfgEpoch,this._capturedSnapshotVirtual=i,this._visibleDeviceSnapshot&&"steady"!==this._continuity.state?this._candidateDeviceSnapshot=d:(this._visibleDeviceSnapshot=d,this._candidateDeviceSnapshot=null)}get _renderDeviceSnapshot(){return this._stagedDeviceSnapshotToken===this._continuity.token?this._candidateDeviceSnapshot||this._visibleDeviceSnapshot:this._visibleDeviceSnapshot||this._candidateDeviceSnapshot}get _renderPlanHass(){return this._renderDeviceSnapshot?.hass||this._planHass}get _renderDevices(){return this._renderDeviceSnapshot?.devices||this._devices}get _renderVacuumDevices(){return this._renderDeviceSnapshot?.vacuumDevices||this._devices}get _fullRegistryHass(){return this._planHass,this._planHassMemo?.full||this.hass}_bindingStatus(e){return dd(this.hass,e,this._haRegistry)}houseplanDiagnostics(){const{registry:e,bindings:t}=this._renderLife.diagnostics(this.hass,this._markers,e=>this._bindingStatus(e));return{registry:{...e,lastSuccessAgeMs:e.lastSuccess?Math.max(0,Date.now()-e.lastSuccess):null},bindings:t}}_openBindingInHa(e){const[t,i]=e.split(":");if(i)if("device"!==t){if("entity"===t){const e=this._fullRegistryHass.entities?.[i];e?.device_id&&fv("/config/devices/device/"+encodeURIComponent(e.device_id))}}else fv("/config/devices/device/"+encodeURIComponent(i))}_bindingHasHaPage(e){const[t,i]=e.split(":");return!!i&&("device"===t||"entity"===t&&!!this._fullRegistryHass.entities?.[i]?.device_id)}_toggleMarkerDialogVisibility(){const e=this._markerDialog;if(!e)return;const t="ha"===e.bindingMode?this._bindingStatus(e.binding):null,i=e.hideFromPlan||"ha_disabled"===t?.kind;i&&"ha_disabled"===t?.kind?this._showToast(this._t("entity"===t.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device")):i&&"unverified"===t?.kind?this._showToast(this._t("toast.ha_binding_unverified")):this._markerDialog={...e,hideFromPlan:!i}}_hookConnection(){const e=this.hass?.connection;e&&e!==this._connHooked&&(this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),e.addEventListener?.("ready",this._onConnReady),e.addEventListener?.("disconnected",this._onConnLost),e.addEventListener?.("reconnect-error",this._onConnLost),this._connHooked=e)}_display(e){return this._signer.display(this.hass,e)}_referencedContentUrls(){const e=Nn(this._serverCfg);for(const t of this._decorAssets.values())e.add(t.url);return e}_resign(){this._signer.resign(this.hass,this._referencedContentUrls())}_onLayoutEvent(e){e<=this._layoutRev||(clearTimeout(this._layoutSyncTimer),this._layoutSyncTimer=window.setTimeout(()=>{e<=this._layoutRev||this._reloadLayoutOnly()},200))}_noteLayoutRev(e){this._adoption.noteLayoutRevision(e?.rev)}async _reloadLayoutOnly(){if(!this._serverStorage||!this.hass?.callWS)return;this._beginContinuityCandidate("layout-reload",!1);const e=new Map;for(const t of this._dirtyPos)this._layout[t]&&e.set(t,this._layout[t]);this._persistLayout.pending()&&this._persistLayout.flush();for(const[t,i]of this._sentPos)e.set(t,i);try{const t=await this.hass.callWS({type:"houseplan/layout/get"}),i={...t?.layout||{}};for(const[t,n]of e)null===n?delete i[t]:i[t]=n;this._adoption.adoptMergedLayout(i,t,()=>{this._cancelDeviceDrag(),this._devicePositionHistory.clear()}),this._canOptimizeUndo=!!t?.can_optimize_undo,this._undoKind=t?.undo_kind||null,this._cacheSnapshot(),this.requestUpdate()}catch{}finally{this._continuityDataReady=!0,this.requestUpdate()}}_persistLocalLayout(){this._layout=So(lo(this._layout)),localStorage.setItem(lv,JSON.stringify(this._layout))}_maybeRebuildDevices(){const e=this.hass;if(!e?.devices||!e?.entities||!e?.areas)return;const t=this._haRegistry,i=od(e,t)+":"+Object.keys(e.areas).length+":"+(this._norm?"n":"l")+":"+kp(e,this._config?.language);if(i===this._regSignature&&this._devices.length)return;this._regSignature=i;const n=new Map(this._devices.map(e=>[e.id,e.bindingStatus?.kind||"active"]));this._devices=iu({hass:e,registry:t,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,showAll:this._showAll,firstSpaceId:this._model[0]?.id||"",loc:e=>this._t(e),iconRules:this._iconRules});const r=this._markers.filter(e=>!e.removed&&"virtual"!==e.binding).map(e=>e.binding).sort(),o=t.revision+":"+r.join("|");if(t.authoritative&&o!==this._haBindingCacheKey){const i=new Map;for(const n of r)i.set(n,dd(e,n,t));!function(e){if("undefined"==typeof localStorage||!e.size)return;const t=hd(),i=Date.now();for(const[n,r]of e)"active"===r.kind?t[n]={kind:"active",ts:i}:"ha_disabled"===r.kind&&(t[n]={kind:"ha_disabled",reason:r.reason,ts:i});const n=Object.fromEntries(Object.entries(t).sort((e,t)=>t[1].ts-e[1].ts).slice(0,1500));Yh=n;try{localStorage.setItem(Kh,JSON.stringify(n))}catch{}}(i),this._haBindingCacheKey=o}let s=null;if(t.authoritative&&(s=this._resolveAreaRelocations(t),this._areaRelocationIds=new Set(s.relocateIds),this._areaRelocationIds.size)){this._cancelDeviceDrag();const e=this._areaRelocationIds;this._devicePositionHistory.removeWhere(({before:t,after:i})=>e.has(t.deviceId)||e.has(i.deviceId));const t=this._markerDialog;if(t?.devId&&!t.roomTouched&&this._areaRelocationIds.has(t.devId)){const e=this._devices.find(e=>e.id===t.devId);e&&(this._markerDialog={...t,room:e.marker?.room_id?`${e.space}#@${e.marker.room_id}`:e.space&&e.area?`${e.space}#${e.area}`:""})}}this._defPos=this._defaultPositions(),this._syncNewDevices(),this._seedHiddenDevices(),s&&this._syncAreaRelocations(s),this._syncActivityRuntime();const a=new Set(this._devices.filter(e=>!e.hidden).map(e=>e.id));for(const e of this._vacRt.keys())a.has(e)||this._vacRt.delete(e);if(this._infoCard){const e=this._devices.find(e=>e.id===this._infoCard.id);this._infoCard=e&&"ha_disabled"!==e.bindingStatus?.kind?e:null}const l=this._devices.some(e=>"ha_disabled"===e.bindingStatus?.kind&&"ha_disabled"!==n.get(e.id));l&&("ha_disabled"!==this._infoCard?.bindingStatus?.kind&&"ha_disabled"!==this._devices.find(e=>e.id===this._infoCard?.id)?.bindingStatus?.kind||this._closeInfoCard(),this._deviceDrag&&"ha_disabled"===this._devices.find(e=>e.id===this._deviceDrag.id)?.bindingStatus?.kind&&(this._cancelDeviceDrag(),this._devicePositionHistory.clear()),clearTimeout(this._holdTimer),this._holdFired=!1,this._tip=null,this._tapConfirm=null),this._nativeMoreInfoEntity&&!this._planEntityAvailable(this._nativeMoreInfoEntity)&&(gv(this,"hass-more-info",{entityId:null}),this._nativeMoreInfoEntity=null)}_resolveAreaRelocations(e=this._haRegistry){const t=function(e){const t=Q_(e.snapshot),i=new Set(Object.values(t).map(e=>e.binding)),n=new Map;for(const[t,r]of e.previousCandidates||[])J_(t)&&Number.isFinite(r)&&i.has(t)&&n.set(t,r);const r=new Set,o=new Set;for(const t of e.markers||[])t.removed||(Z_(t.id)&&r.add(t.id),J_(t.binding)&&o.add(t.binding));const s=new Set(Object.keys(e.registryDevices||{})),a=new Set(Object.keys(e.registryEntities||{})),l=new Set(Object.keys(e.liveStates||{})),c=new Map;for(const[e,i]of Object.entries(t)){const t=c.get(i.binding)||[];t.push(e),c.set(i.binding,t)}const h=new Set;let d=!1;for(const[t,i]of c){const[c,u]=rm(t);if(o.has(t)||i.some(e=>r.has(e))||("device"===c?s.has(u):a.has(u)||l.has(u))){n.delete(t);continue}const p="device"===c?s.size>0:a.size>0;if(!e.authoritative||!p)continue;const _=n.get(t);if(void 0!==_){if(_!==e.revision)for(const e of i)h.add(e)}else n.set(t,e.revision),d=!0}return{removeIds:h,candidates:n,needsConfirmationRefresh:d}}({snapshot:this._settings.marker_area_snapshot,authoritative:e.authoritative,revision:e.revision,registryDevices:e.devices,registryEntities:e.entities,liveStates:this.hass?.states,markers:this._markers,previousCandidates:this._areaSnapshotCleanupCandidates});return this._areaSnapshotCleanupCandidates=t.candidates,t.needsConfirmationRefresh&&this._canEdit&&id(this.hass),om({devices:this._devices,model:this._model,layout:this._layout,snapshot:this._settings.marker_area_snapshot,authoritative:e.authoritative,cleanupSnapshotIds:t.removeIds,coordinateScale:_v})}_syncNewDevices(){if(!this._norm||!this._loadOk||!this._serverCfg)return;const e=this._devices.filter(e=>!e.marker&&!e.virtual).map(e=>e.id).sort(),t=e.join(",");if(t===this._newSyncKey)return;this._newSyncKey=t;const i=this._settings,{fresh:n,known:r}=function(e,t){if(!Array.isArray(t))return{fresh:[],known:[...e]};const i=new Set(t),n=e.filter(e=>!i.has(e));return{fresh:n,known:n.length?[...t,...n]:t}}(e,i.known_devices);if(!Array.isArray(i.known_devices)||n.length){const e=[...new Set([...i.new_device_ids||[],...n])];this._serverCfg={...this._serverCfg,settings:{...i,known_devices:r,new_device_ids:e}},this._saveConfig()}}_syncAreaRelocations(e){if(!(this._loadOk&&this._serverCfg&&this._norm&&this._canEdit&&this._haRegistry.authoritative))return;const t=e.decisions.filter(e=>e.updateSnapshot||e.removeSnapshot);if(!t.length)return;const i=cc({snapshot:Q_(this._settings.marker_area_snapshot),decisions:t});i!==this._areaRelocationSyncKey&&(this._areaRelocationSyncKey=i,this._areaRelocationWrite=this._areaRelocationWrite.catch(()=>{}).then(async()=>{if(!this._serverCfg||!this._haRegistry.authoritative)return;const e=this._resolveAreaRelocations();this._areaRelocationIds=new Set(e.relocateIds);const t=new Set,i=new Map;let n=!1;for(const r of e.decisions){if(!r.relocate)continue;const e=fg(this._layout,r.id);try{await this._persistDevicePlacement(r.id,null),t.add(r.id),e&&i.set(r.id,e),this._areaRelocationIds.delete(r.id)}catch(t){n=!0,this._layout=vg(this._layout,r.id,e),this._showToast(this._t("toast.pos_save_failed",{err:this._errText(t)}))}}const r=this._settings,o=function(e,t,i=new Set){const n=Q_(e);for(const e of t.decisions)e.removeSnapshot?delete n[e.id]:e.updateSnapshot&&e.binding&&e.area&&(e.relocate&&!i.has(e.id)||(n[e.id]={binding:e.binding,area:e.area}));return n}(r.marker_area_snapshot,e,t),s=[...new Set([...Array.isArray(r.new_device_ids)?r.new_device_ids:[],...t])],a=cc(o)!==cc(Q_(r.marker_area_snapshot)),l=cc(s)!==cc(Array.isArray(r.new_device_ids)?r.new_device_ids:[]);if(a||l){const e=r.marker_area_snapshot,n=r.new_device_ids,a={...this._serverCfg,settings:{...r,marker_area_snapshot:o,...l?{new_device_ids:s}:{}}};this._setAreaLifecycleConfig(a);try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.cancel(),await this._writeConfig()}catch(r){const a=this._settings;if(cc(a.marker_area_snapshot)===cc(o)&&cc(a.new_device_ids)===cc(l?s:n)){const t={...a};void 0===e?delete t.marker_area_snapshot:t.marker_area_snapshot=e,void 0===n?delete t.new_device_ids:t.new_device_ids=n;const i={...this._serverCfg,settings:t};this._setAreaLifecycleConfig(i),this._adoption.refreshConfigFingerprint()}for(const e of t)this._areaRelocationIds.add(e);const c=new Set;for(const[e,t]of i)try{await this._persistDevicePlacement(e,t)}catch(t){c.add(e),this._showToast(this._t("toast.pos_save_failed",{err:this._errText(t)}))}this._areaRelocationSyncKey="",this._regSignature="";if("conflict"===(r&&"object"==typeof r&&"code"in r?r.code:void 0)?(this._showToast(this._t("toast.conflict")),await this._reloadConfigOnly(!0)):this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(r)})),c.size&&this._serverCfg){const e=this._settings,t=[...new Set([...Array.isArray(e.new_device_ids)?e.new_device_ids:[],...c])],i={...this._serverCfg,settings:{...e,new_device_ids:t}};this._setAreaLifecycleConfig(i);try{await this._writeConfig()}catch(e){this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(e)}))}}}}n&&(this._areaRelocationSyncKey=""),this.requestUpdate()}))}get _newIds(){const e=this._settings.new_device_ids;return new Set([...Array.isArray(e)?e:[],...this._areaRelocationIds])}_ackNewDevice(e){if(!this._newIds.has(e)||!this._serverCfg)return;const t=this._settings;this._serverCfg={...this._serverCfg,settings:{...t,new_device_ids:(t.new_device_ids||[]).filter(t=>t!==e)}},this._saveConfig(),this.requestUpdate()}get _markers(){return this._serverCfg?.markers||[]}_roomLqi(e){if(!e)return null;const t=[];for(const i of this._renderDevices){if(i.area!==e||i.virtual)continue;const n=Ld(this._renderPlanHass,i.entities);null!=n&&t.push(n)}return Ii(t)}_roomBounds(e){if(e.poly&&e.poly.length){const t=e.poly.map(e=>e[0]),i=e.poly.map(e=>e[1]),n=Math.min(...t),r=Math.min(...i);return{x:n,y:r,w:Math.max(...t)-n,h:Math.max(...i)-r}}return{x:e.x??0,y:e.y??0,w:e.w??0,h:e.h??0}}_defaultPositions(){const e={},t=this._config?.icon_size??2.5;for(const i of this._model){const n=t/100*Ml(i)*1.3;for(const t of i.rooms){if(!t.area)continue;const r=this._devices.filter(e=>e.area===t.area&&e.space===i.id);if(!r.length)continue;const o=this._roomBounds(t),s=.1*Math.min(o.w,o.h),a=o.w-2*s,l=o.h-2*s,c=Math.max(1,Math.round(Math.sqrt(r.length*a/Math.max(l,1)))),h=Math.ceil(r.length/c),d=a/c,u=l/Math.max(h,1),p=r.map((e,t)=>({x:o.x+s+d*(t%c+.5),y:o.y+s+u*(Math.floor(t/c)+.5)}));Ei(p,o,n,.5*s),r.forEach((t,i)=>e[t.id]=al(p[i]))}}return e}_pos(e){const t=this._renderDeviceSnapshot?.positions.get(e.id);return t?{x:t.x,y:t.y}:this._livePos(e)}_livePos(e){const t=this._spaceModelById(e.space),i=this._areaRelocationIds.has(e.id)?void 0:this._layout[e.id];if(i)if(this._norm){if(i.s===e.space)return{x:i.x*_v,y:i.y*_v}}else if(void 0===i.s)return{x:i.x,y:i.y};return this._defPos[e.id]?this._defPos[e.id]:t?al($l(t)):{x:500,y:500}}_devicePlacementForCanvas(e,t,i){if(!this._norm)return{x:Math.round(t),y:Math.round(i)};const n=this._gridPitch,r=Math.round(t/n)*n,o=Math.round(i/n)*n;return{s:e.space,x:cl(r/_v),y:cl(o/_v)}}_previewDevicePlacement(e,t){this._layout=vg(this._layout,e,t),this.requestUpdate()}_cancelDeviceDrag(){const e=this._deviceDrag;if(!e)return!1;this._editorRuntime?._cancelPointerMove("device"),this._deviceDrag=null,this._deviceHits.cancel(e.pointerId);try{e.source?.hasPointerCapture?.(e.pointerId)&&e.source.releasePointerCapture(e.pointerId)}catch{}return this._previewDevicePlacement(e.id,e.before),!0}async _persistDevicePlacement(e,t){if(this._layout=vg(this._layout,e,t),this._serverStorage){let i=null,n=!1;try{let r;if(null===t)i=null,this._sentPos.set(e,i),n=!0,r=await this.hass.callWS({type:"houseplan/layout/delete",device_id:e});else{const t=xo(this._layout[e]);cc(t)!==cc(this._layout[e])&&(this._layout={...this._layout,[e]:t}),i=t,this._sentPos.set(e,i),n=!0,r=await this.hass.callWS({type:"houseplan/layout/update",device_id:e,pos:t})}this._noteLayoutRev(r),this._adoption.refreshLayoutFingerprint(),this._cacheSnapshot()}finally{n&&this._sentPos.get(e)===i&&this._sentPos.delete(e)}return}this._persistLocalLayout()}_devicePositionStateValid(e){const t=this._devices.find(t=>t.id===e.deviceId);return!!t&&t.space===e.spaceId&&"ha_disabled"!==t.bindingStatus?.kind&&!!this._spaceModelById(e.spaceId)}async _runDevicePositionHistory(e){if(this._cancelDeviceDrag()||this._devicePositionBusy)return;const t="undo"===e?this._devicePositionHistory.undo():this._devicePositionHistory.redo();if(!t)return;const i="undo"===e?t.before:t.after;if(!this._devicePositionStateValid(i))return this._devicePositionHistory.clear(),this._showToast(this._t("history.device_stale")),void this.requestUpdate();const n=fg(this._layout,i.deviceId);i.spaceId!==this._space&&(this._commitSpace(i.spaceId),this._restoreZoom()),this._devicePositionBusy=!0,this._previewDevicePlacement(i.deviceId,i.placement);try{await this._persistDevicePlacement(i.deviceId,i.placement),this._showToast(this._t("undo"===e?"history.undone":"history.redone",{name:t.name}))}catch(t){this._previewDevicePlacement(i.deviceId,n),"undo"===e?this._devicePositionHistory.redo():this._devicePositionHistory.undo(),this._showToast(this._t("toast.pos_save_failed",{err:this._errText(t)}))}finally{this._devicePositionBusy=!1,this.requestUpdate()}}_undoDevicePosition(){this._runDevicePositionHistory("undo")}_redoDevicePosition(){this._runDevicePositionHistory("redo")}_savePos(e,t,i){this._spaceModelById(e.space)&&(this._layout=vg(this._layout,e.id,this._devicePlacementForCanvas(e,t,i)),this._dirtyPos.add(e.id),this._persistLayout())}_devicePresentation(e,t=!1!==this._config?.show_signal,i=!1){const n=i?null:this._renderDeviceSnapshot?.presentations.get(f_(e.id,t));return n||p_(this._renderPlanHass,e,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:t,designPreview:i,activityRuntime:this._activityRt.get(e.id),sourceDetails:!1,lightDevices:this._renderDevices,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion})}_deviceVisual(e){return this._devicePresentation(e).visual}_stateClass(e,t=this._deviceVisual(e)){const i=this._devicePresentation(e);return i.effectiveHidden?"":("icon_ripple"!==i.display||!1===this._config?.live_states||"alarm"===t.status||t.activity,u_({...i,visual:t}).join(" "))}_liveTemp(e){if(!this._config?.show_temperature)return null;if(!0===e.marker?.use_climate_temp){const t=qd(this._renderPlanHass,e.entities);if(null!=t)return t}return"mdi:thermometer"!==e.icon&&"mdi:air-filter"!==e.icon?null:Bd(this._renderPlanHass,e.entities)}_bindingEntities(e){if("virtual"===e||!e)return[];const t=this._bindingStatus(e);return"active"===t.kind?t.enabledEntityIds:t.allEntityIds}_bindingHasClimate(e){return this._bindingEntities(e).some(e=>e.startsWith("climate."))}_bindingHasAlarm(e){return this._bindingEntities(e).some(e=>{const t=this._planHass?.states?.[e]||this.hass?.states?.[e],i=this._fullRegistryHass.entities[e]||this.hass?.entities?.[e];return Yn(e.split(".")[0],t?.attributes?.device_class||i?.device_class||i?.original_device_class)})}_deviceBindingActive(e,t=!0){if(e.virtual||"virtual"===e.bindingKind)return!0;if(!e.bindingKind||!e.bindingRef)return!1;const i=this._bindingStatus(`${e.bindingKind}:${e.bindingRef}`);return"active"===i.kind||(t&&this._showToast(this._t("ha_disabled"===i.kind?"toast.ha_disabled_action":"toast.ha_binding_unverified")),!1)}_openMoreInfo(e){e?this._planEntityAvailable(e)?(this._kiosk&&(this._cyclePausedUntil=Math.max(this._cyclePausedUntil,Date.now()+6e4)),this._nativeMoreInfoEntity=e,gv(this,"hass-more-info",{entityId:e})):this._showToast(this._t("toast.ha_disabled_action")):this._showToast(this._t("toast.no_entity"))}_interruptViewGesture(e,t){if(clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),void 0!==e)for(const i of[t,this._stageEl])try{i?.hasPointerCapture?.(e)&&i.releasePointerCapture(e)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null,this._roomPointer=null,this._doubleFit.clear(),this._deviceHits.clearPointers()}_closeInfoCard(){this._interruptViewGesture(),this._holdFired=!1,this._infoCard=null}_invalidateDeviceHitGeometry(){this._deviceHits.invalidate()}_resetDeviceHitState(){this._deviceHits.reset(this.renderRoot)}_deviceHitOwnerAt(e,t){return"view"!==this._mode&&"devices"!==this._mode?null:this._deviceHits.at(this.renderRoot,this._renderDevices,this._space,e,t)}_deviceForPointerEvent(e,t){return this._deviceHits.pointer(this.renderRoot,this._renderDevices,this._space,e,t)}_deviceForClickEvent(e,t){return this._deviceHits.click(this.renderRoot,this._renderDevices,this._space,e,t)}_showDeviceTip(e,t){this._liveRt?this._liveRt.devicePointerTip(e,t):this._ensureLiveRuntime().then(()=>this._liveRt?.devicePointerTip(e,t))}_showDeviceFocusTip(e,t){const i=e.currentTarget;this._liveRt?this._liveRt.deviceFocusTip(i,t):this._ensureLiveRuntime().then(()=>this._liveRt?.deviceFocusTip(i,t))}_hideDeviceFocusTip(e){this._liveRt?.deviceBlur(e)}_clearPointerHover(){this._liveRt?this._liveRt.pointerLeave():this._clearTransientHover()}_ctxDevice(e,t){"view"===this._mode&&(t=this._deviceForPointerEvent(e,t),e.preventDefault(),e.stopPropagation(),this._deviceBindingActive(t)&&(t.primary?this._openMoreInfo(t.primary):this._infoCard=t))}_clickDevice(e,t){if("view"!==this._mode&&"devices"!==this._mode)return;if(e.stopPropagation(),t=this._deviceForClickEvent(e,t),this._deviceDrag?.moved||this._suppressClick||this._holdFired)return;if("devices"===this._mode)return void this._openMarkerDialog(t);const i=this._devices.find(e=>e.id===t.id);if(!i)return;const n=Tu(i.tapAction,i.primary?.split(".")[0]);if("none"===n)return;const r=(e,t)=>{i.marker?.tap_confirm?this._tapConfirm={kind:"run",text:e,exec:t}:t()};if("toggle"===n){const e=this._toggleIntent(i);if(!e)return;if(!Iu(e))return void this._showUnavailableToggleTargets(e);const t=e=>{const t=Iu(e);if(!t)return;if("virtual-light"===t.kind)return this._startDevicePressFeedback(i.id),void this.hass.callWS({type:"houseplan/virtual_light/toggle",marker_id:t.markerId}).then(e=>{const t=Wh(this._virtualLights,e);t!==this._virtualLights&&(this._virtualLights=t,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}).catch(e=>this._showToast(this._t("toast.virtual_light_toggle_failed",{err:this._errText(e)})));const{command:n}=t;this._startDevicePressFeedback(i.id),this.hass.callService(n.domain,n.service,n.data).catch(e=>this._showToast(this._t("toast.error",{err:this._errText(e)})))},n=((o=e).targets.length?o.targets:o.skippedTargets).map(e=>e.name||e.entityId||e.ref).join(", ")||i.name;if(i.marker?.tap_confirm){const r=this._toggleConfirmationLines(e);if(!r.length)return;this._tapConfirm={kind:"toggle",text:this._t("confirm.tap_toggle",{name:n}),lines:r,initialIntent:e,deviceId:i.id,exec:()=>{const n=this._devices.find(e=>e.id===i.id),r=n?this._toggleIntent(n):null;r&&!Iu(r)&&this._showUnavailableToggleTargets(r)||(r&&Eu(e,r)?t(r):this._showToast(this._t("toast.tap_target_changed")))}}}else t(e);return}var o;if("info"===n)return this._interruptViewGesture(),void(this._infoCard=i);if(this._deviceBindingActive(i)){if("run"===n){const e=i.marker?.tap_target||"",t=function(e){const t=String(e||"").split(".")[0];return"automation"===t?{domain:"automation",service:"trigger"}:"script"===t?{domain:"script",service:"turn_on"}:"scene"===t?{domain:"scene",service:"turn_on"}:null}(e),n=this.hass.states[e];if(!t||!n)return void this._showToast(this._t("toast.run_target_missing"));const o=n.attributes?.friendly_name||e;return void r(this._t("confirm.tap_run",{name:o}),()=>{this._deviceBindingActive(i)&&this._planEntityAvailable(e)&&(this._startDevicePressFeedback(i.id),this.hass.callService(t.domain,t.service,{entity_id:e}).then(()=>{this._stampActivity(i.id,"event",this._activitySourceKey(i)),this.requestUpdate(),this._showToast(this._t("toast.run_started",{name:o}))}).catch(e=>this._showToast(this._t("toast.error",{err:this._errText(e)}))))})}"more-info"===n&&i.primary?this._openMoreInfo(i.primary):this._infoCard=i}}_showUnavailableToggleTargets(e){const t=function(e){if(!e||"group"!==e.kind||Iu(e)||"configured-targets-missing"!==e.noneReason)return[];if(!e.skippedTargets.length||e.skippedTargets.some(e=>!Ou.has(e.reason)&&"secure"!==e.reason))return[];const t=[],i=new Set;for(const n of e.skippedTargets){if(!Ou.has(n.reason))continue;const e=String(n.name||n.entityId||n.ref||"").trim();e&&!i.has(e)&&(i.add(e),t.push(e))}return t}(e);return!!t.length&&(this._showToast(1===t.length?this._t("toast.toggle_target_unavailable",{name:t[0]}):this._t("toast.toggle_targets_unavailable",{names:t.join(", ")})),!0)}_keyDevice(e,t){"Enter"!==e.key&&" "!==e.key||"view"!==this._mode&&"devices"!==this._mode||(e.preventDefault(),this._clickDevice(e,t))}_startDevicePressFeedback(e){const t=[...this.renderRoot.querySelectorAll(".dev[data-id]")].find(t=>t.dataset.id===e),i=t?.querySelector(".device-shell");if(!i||"function"!=typeof i.animate)return;const n=Number.parseFloat(this.ownerDocument.defaultView?.getComputedStyle(i).scale||""),r=Number.isFinite(n)?Math.max(.95,Math.min(1,n)):1;this._devicePressAnimations.get(e)?.cancel();const o=this._reducedMotion?[{outlineColor:"transparent",outlineStyle:"solid",outlineWidth:"0px"},{outlineColor:"var(--hp-accent, #3ea6ff)",outlineStyle:"solid",outlineWidth:"2px",outlineOffset:"2px",offset:.5},{outlineColor:"transparent",outlineStyle:"solid",outlineWidth:"0px"}]:[{scale:String(r)},{scale:"0.95",offset:.5},{scale:"1"}],s=i.animate(o,{duration:200,easing:"cubic-bezier(.22,.61,.36,1)"});this._devicePressAnimations.set(e,s);const a=()=>{this._devicePressAnimations.get(e)===s&&this._devicePressAnimations.delete(e)};s.addEventListener("finish",a,{once:!0}),s.addEventListener("cancel",a,{once:!0})}_cancelDevicePressFeedback(){for(const e of this._devicePressAnimations.values())e.cancel();this._devicePressAnimations.clear()}_pruneDevicePressFeedback(){if(!this._devicePressAnimations.size)return;const e=new Set([...this.renderRoot.querySelectorAll(".dev[data-id]")].map(e=>e.dataset.id||""));for(const[t,i]of this._devicePressAnimations)e.has(t)||(i.cancel(),this._devicePressAnimations.delete(t))}_t(e,t){return xp(kp(this.hass,this._config?.language),e,t)}get _colorPickerLabels(){return{title:this._t("color_picker.title"),hue:this._t("color_picker.hue"),saturation:this._t("color_picker.saturation"),value:this._t("color_picker.value"),hex:this._t("color_picker.hex"),invalidHex:this._t("color_picker.invalid_hex"),confirm:this._t("color_picker.confirm")}}_help(e){return this._editorRuntimeOrThrow()._help(e)}get _stageEl(){return this.renderRoot.querySelector(".stage")}_contentItems(e){const t=[];for(const i of this._devices){if(i.space!==e.id||i.hidden)continue;const n=this._pos(i);t.push({minX:n.x,minY:n.y,maxX:n.x,maxY:n.y})}if(e.id===this._space){for(const e of this._openingsR){const i=Number(e.angle)*Math.PI/180,n=Math.cos(i)*e.rlen/2,r=Math.sin(i)*e.rlen/2,o=pl([[e.rx-n,e.ry-r],[e.rx+n,e.ry+r]]);o&&t.push(o)}const i=this._decorH;for(const e of this._decorList){if("image"===e.kind&&!this._decorAssets.has(e.asset_id)&&"decor"!==this._mode)continue;const n=pl("line"===e.kind?[[e.x1*_v,e.y1*i],[e.x2*_v,e.y2*i]]:"text"===e.kind?[[e.x*_v,e.y*i]]:Nr({x:e.x*_v,y:e.y*i,w:e.w*_v,h:e.h*i,angle:e.angle}));n&&t.push(n)}for(const i of this._physicalBodiesR(e)){const e=pl(i);e&&t.push(e)}}return vl(e,t)}_frameOf(){const e=this._spaceModel();if(!e){this._frame=null;const e={x:0,y:0,w:_v,h:_v};return{rect:e,all:e,outliers:0}}const t=this._frame,i="view"!==this._mode;if(t&&t.id===e.id&&this._bdDrag)return t;if(t&&t.id===e.id&&t.model===e&&t.layout===this._layout&&t.devs===this._devices&&t.far===this._showFar&&t.grow===i)return t;const n=kl(this._contentItems(e));let r=n.all||Sl(e),o=this._showFar?r:n.core||Sl(e);return t&&t.id===e.id&&i&&t.grow&&(o=mv(t.rect,o),r=mv(t.all,r)),this._frame={id:e.id,model:e,layout:this._layout,devs:this._devices,far:this._showFar,grow:i,rect:o,all:r,outliers:n.outliers},this._frame}_isoSource(){const e=this._isoSceneRuntime;if(!e)return null;const t=this._spaceModel();if(!t)return null;const i=this._spaceWalls,n=this._openCuts(),r=this._openingsR;return e.createIsoStructuralSource({space:t,walls:i,openCuts:n,openings:r,partitionCuts:()=>this._partitionOpeningCuts(t),roomOpenings:()=>this._roomWallOpeningInputs(r,t),cellCm:this._cellCm,gridPitch:this._gridPitch,wallKeyPitch:this._wallKeyPitch,coordinateScale:_v,onBuild:()=>{this._isoStructuralBuildCount+=1}})}_isoSceneKey(){if(!this._labsIso||"view"!==this._mode)return null;try{return this._isoSource()?.key??null}catch{return this._isoInvalidKey()}}_isoInvalidKey(){return`${this._space}|invalid|${this._cfgEpoch}`}_clearIsoInvalidFallback(e){const t=`${this._space}|invalid|`;for(const i of this._isoFallback)i.startsWith(t)&&i!==e&&this._isoFallback.delete(i)}_isoScene(e=this._isoSource()){const t=this._isoSceneRuntime;if(!t||!e)return null;let i=this._frameOf().rect;const n=this._spaceDisplayForRender(),r=this._spaceModel();if(r&&n.showNames)for(const e of r.rooms)if(e.name){const t=this._labelPos(e,r.id);i=mv(i,{x:t.x,y:t.y,w:0,h:0})}const o=t.resolveIsoScene({source:e,cache:this._isoGeometryCache,cellCm:this._cellCm,liveFrame:i});if(!r||!n.showBorders)return o;const s=this._config?.icon_size??2.5,a=s>8?2.5:s,l=this._stageEl?.getBoundingClientRect?.()??null,c=l?.height?l.width/l.height:o.frame.w/o.frame.h,h=Oi([o.frame.x,o.frame.y,o.frame.w,o.frame.h],c),d=this._isoOverlayScene(r,this._renderDevices.filter(e=>e.space===r.id&&!e.hidden),h,n,t.resolveIsoDecorationLayers(n),o,a,x_(a),n.showLqi??this._config?.show_signal??!0,!1),u=d&&t.resolveIsoOverlayFitEnvelope({baseBounds:o.frame,entries:d.entries,stageSize:l,targetView:e=>Oi([e.x,e.y,e.w,e.h],c)});return u?{...o,frame:u.bounds,overlayFitEntries:d.entries}:o}_latchIsoFallback(e,t){if(this._isoFallback.has(e))return;this._isoFallback.add(e);const i=e.includes("|invalid|")?"invalid":e.split("|").pop()||"invalid";console.warn("HOUSEPLAN ISO FALLBACK: #89/#160",wf("structural",i,!0))}_effectiveProjection(){if(this._isoProjectionSnapshot)return this._isoProjectionSnapshot;const e=e=>this._isoProjectionSnapshot=e,t=()=>("iso"===this._renderProjection&&(this._cancelCameraTransition(!1),this._view=null,this._viewModeSnap=null),e("flat"));if(this._renderIsoScene=null,"iso"!==this._desiredProjection||!this._model.length||!this._isoSceneRuntime)return e("flat");if(!this._spaceDisplayForRender().showBorders)return this._isoFallback.has(`${this._space}|no-borders`)?t():e("iso");let i=this._isoInvalidKey();if(this._clearIsoInvalidFallback(i),this._isoFallback.has(i))return t();try{const n=this._isoSource();if(!n)return e("flat");if(i=n.key,this._isoFallback.has(i))return t();const r=this._isoScene(n);return r?this._isoFallback.has(r.key)?t():(this._renderIsoScene=r,e("iso")):e("flat")}catch(e){return this._latchIsoFallback(i,e),t()}}_scenePoint(e){return"iso"===this._renderProjection?lf(e,0):e}_floorView(e){if("iso"!==this._renderProjection)return e;const t=cf([e.x,e.y]),i=cf([e.x+e.w,e.y+e.h]);return{x:t[0],y:t[1],w:i[0]-t[0],h:i[1]-t[1]}}_isoOverlayScene(e,t,i,n,r,o,s,a,l,c=!0){const h=this._isoSceneRuntime;return h&&r?.structural&&o?h.buildIsoOverlayRenderScene({space:e,devices:t,openings:this._openingsR,view:i,display:n,wallSilhouettes:o.wallSilhouettes,resolveCollisions:c,iconPct:s,deviceBasePct:a,showLqi:l,cellCm:this._cellCm,kioskIconScale:"view"===this._mode?this._kioskScale.icon:1,kioskFontScale:"view"===this._mode?this._kioskScale.font:1,stageSize:this._stageEl?.getBoundingClientRect?.(),positionOf:e=>this._pos(e),presentationOf:(e,t)=>this._devicePresentation(e,t),labelPositionOf:(e,t)=>this._labelPos(e,t),labelScaleOf:e=>this._labelScale(e),openingEntityAvailable:e=>this._renderOpeningEntityAvailable(e),openingWallIndex:()=>this._openingWallIndexFor(e,this._openCuts()).value}):null}_baseVb(e=this._effectiveProjection(),t=this._renderIsoScene){if("iso"===e){if(!this._spaceDisplayForRender().showBorders){const e=uf({rect:this._frameOf().rect,wallHeight:0});return[e.x,e.y,e.w,e.h]}const e=t?.frame??this._frameOf().rect;return[e.x,e.y,e.w,e.h]}const i=this._frameOf().rect;return[i.x,i.y,i.w,i.h]}get _outliers(){return this._showFar?0:this._frameOf().outliers}_fitFar(){this._clearRoomFocus(),this._showFar=!0,this._frame=null,this.requestUpdate(),this._resetZoom()}_clearRoomFocus(e=!1){this._doubleFit.clear(),this._roomFocus=null,e&&(this._roomPointer=null)}_roomFitBounds(e,t){const i=ni(e);if(!i||!e.id)return null;const n=this._spaceWalls,r=this._openCuts(),o=this._wallUnionGeometry(),s=n.length&&this._innerRoomContour(t,e.id,r,o?.roomGeom,o?.multiWallNodes)||i,a=this._spaceDisplayForRender();let l=[];if(a.showBorders&&n.length){const i=Fs(t.rooms,e.id,n,r,this._wallKeyPitch,this._cellCm,this._gridPitch,_v);i&&(l=aa(i.poly,i.offsets,o?.multiWallNodes)||i.poly)}const c=this._effectiveProjection();return function(e){const t=e.floor,i=e.wall||[],n=e.padding??0;if(!t.length||!t.every(vf)||!i.every(vf)||!Number.isFinite(n)||n<0)return null;if("flat"===e.projection)return bf([...t,...i],n);const r=e.wallHeight??0,o=e.floorDepth??0;if(!Number.isFinite(r)||r<0||!Number.isFinite(o)||o<0)return null;try{const e=[];for(const i of t){const t=[i[0],i[1]];e.push(lf(t,0)),o>0&&e.push(lf(t,-o))}for(const t of i){const i=[t[0],t[1]];e.push(lf(i,0)),r>0&&e.push(lf(i,r))}return bf(e,n)}catch{return null}}({floor:s,wall:l,projection:c,wallHeight:"iso"===c&&a.showBorders?Wa(84,this._cellCm):0,floorDepth:"iso"===c&&a.showBorders?Wa(10,this._cellCm):0,padding:a.showBorders?Wa(1.25,this._cellCm):0})}_fitRoom(e,t=!0){if("view"!==this._mode)return!1;this._doubleFit.clear();const i=this._spaceModel(),n=i?.rooms.find(t=>t.id===e);if(!i||!n)return this._clearRoomFocus(),!1;let r=this._roomFitBounds(n,i);if(!r)return this._clearRoomFocus(),!1;this._roomFocus={spaceId:i.id,roomId:e};const o=this._stageEl;if(!o||o.clientWidth<=0||o.clientHeight<=0)return!0;const s=Oi(this._baseVb(),o.clientWidth/o.clientHeight),a=e=>function(e){const t=e.safeFraction??.8,{bounds:i,baseFit:n,stageWidth:r,stageHeight:o,minZoom:s,maxZoom:a}=e;if(!yf(i)||!yf(n)||!Number.isFinite(r)||r<=0||!Number.isFinite(o)||o<=0||!Number.isFinite(s)||s<=0||!Number.isFinite(a)||a1)return null;const l=r/o,c=Math.max(i.w/t,i.h/t*l);if(!Number.isFinite(c)||c<=0)return null;const h=Math.min(a,Math.max(s,n.w/c)),d=n.w/h,u=d/l;return{zoom:h,viewBox:{x:i.x+i.w/2-d/2,y:i.y+i.h/2-u/2,w:d,h:u}}}({bounds:e,baseFit:s,stageWidth:o.clientWidth,stageHeight:o.clientHeight,minZoom:wv.ZOOM_MIN,maxZoom:wv.ZOOM_MAX});let l=a(r);const c=this._isoSceneRuntime,h=this._renderIsoScene?.overlayFitEntries;if(l&&"iso"===this._effectiveProjection()&&c&&h?.length){const e=c.resolveIsoOverlayFitEnvelope({baseBounds:r,entries:h,ownerId:n.id,stageSize:{width:o.clientWidth,height:o.clientHeight},targetView:e=>a(e)?.viewBox??null});e&&(r=e.bounds,l=a(r))}if(!l)return this._clearRoomFocus(),!1;const d=this._cameraState(),u=function(e,t,i,n){const r=[e,t,i,n],o=Math.min(...r.map(e=>e.x)),s=Math.min(...r.map(e=>e.y));return{x:o,y:s,w:Math.max(...r.map(e=>e.x+e.w))-o,h:Math.max(...r.map(e=>e.y+e.h))-s}}(s,d.viewBox,l.viewBox,r);return l.viewBox=this._clampView(l.viewBox,u),t?(this._prepareCameraCommand(),this._startCameraTransition(l,u,"room",220),!0):(this._cancelCameraTransition(!1),Xg(d,l)||(this._zoom=l.zoom,this._view={...l.viewBox},this.requestUpdate()),!0)}_fitAll(e="fit"){this._clearRoomFocus(),this._showFar=!0,this._frame=null,this.requestUpdate(),this._resetZoom(e)}_renderFarHint(){return this._kiosk||"view"!==this._mode||this._booting||!this._outliers?G:j`
    +
    `:G}houseplanContinuityTrace(){return[...this._continuityHistory,...this._continuity.trace].slice(-80).map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}getCardSize(){return 12}getGridOptions(){return{columns:"full"}}get _norm(){return!(!this._serverCfg||!this._serverCfg.spaces.length)}_cfgFingerprint(){const e=this._serverCfg?.spaces||[];let t=e.length+":";for(const i of e){t+=(i.id||"")+","+(i.plan_aspect||"")+","+(i.plan_url||"").length+","+(i.plan_x??"")+","+(i.plan_y??"")+","+(i.plan_scale??"")+","+(i.plan_scale_x??"")+","+(i.plan_scale_y??"")+","+(i.plan_angle??"")+","+(i.rooms?.length||0)+","+(i.openings?.length||0)+","+(i.decor?.length||0)+";";for(const e of i.rooms||[]){const i=e.poly?.[0],n=e.poly?.[e.poly.length-1];t+=(e.poly?.length||0)+"."+(e.id||"")+"."+(e.open_to||[]).join("+")+"."+(e.area||"")+"."+JSON.stringify(e.settings||0)+"."+(e.x??"")+","+(e.y??"")+","+(e.w??"")+","+(e.h??"")+","+(i?i[0]+"/"+i[1]:"")+","+(n?n[0]+"/"+n[1]:"")+";"}}return t}get _model(){if(!this._serverCfg)return[];const e=this._cfgEpoch+"|"+this._cfgFingerprint();if(this._modelCache&&this._modelCache.key===e)return this._modelCache.model;const t=this._buildModel();return this._modelCache={key:e,model:t},t}_buildModel(){if(!this._serverCfg)return[];const e=this._renderCfg;return el(e).map((t,i)=>{const n=e.spaces[i]?.plan_url;return t.bg&&n?{...t,bg:{...t.bg,href:n}}:t})}_spaceModel(){return this._hasFixedFloor?kc(this._model,this._space):(e=this._model,t=this._space,e.find(e=>e.id===t)??e[0]);var e,t}_spaceModelById(e){return kc(this._model,e)}_syncEmptySpaceState(){if(!!this._serverCfg&&0===this._serverCfg.spaces.length){if(!this._emptySpaceStateActive){this._emptySpaceStateActive=!0,this._clearRoomFocus(!0);for(const e of this._pointers.keys())for(const t of this.renderRoot.querySelectorAll("*"))try{t.hasPointerCapture?.(e)&&t.releasePointerCapture(e)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null,this._drag=null,this._deviceDrag=null,this._resetDeviceHitState(),this._rlResize=null,this._vacFit=null,this._compassDrag=!1,this._cancelModeTransition(!1),this._mode="view",this._clearGeometryGesture(),this._geometryHistory.clear(),this._devicePositionHistory.clear(),this._tip=null,this._hoverRoom=null,this._openingInfo=null,this._closeInfoCard(),this._deviceInbox=null,this._deviceInboxReturn=null,this._markerDialog=null,this._physicalDialog=null,this._backdropDialog=null,this._decorShapeDialog=null,this._decorTextDialog=null,this._roomDialog=!1,"edit"===this._spaceDialog?.mode&&(this._spaceDialog=null),this._editorSecondary?.closeForNavigation(),this._saveConfigDebounced.cancel(),this._frame=null,this._planSnapGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._decorSnapCache=null,this._commitSpace("",!0)}}else this._emptySpaceStateActive=!1}get _areaToSpace(){const e={};for(const t of this._model)for(const i of t.rooms)i.area&&(e[i.area]={space:t.id,room:i});return e}get _settings(){return this._serverCfg?.settings||{}}get _showAll(){return this._showHidden||!this._settings.filter_seeded&&!!this._settings.show_all}_seedHiddenDevices(){if(!(this._loadOk&&this._serverCfg&&this._norm&&this._canEdit))return;const e=this._serverCfg,t=eu({hass:this.hass,registry:this._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,firstSpaceId:this._model[0]?.id||"",iconRules:this._iconRules});if(!t.length&&e.settings?.filter_seeded)return;e.markers=e.markers||[];const i=[];for(const n of t){const t="h"+n.slice(n.indexOf(":")+1);e.markers.push({id:t,binding:n,hidden:!0}),i.push(n.slice(n.indexOf(":")+1))}const n={...e.settings||{},filter_seeded:!0};delete n.show_all,i.length&&Array.isArray(n.new_device_ids)&&(n.new_device_ids=n.new_device_ids.filter(e=>!i.includes(e))),e.settings=n,this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate()}get _iconRules(){const e=this._settings.icon_rules;if(!e||!Array.isArray(e)||!e.length)return;const t=JSON.stringify(e);return t!==this._rulesCompiledSrc&&(this._rulesCompiledSrc=t,this._rulesCompiled=Ee(e)),this._rulesCompiled}get _fillColors(){return vn(this._settings)}get _excluded(){return lu(this._settings)}_setAreaLifecycleConfig(e){this._cfgEpochPreservedConfig=e,this._serverCfg=e}willUpdate(e){if(this._isoProjectionSnapshot=null,this._summary?.willUpdate(),e.has("hass")&&this._configReloadAuthority.observeContext(Vu(this)),e.has("_serverCfg")){const e=this._cfgEpochPreservedConfig===this._serverCfg;this._cfgEpochPreservedConfig=null,e||this._cfgEpoch++,this._renderLife.invalidate()}if(this._syncEmptySpaceState(),this._dangerConfirm&&(this._dangerConfirmMissingSpace()||"warm"===this._syncDangerConfirmLocaleGate())&&this._cancelDangerConfirm(),e.has("hass")&&this.hass){const t=this._visibleDeviceSnapshot||this._candidateDeviceSnapshot;this._renderLife.observe(e.get("hass"),this.hass,t?{entityIds:t.entityIds}:null,()=>Mg(this))}this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._continuity.refreshCompleteFrame(this._visualFrameFingerprint()),this._captureRenderDeviceSnapshot()}updated(){this._summary?.updated(),this._liveRt?.commit(),this._editorRuntime?._commitLiveEditor(),this._pruneDevicePressFeedback(),this._syncDayCycleClock(),this._syncRadarLive(),this._warmSnapshot(),this._editorRuntime&&this._dtMeasure();const e=this._stageEl;e&&!this._roViewport&&(this._roViewport=new ResizeObserver(()=>{this._invalidateDeviceHitGeometry(),this._refitView(),requestAnimationFrame(()=>this._summary?.resized())}),this._roViewport.observe(e)),e&&this._booting&&!this._bootTimer&&this._bootWatch();const t=this.renderRoot.querySelector(".hdr");if(t&&e&&!this._roHdr){const i=()=>{const t=ef(this.renderRoot,e,this.panelHost);null!==t&&(t>=0&&t!==this._hdrH&&(this._hdrH=t),t>=0&&!this._booting&&!this._config?.kiosk&&e.clientHeight>0&&this._warmPatch({hdrH:t,stageH:e.clientHeight}))};this._roHdr=new ResizeObserver(()=>requestAnimationFrame(i)),this._roHdr.observe(t),this._onWinResize=()=>requestAnimationFrame(i),window.addEventListener("resize",this._onWinResize),i()}if(e&&!this._view&&this._refitView(),this._editorSecondary?.afterRender(),this._settleContinuityFrame(),this._serverStorage&&this._loadOk&&this._canManageConfiguration&&0===this._model.length&&!this._spaceDialog&&!this._importDialog&&!this._onboardingShown){this._onboardingShown=!0;const e=function(e){const t=e?.floors;if(!t||"object"!=typeof t)return[];const i=[];for(const e of Object.values(t))e&&e.floor_id&&i.push({id:e.floor_id,name:e.name||e.floor_id,level:e.level??null});return i.sort((e,t)=>{const i=e.level??1e9,n=t.level??1e9;return i!==n?i-n:e.name.localeCompare(t.name)}),i}(this.hass);e.length?this._importDialog={floors:e.map(e=>({...e,checked:!0}))}:this._openSpaceDialog("create")}}_adoptConfigCapabilities(e){xg(this,e)}_syncRadarLive(){const e=this._serverCfg?.settings?.radar,t=(this._serverCfg?.markers||[]).some(e=>Cg(e,this._space));this._radarLive.sync(this._space,1===this._haRadarStage1Api&&"view"===this._mode&&!1!==e?.show_live&&t&&"hidden"!==this.ownerDocument.visibilityState)}async _syncDecorAssets(e){const t=++this._decorAssetSyncToken;if(1!==this._haDecorAssetsApi||!this.hass)return void(this._decorAssets=new Map);const i=await um(this.hass,cm(e),this._cfgRev);t===this._decorAssetSyncToken&&(this._decorAssets=i,this._resign(),this.requestUpdate())}_adoptAuthoritative(e){return ju(this,e)}_rollbackOptimistic(e){const t=this._adoption.rollbackOptimistic(e);return t&&this.requestUpdate(),t}_resumePendingNavMode(){if(!this._pendingNavMode||!this._canEdit||this._config?.kiosk)return!1;const e=this._pendingNavMode;return this._pendingNavMode=null,this._setMode(e,!1),!0}_getAuthoritativeConfig(){return e=this,async function(e,t){const i=await e();return t(i),i}(()=>e.hass.callWS({type:"houseplan/config/get"}),t=>xg(e,t));var e}async _loadFromServer(){this._loading=!0,this._loadTries++;const e=this._space,t=!!this._view;let i=!1;const n=()=>{i=!0,this._regSignature="",this._maybeRebuildDevices()};try{const[i,r]=await Promise.all([this._getAuthoritativeConfig(),this.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this._adoptAuthoritative({cfgResp:i,layResp:r,reason:"structural-response",profile:"reload",beforeAdopt:()=>{this._connectionWasLost=!1,this._serverStorage=!0},afterAdopt:()=>{this._warmVpArmed&&this._space===this._warmVp?.space?this._warmVpArmed=!1:t&&this._space===e||this._restoreZoom(),this._loadOk=!0,n()}})).status)return;this.hass.callWS({type:"houseplan/trail/get"}).then(e=>{this._vacSrvTrails=e?.trails||{},this.requestUpdate()}).catch(()=>{}),this._ensureLiveSyncSubscriptions()}catch(e){if(this._serverCfg)this._scheduleLoadRetry(!0);else if(this._loadTries>=8){this._serverStorage=!1;try{this._layout=JSON.parse(localStorage.getItem(lv)||"{}")||{}}catch{this._layout={}}}}finally{this._loading=!1,this._continuityDataReady=!0,i||n(),this.requestUpdate()}}_ensureLiveSyncSubscriptions(){const e=this.hass?.connection;if(!e)return;if(e!==this._liveSyncConnection&&(this._unsubCfg?.(),this._unsubCfg=null,this._unsubLayout?.(),this._unsubLayout=null,this._unsubTrail?.(),this._unsubTrail=void 0,this._unsubVirtual?.(),this._unsubVirtual=null,this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=e),this._liveSyncAttempt)return;const t=this._liveSyncGeneration,i=[],n=(n,r,o,s)=>{n()||i.push(async()=>{const i=await e.subscribeEvents(s,o);t===this._liveSyncGeneration&&this.isConnected&&this.hass?.connection===e&&!n()?r(i):i?.()})};if(n(()=>this._unsubCfg,e=>{this._unsubCfg=e},"houseplan_config_updated",e=>{const t=Number(e?.data?.rev??-1);t!==this._cfgRev&&this._reloadConfigOnly(!1,t)}),n(()=>this._unsubTrail,e=>{this._unsubTrail=e},"houseplan_trail_updated",async()=>{try{const e=await this.hass.callWS({type:"houseplan/trail/get"});this._vacSrvTrails=e?.trails||{},this.requestUpdate()}catch{}}),n(()=>this._unsubLayout,e=>{this._unsubLayout=e},"houseplan_layout_updated",e=>this._onLayoutEvent(Number(e?.data?.rev??-1))),n(()=>this._unsubVirtual,e=>{this._unsubVirtual=e},"houseplan_virtual_light_updated",e=>{const t=Wh(this._virtualLights,e?.data);t!==this._virtualLights&&(this._virtualLights=t,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}),!i.length)return;const r=function(e){return Promise.allSettled(e.map(e=>Promise.resolve().then(e)))}(i).then(()=>{});this._liveSyncAttempt=r,r.finally(()=>{this._liveSyncAttempt===r&&(this._liveSyncAttempt=null)})}async _reloadConfigOnly(e=!1,t){return Ku(this,e,t)}_scheduleLoadRetry(e=!1){if(void 0!==this._loadRetryTimer)return;const t=Math.min(8e3,500*2**Math.min(4,Math.max(1,this._loadTries-7)));this._loadRetryTimer=window.setTimeout(()=>{this._loadRetryTimer=void 0,!e&&this._loadOk||this._loading||!this.hass||this._loadFromServer()},t)}async _ensureLiveRuntime(){if(this._liveRt)return;const e=await import("./live-interaction-runtime-XyTIhKAA.js");this._liveRt=new e.LiveRuntime(this),this.isConnected&&this.requestUpdate()}_liveVp(e=!1){this._liveRt?this._liveRt.viewport(e):this.requestUpdate()}_syncLiveHover(){this._liveRt?this._liveRt.hover():this.requestUpdate()}_flushHa(){this._liveRt?.take()&&(this._terminalFrame=2,super.requestUpdate())}_ensureHaRegistryAuthority(){const e=this.hass?.connection||null;e&&e!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=e,this._haRegistryRev=-1,this._haBindingCacheKey="",this._renderLife.invalidate(),this._areaSnapshotCleanupCandidates.clear(),this._planHassMemo=null,this._haRegistryRelease=td(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}get _haRegistry(){return nd(this.hass)}get _planHass(){const e=this._haRegistry,t=od(this.hass,e),i=this._planHassMemo;if(i&&i.hass===this.hass&&i.sig===t)return i.active;const n=ad(this.hass,e),r=ld(this.hass,e);return this._planHassMemo={hass:this.hass,sig:t,active:n,full:r},n}_captureRenderDeviceSnapshot(){if(!this.hass)return;const e=Date.now(),t=[...this._activityRt.entries()].map(([t,i])=>`${t}:${i.gen}:${i.flashTs}:`+(i.flashKind&&(i.expiresAt||i.flashTs+tg)>e?1:0)).join("|"),i=Bh(this._virtualLights);if(this._capturedSnapshotSequence===this._hassSequence&&this._capturedSnapshotDevices===this._devices&&this._capturedSnapshotLayout===this._layout&&this._capturedSnapshotConfigEpoch===this._cfgEpoch&&this._capturedSnapshotVirtual===i&&this._capturedSnapshotActivity===t)return;const n=this._planHass,r=new Map,o=new Map,s=new Set(["sun.sun"]);for(const e of this._summary?.entityIds()||[])s.add(e);this._vacFit?.source&&s.add(this._vacFit.source);const a=new Set,l=new Set,c=e=>{if(!e)return;const t=e.indexOf(":");if(t<0)return void s.add(e);const i=e.slice(0,t),n=e.slice(t+1);"device"===i?a.add(n):"entity"===i&&s.add(n)};for(const e of this._model)for(const t of e.rooms)t.area&&l.add(t.area),c(t.settings?.temp_source),c(t.settings?.hum_source);for(const e of this._serverCfg?.spaces||[])for(const t of e.openings||[])for(const e of ui(t))s.add(e);for(const e of this._serverCfg?.spaces||[])for(const t of e.decor||[])if("text"===t.kind){for(const e of String(t.text||"").matchAll(/\{([^{}\r\n]+)\}/g)){const t=Xi(e[1]);t?.entity&&s.add(t.entity)}t.entity&&s.add(t.entity),o.set(`decor:${e.id}:${t.id}`,tn(t.text,t,n,e=>!!n.entities?.[e]&&!!n.states?.[e]&&!Jd(n,e,Zd(this._markers))))}const h=Ed(n,this._devices,null,this._virtualLights);for(const e of this._devices){for(const t of[!1,!0])r.set(f_(e.id,t),p_(n,e,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:t,activityRuntime:this._activityRt.get(e.id),sourceDetails:!1,lightDevices:this._devices,lightSources:h,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion}));if(this._isVacDev(e)){const t=this._vacSource(e,n),i=t?Wc(n?.states?.[t]?.attributes):null,r=this._vacRt.get(e.id),s=lh(e.id,e.marker?.vacuum??null,e.space,t),a=hh({routes:s,observed:dh(s,[t],t=>this._vacObservedMapId(e,t,n)),spaceIds:new Set(this._model.map(e=>e.id))});o.set(`vacuum:${e.id}`,{source:t,telemetry:i,routes:s,resolution:a,mapId:i?this._vacMapId(e,i,n):null,runtime:r?{trail:r.trail,lastTs:r.lastTs,moving:r.moving,jump:r.jump}:null,server:this._vacSrvTrails[e.id]||null})}}const d=g_({sourceSequence:this._hassSequence,hass:n,devices:this._devices,presentations:r,positions:(u=this._model.length>0,p=this._devices,_=e=>this._livePos(e),u?new Map(p.map(e=>[e.id,_(e)])):new Map),facts:o,entityIds:s,deviceIds:a,areaIds:l});var u,p,_;this._capturedSnapshotSequence=this._hassSequence,this._capturedSnapshotDevices=this._devices,this._capturedSnapshotLayout=this._layout,this._capturedSnapshotActivity=t,this._capturedSnapshotConfigEpoch=this._cfgEpoch,this._capturedSnapshotVirtual=i,this._visibleDeviceSnapshot&&"steady"!==this._continuity.state?this._candidateDeviceSnapshot=d:(this._visibleDeviceSnapshot=d,this._candidateDeviceSnapshot=null)}get _renderDeviceSnapshot(){return this._stagedDeviceSnapshotToken===this._continuity.token?this._candidateDeviceSnapshot||this._visibleDeviceSnapshot:this._visibleDeviceSnapshot||this._candidateDeviceSnapshot}get _renderPlanHass(){return this._renderDeviceSnapshot?.hass||this._planHass}get _renderDevices(){return this._renderDeviceSnapshot?.devices||this._devices}get _renderVacuumDevices(){return this._renderDeviceSnapshot?.vacuumDevices||this._devices}get _fullRegistryHass(){return this._planHass,this._planHassMemo?.full||this.hass}_bindingStatus(e){return dd(this.hass,e,this._haRegistry)}houseplanDiagnostics(){const{registry:e,bindings:t}=this._renderLife.diagnostics(this.hass,this._markers,e=>this._bindingStatus(e));return{registry:{...e,lastSuccessAgeMs:e.lastSuccess?Math.max(0,Date.now()-e.lastSuccess):null},bindings:t}}_openBindingInHa(e){const[t,i]=e.split(":");if(i)if("device"!==t){if("entity"===t){const e=this._fullRegistryHass.entities?.[i];e?.device_id&&fv("/config/devices/device/"+encodeURIComponent(e.device_id))}}else fv("/config/devices/device/"+encodeURIComponent(i))}_bindingHasHaPage(e){const[t,i]=e.split(":");return!!i&&("device"===t||"entity"===t&&!!this._fullRegistryHass.entities?.[i]?.device_id)}_toggleMarkerDialogVisibility(){const e=this._markerDialog;if(!e)return;const t="ha"===e.bindingMode?this._bindingStatus(e.binding):null,i=e.hideFromPlan||"ha_disabled"===t?.kind;i&&"ha_disabled"===t?.kind?this._showToast(this._t("entity"===t.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device")):i&&"unverified"===t?.kind?this._showToast(this._t("toast.ha_binding_unverified")):this._markerDialog={...e,hideFromPlan:!i}}_hookConnection(){const e=this.hass?.connection;e&&e!==this._connHooked&&(this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),e.addEventListener?.("ready",this._onConnReady),e.addEventListener?.("disconnected",this._onConnLost),e.addEventListener?.("reconnect-error",this._onConnLost),this._connHooked=e)}_display(e){return this._signer.display(this.hass,e)}_referencedContentUrls(){const e=Nn(this._serverCfg);for(const t of this._decorAssets.values())e.add(t.url);return e}_resign(){this._signer.resign(this.hass,this._referencedContentUrls())}_onLayoutEvent(e){e<=this._layoutRev||(clearTimeout(this._layoutSyncTimer),this._layoutSyncTimer=window.setTimeout(()=>{e<=this._layoutRev||this._reloadLayoutOnly()},200))}_noteLayoutRev(e){this._adoption.noteLayoutRevision(e?.rev)}async _reloadLayoutOnly(){if(!this._serverStorage||!this.hass?.callWS)return;this._beginContinuityCandidate("layout-reload",!1);const e=new Map;for(const t of this._dirtyPos)this._layout[t]&&e.set(t,this._layout[t]);this._persistLayout.pending()&&this._persistLayout.flush();for(const[t,i]of this._sentPos)e.set(t,i);try{const t=await this.hass.callWS({type:"houseplan/layout/get"}),i={...t?.layout||{}};for(const[t,n]of e)null===n?delete i[t]:i[t]=n;this._adoption.adoptMergedLayout(i,t,()=>{this._cancelDeviceDrag(),this._devicePositionHistory.clear()}),this._canOptimizeUndo=!!t?.can_optimize_undo,this._undoKind=t?.undo_kind||null,this._cacheSnapshot(),this.requestUpdate()}catch{}finally{this._continuityDataReady=!0,this.requestUpdate()}}_persistLocalLayout(){this._layout=So(lo(this._layout)),localStorage.setItem(lv,JSON.stringify(this._layout))}_maybeRebuildDevices(){const e=this.hass;if(!e?.devices||!e?.entities||!e?.areas)return;const t=this._haRegistry,i=od(e,t)+":"+Object.keys(e.areas).length+":"+(this._norm?"n":"l")+":"+kp(e,this._config?.language);if(i===this._regSignature&&this._devices.length)return;this._regSignature=i;const n=new Map(this._devices.map(e=>[e.id,e.bindingStatus?.kind||"active"]));this._devices=iu({hass:e,registry:t,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,showAll:this._showAll,firstSpaceId:this._model[0]?.id||"",loc:e=>this._t(e),iconRules:this._iconRules});const r=this._markers.filter(e=>!e.removed&&"virtual"!==e.binding).map(e=>e.binding).sort(),o=t.revision+":"+r.join("|");if(t.authoritative&&o!==this._haBindingCacheKey){const i=new Map;for(const n of r)i.set(n,dd(e,n,t));!function(e){if("undefined"==typeof localStorage||!e.size)return;const t=hd(),i=Date.now();for(const[n,r]of e)"active"===r.kind?t[n]={kind:"active",ts:i}:"ha_disabled"===r.kind&&(t[n]={kind:"ha_disabled",reason:r.reason,ts:i});const n=Object.fromEntries(Object.entries(t).sort((e,t)=>t[1].ts-e[1].ts).slice(0,1500));Yh=n;try{localStorage.setItem(Kh,JSON.stringify(n))}catch{}}(i),this._haBindingCacheKey=o}let s=null;if(t.authoritative&&(s=this._resolveAreaRelocations(t),this._areaRelocationIds=new Set(s.relocateIds),this._areaRelocationIds.size)){this._cancelDeviceDrag();const e=this._areaRelocationIds;this._devicePositionHistory.removeWhere(({before:t,after:i})=>e.has(t.deviceId)||e.has(i.deviceId));const t=this._markerDialog;if(t?.devId&&!t.roomTouched&&this._areaRelocationIds.has(t.devId)){const e=this._devices.find(e=>e.id===t.devId);e&&(this._markerDialog={...t,room:e.marker?.room_id?`${e.space}#@${e.marker.room_id}`:e.space&&e.area?`${e.space}#${e.area}`:""})}}this._defPos=this._defaultPositions(),this._syncNewDevices(),this._seedHiddenDevices(),s&&this._syncAreaRelocations(s),this._syncActivityRuntime();const a=new Set(this._devices.filter(e=>!e.hidden).map(e=>e.id));for(const e of this._vacRt.keys())a.has(e)||this._vacRt.delete(e);if(this._infoCard){const e=this._devices.find(e=>e.id===this._infoCard.id);this._infoCard=e&&"ha_disabled"!==e.bindingStatus?.kind?e:null}const l=this._devices.some(e=>"ha_disabled"===e.bindingStatus?.kind&&"ha_disabled"!==n.get(e.id));l&&("ha_disabled"!==this._infoCard?.bindingStatus?.kind&&"ha_disabled"!==this._devices.find(e=>e.id===this._infoCard?.id)?.bindingStatus?.kind||this._closeInfoCard(),this._deviceDrag&&"ha_disabled"===this._devices.find(e=>e.id===this._deviceDrag.id)?.bindingStatus?.kind&&(this._cancelDeviceDrag(),this._devicePositionHistory.clear()),clearTimeout(this._holdTimer),this._holdFired=!1,this._tip=null,this._tapConfirm=null),this._nativeMoreInfoEntity&&!this._planEntityAvailable(this._nativeMoreInfoEntity)&&(gv(this,"hass-more-info",{entityId:null}),this._nativeMoreInfoEntity=null)}_resolveAreaRelocations(e=this._haRegistry){const t=function(e){const t=Q_(e.snapshot),i=new Set(Object.values(t).map(e=>e.binding)),n=new Map;for(const[t,r]of e.previousCandidates||[])J_(t)&&Number.isFinite(r)&&i.has(t)&&n.set(t,r);const r=new Set,o=new Set;for(const t of e.markers||[])t.removed||(Z_(t.id)&&r.add(t.id),J_(t.binding)&&o.add(t.binding));const s=new Set(Object.keys(e.registryDevices||{})),a=new Set(Object.keys(e.registryEntities||{})),l=new Set(Object.keys(e.liveStates||{})),c=new Map;for(const[e,i]of Object.entries(t)){const t=c.get(i.binding)||[];t.push(e),c.set(i.binding,t)}const h=new Set;let d=!1;for(const[t,i]of c){const[c,u]=rm(t);if(o.has(t)||i.some(e=>r.has(e))||("device"===c?s.has(u):a.has(u)||l.has(u))){n.delete(t);continue}const p="device"===c?s.size>0:a.size>0;if(!e.authoritative||!p)continue;const _=n.get(t);if(void 0!==_){if(_!==e.revision)for(const e of i)h.add(e)}else n.set(t,e.revision),d=!0}return{removeIds:h,candidates:n,needsConfirmationRefresh:d}}({snapshot:this._settings.marker_area_snapshot,authoritative:e.authoritative,revision:e.revision,registryDevices:e.devices,registryEntities:e.entities,liveStates:this.hass?.states,markers:this._markers,previousCandidates:this._areaSnapshotCleanupCandidates});return this._areaSnapshotCleanupCandidates=t.candidates,t.needsConfirmationRefresh&&this._canEdit&&id(this.hass),om({devices:this._devices,model:this._model,layout:this._layout,snapshot:this._settings.marker_area_snapshot,authoritative:e.authoritative,cleanupSnapshotIds:t.removeIds,coordinateScale:_v})}_syncNewDevices(){if(!this._norm||!this._loadOk||!this._serverCfg)return;const e=this._devices.filter(e=>!e.marker&&!e.virtual).map(e=>e.id).sort(),t=e.join(",");if(t===this._newSyncKey)return;this._newSyncKey=t;const i=this._settings,{fresh:n,known:r}=function(e,t){if(!Array.isArray(t))return{fresh:[],known:[...e]};const i=new Set(t),n=e.filter(e=>!i.has(e));return{fresh:n,known:n.length?[...t,...n]:t}}(e,i.known_devices);if(!Array.isArray(i.known_devices)||n.length){const e=[...new Set([...i.new_device_ids||[],...n])];this._serverCfg={...this._serverCfg,settings:{...i,known_devices:r,new_device_ids:e}},this._saveConfig()}}_syncAreaRelocations(e){if(!(this._loadOk&&this._serverCfg&&this._norm&&this._canEdit&&this._haRegistry.authoritative))return;const t=e.decisions.filter(e=>e.updateSnapshot||e.removeSnapshot);if(!t.length)return;const i=cc({snapshot:Q_(this._settings.marker_area_snapshot),decisions:t});i!==this._areaRelocationSyncKey&&(this._areaRelocationSyncKey=i,this._areaRelocationWrite=this._areaRelocationWrite.catch(()=>{}).then(async()=>{if(!this._serverCfg||!this._haRegistry.authoritative)return;const e=this._resolveAreaRelocations();this._areaRelocationIds=new Set(e.relocateIds);const t=new Set,i=new Map;let n=!1;for(const r of e.decisions){if(!r.relocate)continue;const e=fg(this._layout,r.id);try{await this._persistDevicePlacement(r.id,null),t.add(r.id),e&&i.set(r.id,e),this._areaRelocationIds.delete(r.id)}catch(t){n=!0,this._layout=vg(this._layout,r.id,e),this._showToast(this._t("toast.pos_save_failed",{err:this._errText(t)}))}}const r=this._settings,o=function(e,t,i=new Set){const n=Q_(e);for(const e of t.decisions)e.removeSnapshot?delete n[e.id]:e.updateSnapshot&&e.binding&&e.area&&(e.relocate&&!i.has(e.id)||(n[e.id]={binding:e.binding,area:e.area}));return n}(r.marker_area_snapshot,e,t),s=[...new Set([...Array.isArray(r.new_device_ids)?r.new_device_ids:[],...t])],a=cc(o)!==cc(Q_(r.marker_area_snapshot)),l=cc(s)!==cc(Array.isArray(r.new_device_ids)?r.new_device_ids:[]);if(a||l){const e=r.marker_area_snapshot,n=r.new_device_ids,a={...this._serverCfg,settings:{...r,marker_area_snapshot:o,...l?{new_device_ids:s}:{}}};this._setAreaLifecycleConfig(a);try{this._saveConfigDebounced.pending()&&this._saveConfigDebounced.cancel(),await this._writeConfig()}catch(r){const a=this._settings;if(cc(a.marker_area_snapshot)===cc(o)&&cc(a.new_device_ids)===cc(l?s:n)){const t={...a};void 0===e?delete t.marker_area_snapshot:t.marker_area_snapshot=e,void 0===n?delete t.new_device_ids:t.new_device_ids=n;const i={...this._serverCfg,settings:t};this._setAreaLifecycleConfig(i),this._adoption.refreshConfigFingerprint()}for(const e of t)this._areaRelocationIds.add(e);const c=new Set;for(const[e,t]of i)try{await this._persistDevicePlacement(e,t)}catch(t){c.add(e),this._showToast(this._t("toast.pos_save_failed",{err:this._errText(t)}))}this._areaRelocationSyncKey="",this._regSignature="";if("conflict"===(r&&"object"==typeof r&&"code"in r?r.code:void 0)?(this._showToast(this._t("toast.conflict")),await this._reloadConfigOnly(!0)):this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(r)})),c.size&&this._serverCfg){const e=this._settings,t=[...new Set([...Array.isArray(e.new_device_ids)?e.new_device_ids:[],...c])],i={...this._serverCfg,settings:{...e,new_device_ids:t}};this._setAreaLifecycleConfig(i);try{await this._writeConfig()}catch(e){this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(e)}))}}}}n&&(this._areaRelocationSyncKey=""),this.requestUpdate()}))}get _newIds(){const e=this._settings.new_device_ids;return new Set([...Array.isArray(e)?e:[],...this._areaRelocationIds])}_ackNewDevice(e){if(!this._newIds.has(e)||!this._serverCfg)return;const t=this._settings;this._serverCfg={...this._serverCfg,settings:{...t,new_device_ids:(t.new_device_ids||[]).filter(t=>t!==e)}},this._saveConfig(),this.requestUpdate()}get _markers(){return this._serverCfg?.markers||[]}_roomLqi(e){if(!e)return null;const t=[];for(const i of this._renderDevices){if(i.area!==e||i.virtual)continue;const n=Ld(this._renderPlanHass,i.entities);null!=n&&t.push(n)}return Ii(t)}_roomBounds(e){if(e.poly&&e.poly.length){const t=e.poly.map(e=>e[0]),i=e.poly.map(e=>e[1]),n=Math.min(...t),r=Math.min(...i);return{x:n,y:r,w:Math.max(...t)-n,h:Math.max(...i)-r}}return{x:e.x??0,y:e.y??0,w:e.w??0,h:e.h??0}}_defaultPositions(){const e={},t=this._config?.icon_size??2.5;for(const i of this._model){const n=t/100*Ml(i)*1.3;for(const t of i.rooms){if(!t.area)continue;const r=this._devices.filter(e=>e.area===t.area&&e.space===i.id);if(!r.length)continue;const o=this._roomBounds(t),s=.1*Math.min(o.w,o.h),a=o.w-2*s,l=o.h-2*s,c=Math.max(1,Math.round(Math.sqrt(r.length*a/Math.max(l,1)))),h=Math.ceil(r.length/c),d=a/c,u=l/Math.max(h,1),p=r.map((e,t)=>({x:o.x+s+d*(t%c+.5),y:o.y+s+u*(Math.floor(t/c)+.5)}));Ei(p,o,n,.5*s),r.forEach((t,i)=>e[t.id]=al(p[i]))}}return e}_pos(e){const t=this._renderDeviceSnapshot?.positions.get(e.id);return t?{x:t.x,y:t.y}:this._livePos(e)}_livePos(e){const t=this._spaceModelById(e.space),i=this._areaRelocationIds.has(e.id)?void 0:this._layout[e.id];if(i)if(this._norm){if(i.s===e.space)return{x:i.x*_v,y:i.y*_v}}else if(void 0===i.s)return{x:i.x,y:i.y};return this._defPos[e.id]?this._defPos[e.id]:t?al($l(t)):{x:500,y:500}}_devicePlacementForCanvas(e,t,i){if(!this._norm)return{x:Math.round(t),y:Math.round(i)};const n=this._gridPitch,r=Math.round(t/n)*n,o=Math.round(i/n)*n;return{s:e.space,x:cl(r/_v),y:cl(o/_v)}}_previewDevicePlacement(e,t){this._layout=vg(this._layout,e,t),this.requestUpdate()}_cancelDeviceDrag(){const e=this._deviceDrag;if(!e)return!1;this._editorRuntime?._cancelPointerMove("device"),this._deviceDrag=null,this._deviceHits.cancel(e.pointerId);try{e.source?.hasPointerCapture?.(e.pointerId)&&e.source.releasePointerCapture(e.pointerId)}catch{}return this._previewDevicePlacement(e.id,e.before),!0}async _persistDevicePlacement(e,t){if(this._layout=vg(this._layout,e,t),this._serverStorage){let i=null,n=!1;try{let r;if(null===t)i=null,this._sentPos.set(e,i),n=!0,r=await this.hass.callWS({type:"houseplan/layout/delete",device_id:e});else{const t=xo(this._layout[e]);cc(t)!==cc(this._layout[e])&&(this._layout={...this._layout,[e]:t}),i=t,this._sentPos.set(e,i),n=!0,r=await this.hass.callWS({type:"houseplan/layout/update",device_id:e,pos:t})}this._noteLayoutRev(r),this._adoption.refreshLayoutFingerprint(),this._cacheSnapshot()}finally{n&&this._sentPos.get(e)===i&&this._sentPos.delete(e)}return}this._persistLocalLayout()}_devicePositionStateValid(e){const t=this._devices.find(t=>t.id===e.deviceId);return!!t&&t.space===e.spaceId&&"ha_disabled"!==t.bindingStatus?.kind&&!!this._spaceModelById(e.spaceId)}async _runDevicePositionHistory(e){if(this._cancelDeviceDrag()||this._devicePositionBusy)return;const t="undo"===e?this._devicePositionHistory.undo():this._devicePositionHistory.redo();if(!t)return;const i="undo"===e?t.before:t.after;if(!this._devicePositionStateValid(i))return this._devicePositionHistory.clear(),this._showToast(this._t("history.device_stale")),void this.requestUpdate();const n=fg(this._layout,i.deviceId);i.spaceId!==this._space&&(this._commitSpace(i.spaceId),this._restoreZoom()),this._devicePositionBusy=!0,this._previewDevicePlacement(i.deviceId,i.placement);try{await this._persistDevicePlacement(i.deviceId,i.placement),this._showToast(this._t("undo"===e?"history.undone":"history.redone",{name:t.name}))}catch(t){this._previewDevicePlacement(i.deviceId,n),"undo"===e?this._devicePositionHistory.redo():this._devicePositionHistory.undo(),this._showToast(this._t("toast.pos_save_failed",{err:this._errText(t)}))}finally{this._devicePositionBusy=!1,this.requestUpdate()}}_undoDevicePosition(){this._runDevicePositionHistory("undo")}_redoDevicePosition(){this._runDevicePositionHistory("redo")}_savePos(e,t,i){this._spaceModelById(e.space)&&(this._layout=vg(this._layout,e.id,this._devicePlacementForCanvas(e,t,i)),this._dirtyPos.add(e.id),this._persistLayout())}_devicePresentation(e,t=!1!==this._config?.show_signal,i=!1){const n=i?null:this._renderDeviceSnapshot?.presentations.get(f_(e.id,t));return n||p_(this._renderPlanHass,e,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:t,designPreview:i,activityRuntime:this._activityRt.get(e.id),sourceDetails:!1,lightDevices:this._renderDevices,registryHass:this._fullRegistryHass,reducedMotion:this._reducedMotion})}_deviceVisual(e){return this._devicePresentation(e).visual}_stateClass(e,t=this._deviceVisual(e)){const i=this._devicePresentation(e);return i.effectiveHidden?"":("icon_ripple"!==i.display||!1===this._config?.live_states||"alarm"===t.status||t.activity,u_({...i,visual:t}).join(" "))}_liveTemp(e){if(!this._config?.show_temperature)return null;if(!0===e.marker?.use_climate_temp){const t=qd(this._renderPlanHass,e.entities);if(null!=t)return t}return"mdi:thermometer"!==e.icon&&"mdi:air-filter"!==e.icon?null:Bd(this._renderPlanHass,e.entities)}_bindingEntities(e){if("virtual"===e||!e)return[];const t=this._bindingStatus(e);return"active"===t.kind?t.enabledEntityIds:t.allEntityIds}_bindingHasClimate(e){return this._bindingEntities(e).some(e=>e.startsWith("climate."))}_bindingHasAlarm(e){return this._bindingEntities(e).some(e=>{const t=this._planHass?.states?.[e]||this.hass?.states?.[e],i=this._fullRegistryHass.entities[e]||this.hass?.entities?.[e];return Yn(e.split(".")[0],t?.attributes?.device_class||i?.device_class||i?.original_device_class)})}_deviceBindingActive(e,t=!0){if(e.virtual||"virtual"===e.bindingKind)return!0;if(!e.bindingKind||!e.bindingRef)return!1;const i=this._bindingStatus(`${e.bindingKind}:${e.bindingRef}`);return"active"===i.kind||(t&&this._showToast(this._t("ha_disabled"===i.kind?"toast.ha_disabled_action":"toast.ha_binding_unverified")),!1)}_openMoreInfo(e){e?this._planEntityAvailable(e)?(this._kiosk&&(this._cyclePausedUntil=Math.max(this._cyclePausedUntil,Date.now()+6e4)),this._nativeMoreInfoEntity=e,gv(this,"hass-more-info",{entityId:e})):this._showToast(this._t("toast.ha_disabled_action")):this._showToast(this._t("toast.no_entity"))}_interruptViewGesture(e,t){if(clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),void 0!==e)for(const i of[t,this._stageEl])try{i?.hasPointerCapture?.(e)&&i.releasePointerCapture(e)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null,this._roomPointer=null,this._doubleFit.clear(),this._deviceHits.clearPointers()}_closeInfoCard(){this._interruptViewGesture(),this._holdFired=!1,this._infoCard=null}_invalidateDeviceHitGeometry(){this._deviceHits.invalidate()}_resetDeviceHitState(){this._deviceHits.reset(this.renderRoot)}_deviceHitOwnerAt(e,t){return"view"!==this._mode&&"devices"!==this._mode?null:this._deviceHits.at(this.renderRoot,this._renderDevices,this._space,e,t)}_deviceForPointerEvent(e,t){return this._deviceHits.pointer(this.renderRoot,this._renderDevices,this._space,e,t)}_deviceForClickEvent(e,t){return this._deviceHits.click(this.renderRoot,this._renderDevices,this._space,e,t)}_showDeviceTip(e,t){this._liveRt?this._liveRt.devicePointerTip(e,t):this._ensureLiveRuntime().then(()=>this._liveRt?.devicePointerTip(e,t))}_showDeviceFocusTip(e,t){const i=e.currentTarget;this._liveRt?this._liveRt.deviceFocusTip(i,t):this._ensureLiveRuntime().then(()=>this._liveRt?.deviceFocusTip(i,t))}_hideDeviceFocusTip(e){this._liveRt?.deviceBlur(e)}_clearPointerHover(){this._liveRt?this._liveRt.pointerLeave():this._clearTransientHover()}_ctxDevice(e,t){"view"===this._mode&&(t=this._deviceForPointerEvent(e,t),e.preventDefault(),e.stopPropagation(),this._deviceBindingActive(t)&&(t.primary?this._openMoreInfo(t.primary):this._infoCard=t))}_clickDevice(e,t){if("view"!==this._mode&&"devices"!==this._mode)return;if(e.stopPropagation(),t=this._deviceForClickEvent(e,t),this._deviceDrag?.moved||this._suppressClick||this._holdFired)return;if("devices"===this._mode)return void this._openMarkerDialog(t);const i=this._devices.find(e=>e.id===t.id);if(!i)return;const n=Tu(i.tapAction,i.primary?.split(".")[0]);if("none"===n)return;const r=(e,t)=>{i.marker?.tap_confirm?this._tapConfirm={kind:"run",text:e,exec:t}:t()};if("toggle"===n){const e=this._toggleIntent(i);if(!e)return;if(!Iu(e))return void this._showUnavailableToggleTargets(e);const t=e=>{const t=Iu(e);if(!t)return;if("virtual-light"===t.kind)return this._startDevicePressFeedback(i.id),void this.hass.callWS({type:"houseplan/virtual_light/toggle",marker_id:t.markerId}).then(e=>{const t=Wh(this._virtualLights,e);t!==this._virtualLights&&(this._virtualLights=t,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}).catch(e=>this._showToast(this._t("toast.virtual_light_toggle_failed",{err:this._errText(e)})));const{command:n}=t;this._startDevicePressFeedback(i.id),this.hass.callService(n.domain,n.service,n.data).catch(e=>this._showToast(this._t("toast.error",{err:this._errText(e)})))},n=((o=e).targets.length?o.targets:o.skippedTargets).map(e=>e.name||e.entityId||e.ref).join(", ")||i.name;if(i.marker?.tap_confirm){const r=this._toggleConfirmationLines(e);if(!r.length)return;this._tapConfirm={kind:"toggle",text:this._t("confirm.tap_toggle",{name:n}),lines:r,initialIntent:e,deviceId:i.id,exec:()=>{const n=this._devices.find(e=>e.id===i.id),r=n?this._toggleIntent(n):null;r&&!Iu(r)&&this._showUnavailableToggleTargets(r)||(r&&Eu(e,r)?t(r):this._showToast(this._t("toast.tap_target_changed")))}}}else t(e);return}var o;if("info"===n)return this._interruptViewGesture(),void(this._infoCard=i);if(this._deviceBindingActive(i)){if("run"===n){const e=i.marker?.tap_target||"",t=function(e){const t=String(e||"").split(".")[0];return"automation"===t?{domain:"automation",service:"trigger"}:"script"===t?{domain:"script",service:"turn_on"}:"scene"===t?{domain:"scene",service:"turn_on"}:null}(e),n=this.hass.states[e];if(!t||!n)return void this._showToast(this._t("toast.run_target_missing"));const o=n.attributes?.friendly_name||e;return void r(this._t("confirm.tap_run",{name:o}),()=>{this._deviceBindingActive(i)&&this._planEntityAvailable(e)&&(this._startDevicePressFeedback(i.id),this.hass.callService(t.domain,t.service,{entity_id:e}).then(()=>{this._stampActivity(i.id,"event",this._activitySourceKey(i)),this.requestUpdate(),this._showToast(this._t("toast.run_started",{name:o}))}).catch(e=>this._showToast(this._t("toast.error",{err:this._errText(e)}))))})}"more-info"===n&&i.primary?this._openMoreInfo(i.primary):this._infoCard=i}}_showUnavailableToggleTargets(e){const t=function(e){if(!e||"group"!==e.kind||Iu(e)||"configured-targets-missing"!==e.noneReason)return[];if(!e.skippedTargets.length||e.skippedTargets.some(e=>!Ou.has(e.reason)&&"secure"!==e.reason))return[];const t=[],i=new Set;for(const n of e.skippedTargets){if(!Ou.has(n.reason))continue;const e=String(n.name||n.entityId||n.ref||"").trim();e&&!i.has(e)&&(i.add(e),t.push(e))}return t}(e);return!!t.length&&(this._showToast(1===t.length?this._t("toast.toggle_target_unavailable",{name:t[0]}):this._t("toast.toggle_targets_unavailable",{names:t.join(", ")})),!0)}_keyDevice(e,t){"Enter"!==e.key&&" "!==e.key||"view"!==this._mode&&"devices"!==this._mode||(e.preventDefault(),this._clickDevice(e,t))}_startDevicePressFeedback(e){const t=[...this.renderRoot.querySelectorAll(".dev[data-id]")].find(t=>t.dataset.id===e),i=t?.querySelector(".device-shell");if(!i||"function"!=typeof i.animate)return;const n=Number.parseFloat(this.ownerDocument.defaultView?.getComputedStyle(i).scale||""),r=Number.isFinite(n)?Math.max(.95,Math.min(1,n)):1;this._devicePressAnimations.get(e)?.cancel();const o=this._reducedMotion?[{outlineColor:"transparent",outlineStyle:"solid",outlineWidth:"0px"},{outlineColor:"var(--hp-accent, #3ea6ff)",outlineStyle:"solid",outlineWidth:"2px",outlineOffset:"2px",offset:.5},{outlineColor:"transparent",outlineStyle:"solid",outlineWidth:"0px"}]:[{scale:String(r)},{scale:"0.95",offset:.5},{scale:"1"}],s=i.animate(o,{duration:200,easing:"cubic-bezier(.22,.61,.36,1)"});this._devicePressAnimations.set(e,s);const a=()=>{this._devicePressAnimations.get(e)===s&&this._devicePressAnimations.delete(e)};s.addEventListener("finish",a,{once:!0}),s.addEventListener("cancel",a,{once:!0})}_cancelDevicePressFeedback(){for(const e of this._devicePressAnimations.values())e.cancel();this._devicePressAnimations.clear()}_pruneDevicePressFeedback(){if(!this._devicePressAnimations.size)return;const e=new Set([...this.renderRoot.querySelectorAll(".dev[data-id]")].map(e=>e.dataset.id||""));for(const[t,i]of this._devicePressAnimations)e.has(t)||(i.cancel(),this._devicePressAnimations.delete(t))}_t(e,t){return xp(kp(this.hass,this._config?.language),e,t)}get _colorPickerLabels(){return{title:this._t("color_picker.title"),hue:this._t("color_picker.hue"),saturation:this._t("color_picker.saturation"),value:this._t("color_picker.value"),hex:this._t("color_picker.hex"),invalidHex:this._t("color_picker.invalid_hex"),confirm:this._t("color_picker.confirm")}}_help(e){return this._editorRuntimeOrThrow()._help(e)}get _stageEl(){return this.renderRoot.querySelector(".stage")}_contentItems(e){const t=[];for(const i of this._devices){if(i.space!==e.id||i.hidden)continue;const n=this._pos(i);t.push({minX:n.x,minY:n.y,maxX:n.x,maxY:n.y})}if(e.id===this._space){for(const e of this._openingsR){const i=Number(e.angle)*Math.PI/180,n=Math.cos(i)*e.rlen/2,r=Math.sin(i)*e.rlen/2,o=pl([[e.rx-n,e.ry-r],[e.rx+n,e.ry+r]]);o&&t.push(o)}const i=this._decorH;for(const e of this._decorList){if("image"===e.kind&&!this._decorAssets.has(e.asset_id)&&"decor"!==this._mode)continue;const n=pl("line"===e.kind?[[e.x1*_v,e.y1*i],[e.x2*_v,e.y2*i]]:"text"===e.kind?[[e.x*_v,e.y*i]]:Nr({x:e.x*_v,y:e.y*i,w:e.w*_v,h:e.h*i,angle:e.angle}));n&&t.push(n)}for(const i of this._physicalBodiesR(e)){const e=pl(i);e&&t.push(e)}}return vl(e,t)}_frameOf(){const e=this._spaceModel();if(!e){this._frame=null;const e={x:0,y:0,w:_v,h:_v};return{rect:e,all:e,outliers:0}}const t=this._frame,i="view"!==this._mode;if(t&&t.id===e.id&&this._bdDrag)return t;if(t&&t.id===e.id&&t.model===e&&t.layout===this._layout&&t.devs===this._devices&&t.far===this._showFar&&t.grow===i)return t;const n=kl(this._contentItems(e));let r=n.all||Sl(e),o=this._showFar?r:n.core||Sl(e);return t&&t.id===e.id&&i&&t.grow&&(o=mv(t.rect,o),r=mv(t.all,r)),this._frame={id:e.id,model:e,layout:this._layout,devs:this._devices,far:this._showFar,grow:i,rect:o,all:r,outliers:n.outliers},this._frame}_isoSource(){const e=this._isoSceneRuntime;if(!e)return null;const t=this._spaceModel();if(!t)return null;const i=this._spaceWalls,n=this._openCuts(),r=this._openingsR;return e.createIsoStructuralSource({space:t,walls:i,openCuts:n,openings:r,partitionCuts:()=>this._partitionOpeningCuts(t),roomOpenings:()=>this._roomWallOpeningInputs(r,t),cellCm:this._cellCm,gridPitch:this._gridPitch,wallKeyPitch:this._wallKeyPitch,coordinateScale:_v,onBuild:()=>{this._isoStructuralBuildCount+=1}})}_isoSceneKey(){if(!this._labsIso||"view"!==this._mode)return null;try{return this._isoSource()?.key??null}catch{return this._isoInvalidKey()}}_isoInvalidKey(){return`${this._space}|invalid|${this._cfgEpoch}`}_clearIsoInvalidFallback(e){const t=`${this._space}|invalid|`;for(const i of this._isoFallback)i.startsWith(t)&&i!==e&&this._isoFallback.delete(i)}_isoScene(e=this._isoSource()){const t=this._isoSceneRuntime;if(!t||!e)return null;let i=this._frameOf().rect;const n=this._spaceDisplayForRender(),r=this._spaceModel();if(r&&n.showNames)for(const e of r.rooms)if(e.name){const t=this._labelPos(e,r.id);i=mv(i,{x:t.x,y:t.y,w:0,h:0})}const o=t.resolveIsoScene({source:e,cache:this._isoGeometryCache,cellCm:this._cellCm,liveFrame:i});if(!r||!n.showBorders)return o;const s=this._config?.icon_size??2.5,a=s>8?2.5:s,l=this._stageEl?.getBoundingClientRect?.()??null,c=l?.height?l.width/l.height:o.frame.w/o.frame.h,h=Oi([o.frame.x,o.frame.y,o.frame.w,o.frame.h],c),d=this._isoOverlayScene(r,this._renderDevices.filter(e=>e.space===r.id&&!e.hidden),h,n,t.resolveIsoDecorationLayers(n),o,a,x_(a),n.showLqi??this._config?.show_signal??!0,!1),u=d&&t.resolveIsoOverlayFitEnvelope({baseBounds:o.frame,entries:d.entries,stageSize:l,targetView:e=>Oi([e.x,e.y,e.w,e.h],c)});return u?{...o,frame:u.bounds,overlayFitEntries:d.entries}:o}_latchIsoFallback(e,t){if(this._isoFallback.has(e))return;this._isoFallback.add(e);const i=e.includes("|invalid|")?"invalid":e.split("|").pop()||"invalid";console.warn("HOUSEPLAN ISO FALLBACK: #89/#160",wf("structural",i,!0))}_effectiveProjection(){if(this._isoProjectionSnapshot)return this._isoProjectionSnapshot;const e=e=>this._isoProjectionSnapshot=e,t=()=>("iso"===this._renderProjection&&(this._cancelCameraTransition(!1),this._view=null,this._viewModeSnap=null),e("flat"));if(this._renderIsoScene=null,"iso"!==this._desiredProjection||!this._model.length||!this._isoSceneRuntime)return e("flat");if(!this._spaceDisplayForRender().showBorders)return this._isoFallback.has(`${this._space}|no-borders`)?t():e("iso");let i=this._isoInvalidKey();if(this._clearIsoInvalidFallback(i),this._isoFallback.has(i))return t();try{const n=this._isoSource();if(!n)return e("flat");if(i=n.key,this._isoFallback.has(i))return t();const r=this._isoScene(n);return r?this._isoFallback.has(r.key)?t():(this._renderIsoScene=r,e("iso")):e("flat")}catch(e){return this._latchIsoFallback(i,e),t()}}_scenePoint(e){return"iso"===this._renderProjection?lf(e,0):e}_floorView(e){if("iso"!==this._renderProjection)return e;const t=cf([e.x,e.y]),i=cf([e.x+e.w,e.y+e.h]);return{x:t[0],y:t[1],w:i[0]-t[0],h:i[1]-t[1]}}_isoOverlayScene(e,t,i,n,r,o,s,a,l,c=!0){const h=this._isoSceneRuntime;return h&&r?.structural&&o?h.buildIsoOverlayRenderScene({space:e,devices:t,openings:this._openingsR,view:i,display:n,wallSilhouettes:o.wallSilhouettes,resolveCollisions:c,iconPct:s,deviceBasePct:a,showLqi:l,cellCm:this._cellCm,kioskIconScale:"view"===this._mode?this._kioskScale.icon:1,kioskFontScale:"view"===this._mode?this._kioskScale.font:1,stageSize:this._stageEl?.getBoundingClientRect?.(),positionOf:e=>this._pos(e),presentationOf:(e,t)=>this._devicePresentation(e,t),labelPositionOf:(e,t)=>this._labelPos(e,t),labelScaleOf:e=>this._labelScale(e),openingEntityAvailable:e=>this._renderOpeningEntityAvailable(e),openingWallIndex:()=>this._openingWallIndexFor(e,this._openCuts()).value}):null}_baseVb(e=this._effectiveProjection(),t=this._renderIsoScene){if("iso"===e){if(!this._spaceDisplayForRender().showBorders){const e=uf({rect:this._frameOf().rect,wallHeight:0});return[e.x,e.y,e.w,e.h]}const e=t?.frame??this._frameOf().rect;return[e.x,e.y,e.w,e.h]}const i=this._frameOf().rect;return[i.x,i.y,i.w,i.h]}get _outliers(){return this._showFar?0:this._frameOf().outliers}_fitFar(){this._clearRoomFocus(),this._showFar=!0,this._frame=null,this.requestUpdate(),this._resetZoom()}_clearRoomFocus(e=!1){this._doubleFit.clear(),this._roomFocus=null,e&&(this._roomPointer=null)}_roomFitBounds(e,t){const i=ni(e);if(!i||!e.id)return null;const n=this._spaceWalls,r=this._openCuts(),o=this._wallUnionGeometry(),s=n.length&&this._innerRoomContour(t,e.id,r,o?.roomGeom,o?.multiWallNodes)||i,a=this._spaceDisplayForRender();let l=[];if(a.showBorders&&n.length){const i=Fs(t.rooms,e.id,n,r,this._wallKeyPitch,this._cellCm,this._gridPitch,_v);i&&(l=aa(i.poly,i.offsets,o?.multiWallNodes)||i.poly)}const c=this._effectiveProjection();return function(e){const t=e.floor,i=e.wall||[],n=e.padding??0;if(!t.length||!t.every(vf)||!i.every(vf)||!Number.isFinite(n)||n<0)return null;if("flat"===e.projection)return bf([...t,...i],n);const r=e.wallHeight??0,o=e.floorDepth??0;if(!Number.isFinite(r)||r<0||!Number.isFinite(o)||o<0)return null;try{const e=[];for(const i of t){const t=[i[0],i[1]];e.push(lf(t,0)),o>0&&e.push(lf(t,-o))}for(const t of i){const i=[t[0],t[1]];e.push(lf(i,0)),r>0&&e.push(lf(i,r))}return bf(e,n)}catch{return null}}({floor:s,wall:l,projection:c,wallHeight:"iso"===c&&a.showBorders?Wa(84,this._cellCm):0,floorDepth:"iso"===c&&a.showBorders?Wa(10,this._cellCm):0,padding:a.showBorders?Wa(1.25,this._cellCm):0})}_fitRoom(e,t=!0){if("view"!==this._mode)return!1;this._doubleFit.clear();const i=this._spaceModel(),n=i?.rooms.find(t=>t.id===e);if(!i||!n)return this._clearRoomFocus(),!1;let r=this._roomFitBounds(n,i);if(!r)return this._clearRoomFocus(),!1;this._roomFocus={spaceId:i.id,roomId:e};const o=this._stageEl;if(!o||o.clientWidth<=0||o.clientHeight<=0)return!0;const s=Oi(this._baseVb(),o.clientWidth/o.clientHeight),a=e=>function(e){const t=e.safeFraction??.8,{bounds:i,baseFit:n,stageWidth:r,stageHeight:o,minZoom:s,maxZoom:a}=e;if(!yf(i)||!yf(n)||!Number.isFinite(r)||r<=0||!Number.isFinite(o)||o<=0||!Number.isFinite(s)||s<=0||!Number.isFinite(a)||a1)return null;const l=r/o,c=Math.max(i.w/t,i.h/t*l);if(!Number.isFinite(c)||c<=0)return null;const h=Math.min(a,Math.max(s,n.w/c)),d=n.w/h,u=d/l;return{zoom:h,viewBox:{x:i.x+i.w/2-d/2,y:i.y+i.h/2-u/2,w:d,h:u}}}({bounds:e,baseFit:s,stageWidth:o.clientWidth,stageHeight:o.clientHeight,minZoom:wv.ZOOM_MIN,maxZoom:wv.ZOOM_MAX});let l=a(r);const c=this._isoSceneRuntime,h=this._renderIsoScene?.overlayFitEntries;if(l&&"iso"===this._effectiveProjection()&&c&&h?.length){const e=c.resolveIsoOverlayFitEnvelope({baseBounds:r,entries:h,ownerId:n.id,stageSize:{width:o.clientWidth,height:o.clientHeight},targetView:e=>a(e)?.viewBox??null});e&&(r=e.bounds,l=a(r))}if(!l)return this._clearRoomFocus(),!1;const d=this._cameraState(),u=function(e,t,i,n){const r=[e,t,i,n],o=Math.min(...r.map(e=>e.x)),s=Math.min(...r.map(e=>e.y));return{x:o,y:s,w:Math.max(...r.map(e=>e.x+e.w))-o,h:Math.max(...r.map(e=>e.y+e.h))-s}}(s,d.viewBox,l.viewBox,r);return l.viewBox=this._clampView(l.viewBox,u),t?(this._prepareCameraCommand(),this._startCameraTransition(l,u,"room",220),!0):(this._cancelCameraTransition(!1),Xg(d,l)||(this._zoom=l.zoom,this._view={...l.viewBox},this.requestUpdate()),!0)}_fitAll(e="fit"){this._clearRoomFocus(),this._showFar=!0,this._frame=null,this.requestUpdate(),this._resetZoom(e)}_renderFarHint(){return this._kiosk||"view"!==this._mode||this._booting||!this._outliers?G:j`
    ${this._t("canvas.far_objects",{n:this._outliers})} @@ -816,7 +816,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${this._renderOpeningLocks(S,R?.locks)} ${g.showNames||this._markup?a.rooms.map(e=>this._renderRoomLabel(e,a,S,g,R?.rooms.get(e))):G} ${this._markup?a.rooms.map(e=>this._renderRoomGear(e,a,S)):G} - ${q={hass:this.hass,settings:this._settings,devices:this._renderDevices,registry:this._haRegistry,currentSpace:a.id,spaces:this._serverCfg?.spaces,viewKey:S,view:"view"===this._mode,kiosk:this._kiosk},q.view&&!q.kiosk&&!0===q.hass?.user?.is_admin&&zg(q.settings).enabled?(import("./hp-zigbee-topology-overlay-jGSF0zVB.js"),j``):G}
    @@ -1105,4 +1105,4 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc 45% · ${this._t("roomcard.light_partial",{on:1,total:3})} -
    `}_renderRoomDialog(){return this._editorRuntimeOrThrow()._renderRoomDialog()}}wv.properties={_tabDrag:{state:!0},_hdrH:{state:!0},_booting:{state:!0},_bootFading:{state:!0},_bootSoft:{state:!0},_continuityEpoch:{state:!0},_editorRuntimeLoadingVisible:{state:!0},_backdropGuard:{state:!0},_tapConfirm:{state:!0},_dangerConfirm:{state:!0},hass:{attribute:!1},panelHost:{type:Boolean,attribute:"panel-host",reflect:!0},narrow:{attribute:!1},_config:{state:!0},_space:{state:!0},_devices:{state:!0},_selId:{state:!0},_toast:{state:!0},_mode:{state:!0},_tool:{state:!0},_wallDialog:{state:!0},_drawWallField:{state:!0},_activeWallChainId:{state:!0},_physicalSel:{state:!0},_physicalDialog:{state:!0},_partitionDeleteDialog:{state:!0},_roomDeleteDialog:{state:!0},_physicalDrag:{state:!0},_physicalRotate:{state:!0},_duplicateColumnId:{state:!0},_opMeasure:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingPreset:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorEraseConfirm:{state:!0},_decorTextDialog:{state:!0},_decorShapeDialog:{state:!0},_backdropDialog:{state:!0},_furnPalette:{state:!0},_decorImagePalette:{state:!0},_decorAssetCatalog:{state:!0},_decorAssetBusy:{state:!0},_furnCategory:{state:!0},_furnPreviewInput:{state:!0},_bdDrag:{state:!0},_dtBox:{state:!0},_dtDrag:{state:!0},_kioskDialog:{state:!0},_vacFit:{state:!0},_vacAllCamerasFor:{state:!0},_vacCalConfirm:{state:!0},_kioskDots:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_roomEditId:{state:!0},_roomFill:{state:!0},_roomCustomFill:{state:!0},_roomTempMin:{state:!0},_roomTempMax:{state:!0},_roomTempSrc:{state:!0},_roomHumSrc:{state:!0},_roomSrcOpen:{state:!0},_roomSrcFilter:{state:!0},_roomNameScale:{state:!0},_roomLabelScale:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_deviceInbox:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_pdfDialog:{state:!0},_supportDialog:{state:!0},_alignDialog:{state:!0},_preflightClipboardFallback:{state:!0},_backupExportDialog:{state:!0},_backupImportDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0}},wv.ZOOM_MAX=8,wv.ZOOM_MIN=1/3,wv.styles=[ap,mg],customElements.get("houseplan-card")||customElements.define("houseplan-card",wv),window.customCards=window.customCards||[],window.customCards.find(e=>"houseplan-card"===e.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info(`%c HOUSEPLAN-CARD %c v${iv} `,"background:#3ea6ff;color:#04121f;font-weight:700","");export{T_ as $,G as A,Li as B,Ep as C,Hi as D,U as E,Ni as F,xd as G,si as H,ol as I,nl as J,ni as K,Ju as L,sp as M,zs as N,Ro as O,rp as P,Xu as Q,is as R,Os as S,ji as T,Qu as U,la as V,da as W,Oo as X,Mo as Y,Bo as Z,C_ as _,lh as a,oi as a$,Ss as a0,ao as a1,Zo as a2,_i as a3,Yo as a4,ko as a5,So as a6,no as a7,N_ as a8,Ka as a9,Kt as aA,ap as aB,xp as aC,Zp as aD,v_ as aE,b_ as aF,zp as aG,k_ as aH,Fg as aI,wi as aJ,Ur as aK,$i as aL,Mi as aM,Ut as aN,Ci as aO,q_ as aP,Ll as aQ,cl as aR,Vl as aS,Wl as aT,gs as aU,Ps as aV,ia as aW,Ls as aX,Zd as aY,Jd as aZ,ti as a_,Qo as aa,rl as ab,Xo as ac,Xa as ad,Za as ae,nn as af,rn as ag,Xi as ah,Zi as ai,el as aj,Fs as ak,cc as al,zg as am,xr as an,fn as ao,Cc as ap,Ui as aq,le as ar,W as as,sa as at,Ao as au,Fo as av,Po as aw,Wa as ax,o as ay,he as az,ih as b,Pr as b$,zn as b0,Vn as b1,pm as b2,Fr as b3,dm as b4,El as b5,ql as b6,tc as b7,tl as b8,ic as b9,$o as bA,Hu as bB,W_ as bC,yi as bD,mi as bE,Fi as bF,Ha as bG,Ma as bH,$a as bI,es as bJ,ts as bK,ra as bL,Rl as bM,Oa as bN,Ia as bO,Zn as bP,Jn as bQ,ki as bR,bs as bS,ys as bT,U_ as bU,G_ as bV,Hr as bW,jr as bX,qr as bY,zr as bZ,Dr as b_,Yl as ba,ws as bb,oa as bc,os as bd,fa as be,Ba as bf,L_ as bg,ya as bh,Is as bi,gn as bj,br as bk,kr as bl,wr as bm,yr as bn,mn as bo,Oe as bp,Sp as bq,lf as br,Io as bs,ll as bt,Qt as bu,ei as bv,Gr as bw,ba as bx,kc as by,H_ as bz,j as c,Ec as c$,Er as c0,Un as c1,Tr as c2,Ar as c3,Jl as c4,Lr as c5,Ql as c6,Kl as c7,jl as c8,ec as c9,em as cA,xo as cB,Xd as cC,Vd as cD,dn as cE,hn as cF,Ga as cG,I_ as cH,cn as cI,ln as cJ,an as cK,sn as cL,Ua as cM,Sc as cN,xc as cO,ev as cP,X_ as cQ,j_ as cR,Or as cS,Ig as cT,uo as cU,Ee as cV,qe as cW,Ne as cX,Wc as cY,Yc as cZ,rh as c_,Xl as ca,Zl as cb,sm as cc,ns as cd,Rp as ce,np as cf,Yf as cg,ip as ch,pa as ci,Wf as cj,Xf as ck,D_ as cl,li as cm,ep as cn,op as co,Di as cp,fi as cq,ai as cr,vi as cs,rs as ct,zi as cu,Cn as cv,Tu as cw,Vi as cx,qn as cy,Kd as cz,Rc as d,ua as d$,Xc as d0,Uc as d1,Gc as d2,nh as d3,eh as d4,Fc as d5,Dc as d6,jn as d7,Ac as d8,Wn as d9,il as dA,Ol as dB,Va as dC,$c as dD,Mc as dE,Wi as dF,Pc as dG,tf as dH,nf as dI,$p as dJ,of as dK,cf as dL,Ml as dM,rf as dN,sf as dO,Da as dP,Js as dQ,Mp as dR,Ri as dS,y_ as dT,$f as dU,Mf as dV,uf as dW,w_ as dX,ja as dY,Wr as dZ,Ea as d_,ci as da,Uf as db,Pp as dc,jf as dd,Tl as de,Es as df,ds as dg,us as dh,Ie as di,lu as dj,Kp as dk,Yp as dl,nu as dm,Nu as dn,Nd as dp,Ed as dq,Fd as dr,Pn as ds,kd as dt,Yd as du,Tn as dv,Co as dw,pi as dx,eu as dy,iu as dz,pe as e,Ir as e0,Nr as e1,Na as e2,Pl as e3,V_ as e4,La as e5,hm as e6,wp as e7,dp as e8,gp as e9,up as ea,Jt as eb,kg as ec,K_ as ed,Ji as ee,Qi as ef,Wt as eg,wv as eh,th as f,Rg as g,_n as h,_e as i,p_ as j,Vp as k,kp as l,Op as m,sh as n,dh as o,zd as p,Id as q,hh as r,on as s,$d as t,Md as u,Gp as v,Su as w,Xn as x,Bi as y,qi as z}; + `}_renderRoomDialog(){return this._editorRuntimeOrThrow()._renderRoomDialog()}}wv.properties={_tabDrag:{state:!0},_hdrH:{state:!0},_booting:{state:!0},_bootFading:{state:!0},_bootSoft:{state:!0},_continuityEpoch:{state:!0},_editorRuntimeLoadingVisible:{state:!0},_backdropGuard:{state:!0},_tapConfirm:{state:!0},_dangerConfirm:{state:!0},hass:{attribute:!1},panelHost:{type:Boolean,attribute:"panel-host",reflect:!0},narrow:{attribute:!1},_config:{state:!0},_space:{state:!0},_devices:{state:!0},_selId:{state:!0},_toast:{state:!0},_mode:{state:!0},_tool:{state:!0},_wallDialog:{state:!0},_drawWallField:{state:!0},_activeWallChainId:{state:!0},_physicalSel:{state:!0},_physicalDialog:{state:!0},_partitionDeleteDialog:{state:!0},_roomDeleteDialog:{state:!0},_physicalDrag:{state:!0},_physicalRotate:{state:!0},_duplicateColumnId:{state:!0},_opMeasure:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingPreset:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorEraseConfirm:{state:!0},_decorTextDialog:{state:!0},_decorShapeDialog:{state:!0},_backdropDialog:{state:!0},_furnPalette:{state:!0},_decorImagePalette:{state:!0},_decorAssetCatalog:{state:!0},_decorAssetBusy:{state:!0},_furnCategory:{state:!0},_furnPreviewInput:{state:!0},_bdDrag:{state:!0},_dtBox:{state:!0},_dtDrag:{state:!0},_kioskDialog:{state:!0},_vacFit:{state:!0},_vacAllCamerasFor:{state:!0},_vacCalConfirm:{state:!0},_kioskDots:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_roomEditId:{state:!0},_roomFill:{state:!0},_roomCustomFill:{state:!0},_roomTempMin:{state:!0},_roomTempMax:{state:!0},_roomTempSrc:{state:!0},_roomHumSrc:{state:!0},_roomSrcOpen:{state:!0},_roomSrcFilter:{state:!0},_roomNameScale:{state:!0},_roomLabelScale:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_deviceInbox:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_pdfDialog:{state:!0},_supportDialog:{state:!0},_alignDialog:{state:!0},_preflightClipboardFallback:{state:!0},_backupExportDialog:{state:!0},_backupImportDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0}},wv.ZOOM_MAX=8,wv.ZOOM_MIN=1/3,wv.styles=[ap,mg],customElements.get("houseplan-card")||customElements.define("houseplan-card",wv),window.customCards=window.customCards||[],window.customCards.find(e=>"houseplan-card"===e.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info(`%c HOUSEPLAN-CARD %c v${iv} `,"background:#3ea6ff;color:#04121f;font-weight:700","");export{Ss as $,G as A,Ep as B,Ni as C,Hi as D,U as E,xd as F,si as G,ol as H,nl as I,ni as J,Ju as K,sp as L,zs as M,Ro as N,rp as O,Xu as P,is as Q,Os as R,Qu as S,ji as T,la as U,da as V,Oo as W,Mo as X,Bo as Y,C_ as Z,T_ as _,lh as a,oi as a$,ao as a0,Zo as a1,_i as a2,Yo as a3,ko as a4,So as a5,no as a6,N_ as a7,Ka as a8,Qo as a9,Kt as aA,ap as aB,xp as aC,Zp as aD,v_ as aE,b_ as aF,zp as aG,k_ as aH,Fg as aI,wi as aJ,Ur as aK,$i as aL,Mi as aM,Ut as aN,Ci as aO,q_ as aP,Ll as aQ,cl as aR,Vl as aS,Wl as aT,gs as aU,Ps as aV,ia as aW,Ls as aX,Zd as aY,Jd as aZ,ti as a_,rl as aa,Xo as ab,Xa as ac,Za as ad,nn as ae,rn as af,Xi as ag,Zi as ah,el as ai,Fs as aj,cc as ak,zg as al,xr as am,fn as an,Rc as ao,Cc as ap,Ui as aq,le as ar,W as as,sa as at,Ao as au,Fo as av,Po as aw,Wa as ax,o as ay,he as az,ih as b,Pr as b$,zn as b0,Vn as b1,pm as b2,Fr as b3,dm as b4,El as b5,ql as b6,tc as b7,tl as b8,ic as b9,$o as bA,Hu as bB,W_ as bC,yi as bD,mi as bE,Fi as bF,Ha as bG,Ma as bH,$a as bI,es as bJ,ts as bK,ra as bL,Rl as bM,Oa as bN,Ia as bO,Zn as bP,Jn as bQ,ki as bR,bs as bS,ys as bT,U_ as bU,G_ as bV,Hr as bW,jr as bX,qr as bY,zr as bZ,Dr as b_,Yl as ba,ws as bb,oa as bc,os as bd,fa as be,Ba as bf,L_ as bg,ya as bh,Is as bi,gn as bj,br as bk,kr as bl,wr as bm,yr as bn,mn as bo,Oe as bp,Sp as bq,lf as br,Io as bs,ll as bt,Qt as bu,ei as bv,Gr as bw,ba as bx,kc as by,H_ as bz,j as c,Ec as c$,Er as c0,Un as c1,Tr as c2,Ar as c3,Jl as c4,Lr as c5,Ql as c6,Kl as c7,jl as c8,ec as c9,em as cA,xo as cB,Xd as cC,Vd as cD,dn as cE,hn as cF,Ga as cG,I_ as cH,cn as cI,ln as cJ,an as cK,sn as cL,Ua as cM,Sc as cN,xc as cO,ev as cP,X_ as cQ,j_ as cR,Or as cS,Ig as cT,uo as cU,Ee as cV,qe as cW,Ne as cX,Wc as cY,Yc as cZ,rh as c_,Xl as ca,Zl as cb,sm as cc,ns as cd,Rp as ce,np as cf,Yf as cg,ip as ch,pa as ci,Wf as cj,Xf as ck,D_ as cl,li as cm,ep as cn,op as co,Di as cp,fi as cq,ai as cr,vi as cs,rs as ct,zi as cu,Cn as cv,Tu as cw,Vi as cx,qn as cy,Kd as cz,Rg as d,ua as d$,Xc as d0,Uc as d1,Gc as d2,nh as d3,eh as d4,Fc as d5,Dc as d6,jn as d7,Ac as d8,Wn as d9,il as dA,Ol as dB,Va as dC,$c as dD,Mc as dE,Wi as dF,Pc as dG,tf as dH,nf as dI,$p as dJ,of as dK,cf as dL,Ml as dM,rf as dN,sf as dO,Da as dP,Js as dQ,Mp as dR,Ri as dS,y_ as dT,$f as dU,Mf as dV,uf as dW,w_ as dX,ja as dY,Wr as dZ,Ea as d_,ci as da,Uf as db,Pp as dc,jf as dd,Tl as de,Es as df,ds as dg,us as dh,Ie as di,lu as dj,Kp as dk,Yp as dl,nu as dm,Nu as dn,Nd as dp,Ed as dq,Fd as dr,Pn as ds,kd as dt,Yd as du,Tn as dv,Co as dw,pi as dx,eu as dy,iu as dz,pe as e,Ir as e0,Nr as e1,Na as e2,Pl as e3,V_ as e4,La as e5,hm as e6,wp as e7,dp as e8,gp as e9,up as ea,Jt as eb,kg as ec,K_ as ed,Ji as ee,Qi as ef,Wt as eg,wv as eh,th as f,_n as g,p_ as h,_e as i,Vp as j,Op as k,kp as l,zd as m,sh as n,dh as o,Id as p,$d as q,hh as r,on as s,Md as t,Su as u,Gp as v,Xn as w,Bi as x,qi as y,Li as z}; diff --git a/dist/houseplan-assets/houseplan-editor-runtime-BlocE3XU.js b/dist/houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js similarity index 73% rename from dist/houseplan-assets/houseplan-editor-runtime-BlocE3XU.js rename to dist/houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js index 427d087c..b8f8530f 100644 --- a/dist/houseplan-assets/houseplan-editor-runtime-BlocE3XU.js +++ b/dist/houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js @@ -1,4 +1,4 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{e as t,i as e,E as s,s as i,a as o,n as a,f as n,b as r,l,o as h,r as c,A as d,c as p,d as u,g as _,h as m,j as g,v as f,k as b,m as v,p as y,q as w,t as $,u as k,w as x,x as M,T as C,y as S,z as P,D,B as I,C as L,F as T,G as R,H as z,I as F,J as N,K as A,L as E,M as O,N as B,O as H,P as W,Q as j,R as G,S as q,U,V as K,W as V,X as J,Y as Z,Z as Y,_ as X,$ as Q,a0 as tt,a1 as et,a2 as st,a3 as it,a4 as ot,a5 as at,a6 as nt,a7 as rt,a8 as lt,a9 as ht,aa as ct,ab as dt,ac as pt,ad as ut,ae as _t,af as mt,ag as gt,ah as ft,ai as bt,aj as vt,ak as yt,al as wt,am as $t,an as kt,ao as xt,ap as Mt,aq as Ct,ar as St,as as Pt,at as Dt,au as It,av as Lt,aw as Tt,ax as Rt,ay as zt,az as Ft,aA as Nt,aB as At,aC as Et,aD as Ot,aE as Bt,aF as Ht,aG as Wt,aH as jt,aI as Gt,aJ as qt,aK as Ut,aL as Kt,aM as Vt,aN as Jt,aO as Zt,aP as Yt,aQ as Xt,aR as Qt,aS as te,aT as ee,aU as se,aV as ie,aW as oe,aX as ae,aY as ne,aZ as re,a_ as le,a$ as he,b0 as ce,b1 as de,b2 as pe,b3 as ue,b4 as _e,b5 as me,b6 as ge,b7 as fe,b8 as be,b9 as ve,ba as ye,bb as we,bc as $e,bd as ke,be as xe,bf as Me,bg as Ce,bh as Se,bi as Pe,bj as De,bk as Ie,bl as Le,bm as Te,bn as Re,bo as ze,bp as Fe,bq as Ne,br as Ae,bs as Ee,bt as Oe,bu as Be,bv as He,bw as We,bx as je,by as Ge,bz as qe,bA as Ue,bB as Ke,bC as Ve,bD as Je,bE as Ze,bF as Ye,bG as Xe,bH as Qe,bI as ts,bJ as es,bK as ss,bL as is,bM as os,bN as as,bO as ns,bP as rs,bQ as ls,bR as hs,bS as cs,bT as ds,bU as ps,bV as us,bW as _s,bX as ms,bY as gs,bZ as fs,b_ as bs,b$ as vs,c0 as ys,c1 as ws,c2 as $s,c3 as ks,c4 as xs,c5 as Ms,c6 as Cs,c7 as Ss,c8 as Ps,c9 as Ds,ca as Is,cb as Ls,cc as Ts,cd as Rs,ce as zs,cf as Fs,cg as Ns,ch as As,ci as Es,cj as Os,ck as Bs,cl as Hs,cm as Ws,cn as js,co as Gs,cp as qs,cq as Us,cr as Ks,cs as Vs,ct as Js,cu as Zs,cv as Ys,cw as Xs,cx as Qs,cy as ti,cz as ei,cA as si,cB as ii,cC as oi,cD as ai,cE as ni,cF as ri,cG as li,cH as hi,cI as ci,cJ as di,cK as pi,cL as ui,cM as _i,cN as mi,cO as gi,cP as fi,cQ as bi,cR as vi,cS as yi,cT as wi,cU as $i,cV as ki,cW as xi,cX as Mi,cY as Ci,cZ as Si,c_ as Pi,c$ as Di,d0 as Ii,d1 as Li,d2 as Ti,d3 as Ri,d4 as zi,d5 as Fi,d6 as Ni,d7 as Ai,d8 as Ei,d9 as Oi,da as Bi,db as Hi,dc as Wi,dd as ji,de as Gi,df as qi,dg as Ui,dh as Ki,di as Vi,dj as Ji,dk as Zi,dl as Yi,dm as Xi,dn as Qi,dp as to,dq as eo,dr as so,ds as io,dt as oo,du as ao,dv as no,dw as ro,dx as lo,dy as ho,dz as co,dA as po,dB as uo}from"./houseplan-card-BWAph8ZF.js";import{r as _o,s as mo,d as go,f as fo,e as bo,a as vo,c as yo,t as wo,b as $o,g as ko,h as xo,i as Mo,j as Co,k as So,l as Po,m as Do,u as Io,n as Lo,o as To,p as Ro,q as zo,v as Fo,w as No,x as Ao,y as Eo,z as Oo,F as Bo,A as Ho,B as Wo,C as jo,D as Go,E as qo,G as Uo,H as Ko,I as Vo,J as Jo,K as Zo}from"./backdrop-pick-CtZfmF4H.js";import{h as Yo,t as Xo,m as Qo,T as ta}from"./zigbee-topology-D0gydI7H.js";import{GENERATED_FURNITURE_ART as ea,FURNITURE_ART_FINGERPRINT as sa}from"./furniture-plan-art.generated-Ck1wv9qF.js";import"./form-kit.styles-DcvCvE8g.js";const ia={},oa=t(class extends e{constructor(){super(...arguments),this.ot=ia}render(t,e){return e()}update(t,[e,i]){if(Array.isArray(e)){if(Array.isArray(this.ot)&&this.ot.length===e.length&&e.every((t,e)=>t===this.ot[e]))return s}else if(this.ot===e)return s;return this.ot=Array.isArray(e)?Array.from(e):e,this.render(e,i)}});var aa={"gs.show_room_tooltip":"Show the room information window on hover","support.about_group":"About the card","support.guide_group":"Documentation","support.guide":"User guide","support.form_group":"Send a report or suggestion","support.contact":"Contact details (email/tg/WhatsApp), optional.","support.message":"Message","support.attach":"Attach anonymized information from your plan","support.attach_hint":"Includes only allowed plan geometry, settings and bounded runtime facts. Excludes names, Home Assistant IDs, live states, URLs, files, and your message/contact.","support.geometry_warning":"The package contains no names or Home Assistant IDs, but it does contain the exact geometry and dimensions of your home.","support.close_busy_title":"Stop the current operation?","support.close_busy_body":"House Plan is preparing or sending the report. Closing now stops waiting for the result.","support.building":"Preparing anonymized data…","support.preview_summary":"Package v{version} · {spaces} spaces · {size} KiB","support.prepared":"Snapshot prepared {n} min ago","support.show_data":"Show data","support.download":"Download JSON","support.refresh":"Refresh snapshot","support.privacy":"When you send, your message, optional contact and, if selected, exact geometry leave your Home Assistant through the House Plan project relay and are visible to maintainers. The project node keeps the report for up to 30 days. Network infrastructure sees your HA server address, but House Plan does not retain it raw; rate-limit and idempotency metadata is kept for up to 24 hours.","support.error_title":"The report was not sent","support.manual_recovery":"You can keep the message and attachment and continue manually:","support.copy_message":"Copy message","support.success":"Report sent: {id}. Save this number when contacting support.","support.copy_id":"Copy ID","support.sending":"Sending…","support.retry":"Retry","support.send":"Send","support.update_required":"Update the House Plan card and integration to compatible versions to send reports.","support.message_copied":"Message copied","support.id_copied":"Report ID copied","support.copy_failed":"Could not access the clipboard. Select and copy the text manually.","support.validation.message_required":"Enter a message.","support.validation.message_too_long":"The message must contain no more than 10,000 characters.","support.validation.contact_too_long":"Contact details must contain no more than 320 characters.","support.validation.preview_missing":"Wait for the attachment preview or turn the attachment off.","support.validation.preview_expired":"The attachment preview expired. Refresh the snapshot.","support.error.support_invalid_message":"Check the message and try again.","support.error.support_preview_expired":"The attachment preview expired or is no longer available. Refresh the snapshot.","support.error.support_package_too_large":"The anonymized package exceeds the 8 MiB limit.","support.error.support_rate_limited":"Too many reports or previews were requested. Try again later.","support.error.support_unavailable":"The private support service is temporarily unavailable. Your draft remains here.","support.error.support_rejected":"The report did not pass the support service validation.","support.error.unauthorized":"You do not have permission to send this report.","vac.routes_section":"Maps and floors","vac.routes_current_map":"Current map","vac.routes_no_map":"no telemetry","vac.routes_status":"Routing","vac.routes_state_ready":"map assigned and calibrated","vac.routes_state_needs_calibration":"map assigned, calibration needed","vac.routes_state_unmapped":"current map is not assigned to a floor","vac.routes_state_ambiguous":"two maps are indistinguishable — no floor is chosen","vac.routes_state_missing_space":"the map's space was deleted","vac.routes_state_none":"no map data","vac.routes_empty":"No map is assigned to a floor yet.","vac.route_map_default":"no map id","vac.route_active":"Active","vac.route_space":"Space","vac.route_space_none":"not selected","vac.route_status_ready":"ready","vac.route_status_needs_calibration":"needs calibration","vac.route_status_ambiguous":"ambiguous","vac.route_status_missing_space":"space deleted","vac.route_missing_space_group":"Deleted space","vac.route_add_current":"Add current map","vac.route_delete":"Remove map","vac.route_delete_title":"Remove the map from its floor?","vac.route_delete_body":"Calibration and saved paths for this map will be removed. Continue?","vac.route_delete_confirm":"Remove","vac.route_space_title":"Move the map to another space?","vac.route_space_body":"Calibration and saved paths for this map will be removed. Continue?","vac.route_space_confirm":"Move","vac.route_missing_space_hint":"One of the maps points at a deleted space: pick a new one or remove the map. Until then the robot is not drawn for that map.","vac.route_default_hint":"The source reports no stable map id. Several floors cannot be told apart without another source or the robot's own selected map.","vac.route_target_hint":"The dock stays in the “{space}” space regardless of the current map.","vac.route_add_source":"Add a map source","vac.route_add_source_hint":"For integrations that give each map its own camera. The “All cameras” section above widens this list.","vac.route_source_no_map":"no map reported"};const na={en:aa,ru:{"gs.show_room_tooltip":"Показывать окно с информацией при наведении на комнату","support.about_group":"О карточке","support.guide_group":"Документация","support.guide":"Руководство пользователя","support.form_group":"Отправить репорт или предложение","support.contact":"Контакт для связи (email/tg/WhatsApp), необязательно.","support.message":"Сообщение","support.attach":"Прикрепить обезличенную информацию из вашего плана","support.attach_hint":"В пакет входят только разрешённые геометрия, настройки и ограниченные сведения о среде. Не входят имена, HA id, текущие состояния, URL, файлы, сообщение и контакт.","support.geometry_warning":"Пакет не содержит имён и HA id, но содержит точную геометрию и размеры дома.","support.close_busy_title":"Прервать текущую операцию?","support.close_busy_body":"House Plan подготавливает или отправляет репорт. При закрытии ожидание результата прекратится.","support.building":"Подготавливаем обезличенные данные…","support.preview_summary":"Пакет v{version} · пространств: {spaces} · {size} КиБ","support.prepared":"Снимок подготовлен {n} мин назад","support.show_data":"Показать данные","support.download":"Скачать JSON","support.refresh":"Обновить снимок","support.privacy":"При отправке сообщение, необязательный контакт и, если выбран пакет, точная геометрия покидают ваш Home Assistant через relay проекта House Plan и доступны мейнтейнерам. Узел проекта хранит репорт до 30 дней. Сетевая инфраструктура видит адрес сервера HA, но House Plan не сохраняет его в исходном виде; метаданные лимитов и идемпотентности хранятся до 24 часов.","support.error_title":"Репорт не отправлен","support.manual_recovery":"Сообщение и вложение можно сохранить и продолжить вручную:","support.copy_message":"Копировать сообщение","support.success":"Репорт отправлен: {id}. Сохраните номер для связи с поддержкой.","support.copy_id":"Копировать ID","support.sending":"Отправляем…","support.retry":"Повторить","support.send":"Отправить","support.update_required":"Обновите карточку и интеграцию House Plan до совместимых версий, чтобы отправлять репорты.","support.message_copied":"Сообщение скопировано","support.id_copied":"ID репорта скопирован","support.copy_failed":"Не удалось получить доступ к буферу обмена. Выделите и скопируйте текст вручную.","support.validation.message_required":"Введите сообщение.","support.validation.message_too_long":"Сообщение должно содержать не более 10 000 символов.","support.validation.contact_too_long":"Контакт должен содержать не более 320 символов.","support.validation.preview_missing":"Дождитесь предпросмотра вложения или отключите его.","support.validation.preview_expired":"Предпросмотр вложения истёк. Обновите снимок.","support.error.support_invalid_message":"Проверьте сообщение и повторите попытку.","support.error.support_preview_expired":"Предпросмотр вложения истёк или больше недоступен. Обновите снимок.","support.error.support_package_too_large":"Обезличенный пакет превышает лимит 8 МиБ.","support.error.support_rate_limited":"Запрошено слишком много репортов или предпросмотров. Повторите позже.","support.error.support_unavailable":"Закрытая служба поддержки временно недоступна. Черновик сохранён в этом окне.","support.error.support_rejected":"Репорт не прошёл проверку службы поддержки.","support.error.unauthorized":"У вас нет прав на отправку этого репорта.","vac.routes_section":"Карты и этажи","vac.routes_current_map":"Текущая карта","vac.routes_no_map":"источник молчит","vac.routes_status":"Маршрутизация","vac.routes_state_ready":"карта сопоставлена и откалибрована","vac.routes_state_needs_calibration":"карта сопоставлена, нужна калибровка","vac.routes_state_unmapped":"текущая карта не сопоставлена этажу","vac.routes_state_ambiguous":"две карты неразличимы — этаж не выбирается","vac.routes_state_missing_space":"пространство карты удалено","vac.routes_state_none":"нет данных о карте","vac.routes_empty":"Ни одна карта ещё не сопоставлена этажу.","vac.route_map_default":"без идентификатора","vac.route_active":"Текущая","vac.route_space":"Пространство","vac.route_space_none":"не выбрано","vac.route_status_ready":"готова","vac.route_status_needs_calibration":"нужна калибровка","vac.route_status_ambiguous":"неоднозначна","vac.route_status_missing_space":"пространство удалено","vac.route_missing_space_group":"Пространство удалено","vac.route_add_current":"Добавить текущую карту","vac.route_delete":"Удалить карту","vac.route_delete_title":"Удалить карту с этажа?","vac.route_delete_body":"Калибровка и сохранённые пути этой карты будут удалены. Продолжить?","vac.route_delete_confirm":"Удалить","vac.route_space_title":"Перенести карту в другое пространство?","vac.route_space_body":"Калибровка и сохранённые пути этой карты будут удалены. Продолжить?","vac.route_space_confirm":"Перенести","vac.route_missing_space_hint":"Одна из карт ссылается на удалённое пространство: выберите новое или удалите карту. Пока ссылка не исправлена, робот на этой карте не рисуется.","vac.route_default_hint":"Источник не сообщает стабильный идентификатор карты. Несколько этажей нельзя различить без другого источника или собственной карты робота.","vac.route_target_hint":"Док остаётся в пространстве «{space}» независимо от текущей карты.","vac.route_add_source":"Добавить источник карты","vac.route_add_source_hint":"Для интеграций, где у каждой карты своя камера. Список расширяется разделом «Все камеры» выше.","vac.route_source_no_map":"карта не читается"},de:{"gs.show_room_tooltip":"Rauminformationen beim Darüberfahren anzeigen","support.about_group":"Über die Karte","support.guide_group":"Dokumentation","support.guide":"Benutzerhandbuch","support.form_group":"Bericht oder Vorschlag senden","support.contact":"Kontakt (E-Mail/tg/WhatsApp), optional.","support.message":"Nachricht","support.attach":"Anonymisierte Informationen aus dem Plan anhängen","support.attach_hint":"Enthält nur erlaubte Plangeometrie, Einstellungen und begrenzte Laufzeitdaten. Namen, Home-Assistant-IDs, Live-Zustände, URLs, Dateien, Nachricht und Kontakt werden ausgeschlossen.","support.geometry_warning":"Das Paket enthält keine Namen oder Home-Assistant-IDs, aber die exakte Geometrie und die Maße Ihres Hauses.","support.close_busy_title":"Aktuellen Vorgang abbrechen?","support.close_busy_body":"House Plan bereitet den Bericht vor oder sendet ihn. Beim Schließen wird nicht weiter auf das Ergebnis gewartet.","support.building":"Anonymisierte Daten werden vorbereitet…","support.preview_summary":"Paket v{version} · {spaces} Bereiche · {size} KiB","support.prepared":"Schnappschuss vor {n} Min. erstellt","support.show_data":"Daten anzeigen","support.download":"JSON herunterladen","support.refresh":"Schnappschuss aktualisieren","support.privacy":"Beim Senden verlassen Ihre Nachricht, der optionale Kontakt und, falls ausgewählt, die exakte Geometrie Ihren Home Assistant über das House-Plan-Projektrelay und sind für die Maintainer sichtbar. Der Projektserver speichert den Bericht bis zu 30 Tage. Die Netzwerkinfrastruktur sieht die Adresse Ihres HA-Servers, House Plan speichert sie jedoch nicht im Rohformat; Limit- und Idempotenzdaten bleiben bis zu 24 Stunden erhalten.","support.error_title":"Der Bericht wurde nicht gesendet","support.manual_recovery":"Nachricht und Anhang können gespeichert und manuell weitergegeben werden:","support.copy_message":"Nachricht kopieren","support.success":"Bericht gesendet: {id}. Bewahren Sie diese Nummer für den Support auf.","support.copy_id":"ID kopieren","support.sending":"Wird gesendet…","support.retry":"Erneut versuchen","support.send":"Senden","support.update_required":"Aktualisieren Sie House-Plan-Karte und Integration auf kompatible Versionen, um Berichte zu senden.","support.message_copied":"Nachricht kopiert","support.id_copied":"Berichts-ID kopiert","support.copy_failed":"Kein Zugriff auf die Zwischenablage. Markieren und kopieren Sie den Text manuell.","support.validation.message_required":"Geben Sie eine Nachricht ein.","support.validation.message_too_long":"Die Nachricht darf höchstens 10.000 Zeichen enthalten.","support.validation.contact_too_long":"Der Kontakt darf höchstens 320 Zeichen enthalten.","support.validation.preview_missing":"Warten Sie auf die Vorschau oder deaktivieren Sie den Anhang.","support.validation.preview_expired":"Die Anhangsvorschau ist abgelaufen. Aktualisieren Sie den Schnappschuss.","support.error.support_invalid_message":"Prüfen Sie die Nachricht und versuchen Sie es erneut.","support.error.support_preview_expired":"Die Anhangsvorschau ist abgelaufen oder nicht mehr verfügbar. Aktualisieren Sie den Schnappschuss.","support.error.support_package_too_large":"Das anonymisierte Paket überschreitet das Limit von 8 MiB.","support.error.support_rate_limited":"Zu viele Berichte oder Vorschauen wurden angefordert. Versuchen Sie es später erneut.","support.error.support_unavailable":"Der private Supportdienst ist vorübergehend nicht verfügbar. Der Entwurf bleibt in diesem Fenster erhalten.","support.error.support_rejected":"Der Bericht hat die Prüfung des Supportdienstes nicht bestanden.","support.error.unauthorized":"Sie dürfen diesen Bericht nicht senden.","vac.routes_section":"Karten und Etagen","vac.routes_current_map":"Aktuelle Karte","vac.routes_no_map":"keine Telemetrie","vac.routes_status":"Zuordnung","vac.routes_state_ready":"Karte zugeordnet und kalibriert","vac.routes_state_needs_calibration":"Karte zugeordnet, Kalibrierung nötig","vac.routes_state_unmapped":"aktuelle Karte keiner Etage zugeordnet","vac.routes_state_ambiguous":"zwei Karten nicht unterscheidbar — keine Etage gewählt","vac.routes_state_missing_space":"der Raum der Karte wurde gelöscht","vac.routes_state_none":"keine Kartendaten","vac.routes_empty":"Noch keine Karte einer Etage zugeordnet.","vac.route_map_default":"ohne Karten-ID","vac.route_active":"Aktiv","vac.route_space":"Raum","vac.route_space_none":"nicht gewählt","vac.route_status_ready":"bereit","vac.route_status_needs_calibration":"Kalibrierung nötig","vac.route_status_ambiguous":"mehrdeutig","vac.route_status_missing_space":"Raum gelöscht","vac.route_missing_space_group":"Gelöschter Bereich","vac.route_add_current":"Aktuelle Karte hinzufügen","vac.route_delete":"Karte entfernen","vac.route_delete_title":"Karte von der Etage entfernen?","vac.route_delete_body":"Kalibrierung und gespeicherte Pfade dieser Karte werden entfernt. Fortfahren?","vac.route_delete_confirm":"Entfernen","vac.route_space_title":"Karte in einen anderen Raum verschieben?","vac.route_space_body":"Kalibrierung und gespeicherte Pfade dieser Karte werden entfernt. Fortfahren?","vac.route_space_confirm":"Verschieben","vac.route_missing_space_hint":"Eine Karte verweist auf einen gelöschten Raum: neuen wählen oder Karte entfernen. Bis dahin wird der Roboter für diese Karte nicht gezeichnet.","vac.route_default_hint":"Die Quelle meldet keine stabile Karten-ID. Mehrere Etagen lassen sich ohne andere Quelle oder die vom Roboter gewählte Karte nicht unterscheiden.","vac.route_target_hint":"Die Station bleibt unabhängig von der aktuellen Karte im Raum „{space}“.","vac.route_add_source":"Kartenquelle hinzufügen","vac.route_add_source_hint":"Für Integrationen, die jeder Karte eine eigene Kamera geben. Der Abschnitt „Alle Kameras“ oben erweitert diese Liste.","vac.route_source_no_map":"keine Karte gemeldet"},fr:{"gs.show_room_tooltip":"Afficher les informations de la pièce au survol","support.about_group":"À propos de la carte","support.guide_group":"Documentation d’aide","support.guide":"Guide utilisateur","support.form_group":"Envoyer un rapport ou une suggestion","support.contact":"Contact (e-mail/tg/WhatsApp), facultatif.","support.message":"Votre message","support.attach":"Joindre des informations anonymisées de votre plan","support.attach_hint":"Inclut uniquement la géométrie, les réglages autorisés et des données d’exécution limitées. Exclut les noms, identifiants Home Assistant, états en direct, URL, fichiers, message et contact.","support.geometry_warning":"Le paquet ne contient ni noms ni identifiants Home Assistant, mais il contient la géométrie et les dimensions exactes de votre logement.","support.close_busy_title":"Interrompre l’opération en cours ?","support.close_busy_body":"House Plan prépare ou envoie le rapport. Fermer maintenant arrête l’attente du résultat.","support.building":"Préparation des données anonymisées…","support.preview_summary":"Paquet v{version} · {spaces} espaces · {size} Kio","support.prepared":"Instantané préparé il y a {n} min","support.show_data":"Afficher les données","support.download":"Télécharger le JSON","support.refresh":"Actualiser l’instantané","support.privacy":"Lors de l’envoi, votre message, le contact facultatif et, si elle est sélectionnée, la géométrie exacte quittent votre Home Assistant via le relais du projet House Plan et sont visibles par les mainteneurs. Le serveur du projet conserve le rapport jusqu’à 30 jours. L’infrastructure réseau voit l’adresse de votre serveur HA, mais House Plan ne la conserve pas en clair ; les métadonnées de limitation et d’idempotence sont gardées jusqu’à 24 heures.","support.error_title":"Le rapport n’a pas été envoyé","support.manual_recovery":"Vous pouvez conserver le message et la pièce jointe puis continuer manuellement :","support.copy_message":"Copier le message","support.success":"Rapport envoyé : {id}. Conservez ce numéro pour contacter l’assistance.","support.copy_id":"Copier l’ID","support.sending":"Envoi…","support.retry":"Réessayer","support.send":"Envoyer","support.update_required":"Mettez à jour la carte et l’intégration House Plan vers des versions compatibles pour envoyer des rapports.","support.message_copied":"Message copié","support.id_copied":"ID du rapport copié","support.copy_failed":"Impossible d’accéder au presse-papiers. Sélectionnez et copiez le texte manuellement.","support.validation.message_required":"Saisissez un message.","support.validation.message_too_long":"Le message ne doit pas dépasser 10 000 caractères.","support.validation.contact_too_long":"Le contact ne doit pas dépasser 320 caractères.","support.validation.preview_missing":"Attendez l’aperçu de la pièce jointe ou désactivez-la.","support.validation.preview_expired":"L’aperçu de la pièce jointe a expiré. Actualisez l’instantané.","support.error.support_invalid_message":"Vérifiez le message et réessayez.","support.error.support_preview_expired":"L’aperçu de la pièce jointe a expiré ou n’est plus disponible. Actualisez l’instantané.","support.error.support_package_too_large":"Le paquet anonymisé dépasse la limite de 8 Mio.","support.error.support_rate_limited":"Trop de rapports ou d’aperçus ont été demandés. Réessayez plus tard.","support.error.support_unavailable":"Le service d’assistance privé est temporairement indisponible. Le brouillon reste dans cette fenêtre.","support.error.support_rejected":"Le rapport n’a pas passé la validation du service d’assistance.","support.error.unauthorized":"Vous n’êtes pas autorisé à envoyer ce rapport.","vac.routes_section":"Cartes et étages","vac.routes_current_map":"Carte actuelle","vac.routes_no_map":"aucune télémétrie","vac.routes_status":"Routage","vac.routes_state_ready":"carte assignée et calibrée","vac.routes_state_needs_calibration":"carte assignée, calibrage requis","vac.routes_state_unmapped":"carte actuelle non assignée à un étage","vac.routes_state_ambiguous":"deux cartes indiscernables — aucun étage choisi","vac.routes_state_missing_space":"l'espace de la carte a été supprimé","vac.routes_state_none":"aucune donnée de carte","vac.routes_empty":"Aucune carte n'est encore assignée à un étage.","vac.route_map_default":"sans identifiant","vac.route_active":"Active","vac.route_space":"Espace","vac.route_space_none":"non sélectionné","vac.route_status_ready":"prête","vac.route_status_needs_calibration":"calibrage requis","vac.route_status_ambiguous":"ambiguë","vac.route_status_missing_space":"espace supprimé","vac.route_missing_space_group":"Espace supprimé","vac.route_add_current":"Ajouter la carte actuelle","vac.route_delete":"Supprimer la carte","vac.route_delete_title":"Retirer la carte de son étage ?","vac.route_delete_body":"Le calibrage et les trajets enregistrés de cette carte seront supprimés. Continuer ?","vac.route_delete_confirm":"Supprimer","vac.route_space_title":"Déplacer la carte vers un autre espace ?","vac.route_space_body":"Le calibrage et les trajets enregistrés de cette carte seront supprimés. Continuer ?","vac.route_space_confirm":"Déplacer","vac.route_missing_space_hint":"Une carte pointe vers un espace supprimé : choisissez-en un autre ou supprimez la carte. D'ici là, le robot n'est pas dessiné pour cette carte.","vac.route_default_hint":"La source ne fournit pas d'identifiant de carte stable. Plusieurs étages ne peuvent pas être distingués sans une autre source ou la carte sélectionnée du robot.","vac.route_target_hint":"La station reste dans l'espace « {space} » quelle que soit la carte actuelle.","vac.route_add_source":"Ajouter une source de carte","vac.route_add_source_hint":"Pour les intégrations qui donnent à chaque carte sa propre caméra. La section « Toutes les caméras » ci-dessus élargit cette liste.","vac.route_source_no_map":"aucune carte signalée"}};function ra(t,e,s){return i(na[t]?.[e]??aa[e]??e,s)}function la(t,e,s,i,o){return{markerId:t,source:i,mapId:o,space:e.length?"":s}}function ha(t,e,s){return{...t,space:s.has(e)?e:""}}function ca(t,e=Math.random){const s=new Set(t);for(let t=0;t<64;t+=1){const t="vr_"+Math.floor(16777215*e()).toString(36).padStart(5,"0");if(!s.has(t))return t}return"vr_"+Date.now().toString(36)}function da(t,e,s){return t.map(t=>t.id===e?{...t,calibration:s}:t)}const pa=new WeakMap,ua=(t,e)=>{const s=(t._serverCfg?.spaces||[]).find(t=>t?.id===e);return String(s?.name||s?.id||e)};function _a(t,e,s){const i=t.host,n=l(i.hass,i._config?.language),r=(t,e)=>ra(n,t,e),u=e.marker?.vacuum||{},_=Array.isArray(u.map_routes),m=i._vacSource(e)||"",g=o(e.id,u,e.space,m),f=(i._serverCfg?.spaces||[]).filter(t=>"string"==typeof t?.id&&!!t.id).map(t=>({id:t.id,name:String(t.name||t.id)})),b=new Set(f.map(t=>t.id)),v=h(g,[m],t=>i._vacObservedMapId(e,t)),y=c({routes:g,observed:v,spaceIds:b}),w="ready"===y.kind||"needs_calibration"===y.kind||"missing_space"===y.kind?y.route.id:"",$=m?v[m]:void 0,k=async s=>{let o=_?u.map_routes??null:null;if(!o&&(o=function(t,e,s,i){if(!s)return null;const o=t?.calibration;if(!o||"object"!=typeof o)return null;const n=new Set,r=[];for(const t of Object.keys(o)){const l=a(o[t]);if(!l)continue;const h=i(n);n.add(h),r.push({id:h,source:s,map_id:t,space:e,calibration:l})}return r.length?r:null}(u,e.space,m,t=>ca(t))??[],!m&&Object.keys(u.calibration||{}).length))return!1;const n=s(o);return!!n&&(async s=>{const o=i._serverCfg;if(!o)return!1;const a=JSON.parse(JSON.stringify(o));a.markers=a.markers||[];let n=a.markers.find(t=>t.id===e.id);if(!n){if("device"!==e.bindingKind&&"entity"!==e.bindingKind||!e.bindingRef)return!1;n={id:e.id,binding:`${e.bindingKind}:${e.bindingRef}`,space:e.space||null,area:e.area||null,hidden:!!e.hidden},a.markers.push(n)}n.vacuum={...n.vacuum||{},map_routes:s},delete n.vacuum.calibration;const r=i._adoption.beginOptimistic(o,a);i._adoption.stageLocalConfig(a),i._regSignature="",i._maybeRebuildDevices(),i.requestUpdate(),i._saveConfigDebounced.pending()&&i._saveConfigDebounced.cancel();try{return await t._saveConfigNow(),!0}catch(t){return i._rollbackOptimistic(r),i._regSignature="",i._maybeRebuildDevices(),i.requestUpdate(),i._showToast(i._t("toast.cfg_save_failed",{err:i._errText(t)})),!1}})(n)},x=s.candidates.filter(t=>t.entityId!==m&&!g.some(e=>e.source===t.entityId)),M=async(t,e)=>{if(!e||e===t.space)return;await i._confirmDanger({key:"vacuum_route_space",kind:"warning",title:r("vac.route_space_title"),message:r("vac.route_space_body"),objectName:t.map_id||r("vac.route_map_default"),confirmLabel:r("vac.route_space_confirm"),cancelLabel:i._t("btn.cancel")})&&await k(s=>function(t,e,s,i){return t.map(t=>t.id===e?{...t,id:i,space:s,calibration:null}:t)}(s,t.id,e,ca(new Set(g.map(t=>t.id)))))},C=new Map(f.map((t,e)=>[t.id,e])),S=(t,e)=>t.map_id.localeCompare(e.map_id)||t.source.localeCompare(e.source)||t.id.localeCompare(e.id),P=g.filter(t=>b.has(t.space)).sort((t,e)=>(C.get(t.space)??0)-(C.get(e.space)??0)||S(t,e)),D=g.filter(t=>!b.has(t.space)).sort(S),I=[...P,...D],L=!!m&&void 0!==$&&!g.some(t=>t.source===m&&t.map_id===$);let T=pa.get(t);const R=T?.source||"",z=T?.mapId||"",F=!!T&&g.some(t=>t.source===R&&t.map_id===z);T&&(T.markerId!==e.id||i._vacObservedMapId(e,T.source)!==T.mapId||F&&!T.saving)&&(pa.delete(t),T=void 0),T?.space&&!b.has(T.space)&&(T=ha(T,"",b),pa.set(t,T));const N=s=>p` +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{e as t,i as e,E as s,s as i,a as o,n as a,f as n,b as r,l,o as h,r as c,A as d,c as p,d as u,g as _,h as m,v as g,j as f,k as b,m as v,p as y,q as w,t as $,u as k,w as x,T as M,x as C,y as S,D as P,z as D,B as I,C as L,F as T,G as R,H as z,I as F,J as N,K as A,L as E,M as O,N as B,O as H,P as W,Q as j,R as G,S as q,U,V as K,W as V,X as J,Y as Z,Z as Y,_ as X,$ as Q,a0 as tt,a1 as et,a2 as st,a3 as it,a4 as ot,a5 as at,a6 as nt,a7 as rt,a8 as lt,a9 as ht,aa as ct,ab as dt,ac as pt,ad as ut,ae as _t,af as mt,ag as gt,ah as ft,ai as bt,aj as vt,ak as yt,al as wt,am as $t,an as kt,ao as xt,ap as Mt,aq as Ct,ar as St,as as Pt,at as Dt,au as It,av as Lt,aw as Tt,ax as Rt,ay as zt,az as Ft,aA as Nt,aB as At,aC as Et,aD as Ot,aE as Bt,aF as Ht,aG as Wt,aH as jt,aI as Gt,aJ as qt,aK as Ut,aL as Kt,aM as Vt,aN as Jt,aO as Zt,aP as Yt,aQ as Xt,aR as Qt,aS as te,aT as ee,aU as se,aV as ie,aW as oe,aX as ae,aY as ne,aZ as re,a_ as le,a$ as he,b0 as ce,b1 as de,b2 as pe,b3 as ue,b4 as _e,b5 as me,b6 as ge,b7 as fe,b8 as be,b9 as ve,ba as ye,bb as we,bc as $e,bd as ke,be as xe,bf as Me,bg as Ce,bh as Se,bi as Pe,bj as De,bk as Ie,bl as Le,bm as Te,bn as Re,bo as ze,bp as Fe,bq as Ne,br as Ae,bs as Ee,bt as Oe,bu as Be,bv as He,bw as We,bx as je,by as Ge,bz as qe,bA as Ue,bB as Ke,bC as Ve,bD as Je,bE as Ze,bF as Ye,bG as Xe,bH as Qe,bI as ts,bJ as es,bK as ss,bL as is,bM as os,bN as as,bO as ns,bP as rs,bQ as ls,bR as hs,bS as cs,bT as ds,bU as ps,bV as us,bW as _s,bX as ms,bY as gs,bZ as fs,b_ as bs,b$ as vs,c0 as ys,c1 as ws,c2 as $s,c3 as ks,c4 as xs,c5 as Ms,c6 as Cs,c7 as Ss,c8 as Ps,c9 as Ds,ca as Is,cb as Ls,cc as Ts,cd as Rs,ce as zs,cf as Fs,cg as Ns,ch as As,ci as Es,cj as Os,ck as Bs,cl as Hs,cm as Ws,cn as js,co as Gs,cp as qs,cq as Us,cr as Ks,cs as Vs,ct as Js,cu as Zs,cv as Ys,cw as Xs,cx as Qs,cy as ti,cz as ei,cA as si,cB as ii,cC as oi,cD as ai,cE as ni,cF as ri,cG as li,cH as hi,cI as ci,cJ as di,cK as pi,cL as ui,cM as _i,cN as mi,cO as gi,cP as fi,cQ as bi,cR as vi,cS as yi,cT as wi,cU as $i,cV as ki,cW as xi,cX as Mi,cY as Ci,cZ as Si,c_ as Pi,c$ as Di,d0 as Ii,d1 as Li,d2 as Ti,d3 as Ri,d4 as zi,d5 as Fi,d6 as Ni,d7 as Ai,d8 as Ei,d9 as Oi,da as Bi,db as Hi,dc as Wi,dd as ji,de as Gi,df as qi,dg as Ui,dh as Ki,di as Vi,dj as Ji,dk as Zi,dl as Yi,dm as Xi,dn as Qi,dp as to,dq as eo,dr as so,ds as io,dt as oo,du as ao,dv as no,dw as ro,dx as lo,dy as ho,dz as co,dA as po,dB as uo}from"./houseplan-card-9fMSy3y3.js";import{r as _o,s as mo,d as go,f as fo,e as bo,a as vo,c as yo,t as wo,b as $o,g as ko,h as xo,i as Mo,j as Co,k as So,l as Po,m as Do,u as Io,n as Lo,o as To,p as Ro,q as zo,v as Fo,w as No,x as Ao,y as Eo,z as Oo,F as Bo,A as Ho,B as Wo,C as jo,D as Go,E as qo,G as Uo,H as Ko,I as Vo,J as Jo,K as Zo}from"./backdrop-pick-BJOCHJxe.js";import{h as Yo,t as Xo,m as Qo,T as ta}from"./zigbee-topology-CI6PJorK.js";import{GENERATED_FURNITURE_ART as ea,FURNITURE_ART_FINGERPRINT as sa}from"./furniture-plan-art.generated-DaxkO8ol.js";import"./form-kit.styles-CKUQLdmn.js";const ia={},oa=t(class extends e{constructor(){super(...arguments),this.ot=ia}render(t,e){return e()}update(t,[e,i]){if(Array.isArray(e)){if(Array.isArray(this.ot)&&this.ot.length===e.length&&e.every((t,e)=>t===this.ot[e]))return s}else if(this.ot===e)return s;return this.ot=Array.isArray(e)?Array.from(e):e,this.render(e,i)}});var aa={"gs.show_room_tooltip":"Show the room information window on hover","support.about_group":"About the card","support.guide_group":"Documentation","support.guide":"User guide","support.form_group":"Send a report or suggestion","support.contact":"Contact details (email/tg/WhatsApp), optional.","support.message":"Message","support.attach":"Attach anonymized information from your plan","support.attach_hint":"Includes only allowed plan geometry, settings and bounded runtime facts. Excludes names, Home Assistant IDs, live states, URLs, files, and your message/contact.","support.geometry_warning":"The package contains no names or Home Assistant IDs, but it does contain the exact geometry and dimensions of your home.","support.close_busy_title":"Stop the current operation?","support.close_busy_body":"House Plan is preparing or sending the report. Closing now stops waiting for the result.","support.building":"Preparing anonymized data…","support.preview_summary":"Package v{version} · {spaces} spaces · {size} KiB","support.prepared":"Snapshot prepared {n} min ago","support.show_data":"Show data","support.download":"Download JSON","support.refresh":"Refresh snapshot","support.privacy":"When you send, your message, optional contact and, if selected, exact geometry leave your Home Assistant through the House Plan project relay and are visible to maintainers. The project node keeps the report for up to 30 days. Network infrastructure sees your HA server address, but House Plan does not retain it raw; rate-limit and idempotency metadata is kept for up to 24 hours.","support.error_title":"The report was not sent","support.manual_recovery":"You can keep the message and attachment and continue manually:","support.copy_message":"Copy message","support.success":"Report sent: {id}. Save this number when contacting support.","support.copy_id":"Copy ID","support.sending":"Sending…","support.retry":"Retry","support.send":"Send","support.update_required":"Update the House Plan card and integration to compatible versions to send reports.","support.message_copied":"Message copied","support.id_copied":"Report ID copied","support.copy_failed":"Could not access the clipboard. Select and copy the text manually.","support.validation.message_required":"Enter a message.","support.validation.message_too_long":"The message must contain no more than 10,000 characters.","support.validation.contact_too_long":"Contact details must contain no more than 320 characters.","support.validation.preview_missing":"Wait for the attachment preview or turn the attachment off.","support.validation.preview_expired":"The attachment preview expired. Refresh the snapshot.","support.error.support_invalid_message":"Check the message and try again.","support.error.support_preview_expired":"The attachment preview expired or is no longer available. Refresh the snapshot.","support.error.support_package_too_large":"The anonymized package exceeds the 8 MiB limit.","support.error.support_rate_limited":"Too many reports or previews were requested. Try again later.","support.error.support_unavailable":"The private support service is temporarily unavailable. Your draft remains here.","support.error.support_rejected":"The report did not pass the support service validation.","support.error.unauthorized":"You do not have permission to send this report.","vac.routes_section":"Maps and floors","vac.routes_current_map":"Current map","vac.routes_no_map":"no telemetry","vac.routes_status":"Routing","vac.routes_state_ready":"map assigned and calibrated","vac.routes_state_needs_calibration":"map assigned, calibration needed","vac.routes_state_unmapped":"current map is not assigned to a floor","vac.routes_state_ambiguous":"two maps are indistinguishable — no floor is chosen","vac.routes_state_missing_space":"the map's space was deleted","vac.routes_state_none":"no map data","vac.routes_empty":"No map is assigned to a floor yet.","vac.route_map_default":"no map id","vac.route_active":"Active","vac.route_space":"Space","vac.route_space_none":"not selected","vac.route_status_ready":"ready","vac.route_status_needs_calibration":"needs calibration","vac.route_status_ambiguous":"ambiguous","vac.route_status_missing_space":"space deleted","vac.route_missing_space_group":"Deleted space","vac.route_add_current":"Add current map","vac.route_delete":"Remove map","vac.route_delete_title":"Remove the map from its floor?","vac.route_delete_body":"Calibration and saved paths for this map will be removed. Continue?","vac.route_delete_confirm":"Remove","vac.route_space_title":"Move the map to another space?","vac.route_space_body":"Calibration and saved paths for this map will be removed. Continue?","vac.route_space_confirm":"Move","vac.route_missing_space_hint":"One of the maps points at a deleted space: pick a new one or remove the map. Until then the robot is not drawn for that map.","vac.route_default_hint":"The source reports no stable map id. Several floors cannot be told apart without another source or the robot's own selected map.","vac.route_target_hint":"The dock stays in the “{space}” space regardless of the current map.","vac.route_add_source":"Add a map source","vac.route_add_source_hint":"For integrations that give each map its own camera. The “All cameras” section above widens this list.","vac.route_source_no_map":"no map reported"};const na={en:aa,ru:{"gs.show_room_tooltip":"Показывать окно с информацией при наведении на комнату","support.about_group":"О карточке","support.guide_group":"Документация","support.guide":"Руководство пользователя","support.form_group":"Отправить репорт или предложение","support.contact":"Контакт для связи (email/tg/WhatsApp), необязательно.","support.message":"Сообщение","support.attach":"Прикрепить обезличенную информацию из вашего плана","support.attach_hint":"В пакет входят только разрешённые геометрия, настройки и ограниченные сведения о среде. Не входят имена, HA id, текущие состояния, URL, файлы, сообщение и контакт.","support.geometry_warning":"Пакет не содержит имён и HA id, но содержит точную геометрию и размеры дома.","support.close_busy_title":"Прервать текущую операцию?","support.close_busy_body":"House Plan подготавливает или отправляет репорт. При закрытии ожидание результата прекратится.","support.building":"Подготавливаем обезличенные данные…","support.preview_summary":"Пакет v{version} · пространств: {spaces} · {size} КиБ","support.prepared":"Снимок подготовлен {n} мин назад","support.show_data":"Показать данные","support.download":"Скачать JSON","support.refresh":"Обновить снимок","support.privacy":"При отправке сообщение, необязательный контакт и, если выбран пакет, точная геометрия покидают ваш Home Assistant через relay проекта House Plan и доступны мейнтейнерам. Узел проекта хранит репорт до 30 дней. Сетевая инфраструктура видит адрес сервера HA, но House Plan не сохраняет его в исходном виде; метаданные лимитов и идемпотентности хранятся до 24 часов.","support.error_title":"Репорт не отправлен","support.manual_recovery":"Сообщение и вложение можно сохранить и продолжить вручную:","support.copy_message":"Копировать сообщение","support.success":"Репорт отправлен: {id}. Сохраните номер для связи с поддержкой.","support.copy_id":"Копировать ID","support.sending":"Отправляем…","support.retry":"Повторить","support.send":"Отправить","support.update_required":"Обновите карточку и интеграцию House Plan до совместимых версий, чтобы отправлять репорты.","support.message_copied":"Сообщение скопировано","support.id_copied":"ID репорта скопирован","support.copy_failed":"Не удалось получить доступ к буферу обмена. Выделите и скопируйте текст вручную.","support.validation.message_required":"Введите сообщение.","support.validation.message_too_long":"Сообщение должно содержать не более 10 000 символов.","support.validation.contact_too_long":"Контакт должен содержать не более 320 символов.","support.validation.preview_missing":"Дождитесь предпросмотра вложения или отключите его.","support.validation.preview_expired":"Предпросмотр вложения истёк. Обновите снимок.","support.error.support_invalid_message":"Проверьте сообщение и повторите попытку.","support.error.support_preview_expired":"Предпросмотр вложения истёк или больше недоступен. Обновите снимок.","support.error.support_package_too_large":"Обезличенный пакет превышает лимит 8 МиБ.","support.error.support_rate_limited":"Запрошено слишком много репортов или предпросмотров. Повторите позже.","support.error.support_unavailable":"Закрытая служба поддержки временно недоступна. Черновик сохранён в этом окне.","support.error.support_rejected":"Репорт не прошёл проверку службы поддержки.","support.error.unauthorized":"У вас нет прав на отправку этого репорта.","vac.routes_section":"Карты и этажи","vac.routes_current_map":"Текущая карта","vac.routes_no_map":"источник молчит","vac.routes_status":"Маршрутизация","vac.routes_state_ready":"карта сопоставлена и откалибрована","vac.routes_state_needs_calibration":"карта сопоставлена, нужна калибровка","vac.routes_state_unmapped":"текущая карта не сопоставлена этажу","vac.routes_state_ambiguous":"две карты неразличимы — этаж не выбирается","vac.routes_state_missing_space":"пространство карты удалено","vac.routes_state_none":"нет данных о карте","vac.routes_empty":"Ни одна карта ещё не сопоставлена этажу.","vac.route_map_default":"без идентификатора","vac.route_active":"Текущая","vac.route_space":"Пространство","vac.route_space_none":"не выбрано","vac.route_status_ready":"готова","vac.route_status_needs_calibration":"нужна калибровка","vac.route_status_ambiguous":"неоднозначна","vac.route_status_missing_space":"пространство удалено","vac.route_missing_space_group":"Пространство удалено","vac.route_add_current":"Добавить текущую карту","vac.route_delete":"Удалить карту","vac.route_delete_title":"Удалить карту с этажа?","vac.route_delete_body":"Калибровка и сохранённые пути этой карты будут удалены. Продолжить?","vac.route_delete_confirm":"Удалить","vac.route_space_title":"Перенести карту в другое пространство?","vac.route_space_body":"Калибровка и сохранённые пути этой карты будут удалены. Продолжить?","vac.route_space_confirm":"Перенести","vac.route_missing_space_hint":"Одна из карт ссылается на удалённое пространство: выберите новое или удалите карту. Пока ссылка не исправлена, робот на этой карте не рисуется.","vac.route_default_hint":"Источник не сообщает стабильный идентификатор карты. Несколько этажей нельзя различить без другого источника или собственной карты робота.","vac.route_target_hint":"Док остаётся в пространстве «{space}» независимо от текущей карты.","vac.route_add_source":"Добавить источник карты","vac.route_add_source_hint":"Для интеграций, где у каждой карты своя камера. Список расширяется разделом «Все камеры» выше.","vac.route_source_no_map":"карта не читается"},de:{"gs.show_room_tooltip":"Rauminformationen beim Darüberfahren anzeigen","support.about_group":"Über die Karte","support.guide_group":"Dokumentation","support.guide":"Benutzerhandbuch","support.form_group":"Bericht oder Vorschlag senden","support.contact":"Kontakt (E-Mail/tg/WhatsApp), optional.","support.message":"Nachricht","support.attach":"Anonymisierte Informationen aus dem Plan anhängen","support.attach_hint":"Enthält nur erlaubte Plangeometrie, Einstellungen und begrenzte Laufzeitdaten. Namen, Home-Assistant-IDs, Live-Zustände, URLs, Dateien, Nachricht und Kontakt werden ausgeschlossen.","support.geometry_warning":"Das Paket enthält keine Namen oder Home-Assistant-IDs, aber die exakte Geometrie und die Maße Ihres Hauses.","support.close_busy_title":"Aktuellen Vorgang abbrechen?","support.close_busy_body":"House Plan bereitet den Bericht vor oder sendet ihn. Beim Schließen wird nicht weiter auf das Ergebnis gewartet.","support.building":"Anonymisierte Daten werden vorbereitet…","support.preview_summary":"Paket v{version} · {spaces} Bereiche · {size} KiB","support.prepared":"Schnappschuss vor {n} Min. erstellt","support.show_data":"Daten anzeigen","support.download":"JSON herunterladen","support.refresh":"Schnappschuss aktualisieren","support.privacy":"Beim Senden verlassen Ihre Nachricht, der optionale Kontakt und, falls ausgewählt, die exakte Geometrie Ihren Home Assistant über das House-Plan-Projektrelay und sind für die Maintainer sichtbar. Der Projektserver speichert den Bericht bis zu 30 Tage. Die Netzwerkinfrastruktur sieht die Adresse Ihres HA-Servers, House Plan speichert sie jedoch nicht im Rohformat; Limit- und Idempotenzdaten bleiben bis zu 24 Stunden erhalten.","support.error_title":"Der Bericht wurde nicht gesendet","support.manual_recovery":"Nachricht und Anhang können gespeichert und manuell weitergegeben werden:","support.copy_message":"Nachricht kopieren","support.success":"Bericht gesendet: {id}. Bewahren Sie diese Nummer für den Support auf.","support.copy_id":"ID kopieren","support.sending":"Wird gesendet…","support.retry":"Erneut versuchen","support.send":"Senden","support.update_required":"Aktualisieren Sie House-Plan-Karte und Integration auf kompatible Versionen, um Berichte zu senden.","support.message_copied":"Nachricht kopiert","support.id_copied":"Berichts-ID kopiert","support.copy_failed":"Kein Zugriff auf die Zwischenablage. Markieren und kopieren Sie den Text manuell.","support.validation.message_required":"Geben Sie eine Nachricht ein.","support.validation.message_too_long":"Die Nachricht darf höchstens 10.000 Zeichen enthalten.","support.validation.contact_too_long":"Der Kontakt darf höchstens 320 Zeichen enthalten.","support.validation.preview_missing":"Warten Sie auf die Vorschau oder deaktivieren Sie den Anhang.","support.validation.preview_expired":"Die Anhangsvorschau ist abgelaufen. Aktualisieren Sie den Schnappschuss.","support.error.support_invalid_message":"Prüfen Sie die Nachricht und versuchen Sie es erneut.","support.error.support_preview_expired":"Die Anhangsvorschau ist abgelaufen oder nicht mehr verfügbar. Aktualisieren Sie den Schnappschuss.","support.error.support_package_too_large":"Das anonymisierte Paket überschreitet das Limit von 8 MiB.","support.error.support_rate_limited":"Zu viele Berichte oder Vorschauen wurden angefordert. Versuchen Sie es später erneut.","support.error.support_unavailable":"Der private Supportdienst ist vorübergehend nicht verfügbar. Der Entwurf bleibt in diesem Fenster erhalten.","support.error.support_rejected":"Der Bericht hat die Prüfung des Supportdienstes nicht bestanden.","support.error.unauthorized":"Sie dürfen diesen Bericht nicht senden.","vac.routes_section":"Karten und Etagen","vac.routes_current_map":"Aktuelle Karte","vac.routes_no_map":"keine Telemetrie","vac.routes_status":"Zuordnung","vac.routes_state_ready":"Karte zugeordnet und kalibriert","vac.routes_state_needs_calibration":"Karte zugeordnet, Kalibrierung nötig","vac.routes_state_unmapped":"aktuelle Karte keiner Etage zugeordnet","vac.routes_state_ambiguous":"zwei Karten nicht unterscheidbar — keine Etage gewählt","vac.routes_state_missing_space":"der Raum der Karte wurde gelöscht","vac.routes_state_none":"keine Kartendaten","vac.routes_empty":"Noch keine Karte einer Etage zugeordnet.","vac.route_map_default":"ohne Karten-ID","vac.route_active":"Aktiv","vac.route_space":"Raum","vac.route_space_none":"nicht gewählt","vac.route_status_ready":"bereit","vac.route_status_needs_calibration":"Kalibrierung nötig","vac.route_status_ambiguous":"mehrdeutig","vac.route_status_missing_space":"Raum gelöscht","vac.route_missing_space_group":"Gelöschter Bereich","vac.route_add_current":"Aktuelle Karte hinzufügen","vac.route_delete":"Karte entfernen","vac.route_delete_title":"Karte von der Etage entfernen?","vac.route_delete_body":"Kalibrierung und gespeicherte Pfade dieser Karte werden entfernt. Fortfahren?","vac.route_delete_confirm":"Entfernen","vac.route_space_title":"Karte in einen anderen Raum verschieben?","vac.route_space_body":"Kalibrierung und gespeicherte Pfade dieser Karte werden entfernt. Fortfahren?","vac.route_space_confirm":"Verschieben","vac.route_missing_space_hint":"Eine Karte verweist auf einen gelöschten Raum: neuen wählen oder Karte entfernen. Bis dahin wird der Roboter für diese Karte nicht gezeichnet.","vac.route_default_hint":"Die Quelle meldet keine stabile Karten-ID. Mehrere Etagen lassen sich ohne andere Quelle oder die vom Roboter gewählte Karte nicht unterscheiden.","vac.route_target_hint":"Die Station bleibt unabhängig von der aktuellen Karte im Raum „{space}“.","vac.route_add_source":"Kartenquelle hinzufügen","vac.route_add_source_hint":"Für Integrationen, die jeder Karte eine eigene Kamera geben. Der Abschnitt „Alle Kameras“ oben erweitert diese Liste.","vac.route_source_no_map":"keine Karte gemeldet"},fr:{"gs.show_room_tooltip":"Afficher les informations de la pièce au survol","support.about_group":"À propos de la carte","support.guide_group":"Documentation d’aide","support.guide":"Guide utilisateur","support.form_group":"Envoyer un rapport ou une suggestion","support.contact":"Contact (e-mail/tg/WhatsApp), facultatif.","support.message":"Votre message","support.attach":"Joindre des informations anonymisées de votre plan","support.attach_hint":"Inclut uniquement la géométrie, les réglages autorisés et des données d’exécution limitées. Exclut les noms, identifiants Home Assistant, états en direct, URL, fichiers, message et contact.","support.geometry_warning":"Le paquet ne contient ni noms ni identifiants Home Assistant, mais il contient la géométrie et les dimensions exactes de votre logement.","support.close_busy_title":"Interrompre l’opération en cours ?","support.close_busy_body":"House Plan prépare ou envoie le rapport. Fermer maintenant arrête l’attente du résultat.","support.building":"Préparation des données anonymisées…","support.preview_summary":"Paquet v{version} · {spaces} espaces · {size} Kio","support.prepared":"Instantané préparé il y a {n} min","support.show_data":"Afficher les données","support.download":"Télécharger le JSON","support.refresh":"Actualiser l’instantané","support.privacy":"Lors de l’envoi, votre message, le contact facultatif et, si elle est sélectionnée, la géométrie exacte quittent votre Home Assistant via le relais du projet House Plan et sont visibles par les mainteneurs. Le serveur du projet conserve le rapport jusqu’à 30 jours. L’infrastructure réseau voit l’adresse de votre serveur HA, mais House Plan ne la conserve pas en clair ; les métadonnées de limitation et d’idempotence sont gardées jusqu’à 24 heures.","support.error_title":"Le rapport n’a pas été envoyé","support.manual_recovery":"Vous pouvez conserver le message et la pièce jointe puis continuer manuellement :","support.copy_message":"Copier le message","support.success":"Rapport envoyé : {id}. Conservez ce numéro pour contacter l’assistance.","support.copy_id":"Copier l’ID","support.sending":"Envoi…","support.retry":"Réessayer","support.send":"Envoyer","support.update_required":"Mettez à jour la carte et l’intégration House Plan vers des versions compatibles pour envoyer des rapports.","support.message_copied":"Message copié","support.id_copied":"ID du rapport copié","support.copy_failed":"Impossible d’accéder au presse-papiers. Sélectionnez et copiez le texte manuellement.","support.validation.message_required":"Saisissez un message.","support.validation.message_too_long":"Le message ne doit pas dépasser 10 000 caractères.","support.validation.contact_too_long":"Le contact ne doit pas dépasser 320 caractères.","support.validation.preview_missing":"Attendez l’aperçu de la pièce jointe ou désactivez-la.","support.validation.preview_expired":"L’aperçu de la pièce jointe a expiré. Actualisez l’instantané.","support.error.support_invalid_message":"Vérifiez le message et réessayez.","support.error.support_preview_expired":"L’aperçu de la pièce jointe a expiré ou n’est plus disponible. Actualisez l’instantané.","support.error.support_package_too_large":"Le paquet anonymisé dépasse la limite de 8 Mio.","support.error.support_rate_limited":"Trop de rapports ou d’aperçus ont été demandés. Réessayez plus tard.","support.error.support_unavailable":"Le service d’assistance privé est temporairement indisponible. Le brouillon reste dans cette fenêtre.","support.error.support_rejected":"Le rapport n’a pas passé la validation du service d’assistance.","support.error.unauthorized":"Vous n’êtes pas autorisé à envoyer ce rapport.","vac.routes_section":"Cartes et étages","vac.routes_current_map":"Carte actuelle","vac.routes_no_map":"aucune télémétrie","vac.routes_status":"Routage","vac.routes_state_ready":"carte assignée et calibrée","vac.routes_state_needs_calibration":"carte assignée, calibrage requis","vac.routes_state_unmapped":"carte actuelle non assignée à un étage","vac.routes_state_ambiguous":"deux cartes indiscernables — aucun étage choisi","vac.routes_state_missing_space":"l'espace de la carte a été supprimé","vac.routes_state_none":"aucune donnée de carte","vac.routes_empty":"Aucune carte n'est encore assignée à un étage.","vac.route_map_default":"sans identifiant","vac.route_active":"Active","vac.route_space":"Espace","vac.route_space_none":"non sélectionné","vac.route_status_ready":"prête","vac.route_status_needs_calibration":"calibrage requis","vac.route_status_ambiguous":"ambiguë","vac.route_status_missing_space":"espace supprimé","vac.route_missing_space_group":"Espace supprimé","vac.route_add_current":"Ajouter la carte actuelle","vac.route_delete":"Supprimer la carte","vac.route_delete_title":"Retirer la carte de son étage ?","vac.route_delete_body":"Le calibrage et les trajets enregistrés de cette carte seront supprimés. Continuer ?","vac.route_delete_confirm":"Supprimer","vac.route_space_title":"Déplacer la carte vers un autre espace ?","vac.route_space_body":"Le calibrage et les trajets enregistrés de cette carte seront supprimés. Continuer ?","vac.route_space_confirm":"Déplacer","vac.route_missing_space_hint":"Une carte pointe vers un espace supprimé : choisissez-en un autre ou supprimez la carte. D'ici là, le robot n'est pas dessiné pour cette carte.","vac.route_default_hint":"La source ne fournit pas d'identifiant de carte stable. Plusieurs étages ne peuvent pas être distingués sans une autre source ou la carte sélectionnée du robot.","vac.route_target_hint":"La station reste dans l'espace « {space} » quelle que soit la carte actuelle.","vac.route_add_source":"Ajouter une source de carte","vac.route_add_source_hint":"Pour les intégrations qui donnent à chaque carte sa propre caméra. La section « Toutes les caméras » ci-dessus élargit cette liste.","vac.route_source_no_map":"aucune carte signalée"}};function ra(t,e,s){return i(na[t]?.[e]??aa[e]??e,s)}function la(t,e,s,i,o){return{markerId:t,source:i,mapId:o,space:e.length?"":s}}function ha(t,e,s){return{...t,space:s.has(e)?e:""}}function ca(t,e=Math.random){const s=new Set(t);for(let t=0;t<64;t+=1){const t="vr_"+Math.floor(16777215*e()).toString(36).padStart(5,"0");if(!s.has(t))return t}return"vr_"+Date.now().toString(36)}function da(t,e,s){return t.map(t=>t.id===e?{...t,calibration:s}:t)}const pa=new WeakMap,ua=(t,e)=>{const s=(t._serverCfg?.spaces||[]).find(t=>t?.id===e);return String(s?.name||s?.id||e)};function _a(t,e,s){const i=t.host,n=l(i.hass,i._config?.language),r=(t,e)=>ra(n,t,e),u=e.marker?.vacuum||{},_=Array.isArray(u.map_routes),m=i._vacSource(e)||"",g=o(e.id,u,e.space,m),f=(i._serverCfg?.spaces||[]).filter(t=>"string"==typeof t?.id&&!!t.id).map(t=>({id:t.id,name:String(t.name||t.id)})),b=new Set(f.map(t=>t.id)),v=h(g,[m],t=>i._vacObservedMapId(e,t)),y=c({routes:g,observed:v,spaceIds:b}),w="ready"===y.kind||"needs_calibration"===y.kind||"missing_space"===y.kind?y.route.id:"",$=m?v[m]:void 0,k=async s=>{let o=_?u.map_routes??null:null;if(!o&&(o=function(t,e,s,i){if(!s)return null;const o=t?.calibration;if(!o||"object"!=typeof o)return null;const n=new Set,r=[];for(const t of Object.keys(o)){const l=a(o[t]);if(!l)continue;const h=i(n);n.add(h),r.push({id:h,source:s,map_id:t,space:e,calibration:l})}return r.length?r:null}(u,e.space,m,t=>ca(t))??[],!m&&Object.keys(u.calibration||{}).length))return!1;const n=s(o);return!!n&&(async s=>{const o=i._serverCfg;if(!o)return!1;const a=JSON.parse(JSON.stringify(o));a.markers=a.markers||[];let n=a.markers.find(t=>t.id===e.id);if(!n){if("device"!==e.bindingKind&&"entity"!==e.bindingKind||!e.bindingRef)return!1;n={id:e.id,binding:`${e.bindingKind}:${e.bindingRef}`,space:e.space||null,area:e.area||null,hidden:!!e.hidden},a.markers.push(n)}n.vacuum={...n.vacuum||{},map_routes:s},delete n.vacuum.calibration;const r=i._adoption.beginOptimistic(o,a);i._adoption.stageLocalConfig(a),i._regSignature="",i._maybeRebuildDevices(),i.requestUpdate(),i._saveConfigDebounced.pending()&&i._saveConfigDebounced.cancel();try{return await t._saveConfigNow(),!0}catch(t){return i._rollbackOptimistic(r),i._regSignature="",i._maybeRebuildDevices(),i.requestUpdate(),i._showToast(i._t("toast.cfg_save_failed",{err:i._errText(t)})),!1}})(n)},x=s.candidates.filter(t=>t.entityId!==m&&!g.some(e=>e.source===t.entityId)),M=async(t,e)=>{if(!e||e===t.space)return;await i._confirmDanger({key:"vacuum_route_space",kind:"warning",title:r("vac.route_space_title"),message:r("vac.route_space_body"),objectName:t.map_id||r("vac.route_map_default"),confirmLabel:r("vac.route_space_confirm"),cancelLabel:i._t("btn.cancel")})&&await k(s=>function(t,e,s,i){return t.map(t=>t.id===e?{...t,id:i,space:s,calibration:null}:t)}(s,t.id,e,ca(new Set(g.map(t=>t.id)))))},C=new Map(f.map((t,e)=>[t.id,e])),S=(t,e)=>t.map_id.localeCompare(e.map_id)||t.source.localeCompare(e.source)||t.id.localeCompare(e.id),P=g.filter(t=>b.has(t.space)).sort((t,e)=>(C.get(t.space)??0)-(C.get(e.space)??0)||S(t,e)),D=g.filter(t=>!b.has(t.space)).sort(S),I=[...P,...D],L=!!m&&void 0!==$&&!g.some(t=>t.source===m&&t.map_id===$);let T=pa.get(t);const R=T?.source||"",z=T?.mapId||"",F=!!T&&g.some(t=>t.source===R&&t.map_id===z);T&&(T.markerId!==e.id||i._vacObservedMapId(e,T.source)!==T.mapId||F&&!T.saving)&&(pa.delete(t),T=void 0),T?.space&&!b.has(T.space)&&(T=ha(T,"",b),pa.set(t,T));const N=s=>p`
  • ${s.map_id||r("vac.route_map_default")} @@ -81,28 +81,28 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${g.some(t=>"default"===t.map_id)?p`
    ${r("vac.route_default_hint")}
    `:d} ${I.length?p`
    ${r("vac.route_target_hint",{space:ua(i,e.space)})}
    `:d} -
    `}const ma=new Set(["bindingOpen","bindingFilter","runFilter","controlsFilter","busy","tapHintAnnouncement","uploadId","autoIcon"]);function ga(t){return mo(t,ma)}function fa(t){fo(t,"marker")}function ba(t){const e=[];return"ha"!==t.bindingMode||t.binding&&"virtual"!==t.binding||e.push({field:"marker-binding",message:"marker.error_binding"}),function(t){if(!t.trim())return!0;const e=u(t);return null!==e&&e>0}(t.glowRadius)||e.push({field:"marker-glow-radius",message:"marker.error_glow_radius"}),e}const va=new Set(["ld2450","hlkld2450","hilinkld2450"]),ya=()=>globalThis.crypto?.randomUUID?.()||`radar_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,8)}`,wa=(t,e,s)=>{const i=!!t?.original;return{radar:i?t:null,radarEligible:i,radarTouched:i?e:e||!!t,radarRemove:i?s:s||!!t}},$a=(t,e="")=>"number"==typeof t&&Number.isFinite(t)?String(t):e,ka=t=>Array.from(new Set([...t.allEntities||t.entities||[],..."entity"===t.bindingKind&&t.bindingRef?[t.bindingRef]:[]])).filter(t=>/^[a-z0-9_]+\.[a-z0-9_]+$/.test(t)),xa=(t,e,s)=>{const i=t.split(".",2)[1]||"";return new RegExp(`(?:^|_)target_?${s}_${e}(?:_|$)`).test(i)||new RegExp(`(?:^|_)target_${e}_${s}(?:_|$)`).test(i)};function Ma(t,e){if(t.marker?.radar&&"object"==typeof t.marker.radar)return _(t.marker.radar)?{eligible:!0,profile:t.marker.radar.profile,reason:"saved"}:{eligible:!0,profile:"presence_v1",reason:"saved_unsupported"};const s="entity"===t.bindingKind?e?.entities?.[t.bindingRef||""]:null,i="device"===t.bindingKind?t.bindingRef:s?.device_id,o=i?e?.devices?.[i]:null,a=ka(t);return va.has((n=o?.model||t.model,String(n||"").toLowerCase().replace(/[^a-z0-9]/g,"")))&&a.some(t=>xa(t,"x",1))&&a.some(t=>xa(t,"y",1))?{eligible:!0,profile:"esphome_ld2450_v1",reason:"ld2450"}:{eligible:!1,profile:"presence_v1",reason:"none"};var n}function Ca(t,e){return t.find(t=>e.some(e=>e.test(t)))||""}function Sa(t,e,s,i,o=!1){const a=Ma(t,i),n=_(t.marker?.radar)?t.marker.radar:null;if(!n&&!a.eligible&&!o)return null;const r=n?.profile||a.profile,l=o&&!a.eligible||"ld2450"!==a.reason?{xEntities:["","",""],yEntities:["","",""],distanceEntity:"",angleEntity:"",occupancyEntity:"",countEntity:"",zoneEntity:""}:function(t,e,s){const i=ka(t).filter(t=>!!s?.states?.[t]),o=[],a=[];for(let t=1;t<=3;t++)o.push(i.find(e=>xa(e,"x",t))||""),a.push(i.find(e=>xa(e,"y",t))||"");const n=i.filter(t=>t.startsWith("binary_sensor.")),r=i.filter(t=>t.startsWith("sensor.")),l=Ca(n,[/(?:occupancy|presence|target)(?:_|$)/]);return{xEntities:o,yEntities:a,distanceEntity:Ca(r,[/(?:target_)?distance(?:_|$)/,/distance/]),angleEntity:Ca(r,[/(?:target_)?angle(?:_|$)/,/angle/]),occupancyEntity:l,countEntity:Ca(r,[/(?:target|people|presence)_count(?:_|$)/,/target_count/]),zoneEntity:"zones_v1"===e?Ca(n,[/(?:zone|region).*(?:occupancy|presence)/,/zone/]):""}}(t,r,i),h=n?.sources||{},c=h.slots||[],d=c.filter(t=>"x_entity"in t),p=c.filter(t=>"distance_entity"in t),u=h.ranges||[],m=h.zones?.[0],g="esphome_ld2450_v1"===r?3:"cartesian_v1"===r?Math.max(1,d.length):"polar_v1"===r?Math.max(1,p.length):1,f=n?.room_id||t.marker?.room_id||e.rooms.find(e=>e.area&&e.area===t.area)?.id||"";return{original:n,enabled:!0===n?.enabled,showLive:!1!==n?.show_live,profile:r,roomId:f,installationId:n?.mount?.installation_id||ya(),mountX:$a(null==n?.mount?.x?void 0:1e3*n.mount.x,$a(s[0],"0")),mountY:$a(null==n?.mount?.y?void 0:1e3*n.mount.y,$a(s[1],"0")),heading:$a(n?.mount?.heading_deg,"0"),rangeCm:$a(n?.mount?.range_cm,"esphome_ld2450_v1"===r?"600":""),fovDeg:$a(n?.mount?.fov_deg,"esphome_ld2450_v1"===r?"120":""),mirror:!0===n?.calibration?.mirror,unit:d[0]?.unit||p[0]?.unit||u[0]?.unit||("esphome_ld2450_v1"===r?"mm":"cm"),xEntities:Array.from({length:g},(t,e)=>d[e]?.x_entity||l.xEntities[e]||""),yEntities:Array.from({length:g},(t,e)=>d[e]?.y_entity||l.yEntities[e]||""),distanceEntities:Array.from({length:g},(t,e)=>p[e]?.distance_entity||(0===e?l.distanceEntity:"")),angleEntities:Array.from({length:g},(t,e)=>p[e]?.angle_entity||(0===e?l.angleEntity:"")),rangeEntities:u.length?u.map(t=>t.entity_id):[l.distanceEntity],slotPresenceEntities:Array.from({length:g},(t,e)=>(d[e]||p[e])?.presence_entity||""),rangePresenceEntities:(u.length?u:[{}]).map(t=>"presence_entity"in t&&t.presence_entity||""),swapXY:Array.from({length:g},(t,e)=>!0===d[e]?.swap_xy),xSigns:Array.from({length:g},(t,e)=>-1===d[e]?.x_sign?-1:1),ySigns:Array.from({length:g},(t,e)=>-1===d[e]?.y_sign?-1:1),angleUnit:p[0]?.angle_unit||"degrees",angleZero:p[0]?.angle_zero||"forward",angleClockwise:!1!==p[0]?.angle_clockwise,occupancyEntity:h.occupancy_entity||l.occupancyEntity,countEntity:h.count_entity||l.countEntity,availabilityEntity:h.availability_entity||"",zoneEntity:m?.entity_id||l.zoneEntity,zoneKind:m?.kind||"occupancy"}}const Pa=t=>JSON.stringify(t,(t,e)=>e&&"object"==typeof e&&!Array.isArray(e)?Object.fromEntries(Object.entries(e).sort(([t],[e])=>te?1:0)):e),Da=t=>{if(!t.trim())return null;const e=Number(t.replace(",","."));return Number.isFinite(e)?e:null};function Ia(t,e){const s=Da(t.mountX),i=Da(t.mountY),o=Da(t.heading);if(!t.roomId||null==s||null==i||null==o)return null;const a={...t.original?.sources||{}};if(delete a.slots,delete a.ranges,delete a.zones,delete a.occupancy_entity,delete a.count_entity,"esphome_ld2450_v1"===t.profile||"cartesian_v1"===t.profile){if(a.slots=t.xEntities.flatMap((e,s)=>{const i=t.yEntities[s]||"";return e&&i?[{id:`target_${s+1}`,x_entity:e,y_entity:i,unit:"esphome_ld2450_v1"===t.profile?"mm":t.unit,..."cartesian_v1"===t.profile&&t.swapXY[s]?{swap_xy:!0}:{},..."cartesian_v1"===t.profile&&-1===t.xSigns[s]?{x_sign:-1}:{},..."cartesian_v1"===t.profile&&-1===t.ySigns[s]?{y_sign:-1}:{},...t.slotPresenceEntities[s]?{presence_entity:t.slotPresenceEntities[s]}:{}}]:[]}),!a.slots.length)return null}else if("polar_v1"===t.profile){if(a.slots=t.distanceEntities.flatMap((e,s)=>{const i=t.angleEntities[s]||"";return e&&i?[{id:`target_${s+1}`,distance_entity:e,angle_entity:i,unit:t.unit,angle_unit:t.angleUnit,angle_zero:t.angleZero,angle_clockwise:t.angleClockwise,...t.slotPresenceEntities[s]?{presence_entity:t.slotPresenceEntities[s]}:{}}]:[]}),!a.slots.length)return null}else if("range_v1"===t.profile){if(a.ranges=t.rangeEntities.flatMap((e,s)=>e?[{id:`range_${s+1}`,entity_id:e,unit:t.unit,...t.rangePresenceEntities[s]?{presence_entity:t.rangePresenceEntities[s]}:{}}]:[]),!a.ranges.length)return null}else if("zones_v1"===t.profile){if(!t.zoneEntity)return null;a.zones=[{id:"zone_1",kind:t.zoneKind,entity_id:t.zoneEntity}]}else if("presence_v1"===t.profile&&!t.occupancyEntity)return null;t.occupancyEntity&&(a.occupancy_entity=t.occupancyEntity),t.countEntity&&(a.count_entity=t.countEntity),t.availabilityEntity&&(a.availability_entity=t.availabilityEntity);const n=Da(t.rangeCm),r=Da(t.fovDeg),l=(o%360+360)%360,h={...t.original?.mount||{},installation_id:t.installationId,x:s/1e3,y:i/1e3,heading_deg:l};null!=n&&n>0?h.range_cm=n:delete h.range_cm,null!=r&&r>0?h.fov_deg=r:delete h.fov_deg;const c=t.original,d="two_point"===c?.calibration?.method&&c.profile===t.profile&&Pa(c.sources)===Pa(a)&&c.mount.installation_id===t.installationId&&Math.abs(c.mount.x-h.x)<1e-12&&Math.abs(c.mount.y-h.y)<1e-12&&Math.abs(c.mount.heading_deg-l)<1e-9&&c.calibration.mirror===t.mirror&&Math.abs(c.calibration.cell_cm-e)<1e-9,p=t.calibrationOverride?{...t.calibrationOverride}:d?{...c.calibration}:{...c?.calibration||{},method:"zones_v1"===t.profile||"presence_v1"===t.profile?"not_required":"manual",mirror:t.mirror,cell_cm:e};t.calibrationOverride||d||(delete p.refs,delete p.rms_cm);const u={...t.original||{},version:1,enabled:t.enabled,profile:t.profile,sources:a,mount:h,room_id:t.roomId,calibration:p};return t.showLive?delete u.show_live:u.show_live=!1,u}const La={badge:"display.badge",icon_ripple:"display.icon_ripple",value:"display.value",static_icon:"display.static_icon",value_static_icon:"display.value_static_icon"},Ta={badge:"marker.display_hint_badge",icon_ripple:"marker.display_hint_icon_ripple",value:"marker.display_hint_value",static_icon:"marker.display_hint_static_icon",value_static_icon:"marker.display_hint_value_static_icon"},Ra=["top","right","bottom","left"];function za(t,e,s){return p``}const ma=new Set(["bindingOpen","bindingFilter","runFilter","controlsFilter","busy","tapHintAnnouncement","uploadId","autoIcon"]);function ga(t){return mo(t,ma)}function fa(t){fo(t,"marker")}const ba=new Set(["ld2450","hlkld2450","hilinkld2450"]),va=()=>globalThis.crypto?.randomUUID?.()||`radar_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,8)}`,ya=(t,e,s)=>{const i=!!t?.original;return{radar:i?t:null,radarEligible:i,radarTouched:i?e:e||!!t,radarRemove:i?s:s||!!t}},wa=(t,e="")=>"number"==typeof t&&Number.isFinite(t)?String(t):e,$a=t=>Array.from(new Set([...t.allEntities||t.entities||[],..."entity"===t.bindingKind&&t.bindingRef?[t.bindingRef]:[]])).filter(t=>/^[a-z0-9_]+\.[a-z0-9_]+$/.test(t)),ka=(t,e,s)=>{const i=t.split(".",2)[1]||"";return new RegExp(`(?:^|_)target_?${s}_${e}(?:_|$)`).test(i)||new RegExp(`(?:^|_)target_${e}_${s}(?:_|$)`).test(i)};function xa(t,e){if(t.marker?.radar&&"object"==typeof t.marker.radar)return u(t.marker.radar)?{eligible:!0,profile:t.marker.radar.profile,reason:"saved"}:{eligible:!0,profile:"presence_v1",reason:"saved_unsupported"};const s="entity"===t.bindingKind?e?.entities?.[t.bindingRef||""]:null,i="device"===t.bindingKind?t.bindingRef:s?.device_id,o=i?e?.devices?.[i]:null,a=$a(t);return ba.has((n=o?.model||t.model,String(n||"").toLowerCase().replace(/[^a-z0-9]/g,"")))&&a.some(t=>ka(t,"x",1))&&a.some(t=>ka(t,"y",1))?{eligible:!0,profile:"esphome_ld2450_v1",reason:"ld2450"}:{eligible:!1,profile:"presence_v1",reason:"none"};var n}function Ma(t,e){return t.find(t=>e.some(e=>e.test(t)))||""}function Ca(t,e,s,i,o=!1){const a=xa(t,i),n=u(t.marker?.radar)?t.marker.radar:null;if(!n&&!a.eligible&&!o)return null;const r=n?.profile||a.profile,l=o&&!a.eligible||"ld2450"!==a.reason?{xEntities:["","",""],yEntities:["","",""],distanceEntity:"",angleEntity:"",occupancyEntity:"",countEntity:"",zoneEntity:""}:function(t,e,s){const i=$a(t).filter(t=>!!s?.states?.[t]),o=[],a=[];for(let t=1;t<=3;t++)o.push(i.find(e=>ka(e,"x",t))||""),a.push(i.find(e=>ka(e,"y",t))||"");const n=i.filter(t=>t.startsWith("binary_sensor.")),r=i.filter(t=>t.startsWith("sensor.")),l=Ma(n,[/(?:occupancy|presence|target)(?:_|$)/]);return{xEntities:o,yEntities:a,distanceEntity:Ma(r,[/(?:target_)?distance(?:_|$)/,/distance/]),angleEntity:Ma(r,[/(?:target_)?angle(?:_|$)/,/angle/]),occupancyEntity:l,countEntity:Ma(r,[/(?:target|people|presence)_count(?:_|$)/,/target_count/]),zoneEntity:"zones_v1"===e?Ma(n,[/(?:zone|region).*(?:occupancy|presence)/,/zone/]):""}}(t,r,i),h=n?.sources||{},c=h.slots||[],d=c.filter(t=>"x_entity"in t),p=c.filter(t=>"distance_entity"in t),_=h.ranges||[],m=h.zones?.[0],g="esphome_ld2450_v1"===r?3:"cartesian_v1"===r?Math.max(1,d.length):"polar_v1"===r?Math.max(1,p.length):1,f=n?.room_id||t.marker?.room_id||e.rooms.find(e=>e.area&&e.area===t.area)?.id||"";return{original:n,enabled:!0===n?.enabled,showLive:!1!==n?.show_live,profile:r,roomId:f,installationId:n?.mount?.installation_id||va(),mountX:wa(null==n?.mount?.x?void 0:1e3*n.mount.x,wa(s[0],"0")),mountY:wa(null==n?.mount?.y?void 0:1e3*n.mount.y,wa(s[1],"0")),heading:wa(n?.mount?.heading_deg,"0"),rangeCm:wa(n?.mount?.range_cm,"esphome_ld2450_v1"===r?"600":""),fovDeg:wa(n?.mount?.fov_deg,"esphome_ld2450_v1"===r?"120":""),mirror:!0===n?.calibration?.mirror,unit:d[0]?.unit||p[0]?.unit||_[0]?.unit||("esphome_ld2450_v1"===r?"mm":"cm"),xEntities:Array.from({length:g},(t,e)=>d[e]?.x_entity||l.xEntities[e]||""),yEntities:Array.from({length:g},(t,e)=>d[e]?.y_entity||l.yEntities[e]||""),distanceEntities:Array.from({length:g},(t,e)=>p[e]?.distance_entity||(0===e?l.distanceEntity:"")),angleEntities:Array.from({length:g},(t,e)=>p[e]?.angle_entity||(0===e?l.angleEntity:"")),rangeEntities:_.length?_.map(t=>t.entity_id):[l.distanceEntity],slotPresenceEntities:Array.from({length:g},(t,e)=>(d[e]||p[e])?.presence_entity||""),rangePresenceEntities:(_.length?_:[{}]).map(t=>"presence_entity"in t&&t.presence_entity||""),swapXY:Array.from({length:g},(t,e)=>!0===d[e]?.swap_xy),xSigns:Array.from({length:g},(t,e)=>-1===d[e]?.x_sign?-1:1),ySigns:Array.from({length:g},(t,e)=>-1===d[e]?.y_sign?-1:1),angleUnit:p[0]?.angle_unit||"degrees",angleZero:p[0]?.angle_zero||"forward",angleClockwise:!1!==p[0]?.angle_clockwise,occupancyEntity:h.occupancy_entity||l.occupancyEntity,countEntity:h.count_entity||l.countEntity,availabilityEntity:h.availability_entity||"",zoneEntity:m?.entity_id||l.zoneEntity,zoneKind:m?.kind||"occupancy"}}const Sa=t=>JSON.stringify(t,(t,e)=>e&&"object"==typeof e&&!Array.isArray(e)?Object.fromEntries(Object.entries(e).sort(([t],[e])=>te?1:0)):e),Pa=t=>{if(!t.trim())return null;const e=Number(t.replace(",","."));return Number.isFinite(e)?e:null};function Da(t,e){const s=Pa(t.mountX),i=Pa(t.mountY),o=Pa(t.heading);if(!t.roomId||null==s||null==i||null==o)return null;const a={...t.original?.sources||{}};if(delete a.slots,delete a.ranges,delete a.zones,delete a.occupancy_entity,delete a.count_entity,"esphome_ld2450_v1"===t.profile||"cartesian_v1"===t.profile){if(a.slots=t.xEntities.flatMap((e,s)=>{const i=t.yEntities[s]||"";return e&&i?[{id:`target_${s+1}`,x_entity:e,y_entity:i,unit:"esphome_ld2450_v1"===t.profile?"mm":t.unit,..."cartesian_v1"===t.profile&&t.swapXY[s]?{swap_xy:!0}:{},..."cartesian_v1"===t.profile&&-1===t.xSigns[s]?{x_sign:-1}:{},..."cartesian_v1"===t.profile&&-1===t.ySigns[s]?{y_sign:-1}:{},...t.slotPresenceEntities[s]?{presence_entity:t.slotPresenceEntities[s]}:{}}]:[]}),!a.slots.length)return null}else if("polar_v1"===t.profile){if(a.slots=t.distanceEntities.flatMap((e,s)=>{const i=t.angleEntities[s]||"";return e&&i?[{id:`target_${s+1}`,distance_entity:e,angle_entity:i,unit:t.unit,angle_unit:t.angleUnit,angle_zero:t.angleZero,angle_clockwise:t.angleClockwise,...t.slotPresenceEntities[s]?{presence_entity:t.slotPresenceEntities[s]}:{}}]:[]}),!a.slots.length)return null}else if("range_v1"===t.profile){if(a.ranges=t.rangeEntities.flatMap((e,s)=>e?[{id:`range_${s+1}`,entity_id:e,unit:t.unit,...t.rangePresenceEntities[s]?{presence_entity:t.rangePresenceEntities[s]}:{}}]:[]),!a.ranges.length)return null}else if("zones_v1"===t.profile){if(!t.zoneEntity)return null;a.zones=[{id:"zone_1",kind:t.zoneKind,entity_id:t.zoneEntity}]}else if("presence_v1"===t.profile&&!t.occupancyEntity)return null;t.occupancyEntity&&(a.occupancy_entity=t.occupancyEntity),t.countEntity&&(a.count_entity=t.countEntity),t.availabilityEntity&&(a.availability_entity=t.availabilityEntity);const n=Pa(t.rangeCm),r=Pa(t.fovDeg),l=(o%360+360)%360,h={...t.original?.mount||{},installation_id:t.installationId,x:s/1e3,y:i/1e3,heading_deg:l};null!=n&&n>0?h.range_cm=n:delete h.range_cm,null!=r&&r>0?h.fov_deg=r:delete h.fov_deg;const c=t.original,d="two_point"===c?.calibration?.method&&c.profile===t.profile&&Sa(c.sources)===Sa(a)&&c.mount.installation_id===t.installationId&&Math.abs(c.mount.x-h.x)<1e-12&&Math.abs(c.mount.y-h.y)<1e-12&&Math.abs(c.mount.heading_deg-l)<1e-9&&c.calibration.mirror===t.mirror&&Math.abs(c.calibration.cell_cm-e)<1e-9,p=t.calibrationOverride?{...t.calibrationOverride}:d?{...c.calibration}:{...c?.calibration||{},method:"zones_v1"===t.profile||"presence_v1"===t.profile?"not_required":"manual",mirror:t.mirror,cell_cm:e};t.calibrationOverride||d||(delete p.refs,delete p.rms_cm);const u={...t.original||{},version:1,enabled:t.enabled,profile:t.profile,sources:a,mount:h,room_id:t.roomId,calibration:p};return t.showLive?delete u.show_live:u.show_live=!1,u}const Ia={badge:"display.badge",icon_ripple:"display.icon_ripple",value:"display.value",static_icon:"display.static_icon",value_static_icon:"display.value_static_icon"},La={badge:"marker.display_hint_badge",icon_ripple:"marker.display_hint_icon_ripple",value:"marker.display_hint_value",static_icon:"marker.display_hint_static_icon",value_static_icon:"marker.display_hint_value_static_icon"},Ta=["top","right","bottom","left"];function Ra(t,e,s){return p` ${t} - `}function Fa(){bo(this.host);const t=this.host._markerDialog,e=this.host._t.bind(this.host),{st:s,shelp:i}=vo(this.host),o="virtual"===t.bindingMode,a=this._bindingCandidates(),n=o?null:this.host._bindingStatus(t.binding),r=!o&&this.host._bindingHasHaPage(t.binding),l=this._markerPreviewDevice(t),h=this._effectiveMarkerTapAction(t,l),c=l?m(this.host._serverCfg?.spaces.find(t=>t.id===l.space)):null,u=l?this._markerPreviewDevices(l):this.host._devices,_="toggle"===h&&l?this._toggleIntent(l,u):null,z=this._toggleHintLines(_),F=l?g(this.host._planHass,l,{liveStates:!1!==this.host._config?.live_states,showTemperature:!1!==this.host._config?.show_temperature,showSignal:c?.showLqi??!1!==this.host._config?.show_signal,designPreview:!0,activityRuntime:this.host._activityRt.get(l.id),lightDevices:u,registryHass:this.host._fullRegistryHass,reducedMotion:this.host._reducedMotion}):null,N=l?f(this.host._planHass,l,u):[],A=l?b(this.host._planHass,l,N):null,E=t.valueBadgeTouched?t.valueBadgeEnabled:!!F?.valueBadge,O=t.valueBadgeTouched?t.valueBadgeSource:F?.valueBadge?.source||t.valueBadgeSource,B=t.valueBadgeTouched?t.valueBadgePosition:F?.valueBadge?.position||t.valueBadgePosition,H=v(O),W=!!O&&!N.some(t=>t.key===H),j=N.find(t=>t.key===H),G=v(t.valueSource),q=!(!t.valueSource||G&&N.some(t=>t.key===G)),U=N.find(t=>t.key===G),K=F?.valueSource?.sourceKey||"",V=this._markerAutoHasSpatialSource(t),J=!!l&&y(this.host._planHass,{...l}),Z=w(t.lightRole,V,J,t.glowMode),Y=!Z.sourceExists,X=!Z.fromSourceEnabled,Q=Z.passive,tt=Z.effectiveMode,et="never"===t.lightRole?e("marker.glow_disabled_never"):"auto"!==t.lightRole||V?e(Q?"marker.glow_passive_hint":"marker.glow_disabled_no_entity"):e("marker.glow_disabled_auto"),st=l?$(l):[],it=l&&k(l)||"",ot=!!t.lightEntity&&!st.includes(t.lightEntity),at=l?x(l):[],nt=!!t.toggleEntity&&!at.includes(t.toggleEntity),rt="toggle"===h?this._toggleIntentForDialog({...t,toggleEntity:"",toggleEntityTouched:!0}):null,lt=rt?[...rt.targets,...rt.skippedTargets].map(t=>t.entityId||("ref"in t?t.ref:"")).filter(Boolean).join(", "):"",ht=(()=>{if(o)return null;const e=a.find(e=>e.value===t.binding);if(e)return e.label;const[s,i]=t.binding.split(":");return"device"===s?this.host._fullRegistryHass.devices[i]?.name_by_user||this.host._fullRegistryHass.devices[i]?.name||i:this.host._fullRegistryHass.entities[i]?.name||this.host.hass.states[i]?.attributes?.friendly_name||i})(),ct=t=>this.host.hass.states[t]?.attributes?.friendly_name||this.host._fullRegistryHass.entities[t]?.name||t,dt=this.host._imperial?e("gs.unit_ft"):e("gs.unit_m"),pt=!!t.devId,ut=ba(t),_t=t=>ut.find(e=>e.field===t),mt=function(t,e){return go(t,"marker",ga(e))}(this.host,t),gt="ha"===t.bindingMode&&!t.devId&&"active"!==n?.kind,ft=!t.busy&&!this._radarSetup.isActive()&&0===ut.length&&!gt&&(!pt||mt),bt=ut[0]?s(ut[0].message):gt&&t.binding&&"virtual"!==t.binding?e("marker.ha_registry_limited"):"",vt=async e=>{if(!pt||!mt)return fa(this.host),void this._closeMarkerDialog();const i=e.currentTarget;await this.host._confirmDanger({key:"discard-marker-dialog",kind:"warning",title:s("dialog.discard_title"),message:s("dialog.discard_message"),objectName:t.name.trim()||l?.name||void 0,confirmLabel:s("dialog.discard_confirm"),cancelLabel:s("dialog.discard_keep")})?(fa(this.host),this._closeMarkerDialog()):i?.rejectClose?.()},yt=_t("marker-binding"),wt=_t("marker-glow-radius"),$t="ha_disabled"===n?.kind?yo({kind:"warning",role:"status",icon:"mdi:power-plug-off-outline",text:e(`marker.ha_disabled_${n.reason}`),action:r?wo(e("btn.open_in_ha"),()=>this.host._openBindingInHa(t.binding)):void 0}):"unverified"===n?.kind&&t.binding?yo({kind:"warning",role:"status",icon:"mdi:shield-alert-outline",text:e("marker.ha_registry_limited")}):d,kt="ha"===t.bindingMode?$o({id:"marker-binding",open:t.bindingOpen,current:ht?{label:ht,sub:`${t.binding}${"ha_disabled"===n?.kind?` · ${e("marker.binding_disabled")}`:""}`}:null,placeholder:e("marker.pick_ph"),ariaLabel:e("marker.binding_label"),filter:t.bindingFilter,filterPlaceholder:e("marker.search_ph"),candidates:a,selected:t.binding,emptyText:e("marker.nothing_found"),onToggle:()=>this.host._markerDialog={...t,bindingOpen:!t.bindingOpen},onFilter:e=>this.host._markerDialog={...t,bindingFilter:e},onPick:e=>{if(e===t.binding)return void(this.host._markerDialog={...t,bindingOpen:!1});const s={...t,binding:e,bindingOpen:!1,controls:R(e,t.controls,this.host._bindingEntities(e)),autoIcon:this.host._autoIconForBinding(e),...wa(t.radar,t.radarTouched,t.radarRemove)};this.host._markerDialog=this._announceToggleDraft({...s,...this._valueBadgeForBinding(s,e),valueSource:null,valueSourceTouched:!0})},toolbar:p``}function za(){bo(this.host);const t=this.host._markerDialog,e=this.host._t.bind(this.host),{st:s,shelp:i}=vo(this.host),o="virtual"===t.bindingMode,a=this._bindingCandidates(),n=o?null:this.host._bindingStatus(t.binding),r=!o&&this.host._bindingHasHaPage(t.binding),l=this._markerPreviewDevice(t),h=this._effectiveMarkerTapAction(t,l),c=l?_(this.host._serverCfg?.spaces.find(t=>t.id===l.space)):null,u=l?this._markerPreviewDevices(l):this.host._devices,R="toggle"===h&&l?this._toggleIntent(l,u):null,z=this._toggleHintLines(R),F=l?m(this.host._planHass,l,{liveStates:!1!==this.host._config?.live_states,showTemperature:!1!==this.host._config?.show_temperature,showSignal:c?.showLqi??!1!==this.host._config?.show_signal,designPreview:!0,activityRuntime:this.host._activityRt.get(l.id),lightDevices:u,registryHass:this.host._fullRegistryHass,reducedMotion:this.host._reducedMotion}):null,N=l?g(this.host._planHass,l,u):[],A=l?f(this.host._planHass,l,N):null,E=t.valueBadgeTouched?t.valueBadgeEnabled:!!F?.valueBadge,O=t.valueBadgeTouched?t.valueBadgeSource:F?.valueBadge?.source||t.valueBadgeSource,B=t.valueBadgeTouched?t.valueBadgePosition:F?.valueBadge?.position||t.valueBadgePosition,H=b(O),W=!!O&&!N.some(t=>t.key===H),j=N.find(t=>t.key===H),G=b(t.valueSource),q=!(!t.valueSource||G&&N.some(t=>t.key===G)),U=N.find(t=>t.key===G),K=F?.valueSource?.sourceKey||"",V=this._markerAutoHasSpatialSource(t),J=!!l&&v(this.host._planHass,{...l}),Z=y(t.lightRole,V,J,t.glowMode),Y=!Z.sourceExists,X=!Z.fromSourceEnabled,Q=Z.passive,tt=Z.effectiveMode,et="never"===t.lightRole?e("marker.glow_disabled_never"):"auto"!==t.lightRole||V?e(Q?"marker.glow_passive_hint":"marker.glow_disabled_no_entity"):e("marker.glow_disabled_auto"),st=l?w(l):[],it=l&&$(l)||"",ot=!!t.lightEntity&&!st.includes(t.lightEntity),at=l?k(l):[],nt=!!t.toggleEntity&&!at.includes(t.toggleEntity),rt="toggle"===h?this._toggleIntentForDialog({...t,toggleEntity:"",toggleEntityTouched:!0}):null,lt=rt?[...rt.targets,...rt.skippedTargets].map(t=>t.entityId||("ref"in t?t.ref:"")).filter(Boolean).join(", "):"",ht=(()=>{if(o)return null;const e=a.find(e=>e.value===t.binding);if(e)return e.label;const[s,i]=t.binding.split(":");return"device"===s?this.host._fullRegistryHass.devices[i]?.name_by_user||this.host._fullRegistryHass.devices[i]?.name||i:this.host._fullRegistryHass.entities[i]?.name||this.host.hass.states[i]?.attributes?.friendly_name||i})(),ct=t=>this.host.hass.states[t]?.attributes?.friendly_name||this.host._fullRegistryHass.entities[t]?.name||t,dt=this.host._imperial?e("gs.unit_ft"):e("gs.unit_m"),pt=!!t.devId,ut=function(t){const e=[];return"ha"!==t.bindingMode||t.binding&&"virtual"!==t.binding||e.push({field:"marker-binding",message:"marker.error_binding"}),e}(t),_t=function(t,e){return go(t,"marker",ga(e))}(this.host,t),mt="ha"===t.bindingMode&&!t.devId&&"active"!==n?.kind,gt=!t.busy&&!this._radarSetup.isActive()&&0===ut.length&&!mt&&(!pt||_t),ft=ut[0]?s(ut[0].message):mt&&t.binding&&"virtual"!==t.binding?e("marker.ha_registry_limited"):"",bt=async e=>{if(!pt||!_t)return fa(this.host),void this._closeMarkerDialog();const i=e.currentTarget;await this.host._confirmDanger({key:"discard-marker-dialog",kind:"warning",title:s("dialog.discard_title"),message:s("dialog.discard_message"),objectName:t.name.trim()||l?.name||void 0,confirmLabel:s("dialog.discard_confirm"),cancelLabel:s("dialog.discard_keep")})?(fa(this.host),this._closeMarkerDialog()):i?.rejectClose?.()},vt=(yt="marker-binding",ut.find(t=>t.field===yt));var yt;const wt="ha_disabled"===n?.kind?yo({kind:"warning",role:"status",icon:"mdi:power-plug-off-outline",text:e(`marker.ha_disabled_${n.reason}`),action:r?wo(e("btn.open_in_ha"),()=>this.host._openBindingInHa(t.binding)):void 0}):"unverified"===n?.kind&&t.binding?yo({kind:"warning",role:"status",icon:"mdi:shield-alert-outline",text:e("marker.ha_registry_limited")}):d,$t="ha"===t.bindingMode?$o({id:"marker-binding",open:t.bindingOpen,current:ht?{label:ht,sub:`${t.binding}${"ha_disabled"===n?.kind?` · ${e("marker.binding_disabled")}`:""}`}:null,placeholder:e("marker.pick_ph"),ariaLabel:e("marker.binding_label"),filter:t.bindingFilter,filterPlaceholder:e("marker.search_ph"),candidates:a,selected:t.binding,emptyText:e("marker.nothing_found"),onToggle:()=>this.host._markerDialog={...t,bindingOpen:!t.bindingOpen},onFilter:e=>this.host._markerDialog={...t,bindingFilter:e},onPick:e=>{if(e===t.binding)return void(this.host._markerDialog={...t,bindingOpen:!1});const s={...t,binding:e,bindingOpen:!1,controls:T(e,t.controls,this.host._bindingEntities(e)),autoIcon:this.host._autoIconForBinding(e),...ya(t.radar,t.radarTouched,t.radarRemove)};this.host._markerDialog=this._announceToggleDraft({...s,...this._valueBadgeForBinding(s,e),valueSource:null,valueSourceTouched:!0})},toolbar:p``}):d,xt=ko({id:"basics",title:e("marker.card_basics"),body:p` - ${$t} + `}):d,kt=ko({id:"basics",title:e("marker.card_basics"),body:p` + ${wt} ${xo({label:e("marker.name_label"),htmlFor:"marker-name",hint:s("marker.name_hint"),control:p`this.host._markerDialog={...t,name:e.target.value}} />`})} - ${xo({label:e("marker.binding_label"),help:i("marker.binding.help"),error:yt?s(yt.message):void 0,hint:o?s("marker.binding_virtual_hint"):void 0,control:p`${Mo({name:"bmode",value:t.bindingMode,ariaLabel:e("marker.binding_label"),options:[{value:"virtual",label:e("marker.virtual_option")},{value:"ha",label:e("marker.from_ha_option")}],onChange:e=>{if("virtual"===e){const e={...t,bindingMode:"virtual",binding:"virtual",bindingOpen:!1,controls:R("virtual",t.controls),autoIcon:this.host._autoIconForBinding("virtual"),...wa(t.radar,t.radarTouched,t.radarRemove)};return void(this.host._markerDialog=this._announceToggleDraft({...e,...this._valueBadgeForBinding(e,"virtual"),valueSource:null,valueSourceTouched:!0}))}this.host._markerDialog=this._announceToggleDraft({...t,bindingMode:"ha",binding:"virtual"===t.binding?"":t.binding,bindingOpen:"virtual"===t.binding||!t.binding})}})}${kt}`})} + ${xo({label:e("marker.binding_label"),help:i("marker.binding.help"),error:vt?s(vt.message):void 0,hint:o?s("marker.binding_virtual_hint"):void 0,control:p`${Mo({name:"bmode",value:t.bindingMode,ariaLabel:e("marker.binding_label"),options:[{value:"virtual",label:e("marker.virtual_option")},{value:"ha",label:e("marker.from_ha_option")}],onChange:e=>{if("virtual"===e){const e={...t,bindingMode:"virtual",binding:"virtual",bindingOpen:!1,controls:T("virtual",t.controls),autoIcon:this.host._autoIconForBinding("virtual"),...ya(t.radar,t.radarTouched,t.radarRemove)};return void(this.host._markerDialog=this._announceToggleDraft({...e,...this._valueBadgeForBinding(e,"virtual"),valueSource:null,valueSourceTouched:!0}))}this.host._markerDialog=this._announceToggleDraft({...t,bindingMode:"ha",binding:"virtual"===t.binding?"":t.binding,bindingOpen:"virtual"===t.binding||!t.binding})}})}${$t}`})} ${xo({label:e("marker.room_label"),htmlFor:"marker-room",hint:t.room?s("marker.room_hint_override"):o?void 0:s("marker.room_hint_auto"),control:p``})} ${this._renderRadarSection(t,l)} - ${this._renderVacSection(t)}`}),Mt="toggle"===h&&(at.length>1||nt)?p`
    ${xo({label:e("marker.toggle_entity_label"),htmlFor:"marker-toggle-entity",help:this._help("marker.toggle_entity.help"),control:p`{const s={...t,toggleEntity:e.target.value,toggleEntityTouched:!0};this.host._markerDialog=this._announceToggleDraft(s)}}> `)} - `,hint:nt?za(e("marker.toggle_entity_missing",{entity:t.toggleEntity,fallback:lt||e("marker.toggle_entity_none")}),"warning"):void 0})}
    `:d,Ct="run"===h?(()=>{const s=t.runFilter.trim().toLowerCase(),i=this._runCandidates().filter(t=>!s||t.label.toLowerCase().includes(s)||t.value.includes(s)),o=t.tapTarget?this._runCandidates().find(e=>e.value===t.tapTarget):null;return xo({label:e("marker.run_target_label"),htmlFor:"marker-run-target",control:p` + `,hint:nt?Ra(e("marker.toggle_entity_missing",{entity:t.toggleEntity,fallback:lt||e("marker.toggle_entity_none")}),"warning"):void 0})}`:d,Mt="run"===h?(()=>{const s=t.runFilter.trim().toLowerCase(),i=this._runCandidates().filter(t=>!s||t.label.toLowerCase().includes(s)||t.value.includes(s)),o=t.tapTarget?this._runCandidates().find(e=>e.value===t.tapTarget):null;return xo({label:e("marker.run_target_label"),htmlFor:"marker-run-target",control:p` ${t.tapTarget&&!o?yo({kind:"warning",role:"status",text:e("marker.run_target_gone",{id:t.tapTarget})}):d} ${e("marker.nothing_found")}

    `} - `}`})})():d,St=t.controlsFilter.trim()?this._controlCandidates(t):[],Pt=ko({id:"tap",title:e("marker.card_tap"),body:p` + `}`})})():d,Ct=t.controlsFilter.trim()?this._controlCandidates(t):[],St=ko({id:"tap",title:e("marker.card_tap"),body:p` ${xo({label:e("marker.tap_label"),htmlFor:"marker-tap-action",control:p``,hint:"toggle"===h?p`${z.map(t=>p`${t}`)} ${t.tapHintAnnouncement}`:void 0})} + ${xt} ${Mt} - ${Ct} ${"run"===h||"toggle"===h?Co({id:"marker-tap-confirm",icon:"mdi:check-decagram-outline",title:e("marker.tap_confirm"),caption:e("marker.tap_confirm_tip"),checked:t.tapConfirm,onChange:e=>this.host._markerDialog={...t,tapConfirm:e}}):d} ${xo({label:e("marker.controls_label"),htmlFor:"marker-controls-filter",help:this._help("marker.controls.help"),control:p` ${t.controls.length?p`
    @@ -144,19 +144,19 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc @click=${()=>this.host._markerDialog=this._announceToggleDraft({...t,controls:t.controls.filter(t=>t!==s)})}> `})}
    `:d} -
    +
    this.host._markerDialog={...t,controlsFilter:e.target.value}} /> ${t.controlsFilter.trim()?p`
    - ${St.map(e=>p``)} - ${St.length?d:p`

    ${e("marker.nothing_found")}

    `} + ${Ct.length?d:p`

    ${e("marker.nothing_found")}

    `}
    `:d} -
    `})}`}),Dt="auto"!==tt?p`
    ${xo({label:e("marker.glow_color"),control:So({hex:t.glowColor,disabled:Y,picker:p``})}`}),Pt="auto"!==tt?p`
    ${xo({label:e("marker.glow_color"),control:So({hex:t.glowColor,disabled:Y,picker:p` ${Po({id:"marker-glow-brightness",min:1,max:100,value:Math.round(t.glowBrightness),unit:"%",ariaLabel:e("marker.glow_brightness"),disabled:Y,slider:this._rangeInput(1,100,1,t.glowBrightness,e=>{this.host._markerDialog={...t,glowMode:tt,glowBrightness:e,glowBrightnessDrafted:!0,glowTouched:!0}},Y,e("marker.glow_brightness")),onInput:e=>{this.host._markerDialog={...t,glowMode:tt,glowBrightness:e,glowBrightnessDrafted:!0,glowTouched:!0}}})} -
    `:d}
    `:d,It=ko({id:"light",title:e("marker.card_light"),body:p` +
    `:d}`:d,Dt=ko({id:"light",title:e("marker.card_light"),body:p` ${this.host._bindingHasClimate(t.binding)?Co({id:"marker-use-climate-temp",icon:"mdi:thermometer",title:e("marker.use_climate_temp"),caption:e("marker.use_climate_temp_tip"),checked:t.useClimateTemp,onChange:e=>this.host._markerDialog={...t,useClimateTemp:e}}):d} ${xo({label:e("marker.light_role_label"),help:this._help("marker.light_role.help"),control:Mo({name:"marker-light-role",value:t.lightRole,ariaLabel:e("marker.light_role_label"),options:[{value:"auto",label:s("marker.light_role_seg_auto")},{value:"always",label:s("marker.light_role_seg_always")},{value:"never",label:s("marker.light_role_seg_never")}],onChange:t=>this._setMarkerLightRole(t)}),hint:"auto"===t.lightRole?e(V?"marker.light_role_auto_yes":"marker.light_role_auto_no"):void 0})} ${"always"===t.lightRole&&(st.length>1||ot)?p`
    ${xo({label:e("marker.light_entity_label"),htmlFor:"marker-light-entity",help:this._help("marker.light_entity.help"),control:p``,hint:ot?Ra(e("marker.light_entity_missing",{entity:t.lightEntity,fallback:it||"—"}),"warning"):void 0})}
    `:d}
    ${Do({title:e("marker.glow_color_label"),help:this._help("marker.glow_mode.help")})} ${Mo({name:"marker-glow-mode",value:tt,ariaLabel:e("marker.glow_color_label"),options:[{value:"auto",label:e("marker.glow_mode_auto"),disabled:X,describedBy:X?"marker-glow-disabled-hint":void 0},{value:"color",label:e("marker.glow_mode_color"),disabled:Y,describedBy:Y?"marker-glow-disabled-hint":void 0},{value:"fixed",label:e("marker.glow_mode_fixed"),disabled:Y,describedBy:Y?"marker-glow-disabled-hint":void 0}],onChange:t=>this._setMarkerGlowMode(t)})} - ${Dt} - ${xo({label:e("marker.glow_radius_label"),htmlFor:"marker-glow-radius",help:this._help("marker.glow_radius.help"),error:wt?s(wt.message):void 0,hint:t.glowRadius.trim()?void 0:s("marker.glow_radius_empty_hint",{v:`${this.host._glowRadiusPlaceholder} ${dt}`}),control:Io({id:"marker-glow-radius",unit:dt,min:.5,step:.5,value:t.glowRadius,placeholder:this.host._glowRadiusPlaceholder,ariaLabel:e("marker.glow_radius_label"),disabled:Y,invalid:!!wt,describedBy:Y||Q?"marker-glow-disabled-hint":void 0,onInput:e=>this.host._markerDialog={...t,glowRadius:e}})})} + ${Pt} + ${xo({label:e("marker.glow_radius_label"),htmlFor:"marker-glow-radius",help:this._help("marker.glow_radius.help"),hint:t.glowRadius.trim()?void 0:s("marker.glow_radius_empty_hint",{v:`${this.host._glowRadiusPlaceholder} ${dt}`}),control:Io({id:"marker-glow-radius",unit:dt,min:.5,step:.5,value:t.glowRadius,placeholder:this.host._glowRadiusPlaceholder,ariaLabel:e("marker.glow_radius_label"),disabled:Y,describedBy:Y||Q?"marker-glow-disabled-hint":void 0,onInput:e=>this.host._markerDialog={...t,glowRadius:e}})})} ${Y||Q?yo({id:"marker-glow-disabled-hint",kind:"info",role:"note",icon:"mdi:information-outline",text:et}):d} -
    `}),Lt=customElements.get("ha-icon-picker")?p``}),It=customElements.get("ha-icon-picker")?p`{const s=e.detail.value||"";(t.icon||s!==t.autoIcon)&&(this.host._markerDialog={...t,icon:s})}}>`:p`this.host._markerDialog={...t,icon:e.target.value}} />`,Tt=S(t.display)||!N.length&&!t.valueBadgeSource,Rt=ko({id:"appearance",title:e("marker.card_appearance"),body:p` + @input=${e=>this.host._markerDialog={...t,icon:e.target.value}} />`,Lt=C(t.display)||!N.length&&!t.valueBadgeSource,Tt=ko({id:"appearance",title:e("marker.card_appearance"),body:p` ${xo({label:e("marker.icon_label"),htmlFor:"marker-icon",help:i("marker.icon.help"),control:p`
    - ${Lt} + ${It} ${t.icon?p``:d}
    `,hint:!t.icon&&t.autoIcon?p` ${e("marker.icon_auto",{icon:t.autoIcon})} ${wo(e("marker.icon_pin_auto"),()=>this.host._markerDialog={...t,icon:t.autoIcon})}`:t.icon?s("marker.icon_custom_hint"):void 0})} ${xo({label:e("marker.display_label"),htmlFor:"marker-display",help:i("marker.display.help"),control:p``,hint:e(Ta[t.display])})} + `,hint:e(La[t.display])})} ${"icon_ripple"===t.display?p`${xo({label:e("marker.activity_color"),control:p`
    ${So({hex:t.rippleColor||"#3ea6ff",picker:p`this.host._markerDialog={...t,rippleSize:e},!1,e("marker.ripple_size")),onInput:e=>this.host._markerDialog={...t,rippleSize:e}})}

    ${e("marker.activity_alarm_note")}

    `:d} - ${I(t.display)?p`
    ${xo({label:e("marker.value_source"),htmlFor:"marker-value-source",help:this._help("marker.value_source.help"),control:p`this.host._markerDialog={...t,valueSource:I(e.target.value),valueSourceTouched:!0}}> @@ -225,15 +225,15 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc title=${t.technical}> ${this._valueBadgeCandidateLabel(t)} · ${t.value} `)} - `,hint:o?za(e("marker.preview.reason.value_virtual"),"info"):q?za(e("marker.value_source_missing_hint"),"warning"):U?p`${U.technical}`:void 0})}
    `:d} - ${S(t.display)&&this.host._bindingHasAlarm(t.binding)?yo({kind:"warning",role:"note",icon:"mdi:alert-outline",text:e("marker.static_alarm_warning")}):d} + `,hint:o?Ra(e("marker.preview.reason.value_virtual"),"info"):q?Ra(e("marker.value_source_missing_hint"),"warning"):U?p`${U.technical}`:void 0})}`:d} + ${C(t.display)&&this.host._bindingHasAlarm(t.binding)?yo({kind:"warning",role:"note",icon:"mdi:alert-outline",text:e("marker.static_alarm_warning")}):d}
    ${Do({title:e("marker.value_badge_title"),help:this._help("marker.value_badge.help")})} - ${Co({id:"marker-value-badge",compact:!0,icon:S(t.display)?"mdi:eye-off-outline":"mdi:card-text-outline",title:e("marker.value_badge_enabled"),checked:E,disabled:Tt,onChange:e=>{const s=O||A;this.host._markerDialog={...t,valueBadgeEnabled:e&&!!s,valueBadgeSource:s,valueBadgeTouched:!0}}})} - ${S(t.display)?yo({kind:"info",role:"note",icon:"mdi:information-outline",text:e("marker.value_badge_static")}):N.length||t.valueBadgeSource?d:yo({kind:"info",role:"note",icon:"mdi:information-outline",text:e("marker.value_badge_empty")})} + ${Co({id:"marker-value-badge",compact:!0,icon:C(t.display)?"mdi:eye-off-outline":"mdi:card-text-outline",title:e("marker.value_badge_enabled"),checked:E,disabled:Lt,onChange:e=>{const s=O||A;this.host._markerDialog={...t,valueBadgeEnabled:e&&!!s,valueBadgeSource:s,valueBadgeTouched:!0}}})} + ${C(t.display)?yo({kind:"info",role:"note",icon:"mdi:information-outline",text:e("marker.value_badge_static")}):N.length||t.valueBadgeSource?d:yo({kind:"info",role:"note",icon:"mdi:information-outline",text:e("marker.value_badge_empty")})} ${E?p` ${xo({label:e("marker.value_badge_source"),htmlFor:"marker-value-badge-source",help:this._help("marker.value_badge_source.help"),control:p``,hint:W?za(e("marker.value_badge_missing_hint"),"warning"):I(t.display)&&H===K?za(e("marker.value_badge_duplicate"),"info"):j?p`${j.technical}`:void 0})} - ${xo({label:e("marker.value_badge_position"),help:this._help("marker.value_badge_position.help"),control:Mo({name:"marker-value-badge-position",value:B,ariaLabel:e("marker.value_badge_position"),options:Ra.map(t=>({value:t,label:e(`marker.value_badge_${t}`)})),onChange:e=>this.host._markerDialog={...t,valueBadgeEnabled:E,valueBadgeSource:O,valueBadgePosition:e,valueBadgeTouched:!0}})})} + `,hint:W?Ra(e("marker.value_badge_missing_hint"),"warning"):D(t.display)&&H===K?Ra(e("marker.value_badge_duplicate"),"info"):j?p`${j.technical}`:void 0})} + ${xo({label:e("marker.value_badge_position"),help:this._help("marker.value_badge_position.help"),control:Mo({name:"marker-value-badge-position",value:B,ariaLabel:e("marker.value_badge_position"),options:Ta.map(t=>({value:t,label:e(`marker.value_badge_${t}`)})),onChange:e=>this.host._markerDialog={...t,valueBadgeEnabled:E,valueBadgeSource:O,valueBadgePosition:e,valueBadgeTouched:!0}})})} `:d}
    ${F?p`this.host._markerDialog={...t,angle:e},!1,e("marker.angle_label")),onInput:e=>this.host._markerDialog={...t,angle:e}})} ${Ro("0°","355°")} - `])}`}),zt=ko({id:"details",title:e("marker.card_details"),body:p` + `])}`}),Rt=ko({id:"details",title:e("marker.card_details"),body:p` ${To([xo({label:e("marker.model_label"),htmlFor:"marker-model",control:p`this.host._markerDialog={...t,model:e.target.value}} />`}),xo({label:e("marker.link_label"),htmlFor:"marker-link",control:p` ${t.pdfs.map(t=>p` - ${t.name} + ${t.name} `)} `:d} @@ -288,38 +288,38 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc this._pickMarkerFiles(t)} /> `})} - ${this._renderRadarSection(t,l,"additional")}`}),Ft=t.hideFromPlan||"ha_disabled"===n?.kind;return p` + icon="mdi:shape-plus" wide @hp-close=${bt}>
    - ${xt}${Pt}${It}${Rt}${zt} + ${kt}${St}${Dt}${Tt}${Rt}
    -
    `}const Na=1e-6*F,Aa=6*F;function Ea(t){return Number.isFinite(t)?Math.round(t/F)*F:t}const Oa=(t,e,s,i)=>Math.hypot(s-t,i-e),Ba=(t,e,s,i,o,a,n,r)=>Math.hypot(Math.max(Math.abs(o-t),Math.abs(o+n-(t+s))),Math.max(Math.abs(a-e),Math.abs(a+r-(e+i)))),Ha=(t,e,s,i,o,a,n)=>{const r=Math.max(Number(i)||0,0)/2,l=Math.PI/180,h=Math.cos(s*l)*r,c=Math.sin(s*l)*r,d=Math.cos(n*l)*r,p=Math.sin(n*l)*r,u=Math.max(Oa(t+h,e+c,o+d,a+p),Oa(t-h,e-c,o-d,a-p)),_=Math.max(Oa(t+h,e+c,o-d,a-p),Oa(t-h,e-c,o+d,a+p));return Math.min(u,_)},Wa=t=>{const e=Number(t?.cell_cm);return e>0?e:5};function ja(t,e){const s=JSON.parse(JSON.stringify(t||[])),i=JSON.parse(JSON.stringify(e||{}));let o=0,a=0,n=0,r=0,l="",h=0,c=0;const d=(t,e)=>{Number.isFinite(t)&&Number.isFinite(e)&&t!==e&&Math.abs(e-t)<=Na&&c++},p=(t,e)=>{d(t[0],e[0]),d(t[1],e[1])},u={};let _=5;for(const t of s){const e=Wa(t);null!=t?.id&&(u[String(t.id)]=e),e>_&&(_=e)}const m=(t,e,s,i=!1)=>{if(!(t>Na||i))return;o++,t>n&&(n=t);const a=t*N*e;a>r&&(r=a,l=s)};for(const t of s){const e=Wa(t),s=null!=t?.id?String(t.id):"";for(const i of t.rooms||[]){a++;let t=0;if(i.poly?.length)i.poly=i.poly.map(e=>{const s=[Ea(e[0]),Ea(e[1])];return t=Math.max(t,Oa(e[0],e[1],s[0],s[1])),p(e,s),s});else if(null!=i.x&&null!=i.y){const e=i.x,s=i.y,o=i.w||0,a=i.h||0,n=Ea(e+o),r=Ea(s+a),l=Ea(e),h=Ea(s),c=Math.max(F,n-l),p=Math.max(F,r-h);t=Ba(e,s,o,a,l,h,c,p),i.x=l,i.y=h,i.w=c,i.h=p,d(e,l),d(s,h),d(e+o,l+c),d(s+a,h+p)}m(t,e,s)}for(const i of t.partitions||[]){a++;const o=[i.a[0],i.a[1]],n=[i.b[0],i.b[1]],r=[Ea(o[0]),Ea(o[1])],l=[Ea(n[0]),Ea(n[1])];let h=Math.max(Oa(o[0],o[1],r[0],r[1]),Oa(n[0],n[1],l[0],l[1]));const c=Oa(r[0],r[1],l[0],l[1]),d=(t.openings||[]).filter(t=>"partition"===t.host?.kind&&t.host.id===i.id).every(t=>{const e=Number(t.length),s=Number(t.host.t),i=s*c;return Number.isFinite(e)&&e>0&&Number.isFinite(s)&&s>=0&&s<=1&&i-e/2>=-Na&&i+e/2<=c+Na});c>Na&&d?(i.a=r,i.b=l,p(o,r),p(n,l)):h=0,m(h,e,s)}for(const i of t.wall_columns||[]){a++;const t=[i.center[0],i.center[1]],o=[Ea(t[0]),Ea(t[1])],n=Oa(t[0],t[1],o[0],o[1]);i.center=o,p(t,o),m(n,e,s)}for(const i of t.decor||[]){if("furniture"===i.kind||"image"===i.kind)continue;a++;let t=0;if("line"===i.kind){const e=[i.x1,i.y1],s=[i.x2,i.y2],o=[Ea(e[0]),Ea(e[1])],a=[Ea(s[0]),Ea(s[1])];t=Math.max(Oa(e[0],e[1],o[0],o[1]),Oa(s[0],s[1],a[0],a[1])),i.x1=o[0],i.y1=o[1],i.x2=a[0],i.y2=a[1],p(e,o),p(s,a)}else{const e=i.x,s=i.y,o=i.w,a=i.h,n=Ea(e),r=Ea(s);if(null!=i.w&&null!=i.h){const l=Ea(e+o),h=Ea(s+a),c=Math.max(F,l-n),p=Math.max(F,h-r);t=Ba(e,s,o,a,n,r,c,p),i.w=c,i.h=p,d(e+o,n+c),d(s+a,r+p)}else t=Oa(e,s,n,r);i.x=n,i.y=r,d(e,n),d(s,r)}m(t,e,s)}for(const i of t.openings||[]){if(a++,"partition"===i.host?.kind){const o=(t.partitions||[]).find(t=>t.id===i.host.id),a=Number(i.host.t);if(!o||!Number.isFinite(a)||a<0||a>1)continue;const n=o.b[0]-o.a[0],r=o.b[1]-o.a[1];if(Math.hypot(n,r)<=Na)continue;const l=o.a[0]+n*a,c=o.a[1]+r*a;let d=180*Math.atan2(r,n)/Math.PI;d>=90?d-=180:d<-90&&(d+=180);const p=Number(i.angle),u=!(Number.isFinite(p)&&p===d),_=Ha(i.x,i.y,Number.isFinite(p)?p:d,Number(i.length)||0,l,c,d);i.x=l,i.y=c,i.angle=d,u&&h++,m(_,e,s,u);continue}const o=z([i.x,i.y],t.rooms||[],Aa,{step:F,length:Number(i.length)||0});if(!o)continue;const n=Number(i.angle),r=!(Number.isFinite(n)&&n===o.angle),l=Ha(i.x,i.y,Number.isFinite(n)?n:o.angle,Number(i.length)||0,o.x,o.y,o.angle);i.x=o.x,i.y=o.y,i.angle=o.angle,r&&h++,m(l,e,s,r)}}for(const[t,e]of Object.entries(i)){if(!e||"object"!=typeof e)continue;const s=e;if("number"!=typeof s.x||"number"!=typeof s.y)continue;a++;const o=Ea(s.x),n=Ea(s.y),r=Oa(s.x,s.y,o,n);i[t]={...s,x:o,y:n},d(s.x,o),d(s.y,n);const l="string"==typeof s.s?s.s:"";m(r,u[l]??_,l)}return{spaces:s,layout:i,report:{moved:o,coordsCanonicalized:c,total:a,maxShift:n,maxShiftCm:r,maxSpace:l,rotated:h},changed:o>0||c>0}}function Ga(t,e){const s=e.base+t*e.span;return Math.min(1,Math.max(0,s))}const qa=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),Ua=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1]);function Ka(t,e,s){const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;if(a<=0)return Ua(t,e);let n=((t[0]-e[0])*i+(t[1]-e[1])*o)/a;return n=Math.max(0,Math.min(1,n)),Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))}function Va(t,e,s,i,o){for(const i of e)if(i&&!s.has(i.id)&&qa(i.a)&&qa(i.b)&&(Ua(t,i.a)<=o||Ua(t,i.b)<=o))return!0;for(const e of i?.roomPolygons||[])for(let s=0;s0&&r>0))return null;if(Math.abs(o[0]/n*(a[1]/r)-o[1]/n*(a[0]/r))>s)return null;for(const[s,o]of[[t.a,e.a],[t.a,e.b],[t.b,e.a],[t.b,e.b]])if(Ua(s,o)<=i)return[(s[0]+o[0])/2,(s[1]+o[1])/2];return null}function Za(t,e){const s=.05*(Number(e.pitch)>0?Number(e.pitch):1),i=new Map;let o=(t||[]).filter(t=>!!t&&"string"==typeof t.id&&qa(t.a)&&qa(t.b));if(o.length<2)return{partitions:[...t||[]],merged:0,openingMoves:[]};const a=e.seedIds&&e.seedIds.length?new Set(e.seedIds):null;let n=0;for(let t=0;tUa(e,t.at)>s);let c=h[0]??r.a,d=h[h.length-1]??l.b;if(h.length<2&&(c=r.a,d=l.b),d[0]0?(d[0]-c[0])/u:0,m=u>0?(d[1]-c[1])/u:0,g=t=>u>0?((t[0]-c[0])*_+(t[1]-c[1])*m)/u:0;for(const t of[r,l]){const e=g(t.a),s=g(t.b)-e;for(const[o,a]of i)a.toId===t.id&&i.set(o,{fromId:a.fromId,toId:p.id,base:e+a.base*s,span:a.span*s});i.set(t.id,{fromId:t.id,toId:p.id,base:e,span:s})}a&&a.add(p.id),o=o.filter((e,s)=>s!==t.i&&s!==t.j),o.splice(t.i,0,p),n++}return{partitions:o,merged:n,openingMoves:[...i.values()]}}function Ya(t,e,s,i){if(!t?.length||!s.length)return 0;const o=new Map(s.map(t=>[t.fromId,t]));let a=0;for(const s of t){const t=s?.host;if(!t||"partition"!==t.kind)continue;const n=o.get(t.id);if(!n)continue;s.host={...t,id:n.toId,t:Ga(t.t,n)},a++;const r=E(s,e,i.coordScale,i.cellCm,i.gridPitch).resolved;r&&Object.assign(s,O(s,r,i.coordScale))}return a}function Xa(t){return{roomPolygons:(t?.rooms||[]).map(t=>A(t)).filter(t=>!!t),columns:t?.wall_columns||[]}}const Qa=t=>!!t&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),tn=(t,e)=>t[0]-e[0]||t[1]-e[1],en=(t,e,s,i)=>[t[0]+e*i,t[1]+s*i],sn=(t,e,s,i)=>(t[0]-e[0])*s+(t[1]-e[1])*i,on=(t,e,s,i,o)=>{const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(!(r>o))return null;const l=a/r,h=n/r,c=e=>Math.abs((e[0]-t[0])*h-(e[1]-t[1])*l);if(c(s)>o||c(i)>o)return null;const d=sn(s,t,l,h),p=sn(i,t,l,h),u=Math.max(0,Math.min(d,p)),_=Math.min(r,Math.max(d,p));return _-u>o?{lo:u,hi:_}:null},an=(t,e,s)=>Math.min(t.hi,e.hi)-Math.max(t.lo,e.lo)>s,nn=t=>{const e=new Set(["id","a","b","cm"]);return Object.keys(t||{}).every(t=>e.has(t))},rn=(t,e,s,i)=>{const o=t.b[0]-t.a[0],a=t.b[1]-t.a[1],n=Math.hypot(o,a);if(!(n>i))return!0;const r=o/n,l=a/n,h=J(t.cm,s.cellCm,s.gridPitch)/2;return e.some(e=>{const o=e?.center;if(!Qa(o))return!0;const a=sn(o,t.a,r,l),c=Math.abs((o[0]-t.a[0])*l-(o[1]-t.a[1])*r),d=J(Number(e.cm),s.cellCm,s.gridPitch)*("square"===e.shape?Math.SQRT1_2:.5);return!(Number.isFinite(d)&&d>0)||a>=-d-i&&a<=n+d+i&&c<=h+d+i})},ln=(t,e,s)=>{if(t.host){const i=E(t,e,s.coordScale,s.cellCm,s.gridPitch).resolved;return i?{center:i.center,angle:i.angle,length:i.length}:null}const i=Number(t.x)*s.coordScale,o=Number(t.y)*s.coordScale,a=Number(t.angle),n=Number(t.length)*s.coordScale;return[i,o,a,n].every(Number.isFinite)&&n>0?{center:[i,o],angle:a,length:n}:null},hn=(t,e,s)=>{const i=t.angle*Math.PI/180,o=Math.cos(i),a=Math.sin(i),n=e.angle*Math.PI/180,r=Math.cos(n),l=Math.sin(n);if(Math.abs(o*l-a*r)>1e-6)return!1;const h=e.center[0]-t.center[0],c=e.center[1]-t.center[1];if(Math.abs(h*a-c*o)>s)return!1;const d=h*o+c*a;return Math.max(-t.length/2,d-e.length/2)({...t,a:[t.a[0]*e,t.a[1]*e],b:[t.b[0]*e,t.b[1]*e]}),dn=(t,e,s,i)=>{const o=`~r-${(t=>{let e=2166136261;for(let s=0;s>>0;return e.toString(36)})(`${t}|${e[0].toFixed(9)},${e[1].toFixed(9)}|${s[0].toFixed(9)},${s[1].toFixed(9)}`)}`,a=`${t.slice(0,Math.max(1,64-o.length))}${o}`;let n=a;for(let t=2;i.has(n);t++){const e=`-${t}`;n=`${a.slice(0,64-e.length)}${e}`}return i.add(n),n},pn=(t,e)=>{const s=[];for(const i of t){const t=s[s.length-1];!(t&&Math.abs(t.hi-i.lo)<=e&&t.safe===i.safe)||i.safe&&t.signature!==i.signature?s.push({lo:i.lo,hi:i.hi,a:i.a,b:i.b,safe:i.safe,signature:i.signature,roomIds:i.roomIds,finalCm:i.finalCm}):(t.hi=i.hi,t.b=i.b)}return s};function un(t,e,s,i,o){const a=s||[],n=Array.isArray(t?.partitions)?t.partitions:[],r=Array.isArray(t?.openings)?t.openings:[],l={walls:a,partitions:n,openings:r,partitionsReconciled:0,openingsRehosted:0};if(!n.length)return l;const h=Math.max(2e-4*o.gridPitch,1e-9);let c=a,d=n,p=r,u=0,_=0;const m=o.partitionIds?new Set(o.partitionIds):null,g=new Map(e.partitions.map(t=>[t.id,t]));for(const t of[...n].sort((t,e)=>t.id.localeCompare(e.id))){if(m&&!m.has(t.id))continue;if(!d.some(e=>e.id===t.id))continue;if(!nn(t))continue;const s=g.get(t.id);if(!(s&&Qa(s.a)&&Qa(s.b)&&Number.isFinite(s.cm)&&(o.allowCoincidentPartitions?!(s.cm<0):s.cm>0)))continue;const[a,n]=tn(s.a,s.b)<=0?[[s.a[0],s.a[1]],[s.b[0],s.b[1]]]:[[s.b[0],s.b[1]],[s.a[0],s.a[1]]],r=n[0]-a[0],l=n[1]-a[1],f=Math.hypot(r,l);if(!(f>h))continue;const b=r/f,v=l/f,y=B(e.rooms,c,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),w=y.flatMap(t=>{if(t.open||"outer"!==t.kind&&"shared"!==t.kind)return[];const e=on(a,n,t.a,t.b,h);return e?[{interval:t,range:e}]:[]});if(!w.length)continue;const $=p.filter(t=>"partition"===t.host?.kind&&t.host.id===s.id).map(t=>({opening:t,resolved:E(t,e.partitions,o.coordScale,o.cellCm,o.gridPitch).resolved}));if($.some(t=>!t.resolved))continue;const k=[0,f];for(const{range:t}of w)k.push(t.lo,t.hi);const x=k.slice(),M=new Map;for(const{opening:t,resolved:e}of $){const s=sn(e.center,a,b,v),i={lo:s-e.length/2,hi:s+e.length/2};M.set(t.id,i),x.push(Math.max(0,i.lo),Math.min(f,i.hi))}const C=[...new Set(x.filter(t=>Number.isFinite(t)&&t>=-h&&t<=f+h).map(t=>Math.max(0,Math.min(f,t)).toFixed(9)))].map(Number).sort((t,e)=>t-e),S=d.map(t=>cn(t,o.coordScale)).filter(t=>t.id!==s.id),P=[];for(let t=0;t+1h))continue;const r=en(a,b,v,i),l=en(a,b,v,n),c=w.filter(({range:t})=>t.lo<=i+h&&t.hi>=n-h).map(({interval:t})=>t),d=new Map;for(const t of c)d.set(t.roomId,t);const p=[...d.values()],u=new Set(p.map(t=>t.kind)),_=new Set(p.map(t=>o.allowCoincidentPartitions||t.cm>0?t.cm:H)),m=p[0]?.kind,g=[...d.keys()].sort(),f=1===u.size&&1===_.size&&("outer"===m&&1===g.length||"shared"===m&&2===g.length),y={id:s.id,a:r,b:l,cm:s.cm},$=S.some(t=>!!on(r,l,t.a,t.b,h)),k=f&&(o.allowCoincidentPartitions||!$)&&!rn(y,e.wall_columns,o,h),x=f?o.allowCoincidentPartitions||p[0].cm>0?p[0].cm:H:0,M=f?Math.max(x,s.cm):s.cm;P.push({lo:i,hi:n,a:r,b:l,safe:k,signature:k?`${m}|${g.join(",")}|${M}`:"",roomIds:g,roomCm:x,finalCm:M})}if(!P.some(t=>t.safe))continue;const D=new Map;for(const{opening:t,resolved:e}of $){const i=M.get(t.id),a=k.some(t=>t>i.lo+h&&tan(t,i,h)),r=new Set(n.filter(t=>t.safe).map(t=>t.signature));if(!a&&n.length>0&&n.every(t=>t.safe)&&1===r.size&&W(e,y,h)){D.set(t.id,{resolved:e,signature:[...r][0]});continue}const l=j(s,o.cellCm,o.gridPitch),c={lo:i.lo-l,hi:i.hi+l};for(const t of P)an(t,c,h)&&(t.safe=!1,t.signature="")}let I=!0;for(;I;){I=!1;for(const[t,e]of[...D.entries()]){const i=M.get(t),a=P.filter(t=>an(t,i,h));if(a.length>0&&a.every(t=>t.safe)&&a.every(t=>t.signature===e.signature))continue;D.delete(t);const n=j(s,o.cellCm,o.gridPitch),r={lo:i.lo-n,hi:i.hi+n};for(const t of P)an(t,r,h)&&(t.safe=!1,t.signature="");I=!0}}const L=pn(P,h),T=L.filter(t=>t.safe),R=L.filter(t=>!t.safe);if(!T.length)continue;if(d.length-1+R.length>2e3)continue;let z=c;for(const t of T){const[e,i]=tn(s.a,s.b)<=0?[t.a,t.b]:[t.b,t.a];z=G(z,e,i,t.finalCm,o.pitch,o.coordScale)}if(z=q(e.rooms,z,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),z.length>500)continue;const F=new Set(d.map(t=>t.id));F.delete(s.id);const N=R.map((t,e)=>{const i=[t.a[0]/o.coordScale,t.a[1]/o.coordScale],a=[t.b[0]/o.coordScale,t.b[1]/o.coordScale],n=0===e?s.id:dn(s.id,i,a,F);return F.add(n),{id:n,a:i,b:a,cm:s.cm}}),A=d.findIndex(t=>t.id===s.id),J=d.slice();J.splice(A,1,...N);const Z=J.map(t=>cn(t,o.coordScale)),Y=new Map;let X=!0;for(const{opening:t,resolved:e}of $){const s=D.get(t.id);if(s){const e=O(t,s.resolved,o.coordScale),{host:i,...a}=e;Y.set(t.id,a);continue}const i=M.get(t.id),a=N[R.findIndex(t=>t.lo<=i.lo+h&&t.hi>=i.hi-h)],n=a&&Z.find(t=>t.id===a.id);if(!a||!n){X=!1;break}const r=n.b[0]-n.a[0],l=n.b[1]-n.a[1],c=Math.hypot(r,l),d=sn(e.center,n.a,r/c,l/c),p={...O(t,e,o.coordScale),host:{kind:"partition",id:a.id,t:d/c}};if(!U(p,Z,o.coordScale,o.cellCm,o.gridPitch).resolved){X=!1;break}Y.set(t.id,p)}if(!X)continue;const Q=p.map(t=>Y.get(t.id)||t),tt=[...D.keys()].map(t=>Y.get(t)),et=tt.map(t=>ln(t,Z,o));if(et.some(t=>!t))continue;let st=!1;for(let t=0;tt.id));for(const t of Q){if(it.has(t.id))continue;const e=ln(t,Z,o);e&&et.some(t=>hn(t,e,h))&&(st=!0)}if(st)continue;const ot=K(e.rooms,z,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale);[...D.entries()].every(([t,e])=>{const s=Y.get(t),i=V(ot,{x:s.x*o.coordScale,y:s.y*o.coordScale,angle:s.angle,length:s.length*o.coordScale},!0),a=[i.negative,i.positive].filter(t=>!!t?.full),n=e.signature.split("|")[1].split(","),r=new Set(a.map(t=>t.roomId));return a.length===n.length&&r.size===n.length&&n.every(t=>r.has(t))})&&(c=z,d=J,p=Q,u+=T.length,_+=D.size)}return{walls:c,partitions:d,openings:p,partitionsReconciled:u,openingsRehosted:_}}const _n=t=>JSON.parse(JSON.stringify(t)),mn=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),gn=(t,e)=>e.length>0&&e.length<=35&&("space"===t?/^[a-z0-9_-]+$/.test(e):/^[A-Za-z0-9_-]+$/.test(e));function fn(t,e){let s=String(e??"");const i=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),o=new RegExp(`^${i}_(.+)_([0-9a-f]{8})$`);let a=0;for(;a<16;a++){const t=o.exec(s);if(!t)return{root:s,layers:a,bounded:!1};s=t[1]}return{root:s,layers:a,bounded:o.test(s)}}const bn=(t,e,s)=>{const i=t.get(e)||[];i.push(s),t.set(e,i)};const vn=1e-9;class yn extends Error{constructor(t,e=""){super(e?`${t}: ${e}`:t),this.reason=t,this.name="WallSegmentModelError"}}const wn=t=>JSON.parse(JSON.stringify(t)),$n=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(Number(t[0]))&&Number.isFinite(Number(t[1])),kn=t=>[Number(t[0]),Number(t[1])],xn=t=>`${Number(t[0]).toFixed(12)},${Number(t[1]).toFixed(12)}`,Mn=(t,e)=>{const s=xn(t),i=xn(e);return sxn(t)<=xn(e)?[kn(t),kn(e)]:[kn(e),kn(t)],Sn=(t,e)=>Math.hypot(e[0]-t[0],e[1]-t[1]),Pn=(t,e=[])=>{const s=new Set,i=t=>{const e=Number(t);if(!Number.isFinite(e))return;const i=e/F;Math.abs(i-Math.round(i))>=et&&s.add(e.toFixed(12))};for(const e of Array.isArray(t?.rooms)?t.rooms:[])for(const t of A(e)||[])i(t[0]),i(t[1]);for(const e of[t?.wall_segments,t?.walls])for(const t of Array.isArray(e)?e:[])i(t?.a?.[0]),i(t?.a?.[1]),i(t?.b?.[0]),i(t?.b?.[1]);for(const t of e)i(t?.[0]),i(t?.[1]);return s.size},Dn=(t,e,s)=>{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;return a>1e-18?((t[0]-e[0])*i+(t[1]-e[1])*o)/a:0},In=(t,e,s)=>{const i=Math.max(0,Math.min(1,Dn(t,e,s)));return Math.hypot(t[0]-(e[0]+(s[0]-e[0])*i),t[1]-(e[1]+(s[1]-e[1])*i))},Ln=(t,e,s,i,o=1e-9)=>{const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(r<=o)return 0;const l=e=>Math.abs((e[0]-t[0])*n-(e[1]-t[1])*a)/r;if(l(s)>o||l(i)>o)return 0;const h=Dn(s,t,e),c=Dn(i,t,e);return Math.max(0,Math.min(1,Math.max(h,c))-Math.max(0,Math.min(h,c)))*r},Tn=t=>{const e=(new TextEncoder).encode(t),s=8*e.length,i=64*Math.ceil((e.length+9)/64),o=new Uint8Array(i);o.set(e),o[e.length]=128;const a=new DataView(o.buffer);a.setUint32(i-8,Math.floor(s/4294967296),!1),a.setUint32(i-4,s>>>0,!1);const n=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),r=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),l=new Uint32Array(64),h=(t,e)=>t>>>e|t<<32-e;for(let t=0;t>>3,o=h(s,17)^h(s,19)^s>>>10;l[t]=l[t-16]+i+l[t-7]+o>>>0}let[e,s,i,o,c,d,p,u]=r;for(let t=0;t<64;t++){const a=u+(h(c,6)^h(c,11)^h(c,25))+(c&d^~c&p)+n[t]+l[t]>>>0,r=e&s^e&i^s&i;u=p,p=d,d=c,c=o+a>>>0,o=i,i=s,s=e,e=a+((h(e,2)^h(e,13)^h(e,22))+r>>>0)>>>0}r[0]=r[0]+e>>>0,r[1]=r[1]+s>>>0,r[2]=r[2]+i>>>0,r[3]=r[3]+o>>>0,r[4]=r[4]+c>>>0,r[5]=r[5]+d>>>0,r[6]=r[6]+p>>>0,r[7]=r[7]+u>>>0}const c=new Uint8Array(32),d=new DataView(c.buffer);for(let t=0;t{const e="abcdefghijklmnopqrstuvwxyz234567";let s=0,i=0,o="";for(const a of t)for(i=i<<8|a,s+=8;s>=5;)o+=e[i>>>s-5&31],s-=5;return s&&(o+=e[i<<5-s&31]),o},zn=(t,e,s,i,o="")=>{const[a,n]=Cn(e,s),r=`${t}|${xn(a)}|${xn(n)}|${[...i].sort().join(",")}${o}`;return`wall-${Rn(Tn(r)).slice(0,20)}`};let Fn=0;const Nn=t=>{for(let e=0;e<1e3;e++){const e=globalThis.crypto?.randomUUID?.(),s=`wall-${e||Rn(Tn(`${Date.now()}|${Fn++}|${Math.random()}`)).slice(0,26)}`;if(!t.has(s))return s}throw new yn("duplicate-id","id factory exhausted")},An=t=>{const e=new Map;for(const s of Array.isArray(t?.wall_segments)?t.wall_segments:[])if(s&&"string"==typeof s.id&&$n(s.a)&&$n(s.b)){if(e.has(s.id))throw new yn("duplicate-id",s.id);e.set(s.id,s)}return e},En=(t,e,s)=>{const i=(s,i)=>{const o=t[0]-s[0],a=t[1]-s[1];return Math.abs(e[0]-i[0]-o)<=vn&&Math.abs(e[1]-i[1]-a)<=vn?[o,a]:null};return i(s.a,s.b)||i(s.b,s.a)},On=(t,e)=>{const s=Array.isArray(t.rooms)?t.rooms:[],i=X(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]),o=i.length?i:Q(s,null,1,.04*F,!0),a=[];for(const t of s){const s=A(t),i=Array.isArray(t?.wall_ids)?t.wall_ids:[];if(s&&i.length===s.length)for(let t=0;t"partition"!==t.host?.kind&&[Number(t.x),Number(t.y)].every(Number.isFinite)&&Number.isFinite(Number(t.angle))&&Number(t.length)>0&&o.some(e=>In([Number(t.x),Number(t.y)],[e[0],e[1]],[e[2],e[3]])<=.04*F)):[],l=r.map(t=>{const e=Number(t.angle)*Math.PI/180,s=[Math.cos(e),Math.sin(e)],i=Number(t.length)/2,o=[Number(t.x),Number(t.y)];return{a:[o[0]-s[0]*i,o[1]-s[1]*i],b:[o[0]+s[0]*i,o[1]+s[1]*i]}}),h=(t,e)=>r.some(s=>{const i=[Number(s.x),Number(s.y)];if(!st(t,e,Number(s.angle)))return!1;if(In(i,t,e)>.02*F)return!1;const o=Sn(t,e),a=Dn(i,t,e)*o,n=Number(s.length)/2;return a+n>=-1e-9&&a-n<=o+vn}),c=new Map,d=[];for(const i of s){const r=String(i?.id||""),p=A(i);if(!r||!p||p.length<3)throw new yn("invalid-room",r);const u=tt(s,r,n,F,1,[...t.walls||[],...l]);if(!u||u.poly.length<3)throw new yn("invalid-room",r);const _=Array.isArray(i.wall_ids)?i.wall_ids:[],m=_.length===p.length;let g=null,f=m;if(f)for(let t=0;tvn||Math.abs(i[1]-g[1])>vn)){f=!1;break}g=i}const b=[];for(let t=0;t2)throw new yn("third-owner",n);const d=m?_[u.parent[t]]:void 0;if("string"==typeof d&&d){const o=e.get(d);f||!o||Ln(s,i,o.a,o.b)>vn?l.preferredIds.add(d):l.positionalIds.add(d),l.preferredCarriers.set(d,{a:kn(p[u.parent[t]]),b:kn(p[(u.parent[t]+1)%p.length])})}const g=u.parent[t];l.parentKeys.add(Y(p[g],p[(g+1)%p.length],F));const v=[(s[0]+i[0])/2,(s[1]+i[1])/2],y=t=>t.some(t=>In(v,[t[0],t[1]],[t[2],t[3]])<=.04*F);l.zeroWall||=y(a)||y(o)&&!h(s,i),b.push(n)}const v={...i};delete v.wall_ids,d.push({...v,poly:u.poly.map(t=>[t[0],t[1]]),wall_ids:b})}return{atoms:[...c.values()].sort((t,e)=>t.key.localeCompare(e.key)),rooms:d}},Bn=(t,e,s,i,o)=>{const a=new Map([...s.values()].map(t=>[Mn(t.a,t.b),t])),n=(t=>{const e=new Map;for(const s of t)"wall"===s.host?.kind&&e.set(s.host.id,(e.get(s.host.id)||0)+1);return e})(t.openings||[]),r=new Map;for(const t of e){const e=o?.get(t.key);if(e){const i=s.get(e);if(!i)throw new yn("duplicate-id",e);r.set(t,i);continue}if(t.preferredIds.size>1)throw new yn("duplicate-id",[...t.preferredIds].sort().join(","));const i=[...t.preferredIds][0],l=i?s.get(i):void 0;if(l){r.set(t,l);continue}const h=i?t.preferredCarriers.get(i):void 0;if(i&&h){r.set(t,{id:i,a:h.a,b:h.b,cm:0});continue}const c=a.get(t.key);if(c){r.set(t,c);continue}const d=[...s.values()].filter(e=>Ln(t.a,t.b,e.a,e.b)>vn),p=[...new Map(d.map(t=>[t.id,t])).values()];if(p.sort((t,e)=>(n.get(e.id)||0)-(n.get(t.id)||0)||Sn(e.a,e.b)-Sn(t.a,t.b)||t.id.localeCompare(e.id)),p[0])r.set(t,p[0]);else if(1===t.positionalIds.size){const e=s.get([...t.positionalIds][0]);e&&r.set(t,e)}}const l=new Map;for(const[t,e]of r){const s=l.get(e.id)||[];s.push(t),l.set(e.id,s)}for(const[t,e]of l){const i=s.get(t)||r.get(e[0]);if(!i)throw new yn("duplicate-id",t);const o=[(i.a[0]+i.b[0])/2,(i.a[1]+i.b[1])/2];e.sort((t,e)=>{const s=In(o,t.a,t.b)<=vn?0:1,a=In(o,e.a,e.b)<=vn?0:1;if(s!==a)return s-a;return(In(i.a,t.a,t.b)<=vn?0:1)-(In(i.a,e.a,e.b)<=vn?0:1)||t.key.localeCompare(e.key)}),e[0].id=t}const h=(t=>{const e=new Set;for(const s of[t.rooms,t.openings,t.decor,t.room_drafts,t.partitions,t.wall_columns])for(const t of Array.isArray(s)?s:[])"string"==typeof t?.id&&t.id&&e.add(t.id);for(const s of Array.isArray(t.room_drafts)?t.room_drafts:[])for(const t of Array.isArray(s?.segments)?s.segments:[])"string"==typeof t?.id&&t.id&&e.add(t.id);return e})(t);for(const t of e)if(t.id){if(h.has(t.id))throw new yn("duplicate-id",t.id);h.add(t.id)}const c=e.filter(t=>!t.id);if(i){const e=c.map(e=>{const[s,i]=Cn(e.a,e.b),o=`${String(t.id||"")}|${xn(s)}|${xn(i)}|${[...e.owners].sort().join(",")}`,a=Rn(Tn(o));return{atom:e,seed:o,digest:a,base:`wall-${a.slice(0,20)}`}}).sort((t,e)=>t.digest.localeCompare(e.digest)||t.atom.key.localeCompare(e.atom.key)),s=new Map;for(const t of e){const e=s.get(t.digest);if(e&&e!==t.seed)throw new yn("duplicate-id",t.digest);s.set(t.digest,t.seed);let i=1,o=t.base;for(;h.has(o);)o=`${t.base}-${++i}`;t.atom.id=o,h.add(o)}}else for(const t of c)t.id=Nn(h),h.add(t.id)},Hn=(t,e)=>{if("partition"===t.host?.kind)return null;const s=[Number(t.x),Number(t.y)];if(!s.every(Number.isFinite))return null;const i=e=>{if(!(Number(e.cm)>0))return!1;const i=Dn(s,e.a,e.b),o=Sn(e.a,e.b),a=Number(t.length)/2;return i>=-1e-9&&i<=1+vn&&In(s,e.a,e.b)<=.02*F&&st(e.a,e.b,Number(t.angle))&&Number.isFinite(a)&&a>=0&&i*o-a>=-1e-9&&i*o+a<=o+vn},o="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null,a=o&&i(o)?[o]:e.filter(i);if(1!==a.length)return null;const n=a[0];return{kind:"wall",id:n.id,t:Math.max(0,Math.min(1,Dn(s,n.a,n.b)))}},Wn=(t,e)=>{const s=[Number(t.x),Number(t.y)];if(!s.every(Number.isFinite))return null;const i=Number(t.length)/2,o=e.filter(e=>{if(!(Number(e.cm)>0))return!1;const o=Dn(s,e.a,e.b),a=Sn(e.a,e.b);return o>=-1e-9&&o<=1+vn&&In(s,e.a,e.b)<=.02*F&&st(e.a,e.b,Number(t.angle))&&Number.isFinite(i)&&i>=0&&o*a-i>=-1e-9&&o*a+i<=a+vn}),a=(e=>{if(!e.length)return null;const i="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null;return i||[...e].sort((t,e)=>In(s,t.a,t.b)-In(s,e.a,e.b)||Number(e.cm)-Number(t.cm)||(t.ide.id?1:0))[0]})(o);return a?{kind:"wall",id:a.id,t:Math.max(0,Math.min(1,Dn(s,a.a,a.b)))}:null},jn=/^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/,Gn=t=>{if("number"!=typeof t&&"string"!=typeof t)return null;if("string"==typeof t&&!jn.test(t.trim()))return null;const e=Number(t);return Number.isFinite(e)?e:null},qn=t=>{if(!Array.isArray(t)||t.length<2)return null;const e=Gn(t[0]),s=Gn(t[1]);return null==e||null==s?null:[e,s]},Un=t=>"string"==typeof t?t:"",Kn=t=>{if(!Object.prototype.hasOwnProperty.call(t,"room_drafts"))return{drafts:0,segments:0};const e=Array.isArray(t.room_drafts)?t.room_drafts:[];if(!e.length)return delete t.room_drafts,{drafts:0,segments:0};const s=new Set;for(const e of[t.rooms,t.openings,t.decor,t.partitions,t.wall_columns,t.wall_segments])for(const t of Array.isArray(e)?e:[])"string"==typeof t?.id&&t.id&&s.add(t.id);for(const t of e)"string"==typeof t?.id&&t.id&&s.add(t.id);const i=Array.isArray(t.partitions)?[...t.partitions]:[];let o=0;for(const a of e){const e=Un(a?.id),n=Array.isArray(a?.points)?a.points:[],r=Array.isArray(a?.segments)?a.segments:[];if(n.length<2||r.length!==n.length-1)throw new yn("zero-length",e);for(let a=0;a+1100)throw new yn("thickness-conflict",e);let p="string"==typeof c?.id&&c.id?c.id:"";if(!p||s.has(p)){const i=zn(Un(t.id),l,h,[`draft:${e}:${a}`]);p=i;for(let t=2;s.has(p);t++)p=`${i}-${t}`}s.add(p),i.push({id:p,a:kn(l),b:kn(h),cm:d}),o++}}return i.length?t.partitions=i:delete t.partitions,delete t.room_drafts,{drafts:e.length,segments:o}},Vn=t=>Kn(t),Jn=(t,e,s)=>{const i=Kn(t),o=An(t),{atoms:a,rooms:n}=On(t,o);Bn(t,a,o,e,s);const r=a.map(e=>{const s=e.id?o.get(e.id):void 0,i=((t,e,s)=>{if(e.zeroWall)return 0;const i=Array.isArray(t.walls)?t.walls:[],o=Y(e.a,e.b,F),a=i.filter(t=>Number(t.cm)>0&&(!(t.key!==o&&!e.parentKeys.has(t.key))||!(!$n(t.a)||!$n(t.b))&&Ln(e.a,e.b,t.a,t.b)>=Sn(e.a,e.b)-vn)).map(t=>Math.max(1,Math.min(100,Number(t.cm))));if(new Set(a.map(t=>t.toFixed(9))).size>1)throw new yn("thickness-conflict",e.key);if(a.length)return a[0];const n=ot(i,e.a,e.b,F,1);return n>0?n:Number(s?.cm)>0?Number(s.cm):0})(t,e,s);return{...s||{},id:e.id,a:[...e.a],b:[...e.b],cm:i}}),l=new Map(a.map(t=>[t.key,t.id]));for(const t of n)t.wall_ids=t.wall_ids.map(t=>l.get(t));t.rooms=n,t.wall_segments=r,t.walls=r.filter(t=>t.cm>0).map(t=>({key:Y(t.a,t.b,F),cm:t.cm,a:[...t.a],b:[...t.b]})),t.walls.length||delete t.walls,delete t.open_spans;for(const e of t.rooms)delete e.open_to;return((t,e,s)=>{const i=Array.isArray(t.openings)?t.openings:[];for(const t of i){if("partition"===t.host?.kind)continue;if(!t.host&&!s){const s=Hn(t,e);s&&(t.host=s);continue}const i=Hn(t,e)??(s?Wn(t,e):null);if(i)t.host=i;else{if(!s)throw new yn("opening-host",t.id);delete t.host}}})(t,r,e),{wallSegments:r.reduce((t,e)=>t+(o.has(e.id)?0:1),0),drafts:i.drafts,draftSegments:i.segments}};function Zn(t,e={}){const s=JSON.stringify(t),i=wn(t);Z(i);let o=0,a=0,n=0;const r=Number(i?.model_version||0)<10;for(const t of Array.isArray(i?.spaces)?i.spaces:[]){const s=e.lineageSpaceId===String(t?.id||"")?e.lineageHints:void 0,i=Jn(t,r,s);o+=i.wallSegments,a+=i.drafts,n+=i.draftSegments}return i.model_version=10,Z(i),{config:i,changed:s!==JSON.stringify(i),migratedSegments:o,migratedDrafts:a,migratedDraftSegments:n}}const Yn=t=>!!t&&"object"==typeof t&&!Array.isArray(t);function Xn(t,e){const s=(t,e)=>{if(Array.isArray(t)&&Array.isArray(e)){const i=new Map;for(const e of t)Yn(e)&&"string"==typeof e.id&&e.id&&i.set(e.id,e);const o=e.map((e,o)=>{if(Yn(e)&&"string"==typeof e.id&&e.id){const t=i.get(e.id);return t?s(t,e):wn(e)}return o[e,e in t?s(t[e],i):wn(i)]);for(const e of Object.keys(t))delete t[e];for(const[e,s]of i)t[e]=s;return t}return wn(e)};return s(t,e)}const Qn=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),tr=(t,e,s)=>Math.min(s,Math.max(e,t)),er=t=>vt({spaces:[t]})[0],sr=(t,e,s)=>{const i=s>0?s:1,o=t=>`${(t[0]/i).toFixed(12)},${(t[1]/i).toFixed(12)}`,a=o(t),n=o(e);return a0?n:1,l=Math.max(i*r*.02,1e-9),h=[];for(const e of t||[])for(const t of A(e)||[])h.push([t[0],t[1]]);const c=[];for(const t of s||[])Array.isArray(t)&&t.length>=4&&t.slice(0,4).every(Number.isFinite)&&c.push([t[0],t[1]],[t[2],t[3]]);const d=(t,e)=>e.some(e=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*l),p=new Map;for(const n of t||[]){if(!n?.id)continue;const u=yt(t,n.id,e,s,i,o,a,r);if(u)for(let t=0;t0&&_>0&&n===m&&_!==n))continue;const g=u.poly[i],f=u.poly[(i+1)%u.poly.length],b=Math.hypot(f[0]-g[0],f[1]-g[1]);if(!(b>l&&b<.5*a-1e-9*a))continue;if(d(g,c)||d(f,c))continue;if(d(g,h)&&d(f,h))continue;const v=sr(g,f,r),y=p.get(v);y?y.targets.add(n):p.set(v,{a:[g[0],g[1]],b:[f[0],f[1]],targets:new Set([n])})}}}let u=e.slice();const _=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*l,m=(t,e)=>{if(!Array.isArray(t.a)||!Array.isArray(t.b)||t.a.length<2||t.b.length<2)return!1;const s=[Number(t.a[0])*r,Number(t.a[1])*r],i=[Number(t.b[0])*r,Number(t.b[1])*r];return!![...s,...i].every(Number.isFinite)&&(_(s,e.a)&&_(i,e.b)||_(s,e.b)&&_(i,e.a))};for(const t of[...p.values()].filter(t=>1===t.targets.size).sort((t,e)=>sr(t.a,t.b,r).localeCompare(sr(e.a,e.b,r)))){const e=[...t.targets][0],s=u.filter(e=>m(e,t));if(new Set(s.map(t=>t.cm)).size>1)continue;let o=!1;u=u.map(s=>m(s,t)?(o=!0,s.cm===e?s:{...s,cm:e}):s),o||(u=G(u,t.a,t.b,e,i,r))}return u}const or=t=>{const e=[];for(const s of t||[]){const t=A(s);if(t?.length)for(let s=0;s"string"==typeof t?.id?t.id:"").filter(Boolean),c=new Set(h),d=new Map;for(const t of h){const e=fn("space",t);e.layers>0&&gn("space",e.root)&&bn(d,e.root,t)}const p=new Map,u=new Map,_=new Map,m=new Map;for(const t of r){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const s=new Map;for(const i of Array.isArray(t.rooms)?t.rooms:[]){const t="string"==typeof i?.id?i.id:"";if(!t)continue;const o=fn("room",t);o.layers>0&&gn("room",o.root)&&bn(s,o.root,t),u.has(t)||u.set(t,e),_.has(t)||_.set(t,String(i.name||""));const a="string"==typeof i.area?i.area:"";if(a){const s=m.get(a)||[];s.push({spaceId:e,roomId:t}),m.set(a,s)}}p.set(e,s)}const g=new Set(u.keys()),f=new Map,b=new Map;for(const t of l)"string"==typeof t?.id&&t.id&&(!0===t.removed?b.set(t.id,t):f.set(t.id,t));const v={spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,positionsUnresolved:0,nestedRefsUnresolved:0,deadSpaceIds:[],orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0,removedPositions:[],liveMissingPositions:[],unverifiedPositions:[]},y=new Set,w=t=>c.has(t)?null:(()=>{const e=fn("space",t).root;if(!gn("space",e))return null;const s=d.get(e)||[];return 1===s.length?s[0]:null})(),$=(t,e)=>{const s=fn("room",t).root;if(!gn("room",s))return null;const i=p.get(e)?.get(s)||[];return 1===i.length?i[0]:null},k=t=>{const e=s.effectiveAreaByMarker?.[t]||"",i=e&&m.get(e)||[];return 1===i.length?i[0]:null},x=(t,e,s)=>{if("string"==typeof t.room_id&&t.room_id&&!g.has(t.room_id)){const i=e?$(t.room_id,e):null;i?(t.room_id=i,v.roomRefsRemapped++):s?(t.room_id=s.roomId,v.roomRefsRemapped++):!0!==t.removed&&delete t.room_id}const i=t.vacuum?.segment_map;if(i&&"object"==typeof i&&!Array.isArray(i))for(const t of Object.keys(i)){const s=i[t];if("string"!=typeof s||!s||g.has(s))continue;const o=e?$(s,e):null;o?(i[t]=o,v.roomRefsRemapped++):v.nestedRefsUnresolved++}};for(const t of l){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const s="string"==typeof t.space?t.space:"",i=s&&!c.has(s),a=o[e],n="string"==typeof a?.s?a.s:"",r=n&&!c.has(n),l=!0===t.removed;let h=s&&c.has(s)?s:null,d=null,p=!1;if(i){const i=w(s);i?(t.space=i,h=i,p=!0,v.spaceRefsRemapped++):l||"virtual"===t.binding?l||(delete t.space,h=null,v.markersDetached++):(d=k(e),d?(t.space=d.spaceId,h=d.spaceId,v.spaceRefsRemapped++):(delete t.space,h=null,v.markersDetached++))}l&&!p||x(t,h,d),r&&p&&n===s&&h&&(o[e]={...a,s:h},v.positionsRemapped++,y.add(e))}for(const t of Object.keys(o)){if(y.has(t))continue;const e=o[t],s="string"==typeof e?.s?e.s:"";if(!s||c.has(s))continue;const i=w(s);if(i){if(t.startsWith("rl_")){const s=t.slice(3),a=$(s,i);if(a){const s=`rl_${a}`;mn(o,s)||(o[s]={...e,s:i}),delete o[t],v.roomRefsRemapped++,v.positionsRemapped++;continue}}o[t]={...e,s:i},v.positionsRemapped++}}const M=s.ownerRoster,C=!0===M?.authoritative,S=new Set(M?.deviceIds||[]),P=new Set(M?.entityIds||[]),D=new Set(Array.isArray(i.settings?.known_devices)?i.settings.known_devices.filter(t=>"string"==typeof t):[]),I=(t,e="")=>{const s=String(M?.names?.[t]||e||"").trim();return s&&s!==t?s:""},L=(t,e,s,i="",o)=>({id:t,spaceId:e,kind:s,name:I(t,i),...o?{reason:o}:{}}),T=t=>{"room_label"===t?v.orphanRoomLabelsRemoved++:"group"===t?v.orphanGroupPositionsRemoved++:v.orphanDevicePositionsRemoved++},R=new Set;for(const[t,e]of Object.entries(o)){const i="string"==typeof e?.s?e.s:"";if(!i||c.has(i))continue;let a,n;const r=f.get(t),l=b.get(t);if(r)a=L(t,i,"device",String(r.name||"")),n="live";else if(l)a=L(t,i,"device",String(l.name||"")),n="absent";else if(t.startsWith("rl_")){const e=t.slice(3);a=L(t,i,"room_label",_.get(e)||""),n=g.has(e)?"live":"absent"}else if(t.startsWith("lg_")){const e=t.slice(3);a=L(t,i,"group"),n=P.has(e)?"live":C?"absent":"unverified","unverified"===n&&(a.reason="registry_unavailable")}else S.has(t)?(a=L(t,i,"device"),n="live"):D.has(t)?(a=L(t,i,"device"),n=C?"absent":"unverified","unverified"===n&&(a.reason="registry_unavailable")):(a=L(t,i,"unknown","","unknown_owner"),n="unverified");if("absent"!==n){if("live"===n){if(v.liveMissingPositions.push(a),!0===s.removeLiveMissingPositions){delete o[t],v.liveMissingPositionsRemoved++,T(a.kind),v.removedPositions.push(a);continue}}else v.unverifiedPositions.push(a);v.positionsUnresolved++,R.add(i)}else delete o[t],T(a.kind),v.removedPositions.push(a)}return v.deadSpaceIds=[...R].sort((t,e)=>t.localeCompare(e)),{config:i,layout:o,report:v,changed:JSON.stringify(i)!==a||JSON.stringify(o)!==n}}(t,e,s),n=a.config,r=at(n,a.layout);Z(n),nt(a.layout);const l=JSON.stringify(t||{}),h=JSON.stringify(e||{}),c=Number.isInteger(Number(n.model_version))?Number(n.model_version):0,d=(t=>{let e=0,s=0,i=0;for(const s of t.markers||[]){if("ripple"===s.display&&(s.display="icon_ripple",e++),Array.isArray(s.controls)){const t="string"==typeof s.binding&&s.binding.startsWith("entity:")?s.binding.slice(7):"",i=t?s.controls.filter(e=>e!==t):s.controls;JSON.stringify(i)!==JSON.stringify(s.controls)&&(s.controls=i.length?i:null,e++)}const t=s.vacuum;t&&Qn(t,"trail")&&(["never","cleaning","always"].includes(t.trail_mode)||(t.trail_mode=!1===t.trail?"never":"cleaning"),delete t.trail,e++)}for(const o of t.spaces||[]){const t=o.settings;"glow"===t?.fill_mode&&("boolean"!=typeof t.glow_enabled&&(t.glow_enabled=!0),t.fill_mode="none",e++,s++);for(const t of o.rooms||[]){const s=t.settings;"glow"===s?.fill_mode&&("boolean"!=typeof s.glow&&(s.glow=!0),delete s.fill_mode,e++,i++)}if(Qn(o,"segments")&&(delete o.segments,e++),Qn(o,"plan_scale")){const t=Number(o.plan_scale);Number.isFinite(t)&&t>=ut&&t<=_t&&(Qn(o,"plan_scale_x")||(o.plan_scale_x=t),Qn(o,"plan_scale_y")||(o.plan_scale_y=t),delete o.plan_scale,e++)}const a=Number(o.cell_cm);Qn(o,"cell_cm")&&(!Number.isFinite(a)||a<.1||a>1e3)&&(o.cell_cm=Number.isFinite(a)&&a>0?tr(a,.1,1e3):5,e++);const n=Number(o.cell_cm),r=Number.isFinite(n)&&n>0?n:5;for(const t of o.wall_columns||[])if("circle"===t.shape)Qn(t,"angle")&&(delete t.angle,e++);else if("square"===t.shape&&Qn(t,"angle")){const s=((Number(t.angle)||0)%90+90)%90;t.angle!==s&&(t.angle=s,e++)}for(const t of o.decor||[]){if(Qn(t,"width")){const s=Number(t.width);(Qn(t,"width_cm")||Number.isFinite(s))&&(Qn(t,"width_cm")||(t.width_cm=Number(tr(s/dt*r,.1,100).toFixed(6))),delete t.width,e++)}if("rect"!==t?.kind&&"ellipse"!==t?.kind||!0!==t.fill||(Qn(t,"fill_color")||(t.fill_color=t.color||"#607d8b",e++),Qn(t,"fill_opacity")||(t.fill_opacity=.25,e++)),"text"!==t?.kind)continue;void 0===t.size_cm?(t.size_cm=Number(tr(mt*gt(t)/dt*r,.1,2e3).toFixed(6)),delete t.scale,delete t.size,e++):(Qn(t,"scale")||Qn(t,"size"))&&(delete t.scale,delete t.size,e++);let s=String(t.text??"");const i=[...s.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!ft(t[1]));if(!(Qn(t,"entity")||Qn(t,"attr")||Qn(t,"unit")))continue;const o=String(t.unit??"").trim(),a="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,n=i||o?"":bt(t.entity,a);if(i||n){if(n){const e=s.indexOf("{}");s=e>=0?s.slice(0,e)+n+s.slice(e+2):`${s}${s?" ":""}${n}`,t.text=s}delete t.entity,delete t.attr,delete t.unit,e++}}}return{total:e,glowSpaces:s,glowRooms:i}})(n);let p=d.total,u=0,_=0,m=0;if(c<10)for(const t of Array.isArray(n.spaces)?n.spaces:[]){const e=Vn(t);_+=e.drafts,m+=e.segments}const g=(f=n.spaces||[],JSON.parse(JSON.stringify(f)));var f;const b=ja(n.spaces||[],a.layout);let v=0,y=0,w=0,$="";const k=b.spaces.map(t=>{const e=rt(t);v+=e.report.wallsStraightened,y+=e.report.wallsStraightenSkipped;const s=Number(t?.cell_cm)>0?Number(t.cell_cm):5,i=e.report.maxStraightenShift/F*s;return i>w&&(w=i,$=String(t?.id||"")),e.space}),x=v?ja(k,b.layout):{...b,spaces:k};n.spaces=x.spaces;const M=v?{...b.report,moved:b.report.moved+x.report.moved,coordsCanonicalized:b.report.coordsCanonicalized+x.report.coordsCanonicalized,maxShift:Math.max(b.report.maxShift,x.report.maxShift),maxShiftCm:Math.max(b.report.maxShiftCm,x.report.maxShiftCm),maxSpace:x.report.maxShiftCm>b.report.maxShiftCm?x.report.maxSpace:b.report.maxSpace,rotated:b.report.rotated+x.report.rotated}:{...b.report};let C=0,S=0,P=0,D=0,I=0,L=0,T=0;for(let t=0;t0===Number(t.cm)),walls:e.walls||[]}),a=er(e),r=er(s);if(!a||!r)continue;const l=or(a.rooms),h=or(r.rooms),c=.02*dt,d=(e.wall_segments||[]).filter(t=>0===Number(t.cm)).map(t=>({...t,key:Y(t.a,t.b,F),cm:0})),p=new Set(d.map(t=>t.key)),u=lt(e,a.rooms,ht,c);S+=u.length;for(const t of u){const e=[t[0]/ht,t[1]/ht],s=[t[2]/ht,t[3]/ht],i=Y(e,s,F);p.has(i)||(p.add(i),d.push({key:i,a:e,b:s,cm:0}))}const _=d.length,m=ct(d,l,h,F,ht),f=(t,e,s)=>{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;if(!(a>0))return Math.hypot(t[0]-e[0],t[1]-e[1]);const n=Math.max(0,Math.min(1,((t[0]-e[0])*i+(t[1]-e[1])*o)/a));return Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))},b=m.filter(t=>{if(!Array.isArray(t.a)||!Array.isArray(t.b))return!1;const e=t.a.map(t=>t*ht),s=t.b.map(t=>t*ht);return h.some(([t,i])=>f(e,t,i)<=4*c&&f(s,t,i)<=4*c)});P+=Math.max(0,_-b.length);const v=(s.wall_segments||[]).filter(t=>Number(t.cm)>0);s.wall_segments=[...v,...b.map(({key:t,...e})=>e)];const y=b.map(t=>[t.a[0]*ht,t.a[1]*ht,t.b[0]*ht,t.b[1]*ht]),w=Array.isArray(e.walls)?e.walls.length:0;let $=ct(e.walls,l,h,F,ht);$=ir(r.rooms,$,y,F,Number(s.cell_cm)>0?Number(s.cell_cm):5,dt,ht),$=q(r.rooms,$,y,F,Number(s.cell_cm)>0?Number(s.cell_cm):5,dt,ht),$=pt($,s.rooms||[],F,1,y.map(t=>[t[0]/ht,t[1]/ht,t[2]/ht,t[3]/ht])),C+=Math.max(0,w-$.length),$.length?s.walls=$:delete s.walls;const k=Za(s.partitions||[],{pitch:F,geometry:Xa(s)});k.merged&&(D+=k.merged,s.partitions=k.partitions,Ya(s.openings,s.partitions,k.openingMoves,{coordScale:ht,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,gridPitch:dt}));const x=er(s);if(x){const t=o(s,x,s.walls||[],y,{pitch:F,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,gridPitch:dt,coordScale:ht});t.partitionsReconciled&&(I+=t.partitionsReconciled,L+=t.openingsRehosted,t.partitions.length?s.partitions=t.partitions:delete s.partitions,t.openings.length?s.openings=t.openings:delete s.openings,t.walls.length?s.walls=t.walls:delete s.walls)}JSON.stringify({zero:(s.wall_segments||[]).filter(t=>0===Number(t.cm)),walls:s.walls||[]})!==i&&T++}if(c<=10){const t=function(t){const e=Zn(t);return Xn(t,e.config),{...e,config:t}}(n);u+=t.migratedSegments,_+=t.migratedDrafts,m+=t.migratedDraftSegments}const R=Z(n),z=nt(x.layout),N=JSON.stringify(R)!==l||JSON.stringify(z)!==h;c<10&&N&&(R.model_version=10);const A=JSON.stringify(R)!==l||JSON.stringify(z)!==h,E=Number.isInteger(Number(R.model_version))?Number(R.model_version):c,O=A?M:{...M,moved:0,coordsCanonicalized:0,maxShift:0,maxShiftCm:0,maxSpace:"",rotated:0},B=A?a.report:{...a.report,spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0};return{config:R,layout:z,report:{...O,modelFrom:c,modelTo:E,migrated:A?p:0,glowSpacesMigrated:A?d.glowSpaces:0,glowRoomsMigrated:A?d.glowRooms:0,canonicalized:A?T:0,wallSegmentsMigrated:A?u:0,roomDraftsMigrated:A?_:0,roomDraftSegmentsMigrated:A?m:0,legacyZeroWallsMigrated:A?S:0,wallsMerged:A?C:0,spansMerged:A?P:0,partitionsMerged:A?D:0,partitionsReconciled:A?I:0,openingsRehosted:A?L:0,wallsStraightened:A?v:0,wallsStraightenSkipped:y,maxStraightenShiftCm:A?w:0,maxStraightenSpace:A?$:"",latticeCoordinatesCanonicalized:A?r.canonicalized:0,latticeCoordinatesFar:A?r.far:0,latticeMaxShift:A?r.maxShift:0,latticeMaxShiftCm:A?r.maxShiftCm:0,latticeSpaces:A?r.spaces:[],...B},changed:A}}async function nr(t,e,s){t._saveConfigDebounced.pending()&&t._saveConfigDebounced.flush(),await t._writeChain;const i=await t.hass.callWS({type:"houseplan/plan/optimize",config:e,layout:s,expected_config_rev:t._cfgRev,expected_layout_rev:t._layoutRev});t._adoption.acceptPairWrite(e,s,i),t._geometryHistory.clear(),t._cancelDeviceDrag(),t._devicePositionHistory.clear(),t._canOptimizeUndo=!0===i.can_undo,t._undoKind=!0===i.can_undo?"optimize":null,t._dirtyPos.clear(),t._sentPos.clear(),t._cfgEpoch++,t._modelCache=null,t._frame=null,t._regSignature="",t._maybeRebuildDevices(),t._cacheSnapshot(),t.requestUpdate()}const rr=Object.freeze({spaces:50,partitions:2e3,openings:500,decor:1e3,columns:500});class lr extends Error{constructor(t){super(t),this.code=t,this.name="SpaceCopyError"}}const hr=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),cr=t=>void 0===t?t:JSON.parse(JSON.stringify(t)),dr=t=>null===t||"object"!=typeof t||Array.isArray(t)?null:t;function pr(t,e=!1){if(void 0===t&&!e)return[];if(!Array.isArray(t))throw new lr("source_invalid");return t.map(t=>{const e=dr(t);if(!e||"string"!=typeof e.id||!e.id)throw new lr("source_invalid");return e})}const ur=t=>Array.isArray(t)&&2===t.length&&t.every(t=>Number.isFinite(t));function _r(t,e,s){const i=String(t??"").trim()||s,o=new Set(e.map(t=>{const e=dr(t);return String(e?.title??"").trim()}));let a=2;for(;o.has(`${i} (${a})`);)a++;return`${i} (${a})`}const mr=["settings","zero_wall_style","cell_cm","view_box","plan_url","plan_aspect","plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"];const gr={source_missing:"space.copy_error_source_missing",source_invalid:"space.copy_error_source_invalid",spaces_limit:"space.copy_error_spaces_limit",partitions_limit:"space.copy_error_partitions_limit",openings_limit:"space.copy_error_openings_limit",decor_limit:"space.copy_error_decor_limit",columns_limit:"space.copy_error_columns_limit",opening_host_missing:"space.copy_error_opening_host",opening_host_unknown:"space.copy_error_opening_host",geometry_unsafe:"space.copy_error_geometry"};let fr=0;function br(t,e,s){const i=t._spaceDialog;return!(!i?.copy||i.copy.token!==e)&&(t._spaceDialog={...i,busy:s,copy:{...i.copy,busy:s}},!0)}function vr(t){t._cfgEpoch++,t._modelCache=null,t._frame=null,t._regSignature="",t._maybeRebuildDevices(),t.requestUpdate()}async function yr(t,e){const s=t._spaceDialog;if(!s?.copy||"edit"!==s.mode||s.busy||s.copy.busy||!s.copy.title.trim()||!s.spaceId||!t._serverCfg)return;const i=++fr,o=s.spaceId,a=s.copy.title.trim();t._spaceDialog={...s,busy:!0,copy:{...s.copy,title:a,busy:!0,token:i}};let n=!1;try{if(t._saveConfigDebounced.pending()&&t._saveConfigDebounced.flush(),await t._writeChain,!br(t,i,!0)||!t._serverCfg)return;const s=t._cfgRev,r=t._layoutRev,l=wt(t._serverCfg),h=wt(t._layout);let c;try{c=(e.optimize??ar)(t._serverCfg,t._layout,e.optimizeReferenceContext())}catch(s){return br(t,i,!1),void e.showWallModelMigrationBlocked(s)}if(c.changed){const d=t._checkOptimizeGeometry(c.config);if(e.reportPreflightFailure(d,c.config),!d.ok)return br(t,i,!1),void t._showToast(t._t("space.copy_error_optimize_geometry"));const p=await t._confirmDanger({key:`copy-space:${o}`,kind:"warning",title:t._t("space.copy_optimize_title"),message:t._t("space.copy_optimize_body",{name:a}),objectName:a,confirmLabel:t._t("space.copy_optimize_confirm"),cancelLabel:t._t("btn.cancel"),icon:"mdi:broom"});if(!br(t,i,p))return;if(!p)return;if(t._cfgRev!==s||t._layoutRev!==r||!t._serverCfg||wt(t._serverCfg)!==l||wt(t._layout)!==h)return br(t,i,!1),void t._showToast(t._t("space.copy_error_changed"));e.clearGeometryGesture(),await nr(t,c.config,c.layout),n=!0}if(!br(t,i,!0)||!t._serverCfg)return;const d=t._serverCfg,p=function(t,e,s,i){const o=t.spaces;if(!s.trim())throw new lr("source_invalid");if(o.length>=rr.spaces)throw new lr("spaces_limit");const a=o.findIndex(t=>t.id===e);if(a<0)throw new lr("source_missing");const n=o[a];if(!Array.isArray(n.view_box))throw new lr("source_invalid");const r=pr(n.wall_segments,!0),l=pr(n.partitions),h=pr(n.openings),c=pr(n.decor),d=pr(n.wall_columns);if(r.length+l.length>rr.partitions)throw new lr("partitions_limit");if(h.length>rr.openings)throw new lr("openings_limit");if(c.length>rr.decor)throw new lr("decor_limit");if(d.length>rr.columns)throw new lr("columns_limit");let p=0;const u=t=>`${t}${i}${(p++).toString(36)}`,_=new Map,m=new Map,g=[];for(const t of r){if(_.has(t.id)||!ur(t.a)||!ur(t.b)||"number"!=typeof t.cm||!Number.isFinite(t.cm))throw new lr("source_invalid");const e=u("cw");_.set(t.id,e),g.push({id:e,a:cr(t.a),b:cr(t.b),cm:t.cm})}for(const t of l){if(m.has(t.id)||!ur(t.a)||!ur(t.b)||"number"!=typeof t.cm||!Number.isFinite(t.cm))throw new lr("source_invalid");const e=u("cp");m.set(t.id,e),g.push({id:e,a:cr(t.a),b:cr(t.b),cm:t.cm})}const f=h.map(t=>{const e=dr(t.host);if(!e||"string"!=typeof e.id||"string"!=typeof e.kind)throw new lr("opening_host_missing");const s="wall"===e.kind?_.get(e.id):"partition"===e.kind?m.get(e.id):void 0;if(!s)throw new lr("opening_host_unknown");const i={...cr(t),id:u("co"),host:{...cr(e),kind:"partition",id:s}};return delete i.contact,delete i.lock,i}),b=c.map(t=>({...cr(t),id:u("cd")})),v=d.map(t=>({...cr(t),id:u("cc")})),y=`s${i}`;if(o.some(t=>t.id===y))throw new lr("source_invalid");const w={id:y,title:s.trim(),rooms:[],wall_segments:[],view_box:cr(n.view_box)};for(const t of mr)"view_box"!==t&&hr(n,t)&&(w[t]=cr(n[t]));g.length&&(w.partitions=g),f.length&&(w.openings=f),b.length&&(w.decor=b),v.length&&(w.wall_columns=v);const $=cr(t);return $.spaces.splice(a+1,0,w),{config:$,space:w,sourceIndex:a}}(d,o,a,e.newSeed?.()??function(t=Date.now(),e=Math.random()){const s=Math.floor(16777216*Math.max(0,Math.min(.999999999,e))).toString(36).padStart(5,"0");return`${Math.max(0,Math.floor(t)).toString(36)}${s}`}());let u=!1;try{u=t._checkSpacePhysicalGeometry(p.config,p.space.id).ok}catch{u=!1}if(!u||t._junctionLimitViolations(p.config,p.space.id).length)throw new lr("geometry_unsafe");const _=t._adoption.beginOptimistic(d,p.config);t._adoption.stageLocalConfig(p.config),vr(t);try{await e.saveConfigNow(_)}catch(e){throw t._rollbackOptimistic(_)&&vr(t),"conflict"!==e?.code&&await t._reloadConfigOnly(!0),e}t._canOptimizeUndo=!1,t._undoKind=null,e.clearGeometryGesture(),t._selId=null,t._physicalSel=null,t._spaceDialog=null,t._commitSpace(p.space.id,!0),e.setMode("plan"),t._tool="draw",t._path=[],t._cursorPt=null,t._activeWallChainId=null,t._activeWallChainPartitionIds=[],t._primeDrawWallField(),t._saveNav(),t.requestUpdate(),t._showToast(t._t("toast.space_copied",{name:a}))}catch(e){"conflict"===e?.code&&await Promise.all([t._reloadConfigOnly(!0),t._reloadLayoutOnly()]),br(t,i,!1),function(t,e){if(e instanceof lr)return void t._showToast(t._t(gr[e.code]));const s=e?.code;"wall_model_client_outdated"!==s?t._showToast(t._t("toast.error",{err:t._errText(e)})):t._showToast(t._t("toast.wall_model_client_outdated"))}(t,e),n&&t.requestUpdate()}}function wr(){if(this.host._spaceDialog.copy)return function(t,e){const s=t._spaceDialog.copy,i=()=>function(t){const e=t._spaceDialog;!e?.copy||e.busy||e.copy.busy||(t._spaceDialog={...e,copy:void 0})}(t);return p``}const Fa=1e-6*z,Na=6*z;function Aa(t){return Number.isFinite(t)?Math.round(t/z)*z:t}const Ea=(t,e,s,i)=>Math.hypot(s-t,i-e),Oa=(t,e,s,i,o,a,n,r)=>Math.hypot(Math.max(Math.abs(o-t),Math.abs(o+n-(t+s))),Math.max(Math.abs(a-e),Math.abs(a+r-(e+i)))),Ba=(t,e,s,i,o,a,n)=>{const r=Math.max(Number(i)||0,0)/2,l=Math.PI/180,h=Math.cos(s*l)*r,c=Math.sin(s*l)*r,d=Math.cos(n*l)*r,p=Math.sin(n*l)*r,u=Math.max(Ea(t+h,e+c,o+d,a+p),Ea(t-h,e-c,o-d,a-p)),_=Math.max(Ea(t+h,e+c,o-d,a-p),Ea(t-h,e-c,o+d,a+p));return Math.min(u,_)},Ha=t=>{const e=Number(t?.cell_cm);return e>0?e:5};function Wa(t,e){const s=JSON.parse(JSON.stringify(t||[])),i=JSON.parse(JSON.stringify(e||{}));let o=0,a=0,n=0,r=0,l="",h=0,c=0;const d=(t,e)=>{Number.isFinite(t)&&Number.isFinite(e)&&t!==e&&Math.abs(e-t)<=Fa&&c++},p=(t,e)=>{d(t[0],e[0]),d(t[1],e[1])},u={};let _=5;for(const t of s){const e=Ha(t);null!=t?.id&&(u[String(t.id)]=e),e>_&&(_=e)}const m=(t,e,s,i=!1)=>{if(!(t>Fa||i))return;o++,t>n&&(n=t);const a=t*F*e;a>r&&(r=a,l=s)};for(const t of s){const e=Ha(t),s=null!=t?.id?String(t.id):"";for(const i of t.rooms||[]){a++;let t=0;if(i.poly?.length)i.poly=i.poly.map(e=>{const s=[Aa(e[0]),Aa(e[1])];return t=Math.max(t,Ea(e[0],e[1],s[0],s[1])),p(e,s),s});else if(null!=i.x&&null!=i.y){const e=i.x,s=i.y,o=i.w||0,a=i.h||0,n=Aa(e+o),r=Aa(s+a),l=Aa(e),h=Aa(s),c=Math.max(z,n-l),p=Math.max(z,r-h);t=Oa(e,s,o,a,l,h,c,p),i.x=l,i.y=h,i.w=c,i.h=p,d(e,l),d(s,h),d(e+o,l+c),d(s+a,h+p)}m(t,e,s)}for(const i of t.partitions||[]){a++;const o=[i.a[0],i.a[1]],n=[i.b[0],i.b[1]],r=[Aa(o[0]),Aa(o[1])],l=[Aa(n[0]),Aa(n[1])];let h=Math.max(Ea(o[0],o[1],r[0],r[1]),Ea(n[0],n[1],l[0],l[1]));const c=Ea(r[0],r[1],l[0],l[1]),d=(t.openings||[]).filter(t=>"partition"===t.host?.kind&&t.host.id===i.id).every(t=>{const e=Number(t.length),s=Number(t.host.t),i=s*c;return Number.isFinite(e)&&e>0&&Number.isFinite(s)&&s>=0&&s<=1&&i-e/2>=-Fa&&i+e/2<=c+Fa});c>Fa&&d?(i.a=r,i.b=l,p(o,r),p(n,l)):h=0,m(h,e,s)}for(const i of t.wall_columns||[]){a++;const t=[i.center[0],i.center[1]],o=[Aa(t[0]),Aa(t[1])],n=Ea(t[0],t[1],o[0],o[1]);i.center=o,p(t,o),m(n,e,s)}for(const i of t.decor||[]){if("furniture"===i.kind||"image"===i.kind)continue;a++;let t=0;if("line"===i.kind){const e=[i.x1,i.y1],s=[i.x2,i.y2],o=[Aa(e[0]),Aa(e[1])],a=[Aa(s[0]),Aa(s[1])];t=Math.max(Ea(e[0],e[1],o[0],o[1]),Ea(s[0],s[1],a[0],a[1])),i.x1=o[0],i.y1=o[1],i.x2=a[0],i.y2=a[1],p(e,o),p(s,a)}else{const e=i.x,s=i.y,o=i.w,a=i.h,n=Aa(e),r=Aa(s);if(null!=i.w&&null!=i.h){const l=Aa(e+o),h=Aa(s+a),c=Math.max(z,l-n),p=Math.max(z,h-r);t=Oa(e,s,o,a,n,r,c,p),i.w=c,i.h=p,d(e+o,n+c),d(s+a,r+p)}else t=Ea(e,s,n,r);i.x=n,i.y=r,d(e,n),d(s,r)}m(t,e,s)}for(const i of t.openings||[]){if(a++,"partition"===i.host?.kind){const o=(t.partitions||[]).find(t=>t.id===i.host.id),a=Number(i.host.t);if(!o||!Number.isFinite(a)||a<0||a>1)continue;const n=o.b[0]-o.a[0],r=o.b[1]-o.a[1];if(Math.hypot(n,r)<=Fa)continue;const l=o.a[0]+n*a,c=o.a[1]+r*a;let d=180*Math.atan2(r,n)/Math.PI;d>=90?d-=180:d<-90&&(d+=180);const p=Number(i.angle),u=!(Number.isFinite(p)&&p===d),_=Ba(i.x,i.y,Number.isFinite(p)?p:d,Number(i.length)||0,l,c,d);i.x=l,i.y=c,i.angle=d,u&&h++,m(_,e,s,u);continue}const o=R([i.x,i.y],t.rooms||[],Na,{step:z,length:Number(i.length)||0});if(!o)continue;const n=Number(i.angle),r=!(Number.isFinite(n)&&n===o.angle),l=Ba(i.x,i.y,Number.isFinite(n)?n:o.angle,Number(i.length)||0,o.x,o.y,o.angle);i.x=o.x,i.y=o.y,i.angle=o.angle,r&&h++,m(l,e,s,r)}}for(const[t,e]of Object.entries(i)){if(!e||"object"!=typeof e)continue;const s=e;if("number"!=typeof s.x||"number"!=typeof s.y)continue;a++;const o=Aa(s.x),n=Aa(s.y),r=Ea(s.x,s.y,o,n);i[t]={...s,x:o,y:n},d(s.x,o),d(s.y,n);const l="string"==typeof s.s?s.s:"";m(r,u[l]??_,l)}return{spaces:s,layout:i,report:{moved:o,coordsCanonicalized:c,total:a,maxShift:n,maxShiftCm:r,maxSpace:l,rotated:h},changed:o>0||c>0}}function ja(t,e){const s=e.base+t*e.span;return Math.min(1,Math.max(0,s))}const Ga=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),qa=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1]);function Ua(t,e,s){const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;if(a<=0)return qa(t,e);let n=((t[0]-e[0])*i+(t[1]-e[1])*o)/a;return n=Math.max(0,Math.min(1,n)),Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))}function Ka(t,e,s,i,o){for(const i of e)if(i&&!s.has(i.id)&&Ga(i.a)&&Ga(i.b)&&(qa(t,i.a)<=o||qa(t,i.b)<=o))return!0;for(const e of i?.roomPolygons||[])for(let s=0;s0&&r>0))return null;if(Math.abs(o[0]/n*(a[1]/r)-o[1]/n*(a[0]/r))>s)return null;for(const[s,o]of[[t.a,e.a],[t.a,e.b],[t.b,e.a],[t.b,e.b]])if(qa(s,o)<=i)return[(s[0]+o[0])/2,(s[1]+o[1])/2];return null}function Ja(t,e){const s=.05*(Number(e.pitch)>0?Number(e.pitch):1),i=new Map;let o=(t||[]).filter(t=>!!t&&"string"==typeof t.id&&Ga(t.a)&&Ga(t.b));if(o.length<2)return{partitions:[...t||[]],merged:0,openingMoves:[]};const a=e.seedIds&&e.seedIds.length?new Set(e.seedIds):null;let n=0;for(let t=0;tqa(e,t.at)>s);let c=h[0]??r.a,d=h[h.length-1]??l.b;if(h.length<2&&(c=r.a,d=l.b),d[0]0?(d[0]-c[0])/u:0,m=u>0?(d[1]-c[1])/u:0,g=t=>u>0?((t[0]-c[0])*_+(t[1]-c[1])*m)/u:0;for(const t of[r,l]){const e=g(t.a),s=g(t.b)-e;for(const[o,a]of i)a.toId===t.id&&i.set(o,{fromId:a.fromId,toId:p.id,base:e+a.base*s,span:a.span*s});i.set(t.id,{fromId:t.id,toId:p.id,base:e,span:s})}a&&a.add(p.id),o=o.filter((e,s)=>s!==t.i&&s!==t.j),o.splice(t.i,0,p),n++}return{partitions:o,merged:n,openingMoves:[...i.values()]}}function Za(t,e,s,i){if(!t?.length||!s.length)return 0;const o=new Map(s.map(t=>[t.fromId,t]));let a=0;for(const s of t){const t=s?.host;if(!t||"partition"!==t.kind)continue;const n=o.get(t.id);if(!n)continue;s.host={...t,id:n.toId,t:ja(t.t,n)},a++;const r=A(s,e,i.coordScale,i.cellCm,i.gridPitch).resolved;r&&Object.assign(s,E(s,r,i.coordScale))}return a}function Ya(t){return{roomPolygons:(t?.rooms||[]).map(t=>N(t)).filter(t=>!!t),columns:t?.wall_columns||[]}}const Xa=t=>!!t&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),Qa=(t,e)=>t[0]-e[0]||t[1]-e[1],tn=(t,e,s,i)=>[t[0]+e*i,t[1]+s*i],en=(t,e,s,i)=>(t[0]-e[0])*s+(t[1]-e[1])*i,sn=(t,e,s,i,o)=>{const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(!(r>o))return null;const l=a/r,h=n/r,c=e=>Math.abs((e[0]-t[0])*h-(e[1]-t[1])*l);if(c(s)>o||c(i)>o)return null;const d=en(s,t,l,h),p=en(i,t,l,h),u=Math.max(0,Math.min(d,p)),_=Math.min(r,Math.max(d,p));return _-u>o?{lo:u,hi:_}:null},on=(t,e,s)=>Math.min(t.hi,e.hi)-Math.max(t.lo,e.lo)>s,an=t=>{const e=new Set(["id","a","b","cm"]);return Object.keys(t||{}).every(t=>e.has(t))},nn=(t,e,s,i)=>{const o=t.b[0]-t.a[0],a=t.b[1]-t.a[1],n=Math.hypot(o,a);if(!(n>i))return!0;const r=o/n,l=a/n,h=V(t.cm,s.cellCm,s.gridPitch)/2;return e.some(e=>{const o=e?.center;if(!Xa(o))return!0;const a=en(o,t.a,r,l),c=Math.abs((o[0]-t.a[0])*l-(o[1]-t.a[1])*r),d=V(Number(e.cm),s.cellCm,s.gridPitch)*("square"===e.shape?Math.SQRT1_2:.5);return!(Number.isFinite(d)&&d>0)||a>=-d-i&&a<=n+d+i&&c<=h+d+i})},rn=(t,e,s)=>{if(t.host){const i=A(t,e,s.coordScale,s.cellCm,s.gridPitch).resolved;return i?{center:i.center,angle:i.angle,length:i.length}:null}const i=Number(t.x)*s.coordScale,o=Number(t.y)*s.coordScale,a=Number(t.angle),n=Number(t.length)*s.coordScale;return[i,o,a,n].every(Number.isFinite)&&n>0?{center:[i,o],angle:a,length:n}:null},ln=(t,e,s)=>{const i=t.angle*Math.PI/180,o=Math.cos(i),a=Math.sin(i),n=e.angle*Math.PI/180,r=Math.cos(n),l=Math.sin(n);if(Math.abs(o*l-a*r)>1e-6)return!1;const h=e.center[0]-t.center[0],c=e.center[1]-t.center[1];if(Math.abs(h*a-c*o)>s)return!1;const d=h*o+c*a;return Math.max(-t.length/2,d-e.length/2)({...t,a:[t.a[0]*e,t.a[1]*e],b:[t.b[0]*e,t.b[1]*e]}),cn=(t,e,s,i)=>{const o=`~r-${(t=>{let e=2166136261;for(let s=0;s>>0;return e.toString(36)})(`${t}|${e[0].toFixed(9)},${e[1].toFixed(9)}|${s[0].toFixed(9)},${s[1].toFixed(9)}`)}`,a=`${t.slice(0,Math.max(1,64-o.length))}${o}`;let n=a;for(let t=2;i.has(n);t++){const e=`-${t}`;n=`${a.slice(0,64-e.length)}${e}`}return i.add(n),n},dn=(t,e)=>{const s=[];for(const i of t){const t=s[s.length-1];!(t&&Math.abs(t.hi-i.lo)<=e&&t.safe===i.safe)||i.safe&&t.signature!==i.signature?s.push({lo:i.lo,hi:i.hi,a:i.a,b:i.b,safe:i.safe,signature:i.signature,roomIds:i.roomIds,finalCm:i.finalCm}):(t.hi=i.hi,t.b=i.b)}return s};function pn(t,e,s,i,o){const a=s||[],n=Array.isArray(t?.partitions)?t.partitions:[],r=Array.isArray(t?.openings)?t.openings:[],l={walls:a,partitions:n,openings:r,partitionsReconciled:0,openingsRehosted:0};if(!n.length)return l;const h=Math.max(2e-4*o.gridPitch,1e-9);let c=a,d=n,p=r,u=0,_=0;const m=o.partitionIds?new Set(o.partitionIds):null,g=new Map(e.partitions.map(t=>[t.id,t]));for(const t of[...n].sort((t,e)=>t.id.localeCompare(e.id))){if(m&&!m.has(t.id))continue;if(!d.some(e=>e.id===t.id))continue;if(!an(t))continue;const s=g.get(t.id);if(!(s&&Xa(s.a)&&Xa(s.b)&&Number.isFinite(s.cm)&&(o.allowCoincidentPartitions?!(s.cm<0):s.cm>0)))continue;const[a,n]=Qa(s.a,s.b)<=0?[[s.a[0],s.a[1]],[s.b[0],s.b[1]]]:[[s.b[0],s.b[1]],[s.a[0],s.a[1]]],r=n[0]-a[0],l=n[1]-a[1],f=Math.hypot(r,l);if(!(f>h))continue;const b=r/f,v=l/f,y=O(e.rooms,c,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),w=y.flatMap(t=>{if(t.open||"outer"!==t.kind&&"shared"!==t.kind)return[];const e=sn(a,n,t.a,t.b,h);return e?[{interval:t,range:e}]:[]});if(!w.length)continue;const $=p.filter(t=>"partition"===t.host?.kind&&t.host.id===s.id).map(t=>({opening:t,resolved:A(t,e.partitions,o.coordScale,o.cellCm,o.gridPitch).resolved}));if($.some(t=>!t.resolved))continue;const k=[0,f];for(const{range:t}of w)k.push(t.lo,t.hi);const x=k.slice(),M=new Map;for(const{opening:t,resolved:e}of $){const s=en(e.center,a,b,v),i={lo:s-e.length/2,hi:s+e.length/2};M.set(t.id,i),x.push(Math.max(0,i.lo),Math.min(f,i.hi))}const C=[...new Set(x.filter(t=>Number.isFinite(t)&&t>=-h&&t<=f+h).map(t=>Math.max(0,Math.min(f,t)).toFixed(9)))].map(Number).sort((t,e)=>t-e),S=d.map(t=>hn(t,o.coordScale)).filter(t=>t.id!==s.id),P=[];for(let t=0;t+1h))continue;const r=tn(a,b,v,i),l=tn(a,b,v,n),c=w.filter(({range:t})=>t.lo<=i+h&&t.hi>=n-h).map(({interval:t})=>t),d=new Map;for(const t of c)d.set(t.roomId,t);const p=[...d.values()],u=new Set(p.map(t=>t.kind)),_=new Set(p.map(t=>o.allowCoincidentPartitions||t.cm>0?t.cm:B)),m=p[0]?.kind,g=[...d.keys()].sort(),f=1===u.size&&1===_.size&&("outer"===m&&1===g.length||"shared"===m&&2===g.length),y={id:s.id,a:r,b:l,cm:s.cm},$=S.some(t=>!!sn(r,l,t.a,t.b,h)),k=f&&(o.allowCoincidentPartitions||!$)&&!nn(y,e.wall_columns,o,h),x=f?o.allowCoincidentPartitions||p[0].cm>0?p[0].cm:B:0,M=f?Math.max(x,s.cm):s.cm;P.push({lo:i,hi:n,a:r,b:l,safe:k,signature:k?`${m}|${g.join(",")}|${M}`:"",roomIds:g,roomCm:x,finalCm:M})}if(!P.some(t=>t.safe))continue;const D=new Map;for(const{opening:t,resolved:e}of $){const i=M.get(t.id),a=k.some(t=>t>i.lo+h&&ton(t,i,h)),r=new Set(n.filter(t=>t.safe).map(t=>t.signature));if(!a&&n.length>0&&n.every(t=>t.safe)&&1===r.size&&H(e,y,h)){D.set(t.id,{resolved:e,signature:[...r][0]});continue}const l=W(s,o.cellCm,o.gridPitch),c={lo:i.lo-l,hi:i.hi+l};for(const t of P)on(t,c,h)&&(t.safe=!1,t.signature="")}let I=!0;for(;I;){I=!1;for(const[t,e]of[...D.entries()]){const i=M.get(t),a=P.filter(t=>on(t,i,h));if(a.length>0&&a.every(t=>t.safe)&&a.every(t=>t.signature===e.signature))continue;D.delete(t);const n=W(s,o.cellCm,o.gridPitch),r={lo:i.lo-n,hi:i.hi+n};for(const t of P)on(t,r,h)&&(t.safe=!1,t.signature="");I=!0}}const L=dn(P,h),T=L.filter(t=>t.safe),R=L.filter(t=>!t.safe);if(!T.length)continue;if(d.length-1+R.length>2e3)continue;let z=c;for(const t of T){const[e,i]=Qa(s.a,s.b)<=0?[t.a,t.b]:[t.b,t.a];z=j(z,e,i,t.finalCm,o.pitch,o.coordScale)}if(z=G(e.rooms,z,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),z.length>500)continue;const F=new Set(d.map(t=>t.id));F.delete(s.id);const N=R.map((t,e)=>{const i=[t.a[0]/o.coordScale,t.a[1]/o.coordScale],a=[t.b[0]/o.coordScale,t.b[1]/o.coordScale],n=0===e?s.id:cn(s.id,i,a,F);return F.add(n),{id:n,a:i,b:a,cm:s.cm}}),V=d.findIndex(t=>t.id===s.id),J=d.slice();J.splice(V,1,...N);const Z=J.map(t=>hn(t,o.coordScale)),Y=new Map;let X=!0;for(const{opening:t,resolved:e}of $){const s=D.get(t.id);if(s){const e=E(t,s.resolved,o.coordScale),{host:i,...a}=e;Y.set(t.id,a);continue}const i=M.get(t.id),a=N[R.findIndex(t=>t.lo<=i.lo+h&&t.hi>=i.hi-h)],n=a&&Z.find(t=>t.id===a.id);if(!a||!n){X=!1;break}const r=n.b[0]-n.a[0],l=n.b[1]-n.a[1],c=Math.hypot(r,l),d=en(e.center,n.a,r/c,l/c),p={...E(t,e,o.coordScale),host:{kind:"partition",id:a.id,t:d/c}};if(!q(p,Z,o.coordScale,o.cellCm,o.gridPitch).resolved){X=!1;break}Y.set(t.id,p)}if(!X)continue;const Q=p.map(t=>Y.get(t.id)||t),tt=[...D.keys()].map(t=>Y.get(t)),et=tt.map(t=>rn(t,Z,o));if(et.some(t=>!t))continue;let st=!1;for(let t=0;tt.id));for(const t of Q){if(it.has(t.id))continue;const e=rn(t,Z,o);e&&et.some(t=>ln(t,e,h))&&(st=!0)}if(st)continue;const ot=U(e.rooms,z,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale);[...D.entries()].every(([t,e])=>{const s=Y.get(t),i=K(ot,{x:s.x*o.coordScale,y:s.y*o.coordScale,angle:s.angle,length:s.length*o.coordScale},!0),a=[i.negative,i.positive].filter(t=>!!t?.full),n=e.signature.split("|")[1].split(","),r=new Set(a.map(t=>t.roomId));return a.length===n.length&&r.size===n.length&&n.every(t=>r.has(t))})&&(c=z,d=J,p=Q,u+=T.length,_+=D.size)}return{walls:c,partitions:d,openings:p,partitionsReconciled:u,openingsRehosted:_}}const un=t=>JSON.parse(JSON.stringify(t)),_n=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),mn=(t,e)=>e.length>0&&e.length<=35&&("space"===t?/^[a-z0-9_-]+$/.test(e):/^[A-Za-z0-9_-]+$/.test(e));function gn(t,e){let s=String(e??"");const i=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),o=new RegExp(`^${i}_(.+)_([0-9a-f]{8})$`);let a=0;for(;a<16;a++){const t=o.exec(s);if(!t)return{root:s,layers:a,bounded:!1};s=t[1]}return{root:s,layers:a,bounded:o.test(s)}}const fn=(t,e,s)=>{const i=t.get(e)||[];i.push(s),t.set(e,i)};const bn=1e-9;class vn extends Error{constructor(t,e=""){super(e?`${t}: ${e}`:t),this.reason=t,this.name="WallSegmentModelError"}}const yn=t=>JSON.parse(JSON.stringify(t)),wn=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(Number(t[0]))&&Number.isFinite(Number(t[1])),$n=t=>[Number(t[0]),Number(t[1])],kn=t=>`${Number(t[0]).toFixed(12)},${Number(t[1]).toFixed(12)}`,xn=(t,e)=>{const s=kn(t),i=kn(e);return skn(t)<=kn(e)?[$n(t),$n(e)]:[$n(e),$n(t)],Cn=(t,e)=>Math.hypot(e[0]-t[0],e[1]-t[1]),Sn=(t,e=[])=>{const s=new Set,i=t=>{const e=Number(t);if(!Number.isFinite(e))return;const i=e/z;Math.abs(i-Math.round(i))>=tt&&s.add(e.toFixed(12))};for(const e of Array.isArray(t?.rooms)?t.rooms:[])for(const t of N(e)||[])i(t[0]),i(t[1]);for(const e of[t?.wall_segments,t?.walls])for(const t of Array.isArray(e)?e:[])i(t?.a?.[0]),i(t?.a?.[1]),i(t?.b?.[0]),i(t?.b?.[1]);for(const t of e)i(t?.[0]),i(t?.[1]);return s.size},Pn=(t,e,s)=>{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;return a>1e-18?((t[0]-e[0])*i+(t[1]-e[1])*o)/a:0},Dn=(t,e,s)=>{const i=Math.max(0,Math.min(1,Pn(t,e,s)));return Math.hypot(t[0]-(e[0]+(s[0]-e[0])*i),t[1]-(e[1]+(s[1]-e[1])*i))},In=(t,e,s,i,o=1e-9)=>{const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(r<=o)return 0;const l=e=>Math.abs((e[0]-t[0])*n-(e[1]-t[1])*a)/r;if(l(s)>o||l(i)>o)return 0;const h=Pn(s,t,e),c=Pn(i,t,e);return Math.max(0,Math.min(1,Math.max(h,c))-Math.max(0,Math.min(h,c)))*r},Ln=t=>{const e=(new TextEncoder).encode(t),s=8*e.length,i=64*Math.ceil((e.length+9)/64),o=new Uint8Array(i);o.set(e),o[e.length]=128;const a=new DataView(o.buffer);a.setUint32(i-8,Math.floor(s/4294967296),!1),a.setUint32(i-4,s>>>0,!1);const n=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),r=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),l=new Uint32Array(64),h=(t,e)=>t>>>e|t<<32-e;for(let t=0;t>>3,o=h(s,17)^h(s,19)^s>>>10;l[t]=l[t-16]+i+l[t-7]+o>>>0}let[e,s,i,o,c,d,p,u]=r;for(let t=0;t<64;t++){const a=u+(h(c,6)^h(c,11)^h(c,25))+(c&d^~c&p)+n[t]+l[t]>>>0,r=e&s^e&i^s&i;u=p,p=d,d=c,c=o+a>>>0,o=i,i=s,s=e,e=a+((h(e,2)^h(e,13)^h(e,22))+r>>>0)>>>0}r[0]=r[0]+e>>>0,r[1]=r[1]+s>>>0,r[2]=r[2]+i>>>0,r[3]=r[3]+o>>>0,r[4]=r[4]+c>>>0,r[5]=r[5]+d>>>0,r[6]=r[6]+p>>>0,r[7]=r[7]+u>>>0}const c=new Uint8Array(32),d=new DataView(c.buffer);for(let t=0;t{const e="abcdefghijklmnopqrstuvwxyz234567";let s=0,i=0,o="";for(const a of t)for(i=i<<8|a,s+=8;s>=5;)o+=e[i>>>s-5&31],s-=5;return s&&(o+=e[i<<5-s&31]),o},Rn=(t,e,s,i,o="")=>{const[a,n]=Mn(e,s),r=`${t}|${kn(a)}|${kn(n)}|${[...i].sort().join(",")}${o}`;return`wall-${Tn(Ln(r)).slice(0,20)}`};let zn=0;const Fn=t=>{for(let e=0;e<1e3;e++){const e=globalThis.crypto?.randomUUID?.(),s=`wall-${e||Tn(Ln(`${Date.now()}|${zn++}|${Math.random()}`)).slice(0,26)}`;if(!t.has(s))return s}throw new vn("duplicate-id","id factory exhausted")},Nn=t=>{const e=new Map;for(const s of Array.isArray(t?.wall_segments)?t.wall_segments:[])if(s&&"string"==typeof s.id&&wn(s.a)&&wn(s.b)){if(e.has(s.id))throw new vn("duplicate-id",s.id);e.set(s.id,s)}return e},An=(t,e,s)=>{const i=(s,i)=>{const o=t[0]-s[0],a=t[1]-s[1];return Math.abs(e[0]-i[0]-o)<=bn&&Math.abs(e[1]-i[1]-a)<=bn?[o,a]:null};return i(s.a,s.b)||i(s.b,s.a)},En=(t,e)=>{const s=Array.isArray(t.rooms)?t.rooms:[],i=Y(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]),o=i.length?i:X(s,null,1,.04*z,!0),a=[];for(const t of s){const s=N(t),i=Array.isArray(t?.wall_ids)?t.wall_ids:[];if(s&&i.length===s.length)for(let t=0;t"partition"!==t.host?.kind&&[Number(t.x),Number(t.y)].every(Number.isFinite)&&Number.isFinite(Number(t.angle))&&Number(t.length)>0&&o.some(e=>Dn([Number(t.x),Number(t.y)],[e[0],e[1]],[e[2],e[3]])<=.04*z)):[],l=r.map(t=>{const e=Number(t.angle)*Math.PI/180,s=[Math.cos(e),Math.sin(e)],i=Number(t.length)/2,o=[Number(t.x),Number(t.y)];return{a:[o[0]-s[0]*i,o[1]-s[1]*i],b:[o[0]+s[0]*i,o[1]+s[1]*i]}}),h=(t,e)=>r.some(s=>{const i=[Number(s.x),Number(s.y)];if(!et(t,e,Number(s.angle)))return!1;if(Dn(i,t,e)>.02*z)return!1;const o=Cn(t,e),a=Pn(i,t,e)*o,n=Number(s.length)/2;return a+n>=-1e-9&&a-n<=o+bn}),c=new Map,d=[];for(const i of s){const r=String(i?.id||""),p=N(i);if(!r||!p||p.length<3)throw new vn("invalid-room",r);const u=Q(s,r,n,z,1,[...t.walls||[],...l]);if(!u||u.poly.length<3)throw new vn("invalid-room",r);const _=Array.isArray(i.wall_ids)?i.wall_ids:[],m=_.length===p.length;let g=null,f=m;if(f)for(let t=0;tbn||Math.abs(i[1]-g[1])>bn)){f=!1;break}g=i}const b=[];for(let t=0;t2)throw new vn("third-owner",n);const d=m?_[u.parent[t]]:void 0;if("string"==typeof d&&d){const o=e.get(d);f||!o||In(s,i,o.a,o.b)>bn?l.preferredIds.add(d):l.positionalIds.add(d),l.preferredCarriers.set(d,{a:$n(p[u.parent[t]]),b:$n(p[(u.parent[t]+1)%p.length])})}const g=u.parent[t];l.parentKeys.add(Z(p[g],p[(g+1)%p.length],z));const v=[(s[0]+i[0])/2,(s[1]+i[1])/2],y=t=>t.some(t=>Dn(v,[t[0],t[1]],[t[2],t[3]])<=.04*z);l.zeroWall||=y(a)||y(o)&&!h(s,i),b.push(n)}const v={...i};delete v.wall_ids,d.push({...v,poly:u.poly.map(t=>[t[0],t[1]]),wall_ids:b})}return{atoms:[...c.values()].sort((t,e)=>t.key.localeCompare(e.key)),rooms:d}},On=(t,e,s,i,o)=>{const a=new Map([...s.values()].map(t=>[xn(t.a,t.b),t])),n=(t=>{const e=new Map;for(const s of t)"wall"===s.host?.kind&&e.set(s.host.id,(e.get(s.host.id)||0)+1);return e})(t.openings||[]),r=new Map;for(const t of e){const e=o?.get(t.key);if(e){const i=s.get(e);if(!i)throw new vn("duplicate-id",e);r.set(t,i);continue}if(t.preferredIds.size>1)throw new vn("duplicate-id",[...t.preferredIds].sort().join(","));const i=[...t.preferredIds][0],l=i?s.get(i):void 0;if(l){r.set(t,l);continue}const h=i?t.preferredCarriers.get(i):void 0;if(i&&h){r.set(t,{id:i,a:h.a,b:h.b,cm:0});continue}const c=a.get(t.key);if(c){r.set(t,c);continue}const d=[...s.values()].filter(e=>In(t.a,t.b,e.a,e.b)>bn),p=[...new Map(d.map(t=>[t.id,t])).values()];if(p.sort((t,e)=>(n.get(e.id)||0)-(n.get(t.id)||0)||Cn(e.a,e.b)-Cn(t.a,t.b)||t.id.localeCompare(e.id)),p[0])r.set(t,p[0]);else if(1===t.positionalIds.size){const e=s.get([...t.positionalIds][0]);e&&r.set(t,e)}}const l=new Map;for(const[t,e]of r){const s=l.get(e.id)||[];s.push(t),l.set(e.id,s)}for(const[t,e]of l){const i=s.get(t)||r.get(e[0]);if(!i)throw new vn("duplicate-id",t);const o=[(i.a[0]+i.b[0])/2,(i.a[1]+i.b[1])/2];e.sort((t,e)=>{const s=Dn(o,t.a,t.b)<=bn?0:1,a=Dn(o,e.a,e.b)<=bn?0:1;if(s!==a)return s-a;return(Dn(i.a,t.a,t.b)<=bn?0:1)-(Dn(i.a,e.a,e.b)<=bn?0:1)||t.key.localeCompare(e.key)}),e[0].id=t}const h=(t=>{const e=new Set;for(const s of[t.rooms,t.openings,t.decor,t.room_drafts,t.partitions,t.wall_columns])for(const t of Array.isArray(s)?s:[])"string"==typeof t?.id&&t.id&&e.add(t.id);for(const s of Array.isArray(t.room_drafts)?t.room_drafts:[])for(const t of Array.isArray(s?.segments)?s.segments:[])"string"==typeof t?.id&&t.id&&e.add(t.id);return e})(t);for(const t of e)if(t.id){if(h.has(t.id))throw new vn("duplicate-id",t.id);h.add(t.id)}const c=e.filter(t=>!t.id);if(i){const e=c.map(e=>{const[s,i]=Mn(e.a,e.b),o=`${String(t.id||"")}|${kn(s)}|${kn(i)}|${[...e.owners].sort().join(",")}`,a=Tn(Ln(o));return{atom:e,seed:o,digest:a,base:`wall-${a.slice(0,20)}`}}).sort((t,e)=>t.digest.localeCompare(e.digest)||t.atom.key.localeCompare(e.atom.key)),s=new Map;for(const t of e){const e=s.get(t.digest);if(e&&e!==t.seed)throw new vn("duplicate-id",t.digest);s.set(t.digest,t.seed);let i=1,o=t.base;for(;h.has(o);)o=`${t.base}-${++i}`;t.atom.id=o,h.add(o)}}else for(const t of c)t.id=Fn(h),h.add(t.id)},Bn=(t,e)=>{if("partition"===t.host?.kind)return null;const s=[Number(t.x),Number(t.y)];if(!s.every(Number.isFinite))return null;const i=e=>{if(!(Number(e.cm)>0))return!1;const i=Pn(s,e.a,e.b),o=Cn(e.a,e.b),a=Number(t.length)/2;return i>=-1e-9&&i<=1+bn&&Dn(s,e.a,e.b)<=.02*z&&et(e.a,e.b,Number(t.angle))&&Number.isFinite(a)&&a>=0&&i*o-a>=-1e-9&&i*o+a<=o+bn},o="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null,a=o&&i(o)?[o]:e.filter(i);if(1!==a.length)return null;const n=a[0];return{kind:"wall",id:n.id,t:Math.max(0,Math.min(1,Pn(s,n.a,n.b)))}},Hn=(t,e)=>{const s=[Number(t.x),Number(t.y)];if(!s.every(Number.isFinite))return null;const i=Number(t.length)/2,o=e.filter(e=>{if(!(Number(e.cm)>0))return!1;const o=Pn(s,e.a,e.b),a=Cn(e.a,e.b);return o>=-1e-9&&o<=1+bn&&Dn(s,e.a,e.b)<=.02*z&&et(e.a,e.b,Number(t.angle))&&Number.isFinite(i)&&i>=0&&o*a-i>=-1e-9&&o*a+i<=a+bn}),a=(e=>{if(!e.length)return null;const i="wall"===t.host?.kind?e.find(e=>e.id===t.host.id):null;return i||[...e].sort((t,e)=>Dn(s,t.a,t.b)-Dn(s,e.a,e.b)||Number(e.cm)-Number(t.cm)||(t.ide.id?1:0))[0]})(o);return a?{kind:"wall",id:a.id,t:Math.max(0,Math.min(1,Pn(s,a.a,a.b)))}:null},Wn=/^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/,jn=t=>{if("number"!=typeof t&&"string"!=typeof t)return null;if("string"==typeof t&&!Wn.test(t.trim()))return null;const e=Number(t);return Number.isFinite(e)?e:null},Gn=t=>{if(!Array.isArray(t)||t.length<2)return null;const e=jn(t[0]),s=jn(t[1]);return null==e||null==s?null:[e,s]},qn=t=>"string"==typeof t?t:"",Un=t=>{if(!Object.prototype.hasOwnProperty.call(t,"room_drafts"))return{drafts:0,segments:0};const e=Array.isArray(t.room_drafts)?t.room_drafts:[];if(!e.length)return delete t.room_drafts,{drafts:0,segments:0};const s=new Set;for(const e of[t.rooms,t.openings,t.decor,t.partitions,t.wall_columns,t.wall_segments])for(const t of Array.isArray(e)?e:[])"string"==typeof t?.id&&t.id&&s.add(t.id);for(const t of e)"string"==typeof t?.id&&t.id&&s.add(t.id);const i=Array.isArray(t.partitions)?[...t.partitions]:[];let o=0;for(const a of e){const e=qn(a?.id),n=Array.isArray(a?.points)?a.points:[],r=Array.isArray(a?.segments)?a.segments:[];if(n.length<2||r.length!==n.length-1)throw new vn("zero-length",e);for(let a=0;a+1100)throw new vn("thickness-conflict",e);let p="string"==typeof c?.id&&c.id?c.id:"";if(!p||s.has(p)){const i=Rn(qn(t.id),l,h,[`draft:${e}:${a}`]);p=i;for(let t=2;s.has(p);t++)p=`${i}-${t}`}s.add(p),i.push({id:p,a:$n(l),b:$n(h),cm:d}),o++}}return i.length?t.partitions=i:delete t.partitions,delete t.room_drafts,{drafts:e.length,segments:o}},Kn=t=>Un(t),Vn=(t,e,s)=>{const i=Un(t),o=Nn(t),{atoms:a,rooms:n}=En(t,o);On(t,a,o,e,s);const r=a.map(e=>{const s=e.id?o.get(e.id):void 0,i=((t,e,s)=>{if(e.zeroWall)return 0;const i=Array.isArray(t.walls)?t.walls:[],o=Z(e.a,e.b,z),a=i.filter(t=>Number(t.cm)>0&&(!(t.key!==o&&!e.parentKeys.has(t.key))||!(!wn(t.a)||!wn(t.b))&&In(e.a,e.b,t.a,t.b)>=Cn(e.a,e.b)-bn)).map(t=>Math.max(1,Math.min(100,Number(t.cm))));if(new Set(a.map(t=>t.toFixed(9))).size>1)throw new vn("thickness-conflict",e.key);if(a.length)return a[0];const n=it(i,e.a,e.b,z,1);return n>0?n:Number(s?.cm)>0?Number(s.cm):0})(t,e,s);return{...s||{},id:e.id,a:[...e.a],b:[...e.b],cm:i}}),l=new Map(a.map(t=>[t.key,t.id]));for(const t of n)t.wall_ids=t.wall_ids.map(t=>l.get(t));t.rooms=n,t.wall_segments=r,t.walls=r.filter(t=>t.cm>0).map(t=>({key:Z(t.a,t.b,z),cm:t.cm,a:[...t.a],b:[...t.b]})),t.walls.length||delete t.walls,delete t.open_spans;for(const e of t.rooms)delete e.open_to;return((t,e,s)=>{const i=Array.isArray(t.openings)?t.openings:[];for(const t of i){if("partition"===t.host?.kind)continue;if(!t.host&&!s){const s=Bn(t,e);s&&(t.host=s);continue}const i=Bn(t,e)??(s?Hn(t,e):null);if(i)t.host=i;else{if(!s)throw new vn("opening-host",t.id);delete t.host}}})(t,r,e),{wallSegments:r.reduce((t,e)=>t+(o.has(e.id)?0:1),0),drafts:i.drafts,draftSegments:i.segments}};function Jn(t,e={}){const s=JSON.stringify(t),i=yn(t);J(i);let o=0,a=0,n=0;const r=Number(i?.model_version||0)<10;for(const t of Array.isArray(i?.spaces)?i.spaces:[]){const s=e.lineageSpaceId===String(t?.id||"")?e.lineageHints:void 0,i=Vn(t,r,s);o+=i.wallSegments,a+=i.drafts,n+=i.draftSegments}return i.model_version=10,J(i),{config:i,changed:s!==JSON.stringify(i),migratedSegments:o,migratedDrafts:a,migratedDraftSegments:n}}const Zn=t=>!!t&&"object"==typeof t&&!Array.isArray(t);function Yn(t,e){const s=(t,e)=>{if(Array.isArray(t)&&Array.isArray(e)){const i=new Map;for(const e of t)Zn(e)&&"string"==typeof e.id&&e.id&&i.set(e.id,e);const o=e.map((e,o)=>{if(Zn(e)&&"string"==typeof e.id&&e.id){const t=i.get(e.id);return t?s(t,e):yn(e)}return o[e,e in t?s(t[e],i):yn(i)]);for(const e of Object.keys(t))delete t[e];for(const[e,s]of i)t[e]=s;return t}return yn(e)};return s(t,e)}const Xn=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),Qn=(t,e,s)=>Math.min(s,Math.max(e,t)),tr=t=>bt({spaces:[t]})[0],er=(t,e,s)=>{const i=s>0?s:1,o=t=>`${(t[0]/i).toFixed(12)},${(t[1]/i).toFixed(12)}`,a=o(t),n=o(e);return a0?n:1,l=Math.max(i*r*.02,1e-9),h=[];for(const e of t||[])for(const t of N(e)||[])h.push([t[0],t[1]]);const c=[];for(const t of s||[])Array.isArray(t)&&t.length>=4&&t.slice(0,4).every(Number.isFinite)&&c.push([t[0],t[1]],[t[2],t[3]]);const d=(t,e)=>e.some(e=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*l),p=new Map;for(const n of t||[]){if(!n?.id)continue;const u=vt(t,n.id,e,s,i,o,a,r);if(u)for(let t=0;t0&&_>0&&n===m&&_!==n))continue;const g=u.poly[i],f=u.poly[(i+1)%u.poly.length],b=Math.hypot(f[0]-g[0],f[1]-g[1]);if(!(b>l&&b<.5*a-1e-9*a))continue;if(d(g,c)||d(f,c))continue;if(d(g,h)&&d(f,h))continue;const v=er(g,f,r),y=p.get(v);y?y.targets.add(n):p.set(v,{a:[g[0],g[1]],b:[f[0],f[1]],targets:new Set([n])})}}}let u=e.slice();const _=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*l,m=(t,e)=>{if(!Array.isArray(t.a)||!Array.isArray(t.b)||t.a.length<2||t.b.length<2)return!1;const s=[Number(t.a[0])*r,Number(t.a[1])*r],i=[Number(t.b[0])*r,Number(t.b[1])*r];return!![...s,...i].every(Number.isFinite)&&(_(s,e.a)&&_(i,e.b)||_(s,e.b)&&_(i,e.a))};for(const t of[...p.values()].filter(t=>1===t.targets.size).sort((t,e)=>er(t.a,t.b,r).localeCompare(er(e.a,e.b,r)))){const e=[...t.targets][0],s=u.filter(e=>m(e,t));if(new Set(s.map(t=>t.cm)).size>1)continue;let o=!1;u=u.map(s=>m(s,t)?(o=!0,s.cm===e?s:{...s,cm:e}):s),o||(u=j(u,t.a,t.b,e,i,r))}return u}const ir=t=>{const e=[];for(const s of t||[]){const t=N(s);if(t?.length)for(let s=0;s"string"==typeof t?.id?t.id:"").filter(Boolean),c=new Set(h),d=new Map;for(const t of h){const e=gn("space",t);e.layers>0&&mn("space",e.root)&&fn(d,e.root,t)}const p=new Map,u=new Map,_=new Map,m=new Map;for(const t of r){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const s=new Map;for(const i of Array.isArray(t.rooms)?t.rooms:[]){const t="string"==typeof i?.id?i.id:"";if(!t)continue;const o=gn("room",t);o.layers>0&&mn("room",o.root)&&fn(s,o.root,t),u.has(t)||u.set(t,e),_.has(t)||_.set(t,String(i.name||""));const a="string"==typeof i.area?i.area:"";if(a){const s=m.get(a)||[];s.push({spaceId:e,roomId:t}),m.set(a,s)}}p.set(e,s)}const g=new Set(u.keys()),f=new Map,b=new Map;for(const t of l)"string"==typeof t?.id&&t.id&&(!0===t.removed?b.set(t.id,t):f.set(t.id,t));const v={spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,positionsUnresolved:0,nestedRefsUnresolved:0,deadSpaceIds:[],orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0,removedPositions:[],liveMissingPositions:[],unverifiedPositions:[]},y=new Set,w=t=>c.has(t)?null:(()=>{const e=gn("space",t).root;if(!mn("space",e))return null;const s=d.get(e)||[];return 1===s.length?s[0]:null})(),$=(t,e)=>{const s=gn("room",t).root;if(!mn("room",s))return null;const i=p.get(e)?.get(s)||[];return 1===i.length?i[0]:null},k=t=>{const e=s.effectiveAreaByMarker?.[t]||"",i=e&&m.get(e)||[];return 1===i.length?i[0]:null},x=(t,e,s)=>{if("string"==typeof t.room_id&&t.room_id&&!g.has(t.room_id)){const i=e?$(t.room_id,e):null;i?(t.room_id=i,v.roomRefsRemapped++):s?(t.room_id=s.roomId,v.roomRefsRemapped++):!0!==t.removed&&delete t.room_id}const i=t.vacuum?.segment_map;if(i&&"object"==typeof i&&!Array.isArray(i))for(const t of Object.keys(i)){const s=i[t];if("string"!=typeof s||!s||g.has(s))continue;const o=e?$(s,e):null;o?(i[t]=o,v.roomRefsRemapped++):v.nestedRefsUnresolved++}};for(const t of l){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const s="string"==typeof t.space?t.space:"",i=s&&!c.has(s),a=o[e],n="string"==typeof a?.s?a.s:"",r=n&&!c.has(n),l=!0===t.removed;let h=s&&c.has(s)?s:null,d=null,p=!1;if(i){const i=w(s);i?(t.space=i,h=i,p=!0,v.spaceRefsRemapped++):l||"virtual"===t.binding?l||(delete t.space,h=null,v.markersDetached++):(d=k(e),d?(t.space=d.spaceId,h=d.spaceId,v.spaceRefsRemapped++):(delete t.space,h=null,v.markersDetached++))}l&&!p||x(t,h,d),r&&p&&n===s&&h&&(o[e]={...a,s:h},v.positionsRemapped++,y.add(e))}for(const t of Object.keys(o)){if(y.has(t))continue;const e=o[t],s="string"==typeof e?.s?e.s:"";if(!s||c.has(s))continue;const i=w(s);if(i){if(t.startsWith("rl_")){const s=t.slice(3),a=$(s,i);if(a){const s=`rl_${a}`;_n(o,s)||(o[s]={...e,s:i}),delete o[t],v.roomRefsRemapped++,v.positionsRemapped++;continue}}o[t]={...e,s:i},v.positionsRemapped++}}const M=s.ownerRoster,C=!0===M?.authoritative,S=new Set(M?.deviceIds||[]),P=new Set(M?.entityIds||[]),D=new Set(Array.isArray(i.settings?.known_devices)?i.settings.known_devices.filter(t=>"string"==typeof t):[]),I=(t,e="")=>{const s=String(M?.names?.[t]||e||"").trim();return s&&s!==t?s:""},L=(t,e,s,i="",o)=>({id:t,spaceId:e,kind:s,name:I(t,i),...o?{reason:o}:{}}),T=t=>{"room_label"===t?v.orphanRoomLabelsRemoved++:"group"===t?v.orphanGroupPositionsRemoved++:v.orphanDevicePositionsRemoved++},R=new Set;for(const[t,e]of Object.entries(o)){const i="string"==typeof e?.s?e.s:"";if(!i||c.has(i))continue;let a,n;const r=f.get(t),l=b.get(t);if(r)a=L(t,i,"device",String(r.name||"")),n="live";else if(l)a=L(t,i,"device",String(l.name||"")),n="absent";else if(t.startsWith("rl_")){const e=t.slice(3);a=L(t,i,"room_label",_.get(e)||""),n=g.has(e)?"live":"absent"}else if(t.startsWith("lg_")){const e=t.slice(3);a=L(t,i,"group"),n=P.has(e)?"live":C?"absent":"unverified","unverified"===n&&(a.reason="registry_unavailable")}else S.has(t)?(a=L(t,i,"device"),n="live"):D.has(t)?(a=L(t,i,"device"),n=C?"absent":"unverified","unverified"===n&&(a.reason="registry_unavailable")):(a=L(t,i,"unknown","","unknown_owner"),n="unverified");if("absent"!==n){if("live"===n){if(v.liveMissingPositions.push(a),!0===s.removeLiveMissingPositions){delete o[t],v.liveMissingPositionsRemoved++,T(a.kind),v.removedPositions.push(a);continue}}else v.unverifiedPositions.push(a);v.positionsUnresolved++,R.add(i)}else delete o[t],T(a.kind),v.removedPositions.push(a)}return v.deadSpaceIds=[...R].sort((t,e)=>t.localeCompare(e)),{config:i,layout:o,report:v,changed:JSON.stringify(i)!==a||JSON.stringify(o)!==n}}(t,e,s),n=a.config,r=ot(n,a.layout);J(n),at(a.layout);const l=JSON.stringify(t||{}),h=JSON.stringify(e||{}),c=Number.isInteger(Number(n.model_version))?Number(n.model_version):0,d=(t=>{let e=0,s=0,i=0;for(const s of t.markers||[]){if("ripple"===s.display&&(s.display="icon_ripple",e++),Array.isArray(s.controls)){const t="string"==typeof s.binding&&s.binding.startsWith("entity:")?s.binding.slice(7):"",i=t?s.controls.filter(e=>e!==t):s.controls;JSON.stringify(i)!==JSON.stringify(s.controls)&&(s.controls=i.length?i:null,e++)}const t=s.vacuum;t&&Xn(t,"trail")&&(["never","cleaning","always"].includes(t.trail_mode)||(t.trail_mode=!1===t.trail?"never":"cleaning"),delete t.trail,e++)}for(const o of t.spaces||[]){const t=o.settings;"glow"===t?.fill_mode&&("boolean"!=typeof t.glow_enabled&&(t.glow_enabled=!0),t.fill_mode="none",e++,s++);for(const t of o.rooms||[]){const s=t.settings;"glow"===s?.fill_mode&&("boolean"!=typeof s.glow&&(s.glow=!0),delete s.fill_mode,e++,i++)}if(Xn(o,"segments")&&(delete o.segments,e++),Xn(o,"plan_scale")){const t=Number(o.plan_scale);Number.isFinite(t)&&t>=pt&&t<=ut&&(Xn(o,"plan_scale_x")||(o.plan_scale_x=t),Xn(o,"plan_scale_y")||(o.plan_scale_y=t),delete o.plan_scale,e++)}const a=Number(o.cell_cm);Xn(o,"cell_cm")&&(!Number.isFinite(a)||a<.1||a>1e3)&&(o.cell_cm=Number.isFinite(a)&&a>0?Qn(a,.1,1e3):5,e++);const n=Number(o.cell_cm),r=Number.isFinite(n)&&n>0?n:5;for(const t of o.wall_columns||[])if("circle"===t.shape)Xn(t,"angle")&&(delete t.angle,e++);else if("square"===t.shape&&Xn(t,"angle")){const s=((Number(t.angle)||0)%90+90)%90;t.angle!==s&&(t.angle=s,e++)}for(const t of o.decor||[]){if(Xn(t,"width")){const s=Number(t.width);(Xn(t,"width_cm")||Number.isFinite(s))&&(Xn(t,"width_cm")||(t.width_cm=Number(Qn(s/ct*r,.1,100).toFixed(6))),delete t.width,e++)}if("rect"!==t?.kind&&"ellipse"!==t?.kind||!0!==t.fill||(Xn(t,"fill_color")||(t.fill_color=t.color||"#607d8b",e++),Xn(t,"fill_opacity")||(t.fill_opacity=.25,e++)),"text"!==t?.kind)continue;void 0===t.size_cm?(t.size_cm=Number(Qn(_t*mt(t)/ct*r,.1,2e3).toFixed(6)),delete t.scale,delete t.size,e++):(Xn(t,"scale")||Xn(t,"size"))&&(delete t.scale,delete t.size,e++);let s=String(t.text??"");const i=[...s.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!gt(t[1]));if(!(Xn(t,"entity")||Xn(t,"attr")||Xn(t,"unit")))continue;const o=String(t.unit??"").trim(),a="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,n=i||o?"":ft(t.entity,a);if(i||n){if(n){const e=s.indexOf("{}");s=e>=0?s.slice(0,e)+n+s.slice(e+2):`${s}${s?" ":""}${n}`,t.text=s}delete t.entity,delete t.attr,delete t.unit,e++}}}return{total:e,glowSpaces:s,glowRooms:i}})(n);let p=d.total,u=0,_=0,m=0;if(c<10)for(const t of Array.isArray(n.spaces)?n.spaces:[]){const e=Kn(t);_+=e.drafts,m+=e.segments}const g=(f=n.spaces||[],JSON.parse(JSON.stringify(f)));var f;const b=Wa(n.spaces||[],a.layout);let v=0,y=0,w=0,$="";const k=b.spaces.map(t=>{const e=nt(t);v+=e.report.wallsStraightened,y+=e.report.wallsStraightenSkipped;const s=Number(t?.cell_cm)>0?Number(t.cell_cm):5,i=e.report.maxStraightenShift/z*s;return i>w&&(w=i,$=String(t?.id||"")),e.space}),x=v?Wa(k,b.layout):{...b,spaces:k};n.spaces=x.spaces;const M=v?{...b.report,moved:b.report.moved+x.report.moved,coordsCanonicalized:b.report.coordsCanonicalized+x.report.coordsCanonicalized,maxShift:Math.max(b.report.maxShift,x.report.maxShift),maxShiftCm:Math.max(b.report.maxShiftCm,x.report.maxShiftCm),maxSpace:x.report.maxShiftCm>b.report.maxShiftCm?x.report.maxSpace:b.report.maxSpace,rotated:b.report.rotated+x.report.rotated}:{...b.report};let C=0,S=0,P=0,D=0,I=0,L=0,T=0;for(let t=0;t0===Number(t.cm)),walls:e.walls||[]}),a=tr(e),r=tr(s);if(!a||!r)continue;const l=ir(a.rooms),h=ir(r.rooms),c=.02*ct,d=(e.wall_segments||[]).filter(t=>0===Number(t.cm)).map(t=>({...t,key:Z(t.a,t.b,z),cm:0})),p=new Set(d.map(t=>t.key)),u=rt(e,a.rooms,lt,c);S+=u.length;for(const t of u){const e=[t[0]/lt,t[1]/lt],s=[t[2]/lt,t[3]/lt],i=Z(e,s,z);p.has(i)||(p.add(i),d.push({key:i,a:e,b:s,cm:0}))}const _=d.length,m=ht(d,l,h,z,lt),f=(t,e,s)=>{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;if(!(a>0))return Math.hypot(t[0]-e[0],t[1]-e[1]);const n=Math.max(0,Math.min(1,((t[0]-e[0])*i+(t[1]-e[1])*o)/a));return Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))},b=m.filter(t=>{if(!Array.isArray(t.a)||!Array.isArray(t.b))return!1;const e=t.a.map(t=>t*lt),s=t.b.map(t=>t*lt);return h.some(([t,i])=>f(e,t,i)<=4*c&&f(s,t,i)<=4*c)});P+=Math.max(0,_-b.length);const v=(s.wall_segments||[]).filter(t=>Number(t.cm)>0);s.wall_segments=[...v,...b.map(({key:t,...e})=>e)];const y=b.map(t=>[t.a[0]*lt,t.a[1]*lt,t.b[0]*lt,t.b[1]*lt]),w=Array.isArray(e.walls)?e.walls.length:0;let $=ht(e.walls,l,h,z,lt);$=sr(r.rooms,$,y,z,Number(s.cell_cm)>0?Number(s.cell_cm):5,ct,lt),$=G(r.rooms,$,y,z,Number(s.cell_cm)>0?Number(s.cell_cm):5,ct,lt),$=dt($,s.rooms||[],z,1,y.map(t=>[t[0]/lt,t[1]/lt,t[2]/lt,t[3]/lt])),C+=Math.max(0,w-$.length),$.length?s.walls=$:delete s.walls;const k=Ja(s.partitions||[],{pitch:z,geometry:Ya(s)});k.merged&&(D+=k.merged,s.partitions=k.partitions,Za(s.openings,s.partitions,k.openingMoves,{coordScale:lt,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,gridPitch:ct}));const x=tr(s);if(x){const t=o(s,x,s.walls||[],y,{pitch:z,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,gridPitch:ct,coordScale:lt});t.partitionsReconciled&&(I+=t.partitionsReconciled,L+=t.openingsRehosted,t.partitions.length?s.partitions=t.partitions:delete s.partitions,t.openings.length?s.openings=t.openings:delete s.openings,t.walls.length?s.walls=t.walls:delete s.walls)}JSON.stringify({zero:(s.wall_segments||[]).filter(t=>0===Number(t.cm)),walls:s.walls||[]})!==i&&T++}if(c<=10){const t=function(t){const e=Jn(t);return Yn(t,e.config),{...e,config:t}}(n);u+=t.migratedSegments,_+=t.migratedDrafts,m+=t.migratedDraftSegments}const R=J(n),F=at(x.layout),N=JSON.stringify(R)!==l||JSON.stringify(F)!==h;c<10&&N&&(R.model_version=10);const A=JSON.stringify(R)!==l||JSON.stringify(F)!==h,E=Number.isInteger(Number(R.model_version))?Number(R.model_version):c,O=A?M:{...M,moved:0,coordsCanonicalized:0,maxShift:0,maxShiftCm:0,maxSpace:"",rotated:0},B=A?a.report:{...a.report,spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0};return{config:R,layout:F,report:{...O,modelFrom:c,modelTo:E,migrated:A?p:0,glowSpacesMigrated:A?d.glowSpaces:0,glowRoomsMigrated:A?d.glowRooms:0,canonicalized:A?T:0,wallSegmentsMigrated:A?u:0,roomDraftsMigrated:A?_:0,roomDraftSegmentsMigrated:A?m:0,legacyZeroWallsMigrated:A?S:0,wallsMerged:A?C:0,spansMerged:A?P:0,partitionsMerged:A?D:0,partitionsReconciled:A?I:0,openingsRehosted:A?L:0,wallsStraightened:A?v:0,wallsStraightenSkipped:y,maxStraightenShiftCm:A?w:0,maxStraightenSpace:A?$:"",latticeCoordinatesCanonicalized:A?r.canonicalized:0,latticeCoordinatesFar:A?r.far:0,latticeMaxShift:A?r.maxShift:0,latticeMaxShiftCm:A?r.maxShiftCm:0,latticeSpaces:A?r.spaces:[],...B},changed:A}}async function ar(t,e,s){t._saveConfigDebounced.pending()&&t._saveConfigDebounced.flush(),await t._writeChain;const i=await t.hass.callWS({type:"houseplan/plan/optimize",config:e,layout:s,expected_config_rev:t._cfgRev,expected_layout_rev:t._layoutRev});t._adoption.acceptPairWrite(e,s,i),t._geometryHistory.clear(),t._cancelDeviceDrag(),t._devicePositionHistory.clear(),t._canOptimizeUndo=!0===i.can_undo,t._undoKind=!0===i.can_undo?"optimize":null,t._dirtyPos.clear(),t._sentPos.clear(),t._cfgEpoch++,t._modelCache=null,t._frame=null,t._regSignature="",t._maybeRebuildDevices(),t._cacheSnapshot(),t.requestUpdate()}const nr=Object.freeze({spaces:50,partitions:2e3,openings:500,decor:1e3,columns:500});class rr extends Error{constructor(t){super(t),this.code=t,this.name="SpaceCopyError"}}const lr=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),hr=t=>void 0===t?t:JSON.parse(JSON.stringify(t)),cr=t=>null===t||"object"!=typeof t||Array.isArray(t)?null:t;function dr(t,e=!1){if(void 0===t&&!e)return[];if(!Array.isArray(t))throw new rr("source_invalid");return t.map(t=>{const e=cr(t);if(!e||"string"!=typeof e.id||!e.id)throw new rr("source_invalid");return e})}const pr=t=>Array.isArray(t)&&2===t.length&&t.every(t=>Number.isFinite(t));function ur(t,e,s){const i=String(t??"").trim()||s,o=new Set(e.map(t=>{const e=cr(t);return String(e?.title??"").trim()}));let a=2;for(;o.has(`${i} (${a})`);)a++;return`${i} (${a})`}const _r=["settings","zero_wall_style","cell_cm","view_box","plan_url","plan_aspect","plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"];const mr={source_missing:"space.copy_error_source_missing",source_invalid:"space.copy_error_source_invalid",spaces_limit:"space.copy_error_spaces_limit",partitions_limit:"space.copy_error_partitions_limit",openings_limit:"space.copy_error_openings_limit",decor_limit:"space.copy_error_decor_limit",columns_limit:"space.copy_error_columns_limit",opening_host_missing:"space.copy_error_opening_host",opening_host_unknown:"space.copy_error_opening_host",geometry_unsafe:"space.copy_error_geometry"};let gr=0;function fr(t,e,s){const i=t._spaceDialog;return!(!i?.copy||i.copy.token!==e)&&(t._spaceDialog={...i,busy:s,copy:{...i.copy,busy:s}},!0)}function br(t){t._cfgEpoch++,t._modelCache=null,t._frame=null,t._regSignature="",t._maybeRebuildDevices(),t.requestUpdate()}async function vr(t,e){const s=t._spaceDialog;if(!s?.copy||"edit"!==s.mode||s.busy||s.copy.busy||!s.copy.title.trim()||!s.spaceId||!t._serverCfg)return;const i=++gr,o=s.spaceId,a=s.copy.title.trim();t._spaceDialog={...s,busy:!0,copy:{...s.copy,title:a,busy:!0,token:i}};let n=!1;try{if(t._saveConfigDebounced.pending()&&t._saveConfigDebounced.flush(),await t._writeChain,!fr(t,i,!0)||!t._serverCfg)return;const s=t._cfgRev,r=t._layoutRev,l=yt(t._serverCfg),h=yt(t._layout);let c;try{c=(e.optimize??or)(t._serverCfg,t._layout,e.optimizeReferenceContext())}catch(s){return fr(t,i,!1),void e.showWallModelMigrationBlocked(s)}if(c.changed){const d=t._checkOptimizeGeometry(c.config);if(e.reportPreflightFailure(d,c.config),!d.ok)return fr(t,i,!1),void t._showToast(t._t("space.copy_error_optimize_geometry"));const p=await t._confirmDanger({key:`copy-space:${o}`,kind:"warning",title:t._t("space.copy_optimize_title"),message:t._t("space.copy_optimize_body",{name:a}),objectName:a,confirmLabel:t._t("space.copy_optimize_confirm"),cancelLabel:t._t("btn.cancel"),icon:"mdi:broom"});if(!fr(t,i,p))return;if(!p)return;if(t._cfgRev!==s||t._layoutRev!==r||!t._serverCfg||yt(t._serverCfg)!==l||yt(t._layout)!==h)return fr(t,i,!1),void t._showToast(t._t("space.copy_error_changed"));e.clearGeometryGesture(),await ar(t,c.config,c.layout),n=!0}if(!fr(t,i,!0)||!t._serverCfg)return;const d=t._serverCfg,p=function(t,e,s,i){const o=t.spaces;if(!s.trim())throw new rr("source_invalid");if(o.length>=nr.spaces)throw new rr("spaces_limit");const a=o.findIndex(t=>t.id===e);if(a<0)throw new rr("source_missing");const n=o[a];if(!Array.isArray(n.view_box))throw new rr("source_invalid");const r=dr(n.wall_segments,!0),l=dr(n.partitions),h=dr(n.openings),c=dr(n.decor),d=dr(n.wall_columns);if(r.length+l.length>nr.partitions)throw new rr("partitions_limit");if(h.length>nr.openings)throw new rr("openings_limit");if(c.length>nr.decor)throw new rr("decor_limit");if(d.length>nr.columns)throw new rr("columns_limit");let p=0;const u=t=>`${t}${i}${(p++).toString(36)}`,_=new Map,m=new Map,g=[];for(const t of r){if(_.has(t.id)||!pr(t.a)||!pr(t.b)||"number"!=typeof t.cm||!Number.isFinite(t.cm))throw new rr("source_invalid");const e=u("cw");_.set(t.id,e),g.push({id:e,a:hr(t.a),b:hr(t.b),cm:t.cm})}for(const t of l){if(m.has(t.id)||!pr(t.a)||!pr(t.b)||"number"!=typeof t.cm||!Number.isFinite(t.cm))throw new rr("source_invalid");const e=u("cp");m.set(t.id,e),g.push({id:e,a:hr(t.a),b:hr(t.b),cm:t.cm})}const f=h.map(t=>{const e=cr(t.host);if(!e||"string"!=typeof e.id||"string"!=typeof e.kind)throw new rr("opening_host_missing");const s="wall"===e.kind?_.get(e.id):"partition"===e.kind?m.get(e.id):void 0;if(!s)throw new rr("opening_host_unknown");const i={...hr(t),id:u("co"),host:{...hr(e),kind:"partition",id:s}};return delete i.contact,delete i.lock,i}),b=c.map(t=>({...hr(t),id:u("cd")})),v=d.map(t=>({...hr(t),id:u("cc")})),y=`s${i}`;if(o.some(t=>t.id===y))throw new rr("source_invalid");const w={id:y,title:s.trim(),rooms:[],wall_segments:[],view_box:hr(n.view_box)};for(const t of _r)"view_box"!==t&&lr(n,t)&&(w[t]=hr(n[t]));g.length&&(w.partitions=g),f.length&&(w.openings=f),b.length&&(w.decor=b),v.length&&(w.wall_columns=v);const $=hr(t);return $.spaces.splice(a+1,0,w),{config:$,space:w,sourceIndex:a}}(d,o,a,e.newSeed?.()??function(t=Date.now(),e=Math.random()){const s=Math.floor(16777216*Math.max(0,Math.min(.999999999,e))).toString(36).padStart(5,"0");return`${Math.max(0,Math.floor(t)).toString(36)}${s}`}());let u=!1;try{u=t._checkSpacePhysicalGeometry(p.config,p.space.id).ok}catch{u=!1}if(!u||t._junctionLimitViolations(p.config,p.space.id).length)throw new rr("geometry_unsafe");const _=t._adoption.beginOptimistic(d,p.config);t._adoption.stageLocalConfig(p.config),br(t);try{await e.saveConfigNow(_)}catch(e){throw t._rollbackOptimistic(_)&&br(t),"conflict"!==e?.code&&await t._reloadConfigOnly(!0),e}t._canOptimizeUndo=!1,t._undoKind=null,e.clearGeometryGesture(),t._selId=null,t._physicalSel=null,t._spaceDialog=null,t._commitSpace(p.space.id,!0),e.setMode("plan"),t._tool="draw",t._path=[],t._cursorPt=null,t._activeWallChainId=null,t._activeWallChainPartitionIds=[],t._primeDrawWallField(),t._saveNav(),t.requestUpdate(),t._showToast(t._t("toast.space_copied",{name:a}))}catch(e){"conflict"===e?.code&&await Promise.all([t._reloadConfigOnly(!0),t._reloadLayoutOnly()]),fr(t,i,!1),function(t,e){if(e instanceof rr)return void t._showToast(t._t(mr[e.code]));const s=e?.code;"wall_model_client_outdated"!==s?t._showToast(t._t("toast.error",{err:t._errText(e)})):t._showToast(t._t("toast.wall_model_client_outdated"))}(t,e),n&&t.requestUpdate()}}function yr(){if(this.host._spaceDialog.copy)return function(t,e){const s=t._spaceDialog.copy,i=()=>function(t){const e=t._spaceDialog;!e?.copy||e.busy||e.copy.busy||(t._spaceDialog={...e,copy:void 0})}(t);return p`
    @@ -341,32 +341,32 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${s.busy?"…":t._t("space.copy_create")}
    -
    `}(this.host,()=>{this._saveSpaceCopy()});const t=Fo({host:this.host,idPrefix:"space",help:this._help.bind(this),rangeInput:(t,e,s,i,o,a,n)=>this._rangeInput(t,e,s,i,o,a,n),pickPlanFile:t=>this._pickPlanFile(t),toggleServerPlans:()=>this._toggleServerPlans(),renderServerPlans:t=>this._renderServerPlans(t),save:()=>this._saveSpaceDialog(),skipImport:()=>this._skipImport(),deleteSpace:()=>this._deleteSpace(),copySpace:()=>function(t){const e=t._spaceDialog;if(!e||"edit"!==e.mode||e.busy||!t._serverCfg)return;const s=t._serverCfg.spaces.find(t=>t?.id===e.spaceId);s&&(t._spaceDialog={...e,copy:{title:_r(s.title,t._serverCfg.spaces,t._t("space.copy_fallback")),busy:!1,token:0}})}(this.host)});return p``}(this.host,()=>{this._saveSpaceCopy()});const t=Fo({host:this.host,idPrefix:"space",help:this._help.bind(this),rangeInput:(t,e,s,i,o,a,n)=>this._rangeInput(t,e,s,i,o,a,n),pickPlanFile:t=>this._pickPlanFile(t),toggleServerPlans:()=>this._toggleServerPlans(),renderServerPlans:t=>this._renderServerPlans(t),save:()=>this._saveSpaceDialog(),skipImport:()=>this._skipImport(),deleteSpace:()=>this._deleteSpace(),copySpace:()=>function(t){const e=t._spaceDialog;if(!e||"edit"!==e.mode||e.busy||!t._serverCfg)return;const s=t._serverCfg.spaces.find(t=>t?.id===e.spaceId);s&&(t._spaceDialog={...e,copy:{title:ur(s.title,t._serverCfg.spaces,t._t("space.copy_fallback")),busy:!1,token:0}})}(this.host)});return p` ${t.body}${t.footer} - `}const $r=new Set(["busy"]);function kr(t){return mo(t,$r)}function xr(){bo(this.host);const t=this.host,e=t._settingsDialog,s=t._t.bind(t),i=l(t.hass,t._config?.language),o=(t,e)=>Eo(i,t,e),a=e=>{t._settingsDialog={...t._settingsDialog,...e}},n=function(t){const e=[];return Number.isFinite(t.glowRadius)&&t.glowRadius>0||e.push({field:"gs-glow-radius",message:"gs.error_glow_radius"}),null===t.northDeg||Number.isInteger(t.northDeg)&&t.northDeg>=0&&t.northDeg<=359||e.push({field:"gs-north",message:"gs.error_north"}),e}(e),r=t=>n.find(e=>e.field===t),h=function(t,e){return go(t,"settings",kr(e))}(t,e),c=h&&0===n.length&&!e.busy,_=()=>{!function(t){fo(t,"settings")}(t),t._settingsDialog=null},m=async s=>{if(!h||e.busy)return void _();const i=s.currentTarget;await t._confirmDanger({key:"discard-settings-dialog",kind:"warning",title:o("dialog.discard_title"),message:o("dialog.discard_message"),confirmLabel:o("dialog.discard_confirm"),cancelLabel:o("dialog.discard_keep")})?_():i?.rejectClose?.()},g=(i,a)=>{const n=e.colors[i],r=s(a);return Oo({label:r,hex:n.c,opacity:n.a,opacityLabel:o("gs.opacity_of",{name:r}),onOpacity:t=>this._setFillColor(i,{c:n.c,a:t}),picker:p``}const wr=new Set(["busy"]);function $r(t){return mo(t,wr)}function kr(){bo(this.host);const t=this.host,e=t._settingsDialog,s=t._t.bind(t),i=l(t.hass,t._config?.language),o=(t,e)=>Eo(i,t,e),a=e=>{t._settingsDialog={...t._settingsDialog,...e}},n=function(t){const e=[];return Number.isFinite(t.glowRadius)&&t.glowRadius>0||e.push({field:"gs-glow-radius",message:"gs.error_glow_radius"}),null===t.northDeg||Number.isInteger(t.northDeg)&&t.northDeg>=0&&t.northDeg<=359||e.push({field:"gs-north",message:"gs.error_north"}),e}(e),r=t=>n.find(e=>e.field===t),h=function(t,e){return go(t,"settings",$r(e))}(t,e),c=h&&0===n.length&&!e.busy,u=()=>{!function(t){fo(t,"settings")}(t),t._settingsDialog=null},_=async s=>{if(!h||e.busy)return void u();const i=s.currentTarget;await t._confirmDanger({key:"discard-settings-dialog",kind:"warning",title:o("dialog.discard_title"),message:o("dialog.discard_message"),confirmLabel:o("dialog.discard_confirm"),cancelLabel:o("dialog.discard_keep")})?u():i?.rejectClose?.()},m=(i,a)=>{const n=e.colors[i],r=s(a);return Oo({label:r,hex:n.c,opacity:n.a,opacityLabel:o("gs.opacity_of",{name:r}),onOpacity:t=>this._setFillColor(i,{c:n.c,a:t}),picker:p`{this._setFillColor(i,{c:t.detail.color,a:t.detail.opacity})}}>`})},f=r("gs-glow-radius"),b=r("gs-north"),v=Yo(i,"help")&&Yo(i,"help_aria")?p``:d;return p` + @hp-color-opacity-change=${t=>{this._setFillColor(i,{c:t.detail.color,a:t.detail.opacity})}}>`})},g=r("gs-glow-radius"),f=r("gs-north"),b=Yo(i,"help")&&Yo(i,"help_aria")?p``:d;return p`
    ${ko({id:"display",title:s("gs.card_display"),body:p` ${Co({id:"gs-room-tooltip",icon:"mdi:tooltip-text-outline",title:ra(i,"gs.show_room_tooltip"),caption:o("gs.show_room_tooltip_hint"),checked:e.showRoomTooltip,onChange:t=>a({showRoomTooltip:t})})} ${Co({id:"gs-radar-live",icon:"mdi:radar",title:s("gs.radar_show_live"),caption:o("gs.radar_show_live_hint"),checked:e.radarShowLive,onChange:t=>a({radarShowLive:t})})}`})} - ${ko({id:"zigbee",title:s("gs.card_zigbee"),help:v,body:p`a({zigbeeTopology:t.detail})}>`})} ${ko({id:"fills",title:s("gs.card_fills"),help:this._help("gs.card_fills.help"),body:p` ${Do({title:s("gs.light_group")})} - ${No([g("light_on","gs.light_on"),g("light_off","gs.light_off"),g("light_none","gs.light_none")])} + ${No([m("light_on","gs.light_on"),m("light_off","gs.light_off"),m("light_none","gs.light_none")])} ${Do({title:s("gs.temp_group")})} - ${No([g("temp_cold","gs.temp_cold"),g("temp_ok","gs.temp_ok"),g("temp_hot","gs.temp_hot")])} + ${No([m("temp_cold","gs.temp_cold"),m("temp_ok","gs.temp_ok"),m("temp_hot","gs.temp_hot")])} ${Do({title:s("gs.lqi_group")})} - ${No([g("lqi_low","gs.lqi_low"),g("lqi_high","gs.lqi_high")])}`})} + ${No([m("lqi_low","gs.lqi_low"),m("lqi_high","gs.lqi_high")])}`})} ${ko({id:"glow",title:s("gs.glow_group"),body:p` - ${No([g("glow_base","gs.glow_base"),g("glow_light","gs.glow_light")])} - ${xo({label:s("gs.glow_radius"),htmlFor:"gs-glow-radius",help:this._help("gs.glow_radius.help"),error:f?o(f.message):void 0,control:Io({id:"gs-glow-radius",value:String(e.glowRadius),min:.5,step:.5,invalid:!!f,unit:t._imperial?s("gs.unit_ft"):s("gs.unit_m"),onInput:t=>{const e=u(t);null!=e&&e>0&&a({glowRadius:e})}})})}`})} + ${No([m("glow_base","gs.glow_base"),m("glow_light","gs.glow_light")])} + ${xo({label:s("gs.glow_radius"),htmlFor:"gs-glow-radius",help:this._help("gs.glow_radius.help"),error:g?o(g.message):void 0,control:Io({id:"gs-glow-radius",value:String(e.glowRadius),min:.5,step:.5,invalid:!!g,unit:t._imperial?s("gs.unit_ft"):s("gs.unit_m"),onInput:t=>{const e=xt(t);null!=e&&e>0&&a({glowRadius:e})}})})}`})} ${ko({id:"plan",title:s("gs.card_plan"),body:p` ${Ao({label:s("gs.wall_fill"),picker:So({hex:e.colors.wall_fill.c,opacity:e.colors.wall_fill.a,opacityLabel:s("space.opacity"),onOpacity:t=>this._setFillColor("wall_fill",{c:e.colors.wall_fill.c,a:t}),picker:p` ${this._help("gs.north.help")}
    - ${Io({id:"gs-north",value:null===e.northDeg?"":String(e.northDeg),unit:"°",min:0,max:359,step:1,placeholder:s("gs.north_ph"),invalid:!!b,onInput:t=>{const e=t.trim(),s=""===e?null:Math.round(Number(e));a({northDeg:null!==s&&Number.isFinite(s)?s:null})}})} + ${Io({id:"gs-north",value:null===e.northDeg?"":String(e.northDeg),unit:"°",min:0,max:359,step:1,placeholder:s("gs.north_ph"),invalid:!!f,onInput:t=>{const e=t.trim(),s=""===e?null:Math.round(Number(e));a({northDeg:null!==s&&Number.isFinite(s)?s:null})}})} ${null!==e.northDeg?wo(s("gs.north_clear"),()=>a({northDeg:null})):d}
    ${t._renderCompass()}
    - ${b?p``:d} + ${f?p``:d} ${Co({id:"gs-sun-rays",icon:"mdi:weather-sunny",title:s("gs.sun_rays"),caption:o("gs.sun_rays_hint"),checked:e.sunRays,onChange:t=>a({sunRays:t})})} - ${y=e.sunRayOrigin,w=t=>s(t),$=t=>a({sunRayOrigin:t}),xo({label:w("gs.sun_ray_origin"),control:Mo({name:"gs-sun-ray-origin",value:y,ariaLabel:w("gs.sun_ray_origin"),options:[{value:"inner",label:w("gs.sun_ray_origin.inner")},{value:"outer",label:w("gs.sun_ray_origin.outer")}],onChange:t=>$("outer"===t?"outer":"inner")})})}`})} + ${v=e.sunRayOrigin,y=t=>s(t),w=t=>a({sunRayOrigin:t}),xo({label:y("gs.sun_ray_origin"),control:Mo({name:"gs-sun-ray-origin",value:v,ariaLabel:y("gs.sun_ray_origin"),options:[{value:"inner",label:y("gs.sun_ray_origin.inner")},{value:"outer",label:y("gs.sun_ray_origin.outer")}],onChange:t=>w("outer"===t?"outer":"inner")})})}`})} ${ko({id:"data",title:s("gs.card_data"),body:p` ${t._canEdit?p` ${Do({title:s("gs.backup_group"),help:this._help("gs.backup_group.help")})} @@ -422,61 +422,61 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc -
    `;var y,w,$}function Mr(t){return mo({name:t._nameSel,area:t._areaSel,fill:t._roomFill,customFill:t._roomCustomFill,tempMin:t._roomTempMin,tempMax:t._roomTempMax,tempSrc:t._roomTempSrc,humSrc:t._roomHumSrc,nameScale:t._roomNameScale,labelScale:t._roomLabelScale})}function Cr(t){fo(t,"room")}function Sr(t,e){const s=t.host,i="temp"===e?s._roomTempSrc:s._roomHumSrc,o=t=>{"temp"===e?s._roomTempSrc=t:s._roomHumSrc=t,s.requestUpdate()},a=s._roomSrcOpen===e,n=s._t("temp"===e?"room.temp_src_label":"room.hum_src_label");return p`${Do({title:n})} +
    `;var v,y,w}function xr(t){return mo({name:t._nameSel,area:t._areaSel,fill:t._roomFill,customFill:t._roomCustomFill,tempMin:t._roomTempMin,tempMax:t._roomTempMax,tempSrc:t._roomTempSrc,humSrc:t._roomHumSrc,nameScale:t._roomNameScale,labelScale:t._roomLabelScale})}function Mr(t){fo(t,"room")}function Cr(t,e){const s=t.host,i="temp"===e?s._roomTempSrc:s._roomHumSrc,o=t=>{"temp"===e?s._roomTempSrc=t:s._roomHumSrc=t,s.requestUpdate()},a=s._roomSrcOpen===e,n=s._t("temp"===e?"room.temp_src_label":"room.hum_src_label");return p`${Do({title:n})} ${Mo({name:`rsrc-${e}`,value:i?"pick":"avg",ariaLabel:n,options:[{value:"avg",label:s._t("room.src_average")},{value:"pick",label:s._t("room.src_pick")}],onChange:t=>{if("avg"===t)return o(""),void(s._roomSrcOpen=null);s._roomSrcOpen=e,s._roomSrcFilter="",s.requestUpdate()}})} - ${i||a?$o({id:`room-${e}-source`,open:a,current:i?{label:t._roomSrcLabel(i),sub:i}:null,placeholder:s._t("room.src_ph"),ariaLabel:n,filter:s._roomSrcFilter,filterPlaceholder:s._t("marker.search_ph"),candidates:a?t._roomSrcCandidates():[],selected:i,emptyText:s._t("marker.nothing_found"),onToggle:()=>{s._roomSrcOpen=a?null:e,s._roomSrcFilter="",s.requestUpdate()},onFilter:t=>{s._roomSrcFilter=t,s.requestUpdate()},onPick:t=>{o(t),s._roomSrcOpen=null}}):d}`}function Pr(){bo(this.host);const t=this.host,e=t._t.bind(t),s=l(t.hass,t._config?.language),i=(t,e)=>Eo(s,t,e),o=!!t._roomEditId,a=o?null:t._wallFaceBatch,n=a&&a.candidates.length>1?e("room.queue_progress",{current:a.index+1,total:a.candidates.length}):"",r=m(t._curSpaceCfg),h=""===t._roomFill,c=t._roomFill||r.fill,_=t._roomCustomFill||r.customFill,g=Mt(t._roomTempMin,t._roomTempMax).valid,f=function(t){const e=[];return!t._roomEditId&&t._areaSel||t._nameSel.trim()||e.push({field:"room-name",message:"room.error_name"}),Mt(t._roomTempMin,t._roomTempMax).valid||e.push({field:"room-temp-min",message:"room.error_temp_range"}),e}(t),b=t=>f.find(e=>e.field===t),v=function(t){return go(t,"room",Mr(t))}(t),y=0===f.length&&g&&(!o||v),w=[...t._freeAreas];if(o&&t._areaSel&&!w.some(e=>e.area_id===t._areaSel)){const e=t.hass.areas[t._areaSel];e&&w.unshift(e)}const $=()=>{Cr(t),this._roomDialogCancel()},k=async e=>{if(!o||!v)return void $();const s=e.currentTarget;await t._confirmDanger({key:"discard-room-dialog",kind:"warning",title:i("dialog.discard_title"),message:i("dialog.discard_message"),objectName:t._nameSel.trim()||void 0,confirmLabel:i("dialog.discard_confirm"),cancelLabel:i("dialog.discard_keep")})?$():s?.rejectClose?.()},x=b("room-name"),M=b("room-temp-min"),C=e=>{t._roomFill=e,"custom"!==e&&(t._roomCustomFill=null),t.requestUpdate()},S=t=>Math.round(100*t),P=t._roomCustomFill?e("room.custom_fill_own"):e("room.custom_fill_space"),D=[["name","room.name_scale",t._roomNameScale,e=>{t._roomNameScale=e}],["label","room.label_scale",t._roomLabelScale,e=>{t._roomLabelScale=e}]];return p`{s._roomSrcOpen=a?null:e,s._roomSrcFilter="",s.requestUpdate()},onFilter:t=>{s._roomSrcFilter=t,s.requestUpdate()},onPick:t=>{o(t),s._roomSrcOpen=null}}):d}`}function Sr(){bo(this.host);const t=this.host,e=t._t.bind(t),s=l(t.hass,t._config?.language),i=(t,e)=>Eo(s,t,e),o=!!t._roomEditId,a=o?null:t._wallFaceBatch,n=a&&a.candidates.length>1?e("room.queue_progress",{current:a.index+1,total:a.candidates.length}):"",r=_(t._curSpaceCfg),h=""===t._roomFill,c=t._roomFill||r.fill,u=t._roomCustomFill||r.customFill,m=Mt(t._roomTempMin,t._roomTempMax).valid,g=function(t){const e=[];return!t._roomEditId&&t._areaSel||t._nameSel.trim()||e.push({field:"room-name",message:"room.error_name"}),Mt(t._roomTempMin,t._roomTempMax).valid||e.push({field:"room-temp-min",message:"room.error_temp_range"}),e}(t),f=t=>g.find(e=>e.field===t),b=function(t){return go(t,"room",xr(t))}(t),v=0===g.length&&m&&(!o||b),y=[...t._freeAreas];if(o&&t._areaSel&&!y.some(e=>e.area_id===t._areaSel)){const e=t.hass.areas[t._areaSel];e&&y.unshift(e)}const w=()=>{Mr(t),this._roomDialogCancel()},$=async e=>{if(!o||!b)return void w();const s=e.currentTarget;await t._confirmDanger({key:"discard-room-dialog",kind:"warning",title:i("dialog.discard_title"),message:i("dialog.discard_message"),objectName:t._nameSel.trim()||void 0,confirmLabel:i("dialog.discard_confirm"),cancelLabel:i("dialog.discard_keep")})?w():s?.rejectClose?.()},k=f("room-name"),x=f("room-temp-min"),M=e=>{t._roomFill=e,"custom"!==e&&(t._roomCustomFill=null),t.requestUpdate()},C=t=>Math.round(100*t),S=t._roomCustomFill?e("room.custom_fill_own"):e("room.custom_fill_space"),P=[["name","room.name_scale",t._roomNameScale,e=>{t._roomNameScale=e}],["label","room.label_scale",t._roomLabelScale,e=>{t._roomLabelScale=e}]];return p` + icon=${o?"mdi:cog-outline":"mdi:floor-plan"} @hp-close=${$}>
    ${n?p`

    ${n}

    `:d} - ${ko({id:"basics",title:e("room.group_basics"),body:To([xo({label:e("room.name_label"),htmlFor:"room-name",error:x?i(x.message):void 0,control:p`{t._nameSel=e.target.value,t.requestUpdate()}} />`}),xo({label:e("room.area_label"),htmlFor:"room-area",help:this._help("room.group_basics.help"),control:p``})])})} ${ko({id:"fill",title:e("room.group_fill"),help:this._help("room.group_fill.help"),body:p` - ${Co({id:"room-fill-inherit",icon:"mdi:layers-outline",title:e("fill.inherit"),caption:i("room.fill_inherit_hint"),checked:h,onChange:t=>C(t?"":Ct.includes(r.fill)?r.fill:"custom")})} - ${h?p`

    ${i("room.fill_following",{mode:e(`fill.${r.fill}`)})}

    `:xo({label:i("room.fill_mode_label"),control:Mo({name:"rfill",value:t._roomFill,ariaLabel:e("room.fill_label"),options:Ct.map(t=>({value:t,label:"lqi"===t?i("room.fill_seg_lqi"):"custom"===t?i("room.fill_seg_custom"):e(`fill.${t}`)})),onChange:t=>C(t)})})} - ${"custom"===t._roomFill?Ao({label:P,picker:So({hex:_.c,opacity:_.a,opacityLabel:e("space.opacity"),onOpacity:e=>{t._roomCustomFill={c:_.c,a:e},t.requestUpdate()},resetLabel:t._roomCustomFill?e("btn.reset"):void 0,onReset:()=>{t._roomCustomFill=null,t.requestUpdate()},picker:p`M(t?"":Ct.includes(r.fill)?r.fill:"custom")})} + ${h?p`

    ${i("room.fill_following",{mode:e(`fill.${r.fill}`)})}

    `:xo({label:i("room.fill_mode_label"),control:Mo({name:"rfill",value:t._roomFill,ariaLabel:e("room.fill_label"),options:Ct.map(t=>({value:t,label:"lqi"===t?i("room.fill_seg_lqi"):"custom"===t?i("room.fill_seg_custom"):e(`fill.${t}`)})),onChange:t=>M(t)})})} + ${"custom"===t._roomFill?Ao({label:S,picker:So({hex:u.c,opacity:u.a,opacityLabel:e("space.opacity"),onOpacity:e=>{t._roomCustomFill={c:u.c,a:e},t.requestUpdate()},resetLabel:t._roomCustomFill?e("btn.reset"):void 0,onReset:()=>{t._roomCustomFill=null,t.requestUpdate()},picker:p`{t._roomCustomFill={c:e.detail.color,a:e.detail.opacity}}}>`})}):d} ${"temp"===c?p`
    ${e("room.temp_range_label")}${this._help("room.temp_range.help")} - ${To([xo({label:i("room.temp_min_label"),htmlFor:"room-temp-min",control:Io({id:"room-temp-min",wide:!0,unit:"°C",step:.5,value:t._roomTempMin,placeholder:String(r.tempMin),ariaLabel:e("room.temp_range_min"),invalid:""!==t._roomTempMin.trim()&&null===u(t._roomTempMin),onInput:e=>{t._roomTempMin=e,t.requestUpdate()}})}),xo({label:i("room.temp_max_label"),htmlFor:"room-temp-max",control:Io({id:"room-temp-max",wide:!0,unit:"°C",step:.5,value:t._roomTempMax,placeholder:String(r.tempMax),ariaLabel:e("room.temp_range_max"),invalid:""!==t._roomTempMax.trim()&&null===u(t._roomTempMax),onInput:e=>{t._roomTempMax=e,t.requestUpdate()}})})])} - ${M?p``:d} + ${To([xo({label:i("room.temp_min_label"),htmlFor:"room-temp-min",control:Io({id:"room-temp-min",wide:!0,unit:"°C",step:.5,value:t._roomTempMin,placeholder:String(r.tempMin),ariaLabel:e("room.temp_range_min"),invalid:""!==t._roomTempMin.trim()&&null===xt(t._roomTempMin),onInput:e=>{t._roomTempMin=e,t.requestUpdate()}})}),xo({label:i("room.temp_max_label"),htmlFor:"room-temp-max",control:Io({id:"room-temp-max",wide:!0,unit:"°C",step:.5,value:t._roomTempMax,placeholder:String(r.tempMax),ariaLabel:e("room.temp_range_max"),invalid:""!==t._roomTempMax.trim()&&null===xt(t._roomTempMax),onInput:e=>{t._roomTempMax=e,t.requestUpdate()}})})])} + ${x?p``:d} ${t._roomTempMin.trim()||t._roomTempMax.trim()?wo(e("room.temp_range_reset"),()=>{t._roomTempMin="",t._roomTempMax="",t.requestUpdate()}):d}
    `:d}`})} - ${ko({id:"sources",title:e("room.group_sources"),help:this._help("room.group_sources.help"),body:p`${Sr(this,"temp")}${Sr(this,"hum")}`})} + ${ko({id:"sources",title:e("room.group_sources"),help:this._help("room.group_sources.help"),body:p`${Cr(this,"temp")}${Cr(this,"hum")}`})} ${ko({id:"sizes",title:e("room.sizes_section"),help:this._help("room.sizes_section.help"),body:p` - ${D.map(([s,o,a,n])=>p`
    + ${P.map(([s,o,a,n])=>p`
    - ${wo(i("btn.reset_100"),()=>{n(1),t.requestUpdate()},{disabled:100===S(a)})} + ${wo(i("btn.reset_100"),()=>{n(1),t.requestUpdate()},{disabled:100===C(a)})}
    - ${Po({id:`room-${s}-scale`,min:50,max:300,value:S(a),unit:"%",ariaLabel:e(o),slider:this._rangeInput(50,300,5,S(a),e=>{n(e/100),t.requestUpdate()},!1,e(o)),onInput:e=>{n(e/100),t.requestUpdate()}})} + ${Po({id:`room-${s}-scale`,min:50,max:300,value:C(a),unit:"%",ariaLabel:e(o),slider:this._rangeInput(50,300,5,C(a),e=>{n(e/100),t.requestUpdate()},!1,e(o)),onInput:e=>{n(e/100),t.requestUpdate()}})} ${Ro("50%","300%")}
    `)} -

    ${i("room.sizes_hint",{v:String(S(r.cardFontScale))})}

    +

    ${i("room.sizes_hint",{v:String(C(r.cardFontScale))})}

    ${t._renderCardPreview(r.cardFontScale,t._roomNameScale,t._roomLabelScale)}
    `})}
    `} - ${zo(f.length?{action:wo(i("dialog.review_fields",{n:String(f.length)}),()=>{const e=f[0];if(!e)return;const s=t.renderRoot.querySelector(`#${e.field}`);s?.scrollIntoView({block:"center"}),s?.focus()})}:{text:o&&v?i("dialog.unsaved"):""})} + ${zo(g.length?{action:wo(i("dialog.review_fields",{n:String(g.length)}),()=>{const e=g[0];if(!e)return;const s=t.renderRoot.querySelector(`#${e.field}`);s?.scrollIntoView({block:"center"}),s?.focus()})}:{text:o&&b?i("dialog.unsaved"):""})}
    - - ${o?p` + ${o?p``:p``:p``}
    -
    `}const Dr=new WeakMap;function Ir(t,e,s){let i=Dr.get(t);i||(i=new Map,Dr.set(t,i));const o=i.get(e);if(o)return void(o.run=s);const a={run:s};i.set(e,a),queueMicrotask(()=>{i.get(e)===a&&(i.delete(e),a.run())})}function Lr(t,e){const s=Dr.get(t),i=s?.get(e);i&&(s.delete(e),i.run())}function Tr(t,e){const s=Dr.get(t);if(!s)return;const i=e?[...s].filter(([t])=>t===e):[...s];for(const[t]of i)s.delete(t);s.size||Dr.delete(t)}const Rr=new WeakMap,zr=new Set(["_cursorPt","_opMeasure","_physicalDrag","_physicalRotate","_decorDraft","_dtBox","_dtDrag","_bdDrag","_furnPreviewInput","_layout"]),Fr=new Set(["_cursorPt","_opMeasure","_furnPreviewInput"]),Nr=new Set(["_physicalDrag","_physicalRotate","_decorDraft","_dtDrag","_bdDrag"]),Ar=t=>{let e=Rr.get(t);return e||(e={raf:0,requestedRevision:0,paintedRevision:0,waiters:[],hidden:[],transparent:[],dimmed:[]},Rr.set(t,e)),e},Er=(t,e)=>{t.paintedRevision=Math.max(t.paintedRevision,e);const s=t.waiters.filter(e=>e.revision<=t.paintedRevision);t.waiters=t.waiters.filter(e=>e.revision>t.paintedRevision);for(const t of s)t.resolve()},Or=t=>!!("view"!==t._mode&&(t._deviceDrag||t._physicalDrag||t._physicalRotate||t._decorDraft||t._decorMove||t._dtDrag||t._bdDrag||t._opDrag||t._resize?.dragging));function Br(t,e,s){const i=t;if(!i?.isConnected||"view"===i._mode)return!1;const o=void 0!==e&&zr.has(e);if("_layout"===e&&!i._deviceDrag)return!1;if("_dtBox"===e&&!i._dtDrag)return!1;if(void 0!==e&&Nr.has(e)&&null==s&&null!=i[e]&&Or(i))return!1;if(void 0!==e&&Nr.has(e)&&null==i[e])return!1;if(void 0!==e&&Fr.has(e)&&null==i[e])return!1;return!!(o&&(Fr.has(e)||Or(i))||void 0===e&&Or(i))&&(function(t){const e=Ar(t);if(e.requestedRevision++,e.raf||"function"!=typeof requestAnimationFrame)return;e.raf=requestAnimationFrame(()=>{e.raf=0;const s=e.requestedRevision;!function(t){const e=t,s=e.renderRoot;if(!s)return;const i=Ar(e);jr(i),Ur(e,s);const o=s.querySelector("[data-hp-live-editor]");if(!o)return;if(Wr(i,s,".hp-editor-only-layer:not(.hp-plan-snap-layer)"),"plan"===e._mode)e._opDrag&&Hr(i,s,".wallbodies"),e._resize?.dragging&&(Jr(i,s,".wallbodies"),Wr(i,s,".resize-layer"),Vr(i,s,e._resize.plan?.movingOpeningIds||[])),e._opDrag&&Wr(i,s,".openinglayer");else if("decor"===e._mode){const t=e._dtDrag?.id||e._decorMove?.id;t&&Kr(i,s,t),Wr(i,s,".dtframe, .backdropframe")}St(qr(e),o);const a=s.querySelector("[data-hp-live-editor-html]");if(a){const t=e._viewOr(e._baseVb());St(e._renderLiveEditorMeasurements(t),a)}e._liveEditorPaintCount=(e._liveEditorPaintCount||0)+1}(t),Er(e,s)})}(i),!0)}const Hr=(t,e,s)=>{for(const i of e.querySelectorAll(s))i.closest("[data-hp-live-editor]")||"hidden"!==i.style.visibility&&(i.style.visibility="hidden",t.hidden.push(i))},Wr=(t,e,s)=>{for(const i of e.querySelectorAll(s))i.closest("[data-hp-live-editor]")||"0"!==i.style.opacity&&(i.style.opacity="0",t.transparent.push(i))},jr=t=>{for(const e of t.hidden)e.style.removeProperty("visibility");t.hidden.length=0;for(const e of t.transparent)e.style.removeProperty("opacity");t.transparent.length=0;for(const e of t.dimmed)e.style.removeProperty("opacity");t.dimmed.length=0},Gr=(t,e,s=[])=>{if("iso"===t._renderProjection)return Pt``;const i=t._spaceModel();if(!i)return Pt``;const o=new Set(s),a=(i.rooms||[]).filter(t=>!!t.id&&o.has(t.id)).flatMap(t=>{const e=t.poly||[];return e.map((t,s)=>[t,e[(s+1)%e.length]])}),n=(t,e)=>{const[s,i]=e,o=i[0]-s[0],a=i[1]-s[1],n=o*o+a*a;if(!(n>0))return!1;const r=((t[0]-s[0])*o+(t[1]-s[1])*a)/n,l=Math.max(0,Math.min(1,r));return Math.hypot(t[0]-s[0]-o*l,t[1]-s[1]-a*l)<1e-4},r=[...t._spaceWalls.filter(t=>{const e=(t.a||[]).map(t=>t*ht),s=(t.b||[]).map(t=>t*ht);return a.some(t=>n(e,t)&&n(s,t))}).map((e,s)=>((e,s,i,o)=>{const a=Math.hypot(s[0]-e[0],s[1]-e[1]);if(!(a>1e-9&&i>0))return null;const n=J(i,t._cellCm,t._gridPitch)/2,r=-(s[1]-e[1])/a*n,l=(s[0]-e[0])/a*n;return{key:o,kind:"outer",cm:i,a:e,b:s,depthUnits:2*n,quad:[[e[0]+r,e[1]+l],[s[0]+r,s[1]+l],[s[0]-r,s[1]-l],[e[0]-r,e[1]-l]]}})((e.a||[]).map(t=>t*ht),(e.b||[]).map(t=>t*ht),e.cm,e.key||`wall-${s}`))].filter(t=>!!t),l=t._openingsR.map(t=>({x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),h=r.map(t=>Dt(t,l)).filter(Boolean);if(!h.length)return Pt``;const c=Math.max(...r.map(t=>t.depthUnits),0),d=t._viewOr(t._baseVb()),p=t._stageEl?.clientWidth&&d.w?t._stageEl.clientWidth/d.w:1,u=It(c,p)||Lt(Tt(t._cellCm),p),_=e?.color||"#607d8b",m=t._fillColors.wall_fill,g=h.join(" ");return Pt``}const Pr=new WeakMap;function Dr(t,e,s){let i=Pr.get(t);i||(i=new Map,Pr.set(t,i));const o=i.get(e);if(o)return void(o.run=s);const a={run:s};i.set(e,a),queueMicrotask(()=>{i.get(e)===a&&(i.delete(e),a.run())})}function Ir(t,e){const s=Pr.get(t),i=s?.get(e);i&&(s.delete(e),i.run())}function Lr(t,e){const s=Pr.get(t);if(!s)return;const i=e?[...s].filter(([t])=>t===e):[...s];for(const[t]of i)s.delete(t);s.size||Pr.delete(t)}const Tr=new WeakMap,Rr=new Set(["_cursorPt","_opMeasure","_physicalDrag","_physicalRotate","_decorDraft","_dtBox","_dtDrag","_bdDrag","_furnPreviewInput","_layout"]),zr=new Set(["_cursorPt","_opMeasure","_furnPreviewInput"]),Fr=new Set(["_physicalDrag","_physicalRotate","_decorDraft","_dtDrag","_bdDrag"]),Nr=t=>{let e=Tr.get(t);return e||(e={raf:0,requestedRevision:0,paintedRevision:0,waiters:[],hidden:[],transparent:[],dimmed:[]},Tr.set(t,e)),e},Ar=(t,e)=>{t.paintedRevision=Math.max(t.paintedRevision,e);const s=t.waiters.filter(e=>e.revision<=t.paintedRevision);t.waiters=t.waiters.filter(e=>e.revision>t.paintedRevision);for(const t of s)t.resolve()},Er=t=>!!("view"!==t._mode&&(t._deviceDrag||t._physicalDrag||t._physicalRotate||t._decorDraft||t._decorMove||t._dtDrag||t._bdDrag||t._opDrag||t._resize?.dragging));function Or(t,e,s){const i=t;if(!i?.isConnected||"view"===i._mode)return!1;const o=void 0!==e&&Rr.has(e);if("_layout"===e&&!i._deviceDrag)return!1;if("_dtBox"===e&&!i._dtDrag)return!1;if(void 0!==e&&Fr.has(e)&&null==s&&null!=i[e]&&Er(i))return!1;if(void 0!==e&&Fr.has(e)&&null==i[e])return!1;if(void 0!==e&&zr.has(e)&&null==i[e])return!1;return!!(o&&(zr.has(e)||Er(i))||void 0===e&&Er(i))&&(function(t){const e=Nr(t);if(e.requestedRevision++,e.raf||"function"!=typeof requestAnimationFrame)return;e.raf=requestAnimationFrame(()=>{e.raf=0;const s=e.requestedRevision;!function(t){const e=t,s=e.renderRoot;if(!s)return;const i=Nr(e);Wr(i),qr(e,s);const o=s.querySelector("[data-hp-live-editor]");if(!o)return;if(Hr(i,s,".hp-editor-only-layer:not(.hp-plan-snap-layer)"),"plan"===e._mode)e._opDrag&&Br(i,s,".wallbodies"),e._resize?.dragging&&(Vr(i,s,".wallbodies"),Hr(i,s,".resize-layer"),Kr(i,s,e._resize.plan?.movingOpeningIds||[])),e._opDrag&&Hr(i,s,".openinglayer");else if("decor"===e._mode){const t=e._dtDrag?.id||e._decorMove?.id;t&&Ur(i,s,t),Hr(i,s,".dtframe, .backdropframe")}St(Gr(e),o);const a=s.querySelector("[data-hp-live-editor-html]");if(a){const t=e._viewOr(e._baseVb());St(e._renderLiveEditorMeasurements(t),a)}e._liveEditorPaintCount=(e._liveEditorPaintCount||0)+1}(t),Ar(e,s)})}(i),!0)}const Br=(t,e,s)=>{for(const i of e.querySelectorAll(s))i.closest("[data-hp-live-editor]")||"hidden"!==i.style.visibility&&(i.style.visibility="hidden",t.hidden.push(i))},Hr=(t,e,s)=>{for(const i of e.querySelectorAll(s))i.closest("[data-hp-live-editor]")||"0"!==i.style.opacity&&(i.style.opacity="0",t.transparent.push(i))},Wr=t=>{for(const e of t.hidden)e.style.removeProperty("visibility");t.hidden.length=0;for(const e of t.transparent)e.style.removeProperty("opacity");t.transparent.length=0;for(const e of t.dimmed)e.style.removeProperty("opacity");t.dimmed.length=0},jr=(t,e,s=[])=>{if("iso"===t._renderProjection)return Pt``;const i=t._spaceModel();if(!i)return Pt``;const o=new Set(s),a=(i.rooms||[]).filter(t=>!!t.id&&o.has(t.id)).flatMap(t=>{const e=t.poly||[];return e.map((t,s)=>[t,e[(s+1)%e.length]])}),n=(t,e)=>{const[s,i]=e,o=i[0]-s[0],a=i[1]-s[1],n=o*o+a*a;if(!(n>0))return!1;const r=((t[0]-s[0])*o+(t[1]-s[1])*a)/n,l=Math.max(0,Math.min(1,r));return Math.hypot(t[0]-s[0]-o*l,t[1]-s[1]-a*l)<1e-4},r=[...t._spaceWalls.filter(t=>{const e=(t.a||[]).map(t=>t*lt),s=(t.b||[]).map(t=>t*lt);return a.some(t=>n(e,t)&&n(s,t))}).map((e,s)=>((e,s,i,o)=>{const a=Math.hypot(s[0]-e[0],s[1]-e[1]);if(!(a>1e-9&&i>0))return null;const n=V(i,t._cellCm,t._gridPitch)/2,r=-(s[1]-e[1])/a*n,l=(s[0]-e[0])/a*n;return{key:o,kind:"outer",cm:i,a:e,b:s,depthUnits:2*n,quad:[[e[0]+r,e[1]+l],[s[0]+r,s[1]+l],[s[0]-r,s[1]-l],[e[0]-r,e[1]-l]]}})((e.a||[]).map(t=>t*lt),(e.b||[]).map(t=>t*lt),e.cm,e.key||`wall-${s}`))].filter(t=>!!t),l=t._openingsR.map(t=>({x:t.rx,y:t.ry,angle:t.angle,length:t.rlen})),h=r.map(t=>Dt(t,l)).filter(Boolean);if(!h.length)return Pt``;const c=Math.max(...r.map(t=>t.depthUnits),0),d=t._viewOr(t._baseVb()),p=t._stageEl?.clientWidth&&d.w?t._stageEl.clientWidth/d.w:1,u=It(c,p)||Lt(Tt(t._cellCm),p),_=e?.color||"#607d8b",m=t._fillColors.wall_fill,g=h.join(" ");return Pt` @@ -507,8 +507,8 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc data-id="preview" data-kind="preview" d=${g} fill=${u?"none":"url(#hp-wall-hatch)"} fill-rule="nonzero" stroke=${_} stroke-width=${Rt(.6,t._cellCm)}> - `},qr=t=>{if("plan"===t._mode)return(t=>{const e=t._baseVb(),s=t._viewOr(e),i=t._opMeasureView;if(t._resize?.dragging){const e=t._spaceDisplayForRender(),i=t._resize.plan;return Pt``},Gr=t=>{if("plan"===t._mode)return(t=>{const e=t._baseVb(),s=t._viewOr(e),i=t._opMeasureView;if(t._resize?.dragging){const e=t._spaceDisplayForRender(),i=t._resize.plan;return Pt``}return Pt``},Ur=(t,e)=>{const s=t._deviceDrag;if(!s)return;const i=t._devices.find(t=>t.id===s.id),o=[...e.querySelectorAll('[data-hp="device"]')].find(t=>t.dataset.id===s.id);if(!i||!o)return;const a=t._livePos(i),n=t._scenePoint([a.x,a.y]),r=t._viewOr(t._baseVb());o.style.left=(n[0]-r.x)/r.w*100+"%",o.style.top=(n[1]-r.y)/r.h*100+"%"},Kr=(t,e,s)=>{for(const i of e.querySelectorAll('.decorlayer [data-hp="decor"]'))i.closest("[data-hp-live-editor]")||i.dataset.id!==s||"0"!==i.style.opacity&&(i.style.opacity="0",t.transparent.push(i))},Vr=(t,e,s)=>{const i=new Set(s);for(const s of e.querySelectorAll('.openinglayer [data-hp="opening"]'))!s.closest("[data-hp-live-editor]")&&i.has(s.dataset.id||"")&&(s.style.opacity="0",t.transparent.push(s))},Jr=(t,e,s)=>{for(const i of e.querySelectorAll(s))i.closest("[data-hp-live-editor]")||(i.style.opacity="0.35",t.dimmed.push(i))};const Zr=(t,e,s)=>Math.min(s,Math.max(e,Number.isFinite(t)?t:e));function Yr(t){return Number.isFinite(t)?(t%360+360)%360:0}function Xr(t){if("string"!=typeof t)return null;const e=t.trim().replace(/^#/,""),s=/^[0-9a-fA-F]{3}$/.test(e)?e.split("").map(t=>`${t}${t}`).join(""):e;return/^[0-9a-fA-F]{6}$/.test(s)?`#${s.toLowerCase()}`:null}function Qr(t){const e=Xr(t);return e?{r:Number.parseInt(e.slice(1,3),16),g:Number.parseInt(e.slice(3,5),16),b:Number.parseInt(e.slice(5,7),16)}:null}function tl(t){const e=Zr(t.r,0,255)/255,s=Zr(t.g,0,255)/255,i=Zr(t.b,0,255)/255,o=Math.max(e,s,i),a=o-Math.min(e,s,i);let n=0;return a>0&&(n=o===e?(s-i)/a%6*60:o===s?60*((i-e)/a+2):60*((e-s)/a+4)),{h:Yr(n),s:0===o?0:a/o*100,v:100*o}}function el(t){return function(t){const e=t=>Math.round(Zr(t,0,255)).toString(16).padStart(2,"0");return`#${e(t.r)}${e(t.g)}${e(t.b)}`}(function(t){const e=Yr(t.h),s=Zr(t.s,0,100)/100,i=Zr(t.v,0,100)/100,o=i*s,a=o*(1-Math.abs(e/60%2-1)),n=i-o;let r;return r=e<60?[o,a,0]:e<120?[a,o,0]:e<180?[0,o,a]:e<240?[0,a,o]:e<300?[a,0,o]:[o,0,a],{r:Math.round(255*(r[0]+n)),g:Math.round(255*(r[1]+n)),b:Math.round(255*(r[2]+n))}}(t))}const sl={title:"Color picker",hue:"Hue",saturation:"Saturation",value:"Brightness",hex:"Hex color",invalidHex:"Enter a 3- or 6-digit hex color",confirm:"OK"};class il extends Ft{constructor(){super(...arguments),this.label="",this.opacityLabel="Opacity",this.color="#607d8b",this.opacity=1,this.disabled=!1,this.showOpacity=!0,this.hideLabel=!1,this.pickerLabels=sl,this._open=!1,this._pickerRaf=0,this._emitRaf=0,this._forceFallback=!1,this._overlayDispose=null,this._hue=0,this._saturation=0,this._value=0,this._hexDraft="#607d8b",this._hexInvalid=!1,this._hexNeedsValidInput=!1,this._lastValidColor="#607d8b",this._activePointerId=null,this._outsidePointerDown=t=>{if(!this._open)return;const e=t.composedPath();this._floating.containsPath(e)||this._closePicker(!1,"outside")},this._keyDown=t=>{this._open&&"Escape"===t.key&&(t.preventDefault(),t.stopImmediatePropagation(),this._closePicker(this._floating.ownsActiveElement(),"escape"))},this._floating=new Bo(this,"color-opacity",this._keyDown),this._queuePickerPosition=()=>{if(!this._open)return;this._pickerRaf&&cancelAnimationFrame(this._pickerRaf);const t=this._window();t&&(this._pickerRaf=t.requestAnimationFrame(()=>{this._pickerRaf=0,this._positionPicker()||this._closePicker()}))}}connectedCallback(){super.connectedCallback(),this._syncFromColor(this.color,!1),this.ownerDocument.addEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.addEventListener("scroll",this._queuePickerPosition,!0);const t=this.ownerDocument.defaultView;t?.addEventListener("resize",this._queuePickerPosition),t?.addEventListener("orientationchange",this._queuePickerPosition),t?.visualViewport?.addEventListener("resize",this._queuePickerPosition),t?.visualViewport?.addEventListener("scroll",this._queuePickerPosition),this.addEventListener("keydown",this._keyDown,!0)}disconnectedCallback(){this.ownerDocument.removeEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.removeEventListener("scroll",this._queuePickerPosition,!0);const t=this.ownerDocument.defaultView;t?.removeEventListener("resize",this._queuePickerPosition),t?.removeEventListener("orientationchange",this._queuePickerPosition),t?.visualViewport?.removeEventListener("resize",this._queuePickerPosition),t?.visualViewport?.removeEventListener("scroll",this._queuePickerPosition),this.removeEventListener("keydown",this._keyDown,!0),this._pickerRaf&&cancelAnimationFrame(this._pickerRaf),this._emitRaf&&cancelAnimationFrame(this._emitRaf),this._pickerRaf=0,this._emitRaf=0,this._closePicker(!1,"disconnect"),super.disconnectedCallback()}updated(t){if(t.has("color")){const t=Xr(this.color);t&&t!==this._lastValidColor&&this._syncFromColor(t,this._open)}this.disabled&&this._open?this._closePicker():this._open&&(this._supportsPopover()||this._renderFallback(),(t.has("color")||t.has("opacity")||t.has("showOpacity")||t.has("label")||t.has("opacityLabel")||t.has("pickerLabels"))&&this._queuePickerPosition())}_window(){return this._floating.window()}_supportsPopover(){return this._floating.usesPopover(this._forceFallback)}_dialog(){return this._floating.dialog()}async _toggle(){this.disabled||(this._open?this._closePicker():(this._forceFallback=!1,this._syncFromColor(this.color,!1),this._hexInvalid=!1,this._hexNeedsValidInput=!1,this._activePointerId=null,this._open=!0,await this.updateComplete,this._open&&(this._supportsPopover()||this._renderFallback(),this._positionPicker()?this._overlayDispose=this._dialog()?.registerOverlay({owner:this,group:"transient",close:t=>this._closePicker("escape"===t&&this._floating.ownsActiveElement(),t)})||null:this._closePicker())))}_closePicker(t=!1,e="exclusive"){if(!this._open&&!this._floating.hasFallback)return;const s=this._overlayDispose;this._overlayDispose=null,s?.();const i=this.renderRoot.querySelector(".picker");if(i?.hidePopover)try{i.matches(":popover-open")&&i.hidePopover()}catch{}this._open=!1,this._cancelQueuedEmit(),this._activePointerId=null,this._floating.destroy(),t&&this.updateComplete.then(()=>this.renderRoot.querySelector(".trigger")?.focus())}_surface(){return this._floating.surface(".picker",this._supportsPopover())}_renderFallback(){const t=il.styles.cssText;this._floating.renderFallback(this._pickerTemplate(!1),t)}_positionPicker(){if(!this._open)return!1;const t=this._window(),e=this.renderRoot.querySelector(".trigger");let s=this._surface();if(!t||!e?.isConnected||!s?.isConnected)return!1;const i=Ho(t);if(s.style.maxWidth=`${Math.max(0,i.width-16)}px`,s.style.maxHeight=`${Math.max(0,i.height-16)}px`,s.style.visibility="hidden",this._supportsPopover()&&s.showPopover)try{s.matches(":popover-open")||s.showPopover()}catch{if(this._forceFallback=!0,this._renderFallback(),s=this._surface(),!s?.isConnected)return!1;s.style.maxWidth=`${Math.max(0,i.width-16)}px`,s.style.maxHeight=`${Math.max(0,i.height-16)}px`,s.style.visibility="hidden"}const o=e.getBoundingClientRect(),a=s.getBoundingClientRect();if(!(o.width&&o.height&&a.width&&a.height))return!1;const n=Wo(o,a,i);return s.style.left=`${n.left}px`,s.style.top=`${n.top}px`,s.dataset.side=n.side,s.style.visibility="",!0}_labels(){const t=this.pickerLabels||sl;return{title:t.title||sl.title,hue:t.hue||sl.hue,saturation:t.saturation||sl.saturation,value:t.value||sl.value,hex:t.hex||sl.hex,invalidHex:t.invalidHex||sl.invalidHex,confirm:t.confirm||sl.confirm}}_syncFromColor(t,e){const s=Xr(Nt(t,"#607d8b"))||"#607d8b",i=Qr(s);if(!i)return;const o=tl(i);(!e||o.s>1e-4)&&(this._hue=o.h),this._saturation=o.s,this._value=o.v,this._hexDraft=s,this._hexInvalid=!1,this._hexNeedsValidInput=!1,this._lastValidColor=s}_cancelQueuedEmit(t=!1){this._emitRaf&&cancelAnimationFrame(this._emitRaf),this._emitRaf=0,t&&this._syncFromColor(this._lastValidColor,!0)}_queueHsvEmit(){if(this._emitRaf)return;const t=this._window();t?this._emitRaf=t.requestAnimationFrame(()=>{this._emitRaf=0,this._emitHsv()}):this._emitHsv()}_emitHsv(){this._emit(el({h:this._hue,s:this._saturation,v:this._value}),this.opacity)}_setHue(t){this._hue=Math.min(359,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setSaturation(t){this._saturation=Math.min(100,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setValue(t){this._value=Math.min(100,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setOpacity(t){this._emit(this._lastValidColor,t)}_shiftRangeKey(t,e,s,i,o){if(!t.shiftKey)return;const a="ArrowRight"===t.key||"ArrowUp"===t.key?10:"ArrowLeft"===t.key||"ArrowDown"===t.key?-10:0;a&&(t.preventDefault(),t.stopPropagation(),o(Math.min(i,Math.max(s,e+a))))}_setSvFromPointer(t,e){const s=t.currentTarget.getBoundingClientRect();s.width&&s.height&&(this._saturation=Math.min(100,Math.max(0,(t.clientX-s.left)/s.width*100)),this._value=Math.min(100,Math.max(0,100*(1-(t.clientY-s.top)/s.height))),e?(this._cancelQueuedEmit(),this._emitHsv()):this._queueHsvEmit())}_svPointerDown(t){if(t.preventDefault(),t.stopPropagation(),null===this._activePointerId){this._activePointerId=t.pointerId;try{t.currentTarget.setPointerCapture(t.pointerId)}catch{}this._setSvFromPointer(t,!0)}}_svPointerMove(t){t.pointerId===this._activePointerId&&(t.preventDefault(),t.stopPropagation(),this._setSvFromPointer(t,!1))}_svPointerUp(t){if(t.pointerId===this._activePointerId){t.preventDefault(),t.stopPropagation(),this._setSvFromPointer(t,!0),this._activePointerId=null;try{t.currentTarget.releasePointerCapture(t.pointerId)}catch{}}}_svPointerCancel(t){t.pointerId===this._activePointerId&&(t.preventDefault(),t.stopPropagation(),this._activePointerId=null,this._cancelQueuedEmit(!0))}_svLostPointerCapture(t){t.pointerId===this._activePointerId&&(this._activePointerId=null,this._cancelQueuedEmit(!0))}_hexInput(t){const e=t.target.value;this._hexDraft=e;const s=Xr(e),i=s?Qr(s):null;if(!s||!i)return void(this._hexInvalid=this._hexNeedsValidInput);this._hexNeedsValidInput=!1,this._hexInvalid=!1;const o=tl(i);o.s>1e-4&&(this._hue=o.h),this._saturation=o.s,this._value=o.v,this._emit(s,this.opacity,!0)}_commitHex(){const t=Xr(this._hexDraft);if(!t)return this._hexDraft=this._lastValidColor,this._hexInvalid=!0,void(this._hexNeedsValidInput=!0);this._hexDraft=t,this._hexNeedsValidInput?this._hexInvalid=!0:(this._hexInvalid=!1,t!==this._lastValidColor&&this._emit(t,this.opacity))}_confirm(t){t.preventDefault(),t.stopPropagation(),this._commitHex(),this._hexInvalid||this._hexNeedsValidInput?this.updateComplete.then(()=>{this._surface()?.querySelector('input[type="text"]')?.focus()}):this._closePicker(!0)}_hexKeyDown(t){"Enter"===t.key&&(t.preventDefault(),t.stopPropagation(),this._commitHex())}_emit(t,e,s=!1){const i=Xr(t)||this._lastValidColor,o=Number.isFinite(e)?e:Number(this.opacity)||0,a=Math.min(1,Math.max(0,o));this.color=i,this.opacity=a,this._lastValidColor=i,s||(this._hexDraft=i),this._hexInvalid=this._hexNeedsValidInput,this.dispatchEvent(new CustomEvent("hp-color-opacity-change",{detail:{color:i,opacity:a},bubbles:!0,composed:!0}))}_pickerTemplate(t){const e=Math.round(100*Math.min(1,Math.max(0,Number(this.opacity)||0))),s=el({h:this._hue,s:this._saturation,v:this._value}),i=el({h:this._hue,s:100,v:100}),o=this._labels(),a=Math.round(this._hue),n=Math.round(this._saturation),r=Math.round(this._value);return p` + `},qr=(t,e)=>{const s=t._deviceDrag;if(!s)return;const i=t._devices.find(t=>t.id===s.id),o=[...e.querySelectorAll('[data-hp="device"]')].find(t=>t.dataset.id===s.id);if(!i||!o)return;const a=t._livePos(i),n=t._scenePoint([a.x,a.y]),r=t._viewOr(t._baseVb());o.style.left=(n[0]-r.x)/r.w*100+"%",o.style.top=(n[1]-r.y)/r.h*100+"%"},Ur=(t,e,s)=>{for(const i of e.querySelectorAll('.decorlayer [data-hp="decor"]'))i.closest("[data-hp-live-editor]")||i.dataset.id!==s||"0"!==i.style.opacity&&(i.style.opacity="0",t.transparent.push(i))},Kr=(t,e,s)=>{const i=new Set(s);for(const s of e.querySelectorAll('.openinglayer [data-hp="opening"]'))!s.closest("[data-hp-live-editor]")&&i.has(s.dataset.id||"")&&(s.style.opacity="0",t.transparent.push(s))},Vr=(t,e,s)=>{for(const i of e.querySelectorAll(s))i.closest("[data-hp-live-editor]")||(i.style.opacity="0.35",t.dimmed.push(i))};const Jr=(t,e,s)=>Math.min(s,Math.max(e,Number.isFinite(t)?t:e));function Zr(t){return Number.isFinite(t)?(t%360+360)%360:0}function Yr(t){if("string"!=typeof t)return null;const e=t.trim().replace(/^#/,""),s=/^[0-9a-fA-F]{3}$/.test(e)?e.split("").map(t=>`${t}${t}`).join(""):e;return/^[0-9a-fA-F]{6}$/.test(s)?`#${s.toLowerCase()}`:null}function Xr(t){const e=Yr(t);return e?{r:Number.parseInt(e.slice(1,3),16),g:Number.parseInt(e.slice(3,5),16),b:Number.parseInt(e.slice(5,7),16)}:null}function Qr(t){const e=Jr(t.r,0,255)/255,s=Jr(t.g,0,255)/255,i=Jr(t.b,0,255)/255,o=Math.max(e,s,i),a=o-Math.min(e,s,i);let n=0;return a>0&&(n=o===e?(s-i)/a%6*60:o===s?60*((i-e)/a+2):60*((e-s)/a+4)),{h:Zr(n),s:0===o?0:a/o*100,v:100*o}}function tl(t){return function(t){const e=t=>Math.round(Jr(t,0,255)).toString(16).padStart(2,"0");return`#${e(t.r)}${e(t.g)}${e(t.b)}`}(function(t){const e=Zr(t.h),s=Jr(t.s,0,100)/100,i=Jr(t.v,0,100)/100,o=i*s,a=o*(1-Math.abs(e/60%2-1)),n=i-o;let r;return r=e<60?[o,a,0]:e<120?[a,o,0]:e<180?[0,o,a]:e<240?[0,a,o]:e<300?[a,0,o]:[o,0,a],{r:Math.round(255*(r[0]+n)),g:Math.round(255*(r[1]+n)),b:Math.round(255*(r[2]+n))}}(t))}const el={title:"Color picker",hue:"Hue",saturation:"Saturation",value:"Brightness",hex:"Hex color",invalidHex:"Enter a 3- or 6-digit hex color",confirm:"OK"};class sl extends Ft{constructor(){super(...arguments),this.label="",this.opacityLabel="Opacity",this.color="#607d8b",this.opacity=1,this.disabled=!1,this.showOpacity=!0,this.hideLabel=!1,this.pickerLabels=el,this._open=!1,this._pickerRaf=0,this._emitRaf=0,this._forceFallback=!1,this._overlayDispose=null,this._hue=0,this._saturation=0,this._value=0,this._hexDraft="#607d8b",this._hexInvalid=!1,this._hexNeedsValidInput=!1,this._lastValidColor="#607d8b",this._activePointerId=null,this._outsidePointerDown=t=>{if(!this._open)return;const e=t.composedPath();this._floating.containsPath(e)||this._closePicker(!1,"outside")},this._keyDown=t=>{this._open&&"Escape"===t.key&&(t.preventDefault(),t.stopImmediatePropagation(),this._closePicker(this._floating.ownsActiveElement(),"escape"))},this._floating=new Bo(this,"color-opacity",this._keyDown),this._queuePickerPosition=()=>{if(!this._open)return;this._pickerRaf&&cancelAnimationFrame(this._pickerRaf);const t=this._window();t&&(this._pickerRaf=t.requestAnimationFrame(()=>{this._pickerRaf=0,this._positionPicker()||this._closePicker()}))}}connectedCallback(){super.connectedCallback(),this._syncFromColor(this.color,!1),this.ownerDocument.addEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.addEventListener("scroll",this._queuePickerPosition,!0);const t=this.ownerDocument.defaultView;t?.addEventListener("resize",this._queuePickerPosition),t?.addEventListener("orientationchange",this._queuePickerPosition),t?.visualViewport?.addEventListener("resize",this._queuePickerPosition),t?.visualViewport?.addEventListener("scroll",this._queuePickerPosition),this.addEventListener("keydown",this._keyDown,!0)}disconnectedCallback(){this.ownerDocument.removeEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.removeEventListener("scroll",this._queuePickerPosition,!0);const t=this.ownerDocument.defaultView;t?.removeEventListener("resize",this._queuePickerPosition),t?.removeEventListener("orientationchange",this._queuePickerPosition),t?.visualViewport?.removeEventListener("resize",this._queuePickerPosition),t?.visualViewport?.removeEventListener("scroll",this._queuePickerPosition),this.removeEventListener("keydown",this._keyDown,!0),this._pickerRaf&&cancelAnimationFrame(this._pickerRaf),this._emitRaf&&cancelAnimationFrame(this._emitRaf),this._pickerRaf=0,this._emitRaf=0,this._closePicker(!1,"disconnect"),super.disconnectedCallback()}updated(t){if(t.has("color")){const t=Yr(this.color);t&&t!==this._lastValidColor&&this._syncFromColor(t,this._open)}this.disabled&&this._open?this._closePicker():this._open&&(this._supportsPopover()||this._renderFallback(),(t.has("color")||t.has("opacity")||t.has("showOpacity")||t.has("label")||t.has("opacityLabel")||t.has("pickerLabels"))&&this._queuePickerPosition())}_window(){return this._floating.window()}_supportsPopover(){return this._floating.usesPopover(this._forceFallback)}_dialog(){return this._floating.dialog()}async _toggle(){this.disabled||(this._open?this._closePicker():(this._forceFallback=!1,this._syncFromColor(this.color,!1),this._hexInvalid=!1,this._hexNeedsValidInput=!1,this._activePointerId=null,this._open=!0,await this.updateComplete,this._open&&(this._supportsPopover()||this._renderFallback(),this._positionPicker()?this._overlayDispose=this._dialog()?.registerOverlay({owner:this,group:"transient",close:t=>this._closePicker("escape"===t&&this._floating.ownsActiveElement(),t)})||null:this._closePicker())))}_closePicker(t=!1,e="exclusive"){if(!this._open&&!this._floating.hasFallback)return;const s=this._overlayDispose;this._overlayDispose=null,s?.();const i=this.renderRoot.querySelector(".picker");if(i?.hidePopover)try{i.matches(":popover-open")&&i.hidePopover()}catch{}this._open=!1,this._cancelQueuedEmit(),this._activePointerId=null,this._floating.destroy(),t&&this.updateComplete.then(()=>this.renderRoot.querySelector(".trigger")?.focus())}_surface(){return this._floating.surface(".picker",this._supportsPopover())}_renderFallback(){const t=sl.styles.cssText;this._floating.renderFallback(this._pickerTemplate(!1),t)}_positionPicker(){if(!this._open)return!1;const t=this._window(),e=this.renderRoot.querySelector(".trigger");let s=this._surface();if(!t||!e?.isConnected||!s?.isConnected)return!1;const i=Ho(t);if(s.style.maxWidth=`${Math.max(0,i.width-16)}px`,s.style.maxHeight=`${Math.max(0,i.height-16)}px`,s.style.visibility="hidden",this._supportsPopover()&&s.showPopover)try{s.matches(":popover-open")||s.showPopover()}catch{if(this._forceFallback=!0,this._renderFallback(),s=this._surface(),!s?.isConnected)return!1;s.style.maxWidth=`${Math.max(0,i.width-16)}px`,s.style.maxHeight=`${Math.max(0,i.height-16)}px`,s.style.visibility="hidden"}const o=e.getBoundingClientRect(),a=s.getBoundingClientRect();if(!(o.width&&o.height&&a.width&&a.height))return!1;const n=Wo(o,a,i);return s.style.left=`${n.left}px`,s.style.top=`${n.top}px`,s.dataset.side=n.side,s.style.visibility="",!0}_labels(){const t=this.pickerLabels||el;return{title:t.title||el.title,hue:t.hue||el.hue,saturation:t.saturation||el.saturation,value:t.value||el.value,hex:t.hex||el.hex,invalidHex:t.invalidHex||el.invalidHex,confirm:t.confirm||el.confirm}}_syncFromColor(t,e){const s=Yr(Nt(t,"#607d8b"))||"#607d8b",i=Xr(s);if(!i)return;const o=Qr(i);(!e||o.s>1e-4)&&(this._hue=o.h),this._saturation=o.s,this._value=o.v,this._hexDraft=s,this._hexInvalid=!1,this._hexNeedsValidInput=!1,this._lastValidColor=s}_cancelQueuedEmit(t=!1){this._emitRaf&&cancelAnimationFrame(this._emitRaf),this._emitRaf=0,t&&this._syncFromColor(this._lastValidColor,!0)}_queueHsvEmit(){if(this._emitRaf)return;const t=this._window();t?this._emitRaf=t.requestAnimationFrame(()=>{this._emitRaf=0,this._emitHsv()}):this._emitHsv()}_emitHsv(){this._emit(tl({h:this._hue,s:this._saturation,v:this._value}),this.opacity)}_setHue(t){this._hue=Math.min(359,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setSaturation(t){this._saturation=Math.min(100,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setValue(t){this._value=Math.min(100,Math.max(0,Number.isFinite(t)?t:0)),this._emitHsv()}_setOpacity(t){this._emit(this._lastValidColor,t)}_shiftRangeKey(t,e,s,i,o){if(!t.shiftKey)return;const a="ArrowRight"===t.key||"ArrowUp"===t.key?10:"ArrowLeft"===t.key||"ArrowDown"===t.key?-10:0;a&&(t.preventDefault(),t.stopPropagation(),o(Math.min(i,Math.max(s,e+a))))}_setSvFromPointer(t,e){const s=t.currentTarget.getBoundingClientRect();s.width&&s.height&&(this._saturation=Math.min(100,Math.max(0,(t.clientX-s.left)/s.width*100)),this._value=Math.min(100,Math.max(0,100*(1-(t.clientY-s.top)/s.height))),e?(this._cancelQueuedEmit(),this._emitHsv()):this._queueHsvEmit())}_svPointerDown(t){if(t.preventDefault(),t.stopPropagation(),null===this._activePointerId){this._activePointerId=t.pointerId;try{t.currentTarget.setPointerCapture(t.pointerId)}catch{}this._setSvFromPointer(t,!0)}}_svPointerMove(t){t.pointerId===this._activePointerId&&(t.preventDefault(),t.stopPropagation(),this._setSvFromPointer(t,!1))}_svPointerUp(t){if(t.pointerId===this._activePointerId){t.preventDefault(),t.stopPropagation(),this._setSvFromPointer(t,!0),this._activePointerId=null;try{t.currentTarget.releasePointerCapture(t.pointerId)}catch{}}}_svPointerCancel(t){t.pointerId===this._activePointerId&&(t.preventDefault(),t.stopPropagation(),this._activePointerId=null,this._cancelQueuedEmit(!0))}_svLostPointerCapture(t){t.pointerId===this._activePointerId&&(this._activePointerId=null,this._cancelQueuedEmit(!0))}_hexInput(t){const e=t.target.value;this._hexDraft=e;const s=Yr(e),i=s?Xr(s):null;if(!s||!i)return void(this._hexInvalid=this._hexNeedsValidInput);this._hexNeedsValidInput=!1,this._hexInvalid=!1;const o=Qr(i);o.s>1e-4&&(this._hue=o.h),this._saturation=o.s,this._value=o.v,this._emit(s,this.opacity,!0)}_commitHex(){const t=Yr(this._hexDraft);if(!t)return this._hexDraft=this._lastValidColor,this._hexInvalid=!0,void(this._hexNeedsValidInput=!0);this._hexDraft=t,this._hexNeedsValidInput?this._hexInvalid=!0:(this._hexInvalid=!1,t!==this._lastValidColor&&this._emit(t,this.opacity))}_confirm(t){t.preventDefault(),t.stopPropagation(),this._commitHex(),this._hexInvalid||this._hexNeedsValidInput?this.updateComplete.then(()=>{this._surface()?.querySelector('input[type="text"]')?.focus()}):this._closePicker(!0)}_hexKeyDown(t){"Enter"===t.key&&(t.preventDefault(),t.stopPropagation(),this._commitHex())}_emit(t,e,s=!1){const i=Yr(t)||this._lastValidColor,o=Number.isFinite(e)?e:Number(this.opacity)||0,a=Math.min(1,Math.max(0,o));this.color=i,this.opacity=a,this._lastValidColor=i,s||(this._hexDraft=i),this._hexInvalid=this._hexNeedsValidInput,this.dispatchEvent(new CustomEvent("hp-color-opacity-change",{detail:{color:i,opacity:a},bubbles:!0,composed:!0}))}_pickerTemplate(t){const e=Math.round(100*Math.min(1,Math.max(0,Number(this.opacity)||0))),s=tl({h:this._hue,s:this._saturation,v:this._value}),i=tl({h:this._hue,s:100,v:100}),o=this._labels(),a=Math.round(this._hue),n=Math.round(this._saturation),r=Math.round(this._value);return p`
    ${this.host._t(t?"decor.image_place_hint":"decor.image_pick_hint")}
    - `}renderFurniturePalette(){const t=this.host._furnPalette,e=this.host._furnCategory,s=me.flatMap(t=>ge(t)),i=vd.filter(t=>s.some(e=>e.category===t.id)),o=i.find(t=>t.id===e)||null,a=o?s.filter(t=>t.category===o.id):[],n=this.host._t(this.host._imperial?"gs.unit_ft":"gs.unit_m");return p`
    t.stopPropagation()}> +
    `}renderFurniturePalette(){const t=this.host._furnPalette,e=this.host._furnCategory,s=me.flatMap(t=>ge(t)),i=bd.filter(t=>s.some(e=>e.category===t.id)),o=i.find(t=>t.id===e)||null,a=o?s.filter(t=>t.category===o.id):[],n=this.host._t(this.host._imperial?"gs.unit_ft":"gs.unit_m");return p`
    t.stopPropagation()}>
    ${this.host._t("furn.title")} @@ -1101,7 +1101,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc this.host._decorTextDialog={...t,sizeCm:this.host._decorTextCm(Number(e.target.value))}} /> ${this.host._t(this.host._imperial?"wallthick.unit_in":"wallthick.unit_cm")}
    @@ -1365,7 +1365,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc @change=${t=>{const e=t.target.value;e&&this._decorInsertLiveVariable("__state__"===e?null:e)}}> - ${Object.keys(s?.attributes||{}).filter(t=>!!bt(e,t)).map(t=>p``)} + ${Object.keys(s?.attributes||{}).filter(t=>!!ft(e,t)).map(t=>p``)} `:d}
    @@ -1393,7 +1393,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc -
    `}_cssPxToRender(t){const e=this.host._stageEl,s=this.host._viewOr(this.host._baseVb());return e?.clientWidth&&e.clientHeight?Math.max(s.w/e.clientWidth,s.h/e.clientHeight)*t:this.host._gridPitch/8*t}_deleteRoomClick(t){const e=this.host._spaceModel();if(!e)return;const s=[...e.rooms].reverse().find(e=>this._pointInRoom(t,e));s?s.id&&(this.host._roomDeleteDialog={roomId:s.id,name:s.name}):this.host._showToast(this.host._t("toast.delete_room_pick"))}_wallThickHit(t){const e=this.host._spaceModel();if(!e)return null;const s=6*this.host._gridPitch,i=this.host._openCuts();let o=null;const a=(t,e,i)=>{e>s||(!o||e100)return void this._showPhysicalRange(100);if("room"!==e.source.kind){const t=this._geometrySnapshot(),i=(s.partitions||[]).find(t=>t.id===e.source.id);if(!i)return;if(0===n&&Ce(s.openings,{kind:"partition",id:i.id}))return void this.host._showToast(this.host._t("toast.zero_wall_opening_conflict"));i.cm=n,this.host._wallDialog=null;return this._commitPhysicalGeometry(this.host._t("history.wall_thickness"),t)&&this.host._showToast(this.host._t("toast.wallthick_set")),void this.host.requestUpdate()}const r=this._geometrySnapshot(),l=n>0?n:null;if(0===n){const i=.02*this.host._gridPitch,o=[e.a[0],e.a[1],e.b[0],e.b[1]],a=(s.rooms||[]).find(t=>t.id===e.roomId),n=new Set(t&&a&&Array.isArray(a.wall_ids)?a.wall_ids:(s.wall_segments||[]).filter(t=>{const e=[Number(t.a?.[0])*Gd,Number(t.a?.[1])*Gd],s=[Number(t.b?.[0])*Gd,Number(t.b?.[1])*Gd];return de(e,o)<=i&&de(s,o)<=i}).map(t=>String(t.id))),r=(s.openings||[]).some(t=>{if("partition"===t.host?.kind)return!1;if("wall"===t.host?.kind&&n.has(t.host.id))return!0;if(t.host)return!1;const e=[Number(t.x)*Gd,Number(t.y)*Gd];return e.every(Number.isFinite)&&de(e,o)<=i});if(r)return void this.host._showToast(this.host._t("toast.zero_wall_opening_conflict"))}let h,c=this.host._openCuts();if(n>0&&c.length){const o=[];if(t&&e.roomId){const t=(s.rooms||[]).find(t=>t.id===e.roomId),a=new Set(Array.isArray(t?.wall_ids)?t.wall_ids:[]);for(const t of s.wall_segments||[])a.has(t.id)&&o.push([Number(t.a?.[0])*Gd,Number(t.a?.[1])*Gd,Number(t.b?.[0])*Gd,Number(t.b?.[1])*Gd]);if(!o.length){const t=i.rooms.find(t=>t.id===e.roomId),s=t?A(t):null;for(let t=0;s&&t!o.some(e=>de([t[0],t[1]],e)<=a&&de([t[2],t[3]],e)<=a&&de([e[0],e[1]],t)<=a&&de([e[2],e[3]],t)<=a))}h=t&&e.roomId?Rs(s.walls,i.rooms,e.roomId,l,this.host._wallKeyPitch,c,Gd):G(s.walls,e.a,e.b,l,this.host._wallKeyPitch,Gd),h=this.host._normalizeWalls(h,c);for(const t of s.wall_segments||[])t.cm=ot(h,t.a,t.b,F,1);h.length?s.walls=h:delete s.walls,this.host._wallDialog=null,this._commitPhysicalGeometry(this.host._t("history.wall_thickness"),r)&&this.host._showToast(this.host._t(0===n?"toast.wallthick_cleared":"toast.wallthick_set")),this.host.requestUpdate()}_wallHatchDefs(t){if(!this.host._spaceWalls.length&&!this.host._physicalBodiesR().length&&!this.host._markup)return Pt``;const e=Tt(this.host._cellCm);return Pt` +
    `}_cssPxToRender(t){const e=this.host._stageEl,s=this.host._viewOr(this.host._baseVb());return e?.clientWidth&&e.clientHeight?Math.max(s.w/e.clientWidth,s.h/e.clientHeight)*t:this.host._gridPitch/8*t}_deleteRoomClick(t){const e=this.host._spaceModel();if(!e)return;const s=[...e.rooms].reverse().find(e=>this._pointInRoom(t,e));s?s.id&&(this.host._roomDeleteDialog={roomId:s.id,name:s.name}):this.host._showToast(this.host._t("toast.delete_room_pick"))}_wallThickHit(t){const e=this.host._spaceModel();if(!e)return null;const s=6*this.host._gridPitch,i=this.host._openCuts();let o=null;const a=(t,e,i)=>{e>s||(!o||e100)return void this._showPhysicalRange(100);if("room"!==e.source.kind){const t=this._geometrySnapshot(),i=(s.partitions||[]).find(t=>t.id===e.source.id);if(!i)return;if(0===n&&Ce(s.openings,{kind:"partition",id:i.id}))return void this.host._showToast(this.host._t("toast.zero_wall_opening_conflict"));i.cm=n,this.host._wallDialog=null;return this._commitPhysicalGeometry(this.host._t("history.wall_thickness"),t)&&this.host._showToast(this.host._t("toast.wallthick_set")),void this.host.requestUpdate()}const r=this._geometrySnapshot(),l=n>0?n:null;if(0===n){const i=.02*this.host._gridPitch,o=[e.a[0],e.a[1],e.b[0],e.b[1]],a=(s.rooms||[]).find(t=>t.id===e.roomId),n=new Set(t&&a&&Array.isArray(a.wall_ids)?a.wall_ids:(s.wall_segments||[]).filter(t=>{const e=[Number(t.a?.[0])*jd,Number(t.a?.[1])*jd],s=[Number(t.b?.[0])*jd,Number(t.b?.[1])*jd];return de(e,o)<=i&&de(s,o)<=i}).map(t=>String(t.id))),r=(s.openings||[]).some(t=>{if("partition"===t.host?.kind)return!1;if("wall"===t.host?.kind&&n.has(t.host.id))return!0;if(t.host)return!1;const e=[Number(t.x)*jd,Number(t.y)*jd];return e.every(Number.isFinite)&&de(e,o)<=i});if(r)return void this.host._showToast(this.host._t("toast.zero_wall_opening_conflict"))}let h,c=this.host._openCuts();if(n>0&&c.length){const o=[];if(t&&e.roomId){const t=(s.rooms||[]).find(t=>t.id===e.roomId),a=new Set(Array.isArray(t?.wall_ids)?t.wall_ids:[]);for(const t of s.wall_segments||[])a.has(t.id)&&o.push([Number(t.a?.[0])*jd,Number(t.a?.[1])*jd,Number(t.b?.[0])*jd,Number(t.b?.[1])*jd]);if(!o.length){const t=i.rooms.find(t=>t.id===e.roomId),s=t?N(t):null;for(let t=0;s&&t!o.some(e=>de([t[0],t[1]],e)<=a&&de([t[2],t[3]],e)<=a&&de([e[0],e[1]],t)<=a&&de([e[2],e[3]],t)<=a))}h=t&&e.roomId?Rs(s.walls,i.rooms,e.roomId,l,this.host._wallKeyPitch,c,jd):j(s.walls,e.a,e.b,l,this.host._wallKeyPitch,jd),h=this.host._normalizeWalls(h,c);for(const t of s.wall_segments||[])t.cm=it(h,t.a,t.b,z,1);h.length?s.walls=h:delete s.walls,this.host._wallDialog=null,this._commitPhysicalGeometry(this.host._t("history.wall_thickness"),r)&&this.host._showToast(this.host._t(0===n?"toast.wallthick_cleared":"toast.wallthick_set")),this.host.requestUpdate()}_wallHatchDefs(t){if(!this.host._spaceWalls.length&&!this.host._physicalBodiesR().length&&!this.host._markup)return Pt``;const e=Tt(this.host._cellCm);return Pt` @@ -1418,7 +1418,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc - `:p``}_openingAt(t){if(!this.host._openingsR.length)return null;const e=this.host._openingsR.flatMap(e=>{const s=e.angle*Math.PI/180,i=t[0]-e.rx,o=t[1]-e.ry,a=i*Math.cos(s)+o*Math.sin(s);return Math.abs(a)>e.rlen/2+Rt(12,this.host._cellCm)?[]:[{o:e,localY:-i*Math.sin(s)+o*Math.cos(s)}]});if(!e.length)return null;const s=this.host._spaceModel();if(!s)return null;const i=this.host._openCuts(),o=this.host._openingWallIndexFor(s,i).value;return e.find(({o:t,localY:e})=>{const s="gate"===t.type?!t.flip_v:t.flip_v,i=t.partitionHost||this.host._spaceWalls.length||"gate"===t.type?this.host._openingFace(t,o,!!s):{ox:0,oy:0,cm:0,side:-1},a=zs({type:t.type,length:t.rlen,angle:t.angle,amount:this.host._openingAmt(t),flipH:!!t.flip_h,flipV:!!t.flip_v,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,face:i});return Math.abs(e)<=a.hitHalf})?.o||null}_resolveOpeningPlacement(t){const e=this.host._openingPreset;if("opening"!==this.host._tool||!e)return null;const s=this.host._spaceModel();if(!s)return null;const i=this.host._openCuts(),o=this.host._openingWallIndexFor(s,i),a=`${o.key}|partitions:${this.host._cfgEpoch}`;this.host._openingPlacementIntervalsCache&&this.host._openingPlacementIntervalsCache.key===a||(this.host._openingPlacementIntervalsCache={key:a,value:[...B(s.rooms,this.host._spaceWalls,i,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,Gd),...Fs(s.partitions,this.host._cellCm,this.host._gridPitch)]}),this.host._openingDimensionContextCache&&this.host._openingDimensionContextCache.key===a||(this.host._openingDimensionContextCache={key:a,value:Pd({rooms:s.rooms,walls:this.host._spaceWalls,openCuts:i,partitions:s.partitions,roomOpenings:this.host._roomWallOpeningInputs(),partitionCuts:this._partitionOpeningCuts(s),pitch:this.host._wallKeyPitch,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,coordScale:Gd,epsilon:2e-4*this.host._gridPitch})});const n=Ns({pointer:[t[0],t[1]],preset:e,geometryRevision:this.host._cfgEpoch,renderedLength:this.host._cmToUnits(e.lengthCm),intervals:this.host._openingPlacementIntervalsCache.value,baseTolerance:1.5*this.host._gridPitch,bodyPointerPadding:this._cssPxToRender("touch"===this.host._pointerModality.modality||"pen"===this.host._pointerModality.modality?10:6),gridStep:this.host._gridPitch});this.host._openingJambBlockCm=n.jambBlockedTarget?n.jambBlockedTarget.physicalHalfWidth/this.host._gridPitch*this.host._cellCm:null;const r=n.candidate;if(!r)return null;const l="gate"===r.type?!r.flipV:r.flipV;let h;if(r.host){const t=E({id:"preview",type:r.type,x:r.x/Gd,y:r.y/Gd,angle:r.angle,length:r.renderedLength/Gd,host:r.host},s.partitions,Gd,this.host._cellCm,this.host._gridPitch).resolved;h=t?As(t,l):{ox:0,oy:0,cm:0,side:-1}}else h=Es(o.value,{x:r.x,y:r.y,angle:r.angle,length:r.renderedLength,flip_v:l});const c="mi"===this.host.hass?.config?.unit_system?.length,d=Fd(r,this.host._openingDimensionContextCache.value).map(t=>({x:t.label[0],y:t.label[1],text:le(t.distance/this.host._gridPitch*this.host._cellCm,c),dimension:t}));return{...r,face:h,measure:{labels:d,guide:r.measure.guide}}}_activateOpeningPlacement(t){this._activateMarkupTool("opening"),"opening"===this.host._tool&&(this.host._openingPreset=Os(t,++this.host._openingPresetRevision),this.host._openingHoverCandidate=null,this.host._cursorPt=null)}_clearOpeningPlacement(t){this.host._openingHoverCandidate=null,this.host._openingJambBlockCm=null,t&&(this.host._openingPreset=null,this.host._openingRebindId=null)}_openingClick(t){const e=this.host._spaceModel();if(!e)return;const s=this.host._openingRebindId?null:this._openingAt(t);if(s)return void this._editOpening(s);const i=this.host._openingPreset;if(!i)return;const o=this.host._openingHoverCandidate,a=o&&Bs(o,[t[0],t[1]],i.revision,this.host._cfgEpoch)?o:this._resolveOpeningPlacement(t);if(!a){if(null!=this.host._openingJambBlockCm)return void this.host._showToast(this.host._t("opening.partition_jamb_margin",{distance:le(this.host._openingJambBlockCm,this.host._imperial)}));const s=1.5*this.host._gridPitch,i=z(t,e.rooms,s);return i&&Hs(i.x,i.y,i.angle,this.host._openCuts(),s)?void this.host._showToast(this.host._t("toast.opening_on_zero_wall")):void this.host._showToast(this.host._t("toast.opening_no_wall"))}const n=this.host._openingRebindId?this.host._curSpaceCfg?.openings?.find(t=>t.id===this.host._openingRebindId):null;this.host._openingDialog={...n?{id:n.id,type:n.type,lengthCm:Math.round(n.length*Gd/this.host._gridPitch*this.host._cellCm),lengthTouched:!1,contact:n.contact||"",lock:n.lock||"",invert:!!n.invert,flipH:!!n.flip_h,flipV:!!n.flip_v}:{type:a.type,lengthCm:a.lengthCm,contact:"",lock:"",invert:!1,flipH:a.flipH,flipV:a.flipV},...a.host?{host:a.host}:{},x:a.x,y:a.y,angle:a.angle},this.host._openingRebindId=null,this.host._openingHoverCandidate=null,this.host._cursorPt=null}_editOpening(t){this.host._openingDialog={id:t.id,type:t.type,lengthCm:Math.round(t.rlen/this.host._gridPitch*this.host._cellCm),lengthTouched:!1,contact:t.contact||"",lock:t.lock||"",invert:!!t.invert,flipH:!!t.flip_h,flipV:!!t.flip_v,..."partition"===t.host?.kind?{host:{...t.host}}:{},x:t.rx,y:t.ry,angle:t.angle}}_opPointerDown(t,e){if("plan"===this.host._mode&&this.host._spaceModel()&&"resize"!==this.host._tool){t.preventDefault(),t.stopPropagation();try{Ud(t)}catch{}this.host._opDrag={id:e.id,moved:!1,sx:t.clientX,sy:t.clientY,dirty:!1,before:this._geometrySnapshot()}}}_opPointerMove(t,e){Ir(this.host,"opening",()=>this._opPointerMoveNow(t,e))}_opPointerMoveNow(t,e){if(!this.host._opDrag||this.host._opDrag.id!==e.id)return;if(Math.abs(t.clientX-this.host._opDrag.sx)+Math.abs(t.clientY-this.host._opDrag.sy)<=3)return;const s=this.host._spaceModel();if(!s)return;const i=this._svgPoint(t),o=this.host._curSpaceCfg,a=o?.openings?.find(t=>t.id===e.id);if(!a)return;if("partition"===a.host?.kind){const t=s.partitions.find(t=>t.id===a.host.id);if(!t)return;const e=t.b[0]-t.a[0],o=t.b[1]-t.a[1],n=Math.hypot(e,o);if(!(n>1e-9))return;const r=e/n,l=o/n;if(Math.abs((i[0]-t.a[0])*l-(i[1]-t.a[1])*r)>4*this.host._gridPitch)return;const h=a.length*Gd/2+j(t,this.host._cellCm,this.host._gridPitch);let c=(i[0]-t.a[0])*r+(i[1]-t.a[1])*l;if(c=Math.round(c/this.host._gridPitch)*this.host._gridPitch,c=Math.max(h,Math.min(n-h,c)),n<2*h-1e-9)return;const d=c/n,p=(t.a[0]+r*c)/Gd,u=(t.a[1]+l*c)/this.host._spaceH;let _=180*Math.atan2(o,e)/Math.PI;_>=90?_-=180:_<-90&&(_+=180);const m=a.host.t!==d||a.x!==p||a.y!==u||a.angle!==_;return this.host._opDrag.moved=!0,m&&(this.host._opDrag.dirty=!0),a.host={...a.host,t:d},a.x=p,a.y=u,a.angle=_,this.host._opMeasure=null,m&&this.host._cfgEpoch++,void this.host.requestUpdate()}const n=z(i,s.rooms,4*this.host._gridPitch);if(!n)return;this.host._opDrag.moved=!0;const r=this._opRuler(n,a.length*Gd);this.host._opMeasure=r.measure;const l=r.x/Gd,h=r.y/this.host._spaceH,c=a.x!==l||a.y!==h||a.angle!==n.angle;if(c&&(this.host._opDrag.dirty=!0),a.x=l,a.y=h,a.angle=n.angle,Number(this.host._serverCfg?.model_version||0)>=9){const t=Hn(a,o?.wall_segments||[]);t?a.host=t:delete a.host}c&&this.host._cfgEpoch++,this.host.requestUpdate()}_opRuler(t,e){const s=this.host._spaceModel()?.rooms||[],i=this.host._gridPitch/2;let o=t.x,a=t.y,n=Ws([o,a],t.angle,e,s,i);if(n&&n.centered&&(o!==n.wallCenter[0]||a!==n.wallCenter[1]))[o,a]=n.wallCenter,n=Ws([o,a],t.angle,e,s,i);else if(n){const[r,l]=n.wallA,[h,c]=n.wallB,d=h-r,p=c-l,u=Math.hypot(d,p);if(u>0){const h=this.host._gridPitch,c=Math.min(e/2,u/2);let _=Math.round(((o-r)*d+(a-l)*p)/u/h)*h;_=Math.max(c,Math.min(u-c,_)),o=r+_/u*d,a=l+_/u*p,n=Ws([o,a],t.angle,e,s,i)||n}}if(!n)return{x:o,y:a,angle:t.angle,measure:null};const r="mi"===this.host.hass?.config?.unit_system?.length,l=(t,e)=>({x:e[0],y:e[1],text:le(t/this.host._gridPitch*this.host._cellCm,r)});return{x:o,y:a,angle:t.angle,measure:{labels:[l(n.sideA,n.midA),l(n.sideB,n.midB)],guide:n.centered?{x:n.wallCenter[0],y:n.wallCenter[1],angle:t.angle}:null}}}_opPointerUp(t,e){if(!this.host._opDrag||this.host._opDrag.id!==e.id)return;Lr(this.host,"opening");const s=this.host._opDrag,i=s.moved;this.host._opMeasure=null,i&&s.dirty&&this._commitPhysicalGeometry(this.host._t("history.move_opening"),s.before);const o=()=>{this.host._opDrag=null,this.host.requestUpdate()};i?window.setTimeout(o,0):o()}_opClick(t,e){"plan"===this.host._mode&&"resize"===this.host._tool||(t.stopPropagation(),this.host._opDrag?.moved||"plan"===this.host._mode&&this._editOpening(e))}_saveOpening(){const t=this.host._openingDialog,e=this.host._curSpaceCfg,s=this.host._spaceModel();if(!t||!e||!s)return;const i=this._geometrySnapshot(),o=this.host._spaceH,a=(e.openings||[]).find(e=>e.id===t.id),n={...a||{},id:t.id||"o"+Date.now().toString(36),type:t.type,x:t.x/Gd,y:t.y/o,angle:t.angle,length:a&&!t.lengthTouched?a.length:this.host._cmToUnits(Math.max(20,t.lengthCm))/Gd,...t.host?{host:{...t.host}}:{}};if("partition"===n.host?.kind){const t=js(a,n)?U(n,s.partitions,Gd,this.host._cellCm,this.host._gridPitch):E(n,s.partitions,Gd,this.host._cellCm,this.host._gridPitch);if(!t.resolved){const e=s.partitions.find(t=>t.id===n.host.id);if("does-not-fit-jamb"===t.reason&&e){const t=j(e,this.host._cellCm,this.host._gridPitch);this.host._showToast(this.host._t("opening.partition_jamb_margin",{distance:le(t/this.host._gridPitch*this.host._cellCm,this.host._imperial)}))}else this.host._showToast(this.host._t("opening.partition_orphan"));return}const i=(e.openings||[]).flatMap(t=>{if(!t.host||t.id===n.id)return[];const e=E(t,s.partitions,Gd,this.host._cellCm,this.host._gridPitch).resolved;return e?[e]:[]});if(Gs(t.resolved,i))return void this.host._showToast(this.host._t("toast.opening_no_wall"));Object.assign(n,O(n,t.resolved,Gd))}else if(Number(this.host._serverCfg?.model_version||0)>=9){const t=Hn(n,e.wall_segments||[]);if(!t)return void this.host._showToast(this.host._t("toast.opening_no_wall"));n.host=t}else delete n.host;"passage"===t.type?(delete n.contact,delete n.lock,delete n.invert,delete n.flip_h,delete n.flip_v):(n.contact=t.contact||null,n.lock=("door"===t.type||"gate"===t.type)&&t.lock||null,n.invert=t.invert||void 0,n.flip_h="gate"!==t.type&&t.flipH||void 0,n.flip_v=t.flipV||void 0),e.openings=e.openings||[];const r=e.openings.findIndex(t=>t.id===n.id);r>=0?e.openings[r]=n:e.openings.push(n),this._commitPhysicalGeometry(this.host._t(t.id?"history.edit_opening":"history.add_opening"),i),this.host._openingDialog=null,this.host.requestUpdate()}_deleteOpening(){const t=this.host._openingDialog,e=this.host._curSpaceCfg;if(!t?.id||!e?.openings)return;const s=this._geometrySnapshot();e.openings=e.openings.filter(e=>e.id!==t.id),this._commitPhysicalGeometry(this.host._t("history.delete_opening"),s),this.host._openingDialog=null,this.host.requestUpdate()}_contactCandidates(){const t=[];for(const e of Object.keys(this.host.hass.states)){if(!this.host._openingEntityAvailable(e))continue;const s=e.split(".")[0];if("binary_sensor"!==s&&"cover"!==s)continue;const i=this.host.hass.states[e],o=["door","window","opening","garage_door","garage"].includes(i?.attributes?.device_class||"");("cover"!==s||o)&&t.push([e,i?.attributes?.friendly_name||e,o?0:1])}return t.sort((t,e)=>t[2]-e[2]||t[1].localeCompare(e[1])).map(([t,e])=>({value:t,label:e}))}_lockCandidates(){return Object.keys(this.host.hass.states).filter(t=>t.startsWith("lock.")&&this.host._openingEntityAvailable(t)).map(t=>({value:t,label:this.host.hass.states[t]?.attributes?.friendly_name||t})).sort((t,e)=>t.label.localeCompare(e.label))}_toggleOpeningEntityPicker(t){const e=this.host._openingDialog;if(!e)return;const s="contact"===t?!e.contactOpen:!e.lockOpen;this.host._openingDialog={...e,contactOpen:"contact"===t&&s,lockOpen:"lock"===t&&s}}_filterOpeningEntities(t,e){const s=this.host._openingDialog;s&&(this.host._openingDialog="contact"===t?{...s,contactFilter:e}:{...s,lockFilter:e})}_selectOpeningEntity(t,e){const s=this.host._openingDialog;s&&(this.host._openingDialog="contact"===t?{...s,contact:e,contactOpen:!1,contactFilter:""}:{...s,lock:e,lockOpen:!1,lockFilter:""})}_mergeClick(t){const e=this.host._spaceModel();if(!e)return;const s=e.rooms,i=[...s].reverse().find(e=>this._pointInRoom(t,e));if(!i?.id)return;const o=i.id;if(!this.host._mergeSel||this.host._mergeSel===o)return void(this.host._mergeSel=this.host._mergeSel===o?null:o);const a=s.find(t=>t.id===this.host._mergeSel),n=a?A(a):null,r=A(i),l=n&&r?qs(n,r):null;if(!l)return this.host._showToast(this.host._t("toast.merge_not_adjacent")),void(this.host._mergeSel=null);this.host._mergeDialog={aId:this.host._mergeSel,bId:o,poly:l,pick:"a"},this.host._mergeSel=null}_commitMerge(){const t=this.host._mergeDialog,e=this.host._curSpaceCfg;if(!t||!e||!this.host._spaceModel())return;const s=this._geometrySnapshot(),i=this.host._spaceH,o="a"===t.pick?t.aId:t.bId,a="a"===t.pick?t.bId:t.aId,n=Bd(this.host._serverCfg?.markers||[],{kind:"merge",dropId:a,keepId:o});s&&n.changed&&(s.roomReferences=n.before);const r=e.rooms.find(t=>t.id===o);if(!r)return void(this.host._mergeDialog=null);r.poly=t.poly.map(t=>[t[0]/Gd,t[1]/i]),delete r.x,delete r.y,delete r.w,delete r.h,e.rooms=e.rooms.filter(t=>t.id!==a),n.changed&&this.host._serverCfg&&(this.host._serverCfg.markers=n.markers);const l=this._commitPhysicalGeometry(this.host._t("history.merge_rooms"),s);this.host._mergeDialog=null,this.host._regSignature="",this.host._maybeRebuildDevices(),l&&this.host._showToast(this.host._t("toast.rooms_merged",{name:r.name||""}))}_splitClick(t){const e=this.host._spaceModel();if(!e)return;const s=e.rooms;if(!this.host._splitSel){const e=[...s].reverse().find(e=>this._pointInRoom(t,e));if(!e?.id)return;return void(this.host._splitSel={roomId:e.id,pts:[]})}const i=s.find(t=>t.id===this.host._splitSel.roomId),o=i?A(i):null;if(!i||!o)return void(this.host._splitSel=null);const a=.02*this.host._gridPitch,n=6*this.host._gridPitch,r=Us(t,o),l=r&&Ks(r,o,this.host._gridPitch)||r,h=r&&l&&Math.hypot(r[0]-t[0],r[1]-t[1])<=n?l:null,c=!!h&&Vs(h,o,a),d=this.host._splitSel.pts;if(!d.length)return c?void(this.host._splitSel={...this.host._splitSel,pts:[h]}):void this.host._showToast(this.host._t("toast.split_pick_wall"));if(!c){const e=this._snap(t);return Je(e,o,a)?void(this.host._splitSel={...this.host._splitSel,pts:[...d,e]}):void this.host._showToast(this.host._t("toast.split_pick_inside"))}const p=Ye(o,[...d,h],a);if(!p)return void this.host._showToast(this.host._t("toast.split_bad_cut"));this._resetRoomDialogFields();const[u,_]=p,m=Zt(u)>=Zt(_)?u:_,g=m===u?_:u;this.host._pendingSplit={roomId:i.id,mainPoly:m,newPoly:g},this.host._cursorPt=null,this.host._nameSel="",this.host._areaSel="",this.host._roomDialog=!0}_markupMove(t){if(!this.host._markup)return;if("column"===this.host._tool)return void(this.host._cursorPt=this._snap(this._svgPoint(t)));if("opening"===this.host._tool||"wallthick"===this.host._tool)return void(this.host._cursorPt=this._svgPoint(t));const e="draw"===this.host._tool&&!this.host._contourClosed,s="split"===this.host._tool&&!!this.host._splitSel?.pts?.length;if(!e&&!s)return;const i=this._svgPoint(t);if(e){const e=this._resolvePlanDrawPoint(i,t.shiftKey);if(this.host._planSnapHover={contextKey:e.contextKey,candidate:e.candidate,conflicts:e.conflicts},this._syncPlanSnapConflictMarkers(e.conflicts),this._syncPlanSnapActiveMarker(e.candidate),!this.host._path.length)return;return void(this.host._cursorPt=e.point)}this.host._cursorPt=this._snap(i)}_saveRoom(){(this.host._areaSel||this.host._nameSel.trim())&&Mt(this.host._roomTempMin,this.host._roomTempMax).valid&&(this.host._wallFaceBatch?this._decideWallFace(!0):this._commitRoom())}_decideWallFace(t){const e=this.host._wallFaceBatch;if(!e)return;const s=e.candidates[e.index];if(!s)return;if(!t&&(s.existing||s.repair)&&1===e.candidates.length)return this.host._wallFaceBatch=null,this.host._roomDialog=!1,this.host._nameSel="",this.host._areaSel="",void this.host.requestUpdate();const i=t?{candidate:s,create:!0,name:this.host._nameSel.trim(),area:this.host._areaSel||null,settings:this._roomSettingsFromDialog()?JSON.parse(JSON.stringify(this._roomSettingsFromDialog())):null}:{candidate:s,create:!1},o=[...e.decisions,i],a=e.index+1;if(a"number"==typeof t&&Number.isFinite(t)&&t>=0?t:null,o=.02*this.host._gridPitch,a=this.host._spaceModel();if(!a)return H;for(const e of this._planSnapGeometrySnapshot().value.segments)if(!("room"===e.sourceKind||de(t,[e.a[0],e.a[1],e.b[0],e.b[1]])>o)&&"partition"===e.sourceKind)return i(a.partitions.find(t=>t.id===e.sourceId)?.cm)??H;const n=xc(Math.max(0,e.length-1),s,this.host._drawWallCm,H);for(let s=0;s+1[...t]);if(!e)return s;const i=this.host._activeWallChainPartitionIds.findIndex((t,s)=>this._activeWallSourceKey(s)===e.sourceKey),o=i>=0?i+("b"===e.endpoint?1:0):-1;return o>=0&&oe.key===t.sourceKey),a=i.find(e=>e.key===t.targetSourceKey);if(!o||!a)return!1;const n="a"===t.endpoint?o.a:o.b;return!(Math.hypot(n[0]-t.from[0],n[1]-t.from[1])>s)&&(!(de(t.to,[a.a[0],a.a[1],a.b[0],a.b[1]])>s)&&!function(t,e){if(!t.sourceKey.startsWith("static:partition|"))return!1;const s=t.sourceKey.slice(17).split("|")[0];return!!s&&e.some(t=>"partition"===t.host?.kind&&t.host.id===s)}(t,this.host._curSpaceCfg?.openings||[]))}_applyWallRepair(t,e){const s=this.host._curSpaceCfg;if(!s||!this._validateWallRepair(t,e.activePath))return!1;if(!t.sourceKey.startsWith("static:"))return!1;const[i,o]=t.sourceKey.slice(7).split("|");if("partition"===i){const i=(s.partitions||[]).find(t=>t.id===o);if(!i)return!1;const a=[i.a[0]*Gd,i.a[1]*Gd],n=[i.b[0]*Gd,i.b[1]*Gd],r=Math.hypot(a[0]-t.from[0],a[1]-t.from[1])<=2e-4*this.host._gridPitch?i.a:Math.hypot(n[0]-t.from[0],n[1]-t.from[1])<=2e-4*this.host._gridPitch?i.b:null;if(!r)return!1;(e=>{e[0]=t.to[0]/Gd,e[1]=t.to[1]/Gd})(r);const l=e.activePartitionIds.indexOf(o);if(l>=0){const s=l+("b"===t.endpoint?1:0);e.activePath[s]&&(e.activePath[s]=[...t.to])}return!0}return!1}_applyWallFaceBatch(){const t=this.host._wallFaceBatch,e=this.host._curSpaceCfg,s=this.host._spaceModel();if(!t||!e||!s)return;const i=(t,e)=>{this.host._showToast(this.host._t(t,e)),this._roomDialogCancel()},o=t.decisions.filter(t=>t.create),a=o.map(t=>t.candidate.ring),n=s.rooms;for(let t=0;ts.id!==e&&!!A(s)&&Vt(a[t],A(s)));if(s)return void i("toast.room_overlap",{name:s.name||""})}if((e.rooms||[]).length+o.length>400)return void i("toast.physical_limit");if(o.some(t=>t.candidate.split&&!e.rooms.some(e=>e.id===t.candidate.split.roomId)))return void i("toast.contour_cannot_close");const r=o.map(t=>t.candidate.repair).filter(t=>!!t);if(r.length>1||r[0]&&!this._validateWallRepair(r[0],t.activePath))return void i("toast.wall_repair_changed");if(this._activePathWithRepair(t.activePath,r[0]),!o.length){if(!this._finalizeWallChainPartitions(t.activePartitionIds))return;return this.host._path=[],this.host._activeWallChainId=null,this.host._activeWallChainPartitionIds=[],this.host._wallChainSegmentCms=[],this.host._wallChainRedo=[],this.host._closingWallCm=null,this.host._wallFaceBatch=null,this.host._roomDialog=!1,this.host._nameSel="",this.host._areaSel="",this.host.requestUpdate(),void this.host._showToast(this.host._t("toast.wall_chain_saved"))}const l=new Set(t.activePartitionIds),h=2e-4*this.host._gridPitch,c=o.map(t=>t.candidate.ring.map((t,e,i)=>{const o=i[(e+1)%i.length],a=s.partitions.filter(e=>{const s=Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1]);if(!(s>h))return!1;const i=(e.b[0]-e.a[0])/s,a=(e.b[1]-e.a[1])/s,n=t=>(t[0]-e.a[0])*i+(t[1]-e.a[1])*a;return de(t,[e.a[0],e.a[1],e.b[0],e.b[1]])<=h&&de(o,[e.a[0],e.a[1],e.b[0],e.b[1]])<=h&&n(t)>=-h&&n(t)<=s+h&&n(o)>=-h&&n(o)<=s+h});return a.sort((t,e)=>Number(l.has(e.id))-Number(l.has(t.id))||Math.hypot(t.b[0]-t.a[0],t.b[1]-t.a[1])-Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])||t.id.localeCompare(e.id)),a[0]?.id||""})),d=this._geometrySnapshot();if(!d)return void i("toast.geometry_unsafe");const p=()=>{this._restoreGeometryStateLocal(d),i("toast.geometry_unsafe")};if(r[0]&&!this._applyWallRepair(r[0],t))return void i("toast.wall_repair_changed");const u=o.some(t=>!!t.candidate.split),_=u?Pe(s.rooms,e.walls,this.host._openCuts(),this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,Gd):null,m=u&&Array.isArray(e.walls)?e.walls:null;for(const t of o){const s=t.candidate.split;if(!s)continue;const i=e.rooms.find(t=>t.id===s.roomId);if(!i)return void p();i.poly=s.mainPoly.map(t=>[t[0]/Gd,t[1]/this.host._spaceH]),delete i.x,delete i.y,delete i.w,delete i.h}const g=Date.now().toString(36),f=[];if(o.forEach((t,s)=>{const i=t.area?this.host.hass.areas[t.area]?.name:"",o={id:`r${g}-${s}`,name:t.name||i||this.host._t("room.default_name"),area:t.area||null,poly:t.candidate.ring.map(t=>[t[0]/Gd,t[1]/this.host._spaceH]),...c[s].some(Boolean)?{wall_ids:c[s]}:{},...t.settings?{settings:JSON.parse(JSON.stringify(t.settings))}:{}};e.rooms.push(o),f.push({room:o,decision:t})}),u){const t=this.host._normalizeWalls(_,this.host._openCuts());t.length?e.walls=t:m?.length?e.walls=m:delete e.walls}if(f.length){this.host._cfgEpoch++;const s=this.host._openCuts(),i=this.host._spaceModel();if(!i)return void p();let o=e.walls;for(const{room:e,decision:a}of f){const n=a.candidate.ring,r=this._wallSourceCmAt(n[0],t.activePath,t.activeCms);o=Js(o,i.rooms,e.id,r,this.host._wallKeyPitch,s,Gd);for(const a of B(i.rooms,o,s,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,Gd)){if(a.roomId!==e.id||"outer"!==a.kind)continue;const s=[(a.a[0]+a.b[0])/2,(a.a[1]+a.b[1])/2];o=G(o,a.a,a.b,this._wallSourceCmAt(s,t.activePath,t.activeCms),this.host._wallKeyPitch,Gd)}}const a=this.host._normalizeWalls(o,s);a.length?e.walls=a:delete e.walls,this.host._cfgEpoch++;const n=this.host._spaceModel();if(!n)return void p();const r=un(e,n,e.walls,s,{pitch:this.host._wallKeyPitch,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,coordScale:Gd,allowCoincidentPartitions:!0});r.walls.length?e.walls=r.walls:delete e.walls,r.partitions.length?e.partitions=r.partitions:delete e.partitions,r.openings.length?e.openings=r.openings:delete e.openings}if(!this._commitPhysicalGeometry(this.host._t("history.wall_face_batch"),d))return;this.host._path=[],this.host._activeWallChainId=null,this.host._activeWallChainPartitionIds=[],this.host._wallChainSegmentCms=[],this.host._wallChainRedo=[],this.host._closingWallCm=null,this.host._wallFaceBatch=null,this.host._roomDialog=!1,this.host._nameSel="",this.host._areaSel="",this.host._regSignature="",this.host._maybeRebuildDevices();const b=new Set(o.map(t=>t.area).filter(t=>!!t));if(b.size){const t={...this.host._layout};for(const e of this.host._devices){if(!b.has(e.area||"")||e.space!==this.host._space)continue;if(this.host._layout[e.id])continue;const s=this.host._defPos[e.id];s&&(t[e.id]={s:this.host._space,x:s.x/Gd,y:s.y/Gd},this.host._dirtyPos.add(e.id))}this.host._layout=t,this.host._persistLayout()}this.host._showToast(this.host._t(o.length?"toast.wall_rooms_saved":"toast.wall_chain_saved",{n:o.length}))}_commitRoom(){const t=this.host._curSpaceCfg,e=this.host._spaceModel();if(!t||!e)return;const s=this._geometrySnapshot();if(!s)return;const i=()=>{this._restoreGeometryStateLocal(s),this.host._showToast(this.host._t("toast.geometry_unsafe"))},o=this.host._spaceH,a=!!this.host._pendingSplit,n=a?Pe(e.rooms,t.walls,this.host._openCuts(),this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,Gd):null,r=a&&Array.isArray(t.walls)?t.walls:null;let l;if(this.host._pendingSplit){const e=t.rooms.find(t=>t.id===this.host._pendingSplit.roomId);if(!e)return this.host._pendingSplit=null,this.host._splitSel=null,void(this.host._roomDialog=!1);e.poly=this.host._pendingSplit.mainPoly.map(t=>[t[0]/Gd,t[1]/o]),delete e.x,delete e.y,delete e.w,delete e.h,l=this.host._pendingSplit.newPoly}else{if(!this.host._contourClosed)return;l=this.host._path.slice(0,-1)}const h=this.host._areaSel?this.host.hass.areas[this.host._areaSel]?.name:"",c={id:"r"+Date.now().toString(36),name:this.host._nameSel||h||this.host._t("room.default_name"),area:this.host._areaSel||null,poly:l.map(t=>[t[0]/Gd,t[1]/o]),...this._roomSettingsFromDialog()?{settings:this._roomSettingsFromDialog()}:{}};if(t.rooms.push(c),a){const e=this.host._normalizeWalls(n,this.host._openCuts());e.length?t.walls=e:r?.length?t.walls=r:delete t.walls}if(!a){const e=xc(l.length,[...this.host._wallChainSegmentCms,this.host._closingWallCm??void 0],this.host._drawWallCm,H),s=e[0];if(null!=s){this.host._cfgEpoch++;const o=this.host._openCuts(),a=this.host._spaceModel();if(!a)return void i();let n=Js(t.walls,a.rooms,c.id,s,this.host._wallKeyPitch,o,Gd);for(const t of B(a.rooms,n,o,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,Gd)){if(t.roomId!==c.id||"outer"!==t.kind)continue;const s=[(t.a[0]+t.b[0])/2,(t.a[1]+t.b[1])/2],i=l.findIndex((t,e)=>{const i=l[(e+1)%l.length];return de(s,[t[0],t[1],i[0],i[1]])<=.02*this.host._gridPitch});i>=0&&(n=G(n,t.a,t.b,e[i],this.host._wallKeyPitch,Gd))}n=this.host._normalizeWalls(n,o),n.length?t.walls=n:delete t.walls;const r=this.host._spaceModel();if(!r)return void i();const h=un(t,r,t.walls,o,{pitch:this.host._wallKeyPitch,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,coordScale:Gd,allowCoincidentPartitions:!0});h.walls.length?t.walls=h.walls:delete t.walls,h.partitions.length?t.partitions=h.partitions:delete t.partitions,h.openings.length?t.openings=h.openings:delete t.openings}}const d=this._commitPhysicalGeometry(this.host._t(a?"history.split_room":"history.add_room"),s);this.host._path=[],this.host._activeWallChainId=null,this.host._activeWallChainPartitionIds=[],this.host._wallChainSegmentCms=[],this.host._wallChainRedo=[],this.host._closingWallCm=null,this.host._pendingSplit=null,this.host._splitSel=null;const p=this.host._areaSel;if(this.host._areaSel="",this.host._nameSel="",this.host._roomDialog=!1,this.host._regSignature="",this.host._maybeRebuildDevices(),!d)return;let u=0;if(p){const t=Gd,e={...this.host._layout};for(const s of this.host._devices){if(s.area!==p||s.space!==this.host._space)continue;if(u++,this.host._layout[s.id])continue;const i=this.host._defPos[s.id];i&&(e[s.id]={s:this.host._space,x:i.x/Gd,y:i.y/t},this.host._dirtyPos.add(s.id))}this.host._layout=e,this.host._persistLayout()}const _=this.host._model.find(t=>t.id===this.host._space)?.rooms.length||0;this.host._showToast(p?this.host._t("toast.room_saved",{n:_,added:u}):this.host._t("toast.room_saved_no_area",{n:_}))}_cancelPath(){this.host._wallRepairDiagnostic=null,this.host._path=[],this.host._activeWallChainId=null,this.host._activeWallChainPartitionIds=[],this.host._wallChainSegmentCms=[],this.host._wallChainRedo=[],this.host._closingWallCm=null,this._clearPlanSnapHover(),this.host._roomDialog=!1,this.host._pendingSplit=null,this.host._wallFaceBatch=null,this.host._splitSel=null,this.host._mergeSel=null,this.host._mergeDialog=null,this.host._physicalSel=null,this.host._physicalDrag=null,this.host._physicalRotate=null,this._clearOpeningPlacement(!0)}_roomDialogCancel(){if(this.host._roomDialog=!1,this.host._roomEditId)return this.host._roomEditId=null,this.host._nameSel="",void(this.host._areaSel="");if(this.host._wallFaceBatch){const t=this.host._wallFaceBatch;return this.host._wallFaceBatch=null,this.host._path=t.activePath.map(t=>[...t]),this.host._wallChainSegmentCms=[...t.activeCms],this.host._activeWallChainPartitionIds=[...t.activePartitionIds],this.host._activeWallChainId||=`chain-${Date.now().toString(36)}`,this.host._nameSel="",this.host._areaSel="",void this.host.requestUpdate()}if(this.host._pendingSplit)return this.host._pendingSplit=null,void(this.host._splitSel=null);this.host._undoPoint()}_openDeviceInbox(){this.host._deviceInboxReturn=null,this.host._deviceInbox=this.host._deviceInbox||{tab:"on_plan",search:"",showEntities:!1,onlyNew:!1,limit:100}}_closeMarkerDialog(){this._radarSetup.isDirty()?this._closeMarkerDialogGuarded():(this._radarSetup.reset(),function(t){if(t._markerDialog=null,!t._deviceInboxReturn)return;const e={...t._deviceInboxReturn};t._deviceInbox=e,t._deviceInboxReturn=null,e.anchor&&t.updateComplete.then(()=>requestAnimationFrame(()=>{const s=`.device-inbox-row[data-binding="${CSS.escape(e.anchor)}"]`;t.renderRoot.querySelector(s)?.scrollIntoView({block:"nearest"})}))}(this.host))}async _closeMarkerDialogGuarded(){if(!await this._radarSetup.discardIfAllowed())return await this.host.updateComplete,void this.host.renderRoot.querySelector("#marker-dialog")?.rejectClose();this._closeMarkerDialog()}_deviceInboxCandidates(t){return Qh({hass:this.host._planHass,devices:this.host._devices,markers:this.host._markers,showEntities:t,labels:{device:this.host._t("marker.sub_device"),z2mGroup:this.host._t("marker.sub_z2m_group"),group:this.host._t("marker.sub_group"),helper:this.host._t("marker.sub_helper"),entity:this.host._t("marker.sub_entity")}})}_deviceInboxRows(){const t=this.host._deviceInbox||this.host._deviceInboxReturn,e=!!t?.showEntities,s=[this.host._haRegistry.revision,this.host._cfgRev,this.host._cfgEpoch,this.host._regSignature,this.host._newSyncKey,e?1:0,this.host._showAll?1:0,l(this.host.hass,this.host._config?.language)].join("|");if(this.host._deviceInboxMemo?.key===s)return this.host._deviceInboxMemo.rows;const i=this._deviceInboxCandidates(e),o=new Set(i.map(t=>t.value));for(const t of this.host._markers)t.binding&&"virtual"!==t.binding&&o.add(t.binding);for(const t of this.host._devices)t.bindingKind&&"virtual"!==t.bindingKind&&t.bindingRef&&o.add(`${t.bindingKind}:${t.bindingRef}`);const a=new Map;for(const t of o)a.set(t,this.host._bindingStatus(t));const n=this.host._areaToSpace,r={};for(const[t,e]of Object.entries(this.host.hass?.areas||{}))r[t]=n[t]?.room?.name||e?.name||t;for(const[t,e]of Object.entries(n))r[t]=e.room.name||r[t]||t;const h=Object.fromEntries(this.host._model.map(t=>[t.id,t.title])),c=Object.fromEntries(Object.entries(n).map(([t,e])=>[t,e.space])),d={},p=new Map;for(const[t,e]of Object.entries(this.host._fullRegistryHass.entities||{})){const s=String(e?.platform||"").trim();if(s&&(d[`entity:${t}`]=s),s&&e?.device_id){const t=p.get(e.device_id)||new Set;t.add(s),p.set(e.device_id,t)}}for(const[t,e]of p)d[`device:${t}`]=[...e].sort().join(", ");const u={};for(const[t,e]of Object.entries(this.host._fullRegistryHass.devices||{})){const s=`device:${t}`,i=p.get(t)||new Set,o=Array.isArray(e?.identifiers?.[0])?String(e.identifiers[0][0]||""):"";o&&!d[s]&&(d[s]=o);const a=[o,...i].some(t=>this.host._excluded.has(t));"service"===e?.entry_type?u[s]="service_entry":a?u[s]="excluded_integration":"Group"===e?.model?u[s]="grouped_light":/scene/i.test(e?.model||"")?u[s]="excluded_domain":(/bridge/i.test(`${e?.model||""}${e?.name||""}`)||"myheat"===o&&e?.via_device_id)&&(u[s]="represented_by_parent")}const _=function(t){const{devices:e,markers:s,candidates:i,statuses:o,newDeviceIds:a,showHiddenOnPlan:n,areaNames:r={},spaceNames:l={},spaceByArea:h={},integrationByBinding:c={},reasonByBinding:d={}}=t,p=new Map;for(const t of e)!t.virtual&&t.bindingKind&&"virtual"!==t.bindingKind&&t.bindingRef&&p.set(`${t.bindingKind}:${t.bindingRef}`,t);const u=new Map,_=new Map;for(const t of s)t?.binding&&"virtual"!==t.binding&&(t.removed?_.set(t.binding,t):u.set(t.binding,t));const m=new Map(i.map(t=>[t.value,t])),g=new Set([...p.keys(),...u.keys(),...m.keys(),...[..._.keys()].filter(t=>m.has(t))]),f=[];for(const t of g){const e=p.get(t),s=u.get(t),i=s?void 0:_.get(t),g=m.get(t);let b;if(i&&g)b="readd";else if(!0===s?.hidden)b="hidden";else if(e||s)b="on_plan";else{if(!g)continue;b="available"}const v=e?.bindingStatus||o.get(t)||tc,y=s||i,w=ec(t),$=e?.area||g?.areaId||y?.area||"",k=e?.space||y?.space||h[$]||"",x=e?.name||y?.name||g?.label||t,M=e?.model||y?.model||g?.model||"",C=!!g?.parentDeviceId&&p.has(`device:${g.parentDeviceId}`),S="readd"===b?"removed":"hidden"===b?s&&sc(s)?d[t]||"automatic_hidden":"manual_hidden":"on_plan"===b?s?"visible_explicit":"visible_auto":d[t]||(C?"represented_by_parent":$&&k?"available":"no_bound_room"),P=!!e&&(!e.hidden||n),D="active"===v.kind,I=P&&(D||"ha_disabled"===v.kind&&n),L=[x,M,c[t],r[$],l[k],t,g?.sub].filter(Boolean).join(" ").toLocaleLowerCase();f.push({key:t,binding:t,category:b,status:v,reason:S,deviceId:e?.id,markerId:y?.id,name:x,icon:e?.icon||y?.icon||("entity"===w?"mdi:code-braces":"mdi:devices"),model:M,integration:c[t]||"",areaId:$,areaName:r[$]||"",spaceId:k,spaceName:l[k]||"",kind:w,isNew:!!e&&a.has(e.id),searchText:L,canFind:I,canEdit:!!e||!!s,canHide:"on_plan"===b&&D,canShow:"hidden"===b&&D,canAdd:("available"===b||"readd"===b)&&D})}const b=t=>"active"===t.status.kind?1:0;return f.sort((t,e)=>t.category.localeCompare(e.category)||Number(e.isNew)-Number(t.isNew)||b(t)-b(e)||t.name.localeCompare(e.name)||t.binding.localeCompare(e.binding))}({devices:this.host._devices,markers:this.host._markers,candidates:i,statuses:a,newDeviceIds:this.host._newIds,showHiddenOnPlan:this.host._showAll,areaNames:r,spaceNames:h,spaceByArea:c,integrationByBinding:d,reasonByBinding:u});return this.host._deviceInboxMemo={key:s,rows:_},_}_deviceForInboxRow(t){const e=t.deviceId?this.host._devices.find(e=>e.id===t.deviceId):null;if(e)return e;const s=t.markerId?this.host._markers.find(e=>e.id===t.markerId):null;return!s||s.removed?null:{id:s.id,name:t.name,model:t.model,area:t.areaId,space:t.spaceId||this.host._space,hidden:!0===s.hidden||"ha_disabled"===t.status.kind,userHidden:!0===s.hidden,bindingStatus:t.status,icon:t.icon,entities:"active"===t.status.kind?t.status.enabledEntityIds:[],allEntities:t.status.allEntityIds,primary:"active"===t.status.kind?t.status.enabledEntityIds[0]:void 0,marker:s,bindingKind:t.kind,bindingRef:t.binding.slice(t.binding.indexOf(":")+1),pdfs:s.pdfs||[]}}_openInboxMarker(t,e=!1){const s=this.host._deviceInbox;if(s){if(this.host._deviceInboxReturn={...s,anchor:t.key},this.host._deviceInbox=null,!e){const e=this._deviceForInboxRow(t);return void(e?this._openMarkerDialog(e):this._closeMarkerDialog())}this._openMarkerDialog(),this.host._markerDialog?this.host._markerDialog={...this.host._markerDialog,bindingMode:"ha",binding:t.binding,bindingOpen:!1,showEntities:"entity"===t.kind,name:""}:this._closeMarkerDialog()}}async _setInboxHidden(t,e){const s=this.host._deviceInbox,i=this.host._serverCfg;if(!s||!i||s.busy||"active"!==t.status.kind)return;const o=i.markers||[],a=o.find(e=>!e.removed&&e.binding===t.binding);if(!e&&!a)return;const n=a?.id||Zs(t.binding,t.markerId,()=>`m_${Date.now().toString(36)}`),r=a?{...a,hidden:e}:{id:n,binding:t.binding,hidden:!0};i.markers=[...o.filter(e=>e.id!==n&&(e.binding!==t.binding||!0===e.removed)),r],this.host._deviceInbox={...s,busy:t.key,anchor:t.key};try{await this._saveConfigNow(),this.host._regSignature="",this.host._deviceInboxMemo=null,this.host._maybeRebuildDevices(),this.host._deviceInbox&&(this.host._deviceInbox={...this.host._deviceInbox,busy:void 0}),this.host._showToast(this.host._t("device_inbox.saved"))}catch(t){this.host._serverCfg===i&&(i.markers=o),this.host._deviceInbox&&(this.host._deviceInbox={...this.host._deviceInbox,busy:void 0}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_findInboxDevice(t){if(!t.canFind)return;const e=this._deviceForInboxRow(t);if(!e)return;if(this.host._deviceInbox=null,e.space&&e.space!==this.host._space){if(!this.host._commitSpace(e.space))return;this.host._restoreZoom()}const s=()=>{const t=this.host._devices.find(t=>t.id===e.id)||e,s=this.host._pos(t);this.host._applyView(this.host._zoom,s.x,s.y),this.host._selId=t.id,this.host.requestUpdate(),window.setTimeout(()=>{this.host._selId===t.id&&(this.host._selId=null,this.host.requestUpdate())},1500)};requestAnimationFrame(()=>requestAnimationFrame(s))}_openMarkerDialog(t){if(this.host._vacAllCamerasFor=null,this.host._vacAllCameraCache=null,t&&this.host._ackNewDevice(t.id),this.host._norm){if(t){const e=t.marker,s=Object.prototype.hasOwnProperty.call(e||{},"is_light"),i=Object.prototype.hasOwnProperty.call(e||{},"light_entity"),o=Object.prototype.hasOwnProperty.call(e||{},"glow_color"),a=Object.prototype.hasOwnProperty.call(e||{},"value_badge"),n=Object.prototype.hasOwnProperty.call(e||{},"value_source"),r=Object.prototype.hasOwnProperty.call(e||{},"tap_action"),l=Object.prototype.hasOwnProperty.call(e||{},"toggle_entity"),h=Ys(e?.glow_color),c=this.host._devicePresentation(t,!0).valueBadge,d=f(this.host._planHass,t,this.host._devices),p=b(this.host._planHass,t,d),u=Ma(t,this.host._fullRegistryHass),_=this.host._spaceModelById(t.space)||this.host._spaceModel(),m=this.host._pos(t),g=_?Sa(t,_,[m.x,m.y],this.host._fullRegistryHass):null;this.host._markerDialog={devId:t.id,name:t.name,binding:"virtual"===t.bindingKind?"virtual":t.bindingKind+":"+t.bindingRef,bindingMode:"virtual"===t.bindingKind?"virtual":"ha",bindingOpen:!1,showEntities:"entity"===t.bindingKind&&!!this.host._fullRegistryHass.entities[t.bindingRef||""]?.device_id,bindingFilter:"",icon:t.marker?.icon||"",autoIcon:t.icon||"",display:P(t.marker?.display),rippleColor:Nt(t.marker?.ripple_color,""),rippleSize:Number(t.marker?.ripple_size)>0?Number(t.marker.ripple_size):1.5,size:Number(t.marker?.size)>0?Number(t.marker.size):1,angle:Number(t.marker?.angle)||0,tapAction:Xs(t.marker?.tap_action,t.primary?.split(".")[0]),tapActionTouched:!1,originalHasTapAction:r,originalTapAction:t.marker?.tap_action,tapHintAnnouncement:"",toggleEntity:e?.toggle_entity||"",toggleEntityTouched:!1,originalHasToggleEntity:l,originalToggleEntity:e?.toggle_entity,tapTarget:t.marker?.tap_target||"",tapConfirm:!0===t.marker?.tap_confirm,runFilter:"",controls:R(t.marker?.binding,t.marker?.controls,t.entities),controlsFilter:"",lightRole:!0===e?.is_light?"always":!1===e?.is_light?"never":"auto",lightRoleTouched:!1,originalHasIsLight:s,originalIsLight:e?.is_light,lightEntity:e?.light_entity||"",lightEntityTouched:!1,originalHasLightEntity:i,originalLightEntity:e?.light_entity,glowMode:null!=h?.bri?"fixed":h?"color":"auto",glowColor:h?.c||this.host._fillColors.glow_light.c,glowBrightness:Math.max(1,Math.round(100*(h?.bri??1))),glowColorDrafted:!!h,glowBrightnessDrafted:null!=h?.bri,glowTouched:!1,originalHasGlowColor:o&&(!!h||null===e?.glow_color),originalGlowColor:h||(null===e?.glow_color?null:void 0),valueBadgeEnabled:a?!0===e?.value_badge?.enabled:!!c,valueBadgeSource:e?.value_badge?.source||c?.source||p,valueBadgePosition:e?.value_badge?.position||c?.position||"right",valueBadgeTouched:!1,originalHasValueBadge:a,originalValueBadge:e?.value_badge,valueSource:e?.value_source||null,valueSourceTouched:!1,originalHasValueSource:n,originalValueSource:e?.value_source,useClimateTemp:!0===t.marker?.use_climate_temp,glowRadius:Number(t.marker?.glow_radius_cm)>0?String(this.host._imperial?Math.round(Number(t.marker.glow_radius_cm)/30.48*10)/10:Math.round(Number(t.marker.glow_radius_cm))/100):"",model:t.model||"",link:t.link||"",description:t.description||"",pdfs:[...t.pdfs||[]],room:t.marker?.room_id?t.space+"#@"+t.marker.room_id:t.space&&t.area?t.space+"#"+t.area:"",roomTouched:!1,radar:g,radarEligible:u.eligible,radarTouched:!1,radarRemove:!1,hideFromPlan:!0===t.marker?.hidden,busy:!1}}else this.host._markerDialog={name:"",binding:"virtual",bindingMode:"virtual",bindingOpen:!1,showEntities:!1,bindingFilter:"",icon:"",autoIcon:"",display:"badge",rippleColor:"",rippleSize:1.5,size:1,angle:0,tapAction:"info",tapActionTouched:!1,originalHasTapAction:!1,originalTapAction:void 0,tapHintAnnouncement:"",toggleEntity:"",toggleEntityTouched:!1,originalHasToggleEntity:!1,originalToggleEntity:void 0,tapTarget:"",tapConfirm:!1,runFilter:"",controls:[],controlsFilter:"",lightRole:"auto",lightRoleTouched:!1,originalHasIsLight:!1,originalIsLight:void 0,lightEntity:"",lightEntityTouched:!1,originalHasLightEntity:!1,originalLightEntity:void 0,glowMode:"auto",glowColor:this.host._fillColors.glow_light.c,glowBrightness:100,glowColorDrafted:!1,glowBrightnessDrafted:!1,glowTouched:!1,originalHasGlowColor:!1,originalGlowColor:void 0,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgePosition:"right",valueBadgeTouched:!1,originalHasValueBadge:!1,originalValueBadge:void 0,valueSource:null,valueSourceTouched:!1,originalHasValueSource:!1,originalValueSource:void 0,useClimateTemp:!1,glowRadius:"",model:"",link:"",description:"",pdfs:[],room:"",roomTouched:!1,radar:null,radarEligible:!1,radarTouched:!1,radarRemove:!1,hideFromPlan:!1,busy:!1,uploadId:"up_"+Date.now().toString(36)+Math.random().toString(36).slice(2,6)};this.host._markerDialog&&function(t,e){_o(t,"marker",ga(e))}(this.host,this.host._markerDialog)}else this.host._showToast(this.host._t("toast.marker_needs_server"))}_runCandidates(){const t=[];for(const e of Qs)for(const[s,i]of Object.entries(this.host.hass.states))s.startsWith(e+".")&&this.host._planEntityAvailable(s)&&t.push({value:s,label:i?.attributes?.friendly_name||s,sub:this.host._t("run."+e)});return t.sort((t,e)=>t.sub.localeCompare(e.sub)||t.label.localeCompare(e.label))}_bindingCandidates(){const t=Qh({hass:this.host._planHass,devices:this.host._devices,markers:this.host._markers,showEntities:!!this.host._markerDialog?.showEntities,currentBinding:this.host._markerDialog?.binding,currentDeviceId:this.host._markerDialog?.devId,labels:{device:this.host._t("marker.sub_device"),z2mGroup:this.host._t("marker.sub_z2m_group"),group:this.host._t("marker.sub_group"),helper:this.host._t("marker.sub_helper"),entity:this.host._t("marker.sub_entity")}}),e=(this.host._markerDialog?.bindingFilter||"").toLowerCase().trim(),s=e?t.filter(t=>(t.label+" "+t.sub+" "+t.value).toLowerCase().includes(e)):t;return s.sort((t,e)=>t.label.localeCompare(e.label)),s.slice(0,200)}_backupErrorText(t){const e=t?.code??t?.error;if("string"==typeof e){const t=`backup.error.${e}`,s=this.host._t(t);if(s!==t)return s}return this.host._errText(t)}async _pickMarkerFiles(t){const e=t.target,s=e.files?[...e.files]:[];if(e.value="",!s.length||!this.host._markerDialog)return;const i=this.host._markerDialog.uploadId||this.host._markerDialog.devId||"new",o=[];for(const t of s)try{const e=new FormData;e.append("marker_id",i),e.append("file",t,t.name);const s=this.host.hass?.fetchWithAuth?await this.host.hass.fetchWithAuth("/api/houseplan/upload",{method:"POST",body:e}):await fetch("/api/houseplan/upload",{method:"POST",body:e,headers:this.host.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.host.hass.auth.data.access_token}`}:{}}),a=await s.json().catch(()=>({}));if(!s.ok||a.error){const t={too_large:this.host._t("err.too_large",{mb:a.max_mb||50}),bad_ext:this.host._t("err.bad_ext"),unauthorized:this.host._t("err.unauthorized")};throw new Error(t[a.error]||a.error||"HTTP "+s.status)}o.push({name:a.name||t.name,url:a.url})}catch(e){this.host._showToast(this.host._t("toast.file_failed",{name:t.name,err:this.host._errText(e)}))}o.length&&this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,pdfs:[...this.host._markerDialog.pdfs,...o]},this.host._showToast(this.host._t("toast.files_attached",{n:o.length})))}_removeMarkerPdf(t){this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,pdfs:this.host._markerDialog.pdfs.filter(e=>e.url!==t)})}_markerLightFields(t){const e={};if(t.lightRoleTouched?"always"===t.lightRole?e.is_light=!0:"never"===t.lightRole&&(e.is_light=!1):t.originalHasIsLight&&(e.is_light=t.originalIsLight??null),t.lightEntityTouched?t.lightEntity&&(e.light_entity=t.lightEntity):t.originalHasLightEntity&&(e.light_entity=t.originalLightEntity??null),t.glowTouched){if("auto"!==t.glowMode){const s={c:Nt(t.glowColor,this.host._fillColors.glow_light.c)};"fixed"===t.glowMode&&(s.bri=Math.max(.01,Math.min(1,Math.round(t.glowBrightness)/100))),e.glow_color=s}}else t.originalHasGlowColor&&(e.glow_color=t.originalGlowColor??null);return e}_markerTapActionFields(t){return t.tapActionTouched?{tap_action:t.tapAction||null}:t.originalHasTapAction?{tap_action:t.originalTapAction??null}:{}}_markerToggleEntityFields(t){return(e={touched:t.toggleEntityTouched,originalHas:t.originalHasToggleEntity,original:t.originalToggleEntity,value:t.toggleEntity}).touched?e.value?{toggle_entity:e.value}:{}:e.originalHas?{toggle_entity:e.original??null}:{};var e}async _saveMarker(){const t=this.host._markerDialog;if(!t||t.busy)return;const e=this._effectiveMarkerTapAction(t);if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return;if("virtual"===t.binding&&!t.name.trim())return void this.host._showToast(this.host._t("toast.virtual_name_required"));if("run"===e&&!t.tapTarget)return void this.host._showToast(this.host._t("toast.run_target_required"));if(t.valueBadgeTouched&&t.valueBadgeEnabled&&!t.valueBadgeSource)return void this.host._showToast(this.host._t("toast.value_badge_source_required"));if("ha"===t.bindingMode){const e=this.host._bindingStatus(t.binding),s=t.devId?this.host._markers.find(e=>e.id===t.devId):null,i=!s||s.binding!==t.binding;if("active"!==e.kind&&i)return void this.host._showToast(this.host._t("ha_disabled"===e.kind?"toast.ha_disabled_add":"toast.ha_binding_unverified"));if("ha_disabled"===e.kind&&!0===s?.hidden&&!t.hideFromPlan)return this.host._markerDialog={...t,hideFromPlan:!0},void this.host._showToast(this.host._t("entity"===e.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device"))}const s=this.host._serverCfg;if(!s)return;const i=this.host._cfgRev,o=wt(s);let a=JSON.parse(JSON.stringify(s));const n=a.markers||[],r=Zs(t.binding,t.devId,()=>"v_"+Date.now().toString(36)),l=t.devId,h=l?this.host._devices.find(t=>t.id===l):null,c=l?n.find(t=>t.id===l):null,d=!!c&&("string"==typeof c.area&&c.area.length>0||null===c.area&&!!c.space&&!!c.room_id),p="virtual"===t.binding||t.roomTouched||d,_="virtual"===t.binding||t.roomTouched?M(t.room):null;let m=d&&!t.roomTouched?c?.space||null:_?.space||null;const g=d&&!t.roomTouched?c?.area||null:_?.area||null,f=d&&!t.roomTouched?c?.room_id||null:_?.roomId||null,b=m||h?.space||null,v=b?this.host._spaceModelById(b):this.host._spaceModel();if(!v)return;const y=v.id;"virtual"!==t.binding||m||(m=y);let w={};if(t.radarTouched){if(t.radarRemove)w={radar:null};else if(t.radar){const e=Ia(t.radar,v.cellCm||5);if(!e)return void this.host._showToast(this.host._t("radar.invalid"));w={radar:e}}}else c&&Object.prototype.hasOwnProperty.call(c,"radar")&&(w={radar:c.radar});this.host._markerDialog={...t,busy:!0};let $=null,k=!1;try{const c="virtual"===t.binding?[]:n.filter(e=>e.removed&&e.binding===t.binding).map(t=>t.id),d=c.length>0,_=R(t.binding,t.controls,this.host._bindingEntities(t.binding)),b=n.find(t=>t.id===r||t.id===l)?.vacuum||null,x={id:r,vacuum:b,...w,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle?t.angle:null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===e&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:_.length?_:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),...this._markerValueSourceFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=u(t.glowRadius);return null==e||e<=0?null:Math.round(this.host._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:!!t.hideFromPlan};p&&(x.space=m,x.area=g,x.room_id=f);const M=h?.marker?.room_id??null,C=t.roomTouched&&null!=h&&(h.space!==m||h.area!==g||M!==f);let S=!1;const P=t.uploadId||l;if(P&&P!==r&&x.pdfs?.length)try{const t=await this.host.hass.callWS({type:"houseplan/files/migrate",from_id:P,to_id:r}),e=t?.mapping||{};x.pdfs=ti(x.pdfs,P,r,e),S=Object.keys(e).length>0}catch(t){this.host._showToast(this.host._t("toast.files_migrate_failed",{err:this.host._errText(t)}))}a.markers=n,l&&l!==r&&(a.markers=ei(a.markers,l,r)),l&&l!==r&&"derived_marker_state"===x.value_badge?.source?.kind&&x.value_badge.source.ref===`marker:${l}`&&(x.value_badge.source={kind:"derived_marker_state",ref:`marker:${r}`}),l&&l!==r&&"derived_marker_state"===x.value_source?.kind&&x.value_source.ref===`marker:${l}`&&(x.value_source={kind:"derived_marker_state",ref:`marker:${r}`}),a.markers=a.markers.filter(t=>t.id!==r&&t.id!==l&&("virtual"===x.binding||t.binding!==x.binding)),a.markers.push(x);const D=new Set(c);l&&l!==r&&D.add(l),D.delete(r),D.size&&a.settings?.marker_area_snapshot&&(a.settings={...a.settings,marker_area_snapshot:si(a.settings.marker_area_snapshot,D)});let I=null;const L=l?this.host._layout[l]:null,T=L?{s:L.s||h?.space||this.host._space,x:L.x,y:L.y}:l&&h&&this.host._defPos[l]?this.host._normPos(h.space,this.host._defPos[l].x,this.host._defPos[l].y):null;if(!d&&T&&T.s===y)r===l&&this.host._layout[r]&&!C||(I={s:T.s,x:T.x,y:T.y});else if(d||!this.host._layout[r]||C){let t=v.vb[0]+v.vb[2]/2,e=v.vb[1]+v.vb[3]/2;const s=f?v.rooms.find(t=>t.id===f):g?v.rooms.find(t=>t.area===g):void 0;s&&([t,e]=this.host._roomCenter(s)),I=this.host._normPos(y,t,e)}if(this.host._serverCfg!==s||this.host._cfgRev!==i||wt(s)!==o)return this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,busy:!1}),void this.host._showToast(this.host._t("toast.conflict"));if(a=this._prepareConfigCandidate(a),$=this.host._adoption.beginOptimistic(s,a),this.host._serverCfg=a,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate(),this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.cancel(),await this._saveConfigNow($),k=!0,I){const t=ii(I);this.host._layout={...this.host._layout,[r]:t},this.host._noteLayoutRev(await this.host.hass.callWS({type:"houseplan/layout/update",device_id:r,pos:t}))}const z=new Set(c);l&&l!==r&&z.add(l),z.delete(r);for(const t of z)delete this.host._layout[t],await this.host.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this.host._noteLayoutRev(t)).catch(()=>{});S&&P&&await this.host.hass.callWS({type:"houseplan/files/cleanup",marker_id:P}).catch(()=>{}),this._closeMarkerDialog(),this.host._cancelDeviceDrag(),this.host._devicePositionHistory.clear(),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.marker_saved"))}catch(t){!k&&$&&(this.host._rollbackOptimistic($),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate()),this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteMarker(){const t=this.host._markerDialog;if(!t||t.busy||!t.devId)return;const e=t.devId?this.host._devices.find(e=>e.id===t.devId):null,s=this.host._markers.find(e=>e.id===t.devId);if(!e&&!s)return;const i=e?"virtual"===e.bindingKind?"virtual":e.bindingKind&&e.bindingRef?`${e.bindingKind}:${e.bindingRef}`:"":s.binding;if(!i)return;const o=t.name||this.host._t("device.fallback"),a=t.devId,n=await this.host._confirmDanger({key:"remove-marker",kind:"destructive",title:this.host._t("confirm.remove_marker_title"),message:this.host._t("confirm.remove_marker_body"),objectName:o,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),r=this.host._markerDialog;if(!n||!r||r.busy||r.devId!==a)return;const l=this.host._devices.find(t=>t.id===a),h=this.host._markers.find(t=>t.id===a);if(!l&&!h)return;const c=this.host._serverCfg;if(!c)return;c.markers=c.markers||[];const d=c.markers,p=l?"virtual"===l.bindingKind?"virtual":l.bindingKind&&l.bindingRef?`${l.bindingKind}:${l.bindingRef}`:"":h.binding;if(!p||p!==i)return;const u=oi(c.markers,a,p,"virtual"===p);c.markers=ai(u.markers,u.cleanupIds);const _=u.cleanupIds;_.size&&c.settings?.marker_area_snapshot&&(c.settings={...c.settings,marker_area_snapshot:si(c.settings.marker_area_snapshot,_)}),this.host._markerDialog={...r,busy:!0};try{await this._saveConfigNow();for(const t of _){delete this.host._layout[t],delete this.host._defPos[t],this.host._dirtyPos.delete(t),this.host._sentPos.delete(t);const e=this.host._activityRt.get(t);e&&clearTimeout(e.timer),this.host._activityRt.delete(t),this.host._vacRt.delete(t),delete this.host._vacSrvTrails[t],await this.host.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this.host._noteLayoutRev(t)).catch(()=>{}),await this.host.hass.callWS({type:"houseplan/files/cleanup",marker_id:t}).catch(()=>{}),await this.host.hass.callWS({type:"houseplan/trail/delete",marker_id:t}).catch(()=>{})}this.host._deviceInboxReturn&&(this.host._deviceInboxReturn={...this.host._deviceInboxReturn,tab:"readd",anchor:p}),this._closeMarkerDialog(),this.host._cancelDeviceDrag(),this.host._devicePositionHistory.clear(),this.host._infoCard?.id===a&&this.host._closeInfoCard(),this.host._selId===a&&(this.host._selId=null),this.host._drag?.id===a&&(this.host._drag=null),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.marker_removed"))}catch(t){this.host._serverCfg===c&&(c.markers=d),this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_openSpaceDialog(t,e){if(this.host._serverStorage&&this.host._serverCfg){if("edit"===t){const s=this.host._serverCfg.spaces.find(t=>t.id===e);if(!s)return;const i=m(s),o=s.settings?.custom_fill&&"object"==typeof s.settings.custom_fill?ni(s.settings.custom_fill):null,a="none"===i.fill?{...o||ri,a:0}:o;this.host._spaceDialog={mode:t,spaceId:e,title:s.title,planUrl:s.plan_url||null,planFile:null,source:s.plan_url?"file":"draw",showBorders:i.showBorders,showNames:i.showNames,zeroWallStyle:hi(s),displayTouched:!0,hideDecor:i.hideDecor,hideOpenings:i.hideOpenings,roomColor:i.color,roomOpacity:i.opacity,fillMode:"none"===i.fill?"custom":i.fill,customFill:a,glowEnabled:i.glow,bgColor:i.bgColor,bgMode:"static"===s.settings?.bg_mode||"daynight"===s.settings?.bg_mode?s.settings.bg_mode:null,northDeg:Re({},s.settings),sunRays:"boolean"==typeof s.settings?.sun_rays?s.settings.sun_rays:null,tempMin:i.tempMin,tempMax:i.tempMax,showLqi:i.showLqi??this.host._config?.show_signal??!0,cardFontScale:i.cardFontScale,labelTemp:i.labelTemp,labelHum:i.labelHum,labelLqi:i.labelLqi,labelLight:i.labelLight,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,cellCmInput:li(Number(s.cell_cm)>0?Number(s.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1}}else this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...mi(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:ui,roomOpacity:pi,fillMode:"custom",customFill:{...ri,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:di,tempMax:ci,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:_i(this.host._imperial),cellCmInput:li(_i(this.host._imperial),this.host._imperial),cellCmTouched:!1,busy:!1};this.host._spaceDialog&&Go(this.host,this.host._spaceDialog)}else this.host._showToast(this.host._t("toast.integration_missing"))}async _pickPlanFile(t){const e=t.target,s=e.files?.[0];if(!s||!this.host._spaceDialog)return;e.value="",this._decorAssetGuardReplace=null;const i=await jo(s);if("reject"===i.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===i.kind)return void(this.host._backdropGuard=i.state);const o=await qo(s,i.ext,s.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:o})}_renderBackdropGuard(){const t=this._decorAssetGuardReplace;return null!==t?Uo(this.host,()=>{},()=>{this.host._backdropGuard=null,this._decorAssetGuardReplace=null},this.host.hass,(e,s)=>this._uploadDecorImage(e,s,t),(this.host._backdropGuard?.file.size||0)<=2097152)??d:Uo(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??d}_useServerPlan(t){const e=this.host._spaceDialog;e&&(this.host._spaceDialog={...e,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let e=0;e<40;e++){const e=this.host._display(t);if(e){const s=await new Promise(t=>{const s=new Image;s.onload=()=>t(s.naturalWidth&&s.naturalHeight?s.naturalWidth/s.naturalHeight:0),s.onerror=()=>t(0),s.src=e}),i=this.host._spaceDialog;return i&&i.planUrl===t&&Number.isFinite(s)&&s>0?(this.host._spaceDialog={...i,savedAspect:s},s):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const e=this.host._spaceDialog,s=e?.saved?.find(e=>e.name===t);if(!e||!s||s.used_by.length||s.url===e.planUrl)return;const i=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),o=this.host._spaceDialog,a=o?.saved?.find(e=>e.name===t);if(i&&o&&a&&a.url===s.url&&a.modified===s.modified&&!a.used_by.length&&a.url!==o.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const e=this.host._spaceDialog;e?.saved&&(this.host._spaceDialog={...e,saved:e.saved.filter(e=>e.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return p`
    ${this.host._t("space.loading")}
    `;const e=t.saved||[];if(!e.length)return p`
    ${this.host._t("space.no_saved")}
    `;return p`
    +
    `:p``}_openingAt(t){if(!this.host._openingsR.length)return null;const e=this.host._openingsR.flatMap(e=>{const s=e.angle*Math.PI/180,i=t[0]-e.rx,o=t[1]-e.ry,a=i*Math.cos(s)+o*Math.sin(s);return Math.abs(a)>e.rlen/2+Rt(12,this.host._cellCm)?[]:[{o:e,localY:-i*Math.sin(s)+o*Math.cos(s)}]});if(!e.length)return null;const s=this.host._spaceModel();if(!s)return null;const i=this.host._openCuts(),o=this.host._openingWallIndexFor(s,i).value;return e.find(({o:t,localY:e})=>{const s="gate"===t.type?!t.flip_v:t.flip_v,i=t.partitionHost||this.host._spaceWalls.length||"gate"===t.type?this.host._openingFace(t,o,!!s):{ox:0,oy:0,cm:0,side:-1},a=zs({type:t.type,length:t.rlen,angle:t.angle,amount:this.host._openingAmt(t),flipH:!!t.flip_h,flipV:!!t.flip_v,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,face:i});return Math.abs(e)<=a.hitHalf})?.o||null}_resolveOpeningPlacement(t){const e=this.host._openingPreset;if("opening"!==this.host._tool||!e)return null;const s=this.host._spaceModel();if(!s)return null;const i=this.host._openCuts(),o=this.host._openingWallIndexFor(s,i),a=`${o.key}|partitions:${this.host._cfgEpoch}`;this.host._openingPlacementIntervalsCache&&this.host._openingPlacementIntervalsCache.key===a||(this.host._openingPlacementIntervalsCache={key:a,value:[...O(s.rooms,this.host._spaceWalls,i,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,jd),...Fs(s.partitions,this.host._cellCm,this.host._gridPitch)]}),this.host._openingDimensionContextCache&&this.host._openingDimensionContextCache.key===a||(this.host._openingDimensionContextCache={key:a,value:Sd({rooms:s.rooms,walls:this.host._spaceWalls,openCuts:i,partitions:s.partitions,roomOpenings:this.host._roomWallOpeningInputs(),partitionCuts:this._partitionOpeningCuts(s),pitch:this.host._wallKeyPitch,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,coordScale:jd,epsilon:2e-4*this.host._gridPitch})});const n=Ns({pointer:[t[0],t[1]],preset:e,geometryRevision:this.host._cfgEpoch,renderedLength:this.host._cmToUnits(e.lengthCm),intervals:this.host._openingPlacementIntervalsCache.value,baseTolerance:1.5*this.host._gridPitch,bodyPointerPadding:this._cssPxToRender("touch"===this.host._pointerModality.modality||"pen"===this.host._pointerModality.modality?10:6),gridStep:this.host._gridPitch});this.host._openingJambBlockCm=n.jambBlockedTarget?n.jambBlockedTarget.physicalHalfWidth/this.host._gridPitch*this.host._cellCm:null;const r=n.candidate;if(!r)return null;const l="gate"===r.type?!r.flipV:r.flipV;let h;if(r.host){const t=A({id:"preview",type:r.type,x:r.x/jd,y:r.y/jd,angle:r.angle,length:r.renderedLength/jd,host:r.host},s.partitions,jd,this.host._cellCm,this.host._gridPitch).resolved;h=t?As(t,l):{ox:0,oy:0,cm:0,side:-1}}else h=Es(o.value,{x:r.x,y:r.y,angle:r.angle,length:r.renderedLength,flip_v:l});const c="mi"===this.host.hass?.config?.unit_system?.length,d=zd(r,this.host._openingDimensionContextCache.value).map(t=>({x:t.label[0],y:t.label[1],text:le(t.distance/this.host._gridPitch*this.host._cellCm,c),dimension:t}));return{...r,face:h,measure:{labels:d,guide:r.measure.guide}}}_activateOpeningPlacement(t){this._activateMarkupTool("opening"),"opening"===this.host._tool&&(this.host._openingPreset=Os(t,++this.host._openingPresetRevision),this.host._openingHoverCandidate=null,this.host._cursorPt=null)}_clearOpeningPlacement(t){this.host._openingHoverCandidate=null,this.host._openingJambBlockCm=null,t&&(this.host._openingPreset=null,this.host._openingRebindId=null)}_openingClick(t){const e=this.host._spaceModel();if(!e)return;const s=this.host._openingRebindId?null:this._openingAt(t);if(s)return void this._editOpening(s);const i=this.host._openingPreset;if(!i)return;const o=this.host._openingHoverCandidate,a=o&&Bs(o,[t[0],t[1]],i.revision,this.host._cfgEpoch)?o:this._resolveOpeningPlacement(t);if(!a){if(null!=this.host._openingJambBlockCm)return void this.host._showToast(this.host._t("opening.partition_jamb_margin",{distance:le(this.host._openingJambBlockCm,this.host._imperial)}));const s=1.5*this.host._gridPitch,i=R(t,e.rooms,s);return i&&Hs(i.x,i.y,i.angle,this.host._openCuts(),s)?void this.host._showToast(this.host._t("toast.opening_on_zero_wall")):void this.host._showToast(this.host._t("toast.opening_no_wall"))}const n=this.host._openingRebindId?this.host._curSpaceCfg?.openings?.find(t=>t.id===this.host._openingRebindId):null;this.host._openingDialog={...n?{id:n.id,type:n.type,lengthCm:Math.round(n.length*jd/this.host._gridPitch*this.host._cellCm),lengthTouched:!1,contact:n.contact||"",lock:n.lock||"",invert:!!n.invert,flipH:!!n.flip_h,flipV:!!n.flip_v}:{type:a.type,lengthCm:a.lengthCm,contact:"",lock:"",invert:!1,flipH:a.flipH,flipV:a.flipV},...a.host?{host:a.host}:{},x:a.x,y:a.y,angle:a.angle},this.host._openingRebindId=null,this.host._openingHoverCandidate=null,this.host._cursorPt=null}_editOpening(t){this.host._openingDialog={id:t.id,type:t.type,lengthCm:Math.round(t.rlen/this.host._gridPitch*this.host._cellCm),lengthTouched:!1,contact:t.contact||"",lock:t.lock||"",invert:!!t.invert,flipH:!!t.flip_h,flipV:!!t.flip_v,..."partition"===t.host?.kind?{host:{...t.host}}:{},x:t.rx,y:t.ry,angle:t.angle}}_opPointerDown(t,e){if("plan"===this.host._mode&&this.host._spaceModel()&&"resize"!==this.host._tool){t.preventDefault(),t.stopPropagation();try{qd(t)}catch{}this.host._opDrag={id:e.id,moved:!1,sx:t.clientX,sy:t.clientY,dirty:!1,before:this._geometrySnapshot()}}}_opPointerMove(t,e){Dr(this.host,"opening",()=>this._opPointerMoveNow(t,e))}_opPointerMoveNow(t,e){if(!this.host._opDrag||this.host._opDrag.id!==e.id)return;if(Math.abs(t.clientX-this.host._opDrag.sx)+Math.abs(t.clientY-this.host._opDrag.sy)<=3)return;const s=this.host._spaceModel();if(!s)return;const i=this._svgPoint(t),o=this.host._curSpaceCfg,a=o?.openings?.find(t=>t.id===e.id);if(!a)return;if("partition"===a.host?.kind){const t=s.partitions.find(t=>t.id===a.host.id);if(!t)return;const e=t.b[0]-t.a[0],o=t.b[1]-t.a[1],n=Math.hypot(e,o);if(!(n>1e-9))return;const r=e/n,l=o/n;if(Math.abs((i[0]-t.a[0])*l-(i[1]-t.a[1])*r)>4*this.host._gridPitch)return;const h=a.length*jd/2+W(t,this.host._cellCm,this.host._gridPitch);let c=(i[0]-t.a[0])*r+(i[1]-t.a[1])*l;if(c=Math.round(c/this.host._gridPitch)*this.host._gridPitch,c=Math.max(h,Math.min(n-h,c)),n<2*h-1e-9)return;const d=c/n,p=(t.a[0]+r*c)/jd,u=(t.a[1]+l*c)/this.host._spaceH;let _=180*Math.atan2(o,e)/Math.PI;_>=90?_-=180:_<-90&&(_+=180);const m=a.host.t!==d||a.x!==p||a.y!==u||a.angle!==_;return this.host._opDrag.moved=!0,m&&(this.host._opDrag.dirty=!0),a.host={...a.host,t:d},a.x=p,a.y=u,a.angle=_,this.host._opMeasure=null,m&&this.host._cfgEpoch++,void this.host.requestUpdate()}const n=R(i,s.rooms,4*this.host._gridPitch);if(!n)return;this.host._opDrag.moved=!0;const r=this._opRuler(n,a.length*jd);this.host._opMeasure=r.measure;const l=r.x/jd,h=r.y/this.host._spaceH,c=a.x!==l||a.y!==h||a.angle!==n.angle;if(c&&(this.host._opDrag.dirty=!0),a.x=l,a.y=h,a.angle=n.angle,Number(this.host._serverCfg?.model_version||0)>=9){const t=Bn(a,o?.wall_segments||[]);t?a.host=t:delete a.host}c&&this.host._cfgEpoch++,this.host.requestUpdate()}_opRuler(t,e){const s=this.host._spaceModel()?.rooms||[],i=this.host._gridPitch/2;let o=t.x,a=t.y,n=Ws([o,a],t.angle,e,s,i);if(n&&n.centered&&(o!==n.wallCenter[0]||a!==n.wallCenter[1]))[o,a]=n.wallCenter,n=Ws([o,a],t.angle,e,s,i);else if(n){const[r,l]=n.wallA,[h,c]=n.wallB,d=h-r,p=c-l,u=Math.hypot(d,p);if(u>0){const h=this.host._gridPitch,c=Math.min(e/2,u/2);let _=Math.round(((o-r)*d+(a-l)*p)/u/h)*h;_=Math.max(c,Math.min(u-c,_)),o=r+_/u*d,a=l+_/u*p,n=Ws([o,a],t.angle,e,s,i)||n}}if(!n)return{x:o,y:a,angle:t.angle,measure:null};const r="mi"===this.host.hass?.config?.unit_system?.length,l=(t,e)=>({x:e[0],y:e[1],text:le(t/this.host._gridPitch*this.host._cellCm,r)});return{x:o,y:a,angle:t.angle,measure:{labels:[l(n.sideA,n.midA),l(n.sideB,n.midB)],guide:n.centered?{x:n.wallCenter[0],y:n.wallCenter[1],angle:t.angle}:null}}}_opPointerUp(t,e){if(!this.host._opDrag||this.host._opDrag.id!==e.id)return;Ir(this.host,"opening");const s=this.host._opDrag,i=s.moved;this.host._opMeasure=null,i&&s.dirty&&this._commitPhysicalGeometry(this.host._t("history.move_opening"),s.before);const o=()=>{this.host._opDrag=null,this.host.requestUpdate()};i?window.setTimeout(o,0):o()}_opClick(t,e){"plan"===this.host._mode&&"resize"===this.host._tool||(t.stopPropagation(),this.host._opDrag?.moved||"plan"===this.host._mode&&this._editOpening(e))}_saveOpening(){const t=this.host._openingDialog,e=this.host._curSpaceCfg,s=this.host._spaceModel();if(!t||!e||!s)return;const i=this._geometrySnapshot(),o=this.host._spaceH,a=(e.openings||[]).find(e=>e.id===t.id),n={...a||{},id:t.id||"o"+Date.now().toString(36),type:t.type,x:t.x/jd,y:t.y/o,angle:t.angle,length:a&&!t.lengthTouched?a.length:this.host._cmToUnits(Math.max(20,t.lengthCm))/jd,...t.host?{host:{...t.host}}:{}};if("partition"===n.host?.kind){const t=js(a,n)?q(n,s.partitions,jd,this.host._cellCm,this.host._gridPitch):A(n,s.partitions,jd,this.host._cellCm,this.host._gridPitch);if(!t.resolved){const e=s.partitions.find(t=>t.id===n.host.id);if("does-not-fit-jamb"===t.reason&&e){const t=W(e,this.host._cellCm,this.host._gridPitch);this.host._showToast(this.host._t("opening.partition_jamb_margin",{distance:le(t/this.host._gridPitch*this.host._cellCm,this.host._imperial)}))}else this.host._showToast(this.host._t("opening.partition_orphan"));return}const i=(e.openings||[]).flatMap(t=>{if(!t.host||t.id===n.id)return[];const e=A(t,s.partitions,jd,this.host._cellCm,this.host._gridPitch).resolved;return e?[e]:[]});if(Gs(t.resolved,i))return void this.host._showToast(this.host._t("toast.opening_no_wall"));Object.assign(n,E(n,t.resolved,jd))}else if(Number(this.host._serverCfg?.model_version||0)>=9){const t=Bn(n,e.wall_segments||[]);if(!t)return void this.host._showToast(this.host._t("toast.opening_no_wall"));n.host=t}else delete n.host;"passage"===t.type?(delete n.contact,delete n.lock,delete n.invert,delete n.flip_h,delete n.flip_v):(n.contact=t.contact||null,n.lock=("door"===t.type||"gate"===t.type)&&t.lock||null,n.invert=t.invert||void 0,n.flip_h="gate"!==t.type&&t.flipH||void 0,n.flip_v=t.flipV||void 0),e.openings=e.openings||[];const r=e.openings.findIndex(t=>t.id===n.id);r>=0?e.openings[r]=n:e.openings.push(n),this._commitPhysicalGeometry(this.host._t(t.id?"history.edit_opening":"history.add_opening"),i),this.host._openingDialog=null,this.host.requestUpdate()}_deleteOpening(){const t=this.host._openingDialog,e=this.host._curSpaceCfg;if(!t?.id||!e?.openings)return;const s=this._geometrySnapshot();e.openings=e.openings.filter(e=>e.id!==t.id),this._commitPhysicalGeometry(this.host._t("history.delete_opening"),s),this.host._openingDialog=null,this.host.requestUpdate()}_contactCandidates(){const t=[];for(const e of Object.keys(this.host.hass.states)){if(!this.host._openingEntityAvailable(e))continue;const s=e.split(".")[0];if("binary_sensor"!==s&&"cover"!==s)continue;const i=this.host.hass.states[e],o=["door","window","opening","garage_door","garage"].includes(i?.attributes?.device_class||"");("cover"!==s||o)&&t.push([e,i?.attributes?.friendly_name||e,o?0:1])}return t.sort((t,e)=>t[2]-e[2]||t[1].localeCompare(e[1])).map(([t,e])=>({value:t,label:e}))}_lockCandidates(){return Object.keys(this.host.hass.states).filter(t=>t.startsWith("lock.")&&this.host._openingEntityAvailable(t)).map(t=>({value:t,label:this.host.hass.states[t]?.attributes?.friendly_name||t})).sort((t,e)=>t.label.localeCompare(e.label))}_toggleOpeningEntityPicker(t){const e=this.host._openingDialog;if(!e)return;const s="contact"===t?!e.contactOpen:!e.lockOpen;this.host._openingDialog={...e,contactOpen:"contact"===t&&s,lockOpen:"lock"===t&&s}}_filterOpeningEntities(t,e){const s=this.host._openingDialog;s&&(this.host._openingDialog="contact"===t?{...s,contactFilter:e}:{...s,lockFilter:e})}_selectOpeningEntity(t,e){const s=this.host._openingDialog;s&&(this.host._openingDialog="contact"===t?{...s,contact:e,contactOpen:!1,contactFilter:""}:{...s,lock:e,lockOpen:!1,lockFilter:""})}_mergeClick(t){const e=this.host._spaceModel();if(!e)return;const s=e.rooms,i=[...s].reverse().find(e=>this._pointInRoom(t,e));if(!i?.id)return;const o=i.id;if(!this.host._mergeSel||this.host._mergeSel===o)return void(this.host._mergeSel=this.host._mergeSel===o?null:o);const a=s.find(t=>t.id===this.host._mergeSel),n=a?N(a):null,r=N(i),l=n&&r?qs(n,r):null;if(!l)return this.host._showToast(this.host._t("toast.merge_not_adjacent")),void(this.host._mergeSel=null);this.host._mergeDialog={aId:this.host._mergeSel,bId:o,poly:l,pick:"a"},this.host._mergeSel=null}_commitMerge(){const t=this.host._mergeDialog,e=this.host._curSpaceCfg;if(!t||!e||!this.host._spaceModel())return;const s=this._geometrySnapshot(),i=this.host._spaceH,o="a"===t.pick?t.aId:t.bId,a="a"===t.pick?t.bId:t.aId,n=Od(this.host._serverCfg?.markers||[],{kind:"merge",dropId:a,keepId:o});s&&n.changed&&(s.roomReferences=n.before);const r=e.rooms.find(t=>t.id===o);if(!r)return void(this.host._mergeDialog=null);r.poly=t.poly.map(t=>[t[0]/jd,t[1]/i]),delete r.x,delete r.y,delete r.w,delete r.h,e.rooms=e.rooms.filter(t=>t.id!==a),n.changed&&this.host._serverCfg&&(this.host._serverCfg.markers=n.markers);const l=this._commitPhysicalGeometry(this.host._t("history.merge_rooms"),s);this.host._mergeDialog=null,this.host._regSignature="",this.host._maybeRebuildDevices(),l&&this.host._showToast(this.host._t("toast.rooms_merged",{name:r.name||""}))}_splitClick(t){const e=this.host._spaceModel();if(!e)return;const s=e.rooms;if(!this.host._splitSel){const e=[...s].reverse().find(e=>this._pointInRoom(t,e));if(!e?.id)return;return void(this.host._splitSel={roomId:e.id,pts:[]})}const i=s.find(t=>t.id===this.host._splitSel.roomId),o=i?N(i):null;if(!i||!o)return void(this.host._splitSel=null);const a=.02*this.host._gridPitch,n=6*this.host._gridPitch,r=Us(t,o),l=r&&Ks(r,o,this.host._gridPitch)||r,h=r&&l&&Math.hypot(r[0]-t[0],r[1]-t[1])<=n?l:null,c=!!h&&Vs(h,o,a),d=this.host._splitSel.pts;if(!d.length)return c?void(this.host._splitSel={...this.host._splitSel,pts:[h]}):void this.host._showToast(this.host._t("toast.split_pick_wall"));if(!c){const e=this._snap(t);return Je(e,o,a)?void(this.host._splitSel={...this.host._splitSel,pts:[...d,e]}):void this.host._showToast(this.host._t("toast.split_pick_inside"))}const p=Ye(o,[...d,h],a);if(!p)return void this.host._showToast(this.host._t("toast.split_bad_cut"));this._resetRoomDialogFields();const[u,_]=p,m=Zt(u)>=Zt(_)?u:_,g=m===u?_:u;this.host._pendingSplit={roomId:i.id,mainPoly:m,newPoly:g},this.host._cursorPt=null,this.host._nameSel="",this.host._areaSel="",this.host._roomDialog=!0}_markupMove(t){if(!this.host._markup)return;if("column"===this.host._tool)return void(this.host._cursorPt=this._snap(this._svgPoint(t)));if("opening"===this.host._tool||"wallthick"===this.host._tool)return void(this.host._cursorPt=this._svgPoint(t));const e="draw"===this.host._tool&&!this.host._contourClosed,s="split"===this.host._tool&&!!this.host._splitSel?.pts?.length;if(!e&&!s)return;const i=this._svgPoint(t);if(e){const e=this._resolvePlanDrawPoint(i,t.shiftKey);if(this.host._planSnapHover={contextKey:e.contextKey,candidate:e.candidate,conflicts:e.conflicts},this._syncPlanSnapConflictMarkers(e.conflicts),this._syncPlanSnapActiveMarker(e.candidate),!this.host._path.length)return;return void(this.host._cursorPt=e.point)}this.host._cursorPt=this._snap(i)}_saveRoom(){(this.host._areaSel||this.host._nameSel.trim())&&Mt(this.host._roomTempMin,this.host._roomTempMax).valid&&(this.host._wallFaceBatch?this._decideWallFace(!0):this._commitRoom())}_decideWallFace(t){const e=this.host._wallFaceBatch;if(!e)return;const s=e.candidates[e.index];if(!s)return;if(!t&&(s.existing||s.repair)&&1===e.candidates.length)return this.host._wallFaceBatch=null,this.host._roomDialog=!1,this.host._nameSel="",this.host._areaSel="",void this.host.requestUpdate();const i=t?{candidate:s,create:!0,name:this.host._nameSel.trim(),area:this.host._areaSel||null,settings:this._roomSettingsFromDialog()?JSON.parse(JSON.stringify(this._roomSettingsFromDialog())):null}:{candidate:s,create:!1},o=[...e.decisions,i],a=e.index+1;if(a"number"==typeof t&&Number.isFinite(t)&&t>=0?t:null,o=.02*this.host._gridPitch,a=this.host._spaceModel();if(!a)return B;for(const e of this._planSnapGeometrySnapshot().value.segments)if(!("room"===e.sourceKind||de(t,[e.a[0],e.a[1],e.b[0],e.b[1]])>o)&&"partition"===e.sourceKind)return i(a.partitions.find(t=>t.id===e.sourceId)?.cm)??B;const n=kc(Math.max(0,e.length-1),s,this.host._drawWallCm,B);for(let s=0;s+1[...t]);if(!e)return s;const i=this.host._activeWallChainPartitionIds.findIndex((t,s)=>this._activeWallSourceKey(s)===e.sourceKey),o=i>=0?i+("b"===e.endpoint?1:0):-1;return o>=0&&oe.key===t.sourceKey),a=i.find(e=>e.key===t.targetSourceKey);if(!o||!a)return!1;const n="a"===t.endpoint?o.a:o.b;return!(Math.hypot(n[0]-t.from[0],n[1]-t.from[1])>s)&&(!(de(t.to,[a.a[0],a.a[1],a.b[0],a.b[1]])>s)&&!function(t,e){if(!t.sourceKey.startsWith("static:partition|"))return!1;const s=t.sourceKey.slice(17).split("|")[0];return!!s&&e.some(t=>"partition"===t.host?.kind&&t.host.id===s)}(t,this.host._curSpaceCfg?.openings||[]))}_applyWallRepair(t,e){const s=this.host._curSpaceCfg;if(!s||!this._validateWallRepair(t,e.activePath))return!1;if(!t.sourceKey.startsWith("static:"))return!1;const[i,o]=t.sourceKey.slice(7).split("|");if("partition"===i){const i=(s.partitions||[]).find(t=>t.id===o);if(!i)return!1;const a=[i.a[0]*jd,i.a[1]*jd],n=[i.b[0]*jd,i.b[1]*jd],r=Math.hypot(a[0]-t.from[0],a[1]-t.from[1])<=2e-4*this.host._gridPitch?i.a:Math.hypot(n[0]-t.from[0],n[1]-t.from[1])<=2e-4*this.host._gridPitch?i.b:null;if(!r)return!1;(e=>{e[0]=t.to[0]/jd,e[1]=t.to[1]/jd})(r);const l=e.activePartitionIds.indexOf(o);if(l>=0){const s=l+("b"===t.endpoint?1:0);e.activePath[s]&&(e.activePath[s]=[...t.to])}return!0}return!1}_applyWallFaceBatch(){const t=this.host._wallFaceBatch,e=this.host._curSpaceCfg,s=this.host._spaceModel();if(!t||!e||!s)return;const i=(t,e)=>{this.host._showToast(this.host._t(t,e)),this._roomDialogCancel()},o=t.decisions.filter(t=>t.create),a=o.map(t=>t.candidate.ring),n=s.rooms;for(let t=0;ts.id!==e&&!!N(s)&&Vt(a[t],N(s)));if(s)return void i("toast.room_overlap",{name:s.name||""})}if((e.rooms||[]).length+o.length>400)return void i("toast.physical_limit");if(o.some(t=>t.candidate.split&&!e.rooms.some(e=>e.id===t.candidate.split.roomId)))return void i("toast.contour_cannot_close");const r=o.map(t=>t.candidate.repair).filter(t=>!!t);if(r.length>1||r[0]&&!this._validateWallRepair(r[0],t.activePath))return void i("toast.wall_repair_changed");if(this._activePathWithRepair(t.activePath,r[0]),!o.length){if(!this._finalizeWallChainPartitions(t.activePartitionIds))return;return this.host._path=[],this.host._activeWallChainId=null,this.host._activeWallChainPartitionIds=[],this.host._wallChainSegmentCms=[],this.host._wallChainRedo=[],this.host._closingWallCm=null,this.host._wallFaceBatch=null,this.host._roomDialog=!1,this.host._nameSel="",this.host._areaSel="",this.host.requestUpdate(),void this.host._showToast(this.host._t("toast.wall_chain_saved"))}const l=new Set(t.activePartitionIds),h=2e-4*this.host._gridPitch,c=o.map(t=>t.candidate.ring.map((t,e,i)=>{const o=i[(e+1)%i.length],a=s.partitions.filter(e=>{const s=Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1]);if(!(s>h))return!1;const i=(e.b[0]-e.a[0])/s,a=(e.b[1]-e.a[1])/s,n=t=>(t[0]-e.a[0])*i+(t[1]-e.a[1])*a;return de(t,[e.a[0],e.a[1],e.b[0],e.b[1]])<=h&&de(o,[e.a[0],e.a[1],e.b[0],e.b[1]])<=h&&n(t)>=-h&&n(t)<=s+h&&n(o)>=-h&&n(o)<=s+h});return a.sort((t,e)=>Number(l.has(e.id))-Number(l.has(t.id))||Math.hypot(t.b[0]-t.a[0],t.b[1]-t.a[1])-Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])||t.id.localeCompare(e.id)),a[0]?.id||""})),d=this._geometrySnapshot();if(!d)return void i("toast.geometry_unsafe");const p=()=>{this._restoreGeometryStateLocal(d),i("toast.geometry_unsafe")};if(r[0]&&!this._applyWallRepair(r[0],t))return void i("toast.wall_repair_changed");const u=o.some(t=>!!t.candidate.split),_=u?Pe(s.rooms,e.walls,this.host._openCuts(),this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,jd):null,m=u&&Array.isArray(e.walls)?e.walls:null;for(const t of o){const s=t.candidate.split;if(!s)continue;const i=e.rooms.find(t=>t.id===s.roomId);if(!i)return void p();i.poly=s.mainPoly.map(t=>[t[0]/jd,t[1]/this.host._spaceH]),delete i.x,delete i.y,delete i.w,delete i.h}const g=Date.now().toString(36),f=[];if(o.forEach((t,s)=>{const i=t.area?this.host.hass.areas[t.area]?.name:"",o={id:`r${g}-${s}`,name:t.name||i||this.host._t("room.default_name"),area:t.area||null,poly:t.candidate.ring.map(t=>[t[0]/jd,t[1]/this.host._spaceH]),...c[s].some(Boolean)?{wall_ids:c[s]}:{},...t.settings?{settings:JSON.parse(JSON.stringify(t.settings))}:{}};e.rooms.push(o),f.push({room:o,decision:t})}),u){const t=this.host._normalizeWalls(_,this.host._openCuts());t.length?e.walls=t:m?.length?e.walls=m:delete e.walls}if(f.length){this.host._cfgEpoch++;const s=this.host._openCuts(),i=this.host._spaceModel();if(!i)return void p();let o=e.walls;for(const{room:e,decision:a}of f){const n=a.candidate.ring,r=this._wallSourceCmAt(n[0],t.activePath,t.activeCms);o=Js(o,i.rooms,e.id,r,this.host._wallKeyPitch,s,jd);for(const a of O(i.rooms,o,s,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,jd)){if(a.roomId!==e.id||"outer"!==a.kind)continue;const s=[(a.a[0]+a.b[0])/2,(a.a[1]+a.b[1])/2];o=j(o,a.a,a.b,this._wallSourceCmAt(s,t.activePath,t.activeCms),this.host._wallKeyPitch,jd)}}const a=this.host._normalizeWalls(o,s);a.length?e.walls=a:delete e.walls,this.host._cfgEpoch++;const n=this.host._spaceModel();if(!n)return void p();const r=pn(e,n,e.walls,s,{pitch:this.host._wallKeyPitch,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,coordScale:jd,allowCoincidentPartitions:!0});r.walls.length?e.walls=r.walls:delete e.walls,r.partitions.length?e.partitions=r.partitions:delete e.partitions,r.openings.length?e.openings=r.openings:delete e.openings}if(!this._commitPhysicalGeometry(this.host._t("history.wall_face_batch"),d))return;this.host._path=[],this.host._activeWallChainId=null,this.host._activeWallChainPartitionIds=[],this.host._wallChainSegmentCms=[],this.host._wallChainRedo=[],this.host._closingWallCm=null,this.host._wallFaceBatch=null,this.host._roomDialog=!1,this.host._nameSel="",this.host._areaSel="",this.host._regSignature="",this.host._maybeRebuildDevices();const b=new Set(o.map(t=>t.area).filter(t=>!!t));if(b.size){const t={...this.host._layout};for(const e of this.host._devices){if(!b.has(e.area||"")||e.space!==this.host._space)continue;if(this.host._layout[e.id])continue;const s=this.host._defPos[e.id];s&&(t[e.id]={s:this.host._space,x:s.x/jd,y:s.y/jd},this.host._dirtyPos.add(e.id))}this.host._layout=t,this.host._persistLayout()}this.host._showToast(this.host._t(o.length?"toast.wall_rooms_saved":"toast.wall_chain_saved",{n:o.length}))}_commitRoom(){const t=this.host._curSpaceCfg,e=this.host._spaceModel();if(!t||!e)return;const s=this._geometrySnapshot();if(!s)return;const i=()=>{this._restoreGeometryStateLocal(s),this.host._showToast(this.host._t("toast.geometry_unsafe"))},o=this.host._spaceH,a=!!this.host._pendingSplit,n=a?Pe(e.rooms,t.walls,this.host._openCuts(),this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,jd):null,r=a&&Array.isArray(t.walls)?t.walls:null;let l;if(this.host._pendingSplit){const e=t.rooms.find(t=>t.id===this.host._pendingSplit.roomId);if(!e)return this.host._pendingSplit=null,this.host._splitSel=null,void(this.host._roomDialog=!1);e.poly=this.host._pendingSplit.mainPoly.map(t=>[t[0]/jd,t[1]/o]),delete e.x,delete e.y,delete e.w,delete e.h,l=this.host._pendingSplit.newPoly}else{if(!this.host._contourClosed)return;l=this.host._path.slice(0,-1)}const h=this.host._areaSel?this.host.hass.areas[this.host._areaSel]?.name:"",c={id:"r"+Date.now().toString(36),name:this.host._nameSel||h||this.host._t("room.default_name"),area:this.host._areaSel||null,poly:l.map(t=>[t[0]/jd,t[1]/o]),...this._roomSettingsFromDialog()?{settings:this._roomSettingsFromDialog()}:{}};if(t.rooms.push(c),a){const e=this.host._normalizeWalls(n,this.host._openCuts());e.length?t.walls=e:r?.length?t.walls=r:delete t.walls}if(!a){const e=kc(l.length,[...this.host._wallChainSegmentCms,this.host._closingWallCm??void 0],this.host._drawWallCm,B),s=e[0];if(null!=s){this.host._cfgEpoch++;const o=this.host._openCuts(),a=this.host._spaceModel();if(!a)return void i();let n=Js(t.walls,a.rooms,c.id,s,this.host._wallKeyPitch,o,jd);for(const t of O(a.rooms,n,o,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,jd)){if(t.roomId!==c.id||"outer"!==t.kind)continue;const s=[(t.a[0]+t.b[0])/2,(t.a[1]+t.b[1])/2],i=l.findIndex((t,e)=>{const i=l[(e+1)%l.length];return de(s,[t[0],t[1],i[0],i[1]])<=.02*this.host._gridPitch});i>=0&&(n=j(n,t.a,t.b,e[i],this.host._wallKeyPitch,jd))}n=this.host._normalizeWalls(n,o),n.length?t.walls=n:delete t.walls;const r=this.host._spaceModel();if(!r)return void i();const h=pn(t,r,t.walls,o,{pitch:this.host._wallKeyPitch,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch,coordScale:jd,allowCoincidentPartitions:!0});h.walls.length?t.walls=h.walls:delete t.walls,h.partitions.length?t.partitions=h.partitions:delete t.partitions,h.openings.length?t.openings=h.openings:delete t.openings}}const d=this._commitPhysicalGeometry(this.host._t(a?"history.split_room":"history.add_room"),s);this.host._path=[],this.host._activeWallChainId=null,this.host._activeWallChainPartitionIds=[],this.host._wallChainSegmentCms=[],this.host._wallChainRedo=[],this.host._closingWallCm=null,this.host._pendingSplit=null,this.host._splitSel=null;const p=this.host._areaSel;if(this.host._areaSel="",this.host._nameSel="",this.host._roomDialog=!1,this.host._regSignature="",this.host._maybeRebuildDevices(),!d)return;let u=0;if(p){const t=jd,e={...this.host._layout};for(const s of this.host._devices){if(s.area!==p||s.space!==this.host._space)continue;if(u++,this.host._layout[s.id])continue;const i=this.host._defPos[s.id];i&&(e[s.id]={s:this.host._space,x:i.x/jd,y:i.y/t},this.host._dirtyPos.add(s.id))}this.host._layout=e,this.host._persistLayout()}const _=this.host._model.find(t=>t.id===this.host._space)?.rooms.length||0;this.host._showToast(p?this.host._t("toast.room_saved",{n:_,added:u}):this.host._t("toast.room_saved_no_area",{n:_}))}_cancelPath(){this.host._wallRepairDiagnostic=null,this.host._path=[],this.host._activeWallChainId=null,this.host._activeWallChainPartitionIds=[],this.host._wallChainSegmentCms=[],this.host._wallChainRedo=[],this.host._closingWallCm=null,this._clearPlanSnapHover(),this.host._roomDialog=!1,this.host._pendingSplit=null,this.host._wallFaceBatch=null,this.host._splitSel=null,this.host._mergeSel=null,this.host._mergeDialog=null,this.host._physicalSel=null,this.host._physicalDrag=null,this.host._physicalRotate=null,this._clearOpeningPlacement(!0)}_roomDialogCancel(){if(this.host._roomDialog=!1,this.host._roomEditId)return this.host._roomEditId=null,this.host._nameSel="",void(this.host._areaSel="");if(this.host._wallFaceBatch){const t=this.host._wallFaceBatch;return this.host._wallFaceBatch=null,this.host._path=t.activePath.map(t=>[...t]),this.host._wallChainSegmentCms=[...t.activeCms],this.host._activeWallChainPartitionIds=[...t.activePartitionIds],this.host._activeWallChainId||=`chain-${Date.now().toString(36)}`,this.host._nameSel="",this.host._areaSel="",void this.host.requestUpdate()}if(this.host._pendingSplit)return this.host._pendingSplit=null,void(this.host._splitSel=null);this.host._undoPoint()}_openDeviceInbox(){this.host._deviceInboxReturn=null,this.host._deviceInbox=this.host._deviceInbox||{tab:"on_plan",search:"",showEntities:!1,onlyNew:!1,limit:100}}_closeMarkerDialog(){this._radarSetup.isDirty()?this._closeMarkerDialogGuarded():(this._radarSetup.reset(),function(t){if(t._markerDialog=null,!t._deviceInboxReturn)return;const e={...t._deviceInboxReturn};t._deviceInbox=e,t._deviceInboxReturn=null,e.anchor&&t.updateComplete.then(()=>requestAnimationFrame(()=>{const s=`.device-inbox-row[data-binding="${CSS.escape(e.anchor)}"]`;t.renderRoot.querySelector(s)?.scrollIntoView({block:"nearest"})}))}(this.host))}async _closeMarkerDialogGuarded(){if(!await this._radarSetup.discardIfAllowed())return await this.host.updateComplete,void this.host.renderRoot.querySelector("#marker-dialog")?.rejectClose();this._closeMarkerDialog()}_deviceInboxCandidates(t){return Xh({hass:this.host._planHass,devices:this.host._devices,markers:this.host._markers,showEntities:t,labels:{device:this.host._t("marker.sub_device"),z2mGroup:this.host._t("marker.sub_z2m_group"),group:this.host._t("marker.sub_group"),helper:this.host._t("marker.sub_helper"),entity:this.host._t("marker.sub_entity")}})}_deviceInboxRows(){const t=this.host._deviceInbox||this.host._deviceInboxReturn,e=!!t?.showEntities,s=[this.host._haRegistry.revision,this.host._cfgRev,this.host._cfgEpoch,this.host._regSignature,this.host._newSyncKey,e?1:0,this.host._showAll?1:0,l(this.host.hass,this.host._config?.language)].join("|");if(this.host._deviceInboxMemo?.key===s)return this.host._deviceInboxMemo.rows;const i=this._deviceInboxCandidates(e),o=new Set(i.map(t=>t.value));for(const t of this.host._markers)t.binding&&"virtual"!==t.binding&&o.add(t.binding);for(const t of this.host._devices)t.bindingKind&&"virtual"!==t.bindingKind&&t.bindingRef&&o.add(`${t.bindingKind}:${t.bindingRef}`);const a=new Map;for(const t of o)a.set(t,this.host._bindingStatus(t));const n=this.host._areaToSpace,r={};for(const[t,e]of Object.entries(this.host.hass?.areas||{}))r[t]=n[t]?.room?.name||e?.name||t;for(const[t,e]of Object.entries(n))r[t]=e.room.name||r[t]||t;const h=Object.fromEntries(this.host._model.map(t=>[t.id,t.title])),c=Object.fromEntries(Object.entries(n).map(([t,e])=>[t,e.space])),d={},p=new Map;for(const[t,e]of Object.entries(this.host._fullRegistryHass.entities||{})){const s=String(e?.platform||"").trim();if(s&&(d[`entity:${t}`]=s),s&&e?.device_id){const t=p.get(e.device_id)||new Set;t.add(s),p.set(e.device_id,t)}}for(const[t,e]of p)d[`device:${t}`]=[...e].sort().join(", ");const u={};for(const[t,e]of Object.entries(this.host._fullRegistryHass.devices||{})){const s=`device:${t}`,i=p.get(t)||new Set,o=Array.isArray(e?.identifiers?.[0])?String(e.identifiers[0][0]||""):"";o&&!d[s]&&(d[s]=o);const a=[o,...i].some(t=>this.host._excluded.has(t));"service"===e?.entry_type?u[s]="service_entry":a?u[s]="excluded_integration":"Group"===e?.model?u[s]="grouped_light":/scene/i.test(e?.model||"")?u[s]="excluded_domain":(/bridge/i.test(`${e?.model||""}${e?.name||""}`)||"myheat"===o&&e?.via_device_id)&&(u[s]="represented_by_parent")}const _=function(t){const{devices:e,markers:s,candidates:i,statuses:o,newDeviceIds:a,showHiddenOnPlan:n,areaNames:r={},spaceNames:l={},spaceByArea:h={},integrationByBinding:c={},reasonByBinding:d={}}=t,p=new Map;for(const t of e)!t.virtual&&t.bindingKind&&"virtual"!==t.bindingKind&&t.bindingRef&&p.set(`${t.bindingKind}:${t.bindingRef}`,t);const u=new Map,_=new Map;for(const t of s)t?.binding&&"virtual"!==t.binding&&(t.removed?_.set(t.binding,t):u.set(t.binding,t));const m=new Map(i.map(t=>[t.value,t])),g=new Set([...p.keys(),...u.keys(),...m.keys(),...[..._.keys()].filter(t=>m.has(t))]),f=[];for(const t of g){const e=p.get(t),s=u.get(t),i=s?void 0:_.get(t),g=m.get(t);let b;if(i&&g)b="readd";else if(!0===s?.hidden)b="hidden";else if(e||s)b="on_plan";else{if(!g)continue;b="available"}const v=e?.bindingStatus||o.get(t)||Qh,y=s||i,w=tc(t),$=e?.area||g?.areaId||y?.area||"",k=e?.space||y?.space||h[$]||"",x=e?.name||y?.name||g?.label||t,M=e?.model||y?.model||g?.model||"",C=!!g?.parentDeviceId&&p.has(`device:${g.parentDeviceId}`),S="readd"===b?"removed":"hidden"===b?s&&ec(s)?d[t]||"automatic_hidden":"manual_hidden":"on_plan"===b?s?"visible_explicit":"visible_auto":d[t]||(C?"represented_by_parent":$&&k?"available":"no_bound_room"),P=!!e&&(!e.hidden||n),D="active"===v.kind,I=P&&(D||"ha_disabled"===v.kind&&n),L=[x,M,c[t],r[$],l[k],t,g?.sub].filter(Boolean).join(" ").toLocaleLowerCase();f.push({key:t,binding:t,category:b,status:v,reason:S,deviceId:e?.id,markerId:y?.id,name:x,icon:e?.icon||y?.icon||("entity"===w?"mdi:code-braces":"mdi:devices"),model:M,integration:c[t]||"",areaId:$,areaName:r[$]||"",spaceId:k,spaceName:l[k]||"",kind:w,isNew:!!e&&a.has(e.id),searchText:L,canFind:I,canEdit:!!e||!!s,canHide:"on_plan"===b&&D,canShow:"hidden"===b&&D,canAdd:("available"===b||"readd"===b)&&D})}const b=t=>"active"===t.status.kind?1:0;return f.sort((t,e)=>t.category.localeCompare(e.category)||Number(e.isNew)-Number(t.isNew)||b(t)-b(e)||t.name.localeCompare(e.name)||t.binding.localeCompare(e.binding))}({devices:this.host._devices,markers:this.host._markers,candidates:i,statuses:a,newDeviceIds:this.host._newIds,showHiddenOnPlan:this.host._showAll,areaNames:r,spaceNames:h,spaceByArea:c,integrationByBinding:d,reasonByBinding:u});return this.host._deviceInboxMemo={key:s,rows:_},_}_deviceForInboxRow(t){const e=t.deviceId?this.host._devices.find(e=>e.id===t.deviceId):null;if(e)return e;const s=t.markerId?this.host._markers.find(e=>e.id===t.markerId):null;return!s||s.removed?null:{id:s.id,name:t.name,model:t.model,area:t.areaId,space:t.spaceId||this.host._space,hidden:!0===s.hidden||"ha_disabled"===t.status.kind,userHidden:!0===s.hidden,bindingStatus:t.status,icon:t.icon,entities:"active"===t.status.kind?t.status.enabledEntityIds:[],allEntities:t.status.allEntityIds,primary:"active"===t.status.kind?t.status.enabledEntityIds[0]:void 0,marker:s,bindingKind:t.kind,bindingRef:t.binding.slice(t.binding.indexOf(":")+1),pdfs:s.pdfs||[]}}_openInboxMarker(t,e=!1){const s=this.host._deviceInbox;if(s){if(this.host._deviceInboxReturn={...s,anchor:t.key},this.host._deviceInbox=null,!e){const e=this._deviceForInboxRow(t);return void(e?this._openMarkerDialog(e):this._closeMarkerDialog())}this._openMarkerDialog(),this.host._markerDialog?this.host._markerDialog={...this.host._markerDialog,bindingMode:"ha",binding:t.binding,bindingOpen:!1,showEntities:"entity"===t.kind,name:""}:this._closeMarkerDialog()}}async _setInboxHidden(t,e){const s=this.host._deviceInbox,i=this.host._serverCfg;if(!s||!i||s.busy||"active"!==t.status.kind)return;const o=i.markers||[],a=o.find(e=>!e.removed&&e.binding===t.binding);if(!e&&!a)return;const n=a?.id||Zs(t.binding,t.markerId,()=>`m_${Date.now().toString(36)}`),r=a?{...a,hidden:e}:{id:n,binding:t.binding,hidden:!0};i.markers=[...o.filter(e=>e.id!==n&&(e.binding!==t.binding||!0===e.removed)),r],this.host._deviceInbox={...s,busy:t.key,anchor:t.key};try{await this._saveConfigNow(),this.host._regSignature="",this.host._deviceInboxMemo=null,this.host._maybeRebuildDevices(),this.host._deviceInbox&&(this.host._deviceInbox={...this.host._deviceInbox,busy:void 0}),this.host._showToast(this.host._t("device_inbox.saved"))}catch(t){this.host._serverCfg===i&&(i.markers=o),this.host._deviceInbox&&(this.host._deviceInbox={...this.host._deviceInbox,busy:void 0}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_findInboxDevice(t){if(!t.canFind)return;const e=this._deviceForInboxRow(t);if(!e)return;if(this.host._deviceInbox=null,e.space&&e.space!==this.host._space){if(!this.host._commitSpace(e.space))return;this.host._restoreZoom()}const s=()=>{const t=this.host._devices.find(t=>t.id===e.id)||e,s=this.host._pos(t);this.host._applyView(this.host._zoom,s.x,s.y),this.host._selId=t.id,this.host.requestUpdate(),window.setTimeout(()=>{this.host._selId===t.id&&(this.host._selId=null,this.host.requestUpdate())},1500)};requestAnimationFrame(()=>requestAnimationFrame(s))}_openMarkerDialog(t){if(this.host._vacAllCamerasFor=null,this.host._vacAllCameraCache=null,t&&this.host._ackNewDevice(t.id),this.host._norm){if(t){const e=t.marker,s=Object.prototype.hasOwnProperty.call(e||{},"is_light"),i=Object.prototype.hasOwnProperty.call(e||{},"light_entity"),o=Object.prototype.hasOwnProperty.call(e||{},"glow_color"),a=Object.prototype.hasOwnProperty.call(e||{},"value_badge"),n=Object.prototype.hasOwnProperty.call(e||{},"value_source"),r=Object.prototype.hasOwnProperty.call(e||{},"tap_action"),l=Object.prototype.hasOwnProperty.call(e||{},"toggle_entity"),h=Ys(e?.glow_color),c=this.host._devicePresentation(t,!0).valueBadge,d=g(this.host._planHass,t,this.host._devices),p=f(this.host._planHass,t,d),u=xa(t,this.host._fullRegistryHass),_=this.host._spaceModelById(t.space)||this.host._spaceModel(),m=this.host._pos(t),b=_?Ca(t,_,[m.x,m.y],this.host._fullRegistryHass):null;this.host._markerDialog={devId:t.id,name:t.name,binding:"virtual"===t.bindingKind?"virtual":t.bindingKind+":"+t.bindingRef,bindingMode:"virtual"===t.bindingKind?"virtual":"ha",bindingOpen:!1,showEntities:"entity"===t.bindingKind&&!!this.host._fullRegistryHass.entities[t.bindingRef||""]?.device_id,bindingFilter:"",icon:t.marker?.icon||"",autoIcon:t.icon||"",display:S(t.marker?.display),rippleColor:Nt(t.marker?.ripple_color,""),rippleSize:Number(t.marker?.ripple_size)>0?Number(t.marker.ripple_size):1.5,size:Number(t.marker?.size)>0?Number(t.marker.size):1,angle:Number(t.marker?.angle)||0,tapAction:Xs(t.marker?.tap_action,t.primary?.split(".")[0]),tapActionTouched:!1,originalHasTapAction:r,originalTapAction:t.marker?.tap_action,tapHintAnnouncement:"",toggleEntity:e?.toggle_entity||"",toggleEntityTouched:!1,originalHasToggleEntity:l,originalToggleEntity:e?.toggle_entity,tapTarget:t.marker?.tap_target||"",tapConfirm:!0===t.marker?.tap_confirm,runFilter:"",controls:T(t.marker?.binding,t.marker?.controls,t.entities),controlsFilter:"",lightRole:!0===e?.is_light?"always":!1===e?.is_light?"never":"auto",lightRoleTouched:!1,originalHasIsLight:s,originalIsLight:e?.is_light,lightEntity:e?.light_entity||"",lightEntityTouched:!1,originalHasLightEntity:i,originalLightEntity:e?.light_entity,glowMode:null!=h?.bri?"fixed":h?"color":"auto",glowColor:h?.c||this.host._fillColors.glow_light.c,glowBrightness:Math.max(1,Math.round(100*(h?.bri??1))),glowColorDrafted:!!h,glowBrightnessDrafted:null!=h?.bri,glowTouched:!1,originalHasGlowColor:o&&(!!h||null===e?.glow_color),originalGlowColor:h||(null===e?.glow_color?null:void 0),valueBadgeEnabled:a?!0===e?.value_badge?.enabled:!!c,valueBadgeSource:e?.value_badge?.source||c?.source||p,valueBadgePosition:e?.value_badge?.position||c?.position||"right",valueBadgeTouched:!1,originalHasValueBadge:a,originalValueBadge:e?.value_badge,valueSource:e?.value_source||null,valueSourceTouched:!1,originalHasValueSource:n,originalValueSource:e?.value_source,useClimateTemp:!0===t.marker?.use_climate_temp,glowRadius:Number(t.marker?.glow_radius_cm)>0?String(this.host._imperial?Math.round(Number(t.marker.glow_radius_cm)/30.48*10)/10:Math.round(Number(t.marker.glow_radius_cm))/100):"",model:t.model||"",link:t.link||"",description:t.description||"",pdfs:[...t.pdfs||[]],room:t.marker?.room_id?t.space+"#@"+t.marker.room_id:t.space&&t.area?t.space+"#"+t.area:"",roomTouched:!1,radar:b,radarEligible:u.eligible,radarTouched:!1,radarRemove:!1,hideFromPlan:!0===t.marker?.hidden,busy:!1}}else this.host._markerDialog={name:"",binding:"virtual",bindingMode:"virtual",bindingOpen:!1,showEntities:!1,bindingFilter:"",icon:"",autoIcon:"",display:"badge",rippleColor:"",rippleSize:1.5,size:1,angle:0,tapAction:"info",tapActionTouched:!1,originalHasTapAction:!1,originalTapAction:void 0,tapHintAnnouncement:"",toggleEntity:"",toggleEntityTouched:!1,originalHasToggleEntity:!1,originalToggleEntity:void 0,tapTarget:"",tapConfirm:!1,runFilter:"",controls:[],controlsFilter:"",lightRole:"auto",lightRoleTouched:!1,originalHasIsLight:!1,originalIsLight:void 0,lightEntity:"",lightEntityTouched:!1,originalHasLightEntity:!1,originalLightEntity:void 0,glowMode:"auto",glowColor:this.host._fillColors.glow_light.c,glowBrightness:100,glowColorDrafted:!1,glowBrightnessDrafted:!1,glowTouched:!1,originalHasGlowColor:!1,originalGlowColor:void 0,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgePosition:"right",valueBadgeTouched:!1,originalHasValueBadge:!1,originalValueBadge:void 0,valueSource:null,valueSourceTouched:!1,originalHasValueSource:!1,originalValueSource:void 0,useClimateTemp:!1,glowRadius:"",model:"",link:"",description:"",pdfs:[],room:"",roomTouched:!1,radar:null,radarEligible:!1,radarTouched:!1,radarRemove:!1,hideFromPlan:!1,busy:!1,uploadId:"up_"+Date.now().toString(36)+Math.random().toString(36).slice(2,6)};this.host._markerDialog&&function(t,e){_o(t,"marker",ga(e))}(this.host,this.host._markerDialog)}else this.host._showToast(this.host._t("toast.marker_needs_server"))}_runCandidates(){const t=[];for(const e of Qs)for(const[s,i]of Object.entries(this.host.hass.states))s.startsWith(e+".")&&this.host._planEntityAvailable(s)&&t.push({value:s,label:i?.attributes?.friendly_name||s,sub:this.host._t("run."+e)});return t.sort((t,e)=>t.sub.localeCompare(e.sub)||t.label.localeCompare(e.label))}_bindingCandidates(){const t=Xh({hass:this.host._planHass,devices:this.host._devices,markers:this.host._markers,showEntities:!!this.host._markerDialog?.showEntities,currentBinding:this.host._markerDialog?.binding,currentDeviceId:this.host._markerDialog?.devId,labels:{device:this.host._t("marker.sub_device"),z2mGroup:this.host._t("marker.sub_z2m_group"),group:this.host._t("marker.sub_group"),helper:this.host._t("marker.sub_helper"),entity:this.host._t("marker.sub_entity")}}),e=(this.host._markerDialog?.bindingFilter||"").toLowerCase().trim(),s=e?t.filter(t=>(t.label+" "+t.sub+" "+t.value).toLowerCase().includes(e)):t;return s.sort((t,e)=>t.label.localeCompare(e.label)),s.slice(0,200)}_backupErrorText(t){const e=t?.code??t?.error;if("string"==typeof e){const t=`backup.error.${e}`,s=this.host._t(t);if(s!==t)return s}return this.host._errText(t)}async _pickMarkerFiles(t){const e=t.target,s=e.files?[...e.files]:[];if(e.value="",!s.length||!this.host._markerDialog)return;const i=this.host._markerDialog.uploadId||this.host._markerDialog.devId||"new",o=[];for(const t of s)try{const e=new FormData;e.append("marker_id",i),e.append("file",t,t.name);const s=this.host.hass?.fetchWithAuth?await this.host.hass.fetchWithAuth("/api/houseplan/upload",{method:"POST",body:e}):await fetch("/api/houseplan/upload",{method:"POST",body:e,headers:this.host.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.host.hass.auth.data.access_token}`}:{}}),a=await s.json().catch(()=>({}));if(!s.ok||a.error){const t={too_large:this.host._t("err.too_large",{mb:a.max_mb||50}),bad_ext:this.host._t("err.bad_ext"),unauthorized:this.host._t("err.unauthorized")};throw new Error(t[a.error]||a.error||"HTTP "+s.status)}o.push({name:a.name||t.name,url:a.url})}catch(e){this.host._showToast(this.host._t("toast.file_failed",{name:t.name,err:this.host._errText(e)}))}o.length&&this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,pdfs:[...this.host._markerDialog.pdfs,...o]},this.host._showToast(this.host._t("toast.files_attached",{n:o.length})))}_removeMarkerPdf(t){this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,pdfs:this.host._markerDialog.pdfs.filter(e=>e.url!==t)})}_markerLightFields(t){const e={};if(t.lightRoleTouched?"always"===t.lightRole?e.is_light=!0:"never"===t.lightRole&&(e.is_light=!1):t.originalHasIsLight&&(e.is_light=t.originalIsLight??null),t.lightEntityTouched?t.lightEntity&&(e.light_entity=t.lightEntity):t.originalHasLightEntity&&(e.light_entity=t.originalLightEntity??null),t.glowTouched){if("auto"!==t.glowMode){const s={c:Nt(t.glowColor,this.host._fillColors.glow_light.c)};"fixed"===t.glowMode&&(s.bri=Math.max(.01,Math.min(1,Math.round(t.glowBrightness)/100))),e.glow_color=s}}else t.originalHasGlowColor&&(e.glow_color=t.originalGlowColor??null);return e}_markerTapActionFields(t){return t.tapActionTouched?{tap_action:t.tapAction||null}:t.originalHasTapAction?{tap_action:t.originalTapAction??null}:{}}_markerToggleEntityFields(t){return(e={touched:t.toggleEntityTouched,originalHas:t.originalHasToggleEntity,original:t.originalToggleEntity,value:t.toggleEntity}).touched?e.value?{toggle_entity:e.value}:{}:e.originalHas?{toggle_entity:e.original??null}:{};var e}async _saveMarker(){const t=this.host._markerDialog;if(!t||t.busy)return;const e=this._effectiveMarkerTapAction(t);if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return;if("virtual"===t.binding&&!t.name.trim())return void this.host._showToast(this.host._t("toast.virtual_name_required"));if("run"===e&&!t.tapTarget)return void this.host._showToast(this.host._t("toast.run_target_required"));if(t.valueBadgeTouched&&t.valueBadgeEnabled&&!t.valueBadgeSource)return void this.host._showToast(this.host._t("toast.value_badge_source_required"));if("ha"===t.bindingMode){const e=this.host._bindingStatus(t.binding),s=t.devId?this.host._markers.find(e=>e.id===t.devId):null,i=!s||s.binding!==t.binding;if("active"!==e.kind&&i)return void this.host._showToast(this.host._t("ha_disabled"===e.kind?"toast.ha_disabled_add":"toast.ha_binding_unverified"));if("ha_disabled"===e.kind&&!0===s?.hidden&&!t.hideFromPlan)return this.host._markerDialog={...t,hideFromPlan:!0},void this.host._showToast(this.host._t("entity"===e.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device"))}const s=this.host._serverCfg;if(!s)return;const i=this.host._cfgRev,o=yt(s);let a=JSON.parse(JSON.stringify(s));const n=a.markers||[],r=Zs(t.binding,t.devId,()=>"v_"+Date.now().toString(36)),l=t.devId,h=l?this.host._devices.find(t=>t.id===l):null,c=l?n.find(t=>t.id===l):null,d=!!c&&("string"==typeof c.area&&c.area.length>0||null===c.area&&!!c.space&&!!c.room_id),p="virtual"===t.binding||t.roomTouched||d,u="virtual"===t.binding||t.roomTouched?x(t.room):null;let _=d&&!t.roomTouched?c?.space||null:u?.space||null;const m=d&&!t.roomTouched?c?.area||null:u?.area||null,g=d&&!t.roomTouched?c?.room_id||null:u?.roomId||null,f=_||h?.space||null,b=f?this.host._spaceModelById(f):this.host._spaceModel();if(!b)return;const v=b.id;"virtual"!==t.binding||_||(_=v);let y={};if(t.radarTouched){if(t.radarRemove)y={radar:null};else if(t.radar){const e=Da(t.radar,b.cellCm||5);if(!e)return void this.host._showToast(this.host._t("radar.invalid"));y={radar:e}}}else c&&Object.prototype.hasOwnProperty.call(c,"radar")&&(y={radar:c.radar});this.host._markerDialog={...t,busy:!0};let w=null,$=!1;try{const c="virtual"===t.binding?[]:n.filter(e=>e.removed&&e.binding===t.binding).map(t=>t.id),d=c.length>0,u=T(t.binding,t.controls,this.host._bindingEntities(t.binding)),f=n.find(t=>t.id===r||t.id===l)?.vacuum||null,k={id:r,vacuum:f,...y,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle?t.angle:null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===e&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:u.length?u:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),...this._markerValueSourceFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=xt(t.glowRadius);return null==e||e<=0?null:Math.round(this.host._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:!!t.hideFromPlan};p&&(k.space=_,k.area=m,k.room_id=g);const x=h?.marker?.room_id??null,M=t.roomTouched&&null!=h&&(h.space!==_||h.area!==m||x!==g);let C=!1;const S=t.uploadId||l;if(S&&S!==r&&k.pdfs?.length)try{const t=await this.host.hass.callWS({type:"houseplan/files/migrate",from_id:S,to_id:r}),e=t?.mapping||{};k.pdfs=ti(k.pdfs,S,r,e),C=Object.keys(e).length>0}catch(t){this.host._showToast(this.host._t("toast.files_migrate_failed",{err:this.host._errText(t)}))}a.markers=n,l&&l!==r&&(a.markers=ei(a.markers,l,r)),l&&l!==r&&"derived_marker_state"===k.value_badge?.source?.kind&&k.value_badge.source.ref===`marker:${l}`&&(k.value_badge.source={kind:"derived_marker_state",ref:`marker:${r}`}),l&&l!==r&&"derived_marker_state"===k.value_source?.kind&&k.value_source.ref===`marker:${l}`&&(k.value_source={kind:"derived_marker_state",ref:`marker:${r}`}),a.markers=a.markers.filter(t=>t.id!==r&&t.id!==l&&("virtual"===k.binding||t.binding!==k.binding)),a.markers.push(k);const P=new Set(c);l&&l!==r&&P.add(l),P.delete(r),P.size&&a.settings?.marker_area_snapshot&&(a.settings={...a.settings,marker_area_snapshot:si(a.settings.marker_area_snapshot,P)});let D=null;const I=l?this.host._layout[l]:null,L=I?{s:I.s||h?.space||this.host._space,x:I.x,y:I.y}:l&&h&&this.host._defPos[l]?this.host._normPos(h.space,this.host._defPos[l].x,this.host._defPos[l].y):null;if(!d&&L&&L.s===v)r===l&&this.host._layout[r]&&!M||(D={s:L.s,x:L.x,y:L.y});else if(d||!this.host._layout[r]||M){let t=b.vb[0]+b.vb[2]/2,e=b.vb[1]+b.vb[3]/2;const s=g?b.rooms.find(t=>t.id===g):m?b.rooms.find(t=>t.area===m):void 0;s&&([t,e]=this.host._roomCenter(s)),D=this.host._normPos(v,t,e)}if(this.host._serverCfg!==s||this.host._cfgRev!==i||yt(s)!==o)return this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,busy:!1}),void this.host._showToast(this.host._t("toast.conflict"));if(a=this._prepareConfigCandidate(a),w=this.host._adoption.beginOptimistic(s,a),this.host._serverCfg=a,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate(),this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.cancel(),await this._saveConfigNow(w),$=!0,D){const t=ii(D);this.host._layout={...this.host._layout,[r]:t},this.host._noteLayoutRev(await this.host.hass.callWS({type:"houseplan/layout/update",device_id:r,pos:t}))}const R=new Set(c);l&&l!==r&&R.add(l),R.delete(r);for(const t of R)delete this.host._layout[t],await this.host.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this.host._noteLayoutRev(t)).catch(()=>{});C&&S&&await this.host.hass.callWS({type:"houseplan/files/cleanup",marker_id:S}).catch(()=>{}),this._closeMarkerDialog(),this.host._cancelDeviceDrag(),this.host._devicePositionHistory.clear(),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.marker_saved"))}catch(t){!$&&w&&(this.host._rollbackOptimistic(w),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate()),this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteMarker(){const t=this.host._markerDialog;if(!t||t.busy||!t.devId)return;const e=t.devId?this.host._devices.find(e=>e.id===t.devId):null,s=this.host._markers.find(e=>e.id===t.devId);if(!e&&!s)return;const i=e?"virtual"===e.bindingKind?"virtual":e.bindingKind&&e.bindingRef?`${e.bindingKind}:${e.bindingRef}`:"":s.binding;if(!i)return;const o=t.name||this.host._t("device.fallback"),a=t.devId,n=await this.host._confirmDanger({key:"remove-marker",kind:"destructive",title:this.host._t("confirm.remove_marker_title"),message:this.host._t("confirm.remove_marker_body"),objectName:o,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),r=this.host._markerDialog;if(!n||!r||r.busy||r.devId!==a)return;const l=this.host._devices.find(t=>t.id===a),h=this.host._markers.find(t=>t.id===a);if(!l&&!h)return;const c=this.host._serverCfg;if(!c)return;c.markers=c.markers||[];const d=c.markers,p=l?"virtual"===l.bindingKind?"virtual":l.bindingKind&&l.bindingRef?`${l.bindingKind}:${l.bindingRef}`:"":h.binding;if(!p||p!==i)return;const u=oi(c.markers,a,p,"virtual"===p);c.markers=ai(u.markers,u.cleanupIds);const _=u.cleanupIds;_.size&&c.settings?.marker_area_snapshot&&(c.settings={...c.settings,marker_area_snapshot:si(c.settings.marker_area_snapshot,_)}),this.host._markerDialog={...r,busy:!0};try{await this._saveConfigNow();for(const t of _){delete this.host._layout[t],delete this.host._defPos[t],this.host._dirtyPos.delete(t),this.host._sentPos.delete(t);const e=this.host._activityRt.get(t);e&&clearTimeout(e.timer),this.host._activityRt.delete(t),this.host._vacRt.delete(t),delete this.host._vacSrvTrails[t],await this.host.hass.callWS({type:"houseplan/layout/delete",device_id:t}).then(t=>this.host._noteLayoutRev(t)).catch(()=>{}),await this.host.hass.callWS({type:"houseplan/files/cleanup",marker_id:t}).catch(()=>{}),await this.host.hass.callWS({type:"houseplan/trail/delete",marker_id:t}).catch(()=>{})}this.host._deviceInboxReturn&&(this.host._deviceInboxReturn={...this.host._deviceInboxReturn,tab:"readd",anchor:p}),this._closeMarkerDialog(),this.host._cancelDeviceDrag(),this.host._devicePositionHistory.clear(),this.host._infoCard?.id===a&&this.host._closeInfoCard(),this.host._selId===a&&(this.host._selId=null),this.host._drag?.id===a&&(this.host._drag=null),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.marker_removed"))}catch(t){this.host._serverCfg===c&&(c.markers=d),this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_openSpaceDialog(t,e){if(this.host._serverStorage&&this.host._serverCfg){if("edit"===t){const s=this.host._serverCfg.spaces.find(t=>t.id===e);if(!s)return;const i=_(s),o=s.settings?.custom_fill&&"object"==typeof s.settings.custom_fill?ni(s.settings.custom_fill):null,a="none"===i.fill?{...o||ri,a:0}:o;this.host._spaceDialog={mode:t,spaceId:e,title:s.title,planUrl:s.plan_url||null,planFile:null,source:s.plan_url?"file":"draw",showBorders:i.showBorders,showNames:i.showNames,zeroWallStyle:hi(s),displayTouched:!0,hideDecor:i.hideDecor,hideOpenings:i.hideOpenings,roomColor:i.color,roomOpacity:i.opacity,fillMode:"none"===i.fill?"custom":i.fill,customFill:a,glowEnabled:i.glow,bgColor:i.bgColor,bgMode:"static"===s.settings?.bg_mode||"daynight"===s.settings?.bg_mode?s.settings.bg_mode:null,northDeg:Re({},s.settings),sunRays:"boolean"==typeof s.settings?.sun_rays?s.settings.sun_rays:null,tempMin:i.tempMin,tempMax:i.tempMax,showLqi:i.showLqi??this.host._config?.show_signal??!0,cardFontScale:i.cardFontScale,labelTemp:i.labelTemp,labelHum:i.labelHum,labelLqi:i.labelLqi,labelLight:i.labelLight,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,cellCmInput:li(Number(s.cell_cm)>0?Number(s.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1}}else this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...mi(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:ui,roomOpacity:pi,fillMode:"custom",customFill:{...ri,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:di,tempMax:ci,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:_i(this.host._imperial),cellCmInput:li(_i(this.host._imperial),this.host._imperial),cellCmTouched:!1,busy:!1};this.host._spaceDialog&&Go(this.host,this.host._spaceDialog)}else this.host._showToast(this.host._t("toast.integration_missing"))}async _pickPlanFile(t){const e=t.target,s=e.files?.[0];if(!s||!this.host._spaceDialog)return;e.value="",this._decorAssetGuardReplace=null;const i=await jo(s);if("reject"===i.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===i.kind)return void(this.host._backdropGuard=i.state);const o=await qo(s,i.ext,s.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:o})}_renderBackdropGuard(){const t=this._decorAssetGuardReplace;return null!==t?Uo(this.host,()=>{},()=>{this.host._backdropGuard=null,this._decorAssetGuardReplace=null},this.host.hass,(e,s)=>this._uploadDecorImage(e,s,t),(this.host._backdropGuard?.file.size||0)<=2097152)??d:Uo(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??d}_useServerPlan(t){const e=this.host._spaceDialog;e&&(this.host._spaceDialog={...e,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let e=0;e<40;e++){const e=this.host._display(t);if(e){const s=await new Promise(t=>{const s=new Image;s.onload=()=>t(s.naturalWidth&&s.naturalHeight?s.naturalWidth/s.naturalHeight:0),s.onerror=()=>t(0),s.src=e}),i=this.host._spaceDialog;return i&&i.planUrl===t&&Number.isFinite(s)&&s>0?(this.host._spaceDialog={...i,savedAspect:s},s):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const e=this.host._spaceDialog,s=e?.saved?.find(e=>e.name===t);if(!e||!s||s.used_by.length||s.url===e.planUrl)return;const i=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),o=this.host._spaceDialog,a=o?.saved?.find(e=>e.name===t);if(i&&o&&a&&a.url===s.url&&a.modified===s.modified&&!a.used_by.length&&a.url!==o.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const e=this.host._spaceDialog;e?.saved&&(this.host._spaceDialog={...e,saved:e.saved.filter(e=>e.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return p`
    ${this.host._t("space.loading")}
    `;const e=t.saved||[];if(!e.length)return p`
    ${this.host._t("space.no_saved")}
    `;return p`
    ${e.map(e=>{return p`
    @@ -1435,7 +1435,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
    `;var s})} -
    `}async _saveSpaceDialog(){const t=this.host._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this.host._showToast(this.host._t("toast.plan_required"));const e="create"===t.mode&&0===(this.host._serverCfg?.spaces.length||0);this.host._spaceDialog={...t,busy:!0};try{const s="create"===t.mode?"s"+Date.now().toString(36):t.spaceId;let i=null;if("file"===t.source&&t.planFile){i={url:(await this.host.hass.callWS({type:"houseplan/plan/set",space_id:s,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let o=t.savedAspect||null;!i&&"file"===t.source&&t.planUrl&&!o&&this.host._aspectJob&&(o=await this.host._aspectJob||null);const a=this.host._serverCfg;let n;if("create"===t.mode)n=gi(s,t.title.trim()),a.spaces.push(n);else{if(n=a.spaces.find(t=>t.id===s),!n)throw new Error("space "+s+" is gone from the config");n.title=t.title.trim()}i?(n.plan_url=i.url,n.plan_aspect=i.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==n.plan_url&&(n.plan_url=t.planUrl,n.plan_aspect=o),"draw"===t.source&&(n.plan_url=null,n.plan_aspect=null,delete n.plan_x,delete n.plan_y,delete n.plan_scale,delete n.plan_scale_x,delete n.plan_scale_y,delete n.plan_angle),n.settings={...n.settings||{},show_borders:t.showBorders,show_names:t.showNames,hide_decor:t.hideDecor||void 0,hide_openings:t.hideOpenings||void 0,room_color:t.roomColor,room_opacity:t.roomOpacity,bg_color:t.bgColor||void 0,bg_mode:t.bgMode||void 0,north_deg:t.northDeg??void 0,sun_rays:t.sunRays??void 0,fill_mode:t.fillMode,custom_fill:t.customFill||void 0,glow_enabled:t.glowEnabled,temp_min:Number.isFinite(t.tempMin)?Math.min(t.tempMin,t.tempMax):di,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):ci,show_lqi:t.showLqi,card_font_scale:1!==t.cardFontScale?t.cardFontScale:void 0,label_temp:t.labelTemp,label_hum:t.labelHum,label_lqi:t.labelLqi,label_light:t.labelLight},n.zero_wall_style=t.zeroWallStyle,n.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(Ko,Math.min(Vo,t.cellCm)):5,await this._saveConfigNow(),this.host._spaceDialog=null,"create"===t.mode&&this.host._commitSpace(n.id),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._importQueue.length?this._openNextImport():e||this.host._importTotal>0?(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this._setMode("plan"),this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this._primeDrawWallField(),this.host._showToast(this.host._t(e&&!this.host._importTotal?"toast.space_added_onboard":"import.done"))):(this.host._showToast("create"===t.mode?this.host._t("toast.space_added"):this.host._t("toast.space_saved")),"create"===t.mode&&("plan"!==this.host._mode?this._setMode("plan"):(this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this._primeDrawWallField(),this.host._saveNav())))}catch(t){"conflict"!==t?.code&&await this.host._reloadConfigOnly(!0),this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteSpace(){const t=this.host._spaceDialog;if(!t||"edit"!==t.mode)return;const e=this.host._serverCfg;if(!e)return;const s=e.spaces.find(e=>e.id===t.spaceId),i=Jo(e,this.host._layout||{},t.spaceId||""),o=1===e.spaces.length&&e.spaces[0]?.id===t.spaceId;if(i.count&&!o)return void(this.host._spaceDialog={...t,deleteBlockers:i.count});if(!s)return;const a=t.spaceId,n=await this.host._confirmDanger({key:"delete-space",kind:"destructive",title:this.host._t("confirm.delete_space_title"),message:Zo(this.host._t("confirm.delete_space_body"),this.host._t("confirm.delete_space_vac_routes"),i.routeCount),objectName:s.title,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),r=this.host._spaceDialog,l=this.host._serverCfg;if(!n||!r||"edit"!==r.mode||r.busy||r.spaceId!==a||!l)return;if(!l.spaces.find(t=>t.id===a))return;const h=Jo(l,this.host._layout||{},a),c=1===l.spaces.length&&l.spaces[0]?.id===a;if(!h.count||c){this.host._spaceDialog={...r,deleteBlockers:0,busy:!0};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),this.host._persistLayout.pending()&&this.host._persistLayout.flush(),await this.host._writeChain,await this.host.hass.callWS({type:"houseplan/space/delete",space_id:a,expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev});const[t,e]=await Promise.all([this.host._getAuthoritativeConfig(),this.host.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this.host._adoptAuthoritative({cfgResp:t,layResp:e,reason:"space-delete",profile:"post-write"})).status)return this.host._spaceDialog={...r,busy:!1},void this.host.requestUpdate();this.host._spaceDialog=null,this.host._space===a&&this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||""),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.space_deleted"))}catch(t){"conflict"!==t?.code&&"space_in_use"!==t?.code||await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]);const e=this.host._serverCfg;if(this.host._spaceDialog&&e){const t=Jo(e,this.host._layout||{},a),s=1===e.spaces.length&&e.spaces[0]?.id===a;this.host._spaceDialog={...this.host._spaceDialog,busy:!1,deleteBlockers:s?0:t.count}}this.host._showToast(this.host._t("toast.delete_failed",{err:this.host._errText(t)}))}}else this.host._spaceDialog={...r,deleteBlockers:h.count}}async _saveConfigNow(t=null){this.host._cfgEpoch++;try{await this._writeConfig(t)}catch(t){throw t?.physicalGeometryRolledBack?await this._reloadRejectedPhysicalWrite():"conflict"===t?.code&&await this.host._reloadConfigOnly(),t}}_saveSpaceCopy(){return yr(this.host,{clearGeometryGesture:()=>this._clearGeometryGesture(),optimizeReferenceContext:()=>this._optimizeReferenceContext(!1),reportPreflightFailure:(t,e)=>this._reportPreflightFailure(t,e),saveConfigNow:t=>this._saveConfigNow(t),setMode:()=>this._setMode("plan"),showWallModelMigrationBlocked:t=>this._showWallModelMigrationBlocked(t)})}_startImport(){const t=this.host._importDialog;if(!t)return;const e=t.floors.filter(t=>t.checked).map(t=>t.name);this.host._importDialog=null,e.length?(this.host._importQueue=e,this.host._importTotal=e.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this.host._importQueue.shift();void 0!==t&&(this.host._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...mi(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:ui,roomOpacity:pi,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:di,tempMax:ci,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:_i(this.host._imperial),cellCmInput:li(_i(this.host._imperial),this.host._imperial),cellCmTouched:!1,busy:!1})}_skipImport(){this.host._spaceDialog=null,this.host._importQueue.length?this._openNextImport():this.host._importTotal>0&&this.host._model.length&&(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this._setMode("plan"),this.host._showToast(this.host._t("import.done")))}_renderImportDialog(){const t=this.host._importDialog,e=t.floors.filter(t=>t.checked).length;return p``}async _saveSpaceDialog(){const t=this.host._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this.host._showToast(this.host._t("toast.plan_required"));const e="create"===t.mode&&0===(this.host._serverCfg?.spaces.length||0);this.host._spaceDialog={...t,busy:!0};try{const s="create"===t.mode?"s"+Date.now().toString(36):t.spaceId;let i=null;if("file"===t.source&&t.planFile){i={url:(await this.host.hass.callWS({type:"houseplan/plan/set",space_id:s,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let o=t.savedAspect||null;!i&&"file"===t.source&&t.planUrl&&!o&&this.host._aspectJob&&(o=await this.host._aspectJob||null);const a=this.host._serverCfg;let n;if("create"===t.mode)n=gi(s,t.title.trim()),a.spaces.push(n);else{if(n=a.spaces.find(t=>t.id===s),!n)throw new Error("space "+s+" is gone from the config");n.title=t.title.trim()}i?(n.plan_url=i.url,n.plan_aspect=i.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==n.plan_url&&(n.plan_url=t.planUrl,n.plan_aspect=o),"draw"===t.source&&(n.plan_url=null,n.plan_aspect=null,delete n.plan_x,delete n.plan_y,delete n.plan_scale,delete n.plan_scale_x,delete n.plan_scale_y,delete n.plan_angle),n.settings={...n.settings||{},show_borders:t.showBorders,show_names:t.showNames,hide_decor:t.hideDecor||void 0,hide_openings:t.hideOpenings||void 0,room_color:t.roomColor,room_opacity:t.roomOpacity,bg_color:t.bgColor||void 0,bg_mode:t.bgMode||void 0,north_deg:t.northDeg??void 0,sun_rays:t.sunRays??void 0,fill_mode:t.fillMode,custom_fill:t.customFill||void 0,glow_enabled:t.glowEnabled,temp_min:Number.isFinite(t.tempMin)?Math.min(t.tempMin,t.tempMax):di,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):ci,show_lqi:t.showLqi,card_font_scale:1!==t.cardFontScale?t.cardFontScale:void 0,label_temp:t.labelTemp,label_hum:t.labelHum,label_lqi:t.labelLqi,label_light:t.labelLight},n.zero_wall_style=t.zeroWallStyle,n.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(Ko,Math.min(Vo,t.cellCm)):5,await this._saveConfigNow(),this.host._spaceDialog=null,"create"===t.mode&&this.host._commitSpace(n.id),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._importQueue.length?this._openNextImport():e||this.host._importTotal>0?(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this._setMode("plan"),this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this._primeDrawWallField(),this.host._showToast(this.host._t(e&&!this.host._importTotal?"toast.space_added_onboard":"import.done"))):(this.host._showToast("create"===t.mode?this.host._t("toast.space_added"):this.host._t("toast.space_saved")),"create"===t.mode&&("plan"!==this.host._mode?this._setMode("plan"):(this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this._primeDrawWallField(),this.host._saveNav())))}catch(t){"conflict"!==t?.code&&await this.host._reloadConfigOnly(!0),this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteSpace(){const t=this.host._spaceDialog;if(!t||"edit"!==t.mode)return;const e=this.host._serverCfg;if(!e)return;const s=e.spaces.find(e=>e.id===t.spaceId),i=Jo(e,this.host._layout||{},t.spaceId||""),o=1===e.spaces.length&&e.spaces[0]?.id===t.spaceId;if(i.count&&!o)return void(this.host._spaceDialog={...t,deleteBlockers:i.count});if(!s)return;const a=t.spaceId,n=await this.host._confirmDanger({key:"delete-space",kind:"destructive",title:this.host._t("confirm.delete_space_title"),message:Zo(this.host._t("confirm.delete_space_body"),this.host._t("confirm.delete_space_vac_routes"),i.routeCount),objectName:s.title,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),r=this.host._spaceDialog,l=this.host._serverCfg;if(!n||!r||"edit"!==r.mode||r.busy||r.spaceId!==a||!l)return;if(!l.spaces.find(t=>t.id===a))return;const h=Jo(l,this.host._layout||{},a),c=1===l.spaces.length&&l.spaces[0]?.id===a;if(!h.count||c){this.host._spaceDialog={...r,deleteBlockers:0,busy:!0};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),this.host._persistLayout.pending()&&this.host._persistLayout.flush(),await this.host._writeChain,await this.host.hass.callWS({type:"houseplan/space/delete",space_id:a,expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev});const[t,e]=await Promise.all([this.host._getAuthoritativeConfig(),this.host.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this.host._adoptAuthoritative({cfgResp:t,layResp:e,reason:"space-delete",profile:"post-write"})).status)return this.host._spaceDialog={...r,busy:!1},void this.host.requestUpdate();this.host._spaceDialog=null,this.host._space===a&&this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||""),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.space_deleted"))}catch(t){"conflict"!==t?.code&&"space_in_use"!==t?.code||await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]);const e=this.host._serverCfg;if(this.host._spaceDialog&&e){const t=Jo(e,this.host._layout||{},a),s=1===e.spaces.length&&e.spaces[0]?.id===a;this.host._spaceDialog={...this.host._spaceDialog,busy:!1,deleteBlockers:s?0:t.count}}this.host._showToast(this.host._t("toast.delete_failed",{err:this.host._errText(t)}))}}else this.host._spaceDialog={...r,deleteBlockers:h.count}}async _saveConfigNow(t=null){this.host._cfgEpoch++;try{await this._writeConfig(t)}catch(t){throw t?.physicalGeometryRolledBack?await this._reloadRejectedPhysicalWrite():"conflict"===t?.code&&await this.host._reloadConfigOnly(),t}}_saveSpaceCopy(){return vr(this.host,{clearGeometryGesture:()=>this._clearGeometryGesture(),optimizeReferenceContext:()=>this._optimizeReferenceContext(!1),reportPreflightFailure:(t,e)=>this._reportPreflightFailure(t,e),saveConfigNow:t=>this._saveConfigNow(t),setMode:()=>this._setMode("plan"),showWallModelMigrationBlocked:t=>this._showWallModelMigrationBlocked(t)})}_startImport(){const t=this.host._importDialog;if(!t)return;const e=t.floors.filter(t=>t.checked).map(t=>t.name);this.host._importDialog=null,e.length?(this.host._importQueue=e,this.host._importTotal=e.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this.host._importQueue.shift();void 0!==t&&(this.host._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...mi(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:ui,roomOpacity:pi,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:di,tempMax:ci,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:_i(this.host._imperial),cellCmInput:li(_i(this.host._imperial),this.host._imperial),cellCmTouched:!1,busy:!1})}_skipImport(){this.host._spaceDialog=null,this.host._importQueue.length?this._openNextImport():this.host._importTotal>0&&this.host._model.length&&(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this._setMode("plan"),this.host._showToast(this.host._t("import.done")))}_renderImportDialog(){const t=this.host._importDialog,e=t.floors.filter(t=>t.checked).length;return p`this.host._importDialog=null}>
    ${this.host._t("import.hint")}
    @@ -1455,13 +1455,13 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${this.host._t("import.start",{n:e})}
    -
    `}_supportPatch(t,e){const s=this.host._supportDialog;if(!s||s.draftId!==t)return null;const i={...s,...e};return this.host._supportDialog=i,i}async _focusSupport(t){await this.host.updateComplete,this.host.renderRoot.querySelector(t)?.focus({preventScroll:!0})}_updateSupportDraft(t,e){const s=this.host._supportDialog;if(!s||"building"===s.status||"sending"===s.status||"success"===s.status)return;const i={...s,[t]:e},o=md({...i,attach:!1,preview:null});"message_required"===o&&"validation.message_required"===s.errorCode||"message_too_long"===o||"contact_too_long"===o?this._supportPatch(s.draftId,{[t]:e,status:"error",errorCode:`validation.${o}`}):i.attach&&i.preview&&i.preview.expiresAt<=Date.now()?this._supportPatch(s.draftId,{[t]:e,status:"error",errorCode:"support_preview_expired"}):this._supportPatch(s.draftId,{[t]:e,status:i.attach&&i.preview?"ready":"idle",errorCode:""})}async _discardSupportPreview(t){if(t)try{await this.host.hass.callWS({type:"houseplan/support/preview/discard",token:t})}catch{}}async _closeSupportDialog(){const t=this.host._supportDialog;if(t){if("building"===t.status||"sending"===t.status){const t=l(this.host.hass,this.host._config?.language);if(!await this.host._confirmDanger({key:"close-support-busy",kind:"warning",title:ra(t,"support.close_busy_title"),message:ra(t,"support.close_busy_body"),confirmLabel:this.host._t("btn.close"),cancelLabel:this.host._t("btn.cancel")}))return await this.host.updateComplete,void this.host.renderRoot.querySelector("#support-dialog")?.rejectClose()}clearTimeout(this._supportExpiryTimer),this._supportExpiryTimer=void 0,this.host._supportDialog=null,t.preview?.token&&"success"!==t.status&&this._discardSupportPreview(t.preview.token)}}_scheduleSupportExpiry(t,e){clearTimeout(this._supportExpiryTimer);const s=Math.max(0,e.expiresAt-Date.now());this._supportExpiryTimer=window.setTimeout(()=>{const s=this.host._supportDialog;s&&s.draftId===t&&s.preview?.token===e.token&&s.attach&&"success"!==s.status&&"sending"!==s.status&&this._supportPatch(t,{status:"error",errorCode:"support_preview_expired"})},Math.min(s+20,2147483647))}_supportFacts(){const t=this.host._haRegistry;return fd({userAgent:globalThis.navigator?.userAgent||"",language:l(this.host.hass,this.host._config?.language),registryAccess:t.access,registryLastSuccess:t.lastSuccess})}_supportPreviewRequestIsCurrent(t,e){const s=this.host._supportDialog;return e===this._supportPreviewGeneration&&s?.draftId===t&&s.attach}async _buildSupportPreview(t){const e=this.host._supportDialog;if(!e||e.draftId!==t||!e.attach||!dd(this.host._haSupportApi))return;const s=++this._supportPreviewGeneration;this._supportPatch(t,{status:"building",errorCode:""});let i="";try{const e=await this.host.hass.callWS({type:"houseplan/support/preview",card_version:fi(Hd),...this._supportFacts(),draft_id:t}),o=e&&"object"==typeof e?e:{},a=Date.now(),n="string"==typeof o.text?o.text:"",r=Number(o.size),l=Number(o.expires_in),h=Number(o.spaces),c=String(o.token||"");/^[0-9a-f]{48}$/.test(c)&&(i=c);const d=String(o.sha256||""),p=Number(o.version),u=String(o.format||""),_=(new TextEncoder).encode(n).byteLength;if(!/^[0-9a-f]{48}$/.test(c)||!/^[0-9a-f]{64}$/.test(d)||"houseplan-support-package"!==u||1!==p||!Number.isInteger(r)||r!==_||!Number.isInteger(h)||h<0||!Number.isFinite(l)||l<=0||l>600||!n.endsWith("\n"))throw{code:"support_rejected"};const m={token:c,expiresAt:a+1e3*l,size:r,sha256:d,spaces:h,format:u,version:p,text:n,preparedAt:a};if(!this._supportPreviewRequestIsCurrent(t,s))return i="",void this._discardSupportPreview(c);if(!this._supportPatch(t,{status:"ready",preview:m,errorCode:"",rawOpen:!1}))return i="",void this._discardSupportPreview(c);i="",this._scheduleSupportExpiry(t,m)}catch(e){if(i){const t=i;i="",this._discardSupportPreview(t)}if(!this._supportPreviewRequestIsCurrent(t,s))return;if(!this._supportPatch(t,{status:"error",errorCode:bd(e)}))return;this._focusSupport("#support-error")}}async _setSupportAttachment(t){const e=this.host._supportDialog;if(!e||"sending"===e.status||"success"===e.status)return;const s=e.preview?.token||"";if(!t)return this._supportPreviewGeneration+=1,clearTimeout(this._supportExpiryTimer),this._supportExpiryTimer=void 0,this._supportPatch(e.draftId,{attach:!1,status:"idle",preview:null,rawOpen:!1,errorCode:""}),void(s&&this._discardSupportPreview(s));this._supportPatch(e.draftId,{attach:!0,errorCode:""}),await this._buildSupportPreview(e.draftId)}async _refreshSupportPreview(){const t=this.host._supportDialog;t&&t.attach&&"building"!==t.status&&"sending"!==t.status&&await this._buildSupportPreview(t.draftId)}_downloadSupportPreview(){const t=this.host._supportDialog?.preview;if(!t)return;const e=new Blob([t.text],{type:"application/json;charset=utf-8"}),s=URL.createObjectURL(e),i=document.createElement("a");i.href=s,i.download=`houseplan-support-${t.sha256.slice(0,12)}.json`,i.style.display="none",document.body.append(i),i.click(),i.remove(),window.setTimeout(()=>URL.revokeObjectURL(s),0)}async _copySupportText(t,e){const s=l(this.host.hass,this.host._config?.language);try{await navigator.clipboard.writeText(t),this.host._showToast(ra(s,e))}catch{this.host._showToast(ra(s,"support.copy_failed"))}}async _submitSupport(){const t=this.host._supportDialog;if(!t||!dd(this.host._haSupportApi))return;const e=md(t);if(e)return this._supportPatch(t.draftId,{status:"error",errorCode:`validation.${e}`}),void this._focusSupport("#support-message");if(!gd(t))return;const s=ud(t),i=this._supportPatch(t.draftId,{status:"sending",errorCode:"",idempotencyKey:s.idempotencyKey,submissionFingerprint:s.fingerprint});if(i)try{const e=await this.host.hass.callWS({type:"houseplan/support/submit",message:i.message.trim(),contact:i.contact.trim(),...i.attach&&i.preview?{preview_token:i.preview.token}:{},idempotency_key:i.idempotencyKey}),s=e&&"object"==typeof e&&"report_id"in e?String(e.report_id||""):"";if(!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(s))throw{code:"support_unavailable"};if(clearTimeout(this._supportExpiryTimer),this._supportExpiryTimer=void 0,!this._supportPatch(t.draftId,{status:"success",reportId:s,errorCode:""}))return;this._focusSupport("#support-receipt")}catch(e){if(!this._supportPatch(t.draftId,{status:"error",errorCode:bd(e)}))return;this._focusSupport("#support-error")}}_supportErrorText(t){const e=l(this.host.hass,this.host._config?.language);if(t.errorCode.startsWith("validation.")){return ra(e,`support.validation.${t.errorCode.slice(11)}`)}return ra(e,`support.error.${t.errorCode||"support_unavailable"}`)}_supportMessageKeydown(t){"Enter"===t.key&&(t.ctrlKey||t.metaKey)&&(t.preventDefault(),this._submitSupport())}_renderSupportDialog(){const t=this.host._supportDialog,e=l(this.host.hass,this.host._config?.language),s="ru"===e?"https://github.com/Matysh/houseplan-card/blob/main/docs/USER-GUIDE.ru.md":"https://github.com/Matysh/houseplan-card/blob/main/docs/USER-GUIDE.md",i=dd(this.host._haSupportApi),o=(t,s)=>ra(e,t,s),a="building"===t.status||"sending"===t.status,n=md(t),r=t.preview?Math.max(0,Math.floor((Date.now()-t.preview.preparedAt)/6e4)):0,h="error"===t.status&&!t.errorCode.startsWith("validation."),c="validation.contact_too_long"===t.errorCode,u="validation.message_required"===t.errorCode||"validation.message_too_long"===t.errorCode;return p``}_supportPatch(t,e){const s=this.host._supportDialog;if(!s||s.draftId!==t)return null;const i={...s,...e};return this.host._supportDialog=i,i}async _focusSupport(t){await this.host.updateComplete,this.host.renderRoot.querySelector(t)?.focus({preventScroll:!0})}_updateSupportDraft(t,e){const s=this.host._supportDialog;if(!s||"building"===s.status||"sending"===s.status||"success"===s.status)return;const i={...s,[t]:e},o=_d({...i,attach:!1,preview:null});"message_required"===o&&"validation.message_required"===s.errorCode||"message_too_long"===o||"contact_too_long"===o?this._supportPatch(s.draftId,{[t]:e,status:"error",errorCode:`validation.${o}`}):i.attach&&i.preview&&i.preview.expiresAt<=Date.now()?this._supportPatch(s.draftId,{[t]:e,status:"error",errorCode:"support_preview_expired"}):this._supportPatch(s.draftId,{[t]:e,status:i.attach&&i.preview?"ready":"idle",errorCode:""})}async _discardSupportPreview(t){if(t)try{await this.host.hass.callWS({type:"houseplan/support/preview/discard",token:t})}catch{}}async _closeSupportDialog(){const t=this.host._supportDialog;if(t){if("building"===t.status||"sending"===t.status){const t=l(this.host.hass,this.host._config?.language);if(!await this.host._confirmDanger({key:"close-support-busy",kind:"warning",title:ra(t,"support.close_busy_title"),message:ra(t,"support.close_busy_body"),confirmLabel:this.host._t("btn.close"),cancelLabel:this.host._t("btn.cancel")}))return await this.host.updateComplete,void this.host.renderRoot.querySelector("#support-dialog")?.rejectClose()}clearTimeout(this._supportExpiryTimer),this._supportExpiryTimer=void 0,this.host._supportDialog=null,t.preview?.token&&"success"!==t.status&&this._discardSupportPreview(t.preview.token)}}_scheduleSupportExpiry(t,e){clearTimeout(this._supportExpiryTimer);const s=Math.max(0,e.expiresAt-Date.now());this._supportExpiryTimer=window.setTimeout(()=>{const s=this.host._supportDialog;s&&s.draftId===t&&s.preview?.token===e.token&&s.attach&&"success"!==s.status&&"sending"!==s.status&&this._supportPatch(t,{status:"error",errorCode:"support_preview_expired"})},Math.min(s+20,2147483647))}_supportFacts(){const t=this.host._haRegistry;return gd({userAgent:globalThis.navigator?.userAgent||"",language:l(this.host.hass,this.host._config?.language),registryAccess:t.access,registryLastSuccess:t.lastSuccess})}_supportPreviewRequestIsCurrent(t,e){const s=this.host._supportDialog;return e===this._supportPreviewGeneration&&s?.draftId===t&&s.attach}async _buildSupportPreview(t){const e=this.host._supportDialog;if(!e||e.draftId!==t||!e.attach||!cd(this.host._haSupportApi))return;const s=++this._supportPreviewGeneration;this._supportPatch(t,{status:"building",errorCode:""});let i="";try{const e=await this.host.hass.callWS({type:"houseplan/support/preview",card_version:fi(Bd),...this._supportFacts(),draft_id:t}),o=e&&"object"==typeof e?e:{},a=Date.now(),n="string"==typeof o.text?o.text:"",r=Number(o.size),l=Number(o.expires_in),h=Number(o.spaces),c=String(o.token||"");/^[0-9a-f]{48}$/.test(c)&&(i=c);const d=String(o.sha256||""),p=Number(o.version),u=String(o.format||""),_=(new TextEncoder).encode(n).byteLength;if(!/^[0-9a-f]{48}$/.test(c)||!/^[0-9a-f]{64}$/.test(d)||"houseplan-support-package"!==u||1!==p||!Number.isInteger(r)||r!==_||!Number.isInteger(h)||h<0||!Number.isFinite(l)||l<=0||l>600||!n.endsWith("\n"))throw{code:"support_rejected"};const m={token:c,expiresAt:a+1e3*l,size:r,sha256:d,spaces:h,format:u,version:p,text:n,preparedAt:a};if(!this._supportPreviewRequestIsCurrent(t,s))return i="",void this._discardSupportPreview(c);if(!this._supportPatch(t,{status:"ready",preview:m,errorCode:"",rawOpen:!1}))return i="",void this._discardSupportPreview(c);i="",this._scheduleSupportExpiry(t,m)}catch(e){if(i){const t=i;i="",this._discardSupportPreview(t)}if(!this._supportPreviewRequestIsCurrent(t,s))return;if(!this._supportPatch(t,{status:"error",errorCode:fd(e)}))return;this._focusSupport("#support-error")}}async _setSupportAttachment(t){const e=this.host._supportDialog;if(!e||"sending"===e.status||"success"===e.status)return;const s=e.preview?.token||"";if(!t)return this._supportPreviewGeneration+=1,clearTimeout(this._supportExpiryTimer),this._supportExpiryTimer=void 0,this._supportPatch(e.draftId,{attach:!1,status:"idle",preview:null,rawOpen:!1,errorCode:""}),void(s&&this._discardSupportPreview(s));this._supportPatch(e.draftId,{attach:!0,errorCode:""}),await this._buildSupportPreview(e.draftId)}async _refreshSupportPreview(){const t=this.host._supportDialog;t&&t.attach&&"building"!==t.status&&"sending"!==t.status&&await this._buildSupportPreview(t.draftId)}_downloadSupportPreview(){const t=this.host._supportDialog?.preview;if(!t)return;const e=new Blob([t.text],{type:"application/json;charset=utf-8"}),s=URL.createObjectURL(e),i=document.createElement("a");i.href=s,i.download=`houseplan-support-${t.sha256.slice(0,12)}.json`,i.style.display="none",document.body.append(i),i.click(),i.remove(),window.setTimeout(()=>URL.revokeObjectURL(s),0)}async _copySupportText(t,e){const s=l(this.host.hass,this.host._config?.language);try{await navigator.clipboard.writeText(t),this.host._showToast(ra(s,e))}catch{this.host._showToast(ra(s,"support.copy_failed"))}}async _submitSupport(){const t=this.host._supportDialog;if(!t||!cd(this.host._haSupportApi))return;const e=_d(t);if(e)return this._supportPatch(t.draftId,{status:"error",errorCode:`validation.${e}`}),void this._focusSupport("#support-message");if(!md(t))return;const s=pd(t),i=this._supportPatch(t.draftId,{status:"sending",errorCode:"",idempotencyKey:s.idempotencyKey,submissionFingerprint:s.fingerprint});if(i)try{const e=await this.host.hass.callWS({type:"houseplan/support/submit",message:i.message.trim(),contact:i.contact.trim(),...i.attach&&i.preview?{preview_token:i.preview.token}:{},idempotency_key:i.idempotencyKey}),s=e&&"object"==typeof e&&"report_id"in e?String(e.report_id||""):"";if(!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(s))throw{code:"support_unavailable"};if(clearTimeout(this._supportExpiryTimer),this._supportExpiryTimer=void 0,!this._supportPatch(t.draftId,{status:"success",reportId:s,errorCode:""}))return;this._focusSupport("#support-receipt")}catch(e){if(!this._supportPatch(t.draftId,{status:"error",errorCode:fd(e)}))return;this._focusSupport("#support-error")}}_supportErrorText(t){const e=l(this.host.hass,this.host._config?.language);if(t.errorCode.startsWith("validation.")){return ra(e,`support.validation.${t.errorCode.slice(11)}`)}return ra(e,`support.error.${t.errorCode||"support_unavailable"}`)}_supportMessageKeydown(t){"Enter"===t.key&&(t.ctrlKey||t.metaKey)&&(t.preventDefault(),this._submitSupport())}_renderSupportDialog(){const t=this.host._supportDialog,e=l(this.host.hass,this.host._config?.language),s="ru"===e?"https://github.com/Matysh/houseplan-card/blob/main/docs/USER-GUIDE.ru.md":"https://github.com/Matysh/houseplan-card/blob/main/docs/USER-GUIDE.md",i=cd(this.host._haSupportApi),o=(t,s)=>ra(e,t,s),a="building"===t.status||"sending"===t.status,n=_d(t),r=t.preview?Math.max(0,Math.floor((Date.now()-t.preview.preparedAt)/6e4)):0,h="error"===t.status&&!t.errorCode.startsWith("validation."),c="validation.contact_too_long"===t.errorCode,u="validation.message_required"===t.errorCode||"validation.message_too_long"===t.errorCode;return p`{this._closeSupportDialog()}}>

    ${o("support.about_group")}

    -
    ${this.host._t("gs.about_version",{v:fi(Hd)})}
    +
    ${this.host._t("gs.about_version",{v:fi(Bd)})}
    - `;var _}_preflightDiagnostics(t,e){const s=new Map((e?.spaces||[]).map(t=>[String(t?.id||""),t]));return{kind:"houseplan-optimize-preflight",origin:"runtime",cardVersion:fi(Hd),checkedAt:(new Date).toISOString(),preflightFingerprint:t.fingerprint,failures:t.failures.map(t=>({spaceId:t.spaceId,displayName:t.displayName,reason:t.reason,detail:t.detail??null,spaceGeometryFingerprint:s.has(t.spaceId)?Yt(s.get(t.spaceId)):null}))}}_reportPreflightFailure(t,e){t.ok||t.fingerprint===this.host._reportedPreflightFingerprint||(this.host._reportedPreflightFingerprint=t.fingerprint,console.warn("[houseplan] optimize preflight failed",this._preflightDiagnostics(t,e)))}_preflightVersionsDiffer(){const t=this.host._haIntegrationVersion;return"string"==typeof t&&t.length>0&&t!==fi(Hd)}async _copyPreflightDiagnostics(){const t=this.host._alignDialog?.preflight;if(!t||t.ok)return;const e=JSON.stringify(this._preflightDiagnostics(t,this.host._alignDialog?.config??null),null,2);try{await navigator.clipboard.writeText(e),this.host._preflightClipboardFallback=null,this.host._showToast(this.host._t("gs.preflight_copied"))}catch{this.host._preflightClipboardFallback=e}}_checkOptimizeGeometryImpl(t){return bi(t,{fallbackSpaceName:t=>this.host._t("gs.align_preflight_space",{n:String(t)})})}_checkSpacePhysicalGeometryImpl(t,e,s){return vi(t,e,{fallbackSpaceName:t=>this.host._t("gs.align_preflight_space",{n:String(t)}),captureWallGeometry:s?(t,e)=>s(e):void 0})}_optimizeReferenceContext(t){const e=this.host._haRegistry,s=this.host._fullRegistryHass,i={},o=(...t)=>{for(const e of t){const t=String(e||"").trim();if(t)return t}return""};for(const[t,s]of Object.entries(e.devices||{}))i[t]=o(s?.name_by_user,s?.name,s?.model);for(const[t,s]of Object.entries(e.entities||{}))i[`lg_${t}`]=o(this.host.hass?.states?.[t]?.attributes?.friendly_name,s?.name,s?.original_name);for(const t of this.host._devices)i[t.id]=o(t.name,i[t.id]);for(const t of this.host._serverCfg?.markers||[]){const e=String(t.binding||"").indexOf(":"),a=e>0?t.binding.slice(0,e):"",n=e>0?t.binding.slice(e+1):"",r="device"===a?s?.devices?.[n]:"entity"===a?s?.entities?.[n]:null;i[t.id]=o(t.name,"device"===a?r?.name_by_user:null,r?.name,"entity"===a?this.host.hass?.states?.[n]?.attributes?.friendly_name:null,i[t.id])}return{effectiveAreaByMarker:Object.fromEntries(this.host._devices.filter(t=>!t.virtual&&!!t.area).map(t=>[t.id,t.area])),ownerRoster:{authoritative:e.authoritative,deviceIds:Object.keys(e.devices||{}),entityIds:[...new Set([...Object.keys(e.entities||{}),...Object.keys(this.host.hass?.states||{})])],names:i},removeLiveMissingPositions:t}}_previewAlignDialog(t){if(!this.host._norm||!this.host._serverCfg)return;const e=this.host._serverCfg.spaces||[];let s;try{s=ar(this.host._serverCfg,this.host._layout||{},this._optimizeReferenceContext(t))}catch(t){return void this._showWallModelMigrationBlocked(t)}const i=s.changed?this.host._checkOptimizeGeometry(s.config):null;i&&this._reportPreflightFailure(i,s.config);const o=Math.ceil(10*s.report.maxShiftCm)/10,a=e.find(t=>null!=t?.id&&String(t.id)===s.report.maxSpace),n=e.length>1&&a?String(a.title||a.id):"";this.host._preflightClipboardFallback=null,this.host._alignDialog={report:s.report,config:s.config,layout:s.layout,cm:o,where:n,preflight:i,changed:s.changed,busy:!1,removeLiveMissingPositions:t}}async _runAlignToGrid(){let t=this.host._alignDialog;if(!t||t.busy||!this.host._serverCfg||!t.changed||!t.preflight?.ok)return;const e=wt(t.config);if(t.preflight.fingerprint!==e){const e=this.host._checkOptimizeGeometry(t.config);if(this._reportPreflightFailure(e,t.config),t={...t,preflight:e},this.host._alignDialog=t,!e.ok)return}this._clearGeometryGesture(),this.host._alignDialog={...t,busy:!0};try{await nr(this.host,t.config,t.layout),this.host._alignDialog=null,this.host._preflightClipboardFallback=null,this.host._showToast(this.host._t("gs.align_done",{n:String(t.report.moved),m:String(t.report.migrated+t.report.canonicalized+t.report.coordsCanonicalized+t.report.latticeCoordinatesCanonicalized+t.report.wallsMerged+t.report.spansMerged+t.report.partitionsMerged+t.report.partitionsReconciled+t.report.openingsRehosted+t.report.wallsStraightened),r:String(t.report.spaceRefsRemapped+t.report.roomRefsRemapped+t.report.positionsRemapped+t.report.markersDetached+t.report.orphanRoomLabelsRemoved+t.report.orphanDevicePositionsRemoved+t.report.orphanGroupPositionsRemoved)}))}catch(t){if(this.host._alignDialog&&(this.host._alignDialog={...this.host._alignDialog,busy:!1}),"wall_model_client_outdated"===t?.code)return void this.host._showToast(this.host._t("toast.wall_model_client_outdated"));"conflict"===t?.code&&await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _undoPlanOptimization(){if(!this.host._canOptimizeUndo||this.host._optimizeUndoBusy)return;const t=this.host._undoKind;this._clearGeometryGesture(),this.host._optimizeUndoBusy=!0,this.host.requestUpdate();try{await this.host.hass.callWS({type:"houseplan/plan/optimize_undo",expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev});const[e,s]=await Promise.all([this.host._getAuthoritativeConfig(),this.host.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this.host._adoptAuthoritative({cfgResp:e,layResp:s,reason:"optimize-undo",profile:"post-write"})).status)return;this.host._geometryHistory.clear(),this.host._cancelDeviceDrag(),this.host._devicePositionHistory.clear(),this.host._canOptimizeUndo=!1,this.host._undoKind=null,this.host._cfgEpoch++,this.host._modelCache=null,this.host._frame=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._cacheSnapshot(),this.host.requestUpdate(),this.host._showToast(this.host._t("import"===t?"backup.import_undone":"gs.optimize_undone"))}catch(t){this.host._canOptimizeUndo=!1,this.host._undoKind=null,this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}finally{this.host._optimizeUndoBusy=!1,this.host.requestUpdate()}}async _runBackupExport(){const t=this.host._backupExportDialog;if(t&&!t.busy){this.host._backupExportDialog={...t,busy:!0,error:""};try{const e=await this.host.hass.callWS({type:"houseplan/export/create",kind:t.kind,space_id:"space"===t.kind?this.host._space:void 0,..."space"===t.kind&&t.planOnly?{plan_only:!0}:{},card_version:fi(Hd)}),s=new Blob([JSON.stringify(e.document,null,2)+"\n"],{type:"application/json;charset=utf-8"}),i=URL.createObjectURL(s),o=document.createElement("a");o.href=i,o.download=e.filename||`houseplan-${t.kind}.json`,o.style.display="none",document.body.append(o),o.click(),o.remove(),window.setTimeout(()=>URL.revokeObjectURL(i),0),this.host._backupExportDialog=null,this.host._showToast(this.host._t("backup.export_done"))}catch(t){this.host._backupExportDialog&&(this.host._backupExportDialog={...this.host._backupExportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _pickBackupImport(t){const e=t.target,s=e.files?.[0];if(e.value="",s){this.host._settingsDialog=null,this.host._backupImportDialog={filename:s.name,size:s.size,token:"",preview:null,expectedConfigRev:this.host._cfgRev,expectedLayoutRev:this.host._layoutRev,duplicatePolicy:"skip",confirmMissing:!1,busy:!0,error:""};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),await this.host._writeChain,this.host._persistLayout.pending()&&this.host._persistLayout.flush();const t="/api/houseplan/import/preview?duplicate_policy=skip",e={method:"POST",body:s,headers:{"content-type":"application/json"}},i=this.host.hass?.fetchWithAuth?await this.host.hass.fetchWithAuth(t,e):await fetch(t,{...e,headers:{...e.headers,...this.host.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.host.hass.auth.data.access_token}`}:{}}}),o=await i.json().catch(()=>({}));if(!i.ok||o.error)throw Object.assign(new Error(o.message||o.error||`HTTP ${i.status}`),{code:o.error});this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,token:o.token,preview:o.preview,expectedConfigRev:o.expected_config_rev,expectedLayoutRev:o.expected_layout_rev,busy:!1})}catch(t){this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _setBackupDuplicatePolicy(t){const e=this.host._backupImportDialog;if(e&&!e.busy&&e.token&&t!==e.duplicatePolicy){this.host._backupImportDialog={...e,duplicatePolicy:t,busy:!0,error:""};try{const s=await this.host.hass.callWS({type:"houseplan/import/revalidate",token:e.token,duplicate_policy:t});this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,preview:{...e.preview,...s.preview},expectedConfigRev:s.expected_config_rev,expectedLayoutRev:s.expected_layout_rev,confirmMissing:!1,busy:!1})}catch(t){this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,duplicatePolicy:e.duplicatePolicy,preview:e.preview,confirmMissing:e.confirmMissing,busy:!1,error:this._backupErrorText(t)})}}}async _applyBackupImport(){const t=this.host._backupImportDialog;if(!t||t.busy||!t.token||!t.preview)return;if(t.preview.confirmation_required&&!t.confirmMissing)return;this.host._backupImportDialog={...t,busy:!0,error:""};const e=this.host._space;try{const s=await this.host.hass.callWS({type:"houseplan/import/apply",token:t.token,expected_config_rev:t.expectedConfigRev,expected_layout_rev:t.expectedLayoutRev,duplicate_policy:t.duplicatePolicy,confirm_missing_content:t.confirmMissing}),[i,o]=await Promise.all([this.host._getAuthoritativeConfig(),this.host.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this.host._adoptAuthoritative({cfgResp:i,layResp:o,reason:"import-apply",profile:"post-write"})).status)return this.host._backupImportDialog={...t,busy:!1,error:""},void this.host.requestUpdate();this.host._geometryHistory.clear(),this.host._dirtyPos.clear(),this.host._sentPos.clear(),this.host._defPos={},this.host._cfgEpoch++,this.host._modelCache=null,this.host._frame=null,this.host._visibleDeviceSnapshot=null,this.host._candidateDeviceSnapshot=null,this.host._stagedDeviceSnapshotToken=-1,this.host._capturedSnapshotConfigEpoch=-1,this.host._regSignature="",this.host._signer.invalidate(this.host.hass),this.host._resign(),this.host._maybeRebuildDevices();const a=this.host._serverCfg?.spaces||[],n="space"===s.kind&&s.space_id?s.space_id:a.some(t=>t.id===e)?e:a[0]?.id||this.host._space;this.host._hasFixedFloor?this.host._adoptInitialSpace(this.host._model,!0):this.host._commitSpace(n),this.host._backupImportDialog=null,this.host._cacheSnapshot(),this.host.requestUpdate();const r="space"===s.kind?t.preview.counts:s.counts;this.host._showToast(this.host._t("space"===s.kind?"backup.space_done":"backup.full_done",{spaces:String(r?.spaces||0),rooms:String(r?.rooms||0),markers:String(r?.markers||0),refs:String(s.repaired_target_refs||0)}))}catch(t){if("conflict"===t?.code&&this.host._backupImportDialog?.token)try{const t=this.host._backupImportDialog,e=await this.host.hass.callWS({type:"houseplan/import/revalidate",token:t.token,duplicate_policy:t.duplicatePolicy});return void(this.host._backupImportDialog={...t,preview:{...t.preview,...e.preview},expectedConfigRev:e.expected_config_rev,expectedLayoutRev:e.expected_layout_rev,confirmMissing:!1,busy:!1,error:this.host._t("backup.revalidated")})}catch(e){t=e}this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}_renderBackupExportDialog(){const t=this.host._backupExportDialog,e=(this.host._serverCfg?.spaces||[]).find(t=>t.id===this.host._space);return p``;var _}_preflightDiagnostics(t,e){const s=new Map((e?.spaces||[]).map(t=>[String(t?.id||""),t]));return{kind:"houseplan-optimize-preflight",origin:"runtime",cardVersion:fi(Bd),checkedAt:(new Date).toISOString(),preflightFingerprint:t.fingerprint,failures:t.failures.map(t=>({spaceId:t.spaceId,displayName:t.displayName,reason:t.reason,detail:t.detail??null,spaceGeometryFingerprint:s.has(t.spaceId)?Yt(s.get(t.spaceId)):null}))}}_reportPreflightFailure(t,e){t.ok||t.fingerprint===this.host._reportedPreflightFingerprint||(this.host._reportedPreflightFingerprint=t.fingerprint,console.warn("[houseplan] optimize preflight failed",this._preflightDiagnostics(t,e)))}_preflightVersionsDiffer(){const t=this.host._haIntegrationVersion;return"string"==typeof t&&t.length>0&&t!==fi(Bd)}async _copyPreflightDiagnostics(){const t=this.host._alignDialog?.preflight;if(!t||t.ok)return;const e=JSON.stringify(this._preflightDiagnostics(t,this.host._alignDialog?.config??null),null,2);try{await navigator.clipboard.writeText(e),this.host._preflightClipboardFallback=null,this.host._showToast(this.host._t("gs.preflight_copied"))}catch{this.host._preflightClipboardFallback=e}}_checkOptimizeGeometryImpl(t){return bi(t,{fallbackSpaceName:t=>this.host._t("gs.align_preflight_space",{n:String(t)})})}_checkSpacePhysicalGeometryImpl(t,e,s){return vi(t,e,{fallbackSpaceName:t=>this.host._t("gs.align_preflight_space",{n:String(t)}),captureWallGeometry:s?(t,e)=>s(e):void 0})}_optimizeReferenceContext(t){const e=this.host._haRegistry,s=this.host._fullRegistryHass,i={},o=(...t)=>{for(const e of t){const t=String(e||"").trim();if(t)return t}return""};for(const[t,s]of Object.entries(e.devices||{}))i[t]=o(s?.name_by_user,s?.name,s?.model);for(const[t,s]of Object.entries(e.entities||{}))i[`lg_${t}`]=o(this.host.hass?.states?.[t]?.attributes?.friendly_name,s?.name,s?.original_name);for(const t of this.host._devices)i[t.id]=o(t.name,i[t.id]);for(const t of this.host._serverCfg?.markers||[]){const e=String(t.binding||"").indexOf(":"),a=e>0?t.binding.slice(0,e):"",n=e>0?t.binding.slice(e+1):"",r="device"===a?s?.devices?.[n]:"entity"===a?s?.entities?.[n]:null;i[t.id]=o(t.name,"device"===a?r?.name_by_user:null,r?.name,"entity"===a?this.host.hass?.states?.[n]?.attributes?.friendly_name:null,i[t.id])}return{effectiveAreaByMarker:Object.fromEntries(this.host._devices.filter(t=>!t.virtual&&!!t.area).map(t=>[t.id,t.area])),ownerRoster:{authoritative:e.authoritative,deviceIds:Object.keys(e.devices||{}),entityIds:[...new Set([...Object.keys(e.entities||{}),...Object.keys(this.host.hass?.states||{})])],names:i},removeLiveMissingPositions:t}}_previewAlignDialog(t){if(!this.host._norm||!this.host._serverCfg)return;const e=this.host._serverCfg.spaces||[];let s;try{s=or(this.host._serverCfg,this.host._layout||{},this._optimizeReferenceContext(t))}catch(t){return void this._showWallModelMigrationBlocked(t)}const i=s.changed?this.host._checkOptimizeGeometry(s.config):null;i&&this._reportPreflightFailure(i,s.config);const o=Math.ceil(10*s.report.maxShiftCm)/10,a=e.find(t=>null!=t?.id&&String(t.id)===s.report.maxSpace),n=e.length>1&&a?String(a.title||a.id):"";this.host._preflightClipboardFallback=null,this.host._alignDialog={report:s.report,config:s.config,layout:s.layout,cm:o,where:n,preflight:i,changed:s.changed,busy:!1,removeLiveMissingPositions:t}}async _runAlignToGrid(){let t=this.host._alignDialog;if(!t||t.busy||!this.host._serverCfg||!t.changed||!t.preflight?.ok)return;const e=yt(t.config);if(t.preflight.fingerprint!==e){const e=this.host._checkOptimizeGeometry(t.config);if(this._reportPreflightFailure(e,t.config),t={...t,preflight:e},this.host._alignDialog=t,!e.ok)return}this._clearGeometryGesture(),this.host._alignDialog={...t,busy:!0};try{await ar(this.host,t.config,t.layout),this.host._alignDialog=null,this.host._preflightClipboardFallback=null,this.host._showToast(this.host._t("gs.align_done",{n:String(t.report.moved),m:String(t.report.migrated+t.report.canonicalized+t.report.coordsCanonicalized+t.report.latticeCoordinatesCanonicalized+t.report.wallsMerged+t.report.spansMerged+t.report.partitionsMerged+t.report.partitionsReconciled+t.report.openingsRehosted+t.report.wallsStraightened),r:String(t.report.spaceRefsRemapped+t.report.roomRefsRemapped+t.report.positionsRemapped+t.report.markersDetached+t.report.orphanRoomLabelsRemoved+t.report.orphanDevicePositionsRemoved+t.report.orphanGroupPositionsRemoved)}))}catch(t){if(this.host._alignDialog&&(this.host._alignDialog={...this.host._alignDialog,busy:!1}),"wall_model_client_outdated"===t?.code)return void this.host._showToast(this.host._t("toast.wall_model_client_outdated"));"conflict"===t?.code&&await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _undoPlanOptimization(){if(!this.host._canOptimizeUndo||this.host._optimizeUndoBusy)return;const t=this.host._undoKind;this._clearGeometryGesture(),this.host._optimizeUndoBusy=!0,this.host.requestUpdate();try{await this.host.hass.callWS({type:"houseplan/plan/optimize_undo",expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev});const[e,s]=await Promise.all([this.host._getAuthoritativeConfig(),this.host.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this.host._adoptAuthoritative({cfgResp:e,layResp:s,reason:"optimize-undo",profile:"post-write"})).status)return;this.host._geometryHistory.clear(),this.host._cancelDeviceDrag(),this.host._devicePositionHistory.clear(),this.host._canOptimizeUndo=!1,this.host._undoKind=null,this.host._cfgEpoch++,this.host._modelCache=null,this.host._frame=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._cacheSnapshot(),this.host.requestUpdate(),this.host._showToast(this.host._t("import"===t?"backup.import_undone":"gs.optimize_undone"))}catch(t){this.host._canOptimizeUndo=!1,this.host._undoKind=null,this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}finally{this.host._optimizeUndoBusy=!1,this.host.requestUpdate()}}async _runBackupExport(){const t=this.host._backupExportDialog;if(t&&!t.busy){this.host._backupExportDialog={...t,busy:!0,error:""};try{const e=await this.host.hass.callWS({type:"houseplan/export/create",kind:t.kind,space_id:"space"===t.kind?this.host._space:void 0,..."space"===t.kind&&t.planOnly?{plan_only:!0}:{},card_version:fi(Bd)}),s=new Blob([JSON.stringify(e.document,null,2)+"\n"],{type:"application/json;charset=utf-8"}),i=URL.createObjectURL(s),o=document.createElement("a");o.href=i,o.download=e.filename||`houseplan-${t.kind}.json`,o.style.display="none",document.body.append(o),o.click(),o.remove(),window.setTimeout(()=>URL.revokeObjectURL(i),0),this.host._backupExportDialog=null,this.host._showToast(this.host._t("backup.export_done"))}catch(t){this.host._backupExportDialog&&(this.host._backupExportDialog={...this.host._backupExportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _pickBackupImport(t){const e=t.target,s=e.files?.[0];if(e.value="",s){this.host._settingsDialog=null,this.host._backupImportDialog={filename:s.name,size:s.size,token:"",preview:null,expectedConfigRev:this.host._cfgRev,expectedLayoutRev:this.host._layoutRev,duplicatePolicy:"skip",confirmMissing:!1,busy:!0,error:""};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),await this.host._writeChain,this.host._persistLayout.pending()&&this.host._persistLayout.flush();const t="/api/houseplan/import/preview?duplicate_policy=skip",e={method:"POST",body:s,headers:{"content-type":"application/json"}},i=this.host.hass?.fetchWithAuth?await this.host.hass.fetchWithAuth(t,e):await fetch(t,{...e,headers:{...e.headers,...this.host.hass?.auth?.data?.access_token?{authorization:`Bearer ${this.host.hass.auth.data.access_token}`}:{}}}),o=await i.json().catch(()=>({}));if(!i.ok||o.error)throw Object.assign(new Error(o.message||o.error||`HTTP ${i.status}`),{code:o.error});this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,token:o.token,preview:o.preview,expectedConfigRev:o.expected_config_rev,expectedLayoutRev:o.expected_layout_rev,busy:!1})}catch(t){this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}}async _setBackupDuplicatePolicy(t){const e=this.host._backupImportDialog;if(e&&!e.busy&&e.token&&t!==e.duplicatePolicy){this.host._backupImportDialog={...e,duplicatePolicy:t,busy:!0,error:""};try{const s=await this.host.hass.callWS({type:"houseplan/import/revalidate",token:e.token,duplicate_policy:t});this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,preview:{...e.preview,...s.preview},expectedConfigRev:s.expected_config_rev,expectedLayoutRev:s.expected_layout_rev,confirmMissing:!1,busy:!1})}catch(t){this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,duplicatePolicy:e.duplicatePolicy,preview:e.preview,confirmMissing:e.confirmMissing,busy:!1,error:this._backupErrorText(t)})}}}async _applyBackupImport(){const t=this.host._backupImportDialog;if(!t||t.busy||!t.token||!t.preview)return;if(t.preview.confirmation_required&&!t.confirmMissing)return;this.host._backupImportDialog={...t,busy:!0,error:""};const e=this.host._space;try{const s=await this.host.hass.callWS({type:"houseplan/import/apply",token:t.token,expected_config_rev:t.expectedConfigRev,expected_layout_rev:t.expectedLayoutRev,duplicate_policy:t.duplicatePolicy,confirm_missing_content:t.confirmMissing}),[i,o]=await Promise.all([this.host._getAuthoritativeConfig(),this.host.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this.host._adoptAuthoritative({cfgResp:i,layResp:o,reason:"import-apply",profile:"post-write"})).status)return this.host._backupImportDialog={...t,busy:!1,error:""},void this.host.requestUpdate();this.host._geometryHistory.clear(),this.host._dirtyPos.clear(),this.host._sentPos.clear(),this.host._defPos={},this.host._cfgEpoch++,this.host._modelCache=null,this.host._frame=null,this.host._visibleDeviceSnapshot=null,this.host._candidateDeviceSnapshot=null,this.host._stagedDeviceSnapshotToken=-1,this.host._capturedSnapshotConfigEpoch=-1,this.host._regSignature="",this.host._signer.invalidate(this.host.hass),this.host._resign(),this.host._maybeRebuildDevices();const a=this.host._serverCfg?.spaces||[],n="space"===s.kind&&s.space_id?s.space_id:a.some(t=>t.id===e)?e:a[0]?.id||this.host._space;this.host._hasFixedFloor?this.host._adoptInitialSpace(this.host._model,!0):this.host._commitSpace(n),this.host._backupImportDialog=null,this.host._cacheSnapshot(),this.host.requestUpdate();const r="space"===s.kind?t.preview.counts:s.counts;this.host._showToast(this.host._t("space"===s.kind?"backup.space_done":"backup.full_done",{spaces:String(r?.spaces||0),rooms:String(r?.rooms||0),markers:String(r?.markers||0),refs:String(s.repaired_target_refs||0)}))}catch(t){if("conflict"===t?.code&&this.host._backupImportDialog?.token)try{const t=this.host._backupImportDialog,e=await this.host.hass.callWS({type:"houseplan/import/revalidate",token:t.token,duplicate_policy:t.duplicatePolicy});return void(this.host._backupImportDialog={...t,preview:{...t.preview,...e.preview},expectedConfigRev:e.expected_config_rev,expectedLayoutRev:e.expected_layout_rev,confirmMissing:!1,busy:!1,error:this.host._t("backup.revalidated")})}catch(e){t=e}this.host._backupImportDialog&&(this.host._backupImportDialog={...this.host._backupImportDialog,busy:!1,error:this._backupErrorText(t)})}}_renderBackupExportDialog(){const t=this.host._backupExportDialog,e=(this.host._serverCfg?.spaces||[]).find(t=>t.id===this.host._space);return p`this.host._backupExportDialog=null}>
    ${this.host._t("backup.export_hint")}
    @@ -1672,7 +1672,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${t.busy?"…":this.host._t("full"===e.kind?"backup.replace":"backup.add")} `:d}
    -
    `}_setFillColor(t,e){const s=this.host._settingsDialog;this.host._settingsDialog={...s,colors:{...s.colors,[t]:{...s.colors[t],...e}}}}_updateDecorStyle(t){this.host._decorStyle=t,null!==this._decorStylePersistTimer&&window.clearTimeout(this._decorStylePersistTimer),this._decorStylePersistTimer=window.setTimeout(()=>{this._decorStylePersistTimer=null,this._persistDecorStyle()},1e3)}_persistDecorStyle(){const t=this.host._serverCfg;if(!t)return;const e=yi(this.host._decorStyle),s={...t.settings},i=JSON.stringify(s.decor_default_style??null);e?s.decor_default_style=e:delete s.decor_default_style,JSON.stringify(s.decor_default_style??null)!==i&&(this.host._serverCfg={...t,settings:s},this._saveConfig())}async _saveSettingsDialog(){const t=this.host._settingsDialog;if(!t||t.busy)return;this.host._settingsDialog={...t,busy:!0};let e=null;try{const s=this.host._serverCfg,i=JSON.stringify(t.colors)===JSON.stringify(xt);let o={...s.settings};i?delete o.fill_colors:o.fill_colors=t.colors;const a=this.host._imperial?30.48*t.glowRadius:100*t.glowRadius;Number.isFinite(a)&&a>0&&300!==Math.round(a)?o.glow_radius_cm=Math.round(a):delete o.glow_radius_cm,t.bgColor?o.bg_color=t.bgColor:delete o.bg_color,null!==t.northDeg&&Number.isInteger(t.northDeg)&&t.northDeg>=0&&t.northDeg<=359?o.north_deg=t.northDeg:delete o.north_deg,o.bg_mode=t.bgMode,t.sunRays?o.sun_rays=!0:delete o.sun_rays,o.sun_ray_origin=t.sunRayOrigin,t.showRoomTooltip?delete o.show_room_tooltip:o.show_room_tooltip=!1;const n=o.radar;n&&null!=n.version&&1!==n.version||(o.radar={...n||{},version:1},t.radarShowLive?delete o.radar.show_live:o.radar.show_live=!1),o=wi(o,t.zigbeeTopology),delete o.weather_entity;const r={...s,settings:o};e=this.host._adoption.beginOptimistic(s,r),this.host._serverCfg=r,await this._saveConfigNow(e),!t.showRoomTooltip&&this.host._tip?.room&&(this.host._tip=null),this.host._settingsDialog=null,this.host.requestUpdate(),this.host._showToast(this.host._t("gs.saved"))}catch(t){e&&this.host._rollbackOptimistic(e),this.host._settingsDialog&&(this.host._settingsDialog={...this.host._settingsDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_boolInput(t,e,s=!1){const i=t=>e(!!t.target.checked);return customElements.get("ha-switch")?p``:p``}_rangeInput(t,e,s,i,o,a=!1,n){const r=t=>{const e=Number(t.target.value);Number.isFinite(e)&&o(e)};return customElements.get("ha-slider")?p``}_setFillColor(t,e){const s=this.host._settingsDialog;this.host._settingsDialog={...s,colors:{...s.colors,[t]:{...s.colors[t],...e}}}}_updateDecorStyle(t){this.host._decorStyle=t,null!==this._decorStylePersistTimer&&window.clearTimeout(this._decorStylePersistTimer),this._decorStylePersistTimer=window.setTimeout(()=>{this._decorStylePersistTimer=null,this._persistDecorStyle()},1e3)}_persistDecorStyle(){const t=this.host._serverCfg;if(!t)return;const e=yi(this.host._decorStyle),s={...t.settings},i=JSON.stringify(s.decor_default_style??null);e?s.decor_default_style=e:delete s.decor_default_style,JSON.stringify(s.decor_default_style??null)!==i&&(this.host._serverCfg={...t,settings:s},this._saveConfig())}async _saveSettingsDialog(){const t=this.host._settingsDialog;if(!t||t.busy)return;this.host._settingsDialog={...t,busy:!0};let e=null;try{const s=this.host._serverCfg,i=JSON.stringify(t.colors)===JSON.stringify(kt);let o={...s.settings};i?delete o.fill_colors:o.fill_colors=t.colors;const a=this.host._imperial?30.48*t.glowRadius:100*t.glowRadius;Number.isFinite(a)&&a>0&&300!==Math.round(a)?o.glow_radius_cm=Math.round(a):delete o.glow_radius_cm,t.bgColor?o.bg_color=t.bgColor:delete o.bg_color,null!==t.northDeg&&Number.isInteger(t.northDeg)&&t.northDeg>=0&&t.northDeg<=359?o.north_deg=t.northDeg:delete o.north_deg,o.bg_mode=t.bgMode,t.sunRays?o.sun_rays=!0:delete o.sun_rays,o.sun_ray_origin=t.sunRayOrigin,t.showRoomTooltip?delete o.show_room_tooltip:o.show_room_tooltip=!1;const n=o.radar;n&&null!=n.version&&1!==n.version||(o.radar={...n||{},version:1},t.radarShowLive?delete o.radar.show_live:o.radar.show_live=!1),o=wi(o,t.zigbeeTopology),delete o.weather_entity;const r={...s,settings:o};e=this.host._adoption.beginOptimistic(s,r),this.host._serverCfg=r,await this._saveConfigNow(e),!t.showRoomTooltip&&this.host._tip?.room&&(this.host._tip=null),this.host._settingsDialog=null,this.host.requestUpdate(),this.host._showToast(this.host._t("gs.saved"))}catch(t){e&&this.host._rollbackOptimistic(e),this.host._settingsDialog&&(this.host._settingsDialog={...this.host._settingsDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_boolInput(t,e,s=!1){const i=t=>e(!!t.target.checked);return customElements.get("ha-switch")?p``:p``}_rangeInput(t,e,s,i,o,a=!1,n){const r=t=>{const e=Number(t.target.value);Number.isFinite(e)&&o(e)};return customElements.get("ha-slider")?p``:p``}_renderAlignDialog(){const t=this.host._alignDialog,e=t.report,s=t.changed&&!t.preflight?.ok,i=t.preflight?.failures||[],o=i.slice(0,3).map(t=>t.displayName),a=o.length?o.join(", "):this.host._t("gs.align_preflight_space",{n:"1"}),n=Math.max(0,i.length-o.length),r=n?this.host._t("gs.align_preflight_more",{n:String(n)}):"",l=e.spaceRefsRemapped+e.roomRefsRemapped+e.positionsRemapped+e.markersDetached,h=e.migrated+e.canonicalized+e.coordsCanonicalized+e.wallSegmentsMigrated+e.roomDraftsMigrated+e.roomDraftSegmentsMigrated+e.wallsMerged+e.spansMerged+e.partitionsMerged+e.partitionsReconciled+e.openingsRehosted,c=e.moved+e.rotated+e.coordsCanonicalized+e.wallsStraightened,u=Math.ceil(10*e.maxStraightenShiftCm)/10,_=(this.host._serverCfg?.spaces||[]).find(t=>String(t?.id||"")===e.maxStraightenSpace),m=(this.host._serverCfg?.spaces||[]).length>1&&_?String(_.title||_.id):"",g=e.orphanRoomLabelsRemoved+e.orphanDevicePositionsRemoved+e.orphanGroupPositionsRemoved,f=e.liveMissingPositions.map(t=>t.name).filter(Boolean),b=f.slice(0,3).join(", "),v=Math.max(0,f.length-3),y=b?this.host._t("gs.optimize_live_names",{names:b,more:v?this.host._t("gs.optimize_reference_more",{n:String(v)}):""}):"",w=e.unverifiedPositions.some(t=>"registry_unavailable"===t.reason),$=t=>e.removedPositions.some(e=>e.id===t.id)?this.host._t("gs.optimize_detail_removed"):e.liveMissingPositions.some(e=>e.id===t.id)?this.host._t("gs.optimize_detail_live"):this.host._t("gs.optimize_detail_unverified"),k=t=>this.host._t("room_label"===t?"gs.optimize_detail_room_label":"group"===t?"gs.optimize_detail_group":"device"===t?"gs.optimize_detail_device":"gs.optimize_detail_unknown"),x=[...e.removedPositions,...e.liveMissingPositions.filter(t=>!e.removedPositions.some(e=>e.id===t.id)),...e.unverifiedPositions],M=x.slice(0,10),C=Math.max(0,x.length-M.length);return p`{this.host._alignDialog=null,this.host._preflightClipboardFallback=null}}> @@ -1752,7 +1752,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${t.busy?"…":this.host._t("gs.align_run")} `:d}
    -
    `}_renderSettingsDialog(){return xr.call(this)}_rulesSet(t){this.host._rulesDialog={...this.host._rulesDialog,rules:t}}async _saveRules(){const t=this.host._rulesDialog;if(!t||t.busy)return;const e=t.rules.filter(t=>t.pattern.trim()&&t.icon.trim());this.host._rulesDialog={...t,busy:!0};try{const t=this.host._serverCfg,s=JSON.stringify(e)===JSON.stringify(Fe),i={...t.settings};s?delete i.icon_rules:i.icon_rules=e,this.host._serverCfg={...t,settings:i},await this._saveConfigNow(),this.host._rulesDialog=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("rules.saved"))}catch(t){this.host._rulesDialog&&(this.host._rulesDialog={...this.host._rulesDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_renderRulesDialog(){const t=this.host._rulesDialog,e=ki(t.rules),s=t.test.trim()?xi(t.test,"",e):null,i=(e,s)=>{const i=[...t.rules],o=e+s;o<0||o>=i.length||([i[e],i[o]]=[i[o],i[e]],this._rulesSet(i))};return p``}_renderSettingsDialog(){return kr.call(this)}_rulesSet(t){this.host._rulesDialog={...this.host._rulesDialog,rules:t}}async _saveRules(){const t=this.host._rulesDialog;if(!t||t.busy)return;const e=t.rules.filter(t=>t.pattern.trim()&&t.icon.trim());this.host._rulesDialog={...t,busy:!0};try{const t=this.host._serverCfg,s=JSON.stringify(e)===JSON.stringify(Fe),i={...t.settings};s?delete i.icon_rules:i.icon_rules=e,this.host._serverCfg={...t,settings:i},await this._saveConfigNow(),this.host._rulesDialog=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("rules.saved"))}catch(t){this.host._rulesDialog&&(this.host._rulesDialog={...this.host._rulesDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}_renderRulesDialog(){const t=this.host._rulesDialog,e=ki(t.rules),s=t.test.trim()?xi(t.test,"",e):null,i=(e,s)=>{const i=[...t.rules],o=e+s;o<0||o>=i.length||([i[e],i[o]]=[i[o],i[e]],this._rulesSet(i))};return p`this.host._rulesDialog=null}>
    ${this.host._t("rules.hint")}
    @@ -1873,7 +1873,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${_a(this,e,a)} `:d} -
    `}_vacMapId(t,e,s=this.host._planHass){return this.host._vacMapId(t,e,s)}_vacSaveMatrix(t,e,s,i,o=""){return cd(this,t,e,s,i,o)}_vacPlanRoomAnchors(t){return(this.host._spaceModelById(t)?.rooms||[]).map(t=>({room:t,poly:A(t)})).filter(({room:t,poly:e})=>t.name&&e).map(({room:t,poly:e})=>{const s=Di(e);return s?{name:String(t.name),cx:s[0],cy:s[1]}:null}).filter(Boolean)}async _vacAutoCalibrate(t){if(this.host._markerDialog?.busy)return;const e=this.host._vacSource(t),s=e?Ci(this.host.hass?.states[e]?.attributes):null;if(!e||!s||s.rooms.length<3)return void this.host._showToast(this.host._t("vac.autocal_no_rooms"));const i=this._vacMapId(t,s),a=function(t,e,s,i,a){const n=o(t,e,s,i).find(t=>t.source===i&&t.map_id===a);return{space:n?.space||s,routeId:n?.id||""}}(t.id,t.marker?.vacuum??null,t.space,e,i),n=Ii(s.rooms,this._vacPlanRoomAnchors(a.space));if(!n)return void this.host._showToast(this.host._t("vac.autocal_no_match"));const r=this.host._serverCfg?.spaces?.find(t=>t.id===a.space),l=Number(r?.cell_cm),h=Number.isFinite(l)&&l>0?l:5,c=Li(n.residual,this.host._gridPitch,h);c>Ti?this.host._vacCalConfirm={markerId:t.id,source:e,mapId:i,routeId:a.routeId,space:a.space,matrix:n.matrix,rooms:n.matched.length,error:le(c,"mi"===this.host.hass?.config?.unit_system?.length)}:await async function(t,e){if(ld.has(t))return;ld.add(t);const s=t.host,i=s._markerDialog,o=i?{...i,busy:!0}:null;o&&(s._markerDialog=o,s.requestUpdate());try{await cd(t,e.markerId,e.source,e.mapId,e.matrix,e.routeId)&&s._showToast(s._t("vac.autocal_done",{rooms:String(e.rooms)}))}finally{ld.delete(t),o&&s._markerDialog===o&&(s._markerDialog={...o,busy:!1},s.requestUpdate())}}(this,{markerId:t.id,source:e,mapId:i,routeId:a.routeId,space:a.space,matrix:n.matrix,rooms:n.matched.length})}_vacApplyCalibrationProposal(t){return async function(t,e){const s=t.host,i=s._vacCalConfirm;if(!i||i.busy)return;if(e){const t=s._devices.find(t=>t.id===i.markerId),e=n(i.matrix);if(!t||!e)return;const o=i.space||t.space;if(o!==s._space&&!s._commitSpace(o))return;return s._vacCalConfirm=null,s._markerDialog=null,void(s._vacFit={markerId:i.markerId,source:i.source,routeId:i.routeId,mapId:i.mapId,p:e,drag:null})}const o={...i,busy:!0};s._vacCalConfirm=o,s.requestUpdate();const a=await cd(t,i.markerId,i.source,i.mapId,i.matrix,i.routeId);s._vacCalConfirm===o&&(s._vacCalConfirm=a?null:{...i,busy:!1},s.requestUpdate()),a&&s._showToast(s._t("vac.autocal_done",{rooms:String(i.rooms)}))}(this,t)}_vacStartFit(t,e=""){if(this.host._markerDialog?.busy)return;const s=this.host._vacSource(t),i=s?Ci(this.host.hass?.states[s]?.attributes):null;if(!s||!i)return void this.host._showToast(this.host._t("vac.cal_need_pos"));const l=this._vacMapId(t,i),h=function(t,e,s){const i=o(t,e,s.dockSpace,s.source),l=i.find(t=>t.id===s.routeId)||i.find(t=>t.source===s.source&&t.map_id===s.mapId)||null,h=l?.space||s.dockSpace,c=s.viewBoxOf(h);if(!c)return null;const d=a(l?l.calibration:e?.calibration?.[s.mapId]),p=d&&n(d)||r(s.rooms,c);return{space:h,routeId:l?.id||"",params:p}}(t.id,t.marker?.vacuum??null,{routeId:e,source:s,mapId:l,dockSpace:t.space,rooms:i.rooms,viewBoxOf:t=>this.host._spaceModelById(t)?.vb??null});h&&(this.host._markerDialog=null,(h.space===this.host._space||this.host._commitSpace(h.space))&&(this.host._vacFit={markerId:t.id,source:s,mapId:l,routeId:h.routeId,p:h.params,drag:null}))}_vacFitSave(){return async function(t,e){const s=t.host,i=s._vacFit;if(!i||i.busy)return;const o={...i,busy:!0,drag:null};s._vacFit=o,s.requestUpdate();const a=await cd(t,i.markerId,i.source,i.mapId,e(i.p),i.routeId);s._vacFit===o&&(s._vacFit=a?null:{...i,busy:!1,drag:null},s.requestUpdate()),a&&s._showToast(s._t("vac.cal_done"))}(this,zi)}_vacFitTurn(t){const e=this.host._vacFit;if(!e||e.busy)return;const s=Ci(this.host.hass?.states[e.source]?.attributes),i=this._vacGhostCentre(s?.rooms||[]),o={...e.p,...t};this.host._vacFit={...e,p:Ri(o,e.p,i[0],i[1])}}_vacGhostCentre(t){const e=[],s=[];for(const i of t)e.push(i.x0??i.cx,i.x1??i.cx),s.push(i.y0??i.cy,i.y1??i.cy);return e.length?[(Math.min(...e)+Math.max(...e))/2,(Math.min(...s)+Math.max(...s))/2]:[0,0]}_vacDelta(t,e,s){const i=this.host._stageEl,o=i?.clientWidth||1,a=i?.clientHeight||1;return[e/o*t.w,s/a*t.h]}_vacFitPointer(t,e){const s=this.host._vacFit;if(!s)return;if(t.stopPropagation(),s.busy)return;if("pointerdown"===t.type){const e=t.target,i=e.getAttribute?.("data-corner");try{t.currentTarget.setPointerCapture?.(t.pointerId)}catch{}return void(this.host._vacFit={...s,drag:i?{kind:"scale",sx:t.clientX,sy:t.clientY,p0:{...s.p},fx:Number(i.split(",")[0]),fy:Number(i.split(",")[1])}:{kind:"move",sx:t.clientX,sy:t.clientY,p0:{...s.p},fx:0,fy:0}})}const i=s.drag;if(i){if("pointermove"===t.type){const[o,a]=this._vacDelta(e,t.clientX-i.sx,t.clientY-i.sy);if("move"===i.kind)this.host._vacFit={...s,p:{...i.p0,ox:i.p0.ox+o,oy:i.p0.oy+a}};else{const t=Ci(this.host.hass?.states[s.source]?.attributes),e=this._vacGhostCentre(t?.rooms||[]),n=zi(i.p0),[r,l]=Fi(n,e[0],e[1]),[h,c]=Fi(n,i.fx,i.fy),d=Math.hypot(r-h,l-c)||1,[p,u]=[2*r-h,2*l-c],_=Math.hypot(p+2*o-h,u+2*a-c)/2,m=Math.max(.05,_/d),g={...i.p0,s:i.p0.s*m};this.host._vacFit={...s,p:Ri(g,i.p0,i.fx,i.fy)}}return}"pointerup"!==t.type&&"pointercancel"!==t.type||(this.host._vacFit={...s,drag:null})}}_renderVacFit(t){const e=this.host._vacFit;if(!e)return d;const s=Ci(this.host._renderPlanHass?.states?.[e.source]?.attributes);if(!s)return d;const i=zi(e.p),o=[],a=[],n=[];for(const t of s.rooms){if(null==t.x0)continue;const e=[[t.x0,t.y0],[t.x1,t.y0],[t.x1,t.y1],[t.x0,t.y1]].map(([t,e])=>Fi(i,t,e));e.forEach(([t,e])=>{a.push(t),n.push(e)});const[s,r]=Fi(i,t.cx,t.cy);o.push(Pt` + `}_vacMapId(t,e,s=this.host._planHass){return this.host._vacMapId(t,e,s)}_vacSaveMatrix(t,e,s,i,o=""){return hd(this,t,e,s,i,o)}_vacPlanRoomAnchors(t){return(this.host._spaceModelById(t)?.rooms||[]).map(t=>({room:t,poly:N(t)})).filter(({room:t,poly:e})=>t.name&&e).map(({room:t,poly:e})=>{const s=Di(e);return s?{name:String(t.name),cx:s[0],cy:s[1]}:null}).filter(Boolean)}async _vacAutoCalibrate(t){if(this.host._markerDialog?.busy)return;const e=this.host._vacSource(t),s=e?Ci(this.host.hass?.states[e]?.attributes):null;if(!e||!s||s.rooms.length<3)return void this.host._showToast(this.host._t("vac.autocal_no_rooms"));const i=this._vacMapId(t,s),a=function(t,e,s,i,a){const n=o(t,e,s,i).find(t=>t.source===i&&t.map_id===a);return{space:n?.space||s,routeId:n?.id||""}}(t.id,t.marker?.vacuum??null,t.space,e,i),n=Ii(s.rooms,this._vacPlanRoomAnchors(a.space));if(!n)return void this.host._showToast(this.host._t("vac.autocal_no_match"));const r=this.host._serverCfg?.spaces?.find(t=>t.id===a.space),l=Number(r?.cell_cm),h=Number.isFinite(l)&&l>0?l:5,c=Li(n.residual,this.host._gridPitch,h);c>Ti?this.host._vacCalConfirm={markerId:t.id,source:e,mapId:i,routeId:a.routeId,space:a.space,matrix:n.matrix,rooms:n.matched.length,error:le(c,"mi"===this.host.hass?.config?.unit_system?.length)}:await async function(t,e){if(rd.has(t))return;rd.add(t);const s=t.host,i=s._markerDialog,o=i?{...i,busy:!0}:null;o&&(s._markerDialog=o,s.requestUpdate());try{await hd(t,e.markerId,e.source,e.mapId,e.matrix,e.routeId)&&s._showToast(s._t("vac.autocal_done",{rooms:String(e.rooms)}))}finally{rd.delete(t),o&&s._markerDialog===o&&(s._markerDialog={...o,busy:!1},s.requestUpdate())}}(this,{markerId:t.id,source:e,mapId:i,routeId:a.routeId,space:a.space,matrix:n.matrix,rooms:n.matched.length})}_vacApplyCalibrationProposal(t){return async function(t,e){const s=t.host,i=s._vacCalConfirm;if(!i||i.busy)return;if(e){const t=s._devices.find(t=>t.id===i.markerId),e=n(i.matrix);if(!t||!e)return;const o=i.space||t.space;if(o!==s._space&&!s._commitSpace(o))return;return s._vacCalConfirm=null,s._markerDialog=null,void(s._vacFit={markerId:i.markerId,source:i.source,routeId:i.routeId,mapId:i.mapId,p:e,drag:null})}const o={...i,busy:!0};s._vacCalConfirm=o,s.requestUpdate();const a=await hd(t,i.markerId,i.source,i.mapId,i.matrix,i.routeId);s._vacCalConfirm===o&&(s._vacCalConfirm=a?null:{...i,busy:!1},s.requestUpdate()),a&&s._showToast(s._t("vac.autocal_done",{rooms:String(i.rooms)}))}(this,t)}_vacStartFit(t,e=""){if(this.host._markerDialog?.busy)return;const s=this.host._vacSource(t),i=s?Ci(this.host.hass?.states[s]?.attributes):null;if(!s||!i)return void this.host._showToast(this.host._t("vac.cal_need_pos"));const l=this._vacMapId(t,i),h=function(t,e,s){const i=o(t,e,s.dockSpace,s.source),l=i.find(t=>t.id===s.routeId)||i.find(t=>t.source===s.source&&t.map_id===s.mapId)||null,h=l?.space||s.dockSpace,c=s.viewBoxOf(h);if(!c)return null;const d=a(l?l.calibration:e?.calibration?.[s.mapId]),p=d&&n(d)||r(s.rooms,c);return{space:h,routeId:l?.id||"",params:p}}(t.id,t.marker?.vacuum??null,{routeId:e,source:s,mapId:l,dockSpace:t.space,rooms:i.rooms,viewBoxOf:t=>this.host._spaceModelById(t)?.vb??null});h&&(this.host._markerDialog=null,(h.space===this.host._space||this.host._commitSpace(h.space))&&(this.host._vacFit={markerId:t.id,source:s,mapId:l,routeId:h.routeId,p:h.params,drag:null}))}_vacFitSave(){return async function(t,e){const s=t.host,i=s._vacFit;if(!i||i.busy)return;const o={...i,busy:!0,drag:null};s._vacFit=o,s.requestUpdate();const a=await hd(t,i.markerId,i.source,i.mapId,e(i.p),i.routeId);s._vacFit===o&&(s._vacFit=a?null:{...i,busy:!1,drag:null},s.requestUpdate()),a&&s._showToast(s._t("vac.cal_done"))}(this,zi)}_vacFitTurn(t){const e=this.host._vacFit;if(!e||e.busy)return;const s=Ci(this.host.hass?.states[e.source]?.attributes),i=this._vacGhostCentre(s?.rooms||[]),o={...e.p,...t};this.host._vacFit={...e,p:Ri(o,e.p,i[0],i[1])}}_vacGhostCentre(t){const e=[],s=[];for(const i of t)e.push(i.x0??i.cx,i.x1??i.cx),s.push(i.y0??i.cy,i.y1??i.cy);return e.length?[(Math.min(...e)+Math.max(...e))/2,(Math.min(...s)+Math.max(...s))/2]:[0,0]}_vacDelta(t,e,s){const i=this.host._stageEl,o=i?.clientWidth||1,a=i?.clientHeight||1;return[e/o*t.w,s/a*t.h]}_vacFitPointer(t,e){const s=this.host._vacFit;if(!s)return;if(t.stopPropagation(),s.busy)return;if("pointerdown"===t.type){const e=t.target,i=e.getAttribute?.("data-corner");try{t.currentTarget.setPointerCapture?.(t.pointerId)}catch{}return void(this.host._vacFit={...s,drag:i?{kind:"scale",sx:t.clientX,sy:t.clientY,p0:{...s.p},fx:Number(i.split(",")[0]),fy:Number(i.split(",")[1])}:{kind:"move",sx:t.clientX,sy:t.clientY,p0:{...s.p},fx:0,fy:0}})}const i=s.drag;if(i){if("pointermove"===t.type){const[o,a]=this._vacDelta(e,t.clientX-i.sx,t.clientY-i.sy);if("move"===i.kind)this.host._vacFit={...s,p:{...i.p0,ox:i.p0.ox+o,oy:i.p0.oy+a}};else{const t=Ci(this.host.hass?.states[s.source]?.attributes),e=this._vacGhostCentre(t?.rooms||[]),n=zi(i.p0),[r,l]=Fi(n,e[0],e[1]),[h,c]=Fi(n,i.fx,i.fy),d=Math.hypot(r-h,l-c)||1,[p,u]=[2*r-h,2*l-c],_=Math.hypot(p+2*o-h,u+2*a-c)/2,m=Math.max(.05,_/d),g={...i.p0,s:i.p0.s*m};this.host._vacFit={...s,p:Ri(g,i.p0,i.fx,i.fy)}}return}"pointerup"!==t.type&&"pointercancel"!==t.type||(this.host._vacFit={...s,drag:null})}}_renderVacFit(t){const e=this.host._vacFit;if(!e)return d;const s=Ci(this.host._renderPlanHass?.states?.[e.source]?.attributes);if(!s)return d;const i=zi(e.p),o=[],a=[],n=[];for(const t of s.rooms){if(null==t.x0)continue;const e=[[t.x0,t.y0],[t.x1,t.y0],[t.x1,t.y1],[t.x0,t.y1]].map(([t,e])=>Fi(i,t,e));e.forEach(([t,e])=>{a.push(t),n.push(e)});const[s,r]=Fi(i,t.cx,t.cy);o.push(Pt` ${t.name}`)}let r=d;if(s.pos){const[e,o]=Fi(i,s.pos.x,s.pos.y);r=Pt``}const l=[];if(a.length){const e=(()=>{const t=i[0]*i[4]-i[1]*i[3];return(e,s)=>[(i[4]*(e-i[2])-i[1]*(s-i[5]))/t,(-i[3]*(e-i[2])+i[0]*(s-i[5]))/t]})(),s=Math.min(...a),o=Math.max(...a),r=Math.min(...n),h=Math.max(...n),c=.022*t.w,d=c/4;for(const[t,i,a,n]of[[s,r,o,h],[o,r,s,h],[o,h,s,r],[s,h,o,r]]){const s=e(a,n);l.push(Pt` `)}}return p`t.id===this.host._roomEditId);if(!e)return this.host._roomDialog=!1,void(this.host._roomEditId=null);e.name=this.host._nameSel.trim()||e.name,e.area=this.host._areaSel||null;const s=e.settings||{},i={...s};Ei(i,this.host._roomTempMin,this.host._roomTempMax)&&(this.host._roomFill?i.fill_mode=this.host._roomFill:delete i.fill_mode,"custom"===this.host._roomFill&&this.host._roomCustomFill?i.custom_fill=this.host._roomCustomFill:delete i.custom_fill,"glow"===s.fill_mode&&"boolean"!=typeof s.glow&&(i.glow=!0),this.host._roomTempSrc?i.temp_source=this.host._roomTempSrc:delete i.temp_source,this.host._roomHumSrc?i.hum_source=this.host._roomHumSrc:delete i.hum_source,1!==this.host._roomNameScale?i.name_scale=this.host._roomNameScale:delete i.name_scale,1!==this.host._roomLabelScale?i.label_scale=this.host._roomLabelScale:delete i.label_scale,Object.keys(i).length?e.settings=i:delete e.settings,this._saveConfig(),this.host._roomDialog=!1,this.host._roomEditId=null,this.host._nameSel="",this.host._areaSel="",this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate(),this.host._showToast(this.host._t("toast.room_updated")))}_roomSrcCandidates(){const t=this.host._planHass,e=ne(this.host._markers),s=this.host._roomSrcFilter.trim().toLowerCase(),i=[];for(const o of Object.values(t.devices)){if("service"===o.entry_type)continue;if(e.devices.has(o.id))continue;const t=(o.name_by_user||o.name||o.id).trim();s&&!t.toLowerCase().includes(s)||i.push({value:"device:"+o.id,label:t,sub:o.model||this.host._t("marker.sub_device")})}for(const[o,a]of Object.entries(t.entities)){if(!o.startsWith("sensor.")||a.hidden)continue;if(re(t,o,e))continue;const n=a.name||t.states[o]?.attributes?.friendly_name||o;s&&!(n+" "+o).toLowerCase().includes(s)||i.push({value:"entity:"+o,label:n,sub:o})}return i.sort((t,e)=>t.label.localeCompare(e.label)),i.slice(0,200)}_roomSrcLabel(t){const e=t.indexOf(":"),s=t.slice(0,e),i=t.slice(e+1);return"device"===s?this.host._fullRegistryHass.devices[i]?.name_by_user||this.host._fullRegistryHass.devices[i]?.name||i:this.host._fullRegistryHass.entities[i]?.name||this.host.hass.states[i]?.attributes?.friendly_name||i}_labelPos(t,e){const s=this.host._layout["rl_"+(t.id||"")];if(s&&s.s===e)return{x:s.x*Gd,y:s.y*Gd};const i=this._snap(this.host._roomCenter(t));return{x:i[0],y:i[1]}}_labelDown(t,e,s){if("plan"!==this.host._mode)return;t.preventDefault(),t.stopPropagation();const i=this._labelPos(e,s);this.host._drag={id:"rl_"+(e.id||""),sx:t.clientX,sy:t.clientY,ox:i.x,oy:i.y,moved:!1},Ud(t),this.host._tip=null}_labelMove(t,e,s){const i="rl_"+(e.id||"");if(!this.host._drag||this.host._drag.id!==i)return;const o=this.host._stageEl;if(!o)return;const a=this.host._spaceModelById(s);if(!a)return;const n=a.vb,r=o.getBoundingClientRect(),l=this.host._viewOr(n),h=(t.clientX-this.host._drag.sx)/r.width*l.w,c=(t.clientY-this.host._drag.sy)/r.height*l.h;Math.abs(t.clientX-this.host._drag.sx)+Math.abs(t.clientY-this.host._drag.sy)>3&&(this.host._drag.moved=!0);const d=Oe(this.host._drag.ox+h),p=Oe(this.host._drag.oy+c);this.host._savePos({id:i,space:s},d,p)}_labelUp(t){const e="rl_"+(t.id||"");if(!this.host._drag||this.host._drag.id!==e)return;const s=this.host._drag.moved;this.host._drag=s?this.host._drag:null,s&&window.setTimeout(()=>this.host._drag=null,0)}_labelScale(t){const e=this.host._layout["rl_"+(t.id||"")]?.k;return"number"==typeof e&&Number.isFinite(e)?Math.min(3,Math.max(.5,e)):1}_rlResizeDown(t,e,s){if("plan"!==this.host._mode)return;t.preventDefault(),t.stopPropagation();const i=t.target.closest(".roomlabel");if(!i)return;const o=i.getBoundingClientRect(),a=o.left+o.width/2,n=o.top+o.height/2,r=Math.max(8,Math.hypot(t.clientX-a,t.clientY-n));this.host._rlResize={id:"rl_"+(e.id||""),space:s,k0:this._labelScale(e),cx:a,cy:n,d0:r},Ud(t)}_rlResizeMove(t){const e=this.host._rlResize;if(!e)return;t.stopPropagation();const s=Math.max(8,Math.hypot(t.clientX-e.cx,t.clientY-e.cy)),i=Math.min(3,Math.max(.5,e.k0*(s/e.d0))),o=this.host._layout[e.id];if(o)this.host._layout={...this.host._layout,[e.id]:{...o,k:i}};else{const t=e.id.slice(3),s=this.host._spaceModelById(e.space);if(!s)return;const o=s.rooms.find(e=>e.id===t);if(!o)return;const a=this._labelPos(o,e.space);this.host._layout={...this.host._layout,[e.id]:{s:e.space,x:a.x/Gd,y:a.y/Gd,k:i}}}this.host._dirtyPos.add(e.id)}_rlResizeUp(){this.host._rlResize&&(this.host._rlResize=null,this.host._persistLayout())}_renderRoomGear(t,e,s){if(!t.id)return d;let i=null;if(t.poly?(i=this.host._gearPtCache.get(t.poly)||null,i||(i=hs(t.poly),this.host._gearPtCache.set(t.poly,i))):null!=t.x&&null!=t.y&&(i=[t.x+(t.w||0)/2,t.y+(t.h||0)/2]),!i)return d;const o=(i[0]-s.x)/s.w*100,a=(i[1]-s.y)/s.h*100;return p``}_resetRoomDialogFields(){this.host._roomEditId=null,this.host._roomFill="",this.host._roomCustomFill=null,this.host._roomTempMin="",this.host._roomTempMax="",this.host._roomTempSrc="",this.host._roomHumSrc="",this.host._roomSrcOpen=null,this.host._roomSrcFilter="",this.host._roomNameScale=1,this.host._roomLabelScale=1}_openRoomEdit(t){if(!t.id)return;this.host._roomEditId=t.id,this.host._nameSel=t.name||"",this.host._areaSel=t.area||"",this.host._roomFill="glow"===t.settings?.fill_mode?"":t.settings?.fill_mode||"";const e="custom"===this.host._roomFill?t.settings?.custom_fill:null;var s;this.host._roomCustomFill=e&&"object"==typeof e?ni(e,_(this.host._curSpaceCfg).customFill):null,[this.host._roomTempMin,this.host._roomTempMax]=Ni(t.settings),this.host._roomTempSrc=t.settings?.temp_source||"",this.host._roomHumSrc=t.settings?.hum_source||"",this.host._roomNameScale=Ai(t.settings?.name_scale),this.host._roomLabelScale=Ai(t.settings?.label_scale),this.host._roomSrcOpen=null,this.host._roomSrcFilter="",this.host._roomDialog=!0,s=this.host,_o(s,"room",xr(s))}_roomSettingsFromDialog(){const t={};return this.host._roomFill&&(t.fill_mode=this.host._roomFill),"custom"===this.host._roomFill&&this.host._roomCustomFill&&(t.custom_fill=this.host._roomCustomFill),this.host._roomTempSrc&&(t.temp_source=this.host._roomTempSrc),this.host._roomHumSrc&&(t.hum_source=this.host._roomHumSrc),Ei(t,this.host._roomTempMin,this.host._roomTempMax),1!==this.host._roomNameScale&&(t.name_scale=this.host._roomNameScale),1!==this.host._roomLabelScale&&(t.label_scale=this.host._roomLabelScale),Object.keys(t).length?t:null}_saveRoomEdit(){const t=this.host._curSpaceCfg,e=t?.rooms.find(t=>t.id===this.host._roomEditId);if(!e)return this.host._roomDialog=!1,void(this.host._roomEditId=null);e.name=this.host._nameSel.trim()||e.name,e.area=this.host._areaSel||null;const s=e.settings||{},i={...s};Ei(i,this.host._roomTempMin,this.host._roomTempMax)&&(this.host._roomFill?i.fill_mode=this.host._roomFill:delete i.fill_mode,"custom"===this.host._roomFill&&this.host._roomCustomFill?i.custom_fill=this.host._roomCustomFill:delete i.custom_fill,"glow"===s.fill_mode&&"boolean"!=typeof s.glow&&(i.glow=!0),this.host._roomTempSrc?i.temp_source=this.host._roomTempSrc:delete i.temp_source,this.host._roomHumSrc?i.hum_source=this.host._roomHumSrc:delete i.hum_source,1!==this.host._roomNameScale?i.name_scale=this.host._roomNameScale:delete i.name_scale,1!==this.host._roomLabelScale?i.label_scale=this.host._roomLabelScale:delete i.label_scale,Object.keys(i).length?e.settings=i:delete e.settings,this._saveConfig(),this.host._roomDialog=!1,this.host._roomEditId=null,this.host._nameSel="",this.host._areaSel="",this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate(),this.host._showToast(this.host._t("toast.room_updated")))}_roomSrcCandidates(){const t=this.host._planHass,e=ne(this.host._markers),s=this.host._roomSrcFilter.trim().toLowerCase(),i=[];for(const o of Object.values(t.devices)){if("service"===o.entry_type)continue;if(e.devices.has(o.id))continue;const t=(o.name_by_user||o.name||o.id).trim();s&&!t.toLowerCase().includes(s)||i.push({value:"device:"+o.id,label:t,sub:o.model||this.host._t("marker.sub_device")})}for(const[o,a]of Object.entries(t.entities)){if(!o.startsWith("sensor.")||a.hidden)continue;if(re(t,o,e))continue;const n=a.name||t.states[o]?.attributes?.friendly_name||o;s&&!(n+" "+o).toLowerCase().includes(s)||i.push({value:"entity:"+o,label:n,sub:o})}return i.sort((t,e)=>t.label.localeCompare(e.label)),i.slice(0,200)}_roomSrcLabel(t){const e=t.indexOf(":"),s=t.slice(0,e),i=t.slice(e+1);return"device"===s?this.host._fullRegistryHass.devices[i]?.name_by_user||this.host._fullRegistryHass.devices[i]?.name||i:this.host._fullRegistryHass.entities[i]?.name||this.host.hass.states[i]?.attributes?.friendly_name||i}_labelPos(t,e){const s=this.host._layout["rl_"+(t.id||"")];if(s&&s.s===e)return{x:s.x*jd,y:s.y*jd};const i=this._snap(this.host._roomCenter(t));return{x:i[0],y:i[1]}}_labelDown(t,e,s){if("plan"!==this.host._mode)return;t.preventDefault(),t.stopPropagation();const i=this._labelPos(e,s);this.host._drag={id:"rl_"+(e.id||""),sx:t.clientX,sy:t.clientY,ox:i.x,oy:i.y,moved:!1},qd(t),this.host._tip=null}_labelMove(t,e,s){const i="rl_"+(e.id||"");if(!this.host._drag||this.host._drag.id!==i)return;const o=this.host._stageEl;if(!o)return;const a=this.host._spaceModelById(s);if(!a)return;const n=a.vb,r=o.getBoundingClientRect(),l=this.host._viewOr(n),h=(t.clientX-this.host._drag.sx)/r.width*l.w,c=(t.clientY-this.host._drag.sy)/r.height*l.h;Math.abs(t.clientX-this.host._drag.sx)+Math.abs(t.clientY-this.host._drag.sy)>3&&(this.host._drag.moved=!0);const d=Oe(this.host._drag.ox+h),p=Oe(this.host._drag.oy+c);this.host._savePos({id:i,space:s},d,p)}_labelUp(t){const e="rl_"+(t.id||"");if(!this.host._drag||this.host._drag.id!==e)return;const s=this.host._drag.moved;this.host._drag=s?this.host._drag:null,s&&window.setTimeout(()=>this.host._drag=null,0)}_labelScale(t){const e=this.host._layout["rl_"+(t.id||"")]?.k;return"number"==typeof e&&Number.isFinite(e)?Math.min(3,Math.max(.5,e)):1}_rlResizeDown(t,e,s){if("plan"!==this.host._mode)return;t.preventDefault(),t.stopPropagation();const i=t.target.closest(".roomlabel");if(!i)return;const o=i.getBoundingClientRect(),a=o.left+o.width/2,n=o.top+o.height/2,r=Math.max(8,Math.hypot(t.clientX-a,t.clientY-n));this.host._rlResize={id:"rl_"+(e.id||""),space:s,k0:this._labelScale(e),cx:a,cy:n,d0:r},qd(t)}_rlResizeMove(t){const e=this.host._rlResize;if(!e)return;t.stopPropagation();const s=Math.max(8,Math.hypot(t.clientX-e.cx,t.clientY-e.cy)),i=Math.min(3,Math.max(.5,e.k0*(s/e.d0))),o=this.host._layout[e.id];if(o)this.host._layout={...this.host._layout,[e.id]:{...o,k:i}};else{const t=e.id.slice(3),s=this.host._spaceModelById(e.space);if(!s)return;const o=s.rooms.find(e=>e.id===t);if(!o)return;const a=this._labelPos(o,e.space);this.host._layout={...this.host._layout,[e.id]:{s:e.space,x:a.x/jd,y:a.y/jd,k:i}}}this.host._dirtyPos.add(e.id)}_rlResizeUp(){this.host._rlResize&&(this.host._rlResize=null,this.host._persistLayout())}_renderRoomGear(t,e,s){if(!t.id)return d;let i=null;if(t.poly?(i=this.host._gearPtCache.get(t.poly)||null,i||(i=hs(t.poly),this.host._gearPtCache.set(t.poly,i))):null!=t.x&&null!=t.y&&(i=[t.x+(t.w||0)/2,t.y+(t.h||0)/2]),!i)return d;const o=(i[0]-s.x)/s.w*100,a=(i[1]-s.y)/s.h*100;return p``}_alignCandidates(){const t=[],e=this.host._spaceModel();if(this.host._markup){if(!e)return t;if(this.host._drag?.id.startsWith("rl_")){const s=this.host._drag.id.slice(3);for(const i of e.rooms){if(!i.name||i.id===s)continue;const e=this._labelPos(i,this.host._space);t.push([e.x,e.y])}return t}for(const s of e.rooms){const e=A(s);if(e)for(const s of e)t.push(s)}if("draw"===this.host._tool)for(const e of this.host._path)t.push(e);if("split"===this.host._tool&&this.host._splitSel?.pts)for(const e of this.host._splitSel.pts)t.push(e);return t}if("devices"===this.host._mode){const e=this.host._deviceDrag?.id??this.host._drag?.id;for(const s of this.host._devices){if(s.space!==this.host._space||s.id===e||"ha_disabled"===s.bindingStatus?.kind)continue;const i=this.host._pos(s);t.push([i.x,i.y])}return t}if("decor"===this.host._mode){const e=this.host._decorMove?.id;return t.push(...this._decorSnapGeometry(e).points),this.host._decorDraft&&t.push(this.host._decorDraft.a),t}return t}_renderAlignGuides(){const t=this.host._alignPoint;if(!t)return Pt``;const e=this.host._drag?.id.startsWith("rl_")?.5*this.host._gridPitch:.05*this.host._gridPitch,s=Oi(t,this._alignCandidates(),e);if(!s.length)return Pt``;const i=this.host._gridPitch,o=1.5*i;return Pt` + `}_alignCandidates(){const t=[],e=this.host._spaceModel();if(this.host._markup){if(!e)return t;if(this.host._drag?.id.startsWith("rl_")){const s=this.host._drag.id.slice(3);for(const i of e.rooms){if(!i.name||i.id===s)continue;const e=this._labelPos(i,this.host._space);t.push([e.x,e.y])}return t}for(const s of e.rooms){const e=N(s);if(e)for(const s of e)t.push(s)}if("draw"===this.host._tool)for(const e of this.host._path)t.push(e);if("split"===this.host._tool&&this.host._splitSel?.pts)for(const e of this.host._splitSel.pts)t.push(e);return t}if("devices"===this.host._mode){const e=this.host._deviceDrag?.id??this.host._drag?.id;for(const s of this.host._devices){if(s.space!==this.host._space||s.id===e||"ha_disabled"===s.bindingStatus?.kind)continue;const i=this.host._pos(s);t.push([i.x,i.y])}return t}if("decor"===this.host._mode){const e=this.host._decorMove?.id;return t.push(...this._decorSnapGeometry(e).points),this.host._decorDraft&&t.push(this.host._decorDraft.a),t}return t}_renderAlignGuides(){const t=this.host._alignPoint;if(!t)return Pt``;const e=this.host._drag?.id.startsWith("rl_")?.5*this.host._gridPitch:.05*this.host._gridPitch,s=Oi(t,this._alignCandidates(),e);if(!s.length)return Pt``;const i=this.host._gridPitch,o=1.5*i;return Pt` ${s.map(e=>{const[s,a,n,r]="x"===e.axis?[e.at,e.from[1],e.at,t[1]+Math.sign(t[1]-e.from[1])*o]:[e.from[0],e.at,t[0]+Math.sign(t[0]-e.from[0])*o,e.at];return Pt` `})} @@ -1920,7 +1920,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc `}_renderOpeningDialog(){const t=this.host._openingDialog,e=this.host._spaceModel()?.partitions||[],s=t.id?this.host._curSpaceCfg?.openings?.find(e=>e.id===t.id):null,i={id:t.id||"preview",type:t.type,x:t.x/Gd,y:t.y/this.host._spaceH,angle:t.angle,length:s&&!t.lengthTouched?s.length:this.host._cmToUnits(Math.max(20,t.lengthCm))/Gd,...t.host?{host:t.host}:{}},o=js(s,i),a=t.host?o?U(i,e,Gd,this.host._cellCm,this.host._gridPitch):E(i,e,Gd,this.host._cellCm,this.host._gridPitch):null,n="does-not-fit-jamb"===a?.reason,r=t.host?e.find(e=>e.id===t.host.id):null,l=r?le(r.cm/2,this.host._imperial):"",h=!!t.host&&!a?.resolved&&!n,c="gate"===t.type?"mdi:gate":"window"===t.type?"mdi:window-closed-variant":"passage"===t.type?"mdi:arch":"mdi:door",_=(e,s)=>{const i="contact"===e?t.contact:t.lock,o="contact"===e?!!t.contactOpen:!!t.lockOpen,a="contact"===e?t.contactFilter||"":t.lockFilter||"",n=s.find(t=>t.value===i),r=n?.label||this.host.hass.states[i]?.attributes?.friendly_name||this.host._fullRegistryHass.entities[i]?.name||i,l=lo(s,a);return p` + r=${Rt(.18*this.host._gridPitch,this.host._cellCm)}>`}_renderOpeningDialog(){const t=this.host._openingDialog,e=this.host._spaceModel()?.partitions||[],s=t.id?this.host._curSpaceCfg?.openings?.find(e=>e.id===t.id):null,i={id:t.id||"preview",type:t.type,x:t.x/jd,y:t.y/this.host._spaceH,angle:t.angle,length:s&&!t.lengthTouched?s.length:this.host._cmToUnits(Math.max(20,t.lengthCm))/jd,...t.host?{host:t.host}:{}},o=js(s,i),a=t.host?o?q(i,e,jd,this.host._cellCm,this.host._gridPitch):A(i,e,jd,this.host._cellCm,this.host._gridPitch):null,n="does-not-fit-jamb"===a?.reason,r=t.host?e.find(e=>e.id===t.host.id):null,l=r?le(r.cm/2,this.host._imperial):"",h=!!t.host&&!a?.resolved&&!n,c="gate"===t.type?"mdi:gate":"window"===t.type?"mdi:window-closed-variant":"passage"===t.type?"mdi:arch":"mdi:door",u=(e,s)=>{const i="contact"===e?t.contact:t.lock,o="contact"===e?!!t.contactOpen:!!t.lockOpen,a="contact"===e?t.contactFilter||"":t.lockFilter||"",n=s.find(t=>t.value===i),r=n?.label||this.host.hass.states[i]?.attributes?.friendly_name||this.host._fullRegistryHass.entities[i]?.name||i,l=lo(s,a);return p` -
    `}_markerValueBadgeFields(t){return Zi({touched:t.valueBadgeTouched,originalHas:t.originalHasValueBadge,original:t.originalValueBadge,enabled:t.valueBadgeEnabled,source:t.valueBadgeSource,position:t.valueBadgePosition})}_markerValueSourceFields(t){return Yi({touched:t.valueSourceTouched,originalHas:t.originalHasValueSource,original:t.originalValueSource,source:t.valueSource})}_markerDraft(t){if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return null;const e=M(t.room),s=Zs(t.binding,t.devId,()=>"__hp_device_preview__"),i=this.host._markers.find(e=>e.id===s||e.id===t.devId),o=R(t.binding,t.controls,this.host._bindingEntities(t.binding)),a=this._effectiveStoredTapAction(t),n={id:s,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle||null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===a&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:o.length?o:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),...this._markerValueSourceFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=u(t.glowRadius);return null==e||e<=0?null:Math.round(this.host._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:t.hideFromPlan,vacuum:i?.vacuum||null},r=!!i&&("string"==typeof i.area&&i.area.length>0||null===i.area&&!!i.space&&!!i.room_id);return"virtual"===t.binding||t.roomTouched?(n.space=e?.space||("virtual"===t.binding?this.host._space:null),n.area=e?.area||null,n.room_id=e?.roomId||null):r&&(n.space=i.space,n.area=i.area,n.room_id=i.room_id),n}_markerPreviewDevice(t){const e=this._markerDraft(t);if(!e)return null;const s=`${this.host._haRegistry.revision}\n${wt(this.host._markers)}\n${JSON.stringify(e)}`;if(this.host._markerPreviewMemo?.key===s)return this.host._markerPreviewMemo.device;const i=Xi({hass:this.host.hass,registry:this.host._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this.host._areaToSpace).map(([t,e])=>[t,e.space])),marker:e,siblingMarkers:this.host._markers,settings:this.host._settings,excluded:this.host._excluded,showAll:this.host._showAll,firstSpaceId:this.host._model[0]?.id||this.host._space,loc:t=>this.host._t(t),iconRules:this.host._iconRules});return this.host._markerPreviewMemo={key:s,device:i},i}_markerPreviewDevices(t){const e=this.host._markerPreviewDevicesMemo;if(e?.base===this.host._devices&&e.preview===t)return e.devices;const s=[...this.host._devices.filter(e=>e.id!==t.id),t];return this.host._markerPreviewDevicesMemo={base:this.host._devices,preview:t,devices:s},s}_toggleIntent(t,e=this.host._devices){return this.host._toggleIntent(t,e)}_toggleIntentForDialog(t){const e=this._markerPreviewDevice(t);if(!e)return null;const s=this._markerPreviewDevices(e);return this._toggleIntent(e,s)}_toggleStateText(t,e){return this.host._toggleStateText(t,e)}_toggleConfirmationStateText(t){return this.host._toggleConfirmationStateText(t)}_toggleConfirmationLines(t){return this.host._toggleConfirmationLines(t)}_toggleHintLines(t){if(!t)return[];const e=t=>this.host._t(`marker.toggle_effect_${t.replace("-","_")}`),s=t=>this.host._t(`marker.toggle_skip_${t.replace("-","_")}`);return Qi(t,{single:t=>{if("via"in t&&"virtual-light"===t.via)return this.host._t("marker.virtual_light_target",{name:t.name});const e=t.entityId||("ref"in t?t.ref:""),s=t.name||e;return this.host._t("marker.toggle_hint_single",{name:s,id:e})},group:t=>this.host._t("marker.toggle_hint_group",{count:t.length,names:t.map(t=>`${t.name} (${t.entityId})`).join(", ")}),currentNext:(t,s)=>"virtual-light"===t.via?this.host._t("marker.virtual_light_current",{state:this.host._t("on"===t.state?"marker.virtual_light_state_on":"marker.virtual_light_state_off"),effect:e(s)}):this.host._t("marker.toggle_hint_current",{state:this._toggleStateText(t.entityId,t.state),effect:e(s)}),groupCurrentNext:(t,s)=>this.host._t("marker.toggle_hint_group_current",{on:t.filter(t=>"on"===t.state).length,count:t.length,effect:e(s)}),skipped:t=>this.host._t("marker.toggle_hint_skipped",{count:t.length,targets:t.map(t=>{const e=t.entityId||t.ref;return`${t.name||e} (${e}: ${s(t.reason)})`}).join(", ")}),none:t=>this.host._t(`marker.toggle_none_${t.replaceAll("-","_")}`)})}_effectiveStoredTapAction(t,e){return t.tapActionTouched?t.tapAction:Xs(t.originalHasTapAction?t.originalTapAction:null,e)}_effectiveMarkerTapAction(t,e=this._markerPreviewDevice(t)){return this._effectiveStoredTapAction(t,e?.primary?.split(".")[0])}_announceToggleDraft(t){const e=this._markerPreviewDevice(t),s=t.tapActionTouched?t:{...t,tapAction:this._effectiveMarkerTapAction(t,e)},i="toggle"===s.tapAction?this._toggleHintLines(this._toggleIntentForDialog(s)).join(" "):"";return{...s,tapHintAnnouncement:i}}_valueBadgeForBinding(t,e){const s={...t,binding:e,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0},i=this._markerPreviewDevice(s);if(!i)return{valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0};const o=[...this.host._devices.filter(t=>t.id!==i.id),i],a=f(this.host._planHass,i,o),n=b(this.host._planHass,i,a);return{valueBadgeEnabled:t.valueBadgeEnabled&&!!n,valueBadgeSource:n,valueBadgeTouched:!0}}_markerSpatialSource(t){const e=this._markerPreviewDevice(t);if(!e)return null;const s={...e,hidden:!1};return to(eo(this.host._planHass,[...this.host._devices.filter(t=>t.id!==s.id),s],null,this.host._virtualLights).filter(t=>t.device.id===s.id))}_markerAutoHasSpatialSource(t){const e={...t,lightRole:"auto",lightRoleTouched:!0},s=this._markerPreviewDevice(e);return!!s&&so(this.host._planHass,{...s})}_setMarkerLightRole(t){const e=this.host._markerDialog;e&&(this.host._markerDialog={...e,lightRole:t,lightRoleTouched:!0})}_controlRefInfo(t){if(!t.startsWith("marker:"))return{label:this.host.hass.states[t]?.attributes?.friendly_name||t,sub:t,icon:t.startsWith("light.")?"mdi:lightbulb":"mdi:toggle-switch",warning:!this.host._planEntityAvailable(t)};const e=t.slice(7),s=this.host._markers.find(t=>t.id===e),i=this.host._devices.find(t=>t.id===e);if(!s||s.removed||!0!==s.is_light)return{label:this.host._t("marker.control_missing_label"),sub:`${this.host._t("marker.control_broken")} (${t})`,icon:"mdi:alert-outline",warning:!0};const o=this.host._serverCfg?.spaces.find(t=>t.id===(i?.space||s.space)),a=!!i&&$(i).length>0;return{label:s.name||i?.name||e,sub:[o?.title||i?.space||s.space,s.room_id||i?.area,a?"":this.host._t("marker.control_passive")].filter(Boolean).join(" · "),icon:s.icon||i?.icon||"mdi:lightbulb-outline",warning:!0===s.hidden||!0===i?.hidden}}_valueBadgeCandidateLabel(t){const e=t.source;if("derived_lqi"===e.kind)return this.host._t("marker.value_badge_lqi");if("derived_marker_state"===e.kind)return this.host._t("marker.value_badge_marker_state",{name:t.label});if("entity_state"===e.kind)return this.host._t("marker.value_badge_state",{name:t.label});const s=this.host.hass.states[e.entity_id]?.attributes?.friendly_name||this.host._fullRegistryHass.entities[e.entity_id]?.name||e.entity_id;return this.host._t(`marker.value_badge_attr_${e.attribute}`,{name:s})}_controlCandidates(t){const e=this._markerDraft(t)?.id||t.devId||"",s=[],i=new Set;for(const t of this.host._markers){if(t.id===e||t.removed||t.hidden||!0!==t.is_light)continue;if("virtual"!==t.binding&&"active"!==this.host._bindingStatus(t.binding).kind)continue;const o=this.host._devices.find(e=>e.id===t.id);if(!o||o.hidden)continue;const a=this._controlRefInfo(`marker:${t.id}`);for(const t of $(o))i.add(t);s.push({value:`marker:${t.id}`,label:a.label,sub:a.sub,icon:a.icon,search:`${a.label} ${a.sub} ${t.id} ${$(o).join(" ")}`.toLowerCase()})}const o=Object.keys(this.host.hass.states||{}).filter(e=>io(e)&&!i.has(e)&&oo(t.binding,[e],this.host._bindingEntities(t.binding)).length>0&&this.host._planEntityAvailable(e)).map(t=>{const e=this._controlRefInfo(t);return{value:t,label:e.label,sub:t,icon:e.icon,search:`${e.label} ${t}`.toLowerCase()}}),a=t.controlsFilter.trim().toLowerCase();return[...s,...o].filter(e=>!t.controls.includes(e.value)&&(!a||e.search.includes(a))).slice(0,12).map(({search:t,...e})=>e)}_addControlRef(t,e){if(e.startsWith("marker:")){const s=this._markerDraft(t)?.id||t.devId||"";if(!s)return void this.host._showToast(this.host._t("toast.marker_binding_required"));const i=e.slice(7),o=this._markerDraft(t),a=o?[...this.host._markers.filter(t=>t.id!==s),o]:this.host._markers;if(ao(a,s,i))return void this.host._showToast(this.host._t("toast.marker_control_cycle"))}this.host._markerDialog=this._announceToggleDraft({...t,controls:[...t.controls,e],controlsFilter:""})}_setMarkerGlowMode(t){const e=this.host._markerDialog;if(!e)return;if("auto"===t)return void(this.host._markerDialog={...e,glowMode:t,glowTouched:!0});const s=this._markerSpatialSource(e),i=no(s?this.host._planHass.states[s.eid]:void 0,null,this.host._fillColors.glow_light.c),o=!e.glowColorDrafted,a="fixed"===t&&!e.glowBrightnessDrafted;this.host._markerDialog={...e,glowMode:t,glowColor:o?i.c:e.glowColor,glowBrightness:a?Math.max(1,Math.round(100*i.bri)):e.glowBrightness,glowColorDrafted:!0,glowBrightnessDrafted:e.glowBrightnessDrafted||"fixed"===t,glowTouched:!0}}_renderRadarSection(t,e,s="main"){return ic({dialog:t,device:e,registryHass:this.host._fullRegistryHass,planHass:this.host._planHass,hass:this.host.hass,spaceModelById:t=>this.host._spaceModelById(t),currentSpace:()=>this.host._spaceModel(),position:t=>this.host._pos(t),updateDialog:t=>{this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,...t})},dialogDeviceId:()=>this.host._markerDialog?.devId,t:(t,e)=>this.host._t(t,e),help:t=>this._help(t),boolInput:(t,e)=>this._boolInput(t,e),toast:t=>this.host._showToast(t),setup:this._radarSetup,configRev:this.host._cfgRev},s)}_renderMarkerDialog(){return Fa.call(this)}_renderSpaceDialog(){return wr.call(this)}_renderMergeDialog(){const t=this.host._mergeDialog,e=this.host._spaceModel()?.rooms||[],s=(s,i)=>{const o=e.find(t=>t.id===s),a=o?.area?this.host.hass.areas[o.area]?.name:null;return p`
    `}_markerValueBadgeFields(t){return Zi({touched:t.valueBadgeTouched,originalHas:t.originalHasValueBadge,original:t.originalValueBadge,enabled:t.valueBadgeEnabled,source:t.valueBadgeSource,position:t.valueBadgePosition})}_markerValueSourceFields(t){return Yi({touched:t.valueSourceTouched,originalHas:t.originalHasValueSource,original:t.originalValueSource,source:t.valueSource})}_markerDraft(t){if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return null;const e=x(t.room),s=Zs(t.binding,t.devId,()=>"__hp_device_preview__"),i=this.host._markers.find(e=>e.id===s||e.id===t.devId),o=T(t.binding,t.controls,this.host._bindingEntities(t.binding)),a=this._effectiveStoredTapAction(t),n={id:s,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle||null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===a&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:o.length?o:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),...this._markerValueSourceFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=xt(t.glowRadius);return null==e||e<=0?null:Math.round(this.host._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:t.hideFromPlan,vacuum:i?.vacuum||null},r=!!i&&("string"==typeof i.area&&i.area.length>0||null===i.area&&!!i.space&&!!i.room_id);return"virtual"===t.binding||t.roomTouched?(n.space=e?.space||("virtual"===t.binding?this.host._space:null),n.area=e?.area||null,n.room_id=e?.roomId||null):r&&(n.space=i.space,n.area=i.area,n.room_id=i.room_id),n}_markerPreviewDevice(t){const e=this._markerDraft(t);if(!e)return null;const s=`${this.host._haRegistry.revision}\n${yt(this.host._markers)}\n${JSON.stringify(e)}`;if(this.host._markerPreviewMemo?.key===s)return this.host._markerPreviewMemo.device;const i=Xi({hass:this.host.hass,registry:this.host._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this.host._areaToSpace).map(([t,e])=>[t,e.space])),marker:e,siblingMarkers:this.host._markers,settings:this.host._settings,excluded:this.host._excluded,showAll:this.host._showAll,firstSpaceId:this.host._model[0]?.id||this.host._space,loc:t=>this.host._t(t),iconRules:this.host._iconRules});return this.host._markerPreviewMemo={key:s,device:i},i}_markerPreviewDevices(t){const e=this.host._markerPreviewDevicesMemo;if(e?.base===this.host._devices&&e.preview===t)return e.devices;const s=[...this.host._devices.filter(e=>e.id!==t.id),t];return this.host._markerPreviewDevicesMemo={base:this.host._devices,preview:t,devices:s},s}_toggleIntent(t,e=this.host._devices){return this.host._toggleIntent(t,e)}_toggleIntentForDialog(t){const e=this._markerPreviewDevice(t);if(!e)return null;const s=this._markerPreviewDevices(e);return this._toggleIntent(e,s)}_toggleStateText(t,e){return this.host._toggleStateText(t,e)}_toggleConfirmationStateText(t){return this.host._toggleConfirmationStateText(t)}_toggleConfirmationLines(t){return this.host._toggleConfirmationLines(t)}_toggleHintLines(t){if(!t)return[];const e=t=>this.host._t(`marker.toggle_effect_${t.replace("-","_")}`),s=t=>this.host._t(`marker.toggle_skip_${t.replace("-","_")}`);return Qi(t,{single:t=>{if("via"in t&&"virtual-light"===t.via)return this.host._t("marker.virtual_light_target",{name:t.name});const e=t.entityId||("ref"in t?t.ref:""),s=t.name||e;return this.host._t("marker.toggle_hint_single",{name:s,id:e})},group:t=>this.host._t("marker.toggle_hint_group",{count:t.length,names:t.map(t=>`${t.name} (${t.entityId})`).join(", ")}),currentNext:(t,s)=>"virtual-light"===t.via?this.host._t("marker.virtual_light_current",{state:this.host._t("on"===t.state?"marker.virtual_light_state_on":"marker.virtual_light_state_off"),effect:e(s)}):this.host._t("marker.toggle_hint_current",{state:this._toggleStateText(t.entityId,t.state),effect:e(s)}),groupCurrentNext:(t,s)=>this.host._t("marker.toggle_hint_group_current",{on:t.filter(t=>"on"===t.state).length,count:t.length,effect:e(s)}),skipped:t=>this.host._t("marker.toggle_hint_skipped",{count:t.length,targets:t.map(t=>{const e=t.entityId||t.ref;return`${t.name||e} (${e}: ${s(t.reason)})`}).join(", ")}),none:t=>this.host._t(`marker.toggle_none_${t.replaceAll("-","_")}`)})}_effectiveStoredTapAction(t,e){return t.tapActionTouched?t.tapAction:Xs(t.originalHasTapAction?t.originalTapAction:null,e)}_effectiveMarkerTapAction(t,e=this._markerPreviewDevice(t)){return this._effectiveStoredTapAction(t,e?.primary?.split(".")[0])}_announceToggleDraft(t){const e=this._markerPreviewDevice(t),s=t.tapActionTouched?t:{...t,tapAction:this._effectiveMarkerTapAction(t,e)},i="toggle"===s.tapAction?this._toggleHintLines(this._toggleIntentForDialog(s)).join(" "):"";return{...s,tapHintAnnouncement:i}}_valueBadgeForBinding(t,e){const s={...t,binding:e,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0},i=this._markerPreviewDevice(s);if(!i)return{valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0};const o=[...this.host._devices.filter(t=>t.id!==i.id),i],a=g(this.host._planHass,i,o),n=f(this.host._planHass,i,a);return{valueBadgeEnabled:t.valueBadgeEnabled&&!!n,valueBadgeSource:n,valueBadgeTouched:!0}}_markerSpatialSource(t){const e=this._markerPreviewDevice(t);if(!e)return null;const s={...e,hidden:!1};return to(eo(this.host._planHass,[...this.host._devices.filter(t=>t.id!==s.id),s],null,this.host._virtualLights).filter(t=>t.device.id===s.id))}_markerAutoHasSpatialSource(t){const e={...t,lightRole:"auto",lightRoleTouched:!0},s=this._markerPreviewDevice(e);return!!s&&so(this.host._planHass,{...s})}_setMarkerLightRole(t){const e=this.host._markerDialog;e&&(this.host._markerDialog={...e,lightRole:t,lightRoleTouched:!0})}_controlRefInfo(t){if(!t.startsWith("marker:"))return{label:this.host.hass.states[t]?.attributes?.friendly_name||t,sub:t,icon:t.startsWith("light.")?"mdi:lightbulb":"mdi:toggle-switch",warning:!this.host._planEntityAvailable(t)};const e=t.slice(7),s=this.host._markers.find(t=>t.id===e),i=this.host._devices.find(t=>t.id===e);if(!s||s.removed||!0!==s.is_light)return{label:this.host._t("marker.control_missing_label"),sub:`${this.host._t("marker.control_broken")} (${t})`,icon:"mdi:alert-outline",warning:!0};const o=this.host._serverCfg?.spaces.find(t=>t.id===(i?.space||s.space)),a=!!i&&w(i).length>0;return{label:s.name||i?.name||e,sub:[o?.title||i?.space||s.space,s.room_id||i?.area,a?"":this.host._t("marker.control_passive")].filter(Boolean).join(" · "),icon:s.icon||i?.icon||"mdi:lightbulb-outline",warning:!0===s.hidden||!0===i?.hidden}}_valueBadgeCandidateLabel(t){const e=t.source;if("derived_lqi"===e.kind)return this.host._t("marker.value_badge_lqi");if("derived_marker_state"===e.kind)return this.host._t("marker.value_badge_marker_state",{name:t.label});if("entity_state"===e.kind)return this.host._t("marker.value_badge_state",{name:t.label});const s=this.host.hass.states[e.entity_id]?.attributes?.friendly_name||this.host._fullRegistryHass.entities[e.entity_id]?.name||e.entity_id;return this.host._t(`marker.value_badge_attr_${e.attribute}`,{name:s})}_controlCandidates(t){const e=this._markerDraft(t)?.id||t.devId||"",s=[],i=new Set;for(const t of this.host._markers){if(t.id===e||t.removed||t.hidden||!0!==t.is_light)continue;if("virtual"!==t.binding&&"active"!==this.host._bindingStatus(t.binding).kind)continue;const o=this.host._devices.find(e=>e.id===t.id);if(!o||o.hidden)continue;const a=this._controlRefInfo(`marker:${t.id}`);for(const t of w(o))i.add(t);s.push({value:`marker:${t.id}`,label:a.label,sub:a.sub,icon:a.icon,search:`${a.label} ${a.sub} ${t.id} ${w(o).join(" ")}`.toLowerCase()})}const o=Object.keys(this.host.hass.states||{}).filter(e=>io(e)&&!i.has(e)&&oo(t.binding,[e],this.host._bindingEntities(t.binding)).length>0&&this.host._planEntityAvailable(e)).map(t=>{const e=this._controlRefInfo(t);return{value:t,label:e.label,sub:t,icon:e.icon,search:`${e.label} ${t}`.toLowerCase()}}),a=t.controlsFilter.trim().toLowerCase();return[...s,...o].filter(e=>!t.controls.includes(e.value)&&(!a||e.search.includes(a))).slice(0,12).map(({search:t,...e})=>e)}_addControlRef(t,e){if(e.startsWith("marker:")){const s=this._markerDraft(t)?.id||t.devId||"";if(!s)return void this.host._showToast(this.host._t("toast.marker_binding_required"));const i=e.slice(7),o=this._markerDraft(t),a=o?[...this.host._markers.filter(t=>t.id!==s),o]:this.host._markers;if(ao(a,s,i))return void this.host._showToast(this.host._t("toast.marker_control_cycle"))}this.host._markerDialog=this._announceToggleDraft({...t,controls:[...t.controls,e],controlsFilter:""})}_setMarkerGlowMode(t){const e=this.host._markerDialog;if(!e)return;if("auto"===t)return void(this.host._markerDialog={...e,glowMode:t,glowTouched:!0});const s=this._markerSpatialSource(e),i=no(s?this.host._planHass.states[s.eid]:void 0,null,this.host._fillColors.glow_light.c),o=!e.glowColorDrafted,a="fixed"===t&&!e.glowBrightnessDrafted;this.host._markerDialog={...e,glowMode:t,glowColor:o?i.c:e.glowColor,glowBrightness:a?Math.max(1,Math.round(100*i.bri)):e.glowBrightness,glowColorDrafted:!0,glowBrightnessDrafted:e.glowBrightnessDrafted||"fixed"===t,glowTouched:!0}}_renderRadarSection(t,e,s="main"){return sc({dialog:t,device:e,registryHass:this.host._fullRegistryHass,planHass:this.host._planHass,hass:this.host.hass,spaceModelById:t=>this.host._spaceModelById(t),currentSpace:()=>this.host._spaceModel(),position:t=>this.host._pos(t),updateDialog:t=>{this.host._markerDialog&&(this.host._markerDialog={...this.host._markerDialog,...t})},dialogDeviceId:()=>this.host._markerDialog?.devId,t:(t,e)=>this.host._t(t,e),help:t=>this._help(t),boolInput:(t,e)=>this._boolInput(t,e),toast:t=>this.host._showToast(t),setup:this._radarSetup,configRev:this.host._cfgRev},s)}_renderMarkerDialog(){return za.call(this)}_renderSpaceDialog(){return yr.call(this)}_renderMergeDialog(){const t=this.host._mergeDialog,e=this.host._spaceModel()?.rooms||[],s=(s,i)=>{const o=e.find(t=>t.id===s),a=o?.area?this.host.hass.areas[o.area]?.name:null;return p`
    `}_renderRoomDialog(){return Pr.call(this)}}export{Kd as EDITOR_RUNTIME_FINGERPRINT,Vd as HouseplanEditorRuntime}; +
    `}_renderRoomDialog(){return Sr.call(this)}}export{Ud as EDITOR_RUNTIME_FINGERPRINT,Kd as HouseplanEditorRuntime}; diff --git a/dist/houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js b/dist/houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js similarity index 95% rename from dist/houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js rename to dist/houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js index b7815f67..8c737236 100644 --- a/dist/houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js +++ b/dist/houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js @@ -1,5 +1,5 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{l as t,bq as s,A as e,aC as o,c as a,h as i,cE as l,cF as h,cG as n,bn as r,cH as c,cM as p,cI as d,cJ as _,cK as u,cL as g,cN as m,cO as b}from"./houseplan-card-BWAph8ZF.js";import{D as f,C as v,E as y,G as w,H as D,I as $,J as S,v as C}from"./backdrop-pick-CtZfmF4H.js";import"./form-kit.styles-DcvCvE8g.js";const k="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";class F{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(i){const l=`${i}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,i)&&s(h,l)?a``:e}_openSpaceDialog(t,s){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===t){const e=this.host._serverCfg.spaces.find(t=>t.id===s);if(!e)return;const o=i(e),a=e.settings?.custom_fill&&"object"==typeof e.settings.custom_fill?l(e.settings.custom_fill):null,p="none"===o.fill?{...a||h,a:0}:a;return void(this.host._spaceDialog={mode:t,spaceId:s,title:e.title,planUrl:e.plan_url||null,planFile:null,source:e.plan_url?"file":"draw",showBorders:o.showBorders,showNames:o.showNames,zeroWallStyle:c(e),displayTouched:!0,hideDecor:o.hideDecor,hideOpenings:o.hideOpenings,roomColor:o.color,roomOpacity:o.opacity,fillMode:"none"===o.fill?"custom":o.fill,customFill:p,glowEnabled:o.glow,bgColor:o.bgColor,bgMode:"static"===e.settings?.bg_mode||"daynight"===e.settings?.bg_mode?e.settings.bg_mode:null,northDeg:r({},e.settings),sunRays:"boolean"==typeof e.settings?.sun_rays?e.settings.sun_rays:null,tempMin:o.tempMin,tempMax:o.tempMax,showLqi:o.showLqi??this.host._config?.show_signal??!0,cardFontScale:o.cardFontScale,labelTemp:o.labelTemp,labelHum:o.labelHum,labelLqi:o.labelLqi,labelLight:o.labelLight,cellCm:Number(e.cell_cm)>0?Number(e.cell_cm):5,cellCmInput:n(Number(e.cell_cm)>0?Number(e.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const e=p(this.host._imperial);this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...m(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:{...h,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:_,tempMax:d,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:e,cellCmInput:n(e,this.host._imperial),cellCmTouched:!1,busy:!1},f(this.host,this.host._spaceDialog)}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;s.value="";const o=await v(e);if("reject"===o.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===o.kind)return void(this.host._backdropGuard=o.state);const a=await y(e,o.ext,e.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:a})}_renderBackdropGuard(){return w(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??e}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),o=this.host._spaceDialog;return o&&o.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...o,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const s=this.host._spaceDialog,e=s?.saved?.find(s=>s.name===t);if(!s||!e||e.used_by.length||e.url===s.planUrl)return;const o=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),a=this.host._spaceDialog,i=a?.saved?.find(s=>s.name===t);if(o&&a&&i&&i.url===e.url&&i.modified===e.modified&&!i.used_by.length&&i.url!==a.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return a`
    ${this.host._t("space.loading")}
    `;const s=t.saved||[];if(!s.length)return a`
    ${this.host._t("space.no_saved")}
    `;return a`
    +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{l as t,bq as s,A as e,aC as o,c as a,g as i,cE as l,cF as h,cG as n,bn as r,cH as c,cM as p,cI as d,cJ as _,cK as u,cL as g,cN as m,cO as f}from"./houseplan-card-9fMSy3y3.js";import{D as b,C as v,E as y,G as w,H as D,I as $,J as S,v as C}from"./backdrop-pick-BJOCHJxe.js";import"./form-kit.styles-CKUQLdmn.js";const k="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";class F{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(i){const l=`${i}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,i)&&s(h,l)?a``:e}_openSpaceDialog(t,s){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===t){const e=this.host._serverCfg.spaces.find(t=>t.id===s);if(!e)return;const o=i(e),a=e.settings?.custom_fill&&"object"==typeof e.settings.custom_fill?l(e.settings.custom_fill):null,p="none"===o.fill?{...a||h,a:0}:a;return void(this.host._spaceDialog={mode:t,spaceId:s,title:e.title,planUrl:e.plan_url||null,planFile:null,source:e.plan_url?"file":"draw",showBorders:o.showBorders,showNames:o.showNames,zeroWallStyle:c(e),displayTouched:!0,hideDecor:o.hideDecor,hideOpenings:o.hideOpenings,roomColor:o.color,roomOpacity:o.opacity,fillMode:"none"===o.fill?"custom":o.fill,customFill:p,glowEnabled:o.glow,bgColor:o.bgColor,bgMode:"static"===e.settings?.bg_mode||"daynight"===e.settings?.bg_mode?e.settings.bg_mode:null,northDeg:r({},e.settings),sunRays:"boolean"==typeof e.settings?.sun_rays?e.settings.sun_rays:null,tempMin:o.tempMin,tempMax:o.tempMax,showLqi:o.showLqi??this.host._config?.show_signal??!0,cardFontScale:o.cardFontScale,labelTemp:o.labelTemp,labelHum:o.labelHum,labelLqi:o.labelLqi,labelLight:o.labelLight,cellCm:Number(e.cell_cm)>0?Number(e.cell_cm):5,cellCmInput:n(Number(e.cell_cm)>0?Number(e.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const e=p(this.host._imperial);this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...m(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:{...h,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:_,tempMax:d,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:e,cellCmInput:n(e,this.host._imperial),cellCmTouched:!1,busy:!1},b(this.host,this.host._spaceDialog)}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;s.value="";const o=await v(e);if("reject"===o.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===o.kind)return void(this.host._backdropGuard=o.state);const a=await y(e,o.ext,e.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:a})}_renderBackdropGuard(){return w(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??e}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),o=this.host._spaceDialog;return o&&o.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...o,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const s=this.host._spaceDialog,e=s?.saved?.find(s=>s.name===t);if(!s||!e||e.used_by.length||e.url===s.planUrl)return;const o=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),a=this.host._spaceDialog,i=a?.saved?.find(s=>s.name===t);if(o&&a&&i&&i.url===e.url&&i.modified===e.modified&&!i.used_by.length&&i.url!==a.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return a`
    ${this.host._t("space.loading")}
    `;const s=t.saved||[];if(!s.length)return a`
    ${this.host._t("space.no_saved")}
    `;return a`
    ${s.map(s=>{return a`
    @@ -16,7 +16,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
    `;var e})} -
    `}async _saveConfigNow(){this.host._cfgEpoch++;try{await this.host._writeConfig()}catch(t){const s=t;throw s?.physicalGeometryRolledBack?await this.host._reloadRejectedPhysicalWrite():"conflict"===s?.code&&await this.host._reloadConfigOnly(),t}}async _saveSpaceDialog(){const t=this.host._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this.host._showToast(this.host._t("toast.plan_required"));const s="create"===t.mode&&0===(this.host._serverCfg?.spaces.length||0);this.host._spaceDialog={...t,busy:!0};try{const e="create"===t.mode?`s${Date.now().toString(36)}`:t.spaceId;let o=null;if("file"===t.source&&t.planFile){o={url:(await this.host.hass.callWS({type:"houseplan/plan/set",space_id:e,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let a=t.savedAspect||null;!o&&"file"===t.source&&t.planUrl&&!a&&this.host._aspectJob&&(a=await this.host._aspectJob||null);const i=this.host._serverCfg;let l=i.spaces.find(t=>t.id===e);if("create"===t.mode)l=b(e,t.title.trim()),i.spaces.push(l);else{if(!l)throw new Error(`space ${e} is gone from the config`);l.title=t.title.trim()}if(!l)throw new Error(`space ${e} is unavailable`);if(o?(l.plan_url=o.url,l.plan_aspect=o.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==l.plan_url&&(l.plan_url=t.planUrl,l.plan_aspect=a),"draw"===t.source&&(l.plan_url=null,l.plan_aspect=null,delete l.plan_x,delete l.plan_y,delete l.plan_scale,delete l.plan_scale_x,delete l.plan_scale_y,delete l.plan_angle),l.settings={...l.settings||{},show_borders:t.showBorders,show_names:t.showNames,hide_decor:t.hideDecor||void 0,hide_openings:t.hideOpenings||void 0,room_color:t.roomColor,room_opacity:t.roomOpacity,bg_color:t.bgColor||void 0,bg_mode:t.bgMode||void 0,north_deg:t.northDeg??void 0,sun_rays:t.sunRays??void 0,fill_mode:t.fillMode,custom_fill:t.customFill||void 0,glow_enabled:t.glowEnabled,temp_min:Number.isFinite(t.tempMin)?Math.min(t.tempMin,t.tempMax):_,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):d,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},l.zero_wall_style=t.zeroWallStyle,l.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(D,Math.min($,t.cellCm)):5,await this._saveConfigNow(),this.host._spaceDialog=null,"create"===t.mode&&this.host._commitSpace(l.id),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._importQueue.length)this._openNextImport();else if(s||this.host._importTotal>0){const t=this.host._importTotal>0;this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),await this.host._requestMode("plan"),this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this.host._primeDrawWallField(),this.host._showToast(this.host._t(s&&!t?"toast.space_added_onboard":"import.done"))}else this.host._showToast(this.host._t("create"===t.mode?"toast.space_added":"toast.space_saved")),"create"===t.mode&&("plan"!==this.host._mode?await this.host._requestMode("plan"):(this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this.host._primeDrawWallField(),this.host._saveNav()))}catch(t){const s=t;"conflict"!==s?.code&&await this.host._reloadConfigOnly(!0),this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteSpace(){const t=this.host._spaceDialog;if(!t||"edit"!==t.mode)return;const s=this.host._serverCfg;if(!s)return;const e=s.spaces.find(s=>s.id===t.spaceId);if(!e)return;const o=S(s,this.host._layout||{},t.spaceId||""),a=1===s.spaces.length&&s.spaces[0]?.id===t.spaceId;if(o.count&&!a)return void(this.host._spaceDialog={...t,deleteBlockers:o.count});const i=t.spaceId,l=await this.host._confirmDanger({key:"delete-space",kind:"destructive",title:this.host._t("confirm.delete_space_title"),message:this.host._t("confirm.delete_space_body"),objectName:e.title,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),h=this.host._spaceDialog,n=this.host._serverCfg;if(!l||!h||"edit"!==h.mode||h.busy||h.spaceId!==i||!n)return;if(!n.spaces.find(t=>t.id===i))return;const r=S(n,this.host._layout||{},i),c=1===n.spaces.length&&n.spaces[0]?.id===i;if(!r.count||c){this.host._spaceDialog={...h,deleteBlockers:0,busy:!0};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),this.host._persistLayout.pending()&&this.host._persistLayout.flush(),await this.host._writeChain,await this.host.hass.callWS({type:"houseplan/space/delete",space_id:i,expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev});const[t,s]=await Promise.all([this.host._getAuthoritativeConfig(),this.host.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this.host._adoptAuthoritative({cfgResp:t,layResp:s,reason:"space-delete",profile:"post-write"})).status)return this.host._spaceDialog={...h,busy:!1},void this.host.requestUpdate();this.host._spaceDialog=null,this.host._space===i&&this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||""),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.space_deleted"))}catch(t){const s=t;"conflict"!==s?.code&&"space_in_use"!==s?.code||await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]);const e=this.host._serverCfg;if(this.host._spaceDialog&&e){const t=S(e,this.host._layout||{},i),s=1===e.spaces.length&&e.spaces[0]?.id===i;this.host._spaceDialog={...this.host._spaceDialog,busy:!1,deleteBlockers:s?0:t.count}}this.host._showToast(this.host._t("toast.delete_failed",{err:this.host._errText(t)}))}}else this.host._spaceDialog={...h,deleteBlockers:r.count}}_startImport(){const t=this.host._importDialog;if(!t)return;const s=t.floors.filter(t=>t.checked).map(t=>t.name);this.host._importDialog=null,s.length?(this.host._importQueue=s,this.host._importTotal=s.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this.host._importQueue.shift();if(void 0===t)return;const s=p(this.host._imperial);this.host._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...m(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:_,tempMax:d,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:s,cellCmInput:n(s,this.host._imperial),cellCmTouched:!1,busy:!1},f(this.host,this.host._spaceDialog)}_skipImport(){this.host._spaceDialog=null,this.host._importQueue.length?this._openNextImport():this.host._importTotal>0&&this.host._model.length&&(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this.host._requestMode("plan").then(()=>{this.host._showToast(this.host._t("import.done"))}))}_renderImportDialog(){const t=this.host._importDialog,s=t.floors.filter(t=>t.checked).length;return a``}async _saveConfigNow(){this.host._cfgEpoch++;try{await this.host._writeConfig()}catch(t){const s=t;throw s?.physicalGeometryRolledBack?await this.host._reloadRejectedPhysicalWrite():"conflict"===s?.code&&await this.host._reloadConfigOnly(),t}}async _saveSpaceDialog(){const t=this.host._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this.host._showToast(this.host._t("toast.plan_required"));const s="create"===t.mode&&0===(this.host._serverCfg?.spaces.length||0);this.host._spaceDialog={...t,busy:!0};try{const e="create"===t.mode?`s${Date.now().toString(36)}`:t.spaceId;let o=null;if("file"===t.source&&t.planFile){o={url:(await this.host.hass.callWS({type:"houseplan/plan/set",space_id:e,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let a=t.savedAspect||null;!o&&"file"===t.source&&t.planUrl&&!a&&this.host._aspectJob&&(a=await this.host._aspectJob||null);const i=this.host._serverCfg;let l=i.spaces.find(t=>t.id===e);if("create"===t.mode)l=f(e,t.title.trim()),i.spaces.push(l);else{if(!l)throw new Error(`space ${e} is gone from the config`);l.title=t.title.trim()}if(!l)throw new Error(`space ${e} is unavailable`);if(o?(l.plan_url=o.url,l.plan_aspect=o.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==l.plan_url&&(l.plan_url=t.planUrl,l.plan_aspect=a),"draw"===t.source&&(l.plan_url=null,l.plan_aspect=null,delete l.plan_x,delete l.plan_y,delete l.plan_scale,delete l.plan_scale_x,delete l.plan_scale_y,delete l.plan_angle),l.settings={...l.settings||{},show_borders:t.showBorders,show_names:t.showNames,hide_decor:t.hideDecor||void 0,hide_openings:t.hideOpenings||void 0,room_color:t.roomColor,room_opacity:t.roomOpacity,bg_color:t.bgColor||void 0,bg_mode:t.bgMode||void 0,north_deg:t.northDeg??void 0,sun_rays:t.sunRays??void 0,fill_mode:t.fillMode,custom_fill:t.customFill||void 0,glow_enabled:t.glowEnabled,temp_min:Number.isFinite(t.tempMin)?Math.min(t.tempMin,t.tempMax):_,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):d,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},l.zero_wall_style=t.zeroWallStyle,l.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(D,Math.min($,t.cellCm)):5,await this._saveConfigNow(),this.host._spaceDialog=null,"create"===t.mode&&this.host._commitSpace(l.id),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._importQueue.length)this._openNextImport();else if(s||this.host._importTotal>0){const t=this.host._importTotal>0;this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),await this.host._requestMode("plan"),this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this.host._primeDrawWallField(),this.host._showToast(this.host._t(s&&!t?"toast.space_added_onboard":"import.done"))}else this.host._showToast(this.host._t("create"===t.mode?"toast.space_added":"toast.space_saved")),"create"===t.mode&&("plan"!==this.host._mode?await this.host._requestMode("plan"):(this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this.host._primeDrawWallField(),this.host._saveNav()))}catch(t){const s=t;"conflict"!==s?.code&&await this.host._reloadConfigOnly(!0),this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteSpace(){const t=this.host._spaceDialog;if(!t||"edit"!==t.mode)return;const s=this.host._serverCfg;if(!s)return;const e=s.spaces.find(s=>s.id===t.spaceId);if(!e)return;const o=S(s,this.host._layout||{},t.spaceId||""),a=1===s.spaces.length&&s.spaces[0]?.id===t.spaceId;if(o.count&&!a)return void(this.host._spaceDialog={...t,deleteBlockers:o.count});const i=t.spaceId,l=await this.host._confirmDanger({key:"delete-space",kind:"destructive",title:this.host._t("confirm.delete_space_title"),message:this.host._t("confirm.delete_space_body"),objectName:e.title,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),h=this.host._spaceDialog,n=this.host._serverCfg;if(!l||!h||"edit"!==h.mode||h.busy||h.spaceId!==i||!n)return;if(!n.spaces.find(t=>t.id===i))return;const r=S(n,this.host._layout||{},i),c=1===n.spaces.length&&n.spaces[0]?.id===i;if(!r.count||c){this.host._spaceDialog={...h,deleteBlockers:0,busy:!0};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),this.host._persistLayout.pending()&&this.host._persistLayout.flush(),await this.host._writeChain,await this.host.hass.callWS({type:"houseplan/space/delete",space_id:i,expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev});const[t,s]=await Promise.all([this.host._getAuthoritativeConfig(),this.host.hass.callWS({type:"houseplan/layout/get"})]);if("adopted"!==(await this.host._adoptAuthoritative({cfgResp:t,layResp:s,reason:"space-delete",profile:"post-write"})).status)return this.host._spaceDialog={...h,busy:!1},void this.host.requestUpdate();this.host._spaceDialog=null,this.host._space===i&&this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||""),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.space_deleted"))}catch(t){const s=t;"conflict"!==s?.code&&"space_in_use"!==s?.code||await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]);const e=this.host._serverCfg;if(this.host._spaceDialog&&e){const t=S(e,this.host._layout||{},i),s=1===e.spaces.length&&e.spaces[0]?.id===i;this.host._spaceDialog={...this.host._spaceDialog,busy:!1,deleteBlockers:s?0:t.count}}this.host._showToast(this.host._t("toast.delete_failed",{err:this.host._errText(t)}))}}else this.host._spaceDialog={...h,deleteBlockers:r.count}}_startImport(){const t=this.host._importDialog;if(!t)return;const s=t.floors.filter(t=>t.checked).map(t=>t.name);this.host._importDialog=null,s.length?(this.host._importQueue=s,this.host._importTotal=s.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this.host._importQueue.shift();if(void 0===t)return;const s=p(this.host._imperial);this.host._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...m(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:_,tempMax:d,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:s,cellCmInput:n(s,this.host._imperial),cellCmTouched:!1,busy:!1},b(this.host,this.host._spaceDialog)}_skipImport(){this.host._spaceDialog=null,this.host._importQueue.length?this._openNextImport():this.host._importTotal>0&&this.host._model.length&&(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this.host._requestMode("plan").then(()=>{this.host._showToast(this.host._t("import.done"))}))}_renderImportDialog(){const t=this.host._importDialog,s=t.floors.filter(t=>t.checked).length;return a`this.host._importDialog=null}>
    diff --git a/dist/houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js b/dist/houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js similarity index 95% rename from dist/houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js rename to dist/houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js index 4e572917..c2c384c1 100644 --- a/dist/houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js +++ b/dist/houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js @@ -1,4 +1,4 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{az as e,l as t,A as i,eb as r,as as o,c as s,ay as n}from"./houseplan-card-BWAph8ZF.js";import{t as a,a as h,r as d}from"./zigbee-topology-D0gydI7H.js";import{zigbeeTopologyRuntimeSnapshot as p,subscribeZigbeeTopology as l}from"./zigbee-topology-runtime-BXasXMdL.js";function c(e,t,i,r,o,s=9,n=4.5){const a=t.x-e.x,h=t.y-e.y,d=Math.hypot(a,h),p=d-Math.max(0,i)-Math.max(0,r);if(!Number.isFinite(d)||d<=0||p<4)return null;const l=a/d,c=h/d,_="toward-neighbor"===o,u=_?{x:t.x-l*Math.max(0,r),y:t.y-c*Math.max(0,r)}:{x:e.x+l*Math.max(0,i),y:e.y+c*Math.max(0,i)},m=Math.min(s,Math.max(4,.45*p)),v=Math.min(n,.5*m),b=_?-1:1,g=u.x+l*m*b,y=u.y+c*m*b,x=-c;return{tip:u,points:[u,{x:g+x*v,y:y+l*v},{x:g-x*v,y:y-l*v}]}}const _={revision:0,topologies:[],states:{}},u="data-hp-zigbee-topology-endpoint";class m extends e{constructor(){super(...arguments),this.devices=[],this.currentSpace="",this._runtime=_,this._hovered="",this._desiredEndpointIds=new Set,this._endpointSetDirty=!1,this._endpointElements=new Set,this._pointerOver=e=>{if(!this._mouseAllowed(e))return void this._clear();const t=this._deviceFromEvent(e),i=t?.dataset.id||"";i&&i!==this._hovered&&(this._hovered=i,this.requestUpdate())},this._pointerOut=e=>{const t=this._deviceFromEvent(e);if(!t||t.dataset.id!==this._hovered)return;const i=e.relatedTarget instanceof Element?e.relatedTarget.closest('[data-hp="device"]'):null;i?.dataset.id!==this._hovered&&this._clear()},this._pointerDown=e=>{"mouse"!==e.pointerType&&this._clear()}}connectedCallback(){super.connectedCallback();const e=this.getRootNode();e.host&&"undefined"!=typeof MutationObserver&&(this._hoverGateObserver=new MutationObserver(()=>{e.host.hasAttribute("data-pointer-hover")||this._clear()}),this._hoverGateObserver.observe(e.host,{attributes:!0,attributeFilter:["data-pointer-hover"]})),queueMicrotask(()=>this._connectParent())}disconnectedCallback(){this._release?.(),this._release=void 0,this._disconnectParent(),this._hoverGateObserver?.disconnect(),this._hoverGateObserver=void 0,this._hovered="",this._desiredEndpointIds.clear(),super.disconnectedCallback()}updated(e){e.has("hass")&&(this._release?.(),this._acceptRuntime(p(this.hass)),this._release=l(this.hass,()=>{this._acceptRuntime(p(this.hass))}));const t=e.has("currentSpace")||e.has("devices")||e.has("registry");t&&(this._mappedMemo=void 0,this.devices.some(e=>e.id===this._hovered&&e.space===this.currentSpace)||this._clear()),this._connectParent(),(this._endpointSetDirty||t)&&this._syncEndpointOwnership()}_acceptRuntime(e){e.revision===this._runtime.revision&&e.topologies===this._runtime.topologies&&e.states===this._runtime.states||(this._setDesiredEndpointIds([]),this._clearEndpointOwnership(),this._endpointSetDirty=!1,this._runtime=e,this._mappedMemo=void 0,this.requestUpdate())}_connectParent(){const e=this.parentElement;e&&e!==this._parent&&(this._disconnectParent(),this._parent=e,e.addEventListener("pointerover",this._pointerOver),e.addEventListener("pointerout",this._pointerOut),e.addEventListener("pointerdown",this._pointerDown,!0),"undefined"!=typeof MutationObserver&&(this._markerObserver=new MutationObserver(()=>this._syncEndpointOwnership()),this._markerObserver.observe(e,{childList:!0})),this._syncEndpointOwnership())}_disconnectParent(){this._parent?.removeEventListener("pointerover",this._pointerOver),this._parent?.removeEventListener("pointerout",this._pointerOut),this._parent?.removeEventListener("pointerdown",this._pointerDown,!0),this._markerObserver?.disconnect(),this._markerObserver=void 0,this._clearEndpointOwnership(),this._parent=void 0}_deviceFromEvent(e){for(const t of e.composedPath())if(t instanceof HTMLElement&&"device"===t.dataset.hp)return t;return null}_mouseAllowed(e){const t=this.getRootNode();return"mouse"===e.pointerType&&t.host?.hasAttribute?.("data-pointer-hover")}_clear(){this._setDesiredEndpointIds([]),this._clearEndpointOwnership(),this._endpointSetDirty=!1,this._hovered&&(this._hovered="",this.requestUpdate())}_setDesiredEndpointIds(e){const t=new Set(e);t.size===this._desiredEndpointIds.size&&[...t].every(e=>this._desiredEndpointIds.has(e))||(this._desiredEndpointIds=t,this._endpointSetDirty=!0)}_marker(e){return[...this._parent?.querySelectorAll('.dev[data-hp="device"][data-id]')||[]].find(t=>t.dataset.id===e)||null}_clearEndpointOwnership(){for(const e of this._endpointElements)e.removeAttribute(u);for(const e of this._parent?.querySelectorAll(`[${u}]`)||[])e.removeAttribute(u);this._endpointElements.clear()}_syncEndpointOwnership(){const e=new Set;for(const t of this._desiredEndpointIds){const i=this._marker(t);i&&e.add(i)}for(const t of this._endpointElements)e.has(t)||t.removeAttribute(u);for(const t of this._parent?.querySelectorAll(`[${u}]`)||[])e.has(t)||t.removeAttribute(u);for(const t of e)this._endpointElements.has(t)&&t.hasAttribute(u)||t.setAttribute(u,"");this._endpointElements=e,this._endpointSetDirty=!1}_position(e,t,i){const r=this._marker(e);if(!r)return null;const o=Number.parseFloat(r.style.left),s=Number.parseFloat(r.style.top),n=r.getBoundingClientRect();return Number.isFinite(o)&&Number.isFinite(s)?{x:o*t/100,y:s*i/100,width:n.width,height:n.height}:null}_targetText(e){if("remote-space"===e.kind){const i=this.spaces?.find(t=>t.id===e.spaceId)?.title;return"string"==typeof i&&i.trim()||a(t(this.hass),"route_other_space")}return a(t(this.hass),"unplaced-coordinator"===e.kind?"route_coordinator_not_on_plan":"route_device_not_on_plan")}_markerClearance(e){return.61*Math.max(e.width,e.height)+3}_points(e){return e.map(e=>`${e.x.toFixed(2)},${e.y.toFixed(2)}`).join(" ")}render(){if(!this._hovered||!this.registry||!this._runtime.topologies.length)return this._setDesiredEndpointIds([]),i;const e=this._mappedMemo,n=e&&e.runtime===this._runtime&&e.devices===this.devices&&e.registry===this.registry?e.mapped:h(this._runtime.topologies,this.devices,this.registry);e&&n===e.mapped||(this._mappedMemo={runtime:this._runtime,devices:this.devices,registry:this.registry,mapped:n});const p=d(n,this.currentSpace,this._hovered),l=this.clientWidth||this._parent?.clientWidth||1,_=this.clientHeight||this._parent?.clientHeight||1,u=this._position(this._hovered,l,_);if(!u)return this._setDesiredEndpointIds([]),i;const m=p.lines.map(e=>({...e,point:this._position(e.neighborMarkerId,l,_)})).filter(e=>!!e.point).map(e=>{const t=void 0===e.lqi?"rgba(145,155,165,.85)":r(e.lqi),i=e.routeDirection?c(u,e.point,this._markerClearance(u),this._markerClearance(e.point),e.routeDirection):null;return{...e,color:t,arrow:i}}),v=u.x>l/2,b=this._markerClearance(u)+18,g=p.parentTargets.map((e,t)=>{const i=30*(t-(p.parentTargets.length-1)/2),r={x:u.x+(v?-b:b),y:Math.max(14,Math.min(_-14,u.y+i))};return{target:e,point:r,arrow:c(u,r,this._markerClearance(u),0,"toward-neighbor")}});return this._setDesiredEndpointIds(m.length||g.length||p.remoteCount?[this._hovered,...m.map(e=>e.neighborMarkerId)]:[]),s` +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{az as e,l as t,A as i,eb as r,as as o,c as s,ay as n}from"./houseplan-card-9fMSy3y3.js";import{t as a,a as h,r as d}from"./zigbee-topology-CI6PJorK.js";import{zigbeeTopologyRuntimeSnapshot as p,subscribeZigbeeTopology as l}from"./zigbee-topology-runtime-d-S2Abll.js";function c(e,t,i,r,o,s=9,n=4.5){const a=t.x-e.x,h=t.y-e.y,d=Math.hypot(a,h),p=d-Math.max(0,i)-Math.max(0,r);if(!Number.isFinite(d)||d<=0||p<4)return null;const l=a/d,c=h/d,_="toward-neighbor"===o,u=_?{x:t.x-l*Math.max(0,r),y:t.y-c*Math.max(0,r)}:{x:e.x+l*Math.max(0,i),y:e.y+c*Math.max(0,i)},m=Math.min(s,Math.max(4,.45*p)),v=Math.min(n,.5*m),b=_?-1:1,g=u.x+l*m*b,y=u.y+c*m*b,f=-c;return{tip:u,points:[u,{x:g+f*v,y:y+l*v},{x:g-f*v,y:y-l*v}]}}const _={revision:0,topologies:[],states:{}},u="data-hp-zigbee-topology-endpoint";class m extends e{constructor(){super(...arguments),this.devices=[],this.currentSpace="",this._runtime=_,this._hovered="",this._desiredEndpointIds=new Set,this._endpointSetDirty=!1,this._endpointElements=new Set,this._pointerOver=e=>{if(!this._mouseAllowed(e))return void this._clear();const t=this._deviceFromEvent(e),i=t?.dataset.id||"";i&&i!==this._hovered&&(this._hovered=i,this.requestUpdate())},this._pointerOut=e=>{const t=this._deviceFromEvent(e);if(!t||t.dataset.id!==this._hovered)return;const i=e.relatedTarget instanceof Element?e.relatedTarget.closest('[data-hp="device"]'):null;i?.dataset.id!==this._hovered&&this._clear()},this._pointerDown=e=>{"mouse"!==e.pointerType&&this._clear()}}connectedCallback(){super.connectedCallback();const e=this.getRootNode();e.host&&"undefined"!=typeof MutationObserver&&(this._hoverGateObserver=new MutationObserver(()=>{e.host.hasAttribute("data-pointer-hover")||this._clear()}),this._hoverGateObserver.observe(e.host,{attributes:!0,attributeFilter:["data-pointer-hover"]})),queueMicrotask(()=>this._connectParent())}disconnectedCallback(){this._release?.(),this._release=void 0,this._disconnectParent(),this._hoverGateObserver?.disconnect(),this._hoverGateObserver=void 0,this._hovered="",this._desiredEndpointIds.clear(),super.disconnectedCallback()}updated(e){e.has("hass")&&(this._release?.(),this._acceptRuntime(p(this.hass)),this._release=l(this.hass,()=>{this._acceptRuntime(p(this.hass))}));const t=e.has("currentSpace")||e.has("devices")||e.has("registry");t&&(this._mappedMemo=void 0,this.devices.some(e=>e.id===this._hovered&&e.space===this.currentSpace)||this._clear()),this._connectParent(),(this._endpointSetDirty||t)&&this._syncEndpointOwnership()}_acceptRuntime(e){e.revision===this._runtime.revision&&e.topologies===this._runtime.topologies&&e.states===this._runtime.states||(this._setDesiredEndpointIds([]),this._clearEndpointOwnership(),this._endpointSetDirty=!1,this._runtime=e,this._mappedMemo=void 0,this.requestUpdate())}_connectParent(){const e=this.parentElement;e&&e!==this._parent&&(this._disconnectParent(),this._parent=e,e.addEventListener("pointerover",this._pointerOver),e.addEventListener("pointerout",this._pointerOut),e.addEventListener("pointerdown",this._pointerDown,!0),"undefined"!=typeof MutationObserver&&(this._markerObserver=new MutationObserver(()=>this._syncEndpointOwnership()),this._markerObserver.observe(e,{childList:!0})),this._syncEndpointOwnership())}_disconnectParent(){this._parent?.removeEventListener("pointerover",this._pointerOver),this._parent?.removeEventListener("pointerout",this._pointerOut),this._parent?.removeEventListener("pointerdown",this._pointerDown,!0),this._markerObserver?.disconnect(),this._markerObserver=void 0,this._clearEndpointOwnership(),this._parent=void 0}_deviceFromEvent(e){for(const t of e.composedPath())if(t instanceof HTMLElement&&"device"===t.dataset.hp)return t;return null}_mouseAllowed(e){const t=this.getRootNode();return"mouse"===e.pointerType&&t.host?.hasAttribute?.("data-pointer-hover")}_clear(){this._setDesiredEndpointIds([]),this._clearEndpointOwnership(),this._endpointSetDirty=!1,this._hovered&&(this._hovered="",this.requestUpdate())}_setDesiredEndpointIds(e){const t=new Set(e);t.size===this._desiredEndpointIds.size&&[...t].every(e=>this._desiredEndpointIds.has(e))||(this._desiredEndpointIds=t,this._endpointSetDirty=!0)}_marker(e){return[...this._parent?.querySelectorAll('.dev[data-hp="device"][data-id]')||[]].find(t=>t.dataset.id===e)||null}_clearEndpointOwnership(){for(const e of this._endpointElements)e.removeAttribute(u);for(const e of this._parent?.querySelectorAll(`[${u}]`)||[])e.removeAttribute(u);this._endpointElements.clear()}_syncEndpointOwnership(){const e=new Set;for(const t of this._desiredEndpointIds){const i=this._marker(t);i&&e.add(i)}for(const t of this._endpointElements)e.has(t)||t.removeAttribute(u);for(const t of this._parent?.querySelectorAll(`[${u}]`)||[])e.has(t)||t.removeAttribute(u);for(const t of e)this._endpointElements.has(t)&&t.hasAttribute(u)||t.setAttribute(u,"");this._endpointElements=e,this._endpointSetDirty=!1}_position(e,t,i){const r=this._marker(e);if(!r)return null;const o=Number.parseFloat(r.style.left),s=Number.parseFloat(r.style.top),n=r.getBoundingClientRect();return Number.isFinite(o)&&Number.isFinite(s)?{x:o*t/100,y:s*i/100,width:n.width,height:n.height}:null}_targetText(e){if("remote-space"===e.kind){const i=this.spaces?.find(t=>t.id===e.spaceId)?.title;return"string"==typeof i&&i.trim()||a(t(this.hass),"route_other_space")}return a(t(this.hass),"unplaced-coordinator"===e.kind?"route_coordinator_not_on_plan":"route_device_not_on_plan")}_markerClearance(e){return.61*Math.max(e.width,e.height)+3}_points(e){return e.map(e=>`${e.x.toFixed(2)},${e.y.toFixed(2)}`).join(" ")}render(){if(!this._hovered||!this.registry||!this._runtime.topologies.length)return this._setDesiredEndpointIds([]),i;const e=this._mappedMemo,n=e&&e.runtime===this._runtime&&e.devices===this.devices&&e.registry===this.registry?e.mapped:h(this._runtime.topologies,this.devices,this.registry);e&&n===e.mapped||(this._mappedMemo={runtime:this._runtime,devices:this.devices,registry:this.registry,mapped:n});const p=d(n,this.currentSpace,this._hovered),l=this.clientWidth||this._parent?.clientWidth||1,_=this.clientHeight||this._parent?.clientHeight||1,u=this._position(this._hovered,l,_);if(!u)return this._setDesiredEndpointIds([]),i;const m=p.lines.map(e=>({...e,point:this._position(e.neighborMarkerId,l,_)})).filter(e=>!!e.point).map(e=>{const t=void 0===e.lqi?"rgba(145,155,165,.85)":r(e.lqi),i=e.routeDirection?c(u,e.point,this._markerClearance(u),this._markerClearance(e.point),e.routeDirection):null;return{...e,color:t,arrow:i}}),v=u.x>l/2,b=this._markerClearance(u)+18,g=p.parentTargets.map((e,t)=>{const i=30*(t-(p.parentTargets.length-1)/2),r={x:u.x+(v?-b:b),y:Math.max(14,Math.min(_-14,u.y+i))};return{target:e,point:r,arrow:c(u,r,this._markerClearance(u),0,"toward-neighbor")}});return this._setDesiredEndpointIds(m.length||g.length||p.remoteCount?[this._hovered,...m.map(e=>e.neighborMarkerId)]:[]),s` ${m.length||g.length?o`${E} @@ -21,4 +21,4 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc ${this.context.t(this.busy?"pdf.saving":"pdf.save")}
    -
    `}}v.properties={context:{attribute:!1}},v.styles=A`:host{display:contents;}.body{display:grid;gap:12px;width:100%;max-width:100%;min-width:0;padding:16px 20px;box-sizing:border-box;}label{display:flex;min-width:0;min-height:44px;align-items:center;gap:12px;cursor:pointer;}label span{min-width:0;overflow-wrap:anywhere;}input{width:20px;height:20px;flex:none;accent-color:var(--hp-accent,#d89300);}.row{display:flex;align-items:center;gap:8px;width:100%;max-width:100%;min-width:0;padding:12px 16px;box-sizing:border-box;}.spacer{flex:1;}button{min-width:0;min-height:44px;max-width:100%;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--hp-line,rgb(127 127 127/.3));border-radius:12px;padding:0 18px;box-sizing:border-box;overflow-wrap:anywhere;white-space:normal;background:transparent;color:inherit;font:inherit;cursor:pointer;}button.primary{background:var(--hp-accent,#d89300);color:var(--hp-on-accent,#111);border-color:transparent;}button:disabled{opacity:.55;cursor:default;}ha-icon{flex:none;margin-right:6px;}@media (max-width:360px){.row{display:grid;grid-template-columns:minmax(0,1fr);}.spacer{display:none;}button{width:100%;}}`,customElements.get("hp-pdf-dialog")||customElements.define("hp-pdf-dialog",v);const V=(A,B,E)=>Math.hypot(A[0]-B[0],A[1]-B[1])<=E,U=A=>Number.isFinite(A)&&A>=0?A:0;function l(A){const B=Number(A);return Number.isFinite(B)&&B>0?.1/B:0}const a=(A,B)=>[...new Set([...A,...B])].sort((A,B)=>A-B),P=(A,B)=>{const E=A.points.length;if(E<=1||!V(A.points[E-1],A.points[0],B))return!1;const s=E-2;return A.edgeSources[s]=a(A.edgeSources[s],A.edgeSources[E-1]),A.points.splice(E-1,1),A.edgeSources.splice(E-1,1),!0},y=(A,B)=>{for(let E=0;E+1{let E=!1;for(;A.points.length>1;)if(P(A,B))E=!0;else{if(!y(A,B))break;E=!0}return E},N=(A,B,E)=>{const s=B[0]-A[0],w=B[1]-A[1],C=E[0]-B[0],g=E[1]-B[1],I=Math.hypot(s,w),Y=Math.hypot(C,g);if(!(I>0&&Y>0))return!1;const R=s*C+w*g;if(!(R>0))return!1;const M=s*g-w*C;return Math.abs(M)<=R*Q},K=A=>{const B=A.points.length;if(B<3)return!1;for(let E=0;E{const E=U(B),s=[],w=[];for(let B=0;B[A])};for(;Q.points.length>1;){const A=u(Q,E);if(Q.points.length<3)break;if(!K(Q)&&!A)break}return u(Q,E),Q};function J(A,B){const E=Number(A[0]),s=Number(A[1]),w=Number(B[0]),C=Number(B[1]);if(![E,s,w,C].every(Number.isFinite))return null;const g=w-E,I=C-s,Y=Math.abs(g),R=Math.abs(I),M=Math.max(Y,R),F=Math.min(Y,R);if(!(M>0)||F/M>Q)return null;const i=[(E+w)/2,(s+C)/2];if(Y>=R){return{axis:"horizontal",a:[E,i[1]],b:[w,i[1]],mid:i,projectedLength:Y,tangentInterval:[Math.min(E,w),Math.max(E,w)],normalCoordinate:i[1]}}return{axis:"vertical",a:[i[0],s],b:[i[0],C],mid:i,projectedLength:R,tangentInterval:[Math.min(s,C),Math.max(s,C)],normalCoordinate:i[0]}}function Z(A,B){const E=B.map(A=>[Number(A[0]),Number(A[1])]);if(!E.every(A=>A.every(Number.isFinite)))return!1;if(E.length<3||((A,B)=>{const E=1e-12*Math.max(1,Math.abs(A[0]),Math.abs(A[1]),...B.flatMap(A=>[Math.abs(A[0]),Math.abs(A[1])]));for(let s=0;s0))continue;const Y=(A[0]-w[0])*g-(A[1]-w[1])*C;if(Math.abs(Y)>E*I)continue;const R=(A[0]-w[0])*C+(A[1]-w[1])*g;if(R>=-E&&R<=I*I+E)return!0}return!1})(A,E))return!1;let s=!1;for(let B=0,w=E.length-1;BA[1]==C[1]>A[1])continue;const g=(C[0]-Q[0])*(A[1]-Q[1])/(C[1]-Q[1])+Q[0];A[0]Object.is(A,-0)?0:A,I=[g(-Q/C),g(w/C)],Y=[g(-I[0]),g(-I[1])],R=[(B[0]+E[0])/2,(B[1]+E[1])/2],M=Math.max(1,C,Math.abs(R[0]),Math.abs(R[1])),F=Math.max(1e-9*M,.01*U(s));for(const B of[F,4*F,16*F]){const E=Z([R[0]+I[0]*B,R[1]+I[1]*B],A);if(E!==Z([R[0]+Y[0]*B,R[1]+Y[1]*B],A))return E?I:Y}return sA(A)>=0?I:Y}function f(A,B){let E=180*Math.atan2(B[1]-A[1],B[0]-A[0])/Math.PI;return E>90&&(E-=180),E<=-90&&(E+=180),E}function k(A,B,E,s={}){const w=Number(B);if(!(w>0&&Number.isFinite(w)))return[];const Q=void 0===s.epsilon?l(w):U(s.epsilon);return z(d(A,Q),w,E,{...s,epsilon:Q})}const z=(A,B,E,s)=>{if(A.points.length<3)return[];const Q=U(s.epsilon??l(B)),C=Number.isFinite(Number(s.ringIndex))?Number(s.ringIndex):0,g=[];for(let s=0;sQ))continue;const M=[...A.edgeSources[s]||[s]].sort((A,B)=>A-B),F=M[0]??s,i=T(A.points,R.a,R.b,Q),x=("horizontal"===R.axis?i[1]:i[0])<0?-1:1,b=[R.axis,O(R.tangentInterval[0]),String(x),O(C),O(F)].join("|"),L=R.projectedLength*B;g.push({sourceA:[...I],sourceB:[...Y],a:R.a,b:R.b,text:w(L,E),short:L<30,angle:f(R.a,R.b),mid:R.mid,axis:R.axis,projectedLength:R.projectedLength,tangentInterval:R.tangentInterval,normalCoordinate:R.normalCoordinate,inwardNormal:i,normalSign:x,source:{ringIndex:C,edgeIndex:F},sourceEdgeIndices:M,stableKey:b})}return g};function p(A,B,E,s={}){const w=Number(B);if(!(w>0&&Number.isFinite(w)))return[];const Q=void 0===s.epsilon?l(w):U(s.epsilon);let C=d(A,Q);if(sA(C.points)<0&&(C=(A=>{const B=A.points.length;return{points:[...A.points].reverse().map(A=>[...A]),edgeSources:A.points.map((E,s)=>[...A.edgeSources[(B-2-s+B)%B]])}})(C)),C.points.length){let A=0;for(let B=1;B({points:[...A.points.slice(B),...A.points.slice(0,B)],edgeSources:[...A.edgeSources.slice(B),...A.edgeSources.slice(0,B)]}))(C,A)}return z(C,w,E,{...s,epsilon:Q})}function X(A,B){const E=U(B),s=[];for(const B of A){const A=s.find(A=>A.axis===B.axis&&A.normalSign===B.normalSign&&Math.abs(A.normalCoordinate-B.normalCoordinate)<=E);A?A.edges.push(B):s.push({axis:B.axis,normalSign:B.normalSign,normalCoordinate:B.normalCoordinate,edges:[B]})}return s.map(A=>A.edges)}const O=A=>Object.is(A,-0)?"0":String(A),q=A=>"horizontal"===A?0:1;function $(A,B){return q(A.axis)-q(B.axis)||A.tangentInterval[0]-B.tangentInterval[0]||A.normalSign-B.normalSign||A.source.ringIndex-B.source.ringIndex||A.source.edgeIndex-B.source.edgeIndex}function _(A,B,E,s){const w=U(s);if(A.axis!==B.axis)return!1;if(A.source.ringIndex!==B.source.ringIndex)return!1;if(A.inwardNormal[0]*B.inwardNormal[0]+A.inwardNormal[1]*B.inwardNormal[1]>=-.5)return!1;if(!((A,B,E)=>Math.abs(A[0]-B[0])<=E&&Math.abs(A[1]-B[1])<=E)(A.tangentInterval,B.tangentInterval,w))return!1;if(Math.abs(A.projectedLength-B.projectedLength)>w)return!1;return Z([(A.mid[0]+B.mid[0])/2,(A.mid[1]+B.mid[1])/2],E)}const AA=(A,B)=>{const E=B?.(A);return{hardCollisions:Number.isFinite(Number(E?.hardCollisions))?Number(E?.hardCollisions):0,normalClearance:Number.isFinite(Number(E?.normalClearance))?Number(E?.normalClearance):0}},BA=(A,B,E)=>{const s=AA(A,E),w=AA(B,E);return s.hardCollisions-w.hardCollisions||w.normalClearance-s.normalClearance||$(A,B)};function EA(A,B){if(A.length<2)return[...A];const E=U(B.epsilon),s=function(A,B=1e-7){return d(A,B).points.map(A=>[...A])}(B.ring,E),w=[];for(let B=0;B{const E=A.separation-B.separation;if(E)return E;const s=$(A.left,A.right)<=0?A.left:A.right,w=s===A.left?A.right:A.left,Q=$(B.left,B.right)<=0?B.left:B.right,C=Q===B.left?B.right:B.left;return $(s,Q)||$(w,C)});const Q=new Set,C=new Set;for(const A of w){if(Q.has(A.left)||Q.has(A.right))continue;Q.add(A.left),Q.add(A.right);const E=BA(A.left,A.right,B.score)<=0?A.left:A.right;C.add(E===A.left?A.right:A.left)}return A.filter(A=>!C.has(A))}function sA(A){let B=0;for(let E=0;E1){const A=Math.sqrt(G);Y*=A,R*=A}const o=Math.max(0,Y*Y*R*R-Y*Y*D*D-R*R*L*L),t=Y*Y*D*D+R*R*L*L||1,c=(Q===C?-1:1)*Math.sqrt(o/t),W=c*Y*D/R,m=c*-R*L/Y,n=F*W-i*m+(A+g)/2,e=i*W+F*m+(B+I)/2;let h=gA(1,0,(L-W)/Y,(D-m)/R),S=gA((L-W)/Y,(D-m)/R,(-L-W)/Y,(-D-m)/R);!C&&S>0&&(S-=2*Math.PI),C&&S<0&&(S+=2*Math.PI);const j=Math.max(1,Math.ceil(Math.abs(S)/(Math.PI/2))),r=S/j,H=A=>[n+F*Y*Math.cos(A)-i*R*Math.sin(A),e+i*Y*Math.cos(A)+F*R*Math.sin(A)],v=A=>[-F*Y*Math.sin(A)-i*R*Math.cos(A),-i*Y*Math.sin(A)+F*R*Math.cos(A)],V=[];for(let A=0;A[B.a*A+B.c*E+B.e,B.b*A+B.d*E+B.f];return function(A){const B=A.match(/[AaCcHhLlMmQqSsTtVvZz]|[-+]?(?:\d*\.\d+|\d+\.?)(?:e[-+]?\d+)?/gi)||[],E=[];let s=0,w="",Q=0,C=0,g=0,I=0,Y=null,R=null;const M=()=>Number(B[s++]);for(;sB.length||QA.test(B[s]))throw new Error(`Invalid SVG path command ${w}`);const x=Array.from({length:i},M),b=A=>A+(F?Q:0),L=A=>A+(F?C:0);if("M"===A||"L"===A)Q=b(x[0]),C=L(x[1]),E.push({op:"M"===A?"M":"L",x:Q,y:C}),"M"===A&&(g=Q,I=C,w=F?"l":"L"),Y=R=null;else if("H"===A)Q=b(x[0]),E.push({op:"L",x:Q,y:C}),Y=R=null;else if("V"===A)C=L(x[0]),E.push({op:"L",x:Q,y:C}),Y=R=null;else if("C"===A){const A=b(x[0]),B=L(x[1]),s=b(x[2]),w=L(x[3]);Q=b(x[4]),C=L(x[5]),Y=[s,w],R=null,E.push({op:"C",x1:A,y1:B,x2:s,y2:w,x:Q,y:C})}else if("S"===A){const A=Y?2*Q-Y[0]:Q,B=Y?2*C-Y[1]:C,s=b(x[0]),w=L(x[1]);Q=b(x[2]),C=L(x[3]),Y=[s,w],R=null,E.push({op:"C",x1:A,y1:B,x2:s,y2:w,x:Q,y:C})}else if("Q"===A||"T"===A){const B="Q"===A?b(x[0]):R?2*Q-R[0]:Q,s="Q"===A?L(x[1]):R?2*C-R[1]:C,w=b("Q"===A?x[2]:x[0]),g=L("Q"===A?x[3]:x[1]);E.push({op:"C",x1:Q+2/3*(B-Q),y1:C+2/3*(s-C),x2:w+2/3*(B-w),y2:g+2/3*(s-g),x:w,y:g}),Q=w,C=g,R=[B,s],Y=null}else if("A"===A){const A=b(x[5]),B=L(x[6]),s=IA(Q,C,x[0],x[1],x[2],x[3],x[4],A,B);s.length?E.push(...s):E.push({op:"L",x:A,y:B}),Q=A,C=B,Y=R=null}}return E}(A).map(A=>{if("Z"===A.op)return A;if("M"===A.op||"L"===A.op){const[B,s]=E(A.x,A.y);return{op:A.op,x:B,y:s}}if("C"!==A.op)throw new Error("Unsupported PDF vector operation");const[B,s]=E(A.x1,A.y1),[w,Q]=E(A.x2,A.y2),[C,g]=E(A.x,A.y);return{op:"C",x1:B,y1:s,x2:w,y2:Q,x:C,y:g}})}const RA=["M20.82,15.31h0L10.46,9c-.46-.26-1.11.37-.86.84l6.15,10.56,10.56,6.15a.66.66,0,0,0,.84-.86Zm-4,4,3-3,4.55,7.44Z","M18,2A16,16,0,1,0,34,18,16,16,0,0,0,18,2Zm1,29.95V29.53H17v2.42A14,14,0,0,1,4.05,19H6.47V17H4.05A14,14,0,0,1,17,4.05V6.47h2V4.05A14,14,0,0,1,31.95,17H29.53v2h2.42A14,14,0,0,1,19,31.95Z"],MA=A=>Math.abs(A)<1e-12?0:Math.abs(A-1)<1e-12?1:Math.abs(A+1)<1e-12?-1:A;function FA(A){const B=function(A){const{centerX:B,centerY:E,size:s,northDeg:w}=A;if(![B,E,s,w].every(Number.isFinite)||s<=0)throw new RangeError("PDF compass placement must contain finite coordinates and a positive size");const Q=((w%360+360)%360+45)*Math.PI/180,C=s/36,g=MA(Math.cos(Q)),I=MA(Math.sin(Q)),Y=C*g,R=C*I,M=-C*I,F=C*g;return{a:Y,b:R,c:M,d:F,e:B-18*Y-18*M,f:E-18*R-18*F}}(A);return RA.flatMap(A=>YA(A,B))}const iA=1e-8,xA=A=>A.length>=2&&Number.isFinite(A[0])&&Number.isFinite(A[1]),bA=(A,B)=>A[0]>=B.minX-iA&&A[0]<=B.maxX+iA&&A[1]>=B.minY-iA&&A[1]<=B.maxY+iA,LA=A=>[A.minX,A.minY,A.maxX,A.maxY].every(Number.isFinite)&&A.maxX>=A.minX&&A.maxY>=A.minY,DA=A=>[[A.minX,A.minY],[A.maxX,A.minY],[A.maxX,A.maxY],[A.minX,A.maxY]];const GA=(A,B,E)=>(B[0]-A[0])*(E[1]-A[1])-(B[1]-A[1])*(E[0]-A[0]),oA=(A,B,E)=>{const s=E[0]-B[0],w=E[1]-B[1],Q=Math.abs(s)>=Math.abs(w)?s:w;return Math.abs(Q)<=iA?0:(Math.abs(s)>=Math.abs(w)?A[0]-B[0]:A[1]-B[1])/Q},tA=(A,B)=>Math.hypot(B[0]-A[0],B[1]-A[1]);function cA(A,B,E){const s=tA(B,E);if(s<=iA)return tA(A,B)<=iA;if(Math.abs(GA(B,E,A))/s>iA)return!1;const w=oA(A,B,E),Q=iA/s;return w>=-Q&&w<=1+Q}function WA(A,B,E,s){const w=B[0]-A[0],Q=B[1]-A[1],C=s[0]-E[0],g=s[1]-E[1],I=Math.hypot(w,Q),Y=Math.hypot(C,g);if(I<=iA)return cA(A,E,s)?{t:0,endT:0,overlap:!1}:null;if(Y<=iA){if(!cA(E,A,B))return null;const s=Math.max(0,Math.min(1,oA(E,A,B)));return{t:s,endT:s,overlap:!1}}const R=w*g-Q*C,M=E[0]-A[0],F=E[1]-A[1],i=iA*I*Y;if(Math.abs(R)<=i){if(Math.abs(GA(A,B,E))/I>iA||Math.abs(GA(A,B,s))/I>iA)return null;const w=oA(E,A,B),Q=oA(s,A,B),C=Math.max(0,Math.min(w,Q)),g=Math.min(1,Math.max(w,Q));return giA}}const x=(M*g-F*C)/R,b=(M*Q-F*w)/R,L=iA/I,D=iA/Y;if(x<-L||x>1+L||b<-D||b>1+D)return null;const G=Math.max(0,Math.min(1,x));return{t:G,endT:G,overlap:!1}}const mA=A=>A.every(A=>A.length>=2&&A.every(xA));function nA(A,B){for(const E of A){const A=E;for(let E=0;Enull!==WA(A,B,E,s[(w+1)%s.length]))}const hA=2048,SA=2146,jA=[-1825,-555,4188,2163],rA={32:1,33:2,34:3,35:4,36:5,37:6,38:7,39:8,40:9,41:10,42:11,43:12,44:13,45:14,46:15,47:16,48:17,49:18,50:19,51:20,52:21,53:22,54:23,55:24,56:25,57:26,58:27,59:28,60:29,61:30,62:31,63:32,64:33,65:34,66:35,67:36,68:37,69:38,70:39,71:40,72:41,73:42,74:43,75:44,76:45,77:46,78:47,79:48,80:49,81:50,82:51,83:52,84:53,85:54,86:55,87:56,88:57,89:58,90:59,91:60,92:61,93:62,94:63,95:64,96:65,97:66,98:67,99:68,100:69,101:70,102:71,103:72,104:73,105:74,106:75,107:76,108:77,109:78,110:79,111:80,112:81,113:82,114:83,115:84,116:85,117:86,118:87,119:88,120:89,121:90,122:91,123:92,124:93,125:94,126:95,160:596,161:96,162:97,163:98,164:99,165:100,166:101,167:102,168:103,169:104,170:105,171:106,172:107,173:597,174:108,175:109,176:110,177:111,178:112,179:113,180:114,181:115,182:116,183:117,184:118,185:119,186:120,187:121,188:122,189:123,190:124,191:125,192:603,193:604,194:605,195:606,196:607,197:608,198:126,199:609,200:610,201:611,202:612,203:613,204:614,205:615,206:616,207:617,208:599,209:618,210:619,211:620,212:621,213:622,214:623,215:127,216:128,217:624,218:625,219:626,220:627,221:628,222:129,223:130,224:629,225:630,226:631,227:632,228:633,229:634,230:131,231:635,232:636,233:637,234:638,235:639,236:640,237:641,238:642,239:643,240:132,241:644,242:645,243:646,244:647,245:648,246:649,247:133,248:134,249:650,250:651,251:652,252:653,253:654,254:135,255:655,256:656,257:657,258:658,259:659,260:660,261:661,262:662,263:663,264:664,265:665,266:666,267:667,268:668,269:669,270:670,271:671,272:598,273:136,274:672,275:673,276:674,277:675,278:676,279:677,280:678,281:679,282:680,283:681,284:682,285:683,286:684,287:685,288:686,289:687,290:688,291:689,292:690,293:691,294:137,295:600,296:692,297:693,298:694,299:695,300:696,301:697,302:698,303:699,304:700,305:138,306:701,307:702,308:703,309:704,310:705,311:706,312:139,313:707,314:708,315:709,316:710,317:711,318:712,319:713,320:714,321:140,322:141,323:715,324:716,325:717,326:718,327:719,328:720,329:721,330:142,331:143,332:722,333:723,334:724,335:725,336:726,337:727,338:144,339:145,340:728,341:729,342:730,343:731,344:732,345:733,346:734,347:735,348:736,349:737,350:738,351:739,352:742,353:743,354:744,355:745,356:746,357:747,358:601,359:602,360:748,361:749,362:750,363:751,364:752,365:753,366:754,367:755,368:756,369:757,370:758,371:759,372:760,373:761,374:762,375:763,376:764,377:765,378:766,379:767,380:768,381:769,382:770,383:146,1024:897,1025:856,1026:165,1027:857,1028:166,1029:858,1030:859,1031:860,1032:861,1033:167,1034:168,1035:169,1036:863,1037:898,1038:864,1039:170,1040:865,1041:171,1042:866,1043:867,1044:172,1045:868,1046:173,1047:174,1048:175,1049:869,1050:862,1051:176,1052:870,1053:871,1054:872,1055:873,1056:874,1057:875,1058:876,1059:177,1060:178,1061:877,1062:179,1063:180,1064:181,1065:182,1066:183,1067:184,1068:185,1069:186,1070:187,1071:188,1072:878,1073:189,1074:190,1075:191,1076:192,1077:879,1078:193,1079:194,1080:195,1081:880,1082:196,1083:197,1084:198,1085:199,1086:881,1087:200,1088:882,1089:883,1090:201,1091:884,1092:202,1093:885,1094:203,1095:204,1096:205,1097:206,1098:207,1099:208,1100:209,1101:210,1102:211,1103:212,1104:899,1105:886,1106:213,1107:887,1108:214,1109:888,1110:889,1111:890,1112:891,1113:215,1114:216,1115:217,1116:892,1117:900,1118:893,1119:218,1120:219,1121:220,1122:965,1123:221,1124:222,1125:223,1126:224,1127:225,1128:226,1129:227,1130:228,1131:229,1132:230,1133:231,1134:232,1135:233,1136:901,1137:902,1138:234,1139:235,1140:236,1141:237,1142:903,1143:904,1144:906,1145:905,1146:238,1147:239,1148:240,1149:241,1150:242,1151:243,1152:244,1153:245,1154:246,1155:247,1156:248,1157:249,1158:250,1159:251,1160:252,1161:253,1162:254,1163:255,1164:964,1165:256,1166:257,1167:258,1168:259,1169:260,1170:966,1171:967,1172:261,1173:262,1174:263,1175:264,1176:907,1177:908,1178:265,1179:266,1180:267,1181:268,1182:968,1183:969,1184:269,1185:270,1186:271,1187:272,1188:273,1189:274,1190:275,1191:276,1192:277,1193:278,1194:909,1195:910,1196:955,1197:956,1198:911,1199:912,1200:970,1201:971,1202:279,1203:280,1204:281,1205:282,1206:283,1207:284,1208:285,1209:286,1210:287,1211:963,1212:288,1213:289,1214:961,1215:962,1216:913,1217:914,1218:915,1219:290,1220:291,1221:292,1222:293,1223:294,1224:295,1225:296,1226:297,1227:957,1228:958,1229:298,1230:299,1231:916,1232:917,1233:918,1234:919,1235:920,1236:921,1237:922,1238:923,1239:924,1240:300,1241:926,1242:925,1243:927,1244:928,1245:929,1246:930,1247:931,1248:301,1249:302,1250:932,1251:933,1252:934,1253:935,1254:936,1255:937,1256:938,1257:939,1258:940,1259:941,1260:942,1261:943,1262:944,1263:945,1264:946,1265:947,1266:948,1267:949,1268:950,1269:951,1270:959,1271:960,1272:952,1273:953,1274:303,1275:304,1276:305,1277:306,1278:972,1279:973,1280:307,1281:954,1282:308,1283:309,1284:310,1285:311,1286:312,1287:313,1288:314,1289:315,1290:316,1291:317,1292:318,1293:319,1294:320,1295:321,1296:322,1297:974,1298:323,1299:324,1300:325,1301:326,1302:327,1303:328,1304:329,1305:330,1306:982,1307:983,1308:984,1309:985,1310:331,1311:332,1312:333,1313:334,1314:335,1315:336,1316:337,1317:338,1318:339,1319:340,1320:341,1321:342,1322:343,1323:344,1324:345,1325:346,1326:347,1327:348,8192:349,8193:350,8194:351,8195:352,8196:353,8197:354,8198:355,8199:356,8200:357,8201:358,8202:360,8203:361,8204:362,8205:363,8206:364,8207:365,8208:366,8209:367,8210:368,8211:369,8212:370,8213:975,8214:371,8215:372,8216:373,8217:374,8218:375,8219:376,8220:377,8221:378,8222:379,8223:380,8224:381,8225:382,8226:383,8227:384,8228:385,8229:386,8230:387,8231:388,8239:986,8240:389,8241:390,8242:894,8243:895,8244:391,8245:392,8246:393,8247:394,8248:395,8249:396,8250:397,8251:398,8252:896,8253:399,8254:400,8255:401,8256:402,8257:403,8258:404,8259:405,8260:406,8261:407,8262:408,8263:987,8264:988,8265:989,8266:409,8267:410,8268:411,8269:412,8270:413,8271:414,8272:415,8273:416,8274:417,8275:418,8276:419,8277:420,8278:421,8279:422,8280:423,8281:424,8282:425,8283:426,8284:427,8285:428,8286:429,8287:990,8364:430,8381:431,8776:433},HA={1:507,2:527,3:655,4:1261,5:1150,6:1500,7:1273,8:357,9:700,10:712,11:882,12:1161,13:402,14:565,15:539,16:844,17:1150,18:1150,19:1150,20:1150,21:1150,22:1150,23:1150,24:1150,25:1150,26:1150,27:496,28:433,29:1041,30:1124,31:1070,32:967,33:1839,34:1336,35:1275,36:1333,37:1343,38:1164,39:1132,40:1395,41:1460,42:557,43:1130,44:1284,45:1102,46:1788,47:1460,48:1408,49:1292,50:1408,51:1261,52:1215,53:1222,54:1328,55:1303,56:1817,57:1284,58:1230,59:1226,60:543,61:840,62:543,63:856,64:924,65:633,66:1114,67:1149,68:1072,69:1155,70:1085,71:711,72:1149,73:1128,74:497,75:489,76:1038,77:497,78:1795,79:1130,80:1168,81:1149,82:1164,83:693,84:1056,85:669,86:1129,87:992,88:1539,89:1015,90:969,91:1015,92:693,93:499,94:693,95:1393,96:499,97:1120,98:1190,99:1460,100:1075,101:491,102:1256,103:856,104:1609,105:915,106:961,107:1134,108:1610,109:938,110:765,111:1094,112:751,113:751,114:642,115:1160,116:1001,117:534,118:507,119:751,120:931,121:960,122:1500,123:1589,124:1593,125:969,126:1914,127:1092,128:1408,129:1210,130:1218,131:1729,132:1200,133:1169,134:1160,135:1180,136:1223,137:1434,138:506,139:1139,140:1103,141:553,142:1419,143:1160,144:1953,145:1860,146:508,165:1535,166:1380,167:2193,168:2212,169:1666,170:1460,171:1291,172:1540,173:1859,174:1215,175:1460,176:1449,177:1287,178:1580,179:1497,180:1402,181:1927,182:1984,183:1554,184:1771,185:1285,186:1380,187:1831,188:1304,189:1132,190:1170,191:859,192:1236,193:1568,194:1040,195:1182,196:1106,197:1184,198:1519,199:1181,200:1182,201:984,202:1485,203:1213,204:1113,205:1656,206:1694,207:1271,208:1590,209:1112,210:1101,211:1671,212:1124,213:1128,214:1101,215:1737,216:1764,217:1161,218:1182,219:1800,220:1579,221:1110,222:1835,223:1528,224:1234,225:1094,226:1803,227:1547,228:1745,229:1505,230:2308,231:2001,232:1059,233:987,234:1393,235:1163,236:1290,237:1027,238:1393,239:1160,240:1793,241:1572,242:1800,243:1579,244:1330,245:1095,246:1277,247:1024,248:1024,249:1024,250:1024,251:1024,252:1024,253:1024,254:1545,255:1261,256:1110,257:1307,258:1161,259:1123,260:912,261:1243,262:1029,263:1954,264:1633,265:1434,266:1208,267:1289,268:1150,269:1676,270:1411,271:1535,272:1241,273:1999,274:1460,275:2097,276:1780,277:1518,278:1235,279:1304,280:1066,281:1836,282:1372,283:1468,284:1174,285:1391,286:1130,287:1391,288:1583,289:1213,290:1289,291:1114,292:1534,293:1263,294:1458,295:1160,296:1554,297:1260,298:1871,299:1598,300:1415,301:1192,302:1192,303:1207,304:939,305:1326,306:1088,307:1270,308:1684,309:1764,310:1622,311:1323,312:1097,313:1031,314:1985,315:1653,316:2043,317:1697,318:1270,319:1053,320:1453,321:1312,322:1380,323:1538,324:1266,325:1920,326:1549,327:1857,328:1547,329:1926,330:1774,331:1316,332:1106,333:2274,334:1832,335:2300,336:1829,337:1526,338:1242,339:1468,340:1208,341:1539,342:1273,343:2710,344:2238,345:1568,346:1240,347:1515,348:1243,349:1044,350:2089,351:1044,352:2089,353:697,354:522,355:348,356:1151,357:560,358:418,360:209,361:1024,362:1024,363:1024,364:1024,365:1024,366:564,367:564,368:1171,369:1344,370:1599,371:778,372:933,373:409,374:409,375:407,376:409,377:724,378:731,379:705,380:764,381:1129,382:1167,383:690,384:1100,385:511,386:964,387:1370,388:382,389:1962,390:2360,391:1045,392:463,393:757,394:1045,395:803,396:614,397:614,398:1241,399:919,400:952,401:1540,402:1540,403:874,404:1370,405:870,406:931,407:640,408:641,409:907,410:1001,411:1237,412:1237,413:985,414:511,415:1541,416:985,417:931,418:1366,419:1540,420:1172,421:932,422:1333,423:1215,424:1125,425:379,426:1071,427:1162,428:379,429:379,430:1150,431:1359,433:1154,596:507,597:565,598:1373,599:1373,600:1158,601:1222,602:669,603:1336,604:1336,605:1336,606:1336,607:1336,608:1336,609:1333,610:1164,611:1164,612:1164,613:1164,614:557,615:557,616:557,617:557,618:1460,619:1408,620:1408,621:1408,622:1408,623:1408,624:1328,625:1328,626:1328,627:1328,628:1230,629:1114,630:1114,631:1114,632:1114,633:1114,634:1114,635:1072,636:1085,637:1085,638:1085,639:1085,640:506,641:506,642:506,643:506,644:1130,645:1168,646:1168,647:1168,648:1168,649:1168,650:1129,651:1129,652:1129,653:1129,654:969,655:969,656:1336,657:1114,658:1336,659:1114,660:1336,661:1114,662:1333,663:1072,664:1333,665:1072,666:1333,667:1072,668:1333,669:1072,670:1343,671:1305,672:1164,673:1085,674:1164,675:1085,676:1164,677:1085,678:1164,679:1085,680:1164,681:1085,682:1395,683:1149,684:1395,685:1149,686:1395,687:1149,688:1395,689:1149,690:1460,691:1128,692:557,693:506,694:557,695:506,696:557,697:506,698:557,699:497,700:557,701:1687,702:986,703:1130,704:515,705:1284,706:1038,707:1102,708:497,709:1102,710:497,711:1102,712:647,713:1102,714:717,715:1460,716:1130,717:1460,718:1130,719:1460,720:1130,721:1130,722:1408,723:1168,724:1408,725:1168,726:1408,727:1168,728:1261,729:693,730:1261,731:693,732:1261,733:693,734:1215,735:1056,736:1215,737:1056,738:1215,739:1056,742:1215,743:1056,744:1222,745:669,746:1222,747:709,748:1328,749:1129,750:1328,751:1129,752:1328,753:1129,754:1328,755:1129,756:1328,757:1129,758:1328,759:1129,760:1817,761:1539,762:1230,763:969,764:1230,765:1226,766:1015,767:1226,768:1015,769:1226,770:1015,856:1164,857:1139,858:1215,859:557,860:557,861:1130,862:1316,863:1284,864:1287,865:1336,866:1275,867:1139,868:1164,869:1460,870:1788,871:1460,872:1408,873:1461,874:1292,875:1333,876:1222,877:1284,878:1114,879:1085,880:1182,881:1168,882:1149,883:1072,884:969,885:1015,886:1085,887:859,888:1056,889:497,890:506,891:489,892:1106,893:969,894:357,895:655,896:1054,897:1164,898:1460,899:1085,900:1182,901:1417,902:1434,903:1290,904:1027,905:2137,906:2377,907:1215,908:1040,909:1333,910:1072,911:1230,912:1026,913:557,914:1859,915:1568,916:557,917:1336,918:1114,919:1336,920:1114,921:1914,922:1729,923:1164,924:1085,925:1415,926:1079,927:1079,928:1859,929:1568,930:1215,931:1040,932:1460,933:1182,934:1460,935:1182,936:1408,937:1168,938:1393,939:1163,940:1393,941:1163,942:1380,943:1101,944:1287,945:969,946:1287,947:969,948:1287,949:969,950:1402,951:1113,952:1771,953:1590,954:1155,955:1222,956:984,957:1402,958:1113,959:1139,960:859,961:1583,962:1213,963:1128,964:1285,965:1285,966:1139,967:859,968:1336,969:1063,970:1230,971:1026,972:1284,973:1015,974:1104,975:1599,982:1408,983:1164,984:1817,985:1539,986:507,987:1934,988:1494,989:1494,990:507},vA=new TextEncoder,VA=A=>{const B=Math.round(100*A)/100;return Number.isInteger(B)?String(B):B.toFixed(2).replace(/0+$/,"")},UA=A=>{const B=Math.round(1e6*A)/1e6;return Number.isInteger(B)?String(B):B.toFixed(6).replace(/0+$/,"")},lA=A=>A.map(UA).join(" ");function aA(A){let B="",E=0;const s=new Map;for(const w of A){const A=w.codePointAt(0)||0,Q=rA[A]||rA[63];B+=Q.toString(16).padStart(4,"0"),E+=HA[Q]||1024,s.has(Q)||s.set(Q,A||63)}return{hex:B,width:E,unicode:s}}function PA(A,B){return aA(A).width*B/hA}function yA(A,B=PA(A.text,A.size)){const E=A.align||"left",s="center"===E?B/2:"right"===E?B:0,w=(A.angle||0)*Math.PI/180,Q=Math.cos(w),C=Math.sin(w);return{width:B,baselineX:A.x-Q*s,baselineY:A.y+C*s,cos:Q,sin:C}}function uA(A){const B=yA(A),E=-555*A.size/hA,s=SA*A.size/hA,w=[0,B.width].flatMap(A=>[E,s].map(E=>({x:B.baselineX+B.cos*A-B.sin*E,y:B.baselineY-B.sin*A-B.cos*E})));return{minX:Math.min(...w.map(A=>A.x)),minY:Math.min(...w.map(A=>A.y)),maxX:Math.max(...w.map(A=>A.x)),maxY:Math.max(...w.map(A=>A.y))}}function NA(A){const B=A.reduce((A,B)=>A+B.length,0),E=new Uint8Array(B);let s=0;for(const B of A)E.set(B,s),s+=B.length;return E}const KA=A=>vA.encode(A),dA=(A,B)=>NA([KA(`<< ${A} /Length ${B.length} >>\nstream\n`),B,KA("\nendstream")]);function JA(A){const B=function(A){const B=atob(A),E=new Uint8Array(B.length);for(let A=0;A"image"===A.kind&&null!=A.opacity&&A.opacity<1?[Math.max(0,Math.min(1,A.opacity))]:[]))].sort((A,B)=>A-B),s=new Map(E.map((A,B)=>[A,`GS${B+1}`])),w=function(A,B){const E=[],s=new Map,w=B=>A.height-B,Q=(A,...B)=>`${B.map(VA).join(" ")} ${A}`,C=A=>{for(const B of A)if(B.length){E.push(Q("m",B[0][0],w(B[0][1])));for(let A=1;A{let B=!1;for(const s of A)if(!(s.length<2)){B=!0,E.push(Q("m",s[0][0],w(s[0][1])));for(let A=1;A Tj`,"ET")}else{const A=(I.angle||0)*Math.PI/180,s=Math.cos(A),C=Math.sin(A),g=I.x+I.width/2,Y=w(I.y+I.height/2);E.push("q");const R=null==I.opacity?1:Math.max(0,Math.min(1,I.opacity)),M=B.get(R);M&&E.push(`/${M} gs`),E.push(Q("cm",s*I.width,C*I.width,C*I.height,-s*I.height,g-s*I.width/2-C*I.height/2,Y-C*I.width/2+s*I.height/2),`/Im${I.imageId} Do`,"Q")}return{stream:E.join("\n"),unicode:s}}(A,s),Q=Math.max(0,...Object.keys(HA).map(Number)),C=Array.from({length:Q+1},(A,B)=>Math.round(1e3*(HA[B]||1024)/hA)),g=[],I=A=>(g.push("string"==typeof A?KA(A):A),g.length),Y=I(""),R=I(""),M=I(""),F=I(dA(`/Length1 ${B.length}`,B)),i=I(`<< /Type /FontDescriptor /FontName /Roboto /Flags 32 /FontBBox [${jA.join(" ")}] /ItalicAngle 0 /Ascent 2146 /Descent -555 /CapHeight 2146 /StemV 80 /FontFile2 ${F} 0 R >>`),x=I(`<< /Type /Font /Subtype /CIDFontType2 /BaseFont /Roboto /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor ${i} 0 R /W [0 [${C.join(" ")}]] /CIDToGIDMap /Identity >>`),b=KA(function(A){const B=[...A].sort((A,B)=>A[0]-B[0]),E=B.map(([A,B])=>`<${A.toString(16).padStart(4,"0")}> <${B<=65535?B.toString(16).padStart(4,"0"):(()=>{const A=B-65536;return(55296+(A>>10)).toString(16).padStart(4,"0")+(56320+(1023&A)).toString(16).padStart(4,"0")})()}>`);return`/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def\n/CMapName /HousePlanUnicode def\n/CMapType 2 def\n1 begincodespacerange\n<0000> \nendcodespacerange\n${B.length} beginbfchar\n${E.join("\n")}\nendbfchar\nendcmap\nCMapName currentdict /CMap defineresource pop\nend\nend`}(w.unicode)),L=I(dA("",b)),D=I(`<< /Type /Font /Subtype /Type0 /BaseFont /Roboto /Encoding /Identity-H /DescendantFonts [${x} 0 R] /ToUnicode ${L} 0 R >>`),G=I(dA("",KA(w.stream))),o=[];for(const B of A.images||[]){const A=I(dA(`/Type /XObject /Subtype /Image /Width ${B.width} /Height ${B.height} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode`,B.bytes));o.push(`/Im${B.id} ${A} 0 R`)}const t=A.now.toISOString().replace(/[-:T]/g,"").slice(0,14),c=I(`<< /CreationDate (D:${t}Z) /ModDate (D:${t}Z) >>`),W=`<< /Font << /F1 ${D} 0 R >>`+(o.length?` /XObject << ${o.join(" ")} >>`:"")+(E.length?` /ExtGState << ${E.map(A=>`/${s.get(A)} << /ca ${VA(A)} /CA ${VA(A)} >>`).join(" ")} >>`:"")+" >>";g[Y-1]=KA(`<< /Type /Catalog /Pages ${R} 0 R >>`),g[R-1]=KA(`<< /Type /Pages /Kids [${M} 0 R] /Count 1 >>`),g[M-1]=KA(`<< /Type /Page /Parent ${R} 0 R /MediaBox [0 0 ${VA(A.width)} ${VA(A.height)}] /Resources ${W} /Contents ${G} 0 R >>`);const m=KA("%PDF-1.4\n%âãÏÓ\n"),n=[m],e=[0];let h=m.length;g.forEach((A,B)=>{const E=KA(`${B+1} 0 obj\n`),s=KA("\nendobj\n");e.push(h),n.push(E,A,s),h+=E.length+A.length+s.length});const S=h,j=["xref",`0 ${g.length+1}`,"0000000000 65535 f "];for(let A=1;A<=g.length;A++)j.push(`${String(e[A]).padStart(10,"0")} 00000 n `);return j.push(`trailer\n<< /Size ${g.length+1} /Root ${Y} 0 R /Info ${c} 0 R >>`,`startxref\n${S}\n%%EOF\n`),n.push(KA(j.join("\n"))),NA(n)}const ZA=A=>[A.minX,A.minY,A.maxX,A.maxY].every(Number.isFinite)&&A.maxX>=A.minX&&A.maxY>=A.minY,TA=A=>A.maxX-A.minX,fA=A=>A.maxY-A.minY;function kA(A,B,E,s=0){Number.isFinite(B)&&Number.isFinite(E)&&(A.minX=Math.min(A.minX,B-s),A.minY=Math.min(A.minY,E-s),A.maxX=Math.max(A.maxX,B+s),A.maxY=Math.max(A.maxY,E+s))}function zA(A,B,E,s,w,Q){const C=Q*Math.PI/180,g=Math.cos(C),I=Math.sin(C),Y=B+s/2,R=E+w/2;for(const[B,E]of[[-s/2,-w/2],[s/2,-w/2],[s/2,w/2],[-s/2,w/2]])kA(A,Y+g*B-I*E,R+I*B+g*E)}function pA(A,B,E){for(const s of B)"M"===s.op||"L"===s.op?kA(A,s.x,s.y,E):"C"===s.op&&(kA(A,s.x1,s.y1,E),kA(A,s.x2,s.y2,E),kA(A,s.x,s.y,E))}function XA(A){const B={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};for(const E of A)if("path"===E.kind){const A=E.stroke?(E.width||.5)/2:0;for(const s of E.rings)for(const[E,w]of s)kA(B,E,w,A)}else if("line"===E.kind)for(const[A,s]of E.points)kA(B,A,s,E.width/2);else if("vector"===E.kind)pA(B,E.ops,E.width/2);else if("text"===E.kind){const A=uA(E);kA(B,A.minX,A.minY),kA(B,A.maxX,A.maxY)}else zA(B,E.x,E.y,E.width,E.height,E.angle||0);return B}function OA(A,B,E){return!!ZA(A)&&(TA(A)<=TA(B)+E&&fA(A)<=fA(B)+E)}function qA(A){return`${A.getFullYear()}-${String(A.getMonth()+1).padStart(2,"0")}-${String(A.getDate()).padStart(2,"0")}`}const $A=72/25.4,_A=5.25,AB=[.08,.08,.08],BB=[127/255,127/255,127/255],EB=[.72,.72,.72],sB=(A,B)=>A.minXB.minX&&A.minYB.minY;function wB(A,B,E,s,w=0,Q="left"){return uA({x:A,y:B,text:E,size:s,angle:w,align:Q})}function QB(A,B,E,s,w){const Q=Math.min(...[[A.minX,A.minY],[A.maxX,A.minY],[A.maxX,A.maxY],[A.minX,A.maxY]].map(([A,w])=>(A-B)*s[0]+(w-E)*s[1]));return Math.max(0,w-Q)}const CB=(A,B)=>`${A.axis}:${B[0]<-.5||B[1]<-.5?-1:1}`,gB=(A,B)=>{A.minX=Math.min(A.minX,B[0]),A.minY=Math.min(A.minY,B[1]),A.maxX=Math.max(A.maxX,B[0]),A.maxY=Math.max(A.maxY,B[1])},IB=A=>{const B={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};for(const E of A)for(const A of E)gB(B,A);return B};function YB(A,B,E,s,w=0){const Q=w*Math.PI/180,C=Math.cos(Q),g=Math.sin(Q),I=A+E/2,Y=B+s/2;return Array.from({length:48},(A,B)=>{const w=B/48*Math.PI*2,Q=Math.cos(w)*E/2,R=Math.sin(w)*s/2;return[I+C*Q-g*R,Y+g*Q+C*R]})}function RB(A,B,E,s,w=0){const Q=w*Math.PI/180,C=Math.cos(Q),g=Math.sin(Q),I=A+E/2,Y=B+s/2;return[[-E/2,-s/2],[E/2,-s/2],[E/2,s/2],[-E/2,s/2]].map(([A,B])=>[I+C*A-g*B,Y+g*A+C*B])}function MB(A,B,E){if("passage"===A.type)return[];const s=A.rlen/2,w=B>0?B/E*Y/2:2,Q=[];if("window"===A.type)Q.push([[-s,-w],[s,-w]],[[-s,w],[s,w]],[[-s,-w],[-s,w]],[[s,-w],[s,w]]);else if("gate"===A.type){const B=10*(A.flip_v?-1:1)*Math.PI/180,E=[[[-s,0],[-s+Math.cos(B)*s,Math.sin(B)*s]],[[s,0],[s-Math.cos(B)*s,Math.sin(-B)*s]]];Q.push(...E);for(const A of E){const B=A[1][0]-A[0][0],E=A[1][1]-A[0][1],s=Math.hypot(B,E)||1,C=-E/s,g=B/s,I=Math.min(.08*s,Math.max(1,.7*w));for(const s of[.3,.5,.7]){const w=A[0][0]+B*s,Y=A[0][1]+E*s;Q.push([[w-C*I,Y-g*I],[w+C*I,Y+g*I]])}}}else{const B=A.flip_v?1:-1,E=A.flip_h?s:-s,w=[E,B*A.rlen];Q.push([[E,0],w]);const C=[];for(let s=0;s<=16;s++){const w=B*s/16*Math.PI/2,Q=A.flip_h?-1:1;C.push([E+Q*Math.cos(w)*A.rlen,Math.sin(w)*A.rlen])}Q.push(C)}const C=A.angle*Math.PI/180,g=Math.cos(C),I=Math.sin(C);return Q.map(B=>B.map(([B,E])=>[A.rx+B*g-E*I,A.ry+B*I+E*g]))}function FB(A,B){const E=IB([A]);return B.filter(A=>{const B=IB([A]);return B.maxX>=E.minX&&B.minX<=E.maxX&&B.maxY>=E.minY&&B.minY<=E.maxY})}function iB(A){const B=function(A){const{rawSpace:B,space:E}=A,s=Number(B.cell_cm)>0?Number(B.cell_cm):5,w=Array.isArray(B.walls)?B.walls:[],Q=c(B,E,I,.02*Y),C=W(B,E,s,Y,I),g=m(C),M=n(E,s,Y,2e-4*Y,g).all,F=e(C,E,w,Q.contour,R,s,Y,I);return{cellCm:s,walls:w,zero:Q,openings:C,extras:M,geometry:A.sharedWallGeometry||h(E.rooms,w,Q.contour,F,R,s,Y,I,M)}}(A),E=new Map;if(A.options.dimensions)for(const s of A.space.rooms){const w=C(s);if(!w)continue;const Q=s.id?A.resolveInnerContour?.(s.id):void 0;E.set(s,s.id&&(void 0===Q?g(A.space.rooms,s.id,B.walls,B.zero.contour,R,B.cellCm,Y,I,B.geometry.roomGeom,B.geometry.multiWallNodes):Q)||w)}const s=new Map;if(A.options.dimensions)for(const w of A.space.rooms){const Q=C(w);if(!Q)continue;const g=E.get(w)||Q,I=w.id?A.resolveRoomArea?.(w.id,g):void 0,Y=Number.isFinite(I)?[]:FB(g,B.extras),R=Y.length?M(g,Y):null,i=Number.isFinite(I)&&I>=0?I:R?F(R):Math.abs(g.reduce((A,B,E)=>{const s=g[(E+1)%g.length];return A+B[0]*s[1]-s[0]*B[1]},0)/2);s.set(w,i)}const w=[..."failed-core"===B.geometry.status?A.space.rooms.map(A=>C(A)||[]).filter(A=>A.length):B.geometry.components.flatMap(A=>i(A.geom)),...B.zero.lines.map(A=>[[A[0],A[1]],[A[2],A[3]]])];A.options.decor&&w.push(...function(A){const B=[];for(const E of A.decor||[])"line"===E.kind?B.push([[E.x1*I,E.y1*I],[E.x2*I,E.y2*I]]):"text"!==E.kind?B.push(L(E).map(([A,B])=>[A*I,B*I])):B.push([[E.x*I,E.y*I]]);return B}(A.rawSpace));for(const B of A.rasters||[])w.push(RB(B.x,B.y,B.drawWidth,B.drawHeight,B.angle));let Q=IB(w);var x;[(x=Q).minX,x.minY,x.maxX,x.maxY].every(Number.isFinite)&&x.maxX>x.minX&&x.maxY>x.minY||(Q={minX:0,minY:0,maxX:I,maxY:I});return{built:B,dimensionContours:E,roomAreas:s,bounds:Q,cmPerUnit:B.cellCm/Y}}function xB(A,B,E,s){const{built:w,dimensionContours:Q,roomAreas:g,bounds:M,cmPerUnit:F}=B,c=(s?297:210)*$A,W=(s?210:297)*$A,m=12*$A,n=18*$A,e=24*$A,h=F*(10*$A)/E,j=(M.maxX-M.minX)*h,H=(M.maxY-M.minY)*h,v=m+n,V=W-v-m-e,U=c-2*m,a=A=>[0+(A[0]-M.minX)*h,0+(A[1]-M.minY)*h],P=(A,B)=>[M.minX+(A-0)/h,M.minY+(B-0)/h],y=A=>{const B=P(A.minX,A.minY),E=P(A.maxX,A.maxY);return{minX:B[0],minY:B[1],maxX:E[0],maxY:E[1]}},u=w.geometry.components.flatMap(A=>i(A.geom)),N=A=>w.geometry.components.some(B=>S([...A],B.geom)),K=A=>function(A,B,E){if(!LA(A)||!mA(B))return!0;const s=DA(A);return!!s.some(E)||!!B.some(B=>B.some(B=>xA(B)&&bA(B,A)))||nA(B,(A,B)=>s.some((E,w)=>null!==WA(A,B,E,s[(w+1)%s.length])))}(y(function(A,B){const E=Number.isFinite(B)&&B>=0?B:0;return{minX:A.minX-E,minY:A.minY-E,maxX:A.maxX+E,maxY:A.maxY+E}}(A,$A-1e-6)),u,N),d=(A,B)=>function(A,B,E){if(!LA(A)||!mA([B]))return!1;const s=DA(A);return!!s.every(E)&&!nA([B],(A,B)=>s.some((E,w)=>null!==WA(A,B,E,s[(w+1)%s.length])))}(y(A),B,A=>Z([...A],B)),J=(A,B,E={})=>function(A,B,E,s,w={}){if(!xA(A)||!xA(B)||!mA(E))return!0;if(w.allowStartExit){const w=tA(A,B);if(w<=iA)return!0;const Q=nA(E,(B,E)=>cA(A,B,E));if(!Q)return!0;const C=[];nA(E,(E,s)=>{const w=WA(A,B,E,s);return w&&C.push(w),!1});const g=iA/w,I=[0,1,...C.flatMap(A=>[A.t,A.endT])].sort((A,B)=>A-B).filter((A,B,E)=>0===B||A-E[B-1]>g),Y=E=>[A[0]+(B[0]-A[0])*E,A[1]+(B[1]-A[1])*E],R=A=>C.some(B=>B.overlap&&A>B.t+g&&AA.t>M+g||A.endT>M+g)}const Q=[(A[0]+B[0])/2,(A[1]+B[1])/2],C=nA(E,(B,E)=>cA(A,B,E));return!((!s(A)||w.allowStartBoundary&&C)&&!s(Q)&&!s(B))||nA(E,(E,s)=>{const Q=WA(A,B,E,s);return!!Q&&(Q.overlap||!w.allowStartBoundary||!C||Q.t*tA(A,B)>iA)})}(P(A[0],A[1]),P(B[0],B[1]),u,N,E),T=(A,B,E)=>{const s=A.x*I,w=A.y*I,Q=A.w*I,C=A.h*I,g=s+Q/2,Y=w+C/2,R=s+(A.flip_h?Q:0),F=w+(A.flip_v?C:0),i=(A.flip_h?-1:1)*Q/B,x=(A.flip_v?-1:1)*C/E,b=(Number(A.angle)||0)*Math.PI/180,L=Math.cos(b),D=Math.sin(b),G=Y+D*(R-g)+L*(F-Y);return{a:h*L*i,b:h*D*i,c:-h*D*x,d:h*L*x,e:0+(g+L*(R-g)-D*(F-Y)-M.minX)*h,f:0+(G-M.minY)*h}};let f=[];const z=[],O=function(A,B){const E=3*$A*Math.SQRT2,s=[];for(let w=-B;w<=A+E;w+=E)s.push([[w,0],[w+B,B]]);return s}(c,W);for(const B of A.rasters||[])f.push({kind:"image",imageId:B.id,...a([B.x,B.y]).reduce((A,B,E)=>({...A,[E?"y":"x"]:B}),{}),width:B.drawWidth*h,height:B.drawHeight*h,angle:B.angle,opacity:B.opacity});for(const A of w.geometry.components)f.push({kind:"path",rings:i(A.geom).map(A=>A.map(a)),fill:BB,stroke:AB,width:.25*$A,hatch:{lines:O,stroke:AB,width:.18*$A}});if("failed-core"===w.geometry.status)for(const B of A.space.rooms){const A=C(B);A&&f.push({kind:"path",rings:[A.map(a)],stroke:AB,width:.25*$A})}for(const A of w.zero.lines)f.push({kind:"line",points:[a([A[0],A[1]]),a([A[2],A[3]])],stroke:AB,width:.35*$A,dash:[3*$A,2*$A]});const q=w.geometry.openingIndex;for(const B of w.openings){const E=B.partitionHost?{cm:B.partitionHost.partition.cm}:q?x(A.space.rooms,B,w.walls,R,w.cellCm,Y,I,w.zero.contour):{cm:0};for(const A of MB(B,E.cm,w.cellCm))f.push({kind:"line",points:A.map(a),stroke:AB,width:.3*$A})}if(A.options.decor)for(const B of A.rawSpace.decor||[])if("image"!==B.kind)if("line"===B.kind)f.push({kind:"line",points:[a([B.x1*I,B.y1*I]),a([B.x2*I,B.y2*I])],stroke:AB,width:Math.max(.2*$A,10*Number(B.width_cm||1)*$A/E),dash:"dashed"===B.line_style?[3*$A,2*$A]:void 0});else if("text"===B.kind)f.push({kind:"text",...(()=>{const[A,E]=a([B.x*I,B.y*I]);return{x:A,y:E}})(),text:B.text,size:Math.max(6,10*Number(B.size_cm||20)*$A/E),angle:Number(B.angle)||0});else if("furniture"===B.kind){const A=r[B.symbol];A?f.push({kind:"vector",ops:YA(A.d,T(B,A.viewW,A.viewH)),stroke:AB,width:Math.max(.2*$A,10*b(B,w.cellCm,Y)*$A/E)}):f.push({kind:"path",rings:[L(B).map(([A,B])=>a([A*I,B*I]))],stroke:AB,width:.25*$A})}else{const A="ellipse"===B.kind?YB(B.x*I,B.y*I,B.w*I,B.h*I,Number(B.angle)||0):L(B).map(([A,B])=>[A*I,B*I]);f.push({kind:"path",rings:[A.map(a)],stroke:AB,width:.25*$A})}if(A.options.dimensions&&w.geometry.roomGeom)for(const[B,E]of D(w.geometry.roomGeom).entries()){const s=l(F),w=(A,B,E)=>{const s=a(A.sourceA),w=a(A.sourceB),Q=a(A.a),C=a(A.b),g=(6+E)*$A,I=[Q[0]+B[0]*g,Q[1]+B[1]*g],Y=[C[0]+B[0]*g,C[1]+B[1]*g],R=[(I[0]+Y[0])/2,(I[1]+Y[1])/2],M=PA(A.text,7)+2*$A>Math.hypot(Y[0]-I[0],Y[1]-I[1]),F=QB(wB(R[0],R[1],A.text,7,A.angle,"center"),R[0],R[1],B,$A),i=[R[0]+B[0]*F,R[1]+B[1]*F];return{edge:A,a:s,b:w,oa:I,ob:Y,middle:R,label:i,box:wB(i[0],i[1],A.text,7,A.angle,"center"),needsShelf:M}},Q=A=>{const B=[{start:A.oa,end:A.ob},{start:A.a,end:A.oa,allowStartExit:!0},{start:A.b,end:A.ob,allowStartExit:!0}];return A.needsShelf&&B.push({start:A.middle,end:A.label,mayEnterOwnLabel:!0}),B},C=A=>K(A.box)||Q(A).some(A=>J(A.start,A.end,{allowStartBoundary:A.allowStartBoundary,allowStartExit:A.allowStartExit})),g=EA(k(E,F,A.imperial,{ringIndex:B,epsilon:s}),{ring:E,epsilon:s,score:A=>{const B=[-A.inwardNormal[0],-A.inwardNormal[1]],E=a(A.mid),s=Array.from({length:21},(A,B)=>4*B).find(E=>!C(w(A,B,E))),Q=E[0]+(U-j)/2,g=E[1]+(V-H)/2;return{hardCollisions:void 0===s?21:s/4,normalClearance:Math.abs(B[0])>.5?B[0]>0?U-Q:Q:B[1]>0?V-g:g}}});for(const A of X(g,s)){const B=A.map(A=>({edge:A,outward:[-A.inwardNormal[0],-A.inwardNormal[1]]})),E=A=>B.map(({edge:B,outward:E})=>w(B,E,A));let s=null;for(let A=0;A<=80&&!s;A+=4){const B=E(A),w=B.some((A,E)=>B.slice(0,E).some(B=>sB(A.box,B.box))),g=B.some(A=>C(A)||z.some(B=>sB(A.box,B))),I=B.some((A,E)=>Q(A).some(A=>z.some(B=>eA(A.start,A.end,B))||B.some((B,s)=>(!A.mayEnterOwnLabel||s!==E)&&eA(A.start,A.end,B.box))));w||g||I||(s=B)}if(s)for(const A of s)f.push({kind:"line",points:[A.oa,A.ob],stroke:AB,width:.2*$A},{kind:"line",points:[A.a,A.oa],stroke:AB,width:.15*$A},{kind:"line",points:[A.b,A.ob],stroke:AB,width:.15*$A}),A.needsShelf&&f.push({kind:"line",points:[A.middle,A.label],stroke:AB,width:.15*$A}),f.push({kind:"text",x:A.label[0],y:A.label[1],text:A.edge.text,size:_A,angle:A.edge.angle,align:"center"}),z.push(A.box)}}const $=[...A.space.rooms].sort((A,B)=>String(A.id||"").localeCompare(String(B.id||"")));for(const[B,E]of $.entries()){const s=C(E);if(!s)continue;const w=Q.get(E)||s,I=g.get(E)||0,Y=G(E,A.space.id,A.layout,A.config),[R,M]=a([Y.x,Y.y]),i=w.map(a),x=IB([i]);let b=!1;if(A.options.roomNames&&E.name){const A=Math.max(0,x.maxX-x.minX-4*$A),B=PA(E.name,6.75)<=A?6.75:PA(E.name,5.25)<=A?5.25:0;B&&(f.push({kind:"text",x:R,y:M-2,text:E.name,size:B,align:"center"}),z.push(wB(R,M-2,E.name,B,0,"center")),b=!0)}if(A.options.dimensions){const B=o(I*F*F/1e4,A.imperial),E=M+(b?8:0);f.push({kind:"text",x:R,y:E,text:B,size:6,align:"center"}),z.push(wB(R,E,B,8,0,"center"))}if(A.options.dimensions){const E=l(F),s=EA(p(w,F,A.imperial,{ringIndex:B,epsilon:E}),{ring:w,epsilon:E,score:A=>{const B=a(A.mid),E=QB(wB(B[0],B[1],A.text,_A,A.angle,"center"),B[0],B[1],A.inwardNormal,$A),s=wB(B[0]+A.inwardNormal[0]*E,B[1]+A.inwardNormal[1]*E,A.text,7,A.angle,"center"),w="horizontal"===A.axis?A.inwardNormal[1]>0?x.maxY-B[1]:B[1]-x.minY:A.inwardNormal[0]>0?x.maxX-B[0]:B[0]-x.minX;return{hardCollisions:Number(K(s))+z.reduce((A,B)=>A+Number(sB(s,B)),0),normalClearance:w}}});for(const A of s.filter(A=>A.short)){const B=A.inwardNormal,E=a(A.a),s=a(A.b),w=(E[0]+s[0])/2,Q=(E[1]+s[1])/2;f.push({kind:"line",points:[[w-1.5*B[0]*$A,Q-1.5*B[1]*$A],[w+1.5*B[0]*$A,Q+1.5*B[1]*$A]],stroke:AB,width:.2*$A})}const Q=new Map;for(const A of s.filter(A=>!A.short)){const B=CB(A,A.inwardNormal),E=Q.get(B)||[];E.push(A),Q.set(B,E)}for(const A of Q.values()){let B=null;for(let E=0;E<=30&&!B;E+=3){const s=A.map(A=>{const B=a(A.mid),s=QB(wB(B[0],B[1],A.text,_A,A.angle,"center"),B[0],B[1],A.inwardNormal,(1+E)*$A),w=B[0]+A.inwardNormal[0]*s,Q=B[1]+A.inwardNormal[1]*s;return{edge:A,x:w,y:Q,box:wB(w,Q,A.text,_A,A.angle,"center")}}),Q=s.some((A,B)=>s.slice(0,B).some(B=>sB(A.box,B.box))),C=s.some(A=>K(A.box)||z.some(B=>sB(A.box,B))),g=s.every(A=>d(A.box,w));Q||C||!g||(B=s)}if(B)for(const A of B)f.push({kind:"text",x:A.x,y:A.y,text:A.edge.text,size:_A,angle:A.edge.angle,align:"center"}),z.push(A.box)}}}const _={minX:m,minY:v,maxX:c-m,maxY:v+V},AA=XA(f),BA=OA(AA,{minX:0,minY:0,maxX:U,maxY:V},.5*$A),sA=function(A,B){const E=XA(A);if(!ZA(E))return{commands:[...A],bounds:E,dx:0,dy:0};const s=(B.minX+B.maxX-E.minX-E.maxX)/2,w=(B.minY+B.maxY-E.minY-E.maxY)/2,Q=function(A,B,E){return A.map(A=>"path"===A.kind?{...A,rings:A.rings.map(A=>A.map(([A,s])=>[A+B,s+E]))}:"line"===A.kind?{...A,points:A.points.map(([A,s])=>[A+B,s+E])}:"vector"===A.kind?{...A,ops:A.ops.map(A=>((A,B,E)=>"M"===A.op||"L"===A.op?{...A,x:A.x+B,y:A.y+E}:"C"===A.op?{...A,x1:A.x1+B,y1:A.y1+E,x2:A.x2+B,y2:A.y2+E,x:A.x+B,y:A.y+E}:A)(A,B,E))}:{...A,x:A.x+B,y:A.y+E})}(A,s,w);return{commands:Q,bounds:{minX:E.minX+s,minY:E.minY+w,maxX:E.maxX+s,maxY:E.maxY+w},dx:s,dy:w}}(f,_);f=sA.commands,f.push({kind:"text",x:m,y:m+10,text:A.space.title,size:14}),A.cardTitle&&f.push({kind:"text",x:c-m,y:m+10,text:A.cardTitle,size:10,align:"right"});const wA=W-m-13*$A;f.push({kind:"line",points:[[m,wA-4*$A],[c-m,wA-4*$A]],stroke:EB,width:.2*$A}),f.push({kind:"text",x:m,y:wA,text:A.t("pdf.scale",{n:E}),size:8});const QA=10*(A.imperial?152.4:100)*$A/E,CA=wA+8;f.push({kind:"line",points:[[m,CA],[m+QA,CA]],stroke:AB,width:.4*$A});for(let A=0;A<=4;A++){const B=m+QA*A/4;f.push({kind:"line",points:[[B,CA-2],[B,CA+2]],stroke:AB,width:.25*$A})}f.push({kind:"text",x:m+QA/2,y:wA+17,text:A.imperial?"5 ft":"1 m",size:7,align:"center"});const gA=t(A.config.settings,A.rawSpace.settings||{});if(null!==gA){const B=c/2,E=wA+5.5*$A;f.push({kind:"vector",ops:FA({centerX:B,centerY:E,size:11*$A,northDeg:gA}),fill:AB,width:0,fillRule:"evenodd"}),f.push({kind:"text",x:B,y:wA,text:A.t("pdf.north"),size:7,align:"center"})}f.push({kind:"text",x:c-m,y:wA+12,text:`${qA(A.now)} · House Plan v${A.version}`,size:7,align:"right"});const IA={width:c,height:W,commands:f,images:(A.rasters||[]).map(({id:A,bytes:B,width:E,height:s})=>({id:A,bytes:B,width:E,height:s})),now:A.now,scale:E,sceneBounds:sA.bounds,planField:_},RA=Math.max(0,TA(AA))*Math.max(0,fA(AA)),MA=U*V;return{page:IA,sceneBounds:sA.bounds,field:_,fits:BA,fillRatio:MA>0?RA/MA:0,landscape:s}}function bB(A,B){return A.fillRatio!==B.fillRatio?A.fillRatio>B.fillRatio?A:B:A.landscape?B:A}function LB(A,B,E){const s=12*$A,w=(E?297:210)*$A-2*s,Q=(E?210:297)*$A-2*s-18*$A-24*$A,C=A.cmPerUnit*(10*$A)/B;return(A.bounds.maxX-A.bounds.minX)*C<=w+.5*$A&&(A.bounds.maxY-A.bounds.minY)*C<=Q+.5*$A}function DB(A){let B=0;for(const E of A)if(B+=Math.max(0,Number(E)||0),B>26214400)throw new Error("pdf.too_large")}const GB="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";async function oB(A,B){if(!A)throw new Error("pdf.asset_failed");const E=await fetch(A,{credentials:"same-origin"});if(!E.ok)throw new Error("pdf.asset_failed");const s=await E.blob();let w;try{w=await createImageBitmap(s)}catch{throw new Error("pdf.asset_failed")}try{if("image/jpeg"===s.type)return{id:B,bytes:new Uint8Array(await s.arrayBuffer()),width:w.width,height:w.height};const A=document.createElement("canvas");A.width=w.width,A.height=w.height;const E=A.getContext("2d");if(!E)throw new Error("pdf.asset_failed");E.fillStyle="#fff",E.fillRect(0,0,A.width,A.height),E.drawImage(w,0,0);const Q=await new Promise(B=>A.toBlob(B,"image/jpeg",.85));if(!Q)throw new Error("pdf.asset_failed");return{id:B,bytes:new Uint8Array(await Q.arrayBuffer()),width:w.width,height:w.height}}finally{w.close()}}async function tB(A,B,E){const s=await async function(A,B){const E=[];if(B.backdrop&&A.space.bg){const B=await oB(A.backdropUrl,"backdrop");E.push({...B,x:A.space.bg.x,y:A.space.bg.y,drawWidth:A.space.bg.w,drawHeight:A.space.bg.h,angle:A.space.bg.angle,opacity:.6})}if(B.decor){let B=0;for(const s of A.rawSpace.decor||[]){if("image"!==s.kind)continue;const w=A.decorAssets.get(s.asset_id),Q=j(s,I,I);if(!w||!Q)throw new Error("pdf.asset_failed");const C=await oB(w.url,"decor"+B++);E.push({...C,x:Q[0],y:Q[1],drawWidth:Q[2],drawHeight:Q[3],opacity:Q[4],angle:Number(s.angle)||0})}}return DB(E.map(A=>A.bytes.byteLength)),E}(A,B),w=JA(function(A){const B=iB(A);let E=[];for(const s of wA){const w=[!1,!0].filter(A=>LB(B,s,A)).map(E=>xB(A,B,s,E));if(!w.length)continue;const Q=w.filter(A=>A.fits);if(Q.length)return Q.reduce(bB).page;E=w}E.length||(E=[!1,!0].map(E=>xB(A,B,500,E)));const s=E.filter(A=>A.fits);if(s.length)return s.reduce(bB).page;const w=Math.min(...E.map(A=>Math.max(TA(A.sceneBounds)/TA(A.field),fA(A.sceneBounds)/fA(A.field)))),Q=50,C=1e6,g=Number.isFinite(w)?Math.ceil(Math.min(C,500*Math.max(1,w))/Q)*Q:C;let I=500,Y=0,R=[],M=Math.max(550,g);for(;M<=C;){const E=[!1,!0].map(E=>xB(A,B,M,E)).filter(A=>A.fits);if(E.length){Y=M,R=E;break}if(I=M,M===C)break;M=Math.min(C,Math.ceil(2*M/Q)*Q)}if(!Y)throw new Error("pdf.failed");let F=Math.floor(I/Q),i=Math.floor(Y/Q);for(;i-F>1;){const E=Math.floor((F+i)/2),s=[!1,!0].map(s=>xB(A,B,E*Q,s)).filter(A=>A.fits);s.length?(i=E,R=s):F=E}const x=R.reduce(bB).page;if(!OA(x.sceneBounds,x.planField,.5*$A))throw new Error("pdf.failed");return x}({...A,options:B,now:E,rasters:s,t:A.t})),Q=new Blob([w],{type:"application/pdf"}),C=URL.createObjectURL(Q);try{const B=document.createElement("a");B.href=C,B.download=`houseplan-${g=A.space.title,g.normalize("NFKD").replace(/[^\p{L}\p{N}]+/gu,"-").replace(/^-|-$/g,"").toLowerCase()||"space"}-${qA(E)}.pdf`,B.style.display="none",document.body.append(B),B.click(),B.remove()}finally{setTimeout(()=>URL.revokeObjectURL(C),0)}var g;return w}class cB{assertRasterBudget(A){DB(A)}render(A){let B;return B={...A,save:async E=>{await tB(A,E,B.now||new Date)}},s``}}export{GB as PDF_EXPORT_FINGERPRINT,cB as PdfExportRuntime,tB as exportSpacePdf}; +
    `}}v.properties={context:{attribute:!1}},v.styles=A`:host{display:contents;}.body{display:grid;gap:12px;width:100%;max-width:100%;min-width:0;padding:16px 20px;box-sizing:border-box;}label{display:flex;min-width:0;min-height:44px;align-items:center;gap:12px;cursor:pointer;}label span{min-width:0;overflow-wrap:anywhere;}input{width:20px;height:20px;flex:none;accent-color:var(--hp-accent,#d89300);}.row{display:flex;align-items:center;gap:8px;width:100%;max-width:100%;min-width:0;padding:12px 16px;box-sizing:border-box;}.spacer{flex:1;}button{min-width:0;min-height:44px;max-width:100%;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--hp-line,rgb(127 127 127/.3));border-radius:12px;padding:0 18px;box-sizing:border-box;overflow-wrap:anywhere;white-space:normal;background:transparent;color:inherit;font:inherit;cursor:pointer;}button.primary{background:var(--hp-accent,#d89300);color:var(--hp-on-accent,#111);border-color:transparent;}button:disabled{opacity:.55;cursor:default;}ha-icon{flex:none;margin-right:6px;}@media (max-width:360px){.row{display:grid;grid-template-columns:minmax(0,1fr);}.spacer{display:none;}button{width:100%;}}`,customElements.get("hp-pdf-dialog")||customElements.define("hp-pdf-dialog",v);const V=(A,B,E)=>Math.hypot(A[0]-B[0],A[1]-B[1])<=E,U=A=>Number.isFinite(A)&&A>=0?A:0;function l(A){const B=Number(A);return Number.isFinite(B)&&B>0?.1/B:0}const a=(A,B)=>[...new Set([...A,...B])].sort((A,B)=>A-B),P=(A,B)=>{const E=A.points.length;if(E<=1||!V(A.points[E-1],A.points[0],B))return!1;const s=E-2;return A.edgeSources[s]=a(A.edgeSources[s],A.edgeSources[E-1]),A.points.splice(E-1,1),A.edgeSources.splice(E-1,1),!0},y=(A,B)=>{for(let E=0;E+1{let E=!1;for(;A.points.length>1;)if(P(A,B))E=!0;else{if(!y(A,B))break;E=!0}return E},N=(A,B,E)=>{const s=B[0]-A[0],w=B[1]-A[1],C=E[0]-B[0],g=E[1]-B[1],I=Math.hypot(s,w),Y=Math.hypot(C,g);if(!(I>0&&Y>0))return!1;const R=s*C+w*g;if(!(R>0))return!1;const M=s*g-w*C;return Math.abs(M)<=R*Q},K=A=>{const B=A.points.length;if(B<3)return!1;for(let E=0;E{const E=U(B),s=[],w=[];for(let B=0;B[A])};for(;Q.points.length>1;){const A=u(Q,E);if(Q.points.length<3)break;if(!K(Q)&&!A)break}return u(Q,E),Q};function J(A,B){const E=Number(A[0]),s=Number(A[1]),w=Number(B[0]),C=Number(B[1]);if(![E,s,w,C].every(Number.isFinite))return null;const g=w-E,I=C-s,Y=Math.abs(g),R=Math.abs(I),M=Math.max(Y,R),F=Math.min(Y,R);if(!(M>0)||F/M>Q)return null;const i=[(E+w)/2,(s+C)/2];if(Y>=R){return{axis:"horizontal",a:[E,i[1]],b:[w,i[1]],mid:i,projectedLength:Y,tangentInterval:[Math.min(E,w),Math.max(E,w)],normalCoordinate:i[1]}}return{axis:"vertical",a:[i[0],s],b:[i[0],C],mid:i,projectedLength:R,tangentInterval:[Math.min(s,C),Math.max(s,C)],normalCoordinate:i[0]}}function Z(A,B){const E=B.map(A=>[Number(A[0]),Number(A[1])]);if(!E.every(A=>A.every(Number.isFinite)))return!1;if(E.length<3||((A,B)=>{const E=1e-12*Math.max(1,Math.abs(A[0]),Math.abs(A[1]),...B.flatMap(A=>[Math.abs(A[0]),Math.abs(A[1])]));for(let s=0;s0))continue;const Y=(A[0]-w[0])*g-(A[1]-w[1])*C;if(Math.abs(Y)>E*I)continue;const R=(A[0]-w[0])*C+(A[1]-w[1])*g;if(R>=-E&&R<=I*I+E)return!0}return!1})(A,E))return!1;let s=!1;for(let B=0,w=E.length-1;BA[1]==C[1]>A[1])continue;const g=(C[0]-Q[0])*(A[1]-Q[1])/(C[1]-Q[1])+Q[0];A[0]Object.is(A,-0)?0:A,I=[g(-Q/C),g(w/C)],Y=[g(-I[0]),g(-I[1])],R=[(B[0]+E[0])/2,(B[1]+E[1])/2],M=Math.max(1,C,Math.abs(R[0]),Math.abs(R[1])),F=Math.max(1e-9*M,.01*U(s));for(const B of[F,4*F,16*F]){const E=Z([R[0]+I[0]*B,R[1]+I[1]*B],A);if(E!==Z([R[0]+Y[0]*B,R[1]+Y[1]*B],A))return E?I:Y}return sA(A)>=0?I:Y}function f(A,B){let E=180*Math.atan2(B[1]-A[1],B[0]-A[0])/Math.PI;return E>90&&(E-=180),E<=-90&&(E+=180),E}function k(A,B,E,s={}){const w=Number(B);if(!(w>0&&Number.isFinite(w)))return[];const Q=void 0===s.epsilon?l(w):U(s.epsilon);return z(d(A,Q),w,E,{...s,epsilon:Q})}const z=(A,B,E,s)=>{if(A.points.length<3)return[];const Q=U(s.epsilon??l(B)),C=Number.isFinite(Number(s.ringIndex))?Number(s.ringIndex):0,g=[];for(let s=0;sQ))continue;const M=[...A.edgeSources[s]||[s]].sort((A,B)=>A-B),F=M[0]??s,i=T(A.points,R.a,R.b,Q),x=("horizontal"===R.axis?i[1]:i[0])<0?-1:1,b=[R.axis,O(R.tangentInterval[0]),String(x),O(C),O(F)].join("|"),L=R.projectedLength*B;g.push({sourceA:[...I],sourceB:[...Y],a:R.a,b:R.b,text:w(L,E),short:L<30,angle:f(R.a,R.b),mid:R.mid,axis:R.axis,projectedLength:R.projectedLength,tangentInterval:R.tangentInterval,normalCoordinate:R.normalCoordinate,inwardNormal:i,normalSign:x,source:{ringIndex:C,edgeIndex:F},sourceEdgeIndices:M,stableKey:b})}return g};function p(A,B,E,s={}){const w=Number(B);if(!(w>0&&Number.isFinite(w)))return[];const Q=void 0===s.epsilon?l(w):U(s.epsilon);let C=d(A,Q);if(sA(C.points)<0&&(C=(A=>{const B=A.points.length;return{points:[...A.points].reverse().map(A=>[...A]),edgeSources:A.points.map((E,s)=>[...A.edgeSources[(B-2-s+B)%B]])}})(C)),C.points.length){let A=0;for(let B=1;B({points:[...A.points.slice(B),...A.points.slice(0,B)],edgeSources:[...A.edgeSources.slice(B),...A.edgeSources.slice(0,B)]}))(C,A)}return z(C,w,E,{...s,epsilon:Q})}function X(A,B){const E=U(B),s=[];for(const B of A){const A=s.find(A=>A.axis===B.axis&&A.normalSign===B.normalSign&&Math.abs(A.normalCoordinate-B.normalCoordinate)<=E);A?A.edges.push(B):s.push({axis:B.axis,normalSign:B.normalSign,normalCoordinate:B.normalCoordinate,edges:[B]})}return s.map(A=>A.edges)}const O=A=>Object.is(A,-0)?"0":String(A),q=A=>"horizontal"===A?0:1;function $(A,B){return q(A.axis)-q(B.axis)||A.tangentInterval[0]-B.tangentInterval[0]||A.normalSign-B.normalSign||A.source.ringIndex-B.source.ringIndex||A.source.edgeIndex-B.source.edgeIndex}function _(A,B,E,s){const w=U(s);if(A.axis!==B.axis)return!1;if(A.source.ringIndex!==B.source.ringIndex)return!1;if(A.inwardNormal[0]*B.inwardNormal[0]+A.inwardNormal[1]*B.inwardNormal[1]>=-.5)return!1;if(!((A,B,E)=>Math.abs(A[0]-B[0])<=E&&Math.abs(A[1]-B[1])<=E)(A.tangentInterval,B.tangentInterval,w))return!1;if(Math.abs(A.projectedLength-B.projectedLength)>w)return!1;return Z([(A.mid[0]+B.mid[0])/2,(A.mid[1]+B.mid[1])/2],E)}const AA=(A,B)=>{const E=B?.(A);return{hardCollisions:Number.isFinite(Number(E?.hardCollisions))?Number(E?.hardCollisions):0,normalClearance:Number.isFinite(Number(E?.normalClearance))?Number(E?.normalClearance):0}},BA=(A,B,E)=>{const s=AA(A,E),w=AA(B,E);return s.hardCollisions-w.hardCollisions||w.normalClearance-s.normalClearance||$(A,B)};function EA(A,B){if(A.length<2)return[...A];const E=U(B.epsilon),s=function(A,B=1e-7){return d(A,B).points.map(A=>[...A])}(B.ring,E),w=[];for(let B=0;B{const E=A.separation-B.separation;if(E)return E;const s=$(A.left,A.right)<=0?A.left:A.right,w=s===A.left?A.right:A.left,Q=$(B.left,B.right)<=0?B.left:B.right,C=Q===B.left?B.right:B.left;return $(s,Q)||$(w,C)});const Q=new Set,C=new Set;for(const A of w){if(Q.has(A.left)||Q.has(A.right))continue;Q.add(A.left),Q.add(A.right);const E=BA(A.left,A.right,B.score)<=0?A.left:A.right;C.add(E===A.left?A.right:A.left)}return A.filter(A=>!C.has(A))}function sA(A){let B=0;for(let E=0;E1){const A=Math.sqrt(G);Y*=A,R*=A}const o=Math.max(0,Y*Y*R*R-Y*Y*D*D-R*R*L*L),t=Y*Y*D*D+R*R*L*L||1,c=(Q===C?-1:1)*Math.sqrt(o/t),W=c*Y*D/R,m=c*-R*L/Y,n=F*W-i*m+(A+g)/2,e=i*W+F*m+(B+I)/2;let h=gA(1,0,(L-W)/Y,(D-m)/R),S=gA((L-W)/Y,(D-m)/R,(-L-W)/Y,(-D-m)/R);!C&&S>0&&(S-=2*Math.PI),C&&S<0&&(S+=2*Math.PI);const j=Math.max(1,Math.ceil(Math.abs(S)/(Math.PI/2))),r=S/j,H=A=>[n+F*Y*Math.cos(A)-i*R*Math.sin(A),e+i*Y*Math.cos(A)+F*R*Math.sin(A)],v=A=>[-F*Y*Math.sin(A)-i*R*Math.cos(A),-i*Y*Math.sin(A)+F*R*Math.cos(A)],V=[];for(let A=0;A[B.a*A+B.c*E+B.e,B.b*A+B.d*E+B.f];return function(A){const B=A.match(/[AaCcHhLlMmQqSsTtVvZz]|[-+]?(?:\d*\.\d+|\d+\.?)(?:e[-+]?\d+)?/gi)||[],E=[];let s=0,w="",Q=0,C=0,g=0,I=0,Y=null,R=null;const M=()=>Number(B[s++]);for(;sB.length||QA.test(B[s]))throw new Error(`Invalid SVG path command ${w}`);const x=Array.from({length:i},M),b=A=>A+(F?Q:0),L=A=>A+(F?C:0);if("M"===A||"L"===A)Q=b(x[0]),C=L(x[1]),E.push({op:"M"===A?"M":"L",x:Q,y:C}),"M"===A&&(g=Q,I=C,w=F?"l":"L"),Y=R=null;else if("H"===A)Q=b(x[0]),E.push({op:"L",x:Q,y:C}),Y=R=null;else if("V"===A)C=L(x[0]),E.push({op:"L",x:Q,y:C}),Y=R=null;else if("C"===A){const A=b(x[0]),B=L(x[1]),s=b(x[2]),w=L(x[3]);Q=b(x[4]),C=L(x[5]),Y=[s,w],R=null,E.push({op:"C",x1:A,y1:B,x2:s,y2:w,x:Q,y:C})}else if("S"===A){const A=Y?2*Q-Y[0]:Q,B=Y?2*C-Y[1]:C,s=b(x[0]),w=L(x[1]);Q=b(x[2]),C=L(x[3]),Y=[s,w],R=null,E.push({op:"C",x1:A,y1:B,x2:s,y2:w,x:Q,y:C})}else if("Q"===A||"T"===A){const B="Q"===A?b(x[0]):R?2*Q-R[0]:Q,s="Q"===A?L(x[1]):R?2*C-R[1]:C,w=b("Q"===A?x[2]:x[0]),g=L("Q"===A?x[3]:x[1]);E.push({op:"C",x1:Q+2/3*(B-Q),y1:C+2/3*(s-C),x2:w+2/3*(B-w),y2:g+2/3*(s-g),x:w,y:g}),Q=w,C=g,R=[B,s],Y=null}else if("A"===A){const A=b(x[5]),B=L(x[6]),s=IA(Q,C,x[0],x[1],x[2],x[3],x[4],A,B);s.length?E.push(...s):E.push({op:"L",x:A,y:B}),Q=A,C=B,Y=R=null}}return E}(A).map(A=>{if("Z"===A.op)return A;if("M"===A.op||"L"===A.op){const[B,s]=E(A.x,A.y);return{op:A.op,x:B,y:s}}if("C"!==A.op)throw new Error("Unsupported PDF vector operation");const[B,s]=E(A.x1,A.y1),[w,Q]=E(A.x2,A.y2),[C,g]=E(A.x,A.y);return{op:"C",x1:B,y1:s,x2:w,y2:Q,x:C,y:g}})}const RA=["M20.82,15.31h0L10.46,9c-.46-.26-1.11.37-.86.84l6.15,10.56,10.56,6.15a.66.66,0,0,0,.84-.86Zm-4,4,3-3,4.55,7.44Z","M18,2A16,16,0,1,0,34,18,16,16,0,0,0,18,2Zm1,29.95V29.53H17v2.42A14,14,0,0,1,4.05,19H6.47V17H4.05A14,14,0,0,1,17,4.05V6.47h2V4.05A14,14,0,0,1,31.95,17H29.53v2h2.42A14,14,0,0,1,19,31.95Z"],MA=A=>Math.abs(A)<1e-12?0:Math.abs(A-1)<1e-12?1:Math.abs(A+1)<1e-12?-1:A;function FA(A){const B=function(A){const{centerX:B,centerY:E,size:s,northDeg:w}=A;if(![B,E,s,w].every(Number.isFinite)||s<=0)throw new RangeError("PDF compass placement must contain finite coordinates and a positive size");const Q=((w%360+360)%360+45)*Math.PI/180,C=s/36,g=MA(Math.cos(Q)),I=MA(Math.sin(Q)),Y=C*g,R=C*I,M=-C*I,F=C*g;return{a:Y,b:R,c:M,d:F,e:B-18*Y-18*M,f:E-18*R-18*F}}(A);return RA.flatMap(A=>YA(A,B))}const iA=1e-8,xA=A=>A.length>=2&&Number.isFinite(A[0])&&Number.isFinite(A[1]),bA=(A,B)=>A[0]>=B.minX-iA&&A[0]<=B.maxX+iA&&A[1]>=B.minY-iA&&A[1]<=B.maxY+iA,LA=A=>[A.minX,A.minY,A.maxX,A.maxY].every(Number.isFinite)&&A.maxX>=A.minX&&A.maxY>=A.minY,DA=A=>[[A.minX,A.minY],[A.maxX,A.minY],[A.maxX,A.maxY],[A.minX,A.maxY]];const GA=(A,B,E)=>(B[0]-A[0])*(E[1]-A[1])-(B[1]-A[1])*(E[0]-A[0]),oA=(A,B,E)=>{const s=E[0]-B[0],w=E[1]-B[1],Q=Math.abs(s)>=Math.abs(w)?s:w;return Math.abs(Q)<=iA?0:(Math.abs(s)>=Math.abs(w)?A[0]-B[0]:A[1]-B[1])/Q},tA=(A,B)=>Math.hypot(B[0]-A[0],B[1]-A[1]);function cA(A,B,E){const s=tA(B,E);if(s<=iA)return tA(A,B)<=iA;if(Math.abs(GA(B,E,A))/s>iA)return!1;const w=oA(A,B,E),Q=iA/s;return w>=-Q&&w<=1+Q}function WA(A,B,E,s){const w=B[0]-A[0],Q=B[1]-A[1],C=s[0]-E[0],g=s[1]-E[1],I=Math.hypot(w,Q),Y=Math.hypot(C,g);if(I<=iA)return cA(A,E,s)?{t:0,endT:0,overlap:!1}:null;if(Y<=iA){if(!cA(E,A,B))return null;const s=Math.max(0,Math.min(1,oA(E,A,B)));return{t:s,endT:s,overlap:!1}}const R=w*g-Q*C,M=E[0]-A[0],F=E[1]-A[1],i=iA*I*Y;if(Math.abs(R)<=i){if(Math.abs(GA(A,B,E))/I>iA||Math.abs(GA(A,B,s))/I>iA)return null;const w=oA(E,A,B),Q=oA(s,A,B),C=Math.max(0,Math.min(w,Q)),g=Math.min(1,Math.max(w,Q));return giA}}const x=(M*g-F*C)/R,b=(M*Q-F*w)/R,L=iA/I,D=iA/Y;if(x<-L||x>1+L||b<-D||b>1+D)return null;const G=Math.max(0,Math.min(1,x));return{t:G,endT:G,overlap:!1}}const mA=A=>A.every(A=>A.length>=2&&A.every(xA));function nA(A,B){for(const E of A){const A=E;for(let E=0;Enull!==WA(A,B,E,s[(w+1)%s.length]))}const hA=2048,SA=2146,jA=[-1825,-555,4188,2163],rA={32:1,33:2,34:3,35:4,36:5,37:6,38:7,39:8,40:9,41:10,42:11,43:12,44:13,45:14,46:15,47:16,48:17,49:18,50:19,51:20,52:21,53:22,54:23,55:24,56:25,57:26,58:27,59:28,60:29,61:30,62:31,63:32,64:33,65:34,66:35,67:36,68:37,69:38,70:39,71:40,72:41,73:42,74:43,75:44,76:45,77:46,78:47,79:48,80:49,81:50,82:51,83:52,84:53,85:54,86:55,87:56,88:57,89:58,90:59,91:60,92:61,93:62,94:63,95:64,96:65,97:66,98:67,99:68,100:69,101:70,102:71,103:72,104:73,105:74,106:75,107:76,108:77,109:78,110:79,111:80,112:81,113:82,114:83,115:84,116:85,117:86,118:87,119:88,120:89,121:90,122:91,123:92,124:93,125:94,126:95,160:596,161:96,162:97,163:98,164:99,165:100,166:101,167:102,168:103,169:104,170:105,171:106,172:107,173:597,174:108,175:109,176:110,177:111,178:112,179:113,180:114,181:115,182:116,183:117,184:118,185:119,186:120,187:121,188:122,189:123,190:124,191:125,192:603,193:604,194:605,195:606,196:607,197:608,198:126,199:609,200:610,201:611,202:612,203:613,204:614,205:615,206:616,207:617,208:599,209:618,210:619,211:620,212:621,213:622,214:623,215:127,216:128,217:624,218:625,219:626,220:627,221:628,222:129,223:130,224:629,225:630,226:631,227:632,228:633,229:634,230:131,231:635,232:636,233:637,234:638,235:639,236:640,237:641,238:642,239:643,240:132,241:644,242:645,243:646,244:647,245:648,246:649,247:133,248:134,249:650,250:651,251:652,252:653,253:654,254:135,255:655,256:656,257:657,258:658,259:659,260:660,261:661,262:662,263:663,264:664,265:665,266:666,267:667,268:668,269:669,270:670,271:671,272:598,273:136,274:672,275:673,276:674,277:675,278:676,279:677,280:678,281:679,282:680,283:681,284:682,285:683,286:684,287:685,288:686,289:687,290:688,291:689,292:690,293:691,294:137,295:600,296:692,297:693,298:694,299:695,300:696,301:697,302:698,303:699,304:700,305:138,306:701,307:702,308:703,309:704,310:705,311:706,312:139,313:707,314:708,315:709,316:710,317:711,318:712,319:713,320:714,321:140,322:141,323:715,324:716,325:717,326:718,327:719,328:720,329:721,330:142,331:143,332:722,333:723,334:724,335:725,336:726,337:727,338:144,339:145,340:728,341:729,342:730,343:731,344:732,345:733,346:734,347:735,348:736,349:737,350:738,351:739,352:742,353:743,354:744,355:745,356:746,357:747,358:601,359:602,360:748,361:749,362:750,363:751,364:752,365:753,366:754,367:755,368:756,369:757,370:758,371:759,372:760,373:761,374:762,375:763,376:764,377:765,378:766,379:767,380:768,381:769,382:770,383:146,1024:897,1025:856,1026:165,1027:857,1028:166,1029:858,1030:859,1031:860,1032:861,1033:167,1034:168,1035:169,1036:863,1037:898,1038:864,1039:170,1040:865,1041:171,1042:866,1043:867,1044:172,1045:868,1046:173,1047:174,1048:175,1049:869,1050:862,1051:176,1052:870,1053:871,1054:872,1055:873,1056:874,1057:875,1058:876,1059:177,1060:178,1061:877,1062:179,1063:180,1064:181,1065:182,1066:183,1067:184,1068:185,1069:186,1070:187,1071:188,1072:878,1073:189,1074:190,1075:191,1076:192,1077:879,1078:193,1079:194,1080:195,1081:880,1082:196,1083:197,1084:198,1085:199,1086:881,1087:200,1088:882,1089:883,1090:201,1091:884,1092:202,1093:885,1094:203,1095:204,1096:205,1097:206,1098:207,1099:208,1100:209,1101:210,1102:211,1103:212,1104:899,1105:886,1106:213,1107:887,1108:214,1109:888,1110:889,1111:890,1112:891,1113:215,1114:216,1115:217,1116:892,1117:900,1118:893,1119:218,1120:219,1121:220,1122:965,1123:221,1124:222,1125:223,1126:224,1127:225,1128:226,1129:227,1130:228,1131:229,1132:230,1133:231,1134:232,1135:233,1136:901,1137:902,1138:234,1139:235,1140:236,1141:237,1142:903,1143:904,1144:906,1145:905,1146:238,1147:239,1148:240,1149:241,1150:242,1151:243,1152:244,1153:245,1154:246,1155:247,1156:248,1157:249,1158:250,1159:251,1160:252,1161:253,1162:254,1163:255,1164:964,1165:256,1166:257,1167:258,1168:259,1169:260,1170:966,1171:967,1172:261,1173:262,1174:263,1175:264,1176:907,1177:908,1178:265,1179:266,1180:267,1181:268,1182:968,1183:969,1184:269,1185:270,1186:271,1187:272,1188:273,1189:274,1190:275,1191:276,1192:277,1193:278,1194:909,1195:910,1196:955,1197:956,1198:911,1199:912,1200:970,1201:971,1202:279,1203:280,1204:281,1205:282,1206:283,1207:284,1208:285,1209:286,1210:287,1211:963,1212:288,1213:289,1214:961,1215:962,1216:913,1217:914,1218:915,1219:290,1220:291,1221:292,1222:293,1223:294,1224:295,1225:296,1226:297,1227:957,1228:958,1229:298,1230:299,1231:916,1232:917,1233:918,1234:919,1235:920,1236:921,1237:922,1238:923,1239:924,1240:300,1241:926,1242:925,1243:927,1244:928,1245:929,1246:930,1247:931,1248:301,1249:302,1250:932,1251:933,1252:934,1253:935,1254:936,1255:937,1256:938,1257:939,1258:940,1259:941,1260:942,1261:943,1262:944,1263:945,1264:946,1265:947,1266:948,1267:949,1268:950,1269:951,1270:959,1271:960,1272:952,1273:953,1274:303,1275:304,1276:305,1277:306,1278:972,1279:973,1280:307,1281:954,1282:308,1283:309,1284:310,1285:311,1286:312,1287:313,1288:314,1289:315,1290:316,1291:317,1292:318,1293:319,1294:320,1295:321,1296:322,1297:974,1298:323,1299:324,1300:325,1301:326,1302:327,1303:328,1304:329,1305:330,1306:982,1307:983,1308:984,1309:985,1310:331,1311:332,1312:333,1313:334,1314:335,1315:336,1316:337,1317:338,1318:339,1319:340,1320:341,1321:342,1322:343,1323:344,1324:345,1325:346,1326:347,1327:348,8192:349,8193:350,8194:351,8195:352,8196:353,8197:354,8198:355,8199:356,8200:357,8201:358,8202:360,8203:361,8204:362,8205:363,8206:364,8207:365,8208:366,8209:367,8210:368,8211:369,8212:370,8213:975,8214:371,8215:372,8216:373,8217:374,8218:375,8219:376,8220:377,8221:378,8222:379,8223:380,8224:381,8225:382,8226:383,8227:384,8228:385,8229:386,8230:387,8231:388,8239:986,8240:389,8241:390,8242:894,8243:895,8244:391,8245:392,8246:393,8247:394,8248:395,8249:396,8250:397,8251:398,8252:896,8253:399,8254:400,8255:401,8256:402,8257:403,8258:404,8259:405,8260:406,8261:407,8262:408,8263:987,8264:988,8265:989,8266:409,8267:410,8268:411,8269:412,8270:413,8271:414,8272:415,8273:416,8274:417,8275:418,8276:419,8277:420,8278:421,8279:422,8280:423,8281:424,8282:425,8283:426,8284:427,8285:428,8286:429,8287:990,8364:430,8381:431,8776:433},HA={1:507,2:527,3:655,4:1261,5:1150,6:1500,7:1273,8:357,9:700,10:712,11:882,12:1161,13:402,14:565,15:539,16:844,17:1150,18:1150,19:1150,20:1150,21:1150,22:1150,23:1150,24:1150,25:1150,26:1150,27:496,28:433,29:1041,30:1124,31:1070,32:967,33:1839,34:1336,35:1275,36:1333,37:1343,38:1164,39:1132,40:1395,41:1460,42:557,43:1130,44:1284,45:1102,46:1788,47:1460,48:1408,49:1292,50:1408,51:1261,52:1215,53:1222,54:1328,55:1303,56:1817,57:1284,58:1230,59:1226,60:543,61:840,62:543,63:856,64:924,65:633,66:1114,67:1149,68:1072,69:1155,70:1085,71:711,72:1149,73:1128,74:497,75:489,76:1038,77:497,78:1795,79:1130,80:1168,81:1149,82:1164,83:693,84:1056,85:669,86:1129,87:992,88:1539,89:1015,90:969,91:1015,92:693,93:499,94:693,95:1393,96:499,97:1120,98:1190,99:1460,100:1075,101:491,102:1256,103:856,104:1609,105:915,106:961,107:1134,108:1610,109:938,110:765,111:1094,112:751,113:751,114:642,115:1160,116:1001,117:534,118:507,119:751,120:931,121:960,122:1500,123:1589,124:1593,125:969,126:1914,127:1092,128:1408,129:1210,130:1218,131:1729,132:1200,133:1169,134:1160,135:1180,136:1223,137:1434,138:506,139:1139,140:1103,141:553,142:1419,143:1160,144:1953,145:1860,146:508,165:1535,166:1380,167:2193,168:2212,169:1666,170:1460,171:1291,172:1540,173:1859,174:1215,175:1460,176:1449,177:1287,178:1580,179:1497,180:1402,181:1927,182:1984,183:1554,184:1771,185:1285,186:1380,187:1831,188:1304,189:1132,190:1170,191:859,192:1236,193:1568,194:1040,195:1182,196:1106,197:1184,198:1519,199:1181,200:1182,201:984,202:1485,203:1213,204:1113,205:1656,206:1694,207:1271,208:1590,209:1112,210:1101,211:1671,212:1124,213:1128,214:1101,215:1737,216:1764,217:1161,218:1182,219:1800,220:1579,221:1110,222:1835,223:1528,224:1234,225:1094,226:1803,227:1547,228:1745,229:1505,230:2308,231:2001,232:1059,233:987,234:1393,235:1163,236:1290,237:1027,238:1393,239:1160,240:1793,241:1572,242:1800,243:1579,244:1330,245:1095,246:1277,247:1024,248:1024,249:1024,250:1024,251:1024,252:1024,253:1024,254:1545,255:1261,256:1110,257:1307,258:1161,259:1123,260:912,261:1243,262:1029,263:1954,264:1633,265:1434,266:1208,267:1289,268:1150,269:1676,270:1411,271:1535,272:1241,273:1999,274:1460,275:2097,276:1780,277:1518,278:1235,279:1304,280:1066,281:1836,282:1372,283:1468,284:1174,285:1391,286:1130,287:1391,288:1583,289:1213,290:1289,291:1114,292:1534,293:1263,294:1458,295:1160,296:1554,297:1260,298:1871,299:1598,300:1415,301:1192,302:1192,303:1207,304:939,305:1326,306:1088,307:1270,308:1684,309:1764,310:1622,311:1323,312:1097,313:1031,314:1985,315:1653,316:2043,317:1697,318:1270,319:1053,320:1453,321:1312,322:1380,323:1538,324:1266,325:1920,326:1549,327:1857,328:1547,329:1926,330:1774,331:1316,332:1106,333:2274,334:1832,335:2300,336:1829,337:1526,338:1242,339:1468,340:1208,341:1539,342:1273,343:2710,344:2238,345:1568,346:1240,347:1515,348:1243,349:1044,350:2089,351:1044,352:2089,353:697,354:522,355:348,356:1151,357:560,358:418,360:209,361:1024,362:1024,363:1024,364:1024,365:1024,366:564,367:564,368:1171,369:1344,370:1599,371:778,372:933,373:409,374:409,375:407,376:409,377:724,378:731,379:705,380:764,381:1129,382:1167,383:690,384:1100,385:511,386:964,387:1370,388:382,389:1962,390:2360,391:1045,392:463,393:757,394:1045,395:803,396:614,397:614,398:1241,399:919,400:952,401:1540,402:1540,403:874,404:1370,405:870,406:931,407:640,408:641,409:907,410:1001,411:1237,412:1237,413:985,414:511,415:1541,416:985,417:931,418:1366,419:1540,420:1172,421:932,422:1333,423:1215,424:1125,425:379,426:1071,427:1162,428:379,429:379,430:1150,431:1359,433:1154,596:507,597:565,598:1373,599:1373,600:1158,601:1222,602:669,603:1336,604:1336,605:1336,606:1336,607:1336,608:1336,609:1333,610:1164,611:1164,612:1164,613:1164,614:557,615:557,616:557,617:557,618:1460,619:1408,620:1408,621:1408,622:1408,623:1408,624:1328,625:1328,626:1328,627:1328,628:1230,629:1114,630:1114,631:1114,632:1114,633:1114,634:1114,635:1072,636:1085,637:1085,638:1085,639:1085,640:506,641:506,642:506,643:506,644:1130,645:1168,646:1168,647:1168,648:1168,649:1168,650:1129,651:1129,652:1129,653:1129,654:969,655:969,656:1336,657:1114,658:1336,659:1114,660:1336,661:1114,662:1333,663:1072,664:1333,665:1072,666:1333,667:1072,668:1333,669:1072,670:1343,671:1305,672:1164,673:1085,674:1164,675:1085,676:1164,677:1085,678:1164,679:1085,680:1164,681:1085,682:1395,683:1149,684:1395,685:1149,686:1395,687:1149,688:1395,689:1149,690:1460,691:1128,692:557,693:506,694:557,695:506,696:557,697:506,698:557,699:497,700:557,701:1687,702:986,703:1130,704:515,705:1284,706:1038,707:1102,708:497,709:1102,710:497,711:1102,712:647,713:1102,714:717,715:1460,716:1130,717:1460,718:1130,719:1460,720:1130,721:1130,722:1408,723:1168,724:1408,725:1168,726:1408,727:1168,728:1261,729:693,730:1261,731:693,732:1261,733:693,734:1215,735:1056,736:1215,737:1056,738:1215,739:1056,742:1215,743:1056,744:1222,745:669,746:1222,747:709,748:1328,749:1129,750:1328,751:1129,752:1328,753:1129,754:1328,755:1129,756:1328,757:1129,758:1328,759:1129,760:1817,761:1539,762:1230,763:969,764:1230,765:1226,766:1015,767:1226,768:1015,769:1226,770:1015,856:1164,857:1139,858:1215,859:557,860:557,861:1130,862:1316,863:1284,864:1287,865:1336,866:1275,867:1139,868:1164,869:1460,870:1788,871:1460,872:1408,873:1461,874:1292,875:1333,876:1222,877:1284,878:1114,879:1085,880:1182,881:1168,882:1149,883:1072,884:969,885:1015,886:1085,887:859,888:1056,889:497,890:506,891:489,892:1106,893:969,894:357,895:655,896:1054,897:1164,898:1460,899:1085,900:1182,901:1417,902:1434,903:1290,904:1027,905:2137,906:2377,907:1215,908:1040,909:1333,910:1072,911:1230,912:1026,913:557,914:1859,915:1568,916:557,917:1336,918:1114,919:1336,920:1114,921:1914,922:1729,923:1164,924:1085,925:1415,926:1079,927:1079,928:1859,929:1568,930:1215,931:1040,932:1460,933:1182,934:1460,935:1182,936:1408,937:1168,938:1393,939:1163,940:1393,941:1163,942:1380,943:1101,944:1287,945:969,946:1287,947:969,948:1287,949:969,950:1402,951:1113,952:1771,953:1590,954:1155,955:1222,956:984,957:1402,958:1113,959:1139,960:859,961:1583,962:1213,963:1128,964:1285,965:1285,966:1139,967:859,968:1336,969:1063,970:1230,971:1026,972:1284,973:1015,974:1104,975:1599,982:1408,983:1164,984:1817,985:1539,986:507,987:1934,988:1494,989:1494,990:507},vA=new TextEncoder,VA=A=>{const B=Math.round(100*A)/100;return Number.isInteger(B)?String(B):B.toFixed(2).replace(/0+$/,"")},UA=A=>{const B=Math.round(1e6*A)/1e6;return Number.isInteger(B)?String(B):B.toFixed(6).replace(/0+$/,"")},lA=A=>A.map(UA).join(" ");function aA(A){let B="",E=0;const s=new Map;for(const w of A){const A=w.codePointAt(0)||0,Q=rA[A]||rA[63];B+=Q.toString(16).padStart(4,"0"),E+=HA[Q]||1024,s.has(Q)||s.set(Q,A||63)}return{hex:B,width:E,unicode:s}}function PA(A,B){return aA(A).width*B/hA}function yA(A,B=PA(A.text,A.size)){const E=A.align||"left",s="center"===E?B/2:"right"===E?B:0,w=(A.angle||0)*Math.PI/180,Q=Math.cos(w),C=Math.sin(w);return{width:B,baselineX:A.x-Q*s,baselineY:A.y+C*s,cos:Q,sin:C}}function uA(A){const B=yA(A),E=-555*A.size/hA,s=SA*A.size/hA,w=[0,B.width].flatMap(A=>[E,s].map(E=>({x:B.baselineX+B.cos*A-B.sin*E,y:B.baselineY-B.sin*A-B.cos*E})));return{minX:Math.min(...w.map(A=>A.x)),minY:Math.min(...w.map(A=>A.y)),maxX:Math.max(...w.map(A=>A.x)),maxY:Math.max(...w.map(A=>A.y))}}function NA(A){const B=A.reduce((A,B)=>A+B.length,0),E=new Uint8Array(B);let s=0;for(const B of A)E.set(B,s),s+=B.length;return E}const KA=A=>vA.encode(A),dA=(A,B)=>NA([KA(`<< ${A} /Length ${B.length} >>\nstream\n`),B,KA("\nendstream")]);function JA(A){const B=function(A){const B=atob(A),E=new Uint8Array(B.length);for(let A=0;A"image"===A.kind&&null!=A.opacity&&A.opacity<1?[Math.max(0,Math.min(1,A.opacity))]:[]))].sort((A,B)=>A-B),s=new Map(E.map((A,B)=>[A,`GS${B+1}`])),w=function(A,B){const E=[],s=new Map,w=B=>A.height-B,Q=(A,...B)=>`${B.map(VA).join(" ")} ${A}`,C=A=>{for(const B of A)if(B.length){E.push(Q("m",B[0][0],w(B[0][1])));for(let A=1;A{let B=!1;for(const s of A)if(!(s.length<2)){B=!0,E.push(Q("m",s[0][0],w(s[0][1])));for(let A=1;A Tj`,"ET")}else{const A=(I.angle||0)*Math.PI/180,s=Math.cos(A),C=Math.sin(A),g=I.x+I.width/2,Y=w(I.y+I.height/2);E.push("q");const R=null==I.opacity?1:Math.max(0,Math.min(1,I.opacity)),M=B.get(R);M&&E.push(`/${M} gs`),E.push(Q("cm",s*I.width,C*I.width,C*I.height,-s*I.height,g-s*I.width/2-C*I.height/2,Y-C*I.width/2+s*I.height/2),`/Im${I.imageId} Do`,"Q")}return{stream:E.join("\n"),unicode:s}}(A,s),Q=Math.max(0,...Object.keys(HA).map(Number)),C=Array.from({length:Q+1},(A,B)=>Math.round(1e3*(HA[B]||1024)/hA)),g=[],I=A=>(g.push("string"==typeof A?KA(A):A),g.length),Y=I(""),R=I(""),M=I(""),F=I(dA(`/Length1 ${B.length}`,B)),i=I(`<< /Type /FontDescriptor /FontName /Roboto /Flags 32 /FontBBox [${jA.join(" ")}] /ItalicAngle 0 /Ascent 2146 /Descent -555 /CapHeight 2146 /StemV 80 /FontFile2 ${F} 0 R >>`),x=I(`<< /Type /Font /Subtype /CIDFontType2 /BaseFont /Roboto /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor ${i} 0 R /W [0 [${C.join(" ")}]] /CIDToGIDMap /Identity >>`),b=KA(function(A){const B=[...A].sort((A,B)=>A[0]-B[0]),E=B.map(([A,B])=>`<${A.toString(16).padStart(4,"0")}> <${B<=65535?B.toString(16).padStart(4,"0"):(()=>{const A=B-65536;return(55296+(A>>10)).toString(16).padStart(4,"0")+(56320+(1023&A)).toString(16).padStart(4,"0")})()}>`);return`/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def\n/CMapName /HousePlanUnicode def\n/CMapType 2 def\n1 begincodespacerange\n<0000> \nendcodespacerange\n${B.length} beginbfchar\n${E.join("\n")}\nendbfchar\nendcmap\nCMapName currentdict /CMap defineresource pop\nend\nend`}(w.unicode)),L=I(dA("",b)),D=I(`<< /Type /Font /Subtype /Type0 /BaseFont /Roboto /Encoding /Identity-H /DescendantFonts [${x} 0 R] /ToUnicode ${L} 0 R >>`),G=I(dA("",KA(w.stream))),o=[];for(const B of A.images||[]){const A=I(dA(`/Type /XObject /Subtype /Image /Width ${B.width} /Height ${B.height} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode`,B.bytes));o.push(`/Im${B.id} ${A} 0 R`)}const t=A.now.toISOString().replace(/[-:T]/g,"").slice(0,14),c=I(`<< /CreationDate (D:${t}Z) /ModDate (D:${t}Z) >>`),W=`<< /Font << /F1 ${D} 0 R >>`+(o.length?` /XObject << ${o.join(" ")} >>`:"")+(E.length?` /ExtGState << ${E.map(A=>`/${s.get(A)} << /ca ${VA(A)} /CA ${VA(A)} >>`).join(" ")} >>`:"")+" >>";g[Y-1]=KA(`<< /Type /Catalog /Pages ${R} 0 R >>`),g[R-1]=KA(`<< /Type /Pages /Kids [${M} 0 R] /Count 1 >>`),g[M-1]=KA(`<< /Type /Page /Parent ${R} 0 R /MediaBox [0 0 ${VA(A.width)} ${VA(A.height)}] /Resources ${W} /Contents ${G} 0 R >>`);const m=KA("%PDF-1.4\n%âãÏÓ\n"),n=[m],e=[0];let h=m.length;g.forEach((A,B)=>{const E=KA(`${B+1} 0 obj\n`),s=KA("\nendobj\n");e.push(h),n.push(E,A,s),h+=E.length+A.length+s.length});const S=h,j=["xref",`0 ${g.length+1}`,"0000000000 65535 f "];for(let A=1;A<=g.length;A++)j.push(`${String(e[A]).padStart(10,"0")} 00000 n `);return j.push(`trailer\n<< /Size ${g.length+1} /Root ${Y} 0 R /Info ${c} 0 R >>`,`startxref\n${S}\n%%EOF\n`),n.push(KA(j.join("\n"))),NA(n)}const ZA=A=>[A.minX,A.minY,A.maxX,A.maxY].every(Number.isFinite)&&A.maxX>=A.minX&&A.maxY>=A.minY,TA=A=>A.maxX-A.minX,fA=A=>A.maxY-A.minY;function kA(A,B,E,s=0){Number.isFinite(B)&&Number.isFinite(E)&&(A.minX=Math.min(A.minX,B-s),A.minY=Math.min(A.minY,E-s),A.maxX=Math.max(A.maxX,B+s),A.maxY=Math.max(A.maxY,E+s))}function zA(A,B,E,s,w,Q){const C=Q*Math.PI/180,g=Math.cos(C),I=Math.sin(C),Y=B+s/2,R=E+w/2;for(const[B,E]of[[-s/2,-w/2],[s/2,-w/2],[s/2,w/2],[-s/2,w/2]])kA(A,Y+g*B-I*E,R+I*B+g*E)}function pA(A,B,E){for(const s of B)"M"===s.op||"L"===s.op?kA(A,s.x,s.y,E):"C"===s.op&&(kA(A,s.x1,s.y1,E),kA(A,s.x2,s.y2,E),kA(A,s.x,s.y,E))}function XA(A){const B={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};for(const E of A)if("path"===E.kind){const A=E.stroke?(E.width||.5)/2:0;for(const s of E.rings)for(const[E,w]of s)kA(B,E,w,A)}else if("line"===E.kind)for(const[A,s]of E.points)kA(B,A,s,E.width/2);else if("vector"===E.kind)pA(B,E.ops,E.width/2);else if("text"===E.kind){const A=uA(E);kA(B,A.minX,A.minY),kA(B,A.maxX,A.maxY)}else zA(B,E.x,E.y,E.width,E.height,E.angle||0);return B}function OA(A,B,E){return!!ZA(A)&&(TA(A)<=TA(B)+E&&fA(A)<=fA(B)+E)}function qA(A){return`${A.getFullYear()}-${String(A.getMonth()+1).padStart(2,"0")}-${String(A.getDate()).padStart(2,"0")}`}const $A=72/25.4,_A=5.25,AB=[.08,.08,.08],BB=[127/255,127/255,127/255],EB=[.72,.72,.72],sB=(A,B)=>A.minXB.minX&&A.minYB.minY;function wB(A,B,E,s,w=0,Q="left"){return uA({x:A,y:B,text:E,size:s,angle:w,align:Q})}function QB(A,B,E,s,w){const Q=Math.min(...[[A.minX,A.minY],[A.maxX,A.minY],[A.maxX,A.maxY],[A.minX,A.maxY]].map(([A,w])=>(A-B)*s[0]+(w-E)*s[1]));return Math.max(0,w-Q)}const CB=(A,B)=>`${A.axis}:${B[0]<-.5||B[1]<-.5?-1:1}`,gB=(A,B)=>{A.minX=Math.min(A.minX,B[0]),A.minY=Math.min(A.minY,B[1]),A.maxX=Math.max(A.maxX,B[0]),A.maxY=Math.max(A.maxY,B[1])},IB=A=>{const B={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};for(const E of A)for(const A of E)gB(B,A);return B};function YB(A,B,E,s,w=0){const Q=w*Math.PI/180,C=Math.cos(Q),g=Math.sin(Q),I=A+E/2,Y=B+s/2;return Array.from({length:48},(A,B)=>{const w=B/48*Math.PI*2,Q=Math.cos(w)*E/2,R=Math.sin(w)*s/2;return[I+C*Q-g*R,Y+g*Q+C*R]})}function RB(A,B,E,s,w=0){const Q=w*Math.PI/180,C=Math.cos(Q),g=Math.sin(Q),I=A+E/2,Y=B+s/2;return[[-E/2,-s/2],[E/2,-s/2],[E/2,s/2],[-E/2,s/2]].map(([A,B])=>[I+C*A-g*B,Y+g*A+C*B])}function MB(A,B,E){if("passage"===A.type)return[];const s=A.rlen/2,w=B>0?B/E*Y/2:2,Q=[];if("window"===A.type)Q.push([[-s,-w],[s,-w]],[[-s,w],[s,w]],[[-s,-w],[-s,w]],[[s,-w],[s,w]]);else if("gate"===A.type){const B=10*(A.flip_v?-1:1)*Math.PI/180,E=[[[-s,0],[-s+Math.cos(B)*s,Math.sin(B)*s]],[[s,0],[s-Math.cos(B)*s,Math.sin(-B)*s]]];Q.push(...E);for(const A of E){const B=A[1][0]-A[0][0],E=A[1][1]-A[0][1],s=Math.hypot(B,E)||1,C=-E/s,g=B/s,I=Math.min(.08*s,Math.max(1,.7*w));for(const s of[.3,.5,.7]){const w=A[0][0]+B*s,Y=A[0][1]+E*s;Q.push([[w-C*I,Y-g*I],[w+C*I,Y+g*I]])}}}else{const B=A.flip_v?1:-1,E=A.flip_h?s:-s,w=[E,B*A.rlen];Q.push([[E,0],w]);const C=[];for(let s=0;s<=16;s++){const w=B*s/16*Math.PI/2,Q=A.flip_h?-1:1;C.push([E+Q*Math.cos(w)*A.rlen,Math.sin(w)*A.rlen])}Q.push(C)}const C=A.angle*Math.PI/180,g=Math.cos(C),I=Math.sin(C);return Q.map(B=>B.map(([B,E])=>[A.rx+B*g-E*I,A.ry+B*I+E*g]))}function FB(A,B){const E=IB([A]);return B.filter(A=>{const B=IB([A]);return B.maxX>=E.minX&&B.minX<=E.maxX&&B.maxY>=E.minY&&B.minY<=E.maxY})}function iB(A){const B=function(A){const{rawSpace:B,space:E}=A,s=Number(B.cell_cm)>0?Number(B.cell_cm):5,w=Array.isArray(B.walls)?B.walls:[],Q=c(B,E,I,.02*Y),C=W(B,E,s,Y,I),g=m(C),M=n(E,s,Y,2e-4*Y,g).all,F=e(C,E,w,Q.contour,R,s,Y,I);return{cellCm:s,walls:w,zero:Q,openings:C,extras:M,geometry:A.sharedWallGeometry||h(E.rooms,w,Q.contour,F,R,s,Y,I,M)}}(A),E=new Map;if(A.options.dimensions)for(const s of A.space.rooms){const w=C(s);if(!w)continue;const Q=s.id?A.resolveInnerContour?.(s.id):void 0;E.set(s,s.id&&(void 0===Q?g(A.space.rooms,s.id,B.walls,B.zero.contour,R,B.cellCm,Y,I,B.geometry.roomGeom,B.geometry.multiWallNodes):Q)||w)}const s=new Map;if(A.options.dimensions)for(const w of A.space.rooms){const Q=C(w);if(!Q)continue;const g=E.get(w)||Q,I=w.id?A.resolveRoomArea?.(w.id,g):void 0,Y=Number.isFinite(I)?[]:FB(g,B.extras),R=Y.length?M(g,Y):null,i=Number.isFinite(I)&&I>=0?I:R?F(R):Math.abs(g.reduce((A,B,E)=>{const s=g[(E+1)%g.length];return A+B[0]*s[1]-s[0]*B[1]},0)/2);s.set(w,i)}const w=[..."failed-core"===B.geometry.status?A.space.rooms.map(A=>C(A)||[]).filter(A=>A.length):B.geometry.components.flatMap(A=>i(A.geom)),...B.zero.lines.map(A=>[[A[0],A[1]],[A[2],A[3]]])];A.options.decor&&w.push(...function(A){const B=[];for(const E of A.decor||[])"line"===E.kind?B.push([[E.x1*I,E.y1*I],[E.x2*I,E.y2*I]]):"text"!==E.kind?B.push(L(E).map(([A,B])=>[A*I,B*I])):B.push([[E.x*I,E.y*I]]);return B}(A.rawSpace));for(const B of A.rasters||[])w.push(RB(B.x,B.y,B.drawWidth,B.drawHeight,B.angle));let Q=IB(w);var x;[(x=Q).minX,x.minY,x.maxX,x.maxY].every(Number.isFinite)&&x.maxX>x.minX&&x.maxY>x.minY||(Q={minX:0,minY:0,maxX:I,maxY:I});return{built:B,dimensionContours:E,roomAreas:s,bounds:Q,cmPerUnit:B.cellCm/Y}}function xB(A,B,E,s){const{built:w,dimensionContours:Q,roomAreas:g,bounds:M,cmPerUnit:F}=B,c=(s?297:210)*$A,W=(s?210:297)*$A,m=12*$A,n=18*$A,e=24*$A,h=F*(10*$A)/E,j=(M.maxX-M.minX)*h,H=(M.maxY-M.minY)*h,v=m+n,V=W-v-m-e,U=c-2*m,a=A=>[0+(A[0]-M.minX)*h,0+(A[1]-M.minY)*h],P=(A,B)=>[M.minX+(A-0)/h,M.minY+(B-0)/h],y=A=>{const B=P(A.minX,A.minY),E=P(A.maxX,A.maxY);return{minX:B[0],minY:B[1],maxX:E[0],maxY:E[1]}},u=w.geometry.components.flatMap(A=>i(A.geom)),N=A=>w.geometry.components.some(B=>S([...A],B.geom)),K=A=>function(A,B,E){if(!LA(A)||!mA(B))return!0;const s=DA(A);return!!s.some(E)||!!B.some(B=>B.some(B=>xA(B)&&bA(B,A)))||nA(B,(A,B)=>s.some((E,w)=>null!==WA(A,B,E,s[(w+1)%s.length])))}(y(function(A,B){const E=Number.isFinite(B)&&B>=0?B:0;return{minX:A.minX-E,minY:A.minY-E,maxX:A.maxX+E,maxY:A.maxY+E}}(A,$A-1e-6)),u,N),d=(A,B)=>function(A,B,E){if(!LA(A)||!mA([B]))return!1;const s=DA(A);return!!s.every(E)&&!nA([B],(A,B)=>s.some((E,w)=>null!==WA(A,B,E,s[(w+1)%s.length])))}(y(A),B,A=>Z([...A],B)),J=(A,B,E={})=>function(A,B,E,s,w={}){if(!xA(A)||!xA(B)||!mA(E))return!0;if(w.allowStartExit){const w=tA(A,B);if(w<=iA)return!0;const Q=nA(E,(B,E)=>cA(A,B,E));if(!Q)return!0;const C=[];nA(E,(E,s)=>{const w=WA(A,B,E,s);return w&&C.push(w),!1});const g=iA/w,I=[0,1,...C.flatMap(A=>[A.t,A.endT])].sort((A,B)=>A-B).filter((A,B,E)=>0===B||A-E[B-1]>g),Y=E=>[A[0]+(B[0]-A[0])*E,A[1]+(B[1]-A[1])*E],R=A=>C.some(B=>B.overlap&&A>B.t+g&&AA.t>M+g||A.endT>M+g)}const Q=[(A[0]+B[0])/2,(A[1]+B[1])/2],C=nA(E,(B,E)=>cA(A,B,E));return!((!s(A)||w.allowStartBoundary&&C)&&!s(Q)&&!s(B))||nA(E,(E,s)=>{const Q=WA(A,B,E,s);return!!Q&&(Q.overlap||!w.allowStartBoundary||!C||Q.t*tA(A,B)>iA)})}(P(A[0],A[1]),P(B[0],B[1]),u,N,E),T=(A,B,E)=>{const s=A.x*I,w=A.y*I,Q=A.w*I,C=A.h*I,g=s+Q/2,Y=w+C/2,R=s+(A.flip_h?Q:0),F=w+(A.flip_v?C:0),i=(A.flip_h?-1:1)*Q/B,x=(A.flip_v?-1:1)*C/E,b=(Number(A.angle)||0)*Math.PI/180,L=Math.cos(b),D=Math.sin(b),G=Y+D*(R-g)+L*(F-Y);return{a:h*L*i,b:h*D*i,c:-h*D*x,d:h*L*x,e:0+(g+L*(R-g)-D*(F-Y)-M.minX)*h,f:0+(G-M.minY)*h}};let f=[];const z=[],O=function(A,B){const E=3*$A*Math.SQRT2,s=[];for(let w=-B;w<=A+E;w+=E)s.push([[w,0],[w+B,B]]);return s}(c,W);for(const B of A.rasters||[])f.push({kind:"image",imageId:B.id,...a([B.x,B.y]).reduce((A,B,E)=>({...A,[E?"y":"x"]:B}),{}),width:B.drawWidth*h,height:B.drawHeight*h,angle:B.angle,opacity:B.opacity});for(const A of w.geometry.components)f.push({kind:"path",rings:i(A.geom).map(A=>A.map(a)),fill:BB,stroke:AB,width:.25*$A,hatch:{lines:O,stroke:AB,width:.18*$A}});if("failed-core"===w.geometry.status)for(const B of A.space.rooms){const A=C(B);A&&f.push({kind:"path",rings:[A.map(a)],stroke:AB,width:.25*$A})}for(const A of w.zero.lines)f.push({kind:"line",points:[a([A[0],A[1]]),a([A[2],A[3]])],stroke:AB,width:.35*$A,dash:[3*$A,2*$A]});const q=w.geometry.openingIndex;for(const B of w.openings){const E=B.partitionHost?{cm:B.partitionHost.partition.cm}:q?x(A.space.rooms,B,w.walls,R,w.cellCm,Y,I,w.zero.contour):{cm:0};for(const A of MB(B,E.cm,w.cellCm))f.push({kind:"line",points:A.map(a),stroke:AB,width:.3*$A})}if(A.options.decor)for(const B of A.rawSpace.decor||[])if("image"!==B.kind)if("line"===B.kind)f.push({kind:"line",points:[a([B.x1*I,B.y1*I]),a([B.x2*I,B.y2*I])],stroke:AB,width:Math.max(.2*$A,10*Number(B.width_cm||1)*$A/E),dash:"dashed"===B.line_style?[3*$A,2*$A]:void 0});else if("text"===B.kind)f.push({kind:"text",...(()=>{const[A,E]=a([B.x*I,B.y*I]);return{x:A,y:E}})(),text:B.text,size:Math.max(6,10*Number(B.size_cm||20)*$A/E),angle:Number(B.angle)||0});else if("furniture"===B.kind){const A=r[B.symbol];A?f.push({kind:"vector",ops:YA(A.d,T(B,A.viewW,A.viewH)),stroke:AB,width:Math.max(.2*$A,10*b(B,w.cellCm,Y)*$A/E)}):f.push({kind:"path",rings:[L(B).map(([A,B])=>a([A*I,B*I]))],stroke:AB,width:.25*$A})}else{const A="ellipse"===B.kind?YB(B.x*I,B.y*I,B.w*I,B.h*I,Number(B.angle)||0):L(B).map(([A,B])=>[A*I,B*I]);f.push({kind:"path",rings:[A.map(a)],stroke:AB,width:.25*$A})}if(A.options.dimensions&&w.geometry.roomGeom)for(const[B,E]of D(w.geometry.roomGeom).entries()){const s=l(F),w=(A,B,E)=>{const s=a(A.sourceA),w=a(A.sourceB),Q=a(A.a),C=a(A.b),g=(6+E)*$A,I=[Q[0]+B[0]*g,Q[1]+B[1]*g],Y=[C[0]+B[0]*g,C[1]+B[1]*g],R=[(I[0]+Y[0])/2,(I[1]+Y[1])/2],M=PA(A.text,7)+2*$A>Math.hypot(Y[0]-I[0],Y[1]-I[1]),F=QB(wB(R[0],R[1],A.text,7,A.angle,"center"),R[0],R[1],B,$A),i=[R[0]+B[0]*F,R[1]+B[1]*F];return{edge:A,a:s,b:w,oa:I,ob:Y,middle:R,label:i,box:wB(i[0],i[1],A.text,7,A.angle,"center"),needsShelf:M}},Q=A=>{const B=[{start:A.oa,end:A.ob},{start:A.a,end:A.oa,allowStartExit:!0},{start:A.b,end:A.ob,allowStartExit:!0}];return A.needsShelf&&B.push({start:A.middle,end:A.label,mayEnterOwnLabel:!0}),B},C=A=>K(A.box)||Q(A).some(A=>J(A.start,A.end,{allowStartBoundary:A.allowStartBoundary,allowStartExit:A.allowStartExit})),g=EA(k(E,F,A.imperial,{ringIndex:B,epsilon:s}),{ring:E,epsilon:s,score:A=>{const B=[-A.inwardNormal[0],-A.inwardNormal[1]],E=a(A.mid),s=Array.from({length:21},(A,B)=>4*B).find(E=>!C(w(A,B,E))),Q=E[0]+(U-j)/2,g=E[1]+(V-H)/2;return{hardCollisions:void 0===s?21:s/4,normalClearance:Math.abs(B[0])>.5?B[0]>0?U-Q:Q:B[1]>0?V-g:g}}});for(const A of X(g,s)){const B=A.map(A=>({edge:A,outward:[-A.inwardNormal[0],-A.inwardNormal[1]]})),E=A=>B.map(({edge:B,outward:E})=>w(B,E,A));let s=null;for(let A=0;A<=80&&!s;A+=4){const B=E(A),w=B.some((A,E)=>B.slice(0,E).some(B=>sB(A.box,B.box))),g=B.some(A=>C(A)||z.some(B=>sB(A.box,B))),I=B.some((A,E)=>Q(A).some(A=>z.some(B=>eA(A.start,A.end,B))||B.some((B,s)=>(!A.mayEnterOwnLabel||s!==E)&&eA(A.start,A.end,B.box))));w||g||I||(s=B)}if(s)for(const A of s)f.push({kind:"line",points:[A.oa,A.ob],stroke:AB,width:.2*$A},{kind:"line",points:[A.a,A.oa],stroke:AB,width:.15*$A},{kind:"line",points:[A.b,A.ob],stroke:AB,width:.15*$A}),A.needsShelf&&f.push({kind:"line",points:[A.middle,A.label],stroke:AB,width:.15*$A}),f.push({kind:"text",x:A.label[0],y:A.label[1],text:A.edge.text,size:_A,angle:A.edge.angle,align:"center"}),z.push(A.box)}}const $=[...A.space.rooms].sort((A,B)=>String(A.id||"").localeCompare(String(B.id||"")));for(const[B,E]of $.entries()){const s=C(E);if(!s)continue;const w=Q.get(E)||s,I=g.get(E)||0,Y=G(E,A.space.id,A.layout,A.config),[R,M]=a([Y.x,Y.y]),i=w.map(a),x=IB([i]);let b=!1;if(A.options.roomNames&&E.name){const A=Math.max(0,x.maxX-x.minX-4*$A),B=PA(E.name,6.75)<=A?6.75:PA(E.name,5.25)<=A?5.25:0;B&&(f.push({kind:"text",x:R,y:M-2,text:E.name,size:B,align:"center"}),z.push(wB(R,M-2,E.name,B,0,"center")),b=!0)}if(A.options.dimensions){const B=o(I*F*F/1e4,A.imperial),E=M+(b?8:0);f.push({kind:"text",x:R,y:E,text:B,size:6,align:"center"}),z.push(wB(R,E,B,8,0,"center"))}if(A.options.dimensions){const E=l(F),s=EA(p(w,F,A.imperial,{ringIndex:B,epsilon:E}),{ring:w,epsilon:E,score:A=>{const B=a(A.mid),E=QB(wB(B[0],B[1],A.text,_A,A.angle,"center"),B[0],B[1],A.inwardNormal,$A),s=wB(B[0]+A.inwardNormal[0]*E,B[1]+A.inwardNormal[1]*E,A.text,7,A.angle,"center"),w="horizontal"===A.axis?A.inwardNormal[1]>0?x.maxY-B[1]:B[1]-x.minY:A.inwardNormal[0]>0?x.maxX-B[0]:B[0]-x.minX;return{hardCollisions:Number(K(s))+z.reduce((A,B)=>A+Number(sB(s,B)),0),normalClearance:w}}});for(const A of s.filter(A=>A.short)){const B=A.inwardNormal,E=a(A.a),s=a(A.b),w=(E[0]+s[0])/2,Q=(E[1]+s[1])/2;f.push({kind:"line",points:[[w-1.5*B[0]*$A,Q-1.5*B[1]*$A],[w+1.5*B[0]*$A,Q+1.5*B[1]*$A]],stroke:AB,width:.2*$A})}const Q=new Map;for(const A of s.filter(A=>!A.short)){const B=CB(A,A.inwardNormal),E=Q.get(B)||[];E.push(A),Q.set(B,E)}for(const A of Q.values()){let B=null;for(let E=0;E<=30&&!B;E+=3){const s=A.map(A=>{const B=a(A.mid),s=QB(wB(B[0],B[1],A.text,_A,A.angle,"center"),B[0],B[1],A.inwardNormal,(1+E)*$A),w=B[0]+A.inwardNormal[0]*s,Q=B[1]+A.inwardNormal[1]*s;return{edge:A,x:w,y:Q,box:wB(w,Q,A.text,_A,A.angle,"center")}}),Q=s.some((A,B)=>s.slice(0,B).some(B=>sB(A.box,B.box))),C=s.some(A=>K(A.box)||z.some(B=>sB(A.box,B))),g=s.every(A=>d(A.box,w));Q||C||!g||(B=s)}if(B)for(const A of B)f.push({kind:"text",x:A.x,y:A.y,text:A.edge.text,size:_A,angle:A.edge.angle,align:"center"}),z.push(A.box)}}}const _={minX:m,minY:v,maxX:c-m,maxY:v+V},AA=XA(f),BA=OA(AA,{minX:0,minY:0,maxX:U,maxY:V},.5*$A),sA=function(A,B){const E=XA(A);if(!ZA(E))return{commands:[...A],bounds:E,dx:0,dy:0};const s=(B.minX+B.maxX-E.minX-E.maxX)/2,w=(B.minY+B.maxY-E.minY-E.maxY)/2,Q=function(A,B,E){return A.map(A=>"path"===A.kind?{...A,rings:A.rings.map(A=>A.map(([A,s])=>[A+B,s+E]))}:"line"===A.kind?{...A,points:A.points.map(([A,s])=>[A+B,s+E])}:"vector"===A.kind?{...A,ops:A.ops.map(A=>((A,B,E)=>"M"===A.op||"L"===A.op?{...A,x:A.x+B,y:A.y+E}:"C"===A.op?{...A,x1:A.x1+B,y1:A.y1+E,x2:A.x2+B,y2:A.y2+E,x:A.x+B,y:A.y+E}:A)(A,B,E))}:{...A,x:A.x+B,y:A.y+E})}(A,s,w);return{commands:Q,bounds:{minX:E.minX+s,minY:E.minY+w,maxX:E.maxX+s,maxY:E.maxY+w},dx:s,dy:w}}(f,_);f=sA.commands,f.push({kind:"text",x:m,y:m+10,text:A.space.title,size:14}),A.cardTitle&&f.push({kind:"text",x:c-m,y:m+10,text:A.cardTitle,size:10,align:"right"});const wA=W-m-13*$A;f.push({kind:"line",points:[[m,wA-4*$A],[c-m,wA-4*$A]],stroke:EB,width:.2*$A}),f.push({kind:"text",x:m,y:wA,text:A.t("pdf.scale",{n:E}),size:8});const QA=10*(A.imperial?152.4:100)*$A/E,CA=wA+8;f.push({kind:"line",points:[[m,CA],[m+QA,CA]],stroke:AB,width:.4*$A});for(let A=0;A<=4;A++){const B=m+QA*A/4;f.push({kind:"line",points:[[B,CA-2],[B,CA+2]],stroke:AB,width:.25*$A})}f.push({kind:"text",x:m+QA/2,y:wA+17,text:A.imperial?"5 ft":"1 m",size:7,align:"center"});const gA=t(A.config.settings,A.rawSpace.settings||{});if(null!==gA){const B=c/2,E=wA+5.5*$A;f.push({kind:"vector",ops:FA({centerX:B,centerY:E,size:11*$A,northDeg:gA}),fill:AB,width:0,fillRule:"evenodd"}),f.push({kind:"text",x:B,y:wA,text:A.t("pdf.north"),size:7,align:"center"})}f.push({kind:"text",x:c-m,y:wA+12,text:`${qA(A.now)} · House Plan v${A.version}`,size:7,align:"right"});const IA={width:c,height:W,commands:f,images:(A.rasters||[]).map(({id:A,bytes:B,width:E,height:s})=>({id:A,bytes:B,width:E,height:s})),now:A.now,scale:E,sceneBounds:sA.bounds,planField:_},RA=Math.max(0,TA(AA))*Math.max(0,fA(AA)),MA=U*V;return{page:IA,sceneBounds:sA.bounds,field:_,fits:BA,fillRatio:MA>0?RA/MA:0,landscape:s}}function bB(A,B){return A.fillRatio!==B.fillRatio?A.fillRatio>B.fillRatio?A:B:A.landscape?B:A}function LB(A,B,E){const s=12*$A,w=(E?297:210)*$A-2*s,Q=(E?210:297)*$A-2*s-18*$A-24*$A,C=A.cmPerUnit*(10*$A)/B;return(A.bounds.maxX-A.bounds.minX)*C<=w+.5*$A&&(A.bounds.maxY-A.bounds.minY)*C<=Q+.5*$A}function DB(A){let B=0;for(const E of A)if(B+=Math.max(0,Number(E)||0),B>26214400)throw new Error("pdf.too_large")}const GB="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";async function oB(A,B){if(!A)throw new Error("pdf.asset_failed");const E=await fetch(A,{credentials:"same-origin"});if(!E.ok)throw new Error("pdf.asset_failed");const s=await E.blob();let w;try{w=await createImageBitmap(s)}catch{throw new Error("pdf.asset_failed")}try{if("image/jpeg"===s.type)return{id:B,bytes:new Uint8Array(await s.arrayBuffer()),width:w.width,height:w.height};const A=document.createElement("canvas");A.width=w.width,A.height=w.height;const E=A.getContext("2d");if(!E)throw new Error("pdf.asset_failed");E.fillStyle="#fff",E.fillRect(0,0,A.width,A.height),E.drawImage(w,0,0);const Q=await new Promise(B=>A.toBlob(B,"image/jpeg",.85));if(!Q)throw new Error("pdf.asset_failed");return{id:B,bytes:new Uint8Array(await Q.arrayBuffer()),width:w.width,height:w.height}}finally{w.close()}}async function tB(A,B,E){const s=await async function(A,B){const E=[];if(B.backdrop&&A.space.bg){const B=await oB(A.backdropUrl,"backdrop");E.push({...B,x:A.space.bg.x,y:A.space.bg.y,drawWidth:A.space.bg.w,drawHeight:A.space.bg.h,angle:A.space.bg.angle,opacity:.6})}if(B.decor){let B=0;for(const s of A.rawSpace.decor||[]){if("image"!==s.kind)continue;const w=A.decorAssets.get(s.asset_id),Q=j(s,I,I);if(!w||!Q)throw new Error("pdf.asset_failed");const C=await oB(w.url,"decor"+B++);E.push({...C,x:Q[0],y:Q[1],drawWidth:Q[2],drawHeight:Q[3],opacity:Q[4],angle:Number(s.angle)||0})}}return DB(E.map(A=>A.bytes.byteLength)),E}(A,B),w=JA(function(A){const B=iB(A);let E=[];for(const s of wA){const w=[!1,!0].filter(A=>LB(B,s,A)).map(E=>xB(A,B,s,E));if(!w.length)continue;const Q=w.filter(A=>A.fits);if(Q.length)return Q.reduce(bB).page;E=w}E.length||(E=[!1,!0].map(E=>xB(A,B,500,E)));const s=E.filter(A=>A.fits);if(s.length)return s.reduce(bB).page;const w=Math.min(...E.map(A=>Math.max(TA(A.sceneBounds)/TA(A.field),fA(A.sceneBounds)/fA(A.field)))),Q=50,C=1e6,g=Number.isFinite(w)?Math.ceil(Math.min(C,500*Math.max(1,w))/Q)*Q:C;let I=500,Y=0,R=[],M=Math.max(550,g);for(;M<=C;){const E=[!1,!0].map(E=>xB(A,B,M,E)).filter(A=>A.fits);if(E.length){Y=M,R=E;break}if(I=M,M===C)break;M=Math.min(C,Math.ceil(2*M/Q)*Q)}if(!Y)throw new Error("pdf.failed");let F=Math.floor(I/Q),i=Math.floor(Y/Q);for(;i-F>1;){const E=Math.floor((F+i)/2),s=[!1,!0].map(s=>xB(A,B,E*Q,s)).filter(A=>A.fits);s.length?(i=E,R=s):F=E}const x=R.reduce(bB).page;if(!OA(x.sceneBounds,x.planField,.5*$A))throw new Error("pdf.failed");return x}({...A,options:B,now:E,rasters:s,t:A.t})),Q=new Blob([w],{type:"application/pdf"}),C=URL.createObjectURL(Q);try{const B=document.createElement("a");B.href=C,B.download=`houseplan-${g=A.space.title,g.normalize("NFKD").replace(/[^\p{L}\p{N}]+/gu,"-").replace(/^-|-$/g,"").toLowerCase()||"space"}-${qA(E)}.pdf`,B.style.display="none",document.body.append(B),B.click(),B.remove()}finally{setTimeout(()=>URL.revokeObjectURL(C),0)}var g;return w}class cB{assertRasterBudget(A){DB(A)}render(A){let B;return B={...A,save:async E=>{await tB(A,E,B.now||new Date)}},s``}}export{GB as PDF_EXPORT_FINGERPRINT,cB as PdfExportRuntime,tB as exportSpacePdf}; diff --git a/custom_components/houseplan/frontend/houseplan-assets/summary-panel-editor-1TWzLmMH.js b/dist/houseplan-assets/summary-panel-editor-CNT_mev4.js similarity index 75% rename from custom_components/houseplan/frontend/houseplan-assets/summary-panel-editor-1TWzLmMH.js rename to dist/houseplan-assets/summary-panel-editor-CNT_mev4.js index b83329e7..842d4c9d 100644 --- a/custom_components/houseplan/frontend/houseplan-assets/summary-panel-editor-1TWzLmMH.js +++ b/dist/houseplan-assets/summary-panel-editor-CNT_mev4.js @@ -1,4 +1,4 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{c as a,A as e}from"./houseplan-card-BWAph8ZF.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-BGIJeXIz.js";import"./form-kit.styles-DcvCvE8g.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`
    `}renderDialog(){return this.dialog&&this.editorRenderer?(this.dialog.localOnly||this.refreshEntityIndex(),this.editorRenderer({host:this.host,dialog:this.dialog,local:this.local,storageUnavailable:this.storageUnavailable,problems:this.problems(this.dialog),entityIndex:this.entityIndex||F({},null),setDialog:e=>{this.dialog=e,this.host.requestUpdate()},saveLocal:e=>this.saveLocal(e),mutate:e=>this.mutate(e),deleteBlock:e=>{this.deleteBlock(e)},dragStart:(e,t)=>this.dragStart(e,t),drop:(e,t)=>this.drop(e,t),sourceToken:e=>this.sourceToken(e),openSource:(e,t)=>this.openSource(e,t),closeSource:e=>this.closeSource(e),setSource:(e,t,s)=>this.setSource(e,t,s),save:()=>{this.saveDialog()},reload:()=>{this.reloadDialog()},close:()=>this.closeDialogIfIdle(),t:e=>this.t(e)})):t}t(e){return e.startsWith("summary.")?function(e,t){const s=e.toLowerCase().split("-")[0];return(q[s]||q.en)[t]||q.en[t]||t}(r(this.host.hass,this.host._config?.language),e):this.host._t(e)}ensureStyle(){const e=this.host.renderRoot;if(this.styleSheet&&e.adoptedStyleSheets.includes(this.styleSheet))return;const t=this.host.ownerDocument.defaultView?.CSSStyleSheet;if(t&&"adoptedStyleSheets"in e){const s=new t;return s.replaceSync(R),this.styleSheet=s,void(e.adoptedStyleSheets=[...e.adoptedStyleSheets,s])}if(e.querySelector("style[data-hp-summary]"))return;const s=this.host.ownerDocument.createElement("style");s.dataset.hpSummary="true",s.textContent=R,e.insertBefore(s,e.firstChild)}ensureDialogStyle(){const e=this.host.renderRoot.querySelector('hp-dialog[data-kind="summary"]')?.shadowRoot;if(!e||this.styledDialogRoots.has(e))return;const t=this.host.ownerDocument.defaultView?.CSSStyleSheet;if(t&&"adoptedStyleSheets"in e)this.dialogStyleSheet||(this.dialogStyleSheet=new t,this.dialogStyleSheet.replaceSync(I)),e.adoptedStyleSheets=[...e.adoptedStyleSheets,this.dialogStyleSheet];else{const t=this.host.ownerDocument.createElement("style");t.dataset.hpSummaryShell="true",t.textContent=I,e.appendChild(t)}this.styledDialogRoots.add(e)}placementSlot(){return K(this.host)}preferenceKey(){return function(e){const t=y(e.userId),s=y(e.slot);return t&&s?`houseplan.summary-panel.v1:${[t,y(e.path)||"/",y(e.host)||"card",s].map(e=>encodeURIComponent(e)).join(":")}`:null}({userId:this.host.hass?.user?.id||this.host.hass?.user?.name,path:location.pathname,host:this.host.panelHost?"panel":"lovelace",slot:this.placementSlot()})}identity(){return JSON.stringify({key:this.preferenceKey(),user:this.host.hass?.user?.id||this.host.hass?.user?.name||"",route:location.pathname,host:this.host.panelHost?"panel":"lovelace",slot:this.placementSlot(),kiosk:this.host._kiosk,canManage:this.host._canManageConfiguration})}syncLifecycle(){const e=this.identity();this.lifecycleIdentity&&e!==this.lifecycleIdentity&&this.resetLifecycle(),this.lifecycleIdentity=e}resetLifecycle(){this.presentation.reset(),this.lifecycleGeneration++,this.dialog=null,this.entityIndex=null,this.deviceMemo=null,this.areaMemo=null,this.clockContext="",this.storageKey=null,this.storageUnavailable=!1,this.local={version:1,show:!1,icon_scale:1,font_scale:1},this.clockTimer&&clearTimeout(this.clockTimer),this.clockTimer=0,this.lifecycleIdentity=this.connected?this.identity():"",this.host.requestUpdate()}current(e){return this.connected&&e===this.lifecycleGeneration&&this.lifecycleIdentity===this.identity()}refreshEntityIndex(){this.entityIndex=F(this.host.hass?.states,this.entityIndex)}syncNativeNarrow(){if(this.host.panelHost)return;let e=this.host;for(let t=0;e&&t<12;t++){const t=e.getRootNode();if(e=e.parentNode||(t instanceof ShadowRoot?t.host:null),!e||e===this.host)continue;const s=e.narrow;if("boolean"==typeof s)return void(this.host.narrow!==s&&(this.host.narrow=s))}}loadLocal(){const e=this.preferenceKey();if(!e||e===this.storageKey)return;let t=null,s=null,r=!0;try{t=JSON.parse(localStorage.getItem(e)||"null")}catch{r=!1}try{s=JSON.parse(localStorage.getItem("houseplan_card_kiosk_v1")||"null")}catch{r=!1}this.storageKey=e,this.storageUnavailable=!r,this.local=function(e,t){const s=e&&"object"==typeof e?e:{},r=t&&"object"==typeof t?t:{};return{version:1,show:!0===s.show,icon_scale:M(p(s,"icon_scale")?s.icon_scale:r.icon),font_scale:M(p(s,"font_scale")?s.font_scale:r.font)}}(t,s),this.host._kioskScale={icon:this.local.icon_scale,font:this.local.font_scale}}saveLocal(e){this.local={...this.local,...e,version:1,icon_scale:M(e.icon_scale??this.local.icon_scale),font_scale:M(e.font_scale??this.local.font_scale)},this.host._kioskScale={icon:this.local.icon_scale,font:this.local.font_scale},this.storageKey||=this.preferenceKey();let t=!1;try{this.storageKey&&(localStorage.setItem(this.storageKey,JSON.stringify(this.local)),t=!0)}catch{}this.storageUnavailable=!t,t||this.host._showToast?.(this.t("summary.storage_unavailable")),this.host.requestUpdate()}config(){return function(e,t){const s=e?.summary_panel;return void 0===s?{config:b(t),derived:!0,unsupported:!1}:v(s)?{config:s,derived:!1,unsupported:!1}:{config:null,derived:!1,unsupported:!0}}(this.host._settings,this.translate)}async openDialog(){const e=this.lifecycleGeneration;this.loadLocal();try{this.editorLoad||=import("./summary-panel-editor-1TWzLmMH.js").then(e=>e.renderSummaryPanelEditor),this.editorRenderer=await this.editorLoad}catch(t){if(this.editorLoad=null,!this.current(e))return;return void this.host._showToast?.(`${this.t("summary.load_failed")} ${this.host._errText(t)}`)}if(!this.current(e))return;const t=this.config(),s=t.config||b(this.translate),r=this.host._haSummaryPanelApi!==i,a=t.unsupported?"summary.unsupported_schema":r&&this.host._canManageConfiguration?"summary.backend_required":"summary.local_only";this.dialog={draft:_(s),base:_(s),baseRevision:this.host._cfgRev,localShow:this.local.show,baseLocalShow:this.local.show,localOnly:this.host._kiosk||!this.host._canManageConfiguration||r||t.unsupported,localOnlyHint:a,busy:!1,attempted:!1,entityFilter:"",activeSource:null,error:"",conflict:!1},this.dialog.localOnly||this.refreshEntityIndex(),this.host.requestUpdate()}problems(e=this.dialog){return!e||e.localOnly?[]:k(x(e.draft),e.base,new Set(this.host._model.map(e=>e.id)),new Set(Object.keys(this.host.hass?.states||{})))}mutate(e){if(!this.dialog||this.dialog.busy||this.dialog.localOnly)return;const t=_(this.dialog.draft);e(t);const s=this.dialog.activeSource,r=!s||t.blocks.some(e=>e.id===s.blockId&&e.values.some(e=>e.id===s.valueId));this.dialog={...this.dialog,draft:t,error:"",conflict:!1,activeSource:r?s:null,entityFilter:r?this.dialog.entityFilter:""},this.host.requestUpdate()}async deleteBlock(e){const t=this.dialog?.draft.blocks[e];if(!t)return;const s=this.lifecycleGeneration;if(t.values.length){if(!await this.host._confirmDanger({key:"summary-block",kind:"warning",title:this.t("summary.delete_block_title"),message:this.t("summary.delete_block_body"),objectName:t.title,confirmLabel:this.t("btn.delete"),cancelLabel:this.t("btn.cancel")})||!this.current(s))return}this.mutate(e=>{const s=e.blocks.findIndex(e=>e.id===t.id);s>=0&&e.blocks.splice(s,1)})}sourceToken(e){return"system"===e.type?`system:${e.key}`:`entity:${e.entity_id}`}openSource(e,t){!this.dialog||this.dialog.busy||this.dialog.localOnly||(this.refreshEntityIndex(),this.dialog={...this.dialog,activeSource:{blockId:e,valueId:t},entityFilter:""},this.host.requestUpdate(),this.host.updateComplete.then(()=>{this.dialog?.activeSource?.blockId===e&&this.dialog.activeSource.valueId===t&&this.host.renderRoot.querySelector("[data-summary-picker-search]")?.focus()}))}closeSource(e=!1){const t=this.dialog?.activeSource;this.dialog&&t&&(this.dialog={...this.dialog,activeSource:null,entityFilter:""},this.host.requestUpdate(),e&&this.focusSource(t.blockId,t.valueId))}async focusSource(e,t){await this.host.updateComplete;const s=`${e}\n${t}`,r=this.host.renderRoot.querySelectorAll("[data-summary-source-owner]");[...r].find(e=>e.dataset.summarySourceOwner===s)?.focus()}setSource(e,t,s){this.mutate(r=>{const i=r.blocks.find(t=>t.id===e)?.values.find(e=>e.id===t);if(i)if(s.startsWith("system:")){const e=s.slice(7);(e=>"device_count"===e||"total_area"===e||"datetime"===e)(e)&&(i.source={type:"system",key:e})}else i.source={type:"entity",entity_id:s.startsWith("entity:")?s.slice(7):s}}),this.dialog&&(this.dialog={...this.dialog,activeSource:null,entityFilter:""}),this.host.requestUpdate(),this.focusSource(e,t)}dragStart(e,t){e.dataTransfer?.setData("text/x-houseplan-summary",t),e.dataTransfer&&(e.dataTransfer.effectAllowed="move")}drop(e,t){e.preventDefault(),e.stopPropagation();const s=e.dataTransfer?.getData("text/x-houseplan-summary")||"",r=s.split(":").map(Number),i=t.split(":").map(Number);s.startsWith("block:")&&t.startsWith("block:")?this.mutate(e=>{e.blocks=C(e.blocks,r[1],i[1])}):s.startsWith("value:")&&t.startsWith("value:")&&r[1]===i[1]&&this.mutate(e=>{e.blocks[r[1]].values=C(e.blocks[r[1]].values,r[2],i[2])})}async saveDialog(){const e=this.dialog;if(!e||e.busy)return;const t=this.lifecycleGeneration,s=x(e.draft);if((e.localOnly?[]:k(s,e.base,new Set(this.host._model.map(e=>e.id)),new Set(Object.keys(this.host.hass?.states||{})))).some(e=>"error"===e.kind))return this.dialog={...e,draft:s,attempted:!0},this.host.requestUpdate(),await this.host.updateComplete,void this.host.renderRoot.querySelector('[data-summary-error="true"]')?.focus?.();this.dialog={...e,draft:s,busy:!0,attempted:!1,error:"",conflict:!1},this.host.requestUpdate();try{if(!e.localOnly&&!$(s,e.base)){this.host._writesPending++;const r=a(this.host._writeChain,async()=>{if(!this.current(t))return;if(!this.host._serverCfg)throw new Error(this.t("summary.save_failed"));if(this.host._cfgRev!==e.baseRevision)throw new Error(this.t("summary.conflict"));const r=o({...this.host._serverCfg,settings:{...this.host._serverCfg.settings||{},summary_panel:s}});let i=!1;try{if(await this.host._sendConfigCandidate(r),!this.current(t))return}catch(e){if(!this.current(t))throw e;try{const r=await this.host._getAuthoritativeConfig();if(!this.current(t))throw e;const a=function(e,t){if(!g(e))return null;const s=e.config,r=e.rev;if(!g(s)||!Array.isArray(s.spaces)||"number"!=typeof r||!Number.isSafeInteger(r)||r<0)return null;const i=g(s.settings)?s.settings:null,a=i?.summary_panel;return v(a)&&$(a,t)?{config:s,rev:r}:null}(r,s);if(!a)throw e;const o=await this.host._adoptAuthoritative({cfgResp:r,reason:"summary-recovery",profile:"reload"});if("adopted"!==o.status)throw e;o.spaceChanged&&this.host._restoreZoom(),this.host._regSignature="",this.host._maybeRebuildDevices(),i=!0}catch{throw e}}if(!i){if(!this.current(t))return;this.host._adoption.stageConfigCandidate(r),this.host._cacheSnapshot()}});this.host._writeChain=r,await r.finally(()=>{this.host._writesPending--})}if(!this.current(t))return;this.saveLocal({show:e.localShow}),this.dialog=null}catch(s){if(!this.current(t))return;const r="conflict"===s?.code||this.host._cfgRev!==e.baseRevision;this.dialog={...this.dialog||e,busy:!1,conflict:r,error:r?this.t("summary.conflict"):this.host._errText(s)}}this.current(t)&&this.host.requestUpdate()}async reloadDialog(){const e=this.dialog;if(!e||e.busy)return;const t=this.lifecycleGeneration;this.dialog={...e,busy:!0,error:"",conflict:!1},this.host.requestUpdate();try{if(await this.host._reloadConfigOnly(!0),!this.current(t))return;if(e.conflict&&this.host._cfgRev===e.baseRevision)throw new Error(this.t("summary.load_failed"));const s=this.config().config||b(this.translate);this.dialog={...e,draft:_(s),base:_(s),baseRevision:this.host._cfgRev,busy:!1,attempted:!1,error:"",conflict:!1}}catch(s){if(!this.current(t))return;this.dialog={...e,busy:!1,error:this.host._errText(s),conflict:!0}}this.current(t)&&this.host.requestUpdate()}metricsFresh(){return!!this.deviceMemo&&!!this.areaMemo&&this.deviceMemo.cfgEpoch===this.host._cfgEpoch&&this.deviceMemo.layoutRev===this.host._layoutRev&&this.deviceMemo.registryRev===this.host._haRegistry.revision&&this.areaMemo.cfgEpoch===this.host._cfgEpoch}scheduleMetrics(){if(this.metricsRefresh||!this.metricsModule||this.metricsFresh())return;const e=this.lifecycleGeneration,t="undefined"==typeof window?void 0:window,s=()=>{if(this.metricsRefresh=0,!this.current(e))return;const t=this.advanceMetrics(8);this.host.requestUpdate(),t||this.scheduleMetrics()};this.metricsRefresh=t?.setTimeout(()=>{"function"==typeof t.requestAnimationFrame?t.requestAnimationFrame(()=>t.setTimeout(s,0)):s()},0)||0}advanceMetrics(e=8){const t=this.metricsModule;if(!t)return!0;if(this.computeDeviceCount(),!this.host._serverCfg)return this.areaMemo={cfgEpoch:this.host._cfgEpoch,value:null},!0;if(this.areaMemo&&this.areaMemo.cfgEpoch===this.host._cfgEpoch)return!0;this.areaSteps&&this.areaStepsEpoch===this.host._cfgEpoch||(this.areaSteps=t.cleanFloorAreaSteps(this.host._serverCfg,this.host._model),this.areaStepsEpoch=this.host._cfgEpoch);const s=Date.now();let r=this.areaSteps.next();for(;!r.done&&Date.now()-s[e,t.space])),spaceIds:new Set(this.host._model.map(e=>e.id)),firstSpaceId:this.host._model[0]?.id||"",markers:this.host._markers});this.deviceMemo={cfgEpoch:this.host._cfgEpoch,layoutRev:this.host._layoutRev,registryRev:this.host._haRegistry.revision,value:t?.size??null}}}computeMetrics(){for(;!this.advanceMetrics(Number.POSITIVE_INFINITY););}metrics(){return{deviceCount:this.deviceMemo?this.deviceMemo.value:null,areaM2:this.areaMemo?this.areaMemo.value:null,now:this.clock}}valueState(e){const t=this.metricsModule;if(!t)return{kind:"pending"};if("entity"===e.source.type){const s=t.summaryEntityValue(this.host.hass,e.source.entity_id);return null===s?{kind:"unavailable"}:{kind:"ready",text:s}}const s="device_count"===e.source.key||"total_area"===e.source.key,i="device_count"===e.source.key?this.deviceMemo:this.areaMemo;if(s&&!i)return this.scheduleMetrics(),{kind:"pending"};s&&this.scheduleMetrics();const a=t.summarySystemValue(e.source,this.metrics(),this.host.hass,r(this.host.hass,this.host._config?.language));return null===a?{kind:"unavailable"}:{kind:"ready",text:a}}value(e){const t=this.valueState(e);return"ready"===t.kind?t.text:this.t("summary.unavailable")}ensureMetrics(){if(this.metricsModule||this.metricsLoad)return;const e=this.lifecycleGeneration;this.metricsLoad=import("./summary-panel-metrics-CsJSnPHD.js"),this.metricsLoad.then(t=>{this.metricsModule=t,this.current(e)&&this.host.requestUpdate()}).catch(()=>{}).finally(()=>{this.metricsLoad=null})}layout(){return function(e){const t=Math.max(0,Number(e.width)||0),s=Math.max(0,Number(e.height)||0),r=t>=s?"right":"bottom",i=Math.max(0,e.safeLeft||0)+12,a=Math.max(0,e.safeRight||0)+12,o=Math.max(Math.max(0,e.safeTop||0)+12,e.controlTop||0),n=Math.max(Math.max(0,e.safeBottom||0)+12,e.controlBottom||0),l=Math.max(0,t-i-a),m=Math.max(0,s-o-n),c="bottom"===r?Math.min(.6*s,m):m;return{side:r,fits:t>0&&s>0&&l>=280&&c>=Math.max(0,e.minimumHeight),availableWidth:l,heightCap:c,top:o,bottom:n}}({width:this.stage.width,height:this.stage.height,...this.safeInsets(),controlTop:this.host._kiosk?this.stage.controlTop:0,minimumHeight:this.stage.minimumHeight})}syncPresentation(e=!1){const t=this.config().config,s=this.layout(),r=!!t&&"view"===this.host._mode&&s.fits&&S({view:!0,localShow:!0,showOnMobile:t.show_on_mobile,narrow:this.host.narrow,fits:!0});this.presentation.sync(r&&this.local.show,s.side,e||!r||"hidden"===this.host.ownerDocument.visibilityState)}measureLayout(){const e=this.host._stageEl;if(!e)return;const t=this.host.renderRoot.querySelector(".summary-measure"),s=this.host.renderRoot.querySelector(".summary-control.kiosk"),r=e.getBoundingClientRect(),i=s?.getBoundingClientRect(),a={width:Math.round(e.clientWidth),height:Math.round(e.clientHeight),minimumHeight:Math.max(162,Math.ceil(t?.getBoundingClientRect().height||0)),controlTop:i?Math.max(0,Math.ceil(i.bottom-r.top+12)):0};a.width===this.stage.width&&a.height===this.stage.height&&a.minimumHeight===this.stage.minimumHeight&&a.controlTop===this.stage.controlTop||(this.stage=a,this.host.requestUpdate())}safeInsets(){const e=this.host.renderRoot.querySelector(".summary-safe-probe");if(!e)return{safeLeft:0,safeRight:0,safeTop:0,safeBottom:0};const t=this.host.ownerDocument.defaultView?.getComputedStyle(e);if(!t)return{safeLeft:0,safeRight:0,safeTop:0,safeBottom:0};const s=e=>Number.parseFloat(e)||0;return{safeLeft:s(t.paddingLeft),safeRight:s(t.paddingRight),safeTop:s(t.paddingTop),safeBottom:s(t.paddingBottom)}}hasVisibleClock(){const e=this.config().config;return!("hidden"===this.host.ownerDocument.visibilityState||!e)&&(!!S({view:"view"===this.host._mode,localShow:this.local.show,showOnMobile:e.show_on_mobile,narrow:this.host.narrow,fits:this.layout().fits})&&w(e,this.host._space).some(e=>e.values.some(e=>"system"===e.source.type&&"datetime"===e.source.key)))}syncClock(){const e=`${r(this.host.hass,this.host._config?.language)}\n${this.host.hass?.config?.time_zone||""}`;e!==this.clockContext&&(this.clockContext=e,this.clock=new Date);const t=this.hasVisibleClock();if(t&&!this.clockTimer){this.clock=new Date;const e=()=>{this.clock=new Date,this.clockTimer=0,this.host.requestUpdate(),this.syncClock()};this.clockTimer=window.setTimeout(e,6e4-Date.now()%6e4+25)}else!t&&this.clockTimer&&(clearTimeout(this.clockTimer),this.clockTimer=0)}}});export{A as a,G as b,z as c,D as d,V as e,C as m,x as n,$ as s}; + `}renderDialog(){return this.dialog&&this.editorRenderer?(this.dialog.localOnly||this.refreshEntityIndex(),this.editorRenderer({host:this.host,dialog:this.dialog,local:this.local,storageUnavailable:this.storageUnavailable,problems:this.problems(this.dialog),entityIndex:this.entityIndex||F({},null),setDialog:e=>{this.dialog=e,this.host.requestUpdate()},saveLocal:e=>this.saveLocal(e),mutate:e=>this.mutate(e),deleteBlock:e=>{this.deleteBlock(e)},dragStart:(e,t)=>this.dragStart(e,t),drop:(e,t)=>this.drop(e,t),sourceToken:e=>this.sourceToken(e),openSource:(e,t)=>this.openSource(e,t),closeSource:e=>this.closeSource(e),setSource:(e,t,s)=>this.setSource(e,t,s),save:()=>{this.saveDialog()},reload:()=>{this.reloadDialog()},close:()=>this.closeDialogIfIdle(),t:e=>this.t(e)})):t}t(e){return e.startsWith("summary.")?function(e,t){const s=e.toLowerCase().split("-")[0];return(q[s]||q.en)[t]||q.en[t]||t}(r(this.host.hass,this.host._config?.language),e):this.host._t(e)}ensureStyle(){const e=this.host.renderRoot;if(this.styleSheet&&e.adoptedStyleSheets.includes(this.styleSheet))return;const t=this.host.ownerDocument.defaultView?.CSSStyleSheet;if(t&&"adoptedStyleSheets"in e){const s=new t;return s.replaceSync(R),this.styleSheet=s,void(e.adoptedStyleSheets=[...e.adoptedStyleSheets,s])}if(e.querySelector("style[data-hp-summary]"))return;const s=this.host.ownerDocument.createElement("style");s.dataset.hpSummary="true",s.textContent=R,e.insertBefore(s,e.firstChild)}ensureDialogStyle(){const e=this.host.renderRoot.querySelector('hp-dialog[data-kind="summary"]')?.shadowRoot;if(!e||this.styledDialogRoots.has(e))return;const t=this.host.ownerDocument.defaultView?.CSSStyleSheet;if(t&&"adoptedStyleSheets"in e)this.dialogStyleSheet||(this.dialogStyleSheet=new t,this.dialogStyleSheet.replaceSync(I)),e.adoptedStyleSheets=[...e.adoptedStyleSheets,this.dialogStyleSheet];else{const t=this.host.ownerDocument.createElement("style");t.dataset.hpSummaryShell="true",t.textContent=I,e.appendChild(t)}this.styledDialogRoots.add(e)}placementSlot(){return K(this.host)}preferenceKey(){return function(e){const t=y(e.userId),s=y(e.slot);return t&&s?`houseplan.summary-panel.v1:${[t,y(e.path)||"/",y(e.host)||"card",s].map(e=>encodeURIComponent(e)).join(":")}`:null}({userId:this.host.hass?.user?.id||this.host.hass?.user?.name,path:location.pathname,host:this.host.panelHost?"panel":"lovelace",slot:this.placementSlot()})}identity(){return JSON.stringify({key:this.preferenceKey(),user:this.host.hass?.user?.id||this.host.hass?.user?.name||"",route:location.pathname,host:this.host.panelHost?"panel":"lovelace",slot:this.placementSlot(),kiosk:this.host._kiosk,canManage:this.host._canManageConfiguration})}syncLifecycle(){const e=this.identity();this.lifecycleIdentity&&e!==this.lifecycleIdentity&&this.resetLifecycle(),this.lifecycleIdentity=e}resetLifecycle(){this.presentation.reset(),this.lifecycleGeneration++,this.dialog=null,this.entityIndex=null,this.deviceMemo=null,this.areaMemo=null,this.clockContext="",this.storageKey=null,this.storageUnavailable=!1,this.local={version:1,show:!1,icon_scale:1,font_scale:1},this.clockTimer&&clearTimeout(this.clockTimer),this.clockTimer=0,this.lifecycleIdentity=this.connected?this.identity():"",this.host.requestUpdate()}current(e){return this.connected&&e===this.lifecycleGeneration&&this.lifecycleIdentity===this.identity()}refreshEntityIndex(){this.entityIndex=F(this.host.hass?.states,this.entityIndex)}syncNativeNarrow(){if(this.host.panelHost)return;let e=this.host;for(let t=0;e&&t<12;t++){const t=e.getRootNode();if(e=e.parentNode||(t instanceof ShadowRoot?t.host:null),!e||e===this.host)continue;const s=e.narrow;if("boolean"==typeof s)return void(this.host.narrow!==s&&(this.host.narrow=s))}}loadLocal(){const e=this.preferenceKey();if(!e||e===this.storageKey)return;let t=null,s=null,r=!0;try{t=JSON.parse(localStorage.getItem(e)||"null")}catch{r=!1}try{s=JSON.parse(localStorage.getItem("houseplan_card_kiosk_v1")||"null")}catch{r=!1}this.storageKey=e,this.storageUnavailable=!r,this.local=function(e,t){const s=e&&"object"==typeof e?e:{},r=t&&"object"==typeof t?t:{};return{version:1,show:!0===s.show,icon_scale:M(p(s,"icon_scale")?s.icon_scale:r.icon),font_scale:M(p(s,"font_scale")?s.font_scale:r.font)}}(t,s),this.host._kioskScale={icon:this.local.icon_scale,font:this.local.font_scale}}saveLocal(e){this.local={...this.local,...e,version:1,icon_scale:M(e.icon_scale??this.local.icon_scale),font_scale:M(e.font_scale??this.local.font_scale)},this.host._kioskScale={icon:this.local.icon_scale,font:this.local.font_scale},this.storageKey||=this.preferenceKey();let t=!1;try{this.storageKey&&(localStorage.setItem(this.storageKey,JSON.stringify(this.local)),t=!0)}catch{}this.storageUnavailable=!t,t||this.host._showToast?.(this.t("summary.storage_unavailable")),this.host.requestUpdate()}config(){return function(e,t){const s=e?.summary_panel;return void 0===s?{config:b(t),derived:!0,unsupported:!1}:v(s)?{config:s,derived:!1,unsupported:!1}:{config:null,derived:!1,unsupported:!0}}(this.host._settings,this.translate)}async openDialog(){const e=this.lifecycleGeneration;this.loadLocal();try{this.editorLoad||=import("./summary-panel-editor-CNT_mev4.js").then(e=>e.renderSummaryPanelEditor),this.editorRenderer=await this.editorLoad}catch(t){if(this.editorLoad=null,!this.current(e))return;return void this.host._showToast?.(`${this.t("summary.load_failed")} ${this.host._errText(t)}`)}if(!this.current(e))return;const t=this.config(),s=t.config||b(this.translate),r=this.host._haSummaryPanelApi!==i,a=t.unsupported?"summary.unsupported_schema":r&&this.host._canManageConfiguration?"summary.backend_required":"summary.local_only";this.dialog={draft:_(s),base:_(s),baseRevision:this.host._cfgRev,localShow:this.local.show,baseLocalShow:this.local.show,localOnly:this.host._kiosk||!this.host._canManageConfiguration||r||t.unsupported,localOnlyHint:a,busy:!1,attempted:!1,entityFilter:"",activeSource:null,error:"",conflict:!1},this.dialog.localOnly||this.refreshEntityIndex(),this.host.requestUpdate()}problems(e=this.dialog){return!e||e.localOnly?[]:k(x(e.draft),e.base,new Set(this.host._model.map(e=>e.id)),new Set(Object.keys(this.host.hass?.states||{})))}mutate(e){if(!this.dialog||this.dialog.busy||this.dialog.localOnly)return;const t=_(this.dialog.draft);e(t);const s=this.dialog.activeSource,r=!s||t.blocks.some(e=>e.id===s.blockId&&e.values.some(e=>e.id===s.valueId));this.dialog={...this.dialog,draft:t,error:"",conflict:!1,activeSource:r?s:null,entityFilter:r?this.dialog.entityFilter:""},this.host.requestUpdate()}async deleteBlock(e){const t=this.dialog?.draft.blocks[e];if(!t)return;const s=this.lifecycleGeneration;if(t.values.length){if(!await this.host._confirmDanger({key:"summary-block",kind:"warning",title:this.t("summary.delete_block_title"),message:this.t("summary.delete_block_body"),objectName:t.title,confirmLabel:this.t("btn.delete"),cancelLabel:this.t("btn.cancel")})||!this.current(s))return}this.mutate(e=>{const s=e.blocks.findIndex(e=>e.id===t.id);s>=0&&e.blocks.splice(s,1)})}sourceToken(e){return"system"===e.type?`system:${e.key}`:`entity:${e.entity_id}`}openSource(e,t){!this.dialog||this.dialog.busy||this.dialog.localOnly||(this.refreshEntityIndex(),this.dialog={...this.dialog,activeSource:{blockId:e,valueId:t},entityFilter:""},this.host.requestUpdate(),this.host.updateComplete.then(()=>{this.dialog?.activeSource?.blockId===e&&this.dialog.activeSource.valueId===t&&this.host.renderRoot.querySelector("[data-summary-picker-search]")?.focus()}))}closeSource(e=!1){const t=this.dialog?.activeSource;this.dialog&&t&&(this.dialog={...this.dialog,activeSource:null,entityFilter:""},this.host.requestUpdate(),e&&this.focusSource(t.blockId,t.valueId))}async focusSource(e,t){await this.host.updateComplete;const s=`${e}\n${t}`,r=this.host.renderRoot.querySelectorAll("[data-summary-source-owner]");[...r].find(e=>e.dataset.summarySourceOwner===s)?.focus()}setSource(e,t,s){this.mutate(r=>{const i=r.blocks.find(t=>t.id===e)?.values.find(e=>e.id===t);if(i)if(s.startsWith("system:")){const e=s.slice(7);(e=>"device_count"===e||"total_area"===e||"datetime"===e)(e)&&(i.source={type:"system",key:e})}else i.source={type:"entity",entity_id:s.startsWith("entity:")?s.slice(7):s}}),this.dialog&&(this.dialog={...this.dialog,activeSource:null,entityFilter:""}),this.host.requestUpdate(),this.focusSource(e,t)}dragStart(e,t){e.dataTransfer?.setData("text/x-houseplan-summary",t),e.dataTransfer&&(e.dataTransfer.effectAllowed="move")}drop(e,t){e.preventDefault(),e.stopPropagation();const s=e.dataTransfer?.getData("text/x-houseplan-summary")||"",r=s.split(":").map(Number),i=t.split(":").map(Number);s.startsWith("block:")&&t.startsWith("block:")?this.mutate(e=>{e.blocks=C(e.blocks,r[1],i[1])}):s.startsWith("value:")&&t.startsWith("value:")&&r[1]===i[1]&&this.mutate(e=>{e.blocks[r[1]].values=C(e.blocks[r[1]].values,r[2],i[2])})}async saveDialog(){const e=this.dialog;if(!e||e.busy)return;const t=this.lifecycleGeneration,s=x(e.draft);if((e.localOnly?[]:k(s,e.base,new Set(this.host._model.map(e=>e.id)),new Set(Object.keys(this.host.hass?.states||{})))).some(e=>"error"===e.kind))return this.dialog={...e,draft:s,attempted:!0},this.host.requestUpdate(),await this.host.updateComplete,void this.host.renderRoot.querySelector('[data-summary-error="true"]')?.focus?.();this.dialog={...e,draft:s,busy:!0,attempted:!1,error:"",conflict:!1},this.host.requestUpdate();try{if(!e.localOnly&&!$(s,e.base)){this.host._writesPending++;const r=a(this.host._writeChain,async()=>{if(!this.current(t))return;if(!this.host._serverCfg)throw new Error(this.t("summary.save_failed"));if(this.host._cfgRev!==e.baseRevision)throw new Error(this.t("summary.conflict"));const r=o({...this.host._serverCfg,settings:{...this.host._serverCfg.settings||{},summary_panel:s}});let i=!1;try{if(await this.host._sendConfigCandidate(r),!this.current(t))return}catch(e){if(!this.current(t))throw e;try{const r=await this.host._getAuthoritativeConfig();if(!this.current(t))throw e;const a=function(e,t){if(!g(e))return null;const s=e.config,r=e.rev;if(!g(s)||!Array.isArray(s.spaces)||"number"!=typeof r||!Number.isSafeInteger(r)||r<0)return null;const i=g(s.settings)?s.settings:null,a=i?.summary_panel;return v(a)&&$(a,t)?{config:s,rev:r}:null}(r,s);if(!a)throw e;const o=await this.host._adoptAuthoritative({cfgResp:r,reason:"summary-recovery",profile:"reload"});if("adopted"!==o.status)throw e;o.spaceChanged&&this.host._restoreZoom(),this.host._regSignature="",this.host._maybeRebuildDevices(),i=!0}catch{throw e}}if(!i){if(!this.current(t))return;this.host._adoption.stageConfigCandidate(r),this.host._cacheSnapshot()}});this.host._writeChain=r,await r.finally(()=>{this.host._writesPending--})}if(!this.current(t))return;this.saveLocal({show:e.localShow}),this.dialog=null}catch(s){if(!this.current(t))return;const r="conflict"===s?.code||this.host._cfgRev!==e.baseRevision;this.dialog={...this.dialog||e,busy:!1,conflict:r,error:r?this.t("summary.conflict"):this.host._errText(s)}}this.current(t)&&this.host.requestUpdate()}async reloadDialog(){const e=this.dialog;if(!e||e.busy)return;const t=this.lifecycleGeneration;this.dialog={...e,busy:!0,error:"",conflict:!1},this.host.requestUpdate();try{if(await this.host._reloadConfigOnly(!0),!this.current(t))return;if(e.conflict&&this.host._cfgRev===e.baseRevision)throw new Error(this.t("summary.load_failed"));const s=this.config().config||b(this.translate);this.dialog={...e,draft:_(s),base:_(s),baseRevision:this.host._cfgRev,busy:!1,attempted:!1,error:"",conflict:!1}}catch(s){if(!this.current(t))return;this.dialog={...e,busy:!1,error:this.host._errText(s),conflict:!0}}this.current(t)&&this.host.requestUpdate()}metricsFresh(){return!!this.deviceMemo&&!!this.areaMemo&&this.deviceMemo.cfgEpoch===this.host._cfgEpoch&&this.deviceMemo.layoutRev===this.host._layoutRev&&this.deviceMemo.registryRev===this.host._haRegistry.revision&&this.areaMemo.cfgEpoch===this.host._cfgEpoch}scheduleMetrics(){if(this.metricsRefresh||!this.metricsModule||this.metricsFresh())return;const e=this.lifecycleGeneration,t="undefined"==typeof window?void 0:window,s=()=>{if(this.metricsRefresh=0,!this.current(e))return;const t=this.advanceMetrics(8);this.host.requestUpdate(),t||this.scheduleMetrics()};this.metricsRefresh=t?.setTimeout(()=>{"function"==typeof t.requestAnimationFrame?t.requestAnimationFrame(()=>t.setTimeout(s,0)):s()},0)||0}advanceMetrics(e=8){const t=this.metricsModule;if(!t)return!0;if(this.computeDeviceCount(),!this.host._serverCfg)return this.areaMemo={cfgEpoch:this.host._cfgEpoch,value:null},!0;if(this.areaMemo&&this.areaMemo.cfgEpoch===this.host._cfgEpoch)return!0;this.areaSteps&&this.areaStepsEpoch===this.host._cfgEpoch||(this.areaSteps=t.cleanFloorAreaSteps(this.host._serverCfg,this.host._model),this.areaStepsEpoch=this.host._cfgEpoch);const s=Date.now();let r=this.areaSteps.next();for(;!r.done&&Date.now()-s[e,t.space])),spaceIds:new Set(this.host._model.map(e=>e.id)),firstSpaceId:this.host._model[0]?.id||"",markers:this.host._markers});this.deviceMemo={cfgEpoch:this.host._cfgEpoch,layoutRev:this.host._layoutRev,registryRev:this.host._haRegistry.revision,value:t?.size??null}}}computeMetrics(){for(;!this.advanceMetrics(Number.POSITIVE_INFINITY););}metrics(){return{deviceCount:this.deviceMemo?this.deviceMemo.value:null,areaM2:this.areaMemo?this.areaMemo.value:null,now:this.clock}}valueState(e){const t=this.metricsModule;if(!t)return{kind:"pending"};if("entity"===e.source.type){const s=t.summaryEntityValue(this.host.hass,e.source.entity_id);return null===s?{kind:"unavailable"}:{kind:"ready",text:s}}const s="device_count"===e.source.key||"total_area"===e.source.key,i="device_count"===e.source.key?this.deviceMemo:this.areaMemo;if(s&&!i)return this.scheduleMetrics(),{kind:"pending"};s&&this.scheduleMetrics();const a=t.summarySystemValue(e.source,this.metrics(),this.host.hass,r(this.host.hass,this.host._config?.language));return null===a?{kind:"unavailable"}:{kind:"ready",text:a}}value(e){const t=this.valueState(e);return"ready"===t.kind?t.text:this.t("summary.unavailable")}ensureMetrics(){if(this.metricsModule||this.metricsLoad)return;const e=this.lifecycleGeneration;this.metricsLoad=import("./summary-panel-metrics-BhoEMuKv.js"),this.metricsLoad.then(t=>{this.metricsModule=t,this.current(e)&&this.host.requestUpdate()}).catch(()=>{}).finally(()=>{this.metricsLoad=null})}layout(){return function(e){const t=Math.max(0,Number(e.width)||0),s=Math.max(0,Number(e.height)||0),r=t>=s?"right":"bottom",i=Math.max(0,e.safeLeft||0)+12,a=Math.max(0,e.safeRight||0)+12,o=Math.max(Math.max(0,e.safeTop||0)+12,e.controlTop||0),n=Math.max(Math.max(0,e.safeBottom||0)+12,e.controlBottom||0),l=Math.max(0,t-i-a),m=Math.max(0,s-o-n),c="bottom"===r?Math.min(.6*s,m):m;return{side:r,fits:t>0&&s>0&&l>=280&&c>=Math.max(0,e.minimumHeight),availableWidth:l,heightCap:c,top:o,bottom:n}}({width:this.stage.width,height:this.stage.height,...this.safeInsets(),controlTop:this.host._kiosk?this.stage.controlTop:0,minimumHeight:this.stage.minimumHeight})}syncPresentation(e=!1){const t=this.config().config,s=this.layout(),r=!!t&&"view"===this.host._mode&&s.fits&&S({view:!0,localShow:!0,showOnMobile:t.show_on_mobile,narrow:this.host.narrow,fits:!0});this.presentation.sync(r&&this.local.show,s.side,e||!r||"hidden"===this.host.ownerDocument.visibilityState)}measureLayout(){const e=this.host._stageEl;if(!e)return;const t=this.host.renderRoot.querySelector(".summary-measure"),s=this.host.renderRoot.querySelector(".summary-control.kiosk"),r=e.getBoundingClientRect(),i=s?.getBoundingClientRect(),a={width:Math.round(e.clientWidth),height:Math.round(e.clientHeight),minimumHeight:Math.max(162,Math.ceil(t?.getBoundingClientRect().height||0)),controlTop:i?Math.max(0,Math.ceil(i.bottom-r.top+12)):0};a.width===this.stage.width&&a.height===this.stage.height&&a.minimumHeight===this.stage.minimumHeight&&a.controlTop===this.stage.controlTop||(this.stage=a,this.host.requestUpdate())}safeInsets(){const e=this.host.renderRoot.querySelector(".summary-safe-probe");if(!e)return{safeLeft:0,safeRight:0,safeTop:0,safeBottom:0};const t=this.host.ownerDocument.defaultView?.getComputedStyle(e);if(!t)return{safeLeft:0,safeRight:0,safeTop:0,safeBottom:0};const s=e=>Number.parseFloat(e)||0;return{safeLeft:s(t.paddingLeft),safeRight:s(t.paddingRight),safeTop:s(t.paddingTop),safeBottom:s(t.paddingBottom)}}hasVisibleClock(){const e=this.config().config;return!("hidden"===this.host.ownerDocument.visibilityState||!e)&&(!!S({view:"view"===this.host._mode,localShow:this.local.show,showOnMobile:e.show_on_mobile,narrow:this.host.narrow,fits:this.layout().fits})&&w(e,this.host._space).some(e=>e.values.some(e=>"system"===e.source.type&&"datetime"===e.source.key)))}syncClock(){const e=`${r(this.host.hass,this.host._config?.language)}\n${this.host.hass?.config?.time_zone||""}`;e!==this.clockContext&&(this.clockContext=e,this.clock=new Date);const t=this.hasVisibleClock();if(t&&!this.clockTimer){this.clock=new Date;const e=()=>{this.clock=new Date,this.clockTimer=0,this.host.requestUpdate(),this.syncClock()};this.clockTimer=window.setTimeout(e,6e4-Date.now()%6e4+25)}else!t&&this.clockTimer&&(clearTimeout(this.clockTimer),this.clockTimer=0)}}});export{A as a,G as b,z as c,D as d,V as e,C as m,x as n,$ as s}; diff --git a/custom_components/houseplan/frontend/houseplan-assets/zigbee-topology-D0gydI7H.js b/dist/houseplan-assets/zigbee-topology-CI6PJorK.js similarity index 95% rename from custom_components/houseplan/frontend/houseplan-assets/zigbee-topology-D0gydI7H.js rename to dist/houseplan-assets/zigbee-topology-CI6PJorK.js index 3f3726b1..a8217f2e 100644 --- a/custom_components/houseplan/frontend/houseplan-assets/zigbee-topology-D0gydI7H.js +++ b/dist/houseplan-assets/zigbee-topology-CI6PJorK.js @@ -1 +1 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{s as e,aI as n}from"./houseplan-card-BWAph8ZF.js";var t={title:"Zigbee links",toggle:"Show Zigbee links when hovering over a device",hint:"Shows observed direct neighbours only. Nothing is fetched while you hover.",help:"Shows which Zigbee devices each device talks to directly. Line colour is link quality (LQI) on the same scale as the device's LQI reading: red at 40 and below, green at 180 and above. A dashed line means quality was not reported. An arrow points to the next device on the way to the coordinator: one arrow leads out, incoming arrows are the devices that route through this one. A line without an arrow is a spare neighbour. This is the route tree House Plan builds, not the path a packet takes right now: a label at the end of an arrow means its target is not on this plan, and no arrow at all means the route is unknown. Data comes from the last load and goes stale; links are shown with a mouse only.",help_aria:"Help: Zigbee links",admin_only:"Topology data is available to Home Assistant administrators only.",save_first:"Save this setting before loading topology data.",zha:"ZHA",zha_read:"Read ZHA data",zha_hint:"Reads ZHA's cached topology; it does not start a radio scan.",z2m:"Zigbee2MQTT",z2m_topics:"Base topics (one per line)",z2m_update:"Update map",z2m_warning:"A network-map scan can take 10 seconds to 2 minutes and may temporarily reduce Zigbee responsiveness.",status_idle:"Data not loaded",status_loading:"Loading…",status_ready:"Received {time}",status_stale:"Received {time} · stale",status_partial:"Received {time} · some nodes were omitted",status_no_links:"Received {time} · no observed links found",error_permission:"Administrator permission is required.",error_unsupported:"This provider or Home Assistant API is unavailable.",error_timeout:"The provider did not respond in time.",error_invalid_topic:"Check the Zigbee2MQTT base topic.",error_invalid_payload:"The provider returned unsupported topology data.",error_provider:"Topology data could not be loaded.",remote_count:"+{n} in other spaces",route_device_not_on_plan:"device is not on the plan",route_coordinator_not_on_plan:"coordinator is not on the plan",route_other_space:"another space"};const i={en:t,ru:{title:"Связи Zigbee",toggle:"Показывать связи Zigbee при наведении на устройство",hint:"Показываются только наблюдаемые прямые соседи. Наведение ничего не запрашивает.",help:"Показывает, с какими устройствами Zigbee каждое связано напрямую. Цвет линии — качество связи (LQI) по той же шкале, что у показателя LQI устройства: красный при 40 и ниже, зелёный при 180 и выше. Пунктир — качество не сообщено. Стрелка ведёт к следующему устройству по пути к координатору: исходящая одна, входящие — те, кто ходит через это устройство. Линия без стрелки — запасной сосед. Это дерево маршрутов, которое строит House Plan, а не путь пакета в эту секунду: подпись на конце стрелки значит, что цель не на этом плане, а отсутствие стрелки — что путь неизвестен. Данные из последней загрузки и устаревают, связи видны только при работе мышью.",help_aria:"Справка: связи Zigbee",admin_only:"Данные топологии доступны только администраторам Home Assistant.",save_first:"Сохраните настройку перед загрузкой данных топологии.",zha:"ZHA",zha_read:"Прочитать данные ZHA",zha_hint:"Читает сохранённую топологию ZHA и не запускает радио-сканирование.",z2m:"Zigbee2MQTT",z2m_topics:"Базовые топики (по одному в строке)",z2m_update:"Обновить карту",z2m_warning:"Сканирование карты сети занимает от 10 секунд до 2 минут и временно может снизить отзывчивость Zigbee.",status_idle:"Данные не загружены",status_loading:"Загрузка…",status_ready:"Получено: {time}",status_stale:"Получено: {time} · данные устарели",status_partial:"Получено: {time} · часть узлов не показана",status_no_links:"Получено: {time} · наблюдаемые связи не найдены",error_permission:"Нужны права администратора.",error_unsupported:"Провайдер или API Home Assistant недоступен.",error_timeout:"Провайдер не ответил вовремя.",error_invalid_topic:"Проверьте базовый топик Zigbee2MQTT.",error_invalid_payload:"Провайдер вернул неподдерживаемые данные топологии.",error_provider:"Не удалось загрузить данные топологии.",remote_count:"+{n} в других пространствах",route_device_not_on_plan:"устройства нет на плане",route_coordinator_not_on_plan:"координатора нет на плане",route_other_space:"другое пространство"},de:{title:"Zigbee-Verbindungen",toggle:"Zigbee-Verbindungen beim Darüberfahren über ein Gerät anzeigen",hint:"Es werden nur beobachtete direkte Nachbarn angezeigt. Beim Darüberfahren werden keine Daten abgerufen.",help:"Zeigt, mit welchen Zigbee-Geräten jedes Gerät direkt verbunden ist. Die Linienfarbe ist die Verbindungsqualität (LQI) auf derselben Skala wie der LQI-Wert des Geräts: rot bei 40 und darunter, grün bei 180 und darüber. Eine gestrichelte Linie bedeutet, dass die Qualität nicht gemeldet wurde. Ein Pfeil zeigt auf das nächste Gerät auf dem Weg zum Koordinator: ein Pfeil führt hinaus, eingehende Pfeile sind die Geräte, die über dieses Gerät routen. Eine Linie ohne Pfeil ist ein Ersatznachbar. Das ist der Routenbaum, den House Plan bildet, nicht der Weg eines Pakets in diesem Moment: eine Beschriftung am Pfeilende bedeutet, dass das Ziel nicht auf diesem Plan liegt, und ein fehlender Pfeil, dass die Route unbekannt ist. Die Daten stammen aus dem letzten Laden und veralten; Verbindungen sind nur mit der Maus sichtbar.",help_aria:"Hilfe: Zigbee-Verbindungen",admin_only:"Topologiedaten sind nur für Home-Assistant-Administratoren verfügbar.",save_first:"Speichere diese Einstellung, bevor Topologiedaten geladen werden.",zha:"ZHA",zha_read:"ZHA-Daten lesen",zha_hint:"Liest den ZHA-Topologiecache; es wird kein Funkscan gestartet.",z2m:"Zigbee2MQTT",z2m_topics:"Basistopics (eines pro Zeile)",z2m_update:"Karte aktualisieren",z2m_warning:"Ein Netzwerkscan kann 10 Sekunden bis 2 Minuten dauern und Zigbee vorübergehend verlangsamen.",status_idle:"Daten nicht geladen",status_loading:"Wird geladen…",status_ready:"Empfangen: {time}",status_stale:"Empfangen: {time} · veraltet",status_partial:"Empfangen: {time} · einige Knoten fehlen",status_no_links:"Empfangen: {time} · keine beobachteten Verbindungen gefunden",error_permission:"Administratorrechte sind erforderlich.",error_unsupported:"Dieser Anbieter oder die Home-Assistant-API ist nicht verfügbar.",error_timeout:"Der Anbieter hat nicht rechtzeitig geantwortet.",error_invalid_topic:"Prüfe das Zigbee2MQTT-Basistopic.",error_invalid_payload:"Der Anbieter hat nicht unterstützte Topologiedaten geliefert.",error_provider:"Topologiedaten konnten nicht geladen werden.",remote_count:"+{n} in anderen Bereichen",route_device_not_on_plan:"Gerät ist nicht im Plan",route_coordinator_not_on_plan:"Koordinator ist nicht im Plan",route_other_space:"anderer Bereich"},fr:{title:"Liens Zigbee",toggle:"Afficher les liens Zigbee au survol d’un appareil",hint:"Seuls les voisins directs observés sont affichés. Le survol ne lance aucune requête.",help:"Montre avec quels appareils Zigbee chaque appareil communique directement. La couleur de la ligne est la qualité du lien (LQI) sur la même échelle que l'indicateur LQI de l'appareil : rouge à 40 et en dessous, vert à 180 et au-dessus. Une ligne pointillée signifie que la qualité n'a pas été communiquée. Une flèche pointe vers l'appareil suivant sur le chemin du coordinateur : une flèche part, les flèches entrantes sont les appareils qui passent par celui-ci. Une ligne sans flèche est un voisin de secours. C'est l'arbre de routes que construit House Plan, pas le trajet d'un paquet à cet instant : une étiquette au bout d'une flèche signifie que sa cible n'est pas sur ce plan, et l'absence de flèche que la route est inconnue. Les données proviennent du dernier chargement et vieillissent ; les liens ne sont visibles qu'à la souris.",help_aria:"Aide : liens Zigbee",admin_only:"Les données de topologie sont réservées aux administrateurs Home Assistant.",save_first:"Enregistrez ce réglage avant de charger les données de topologie.",zha:"ZHA",zha_read:"Lire les données ZHA",zha_hint:"Lit la topologie en cache de ZHA sans lancer d’analyse radio.",z2m:"Zigbee2MQTT",z2m_topics:"Topics de base (un par ligne)",z2m_update:"Actualiser la carte",z2m_warning:"L’analyse de la carte réseau peut durer de 10 secondes à 2 minutes et réduire temporairement la réactivité de Zigbee.",status_idle:"Données non chargées",status_loading:"Chargement…",status_ready:"Reçu : {time}",status_stale:"Reçu : {time} · obsolète",status_partial:"Reçu : {time} · certains nœuds sont omis",status_no_links:"Reçu : {time} · aucun lien observé trouvé",error_permission:"Les droits administrateur sont requis.",error_unsupported:"Ce fournisseur ou l’API Home Assistant n’est pas disponible.",error_timeout:"Le fournisseur n’a pas répondu à temps.",error_invalid_topic:"Vérifiez le topic de base Zigbee2MQTT.",error_invalid_payload:"Le fournisseur a renvoyé des données de topologie non prises en charge.",error_provider:"Impossible de charger les données de topologie.",remote_count:"+{n} dans d’autres espaces",route_device_not_on_plan:"appareil absent du plan",route_coordinator_not_on_plan:"coordinateur absent du plan",route_other_space:"autre espace"}};function r(e,n){const r=i[e]?.[n]??t[n];return"string"==typeof r&&r.trim().length>0}function o(n,r,o){return e(i[n]?.[r]??t[r]??r,o)}const s=3e5,a=2097152,d=6e3;function l(e){return null!==e&&"object"==typeof e?e:null}function u(e){if("string"!=typeof e&&"number"!=typeof e)return null;let n=String(e).trim().toLowerCase();return n=/^0x[0-9a-f]{16}$/.test(n)?n.slice(2):n.replace(/[:-]/g,""),/^[0-9a-f]{16}$/.test(n)?n:null}function c(e,n,t){return`${e}:${n}:${t}`}function p(e){const n=String(e||"").toLowerCase().replace(/[ _-]/g,"");return n.includes("coordinator")?"coordinator":n.includes("router")?"router":n.includes("enddevice")||"end"===n?"end":"unknown"}const h=["parent","child","sibling","none","previous_child"];function g(e){const n=l(e),t=function(e){const n=Number(e);return Number.isFinite(n)&&n>=0&&n<=255?Math.round(n):void 0}(n?.lqi??n?.linkquality??n?.link_quality),i=function(e){if("number"==typeof e)return h[e];if("string"!=typeof e)return;const n=e.trim().toLowerCase().replace(/[\s_-]+/g,"");return"previouschild"===n?"previous_child":n.slice(0,40)||void 0}(n?.relationship);return{...void 0===t?{}:{lqi:t},...i?{relationship:i}:{}}}function f(e,n){return Array.isArray(e)&&e.length<=n?e:null}function _(e){if("string"==typeof e)return e.length<=a;try{return JSON.stringify(e).length<=a}catch{return!1}}function b(e,n,t,i,r){if(t===i)return void n.push({code:"self_link",nodeKey:t});const o=t=d){t.push({code:"invalid_payload"});break}const n=l(e),i=u(n?.ieee??n?.ieee_address);if(!i){t.push({code:"invalid_payload",nodeKey:s});continue}const a=c("zha","zha",i);r.has(a)||r.set(a,{key:a,ieee:i,role:p(n?.device_type)}),b(o,t,s,a,e)}else null!=n?.neighbors&&t.push({code:"invalid_payload",nodeKey:s})}return{provider:"zha",instanceId:"zha",obtainedAt:n,freshness:"provider-cache",nodes:[...r.values()],links:[...o.values()],warnings:t}}function v(e,n){const t=l(e),i=u(t?.ieeeAddr??t?.ieee_address??t?.ieee??e);if(i)return i;for(const i of[t?.id,t?.networkAddress,t?.network_address,e])if(null!=i){const e=n.get(String(i));if(e)return e}return null}function y(e,t,i=Date.now()){const r=[],o=n(t)||"invalid",s=_(e)?function(e){let n=e;if("string"==typeof n){if(n.length>a)return null;try{n=JSON.parse(n)}catch{return null}}const t=l(n),i=l(t?.data);if(n=i?.value??t?.value??t?.data??n,"string"==typeof n){if(n.length>a)return null;try{n=JSON.parse(n)}catch{return null}}return n}(e):null,h=l(s),g=f(h?.nodes,1e3),m=f(h?.links,d);if(!g||!m)return{provider:"z2m",instanceId:o,obtainedAt:i,freshness:"fresh-scan",nodes:[],links:[],warnings:[{code:"invalid_payload"}]};const y=new Map,k=new Map;for(const e of g){const n=l(e),t=u(n?.ieeeAddr??n?.ieee_address??n?.ieee);if(!t){r.push({code:"invalid_payload"});continue}const i=c("z2m",o,t);y.set(i,{key:i,ieee:t,role:p(n?.type??n?.device_type),..."boolean"==typeof n?.failed?{available:!n.failed}:{}});for(const e of[n?.id,n?.networkAddress,n?.network_address])null!=e&&k.set(String(e),t)}const w=new Map;for(const e of m){const n=l(e),t=u(n?.sourceIeeeAddr)??v(n?.source,k),i=u(n?.targetIeeeAddr)??v(n?.target,k);if(!t||!i){r.push({code:"invalid_payload"});continue}const s=c("z2m",o,t),a=c("z2m",o,i);y.has(s)||y.set(s,{key:s,ieee:t,role:"unknown"}),y.has(a)||y.set(a,{key:a,ieee:i,role:"unknown"}),b(w,r,s,a,e)}return{provider:"z2m",instanceId:o,obtainedAt:i,freshness:"fresh-scan",nodes:[...y.values()],links:[...w.values()],warnings:r}}function k(e){if("string"!=typeof e)return null;const n=u(e);if(n)return n;const t=e.toLowerCase().match(/^zigbee2mqtt(?:_bridge)?_(.+)$/);return t?u(t[1]):null}function w(e,n){if(e.deviceId&&n.devices[e.deviceId])return[e.deviceId];const t=new Set;for(const[i,r]of Object.entries(n.devices)){const n=l(r);(Array.isArray(n?.identifiers)?n.identifiers:[]).some(n=>Array.isArray(n)&&k(n[1])===e.ieee)&&t.add(i)}if(t.size)return[...t];for(const i of Object.values(n.entities)){const n=l(i);"string"==typeof n?.device_id&&"string"==typeof n.unique_id&&(k(n.unique_id)===e.ieee&&t.add(n.device_id))}return[...t]}function z(e){return!e.hidden&&!e.virtual&&"ha_disabled"!==e.bindingStatus?.kind&&"orphaned"!==e.bindingStatus?.kind&&"unverified"!==e.bindingStatus?.kind}function A(e){const n=new Map,t=new Map,i=e.nodes.filter(e=>"coordinator"===e.role).map(e=>e.key).sort();if(1!==i.length)return{distances:n,parents:t};const r=i[0],o=function(e){const n=new Set(e.nodes.map(e=>e.key)),t=new Map;for(const e of[...n].sort())t.set(e,[]);for(const i of[...e.links].sort((e,n)=>`${e.a}\0${e.b}`.localeCompare(`${n.a}\0${n.b}`)))n.has(i.a)&&n.has(i.b)&&(t.get(i.a).push({neighborKey:i.b,observation:i.aToB}),t.get(i.b).push({neighborKey:i.a,observation:i.bToA}));for(const e of t.values())e.sort((e,n)=>e.neighborKey.localeCompare(n.neighborKey));return t}(e);if(!o.has(r))return{distances:n,parents:t};n.set(r,0);const s=[r];for(let e=0;en.get(e)===i-1).sort((e,n)=>{const t="parent"===e.observation?.relationship?1:0,i="parent"===n.observation?.relationship?1:0;if(t!==i)return i-t;const r=e.observation?.lqi??-1;return(n.observation?.lqi??-1)-r||e.neighborKey.localeCompare(n.neighborKey)});r[0]&&t.set(e,r[0].neighborKey)}return{coordinatorKey:r,distances:n,parents:t}}function Z(e,n,t){const i=new Map,r=[];for(const o of e.nodes){if(!1===o.available){r.push({code:"provider_scan_failure",nodeKey:o.key});continue}const e=w(o,t);if(1!==e.length){r.push({code:"unmatched_device",nodeKey:o.key});continue}const s=e[0];let a=n.filter(e=>z(e)&&"device"===e.bindingKind&&e.bindingRef===s);a.length||(a=n.filter(e=>z(e)&&"entity"===e.bindingKind&&!!e.bindingRef&&t.entities[e.bindingRef]?.device_id===s)),1===a.length?i.set(o.key,{markerId:a[0].id,space:a[0].space}):r.push({code:a.length>1?"ambiguous_placement":"unmatched_device",nodeKey:o.key})}return{placements:i,warnings:r}}function T(e,n,t){return e.map(e=>({topology:e,placements:Z(e,n,t).placements,routes:A(e)}))}function I(e,n,t){const i=new Map,r=new Set,o=new Map;let s=0;for(const{topology:a,placements:d,routes:l}of e){const e=new Set([...d].filter(([,e])=>e.markerId===t&&e.space===n).map(([e])=>e));if(e.size){for(const t of e){const e=l.parents.get(t);if(!e)continue;const i=d.get(e);if(i?.space===n)continue;let r;r=i?{kind:"remote-space",spaceId:i.space}:"coordinator"===a.nodes.find(n=>n.key===e)?.role?{kind:"unplaced-coordinator"}:{kind:"unplaced-device"};const s="remote-space"===r.kind?`${r.kind}:${r.spaceId}`:r.kind;o.set(s,r)}for(const o of a.links){const a=e.has(o.a),u=e.has(o.b);if(!a&&!u)continue;const c=a?o.a:o.b,p=a?o.b:o.a,h=d.get(p);if(!h||h.markerId===t){s++;continue}const g=l.parents.get(c)===p;if(h.space!==n){g||r.add(h.markerId);continue}const f=a?o.aToB:o.bToA,_=g?"toward-neighbor":l.parents.get(p)===c?"toward-origin":void 0,b=i.get(h.markerId);b?(void 0===b.line.lqi&&void 0!==f?.lqi&&(b.line.lqi=f.lqi),_&&b.directions.add(_)):i.set(h.markerId,{line:{neighborMarkerId:h.markerId,lqi:f?.lqi},directions:new Set(_?[_]:[])})}}}return{lines:[...i.values()].map(({line:e,directions:n})=>1===n.size?{...e,routeDirection:[...n][0]}:e),remoteCount:r.size,omittedCount:s,parentTargets:[...o.values()]}}export{s as T,T as a,y as b,r as h,Z as m,m as n,I as r,o as t}; +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{s as e,aI as n}from"./houseplan-card-9fMSy3y3.js";var t={title:"Zigbee links",toggle:"Show Zigbee links when hovering over a device",hint:"Shows observed direct neighbours only. Nothing is fetched while you hover.",help:"Shows which Zigbee devices each device talks to directly. Line colour is link quality (LQI) on the same scale as the device's LQI reading: red at 40 and below, green at 180 and above. A dashed line means quality was not reported. An arrow points to the next device on the way to the coordinator: one arrow leads out, incoming arrows are the devices that route through this one. A line without an arrow is a spare neighbour. This is the route tree House Plan builds, not the path a packet takes right now: a label at the end of an arrow means its target is not on this plan, and no arrow at all means the route is unknown. Data comes from the last load and goes stale; links are shown with a mouse only.",help_aria:"Help: Zigbee links",admin_only:"Topology data is available to Home Assistant administrators only.",save_first:"Save this setting before loading topology data.",zha:"ZHA",zha_read:"Read ZHA data",zha_hint:"Reads ZHA's cached topology; it does not start a radio scan.",z2m:"Zigbee2MQTT",z2m_topics:"Base topics (one per line)",z2m_update:"Update map",z2m_warning:"A network-map scan can take 10 seconds to 2 minutes and may temporarily reduce Zigbee responsiveness.",status_idle:"Data not loaded",status_loading:"Loading…",status_ready:"Received {time}",status_stale:"Received {time} · stale",status_partial:"Received {time} · some nodes were omitted",status_no_links:"Received {time} · no observed links found",error_permission:"Administrator permission is required.",error_unsupported:"This provider or Home Assistant API is unavailable.",error_timeout:"The provider did not respond in time.",error_invalid_topic:"Check the Zigbee2MQTT base topic.",error_invalid_payload:"The provider returned unsupported topology data.",error_provider:"Topology data could not be loaded.",remote_count:"+{n} in other spaces",route_device_not_on_plan:"device is not on the plan",route_coordinator_not_on_plan:"coordinator is not on the plan",route_other_space:"another space"};const i={en:t,ru:{title:"Связи Zigbee",toggle:"Показывать связи Zigbee при наведении на устройство",hint:"Показываются только наблюдаемые прямые соседи. Наведение ничего не запрашивает.",help:"Показывает, с какими устройствами Zigbee каждое связано напрямую. Цвет линии — качество связи (LQI) по той же шкале, что у показателя LQI устройства: красный при 40 и ниже, зелёный при 180 и выше. Пунктир — качество не сообщено. Стрелка ведёт к следующему устройству по пути к координатору: исходящая одна, входящие — те, кто ходит через это устройство. Линия без стрелки — запасной сосед. Это дерево маршрутов, которое строит House Plan, а не путь пакета в эту секунду: подпись на конце стрелки значит, что цель не на этом плане, а отсутствие стрелки — что путь неизвестен. Данные из последней загрузки и устаревают, связи видны только при работе мышью.",help_aria:"Справка: связи Zigbee",admin_only:"Данные топологии доступны только администраторам Home Assistant.",save_first:"Сохраните настройку перед загрузкой данных топологии.",zha:"ZHA",zha_read:"Прочитать данные ZHA",zha_hint:"Читает сохранённую топологию ZHA и не запускает радио-сканирование.",z2m:"Zigbee2MQTT",z2m_topics:"Базовые топики (по одному в строке)",z2m_update:"Обновить карту",z2m_warning:"Сканирование карты сети занимает от 10 секунд до 2 минут и временно может снизить отзывчивость Zigbee.",status_idle:"Данные не загружены",status_loading:"Загрузка…",status_ready:"Получено: {time}",status_stale:"Получено: {time} · данные устарели",status_partial:"Получено: {time} · часть узлов не показана",status_no_links:"Получено: {time} · наблюдаемые связи не найдены",error_permission:"Нужны права администратора.",error_unsupported:"Провайдер или API Home Assistant недоступен.",error_timeout:"Провайдер не ответил вовремя.",error_invalid_topic:"Проверьте базовый топик Zigbee2MQTT.",error_invalid_payload:"Провайдер вернул неподдерживаемые данные топологии.",error_provider:"Не удалось загрузить данные топологии.",remote_count:"+{n} в других пространствах",route_device_not_on_plan:"устройства нет на плане",route_coordinator_not_on_plan:"координатора нет на плане",route_other_space:"другое пространство"},de:{title:"Zigbee-Verbindungen",toggle:"Zigbee-Verbindungen beim Darüberfahren über ein Gerät anzeigen",hint:"Es werden nur beobachtete direkte Nachbarn angezeigt. Beim Darüberfahren werden keine Daten abgerufen.",help:"Zeigt, mit welchen Zigbee-Geräten jedes Gerät direkt verbunden ist. Die Linienfarbe ist die Verbindungsqualität (LQI) auf derselben Skala wie der LQI-Wert des Geräts: rot bei 40 und darunter, grün bei 180 und darüber. Eine gestrichelte Linie bedeutet, dass die Qualität nicht gemeldet wurde. Ein Pfeil zeigt auf das nächste Gerät auf dem Weg zum Koordinator: ein Pfeil führt hinaus, eingehende Pfeile sind die Geräte, die über dieses Gerät routen. Eine Linie ohne Pfeil ist ein Ersatznachbar. Das ist der Routenbaum, den House Plan bildet, nicht der Weg eines Pakets in diesem Moment: eine Beschriftung am Pfeilende bedeutet, dass das Ziel nicht auf diesem Plan liegt, und ein fehlender Pfeil, dass die Route unbekannt ist. Die Daten stammen aus dem letzten Laden und veralten; Verbindungen sind nur mit der Maus sichtbar.",help_aria:"Hilfe: Zigbee-Verbindungen",admin_only:"Topologiedaten sind nur für Home-Assistant-Administratoren verfügbar.",save_first:"Speichere diese Einstellung, bevor Topologiedaten geladen werden.",zha:"ZHA",zha_read:"ZHA-Daten lesen",zha_hint:"Liest den ZHA-Topologiecache; es wird kein Funkscan gestartet.",z2m:"Zigbee2MQTT",z2m_topics:"Basistopics (eines pro Zeile)",z2m_update:"Karte aktualisieren",z2m_warning:"Ein Netzwerkscan kann 10 Sekunden bis 2 Minuten dauern und Zigbee vorübergehend verlangsamen.",status_idle:"Daten nicht geladen",status_loading:"Wird geladen…",status_ready:"Empfangen: {time}",status_stale:"Empfangen: {time} · veraltet",status_partial:"Empfangen: {time} · einige Knoten fehlen",status_no_links:"Empfangen: {time} · keine beobachteten Verbindungen gefunden",error_permission:"Administratorrechte sind erforderlich.",error_unsupported:"Dieser Anbieter oder die Home-Assistant-API ist nicht verfügbar.",error_timeout:"Der Anbieter hat nicht rechtzeitig geantwortet.",error_invalid_topic:"Prüfe das Zigbee2MQTT-Basistopic.",error_invalid_payload:"Der Anbieter hat nicht unterstützte Topologiedaten geliefert.",error_provider:"Topologiedaten konnten nicht geladen werden.",remote_count:"+{n} in anderen Bereichen",route_device_not_on_plan:"Gerät ist nicht im Plan",route_coordinator_not_on_plan:"Koordinator ist nicht im Plan",route_other_space:"anderer Bereich"},fr:{title:"Liens Zigbee",toggle:"Afficher les liens Zigbee au survol d’un appareil",hint:"Seuls les voisins directs observés sont affichés. Le survol ne lance aucune requête.",help:"Montre avec quels appareils Zigbee chaque appareil communique directement. La couleur de la ligne est la qualité du lien (LQI) sur la même échelle que l'indicateur LQI de l'appareil : rouge à 40 et en dessous, vert à 180 et au-dessus. Une ligne pointillée signifie que la qualité n'a pas été communiquée. Une flèche pointe vers l'appareil suivant sur le chemin du coordinateur : une flèche part, les flèches entrantes sont les appareils qui passent par celui-ci. Une ligne sans flèche est un voisin de secours. C'est l'arbre de routes que construit House Plan, pas le trajet d'un paquet à cet instant : une étiquette au bout d'une flèche signifie que sa cible n'est pas sur ce plan, et l'absence de flèche que la route est inconnue. Les données proviennent du dernier chargement et vieillissent ; les liens ne sont visibles qu'à la souris.",help_aria:"Aide : liens Zigbee",admin_only:"Les données de topologie sont réservées aux administrateurs Home Assistant.",save_first:"Enregistrez ce réglage avant de charger les données de topologie.",zha:"ZHA",zha_read:"Lire les données ZHA",zha_hint:"Lit la topologie en cache de ZHA sans lancer d’analyse radio.",z2m:"Zigbee2MQTT",z2m_topics:"Topics de base (un par ligne)",z2m_update:"Actualiser la carte",z2m_warning:"L’analyse de la carte réseau peut durer de 10 secondes à 2 minutes et réduire temporairement la réactivité de Zigbee.",status_idle:"Données non chargées",status_loading:"Chargement…",status_ready:"Reçu : {time}",status_stale:"Reçu : {time} · obsolète",status_partial:"Reçu : {time} · certains nœuds sont omis",status_no_links:"Reçu : {time} · aucun lien observé trouvé",error_permission:"Les droits administrateur sont requis.",error_unsupported:"Ce fournisseur ou l’API Home Assistant n’est pas disponible.",error_timeout:"Le fournisseur n’a pas répondu à temps.",error_invalid_topic:"Vérifiez le topic de base Zigbee2MQTT.",error_invalid_payload:"Le fournisseur a renvoyé des données de topologie non prises en charge.",error_provider:"Impossible de charger les données de topologie.",remote_count:"+{n} dans d’autres espaces",route_device_not_on_plan:"appareil absent du plan",route_coordinator_not_on_plan:"coordinateur absent du plan",route_other_space:"autre espace"}};function r(e,n){const r=i[e]?.[n]??t[n];return"string"==typeof r&&r.trim().length>0}function o(n,r,o){return e(i[n]?.[r]??t[r]??r,o)}const s=3e5,a=2097152,d=6e3;function l(e){return null!==e&&"object"==typeof e?e:null}function u(e){if("string"!=typeof e&&"number"!=typeof e)return null;let n=String(e).trim().toLowerCase();return n=/^0x[0-9a-f]{16}$/.test(n)?n.slice(2):n.replace(/[:-]/g,""),/^[0-9a-f]{16}$/.test(n)?n:null}function c(e,n,t){return`${e}:${n}:${t}`}function p(e){const n=String(e||"").toLowerCase().replace(/[ _-]/g,"");return n.includes("coordinator")?"coordinator":n.includes("router")?"router":n.includes("enddevice")||"end"===n?"end":"unknown"}const h=["parent","child","sibling","none","previous_child"];function g(e){const n=l(e),t=function(e){const n=Number(e);return Number.isFinite(n)&&n>=0&&n<=255?Math.round(n):void 0}(n?.lqi??n?.linkquality??n?.link_quality),i=function(e){if("number"==typeof e)return h[e];if("string"!=typeof e)return;const n=e.trim().toLowerCase().replace(/[\s_-]+/g,"");return"previouschild"===n?"previous_child":n.slice(0,40)||void 0}(n?.relationship);return{...void 0===t?{}:{lqi:t},...i?{relationship:i}:{}}}function f(e,n){return Array.isArray(e)&&e.length<=n?e:null}function _(e){if("string"==typeof e)return e.length<=a;try{return JSON.stringify(e).length<=a}catch{return!1}}function m(e,n,t,i,r){if(t===i)return void n.push({code:"self_link",nodeKey:t});const o=t=d){t.push({code:"invalid_payload"});break}const n=l(e),i=u(n?.ieee??n?.ieee_address);if(!i){t.push({code:"invalid_payload",nodeKey:s});continue}const a=c("zha","zha",i);r.has(a)||r.set(a,{key:a,ieee:i,role:p(n?.device_type)}),m(o,t,s,a,e)}else null!=n?.neighbors&&t.push({code:"invalid_payload",nodeKey:s})}return{provider:"zha",instanceId:"zha",obtainedAt:n,freshness:"provider-cache",nodes:[...r.values()],links:[...o.values()],warnings:t}}function v(e,n){const t=l(e),i=u(t?.ieeeAddr??t?.ieee_address??t?.ieee??e);if(i)return i;for(const i of[t?.id,t?.networkAddress,t?.network_address,e])if(null!=i){const e=n.get(String(i));if(e)return e}return null}function y(e,t,i=Date.now()){const r=[],o=n(t)||"invalid",s=_(e)?function(e){let n=e;if("string"==typeof n){if(n.length>a)return null;try{n=JSON.parse(n)}catch{return null}}const t=l(n),i=l(t?.data);if(n=i?.value??t?.value??t?.data??n,"string"==typeof n){if(n.length>a)return null;try{n=JSON.parse(n)}catch{return null}}return n}(e):null,h=l(s),g=f(h?.nodes,1e3),b=f(h?.links,d);if(!g||!b)return{provider:"z2m",instanceId:o,obtainedAt:i,freshness:"fresh-scan",nodes:[],links:[],warnings:[{code:"invalid_payload"}]};const y=new Map,k=new Map;for(const e of g){const n=l(e),t=u(n?.ieeeAddr??n?.ieee_address??n?.ieee);if(!t){r.push({code:"invalid_payload"});continue}const i=c("z2m",o,t);y.set(i,{key:i,ieee:t,role:p(n?.type??n?.device_type),..."boolean"==typeof n?.failed?{available:!n.failed}:{}});for(const e of[n?.id,n?.networkAddress,n?.network_address])null!=e&&k.set(String(e),t)}const w=new Map;for(const e of b){const n=l(e),t=u(n?.sourceIeeeAddr)??v(n?.source,k),i=u(n?.targetIeeeAddr)??v(n?.target,k);if(!t||!i){r.push({code:"invalid_payload"});continue}const s=c("z2m",o,t),a=c("z2m",o,i);y.has(s)||y.set(s,{key:s,ieee:t,role:"unknown"}),y.has(a)||y.set(a,{key:a,ieee:i,role:"unknown"}),m(w,r,s,a,e)}return{provider:"z2m",instanceId:o,obtainedAt:i,freshness:"fresh-scan",nodes:[...y.values()],links:[...w.values()],warnings:r}}function k(e){if("string"!=typeof e)return null;const n=u(e);if(n)return n;const t=e.toLowerCase().match(/^zigbee2mqtt(?:_bridge)?_(.+)$/);return t?u(t[1]):null}function w(e,n){if(e.deviceId&&n.devices[e.deviceId])return[e.deviceId];const t=new Set;for(const[i,r]of Object.entries(n.devices)){const n=l(r);(Array.isArray(n?.identifiers)?n.identifiers:[]).some(n=>Array.isArray(n)&&k(n[1])===e.ieee)&&t.add(i)}if(t.size)return[...t];for(const i of Object.values(n.entities)){const n=l(i);"string"==typeof n?.device_id&&"string"==typeof n.unique_id&&(k(n.unique_id)===e.ieee&&t.add(n.device_id))}return[...t]}function z(e){return!e.hidden&&!e.virtual&&"ha_disabled"!==e.bindingStatus?.kind&&"orphaned"!==e.bindingStatus?.kind&&"unverified"!==e.bindingStatus?.kind}function A(e){const n=new Map,t=new Map,i=e.nodes.filter(e=>"coordinator"===e.role).map(e=>e.key).sort();if(1!==i.length)return{distances:n,parents:t};const r=i[0],o=function(e){const n=new Set(e.nodes.map(e=>e.key)),t=new Map;for(const e of[...n].sort())t.set(e,[]);for(const i of[...e.links].sort((e,n)=>`${e.a}\0${e.b}`.localeCompare(`${n.a}\0${n.b}`)))n.has(i.a)&&n.has(i.b)&&(t.get(i.a).push({neighborKey:i.b,observation:i.aToB}),t.get(i.b).push({neighborKey:i.a,observation:i.bToA}));for(const e of t.values())e.sort((e,n)=>e.neighborKey.localeCompare(n.neighborKey));return t}(e);if(!o.has(r))return{distances:n,parents:t};n.set(r,0);const s=[r];for(let e=0;en.get(e)===i-1).sort((e,n)=>{const t="parent"===e.observation?.relationship?1:0,i="parent"===n.observation?.relationship?1:0;if(t!==i)return i-t;const r=e.observation?.lqi??-1;return(n.observation?.lqi??-1)-r||e.neighborKey.localeCompare(n.neighborKey)});r[0]&&t.set(e,r[0].neighborKey)}return{coordinatorKey:r,distances:n,parents:t}}function Z(e,n,t){const i=new Map,r=[];for(const o of e.nodes){if(!1===o.available){r.push({code:"provider_scan_failure",nodeKey:o.key});continue}const e=w(o,t);if(1!==e.length){r.push({code:"unmatched_device",nodeKey:o.key});continue}const s=e[0];let a=n.filter(e=>z(e)&&"device"===e.bindingKind&&e.bindingRef===s);a.length||(a=n.filter(e=>z(e)&&"entity"===e.bindingKind&&!!e.bindingRef&&t.entities[e.bindingRef]?.device_id===s)),1===a.length?i.set(o.key,{markerId:a[0].id,space:a[0].space}):r.push({code:a.length>1?"ambiguous_placement":"unmatched_device",nodeKey:o.key})}return{placements:i,warnings:r}}function T(e,n,t){return e.map(e=>({topology:e,placements:Z(e,n,t).placements,routes:A(e)}))}function I(e,n,t){const i=new Map,r=new Set,o=new Map;let s=0;for(const{topology:a,placements:d,routes:l}of e){const e=new Set([...d].filter(([,e])=>e.markerId===t&&e.space===n).map(([e])=>e));if(e.size){for(const t of e){const e=l.parents.get(t);if(!e)continue;const i=d.get(e);if(i?.space===n)continue;let r;r=i?{kind:"remote-space",spaceId:i.space}:"coordinator"===a.nodes.find(n=>n.key===e)?.role?{kind:"unplaced-coordinator"}:{kind:"unplaced-device"};const s="remote-space"===r.kind?`${r.kind}:${r.spaceId}`:r.kind;o.set(s,r)}for(const o of a.links){const a=e.has(o.a),u=e.has(o.b);if(!a&&!u)continue;const c=a?o.a:o.b,p=a?o.b:o.a,h=d.get(p);if(!h||h.markerId===t){s++;continue}const g=l.parents.get(c)===p;if(h.space!==n){g||r.add(h.markerId);continue}const f=a?o.aToB:o.bToA,_=g?"toward-neighbor":l.parents.get(p)===c?"toward-origin":void 0,m=i.get(h.markerId);m?(void 0===m.line.lqi&&void 0!==f?.lqi&&(m.line.lqi=f.lqi),_&&m.directions.add(_)):i.set(h.markerId,{line:{neighborMarkerId:h.markerId,lqi:f?.lqi},directions:new Set(_?[_]:[])})}}}return{lines:[...i.values()].map(({line:e,directions:n})=>1===n.size?{...e,routeDirection:[...n][0]}:e),remoteCount:r.size,omittedCount:s,parentTargets:[...o.values()]}}export{s as T,T as a,y as b,r as h,Z as m,b as n,I as r,o as t}; diff --git a/dist/houseplan-assets/zigbee-topology-runtime-BXasXMdL.js b/dist/houseplan-assets/zigbee-topology-runtime-d-S2Abll.js similarity index 93% rename from dist/houseplan-assets/zigbee-topology-runtime-BXasXMdL.js rename to dist/houseplan-assets/zigbee-topology-runtime-d-S2Abll.js index 105e28f5..5f755073 100644 --- a/dist/houseplan-assets/zigbee-topology-runtime-BXasXMdL.js +++ b/dist/houseplan-assets/zigbee-topology-runtime-d-S2Abll.js @@ -1 +1 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{n as t,b as n}from"./zigbee-topology-D0gydI7H.js";import{aI as e}from"./houseplan-card-BWAph8ZF.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function f(t){if(!0!==t?.user?.is_admin)throw a("permission")}function p(n){const e=i(n);return e?c(e,"zha",async()=>{if(f(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function m(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function g(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(f(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,p=null,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,g=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const f=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&p?.(n):c&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await m(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await m(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{p as readZhaTopology,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot}; +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{n as t,b as n}from"./zigbee-topology-CI6PJorK.js";import{aI as e}from"./houseplan-card-9fMSy3y3.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function f(t){if(!0!==t?.user?.is_admin)throw a("permission")}function p(n){const e=i(n);return e?c(e,"zha",async()=>{if(f(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function m(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function g(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(f(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,p=null,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,g=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const f=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&p?.(n):c&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await m(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await m(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{p as readZhaTopology,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot}; diff --git a/dist/houseplan-card.js b/dist/houseplan-card.js index a151f1cf..7ef80fee 100644 --- a/dist/houseplan-card.js +++ b/dist/houseplan-card.js @@ -1 +1 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";try{await import("./houseplan-assets/houseplan-card-BWAph8ZF.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)} +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";try{await import("./houseplan-assets/houseplan-card-9fMSy3y3.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)} diff --git a/dist/houseplan-panel.js b/dist/houseplan-panel.js index c386a019..4b698642 100644 --- a/dist/houseplan-panel.js +++ b/dist/houseplan-panel.js @@ -1 +1 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";try{await import("./houseplan-assets/houseplan-card-BWAph8ZF.js")}catch(e){if(!customElements.get("houseplan-panel")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-panel",class extends HTMLElement{connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;min-height:100%;background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-panel.js: the card implementation chunk is unavailable",e)}const e=["panel","hass","narrow","route"];class n extends HTMLElement{constructor(){super(),this._narrow=!1,this.attachShadow({mode:"open"}),this._adoptPreUpgradeProperties()}connectedCallback(){this._adoptPreUpgradeProperties(),this._ensureShell()}_adoptPreUpgradeProperties(){for(const n of e){if(!Object.prototype.hasOwnProperty.call(this,n))continue;const e=this[n];delete this[n],this[n]=e}}get hass(){return this._hass}set hass(e){this._hass=e,this._ensureShell(),this._card&&(this._card.hass=e),this._syncMenuLabel()}get narrow(){return this._narrow}set narrow(e){this._narrow=Boolean(e),this.toggleAttribute("narrow",this._narrow),this._card&&(this._card.narrow=this._narrow)}get route(){return this._route}set route(e){this._route=e}get panel(){return this._panel}set panel(e){this._panel=e}_ensureShell(){if(this._card||!this.shadowRoot)return;const e=document.createElement("style");e.textContent="\n :host {\n display: block;\n width: 100%;\n /* HA mounts a custom panel inside , a block with\n * safe-area padding and NO height, so a percentage here resolves to\n * auto and the stage collapses to 0 px (#488). Take the viewport\n * like HA's own iframe panels do, minus the insets HA pads with. */\n height: 100vh;\n height: calc(100dvh - var(--safe-area-inset-top, 0px) - var(--safe-area-inset-bottom, 0px));\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n color: var(--primary-text-color);\n background: var(--primary-background-color);\n }\n .page {\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n display: grid;\n grid-template-rows: auto minmax(0, 1fr);\n overflow: hidden;\n }\n .appbar {\n box-sizing: border-box;\n min-width: 0;\n min-height: var(--header-height, 56px);\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 0 16px;\n background: var(--app-header-background-color, var(--primary-background-color));\n color: var(--app-header-text-color, var(--primary-text-color));\n border-bottom: 1px solid var(--divider-color);\n z-index: 1;\n }\n .toolbar {\n min-width: 0;\n width: 100%;\n display: flex;\n align-items: center;\n gap: 12px;\n }\n .menu {\n box-sizing: border-box;\n width: 44px;\n height: 44px;\n min-width: 44px;\n min-height: 44px;\n margin: 0;\n padding: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: 0;\n border-radius: 50%;\n color: inherit;\n background: transparent;\n cursor: pointer;\n }\n .menu:focus-visible {\n outline: 2px solid var(--primary-color);\n outline-offset: 2px;\n }\n @media (hover: hover) {\n .menu:hover { background: var(--secondary-background-color); }\n }\n .menu ha-icon { --mdc-icon-size: 24px; }\n .title {\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 20px;\n font-weight: 500;\n line-height: 1.2;\n }\n .title ha-icon {\n --mdc-icon-size: 24px;\n color: var(--primary-color);\n }\n .content {\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n }\n houseplan-card {\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n }\n ";const n=document.createElement("div");n.className="page";const t=document.createElement("header");t.className="appbar";const a=document.createElement("div");a.className="toolbar",a.setAttribute("role","toolbar");const o=document.createElement("button");o.className="menu",o.dataset.hp="panel-menu",o.type="button",o.innerHTML='',o.addEventListener("click",()=>{o.dispatchEvent(new CustomEvent("hass-toggle-menu",{bubbles:!0,composed:!0}))}),this._menuButton=o;const i=document.createElement("div");i.className="title",i.dataset.hp="panel-title",i.setAttribute("role","heading"),i.setAttribute("aria-level","1"),i.innerHTML='House Plan',a.append(o,i),t.append(a);const r=document.createElement("main");r.className="content";const s=document.createElement("houseplan-card");s.panelHost=!0,s.narrow=this._narrow,s.setConfig({type:"custom:houseplan-card"}),void 0!==this._hass&&(s.hass=this._hass),r.append(s),n.append(t,r),this.shadowRoot.append(e,n),this._card=s,this._syncMenuLabel()}_syncMenuLabel(){if(!this._menuButton)return;const e=this._hass?.localize?.("ui.common.menu")||this._hass?.localize?.("ui.panel.lovelace.menu")||"Menu";this._menuButton.setAttribute("aria-label",e),this._menuButton.title=e}}customElements.get("houseplan-panel")||customElements.define("houseplan-panel",n);export{n as HouseplanPanel}; +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";try{await import("./houseplan-assets/houseplan-card-9fMSy3y3.js")}catch(e){if(!customElements.get("houseplan-panel")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-panel",class extends HTMLElement{connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;min-height:100%;background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-panel.js: the card implementation chunk is unavailable",e)}const e=["panel","hass","narrow","route"];class n extends HTMLElement{constructor(){super(),this._narrow=!1,this.attachShadow({mode:"open"}),this._adoptPreUpgradeProperties()}connectedCallback(){this._adoptPreUpgradeProperties(),this._ensureShell()}_adoptPreUpgradeProperties(){for(const n of e){if(!Object.prototype.hasOwnProperty.call(this,n))continue;const e=this[n];delete this[n],this[n]=e}}get hass(){return this._hass}set hass(e){this._hass=e,this._ensureShell(),this._card&&(this._card.hass=e),this._syncMenuLabel()}get narrow(){return this._narrow}set narrow(e){this._narrow=Boolean(e),this.toggleAttribute("narrow",this._narrow),this._card&&(this._card.narrow=this._narrow)}get route(){return this._route}set route(e){this._route=e}get panel(){return this._panel}set panel(e){this._panel=e}_ensureShell(){if(this._card||!this.shadowRoot)return;const e=document.createElement("style");e.textContent="\n :host {\n display: block;\n width: 100%;\n /* HA mounts a custom panel inside , a block with\n * safe-area padding and NO height, so a percentage here resolves to\n * auto and the stage collapses to 0 px (#488). Take the viewport\n * like HA's own iframe panels do, minus the insets HA pads with. */\n height: 100vh;\n height: calc(100dvh - var(--safe-area-inset-top, 0px) - var(--safe-area-inset-bottom, 0px));\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n color: var(--primary-text-color);\n background: var(--primary-background-color);\n }\n .page {\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n display: grid;\n grid-template-rows: auto minmax(0, 1fr);\n overflow: hidden;\n }\n .appbar {\n box-sizing: border-box;\n min-width: 0;\n min-height: var(--header-height, 56px);\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 0 16px;\n background: var(--app-header-background-color, var(--primary-background-color));\n color: var(--app-header-text-color, var(--primary-text-color));\n border-bottom: 1px solid var(--divider-color);\n z-index: 1;\n }\n .toolbar {\n min-width: 0;\n width: 100%;\n display: flex;\n align-items: center;\n gap: 12px;\n }\n .menu {\n box-sizing: border-box;\n width: 44px;\n height: 44px;\n min-width: 44px;\n min-height: 44px;\n margin: 0;\n padding: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: 0;\n border-radius: 50%;\n color: inherit;\n background: transparent;\n cursor: pointer;\n }\n .menu:focus-visible {\n outline: 2px solid var(--primary-color);\n outline-offset: 2px;\n }\n @media (hover: hover) {\n .menu:hover { background: var(--secondary-background-color); }\n }\n .menu ha-icon { --mdc-icon-size: 24px; }\n .title {\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 20px;\n font-weight: 500;\n line-height: 1.2;\n }\n .title ha-icon {\n --mdc-icon-size: 24px;\n color: var(--primary-color);\n }\n .content {\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n }\n houseplan-card {\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n }\n ";const n=document.createElement("div");n.className="page";const t=document.createElement("header");t.className="appbar";const a=document.createElement("div");a.className="toolbar",a.setAttribute("role","toolbar");const o=document.createElement("button");o.className="menu",o.dataset.hp="panel-menu",o.type="button",o.innerHTML='',o.addEventListener("click",()=>{o.dispatchEvent(new CustomEvent("hass-toggle-menu",{bubbles:!0,composed:!0}))}),this._menuButton=o;const i=document.createElement("div");i.className="title",i.dataset.hp="panel-title",i.setAttribute("role","heading"),i.setAttribute("aria-level","1"),i.innerHTML='House Plan',a.append(o,i),t.append(a);const r=document.createElement("main");r.className="content";const s=document.createElement("houseplan-card");s.panelHost=!0,s.narrow=this._narrow,s.setConfig({type:"custom:houseplan-card"}),void 0!==this._hass&&(s.hass=this._hass),r.append(s),n.append(t,r),this.shadowRoot.append(e,n),this._card=s,this._syncMenuLabel()}_syncMenuLabel(){if(!this._menuButton)return;const e=this._hass?.localize?.("ui.common.menu")||this._hass?.localize?.("ui.panel.lovelace.menu")||"Menu";this._menuButton.setAttribute("aria-label",e),this._menuButton.title=e}}customElements.get("houseplan-panel")||customElements.define("houseplan-panel",n);export{n as HouseplanPanel}; diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 5416bc78..241f2c06 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -19,8 +19,8 @@ switch — turning it off opens a five-mode segment that starts at the space's current mode; comfort bounds are two °C fields with a Cold / Comfort / Hot legend. **Save** is enabled only when something changed, and closing a - dialog with unsaved changes asks first; broken values (an inverted or empty - bound, a north outside 0–359°, a missing binding, a non-positive glow radius) + dialog with unsaved changes asks first; broken values (an empty or + non-numeric bound, a north outside 0–359°, a missing binding) are named under the field and a "Review N fields" link in the footer jumps to the first one. The "Ask for confirmation" row is shown only for actions that do something; the Zigbee links card no longer repeats its heading; the diff --git a/docs/CHANGELOG.ru.md b/docs/CHANGELOG.ru.md index 780d6f43..767e562a 100755 --- a/docs/CHANGELOG.ru.md +++ b/docs/CHANGELOG.ru.md @@ -27,8 +27,7 @@ два поля °C с легендой «Холодно / Комфорт / Жарко». **Сохранить** активна только при изменениях, закрытие с несохранёнными изменениями сначала спрашивает; сломанные значения (пустая или нечисловая граница, север вне - 0–359°, не выбранная привязка, неположительный радиус свечения) названы под - полем, а ссылка «Проверить N полей» в футере ведёт к первому. Строка + 0–359°, не выбранная привязка) названы под полем, а ссылка «Проверить N полей» в футере ведёт к первому. Строка «Спрашивать подтверждение» показывается только у действий; карточка «Связи Zigbee» больше не повторяет заголовок; ленивый редактор загружается с простым «Загрузка…». Все настройки, ключи и сохранённые значения прежние — переделаны diff --git a/docs/USER-GUIDE.md b/docs/USER-GUIDE.md index 162616ae..2f7f3ccb 100644 --- a/docs/USER-GUIDE.md +++ b/docs/USER-GUIDE.md @@ -463,7 +463,7 @@ elements: changes". Closing a dialog with unsaved changes — by the close button, **Cancel** or a click outside — asks first whether to discard them. An invalid value — an empty or non-numeric temperature bound, a north outside 0–359°, a -missing binding, a non-positive glow radius — is named in red under the field, +missing binding — is named in red under the field, and the **Review N fields** link in the footer jumps to the first one. ### Display settings @@ -793,7 +793,8 @@ chosen, Save stays disabled and the reason is written under the field. **Ask for confirmation** is shown only for actions that do something (toggle or run). The light-source role and the glow mode are segments; with **Never** the whole glow block is dimmed and explains why. The glow radius is a field with a -unit — empty means the general radius, and the hint names it. The dialog shows +unit — empty means the general radius, and the hint names it; a value that is +not a positive number is saved as the general radius too, as before. The dialog shows binding provenance, exact next tap result, skipped targets and a live presentation preview in a tinted **Display preview** block. Icon size and rotation are two sliders with numbers. A saved missing source is shown as diff --git a/docs/USER-GUIDE.ru.md b/docs/USER-GUIDE.ru.md index 6d6762ba..219e20f6 100644 --- a/docs/USER-GUIDE.ru.md +++ b/docs/USER-GUIDE.ru.md @@ -409,9 +409,9 @@ Zigbee2MQTT для каждого указанного базового топи написано «Есть несохранённые изменения». Если закрыть диалог крестиком, кнопкой **Отмена** или щелчком мимо него при несохранённых изменениях, House Plan сначала спросит, сбросить ли их. Неверное значение — пустая или нечисловая -граница температуры, север вне 0–359°, не выбранная привязка, неположительный -радиус свечения — подписано под полем красным, а ссылка **Проверить N полей** в -футере ведёт к первому такому полю. +граница температуры, север вне 0–359°, не выбранная привязка — подписано под +полем красным, а ссылка **Проверить N полей** в футере ведёт к первому такому +полю. @@ -524,9 +524,9 @@ desktop: для точного рисования, Resize, модификато | Масштаб | См или дюймов на клетку | Переводит сетку в реальные размеры и площади; новое пространство начинается с 1 см или 1 дюйма по системе единиц HA | | Внешний вид | Всегда отображать границы комнат | Строка с тумблером: рисует контуры комнат в просмотре | | Внешний вид | Стены нулевой толщины | Сегмент «Пунктирные / Сплошные» с образцом линии | -| Внешний вид | Видимые слои | Две строки с тумблерами: **Декоративный слой** и **Двери, окна и ворота**. Включено — видно; выключенный декоративный слой не рисует линии, фигуры, текст и мебель в просмотре, выключенные проёмы скрывают только их символы — свет, солнечные лучи и датчики продолжают работать | +| Внешний вид | Видимые слои | Две строки с тумблерами: **Декоративный слой** и **Двери, окна и ворота**. Включено — видно; выключенный декоративный слой не рисует линии, фигуры, текст и мебель в просмотре (в редакторе подложки они остаются видимыми), выключенные проёмы скрывают только их символы — свет, солнечные лучи и датчики продолжают работать | | Карточки комнат | Показывать названия комнат | Рисует карточки комнат в Просмотре, киоске и статической карточке; при выключении не оставляет упрощённых подписей | -| Карточки комнат | Сигнал Zigbee рядом с устройствами | Переопределяет базовую настройку карточки для этого пространства |ожки они остаются видимыми | +| Карточки комнат | Сигнал Zigbee рядом с устройствами | Переопределяет базовую настройку карточки для этого пространства | | Карточки комнат | Температура / влажность / сигнал / свет | Четыре плитки под тумблером названий добавляют показатели под названием комнаты; без названий плитки неактивны, а сообщение предлагает включить их | | Карточки комнат | Размер шрифта карточек | Слайдер с числом и «Сбросить до 100%»: масштабирует все комнатные карточки пространства, 50–300%; ниже — образец карточки | @@ -1071,7 +1071,7 @@ binding tombstone не вырезает её из живого устройст | Использовать температуру climate | Добавляет `current_temperature` термостата/кондиционера в маркер и среднее назначенной ему комнаты | | Скрыть / Показать | Кнопка слева в футере диалога. После сохранения убирает или возвращает значок; LQI и климатические данные скрытого устройства всё ещё могут участвовать в среднем назначенной комнаты | | Удалить | Кнопка рядом со «Скрыть». Общий диалог House Plan называет устройство и объясняет последствия; после подтверждения устройство полностью исчезает с плана и позднее может быть добавлено заново | -| Радиус свечения | Поле с единицей; пустое — общий радиус, подсказка называет его. Локально переопределяет общий радиус, 0.1–100 м в хранилище | +| Радиус свечения | Поле с единицей; пустое — общий радиус, подсказка называет его; значение, не являющееся положительным числом, тоже сохраняется как общий радиус, как и раньше. Локально переопределяет общий радиус, 0.1–100 м в хранилище | | Иконка | Ручная `mdi:*`; пусто — автоматический подбор. Автовариант показывается в поле как значок с именем `mdi:*`, но не сохраняется как ручная замена | | Отображение | Иконка, иконка + активность или значение вместо иконки. Ниже сразу видны фактический результат, источник и интеграция | | Размер и поворот иконки | Два слайдера с числами: масштаб маркера (×0.5–×3) и угол (шаг 5°) | @@ -1731,7 +1731,7 @@ WebP и безопасный SVG; лимит 2 МиБ относится к со | Толстая внешняя стена, режим «внутренние углы» | Луч начинается с комнатной стороны оконного тоннеля | | Толстая внешняя стена, режим «внешние углы» | Луч начинается с фасадной стороны и проходит к комнате только внутри оконного тоннеля | | Стена нулевой толщины | Оба режима выглядят одинаково | -| «Скрыть проёмы» включено | Символ окна скрыт, луч продолжает работать | +| Слой «Двери, окна и ворота» выключен | Символ окна скрыт, луч продолжает работать | | Белый план | По бокам луча есть тонкая 1px тёмная кромка для читаемости | | Любая погода, включая дождь и снег | Погода не влияет на лучи | diff --git a/docs/design/600-settings-dialogs/ACCEPTANCE.md b/docs/design/600-settings-dialogs/ACCEPTANCE.md index f61caf65..6794ba9d 100644 --- a/docs/design/600-settings-dialogs/ACCEPTANCE.md +++ b/docs/design/600-settings-dialogs/ACCEPTANCE.md @@ -25,8 +25,11 @@ Always и фиксированным свечением), раскрывает из архива дизайнера (светлая тема, 1120 px при devicePixelRatio 2). Это **диагностические** кадры, а не golden-базы: они не принимаются -`golden:accept` и не участвуют в `golden:verify`. Эталоны одиннадцати сцен живут -отдельно и закрываются AC10. PNG пережаты в палитру 256 цветов — для сравнения +`golden:accept` и не участвуют в `golden:verify`. Эталоны живут отдельно и +закрываются AC10: принято **13 сцен** (`ed2af1b1`) — одиннадцать из ТЗ (список +AC10 унаследован от #598, где диалог комнаты не менялся) плюс две +`room-temperature-dialog-{desktop-en,mobile-ru}`, потому что диалог комнаты в +скоупе #600. PNG пережаты в палитру 256 цветов — для сравнения раскладки этого достаточно, а вес папки остаётся в полумегабайте. ## Статус по диалогам @@ -66,7 +69,7 @@ Always и фиксированным свечением), раскрывает |---|---|---|---| | Образец карточки | убран (§6.1 «Font sizes») | под подсказкой размеров, на тинте | решение владельца Q2 | | «?» у Basics | у поля Home Assistant area | у поля Home Assistant area (перенесён с заголовка карточки) | §6.1 | -| Подписи сегмента заливки | None · Zigbee · Lights · Temperature · Custom | None · Zigbee · Lights · Temperature · Custom (короткие ключи `room.fill_seg_*` для двух длинных) | §6.1 | +| Подписи сегмента заливки | None · Zigbee · Lights · Temperature · Custom, по одной строке на пункт | те же (короткие ключи `room.fill_seg_*` для двух длинных). Ревью r1 M1: «Temperature» рвалось посреди слова в пяти равных колонках — колонка сегмента больше не сжимается ниже самого длинного слова, слова переносятся только по пробелам, не поместившийся сегмент переносится на вторую строку целыми кнопками; свидетель — `smoke_dialog_segments_i18n` (четыре диалога × en/ru/de/fr) | §6.1, §3.1 «Сегмент» | | Подписи источников | Temperature / Humidity | Temperature source / Humidity source (прежние ключи) | текст, не раскладка | | Поле цвета «Свой цвет» | `input[type=color]` | плашка вокруг `hp-color-opacity` | Q5 | | Кнопка выбора датчика | в потоке, панель с поиском | то же (`sourcePicker` набора) | §3.1 «Кнопка выбора источника» | @@ -83,6 +86,20 @@ Always и фиксированным свечением), раскрывает | Иконка | поле с превью, Clear, Pin в подсказке | то же; в HA — `ha-icon-picker` вместо текстового поля | §7.1 | | Value badge | тумблер, Value, Position сегментом | то же; предупреждения бейджа — заметки и callout'ы | §7.1 | +## AC8: девять прямых дефектов выпущенного — свидетель на каждый + +| № | Дефект (тело issue) | Чем закрыт | Свидетель | +|---|---|---|---| +| 1 | дублированный заголовок Zigbee links | карточка рисует заголовок и «?», `hp-zigbee-topology-settings` в режиме `embedded` своего не рисует | `smoke_general_settings_form` → `zigbeeHeadingOnce`; мутант `topology-embedded-draws-its-own-heading` | +| 2 | «Fill color» дважды в строке заливки пространства | плашка цвета с одной подписью поля (`colorRow` + `colorField`, у пикера `hide-label`) | `smoke_space_settings_form` → `hexIsPrinted`, `noNativeColorInputs`; `noLegacyMarkup` | +| 3 | семь `rhint`-абзацев в четырёх диалогах | пояснения — под «?» (`_help`/`shelp`), сообщения о состоянии — callout'ы (К5) | `noLegacyMarkup` в четырёх фокусных смоках (класс `.rhint` отсутствует); `test/i18n-dead-keys`; мутант `state-callout-hidden-under-help` | +| 4 | карточка внутри карточки (`fieldset` в Light and glow, Value badge) | плоские блоки `.hpf-block` с подзаголовком | `smoke_device_settings_form` → `noLegacyMarkup` (`fieldset`, `.markerlightgroup`), `badgeBlock`, `neverDisablesGlowBlock` | +| 5 | поповер «?» обрезается границей диалога комнаты | подсказка живёт в top layer (Popover API) либо в портале `.overlay-portal` **вне** поверхности диалога; тело формы без своего скроллера — резать нечем | **`smoke_dialog_help_clipping`**: короткое окно, «?» нижней карточки комнаты, подсказка выходит за край скроллера и остаётся hit-test'ируемой во всех точках; четыре ветки — нативный `` и `ha-dialog` × Popover и fallback. Ветка `ha-dialog` — заглушка с ловушками настоящей mwc-поверхности (`transform` + `overflow: hidden` + свой скроллер); настоящий `ha-dialog` (#505, загрузка колеса HA-frontend) — отдельная диагностическая приёмка владельца, `demo/capture_summary_panel_505.mjs` как образец | +| 6 | белый инпут на тёмной теме у Glow radius | поле набора `.hpf-unit` на токенах темы | `pairs/device-dark.png`; `smoke_device_settings_form` | +| 7 | два скролла (тело формы и оболочка) | скроллер один — `.content` в `hp-dialog`; `.body` без `max-height`/`overflow` | фокусные смоки → `singleScroller` / `bodyHasNoOwnScroller` | +| 8 | пустое пространство внизу | `.body` без `max-height` и лишнего `padding-bottom` | те же; кадры `pairs/` | +| 9 | «Загружаем редактор…» | `editor.loading` → «Загрузка…» / «Loading…» | `src/i18n/*.json` | + ## Принятые адаптации Расхождения, которые **не** являются дефектом, потому что продиктованы diff --git a/scripts/mutation-registry.mjs b/scripts/mutation-registry.mjs index c2643019..95d5b73a 100644 --- a/scripts/mutation-registry.mjs +++ b/scripts/mutation-registry.mjs @@ -10496,6 +10496,23 @@ const MUTANT_DEFINITIONS = [ replace: " valueBadgePosition: position,\n valueBadgeTouched: false,", }], }, + { + id: 'form-kit-segment-breaks-words', + guard: 'node demo/smoke_dialog_segments_i18n.mjs', + because: '#600 ревью r1 M1: пять равных колонок сегмента с overflow-wrap: anywhere рвали ' + + '«Temperature» посреди слова, и ни один смок этого не видел — scrollWidth контейнера не ' + + 'рос. Колонка не сжимается ниже самого длинного слова, слова переносятся только по ' + + 'пробелам; вернуть прежние две строки — вернуть дефект в четырёх локалях', + patches: [{ + file: 'src/styles/form-kit.styles.ts', + find: ' min-width: fit-content;\n min-height: 38px;\n flex: 1 1 0;', + replace: ' min-height: 38px;\n flex: 1 1 0;', + }, { + file: 'src/styles/form-kit.styles.ts', + find: ' text-align: center;\n overflow-wrap: normal;\n }', + replace: ' text-align: center;\n overflow-wrap: anywhere;\n }', + }], + }, { id: 'form-kit-segment-drops-radio-semantics', guard: 'node --test test/form-kit.test.mjs', diff --git a/src/editors/marker-dialog.ts b/src/editors/marker-dialog.ts index 48c144fd..87d4f66c 100644 --- a/src/editors/marker-dialog.ts +++ b/src/editors/marker-dialog.ts @@ -187,7 +187,6 @@ export function renderMarkerDialog(this: HouseplanEditorRuntime): TemplateResult node?.focus(); }; const bindingProblem = problemFor('marker-binding'); - const radiusProblem = problemFor('marker-glow-radius'); // ------------------------------------------------------------ Basics const bindingBanner = bindingStatus?.kind === 'ha_disabled' @@ -565,12 +564,11 @@ export function renderMarkerDialog(this: HouseplanEditorRuntime): TemplateResult ${glowValue} ${field({ label: t('marker.glow_radius_label'), htmlFor: 'marker-glow-radius', help: this._help('marker.glow_radius.help'), - error: radiusProblem ? st(radiusProblem.message) : undefined, hint: d.glowRadius.trim() ? undefined : st('marker.glow_radius_empty_hint', { v: `${this.host._glowRadiusPlaceholder} ${unit}` }), control: unitInput({ id: 'marker-glow-radius', unit, min: 0.5, step: 0.5, value: d.glowRadius, placeholder: this.host._glowRadiusPlaceholder, ariaLabel: t('marker.glow_radius_label'), - disabled: glowSourceDisabled, invalid: !!radiusProblem, + disabled: glowSourceDisabled, describedBy: glowSourceDisabled || passiveSource ? 'marker-glow-disabled-hint' : undefined, onInput: (raw) => (this.host._markerDialog = { ...d, glowRadius: raw }), }), diff --git a/src/editors/marker-form-state.ts b/src/editors/marker-form-state.ts index ed3eb115..12452887 100644 --- a/src/editors/marker-form-state.ts +++ b/src/editors/marker-form-state.ts @@ -6,7 +6,6 @@ * в отпечаток не входят. Флаги `*Touched` и `original*` входят: они меняются * только действием человека, и это тоже изменение. */ -import { strictNumber } from '../space-dialog'; import type { HouseplanEditorHostPort } from '../houseplan-editor-runtime'; import { dialogDirty, forgetDialogBaseline, rememberDialogBaseline, stableKey } from './dialog-baseline'; @@ -34,28 +33,20 @@ export function markerDirty(host: object, d: MarkerDialogDraft): boolean { export interface MarkerProblem { field: string; - message: 'marker.error_binding' | 'marker.error_glow_radius'; -} - -/** Радиус: пусто (общий радиус) либо положительное число — тем же парсером, что и запись. */ -export function glowRadiusValid(raw: string): boolean { - if (!raw.trim()) return true; - const n = strictNumber(raw); - return n !== null && n > 0; + message: 'marker.error_binding'; } /** - * Ошибки черновика (§7 референса): привязка обязательна в режиме HA (прежнее - * условие Save, теперь названное словами), радиус свечения — положительное число - * либо пусто (общий радиус). + * Ошибки черновика: привязка обязательна в режиме HA — прежнее условие Save, + * теперь названное словами под полем. Радиус свечения ошибкой **не является** + * (ревью #600 r1, M2): как и на `dev`, непустое нечисло или неположительное + * значение при сохранении молча становится «общим радиусом» (`null`), и К10 + * закрытым списком других условий не называет. */ export function markerProblems(d: MarkerDialogDraft): MarkerProblem[] { const problems: MarkerProblem[] = []; if (d.bindingMode === 'ha' && (!d.binding || d.binding === 'virtual')) { problems.push({ field: 'marker-binding', message: 'marker.error_binding' }); } - if (!glowRadiusValid(d.glowRadius)) { - problems.push({ field: 'marker-glow-radius', message: 'marker.error_glow_radius' }); - } return problems; } diff --git a/src/i18n/settings/de.json b/src/i18n/settings/de.json index ca9ee148..a45cf872 100644 --- a/src/i18n/settings/de.json +++ b/src/i18n/settings/de.json @@ -85,7 +85,6 @@ "marker.size.help.aria": "Hilfe: Symbolgröße und Drehung", "marker.size_short": "Größe", "marker.error_binding": "Wählen Sie ein Gerät oder eine Entität zum Verknüpfen.", - "marker.error_glow_radius": "Geben Sie einen Radius größer als 0 ein oder lassen Sie das Feld leer.", "room.fill_seg_lqi": "Zigbee", "room.fill_seg_custom": "Eigene" } diff --git a/src/i18n/settings/en.json b/src/i18n/settings/en.json index c1a46f9c..6450603a 100644 --- a/src/i18n/settings/en.json +++ b/src/i18n/settings/en.json @@ -85,7 +85,6 @@ "marker.size.help.aria": "Help: icon size and rotation", "marker.size_short": "Size", "marker.error_binding": "Choose a device or entity to bind.", - "marker.error_glow_radius": "Enter a radius greater than 0, or leave it empty.", "room.fill_seg_lqi": "Zigbee", "room.fill_seg_custom": "Custom" } diff --git a/src/i18n/settings/fr.json b/src/i18n/settings/fr.json index fff4fc22..6858b649 100644 --- a/src/i18n/settings/fr.json +++ b/src/i18n/settings/fr.json @@ -85,7 +85,6 @@ "marker.size.help.aria": "Aide : taille et rotation de l’icône", "marker.size_short": "Taille", "marker.error_binding": "Choisissez un appareil ou une entité à lier.", - "marker.error_glow_radius": "Saisissez un rayon supérieur à 0 ou laissez le champ vide.", "room.fill_seg_lqi": "Zigbee", "room.fill_seg_custom": "Perso" } diff --git a/src/i18n/settings/ru.json b/src/i18n/settings/ru.json index 6a73c6e1..25fc1d4a 100644 --- a/src/i18n/settings/ru.json +++ b/src/i18n/settings/ru.json @@ -85,7 +85,6 @@ "marker.size.help.aria": "Справка: размер и поворот иконки", "marker.size_short": "Размер", "marker.error_binding": "Выберите устройство или сущность для привязки.", - "marker.error_glow_radius": "Введите радиус больше 0 или оставьте поле пустым.", "room.fill_seg_lqi": "Zigbee", "room.fill_seg_custom": "Свой цвет" } diff --git a/src/styles/form-kit.styles.ts b/src/styles/form-kit.styles.ts index b3791174..68999c4a 100644 --- a/src/styles/form-kit.styles.ts +++ b/src/styles/form-kit.styles.ts @@ -144,6 +144,13 @@ function sharedCss(options: FormKitCssOptions, withSwitch: boolean): string { * Числа — из §3.1 `SPEC.md` референса; цвета — через переменные темы HA, а не * hex прототипа: тёмная тема обязательна. Всё здесь видит только ленивый * редакторский граф — панель эти правила не получает (#597 К9). + * + * Сегмент (`-seg`): подпись варианта не рвётся посреди слова (ревью #600 r1, + * M1 — «Temperatur/e» в пяти колонках). Колонка не сжимается ниже самого + * длинного слова (`min-width: fit-content`; браузер без него берёт `0` + * строкой выше), слова переносятся только по пробелам (`overflow-wrap: + * normal`), а если варианты не помещаются в ряд — сегмент переносится на + * вторую строку целыми кнопками (`flex-wrap`), а не ломает текст. */ function extrasCss(options: FormKitCssOptions): string { const { form, prefix, tokens } = options; @@ -285,6 +292,7 @@ function extrasCss(options: FormKitCssOptions): string { .${p}-toggle > input:disabled::before { opacity: .4; } .${p}-seg { display: flex; + flex-wrap: wrap; min-width: 0; gap: 3px; padding: 3px; @@ -296,6 +304,7 @@ function extrasCss(options: FormKitCssOptions): string { position: relative; display: flex; min-width: 0; + min-width: fit-content; min-height: 38px; flex: 1 1 0; align-items: center; @@ -309,7 +318,7 @@ function extrasCss(options: FormKitCssOptions): string { font-weight: 500; cursor: pointer; text-align: center; - overflow-wrap: anywhere; + overflow-wrap: normal; } .${p}-seg input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; pointer-events: none; } .${p}-seg label:has(input:checked) { diff --git a/test/fixtures/form-kit-card-dialog-with-switch.css b/test/fixtures/form-kit-card-dialog-with-switch.css index b9fd63ba..6b21b1d1 100644 --- a/test/fixtures/form-kit-card-dialog-with-switch.css +++ b/test/fixtures/form-kit-card-dialog-with-switch.css @@ -166,6 +166,7 @@ .hpf-toggle > input:disabled::before { opacity: .4; } .hpf-seg { display: flex; + flex-wrap: wrap; min-width: 0; gap: 3px; padding: 3px; @@ -177,6 +178,7 @@ position: relative; display: flex; min-width: 0; + min-width: fit-content; min-height: 38px; flex: 1 1 0; align-items: center; @@ -190,7 +192,7 @@ font-weight: 500; cursor: pointer; text-align: center; - overflow-wrap: anywhere; + overflow-wrap: normal; } .hpf-seg input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; pointer-events: none; } .hpf-seg label:has(input:checked) { diff --git a/test/fixtures/form-kit-card-dialog.css b/test/fixtures/form-kit-card-dialog.css index 790c5c24..a99598b2 100644 --- a/test/fixtures/form-kit-card-dialog.css +++ b/test/fixtures/form-kit-card-dialog.css @@ -152,6 +152,7 @@ .hpf-toggle > input:disabled::before { opacity: .4; } .hpf-seg { display: flex; + flex-wrap: wrap; min-width: 0; gap: 3px; padding: 3px; @@ -163,6 +164,7 @@ position: relative; display: flex; min-width: 0; + min-width: fit-content; min-height: 38px; flex: 1 1 0; align-items: center; @@ -176,7 +178,7 @@ font-weight: 500; cursor: pointer; text-align: center; - overflow-wrap: anywhere; + overflow-wrap: normal; } .hpf-seg input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; pointer-events: none; } .hpf-seg label:has(input:checked) {