diff --git a/custom_components/houseplan/frontend/houseplan-assets.json b/custom_components/houseplan/frontend/houseplan-assets.json index 665f05bc..e5d92202 100644 --- a/custom_components/houseplan/frontend/houseplan-assets.json +++ b/custom_components/houseplan/frontend/houseplan-assets.json @@ -1,111 +1,111 @@ { "schema": 1, - "fingerprint": "e6c51f2467ae4e22a792e536ae954291ab5a46915e728b216c8c45bc6816b209", + "fingerprint": "817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073", "entry": "houseplan-card.js", "initialViewFiles": [ - "houseplan-assets/houseplan-card-DI__VUPO.js", + "houseplan-assets/houseplan-card-BrUCyMoE.js", "houseplan-card.js" ], - "initialViewGzipBytes": 272469, + "initialViewGzipBytes": 271841, "lazyFiles": [ - "houseplan-assets/de-gTJXGK7s.js", - "houseplan-assets/editor-LGCA8WjH.js", - "houseplan-assets/houseplan-editor-runtime-Cu2NFP8N.js", - "houseplan-assets/houseplan-onboarding-runtime-B4PXZ4um.js", - "houseplan-assets/space-deletion-Do1Uuvoz.js" + "houseplan-assets/de-CndLXoON.js", + "houseplan-assets/editor-H80bjnWS.js", + "houseplan-assets/houseplan-editor-runtime-LLPkWHY0.js", + "houseplan-assets/houseplan-onboarding-runtime-BkWWzfSR.js", + "houseplan-assets/space-deletion-CLA5ezlL.js" ], - "lazyGzipBytes": 166314, + "lazyGzipBytes": 165904, "lazyEditorFiles": [ - "houseplan-assets/editor-LGCA8WjH.js", - "houseplan-assets/houseplan-editor-runtime-Cu2NFP8N.js", - "houseplan-assets/space-deletion-Do1Uuvoz.js" + "houseplan-assets/editor-H80bjnWS.js", + "houseplan-assets/houseplan-editor-runtime-LLPkWHY0.js", + "houseplan-assets/space-deletion-CLA5ezlL.js" ], - "lazyEditorGzipBytes": 137196, + "lazyEditorGzipBytes": 136806, "lazyOnboardingFiles": [ - "houseplan-assets/houseplan-onboarding-runtime-B4PXZ4um.js", - "houseplan-assets/space-deletion-Do1Uuvoz.js" + "houseplan-assets/houseplan-onboarding-runtime-BkWWzfSR.js", + "houseplan-assets/space-deletion-CLA5ezlL.js" ], - "lazyOnboardingGzipBytes": 7204, + "lazyOnboardingGzipBytes": 7193, "lazyLocaleFiles": [ - "houseplan-assets/de-gTJXGK7s.js" + "houseplan-assets/de-CndLXoON.js" ], - "lazyLocaleGzipBytes": 22468, + "lazyLocaleGzipBytes": 22454, "files": [ { - "path": "houseplan-assets/de-gTJXGK7s.js", - "sha256": "2ed2a8aad10d9eaa16fe3fe2e591c2d736d948b2fd35aca01fcffb33264e1284", + "path": "houseplan-assets/de-CndLXoON.js", + "sha256": "c3fb30be483664a92a555e2a916d2d6201a5d950d77385a34869445625732be1", "rawBytes": 73919, - "gzipBytes": 22468, + "gzipBytes": 22454, "isEntry": false, "imports": [], "dynamicImports": [] }, { - "path": "houseplan-assets/editor-LGCA8WjH.js", - "sha256": "0f4ce2555703ec01ee188cf84badfdee661587e849c1b604ec88354c3f94894f", + "path": "houseplan-assets/editor-H80bjnWS.js", + "sha256": "bcd9f271360a94dfbf63d5bcdf3c965aed1e1b17d0c543ac0b554d5527b90250", "rawBytes": 3831, - "gzipBytes": 1585, + "gzipBytes": 1580, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-DI__VUPO.js" + "houseplan-assets/houseplan-card-BrUCyMoE.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/houseplan-card-DI__VUPO.js", - "sha256": "35a537b289b388f34a5f6efc01a95254207be9880fa9fd931723ccfa258ad602", - "rawBytes": 960284, - "gzipBytes": 271715, + "path": "houseplan-assets/houseplan-card-BrUCyMoE.js", + "sha256": "bdcf3f7e9306428b2583f1e662541bebebcf2f106b48a53df117c6c9c54c5cde", + "rawBytes": 958245, + "gzipBytes": 271090, "isEntry": false, "imports": [], "dynamicImports": [ - "houseplan-assets/de-gTJXGK7s.js", - "houseplan-assets/editor-LGCA8WjH.js", - "houseplan-assets/houseplan-editor-runtime-Cu2NFP8N.js", - "houseplan-assets/houseplan-onboarding-runtime-B4PXZ4um.js" + "houseplan-assets/de-CndLXoON.js", + "houseplan-assets/editor-H80bjnWS.js", + "houseplan-assets/houseplan-editor-runtime-LLPkWHY0.js", + "houseplan-assets/houseplan-onboarding-runtime-BkWWzfSR.js" ] }, { - "path": "houseplan-assets/houseplan-editor-runtime-Cu2NFP8N.js", - "sha256": "4eb656ee069026534dace297817908e97d0e82e63ba1059d0c3d6c283d913344", - "rawBytes": 522188, - "gzipBytes": 135057, + "path": "houseplan-assets/houseplan-editor-runtime-LLPkWHY0.js", + "sha256": "e49282b51d104baff861b3c21261e66dcbfd58807e0db444b04f1f171499e24d", + "rawBytes": 520292, + "gzipBytes": 134677, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-DI__VUPO.js", - "houseplan-assets/space-deletion-Do1Uuvoz.js" + "houseplan-assets/houseplan-card-BrUCyMoE.js", + "houseplan-assets/space-deletion-CLA5ezlL.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/houseplan-onboarding-runtime-B4PXZ4um.js", - "sha256": "73ad6471b2395b982d233754598fcb6fb296c29b01a188cce724c2861e044187", + "path": "houseplan-assets/houseplan-onboarding-runtime-BkWWzfSR.js", + "sha256": "5446043fbf2a383f84df3751b1fd97ecac72d8bcf3c254da80ad4176538c91da", "rawBytes": 26356, - "gzipBytes": 6650, + "gzipBytes": 6644, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-DI__VUPO.js", - "houseplan-assets/space-deletion-Do1Uuvoz.js" + "houseplan-assets/houseplan-card-BrUCyMoE.js", + "houseplan-assets/space-deletion-CLA5ezlL.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/space-deletion-Do1Uuvoz.js", - "sha256": "258cd7b7338ca746122d6afcfc63f81d34be23a7bd31f1599ed8d45ec0daa5b6", - "rawBytes": 911, - "gzipBytes": 554, + "path": "houseplan-assets/space-deletion-CLA5ezlL.js", + "sha256": "ec0519abd52ab649e2ed8f5744cc8284d96d8a83f3c9517df7f5070be63a66e9", + "rawBytes": 906, + "gzipBytes": 549, "isEntry": false, "imports": [], "dynamicImports": [] }, { "path": "houseplan-card.js", - "sha256": "031ef9710a85647066f82b62cd7a294c752493c0391cf59b1688380f7cac2a18", + "sha256": "9bb7a0cb60837b9a006d1c0d125c820ab083b270a9c6130147cd5c8c8b47cff1", "rawBytes": 1089, - "gzipBytes": 754, + "gzipBytes": 751, "isEntry": true, "imports": [ - "houseplan-assets/houseplan-card-DI__VUPO.js" + "houseplan-assets/houseplan-card-BrUCyMoE.js" ], "dynamicImports": [] } diff --git a/custom_components/houseplan/frontend/houseplan-assets/de-CndLXoON.js b/custom_components/houseplan/frontend/houseplan-assets/de-CndLXoON.js new file mode 100644 index 00000000..749f9cb3 --- /dev/null +++ b/custom_components/houseplan/frontend/houseplan-assets/de-CndLXoON.js @@ -0,0 +1 @@ +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";var e={"editor.context_actions":"Aktionen: {object}","editor.tool_options":"Werkzeugoptionen: {tool}","editor.palette":"Palette: {tool}","editor.open_group":"Werkzeuggruppe: {group}","editor.group_active":"{group} — aktiv: {item}","editor.disabled_action":"{action} ist nicht verfügbar: {reason}","editor.loading":"Editor wird geladen…","editor.loading_aria":"Der Plan-Editor wird geladen","editor.load_failed":"Der Editor konnte nicht geladen werden.","editor.refresh_advice":"Seite aktualisieren und erneut versuchen.","editor.retry_advice":"Verbindung prüfen und erneut drücken.","color_picker.title":"Farbwähler","color_picker.hue":"Farbton","color_picker.saturation":"Sättigung","color_picker.value":"Helligkeit","color_picker.hex":"Hex-Farbe","color_picker.invalid_hex":"Geben Sie eine 3- oder 6-stellige Hex-Farbe ein","btn.properties":"Eigenschaften","btn.keep_as_walls":"Als Wände behalten","btn.delete_room_keep_walls":"Raum löschen, Wände behalten","btn.delete_room_with_walls":"Raum und Wände löschen","title.markup_select":"Wände, Säulen und gespeicherte Umrisse auswählen und bearbeiten","title.markup_column":"Säule: Klicken Sie auf einen Rasterpunkt, um eine quadratische Säule zu platzieren","markup.partition":"Trennwand","markup.column":"Säule","markup.hint_column":"Klicken Sie auf einen Rasterpunkt, um eine quadratische Säule zu platzieren","history.draft_segment":"Raum-Entwurfsegment hinzufügen","history.draft_merge":"Unvollständige Raumumrisse verbinden","history.draft_segment_delete":"Raum-Entwurfssegment entfernen","history.partition_add":"Trennwand hinzufügen","history.column_add":"Säule hinzufügen","history.physical_edit":"Physisches Objekt ändern","history.physical_delete":"Physisches Objekt löschen","history.physical_move":"Physisches Objekt verschieben","history.contour_to_partitions":"Umriss in geschlossene Wände umwandeln","history.wall_chain_finish":"Wandkette fertigstellen","history.wall_face_batch":"Räume aus Wänden erstellen","toast.column_duplicate":"Eine Säule mit demselben Zentrum und äußerer Größe existiert bereits","confirm.delete_draft":"Sofort den gesamten unvollständigen Raumumriss löschen?","confirm.delete_draft_segment":"Dieses Entwurfssegment löschen? Der verbleibende Umriss könnte sich in zwei teilen.","physical.partition_properties":"Eigenschaften der Trennwand","physical.column_properties":"Eigenschaften der Säule","physical.draft_properties":"Eigenschaften des Entwurfssegments","physical.shape":"Form","physical.square":"Quadrat","physical.circle":"Kreis","physical.diameter":"Durchmesser","physical.side":"Seite","physical.rotation":"Drehwinkel","physical.length":"Länge","physical.allowed_range":"Erlaubt: {min}–{max} {unit}","physical.delete_segment":"Segment löschen","physical.delete_draft":"Gesamten Umriss löschen","physical.column_size_title":"Außenmaß der per Klick platzierten quadratischen Säule (1–150 cm).","card.title":"Hausplan","count.devices":"{n} Entwicklung","empty.no_spaces":"Noch keine Bereiche.","empty.add_first":"Ersten Bereich hinzufügen und einen Grundriss hochladen.","empty.install":"Installieren Sie die House Plan-Integration und fügen Sie sie unter „Geräte & Dienste“ hinzu.","btn.add_space":"Bereich hinzufügen","btn.cancel":"Abbrechen","btn.save":"Speichern","btn.close":"Schließen","btn.delete":"Löschen","btn.edit":"Bearbeiten","btn.open_in_ha":"In HA öffnen","btn.reset":"Zurücksetzen","btn.attach":"Anhängen…","btn.upload":"Hochladen…","btn.replace":"Ersetzen…","title.zoom_in":"Zoomen","title.zoom_out":"Herauszoomen","title.zoom_fit":"Alles anpassen","title.markup":"Raum-Markierung: Gitter, Linien, Konturen","title.configure_space":"Bereich konfigurieren","title.add_space":"Bereich hinzufügen","title.markup_add":"Wände: eine durchgehende Kette zeichnen; Shift sperrt auf 45°. Werkzeugwechsel oder Verlassen des Editors beendet die Kette und wandelt sie in unabhängige Wände","title.markup_merge":"Zusammenführen: Klicken Sie auf einen Raum und dann auf den Nachbarraum, mit dem er eine Wand teilt","title.markup_split":"Raum teilen: Klicken Sie auf den Raum und dann auf zwei Punkte an seinen Wänden","title.markup_delroom":"Raum löschen: Klicken Sie in einen Raum und bestätigen Sie","title.need_plan":"Einen Grundriss hochladen","markup.add":"Wände","markup.merge":"Zusammenführen","markup.split":"Teilen","markup.resize":"Größe ändern","title.markup_resize":"Räume vergrößern/verkleinern: Ziehen Sie einen verfügbaren horizontalen oder vertikalen Wandgriff","markup.hint_resize":"Ziehen Sie einen verfügbaren Wandgriff · die Wand stoppt an der ersten unsicheren Position · Esc bricht ab · Strg+Z — rückgängig","resize.disabled.diagonal":"Diese Wand ist geneigt; Größe ändern unterstützt nur horizontale und vertikale Wände","resize.disabled.side-angle":"Eine angrenzende Wand ist geneigt; Größe ändern erfordert, dass beide angrenzenden Wände diese Wand im rechten Winkel treffen","resize.disabled.duplicate-physical-wall":"Eine separate Trennwand, unfertige Kontur oder ein Pfeiler überlappt diese Wand; entfernen oder verschieben Sie sie, bevor Sie die Größe ändern","resize.disabled.partial-shared":"Ein angrenzender Raum nutzt nur einen Teil dieser Wand, daher kann sie nicht sicher als gemeinsame Wand verschoben werden","resize.disabled.unequal-shared":"Der angrenzende Raum nutzt andere Endpunkte oder Wandlängen, daher können die Wände nicht gemeinsam sicher bewegt werden","resize.disabled.multiple-rooms":"Das Verschieben dieser Wand würde mehr als zwei Räume betreffen","resize.disabled.thickness-conflict":"Die Wandstärke kann nicht sicher beibehalten werden","resize.disabled.opening-conflict":"Eine Öffnung an dieser Wand kann nicht sicher verschoben werden","resize.disabled.invalid-geometry":"Diese Wand kann nicht ohne Änderung der Planstruktur geändert werden","resize.limit_stopped":"Wand gestoppt: der nächste Schritt würde ein Anschlusslimit verletzen","resize.commit_failed":"Größenänderung wurde abgebrochen, da der endgültige Plan die Geometrieprüfung nicht bestanden hat","resize.preview_failed":"Größenänderung am letzten sicheren Punkt gestoppt, da die Plan-Geometrie nicht beibehalten werden konnte","markup.opening":"Öffnung","markup.delete_room":"Raum löschen","history.undo":"Rückgängig","history.redo":"Wiederholen","history.undo_named":"Rückgängig: {name} (Strg+Z)","history.redo_named":"Wiederholen: {name} (Strg+Shift+Z / Strg+Y)","history.undo_empty":"Nichts zu widerrufen","history.redo_empty":"Nichts zu wiederholen","history.undone":"Rückgängig gemacht: {name}","history.redone":"Wiederholt: {name}","history.add_room":"Raum erstellen","history.split_room":"Raum teilen","history.merge_rooms":"Räume zusammenführen","history.resize_room":"Raumgröße ändern","history.wall_thickness":"Wandstärke ändern","history.add_opening":"Tür- oder Fensteröffnung hinzufügen","history.edit_opening":"Öffnung bearbeiten","history.move_opening":"Öffnung verschieben","history.delete_opening":"Öffnung löschen","history.delete_room":"Raum löschen","history.delete_room_keep_walls":"Raum löschen, Wände behalten","history.delete_room_with_walls":"Raum und Wände löschen","history.decor_add":"Dekorobjekt hinzufügen","history.decor_edit":"Dekorobjekt bearbeiten","history.decor_move":"Dekorobjekt verschieben","history.decor_transform":"Dekorobjekt transformieren","history.decor_delete":"Dekorobjekt löschen","history.backdrop_transform":"Plan-Hintergrund transformieren","opening.new":"Neue Öffnung","opening.edit":"Öffnung","opening.door":"Tür","opening.window":"Fenster","opening.gate":"Tor","opening.passage":"Offener Durchgang","opening.passage_binding_warning":"Das Speichern entfernt den Öffnungs-/Schließsensor und das Schloss.","opening.invalid_passage_fields":"Der offene Durchgang auf dem Plan „{room}“ hat nicht unterstützte Einstellungen: {fields}.","opening.type_label":"Typ","opening.length_label":"Länge, cm","opening.contact_label":"Öffnungs-/Schließsensor","opening.lock_label":"Schloss","opening.none":"— keine —","opening.search_ph":"Suche: Name oder Entitäts-ID…","opening.invert":"Geöffnet/geschlossen invertieren","opening.flip_h":"Scharnier an der anderen Zarge","opening.flip_v":"Öffnet zur anderen Seite","opening.open":"Offen","opening.closed":"Geschlossen","opening.locked":"Verriegelt","opening.unlocked":"Entriegelt","opening.state_unknown":"nicht verfügbar","opening.no_entities":"Keine Sensoren gebunden — ein statisches Symbol auf dem Plan.","toast.opening_no_wall":"Neben eine Raumwand oder eine unabhängige Wand klicken","opening.host_partition":"Unabhängige Wand","opening.partition_orphan":"Die unabhängige Wand für diese Öffnung existiert nicht mehr","opening.partition_jamb_margin":"Mindestens {distance} zwischen der Öffnung und dem Wandende lassen","opening.rebind_partition":"An eine andere unabhängige Wand anfügen","confirm.delete_partition_openings_title":"Wand und Öffnungen löschen?","confirm.delete_partition_openings_body":"Diese Wand enthält {count} Öffnung(en). Sie werden zusammen gelöscht.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.delete":"Löschen","markup.hint_points":"Punkte: {n} · Shift — 45° Schritte · Esc — Kette beenden · Ctrl+Z — Punkt rückgängig machen · Schließen eines Bereichs erstellt einen Raum","markup.hint_start":"Klicken Sie auf einen Rasterpunkt, um eine Wandkette zu starten","tip.lqi":"durchschnittliches Zigbee-Signal:","tip.area":"Bereich: {value}","info.device_header":"Gerät im Plan","info.model":"Modell","info.state":"Status","info.link":"Verbindung","info.manuals":"Handbücher","info.none":"Keine zusätzlichen Informationen","marker.new_device":"Neues Gerät","marker.name_label":"Name (im Plan angezeigt)","marker.name_ph":"Name","marker.binding_label":"An ein HA-Gerät binden","marker.binding_disabled":"in Home Assistant deaktiviert","marker.virtual_option":"Virtuelles Gerät (keine Bindung)","marker.search_ph":"Gerät/Gruppe suchen…","marker.nothing_found":"Nichts gefunden","marker.room_label":"Raum","marker.room_override":" (Platzierung überschreiben)","marker.room_choose":"— Raum auswählen —","marker.room_auto":"— nach Gerätebereich (auto) —","marker.icon_label":"Symbol","marker.icon_ph":"mdi:… (leer = automatisch)","marker.display_label":"Anzeige","display.badge":"Symbol + Zustand","display.icon_ripple":"Symbol + Zustand und Aktivität","display.static_icon":"Immer statisches Symbol","marker.display_hint":"Symbol + Zustand ändert die Platte für die Zustände Arbeit, geöffnet, Alarm und nicht verfügbar. Symbol + Zustand und Aktivität zeigt zusätzlich einen kurzen Impuls für Ereignisse und einen kontinuierlichen Impuls für laufende Arbeit, Bewegung oder Präsenz. Wert + Zustand ersetzt das Symbol durch einen eindeutigen HA-Wert. Ein statisches Symbol reagiert niemals auf Gerätezustände.","marker.display_hint_badge":"Das Symbol und die dynamische Platte zeigen den Gerätezustand ohne den üblichen Aktivitätspuls. Rote Alarme bleiben sichtbar.","marker.display_hint_icon":"Das Symbol und die dynamische Platte zeigen den Gerätezustand ohne den üblichen Aktivitätspuls. Rote Alarme bleiben sichtbar.","marker.display_hint_icon_ripple":"Das Symbol, die dynamische Platte und der Puls zeigen einen kurzen Puls für Ereignisse und einen kontinuierlichen Puls für Arbeit, Bewegung oder Anwesenheit. Rote Alarme haben eine separate Priorität.","marker.display_hint_value":"Ein eindeutiger Home Assistant-Wert ersetzt das Symbol, während die Platte weiterhin den Zustand anzeigt. Rote Alarme bleiben sichtbar.","marker.display_hint_static_icon":"Die themenabhängige Hülle und das Symbol bleiben immer gleich. Zustand, Aktivität, Nichtverfügbarkeit und Alarme verändern nicht das Erscheinungsbild.","marker.static_alarm_warning":"Dieses Gerät kann Alarme melden. Die statische Anzeige verbirgt die visuelle Alarmanzeige des Markers.","marker.preview.title":"Anzeigevorschau","marker.preview.actual":"Jetzt","marker.preview.example":"Beispiel","marker.preview.integration":"Bereitgestellt von","marker.preview.source":"Anzeigquelle","marker.preview.current_state":"Aktueller Zustand","marker.preview.result":"Auf dem Plan","marker.preview.details":"Quelldetails","marker.preview.select_source":"Ein Home-Assistant-Gerät oder eine Entität auswählen, um die tatsächliche Anzeige zu sehen.","marker.preview.unknown_provider":"Unbekannte Integration","marker.preview.virtual_provider":"House Plan · virtuelles Gerät","marker.preview.no_source":"Keine aktive Quelle","marker.preview.no_state":"Kein aktueller Zustand","marker.preview.mixed_states":"Mehrere verschiedene Zustände","marker.preview.multiple_sources":"{n}-Quellen","marker.preview.more_sources":"+{n} mehr","marker.preview.scaled":"Die Vorschau wird auf {n}% skaliert, um zu passen. Die gespeicherte Größe bleibt unverändert.","marker.preview.demo_short":"Kurze Aktivität anzeigen","marker.preview.demo_continuous":"Kontinuierliche Aktivität anzeigen","marker.preview.stop_continuous":"Kontinuierliche Aktivität stoppen","marker.preview.demo_short_notice":"Kurzes Aktivitätsbeispiel; der tatsächliche Gerätezustand bleibt unverändert.","marker.preview.demo_continuous_notice":"Kontinuierliches Aktivitätsbeispiel; der tatsächliche Gerätezustand bleibt unverändert.","marker.preview.demo_already_visible":"Der aktuelle Zustand zeigt bereits eine echte Aktivitäts- oder Alarmeffekt.","marker.preview.reduced_motion":"Systemweit reduzierte Bewegungen sind aktiviert, daher wird gewöhnliche Aktivität als Punkt angezeigt.","marker.preview.reason.neutral":"Neutrale dunkle Platte","marker.preview.reason.working":"Gelbe Platte: Das Gerät arbeitet jetzt","marker.preview.reason.working_activity":"Gelbe Platte und Aktivitätseffekt: das Gerät funktioniert jetzt","marker.preview.reason.open":"Orange Platte: physisch geöffnet oder entriegelt","marker.preview.reason.cover_icon_state":"Neutrale Platte; die Abdeckungseinheit steuert den angezeigten Zustand und das Symbol","marker.preview.reason.presence":"Aktivitätseffekt, während Präsenz erkannt wird","marker.preview.reason.event":"Kurzer Aktivitätseffekt nach einem erkannten Ereignis","marker.preview.reason.transition":"Aktivitätseffekt, während das Gerät sich bewegt oder den Zustand ändert","marker.preview.reason.media_neutral":"Mediengeräte bleiben im verfügbaren Zustand auf einer neutralen dunklen Platte","marker.preview.reason.unavailable":"Gedämpfte neutrale Platte: nicht verfügbar oder ausgeschaltet","marker.preview.reason.alarm":"Rote Alarmplatte; Alarmanzeige wird immer angezeigt","marker.preview.reason.live_states_disabled":"Live-Zustandsstil ist für diese Karte deaktiviert","marker.preview.reason.value_no_state":"Kein nutzbarer Zustandswert; stattdessen wird das Symbol angezeigt","marker.preview.reason.value_ambiguous_sources":"Mehrere mögliche Wertequellen; stattdessen wird das Symbol angezeigt","marker.preview.reason.value_non_scalar":"Die Quelle lieferte keinen einfachen Wert; stattdessen wird das Symbol angezeigt","marker.preview.reason.value_virtual":"Ein virtuelles Gerät hat keinen Home Assistant-Wert; stattdessen wird das Symbol angezeigt","marker.preview.reason.vacuum_live_plan_only":"Echtzeitposition und -spur des Staubsaugers sind nur im vollständigen Plan verfügbar","marker.preview.reason.hidden_design_preview":"Das Gerät ist im Plan ausgeblendet; diese Designvorschau bleibt sichtbar","marker.preview.reason.composite_power_source":"Der Status stammt vom Power-Entity des Geräts; Hilfsschalter werden ignoriert","marker.preview.reason.activity_display_disabled":"Der gewählte Anzeigemodus zeigt gewöhnliche Aktivitätseffekte nicht an","marker.preview.reason.ha_disabled":"Die Home Assistant-Verbindung ist deaktiviert und wird im Plan ausgeblendet","marker.preview.reason.orphaned":"Die gespeicherte Home Assistant-Verbindung konnte nicht mehr gefunden werden","marker.preview.reason.static_icon":"Statischer Modus: Der Gerätestatus ändert das Symbol nicht","marker.activity_color":"Aktivitätspulsfarbe","marker.ripple_size":"Aktivitätspulsgröße","marker.activity_alarm_note":"Farbe und Größe betreffen nur gewöhnliche Aktivität und ändern keine roten Alarme.","marker.pulse_a11y_alarm":"Alarm","marker.pulse_a11y_event":"Kürzliches Ereignis","marker.pulse_a11y_presence":"Anwesenheit erkannt","marker.pulse_a11y_transition":"Statusänderung","marker.pulse_a11y_running":"Arbeitet","marker.state_a11y_neutral":"Standardzustand","marker.state_a11y_working":"Funktionierend","marker.state_a11y_open":"Offen","marker.state_a11y_locked":"Verschlossen","marker.state_a11y_unlocked":"Entriegelt","marker.state_a11y_alarm":"Alarm","marker.state_a11y_unavailable":"Nicht verfügbar","marker.lqi_a11y_low":"LQI {value}, schwaches Signal","marker.lqi_a11y_mid":"LQI {value}, mittleres Signal","marker.lqi_a11y_high":"LQI {value}, starkes Signal","marker.size_label":"Symbolgröße / Drehung","marker.angle_label":"Drehen","marker.model_label":"Modell","marker.model_ph":"z.B. Aqara T&H","marker.link_label":"Link","marker.desc_label":"Beschreibung","marker.desc_ph":"Notizen, Spezifikationen…","marker.manuals_label":"Handbücher (PDF usw.)","marker.sub_device":"Gerät","marker.sub_z2m_group":"· Z2M Gruppe","marker.sub_group":"Gruppe","marker.sub_helper":"Helfer","space.new":"Neuer Bereich","space.header":"Bereich","space.title_label":"Titel","space.title_ph":"z.B. Garage","space.plan_label":"Grundriss (Hintergrund)","space.no_plan":"Kein Planbild","space.plan_alt":"Grundriss","room.new":"Neuer Raum","room.name_label":"Anzeigename","room.name_ph":"z.B. Terrasse","room.area_label":"Home Assistant Bereich (nicht zugewiesen)","room.no_area_option":"— kein Bereich —","room.default_name":"Raum","device.unnamed":"unbenannt","device.light_group":"Lichtgruppe","device.fallback":"Gerät","device.virtual":"Virtuelles Gerät","confirm.delete_room":'Raum "{name}" löschen?',"confirm.delete_room_title":'Raum "{name}" löschen?',"confirm.delete_room_body":"Festlegen, ob die ausschließlich zu diesem Raum gehörenden physischen Wände erhalten bleiben. Mit einem anderen Raum geteilte Wände bleiben immer erhalten.","confirm.remove_marker":"„{name}“ aus dem Plan löschen? Das Gerät verschwindet vollständig und trägt nicht mehr zu den Plandaten bei. Es kann später erneut hinzugefügt werden.","confirm.erase_decor":"Das Objekt „{kind}“ löschen? Diese Aktion kann im Editor rückgängig gemacht werden.","confirm.delete_space":"Bereich „{title}“ mit allen Räumen und Markierungen löschen?","space.delete_blocked":"Dieser Bereich wird noch von {n} Gerät(en) verwendet. Die Geräte zuerst in einen anderen Bereich verschieben oder löschen.","toast.pos_save_failed":"Position nicht gespeichert: {err}","toast.no_entity":"Das Gerät hat keine geeignete Entität","toast.ha_disabled_action":"Ein deaktiviertes Home Assistant-Objekt kann im Plan nicht verwendet werden.","toast.ha_disabled_show_device":"Ein in Home Assistant deaktiviertes Gerät kann im Plan nicht angezeigt werden. Aktivieren Sie es zuerst in Home Assistant.","toast.ha_disabled_show_entity":"Eine in Home Assistant deaktivierte Entität kann im Plan nicht angezeigt werden. Aktivieren Sie sie zuerst in Home Assistant.","toast.ha_disabled_add":"Ein deaktiviertes Home Assistant-Objekt kann nicht dem Plan hinzugefügt werden. Aktivieren Sie es zuerst in Home Assistant.","toast.ha_binding_unverified":"Der Status des Objekts konnte über das Home Assistant-Register nicht überprüft werden. Anzeige und Aktionen sind vorübergehend nicht verfügbar.","toast.markup_needs_server":"Markup ist verfügbar, nachdem die Konfiguration auf den Server verschoben wurde.","toast.space_order_changed":"Reihenfolge geändert. Wenn eine Karte ihr Stockwerk nach Nummer festlegt, überprüfen Sie diese Paneele.","toast.conflict":"Die Konfiguration wurde in einem anderen Fenster geändert — Daten aktualisiert, wiederholen Sie Ihre letzte Aktion.","toast.cfg_save_failed":"Speichern der Konfiguration fehlgeschlagen: {err}","toast.room_overlap":"Die Umrisse überlappen den Raum „{name}“ — Räume dürfen sich nicht überlappen","toast.contour_cannot_close":"Die Kontur kann nicht geschlossen werden, da sie entartet ist oder sich selbst schneidet","toast.merge_not_adjacent":"Es können nur Räume zusammengeführt werden, die eine Wand teilen","toast.rooms_merged":"Räume zu „{name}“ zusammengeführt","toast.split_pick_wall":"Beginnen Sie den Schnitt an der Wand des Raumes","toast.split_bad_cut":"Der Schnitt muss wand-zu-wand innerhalb des Raumes verlaufen, ohne Wände oder sich selbst zu kreuzen","merge.header":"Räume zusammenführen","merge.hint":"Der zusammengeführte Raum behält einen Namen und eine Fläche. Die andere Fläche wird freigegeben — ihre Geräte verlassen den Plan, bis ein anderer Raum sie beansprucht.","merge.keep":"Behalten","merge.no_area":"keine Fläche","toast.room_saved":"Raum gespeichert ({n}). Hinzugefügte Geräte: {added}. Zeichnen Sie die nächste Kontur oder verlassen Sie die Markierung.","toast.room_saved_no_area":"Raum gespeichert ({n}, keine Fläche). Zeichnen Sie die nächste Kontur oder verlassen Sie die Markierung.","toast.marker_needs_server":"Die Gerätebearbeitung ist verfügbar, nachdem die Konfiguration auf den Server verschoben wurde","toast.virtual_name_required":"Einen Namen für das virtuelle Gerät eingeben","toast.marker_saved":"Gerät gespeichert","toast.marker_removed":"Gerät aus dem Plan gelöscht","toast.integration_missing":"Die House Plan-Integration ist nicht installiert — Verwaltung nicht verfügbar","toast.plan_formats":"Unterstützte Formate: SVG, PNG, JPG, WebP","toast.plan_required":"Grundriss hochladen — erforderlich","toast.space_added_onboard":"Bereich hinzugefügt. Räume einzeichnen: Rasterpunkte anklicken und die Kontur schließen.","toast.space_added":"Bereich hinzugefügt","toast.space_saved":"Bereich gespeichert","toast.space_deleted":"Bereich gelöscht","toast.delete_failed":"Löschen fehlgeschlagen: {err}","toast.error":"Fehler: {err}","toast.toggle_target_unavailable":"Ziel „{name}“ ist nicht verfügbar — keine Aktion durchgeführt","toast.toggle_targets_unavailable":"Ziele nicht verfügbar: {names}. Keine Aktion durchgeführt","toast.file_failed":'Datei "{name}" wurde nicht hochgeladen: {err}',"toast.files_attached":"Dateien angehängt: {n}","err.unknown":"unbekannter Fehler","err.code":"Code {code}","err.too_large":"Datei größer als {mb} MB","err.bad_ext":"nicht unterstützter Typ (PDF/Bild erwartet)","err.unauthorized":"Administratorrechte erforderlich","editor.title":"Titel","editor.default_floor":"Anfangsbereich","editor.default_floor_missing":"Anfangsbereich „{id}“ existiert nicht mehr. Wählen Sie einen anderen Bereich.","editor.floor":"Fester Bereich","editor.floor_none":"— nicht fest —","editor.floor_index":"YAML-Index {index} (beibehalten)","fixed_floor.loading":"Lade den festen Bereich…","fixed_floor.invalid_title":"Der feste Bereich ist nicht verfügbar","fixed_floor.invalid_body":"Überprüfen Sie die Etage in der Kartenkonfiguration. Der konfigurierte Wert ist: {value}","editor.icon_size":"Symbolgröße, % der Planbreite","editor.show_temperature":"Temperatur anzeigen","editor.live_states":"Live-Zustände (ein/aus, offen…)","editor.show_signal":"Zigbee-Signal anzeigen (LQI)","editor.language":"Schnittstellensprache","editor.lang_auto":"Automatisch (HA-Profil)","title.icon_rules":"Symbolregeln: welche MDI-Symbole Geräte nach Namen erhalten","rules.title":"Symbolregeln","rules.hint":'Regeln werden von oben anhand von "Gerätename + Modell" (Großschreibungs-unempfindliches Regex) überprüft; das erste Match gewinnt. Wenn nichts übereinstimmt, entscheidet die Entität-Geräteklasse, dann das generische Chip-Symbol.',"rules.pattern_ph":"regex, z. B. Stecker|Steckdose","rules.icon_ph":"mdi:power-socket-de","rules.add":"Regel hinzufügen","rules.reset":"Zurücksetzen auf Standardeinstellungen","rules.test_ph":"Versuch mal einen Gerätenamen...","rules.invalid":"ungültiges regex","rules.saved":"Icon-Regeln gespeichert","btn.up":"Nach oben","btn.down":"Nach unten","tap.info":"Gerätekarte","tap.more_info":"HA Mehr-Info-Dialog","tap.toggle":"Zustand umschalten","marker.tap_label":"Tap-Aktion für dieses Gerät","tap.toggle_note":"Der aufgelöste Zustand ist unten dargestellt. Sichere Geräte werden niemals aus dem Plan umgeschaltet.","import.title":"Bereiche aus HA-Etagen erstellen","import.hint":"Home Assistant kennt diese Etagen bereits. Die Etagen auswählen, die zu Planbereichen werden sollen; anschließend für jeden Bereich einen Grundriss hochladen. Die Räume werden danach von Hand eingezeichnet.","import.start":"{n} Bereich(e) erstellen","import.manual":"Von Grund auf neu starten","import.progress":"Etage {i} von {n}","import.done":"Bereiche erstellt. Räume einzeichnen: Rasterpunkte anklicken und die Kontur schließen.","btn.skip":"Überspringen","space.scale_label":"Maßstab (Rasterzellen-Größe)","space.scale_unit":"cm pro Zelle","space.scale_unit_imperial":"Zoll pro Zelle","space.display_section":"Anzeige","space.show_borders":"Raumgrenzen immer anzeigen","space.zero_wall_style":"Wände ohne Dicke","space.zero_wall_dashed":"Gestrichelt","space.zero_wall_solid":"Durchgezogen","space.zero_wall_help":"Gestrichelte Wände lassen Licht durch. Durchgezogene Wände blockieren Licht auch bei einer Dicke von 0.","space.show_names":"Raumnamen anzeigen (zum Verschieben ziehen)","space.room_color":"Farbe der Begrenzung & des Namens","space.opacity":"Deckkraft","space.fill_label":"Raumausfüllung","fill.none":"Keine","fill.lqi":"Zigbee-Signal","fill.light":"Lichter","fill.custom":"Benutzerdefinierte Farbe","space.custom_fill":"Füllfarbe","space.source_file":"Ich habe einen Grundriss als Bild","space.source_draw":"Kein Bild – ich werde die Räume von Hand umreißen","fill.temp":"Temperatur","tip.temp_avg":"Durchschnittstemperatur:","tip.hum_avg":"Durchschnittliche Luftfeuchtigkeit:","space_card.button":"Grundriss öffnen","space_card.not_found":"Bereich „{id}“ nicht gefunden","space_card.loading":"Laden…","continuity.restore_plan":"Grundriss wiederherstellen…","continuity.restore_connection":"Geräteverbindung wiederherstellen…","continuity.retry":"Erneut versuchen","editor.space":"Bereich","editor.show_button":"Schaltfläche anzeigen","editor.button_label":"Beschriftung der Schaltfläche","editor.button_target":"Ziel-Dashboard-Pfad","marker.sub_entity":"Entität","title.general_settings":"Allgemeine Einstellungen","gs.title":"Allgemeine Einstellungen","gs.hint":"Füllfarben gelten für jeden Bereich; jede Farbe hat ihre eigene Deckkraft. Der Füllmodus wird in den Einstellungen des jeweiligen Bereichs festgelegt.","gs.light_group":"Füllung: Licht","gs.light_on":"Lichter an","gs.light_off":"Alle Lichter aus","gs.temp_group":"Füllung: Temperatur","gs.temp_cold":"Kalt","gs.temp_ok":"Angenehm","gs.temp_hot":"Heiß","gs.lqi_group":"Füllung: Zigbee-Signal","gs.lqi_low":"Schwaches Signal","gs.lqi_high":"Starkes Signal","gs.reset":"Auf Standard zurücksetzen","gs.saved":"Allgemeine Einstellungen gespeichert","space.show_lqi":"Zigbee-Signal (LQI) neben Geräten anzeigen","space.hide_decor":"Dekorationsschicht ausblenden","space.hide_decor_tip":"Linien, Formen, Beschriftungen und Möbel bleiben an ihrem Platz — im Hintergrundeditor sichtbar, aber nicht auf dem Plan.","space.hide_openings":"Öffnungen ausblenden","space.hide_openings_tip":"Tür-, Fenster- und Tor-Symbole werden nicht gezeichnet, aber die Öffnungen funktionieren weiterhin: Licht fällt hindurch, die Sonne kommt durch ein Fenster herein, Kontaktsensoren öffnen sie weiterhin. Der Planeditor zeigt sie immer an.","gs.light_none":"Keine Lichtquellen","mode.plan":"Planeditor","mode.devices":"Geräteeditor","display.value":"Wert + Zustand","marker.subarea":"kein Bereich, manuell","device.new":"Neues Gerät — Editor öffnen, um zu schließen","opening.unlock_action":"Entsperren","opening.lock_action":"Sperren","opening.lock_pending":"Wird ausgeführt…","title.close_editor":"Editor schließen (zur Ansicht zurück)","devbar.rules":"Symbolregeln","device_inbox.button":"Geräte","device_inbox.title":"Geräte auf dem Plan","device_inbox.search":"Geräte, Entitäten und Integrationen suchen…","device_inbox.add_virtual":"Virtuelles Gerät hinzufügen","device_inbox.tab_on_plan":"Auf Plan","device_inbox.tab_available":"Verfügbar","device_inbox.tab_hidden":"Versteckt","device_inbox.tab_readd":"Wieder verfügbar","device_inbox.only_new":"Nur neu","device_inbox.show_entities":"Entitäten anzeigen","device_inbox.show_hidden":"Versteckte auf Plan anzeigen","device_inbox.new":"Neu","device_inbox.find":"Auf dem Plan finden","device_inbox.edit":"Bearbeiten","device_inbox.hide":"Ausblenden","device_inbox.show":"Anzeigen","device_inbox.add":"Hinzufügen","device_inbox.readd":"Wieder hinzufügen","device_inbox.hide_available":"Aus der Liste ausblenden","device_inbox.show_more":"Mehr anzeigen","device_inbox.more_actions":"Weitere Aktionen","device_inbox.find_hidden_hint":"Zuerst „Versteckte auf Plan anzeigen“ aktivieren","device_inbox.show_disabled":"Diese Bindung in Home Assistant aktivieren, bevor sie angezeigt wird","device_inbox.empty_on_plan":"Es befinden sich noch keine passenden Geräte auf dem Plan.","device_inbox.empty_available":"Es sind keine Geräte zum Hinzufügen verfügbar.","device_inbox.empty_hidden":"Es gibt keine versteckten Geräte.","device_inbox.empty_readd":"Es sind keine entfernten Geräte verfügbar, um sie erneut hinzuzufügen.","device_inbox.reason_visible_auto":"Automatisch erkannt","device_inbox.reason_visible_explicit":"Explizit hinzugefügt","device_inbox.reason_manual_hidden":"Vom Benutzer versteckt","device_inbox.reason_automatic_hidden":"Automatisch versteckt","device_inbox.reason_service_entry":"Nur Service-Registry-Eintrag","device_inbox.reason_excluded_integration":"Integration durch Gerätefilter ausgeschlossen","device_inbox.reason_excluded_domain":"Nicht-räumlicher Entitätstyp","device_inbox.reason_grouped_light":"Dargestellt durch eine Raumlichtgruppe","device_inbox.reason_represented_by_parent":"Dargestellt durch sein übergeordnetes Gerät","device_inbox.reason_removed":"Zuvor aus dem Plan entfernt","device_inbox.reason_available":"Zum Hinzufügen zum Plan verfügbar","device_inbox.reason_no_bound_room":"HA-Bereich ist nicht mit einem Planraum verknüpft","device_inbox.status_ha_disabled":"In Home Assistant deaktiviert","device_inbox.status_orphaned":"Bindung ist in Home Assistant nicht mehr vorhanden","device_inbox.status_unverified":"Home Assistant-Register vorübergehend nicht verfügbar","device_inbox.saved":"Geräteliste aktualisiert","space.roomcard_section":"Raumkarte zeigt:","space.label_temp":"Temperatur","space.label_hum":"Luftfeuchtigkeit","space.label_lqi":"Durchschnittliches Zigbee-Signal","space.label_light":"Lichter ein/aus","roomcard.light_on":"Ein","roomcard.light_off":"Aus","roomcard.light_partial":"{on} von {total}","toast.split_pick_inside":"Zwischenliegende Schnittpunkte müssen innerhalb des Raumes liegen","mode.decor":"Hintergrundeditor","decor.select":"Auswählen","decor.line":"Linie","decor.rect":"Rechteck","decor.ellipse":"Oval","decor.text":"Text","decor.erase":"Löschen","decor.erase_confirm_title":"Objekt löschen?","decor.color":"Farbe","decor.width":"Linienbreite","decor.line_style":"Linienstil","decor.line_style_solid":"Durchgehend","decor.line_style_dashed":"Gepunktet","decor.fill":"Füllen","decor.fill_color":"Füllfarbe","decor.length":"Länge","decor.size":"Größe","decor.angle":"Rotationswinkel, °","decor.text_size":"Textgröße","decor.backdrop_properties":"Eigenschaften des Planhintergrunds","decor.text_title":"Textbeschriftung","decor.object_title":"{kind} bearbeiten","decor.text_label":"Text","decor.live_group":"HA-Variable einfügen","decor.live_entity":"Entität","decor.live_entity_ph":"Wählen Sie eine Entität","decor.live_attr":"Wert","decor.live_attr_ph":"Wählen Sie Status oder Attribut","decor.live_state":"Status","decor.backdrop":"Hintergrundbild","decor.backdrop_hint":"Ziehen zum Verschieben; eine Ecke ziehen zum Größenändern; den oberen Griff zum Drehen verwenden. Shift ändert das Verhältnis oder befreit den Winkel.","decor.backdrop_reset":"Bild zurücksetzen","decor.backdrop_reset_done":"Das Bild ist wieder an seinem ursprünglichen Platz und in seiner ursprünglichen Größe","marker.icon_auto":"Auto: {icon} (nach Symbolregeln; wählen Sie eines zur Überschreibung)","marker.icon_pin_auto":"Anheften","mode.plan_tip":"Planungseditor — die Geometrie des Hauses: Räume zeichnen und teilen/zusammenführen, sie mit HA-Bereichen verbinden, Türen, Fenster und Tore platzieren, Raumkarten verschieben, Maßstab festlegen","mode.devices_tip":"Geräteeditor — alles über Symbole: ziehen zum Positionieren, klicken zum Bearbeiten von Bindung/Symbol/Anzeige, virtuelle Geräte hinzufügen, Symbolregeln","mode.decor_tip":"Hintergrundeditor — rein visuelle Dekoration unter dem Plan: Linien, Rechtecke, Ellipsen und Textbeschriftungen, die niemals auf Klicks reagieren","space.glow_enabled":"Lichtquellen-Glühen","gs.glow_group":"Glow von Lichtquellen","gs.glow_base":"Grunddunkelheit des Hauses","gs.glow_light":"Standardlichtfarbe / Intensität","gs.wall_group":"Wände","gs.wall_fill":"Wandfüllung","gs.glow_radius":"Glow-Radius","gs.unit_m":"m","gs.unit_ft":"ft","marker.controls_label":"Steuert andere Lichtquellen","marker.controls_hint":"Mit der Tippen-Aktion „Umschalten“ wechselt ein Klick jede hier hinzugefügte Quelle. Die eigene zugeordnete Entität des Markers wird direkt gesteuert und kann nicht hinzugefügt werden; verwenden Sie den untenstehenden Schalter, um ihn als Licht zu klassifizieren.","marker.controls_filter":"Suchlichter und Schalter…","info.controls":"Steuerungen","marker.glow_radius_label":"Leuchtradius","marker.glow_radius.help":"Legt den Leuchtradius in Metern oder Fuß fest; ein leerer Wert verwendet den Radius aus den allgemeinen Einstellungen.","marker.glow_radius.help.aria":"Hilfe: Leuchtradius","markup.wallthick":"Dicke","markup.select":"Auswählen","title.markup_wallthick":"Dicke — klicken Sie auf eine Wand, um ihre Dicke von 0 bis 100 cm festzulegen.","markup.hint_wallthick":"klicken Sie auf eine Wand · Esc schließt ohne Anwendung","wallthick.field":"Dicke","wallthick.unit_cm":"cm","wallthick.unit_in":"in","wallthick.apply_room":"Auf alle Wände dieses Raums anwenden","markup.draw_wall_title":"Dicke jedes neuen Wandsegments (0–100 cm). Gemeinsame Wände behalten den bestehenden Wert.","room.queue_progress":"Raum {current} von {total}","toast.wall_rooms_saved":"Erstellte Räume: {n}","toast.wall_chain_saved":"Wandkette gespeichert","toast.wallthick_pick":"Eine Wand anklicken","toast.wallthick_set":"Wandstärke eingestellt","toast.wallthick_cleared":"Wandstärke entfernt","toast.physical_range":"Einen Wert von {min} bis {max} {unit} eingeben","toast.zero_wall_opening_conflict":"Entfernen Sie zuerst die Öffnung an diesem Wandsegment.","toast.zero_wall_ambiguous":"Das Wandsegment ist mehrdeutig. Vereinfachen oder passen Sie den Anschluss an.","toast.zero_wall_migration_blocked":"Der Bereich wurde nicht konvertiert: {reason}. Es wurden keine Daten geändert.","toast.physical_angle":"Einen Drehwinkel von 0° bis unter 90° eingeben","toast.physical_limit":"Der Bereich hat das Limit für diesen Geometrietyp erreicht","toast.geometry_unsafe":"Änderung abgebrochen: Wandgeometrie konnte nicht sicher erstellt werden.","junction.limit_angle":"Der Winkel zwischen den Wänden ist zu spitz: {actual}°, mindestens {limit}°.","junction.limit_valence":"Zu viele Wände treffen in einem Knoten aufeinander: {actual}, maximal {limit}.","junction.limit_length":"Das Wandsegment ist zu kurz: {actual} cm, mindestens {limit} cm.","junction.limit_distance":"Wände und Knoten sind zu dicht beieinander: {actual} cm, Minimum {limit} cm.","junction.limit_clearance":"Kein Wohnbereich ist übrig: {actual} cm², Minimum {limit} cm².","junction.limit_check_failed":"Die Überprüfung der Verbindungen konnte nicht durchgeführt werden — die Änderung wurde nicht gespeichert.","toast.wall_model_migration_blocked":"Das Wandmodell konnte nicht aktualisiert werden: {reason}. Der Plan wurde nicht geändert. Führen Sie „Pläne optimieren“ aus; wenn der Fehler erneut auftritt, beheben Sie die widersprüchliche Wandgeometrie.","toast.wall_model_client_outdated":"Aktualisieren Sie die Karte und laden Sie die Seite neu, bevor Sie den Plan bearbeiten.","wall_model.reason.invalid-room":"ungültiger Raumkontur","wall_model.reason.zero-length":"Wandsegment mit null Länge","wall_model.reason.third-owner":"Wand, die von mehr als zwei Räumen geteilt wird","wall_model.reason.duplicate-id":"widersprüchliche Wandkennungen","wall_model.reason.thickness-conflict":"widersprüchliche Wandstärkenwerte","wall_model.reason.opening-host":"Öffnung kann nicht einer Wand zugewiesen werden","toast.delete_room_pick":"Klicken Sie in den Raum, den Sie löschen möchten","toast.plan_snap_ambiguous":"Zoomen Sie hinein, um den Wandknoten auszuwählen","toast.wall_repair_ambiguous":"Der Raumumriss hat mehr als eine mögliche Verbindung. Zoomen Sie hinein und verbinden Sie ihn explizit.","toast.wall_repair_too_large":"Die Lücke ist größer als 2 cm. Verbinden Sie die Wände, bevor Sie den Raum erstellen.","toast.wall_repair_changed":"Die Wandgeometrie hat sich geändert. Versuchen Sie erneut, den Raum zu erstellen.","toast.opening_on_zero_wall":"Öffnungen können nicht auf einer Wand mit null Dicke sitzen.","marker.from_ha_option":"Wählen Sie aus der HA-Liste.","marker.show_entities":"Entitäten anzeigen.","marker.show_entities_tip":"Fügt nicht nur Geräte zur Liste hinzu, sondern auch alle ihre Entitäten.","marker.pick_ph":"Wählen Sie ein Gerät…","room.open_area":"Öffnen Sie den HA-Bereich.","view.volumetric":"Volumetrische Ansicht.","view.flat":"Flache Ansicht.","kiosk.title":"Die Größen dieses Bildschirms.","kiosk.hint":"Nur auf diesem Gerät gespeichert – jedes Wandtablet oder TV kann seine eigenen komfortablen Größen haben.","kiosk.icon_scale":"Gerätesymbolgröße.","kiosk.font_scale":"Textgröße der Raumkarte.","editor.kiosk":"Wandgeräte- (Kiosk-)Modus.","editor.cycle":"Bereiche automatisch alle N Sekunden wechseln (Kiosk, 0 = aus)","room.settings_title":"Raumeinstellungen.","room.settings_section":"Raumeinstellungen (überschreibt den Bereich)","room.fill_label":"Diesen Raum ausfüllen","fill.inherit":"Als den Bereich","room.custom_fill_space":"Bereichsfarbe","room.custom_fill_own":"Raumfarbe","room.temp_src_label":"Temperaturquelle","room.hum_src_label":"Luftfeuchtigkeitsquelle","room.src_average":"Durchschnitt über die Sensoren des Raums (Standard)","room.src_pick":"Ein bestimmtes HA-Gerät oder Entität","room.src_ph":"Quelle wählen…","toast.room_updated":"Raum aktualisiert","space.card_font":"Schriftgröße der Raumkarte (gesamter Bereich)","room.sizes_section":"Schriftgrößen","room.name_scale":"Raumname Größe","room.label_scale":"Metrikgröße","preview.room_name":"Wohnzimmer","toast.cfg_reload_failed":"Der Plan konnte nicht vom Server neu geladen werden: {err}","toast.locale_load_failed":"Das Sprachpaket konnte nicht geladen werden. Bis zum Neuladen der Seite wird Englisch verwendet.","room.settings_short":"Raumeinstellungen","room.unnamed":"Unbenannter Raum","marker.use_climate_temp":"Geräte-Temperatur im Raum berücksichtigen","marker.use_climate_temp_tip":"Fügt die aktuelle Temperatur einer Klimaanlage oder eines Thermostats zum Raumdurchschnitt hinzu. Das externe Wert-Label unten separat konfigurieren.","marker.value_badge_title":"Wert-Label","marker.value_badge.help":"Zeigt einen ausgewählten Wert neben dem Symbol an. Dies beeinflusst nicht die Raumkennzahlen, Licht, Glanz oder die Tippaktion.","marker.value_badge.help.aria":"Hilfe: Gerätewert-Badge","marker.value_badge_enabled":"Zeige ein Wert-Badge","marker.value_badge_source":"Wert","marker.value_badge_source.help":"Wählen Sie einen bestimmten Zustand, ein unterstütztes Attribut oder einen abgeleiteten Wert dieses Geräts.","marker.value_badge_source.help.aria":"Hilfe: Quelle des Wert-Badges","marker.value_badge_position":"Position","marker.value_badge_position.help":"Die gewählte Seite bleibt fest und dreht sich nicht automatisch an einem Planrand.","marker.value_badge_position.help.aria":"Hilfe: Position des Wert-Badges","marker.value_badge_right":"Rechts","marker.value_badge_bottom":"Unten","marker.value_badge_left":"Links","marker.value_badge_top":"Oben","marker.value_badge_empty":"Für dieses Gerät stehen keine Werte zur Verfügung","marker.value_badge_static":"Ein statisches Symbol zeigt keine Live-Werte an. Die Einstellung wird beibehalten.","marker.value_badge_missing":"Quelle nicht verfügbar","marker.value_badge_missing_hint":"Die gespeicherte Quelle ist derzeit nicht verfügbar. Behalten Sie sie bei, deaktivieren Sie das Badge oder wählen Sie einen anderen Wert.","marker.value_badge_duplicate":"Derselbe Wert wird bereits im Symbol angezeigt.","marker.value_badge_state":"Status · {name}","marker.value_badge_marker_state":"Lichtquellstatus · {name}","marker.value_badge_lqi":"Durchschnittliche Zigbee-Signalqualität","marker.value_badge_attr_current_temperature":"Aktuelle Temperatur · {name}","marker.value_badge_attr_temperature":"Zieltemperatur · {name}","marker.value_badge_attr_current_humidity":"Aktuelle Luftfeuchtigkeit · {name}","marker.value_badge_attr_humidity":"Luftfeuchtigkeit · {name}","marker.value_badge_attr_current_position":"Position · {name}","marker.value_badge_attr_percentage":"Geschwindigkeit · {name}","marker.value_badge_attr_brightness":"Helligkeit · {name}","marker.value_badge_attr_volume_level":"Lautstärke · {name}","marker.value_badge_attr_battery_level":"Batterie · {name}","marker.value_badge_attr_fan_speed":"Lüftergeschwindigkeit · {name}","marker.light_role_label":"Ist dieses Gerät eine Lichtquelle?","marker.light_role.help":"Steuert, ob dieser Marker selbst eine räumliche Lichtquelle ist. Verknüpfte Lichter oben bleiben unabhängige Raumlichtsteuerungen.","marker.light_role.help.aria":"Hilfe: ob dieses Gerät eine Lichtquelle ist","marker.light_role_auto_yes":"Automatisch (Lichtquelle)","marker.light_role_auto_no":"Automatisch (keine Lichtquelle)","marker.light_role_always":"Immer eine Lichtquelle","marker.light_role_never":"Nie eine Lichtquelle","marker.light_entity_label":"Führende Lichtereinheit","marker.light_entity.help":"Für ein Verbundgerät wählen Sie die Entität, deren Zustand, Farbe und Helligkeit diese Planquelle darstellen. Der automatische Rückgriff bleibt mit älteren Plänen kompatibel.","marker.light_entity.help.aria":"Hilfe: führende Lichtentität","marker.light_entity_auto":"Automatisch ({entity})","marker.light_entity_none":"keine steuerbare Entität","marker.light_entity_missing":"Die gespeicherte Entität {entity} ist nicht verfügbar. House Plan verwendet vorübergehend {fallback}; die gespeicherte Auswahl wird wiederhergestellt, wenn sie zurückkehrt.","marker.toggle_entity_label":"Zu toggelnde Entität","marker.toggle_entity.help":"Für ein Verbundgerät wählen Sie das genaue eigene Licht oder den Schalter, der durch Tippen bedient wird. Automatisch behält die vorherigen Zielregeln bei und ist unabhängig von der führenden Lichtentität.","marker.toggle_entity.help.aria":"Hilfe: zu toggelnde Entität","marker.toggle_entity_auto":"Automatisch ({entity})","marker.toggle_entity_none":"keine eigene steuerbare Entität","marker.toggle_entity_missing":"Die gespeicherte Entität {entity} ist nicht mehr unter den auswählbaren Kanälen dieses Markers. House Plan verwendet vorübergehend {fallback}; die gespeicherte Auswahl wird wiederhergestellt, wenn sie zurückkehrt.","marker.glow_color_label":"Leuchtfarbe und Helligkeit","marker.glow_mode.help":"Verwenden Sie Live-Quellwerte, überschreiben Sie nur deren Farbe oder fixieren Sie sowohl Farbe als auch Helligkeit. Das Minimum beträgt 1 %; um die Quelle zu deaktivieren, wählen Sie „Nie“.","marker.glow_mode.help.aria":"Hilfe: Leuchtfarbe und Helligkeit","marker.glow_mode_auto":"Von Quelle","marker.glow_mode_color":"Farbe einstellen","marker.glow_mode_fixed":"Farbe und Helligkeit einstellen","marker.glow_color":"Leuchtfarbe","marker.glow_brightness":"Helligkeit","marker.glow_disabled_never":"Leuchteinstellungen sind nicht verfügbar, da dieser Marker ausdrücklich keine Lichtquelle ist.","marker.glow_disabled_auto":"Im Automatikmodus wurde keine räumliche Lichtquelle für diesen Marker gefunden.","marker.glow_disabled_no_entity":"Keine aktive steuerbare Home Assistant-Entität ist für diese räumliche Quelle verfügbar.","marker.glow_passive_hint":"Diese Quelle hat keine eigenen Home Assistant-Daten. Stellen Sie ihre Farbe und Helligkeit manuell ein; ihr Radius bleibt verfügbar.","marker.control_broken":"Gespeicherte Quelle fehlt oder ist nicht mehr als Licht markiert","marker.control_missing_label":"Fehlendes Planlicht","marker.control_passive":"passive Quelle","toast.marker_control_cycle":"Dieser Link würde eine kreisförmige Kette von Lichtsteuerungen erzeugen.","toast.marker_binding_required":"Wählen Sie ein Home Assistant-Gerät, bevor Sie eine andere Lichtquelle verlinken.","confirm.unlock":"„{name}“ entsperren?","toast.files_migrate_failed":"Anhänge konnten nicht zur neuen Bindung verschoben werden, Links zeigen weiterhin auf die alten Dateien: {err}","space.pick_saved":"Bereits hochgeladen","space.pick_saved_hint":"Auf dem Server gespeicherte Pläne, einschließlich solcher, die Sie zuvor getrennt haben","space.no_saved":"Noch keine Pläne auf dem Server gespeichert.","space.loading":"Laden…","space.used_by":"in Benutzung: {list}","space.in_use":"Ein Bereich verwendet diesen Plan noch — zuerst die Verknüpfung lösen","btn.use":"Verwenden","confirm.delete_plan":"Plandatei „{name}“ vom Server löschen? Dies kann nicht rückgängig gemacht werden.","toast.plans_list_failed":"Konnte die gespeicherten Pläne nicht auflisten: {err}","toast.plan_delete_failed":"Konnte den Plan nicht löschen: {err}","marker.hide":"Ausblenden","marker.hide_tip":'Das Gerät wird nach dem Speichern aus dem Plan verschwinden, aber weiterhin zum Signalsignal des Raums zählen. Stellen Sie es über den Katalog "Geräte" im Geräte-Editor wieder her.',"marker.show":"Anzeigen","marker.show_tip":"Das Gerät wird nach dem Speichern wieder im Plan erscheinen.","marker.hidden_ghost":"Vom Benutzer ausgeblendetes Gerät","marker.ha_disabled_device":"Das Gerät ist in Home Assistant deaktiviert und im Plan ausgeblendet.","marker.ha_disabled_entity":"Die Entität ist in Home Assistant deaktiviert und im Plan ausgeblendet.","marker.ha_disabled_all_entities":"Das Gerät hat keine aktiven Home Assistant-Entitäten, daher ist es im Plan ausgeblendet.","marker.ha_registry_limited":"Das vollständige Home Assistant-Register ist für diesen Benutzer nicht verfügbar. Das nicht verifizierte Objekt kann vorerst nicht angezeigt oder verwendet werden.","marker.delete_tip":"Löschen Sie das Gerät vollständig aus dem Plan und allen Aggregaten. Sie können es später wieder hinzufügen.","tap.run":"Führen Sie Automation/Skript/Szene aus","marker.run_target_label":"Was ausführen","marker.run_search_ph":"Suchen: Automation, Skript oder Szene…","marker.run_target_gone":"Ziel {id} nicht gefunden — erneut auswählen","marker.tap_confirm":"Um Bestätigung bitten","marker.tap_confirm_tip":"Vor der Ausführung ein Bestätigungsdialogfeld anzeigen — eine Vorsichtsmaßnahme gegen versehentliche Berührungen.","marker.toggle_hint_single":"Ziel: {name} ({id}).","marker.virtual_light_target":"Virtuelles Licht: {name}.","marker.virtual_light_current":"Manueller Zustand: {state} → {effect}.","marker.virtual_light_state_on":"ein","marker.virtual_light_state_off":"aus","marker.toggle_hint_group":"Wird {count}-Quelle(n) umschalten: {names}.","marker.toggle_hint_current":"Jetzt: {state} → {effect}.","marker.toggle_hint_group_current":"Derzeit an: {on} von {count} → {effect}.","marker.toggle_hint_skipped":"Wird übersprungen ({count}): {targets}.","marker.toggle_effect_turn_on":"wird eingeschaltet","marker.toggle_effect_turn_off":"wird ausgeschaltet","marker.toggle_effect_open":"wird geöffnet","marker.toggle_effect_close":"wird geschlossen","marker.toggle_effect_stop":"wird gestoppt","marker.toggle_effect_toggle":"Zustand wird umgeschaltet","marker.toggle_skip_missing":"nicht gefunden","marker.toggle_skip_ha_disabled":"in HA deaktiviert","marker.toggle_skip_unavailable":"nicht verfügbar","marker.toggle_skip_unsupported":"Umschalten wird nicht unterstützt","marker.toggle_skip_secure":"aus Sicherheitsgründen blockiert","marker.toggle_none_no_binding":"Dieses Gerät hat keine Bindung, daher gibt es keinen Zustand, der umgeschaltet werden könnte. Tippen bewirkt nichts.","marker.toggle_none_no_actionable_entity":"Dieses Gerät hat keinen Zustand, der umgeschaltet werden könnte. Tippen bewirkt nichts.","marker.toggle_none_configured_targets_missing":"Die konfigurierten Ziele sind nicht verfügbar. Die eigene Entität des Geräts wird nicht ersetzt.","marker.toggle_none_ha_disabled":"Das Ziel ist in Home Assistant deaktiviert und kann im Plan nicht verwendet werden.","marker.toggle_none_unavailable":"Das Ziel ist derzeit nicht verfügbar. Tippen bewirkt nichts.","marker.toggle_none_unsupported":"Home Assistant bietet keine sichere Umschaltfunktion für dieses Gerät. Tippen bewirkt nichts.","marker.toggle_none_secure":"Das Umschalten von Schlössern, Alarmen und gesicherten Toren über den Plan ist aus Sicherheitsgründen gesperrt.","run.automation":"Automatisierung","run.script":"Skript","run.scene":"Szene","confirm.tap_run":'"{name}" ausführen?',"confirm.tap_toggle":'"{name}" umschalten?',"confirm.current_state":"Aktueller Zustand: {state}","confirm.expected_state":"Nach dem Umschalten: {state}","confirm.group_current":"an {on} von {total}","confirm.group_all_on":"alle sind eingeschaltet","confirm.group_all_off":"alle sind ausgeschaltet","confirm.unavailable_targets":"Nicht verfügbar: {count}","confirm.expected_by_ha":"Home Assistant ermittelt den Zustand","confirm.state_on":"Ein","confirm.state_off":"Aus","confirm.state_open":"Offen","confirm.state_closed":"Geschlossen","confirm.state_opening":"Wird geöffnet","confirm.state_closing":"Wird geschlossen","confirm.state_stopped":"Gestoppt","confirm.state_unknown":"Unbekannt","toast.run_started":"Gestartet: {name}","toast.run_target_missing":"Ausführungsziel nicht gefunden — überprüfen Sie die Geräteeinstellungen","toast.run_target_required":"Wählen Sie eine Automatisierung, ein Skript oder eine Szene aus","toast.tap_target_changed":"Das Ziel der Aktion hat sich geändert. Versuchen Sie es erneut.","toast.virtual_light_toggle_failed":"Das virtuelle Licht konnte nicht umgeschaltet werden: {err}","toast.value_badge_source_required":"Einen Wert für den Badge auswählen","btn.run":"Ausführen","vac.section":"Roboterstaubsauger: aktuelle Position","vac.autocal":"Automatisch einrichten","vac.live":"Aktuelle Position im Plan","vac.trail":"Roboterpfad anzeigen","vac.cal_maps":"Kalibrierte Karten: {maps}","vac.autocal_no_rooms":'Die Integration meldet keine Raumliste — öffnen Sie "Manuell anpassen"',"vac.autocal_no_match":'Raumnamen stimmten nicht überein (mindestens 3 müssen übereinstimmen) — öffnen Sie "Manuell anpassen"',"vac.autocal_done":"Fertig: über {rooms} Räume zugeordnet. Eine Reinigung starten und das Ergebnis prüfen.","vac.cal_need_pos":"Der Roboter meldet keine Koordinaten — starten Sie eine Reinigung und pausieren Sie sie","vac.cal_done":"Kalibrierung gespeichert. Eine Reinigung starten und das Ergebnis prüfen.","vac.cal_cancelled":"Kalibrierung abgebrochen","vac.fit":"Manuell anpassen","vac.fit_hint":"Roboterkarte an die richtige Position ziehen und an den Ecken skalieren","vac.fit_rotate":"90° drehen","vac.fit_mirror":"Spiegeln","vac.trail_never":"Nie","vac.trail_cleaning":"Beim Reinigen","vac.trail_always":"Immer","gs.bg_group":"Bühnenhintergrund","gs.bg_color":"Hintergrund um den Plan","gs.bg_default":"Standardthema","gs.bg_theme":"Standardthema","gs.bg_mode":"Planhintergrund","gs.bg_static":"Statische Farbe","gs.bg_daynight":"Folgt der Sonne","gs.bg_daynight_hint":"Der Hintergrund wechselt durch Morgendämmerung, Tag, Abenddämmerung und Nacht mithilfe von sun.sun oder Ihrer lokalen Uhr, wenn keine Sonnendaten verfügbar sind. Für den Hintergrund ist kein Kompass erforderlich.","gs.sun_group":"Sonne","gs.sun_missing":"Die sun.sun-Entität wurde nicht gefunden — der Hintergrund folgt Ihrer lokalen Uhr; Fensterstrahlen sind nicht verfügbar.","gs.north":"Norden auf dem Plan","gs.north_ph":"nicht gesetzt","gs.north_hint":"Norden nur für Fensterstrahlen einstellen (1° Schritte, 15° mit Shift); der Sonnenhintergrund funktioniert auch ohne ihn.","gs.north_clear":"Löschen","gs.north_letter":"N","gs.sun_rays":"Sonnenlicht durch Fenster","gs.about_group":"Über","gs.about_version":"House Plan Card v{v}","gs.about_github":"GitHub · Dokumentation & Probleme","gs.about_telegram":"Telegram-Chat","space.bg_color":"Hintergrund rund um den Plan","space.bg_inherit":"Allgemein erben","space.bg_inherited":"erbt allgemeine Einstellungen","space.bg_mode":"Planhintergrund","space.north":"Norden auf dem Plan (überschreiben)","space.north_inherited":"geerbt: {v}","space.sun_rays":"Sonnenlicht durch Fenster","space.sun_inherit":"Allgemein erben","space.sun_on":"Ein","space.sun_off":"Aus","canvas.far_objects":"{n} Objekt(e) weit vom Plan entfernt","canvas.show_far":"Anzeigen","canvas.home_tip":"Der Plan ist dort drüben — klicken, um ihn anzupassen","gs.grid_group":"Planwartung","gs.grid_hint":"Aktualisiert Datenmodelle, richtet Planelemente am Raster aus und fasst redundante Wandfragmente zusammen. Ein exakter Bericht wird angezeigt, bevor etwas gespeichert wird.","gs.align_all":"Pläne optimieren","gs.align_title":"Pläne optimieren","gs.align_none":"Alle Pläne verwenden bereits das aktuelle optimierte Datenmodell.","gs.optimize_no_automatic_changes":"Es gibt keine automatischen Änderungen, die angewendet werden müssen. Überprüfen Sie die unten stehenden Punkte.","gs.align_count":"{n} von {total} Elementen werden sich um höchstens {cm} cm bewegen.","gs.align_where":"Die größte Verschiebung ist in „{s}“.","gs.align_turned":"Öffnungen, deren Winkel korrigiert wurde: {n}.","gs.align_removed_drafts":"Ungültige Umrisse vom Raster zusammengeklappt und entfernt: {n}.","gs.optimize_redundant_drafts":"Gespeicherte Wandketten, die durch feste Raumwände verdeckt waren, wurden entfernt: {n}.","gs.align_preflight_failed":"Die Geometrie der folgenden Bereiche konnte nicht sicher überprüft werden: {spaces}{more}.","gs.align_preflight_hint":"Pläne wurden nicht geändert. Kopieren Sie die Diagnosen mit dem untenstehenden Button und fügen Sie sie zusammen mit einem Raumexport dem Fehlerbericht bei.","gs.preflight_reason_prepare-exception":"Die Bereichsgeometrie konnte nicht vorbereitet werden (Ausnahme beim Erstellen des Modells)","gs.preflight_reason_wall-null":"Der Wandkörper wurde nicht erstellt (die Vereinigung lieferte leer zurück)","gs.preflight_reason_wall-degraded-extra":"Der Wandkörper wurde mit zusätzlicher Geometrie beschädigt","gs.preflight_reason_wall-failed-core":"Der Kern des Wandkörpers konnte nicht zusammengesetzt werden","gs.preflight_reason_wall-exception":"Die Wandkonstruktion warf eine Ausnahme","gs.preflight_reason_floor-null":"Der Fußbodenumriss wurde nicht erstellt","gs.preflight_reason_floor-exception":"Bodenaufbau hat eine Ausnahme ausgelöst","gs.preflight_copy":"Diagnosen kopieren","gs.preflight_copied":"Diagnosen kopiert","gs.preflight_update_hint":"Die Karten- und Integrationsversionen unterscheiden sich — Hausplan aktualisieren und erneut versuchen.","gs.align_preflight_space":"Bereich {n}","gs.align_preflight_more":", und {n} mehr","gs.optimize_changes":"Modellmigrationen: {m}; aktualisierte Bereiche: {c}; entfernte verrauschte Koordinatenwerte: {p}; zusammengeführte Fragmente realer Wände: {w}; zusammengeführte Fragmente von Wänden ohne Dicke: {s}; unabhängige Wände: {i}.","gs.zero_walls_migrated":"Virtuelle Wandspannweiten konvertiert: {n}.","gs.wall_segments_migrated":"Wandsegmente stabilisiert: {n}.","gs.optimize_lattice_summary":"Rauschen in den Koordinatenwerten kanonisiert: {n}; maximale Bewegung: {cm} cm.","gs.optimize_lattice_space":"{space}: Koordinatenwerte kanonisiert: {n}; außerhalb des Rasters liegende Werte unverändert gelassen: {far}.","gs.optimize_coincident_partitions":"Versteckte unabhängige Wandabschnitte in Raumwände integriert: {n}.","gs.optimize_openings_rehosted":"Öffnungen wieder an Raumwände angebracht: {n}.","gs.optimize_walls_straightened":"Wände begradigt: {n}; maximale Bewegung: {cm} cm.","gs.optimize_walls_straightened_where":"Größte Wandkorrektur: {s}.","gs.optimize_walls_straighten_skipped":"Nahe Achsenwände unverändert gelassen, da sie nicht sicher repariert werden konnten: {n}.","gs.optimize_glow_migration":"Legacy Glow: {spaces} Bereiche → keine Datenfüllung + unabhängiges Glow; {rooms} Räume → geerbte Datenfüllung + unabhängiges Glow.","gs.optimize_references":"Referenzen repariert: Bereiche — {spaces}; Räume — {rooms}; Positionen — {positions}; Geräte aus fehlenden Bereichen gelöst — {detached}.","gs.optimize_reference_more":", und {n} mehr","gs.optimize_orphans_removed":"Vergessene Einträge entfernt: {total} — Raumbezeichnungen: {rooms}; Geräte: {devices}; Gruppenmarkierungen: {groups}. Sie gehörten zu zuvor gelöschten Bereichen.","gs.optimize_live_positions":"Alte Positionen in gelöschten Bereichen gehören zu vorhandenen Objekten: {n}{names}. Sie werden beibehalten.","gs.optimize_live_positions_remove":"Alte Positionen in gelöschten Bereichen gehören zu vorhandenen Objekten: {n}{names}. Sie sind zur Entfernung ausgewählt.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Alte Positionen entfernen","gs.optimize_live_keep":"Alte Positionen beibehalten","gs.optimize_live_selected":"Alte Positionen werden nach der Anwendung von Optimieren entfernt.","gs.optimize_unverified":"Positionen konnten nicht sicher überprüft werden: {n}. Sie wurden unverändert belassen.","gs.optimize_registry_limited":"Voller Administratorzugriff auf die Home Assistant-Registries ist für eine sichere Überprüfung erforderlich.","gs.optimize_vacuum_warning":"Raumzuordnungen, die noch überprüft werden müssen: {n}.","gs.optimize_details":"Details","gs.optimize_details_more":"Und {n} weitere Einträge.","gs.optimize_detail_removed":"wird entfernt","gs.optimize_detail_live":"wird beibehalten","gs.optimize_detail_unverified":"nicht überprüft","gs.optimize_detail_room_label":"Raumkennzeichnung","gs.optimize_detail_device":"Gerät","gs.optimize_detail_group":"Gruppenkennzeichen","gs.optimize_detail_unknown":"unbekannter Eigentümer","gs.optimize_detail_item":"{status}: {kind} {id}; alter Bereich {space}","gs.align_warn":"Absichtlich zwischen Rasterknoten platzierte Elemente werden sich bewegen. Nach der Operation ist nur eine Rückgängig-Funktion verfügbar, und zwar nur bis zur nächsten Planbearbeitung.","gs.align_run":"Optimieren","gs.align_done":"Pläne optimiert: {n} Elemente bewegt, {m} Datensätze beibehalten, {r} Verweise repariert","gs.optimize_undo":"Letzte Optimierung rückgängig machen","gs.optimize_undone":"Die letzte Optimierung wurde rückgängig gemacht","decor.furniture":"Möbel","furn.title":"Möbelbibliothek","furn.symbol":"Symbol","furn.group_furniture":"Möbel","furn.group_appliance":"Geräte","furn.group_sanitary":"Sanitär","furn.group_other":"Sonstiges","furn.width":"Breite","furn.depth":"Tiefe","furn.back_to_categories":"Alle Kategorien","furn.pick_hint":"Wählen Sie eine Kategorie und dann ein Symbol.","furn.place_hint":"Klicken Sie auf den Plan — das Element wird an der nächsten Wand platziert. Mit Shift wird es frei platziert.","furn.cat_air_conditioner":"Klimaanlagen","furn.cat_armchair":"Sessel","furn.cat_bathtub":"Badewannen","furn.cat_bed":"Betten","furn.cat_bidet":"Bidets","furn.cat_boiler":"Warmwasserbereiter","furn.cat_chair":"Stühle","furn.cat_coffee_table":"Couchtische","furn.cat_cooktop":"Kochfelder","furn.cat_dining_table":"Esstische","furn.cat_dishwasher":"Geschirrspüler","furn.cat_dryer":"Wäschetrockner","furn.cat_fireplace":"Kamine","furn.cat_fridge":"Kühlschränke","furn.cat_kitchen_cabinet":"Küchenschränke","furn.cat_kitchen_sink":"Küchenspülen","furn.cat_nightstand":"Schränke","furn.cat_plant":"Pflanzen","furn.cat_rug":"Teppiche","furn.cat_shelving":"Regale","furn.cat_shower":"Duschen","furn.cat_sink":"Waschbecken","furn.cat_sofa":"Sofas","furn.cat_stairs":"Treppen","furn.cat_toilet":"Toiletten","furn.cat_tv":"Fernseher","furn.cat_wardrobe":"Kleiderschränke","furn.cat_washer":"Waschmaschinen","furn.cat_work_table":"Schreibtische","furn.sym_sofa":"Zweisitzer-Sofa","furn.sym_sofa_three_seat":"Dreisitzer-Sofa","furn.sym_sofa_corner_right":"Ecksofa rechts","furn.sym_armchair":"Polstersessel","furn.sym_armchair_office":"Bürostuhl","furn.sym_coffee_table":"Rechteckiger Couchtisch","furn.sym_coffee_table_round":"Runder Couchtisch","furn.sym_coffee_table_oval":"Ovaler Couchtisch","furn.sym_coffee_table_rounded":"Abgerundeter Couchtisch","furn.sym_table_dining":"Rechteckiger Esstisch","furn.sym_table_round":"Rundtisch","furn.sym_table_dining_oval":"Ovaler Esstisch","furn.sym_table_dining_rounded":"Abgerundeter Esstisch","furn.sym_chair":"Stuhl","furn.sym_chair_bar":"Barhocker","furn.sym_desk":"Rechteckiger Schreibtisch","furn.sym_desk_corner":"Eckschreibtisch","furn.sym_bed_double":"Doppelbett","furn.sym_bed_single":"Einzelbett","furn.sym_nightstand":"Nachttisch","furn.sym_cabinet_tv":"TV-Schrank","furn.sym_cabinet_shoe":"Schuhschrank","furn.sym_cabinet_sink":"Waschtischunterschrank","furn.sym_wardrobe":"Kleiderschrank","furn.sym_bookshelf":"Bücherschrank","furn.sym_wall_unit":"Schrankwand","furn.sym_kitchen_floor":"Küchen-Unterschrank","furn.sym_kitchen_floor_corner":"Küchen-Eckunterschrank","furn.sym_kitchen_wall":"Küchen-Hängeschrank","furn.sym_kitchen_wall_corner":"Küchen-Eckhängeschrank","furn.sym_shelf_floor":"Standregal","furn.sym_shelf_wall":"Wandregal","furn.sym_fridge":"Kühlschrank","furn.sym_stove":"Vierflammiges Kochfeld","furn.sym_cooktop_two":"Zweiflammiges Kochfeld","furn.sym_dishwasher":"Geschirrspüler","furn.sym_washer":"Waschmaschine","furn.sym_dryer":"Wäschetrockner","furn.sym_tv":"Fernseher mit Standfuß","furn.sym_tv_wall":"Wandfernseher","furn.sym_ac":"Klimaanlage","furn.sym_water_heater":"Wassererhitzer","furn.sym_toilet":"Stand-WC","furn.sym_toilet_built_in":"Wand-WC","furn.sym_bathtub":"Rechteckige Badewanne","furn.sym_bathtub_corner":"Eckbadewanne","furn.sym_shower":"Dusche","furn.sym_sink":"Waschbecken","furn.sym_kitchen_sink":"Einzel-Küchenspüle","furn.sym_kitchen_sink_double":"Doppel-Küchenspüle","furn.sym_bidet":"Stand-Bidet","furn.sym_bidet_built_in":"Wand-Bidet","furn.sym_stairs":"Treppe","furn.sym_fireplace":"Kamin","furn.sym_plant":"Pflanze","furn.sym_rug":"Teppich","common.yes":"Ja","common.no":"Nein","vac.diag_source":"Quelle","vac.diag_platform":"Integration","vac.diag_status":"Status","vac.diag_position":"Position","vac.diag_rooms":"Räume","vac.diag_rooms_value":"{total} · {matched} Namen stimmen überein · {readiness}","vac.autocal_ready":"Auto-Kalibrierung verfügbar","vac.autocal_not_ready":"3 übereinstimmende Namen erforderlich","vac.diag_path":"Integrationspfad","vac.diag_map":"Karten-ID","vac.source_none":"nicht ausgewählt","vac.source_status_ok":"Bereit","vac.source_status_missing":"Fehlend","vac.source_status_disabled":"In Home Assistant deaktiviert","vac.source_status_unavailable":"Nicht verfügbar","vac.source_status_unverified":"Kann mit den aktuellen Berechtigungen nicht verifizieren","vac.source_status_unsupported":"Keine Positionsdaten","vac.source_status_none":"Keine Quelle","vac.source_banner_missing":"Die gespeicherte Quelle existiert nicht mehr. Sie wurde nicht automatisch ersetzt; wählen Sie eine andere Quelle oder stellen Sie sie in Home Assistant wieder her.","vac.source_banner_disabled":"Die gespeicherte Quelle ist in Home Assistant deaktiviert. Aktivieren Sie sie dort oder wählen Sie eine andere Quelle.","vac.source_banner_unverified":"Die aktuellen Home Assistant-Berechtigungen können diese gespeicherte Quelle nicht verifizieren. Sie bleibt angepinnt und wird nicht automatisch ersetzt.","vac.choose_source":"Quelle wählen","vac.source_auto":"Automatisch","vac.source_auto_hint":"Verwenden Sie eine kompatible Entität von diesem Gerät","vac.all_cameras":"Alle Kameras","vac.all_cameras_warn":"Eine Kamera liefert möglicherweise keine Roboter-Daten. Wählen Sie eine nur, wenn es Ihre Saugroboter-Karte ist.","vac.all_cameras_empty":"Keine anderen Kamera-Entitäten gefunden.","vac.platform_unknown":"unbekannte Integration","vac.cap_position":"Position","vac.cap_rooms_short":"Räume","vac.cap_path":"Pfad","vac.cap_map":"Karten-ID","vac.cap_none":"Keine Roboter-Daten erkannt","vac.xcme_hint":"Aktivieren Sie diese Xiaomi Cloud Map Extractor-Attribute:","vac.documentation":"Dokumentation","vac.residual_title":"Automatische Kalibrierung überprüfen","vac.residual_message":"Die zugeordneten Räume weichen um bis zu {error} voneinander ab. Diese ungefähre Kalibrierung anwenden, manuell verfeinern oder ohne Änderung der gespeicherten Einrichtung abbrechen.","vac.apply_proposal":"Anwenden","gs.backup_group":"Sichern und übertragen","gs.backup_hint":"Laden Sie ein tragbares JSON-Backup herunter oder sehen Sie eine Vorschau und importieren Sie ein Backup, das mit House Plan erstellt wurde.","backup.export_open":"Exportieren","backup.import_open":"Importieren","backup.export_title":"House Plan exportieren","backup.import_title":"House Plan importieren","backup.export_hint":"Wählen Sie, ob das Backup die gesamte House Plan-Konfiguration oder nur den aktuellen Bereich enthalten soll.","backup.full":"Vollständiges Backup","backup.current_space":"Aktueller Bereich","backup.current_space_title":"Aktueller Bereich: {title}","backup.no_current_space":"Kein aktueller Bereich","backup.plan_only":"Nur Plan","backup.plan_only_hint":"Räume, Wände, Öffnungen, Dekor und Raumbezeichnungspositionen ohne Geräte oder Home Assistant-Bindungen beibehalten.","backup.plan_only_preview":"Diese Datei enthält nur den Plan.","backup.privacy_warning":"Das Archiv enthält Namen, Home Assistant-Kennungen und genaue Koordinaten. Interne Pläne und Anhänge werden referenziert, nicht eingebettet; Laufzeitzustände und Staubsaugerspuren sind nicht enthalten.","backup.download":"JSON herunterladen","backup.export_done":"Backup heruntergeladen","backup.reading":"Überprüfe das Backup…","backup.revalidated":"Der Plan wurde nach dieser Vorschau geändert. Die Zusammenfassung wurde aktualisiert; überprüfen Sie sie und bestätigen Sie erneut.","backup.error.unauthorized":"Sie haben keine Berechtigung, diesen Plan zu exportieren oder zu importieren.","backup.error.not_ready":"Der Hausplan ist noch nicht fertig. Versuchen Sie es in einem Moment erneut.","backup.error.too_large":"Das Backup überschreitet das 8-MiB-Limit.","backup.error.invalid_json":"Die ausgewählte Datei ist kein gültiges JSON.","backup.error.invalid_format":"Die ausgewählte Datei ist kein House Plan-Backup.","backup.error.unsupported_export_version":"Dieses Backup-Format wird von der installierten Version nicht unterstützt.","backup.error.future_model":"Das Backup wurde mit einem neueren House-Plan-Datenmodell erstellt.","backup.error.invalid_config":"Das Backup enthält eine ungültige House-Plan-Konfiguration.","backup.error.wall_model_migration_blocked":"Das Backup-Wandmodell konnte nicht sicher aktualisiert werden. Optimieren Sie zuerst den Quellplan und exportieren Sie ihn dann erneut.","backup.error.invalid_layout":"Das Backup enthält ungültige Objektpositionen.","backup.error.invalid_content":"Das Backup enthält ungültige oder inkonsistente Inhaltsreferenzen.","backup.error.space_not_found":"Der ausgewählte Bereich existiert nicht mehr.","backup.error.capacity_exceeded":"Durch das Hinzufügen dieses Backups würden die Planlimits überschritten.","backup.error.preview_expired":"Die Vorschau ist abgelaufen. Wählen Sie die Backup-Datei erneut aus.","backup.error.preview_owner_mismatch":"Diese Vorschau gehört zu einem anderen Home-Assistant-Benutzer.","backup.error.conflict":"Der Plan hat sich nach der Vorschau geändert. Überprüfen Sie die aktualisierte Zusammenfassung.","backup.error.content_confirmation_required":"Bestätigen Sie, dass nicht verfügbare lokale Inhalte getrennt werden können.","backup.error.commit_failed":"Das Backup konnte nicht sicher angewendet werden. Der vorherige Plan wurde wiederhergestellt oder wartet auf die Wiederherstellung.","backup.error.missing_plan":"Eine referenzierte Plan-Datei ist nach der Vorschau verschwunden. Überprüfen Sie das Backup erneut.","backup.error.missing_content":"Ein referenziertes lokales Anhangselement ist nach der Vorschau verschwunden. Überprüfen Sie das Backup erneut.","backup.error.marker_control_missing":"Ein verknüpftes Planlicht fehlt im Backup.","backup.error.marker_control_not_light":"Ein verknüpftes Planziel ist nicht mehr als Lichtquelle markiert.","backup.error.marker_control_self":"Eine Lichtquelle kann sich nicht selbst steuern.","backup.error.marker_control_cycle":"Das Backup enthält eine kreisförmige Kette von Lichtsteuerungen.","backup.error.duplicate_marker_control":"Das Backup enthält eine doppelte Plan-Licht-Verknüpfung.","backup.error.no_backup":"Es gibt keinen Import- oder Optimierungssnapshot zur Wiederherstellung.","backup.same_source":"Erstellt auf dieser Home Assistant-Instanz","backup.foreign_source":"Erstellt auf einer anderen Home Assistant-Instanz","backup.created":"Erstellt: {value}","backup.versions":"Karte {card}; Integration {integration}; Datenmodell {model}","backup.count_spaces":"Bereiche: {n}","backup.count_rooms":"Räume: {n}","backup.count_walls":"Wände: {n}","backup.count_openings":"Öffnungen: {n}","backup.count_decor":"Dekorationsobjekte: {n}","backup.count_markers":"Geräte: {n}","backup.count_layout":"Positionen: {n}","backup.bindings":"Verknüpfungen — Geräte: {device}, Entitäten: {entity}, virtuell: {virtual}; Positionen ohne Bereich: {legacy}","backup.binding_status":"Zielstatus — aktiv: {active}, deaktiviert: {disabled}, fehlt: {missing}","backup.missing_areas":"Auf dem Ziel fehlende Bereiche: {areas}","backup.dropped_marker_links":"Planlicht-Verknüpfungen außerhalb dieses übertragenen Bereichs wurden ausgelassen: {n}.","backup.repaired_target_refs":"Durch den Import dieses Bereichs wiederhergestellte vorhandene Referenzen: {n}.","backup.preserved_unresolved_refs":"Referenzen, die nicht eindeutig wiederhergestellt werden konnten, wurden beibehalten: {n}.","backup.preserved_unresolved_hint":"Es wurden keine Daten geraten oder gelöscht. Führen Sie nach dem Import Optimierungspläne aus, um die verbleibenden Referenzen zu überprüfen.","backup.import_details":"Importieren von Referenzdetails","backup.import_detail.incoming_remapped":"Referenzen innerhalb der importierten Kopie aktualisiert: {n}","backup.import_detail.target_repaired":"Vorhandene Referenzen wiederhergestellt: {n}","backup.import_detail.preserved_unresolved":"Unaufgelöste Referenzen beibehalten: {n}","backup.import_detail.collisions":"Zielkonflikte sicher beibehalten: {n}","backup.import_detail.dropped_links":"Eingehende Links durch Übertragungsregeln ausgelassen: {n}","backup.import_detail.bounded_lineages":"Übermäßig verschachtelte Kennungen begrenzt belassen: {n}","backup.replace_warning":"Dies ersetzt die aktuelle Konfiguration und das Layout. Hochgeladene Dateien werden niemals gelöscht. Eine Rückgängig-Möglichkeit bleibt bis zur nächsten Planbearbeitung verfügbar.","backup.foreign_bookkeeping":"Instanzspezifische bekannte/neue Gerätebuchführung wird nicht importiert.","backup.final_name":"Name des neuen Bereichs","backup.target_settings":"Die globalen Einstellungen der Zielinstanz bleiben unverändert.","backup.duplicates":"Bindungen bereits vorhanden: {n}","backup.skip":"Doppelte Geräte überspringen","backup.virtual_copy":"Sichere statische virtuelle Kopien hinzufügen","backup.content":"Referenzierter Inhalt","backup.content_available":"lokal verfügbar","backup.content_external":"externer Link","backup.content_detach_required":"wird getrennt","backup.confirm_detach":"Ich verstehe, dass nicht verfügbare interne Pläne und Anhänge von der importierten Konfiguration getrennt werden.","backup.replace":"Ersetzen","backup.add":"Bereich hinzufügen","backup.space_done":"Bereich importiert: {rooms} Räume, {markers} Geräte, {refs} bestehende Referenzen wiederhergestellt","backup.full_done":"Backup wiederhergestellt: {spaces} Bereiche, {rooms} Räume, {markers} Geräte","backup.undo_import":"Letzten vollständigen Import rückgängig machen","backup.import_undone":"Vollständiger Import rückgängig gemacht"};const n="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";export{e as dictionary,n as fingerprint}; diff --git a/custom_components/houseplan/frontend/houseplan-assets/editor-H80bjnWS.js b/custom_components/houseplan/frontend/houseplan-assets/editor-H80bjnWS.js new file mode 100644 index 00000000..c96d3dc2 --- /dev/null +++ b/custom_components/houseplan/frontend/houseplan-assets/editor-H80bjnWS.js @@ -0,0 +1,14 @@ +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";import{c as e,l as o,t,c_ as s,A as a,c$ as i,d0 as l,d1 as n,E as r,b as c}from"./houseplan-card-BrUCyMoE.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`h[e.name]||e.name} + @value-changed=${this._valueChanged} + >`;return c` + ${d(f.slice(0,3))} + ${_?c``:a} + ${d(f.slice(3))} + `}_valueChanged(e){const o={...this._config,...e.detail.value};""===o.floor?delete o.floor:o.floor===this._floorToken&&(o.floor=this._config?.floor);const t=new Event("config-changed",{bubbles:!0,composed:!0});t.detail={config:o},this.dispatchEvent(t)}}h.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",h); diff --git a/custom_components/houseplan/frontend/houseplan-assets/houseplan-card-BrUCyMoE.js b/custom_components/houseplan/frontend/houseplan-assets/houseplan-card-BrUCyMoE.js new file mode 100644 index 00000000..8a05b20e --- /dev/null +++ b/custom_components/houseplan/frontend/houseplan-assets/houseplan-card-BrUCyMoE.js @@ -0,0 +1,5247 @@ +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";const e=globalThis,t=e.ShadowRoot&&(void 0===e.ShadyCSS||e.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,i=Symbol(),n=new WeakMap;let r=class{constructor(e,t,n){if(this._$cssResult$=!0,n!==i)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const i=this.t;if(t&&void 0===e){const t=void 0!==i&&1===i.length;t&&(e=n.get(i)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),t&&n.set(i,e))}return e}toString(){return this.cssText}};const o=(e,...t)=>{const n=1===e.length?e[0]:t.reduce((t,i,n)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+e[n+1],e[0]);return new r(n,e,i)},s=t?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const i of e.cssRules)t+=i.cssText;return(e=>new r("string"==typeof e?e:e+"",void 0,i))(t)})(e):e,{is:a,defineProperty:l,getOwnPropertyDescriptor:c,getOwnPropertyNames:h,getOwnPropertySymbols:d,getPrototypeOf:u}=Object,p=globalThis,_=p.trustedTypes,m=_?_.emptyScript:"",f=p.reactiveElementPolyfillSupport,g=(e,t)=>e,v={toAttribute(e,t){switch(t){case Boolean:e=e?m:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let i=e;switch(t){case Boolean:i=null!==e;break;case Number:i=null===e?null:Number(e);break;case Object:case Array:try{i=JSON.parse(e)}catch(e){i=null}}return i}},y=(e,t)=>!a(e,t),b={attribute:!0,type:String,converter:v,reflect:!1,useDefault:!1,hasChanged:y};Symbol.metadata??=Symbol("metadata"),p.litPropertyMetadata??=new WeakMap;let w=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=b){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const i=Symbol(),n=this.getPropertyDescriptor(e,i,t);void 0!==n&&l(this.prototype,e,n)}}static getPropertyDescriptor(e,t,i){const{get:n,set:r}=c(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:n,set(t){const o=n?.call(this);r?.call(this,t),this.requestUpdate(e,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??b}static _$Ei(){if(this.hasOwnProperty(g("elementProperties")))return;const e=u(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(g("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(g("properties"))){const e=this.properties,t=[...h(e),...d(e)];for(const i of t)this.createProperty(i,e[i])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,i]of t)this.elementProperties.set(e,i)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const i=this._$Eu(e,t);void 0!==i&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const i=new Set(e.flat(1/0).reverse());for(const e of i)t.unshift(s(e))}else void 0!==e&&t.push(s(e));return t}static _$Eu(e,t){const i=t.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof e?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const i of t.keys())this.hasOwnProperty(i)&&(e.set(i,this[i]),delete this[i]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const i=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((i,n)=>{if(t)i.adoptedStyleSheets=n.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const t of n){const n=document.createElement("style"),r=e.litNonce;void 0!==r&&n.setAttribute("nonce",r),n.textContent=t.cssText,i.appendChild(n)}})(i,this.constructor.elementStyles),i}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,i){this._$AK(e,i)}_$ET(e,t){const i=this.constructor.elementProperties.get(e),n=this.constructor._$Eu(e,i);if(void 0!==n&&!0===i.reflect){const r=(void 0!==i.converter?.toAttribute?i.converter:v).toAttribute(t,i.type);this._$Em=e,null==r?this.removeAttribute(n):this.setAttribute(n,r),this._$Em=null}}_$AK(e,t){const i=this.constructor,n=i._$Eh.get(e);if(void 0!==n&&this._$Em!==n){const e=i.getPropertyOptions(n),r="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:v;this._$Em=n;const o=r.fromAttribute(t,e.type);this[n]=o??this._$Ej?.get(n)??o,this._$Em=null}}requestUpdate(e,t,i,n=!1,r){if(void 0!==e){const o=this.constructor;if(!1===n&&(r=this[e]),i??=o.getPropertyOptions(e),!((i.hasChanged??y)(r,t)||i.useDefault&&i.reflect&&r===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,i))))return;this.C(e,t,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:i,reflect:n,wrapped:r},o){i&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==r||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||i||(t=void 0),this._$AL.set(e,t)),!0===n&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,i]of e){const{wrapped:e}=i,n=this[t];!0!==e||this._$AL.has(t)||void 0===n||this.C(t,void 0,i,n)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};w.elementStyles=[],w.shadowRootOptions={mode:"open"},w[g("elementProperties")]=new Map,w[g("finalized")]=new Map,f?.({ReactiveElement:w}),(p.reactiveElementVersions??=[]).push("2.1.2");const k=globalThis,x=e=>e,$=k.trustedTypes,S=$?$.createPolicy("lit-html",{createHTML:e=>e}):void 0,M="$lit$",R=`lit$${Math.random().toFixed(9).slice(2)}$`,T="?"+R,C=`<${T}>`,D=document,z=()=>D.createComment(""),A=e=>null===e||"object"!=typeof e&&"function"!=typeof e,O=Array.isArray,P="[ \t\n\f\r]",F=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,E=/-->/g,I=/>/g,H=RegExp(`>|${P}(?:([^\\s"'>=/]+)(${P}*=${P}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),N=/'/g,L=/"/g,q=/^(?:script|style|textarea|title)$/i,W=e=>(t,...i)=>({_$litType$:e,strings:t,values:i}),j=W(1),B=W(2),V=Symbol.for("lit-noChange"),U=Symbol.for("lit-nothing"),G=new WeakMap,K=D.createTreeWalker(D,129);function Y(e,t){if(!O(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==S?S.createHTML(t):t}const Z=(e,t)=>{const i=e.length-1,n=[];let r,o=2===t?"":3===t?"":"",s=F;for(let t=0;t"===l[0]?(s=r??F,c=-1):void 0===l[1]?c=-2:(c=s.lastIndex-l[2].length,a=l[1],s=void 0===l[3]?H:'"'===l[3]?L:N):s===L||s===N?s=H:s===E||s===I?s=F:(s=H,r=void 0);const d=s===H&&e[t+1].startsWith("/>")?" ":"";o+=s===F?i+C:c>=0?(n.push(a),i.slice(0,c)+M+i.slice(c)+R+d):i+R+(-2===c?t:d)}return[Y(e,o+(e[i]||"")+(2===t?"":3===t?"":"")),n]};class X{constructor({strings:e,_$litType$:t},i){let n;this.parts=[];let r=0,o=0;const s=e.length-1,a=this.parts,[l,c]=Z(e,t);if(this.el=X.createElement(l,i),K.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(n=K.nextNode())&&a.length0){n.textContent=$?$.emptyScript:"";for(let i=0;iO(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==U&&A(this._$AH)?this._$AA.nextSibling.data=e:this.T(D.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:i}=e,n="number"==typeof i?this._$AC(e):(void 0===i.el&&(i.el=X.createElement(Y(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===n)this._$AH.p(t);else{const e=new Q(n,this),i=e.u(this.options);e.p(t),this.T(i),this._$AH=e}}_$AC(e){let t=G.get(e.strings);return void 0===t&&G.set(e.strings,t=new X(e)),t}k(e){O(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let i,n=0;for(const r of e)n===t.length?t.push(i=new ee(this.O(z()),this.O(z()),this,this.options)):i=t[n],i._$AI(r),n++;n2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=U}_$AI(e,t=this,i,n){const r=this.strings;let o=!1;if(void 0===r)e=J(this,e,t,0),o=!A(e)||e!==this._$AH&&e!==V,o&&(this._$AH=e);else{const n=e;let s,a;for(e=r[0],s=0;s{const n=i?.renderBefore??t;let r=n._$litPart$;if(void 0===r){const e=i?.renderBefore??null;n._$litPart$=r=new ee(t.insertBefore(z(),e),e,void 0,i??{})}return r._$AI(e),r},ce=globalThis;let he=class extends w{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const e=super.createRenderRoot();return this.renderOptions.renderBefore??=e.firstChild,e}update(e){const t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=le(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return V}};he._$litElement$=!0,he.finalized=!0,ce.litElementHydrateSupport?.({LitElement:he});const de=ce.litElementPolyfillSupport;de?.({LitElement:he}),(ce.litElementVersions??=[]).push("4.2.2");const ue=2,pe=e=>(...t)=>({_$litDirective$:e,values:t});let _e=class{constructor(e){}get _$AU(){return this._$AM._$AU}_$AT(e,t,i){this._$Ct=e,this._$AM=t,this._$Ci=i}_$AS(e,t){return this.update(e,t)}update(e,t){return this.render(...t)}};const{I:me}=se,fe=e=>e,ge=()=>document.createComment(""),ve=(e,t,i)=>{const n=e._$AA.parentNode,r=void 0===t?e._$AB:t._$AA;if(void 0===i){const t=n.insertBefore(ge(),r),o=n.insertBefore(ge(),r);i=new me(t,o,e,e.options)}else{const t=i._$AB.nextSibling,o=i._$AM,s=o!==e;if(s){let t;i._$AQ?.(e),i._$AM=e,void 0!==i._$AP&&(t=e._$AU)!==o._$AU&&i._$AP(t)}if(t!==r||s){let e=i._$AA;for(;e!==t;){const t=fe(e).nextSibling;fe(n).insertBefore(e,r),e=t}}}return i},ye=(e,t,i=e)=>(e._$AI(t,i),e),be={},we=(e,t=be)=>e._$AH=t,ke=e=>{e._$AR(),e._$AA.remove()},xe=(e,t,i)=>{const n=new Map;for(let r=t;r<=i;r++)n.set(e[r],r);return n},$e=pe(class extends _e{constructor(e){if(super(e),e.type!==ue)throw Error("repeat() can only be used in text expressions")}dt(e,t,i){let n;void 0===i?i=t:void 0!==t&&(n=t);const r=[],o=[];let s=0;for(const t of e)r[s]=n?n(t,s):s,o[s]=i(t,s),s++;return{values:o,keys:r}}render(e,t,i){return this.dt(e,t,i).values}update(e,[t,i,n]){const r=(e=>e._$AH)(e),{values:o,keys:s}=this.dt(t,i,n);if(!Array.isArray(r))return this.ut=s,o;const a=this.ut??=[],l=[];let c,h,d=0,u=r.length-1,p=0,_=o.length-1;for(;d<=u&&p<=_;)if(null===r[d])d++;else if(null===r[u])u--;else if(a[d]===s[p])l[p]=ye(r[d],o[p]),d++,p++;else if(a[u]===s[_])l[_]=ye(r[u],o[_]),u--,_--;else if(a[d]===s[_])l[_]=ye(r[d],o[_]),ve(e,l[_+1],r[d]),d++,_--;else if(a[u]===s[p])l[p]=ye(r[u],o[p]),ve(e,r[d],r[u]),u--,p++;else if(void 0===c&&(c=xe(s,p,_),h=xe(a,d,u)),c.has(a[d]))if(c.has(a[u])){const t=h.get(s[p]),i=void 0!==t?r[t]:null;if(null===i){const t=ve(e,r[d]);ye(t,o[p]),l[p]=t}else l[p]=ye(i,o[p]),ve(e,r[d],i),r[t]=null;p++}else ke(r[u]),u--;else ke(r[d]),d++;for(;p<=_;){const t=ve(e,l[_+1]);ye(t,o[p]),l[p++]=t}for(;d<=u;){const e=r[d++];null!==e&&ke(e)}return this.ut=s,we(e,l),V}}),Se=new WeakMap;let Me=0;class Re extends he{constructor(){super(...arguments),this.title="",this.icon="",this.wide=!1,this.dismissOnScrim=!1,this.hass=null,this._opener=null,this._focusRoot=null,this._useHaDialog=!1,this._closing=!1,this._overlays=[],this._titleId="hp-dialog-title-"+ ++Me,this._focusInitial=()=>{const e=this._focusableElements(),t=e.find(e=>e.hasAttribute("autofocus"))||e[0]||(this._useHaDialog?null:this.renderRoot.querySelector(".close"))||this.renderRoot.querySelector(".surface")||this.renderRoot.querySelector("ha-dialog");t?.focus({preventScroll:!0})},this._requestClose=()=>{this._closing||(this._closing=!0,this.dispatchEvent(new CustomEvent("hp-close",{bubbles:!0,composed:!0})))},this._onKeyDown=e=>{if("Escape"===e.key){e.preventDefault(),e.stopImmediatePropagation(),this._pruneOverlays();const t=this._overlays[this._overlays.length-1];return t?void this._closeOverlay(t,"escape"):void this._requestClose()}if("Tab"!==e.key||this._useHaDialog)return;const t=this.renderRoot.querySelector(".close"),i=t?[t,...this._focusableElements()]:this._focusableElements();if(!i.length)return e.preventDefault(),void this.renderRoot.querySelector(".surface")?.focus({preventScroll:!0});const n=this._deepActiveElement(),r=i[0],o=i[i.length-1];!e.shiftKey||n!==r&&i.includes(n)?e.shiftKey||n!==o||(e.preventDefault(),r.focus()):(e.preventDefault(),o.focus())},this._onFallbackCancel=e=>{e.preventDefault(),this._requestClose()},this._onFallbackClick=e=>{this.dismissOnScrim&&e.target===e.currentTarget&&this._requestClose()}}connectedCallback(){super.connectedCallback(),this._opener=this._deepActiveElement();const e=this.getRootNode();this._focusRoot=e;const t=Se.get(e)||{dialogs:new Set,opener:this._opener};t.dialogs.add(this),Se.set(e,t),this._useHaDialog=!!customElements.get("ha-dialog"),this.addEventListener("keydown",this._onKeyDown,!0)}disconnectedCallback(){this.removeEventListener("keydown",this._onKeyDown,!0);const e=[...this._overlays];this._overlays=[];for(const t of e.reverse())t.close("disconnect");const t=this._focusRoot,i=this._opener;this._opener=null,this._focusRoot=null;const n=t?Se.get(t):void 0;n?.dialogs.delete(this),super.disconnectedCallback(),t&&n&&requestAnimationFrame(()=>{const e=Se.get(t);if(!e)return;if(!e.dialogs.size)return e.opener?.isConnected&&e.opener.focus({preventScroll:!0}),void Se.delete(t);const n=i?.closest("hp-dialog");i?.isConnected&&n&&e.dialogs.has(n)&&i.focus({preventScroll:!0})})}firstUpdated(e){if(super.firstUpdated(e),!this._useHaDialog){const e=this.renderRoot.querySelector("dialog");e&&!e.open&&e.showModal()}queueMicrotask(()=>this._focusInitial())}_deepActiveElement(){let e=document.activeElement;for(;e?.shadowRoot?.activeElement;)e=e.shadowRoot.activeElement;return e&&e!==document.body?e:null}_focusableElements(){const e=["[autofocus]","a[href]","button:not([disabled])",'input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])",'[contenteditable="true"]','[tabindex]:not([tabindex="-1"])'].join(","),t=[],i=new Set,n=r=>{if(!i.has(r)){if(i.add(r),r instanceof HTMLElement){if(r.matches(e)&&t.push(r),r instanceof HTMLSlotElement){for(const e of r.assignedNodes({flatten:!0}))n(e);return}if(r.shadowRoot){for(const e of r.shadowRoot.childNodes)n(e);return}}for(const e of r.childNodes)n(e)}};for(const e of this.childNodes)n(e);const r=this.overlayPortal();return r&&n(r),t.filter(e=>{let t=e;for(;t;){const e=getComputedStyle(t);if(t.hidden||t.inert||"true"===t.getAttribute("aria-hidden")||"none"===e.display||"hidden"===e.visibility)return!1;if(t=t.assignedSlot||t.parentElement||(t.getRootNode()instanceof ShadowRoot?t.getRootNode().host:null),t===this)break}return!0})}_pruneOverlays(){this._overlays=this._overlays.filter(e=>e.owner.isConnected)}_closeOverlay(e,t){const i=this._overlays.findIndex(t=>t.token===e.token);i>=0&&this._overlays.splice(i,1),e.close(t)}registerOverlay(e){this._pruneOverlays();const t=this._overlays.find(t=>t.owner===e.owner);t&&this._overlays.splice(this._overlays.indexOf(t),1);const i=e.group||"transient";for(const e of[...this._overlays].reverse())e.group===i&&this._closeOverlay(e,"exclusive");const n={...e,group:i,token:Symbol("hp-overlay")};this._overlays.push(n);let r=!1;return()=>{if(r)return;r=!0;const e=this._overlays.findIndex(e=>e.token===n.token);e>=0&&this._overlays.splice(e,1)}}closeTransientOverlays(e="outside"){this._pruneOverlays();const t=[...this._overlays].filter(e=>"transient"===(e.group||"transient"));for(const i of t.reverse())this._closeOverlay(i,e);return t.length>0}overlayPortal(){return this.renderRoot.querySelector(".overlay-portal")}render(){const e=j` + ${this.icon?j``:U} + ${this.title} + `;return this._useHaDialog?j` + ${e} + + +
`:j` +
+
+ ${e} + +
+
+ +
+
+
`}}Re.properties={title:{type:String},icon:{type:String},wide:{type:Boolean,reflect:!0},dismissOnScrim:{type:Boolean,attribute:"dismiss-on-scrim"},hass:{attribute:!1}},Re.styles=o` + :host { + display: contents; + color: var(--primary-text-color, #e6e7eb); + font: inherit; + } + + ha-dialog { + --dialog-content-padding: 0; + --dialog-surface-background: var(--card-background-color, var(--hp-bg, #202126)); + --ha-dialog-border-radius: var(--rad-l, 18px); + /* HA's ha-dialog-header defaults this custom property to a one-line + fixed height. Our localized slot is intentionally allowed to wrap, + so leaving that default in place clips every line after the first at + the bottom of the header. auto is HA's public sizing hook and also + stays harmless on older ha-dialog implementations that do not consume + it. */ + --ha-dialog-header-title-height: auto; + color: inherit; + } + + ha-dialog::part(dialog) { + border: 1px solid var(--hp-accent, #d89300); + box-shadow: var(--shadow-3, 0 18px 48px rgb(0 0 0 / 0.34)); + overflow: hidden; + } + + /* The HA header slot is a flex item with a constrained inline size. The + old inline-flex title kept its min-content width, so HA clipped the last + word instead of giving it a second line. Keep every wrapper shrinkable + and let the text wrap; this applies to every hp-dialog, including long + device names and translated titles. */ + .header-title-slot { + display: block; + flex: 1 1 auto; + width: 100%; + max-width: 100%; + min-width: 0; + box-sizing: border-box; + white-space: normal; + } + + .title { + display: flex; + flex: 1 1 auto; + align-items: center; + gap: var(--sp-4, 12px); + width: 100%; + max-width: 100%; + min-width: 0; + font-weight: 600; + line-height: 1.25; + white-space: normal; + } + + .title ha-icon { + flex: none; + color: var(--hp-accent, #d89300); + } + + .title-text { + flex: 1 1 auto; + min-width: 0; + max-width: 100%; + white-space: normal; + overflow-wrap: anywhere; + word-break: normal; + } + + .footer { + /* ha-dialog lays out its footer slot as a flex row. display: contents + exposed the consumer's action row as a shrink-to-fit flex item, so a + wide device dialog got a half-width divider and its Hide action slid + toward the centre. Keep one full-width slot item in both HA and the + native fallback. */ + display: block; + width: 100%; + min-width: 0; + box-sizing: border-box; + } + + ::slotted([slot='footer']) { + width: 100%; + box-sizing: border-box; + } + + dialog { + width: auto; + max-width: none; + max-height: none; + margin: auto; + padding: 0; + border: 0; + overflow: visible; + color: inherit; + background: transparent; + } + + dialog::backdrop { + background: rgb(0 0 0 / 0.45); + } + + .surface { + width: min(360px, 92vw); + max-height: 92vh; + display: flex; + flex-direction: column; + overflow: hidden; + box-sizing: border-box; + color: inherit; + background: var(--card-background-color, var(--hp-bg, #202126)); + border: 1px solid var(--hp-accent, #d89300); + border-radius: var(--rad-l, 18px); + box-shadow: var(--shadow-3, 0 18px 48px rgb(0 0 0 / 0.34)); + } + + :host([wide]) .surface { + width: min(var(--hp-dialog-wide-width, 500px), 94vw); + } + + .header { + min-height: 56px; + display: flex; + align-items: center; + gap: var(--sp-4, 12px); + padding: var(--sp-4, 12px) var(--sp-5, 16px); + box-sizing: border-box; + border-bottom: 1px solid var(--hp-line, rgb(255 255 255 / 0.12)); + } + + .header .title { + flex: 1; + } + + .close { + width: 40px; + height: 40px; + flex: none; + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0; + color: inherit; + background: transparent; + border: 0; + border-radius: 50%; + cursor: pointer; + } + + :host([data-pointer-hover]) .close:hover, + .close:focus-visible { + background: rgb(127 127 127 / 0.16); + } + + .content { + min-height: 0; + display: flex; + flex-direction: column; + } + + .overlay-portal { + position: fixed; + z-index: 2147483647; + inset: 0; + overflow: visible; + pointer-events: none; + } + + .overlay-portal:empty { + display: none; + } + + .overlay-portal > * { + pointer-events: auto; + } + `,customElements.get("hp-dialog")||customElements.define("hp-dialog",Re);const Te=new Set(["hacs","sun","backup","hassio","met","telegram_bot","mobile_app","systemmonitor","better_thermostat","adaptive_lighting","yandex_pogoda","upnp_serial_number"]),Ce=[{pattern:"протечк|leak|water sensor",icon:"mdi:water-alert"},{pattern:"клапан|valve",icon:"mdi:pipe-valve"},{pattern:"дым|smoke",icon:"mdi:smoke-detector"},{pattern:"термоголов|trv|radiator",icon:"mdi:radiator"},{pattern:"чайник|kettle|термопот",icon:"mdi:kettle"},{pattern:"сауна|sauna|harvia|парная|парилк",icon:"mdi:hot-tub"},{pattern:"температ|temperature|thermometer|climate sensor",icon:"mdi:thermometer"},{pattern:"qingping|air monitor|молекул|air quality",icon:"mdi:air-filter"},{pattern:"штор|curtain|blind|shade",icon:"mdi:roller-shade"},{pattern:"розетк|plug|socket|outlet",icon:"mdi:power-socket-de"},{pattern:"выключат|switch",icon:"mdi:light-switch"},{pattern:"лампа|лампочк|bulb|gx53|светильник|rgb|lamp|light strip",icon:"mdi:lightbulb"},{pattern:"камер|camera",icon:"mdi:cctv"},{pattern:"замок|ttlock|lock|sn609|sn9161",icon:"mdi:lock"},{pattern:"ворота|garage|gate",icon:"mdi:garage-variant"},{pattern:"калитк|door|открыт|contact",icon:"mdi:door"},{pattern:"счётчик|счетчик|kws|meter",icon:"mdi:meter-electric"},{pattern:"вводный автомат|breaker|wifimcbn",icon:"mdi:electric-switch"},{pattern:"myheat|котёл|котел|boiler|отоплен|heating",icon:"mdi:water-boiler"},{pattern:"холодильник|fridge",icon:"mdi:fridge"},{pattern:"стиральн|washer|washing",icon:"mdi:washing-machine"},{pattern:"сушилк|dryer",icon:"mdi:tumble-dryer"},{pattern:"пылесос|vacuum|dreame|roborock",icon:"mdi:robot-vacuum"},{pattern:"soundbar",icon:"mdi:soundbar"},{pattern:"колонк|станц|speaker|яндекс|yandex|алиса|alice",icon:"mdi:speaker"},{pattern:"tv|телевизор|hyundaitv|mitv|television",icon:"mdi:television"},{pattern:"keenetic|роутер|router|mesh|access point",icon:"mdi:router-wireless"},{pattern:"ибп|ups|kirpich",icon:"mdi:battery-charging-high"},{pattern:"slzb|координат|zigbee|coordinator",icon:"mdi:zigbee"},{pattern:"motion|движен|presence|присутств",icon:"mdi:motion-sensor"},{pattern:"humidity|влажн",icon:"mdi:water-percent"}];function De(e){const t=[];for(const i of e)if(i&&"string"==typeof i.pattern&&i.icon)try{t.push({re:new RegExp(i.pattern,"i"),icon:i.icon})}catch{}return t}function ze(e){try{return new RegExp(e,"i"),!0}catch{return!1}}const Ae=De(Ce),Oe={temperature:"mdi:thermometer",humidity:"mdi:water-percent",motion:"mdi:motion-sensor",occupancy:"mdi:motion-sensor",presence:"mdi:motion-sensor",door:"mdi:door",window:"mdi:window-closed",garage_door:"mdi:garage-variant",smoke:"mdi:smoke-detector",moisture:"mdi:water-alert",gas:"mdi:gas-cylinder",power:"mdi:meter-electric",energy:"mdi:meter-electric",illuminance:"mdi:brightness-5",co2:"mdi:molecule-co2",pm25:"mdi:air-filter",battery:"mdi:battery"},Pe="mdi:chip";function Fe(e,t,i){const n=((e||"")+" "+(t||"")).toLowerCase();for(const{re:e,icon:t}of i??Ae)if(e.test(n))return t;return Pe}const Ee=["light","switch","cover","valve","lock","climate","fan","media_player","camera","vacuum","humidifier","water_heater","alarm_control_panel","sensor","binary_sensor","event","button","number","select","update"];var Ie=/^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i,He=Math.ceil,Ne=Math.floor,Le="[BigNumber Error] ",qe=Le+"Number primitive has more than 15 significant digits: ",We=1e14,je=14,Be=9007199254740991,Ve=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],Ue=1e7,Ge=1e9;function Ke(e){var t=0|e;return e>0||e===t?t:t-1}function Ye(e){for(var t,i,n=1,r=e.length,o=e[0]+"";nc^i?1:-1;for(a=(l=r.length)<(c=o.length)?l:c,s=0;so[s]^i?1:-1;return l==c?0:l>c^i?1:-1}function Xe(e,t,i,n){if(ei||e!==Ne(e))throw Error(Le+(n||"Argument")+("number"==typeof e?ei?" out of range: ":" not an integer: ":" not a primitive number: ")+String(e))}function Je(e){var t=e.c.length-1;return Ke(e.e/je)==t&&e.c[t]%2!=0}function Qe(e,t){return(e.length>1?e.charAt(0)+"."+e.slice(1):e)+(t<0?"e":"e+")+t}function et(e,t,i){var n,r;if(t<0){for(r=i+".";++t;r+=i);e=r+e}else if(++t>(n=e.length)){for(r=i,t-=n;--t;r+=i);e+=r}else ty?u.c=u.e=null:e.e=10;l/=10,a++);return void(a>y?u.c=u.e=null:(u.e=a,u.c=[e]))}d=String(e)}else{if(!Ie.test(d=String(e)))return r(u,d,c);u.s=45==d.charCodeAt(0)?(d=d.slice(1),-1):1}(a=d.indexOf("."))>-1&&(d=d.replace(".","")),(l=d.search(/e/i))>0?(a<0&&(a=l),a+=+d.slice(l+1),d=d.substring(0,l)):a<0&&(a=d.length)}else{if(Xe(t,2,$.length,"Base"),10==t&&S)return D(u=new M(e),_+u.e+1,m);if(d=String(e),c="number"==typeof e){if(0*e!=0)return r(u,d,c,t);if(u.s=1/e<0?(d=d.slice(1),-1):1,M.DEBUG&&d.replace(/^0\.0*|\./,"").length>15)throw Error(qe+e)}else u.s=45===d.charCodeAt(0)?(d=d.slice(1),-1):1;for(i=$.slice(0,t),a=l=0,h=d.length;la){a=h;continue}}else if(!s&&(d==d.toUpperCase()&&(d=d.toLowerCase())||d==d.toLowerCase()&&(d=d.toUpperCase()))){s=!0,l=-1,a=0;continue}return r(u,String(e),c,t)}c=!1,(a=(d=n(d,t,10,u.s)).indexOf("."))>-1?d=d.replace(".",""):a=d.length}for(l=0;48===d.charCodeAt(l);l++);for(h=d.length;48===d.charCodeAt(--h););if(d=d.slice(l,++h)){if(h-=l,c&&M.DEBUG&&h>15&&(e>Be||e!==Ne(e)))throw Error(qe+u.s*e);if((a=a-l-1)>y)u.c=u.e=null;else if(a=g)?Qe(l,s):et(l,s,"0");else if(o=(e=D(new M(e),t,i)).e,a=(l=Ye(e.c)).length,1==n||2==n&&(t<=o||o<=f)){for(;as),l=et(l,o,"0"),o+1>a){if(--t>0)for(l+=".";t--;l+="0");}else if((t+=o-a)>0)for(o+1==a&&(l+=".");t--;l+="0");return e.s<0&&r?"-"+l:l}function T(e,t){for(var i,n,r=1,o=new M(e[0]);r=10;r/=10,n++);return(i=n+i*je-1)>y?e.c=e.e=null:i=10;a/=10,r++);if((o=t-r)<0)o+=je,s=t,l=d[c=0],h=Ne(l/u[r-s-1]%10);else if((c=He((o+1)/je))>=d.length){if(!n)break e;for(;d.length<=c;d.push(0));l=h=0,r=1,s=(o%=je)-je+1}else{for(l=a=d[c],r=1;a>=10;a/=10,r++);h=(s=(o%=je)-je+r)<0?0:Ne(l/u[r-s-1]%10)}if(n=n||t<0||null!=d[c+1]||(s<0?l:l%u[r-s-1]),n=i<4?(h||n)&&(0==i||i==(e.s<0?3:2)):h>5||5==h&&(4==i||n||6==i&&(o>0?s>0?l/u[r-s]:0:d[c-1])%10&1||i==(e.s<0?8:7)),t<1||!d[0])return d.length=0,n?(t-=e.e+1,d[0]=u[(je-t%je)%je],e.e=-t||0):d[0]=e.e=0,e;if(0==o?(d.length=c,a=1,c--):(d.length=c+1,a=u[je-o],d[c]=s>0?Ne(l/u[r-s]%u[s])*a:0),n)for(;;){if(0==c){for(o=1,s=d[0];s>=10;s/=10,o++);for(s=d[0]+=a,a=1;s>=10;s/=10,a++);o!=a&&(e.e++,d[0]==We&&(d[0]=1));break}if(d[c]+=a,d[c]!=We)break;d[c--]=0,a=1}for(o=d.length;0===d[--o];d.pop());}e.e>y?e.c=e.e=null:e.e=g?Qe(t,i):et(t,i,"0"),e.s<0?"-"+t:t)}return M.clone=e,M.ROUND_UP=0,M.ROUND_DOWN=1,M.ROUND_CEIL=2,M.ROUND_FLOOR=3,M.ROUND_HALF_UP=4,M.ROUND_HALF_DOWN=5,M.ROUND_HALF_EVEN=6,M.ROUND_HALF_CEIL=7,M.ROUND_HALF_FLOOR=8,M.EUCLID=9,M.config=M.set=function(e){var t,i;if(null!=e){if("object"!=typeof e)throw Error(Le+"Object expected: "+e);if(e.hasOwnProperty(t="DECIMAL_PLACES")&&(Xe(i=e[t],0,Ge,t),_=i),e.hasOwnProperty(t="ROUNDING_MODE")&&(Xe(i=e[t],0,8,t),m=i),e.hasOwnProperty(t="EXPONENTIAL_AT")&&((i=e[t])&&i.pop?(Xe(i[0],-Ge,0,t),Xe(i[1],0,Ge,t),f=i[0],g=i[1]):(Xe(i,-Ge,Ge,t),f=-(g=i<0?-i:i))),e.hasOwnProperty(t="RANGE"))if((i=e[t])&&i.pop)Xe(i[0],-Ge,-1,t),Xe(i[1],1,Ge,t),v=i[0],y=i[1];else{if(Xe(i,-Ge,Ge,t),!i)throw Error(Le+t+" cannot be zero: "+i);v=-(y=i<0?-i:i)}if(e.hasOwnProperty(t="CRYPTO")){if((i=e[t])!==!!i)throw Error(Le+t+" not true or false: "+i);if(i){if("undefined"==typeof crypto||!crypto||!crypto.getRandomValues&&!crypto.randomBytes)throw b=!i,Error(Le+"crypto unavailable");b=i}else b=i}if(e.hasOwnProperty(t="MODULO_MODE")&&(Xe(i=e[t],0,9,t),w=i),e.hasOwnProperty(t="POW_PRECISION")&&(Xe(i=e[t],0,Ge,t),k=i),e.hasOwnProperty(t="FORMAT")){if("object"!=typeof(i=e[t]))throw Error(Le+t+" not an object: "+i);x=i}if(e.hasOwnProperty(t="ALPHABET")){if("string"!=typeof(i=e[t])||/^.?$|[+\-.\s]|(.).*\1/.test(i))throw Error(Le+t+" invalid: "+i);S="0123456789"==i.slice(0,10),$=i}}return{DECIMAL_PLACES:_,ROUNDING_MODE:m,EXPONENTIAL_AT:[f,g],RANGE:[v,y],CRYPTO:b,MODULO_MODE:w,POW_PRECISION:k,FORMAT:x,ALPHABET:$}},M.isBigNumber=function(e){if(!e||!0!==e._isBigNumber)return!1;if(!M.DEBUG)return!0;var t,i,n=e.c,r=e.e,o=e.s;e:if("[object Array]"=={}.toString.call(n)){if((1===o||-1===o)&&r>=-Ge&&r<=Ge&&r===Ne(r)){if(0===n[0]){if(0===r&&1===n.length)return!0;break e}if((t=(r+1)%je)<1&&(t+=je),String(n[0]).length==t){for(t=0;t=We||i!==Ne(i))break e;if(0!==i)return!0}}}else if(null===n&&null===r&&(null===o||1===o||-1===o))return!0;throw Error(Le+"Invalid BigNumber: "+e)},M.maximum=M.max=function(){return T(arguments,-1)},M.minimum=M.min=function(){return T(arguments,1)},M.random=(o=9007199254740992,s=Math.random()*o&2097151?function(){return Ne(Math.random()*o)}:function(){return 8388608*(1073741824*Math.random()|0)+(8388608*Math.random()|0)},function(e){var t,i,n,r,o,a=0,l=[],c=new M(p);if(null==e?e=_:Xe(e,0,Ge),r=He(e/je),b)if(crypto.getRandomValues){for(t=crypto.getRandomValues(new Uint32Array(r*=2));a>>11))>=9e15?(i=crypto.getRandomValues(new Uint32Array(2)),t[a]=i[0],t[a+1]=i[1]):(l.push(o%1e14),a+=2);a=r/2}else{if(!crypto.randomBytes)throw b=!1,Error(Le+"crypto unavailable");for(t=crypto.randomBytes(r*=7);a=9e15?crypto.randomBytes(7).copy(t,a):(l.push(o%1e14),a+=7);a=r/7}if(!b)for(;a=10;o/=10,a++);ai-1&&(null==s[r+1]&&(s[r+1]=0),s[r+1]+=s[r]/i|0,s[r]%=i)}return s.reverse()}return function(n,r,o,s,a){var l,c,h,d,u,p,f,g,v=n.indexOf("."),y=_,b=m;for(v>=0&&(d=k,k=0,n=n.replace(".",""),p=(g=new M(r)).pow(n.length-v),k=d,g.c=t(et(Ye(p.c),p.e,"0"),10,o,e),g.e=g.c.length),h=d=(f=t(n,r,o,a?(l=$,e):(l=e,$))).length;0==f[--d];f.pop());if(!f[0])return l.charAt(0);if(v<0?--h:(p.c=f,p.e=h,p.s=s,f=(p=i(p,g,y,b,o)).c,u=p.r,h=p.e),v=f[c=h+y+1],d=o/2,u=u||c<0||null!=f[c+1],u=b<4?(null!=v||u)&&(0==b||b==(p.s<0?3:2)):v>d||v==d&&(4==b||u||6==b&&1&f[c-1]||b==(p.s<0?8:7)),c<1||!f[0])n=u?et(l.charAt(1),-y,l.charAt(0)):l.charAt(0);else{if(f.length=c,u)for(--o;++f[--c]>o;)f[c]=0,c||(++h,f=[1].concat(f));for(d=f.length;!f[--d];);for(v=0,n="";v<=d;n+=l.charAt(f[v++]));n=et(n,h,l.charAt(0))}return n}}(),i=function(){function e(e,t,i){var n,r,o,s,a=0,l=e.length,c=t%Ue,h=t/Ue|0;for(e=e.slice();l--;)a=((r=c*(o=e[l]%Ue)+(n=h*o+(s=e[l]/Ue|0)*c)%Ue*Ue+a)/i|0)+(n/Ue|0)+h*s,e[l]=r%i;return a&&(e=[a].concat(e)),e}function t(e,t,i,n){var r,o;if(i!=n)o=i>n?1:-1;else for(r=o=0;rt[r]?1:-1;break}return o}function i(e,t,i,n){for(var r=0;i--;)e[i]-=r,r=e[i]1;e.splice(0,1));}return function(n,r,o,s,a){var l,c,h,d,u,p,_,m,f,g,v,y,b,w,k,x,$,S=n.s==r.s?1:-1,R=n.c,T=r.c;if(!(R&&R[0]&&T&&T[0]))return new M(n.s&&r.s&&(R?!T||R[0]!=T[0]:T)?R&&0==R[0]||!T?0*S:S/0:NaN);for(f=(m=new M(S)).c=[],S=o+(c=n.e-r.e)+1,a||(a=We,c=Ke(n.e/je)-Ke(r.e/je),S=S/je|0),h=0;T[h]==(R[h]||0);h++);if(T[h]>(R[h]||0)&&c--,S<0)f.push(1),d=!0;else{for(w=R.length,x=T.length,h=0,S+=2,(u=Ne(a/(T[0]+1)))>1&&(T=e(T,u,a),R=e(R,u,a),x=T.length,w=R.length),b=x,v=(g=R.slice(0,x)).length;v=a/2&&k++;do{if(u=0,(l=t(T,g,x,v))<0){if(y=g[0],x!=v&&(y=y*a+(g[1]||0)),(u=Ne(y/k))>1)for(u>=a&&(u=a-1),_=(p=e(T,u,a)).length,v=g.length;1==t(p,g,_,v);)u--,i(p,x<_?$:T,_,a),_=p.length,l=1;else 0==u&&(l=u=1),_=(p=T.slice()).length;if(_=10;S/=10,h++);D(m,o+(m.e=h+c*je-1)+1,s,d)}else m.e=c,m.r=+d;return m}}(),a=/^(-?)0([xbo])(?=\w[\w.]*$)/i,l=/^([^.]+)\.$/,c=/^\.([^.]+)$/,h=/^-?(Infinity|NaN)$/,d=/^\s*\+(?=[\w.])|^\s+|\s+$/g,r=function(e,t,i,n){var r,o=i?t:t.replace(d,"");if(h.test(o))e.s=isNaN(o)?null:o<0?-1:1;else{if(!i&&(o=o.replace(a,function(e,t,i){return r="x"==(i=i.toLowerCase())?16:"b"==i?2:8,n&&n!=r?e:t}),n&&(r=n,o=o.replace(l,"$1").replace(c,"0.$1")),t!=o))return new M(o,r);if(M.DEBUG)throw Error(Le+"Not a"+(n?" base "+n:"")+" number: "+t);e.s=null}e.c=e.e=null},u.absoluteValue=u.abs=function(){var e=new M(this);return e.s<0&&(e.s=1),e},u.comparedTo=function(e,t){return Ze(this,new M(e,t))},u.decimalPlaces=u.dp=function(e,t){var i,n,r,o=this;if(null!=e)return Xe(e,0,Ge),null==t?t=m:Xe(t,0,8),D(new M(o),e+o.e+1,t);if(!(i=o.c))return null;if(n=((r=i.length-1)-Ke(this.e/je))*je,r=i[r])for(;r%10==0;r/=10,n--);return n<0&&(n=0),n},u.dividedBy=u.div=function(e,t){return i(this,new M(e,t),_,m)},u.dividedToIntegerBy=u.idiv=function(e,t){return i(this,new M(e,t),0,1)},u.exponentiatedBy=u.pow=function(e,t){var i,n,r,o,s,a,l,c,h=this;if((e=new M(e)).c&&!e.isInteger())throw Error(Le+"Exponent not an integer: "+z(e));if(null!=t&&(t=new M(t)),s=e.e>14,!h.c||!h.c[0]||1==h.c[0]&&!h.e&&1==h.c.length||!e.c||!e.c[0])return c=new M(Math.pow(+z(h),s?e.s*(2-Je(e)):+z(e))),t?c.mod(t):c;if(a=e.s<0,t){if(t.c?!t.c[0]:!t.s)return new M(NaN);(n=!a&&h.isInteger()&&t.isInteger())&&(h=h.mod(t))}else{if(e.e>9&&(h.e>0||h.e<-1||(0==h.e?h.c[0]>1||s&&h.c[1]>=24e7:h.c[0]<8e13||s&&h.c[0]<=9999975e7)))return o=h.s<0&&Je(e)?-0:0,h.e>-1&&(o=1/o),new M(a?1/o:o);k&&(o=He(k/je+2))}for(s?(i=new M(.5),a&&(e.s=1),l=Je(e)):l=(r=Math.abs(+z(e)))%2,c=new M(p);;){if(l){if(!(c=c.times(h)).c)break;o?c.c.length>o&&(c.c.length=o):n&&(c=c.mod(t))}if(r){if(0===(r=Ne(r/2)))break;l=r%2}else if(D(e=e.times(i),e.e+1,1),e.e>14)l=Je(e);else{if(0===(r=+z(e)))break;l=r%2}h=h.times(h),o?h.c&&h.c.length>o&&(h.c.length=o):n&&(h=h.mod(t))}return n?c:(a&&(c=p.div(c)),t?c.mod(t):o?D(c,k,m,void 0):c)},u.integerValue=function(e){var t=new M(this);return null==e?e=m:Xe(e,0,8),D(t,t.e+1,e)},u.isEqualTo=u.eq=function(e,t){return 0===Ze(this,new M(e,t))},u.isFinite=function(){return!!this.c},u.isGreaterThan=u.gt=function(e,t){return Ze(this,new M(e,t))>0},u.isGreaterThanOrEqualTo=u.gte=function(e,t){return 1===(t=Ze(this,new M(e,t)))||0===t},u.isInteger=function(){return!!this.c&&Ke(this.e/je)>this.c.length-2},u.isLessThan=u.lt=function(e,t){return Ze(this,new M(e,t))<0},u.isLessThanOrEqualTo=u.lte=function(e,t){return-1===(t=Ze(this,new M(e,t)))||0===t},u.isNaN=function(){return!this.s},u.isNegative=function(){return this.s<0},u.isPositive=function(){return this.s>0},u.isZero=function(){return!!this.c&&0==this.c[0]},u.minus=function(e,t){var i,n,r,o,s=this,a=s.s;if(t=(e=new M(e,t)).s,!a||!t)return new M(NaN);if(a!=t)return e.s=-t,s.plus(e);var l=s.e/je,c=e.e/je,h=s.c,d=e.c;if(!l||!c){if(!h||!d)return h?(e.s=-t,e):new M(d?s:NaN);if(!h[0]||!d[0])return d[0]?(e.s=-t,e):new M(h[0]?s:3==m?-0:0)}if(l=Ke(l),c=Ke(c),h=h.slice(),a=l-c){for((o=a<0)?(a=-a,r=h):(c=l,r=d),r.reverse(),t=a;t--;r.push(0));r.reverse()}else for(n=(o=(a=h.length)<(t=d.length))?a:t,a=t=0;t0)for(;t--;h[i++]=0);for(t=We-1;n>a;){if(h[--n]=0;){for(i=0,u=y[r]%f,p=y[r]/f|0,o=r+(s=l);o>r;)i=((c=u*(c=v[--s]%f)+(a=p*c+(h=v[s]/f|0)*u)%f*f+_[o]+i)/m|0)+(a/f|0)+p*h,_[o--]=c%m;_[o]=i}return i?++n:_.splice(0,1),C(e,_,n)},u.negated=function(){var e=new M(this);return e.s=-e.s||null,e},u.plus=function(e,t){var i,n=this,r=n.s;if(t=(e=new M(e,t)).s,!r||!t)return new M(NaN);if(r!=t)return e.s=-t,n.minus(e);var o=n.e/je,s=e.e/je,a=n.c,l=e.c;if(!o||!s){if(!a||!l)return new M(r/0);if(!a[0]||!l[0])return l[0]?e:new M(a[0]?n:0*r)}if(o=Ke(o),s=Ke(s),a=a.slice(),r=o-s){for(r>0?(s=o,i=l):(r=-r,i=a),i.reverse();r--;i.push(0));i.reverse()}for((r=a.length)-(t=l.length)<0&&(i=l,l=a,a=i,t=r),r=0;t;)r=(a[--t]=a[t]+l[t]+r)/We|0,a[t]=We===a[t]?0:a[t]%We;return r&&(a=[r].concat(a),++s),C(e,a,s)},u.precision=u.sd=function(e,t){var i,n,r,o=this;if(null!=e&&e!==!!e)return Xe(e,1,Ge),null==t?t=m:Xe(t,0,8),D(new M(o),e,t);if(!(i=o.c))return null;if(n=(r=i.length-1)*je+1,r=i[r]){for(;r%10==0;r/=10,n--);for(r=i[0];r>=10;r/=10,n++);}return e&&o.e+1>n&&(n=o.e+1),n},u.shiftedBy=function(e){return Xe(e,-9007199254740991,Be),this.times("1e"+e)},u.squareRoot=u.sqrt=function(){var e,t,n,r,o,s=this,a=s.c,l=s.s,c=s.e,h=_+4,d=new M("0.5");if(1!==l||!a||!a[0])return new M(!l||l<0&&(!a||a[0])?NaN:a?s:1/0);if(0==(l=Math.sqrt(+z(s)))||l==1/0?(((t=Ye(a)).length+c)%2==0&&(t+="0"),l=Math.sqrt(+t),c=Ke((c+1)/2)-(c<0||c%2),n=new M(t=l==1/0?"5e"+c:(t=l.toExponential()).slice(0,t.indexOf("e")+1)+c)):n=new M(l+""),n.c[0])for((l=(c=n.e)+h)<3&&(l=0);;)if(o=n,n=d.times(o.plus(i(s,o,h,1))),Ye(o.c).slice(0,l)===(t=Ye(n.c)).slice(0,l)){if(n.e0&&_>0){for(o=_%a||a,h=p.substr(0,o);o<_;o+=a)h+=c+p.substr(o,a);l>0&&(h+=c+p.slice(o)),u&&(h="-"+h)}n=d?h+(i.decimalSeparator||"")+((l=+i.fractionGroupSize)?d.replace(new RegExp("\\d{"+l+"}\\B","g"),"$&"+(i.fractionGroupSeparator||"")):d):h}return(i.prefix||"")+n+(i.suffix||"")},u.toFraction=function(e){var t,n,r,o,s,a,l,c,h,d,u,_,f=this,g=f.c;if(null!=e&&(!(l=new M(e)).isInteger()&&(l.c||1!==l.s)||l.lt(p)))throw Error(Le+"Argument "+(l.isInteger()?"out of range: ":"not an integer: ")+z(l));if(!g)return new M(f);for(t=new M(p),h=n=new M(p),r=c=new M(p),_=Ye(g),s=t.e=_.length-f.e-1,t.c[0]=Ve[(a=s%je)<0?je+a:a],e=!e||l.comparedTo(t)>0?s>0?t:h:l,a=y,y=1/0,l=new M(_),c.c[0]=0;d=i(l,t,0,1),1!=(o=n.plus(d.times(r))).comparedTo(e);)n=r,r=o,h=c.plus(d.times(o=h)),c=o,t=l.minus(d.times(o=t)),l=o;return o=i(e.minus(n),r,0,1),c=c.plus(o.times(h)),n=n.plus(o.times(r)),c.s=h.s=f.s,u=i(h,r,s*=2,m).minus(f).abs().comparedTo(i(c,n,s,m).minus(f).abs())<1?[h,r]:[c,n],y=a,u},u.toNumber=function(){return+z(this)},u.toPrecision=function(e,t){return null!=e&&Xe(e,1,Ge),R(this,e,t,2)},u.toString=function(e){var t,i=this,r=i.s,o=i.e;return null===o?r?(t="Infinity",r<0&&(t="-"+t)):t="NaN":(null==e?t=o<=f||o>=g?Qe(Ye(i.c),o):et(Ye(i.c),o,"0"):10===e&&S?t=et(Ye((i=D(new M(i),_+o+1,m)).c),i.e,"0"):(Xe(e,2,$.length,"Base"),t=n(et(Ye(i.c),o,"0"),10,e,r,!0)),r<0&&i.c[0]&&(t="-"+t)),t},u.valueOf=u.toJSON=function(){return z(this)},u._isBigNumber=!0,u[Symbol.toStringTag]="BigNumber",u[Symbol.for("nodejs.util.inspect.custom")]=u.valueOf,null!=t&&M.set(t),M}(),it=class{key;left=null;right=null;constructor(e){this.key=e}},nt=class extends it{constructor(e){super(e)}},rt=class{size=0;modificationCount=0;splayCount=0;splay(e){const t=this.root;if(null==t)return this.compare(e,e),-1;let i=null,n=null,r=null,o=null,s=t;const a=this.compare;let l;for(;;)if(l=a(s.key,e),l>0){let t=s.left;if(null==t)break;if(l=a(t.key,e),l>0&&(s.left=t.right,t.right=s,s=t,t=s.left,null==t))break;null==i?n=s:i.left=s,i=s,s=t}else{if(!(l<0))break;{let t=s.right;if(null==t)break;if(l=a(t.key,e),l<0&&(s.right=t.left,t.left=s,s=t,t=s.right,null==t))break;null==r?o=s:r.right=s,r=s,s=t}}return null!=r&&(r.right=s.left,s.left=o),null!=i&&(i.left=s.right,s.right=n),this.root!==s&&(this.root=s,this.splayCount++),l}splayMin(e){let t=e,i=t.left;for(;null!=i;){const e=i;t.left=e.right,e.right=t,t=e,i=t.left}return t}splayMax(e){let t=e,i=t.right;for(;null!=i;){const e=i;t.right=e.left,e.left=t,t=e,i=t.right}return t}_delete(e){if(null==this.root)return null;if(0!=this.splay(e))return null;let t=this.root;const i=t,n=t.left;if(this.size--,null==n)this.root=t.right;else{const e=t.right;t=this.splayMax(n),t.right=e,this.root=t}return this.modificationCount++,i}addNewRoot(e,t){this.size++,this.modificationCount++;const i=this.root;null!=i?(t<0?(e.left=i,e.right=i.right,i.right=null):(e.right=i,e.left=i.left,i.left=null),this.root=e):this.root=e}_first(){const e=this.root;return null==e?null:(this.root=this.splayMin(e),this.root)}_last(){const e=this.root;return null==e?null:(this.root=this.splayMax(e),this.root)}clear(){this.root=null,this.size=0,this.modificationCount++}has(e){return this.validKey(e)&&0==this.splay(e)}defaultCompare(){return(e,t)=>et?1:0}wrap(){return{getRoot:()=>this.root,setRoot:e=>{this.root=e},getSize:()=>this.size,getModificationCount:()=>this.modificationCount,getSplayCount:()=>this.splayCount,setSplayCount:e=>{this.splayCount=e},splay:e=>this.splay(e),has:e=>this.has(e)}}},ot=class e extends rt{root=null;compare;validKey;constructor(e,t){super(),this.compare=e??this.defaultCompare(),this.validKey=t??(e=>null!=e&&null!=e)}delete(e){return!!this.validKey(e)&&null!=this._delete(e)}deleteAll(e){for(const t of e)this.delete(t)}forEach(e){const t=this[Symbol.iterator]();let i;for(;i=t.next(),!i.done;)e(i.value,i.value,this)}add(e){const t=this.splay(e);return 0!=t&&this.addNewRoot(new nt(e),t),this}addAndReturn(e){const t=this.splay(e);return 0!=t&&this.addNewRoot(new nt(e),t),this.root.key}addAll(e){for(const t of e)this.add(t)}isEmpty(){return null==this.root}isNotEmpty(){return null!=this.root}single(){if(0==this.size)throw"Bad state: No element";if(this.size>1)throw"Bad state: Too many element";return this.root.key}first(){if(0==this.size)throw"Bad state: No element";return this._first().key}last(){if(0==this.size)throw"Bad state: No element";return this._last().key}lastBefore(e){if(null==e)throw"Invalid arguments(s)";if(null==this.root)return null;if(this.splay(e)<0)return this.root.key;let t=this.root.left;if(null==t)return null;let i=t.right;for(;null!=i;)t=i,i=t.right;return t.key}firstAfter(e){if(null==e)throw"Invalid arguments(s)";if(null==this.root)return null;if(this.splay(e)>0)return this.root.key;let t=this.root.right;if(null==t)return null;let i=t.left;for(;null!=i;)t=i,i=t.left;return t.key}retainAll(t){const i=new e(this.compare,this.validKey),n=this.modificationCount;for(const e of t){if(n!=this.modificationCount)throw"Concurrent modification during iteration.";this.validKey(e)&&0==this.splay(e)&&i.add(this.root.key)}i.size!=this.size&&(this.root=i.root,this.size=i.size,this.modificationCount++)}lookup(e){if(!this.validKey(e))return null;return 0!=this.splay(e)?null:this.root.key}intersection(t){const i=new e(this.compare,this.validKey);for(const e of this)t.has(e)&&i.add(e);return i}difference(t){const i=new e(this.compare,this.validKey);for(const e of this)t.has(e)||i.add(e);return i}union(e){const t=this.clone();return t.addAll(e),t}clone(){const t=new e(this.compare,this.validKey);return t.size=this.size,t.root=this.copyNode(this.root),t}copyNode(e){if(null==e)return null;const t=new nt(e.key);return function e(t,i){let n,r;do{if(n=t.left,r=t.right,null!=n){const t=new nt(n.key);i.left=t,e(n,t)}if(null!=r){const e=new nt(r.key);i.right=e,t=r,i=e}}while(null!=r)}(e,t),t}toSet(){return this.clone()}entries(){return new lt(this.wrap())}keys(){return this[Symbol.iterator]()}values(){return this[Symbol.iterator]()}[Symbol.iterator](){return new at(this.wrap())}[Symbol.toStringTag]="[object Set]"},st=class{tree;path=new Array;modificationCount=null;splayCount;constructor(e){this.tree=e,this.splayCount=e.getSplayCount()}[Symbol.iterator](){return this}next(){return this.moveNext()?{done:!1,value:this.current()}:{done:!0,value:null}}current(){if(!this.path.length)return null;const e=this.path[this.path.length-1];return this.getValue(e)}rebuildPath(e){this.path.splice(0,this.path.length),this.tree.splay(e),this.path.push(this.tree.getRoot()),this.splayCount=this.tree.getSplayCount()}findLeftMostDescendent(e){for(;null!=e;)this.path.push(e),e=e.left}moveNext(){if(this.modificationCount!=this.tree.getModificationCount()){if(null==this.modificationCount){this.modificationCount=this.tree.getModificationCount();let e=this.tree.getRoot();for(;null!=e;)this.path.push(e),e=e.left;return this.path.length>0}throw"Concurrent modification during iteration."}if(!this.path.length)return!1;this.splayCount!=this.tree.getSplayCount()&&this.rebuildPath(this.path[this.path.length-1].key);let e=this.path[this.path.length-1],t=e.right;if(null!=t){for(;null!=t;)this.path.push(t),t=t.left;return!0}for(this.path.pop();this.path.length&&this.path[this.path.length-1].right===e;)e=this.path.pop();return this.path.length>0}},at=class extends st{getValue(e){return e.key}},lt=class extends st{getValue(e){return[e.key,e.key]}},ct=e=>()=>e,ht=e=>{const t=e?(t,i)=>i.minus(t).abs().isLessThanOrEqualTo(e):ct(!1);return(e,i)=>t(e,i)?0:e.comparedTo(i)};function dt(e){const t=e?(t,i,n,r,o)=>t.exponentiatedBy(2).isLessThanOrEqualTo(r.minus(i).exponentiatedBy(2).plus(o.minus(n).exponentiatedBy(2)).times(e)):ct(!1);return(e,i,n)=>{const r=e.x,o=e.y,s=n.x,a=n.y,l=o.minus(a).times(i.x.minus(s)).minus(r.minus(s).times(i.y.minus(a)));return t(l,r,o,s,a)?0:l.comparedTo(0)}}var ut=e=>e,pt=e=>{if(e){const t=new ot(ht(e)),i=new ot(ht(e)),n=(e,t)=>t.addAndReturn(e),r=e=>({x:n(e.x,t),y:n(e.y,i)});return r({x:new tt(0),y:new tt(0)}),r}return ut},_t=e=>({set:e=>{mt=_t(e)},reset:()=>_t(e),compare:ht(e),snap:pt(e),orient:dt(e)}),mt=_t(),ft=(e,t)=>e.ll.x.isLessThanOrEqualTo(t.x)&&t.x.isLessThanOrEqualTo(e.ur.x)&&e.ll.y.isLessThanOrEqualTo(t.y)&&t.y.isLessThanOrEqualTo(e.ur.y),gt=(e,t)=>{if(t.ur.x.isLessThan(e.ll.x)||e.ur.x.isLessThan(t.ll.x)||t.ur.y.isLessThan(e.ll.y)||e.ur.y.isLessThan(t.ll.y))return null;const i=e.ll.x.isLessThan(t.ll.x)?t.ll.x:e.ll.x,n=e.ur.x.isLessThan(t.ur.x)?e.ur.x:t.ur.x;return{ll:{x:i,y:e.ll.y.isLessThan(t.ll.y)?t.ll.y:e.ll.y},ur:{x:n,y:e.ur.y.isLessThan(t.ur.y)?e.ur.y:t.ur.y}}},vt=(e,t)=>e.x.times(t.y).minus(e.y.times(t.x)),yt=(e,t)=>e.x.times(t.x).plus(e.y.times(t.y)),bt=e=>yt(e,e).sqrt(),wt=(e,t,i)=>{const n={x:t.x.minus(e.x),y:t.y.minus(e.y)},r={x:i.x.minus(e.x),y:i.y.minus(e.y)};return vt(r,n).div(bt(r)).div(bt(n))},kt=(e,t,i)=>{const n={x:t.x.minus(e.x),y:t.y.minus(e.y)},r={x:i.x.minus(e.x),y:i.y.minus(e.y)};return yt(r,n).div(bt(r)).div(bt(n))},xt=(e,t,i)=>t.y.isZero()?null:{x:e.x.plus(t.x.div(t.y).times(i.minus(e.y))),y:i},$t=(e,t,i)=>t.x.isZero()?null:{x:i,y:e.y.plus(t.y.div(t.x).times(i.minus(e.x)))},St=class e{point;isLeft;segment;otherSE;consumedBy;static compare(t,i){const n=e.comparePoints(t.point,i.point);return 0!==n?n:(t.point!==i.point&&t.link(i),t.isLeft!==i.isLeft?t.isLeft?1:-1:Ot.compare(t.segment,i.segment))}static comparePoints(e,t){return e.x.isLessThan(t.x)?-1:e.x.isGreaterThan(t.x)?1:e.y.isLessThan(t.y)?-1:e.y.isGreaterThan(t.y)?1:0}constructor(e,t){void 0===e.events?e.events=[this]:e.events.push(this),this.point=e,this.isLeft=t}link(e){if(e.point===this.point)throw new Error("Tried to link already linked events");const t=e.point.events;for(let e=0,i=t.length;e{const n=i.otherSE;t.set(i,{sine:wt(this.point,e.point,n.point),cosine:kt(this.point,e.point,n.point)})};return(e,n)=>{t.has(e)||i(e),t.has(n)||i(n);const{sine:r,cosine:o}=t.get(e),{sine:s,cosine:a}=t.get(n);return r.isGreaterThanOrEqualTo(0)&&s.isGreaterThanOrEqualTo(0)?o.isLessThan(a)?1:o.isGreaterThan(a)?-1:0:r.isLessThan(0)&&s.isLessThan(0)?o.isLessThan(a)?-1:o.isGreaterThan(a)?1:0:s.isLessThan(r)?-1:s.isGreaterThan(r)?1:0}}},Mt=class e{events;poly;_isExteriorRing;_enclosingRing;static factory(t){const i=[];for(let n=0,r=t.length;n0&&(e=i)}let t=e.segment.prevInResult(),i=t?t.prevInResult():null;for(;;){if(!t)return null;if(!i)return t.ringOut;if(i.ringOut!==t.ringOut)return i.ringOut?.enclosingRing()!==t.ringOut?t.ringOut:t.ringOut?.enclosingRing();t=i.prevInResult(),i=t?t.prevInResult():null}}},Rt=class{exteriorRing;interiorRings;constructor(e){this.exteriorRing=e,e.poly=this,this.interiorRings=[]}addInterior(e){this.interiorRings.push(e),e.poly=this}getGeom(){const e=this.exteriorRing.getGeom();if(null===e)return null;const t=[e];for(let e=0,i=this.interiorRings.length;e0?(this.tree.delete(t),i.push(e)):(this.segments.push(t),t.prev=n)}else{if(n&&r){const e=n.getIntersection(r);if(null!==e){if(!n.isAnEndpoint(e)){const t=this._splitSafely(n,e);for(let e=0,n=t.length;e0)return-1;const n=t.comparePoint(e.rightSE.point);return 0!==n?n:-1}if(i.isGreaterThan(n)){if(s.isLessThan(a)&&s.isLessThan(c))return-1;if(s.isGreaterThan(a)&&s.isGreaterThan(c))return 1;const i=t.comparePoint(e.leftSE.point);if(0!==i)return i;const n=e.comparePoint(t.rightSE.point);return n<0?1:n>0?-1:1}if(s.isLessThan(a))return-1;if(s.isGreaterThan(a))return 1;if(r.isLessThan(o)){const i=t.comparePoint(e.rightSE.point);if(0!==i)return i}if(r.isGreaterThan(o)){const i=e.comparePoint(t.rightSE.point);if(i<0)return 1;if(i>0)return-1}if(!r.eq(o)){const e=l.minus(s),t=r.minus(i),h=c.minus(a),d=o.minus(n);if(e.isGreaterThan(t)&&h.isLessThan(d))return 1;if(e.isLessThan(t)&&h.isGreaterThan(d))return-1}return r.isGreaterThan(o)?1:r.isLessThan(o)||l.isLessThan(c)?-1:l.isGreaterThan(c)?1:e.idt.id?1:0}constructor(e,t,i,n){this.id=++At,this.leftSE=e,e.segment=this,e.otherSE=t,this.rightSE=t,t.segment=this,t.otherSE=e,this.rings=i,this.windings=n}static fromRing(t,i,n){let r,o,s;const a=St.comparePoints(t,i);if(a<0)r=t,o=i,s=1;else{if(!(a>0))throw new Error(`Tried to create degenerate segment at [${t.x}, ${t.y}]`);r=i,o=t,s=-1}const l=new St(r,!0),c=new St(o,!1);return new e(l,c,[n],[s])}replaceRightSE(e){this.rightSE=e,this.rightSE.segment=this,this.rightSE.otherSE=this.leftSE,this.leftSE.otherSE=this.rightSE}bbox(){const e=this.leftSE.point.y,t=this.rightSE.point.y;return{ll:{x:this.leftSE.point.x,y:e.isLessThan(t)?e:t},ur:{x:this.rightSE.point.x,y:e.isGreaterThan(t)?e:t}}}vector(){return{x:this.rightSE.point.x.minus(this.leftSE.point.x),y:this.rightSE.point.y.minus(this.leftSE.point.y)}}isAnEndpoint(e){return e.x.eq(this.leftSE.point.x)&&e.y.eq(this.leftSE.point.y)||e.x.eq(this.rightSE.point.x)&&e.y.eq(this.rightSE.point.y)}comparePoint(e){return mt.orient(this.leftSE.point,e,this.rightSE.point)}getIntersection(e){const t=this.bbox(),i=e.bbox(),n=gt(t,i);if(null===n)return null;const r=this.leftSE.point,o=this.rightSE.point,s=e.leftSE.point,a=e.rightSE.point,l=ft(t,s)&&0===this.comparePoint(s),c=ft(i,r)&&0===e.comparePoint(r),h=ft(t,a)&&0===this.comparePoint(a),d=ft(i,o)&&0===e.comparePoint(o);if(c&&l)return d&&!h?o:!d&&h?a:null;if(c)return h&&r.x.eq(a.x)&&r.y.eq(a.y)?null:r;if(l)return d&&o.x.eq(s.x)&&o.y.eq(s.y)?null:s;if(d&&h)return null;if(d)return o;if(h)return a;const u=((e,t,i,n)=>{if(t.x.isZero())return $t(i,n,e.x);if(n.x.isZero())return $t(e,t,i.x);if(t.y.isZero())return xt(i,n,e.y);if(n.y.isZero())return xt(e,t,i.y);const r=vt(t,n);if(r.isZero())return null;const o={x:i.x.minus(e.x),y:i.y.minus(e.y)},s=vt(o,t).div(r),a=vt(o,n).div(r),l=e.x.plus(a.times(t.x)),c=i.x.plus(s.times(n.x)),h=e.y.plus(a.times(t.y)),d=i.y.plus(s.times(n.y));return{x:l.plus(c).div(2),y:h.plus(d).div(2)}})(r,this.vector(),s,e.vector());return null===u?null:ft(n,u)?mt.snap(u):null}split(t){const i=[],n=void 0!==t.events,r=new St(t,!0),o=new St(t,!1),s=this.rightSE;this.replaceRightSE(o),i.push(o),i.push(r);const a=new e(r,s,this.rings.slice(),this.windings.slice());return St.comparePoints(a.leftSE.point,a.rightSE.point)>0&&a.swapEvents(),St.comparePoints(this.leftSE.point,this.rightSE.point)>0&&this.swapEvents(),n&&(r.checkForConsuming(),o.checkForConsuming()),i}swapEvents(){const e=this.rightSE;this.rightSE=this.leftSE,this.leftSE=e,this.leftSE.isLeft=!0,this.rightSE.isLeft=!1;for(let e=0,t=this.windings.length;e0){const e=i;i=n,n=e}if(i.prev===n){const e=i;i=n,n=e}for(let e=0,t=n.rings.length;e1===e.length&&e[0].isSubject;this._isInResult=i(e)!==i(t);break}}return this._isInResult}},Pt=class{poly;isExterior;segments;bbox;constructor(e,t,i){if(!Array.isArray(e)||0===e.length)throw new Error("Input geometry is not a valid Polygon or MultiPolygon");if(this.poly=t,this.isExterior=i,this.segments=[],"number"!=typeof e[0][0]||"number"!=typeof e[0][1])throw new Error("Input geometry is not a valid Polygon or MultiPolygon");const n=mt.snap({x:new tt(e[0][0]),y:new tt(e[0][1])});this.bbox={ll:{x:n.x,y:n.y},ur:{x:n.x,y:n.y}};let r=n;for(let t=1,i=e.length;tzt.run("union",e,t),Ht=(e,...t)=>zt.run("intersection",e,t),Nt=(e,...t)=>zt.run("difference",e,t);mt.set;const Lt=/^#[0-9a-fA-F]{6}$/;function qt(e,t){return"string"==typeof e&&Lt.test(e)?e:t}const Wt="(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])",jt=new RegExp(`^rgb\\(${Wt}, ${Wt}, ${Wt}\\)$`);function Bt(e){if(!Array.isArray(e)||e.length<3)return null;const t=e.slice(0,3);if(!t.every(e=>"number"==typeof e&&Number.isFinite(e)))return null;const[i,n,r]=t.map(e=>Math.round(Math.min(255,Math.max(0,e))));return`rgb(${i}, ${n}, ${r})`}function Vt(e){const t=Math.max(0,Math.min(120,(e-40)/140*120));return`hsl(${Math.round(t)}, 85%, 55%)`}function Ut(e,t){if(!(Number.isFinite(e)&&t>0))return e;const i=Math.round(e/t)*t;return Math.abs(i-e)<=1e-9*t?e:i}function Gt(e,t,i,n=1/0){if(!(i>0&&e?.every(Number.isFinite)&&t?.every(Number.isFinite)))return[t[0],t[1]];const r=t[0]-e[0],o=t[1]-e[1];if(Math.abs(r)+Math.abs(o)<=1e-12)return[e[0],e[1]];const s=Math.PI/4;let a=Math.atan2(o,r);a<0&&(a+=2*Math.PI);const l=Math.floor(a/s+.5)%8,[c,h]=[[1,0],[1,1],[0,1],[-1,1],[-1,0],[-1,-1],[0,-1],[1,-1]][l],d=c*c+h*h;let u=Math.max(0,Math.round((r*c+o*h)/(i*d)));if(Number.isFinite(n)&&n>=0){const t=(e,t)=>{if(!t)return 1/0;const r=t>0?n-e:e+n;return Math.max(0,Math.floor((r+1e-9*i)/i))};u=Math.min(u,t(e[0],c),t(e[1],h))}return[e[0]+c*u*i,e[1]+h*u*i]}function Kt(e,t){if(t){const t=e/2.54;let i=Math.floor(t/12),n=Math.round(t-12*i);return 12===n&&(i+=1,n=0),`${i}′ ${n}″`}return`${(e/100).toFixed(2)} m`}function Yt(e,t,i=1){const n=e[0].toFixed(i),r=e[1].toFixed(i),o=t[0].toFixed(i),s=t[1].toFixed(i),a=n=3?e.poly:e&&null!=e.x&&null!=e.y&&null!=e.w&&null!=e.h?[[e.x,e.y],[e.x+e.w,e.y],[e.x+e.w,e.y+e.h],[e.x,e.y+e.h]]:null}function Xt(e){const t=[];for(const i of e||[])i?.poly?.length>=3?t.push({poly:i.poly.map(e=>e.join(",")).join(" ")}):i&&null!=i.x&&null!=i.y&&null!=i.w&&null!=i.h&&t.push({rect:{x:i.x,y:i.y,w:i.w,h:i.h,rx:.03*Math.min(i.w,i.h)}});return t}function Jt(e){const t=[],i=new Set;for(const n of e||[]){const e=Zt(n);if(e)for(let n=0;n=90?e-=180:e<-90&&(e+=180),n.step&&n.step>0){const i=Math.sqrt(d),o=Math.min(Math.max(n.length||0,0)/2,i/2);let a=Math.round(u*i/n.step)*n.step;Math.abs(u*i-i/2)<=n.step/2&&(a=i/2),a=Math.max(o,Math.min(i-o,a));const l=a/i;r={x:t+l*c,y:s+l*h,angle:e}}else r={x:p[0],y:p[1],angle:e}}}return r}function ei(e,t,i){let n=null,r=1/0;for(let o=0;o=r)continue;r=_;const m=Math.sqrt(u),f=(i>0?Math.max(0,Math.min(m,Math.round(p*m/i)*i)):p*m)/m;n=[s+f*h,a+f*d]}return n}function ti(e,t,i,n,r,o=1){const s=t*Math.PI/180,a=[Math.cos(s),Math.sin(s)];let l=null,c=o;for(const t of Jt(n)){const i=[[t[0],t[1]],[t[2],t[3]]],n=t=>Math.abs(a[0]*(t[1]-e[1])-a[1]*(t[0]-e[0]));if(n(i[0])>o||n(i[1])>o)continue;const r=(i[0][0]-e[0])*a[0]+(i[0][1]-e[1])*a[1],s=(i[1][0]-e[0])*a[0]+(i[1][1]-e[1])*a[1],h=Math.min(r,s),d=Math.max(r,s),u=h>0?h:d<0?-d:0;u[e[0]+a[0]*t,e[1]+a[1]*t],f=(h+d)/2;return{wallA:m(h),wallB:m(d),sideA:p,sideB:_,midA:m((h-u)/2),midB:m((u+d)/2),wallCenter:m(f),centered:Math.abs(f)<=r}}function ii(e,t,i=!1,n){if("passage"===e)return 1;if(null==t||"unavailable"===t||"unknown"===t)return"window"===e?0:1;const r="string"==typeof n?n.trim()?Number(n):NaN:Number(n),o=null!=n&&Number.isFinite(r)?Math.max(0,Math.min(1,r/100)):function(e){return["on","open","home","detected","playing","cleaning"].includes(String(e))}(t)?1:0;return i?1-o:o}function ni(e,t){return(Number.isFinite(e)&&e>0?e:0)*(Number.isFinite(t)?Math.max(0,Math.min(1,t)):0)}function ri(e){return"passage"===e.type?[]:[e.contact,e.lock].filter(e=>"string"==typeof e&&e.length>0)}function oi(e,t,i=200){const n=t.trim().toLowerCase();return(n?e.filter(e=>e.label.toLowerCase().includes(n)||e.value.toLowerCase().includes(n)):e).slice(0,Math.max(0,i))}function si(e,t,i=.001){return Math.abs(e[0]-t[0])e[1]!=l>e[1]&&e[0]<(a-o)*(e[1]-s)/(l-s)+o&&(i=!i)}return i}function li(e,t,i){const n=i[0]-t[0],r=i[1]-t[1],o=n*n+r*r;let s=o?((e[0]-t[0])*n+(e[1]-t[1])*r)/o:0;return s=Math.max(0,Math.min(1,s)),Math.hypot(e[0]-(t[0]+s*n),e[1]-(t[1]+s*r))}function ci(e,t){if(!t||t.length<2)return null;let i=null,n=1/0;for(let r=0;rr&&s<-r||o<-r&&s>r)&&(a>r&&l<-r||a<-r&&l>r)}function _i(e,t=24){const i=e.map(e=>e[0]),n=e.map(e=>e[1]),r=Math.min(...i),o=Math.max(...i),s=Math.min(...n),a=Math.max(...n),l=Math.max(o-r,a-s)||1;let c=0,h=0,d=0;for(let t=0;t1e-9?[h/(3*c),d/(3*c)]:[(r+o)/2,(s+a)/2],p=(t,i)=>{const n=((t,i)=>{if(!ai([t,i],e))return-1/0;let n=1/0;for(let r=0;rm&&(m=c,_=[n,l])}if(_){const[e,i]=_,n=(o-r)/t,l=(a-s)/t;for(let t=-4;t<=4;t++)for(let r=-4;r<=4;r++){const o=e+n*t/4,s=i+l*r/4,a=p(o,s);a>m&&(m=a,_=[o,s])}}return _||mi(e)||e[0]}function mi(e,t=1e-6){if(!e||e.length<3)return null;const i=e.length,n=[e.reduce((e,t)=>e+t[0],0)/i,e.reduce((e,t)=>e+t[1],0)/i];if(di(n,e,t))return n;for(let n=0;ngi(e,t,i));return n.filter(e=>!n.some(t=>t!==e&&gi(t,e,i)))}function bi(e){if(!e||e.length<3)return 0;let t=0;for(let i=0;i[e[0],e[1]]),[e[0][0],e[0][1]]]]}function ki(e,t){if(!e||!t||e.length<3||t.length<3)return null;const i=It(wi(e),wi(t));if(1!==i.length)return null;if(1!==i[0].length)return null;const n=i[0][0].slice(0,-1).map(e=>[e[0],e[1]]);return n.length>=3?n:null}function xi(e,t,i){for(let n=0;n1&&si(i[0],i[i.length-1],t)&&i.pop(),i}function Si(e,t,i=1e-6){if(!e||e.length<3||!t||t.length<2)return null;const n=t[0],r=t[t.length-1];if(si(n,r,i))return null;const o=xi(e,n,i),s=xi(e,r,i);if(o<0||s<0)return null;const a=t.slice(1,-1);for(const t of a)if(!di(t,e,i))return null;for(let i=0;i{const s=[t];let a=(n+1)%e.length;for(let t=0;t<=e.length&&(s.push(e[a]),a!==o);t++)a=(a+1)%e.length;return s.push(r),$i(s,i)};let c,h;if(o===s){const s=$i([...t],i);if(s.length<3||bi(s)<=i)return null;const a=[];for(let i=0;i=0?t:[...t].reverse();for(const e of i)a.push(e)}c=$i(a,i),h=s}else c=$i([...l(n,o,r,s),...[...a].reverse()],i),h=$i([...l(r,s,n,o),...a],i);return c.length<3||h.length<3||bi(c)<=i||bi(h)<=i||Math.abs(bi(c)+bi(h)-bi(e))>Math.max(i,1e-6*bi(e))?null:[c,h]}function Mi(e,t,i){const[n,r]=e.split(":");return"device"===n?r:"entity"===n?"lg_"+r:t&&t.startsWith("v_")?t:i()}function Ri(e){return e.length?Math.round(e.reduce((e,t)=>e+t,0)/e.length):null}function Ti(e,t){if(t>e[2]/e[3]){const i=e[3],n=e[3]*t;return{x:e[0]-(n-e[2])/2,y:e[1],w:n,h:i}}const i=e[2],n=e[2]/t;return{x:e[0],y:e[1]-(n-e[3])/2,w:i,h:n}}function Ci(e,t,i,n){if(e.length<2)return;const r=t.x+n,o=t.x+t.w-n,s=t.y+n,a=t.y+t.h-n;for(let t=0;t<60;t++){let t=!1;for(let n=0;n=0)i=t.slice(0,r).trim(),n=t.slice(r+1).trim();else{const e=t.split(".");e.length>2&&(i=e.slice(0,2).join("."),n=e.slice(2).join("."))}return/^[a-z0-9_]+\.[a-z0-9_]+$/.test(i)?r>=0&&!n||n&&!/^[a-zA-Z0-9_.-]+$/.test(n)?null:n?{entity:i,attr:n}:{entity:i}:null}function qi(e,t){const i=String(e??"").trim(),n=String(t??"").trim(),r=Li(n?`${i}:${n}`:i);return r?`{${r.entity}${r.attr?`:${r.attr}`:""}}`:""}function Wi(e,t,i){const n=String(t??"").trim();if(!n)return null;const r=e?.states?.[n];if(!r)return null;const o=String(i??"").trim(),s=e=>e.slice(0,60);if(o){const t=function(e){if(null==e)return null;if(Array.isArray(e)){const t=e.map(e=>null==e?"":String(e)).join(", ");return t?t.slice(0,60):null}if("object"==typeof e)return null;const t=String(e);return""===t?null:t.slice(0,60)}(r.attributes?.[o]);if(null===t)return null;const i=e?.formatEntityAttributeValue;if("function"==typeof i)try{const t=i.call(e,r,o);if("string"==typeof t&&""!==t)return{text:s(t),formatted:!0}}catch{}return{text:t,formatted:!1}}const a=r.state;if(null==a||""===a)return null;const l=e?.formatEntityState;if("function"==typeof l)try{const t=l.call(e,r);if("string"==typeof t&&""!==t)return{text:s(t),formatted:!0}}catch{}return{text:s(String(a)),formatted:!1}}function ji(e,t,i){const n=String(t??"").trim(),r=String(i??"").trim()||n;if(!r)return e.text;const o=e.formatted&&n?function(e,t){if(!t)return e;const i=e.replace(/\s+$/,"");return i.endsWith(t)?i.slice(0,i.length-t.length).replace(/\s+$/,""):e}(e.text,n):e.text;return`${o} ${r}`}function Bi(e,t){const i=(t?.entity||"").trim();if(!i)return"";const n=e?.states?.[i],r=n?.state;if(!n||null==r||""===r||"unavailable"===r||"unknown"===r)return Hi;const o=(t?.attr||"").trim(),s=Wi(e,i,o||null);if(null===s)return Hi;return ji(s,o?"":String(n.attributes?.unit_of_measurement??"").trim(),t?.unit)}function Vi(e,t,i,n=()=>!0){const r=e??"";let o=!1;const s=r.replace(/\{([^{}\r\n]+)\}/g,(e,t)=>{const r=Li(t);return r?(o=!0,n(r.entity||"")?Bi(i,r):Hi):e});if(o)return s;const a=(t?.entity||"").trim();if(!a)return r;if(!n(a)){const e=r.indexOf(Ni);return e>=0?r.slice(0,e)+Hi+r.slice(e+2):r?`${r} ${Hi}`:Hi}const l=Bi(i,t),c=r.indexOf(Ni);return c>=0?r.slice(0,c)+l+r.slice(c+2):r?`${r} ${l}`:l}const Ui=20;function Gi(e){const t=Number(e?.scale);if(Number.isFinite(t)&&t>0)return Math.min(20,Math.max(.15,t));return{s:.7,m:1,l:1.5}[String(e?.size??"")]??1}function Ki(e,t){if(!t)return e;let i=e;for(const[e,n]of Object.entries(t))i=i.split("{"+e+"}").join(String(n));return i}const Yi="#55606c",Zi=.55,Xi=20,Ji=25,Qi={c:"#607d8b",a:.18};function en(e,t=Qi){const i=e&&"object"==typeof e?e:null,n=i?.a;return{c:qt(i?.c,t.c),a:"number"==typeof n&&Number.isFinite(n)?Math.min(1,Math.max(0,n)):t.a}}function tn(e,t){const i=en(e),n=t?.settings?.custom_fill;return n&&"object"==typeof n?en(n,i):i}function nn(e){const t=e?.settings||{},i=!e?.plan_url,n="glow"===t.fill_mode;return{showBorders:t.show_borders??i,showNames:t.show_names??i,color:qt(t.room_color,Yi),opacity:"number"==typeof t.room_opacity?Math.min(1,Math.max(0,t.room_opacity)):.55,fill:["lqi","light","temp","custom"].includes(t.fill_mode)?t.fill_mode:"none",customFill:en(t.custom_fill),glow:"boolean"==typeof t.glow_enabled?t.glow_enabled:n,tempMin:"number"==typeof t.temp_min?t.temp_min:20,tempMax:"number"==typeof t.temp_max?t.temp_max:25,showLqi:"boolean"==typeof t.show_lqi?t.show_lqi:null,cardFontScale:"number"==typeof t.card_font_scale&&t.card_font_scale>0?Math.min(3,Math.max(.5,t.card_font_scale)):1,labelTemp:!0===t.label_temp,labelHum:!0===t.label_hum,labelLqi:!0===t.label_lqi,labelLight:!0===t.label_light,bgColor:qt(t.bg_color,null),hideDecor:!0===t.hide_decor,hideOpenings:!0===t.hide_openings}}function rn(e,t){if(t.bgColor)return t.bgColor;const i=e?.bg_color;return qt(i,"")}const on={light_on:{c:"#ffd45c",a:.18},light_off:{c:"#9aa0a6",a:.14},light_none:{c:"#6b7480",a:0},temp_cold:{c:"#4fc3f7",a:.18},temp_ok:{c:"#66d17a",a:.18},temp_hot:{c:"#ffd45c",a:.18},lqi_low:{c:"#f25a4a",a:.18},lqi_high:{c:"#4bd28f",a:.18},glow_base:{c:"#0d1b2a",a:.5},glow_light:{c:"#ffd9a0",a:.85},wall_fill:{c:"#ffffff",a:1}};function sn(e){const t={},i=e?.fill_colors||{};for(const e of Object.keys(on)){const n=on[e],r=i[e];t[e]={c:qt(r?.c,n.c),a:r&&"number"==typeof r.a?Math.min(1,Math.max(0,r.a)):n.a}}return t}function an(e,t,i){const n=Math.min(1,Math.max(0,i)),r=[1,3,5].map(t=>parseInt(e.slice(t,t+2),16)),o=[1,3,5].map(e=>parseInt(t.slice(e,e+2),16)),s=r.map((e,t)=>Math.round(e+(o[t]-e)*n));return"#"+s.map(e=>e.toString(16).padStart(2,"0")).join("")}function ln(e,t,i,n,r,o,s,a=Qi){const l=function(e,t,i,n,r,o,s,a=Qi){if("custom"===e)return en(a);if("lqi"===e){if(null==t)return null;const e=(t-40)/140;return{c:an(s.lqi_low.c,s.lqi_high.c,e),a:s.lqi_low.a+(s.lqi_high.a-s.lqi_low.a)*Math.min(1,Math.max(0,e))}}if("light"===e)return"none"===i?s.light_none.a>0?s.light_none:null:"on"===i?s.light_on:s.light_off;if("temp"===e){if(null==n)return null;const e=Math.min(r,o),t=Math.max(r,o);return nt?s.temp_hot:s.temp_ok}return null}(e,t,i,n,r,o,s,a);return l?{color:l.c,opacity:l.a,mode:e}:null}const cn={blind:["mdi:blinds","mdi:blinds-open"],shade:["mdi:blinds","mdi:blinds-open"],shutter:["mdi:window-shutter","mdi:window-shutter-open"],curtain:["mdi:curtains-closed","mdi:curtains"],window:["mdi:window-closed","mdi:window-open"],awning:["mdi:awning-outline","mdi:awning"],door:["mdi:door-closed","mdi:door-open"],garage:["mdi:garage","mdi:garage-open"],gate:["mdi:gate","mdi:gate-open"],damper:["mdi:circle-slice-8","mdi:circle-outline"]},hn=[["mdi:roller-shade-closed","mdi:roller-shade"],["mdi:blinds-horizontal-closed","mdi:blinds-horizontal"],["mdi:garage-variant","mdi:garage-open-variant"],["mdi:door","mdi:door-open"]];function dn(e){for(const t of[...Object.values(cn),...hn])if(e===t[0]||e===t[1])return t;return null}function un(e,t,i,n,r){if(!n||"unavailable"===n||"unknown"===n)return e;if(r){const i="cover"===t?dn(e):null;return i?"closed"===n?i[0]:i[1]:e}if("binary_sensor"===t){if("door"===i)return"on"===n?"mdi:door-open":"mdi:door-closed";if("window"===i)return"on"===n?"mdi:window-open":"mdi:window-closed";if("garage_door"===i)return"on"===n?"mdi:garage-open-variant":"mdi:garage-variant"}if("cover"===t){const t=cn[String(i||"")];if(t)return"closed"===n?t[0]:t[1];const r=dn(e);return r?"closed"===n?r[0]:r[1]:e}return"lock"===t?"locked"===n?"mdi:lock":"mdi:lock-open-variant":"light"===t&&"mdi:lightbulb"===e&&"on"===n?"mdi:lightbulb-on":e}function pn(e){const t=Math.min(4e4,Math.max(1e3,e))/100,i=t<=66?255:329.698727446*Math.pow(t-60,-.1332047592),n=t<=66?99.4708025861*Math.log(t)-161.1195681661:288.1221695283*Math.pow(t-60,-.0755148492),r=t>=66?255:t<=19?0:138.5177312231*Math.log(t-10)-305.0447927307,o=e=>Math.round(Math.min(255,Math.max(0,e)));return[o(i),o(n),o(r)]}const _n=1/2.2;function mn(e){const t=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/.exec(e);return t?"#"+t.slice(1).map(e=>Math.min(255,Number(e)).toString(16).padStart(2,"0")).join(""):null}function fn(e){if(!e||"object"!=typeof e||Array.isArray(e))return null;const t=e;if(Object.keys(t).some(e=>"c"!==e&&"bri"!==e))return null;const i=qt(t.c,null);return i?void 0===t.bri||null===t.bri?{c:i}:"number"!=typeof t.bri||!Number.isFinite(t.bri)||t.bri<.01||t.bri>1?null:{c:i,bri:t.bri}:null}function gn(e,t,i){const n=fn(t),r=e?.attributes||{},o=n?.bri??function(e){const t=e?.attributes?.brightness,i="number"==typeof t?t:"string"==typeof t&&""!==t.trim()?Number(t):Number.NaN;return Number.isFinite(i)?Math.max(0,Math.min(1,i/255)):1}(e);if(n)return{c:n.c,bri:o};const s=Bt(r.rgb_color);if(s)return{c:mn(s)||qt(i,"#ffd9a0"),bri:o};const a=Number(r.color_temp_kelvin)||(Number(r.color_temp)>0?1e6/Number(r.color_temp):NaN);return Number.isFinite(a)&&a>0?{c:(l=pn(a),"#"+l.slice(0,3).map(e=>Math.min(255,Math.max(0,Math.round(Number(e)||0))).toString(16).padStart(2,"0")).join("")),bri:o}:{c:qt(i,"#ffd9a0"),bri:o};var l}function vn(e,t,i){return"on"===e?.state?gn(e,t,i):null}function yn(e,t=1){const i=Math.max(0,Math.min(1,Number.isFinite(e)?e:1)),n=.7*Math.max(0,Math.min(1,Number.isFinite(t)?t:1))*(.4+.6*Math.pow(i,_n));return Math.max(0,Math.min(1,n))}function bn(e){return e.startsWith("light.")||e.startsWith("switch.")}function wn(e,t,i=1e-6){const n=[];if(!e||!t||e.length<3||t.length<3)return n;for(let r=0;ru||l>u)continue;const p=(r[0]-o[0])*h+(r[1]-o[1])*d,_=(s[0]-o[0])*h+(s[1]-o[1])*d,m=Math.max(0,Math.min(p,_)),f=Math.min(c,Math.max(p,_));f-m>i&&n.push([o[0]+h*m,o[1]+d*m,o[0]+h*f,o[1]+d*f])}}return n}function kn(e,t,i=1e-6){const n=[];for(const r of e){const e=[r[0],r[1]],o=[r[2],r[3]],s=o[0]-e[0],a=o[1]-e[1],l=Math.hypot(s,a);if(lo||r>o)continue;const s=(n[0]-e[0])*c+(n[1]-e[1])*h,a=(n[2]-e[0])*c+(n[3]-e[1])*h,u=Math.max(0,Math.min(s,a)),p=Math.min(l,Math.max(s,a));p-u>i&&d.push([u,p])}if(!d.length){n.push([e[0],e[1],o[0],o[1]]);continue}d.sort((e,t)=>e[0]-t[0]);let u=0;for(const[t,r]of d)t-u>i&&n.push([e[0]+c*u,e[1]+h*u,e[0]+c*t,e[1]+h*t]),u=Math.max(u,r);l-u>i&&n.push([e[0]+c*u,e[1]+h*u,o[0],o[1]])}return n}function xn(e,t,i=1e-6){const n=[];for(let t=0;t{if("string"!=typeof e||!e)return;const i=Rn(e);i.startsWith("/api/houseplan/content/")&&t.add(i)};for(const t of e?.spaces||[]){i(t?.plan_url);for(const e of t?.markers||[])for(const t of e?.pdfs||[])i(t?.url)}for(const t of e?.markers||[])for(const e of t?.pdfs||[])i(e?.url);return t}function Rn(e){return e?e.startsWith("/houseplan_files/plans/")?"/api/houseplan/content/plans/_/"+e.slice(23):e.startsWith("/houseplan_files/files/")?"/api/houseplan/content/files/"+e.slice(23):e:""}function Tn(e,t){const i=t?.settings?.fill_mode;return"none"===i||"lqi"===i||"light"===i||"temp"===i||"custom"===i?i:e}function Cn(e,t){const i=t?.settings;return"boolean"==typeof i?.glow?i.glow:"glow"===i?.fill_mode||e}function Dn(e,t,i,n){if(!t||!i||t===i)return e;const r="/files/"+t+"/",o="/files/"+i+"/";return e.map(e=>{if(!e.url.includes(r))return e;const t=e.url.split(r)[1]||"",[i,s]=[t.split("?")[0],t.includes("?")?"?"+t.split("?")[1]:""];if(n){const t=n[decodeURIComponent(i)]??n[i];return t?{...e,url:e.url.split(r+i)[0]+o+encodeURIComponent(t)+s}:e}return{...e,url:e.url.split(r).join(o)}})}function zn(e,t=1){const i=Number(e);return Number.isFinite(i)&&i>0?Math.min(3,Math.max(.5,i)):t}function An(e,t,i){let n=null,r=null;for(const o of t){if(!(Math.abs(o[0]-e[0])<1e-6&&Math.abs(o[1]-e[1])<1e-6)){if(Math.abs(o[0]-e[0])<=i){const t=Math.abs(o[1]-e[1]);t>1e-6&&(!n||t1e-6&&(!r||t"number"==typeof e&&Number.isFinite(e),Vn=(e,t,i)=>Math.min(i,Math.max(t,e));function Un(e){return e.elevation<=-6?"night":e.elevation>=6?"day":e.rising?"dawn":"dusk"}function Gn(e){const t=(Math.floor(Number(e)||0)%1440+1440)%1440;return t>=300&&t<480?"dawn":t>=480&&t<1080?"day":t>=1080&&t<1260?"dusk":"night"}function Kn(e){const t=Un(e),i=e.azimuth*Math.PI/180;return{sunX:50-42*Math.sin(i),sunY:78-Vn(e.elevation,0,90)/90*64,sunOpacity:"night"===t?0:Vn((e.elevation+6)/12,0,1)}}function Yn(e){const t=(Math.floor(Number(e)||0)%1440+1440)%1440;if(t<300||t>=1260)return{sunX:50,sunY:78,sunOpacity:0};const i=(t-300)/960,n=(t-300)/120,r=(1260-t)/120;return{sunX:8+84*i,sunY:78-64*Math.sin(i*Math.PI),sunOpacity:Math.max(.18,Math.min(n,r,1))}}function Zn(e,t=new Date){const i=function(e){const t=e?.states?.["sun.sun"]?.attributes;return t&&Bn(t.azimuth)&&Bn(t.elevation)&&"boolean"==typeof t.rising?{azimuth:qn(t.azimuth),elevation:t.elevation,rising:t.rising}:null}(e);if(i)return{phase:Un(i),source:"sun",...Kn(i)};const n="number"==typeof t?t:function(e=new Date){return 60*e.getHours()+e.getMinutes()}(t);return{phase:Gn(n),source:"clock",...Yn(n)}}function Xn(e){return`${e.source}|${e.phase}|${e.sunX.toFixed(2)}|${e.sunY.toFixed(2)}|`+e.sunOpacity.toFixed(3)}const Jn=[[-90,"#070c14"],[-12,"#070c14"],[-4,"#131a28"],[0,"#4a3527"],[10,"#e8ddcf"],[30,"#ffffff"],[90,"#ffffff"]],Qn=e=>Math.min(1,Math.max(0,e));function er(e,t,i=6){const n=e.angle*Math.PI/180,r=[Math.sin(n),-Math.cos(n)],o=n=>{const o=[e.x+r[0]*i*n,e.y+r[1]*i*n];return t.find(e=>e.poly.length>=3&&ai(o,e.poly))||null},s=o(1),a=o(-1);return s&&a?null:s||a?s?{normal:[-r[0],-r[1]],roomId:s.id}:{normal:r,roomId:a.id}:null}function tr(e,t,i){return i>0&&e[0]*t[0]+e[1]*t[1]>.05}function ir(e,t,i,n){return[[e[0],e[1]],[t[0],t[1]],[t[0]+i[0]*n,t[1]+i[1]*n],[e[0]+i[0]*n,e[1]+i[1]*n]]}function nr(e,t){try{const i=Ht([[...e.map(e=>[e[0],e[1]]),[e[0][0],e[0][1]]]],[[...t.map(e=>[e[0],e[1]]),[t[0][0],t[0][1]]]]),n=[];for(const e of i){const t=e?.[0];!Array.isArray(t)||t.length<4||n.push(t.slice(0,t.length-1).map(e=>[e[0],e[1]]))}return n}catch{return[]}}function rr(e,t,i,n,r,o,s){if(!(n>0))return[];const a=Wn(i,r),l=[-a[0],-a[1]],c=function(e){const t=Math.min(90,Math.max(0,e));return.7*(.8+1.7*Math.pow(1-t/90,1.6))}(n),h=[];for(const i of t){if(!(i.length>0))continue;const t=er(i,e);if(!t||!tr(t.normal,a,n))continue;const r=e.find(e=>e.id===t.roomId);if(!r)continue;const d=o&&o[t.roomId]||r.poly,u=i.angle*Math.PI/180,p=i.length/2,_=[-t.normal[0],-t.normal[1]],m=Math.max(0,s?.[i.id]||0),f=i.x+_[0]*m/2,g=i.y+_[1]*m/2,v=Math.cos(u)*p,y=Math.sin(u)*p,b=[f-v,g-y],w=[f+v,g+y],k=c*i.length,x=nr(ir(b,w,l,k),d);if(!x.length)continue;const $=l[0]*_[0]+l[1]*_[1];h.push({openingId:i.id,roomId:t.roomId,polys:x,a:b,b:w,dir:l,len:k,normal:_,depth:k*$})}return h}const or=e=>"number"==typeof e&&Number.isInteger(e)&&e>=0&&e<=359?e:null;function sr(e,t){const i=or(t?.north_deg);return null!==i?i:or(e?.north_deg)}function ar(e,t){const i=e=>"static"===e||"daynight"===e?e:null;return i(t?.bg_mode)??i(e?.bg_mode)??"static"}function lr(e,t){const i=t?.sun_rays;return"boolean"==typeof i?i:!0===e?.sun_rays}function cr(e){const t=e?.states?.["sun.sun"]?.attributes,i=Number(t?.azimuth),n=Number(t?.elevation);return Number.isFinite(i)&&Number.isFinite(n)?{azimuth:i,elevation:n}:null}const hr=["dawn","day","dusk","night"];function dr(e){if(!e)return"";const t=jn[e.phase];return[`--hp-day-cycle-outline-near:${t.outlineNear}`,`--hp-day-cycle-outline-mid:${t.outlineMid}`,`--hp-day-cycle-outline-far:${t.outlineFar}`].join(";")}function ur(e,t=1){if(!e)return U;const i=[`--hp-day-cycle-sun-x:${e.sunX.toFixed(2)}%`,`--hp-day-cycle-sun-y:${e.sunY.toFixed(2)}%`,`--hp-day-cycle-sun-opacity:${e.sunOpacity.toFixed(3)}`,`opacity:${Math.min(1,Math.max(0,t)).toFixed(4)}`].join(";");return j``}const pr={color:"#607d8b",opacity:1,widthCm:3.6,fill:!1,fillColor:"#607d8b",fillOpacity:.25},_r=(e,t=1)=>{const i=Number(e);return Number.isFinite(i)?Math.min(1,Math.max(0,i)):t},mr=e=>{let t=Number(e);return Number.isFinite(t)?(t=(t%360+360)%360,t>180?t-360:t):0};function fr(e,t,i){return mr(t)?[e.x,e.y]:i([e.x,e.y])}function gr(e,t,i,n){const r=Math.abs(i[0]-t[0]),o=Math.abs(i[1]-t[1]);return"line"===e?Math.hypot(r,o)>=n:r>=n&&o>=n}const vr=(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},yr=(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},br=(e,t,i,n=pr.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?yr(o,t,i):n};function wr(e,t){return{color:e.color,opacity:_r(e.opacity),width_cm:Math.max(.1,Math.min(100,Number(e.widthCm)||.1)),...t?{fill:e.fill,fill_color:e.fillColor,fill_opacity:_r(e.fillOpacity,.25)}:{}}}function kr(e){const t=e.x+e.w/2,i=e.y+e.h/2,n=mr(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 xr(e){const t=kr(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 $r(e,t,i,n,r,o,s,a){const l=mr(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,f=i>0?-e.h/2:e.h/2,g=p+m*c+f*d,v=_+m*h+f*u,y=n-g,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:g+(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:mr(e.angle)||void 0}}const Sr=(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 Mr(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 Tr=Math.tan(.25*Math.PI/180);function Cr(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>Tr?null:{axis:r,major:o,minor:s,angleDegrees:180*Math.atan2(s,o)/Math.PI}}function Dr(e,t){const i=Cr(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 zr=e=>`${e[0]},${e[1]}`,Ar=(e,t)=>e[0]===t[0]&&e[1]===t[1],Or=(e,t)=>{const i=zr(e),n=zr(t);return i{let t=0;for(let i=0;i{if(e.length<3)return!1;for(let t=0;t1e-12},Er=e=>{for(let t=0;t+1Ar(e,t.from)?[...t.to]:[...e],Hr=(e,t)=>e.map(e=>Array.isArray(e?.poly)?{...e,poly:e.poly.map(e=>Ir(e,t))}:e),Nr=(e,t,i)=>{const n=e.flatMap((e,t)=>Zt(e)?.some(e=>Ar(e,i.from))?[t]:[]);if(!n.length)return!1;for(const i of n){const n=Zt(e[i]),r=Zt(t[i]);if(!n||!r)continue;if(!Fr(r))return!1;const o=Math.sign(Pr(n)),s=Math.sign(Pr(r));if(o&&s&&o!==s)return!1}const r=new Set;for(const e of n){const i=Zt(t[e]);if(i)for(let n=0;n{let i=0;for(const n of e){const e=Zt(n);if(e)for(let n=0;n{const{a:i,b:n,axis:r}=e,o="horizontal"===r?{from:n,to:[n[0],i[1]]}:{from:n,to:[i[0],n[1]]},s="horizontal"===r?{from:i,to:[i[0],n[1]]}:{from:i,to:[n[0],i[1]]};return[{move:o,preservedDegree:Lr(t,i)},{move:s,preservedDegree:Lr(t,n)}].sort((e,t)=>t.preservedDegree-e.preservedDegree||zr(e.move.to).localeCompare(zr(t.move.to))||zr(e.move.from).localeCompare(zr(t.move.from))).map(e=>e.move)};function Wr(e){const t=JSON.parse(JSON.stringify(e||{}));let i=Array.isArray(t.rooms)?t.rooms:[];const n=new Map;for(const e of i){const t=Zt(e);if(t)for(let e=0;ee.key.localeCompare(t.key))){let t=null;for(const n of qr(e,i)){const e=a.get(zr(n.from));if(e&&e!==zr(n.to))continue;const r=Hr(i,n);if(Nr(i,r,n)){t=n,i=r;break}}t?(a.set(zr(t.from),zr(t.to)),r++,s=Math.max(s,Math.hypot(t.to[0]-t.from[0],t.to[1]-t.from[1]))):o++}t.rooms=i;for(const e of t.room_drafts||[]){if(!Array.isArray(e?.points)||e.points.length<2)continue;const t=e.points.map(e=>[...e]),i=t.slice(0,-1).flatMap((i,n)=>{const r=t[n+1],o=Cr(i,r);return o?[{key:`${String(e.id||"")}:${n}`,a:[...i],b:[...r],axis:o.axis}]:[]});let n=t;for(const e of i){let t=null;for(const i of qr(e,[{poly:n}])){const e=n.map(e=>Ir(e,i)),r=e.length>=4&&Ar(e[0],e[e.length-1]),o=r?e.slice(0,-1):e;if(r?Fr(o):Er(o)){t=i,n=e;break}}t?(r++,s=Math.max(s,Math.hypot(t.to[0]-t.from[0],t.to[1]-t.from[1]))):o++}e.points=n}for(const e of t.partitions||[]){if(!Array.isArray(e?.a)||!Array.isArray(e?.b))continue;const i=Cr(e.a,e.b);if(!i)continue;const n={key:String(e.id||Or(e.a,e.b)),a:[...e.a],b:[...e.b],axis:i.axis};let a=null;for(const i of qr(n,[{poly:[e.a,e.b]}])){const n=Ir(e.a,i),r=Ir(e.b,i),o=Math.hypot(r[0]-n[0],r[1]-n[1]);if(!(o>0))continue;const s=(t.openings||[]).filter(t=>"partition"===t?.host?.kind&&t.host.id===e.id).every(e=>{const t=Number(e.host.t),i=Number(e.length);return Number.isFinite(t)&&t>=0&&t<=1&&Number.isFinite(i)&&i>0&&t*o-i/2>=-1e-12&&t*o+i/2<=o+1e-12});if(s){a=i,e.a=n,e.b=r;break}}a?(r++,s=Math.max(s,Math.hypot(a.to[0]-a.from[0],a.to[1]-a.from[1]))):o++}return{space:t,report:{wallsStraightened:r,wallsStraightenSkipped:o,maxStraightenShift:s},changed:r>0}}const jr=10**9,Br=240,Vr=1e-4;function Ur(e){if(Array.isArray(e))return e.map(e=>Ur(e));if(null!==e&&"object"==typeof e){const t={};for(const[i,n]of Object.entries(e))t[i]=Ur(n);return t}return e}function Gr(e){if("number"!=typeof e||!Number.isFinite(e))return e;const t=(e<0||Object.is(e,-0)?-1:1)*(Math.floor(Math.abs(e)*jr+.5)/jr);return 0===t?0:t}function Kr(e){if("number"!=typeof e||!Number.isFinite(e))return e;const t=e*Br,i=Math.round(t);if(Math.abs(t-i)null!==Zr(e)):[]}function Jr(e,t){for(const i of t)Object.prototype.hasOwnProperty.call(e,i)&&(e[i]=Gr(e[i]))}function Qr(e,t){for(const i of t)Object.prototype.hasOwnProperty.call(e,i)&&(e[i]=Kr(e[i]))}function eo(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 Xr(e.rooms))t(i,["x","y","w","h"]),r(i.poly);for(const t of Xr(e.walls))n(t.a),n(t.b);for(const t of Xr(e.wall_segments))n(t.a),n(t.b);for(const i of Xr(e.openings))t(i,["x","y"]);for(const i of Xr(e.decor))"line"===i.kind?t(i,["x1","y1","x2","y2"]):"rect"===i.kind||"ellipse"===i.kind||"furniture"===i.kind?t(i,["x","y","w","h"]):"text"===i.kind&&t(i,["x","y"]);for(const t of Xr(e.room_drafts))r(t.points);for(const t of Xr(e.partitions))n(t.a),n(t.b);for(const t of Xr(e.wall_columns))n(t.center);for(const t of Xr(e.open_spans))n(t.a),n(t.b)}const r=Zr(t);if(!r)return;const o=new Map;if(n)for(const e of Xr(n.spaces))null!=e.id&&o.set(String(e.id),e);for(const e of Object.values(r)){const t=Zr(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 no(e){const t=Number(e?.cell_cm);return t>0?t:5}function ro(e,t={}){const i={canonicalized:0,far:0,maxShift:0,maxShiftCm:0,spaces:[],bySpace:new Map},n=Xr(Zr(e)?.spaces);let r=5;for(const e of n)r=Math.max(r,no(e));io(e,t,(e,t)=>{const n=e*Br,o=Math.abs(n-Math.round(n)),s=Kr(e),a=o>0&&o=Vr))return;const l=a&&"number"==typeof s?Math.abs(s-e):0;if(a?i.canonicalized++:i.far++,i.maxShift=Math.max(i.maxShift,l),i.maxShiftCm=Math.max(i.maxShiftCm,l*Br*(t?no(t):r)),!t?.id||!a)return;const c=String(t.id);let h=i.bySpace.get(c);h||(h={spaceId:c,space:String(t.title||c),canonicalized:0,far:0,maxShift:0,maxShiftCm:0},i.bySpace.set(c,h)),h.canonicalized++,h.maxShift=Math.max(h.maxShift,l),h.maxShiftCm=Math.max(h.maxShiftCm,l*Br*no(t))}),i.bySpace.size&&io(e,t,(e,t)=>{if(!t?.id)return;const n=i.bySpace.get(String(t.id));if(!n)return;const r=e*Br;Math.abs(r-Math.round(r))>=Vr&&n.far++}),i.spaces=[...i.bySpace.values()];const{bySpace:o,...s}=i;return s}function oo(e){return function(e){const t=e,i=Zr(t);i&&Qr(i,["x","y"]);return t}(Ur(e))}function so(e){const t=e,i=Zr(t);if(!i)return t;for(const e of Object.values(i)){const t=Zr(e);t&&Qr(t,["x","y"])}return t}function ao(e){return lo(Ur(e))}function lo(e){const t=e,i=Zr(t);if(!i)return t;for(const e of Xr(i.spaces)){Jr(e,["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"]);for(const t of Xr(e.rooms))Qr(t,["x","y","w","h"]),to(t.poly);for(const t of Xr(e.walls))eo(t.a),eo(t.b);for(const t of Xr(e.wall_segments))eo(t.a),eo(t.b);for(const t of Xr(e.openings)){Qr(t,["x","y"]),Jr(t,["angle","length"]);const e=Zr(t.host);e&&Jr(e,["t"])}for(const t of Xr(e.decor))"line"===t.kind?Qr(t,["x1","y1","x2","y2"]):"rect"===t.kind||"ellipse"===t.kind||"furniture"===t.kind?(Qr(t,["x","y","w","h"]),Jr(t,["angle"])):"text"===t.kind&&(Qr(t,["x","y"]),Jr(t,["scale","angle"]));for(const t of Xr(e.room_drafts))to(t.points);for(const t of Xr(e.partitions))eo(t.a),eo(t.b);for(const t of Xr(e.wall_columns))eo(t.center),"square"===t.shape&&Jr(t,["angle"]);for(const t of Xr(e.open_spans))eo(t.a),eo(t.b)}for(const e of Xr(i.markers))Jr(e,["angle"]);return t}const co=15,ho=8;function uo(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 po=Math.sin(.25*Math.PI/180);function _o(e,t){return Number.isFinite(e)&&e>0&&Number.isFinite(t)&&t>0&&e*t<3}function mo(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 go(e){return Number.isFinite(e)?Math.max(1,Math.min(100,e)):1}function vo(e,t){return!Number.isFinite(e)||e<0?"":String(t?Math.round(e/2.54*100)/100:Math.round(100*e)/100)}function yo(e,t,i){if(!Number.isFinite(e)||e<=0)return 0;const n=Number(t)>0?Number(t):5;return go(e)/n*i}function bo(e,t){return t>0&&Number.isFinite(e)?Math.round(e/t)*t:e}function wo(e){return Math.max(1e-6*Math.abs(e),1e-9)}function ko(e,t){if(!(t>0&&Number.isFinite(e)))return e;const i=bo(e,t);return Math.abs(i-e)<=wo(t)?i:e}function xo(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 $o(e,t,i){const n=[ko(e[0],i),ko(e[1],i)],r=[ko(t[0],i),ko(t[1],i)],o=bo((n[0]+r[0])/2,i),s=bo((n[1]+r[1])/2,i),[a,l]=xo(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 So(e,t,i,n){return 1===n?$o(e,t,i):$o([e[0]/n,e[1]/n],[t[0]/n,t[1]/n],i)}function Mo(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 Ro(e,t,i,n,r){const o=r>0?r:1;return{key:So(e,t,n,o),cm:go(i),a:[e[0]/o,e[1]/o],b:[t[0]/o,t[1]/o]}}function To(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 Co(e,t){const[i,n]=xo(e,t);let r=Math.atan2(n,i);return r<0&&(r+=Math.PI),r}function Do(e,t){let i=Math.abs(e-t);return i>Math.PI/2&&(i=Math.PI-i),i<.02}function zo(e,t,i,n,r=1){if(!e?.length)return null;const o=So(t,i,n,r),s=e.find(e=>e.key===o);if(s)return s;const a=r>0?r:1,l=wo(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=Mo(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=Co(t,i),p=Math.max(.5*n,1e-9)*a;for(const t of To(e,a))if(Do(t.ang,u)&&Math.hypot(t.x-h,t.y-d)<=p)return t.w;return null}function Ao(e,t,i,n,r=1){const o=zo(e,t,i,n,r);if(o&&o.cm>0)return go(o.cm);const s=function(e,t,i,n,r){if(!e?.length)return null;const o=r>0?r:1,s=Math.hypot(i[0]-t[0],i[1]-t[1]);if(s<1e-12)return null;const a=Co(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=Mo(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||!Do(Co(e[0],e[1]),a))continue;if(ws(t[0],t[1],e[0][0],e[0][1],e[1][0],e[1][1])>l||ws(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=Mo(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 Do(Co(i,o),Co(t,n))&&ws(i[0],i[1],t[0],t[1],n[0],n[1])<=l&&ws(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(!Do(Co(i,o),Co(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 Po(e,t,i,n=8){const[r,o]=xo(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 Fo(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,f=(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)},g=(e,t)=>{const[i,n]=xo(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]=g(e,t),s=go(i);if(y.some(e=>e.entry.cm===s&&m(e.span[0],r)&&m(e.span[1],o)))return;const l=Ro(r,o,s,n,a);v.push(l),y.push({entry:l,span:[r,o]})};for(const t of e){const e=Mo(t,a);if(e){const[i,n]=g(e[0],e[1]),r=n[0]-i[0],s=n[1]-i[1],a=r*r+s*s,d=Math.sqrt(a);if(d<=c){v.push({...t,cm:go(t.cm)});continue}const u=[];for(const e of h){if(!Do(Co(i,n),Co(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=[f(o,l[0].move),f(s,l[0].move)],g=l.slice(1).some(e=>{const t=f(o,e.move),i=f(s,e.move);return!m(h[0],t)||!m(h[1],i)});y.push(g?[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=[To([t],a)[0]];1!==a&&i.push(To([t],1)[0]);const n=i.filter(Boolean).some(e=>h.some(t=>{if(!Do(e.ang,Co(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&&ws(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=To([t],a)[0];if(e){const t=new Set;for(const i of h){if(!Do(e.ang,Co(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(ws(e.x,e.y,i.oa[0],i.oa[1],i.ob[0],i.ob[1])>l)continue;const o=f([e.x,e.y],i),[s,c]=xo(i.na,i.nb),h=Math.max(n*a,1e-6);t.add(So([o[0]-s*h,o[1]-c*h],[o[0]+s*h,o[1]+c*h],n,a))}1===t.size&&(i=[...t][0])}}v.push({...t,key:i||t.key,cm:go(t.cm)})}return v}function Eo(e,t,i,n,r=1,o="affine"){return Fo(e,t,i,n,r,o)}function Io(e,t,i,n,r=1,o="fixed-topology"){let s=!1;const a=Fo(e,t,i,n,r,o,()=>{s=!0});return{walls:s?(e||[]).map(e=>({...e})):a,rejected:s}}function Ho(e,t,i,n=1,r=[]){const o=n>0?n:1,s=Math.abs(i),a=Math.max(s*o*Vr,1e-9),l=(r||[]).flatMap(e=>{const t=Mo(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=Mo(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 f=0;for(const[e,t]of m){if(e>f+a)break;if(f=Math.max(f,t),f>=u-a)break}fe.key!==s);return null==n||n<1?a:[...a,Ro(t,i,n,r,o)]}function Lo(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=as(e,t,i,n,r,o);if(!s)return[];const a=[];for(let e=0;e0||(c=No(c,t,i,n,r,s)))}return c}function Wo(e){const{a:t,b:i,halfDepth:n}=e;if(!Array.isArray(t)||!Array.isArray(i)||t.length<2||i.length<2||![t[0],t[1],i[0],i[1]].every(Number.isFinite))return null;const r=i[0]-t[0],o=i[1]-t[1],s=Math.hypot(r,o);if(!(s>1e-9&&n>0&&Number.isFinite(n)))return null;const a=-o/s*n,l=r/s*n;return[[t[0]+a,t[1]+l],[i[0]+a,i[1]+l],[i[0]-a,i[1]-l],[t[0]-a,t[1]-l]]}function jo(e,t,i){return Math.hypot(e[0]-t[0],e[1]-t[1])<=i}function Bo(e,t,i){const n=t.b[0]-t.a[0],r=t.b[1]-t.a[1],o=n*n+r*r;if(!(o>i*i))return!1;const s=((e[0]-t.a[0])*n+(e[1]-t.a[1])*r)/o;if(!(s>0&&s<1))return!1;const a=[t.a[0]+n*s,t.a[1]+r*s];return Math.hypot(e[0]-a[0],e[1]-a[1])<=i}function Vo(e,t,i,n){const r=Math.hypot(t,i);if(!(r>1e-9&&n>0))return;const o=[t/r,i/r],s=e.find(e=>Math.abs(e.u[0]*o[1]-e.u[1]*o[0])<1e-9&&e.u[0]*o[0]+e.u[1]*o[1]>1-1e-9);s?s.halfDepth=Math.max(s.halfDepth,n):e.push({u:o,halfDepth:n})}function Uo(e,t){try{const i=Nt($s(e),$s(t));let n=null,r=0;for(const e of i||[]){const t=e?.[0]||[],i=Math.abs(Jo(t));t.length>=4&&i>r&&(r=i,n=t.slice(0,-1).map(e=>[e[0],e[1]]))}return n}catch{return null}}function Go(e,t=1e-6){const i=(e||[]).map((e,t)=>({segment:e,index:t})).filter(({segment:e})=>e&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&e.a.every(Number.isFinite)&&e.b.every(Number.isFinite)&&Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>1e-9);if(i.length<2)return[];const n=Math.max(Number.isFinite(t)?t:0,1e-9),r=i.flatMap(({segment:e})=>[e.a,e.b]).map(e=>[e[0],e[1]]).sort((e,t)=>e[0]-t[0]||e[1]-t[1]),o=[];for(const e of r)o.some(t=>jo(t,e,n))||o.push(e);const s=[];for(const e of o){const t=[];let r=!1;for(const{segment:o,index:s}of i){const i=Math.hypot(o.b[0]-o.a[0],o.b[1]-o.a[1]);jo(e,o.a,n)?t.push({u:[(o.b[0]-o.a[0])/i,(o.b[1]-o.a[1])/i],halfDepth:o.halfDepth,length:i,index:s}):jo(e,o.b,n)?t.push({u:[(o.a[0]-o.b[0])/i,(o.a[1]-o.b[1])/i],halfDepth:o.halfDepth,length:i,index:s}):Bo(e,o,n)&&(r=!0)}if(r||2!==t.length)continue;const[o,a]=t,l=o.u[0]*a.u[1]-o.u[1]*a.u[0];if(Math.abs(l)<1e-9)continue;const c=l<0?1:-1,h=[-o.u[1],o.u[0]],d=[-a.u[1],a.u[0]],u=[e[0]+h[0]*o.halfDepth*c,e[1]+h[1]*o.halfDepth*c],p=[e[0]-d[0]*a.halfDepth*c,e[1]-d[1]*a.halfDepth*c];if(!ts(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(Jo(h))>n*n&&s.push({segmentIndex:t.index,wedge:h})}}return s}function Ko(e,t=1e-6){const i=(e||[]).filter(e=>e&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&e.a.every(Number.isFinite)&&e.b.every(Number.isFinite)&&Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>1e-9);if(i.length<2)return[];const n=Math.max(Number.isFinite(t)?t:0,1e-9),r=i.flatMap(e=>[e.a,e.b]).map(e=>[e[0],e[1]]).sort((e,t)=>e[0]-t[0]||e[1]-t[1]),o=[];for(const e of r)o.some(t=>jo(t,e,n))||o.push(e);const s=[],a=i.map((e,t)=>({roomId:"",a:[e.a[0],e.a[1]],b:[e.b[0],e.b[1]],key:`join-${t}`,kind:"outer",cm:0,open:!1,half:e.halfDepth})),l=us(a,n);for(const e of ps(l).fans)s.push(e);const c=e=>!!_s(l,e);for(const e of o){if(c(e))continue;const t=[];for(const r of i)jo(e,r.a,n)?Vo(t,r.b[0]-r.a[0],r.b[1]-r.a[1],r.halfDepth):jo(e,r.b,n)?Vo(t,r.a[0]-r.b[0],r.a[1]-r.b[1],r.halfDepth):Bo(e,r,n)&&(Vo(t,r.a[0]-e[0],r.a[1]-e[1],r.halfDepth),Vo(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 Yo(e,t,i,n){if(!(t>0)||!e||e.length<2)return"";if(i&&e.length>=3){let i=e;const r=e[e.length-1];if(e.length>=4&&Math.hypot(e[0][0]-r[0],e[0][1]-r[1])<1e-9&&(i=e.slice(0,-1)),i.length>=3){const e=i.map((e,i)=>n?.[i]||t),r=js(i,e),o=rs(i,e);if(r&&o)return`${os(r)} ${os(ss(o))}`}}const r=[];for(let i=0;i=1e-9&&a>0&&r.push({a:o,b:s,halfDepth:a})}const o=r.map(Wo);for(const{segmentIndex:e,wedge:t}of Go(r)){const i=o[e];if(!i)continue;const n=Uo(i,t);n&&(o[e]=n)}const s=[...o.filter(e=>!!e),...Ko(r)],a=function(e){let t=null;try{for(const i of e){if(i.length<3)continue;const e=$s(i);t=t?It(t,e):[e]}return t}catch{return null}}(s);return a?Es(a):s.map(e=>os(e)).join(" ")}function Zo(e,t,i,n,r=1){if(!i.length)return!1;const o=Xo(n,r),s=(e[0]+t[0])/2,a=(e[1]+t[1])/2,[l,c]=xo(e,t);for(const e of i){const[t,i]=xo([e[0],e[1]],[e[2],e[3]]);if(!(Math.abs(l*i-c*t)>.05)&&ws(s,a,e[0],e[1],e[2],e[3])<=o)return!0}return!1}function Xo(e,t){return Math.max(e*(t>0?t:1)*.04,1e-9)}function Jo(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 es(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 ts(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 is(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=Qo(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=Qo(e,t),_=ts(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,f=(_((r+1)%n)??c)-m;return f>0?f:0}function ns(e,t,i,n,r,o,s,a=1){const l=(e||[]).find(e=>e?.id===t),c=Zt(l);if(!c||c.length<3)return null;const h=fs(e,t,i,n,r,o,s,a);if(!h)return c.map(()=>0);const d=4*Xo(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]+f*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(es(w,k)){const t=e[o],i=[t[0]+p*d,t[1]+_*d],n=[t[0]+m*u,t[1]+f*u];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}const S=ts(x,w,$,k),M=Math.max(d,u,1e-9),R=_s(i,e[o])?.limit??4*M;if(S){const i=Math.hypot(S[0]-e[o][0],S[1]-e[o][1]);if(Number.isFinite(i)&&i<=R){r.push(S);continue}if(Hs(e,t,o)){r.push(S);continue}}d>0&&r.push([e[o][0]+p*d,e[o][1]+_*d]),u>0&&r.push([e[o][0]+m*u,e[o][1]+f*u]),d>0||u>0||r.push([e[o][0],e[o][1]])}return r.length>=3?r:null}function os(e,t=!0){if(!e.length)return"";let i=`M ${e[0][0]} ${e[0][1]}`;for(let t=1;te?.id===t),a=Zt(s);if(!a||a.length<3)return null;const l=Xo(n,r),c=[];for(const i of e||[]){if(!i||i.id===t)continue;const e=Zt(i);if(e)for(const t of wn(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=Mo(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 ls(e,t,i,n){const r=t.poly.length,o=new Array(r).fill(0);if(!e?.length)return o;const s=new Set,a=[];for(let l=0;l0?(o[l]=go(c.cm),s.add(c.key)):a.push(l)}if(!a.length)return o;const l=n>0?n:1,c=Math.max(.5*i,1e-9)*l,h=To(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=Co(n,s);let u=null;for(const e of h){const t=Mo(e.w,l);if(!t||!Do(Co(t[0],t[1]),d))continue;if(ws(n[0],n[1],t[0][0],t[0][1],t[1][0],t[1][1])>c||ws(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||ws(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(ws(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]=cs(e.point,n),r=hs(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=ds(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]=cs(i.point,n),o=hs(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 ds(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]=cs(e.point,n),r=hs(t,i),o=p.get(r)||[];o.push(e),p.set(r,o)}return{epsilon:n,coordinateScale:r,nodes:d,index:p}}function ps(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(Jo(e))>i&&t.fans.push(e)};if(_){const e=1.5*Math.max(o.halfDepth,s.halfDepth);m(uo([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 f=(e,t)=>Math.min(t,Math.sqrt(Math.max(c**2-e**2,0)),2*Math.max(o.halfDepth,s.halfDepth)),g=[h[0]+o.u[0]*f(o.halfDepth,o.thickLength),h[1]+o.u[1]*f(o.halfDepth,o.thickLength)],v=[d[0]+s.u[0]*f(s.halfDepth,s.thickLength),d[1]+s.u[1]*f(s.halfDepth,s.thickLength)];m([[r[0],r[1]],h,g,v,d])}}return t}function _s(e,t){return!e||!Array.isArray(t)||t.length<2||!t.slice(0,2).every(Number.isFinite)?null:ds(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 ms(e,t,i,n,r,o,s){return us(gs(e,t,i,n,r,o,s),4*Xo(n,s),s)}function fs(e,t,i,n,r,o,s,a=1){const l=as(e,t,n,r,a,i);if(!l)return null;const c=function(e,t,i){const n=(e||[]).find(e=>e?.id===t),r=Zt(n);if(!r)return[];const o=[];for(const n of e||[]){if(!n||n.id===t)continue;const e=Zt(n);if(e)for(const t of wn(r,e,i))o.push(t)}return o}(e,t,Xo(r,a)),h=function(e,t,i,n,r){const o=Xo(n,r),s=[];for(let a=0;aws(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=ls(i,l,r,a),u=d.map((e,t)=>h[t]&&e>0?yo(e,o,s)/2:0);return{...l,kinds:h,cms:d,offsets:u}}function gs(e,t,i,n,r,o,s=1){const a=[];for(const l of e||[]){if(!l?.id)continue;const c=fs(e,l.id,t,i,n,r,o,s);if(c)for(let e=0;e0&&(a=No(a,e.a,e.b,e.cm,n,s));return a}function ys(e,t,i,n,r,o,s=1){if(!t?.length)return[];const a=gs(e,t,i,n,r,o,s),l=new Map;for(const e of a){if(e.open||!e.kind||!e.roomId)continue;const t=l.get(e.key)||new Set;t.add(e.roomId),l.set(e.key,t)}const c=e=>{const t=[...l.get(e)||[]].sort();return 1!==t.length&&2!==t.length?`ambiguous:${e}`:`${1===t.length?"outer":"shared"}:${t.join("|")}`},h=[],d=new Set;for(const e of a)!e.open&&e.cm>0&&!d.has(e.key)&&(d.add(e.key),h.push({...e,ownerSignature:c(e.key)}));const u=[];for(const a of e||[]){if(!a?.id)continue;const l=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(So(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:So(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,f=4*Xo(n,s);for(const e of u){const t=h.filter(t=>!m.has(t.key)&&t.cm===e.cm&&t.ownerSignature===e.ownerSignature&&Do(Co(t.a,t.b),Co(e.a,e.b))&&ws(t.a[0],t.a[1],e.a[0],e.a[1],e.b[0],e.b[1])<=f&&ws(t.b[0],t.b[1],e.a[0],e.a[1],e.b[0],e.b[1])<=f);if(t.length){for(const e of t)m.add(e.key);_.has(e.key)||(_.add(e.key),p.push(Ro(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(Ro(e.a,e.b,e.cm,n,s)));return p}function bs(e,t,i,n,r,o,s,a=1){const l=Xo(r,a),c=(n[0]+n[2])/2,h=(n[1]+n[3])/2,d=Co([n[0],n[1]],[n[2],n[3]]);let u=null;for(const n of gs(e,t,i,r,o,s,a)){if(!Do(Co(n.a,n.b),d))continue;const e=ws(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(Jo(r));r.length>=3&&o>i&&(t=r,i=o)}return t}function xs(e,t,i,n,r,o,s,a=1,l,c){const h=(e||[]).find(e=>e?.id===t),d=Zt(h);if(!d||d.length<3)return null;if(!i?.length)return d.map(e=>[e[0],e[1]]);const u=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||ms(e,i,n,r,o,s,a),_=rs(u.poly,u.offsets,p);if(!_)return d.map(e=>[e[0],e[1]]);if(!p.nodes.length)return _;const m=void 0===l?Ns(e,i,n,[],r,o,s,a):null,f=l??("ok"===m?.status||"degraded-extra"===m?.status?m.roomGeom:void 0);if(f)try{const e=ks(Nt($s(u.poly),f));if(e)return e}catch{}return function(e,t){try{return ks(Ht($s(e),$s(t)))}catch{return null}}(_,u.poly)||d.map(e=>[e[0],e[1]])}function $s(e){const t=e.map(e=>[e[0],e[1]]);return t.push([e[0][0],e[0][1]]),[t]}function Ss(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(bi(e[0]))>1e-9)}function Ms(e,t,i,n){const r=n?new Set(n):null;let o=null;for(let n=0;nt.epsilon))continue;const l=zs([[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=$s(l);o=o?It(o,c):c}}return o}function Rs(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=zs([[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=Ht($s(s),i);Array.isArray(a)&&0!==a.length&&(n=n?It(n,a):a)}return n}function Ts(e,t,i=2*(4*e.halfDepth+2*t.epsilon)){const n=function(e,t=po){const i=new Set,n=Number.isFinite(t)&&t>=0?t:po;for(let t=0;te-t)}(e);return n.length?Ms(e,t,i,n):null}function Cs(e,t,i,n,r){const o=function(e){let t=null;for(const i of e){const e=$s(i);try{t=t?It(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=ts(p,s.u,_,a.u);if(!m)continue;const f=Math.hypot(m[0]-r.point[0],m[1]-r.point[1]);if(!Number.isFinite(f)||f<=r.limit)continue;const g=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=zs([[p[0]+s.u[0]*g,p[1]+s.u[1]*g],[_[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=f-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=zs([[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?Nt(o,r):o}function Ds(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=Ts(i,e);n&&(t=t?It(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=Cs(e,t,!1,!0,r);c&&(s=Nt(s,c));let h=Ms(e,t,a);const d=Cs(e,t,!0,!0,r);d&&(h=Nt(h,d)),r&&(h=It(h,r));const u=.02*Math.min(...e.rays.map(e=>e.halfDepth));if(h=It(h,$s([[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=Ht(h,$s(l));n?p=Ht(p,n):i&&(p=Ht(p,i));const _=$s(l),m=Nt(s,_),f=i?Nt(Ht(s,_),i):null,g=Rs(e,t,_);o=It(m,...f?[f]:[],...g?[g]:[],p)}catch{}}if(r)try{let e=r;n?e=Ht(e,n):i&&(e=Ht(e,i)),o=It(o,e)}catch{}return o}function zs(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(Jo(r))>n*n?r:null}function As(e,t,i,n){if(ws(e[0],e[1],t[0],t[1],i[0],i[1])>n)return!1;const r=i[0]-t[0],o=i[1]-t[1],s=(e[0]-t[0])*r+(e[1]-t[1])*o,a=r*r+o*o,l=n*Math.sqrt(a);return s>=-l&&s<=a+l}function Os(e,t,i){const n=[],r=[];for(let o=0;oi*i))continue;const d=i/Math.sqrt(h),u=[0,1];for(const e of t)for(const t of[e.a,e.b]){if(!As(t,s,a,i))continue;const e=((t[0]-s[0])*l+(t[1]-s[1])*c)/h;e>d&&e<1-d&&u.push(e)}u.sort((e,t)=>e-t);const p=u.filter((e,t)=>0===t||Math.abs(e-u[t-1])>d);for(let e=0;e=3&&r.length===n.length?{poly:n,offsets:r}:null}function Ps(e,t,i,n,r,o,s,a){const l=(e||[]).map(Zt).filter(e=>!!e&&e.length>=3);if(!l.length)return null;let c=It($s(l[0]));for(let e=1;e"outer"===e.kind&&e.half>0),u=4*Xo(n,s),p=a||us(h,u,s);let _=null;for(const e of function(e){const t=[];for(const i of Array.isArray(e)?e:[])if(Array.isArray(i))for(const e of i){if(!Array.isArray(e)||e.length<4)continue;const i=e.slice(0,-1).map(e=>[e[0],e[1]]);i.length>=3&&t.push(i)}return t}(c)){const t=Os(e,d,u);if(!t||!t.offsets.some(e=>e>0))continue;const i=js(t.poly,t.offsets,p),n=rs(t.poly,t.offsets,p);if(!i||!n)continue;const r=Nt($s(i),$s(n));_=_?It(_,r):r}return{centre:c,shell:_||[]}}function Fs(e,t,i,n,r,o,s=1){try{const a=Ps(e,t,i,n,r,o,s,ms(e,t,i,n,r,o,s));if(!a)return[];return a.shell?.length?It(a.centre,a.shell):a.centre}catch{return null}}function Es(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?" ":"")+os(i.map(e=>[e[0],e[1]])))}return t}const Is=15;function Hs(e,t,i){const n=e?.length||0;if(n<3||t?.length!==n)return!1;const r=e[(i-1+n)%n],o=e[i],s=e[(i+1)%n],a=[r[0]-o[0],r[1]-o[1]],l=[s[0]-o[0],s[1]-o[1]],c=Math.hypot(a[0],a[1]),h=Math.hypot(l[0],l[1]);if(!(c>1e-9&&h>1e-9))return!1;const d=Math.max(-1,Math.min(1,(a[0]*l[0]+a[1]*l[1])/(c*h))),u=Math.acos(d);if(!(u>1e-9))return!1;if(u>=Is*Math.PI/180)return!1;const p=Math.max(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 f=(_+p*d)/m,g=(p+_*d)/m;return Number.isFinite(f)&&Number.isFinite(g)&&f>0&&g>0&&fe>0))continue;for(const e of l.offsets)e>0&&(u=Math.max(u,2*e));const c=js(l.poly,l.offsets,d),p=rs(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*Xo(n,s),c=new Map;for(const a of gs(e,t,i,n,r,o,s))!a.open&&a.half>0&&!c.has(a.key)&&c.set(a.key,a);const h=[...c.values()];if(h.length<2)return[];const d=a||us(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(!g)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(Jo(y))>l*l&&p.push(y)}}return p}(e,t,i,r,o,s,a,d),_=n.length?Bs(e,t,i,r,o,s,a):null;let m="exterior";try{const v=Ps(e,t,i,r,o,s,a,d);m="paper";const y=v?v.shell?.length?It(v.centre,v.shell):v.centre:[],b=e=>{const t=$s(e.outset);if(!e.inset)return t;const i=$s(e.inset);return Nt(t,i)};m="room-rings";let w=null;for(const e of h)try{const t=b(e);w=w?It(w,t):t}catch{}if(m="edge-bodies",v)for(const n of Ws(e,t,i,r,o,s,a))try{const e=Ht($s(n.quad),v.centre);w=w?It(w,e):e}catch{}m="junctions",w=function(e,t,i=1,n=It){let r=e;for(const e of t||[]){const t=zs(e,i);if(t)try{const e=$s(t);r=r?n(r,e):e}catch{}}return r}(w,p,a),m="facade-clip",w&&v&&(w=Ht(w,v.centre)),m="exterior-shell";const k=[];let x=0;if(v?.shell?.length)if(w)try{const e=It(w,v.shell);if(!Ss(e))throw new Error("invalid shell union");w=e}catch{if(!Ss(w)||!Ss(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=Ds(w,{...d,nodes:t},v?.centre,y)}}if(m="junction-corners",d.nodes.length){const n=ps(d),l=function(e,t,i,n,r,o,s,a){try{const l=Ps(e,t,i,n,r,o,s,{epsilon:a.epsilon,coordinateScale:a.coordinateScale,nodes:[],index:new Map});return l?l.shell?.length?It(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=[$s(e)];if(l&&(t=Ht(t,l)),!t?.length)continue;w=w?It(w,t):t}catch{}f=w,g=Math.max(d.epsilon,1e-9)**2,w=Array.isArray(f)?f.map(e=>{if(!Array.isArray(e)||!e.length)return e;const[t,...i]=e;return Math.abs(Jo(t||[]))<=g?null:[t,...i.filter(e=>Math.abs(Jo(e||[]))>g)]}).filter(e=>!!e):f}const $=w||[],S=[...Ss($)?[{id:"room-primary",geom:$}]:[],...k.map((e,t)=>({id:`room-isolated-${t}`,geom:e.geom}))];m="openings";for(const e of n){if(!(e.length>0))continue;const t=Gs(_,e,!0);if(!t.negative&&!t.positive)continue;const i=e.angle*Math.PI/180,n=Math.cos(i),o=Math.sin(i),s=-o,l=n,c=e.length/2,h=1.25*Math.max(u,r*a),d=[[e.x-n*c-s*h,e.y-o*c-l*h],[e.x+n*c-s*h,e.y+o*c-l*h],[e.x+n*c+s*h,e.y+o*c+l*h],[e.x-n*c+s*h,e.y-o*c+l*h]];w&&(w=Nt(w,$s(d)));for(const e of k)e.geom=Nt(e.geom,$s(d))}m="extras";const M=[];let R=0;const T=c.mergeExtra||((e,t)=>e?It(e,t):t);for(let e=0;ee.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]))||Math.abs(bi(t))<=1e-9){R++;continue}const i=[$s(t)];try{const t=T(w,i,e);if(!Ss(t))throw new Error("invalid extra union");w=t}catch{R++,Ss(i)&&M.push({id:`extra-${e}`,geom:i})}}M.push(...k),M.sort((e,t)=>Es(e.geom).localeCompare(Es(t.geom)));const C=w||[];return{status:R||x?"degraded-extra":"ok",geom:C,components:[...Ss(C)?[{id:"primary",geom:C}]:[],...M.map((e,t)=>({...e,id:`isolated-${t}`}))],roomGeom:$,roomComponents:S,paperGeom:y,depthUnits:u,openingPadUnits:1.25*Math.max(u,r*a),openingIndex:_,multiWallNodes:d,degradedExtraCount:R+x}}catch{return c.onCoreFailure?.(m),{status:"failed-core",geom:[],components:[],roomGeom:[],paperGeom:[],roomComponents:[],depthUnits:u,openingIndex:null,multiWallNodes:d,degradedExtraCount:0}}var f,g}function Ls(e,t,i,n=[],r,o,s,a=1,l=[],c={}){if(!t?.length&&!l.length)return null;return qs(Ns(e,t,i,n,r,o,s,a,l,c))}function qs(e){if("failed-core"===e.status||"not-applicable"===e.status)return null;const t=e.components.map(e=>({id:e.id,d:Es(e.geom),fillRule:"evenodd"})).filter(e=>!!e.d),i=t[0]?.d||"",n=Es(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 Ws(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=So(t,i,n,s);if(a.has(p))continue;a.add(p);const _=yo(u,r,o),[m,f]=Qo(d,e),g=-m,v=-f,y=_/2,b=[[t[0]+g*y,t[1]+v*y],[i[0]+g*y,i[1]+v*y],[i[0]+m*y,i[1]+f*y],[t[0]+m*y,t[1]+f*y]];l.push({key:p,kind:c,cm:u,quad:b,a:[t[0],t[1]],b:[i[0],i[1]],depthUnits:_})}}return l}function js(e,t,i){const n=e?.length||0;if(n<3||t.length!==n)return null;if(t.every(e=>!(e>0)))return e.map(e=>[e[0],e[1]]);ss(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(es(w,k)){const t=e[o],i=[t[0]-c*a,t[1]-h*a],n=[t[0]-d*l,t[1]-u*l];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}const S=ts(x,w,$,k),M=Math.max(a,l,1e-9),R=_s(i,e[o])?.limit??4*M;if(S){const i=Math.hypot(S[0]-e[o][0],S[1]-e[o][1]);if(Number.isFinite(i)&&i<=R){r.push(S);continue}if(Hs(e,t,o)){r.push([e[o][0],e[o][1]]);continue}}a>0&&r.push([e[o][0]-c*a,e[o][1]-h*a]),l>0&&r.push([e[o][0]-d*l,e[o][1]-u*l])}return r.length>=3?r:null}function Bs(e,t,i,n,r,o,s=1){const a=[];for(const l of e||[]){if(!l?.id)continue;const c=fs(e,l.id,t,i,n,r,o,s);if(!c)continue;const h=Math.abs(bi(c.poly));for(let e=0;e[Math.max(t,e.x0),Math.min(i,e.x1)]).filter(e=>e[1]-e[0]>n).sort((e,t)=>e[0]-t[0]||e[1]-t[1]);if(!r.length)return{coverage:0,full:!1};let o=r[0][0],s=r[0][1],a=0,l=o<=t+n;for(let e=1;e=i-n,{coverage:a,full:l}}function Us(e,t){return Number(t.full)-Number(e.full)||e.faceDistance-t.faceDistance||e.area-t.area||e.roomId.localeCompare(t.roomId)}function Gs(e,t,i=!1){const n=Number(t?.x),r=Number(t?.y),o=Number(t?.angle),s=Number(t?.length);if(!([n,r,o,s].every(Number.isFinite)&&s>0))return{negative:null,positive:null};const a=o*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=-c,d=l,u=s/2,p=Math.max(1e-9,e.adjacencyEps),_=new Map;let m=0;for(const t of e.edges){if(i&&!(t.half>0))continue;if(!Po(t.a,t.b,o))continue;const[e,s]=xo(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,f=(t.b[0]-n)*l+(t.b[1]-r)*c,g=Math.max(-u,Math.min(a,f)),v=Math.min(u,Math.max(a,f));if(v-g<=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:g,x1:v,half:t.half,cm:t.cm,key:t.key,axis:[e,s]},$=_.get(k);$?($.pieces.push(x),$.faceDistance=Math.min($.faceDistance,w)):_.set(k,{roomId:t.roomId,side:y,order:m++,pieces:[x],faceDistance:w,area:t.area,coverage:0,full:!1})}for(const e of _.values()){const t=Vs(e.pieces,-u,u,p);e.coverage=t.coverage,e.full=t.full}const f=e=>{const t=[..._.values()].filter(t=>t.side===e&&t.coverage>p);return t.sort(Us),t[0]||null};return{negative:f(-1),positive:f(1)}}function Ks(e,t){const i=Gs(e,t),n=[i.negative,i.positive].filter(e=>!!e);if(!n.length)return{ox:0,oy:0,cm:0,side:-1};const r=i.negative&&i.positive?-1:n[0].side,o=t.flip_v?-r:r,s=(-1===o?i.negative:i.positive)||n[0],a=[...s.pieces].sort((e,t)=>(e.x0<=0&&e.x1>=0?0:Math.min(Math.abs(e.x0),Math.abs(e.x1)))-(t.x0<=0&&t.x1>=0?0:Math.min(Math.abs(t.x0),Math.abs(t.x1)))||t.x1-t.x0-(e.x1-e.x0)||e.key.localeCompare(t.key))[0];if(!(a.half>0&&a.cm>0))return{ox:0,oy:0,cm:0,side:o};const l=t.angle*Math.PI/180,c=-Math.sin(l),h=Math.cos(l);return{ox:c*o*a.half,oy:h*o*a.half,cm:a.cm,side:o}}function Ys(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 Zs(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),f=`${r.key}|${t}`,g=n.get(f)||[];let v=[[_,m]];for(const[e,t]of g){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(f,b)}return a}function Xs(e,t){const i=new Map;return t.map(t=>function(e,t,i){const n=Gs(e,t,!0),r=n.negative,o=n.positive;if(!r&&!o)return null;let s;if(r&&o)s=[{candidate:r,side:-1},{candidate:o,side:1}];else{const e=r||o;s=[{candidate:e,side:-1},{candidate:e,side:1}]}const a=s.map(({candidate:e,side:n})=>({candidate:e,side:n,pieces:Zs(t,n,e.pieces,i)})),l=a.map(({candidate:e,side:t,pieces:i})=>({side:t,roomId:e.roomId,d:Ys(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 Js=150,Qs=1e-6;function ea(e){return Number.isFinite(e)?Math.max(1,Math.min(Js,e)):1}function ta(e){return((Number.isFinite(Number(e))?Number(e):0)%90+90)%90}const ia=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]},na=(e,t)=>e[0]===t[0]&&e[1]===t[1];function ra(e,t=1e-6){const i=Number.isFinite(t)&&t>0?t:Qs,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&&na(n[n.length-1],a)||n.push(a)}return n.length>1&&na(n[0],n[n.length-1])&&n.pop(),n.length<3||new Set(n.map(e=>`${e[0]},${e[1]}`)).size<3?null:bi(n)>i*i?n:null}function oa(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 sa(e,t,i,n,r){return Wo({a:e,b:t,halfDepth:yo(i,n,r)/2})}function aa(e,t,i){const n=Number(t)>0?Number(t):5,r=ea(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=ta(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 la(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=[ia(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=Nt(n,ia(u))}return ya(n)}catch{return[e]}}function ha(e,t){try{const i=Nt([[...e.map(e=>[e[0],e[1]]),[e[0][0],e[0][1]]]],[[...t.map(e=>[e[0],e[1]]),[t[0][0],t[0][1]]]]);let n=null,r=0;for(const e of i||[]){const t=e?.[0]||[],i=Math.abs(bi(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=[],a=new Map;for(const e of r){const t=a.get(e.hostId)||[];t.push(e),a.set(e.hostId,t)}const l=[],c=[],h=[];for(const n of e.room_drafts||[])for(let e=0;e+10))continue;const a={a:n.points[e],b:n.points[e+1],halfDepth:s},c=Wo(a);c&&(o.push(a),l.push(c))}const d=[];for(const n of e.partitions||[]){const e={a:n.a,b:n.b,halfDepth:yo(n.cm,t,i)/2};if(!(e.halfDepth>0))continue;const r=Wo(e);r&&(s.push(e),c.push(r),d.push({id:n.id,body:r}))}const u=[...o,...s];for(const{segmentIndex:e,wedge:t}of Go(u,n)){const i=e=o.length&&(d[i.at].body=n))}for(const e of d)h.push(...ca(e.body,a.get(e.id)||[],n));const p=(e.wall_columns||[]).map(e=>aa(e,t,i)),_=Ko([...o,...s],n).flatMap(e=>ca(e,r,n));return{drafts:l,partitions:c,columns:p,patches:_,all:[...l,...h,..._,...p]}}function ua(e){try{const t=e.map(e=>ra(e)).filter(e=>!!e).map(e=>ia(e));return t.length?It(t[0],...t.slice(1)):null}catch{return null}}const pa=e=>`M ${e.map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`;function _a(e){const t=[];for(const i of e||[]){if(ga([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 ma(e,t,i={}){const n=ua(e.filter(e=>e.length>=3)),r=t.some(e=>!ra(e))?null:ua(t);if(!n)return[];if(r)try{return _a(Ht(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 ya(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 ba(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 wa(e,t,i){return function(e,t){for(const i of t||[]){const t=i?.[0];if(!t?.length||!ba(e,t))continue;let n=!1;for(let t=1;tba(e,t))}function ka(e,t,i){if(Math.hypot(e.center[0]-t.center[0],e.center[1]-t.center[1])>i)return!1;if(Math.abs(ea(e.cm)-ea(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(ta(e.angle)-ta(t.angle));return Math.min(n,90-n)<=1e-6}const xa=2.54;function $a(e){const t="number"==typeof e?e:NaN;return!Number.isFinite(t)||t<=0||5===t?1:5/t}function Sa(e,t){return e*$a(t)}function Ma(e){return e?xa:1}function Ra(e,t){if(!t)return String(e);const i=e/xa;return String(Math.round(1e6*i)/1e6)}function Ta(e,t){return t?e*xa:e}const Ca=1e3;function Da(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 za=.01,Aa=100;function Oa(e,t=1e3){const i=Da(e?.plan_aspect,t),n=Number(e?.plan_scale),r=Number.isFinite(n)&&n>0?Math.min(Aa,Math.max(za,n)):1,o=Number(e?.plan_scale_x),s=Number(e?.plan_scale_y),a=Number.isFinite(o)&&o>0?Math.min(Aa,Math.max(za,o)):r,l=Number.isFinite(s)&&s>0?Math.min(Aa,Math.max(za,s)):r,c=Number(e?.plan_x),h=Number(e?.plan_y),d=mr(e?.plan_angle);return{x:i.x+(Number.isFinite(c)?Ba(c):0)*t,y:i.y+(Number.isFinite(h)?Ba(h):0)*t,w:i.w*a,h:i.h*l,...d?{angle:d}:{}}}function Pa(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 Fa(e){return e&&Array.isArray(e.spaces)?e.spaces.map(e=>{const t=Ca,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]*Ca,i[1]*t,i[2]*Ca,i[3]*t],bg:e.plan_url?{href:Rn(e.plan_url),...Oa(e,Ca)}:null,rooms:(e.rooms||[]).map(e=>{const i={...e,...Pa(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*Ca:void 0,y:null!=i.y?i.y*t:void 0,w:null!=i.w?i.w*Ca:void 0,h:null!=i.h?i.h*t:void 0,poly:i.poly?i.poly.map(e=>[e[0]*Ca,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])*Ca,Number(e.a?.[1])*t],b:[Number(e.b?.[0])*Ca,Number(e.b?.[1])*t],cm:Number(e.cm)})),room_drafts:(e.room_drafts||[]).map(e=>({id:e.id,points:(e.points||[]).map(e=>[e[0]*Ca,e[1]*t]),segments:(e.segments||[]).map(e=>({..."string"==typeof e.id&&e.id?{id:e.id}:{},cm:Number(e.cm)}))})),partitions:(e.partitions||[]).map(e=>({id:e.id,a:[e.a[0]*Ca,e.a[1]*t],b:[e.b[0]*Ca,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]*Ca,e.center[1]*t],cm:Number(e.cm),..."circle"===e.shape?{}:{angle:ta(e.angle)}}))}}):[]}const Ea=5e3,Ia=Ea*Ca,Ha=240,Na=Ca/Ha,La=1/Ha;function qa(e){if(!Number.isFinite(e))return e;const t=Math.round(e*Ha/Ca)*Ca/Ha;return Math.abs(t-e)<=1e-9*Na?e:t}function Wa(e){return{x:qa(e.x),y:qa(e.y)}}function ja(e){return Number.isFinite(e)?Math.min(Ia,Math.max(-Ia,e)):0}function Ba(e){return Number.isFinite(e)?Math.min(Ea,Math.max(-Ea,e)):0}const Va=1/3,Ua=200;function Ga(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 Ka(e){return e.poly&&e.poly.length?Ga(e.poly):null==e.x||null==e.y?null:Ga([[e.x,e.y],[e.x+(e.w||0),e.y+(e.h||0)]])}function Ya(e,t){const i=[];for(const t of e.rooms||[]){const e=Ka(t);e&&i.push(e)}if(e.bg){const t=Ga(kr(e.bg));t&&i.push(t)}for(const e of t||[])if(Array.isArray(e)){const t=Ga([e]);t&&i.push(t)}else i.push(e);return i}const Za=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},Xa=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 Ja(e,t){let{x:i,y:n,w:r,h:o}=e;r<30&&(i=i+r/2-100,r=Ua),o<30&&(n=n+o/2-100,o=Ua);const s=Math.max(r,o)*t;return{x:i-s,y:n-s,w:r+2*s,h:o+2*s}}function Qa(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)<=Ia&&Math.abs(e.maxX)<=Ia&&Math.abs(e.minY)<=Ia&&Math.abs(e.maxY)<=Ia);if(!o.length)return{core:null,all:null,outliers:0};const s=Xa(o);if(o.length<4){const e=Ja(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=Za(a),h=Za(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*Va?o.filter((e,t)=>!p[t]):o;return{core:Ja(Xa(m)||s,i),all:Ja(s,i),outliers:m===o?0:_}}function el(e,t,i=.05){const n=Qa(Ya(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,Ca,Ca];return{x:r[0],y:r[1],w:r[2],h:r[3]}}function tl(e){const t=el(e);return{x:t.x+t.w/2,y:t.y+t.h/2}}function il(e){const t=[];for(const i of e.rooms||[]){const e=Ka(i);e&&t.push(e)}const i=Qa(t,{pad:0}).core,n=Ca*$a(e.cellCm??5);return i?Math.max(n,Math.min(Ia,Math.max(i.w,i.h))):n}function nl(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*il(t)*o/r}const rl=[1,2,5,10,20,50,100,200,500,1e3];function ol(e,t,i=7){if(!(e>0&&t>0&&Number.isFinite(t)))return null;const n=rl.find(n=>e*n*t>=i);if(void 0===n)return null;const r=rl.find(e=>e>=5*n)??5*n;return{fine:n,coarse:r}}function sl(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){const r=i["rl_"+(e.id||"")];if(r&&r.s===t)return{x:r.x*Ca,y:r.y*Ca};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 Wa({x:o[0],y:o[1]})}const ll=["furniture","appliance","sanitary","other"],cl=[{id:"sofa",group:"furniture",category:"sofa",w:220,h:90,g:[["r",0,0,1,1],["l",.09,.26,.91,.26],["l",.09,.26,.09,1],["l",.91,.26,.91,1],["l",.5,.26,.5,1]]},{id:"armchair",group:"furniture",category:"armchair",w:90,h:85,g:[["r",0,0,1,1],["l",.14,.28,.86,.28],["l",.14,.28,.14,1],["l",.86,.28,.86,1]]},{id:"coffee_table",group:"furniture",category:"coffee_table",w:110,h:60,g:[["r",0,0,1,1],["r",.08,.14,.84,.72]]},{id:"table_dining",group:"furniture",category:"dining_table",w:140,h:80,g:[["r",0,0,1,1],["r",.06,.11,.88,.78]]},{id:"table_round",group:"furniture",category:"dining_table",w:120,h:120,g:[["e",.5,.5,.5,.5],["e",.5,.5,.41,.41]]},{id:"chair",group:"furniture",category:"chair",w:45,h:45,g:[["r",0,0,1,.18],["r",.06,.18,.88,.8]]},{id:"desk",group:"furniture",category:"work_table",w:120,h:60,g:[["r",0,0,1,1],["r",.63,.07,.31,.86],["l",.63,.5,.94,.5]]},{id:"bed_double",group:"furniture",category:"bed",w:160,h:200,g:[["r",0,0,1,1],["r",0,0,1,.07],["r",.06,.1,.4,.15],["r",.54,.1,.4,.15],["l",0,.33,1,.33]]},{id:"bed_single",group:"furniture",category:"bed",w:90,h:200,g:[["r",0,0,1,1],["r",0,0,1,.07],["r",.15,.1,.7,.15],["l",0,.33,1,.33]]},{id:"nightstand",group:"furniture",category:"nightstand",w:45,h:40,g:[["r",0,0,1,1],["r",.12,.14,.76,.33],["r",.12,.53,.76,.33]]},{id:"wardrobe",group:"furniture",category:"wardrobe",w:100,h:60,g:[["r",0,0,1,1],["l",0,.72,1,.72],["l",.5,.72,.5,1]]},{id:"bookshelf",group:"furniture",category:"wardrobe",w:80,h:30,g:[["r",0,0,1,1],["l",.34,0,.34,1],["l",.67,0,.67,1]]},{id:"fridge",group:"appliance",category:"fridge",w:60,h:65,g:[["r",0,0,1,1],["l",0,.36,1,.36],["l",.83,.44,.83,.64]]},{id:"stove",group:"appliance",category:"cooktop",w:60,h:60,g:[["r",0,0,1,1],["e",.29,.31,.15,.15],["e",.71,.31,.15,.15],["e",.29,.71,.15,.15],["e",.71,.71,.15,.15]]},{id:"dishwasher",group:"appliance",category:"dishwasher",w:60,h:60,g:[["r",0,0,1,1],["r",.1,.12,.8,.76],["e",.5,.5,.27,.27],["e",.5,.5,.13,.13]]},{id:"washer",group:"appliance",category:"washer",w:60,h:60,g:[["r",0,0,1,1],["l",.08,.17,.92,.17],["e",.5,.57,.3,.3],["e",.5,.57,.14,.14]]},{id:"dryer",group:"appliance",category:"dryer",w:60,h:60,g:[["r",0,0,1,1],["l",.08,.17,.92,.17],["e",.5,.57,.3,.3],["p",.36,.5,.5,.64,.64,.5]]},{id:"tv",group:"appliance",category:"tv",w:120,h:30,g:[["r",0,0,1,.42],["l",.5,.42,.5,.72],["l",.3,.72,.7,.72]]},{id:"ac",group:"appliance",category:"air_conditioner",w:90,h:25,g:[["r",0,0,1,1],["l",.05,.55,.95,.55],["l",.05,.79,.95,.79]]},{id:"water_heater",group:"appliance",category:"boiler",w:45,h:45,g:[["e",.5,.5,.5,.5],["e",.5,.5,.31,.31]]},{id:"toilet",group:"sanitary",category:"toilet",w:40,h:70,g:[["r",.06,0,.88,.2],["e",.5,.58,.37,.35],["e",.5,.58,.22,.2]]},{id:"bathtub",group:"sanitary",category:"bathtub",w:170,h:75,g:[["r",0,0,1,1],["r",.05,.11,.77,.78],["e",.89,.5,.045,.1]]},{id:"shower",group:"sanitary",category:"shower",w:90,h:90,g:[["r",0,0,1,1],["l",0,0,1,1],["l",1,0,0,1],["e",.5,.5,.08,.08]]},{id:"sink",group:"sanitary",category:"sink",w:60,h:45,g:[["r",0,0,1,1],["e",.5,.6,.34,.3],["e",.5,.15,.07,.07]]},{id:"kitchen_sink",group:"sanitary",category:"kitchen_sink",w:80,h:60,g:[["r",0,0,1,1],["r",.06,.24,.44,.64],["r",.54,.24,.4,.64],["e",.5,.12,.06,.06]]},{id:"bidet",group:"sanitary",category:"bidet",w:40,h:55,g:[["e",.5,.5,.44,.5],["e",.5,.5,.26,.3]]},{id:"stairs",group:"other",category:"stairs",w:100,h:280,g:[["r",0,0,1,1],["l",0,.111,1,.111],["l",0,.222,1,.222],["l",0,.333,1,.333],["l",0,.444,1,.444],["l",0,.556,1,.556],["l",0,.667,1,.667],["l",0,.778,1,.778],["l",0,.889,1,.889],["l",.5,.93,.5,.06],["p",.38,.16,.5,.06,.62,.16]]},{id:"fireplace",group:"other",category:"fireplace",w:120,h:40,g:[["r",0,0,1,1],["p",.22,1,.22,.42,.78,.42,.78,1]]},{id:"plant",group:"other",category:"plant",w:40,h:40,g:[["e",.5,.5,.22,.22],["l",.5,.28,.5,.02],["l",.5,.72,.5,.98],["l",.28,.5,.02,.5],["l",.72,.5,.98,.5],["l",.34,.34,.13,.13],["l",.66,.66,.87,.87],["l",.66,.34,.87,.13],["l",.34,.66,.13,.87]]},{id:"rug",group:"other",category:"rug",w:200,h:140,g:[["r",0,0,1,1],["r",.06,.09,.88,.82]]}],hl=new Set(["fridge","dishwasher","washer","dryer","ac","water_heater","shower","sink","stairs","fireplace","plant","rug"]),dl=[...[{id:"coffee_table",group:"furniture",category:"coffee_table",w:120,h:60,art:{d:"M3.84 5.884c0-1.21 1.048-2.192 2.34-2.192h107.64c1.293 0 2.34.981 2.34 2.192v48.23c0 1.212-1.047 2.193-2.34 2.193H6.18c-1.292 0-2.34-.981-2.34-2.192z M103.056 15.093V9.83a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877m0 35.078v-5.262a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877m-93.6-35.077V9.83a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877m0 35.078v-5.262a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877",viewW:120,viewH:60}},{id:"coffee_table_round",group:"furniture",category:"coffee_table",w:80,h:80,art:{d:"M3.765 40a36.235 36.235 0 1 0 72.47 0 36.235 36.235 0 1 0-72.47 0 m56.26 26.96-3.843-3.843a.906.906 0 0 1 0-1.28l3.843-3.844a.906.906 0 0 1 1.281 0l3.844 3.843a.906.906 0 0 1 0 1.281l-3.844 3.844a.906.906 0 0 1-1.28 0m-.001 34.66-3.843-3.843a.906.906 0 0 1 0-1.281l3.843-3.844a.906.906 0 0 1 1.281 0l3.843 3.844a.906.906 0 0 1 0 1.28l-3.843 3.844a.906.906 0 0 1-1.281 0m-34.423-34.66-3.843-3.843a.906.906 0 0 1 0-1.281l3.843-3.844a.906.906 0 0 1 1.281 0l3.844 3.844a.906.906 0 0 1 0 1.28l-3.844 3.844a.906.906 0 0 1-1.28 0m-.001 34.66-3.843-3.843a.906.906 0 0 1 0-1.281l3.843-3.843a.906.906 0 0 1 1.281 0l3.844 3.843a.906.906 0 0 1 0 1.281l-3.844 3.843a.906.906 0 0 1-1.28 0",viewW:80,viewH:80}},{id:"coffee_table_oval",group:"furniture",category:"coffee_table",w:120,h:60,art:{d:"M3.84 30c0-14.53 12.572-26.308 28.08-26.308h56.16c15.509 0 28.08 11.778 28.08 26.308s-12.571 26.307-28.08 26.307H31.92C16.412 56.307 3.84 44.53 3.84 30 M80.592 15.093V9.83a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877m0 35.077v-5.262a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877M31.92 15.093V9.83a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.876h-5.616a.936.877 0 0 1-.936-.876m0 35.077v-5.262a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.876h-5.616a.936.877 0 0 1-.936-.876",viewW:120,viewH:60}},{id:"coffee_table_rounded",group:"furniture",category:"coffee_table",w:120,h:60,art:{d:"M3.84 12.461c0-4.843 4.19-8.77 9.36-8.77h93.6c5.17 0 9.36 3.927 9.36 8.77v35.077c0 4.843-4.19 8.77-9.36 8.77H13.2c-5.17 0-9.36-3.927-9.36-8.77z M103.056 15.093V9.83a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877m0 35.078v-5.262a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877m-93.6-35.077V9.83a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877m0 35.078v-5.262a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877",viewW:120,viewH:60}},{id:"table_dining",group:"furniture",category:"dining_table",w:160,h:90,art:{d:"M3.879 6.08c0-1.265 1.065-2.29 2.378-2.29h147.484c1.314 0 2.38 1.025 2.38 2.29v77.84c0 1.265-1.066 2.29-2.38 2.29H6.257c-1.313 0-2.378-1.025-2.378-2.29z M138.994 19.358v-5.495a.952.916 0 0 1 .951-.915h5.71a.952.916 0 0 1 .95.915v5.495a.952.916 0 0 1-.95.916h-5.71a.952.916 0 0 1-.951-.916m-.001 56.778v-5.495a.952.916 0 0 1 .952-.915h5.709a.952.916 0 0 1 .951.915v5.495a.952.916 0 0 1-.951.916h-5.71a.952.916 0 0 1-.95-.916m-125.6-56.778v-5.495a.952.916 0 0 1 .951-.916h5.71a.952.916 0 0 1 .95.916v5.495a.952.916 0 0 1-.95.915h-5.71a.952.916 0 0 1-.951-.915m-.001 56.779v-5.495a.952.916 0 0 1 .952-.916h5.709a.952.916 0 0 1 .951.916v5.495a.952.916 0 0 1-.951.915h-5.71a.952.916 0 0 1-.95-.915",viewW:160,viewH:90}},{id:"table_round",group:"furniture",category:"dining_table",w:110,h:110,art:{d:"M3.826 55a51.174 51.174 0 1 0 102.349 0A51.174 51.174 0 1 0 3.826 55 m81.005 32.303-3.947-3.947a.93.93 0 0 1 0-1.316l3.947-3.948a.93.93 0 0 1 1.316 0l3.948 3.948a.93.93 0 0 1 0 1.316l-3.948 3.947a.93.93 0 0 1-1.316 0m0 54.897-3.947-3.948a.93.93 0 0 1 0-1.316l3.947-3.947a.93.93 0 0 1 1.316 0l3.948 3.947a.93.93 0 0 1 0 1.316L82.32 87.2a.93.93 0 0 1-1.316 0M27.04 32.304l-3.947-3.948a.93.93 0 0 1 0-1.315l3.948-3.948a.93.93 0 0 1 1.315 0l3.948 3.948a.93.93 0 0 1 0 1.315l-3.948 3.948a.93.93 0 0 1-1.315 0m-.001 54.604-3.947-3.948a.93.93 0 0 1 0-1.316l3.948-3.947a.93.93 0 0 1 1.315 0l3.948 3.947a.93.93 0 0 1 0 1.316l-3.948 3.948a.93.93 0 0 1-1.315 0",viewW:110,viewH:110}},{id:"table_dining_oval",group:"furniture",category:"dining_table",w:180,h:100,art:{d:"M3.892 50c0-25.51 21.418-46.19 47.838-46.19h76.54c26.42 0 47.839 20.68 47.839 46.19S154.69 96.19 128.27 96.19H51.73C25.31 96.19 3.892 75.51 3.892 50 M122.53 19.514V13.97a.957.924 0 0 1 .956-.924h5.74a.957.924 0 0 1 .958.924v5.543a.957.924 0 0 1-.957.924h-5.74a.957.924 0 0 1-.958-.924m.001 66.516v-5.543a.957.924 0 0 1 .957-.924h5.74a.957.924 0 0 1 .957.924v5.543a.957.924 0 0 1-.957.924h-5.74a.957.924 0 0 1-.957-.924M49.816 19.515v-5.543a.957.924 0 0 1 .957-.924h5.74a.957.924 0 0 1 .958.924v5.542a.957.924 0 0 1-.957.924h-5.74a.957.924 0 0 1-.958-.924m0 66.516v-5.543a.957.924 0 0 1 .957-.924h5.74a.957.924 0 0 1 .957.924v5.543a.957.924 0 0 1-.957.923h-5.74a.957.924 0 0 1-.957-.924",viewW:180,viewH:100}},{id:"table_dining_rounded",group:"furniture",category:"dining_table",w:160,h:90,art:{d:"M3.879 17.527c0-7.587 6.39-13.737 14.272-13.737h123.696c7.883 0 14.273 6.15 14.273 13.737v54.947c0 7.587-6.39 13.737-14.273 13.737H18.151c-7.882 0-14.272-6.15-14.272-13.737z M138.994 19.358v-5.495a.952.916 0 0 1 .951-.915h5.71a.952.916 0 0 1 .95.915v5.495a.952.916 0 0 1-.95.916h-5.71a.952.916 0 0 1-.951-.916m-.001 56.778v-5.495a.952.916 0 0 1 .952-.915h5.709a.952.916 0 0 1 .951.915v5.495a.952.916 0 0 1-.951.916h-5.71a.952.916 0 0 1-.95-.916m-125.6-56.778v-5.495a.952.916 0 0 1 .951-.916h5.71a.952.916 0 0 1 .95.916v5.495a.952.916 0 0 1-.95.915h-5.71a.952.916 0 0 1-.951-.915m-.001 56.779v-5.495a.952.916 0 0 1 .952-.916h5.709a.952.916 0 0 1 .951.916v5.495a.952.916 0 0 1-.951.915h-5.71a.952.916 0 0 1-.95-.915",viewW:160,viewH:90}},{id:"desk",group:"furniture",category:"work_table",w:140,h:70,art:{d:"M3.862 5.967c0-1.234 1.057-2.234 2.362-2.234h127.552c1.305 0 2.362 1 2.362 2.234v58.066c0 1.234-1.057 2.233-2.362 2.233H6.224c-1.305 0-2.362-1-2.362-2.233z M9.531 15.346v-5.36a.945.893 0 0 1 .945-.893h5.67a.945.893 0 0 1 .944.893v5.36a.945.893 0 0 1-.945.894h-5.669a.945.893 0 0 1-.945-.894m113.379.001v-5.36a.945.893 0 0 1 .945-.894h5.67a.945.893 0 0 1 .944.894v5.36a.945.893 0 0 1-.945.893h-5.669a.945.893 0 0 1-.945-.893M9.53 60.013v-5.36a.945.893 0 0 1 .946-.893h5.669a.945.893 0 0 1 .945.893v5.36a.945.893 0 0 1-.945.894h-5.67a.945.893 0 0 1-.944-.894m113.38.001v-5.36a.945.893 0 0 1 .945-.894h5.669a.945.893 0 0 1 .945.894v5.36a.945.893 0 0 1-.945.893h-5.67a.945.893 0 0 1-.944-.893m-97.318-2.681h88.814",viewW:140,viewH:70}},{id:"desk_corner",group:"furniture",category:"work_table",w:160,h:160,art:{d:"M156.12 66.202a2.38 2.38 0 0 1-2.379 2.38H94.272c-13.138 0-23.788 10.65-23.788 23.787v61.372a2.38 2.38 0 0 1-2.379 2.38H6.257a2.38 2.38 0 0 1-2.378-2.38V6.257A2.38 2.38 0 0 1 6.257 3.88h147.484a2.38 2.38 0 0 1 2.38 2.378z M9.588 16.249v-5.71a.95.95 0 0 1 .951-.95h5.71a.95.95 0 0 1 .95.95v5.71a.95.95 0 0 1-.95.951h-5.71a.95.95 0 0 1-.951-.951m133.212.001v-5.71a.95.95 0 0 1 .951-.951h5.71a.95.95 0 0 1 .95.951v5.71a.95.95 0 0 1-.95.951h-5.71a.95.95 0 0 1-.951-.951m0 45.672v-5.71a.95.95 0 0 1 .952-.951h5.709a.95.95 0 0 1 .951.951v5.71a.95.95 0 0 1-.951.951h-5.71a.95.95 0 0 1-.95-.951M9.587 149.46v-5.708a.95.95 0 0 1 .952-.952h5.709a.95.95 0 0 1 .951.952v5.709a.95.95 0 0 1-.951.951h-5.71a.95.95 0 0 1-.951-.951m47.576 0v-5.709a.95.95 0 0 1 .952-.951h5.709a.95.95 0 0 1 .951.951v5.71a.95.95 0 0 1-.951.95h-5.71a.95.95 0 0 1-.951-.95m51.382-90.396H95.569a34.6 34.6 0 0 0-34.6 34.6v12.976",viewW:160,viewH:160}},{id:"chair",group:"furniture",category:"chair",w:50,h:50,art:{d:"M39.452 12.433H10.548a4.398 4.398 0 1 1 0-8.796h28.904a4.398 4.398 0 0 1 0 8.796m-28.904 0H8.035a4.4 4.4 0 0 0-4.398 4.399V40.08a6.283 6.283 0 0 0 6.283 6.284h30.16a6.283 6.283 0 0 0 6.284-6.284V16.832c0-2.43-1.97-4.399-4.399-4.399h-2.513",viewW:50,viewH:50}},{id:"chair_bar",group:"furniture",category:"chair",w:45,h:48,art:{d:"M38.579 17.168c1.326 2.526 1.947 6.015 1.947 9.071 0 10.018-8.07 18.139-18.025 18.139S4.475 36.257 4.475 26.239c0-3.056.586-6.552 1.912-9.078m32.192.007a3.59 3.59 0 0 1-3.333-.976m3.333.976a3.6 3.6 0 0 0 1.765-.976m-33.827.996-.13-.027a3.6 3.6 0 0 1-1.731-.969m30.59 0a18 18 0 0 0-5.848-3.932 17.93 17.93 0 0 0-13.796 0 18 18 0 0 0-5.848 3.932 3.59 3.59 0 0 1-3.237.996m28.729-.996a3.59 3.59 0 0 0 5.098 0m-33.827.996a3.6 3.6 0 0 1-1.861-.996 3.644 3.644 0 0 1 0-5.13 25.2 25.2 0 0 1 8.187-5.505A25.1 25.1 0 0 1 22.5 3.623a25.1 25.1 0 0 1 9.657 1.934 25.2 25.2 0 0 1 8.187 5.505 3.644 3.644 0 0 1 0 5.13",viewW:45,viewH:48}},{id:"armchair",group:"furniture",category:"armchair",w:90,h:90,art:{d:"M75.702 13.011q.012-.225.012-.453c0-4.843-3.917-8.768-8.748-8.768H23.034c-4.83 0-8.747 3.925-8.747 8.768q0 .228.011.453M77.132 72.09q.59.091 1.206.092c4.348 0 7.873-3.533 7.873-7.892V20.45c0-4.359-3.525-7.892-7.873-7.892-.924 0-1.812.16-2.636.453a7.89 7.89 0 0 0-5.237 7.438v.148m0 0a8.7 8.7 0 0 1-3.499.73H23.034a8.7 8.7 0 0 1-3.499-.73m50.93 0V64.29a7.89 7.89 0 0 0 6.667 7.8M14.298 13.01a7.89 7.89 0 0 1 5.237 7.438v.148m0 0V64.29a7.89 7.89 0 0 1-6.666 7.8q-.59.091-1.206.092c-4.348 0-7.873-3.533-7.873-7.892V20.45c0-4.359 3.525-7.892 7.873-7.892.924 0 1.811.16 2.635.453M77.132 72.09c-1.585 8.05-8.667 14.12-17.164 14.12H30.032c-8.496 0-15.578-6.07-17.163-14.12",viewW:90,viewH:90}},{id:"armchair_office",group:"furniture",category:"armchair",w:65,h:65,art:{d:"M56.968 18.845q0-.368-.05-.72M49.051 13.8H15.95a5.04 5.04 0 0 1-5.038-5.043 5.04 5.04 0 0 1 5.038-5.043h33.103a5.04 5.04 0 0 1 5.038 5.043 5.04 5.04 0 0 1-5.038 5.043m-33.103 0h-2.88a5.04 5.04 0 0 0-4.986 4.323M49.052 13.8h2.879a5.04 5.04 0 0 1 4.986 4.324m.051 24.826a4.32 4.32 0 0 0 4.318-4.323v-16.18a4.32 4.32 0 0 0-4.369-4.322m.051 24.826a4.32 4.32 0 0 1-4.318-4.323V22.447a4.32 4.32 0 0 1 4.267-4.322m-11.84 37.24h4.695c.736 0 1.446-.111 2.115-.317a7.21 7.21 0 0 0 5.081-6.889v-5.208M8.084 18.124h-.051a4.32 4.32 0 0 0-4.318 4.323v16.18a4.32 4.32 0 0 0 4.318 4.324 4.32 4.32 0 0 0 4.317-4.323V22.447a4.32 4.32 0 0 0-4.266-4.323m11.935 37.24h-4.79a7.2 7.2 0 0 1-2.04-.294 7.21 7.21 0 0 1-5.156-6.91v-5.21m37.045 12.414 5.177 5.183c.969.97 2.534.987 3.524.038a2.526 2.526 0 0 0 .038-3.605l-1.93-1.932m-6.81.316H20.02m-6.83-.294-1.909 1.91c-.998 1-.98 2.627.038 3.605.99.949 2.555.932 3.524-.038l5.177-5.183",viewW:65,viewH:65}},{id:"sofa",group:"furniture",category:"sofa",w:180,h:90,art:{d:"M90 19.365v57.111m0-57.11V7.683m0 11.681c0 2.151-1.836 3.894-4.1 3.894H30.544a10.7 10.7 0 0 1-4.136-.825M90 19.365c0 2.151 1.836 3.894 4.1 3.894h55.356c1.472 0 2.871-.294 4.137-.825M90 76.476c0 5.376-4.59 9.735-10.25 9.735H30.543c-5.266 0-9.605-3.772-10.185-8.625M90 76.476c0 5.376 4.59 9.735 10.25 9.735h49.206c5.266 0 9.605-3.772 10.185-8.625M90 7.684c0-2.15-1.837-3.894-4.101-3.894H30.544c-5.661 0-10.25 4.358-10.25 9.735q0 .416.036.825M90 7.684c0-2.15 1.836-3.894 4.1-3.894h55.356c5.661 0 10.25 4.358 10.25 9.735q0 .416-.036.825m0 0a10.7 10.7 0 0 1 4.137-.825h2.05c5.662 0 10.252 4.358 10.252 9.734v45.43c0 5.376-4.59 9.734-10.251 9.734h-2.05c-1.484 0-2.894-.3-4.167-.837m0 0c-3.585-1.517-6.084-4.93-6.084-8.898V23.26q0-.417.036-.825c.32-3.622 2.728-6.68 6.077-8.084m-139.34 0c3.35 1.404 5.758 4.462 6.078 8.084q.036.408.036.825v45.43c0 3.967-2.5 7.38-6.085 8.897a10.7 10.7 0 0 1-4.166.837h-2.05c-5.662 0-10.251-4.358-10.251-9.735V23.26c0-5.376 4.59-9.734 10.25-9.734h2.05c1.473 0 2.872.294 4.138.825",viewW:180,viewH:90}},{id:"sofa_three_seat",group:"furniture",category:"sofa",w:240,h:90,art:{d:"M86.553 18.593V76.96m0-58.366V7.491m0 11.102c0 2.044-1.762 3.701-3.935 3.701H29.496c-1.413 0-2.756-.28-3.97-.784m61.027-2.917c0 2.044 1.762 3.701 3.935 3.701h59.024c2.174 0 3.935-1.657 3.935-3.7M86.553 76.958c0 5.11-4.404 9.252-9.837 9.252h-47.22c-5.054 0-9.218-3.585-9.775-8.198m66.832-1.054c0 5.11 4.404 9.252 9.837 9.252h47.22c5.433 0 9.837-4.142 9.837-9.252m0-58.366V76.96m0-58.366V7.491m0 11.102c0 2.044 1.762 3.701 3.936 3.701h53.122c1.413 0 2.756-.28 3.97-.784m-61.028 55.449c0 5.11 4.405 9.252 9.838 9.252h47.22c5.054 0 9.218-3.585 9.775-8.198M86.553 7.491c0-2.044-1.762-3.701-3.935-3.701H29.496c-5.433 0-9.838 4.142-9.838 9.252q0 .396.035.784m66.86-6.335c0-2.044 1.762-3.701 3.935-3.701h59.024c2.174 0 3.935 1.657 3.935 3.7m0 0c0-2.043 1.762-3.7 3.936-3.7h53.122c5.433 0 9.838 4.142 9.838 9.252 0 .258.022.517 0 .77m-.063 64.201c1.22.512 2.574.796 3.998.796h1.967c5.433 0 9.837-4.142 9.837-9.252V22.294c0-5.11-4.404-9.252-9.837-9.252h-1.967c-5.153 0-9.38 3.725-9.803 8.468q-.036.387-.035.784v47.263c0 3.771 2.399 7.015 5.84 8.456M19.693 13.826a10.3 10.3 0 0 0-3.97-.784h-1.967c-5.433 0-9.838 4.142-9.838 9.252v47.263c0 5.11 4.405 9.252 9.838 9.252h1.967c1.424 0 2.777-.284 3.998-.796 3.441-1.441 5.84-4.685 5.84-8.456V22.294a9 9 0 0 0-.035-.784c-.307-3.443-2.618-6.349-5.833-7.684",viewW:240,viewH:90}},{id:"sofa_corner_right",group:"furniture",category:"sofa",w:260,h:170,art:{d:"M93.673 20.687V83.69m0-63.004v-12.6m0 12.6c0 2.32-1.913 4.2-4.273 4.2H31.704a10.8 10.8 0 0 1-4.311-.89m66.28-3.31c0 2.32 1.914 4.2 4.274 4.2h64.106c2.36 0 4.274-1.88 4.274-4.2M93.673 83.692c0 5.8-4.783 10.501-10.684 10.501H31.704c-5.489 0-10.011-4.068-10.616-9.304m72.585-1.197c0 5.8 4.784 10.501 10.684 10.501h51.286c5.9 0 10.684-4.701 10.684-10.5m0-63.005V83.69m0-63.004v-12.6m0 12.6c0 2.32 1.914 4.2 4.273 4.2h57.696c1.534 0 2.993-.317 4.312-.89m-66.28 59.695v71.923c0 5.799 4.782 10.5 10.684 10.5h51.284c5.49 0 10.012-4.068 10.616-9.304V84.888M93.673 8.086c0-2.32-1.913-4.2-4.273-4.2H31.704c-5.9 0-10.684 4.7-10.684 10.5q0 .45.038.89m72.615-7.19c0-2.32 1.914-4.2 4.274-4.2h64.106c2.36 0 4.274 1.88 4.274 4.2m0 0c0-2.32 1.914-4.2 4.273-4.2h57.696c5.9 0 10.685 4.7 10.685 10.5 0 .293.024.587 0 .874m-.07 69.628c1.327.58 2.797.904 4.344.904h2.136c5.901 0 10.684-4.702 10.684-10.501V24.887c0-5.8-4.783-10.5-10.684-10.5h-2.136c-5.596 0-10.187 4.227-10.647 9.61q-.038.44-.038.89V75.29c0 4.28 2.605 7.961 6.342 9.597M21.059 15.276a10.8 10.8 0 0 0-4.312-.89H14.61c-5.9 0-10.684 4.701-10.684 10.5v50.405c0 5.8 4.783 10.5 10.684 10.5h2.137c1.546 0 3.016-.322 4.342-.903 3.737-1.636 6.342-5.317 6.342-9.597V24.887q0-.45-.037-.89c-.334-3.907-2.844-7.206-6.335-8.72",viewW:260,viewH:170}},{id:"bed_single",group:"furniture",category:"bed",w:90,h:200,art:{d:"M3.79 14.024c0 5.59 4.318 10.122 9.645 10.122h63.13c5.328 0 9.646-4.532 9.646-10.122m-22.797 46.93V46.23c0-5.082-3.926-9.201-8.769-9.201h-19.29c-4.842 0-8.768 4.12-8.768 9.201v14.723m-22.797 0h82.42m0 22.085H3.79m8.768 113.06h64.885c4.842 0 8.768-4.12 8.768-9.202V13.104c0-5.082-3.926-9.202-8.768-9.202H12.558c-4.843 0-8.768 4.12-8.768 9.202v173.792c0 5.082 3.925 9.202 8.768 9.202",viewW:90,viewH:200}},{id:"bed_double",group:"furniture",category:"bed",w:160,h:200,art:{d:"M3.879 14.073c0 5.618 4.516 10.172 10.088 10.172h132.065c5.571 0 10.088-4.554 10.088-10.172m-81.165 47.16V46.438c0-5.107-4.106-9.247-9.171-9.247H45.607c-5.065 0-9.17 4.14-9.17 9.247v14.795m89.877 0V46.438c0-5.107-4.107-9.247-9.172-9.247H96.966c-5.065 0-9.171 4.14-9.171 9.247v14.795m-83.916 0H156.12m0 22.192H3.88m9.17 112.673h133.9c5.065 0 9.171-4.14 9.171-9.247V13.15c0-5.107-4.106-9.247-9.171-9.247H13.05c-5.064 0-9.17 4.14-9.17 9.247v173.7c0 5.107 4.106 9.247 9.17 9.247",viewW:160,viewH:200}},{id:"nightstand",group:"furniture",category:"nightstand",w:50,h:40,art:{d:"M5.773 3.555h38.454a2.136 2.056 0 0 1 2.137 2.056v28.777a2.136 2.056 0 0 1-2.137 2.056H5.773a2.136 2.056 0 0 1-2.136-2.056V5.611a2.136 2.056 0 0 1 2.136-2.056",viewW:50,viewH:40}},{id:"cabinet_tv",group:"furniture",category:"nightstand",w:140,h:45,art:{d:"M56.772 17.88h5.315m0 0h5.315m-5.315 0v9.214m9.832-9.214 5.315 9.45 5.314-9.45M6.224 41.4h127.552c1.305 0 2.362-.94 2.362-2.1V5.7c0-1.16-1.057-2.1-2.362-2.1H6.224c-1.305 0-2.362.94-2.362 2.1v33.6c0 1.16 1.057 2.1 2.362 2.1",viewW:140,viewH:45}},{id:"cabinet_shoe",group:"furniture",category:"nightstand",w:80,h:35,art:{d:"m39.722 16.231 1.505-1.596m1.134 3.15 1.53-1.738M6.03 31.5h67.94c1.251 0 2.265-.895 2.265-2v-24c0-1.105-1.014-2-2.264-2H6.03c-1.251 0-2.265.895-2.265 2v24c0 1.105 1.014 2 2.265 2m41.966-14.305L46.92 17.1a3.4 3.4 0 0 1-1.813-.706l-4.583-3.62c-1.264-1-3.277-.326-3.475 1.161-.185 1.39-1.983 2.1-3.28 1.299l-1.532-.947c-.968-.513-2.2.103-2.2 1.1v3.463c0 1.559 1.43 2.823 3.196 2.823h14.51c1.404 0 2.542-1.005 2.542-2.245 0-1.153-.99-2.118-2.289-2.233",viewW:80,viewH:35}},{id:"cabinet_sink",group:"furniture",category:"nightstand",w:80,h:50,art:{d:"M3.765 5.773c0-1.18 1.014-2.136 2.265-2.136h67.94c1.251 0 2.265.956 2.265 2.136v38.454c0 1.18-1.014 2.137-2.264 2.137H6.03c-1.251 0-2.265-.957-2.265-2.137z M36.088 32.135c2.525 1.88 6.205 1.88 8.73 0s3.167-5.101 1.52-7.637l-5.879-8.043-5.893 8.043c-1.644 2.536-1.003 5.755 1.522 7.637",viewW:80,viewH:50}},{id:"bookshelf",group:"furniture",category:"wardrobe",w:100,h:35,art:{d:"M57.12 20.488H45.473c-.514 0-1.008.124-1.372.345s-.568.52-.568.832m4.076-8.236h5.434M6.119 3.5h87.762c1.276 0 2.31.895 2.31 2v24c0 1.105-1.034 2-2.31 2H6.12c-1.275 0-2.31-.895-2.31-2v-24c0-1.105 1.035-2 2.31-2m51 6.4v14.118H45.474a2.04 2.04 0 0 1-1.372-.517 1.7 1.7 0 0 1-.568-1.248V11.665c0-.468.204-.917.568-1.248a2.04 2.04 0 0 1 1.372-.517z",viewW:100,viewH:35}},{id:"wall_unit",group:"furniture",category:"wardrobe",w:240,h:45,art:{d:"M6.336 41.4h227.328a2.418 2.1 0 0 0 2.418-2.1V5.7a2.418 2.1 0 0 0-2.418-2.1H6.336a2.418 2.1 0 0 0-2.418 2.1v33.6a2.418 2.1 0 0 0 2.418 2.1m43.744-5.88V9.48m46.432 26.04V9.48m46.433 26.04V9.48m46.433 26.04V9.48",viewW:240,viewH:45}},{id:"wardrobe",group:"furniture",category:"wardrobe",w:180,h:60,art:{d:"M93.87 20.25a3.3 3.3 0 0 0-1.072-2.407 3.8 3.8 0 0 0-2.586-.997c-.97 0-1.9.358-2.587.997a3.3 3.3 0 0 0-1.071 2.407c0 2.838 1.225 5.107 3.658 6.81h-.015m0 0 14.58 7.537c.57.295 1.046.726 1.377 1.25.331.523.505 1.12.505 1.727v1.401a3.3 3.3 0 0 1-1.071 2.407 3.8 3.8 0 0 1-2.587.998H77.393a3.8 3.8 0 0 1-2.586-.998 3.3 3.3 0 0 1-1.072-2.407v-1.4c0-.608.174-1.205.505-1.728a3.55 3.55 0 0 1 1.377-1.25zM6.284 3.691h167.433c1.32 0 2.392.981 2.392 2.192v48.23c0 1.212-1.071 2.193-2.392 2.193H6.284c-1.321 0-2.392-.981-2.392-2.192V5.885c0-1.212 1.07-2.193 2.392-2.193",viewW:180,viewH:60}},{id:"kitchen_floor",group:"furniture",category:"kitchen_cabinet",w:60,h:60,art:{d:"M3.692 5.884c0-1.21.981-2.192 2.192-2.192h48.23c1.212 0 2.193.981 2.193 2.192v48.23a2.19 2.19 0 0 1-2.192 2.193H5.885a2.19 2.19 0 0 1-2.193-2.192z",viewW:60,viewH:60}},{id:"kitchen_floor_corner",group:"furniture",category:"kitchen_cabinet",w:90,h:90,art:{d:"M45.944 41.767a2.29 2.29 0 0 0 2.29 2.29H83.92a2.29 2.29 0 0 1 2.29 2.29V83.92a2.29 2.29 0 0 1-2.29 2.29H6.08a2.29 2.29 0 0 1-2.29-2.29V6.08a2.29 2.29 0 0 1 2.29-2.29h37.576a2.29 2.29 0 0 1 2.29 2.29z",viewW:90,viewH:90}},{id:"kitchen_wall",group:"furniture",category:"kitchen_cabinet",w:60,h:35,art:{d:"m4.444 31.033 50.75-27.007m-50.752-.06 50.75 27.008M5.884 31.5h48.23c1.212 0 2.193-.895 2.193-2v-24c0-1.105-.981-2-2.192-2H5.885c-1.212 0-2.193.895-2.193 2v24c0 1.105.981 2 2.192 2",viewW:60,viewH:35}},{id:"kitchen_wall_corner",group:"furniture",category:"kitchen_cabinet",w:60,h:60,art:{d:"M3.772 29.59 29.88 4.383M4.57 55.43 55.43 30M4.175 4.383l26.701 23.863m-27.184.877L55.43 55.43M28.41 3.692H5.884c-1.21 0-2.192.981-2.192 2.192v48.23c0 1.212.981 2.193 2.192 2.193h48.23a2.19 2.19 0 0 0 2.193-2.192V31.589c0-1.21-.981-2.192-2.192-2.192h-21.32a2.19 2.19 0 0 1-2.193-2.192V5.885a2.19 2.19 0 0 0-2.192-2.193",viewW:60,viewH:60}},{id:"shelf_floor",group:"furniture",category:"shelving",w:100,h:35,art:{d:"M6.12 31.5h87.76a2.31 2 0 0 0 2.31-2v-24a2.31 2 0 0 0-2.31-2H6.12a2.31 2 0 0 0-2.31 2v24a2.31 2 0 0 0 2.31 2 M9.089 25.933c-.494.112-.776.546-.63.97s.664.675 1.157.564l-.263-.767zM90.912 9.067c.493-.112.775-.546.63-.97s-.664-.675-1.158-.564l.264.767zM11.875 26.956c.493-.112.775-.546.63-.97s-.664-.676-1.158-.564l.264.767zm3.988-2.556c-.493.112-.775.546-.63.969s.664.676 1.158.564l-.264-.766zm5.045.511c.493-.112.775-.545.63-.969s-.664-.676-1.158-.564l.264.766zm3.988-2.555c-.493.111-.775.545-.63.968.146.424.664.677 1.158.565l-.264-.767zm5.044.51c.494-.111.776-.545.63-.968-.145-.424-.664-.676-1.157-.565l.263.767zm3.99-2.555c-.495.112-.777.546-.63.97.145.423.663.675 1.157.563l-.264-.766zm5.043.511c.494-.112.776-.545.63-.969s-.664-.676-1.158-.564l.264.767zm3.989-2.555c-.494.111-.776.545-.63.969s.664.676 1.157.564l-.263-.767zm5.044.51c.494-.11.776-.545.63-.968-.146-.424-.664-.676-1.158-.565l.264.767zm3.989-2.555c-.494.112-.776.546-.63.97.145.423.664.675 1.157.564l-.264-.767zm5.044.511c.493-.111.775-.545.63-.969s-.664-.676-1.158-.564l.264.767zm3.988-2.555c-.493.112-.775.545-.63.969s.664.676 1.158.564l-.264-.767zm5.045.51c.493-.11.775-.545.63-.968-.146-.424-.664-.676-1.158-.564l.264.766zm3.988-2.555c-.493.112-.775.546-.63.97s.664.675 1.158.564l-.264-.767zm5.044.511c.494-.111.776-.545.63-.968-.145-.424-.664-.677-1.157-.565l.264.767zm3.99-2.555c-.494.112-.777.545-.63.969.145.423.663.676 1.157.564l-.264-.766zm5.043.511c.494-.112.776-.546.63-.969s-.664-.676-1.157-.564l.263.766zm3.989-2.556c-.494.112-.776.546-.63.97s.664.676 1.158.564l-.264-.767zM9.353 26.7l.263.767 2.259-.511-.264-.767-.264-.767-2.258.511zm6.774-1.533.264.766 4.517-1.022-.264-.767-.264-.766-4.517 1.022zm9.033-2.045.264.767 4.516-1.022-.264-.767-.263-.767-4.517 1.023zm9.033-2.044.264.766 4.516-1.022-.264-.766-.264-.767-4.516 1.022zm9.033-2.045.263.767 4.517-1.022-.264-.767-.264-.767-4.516 1.023zm9.032-2.044.264.767 4.517-1.023-.264-.766-.264-.767-4.516 1.022zm9.033-2.045.264.767 4.517-1.022-.264-.767-.264-.766-4.517 1.022zm9.033-2.044.264.767 4.516-1.023-.263-.766-.264-.767-4.517 1.022zm9.033-2.044.264.766 4.516-1.022-.264-.767-.263-.766-4.517 1.022zM88.39 8.81l.264.767 2.258-.511-.264-.767-.264-.767-2.258.511z M9.089 9.067c-.494-.112-.776-.546-.63-.97s.664-.675 1.157-.564l-.263.767zm81.823 16.866c.493.112.775.546.63.97s-.664.675-1.158.564l.264-.767zM11.875 8.044c.493.112.775.546.63.97s-.664.676-1.158.564l.264-.767zm3.988 2.556c-.493-.112-.775-.546-.63-.969s.664-.676 1.158-.564l-.264.766zm5.045-.511c.493.112.775.545.63.969s-.664.676-1.158.564l.264-.766zm3.988 2.555c-.493-.111-.775-.545-.63-.968.146-.424.664-.677 1.158-.565l-.264.767zm5.044-.51c.494.111.776.545.63.968-.145.424-.664.676-1.157.565l.263-.767zm3.99 2.555c-.495-.112-.777-.546-.63-.97.145-.423.663-.675 1.157-.563l-.264.766zm5.043-.511c.494.112.776.545.63.969s-.664.676-1.158.564l.264-.767zm3.989 2.555c-.494-.111-.776-.545-.63-.969s.664-.676 1.157-.564l-.263.767zm5.044-.51c.494.11.776.545.63.968-.146.424-.664.676-1.158.565l.264-.767zm3.989 2.555c-.494-.112-.776-.546-.63-.97.145-.423.664-.675 1.157-.564l-.264.767zm5.044-.511c.493.111.775.545.63.969s-.664.676-1.158.564l.264-.767zm3.988 2.555c-.493-.112-.775-.545-.63-.969s.664-.676 1.158-.564l-.264.767zm5.045-.51c.493.11.775.545.63.968-.146.424-.664.676-1.158.564l.264-.766zm3.988 2.555c-.493-.112-.775-.546-.63-.97s.664-.675 1.158-.564l-.264.767zm5.044-.511c.494.111.776.545.63.968-.145.424-.664.677-1.157.565l.264-.767zm3.99 2.555c-.494-.112-.777-.545-.63-.969.145-.423.663-.676 1.157-.564l-.264.766zm5.043-.511c.494.112.776.546.63.969s-.664.676-1.157.564l.263-.766zm3.989 2.556c-.494-.112-.776-.546-.63-.97s.664-.676 1.158-.564l-.264.767zM9.353 8.3l.263-.767 2.259.511-.264.767-.264.767-2.258-.511zm6.774 1.533.264-.766 4.517 1.022-.264.767-.264.766-4.517-1.022zm9.033 2.045.264-.767 4.516 1.022-.264.767-.263.767-4.517-1.023zm9.033 2.044.264-.766 4.516 1.022-.264.766-.264.767-4.516-1.022zm9.033 2.045.263-.767 4.517 1.022-.264.767-.264.767-4.516-1.023zm9.032 2.044.264-.767 4.517 1.023-.264.766-.264.767-4.516-1.022zm9.033 2.045.264-.767 4.517 1.022-.264.767-.264.766-4.517-1.022zm9.033 2.044.264-.767 4.516 1.023-.263.766-.264.767-4.517-1.022zm9.033 2.044.264-.766 4.516 1.022-.264.767-.263.766-4.517-1.022zm9.033 2.045.264-.767 2.258.511-.264.767-.264.767-2.258-.511z",viewW:100,viewH:35}},{id:"shelf_wall",group:"furniture",category:"shelving",w:100,h:25,art:{d:"M18.36 3.15v2.567c0 1.012-1.034 1.833-2.31 1.833h-.924c-1.275 0-2.309-.82-2.309-1.833V3.15m73.905 0v2.567c0 1.012-1.034 1.833-2.31 1.833h-.924c-1.275 0-2.31-.82-2.31-1.833V3.15m-75.29 0H93.65c1.276 0 2.31.82 2.31 1.833V19.65c0 1.012-1.034 1.833-2.31 1.833H5.888c-1.275 0-2.31-.82-2.31-1.833V4.983c0-1.012 1.035-1.833 2.31-1.833",viewW:100,viewH:25}},{id:"cooktop_two",group:"appliance",category:"cooktop",w:30,h:50,art:{d:"M15 30.982v-1.71m3.086 5.128h1.542M15 39.527v-1.709M10.372 34.4h1.542M5.84 46.364h18.322c1.331 0 2.41-1.196 2.41-2.67V6.306c0-1.475-1.079-2.67-2.41-2.67H5.839c-1.331 0-2.41 1.195-2.41 2.67v37.386c0 1.475 1.079 2.67 2.41 2.67m14.56-29.91c0 3.304-2.417 5.982-5.4 5.982-2.981 0-5.4-2.678-5.4-5.981s2.419-5.982 5.4-5.982c2.983 0 5.4 2.678 5.4 5.982M18.858 34.4c0 2.36-1.727 4.273-3.857 4.273s-3.857-1.913-3.857-4.273S12.87 30.127 15 30.127s3.857 1.913 3.857 4.273",viewW:30,viewH:50}},{id:"stove",group:"appliance",category:"cooktop",w:60,h:60,art:{d:"M41.4 35.261a.877.877 0 1 0-1.754 0zm4.384 6.138a.877.877 0 1 0 0-1.753zM41.4 44.03a.877.877 0 1 0-1.753 0zm-4.384-2.63a.877.877 0 1 0 0-1.754zM5.885 3.691v.877h48.23V2.815H5.885zm50.422 2.192h-.877v48.23h1.754V5.885zm-2.192 50.423v-.877H5.885v1.754h48.23zM3.692 54.115h.877V5.885H2.815v48.23zm2.192 2.192v-.877a1.315 1.315 0 0 1-1.315-1.315H2.815a3.07 3.07 0 0 0 3.07 3.069zm50.423-2.192h-.877c0 .726-.589 1.315-1.315 1.315v1.754a3.07 3.07 0 0 0 3.069-3.07zM54.115 3.692v.877c.726 0 1.315.589 1.315 1.315h1.754a3.07 3.07 0 0 0-3.07-3.069zm-48.23 0v-.877a3.07 3.07 0 0 0-3.07 3.07h1.754c0-.727.589-1.316 1.315-1.316zm19.73 36.83h-.877a5.26 5.26 0 0 1-5.262 5.262v1.754a7.015 7.015 0 0 0 7.016-7.015zm-6.139 6.139v-.877a5.26 5.26 0 0 1-5.261-5.261h-1.754a7.015 7.015 0 0 0 7.015 7.015zm-6.138-6.138h.877a5.26 5.26 0 0 1 5.261-5.262v-1.754a7.015 7.015 0 0 0-7.015 7.016zm6.138-6.139v.877a5.26 5.26 0 0 1 5.262 5.262h1.754a7.015 7.015 0 0 0-7.016-7.016zm27.185-14.908h-.877a5.26 5.26 0 0 1-5.261 5.262v1.754a7.015 7.015 0 0 0 7.015-7.016zm-6.138 6.139v-.877a5.26 5.26 0 0 1-5.262-5.262h-1.754a7.015 7.015 0 0 0 7.016 7.016zm-6.139-6.139h.877a5.26 5.26 0 0 1 5.262-5.261v-1.754a7.015 7.015 0 0 0-7.016 7.015zm6.139-6.138v.877a5.26 5.26 0 0 1 5.261 5.261h1.754a7.015 7.015 0 0 0-7.015-7.015zm4.384 27.185h-.877a3.51 3.51 0 0 1-3.507 3.507v1.754a5.26 5.26 0 0 0 5.261-5.261zm-4.384 4.384v-.877a3.51 3.51 0 0 1-3.508-3.507H35.26a5.26 5.26 0 0 0 5.262 5.261zm-4.385-4.384h.877a3.51 3.51 0 0 1 3.508-3.508V35.26a5.26 5.26 0 0 0-5.262 5.262zm4.385-4.385v.877a3.51 3.51 0 0 1 3.507 3.508h1.754a5.26 5.26 0 0 0-5.261-5.262zm0 .877h.876V35.26h-1.753v1.754zm3.508 3.508v.876h1.753v-1.753h-1.753zm-3.508 5.261h.876V44.03h-1.753v1.754zm-5.261-5.261v.876h1.753v-1.753h-1.753zm-9.647-21.047h-.877a5.26 5.26 0 0 1-5.262 5.262v1.754a7.015 7.015 0 0 0 7.016-7.016zm-6.139 6.139v-.877a5.26 5.26 0 0 1-5.261-5.262h-1.754a7.015 7.015 0 0 0 7.015 7.016zm-6.138-6.139h.877a5.26 5.26 0 0 1 5.261-5.261v-1.754a7.015 7.015 0 0 0-7.015 7.015zm6.138-6.138v.877a5.26 5.26 0 0 1 5.262 5.261h1.754a7.015 7.015 0 0 0-7.016-7.015z",viewW:60,viewH:60}},{id:"tv",group:"appliance",category:"tv",w:120,h:28,art:{d:"M45.134 10.766H6.18c-1.292 0-2.34.848-2.34 1.894v2.68c0 1.045 1.048 1.893 2.34 1.893h38.954m0-6.467V5.288c0-1.046 1.048-1.894 2.34-1.894h26.704c1.292 0 2.34.848 2.34 1.894v5.478m-31.384 0h31.384m0 0h37.302c1.293 0 2.34.848 2.34 1.894v2.68c0 1.045-1.047 1.893-2.34 1.893H76.518m-31.384 0v5.479c0 1.046 1.048 1.894 2.34 1.894h26.704c1.292 0 2.34-.848 2.34-1.894v-5.479m-31.384 0h31.384",viewW:120,viewH:28}},{id:"tv_wall",group:"appliance",category:"tv",w:120,h:15,art:{d:"M35.664 11.4c-.517 0-.936.269-.936.6s.419.6.936.6zm49.553 1.2c.517 0 .936-.269.936-.6s-.42-.6-.936-.6zM6.18 3v.6h107.64V2.4H6.18zm109.98 1.5h-.936v1.8h1.872V4.5zm-2.34 3.3v-.6H6.18v1.2h107.64zM3.84 6.3h.936V4.5H2.904v1.8zm2.34 1.5v-.6c-.775 0-1.404-.403-1.404-.9H2.904c0 1.16 1.467 2.1 3.276 2.1zm109.98-1.5h-.936c0 .497-.629.9-1.404.9v1.2c1.81 0 3.276-.94 3.276-2.1zM113.82 3v.6c.775 0 1.404.403 1.404.9h1.872c0-1.16-1.467-2.1-3.276-2.1zM6.18 3v-.6c-1.81 0-3.276.94-3.276 2.1h1.872c0-.497.629-.9 1.404-.9zm61.308 4.2h-.936V12h1.872V7.2zM52.512 12h.936V7.2h-1.872V12zm-16.848 0v.6h49.553v-1.2H35.664z",viewW:120,viewH:15}},{id:"toilet",group:"sanitary",category:"toilet",w:40,h:70,art:{d:"M3.555 48.976c0 9.55 7.125 17.29 15.914 17.29h1.061c8.79 0 15.914-7.74 15.914-17.29V5.966c0-1.233-.92-2.233-2.056-2.233H5.611c-1.135 0-2.056 1-2.056 2.234z M7.666 49.12c0 7.003 5.225 12.68 11.67 12.68h1.327c6.445 0 11.67-5.677 11.67-12.68V31.873c0-1.233-.92-2.233-2.056-2.233H9.722c-1.135 0-2.056 1-2.056 2.233zM33.792 3.733c1.465 0 2.652 1.29 2.652 2.882v12.103c0 1.592-1.187 2.882-2.652 2.882H6.208c-1.465 0-2.653-1.29-2.653-2.882V6.615c0-1.591 1.188-2.882 2.653-2.882z M24.11 50.186c0 2.467-1.84 4.467-4.11 4.467s-4.111-2-4.111-4.467 1.84-4.466 4.11-4.466 4.112 2 4.112 4.466",viewW:40,viewH:70}},{id:"toilet_built_in",group:"sanitary",category:"toilet",w:40,h:55,art:{d:"M3.555 34.56c0 9.263 7.125 16.774 15.914 16.774h1.061c8.79 0 15.914-7.51 15.914-16.775V5.833c0-1.196-.92-2.166-2.056-2.166H5.611c-1.135 0-2.056.97-2.056 2.166z M7.666 34.7c0 6.793 5.225 12.3 11.67 12.3h1.327c6.445 0 11.67-5.507 11.67-12.3V14.5c0-1.197-.92-2.167-2.056-2.167H9.722c-1.135 0-2.056.97-2.056 2.167z M24.11 35.733c0 2.394-1.84 4.334-4.11 4.334s-4.111-1.94-4.111-4.334 1.84-4.333 4.11-4.333 4.112 1.94 4.112 4.333",viewW:40,viewH:55}},{id:"bathtub",group:"sanitary",category:"bathtub",w:170,h:75,art:{d:"M3.885 6c0-1.243 1.068-2.25 2.386-2.25h157.458c1.318 0 2.386 1.007 2.386 2.25v63c0 1.243-1.068 2.25-2.386 2.25H6.27c-1.318 0-2.386-1.007-2.386-2.25z M13.428 37.5c0-13.669 11.75-24.75 26.243-24.75h90.658c14.493 0 26.243 11.081 26.243 24.75s-11.75 24.75-26.243 24.75H39.67c-14.493 0-26.243-11.081-26.243-24.75 M31.56 37.5c0 2.237-1.923 4.05-4.295 4.05s-4.294-1.813-4.294-4.05 1.923-4.05 4.294-4.05c2.372 0 4.295 1.813 4.295 4.05",viewW:170,viewH:75}},{id:"bathtub_corner",group:"sanitary",category:"bathtub",w:140,h:140,art:{d:"M3.862 6.224a2.36 2.36 0 0 1 2.362-2.362H133.97c1.197 0 2.168.97 2.168 2.168 0 71.857-58.251 130.108-130.108 130.108a2.17 2.17 0 0 1-2.168-2.168z M13.31 32.207c0-10.437 8.46-18.897 18.897-18.897h87.628a2.13 2.13 0 0 1 2.13 2.13c0 58.833-47.692 106.526-106.524 106.526a2.13 2.13 0 0 1-2.13-2.131z M32.207 27.483a4.724 4.724 0 1 1-9.449 0 4.724 4.724 0 0 1 9.449 0",viewW:140,viewH:140}},{id:"bidet",group:"sanitary",category:"bidet",w:40,h:60,art:{d:"M22.466 3.692v10.085c0 1.21-.92 2.192-2.055 2.192h-.822c-1.136 0-2.056-.981-2.056-2.192V3.692m4.933 8.77h2.878c1.135 0 2.056-.982 2.056-2.193v-.877c0-1.21-.92-2.192-2.056-2.192h-2.878m-4.933 5.262h-2.878c-1.135 0-2.055-.982-2.055-2.193v-.877c0-1.21.92-2.192 2.055-2.192h2.878M5.611 3.692h28.777c1.136 0 2.056.981 2.056 2.192v33.45c0 9.374-7.125 16.973-15.914 16.973h-1.06c-8.79 0-15.915-7.599-15.915-16.972V5.885c0-1.212.92-2.193 2.056-2.193m4.11 15.785h20.556c1.136 0 2.056.981 2.056 2.192v17.807c0 6.874-5.225 12.447-11.67 12.447h-1.327c-6.445 0-11.67-5.573-11.67-12.447V21.67c0-1.21.92-2.192 2.056-2.192m13.567 7.892c0 1.937-1.472 3.508-3.288 3.508-1.817 0-3.29-1.57-3.29-3.508s1.473-3.507 3.29-3.507 3.288 1.57 3.288 3.507",viewW:40,viewH:60}},{id:"bidet_built_in",group:"sanitary",category:"bidet",w:40,h:50,art:{d:"M17.318 12.182h-8.06c-.88 0-1.592.74-1.592 1.654v16.126c0 6.698 5.225 12.129 11.67 12.129h1.327c6.445 0 11.67-5.43 11.67-12.13V13.837c0-.914-.713-1.654-1.591-1.654H22.68m-.215-8.545v9.827c0 1.18-.92 2.136-2.055 2.136h-.822c-1.136 0-2.056-.956-2.056-2.136V3.637m10.689 8.545V3.637m-16.445 0v8.545M5.611 3.637h28.777c1.136 0 2.056.956 2.056 2.136v24.051c0 9.135-7.125 16.54-15.914 16.54h-1.06c-8.79 0-15.915-7.405-15.915-16.54V5.773c0-1.18.92-2.136 2.056-2.136M23.289 23.29c0 1.888-1.473 3.418-3.29 3.418s-3.288-1.53-3.288-3.418 1.472-3.418 3.289-3.418c1.816 0 3.288 1.53 3.288 3.418",viewW:40,viewH:50}},{id:"kitchen_sink",group:"sanitary",category:"kitchen_sink",w:60,h:50,art:{d:"M38.188 8.7h10.598c1.211 0 2.193.956 2.193 2.136v28.2c0 1.18-.982 2.136-2.193 2.136H11.08c-1.21 0-2.192-.956-2.192-2.136v-28.2c0-1.18.981-2.136 2.192-2.136h10.599m10.885-5.128V15.11c0 1.18-.981 2.136-2.192 2.136h-.877c-1.21 0-2.192-.957-2.192-2.136V3.572m5.261 7.691h3.07c1.21 0 2.192-.956 2.192-2.136v-.855c0-1.18-.982-2.136-2.192-2.136h-3.07m-5.261 5.127h-3.07c-1.21 0-2.192-.956-2.192-2.136v-.855c0-1.18.982-2.136 2.193-2.136h3.069M5.817 46.299h48.231c1.21 0 2.192-.956 2.192-2.136V5.709c0-1.18-.981-2.137-2.192-2.137H5.818c-1.211 0-2.193.957-2.193 2.137v38.454c0 1.18.982 2.136 2.192 2.136M33.44 25.79c0 1.888-1.57 3.418-3.507 3.418s-3.508-1.53-3.508-3.418c0-1.887 1.57-3.418 3.508-3.418s3.507 1.53 3.507 3.418",viewW:60,viewH:50}},{id:"kitchen_sink_double",group:"sanitary",category:"kitchen_sink",w:90,h:50,art:{d:"M53.173 12.182c-.468 0-.847.354-.847.79s.38.79.847.79zm21.979 1.58c.467 0 .846-.353.846-.79 0-.436-.379-.79-.846-.79zM6.01 3.572v.79h77.842v-1.58H6.01zM86.14 5.71h-.847v38.454h1.694V5.709zM83.85 46.3v-.79H6.01v1.58h77.842zM3.72 44.163h.847V5.709H2.873v38.454zm2.29 2.136v-.79c-.797 0-1.443-.603-1.443-1.346H2.873c0 1.616 1.404 2.926 3.137 2.926zm80.131-2.136h-.847c0 .743-.646 1.346-1.442 1.346v1.58c1.732 0 3.136-1.31 3.136-2.926zm-2.29-40.59v.79c.797 0 1.443.602 1.443 1.346h1.694c0-1.617-1.404-2.927-3.136-2.927zm-77.841 0v-.79c-1.733 0-3.137 1.31-3.137 2.926h1.694c0-.744.646-1.347 1.443-1.347zm5.494 37.599v.79h28.39v-1.58h-28.39zm30.68-2.136h.846v-28.2h-1.694v28.2zm-32.97-28.2h-.846v28.2h1.694v-28.2zM39.895 8.7v-.79h-5.669v1.58h5.669zm-22.721 0v-.79h-5.669v1.58h5.669zm-7.958 2.136h.847c0-.744.645-1.346 1.442-1.346V7.91c-1.732 0-3.136 1.31-3.136 2.926zm32.968 0h.847c0-1.616-1.404-2.927-3.136-2.927v1.58c.797 0 1.442.603 1.442 1.347zm-2.29 30.336v.79c1.733 0 3.137-1.31 3.137-2.926h-1.694c0 .743-.645 1.346-1.442 1.346zm-28.389 0v-.79c-.797 0-1.442-.603-1.442-1.346H8.368c0 1.616 1.404 2.926 3.136 2.926zm13.737-23.927v.79h.916v-1.58h-.916zm3.205-2.136h.847V3.572H27.6V15.11zM22.952 3.572h-.847V15.11h1.693V3.572zm3.205 13.673v.79c1.732 0 3.136-1.31 3.136-2.926H27.6c0 .743-.646 1.346-1.443 1.346zm-.916 0v-.79c-.797 0-1.443-.603-1.443-1.346h-1.693c0 1.616 1.404 2.926 3.136 2.926zm3.205-5.982v.79h3.206v-1.58h-3.206zm5.495-2.136h.847v-.855h-1.694v.855zm-2.29-2.991v-.79h-3.205v1.58h3.206zm2.29 2.136h.847c0-1.616-1.404-2.926-3.136-2.926v1.58c.796 0 1.442.603 1.442 1.346zm-2.29 2.991v.79c1.733 0 3.137-1.31 3.137-2.926h-1.694c0 .743-.646 1.346-1.442 1.346zm-11.905 0v.79h3.206v-1.58h-3.206zm3.206-5.127v-.79h-3.206v1.58h3.206zm-5.495 2.136h-.847v.855h1.694v-.855zm2.29-2.136v-.79c-1.733 0-3.137 1.31-3.137 2.926h1.694c0-.743.646-1.346 1.442-1.346zm0 5.127v-.79c-.797 0-1.443-.603-1.443-1.346H16.61c0 1.616 1.404 2.926 3.136 2.926zm9.615 14.527h-.847c0 1.452-1.26 2.628-2.816 2.628v1.58c2.49 0 4.51-1.884 4.51-4.208zM25.7 29.208v-.79c-1.555 0-2.816-1.176-2.816-2.628H21.19c0 2.324 2.02 4.209 4.51 4.209zm-3.663-3.418h.847c0-1.451 1.26-2.628 2.816-2.628v-1.58c-2.49 0-4.51 1.884-4.51 4.208zm3.663-3.418v.79c1.555 0 2.816 1.177 2.816 2.628h1.694c0-2.324-2.02-4.208-4.51-4.208zm24.268 18.8v.79h28.39v-1.58h-28.39zm30.68-2.136h.846v-28.2H79.8v28.2zM78.356 8.7v-.79h-28.39v1.58h28.39zm-30.68 2.136h-.846v28.2h1.694v-28.2zm2.29-2.136v-.79c-1.732 0-3.136 1.31-3.136 2.926h1.694c0-.744.646-1.346 1.442-1.346zm30.68 2.136h.846c0-1.616-1.404-2.927-3.136-2.927v1.58c.797 0 1.443.603 1.443 1.347zm-2.29 30.336v.79c1.732 0 3.136-1.31 3.136-2.926H79.8c0 .743-.646 1.346-1.443 1.346zm-28.39 0v-.79c-.796 0-1.442-.603-1.442-1.346H46.83c0 1.616 1.404 2.926 3.136 2.926zm3.206-28.2v.79h21.979v-1.58h-21.98z",viewW:90,viewH:50}}].map(e=>({id:e.id,group:e.group,category:e.category,w:e.w,h:e.h,art:e.art})),...cl.filter(e=>hl.has(e.id))],ul=new Map(dl.map(e=>[e.id,e]));function pl(e){return e&&ul.get(e)||null}function _l(e){return dl.filter(t=>t.group===e)}function ml(e){const t=pl(e);return t?{w:t.w,h:t.h}:{w:60,h:60}}function fl(e,t,i=Na,n=1e3){const r=Number(t)>0?Number(t):5;return(Number(e)||0)/r*i/n}const gl=5e-4,vl=Ea;function yl(e){return Number.isFinite(e)?Math.max(gl,Math.min(vl,e)):gl}function bl(e){return Number.isFinite(e)?Math.max(1,Math.min(1e4,e)):1}const wl=e=>{const t=Math.round(1e3*e)/1e3;return Object.is(t,-0)?"0":String(t)};function kl(e){const t=pl(e);if(!t)return null;if(t.art)return t.art;const i=function(e,t,i){if(!e.g)return"";const n=e=>wl(e*t),r=e=>wl(e*i),o=[];for(const s of e.g)if("r"===s[0]){const[,e,t,i,a]=s;o.push(`M${n(e)} ${r(t)}H${n(e+i)}V${r(t+a)}H${n(e)}Z`)}else if("l"===s[0]){const[,e,t,i,a]=s;o.push(`M${n(e)} ${r(t)}L${n(i)} ${r(a)}`)}else if("e"===s[0]){const[,e,a,l,c]=s;o.push(`M${n(e-l)} ${r(a)}A${wl(l*t)} ${wl(c*i)} 0 0 1 ${n(e+l)} ${r(a)}A${wl(l*t)} ${wl(c*i)} 0 0 1 ${n(e-l)} ${r(a)}Z`)}else{const e=s.slice(1);if(e.length<4)continue;let t=`M${n(e[0])} ${r(e[1])}`;for(let i=2;i+1{let t=(e%360+360)%360;return t>180&&(t-=360),t};function $l(e,t,i,n,r,o=0){let s=null,a=r;for(const r of n){const[n,l,c,h]=r,d=c-n,u=h-l,p=d*d+u*u;if(!p)continue;const _=Math.sqrt(p);let m=((e-n)*d+(t-l)*u)/p;m=Math.max(0,Math.min(1,m));let f=n+m*d,g=l+m*u;const v=Math.hypot(e-f,t-g);if(!(v0){const e=Math.round(m*_/o)*o;f=n+e/_*d,g=l+e/_*u}s={cx:f+y*(i/2),cy:g+b*(i/2),angle:xl(180*Math.atan2(-y,b)/Math.PI),dist:v}}return s}const Sl=15e3,Ml=2e3,Rl=new WeakMap;function Tl(e,t){let i=Rl.get(e);if(!i){const t=new Set;i={hiddenAt:"hidden"===e.visibilityState?Date.now():0,token:0,subscribers:t,onVisibility:()=>{const t=Rl.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>=Sl};for(const e of[...t.subscribers])e(r)},onPageShow:t=>{const i=Rl.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)}},Rl.set(e,i),e.addEventListener("visibilitychange",i.onVisibility),e.defaultView?.addEventListener("pageshow",i.onPageShow)}return i.subscribers.add(t),()=>{const i=Rl.get(e);i&&(i.subscribers.delete(t),i.subscribers.size||(e.removeEventListener("visibilitychange",i.onVisibility),e.defaultView?.removeEventListener("pageshow",i.onPageShow),Rl.delete(e)))}}const Cl={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 Dl{constructor(e,t=Cl){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}),Ml)}),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 zl(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 Al(e){return zl(e)}const Ol=new WeakMap;class Pl{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=Ol.get(e);return t||(t={signed:{},queued:new Set,inFlight:new Map,retry:new Map,listeners:new Set,settlers:new Set,references:new Map},Ol.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=Rn(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),Ml);o.src=n}),i.preload}prepareImage(e,t){const i=Rn(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.at<$n)return this.preloadCurrentImage(n,i,t);this.display(e,i);const r=n.retry.get(i);return r&&r.notBefore>this.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),Ml);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),Ml);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<$n&&(o[e]=t);i.signed=o,i.retry.clear(),this.sign(e,[...t].filter(e=>!!o[e]&&!o[e].pending))}markLoaded(e,t,i){const n=Rn(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=Rn(t);if(!i.startsWith("/api/houseplan/content/"))return!0;const n=this.bind(e).signed[i];return!!n&&this.now()-n.at<$n&&n.loaded}get entries(){const e={};for(const[t,i]of Object.entries(this.shared?.signed||{}))e[t]={url:i.url,at:i.at};return e}get inFlightUrls(){return[...this.shared?.inFlight.keys()||[]]}}function Fl(e,t){if(t)return e.find(e=>e.id===t)}var El="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 Il(e,t,i){return[e[0]*t+e[1]*i+e[2],e[3]*t+e[4]*i+e[5]]}function Hl(e,t){let i=0;for(const[n,r]of t){const t=Il(e,n[0],n[1]);i=Math.max(i,Math.hypot(t[0]-r[0],t[1]-r[1]))}return i}const Nl=e=>{if(null==e||""===e)return null;const t=Number(e);return Number.isFinite(t)?t:null},Ll=e=>{const t=e,i=Nl(Array.isArray(t)?t[0]:t?.x),n=Nl(Array.isArray(t)?t[1]:t?.y);return null==i||null==n?null:[i,n]};function ql(e){if(!Array.isArray(e))return null;const t=[];for(const i of e){const e=Ll(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 Wl(e){if(!Array.isArray(e))return null;const t=[];for(const i of e){const e=Ll(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=ql(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 jl(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(Ll).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 Ul=e=>Number.isFinite(e[0])&&Number.isFinite(e[1]),Gl=(e,t)=>e[0]===t[0]&&e[1]===t[1];function Kl(e){if(!e)return null;const t=e.vacuum_position||e.robot_position||null,i=t&&null!=Nl(t.x)&&null!=Nl(t.y)?{x:Nl(t.x),y:Nl(t.y),a:Nl(t.a??t.angle??t.theta)}:null,n=jl(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=[[Nl(t.cx),Nl(t.cy)],[Nl(t.center?.x),Nl(t.center?.y)],[Nl(t.x),Nl(t.y)]].find(([e,t])=>null!=e&&null!=t);let o=n?.[0]??null,s=n?.[1]??null;const a=Wl(t.outline),l=Nl(t.x0),c=Nl(t.y0),h=Nl(t.x1),d=Nl(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 Yl(e,t,i){return![e,t,i].every(Number.isFinite)||e<0||t<=0||i<=0?Number.POSITIVE_INFINITY:e/t*i}const Zl=40;function Xl(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=!!Ll(n.vacuum_position??n.robot_position),a=!(!n.rooms||"object"!=typeof n.rooms),l=jl(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 Jl=e=>e.toLowerCase().replace(/[\s_\-.,]+/g,"");function Ql(e,t){const i=new Set(t.map(Jl).filter(Boolean)),n=new Set;for(const t of e){const e=Jl(t.name||"");e&&i.has(e)&&n.add(e)}return n.size}function ec(e,t){const i=new Map(t.map(e=>[Jl(e.name),e])),n=[],r=[];for(const t of e){const e=i.get(Jl(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,f]]of e){if(![p,_,m,f].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*f,d+=_*f,u+=f}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]),f=_([h,d,u]);if(!m||!f)return null;const g=[m[0],m[1],m[2],f[0],f[1],f[2]];return g.every(Number.isFinite)?g:null}(n);return o?{matrix:o,matched:r,residual:Hl(o,n)}:null}function tc(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 ic(e){return"cleaning"===e||"returning"===e||"on"===e}const nc={0:[1,0],90:[0,1],180:[-1,0],270:[0,-1]};function rc(e){const[t,i]=nc[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 oc(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 sc(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=rc(c),[d,u]=Il(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 ac(e,t,i,n){const[r,o]=Il(rc(t),i,n),s=rc({...e,ox:0,oy:0}),[a,l]=Il(s,i,n);return{...e,ox:r-a,oy:o-l}}function lc(e){const t=e?.trail_mode;return"never"===t||"cleaning"===t||"always"===t?t:!1===e?.trail?"never":"cleaning"}const cc={availability:"available",status:"alarm",activity:"none"},hc=new Set(["motion","vibration","sound"]),dc=new Set(["occupancy","presence"]),uc=new Set(["door","window","garage_door","opening"]),pc=new Set(["running","power"]),_c=new Set(["smoke","gas","carbon_monoxide","moisture","safety","tamper","problem"]);const mc=new Set(["running","working","washing","rinsing","spinning","drying","heating","cooling","cleaning","cooking","playing","recording","pumping","irrigating","humidifying","dehumidifying","fan","preheating","defrosting"]),fc=new Set([...mc,"start","started","run","active","in_progress","wash","rinse","spin","dry"]),gc=new Set(["off","idle","paused","standby","docked","finished","complete","completed","stopped","ready","sleeping","stop","end","done","inactive"]),vc=new Set(["heat","cool","heat_cool","auto","dry","fan_only"]),yc=e=>""===e||"unknown"===e||"unavailable"===e||"__missing__"===e,bc=e=>String(e??"").trim().toLowerCase(),wc=e=>bc(e).replace(/[\s-]+/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,""),kc=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]]),xc=new Set(["wifi","connection","signal","battery"]);function $c(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=>bc(e))||o.push(e?.states?.[t]?.attributes?.friendly_name);const s=o.map(wc).filter(Boolean);if(s.some(e=>e.split("_").some(e=>xc.has(e))))return null;let a=null;for(const e of s)for(const[t,i]of kc)(e===t||e.endsWith(`_${t}`))&&(a=null==a?i:Math.min(a,i));return a}const Sc=(e,t)=>null!=$c(e,t);function Mc(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(bc).some(e=>["power","main power","power switch","питание"].includes(e)))return!0;const o=bc(n?.attributes?.friendly_name);return/(?:^|[\s._-])(?:main[\s._-]+)?power$/.test(o)||/(?:^|[\s._-])питание$/.test(o)}function Rc(e){for(const t of["hvac_action","action","current_operation","run_state","job_state","operation","activity"]){const i=bc(e?.[t]);if(mc.has(i)||gc.has(i))return i}return""}function Tc(e,t){const i=e?.states?.[t],n=i?bc(i.state):"__missing__",r=String(t||"").split(".")[0],o=bc(i?.attributes?.device_class),s={eid:t,state:n,availability:yc(n)?"unavailable":"available",status:"neutral",activity:"none",edge:"none"};if("unavailable"===s.availability)return s;if(function(e,t,i){return"alarm_control_panel"===e?"triggered"===i:"on"===i&&In(e,t)}(r,o,n))return{...s,status:"alarm"};if("binary_sensor"===r)return hc.has(o)?{...s,edge:"rising"}:dc.has(o)?{...s,activity:"on"===n?"presence":"none"}:uc.has(o)?{...s,status:"on"===n?"open":"neutral",edge:"rising"}:"moving"===o?{...s,activity:"on"===n?"transition":"none"}:pc.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=Rc(i.attributes),t=Array.isArray(i.attributes?.hvac_modes)?i.attributes.hvac_modes.map(bc):[],r=!gc.has(n)&&(vc.has(n)||mc.has(n)||t.includes(n));return(e?mc.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=Rc(i.attributes);return mc.has(a)||mc.has(n)&&!gc.has(n)?{...s,status:"working",activity:"running"}:s}function Cc(e,t,i){const n=i.filter(t=>t.startsWith("switch.")&&!e?.entities?.[t]?.entity_category),r=t.find(t=>Mc(e,t));if(!(n.length>1&&!!r))return t.map(t=>Tc(e,t));const o=t.find(t=>t!==r&&Sc(e,t)),s=Tc(e,r);return"unavailable"===s.availability||"off"===s.state?t.map(t=>({eid:t,state:e?.states?.[t]?bc(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?bc(i.state):"__missing__",r={eid:t,state:n,availability:yc(n)?"unavailable":"available",status:"neutral",activity:"none",edge:"none"};if("unavailable"===r.availability)return r;const o=Rc(i?.attributes);return mc.has(o)||fc.has(n)&&!gc.has(n)?{...r,status:"working",activity:"running"}:r}(e,t);return{...t===r?s:Tc(e,t),status:"neutral",activity:"none",edge:"none"}})}function Dc(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 cc;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 zc(e,t){if(!(e=>!!e&&!yc(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 Ac=(e,t=0)=>{const i=Number(e);return Number.isInteger(i)&&i>=0?i:t},Oc=(e,t)=>{const i={rev:0,configRev:Ac(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 Pc(e,t=0){return Oc(e,t).snapshot}function Fc(e,t,i,n){const r=Oc(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=Gc(i,"id"),o=Gc(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 Yc(e,t){void 0===t.reloadTimer&&(t.reloadTimer=globalThis.setTimeout(()=>{t.reloadTimer=void 0,Kc(e,t)},80))}async function Zc(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,()=>Yc(e,t),"device_registry_updated")),t.unsubEntity||(t.unsubEntity=await i.call(e.connection,()=>Yc(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 Xc(e,t){const i=Uc(e);if(!i)return()=>{};const n=0===i.refs;i.refs++,i.listeners.add(t),("pending"===i.access||n)&&Kc(e,i),Zc(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 Jc(e){const t=Uc(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&&Yc(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 Qc(e){if(!e||"object"!=typeof e&&"function"!=typeof e)return 0;let t=Wc.get(e);return t||(t=jc++,Wc.set(e,t)),t}function eh(e,t=Jc(e)){return[t.revision,t.access,Qc(t.devices),Qc(t.entities)].join(":")}function th(e){return!!e&&null==e.disabled_by}function ih(e,t=Jc(e)){const i={},n={},r={};for(const[e,n]of Object.entries(t.devices||{}))th(n)&&(i[e]=n);for(const[e,i]of Object.entries(t.entities||{})){if(!th(i))continue;const r=i.device_id?t.devices?.[i.device_id]:null;t.authoritative&&i.device_id&&!r||(r&&!th(r)||(n[e]=i))}for(const[i,n]of Object.entries(e?.states||{})){const e=t.entities?.[i];if(e&&!th(e))continue;const o=e?.device_id?t.devices?.[e.device_id]:null;t.authoritative&&e?.device_id&&!o||(o&&!th(o)||(r[i]=n))}return{...e,devices:i,entities:n,states:r}}function nh(e,t=Jc(e)){return{...e,devices:t.devices||{},entities:t.entities||{}}}function rh(e,t){const i=[];for(const[n,r]of Object.entries(e||{}))r?.device_id===t&&i.push(n);return i}function oh(){if(Vc)return Vc;if("undefined"==typeof localStorage)return{};try{const e=JSON.parse(localStorage.getItem(Bc)||"{}");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 Vc=i,Vc}catch{return{}}}function sh(e,t,i=Jc(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=rh(a,o);if(!th(e))return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:t};const i=t.filter(e=>th(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&&!th(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&&!th(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 oh()[e]||null}(t);if("device"===r){const t=s[o],i=rh(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 ah(e){const t={};for(const[i,n]of Object.entries(e.entities)){if(!n?.device_id||!th(n))continue;const r=e.devices?.[n.device_id];r&&!th(r)||(t[n.device_id]=t[n.device_id]||[]).push(i)}return t}function lh(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 ch(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 hh(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 dh(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 uh=["vacuum","lawn_mower","climate","media_player","light","cover","lock","valve","alarm_control_panel","water_heater","fan","humidifier","siren","camera","remote"],ph=e=>[...e.filter(e=>!e.reg?.hidden),...e.filter(e=>!!e.reg?.hidden)];function _h(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 uh){const t=r.filter(t=>t.eid.startsWith(e+"."));if(t.length)return ph(t).map(e=>e.eid)}const o=r.filter(t=>function(e,t){if(!t.startsWith("binary_sensor."))return!1;const i=bc(e?.states?.[t]?.attributes?.device_class||e?.entities?.[t]?.device_class||e?.entities?.[t]?.original_device_class);return hc.has(i)||dc.has(i)||uc.has(i)||pc.has(i)||"moving"===i||_c.has(i)}(e,t.eid));if(o.length)return ph(o).map(e=>e.eid);const s=r.filter(e=>e.eid.startsWith("switch."));if(s.length){const t=ph(s),n=t.find(t=>Mc(e,t.eid));if(s.length>1&&n){const t=i.filter(t=>t.eid!==n.eid&&"config"!==t.reg?.entity_category&&null!=$c(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=ph(o.filter(i=>$c(e,i.eid)===t));if(i.length)return[i[0].eid,n.eid]}}return[(n||t[0]).eid]}const a=[];for(const e of Ee)a.push(...ph(r.filter(t=>t.eid.startsWith(e+"."))));return a.push(...ph(r.filter(e=>!Ee.includes(e.eid.split(".")[0])))),a.map(e=>e.eid)}function mh(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=>dh(e,t.eid));if(i)return i.eid}const o=_h(e,t);return o.find(bn)||o[0]}function fh(e,t,i=[]){return[...new Set(gh(e,t,i))].filter(e=>bn(e))}function gh(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 vh(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 yh(e){const t=e.marker?.binding?.startsWith("entity:")?e.marker.binding.slice(7):null,i=e.entities.filter(bn),n=e.primary&&bn(e.primary)?e.primary:null;return[...new Set([t,n,...i].filter(e=>!!e&&bn(e)))]}function bh(e){const t=yh(e),i=e.marker?.light_entity;return i&&t.includes(i)?i:t[0]||null}function wh(e,t){if(!1===t.marker?.is_light)return[];if(!0===t.marker?.is_light){return[{eid:bh(t),via:"forced"}]}const i=t.primary||_h(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 kh=new WeakMap,xh=new WeakMap;function $h(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 Sh(e){const t=$h(e),i=kh.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,gh(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(bn):t.controls.filter(bn)),n=bh(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 kh.set(e,a),a}function Mh(e){return Sh(e).incomingByMarker}function Rh(e,t){const i=fh(t.marker?.binding,t.controls??t.marker?.controls,t.entities),n=gh(t.marker?.binding,t.marker?.controls??t.controls,t.entities);return(null!=t.marker?.is_light||!i.length&&!n.some(e=>e.startsWith("marker:")))&&wh(e,t).length>0}function Th(e,t){return wh(e,t).some(e=>!!e.eid)}function Ch(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 Dh(e,t){const i=fh(t.marker?.binding,t.controls??t.marker?.controls,t.entities).map(e=>({eid:e,via:"controls"})),n=Rh(e,t)?wh(e,t):[];for(const e of n)e.eid&&i.some(t=>t.eid===e.eid)||i.push(e);return i}function zh(e,t,i,n){if(null!=i)return zh(e,t,null,n).filter(e=>vh(e.device,i));const r=$h(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=Ic(n),a=xh.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}=Sh(t),u=null==i?l:l.filter(e=>vh(e,i)),p=new Map,_=new Map;for(const t of u){const i=Dh(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(bn):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&&Hc(i.device.marker)&&(i.on=Nc(i.device.marker,n))}const f=new Map,g=e=>{const t=f.get(e.key);(!t||e.castsGlow&&!t.castsGlow)&&f.set(e.key,e)};for(const t of l){const n=h.get(t)||[],r=null==i||vh(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)g(e);continue}if(!bn(i)||!m.get(t)?.has(i))continue;const n=_.get(i);n?g(n):r&&g({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)||[])g(e)}const v=[...f.values()];return xh.set(t,{graphFingerprint:r,stateFingerprint:o,virtualLightFingerprint:s,registry:e?.entities,sources:v}),v}function Ah(e){const t=e.filter(e=>e.castsGlow);return t.find(e=>e.on)||t[0]||null}function Oh(e){return e.length?e.some(e=>e.on)?"on":"off":"none"}function Ph(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 Ri(i)}function Fh(e,t){for(const i of t){if(!dh(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 Eh(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 Ih(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 Hh(e,t){for(const i of t){if(!Ih(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 Nh(e,t){if(!t)return[];const i=[];for(const[t,n]of Object.entries(e.entities)){if(!t.startsWith("light.")||n.hidden||!th(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(!th(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 Lh(e,t,i,n,r){const o=Fe(t,i,r);if(o!==Pe)return o;const s=[];for(const t of n){const i=e.states[t]?.attributes?.device_class;i&&s.push(i)}return function(e){for(const t of e){const e=Oe[t];if(e)return e}return null}(s)??Pe}function qh(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 Wh(e,t,i){if(!t||!i||t===i)return[...e];const n=`marker:${t}`,r=`marker:${i}`;return e.map(e=>{const t=Array.isArray(e.controls)?e.controls.map(e=>e===n?r:e):e.controls,i="derived_marker_state"===e.value_badge?.source?.kind&&e.value_badge.source.ref===n?{...e.value_badge,source:{...e.value_badge.source,ref:r}}:e.value_badge;return t===e.controls&&i===e.value_badge?e:{...e,controls:t,value_badge:i}})}function jh(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 Bh(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 Vh(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 Uh(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 Gh(e,t,i,n,r){const o=fh(t.binding,t.controls,e.entities).filter(e=>!Uh(i,e,n)).filter(e=>"active"===sh(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 Kh(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 Yh(e){const t=e.hass,i=e.registry||Jc(t),n=ih(t,i),r=nh(t,i),{areaToSpace:o,markers:s,settings:a,excluded:l,showAll:c,firstSpaceId:h,loc:d,iconRules:u}=e,p=!1!==a.group_lights,_=Vh(s),m=Nh(n,p).filter(e=>!Uh(n,e.eid,_)),f=new Set(m.map(e=>e.area)),g=ah(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=lh(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=sh(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 _=ch(n,e.id,g[e.id]||[],y);if(_.partial&&!_.entityIds.length)continue;const m=_.entityIds,v=_.partial?{kind:"active",enabledEntityIds:m,allEntityIds:m}:s,$=hh(n,e,m),S=!a.filter_seeded;if(S&&!c){if(l.has($))continue;if("Group"===e.model)continue;if(/scene/i.test(e.model||""))continue;if(/bridge/i.test((e.model||"")+(e.name||"")))continue;if("myheat"===$&&e.via_device_id)continue}const M=(e.name_by_user||e.name||d("device.unnamed")).trim(),R=M+"|"+r;let T=Lh(n,M,e.model,m,u);if(m.some(e=>e.startsWith("lock."))&&(T="mdi:lock"),S&&!c&&p&&"mdi:lightbulb"===T&&f.has(r))continue;k[R]=(k[R]||0)+1;const C=k[R]>1?M+" "+k[R]:M,D={id:e.id,name:C,model:e.model||"",area:r,space:o[r],icon:T,entities:m,allEntities:v.allEntityIds,bindingStatus:v,bindingKind:"device",bindingRef:e.id,pdfs:[]};D.primary=mh(n,m,T),"mdi:thermometer"!==T&&"mdi:air-filter"!==T||(D.temp=Fh(n,m)),D.primary&&Ih(n,D.primary)&&(D.hum=Hh(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?sh(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}=Kh(e,s?.area_id,o,h),m="active"===t.kind?t.enabledEntityIds:[];let f=s?Lh(n,s.name_by_user||s.name||"",s.model,m,u):"mdi:help-circle";m.some(e=>e.startsWith("lock."))&&(f="mdi:lock");const g={id:e.id,name:s?.name_by_user||s?.name||d("device.fallback"),model:s?.model||"",area:a,space:p,icon:f,entities:m,allEntities:t.allEntityIds.length?t.allEntityIds:s&&v[s.id]||[],bindingStatus:t,bindingKind:"device",bindingRef:l};g.primary=mh(n,m,f),"mdi:thermometer"!==f&&"mdi:air-filter"!==f||(g.temp=Fh(n,m)),g.primary&&Ih(n,g.primary)&&(g.hum=Hh(n,m)),Gh(g,e,r,_,i),x.push(g)}else if("entity"===s){if(Uh(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}=Kh(e,a,o,h),m=n.states[l],f=s?.name||m?.attributes?.friendly_name||l;let g=Lh(n,f,"",[l],u);l.startsWith("lock.")&&(g="mdi:lock");const v={id:e.id,name:f,model:"",area:d,space:p,icon:g,entities:"active"===t.kind?[l]:[],allEntities:[l],bindingStatus:t,primary:"active"===t.kind?l:void 0,bindingKind:"entity",bindingRef:l};"mdi:thermometer"!==g&&"mdi:air-filter"!==g||!v.entities.length||(v.temp=Fh(n,v.entities)),v.entities.length&&Ih(n,l)&&(v.hum=Hh(n,v.entities)),Gh(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};Gh(s,e,r,_,i),x.push(s)}}return x}function Zh(e){const{marker:t,siblingMarkers:i=[],...n}=e;return Yh({...n,markers:[...i.filter(e=>e.id!==t.id),t]}).find(e=>e.id===t.id)||null}function Xh(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=Vh(i);return"device"===r?s.devices.has(o):"entity"===r&&Uh(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?Fh(e,t):Hh(e,t)}return null}const Jh=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 Qh(e,t){return t.area?t.area:e&&t.id?`@room/${encodeURIComponent(e)}/${encodeURIComponent(t.id)}`:null}function ed(e){return null===e.area&&e.space&&e.room_id?Qh(e.space,{id:e.room_id,area:null}):e.area||null}function td(e,t,i){const n=new Map;if(!e?.entities)return n;const r=Vh(i),o=new Set,s=new Map,a=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&&o.add(n);const r=ed(e);r&&("entity"!==i||s.has(n)?"device"!==i||a.has(n)||a.set(n,r):s.set(n,r))}const l=new Map;for(const[t,i]of Object.entries(e.entities)){if(i.device_id&&r.devices.has(i.device_id)&&!r.liveEntities.has(t)||!i.device_id&&r.entities.has(t)&&!r.liveEntities.has(t))continue;const n=i.device_id?e.devices?.[i.device_id]:null;if(!th(i)||n&&!th(n))continue;const c=s.get(t)||(i.device_id?a.get(i.device_id):null)||i.area_id||n?.area_id||null;if(!c)continue;if(i.entity_category)continue;if(!(o.size>0&&t.startsWith("climate.")&&(o.has(t)||i.device_id&&o.has(i.device_id)))){if(Te.has(i.platform))continue;if(Jh.test(t))continue}let h=l.get(c);h||(h=new Map,l.set(c,h));const d=i.device_id||t;let u=h.get(d);if(!u){const r=e.states?.[t];u={name:(n?n.name_by_user||n.name:i.name||r?.attributes?.friendly_name||t)||t,model:n?.model,ents:[]},h.set(d,u)}u.ents.push(t)}for(const[i,r]of l){const s=[],a=[];for(const[i,n]of r){const r=Lh(e,n.name,n.model,n.ents,t),l="mdi:thermometer"===r||"mdi:air-filter"===r;if(l){const t=Fh(e,n.ents);null!=t&&s.push(t)}if(o.size>0&&(o.has(i)||n.ents.some(e=>o.has(e)))){const t=Eh(e,n.ents);null!=t&&s.push(t)}if(l||"mdi:water-percent"===r){const t=Hh(e,n.ents);null!=t&&a.push(t)}}(s.length||a.length)&&n.set(i,{temp:s.length?Math.round(s.reduce((e,t)=>e+t,0)/s.length*10)/10:null,hum:a.length?Math.round(a.reduce((e,t)=>e+t,0)/a.length):null})}return n}function id(e,t,i){const n=[];for(const r of t){if(r.area!==i||r.virtual)continue;const t=Ph(e,r.entities);null!=t&&n.push(t)}return Ri(n)}const nd={offStates:["off"],unknownUsesToggle:!0},rd={light:nd,switch:nd,fan:nd,humidifier:nd,input_boolean:nd,automation:nd,remote:nd,group:nd,climate:{...nd,featureMasks:{turn_on:256,turn_off:128,toggle:384}},media_player:{...nd,featureMasks:{turn_on:128,turn_off:256,toggle:384}},siren:{...nd,featureMasks:{turn_on:1,turn_off:2,toggle:3}},vacuum:{...nd,featureMasks:{turn_on:1,turn_off:2,toggle:3}},water_heater:{...nd,featureMasks:{turn_on:8,turn_off:8,toggle:8}},camera:{...nd,featureMasks:{turn_on:1,turn_off:1,toggle:1}}};function od(e){return e.slice(0,e.indexOf("."))}function sd(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 ad(e,t,i){return sd(e,t,i)?{domain:t,service:i}:sd(e,"homeassistant",i)?{domain:"homeassistant",service:i}:null}function ld(e,t){return e?.entities?.[t]||null}function cd(e,t,i){const n=e?.states?.[i],r=ld(t,i);return n?.attributes?.friendly_name||r?.name||r?.original_name||i}function hd(e,t){const i=ld(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 dd(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 ud(e,t,i){const n=od(i);if("lock"===n||"alarm_control_panel"===n)return!0;if("cover"!==n)return!1;const r=e?.states?.[i],o=ld(t,i),s=String(r?.attributes?.device_class||o?.device_class||o?.original_device_class||"");return Ei.has(s)}function pd(e,t,i,n,r){return{ref:i,entityId:n,name:n?cd(e,t,n):null,reason:r}}function _d(e,t,i,n,r,o=null){return{target:null,skipped:pd(e,t,i,n,r),semantics:o,nextEffect:null,command:null}}function md(e,t,i,n,r=i){const o=od(i);if("cover"!==o&&"valve"!==o)return function(e,t,i,n,r=i){const o=od(i),s=e?.states?.[i];if(hd(t,i))return _d(e,t,r,i,"ha-disabled","power");if(ud(e,t,i))return _d(e,t,r,i,"secure");if(!s)return _d(e,t,r,i,"missing","power");if("unavailable"===s.state)return _d(e,t,r,i,"unavailable","power");const a=rd[o];if(!a)return _d(e,t,r,i,"unsupported");let l,c;if("unknown"===s.state||""===s.state){if(!a.unknownUsesToggle)return _d(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&&!dd(s,h))return _d(e,t,r,i,"unsupported","power");const d=ad(e,o,c);return d?{target:{entityId:i,name:cd(e,t,i),state:String(s.state||""),via:n},skipped:null,semantics:"power",nextEffect:l,command:{...d,data:{entity_id:i}}}:_d(e,t,r,i,"unsupported","power")}(e,t,i,n,r);if(hd(t,i))return _d(e,t,r,i,"ha-disabled",o);if(ud(e,t,i))return _d(e,t,r,i,"secure",o);const s=e?.states?.[i];if(!s)return _d(e,t,r,i,"missing",o);if("unavailable"===s.state)return _d(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&&dd(i,r.feature)&&sd(e,t,r.service)?r:dd(i,3)&&sd(e,t,"toggle")?{service:"toggle",effect:"toggle"}:null}(e,o,s);if(!a)return _d(e,t,r,i,"unsupported",o);return{target:{entityId:i,name:cd(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 fd(e){return"entity"===e.bindingKind?e.bindingRef&&bn(e.bindingRef)?[e.bindingRef]:[]:"virtual"===e.bindingKind?[]:yh(e)}function gd(e){const t=e.marker?.toggle_entity;return t&&fd(e).includes(t)?t:null}function vd(e,t,i){const n=function(e,t){if("entity"===e.bindingKind&&e.bindingRef){const t=e.marker?.light_entity?bh(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&&bn(e.primary)?bh(e):null;return[...new Set([n,..._h(t,i)].filter(e=>!!e))]}(i,t);if(!n.length)return null;const r="entity"===i.bindingKind?"binding":"device-role";if("binding"===r)return md(e,t,n[0],r);let o=null,s=null;for(const i of n){const n=md(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 yd(e){const t=e.skipped?.reason;return"missing"===t?"unavailable":t||"unsupported"}function bd(e,t){return{origin:e,kind:"none",semantics:null,targets:[],skippedTargets:[],noneReason:t,nextEffect:null,command:null}}function wd(e,t){return"cover"===e||"toggle"===e?"toggle":"more-info"===e||"run"===e||"info"===e?e:(null==e||""===e)&&"light"===t?"toggle":"info"}function kd(e,t){return{origin:e,kind:"single",semantics:t.semantics,targets:t.target?[t.target]:[],skippedTargets:t.skipped?[t.skipped]:[],noneReason:t.command?null:yd(t),nextEffect:t.nextEffect,command:t.command}}function xd(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=md(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=ad(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=>pd(e,t,i.entityId,i.entityId,"unsupported"))],noneReason:"unsupported",nextEffect:null,command:null}}function $d(e){return String(e.marker?.id||e.id||"")}function Sd(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&&Hc(o)){const t=String(o?.id||i.id||""),n=Mh(e.devices).get(t);if(n)return function(e,t){const i=e.registryHass||e.hass;return xd(e.hass,i,t.driverEids.map(e=>({entityId:e,via:"control-marker-driver",ref:`marker:${t.markerId}`})))}(e,n);const s=Nc(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(gh(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=gh(n.marker?.binding,n.marker?.controls??n.controls,n.entities),a=e.lightSources||zh(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=Mh(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:")){bn(e)?d.push({entityId:e,via:"control-entity",ref:e}):u.push(pd(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?cd(i,o,n):null),reason:"ha-disabled"})}else u.push(pd(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=$d(n),_=c.get(a)?.controllers.find(e=>$d(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(pd(i,o,e,null,s?"missing":"unsupported"))}return xd(i,o,d,u)}(e,gd(i))}if("legacy-cover"===r){const e=i.entities.find(e=>e.startsWith("cover."))||i.allEntities?.find(e=>e.startsWith("cover."));return e?kd(r,md(t,n,e,"device-role")):bd(r,"no-actionable-entity")}const s=gd(i),a=s?md(t,n,s,"entity"===i.bindingKind?"binding":"device-role"):vd(t,n,i);return a?kd(r,a):bd(r,i.virtual||"virtual"===i.bindingKind?"no-actionable-entity":"no-binding")}function Md(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 Rd(e){return e?e.operation?e.operation:e.command?{kind:"ha-service",command:e.command}:null:null}const Td=new Set(["missing","ha-disabled","unavailable"]);function Cd(e,t){const i=Rd(e),n=Rd(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=Md(e),n=Md(t);return i.length===n.length&&i.every((e,t)=>e===n[t])}(i.command,n.command))}function Dd(e,t){const i=e.targets[0]||e.skippedTargets[0],n=[];return"group"===e.kind?e.targets.length&&n.push(t.group(e.targets)):i&&n.push(t.single(i)),e.nextEffect&&e.targets.length&&n.push("group"===e.kind?t.groupCurrentNext(e.targets,e.nextEffect):t.currentNext(e.targets[0],e.nextEffect)),e.skippedTargets.length&&n.push(t.skipped(e.skippedTargets)),!e.command&&e.noneReason&&n.push(t.none(e.noneReason)),n}const zd=e=>!!e&&e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]);function Ad(e,t=5,i=5){return yo(e.cm,t,i)/2}function Od(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(!zd(a.a)||!zd(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:yo(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 Pd(e,t,i=1,n=5,r=5){return Od(e,t,i,n,r,0)}function Fd(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 Pd(e,t,i,n,r);const a=Od(e,t,i,n,r,Ad(s,n,r));return"does-not-fit"===a.reason?{resolved:null,reason:"does-not-fit-jamb"}:a}function Ed(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 Id(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 Hd(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 Nd(e,t,i){return e.flatMap(e=>!zd(e.a)||!zd(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:yo(e.cm,t,i)/2,partitionHost:{kind:"partition",id:e.id}}])}function Ld(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 qd(e,t,i=1e-9){const n=e.length/(2*e.axis.length),r=e.t-n,o=e.t+n;return t.some(t=>{if(t.host.id!==e.host.id||t.opening.id===e.opening.id)return!1;const n=t.length/(2*t.axis.length);return Math.max(r,t.t-n)[]);for(let i=0;i=1-1e-9||u<=1e-9||u>=1-1e-9||(t[i].push(d),t[s].push(u))}}const i=[];for(let n=0;ne-t),1];for(let e=1;e{const i=t[2]-t[0],n=t[3]-t[1],r=i*i+n*n;if(!(r>0))return Math.hypot(e[0]-t[0],e[1]-t[1]);const o=Math.max(0,Math.min(1,((e[0]-t[0])*i+(e[1]-t[1])*n)/r));return Math.hypot(e[0]-(t[0]+o*i),e[1]-(t[1]+o*n))},Gd=(e,t,i,n)=>{const r=n[2]-n[0],o=n[3]-n[1],s=t*o-i*r;if(Math.abs(s)<1e-12)return 1/0;const a=n[0]-e[0],l=n[1]-e[1],c=(a*o-l*r)/s;if(!(c>1e-9))return 1/0;const h=(a*i-l*t)/s;return h<-1e-9||h>1+1e-9?1/0:c};function Kd(e,t,i,n=96){if(!(t>0&&Number.isFinite(e[0])&&Number.isFinite(e[1])))return[];const r=[];for(const n of i){if(!n||n.length<4)continue;if(![n[0],n[1],n[2],n[3]].every(Number.isFinite))continue;const i=Ud(e,n);if(i<1e-7)return[];i>t||r.push(n)}const o=[],s=Math.max(12,Math.round(n));for(let e=0;ee-t);const l=[];let c=Number.NEGATIVE_INFINITY;for(const i of o){if(i-c<1e-9)continue;c=i;const n=Math.cos(i),o=Math.sin(i);let s=t;for(const t of r){const i=Gd(e,n,o,t);i=3?l:[]}const Yd=[o` + :host { + --hp-bg: var(--card-background-color, #16212e); + --hp-line: var(--divider-color, #2b3d4f); + --hp-txt: var(--primary-text-color, #e6edf3); + --hp-muted: var(--secondary-text-color, #8aa0b3); + --hp-accent: var(--primary-color, #3ea6ff); + --hp-on: #ffd45c; + --hp-open: #ff9f43; + /* design tokens (UI chrome only). The icon/plan scale math stays on + --icon-size/--dev-size cqw units and never uses these. */ + /* spacing scale, fact-based; stray 3/5/7/9/13/14px values are unified + onto the nearest step (max +-2px, the whole point of the pass) */ + --sp-1: 2px; + --sp-2: 4px; + --sp-3: 6px; + --sp-4: 8px; + --sp-5: 12px; + --sp-6: 16px; + /* px radii of dialogs/buttons/plates (the 22% badge radius is scale math) */ + --rad-s: 6px; + --rad-m: 8px; + --rad-l: 12px; + /* font tiers: fine print+labels / body+buttons / title */ + --fs-s: 12px; + --fs-m: 13px; + --fs-l: 15px; + /* elevation: badge / floating panel (menu, tip, toast) / dialog */ + --shadow-1: 0 1px 3px rgba(0, 0, 0, 0.45); + --shadow-2: 0 6px 22px rgba(0, 0, 0, 0.45); + --shadow-3: 0 8px 30px rgba(0, 0, 0, 0.5); + } + ha-card { + overflow: visible; /* overflow:hidden breaks position:sticky on the header */ + } + .empty { + padding: 40px 24px; + color: var(--hp-txt); + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + gap: var(--sp-4); + } + .empty .big { + --mdc-icon-size: 56px; + color: var(--hp-accent); + opacity: 0.7; + } + .empty .muted { + color: var(--hp-muted); + font-size: var(--fs-m); + margin: 0; + } + .empty .btn { + margin-top: var(--sp-4); + } + @keyframes fixedfloor-spin { + to { transform: rotate(360deg); } + } + .spacer { + flex: 1; + } + .bootveil { + position: absolute; + inset: 0; + z-index: 40; + display: flex; + align-items: center; + justify-content: center; + background: var(--hp-bg, #16212e); + opacity: 1; + transition: opacity 0.15s ease; + pointer-events: none; + } + .bootveil.off { + opacity: 0; + } + .bootveil .boothouse { + position: static; /* the main .zoomwrap SVG is pinned to inset:0 — not this icon */ + width: 56px; + height: 56px; + fill: var(--hp-accent); + opacity: 0.85; + animation: hp-boot-pulse 1.3s ease-in-out infinite; + } + @keyframes hp-boot-pulse { + 0%, 100% { opacity: 0.3; transform: scale(0.94); } + 50% { opacity: 0.9; transform: scale(1); } + } + @media (prefers-reduced-motion: reduce) { + .bootveil .boothouse { + animation: none; + opacity: 0.7; + } + } + @keyframes hp-pulse-short { + 0% { transform: scale(1); opacity: 0.55; } + 70% { opacity: 0.22; } + 100% { transform: scale(var(--ripple-scale, 1.5)); opacity: 0; } + } + /* Alternate identity: a rapid retrigger restarts the browser timeline. */ + @keyframes hp-pulse-short-b { + 0% { transform: scale(1); opacity: 0.55; } + 70% { opacity: 0.22; } + 100% { transform: scale(var(--ripple-scale, 1.5)); opacity: 0; } + } + @keyframes hp-pulse-continuous { + 0% { transform: scale(1); opacity: 0.55; } + 65% { opacity: 0.18; } + 100% { transform: scale(var(--ripple-scale, 1.5)); opacity: 0; } + } + @keyframes hp-pulse-alarm { + 0% { transform: scale(1); opacity: 0.72; } + 100% { transform: scale(1.5); opacity: 0; } + } + /* Space changes keep their direction, but travel only a few percent: the + motion explains what changed without making the whole plan fly around. */ + @keyframes hp-slide-left { + 0% { transform: translateX(4%); opacity: 0.72; } + 100% { transform: translateX(0); opacity: 1; } + } + @keyframes hp-slide-right { + 0% { transform: translateX(-4%); opacity: 0.72; } + 100% { transform: translateX(0); opacity: 1; } + } + @keyframes hp-sunfade-in { + from { opacity: 0; } + to { opacity: 1; } + } + @keyframes hp-sunfade-out { + from { opacity: 1; } + to { opacity: 0; } + } + .sr-only { + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; + } + .toast { + position: fixed; + pointer-events: none; + left: 50%; + bottom: 22px; + transform: translateX(-50%); + background: var(--hp-bg); + border: 1px solid var(--hp-accent); + color: var(--hp-txt); + padding: var(--sp-4) var(--sp-6); + border-radius: var(--rad-l); + font-size: var(--fs-m); + box-shadow: var(--shadow-2); + z-index: 120; + max-width: 90vw; + } +`,o` + .fixedfloor-loading { + animation: fixedfloor-spin 1.1s linear infinite; + } + .fixedfloor-error p { + max-width: 42rem; + margin: 0; + overflow-wrap: anywhere; + } + @media (prefers-reduced-motion: reduce) { + .fixedfloor-loading { animation: none; } + } + .stage.noplan { + background: #ffffff; + } + /* Editors always keep the white drawing sheet — even when a backdrop + image is loaded. Without this, a picture plan painted the theme card + colour under the grid (owner 2026-08-05). View keeps the historical + theme / .noplan split. */ + .stage.mode-plan, + .stage.mode-devices, + .stage.mode-decor { + background: #ffffff; + } + .stage { + position: relative; + width: 100%; + container-type: inline-size; + overflow: hidden; + touch-action: none; /* custom pinch/pan gestures */ + background: var(--ha-card-background, var(--card-background-color, #111)); + } + .zoomwrap { + position: absolute; + inset: 0; + z-index: 1; + } + .stage.mode-transition, + .stage.mode-transition .zoomwrap { + transition: none !important; + } + .stage.mode-transition .hp-view-only-layer, + .stage.mode-transition .hp-editor-only-layer { + pointer-events: none; + will-change: opacity; + } + .stage.mode-transition .hp-paper { + fill: var(--hp-mode-paper) !important; + } + /* Four-phase environment (#146): constant layers cross-fade because CSS + gradients themselves are not reliably interpolated. Everything stays + behind the plan; the plan tree is never dimmed, tinted or faded. */ + .hp-day-cycle-env { + position: absolute; + inset: 0; + z-index: 0; + overflow: hidden; + pointer-events: none; + isolation: isolate; + } + .hp-day-cycle-bg { + position: absolute; + inset: 0; + opacity: 0; + overflow: hidden; + transition: opacity 1100ms cubic-bezier(.22, .61, .36, 1); + } + .hp-day-cycle-bg.active { opacity: 1; } + .hp-day-cycle-sun { + position: absolute; + left: var(--hp-day-cycle-sun-x); + top: var(--hp-day-cycle-sun-y); + width: clamp(140px, 25cqw, 250px); + height: clamp(140px, 25cqw, 250px); + transform: translate(-50%, -50%); + border-radius: 50%; + filter: blur(10px); + opacity: var(--hp-day-cycle-sun-opacity); + transition: + left 1100ms cubic-bezier(.22, .61, .36, 1), + top 1100ms cubic-bezier(.22, .61, .36, 1), + opacity 1100ms cubic-bezier(.22, .61, .36, 1); + } + .stage.mode-transition .hp-day-cycle-env { transition: none; } + .stage.daycycle .hp-paperg, + .hp-static-stage.daycycle .hp-paperg { + filter: + drop-shadow(0 0 1px var(--hp-day-cycle-outline-near)) + drop-shadow(0 0 5px var(--hp-day-cycle-outline-mid)) + drop-shadow(0 0 10px var(--hp-day-cycle-outline-far)); + transition: filter 1100ms cubic-bezier(.22, .61, .36, 1); + } + @media (prefers-reduced-motion: reduce) { + .hp-day-cycle-bg, + .hp-day-cycle-sun, + .stage.daycycle .hp-paperg, + .hp-static-stage.daycycle .hp-paperg { + transition: none; + } + } + .sunlayer { + pointer-events: none; + } + .compass { + width: 120px; + height: 120px; + flex: none; + touch-action: none; + cursor: grab; + user-select: none; + } + .compass:active { + cursor: grabbing; + } + .compass .cring { + fill: rgba(255, 255, 255, 0.04); + stroke: var(--divider-color, #444); + stroke-width: 2; + } + .compass .ctick { + stroke: var(--secondary-text-color, #9aa4ad); + stroke-width: 2; + } + .compass .ctick.minor { + stroke-width: 1; + opacity: 0.6; + } + .compass .cneedle line { + stroke: var(--primary-color, #3ea6ff); + stroke-width: 2.5; + stroke-linecap: round; + } + .compass .cneedle path { + fill: var(--primary-color, #3ea6ff); + } + .compass .cneedle text { + fill: var(--text-primary-color, #fff); + font-size: 11px; + font-weight: 700; + } + .compass .cdeg { + fill: var(--secondary-text-color, #9aa4ad); + font-size: 13px; + } + .compass.unset .cneedle { + opacity: 0.35; + } + /* HP-1552: first-open boot veil — the plan hides until the stage height settles */ + .stage.hpboot .zoomwrap, + .stage.hpboot .zoombadge { + visibility: hidden; + } + /* AUD-1552-02: post-veil grace — HA chrome landing after the cap moves + the stage height smoothly; the viewport ResizeObserver refits the plan + along the transition, so a late panel glides instead of jumping. */ + .stage.hpsettle { + transition: height 0.25s ease; + } + @media (prefers-reduced-motion: reduce) { + .stage.hpsettle { + transition: none; + } + } + .zoomctl { + display: inline-flex; + gap: var(--sp-1); + background: rgba(127, 127, 127, 0.12); + border-radius: var(--rad-m); + padding: var(--sp-1); + } + .zoomctl .zb { + border: none; + padding: var(--sp-3) var(--sp-4); + } + .zoomctl .zb[disabled] { + opacity: 0.4; + pointer-events: none; + } + .projection-toggle { + min-width: 44px; + min-height: 44px; + justify-content: center; + padding: var(--sp-3); + } + /* docs/CANVAS.md §5: the plane has no edges, so you can pan until nothing + is on screen. One pointer home, one click back. */ + .homearrow { + position: absolute; + z-index: 12; + transform: translate(-50%, -50%); + width: 40px; + height: 40px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + background: var(--card-background-color, var(--hp-bg)); + color: var(--hp-accent); + border: 1px solid var(--hp-accent); + opacity: 0.9; + padding: 0; + } + .homearrow ha-icon { + --mdc-icon-size: 22px; + line-height: 1; + } + .zoombadge { + position: absolute; + z-index: 12; + left: var(--sp-4); + bottom: var(--sp-4); + background: var(--card-background-color, var(--hp-bg)); + opacity: 0.92; + color: var(--hp-txt); + border: 1px solid var(--hp-accent); + border-radius: var(--rad-m); + padding: var(--sp-1) var(--sp-4); + font-size: var(--fs-s); + font-weight: 600; + pointer-events: none; + } + /* Only the plan canvas owns the whole zoom wrapper. Context trays now live + inside .stage as well, and may contain small SVG previews (furniture in + particular); the old descendant-wide stage-SVG selector stretched every + preview over the tray and stacked them into one blocking artefact. The + vacuum trail/fit overlays have their own explicit geometry below. */ + .zoomwrap > svg { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + display: block; + } + .plan-svg { z-index: 1; } + .iso-underlay-svg { z-index: 0; overflow: visible; } + .iso-shadows-svg { z-index: 3; overflow: visible; } + .iso-walls-svg { + z-index: 4; + overflow: visible; + } + .iso-underlay-svg, + .iso-shadows-svg, + .iso-walls-svg, + .iso-underlay, + .iso-shadows, + .iso-walls, + .iso-openings { + pointer-events: none; + } + .iso-side-hi { stop-color: #b9bdbe; } + .iso-side-lo { stop-color: #969c9f; } + .iso-top-hi { stop-color: #fafaf7; } + .iso-top-lo { stop-color: #e2e4e2; } + .iso-wall-side { + fill: url(#hp-iso-wall-side) #a8acae; + stroke: #92989b; + stroke-width: 0.7; + vector-effect: non-scaling-stroke; + } + .iso-wall-top { + fill: url(#hp-iso-wall-top) #f3f3f1; + stroke: #d7d9d8; + stroke-width: 0.8; + vector-effect: non-scaling-stroke; + } + .iso-floor-side { + fill: #858b8d; + stroke: #71787b; + stroke-width: 0.7; + vector-effect: non-scaling-stroke; + } + .iso-opening-panel { + fill: #d7d9d7; + fill-opacity: 0.96; + stroke: #7f878b; + stroke-width: 0.9; + vector-effect: non-scaling-stroke; + } + .iso-opening-panel.iso-window { + fill: #dfeff4; + fill-opacity: 0.72; + stroke: #8aa7b1; + } + .iso-ambient-shadow { + fill: rgba(15, 21, 25, 0.22); + filter: url(#hp-iso-ambient-shadow); + } + .iso-contact-shadow { + fill: none; + stroke: rgba(22, 28, 31, 0.25); + stroke-width: 3; + filter: url(#hp-iso-contact-shadow); + vector-effect: non-scaling-stroke; + } + .iso-leaf-shadow { + fill: none; + stroke: rgba(18, 23, 27, 0.24); + stroke-width: 4; + filter: url(#hp-iso-leaf-shadow); + vector-effect: non-scaling-stroke; + } + @media (prefers-color-scheme: dark) { + .iso-side-hi { stop-color: #4c555a; } + .iso-side-lo { stop-color: #343c40; } + .iso-top-hi { stop-color: #687176; } + .iso-top-lo { stop-color: #50585d; } + .iso-wall-side { stroke: #30373b; } + .iso-wall-top { stroke: #7b858a; } + .iso-floor-side { fill: #2d3438; stroke: #20272a; } + .iso-opening-panel { fill: #626b70; stroke: #899399; } + .iso-opening-panel.iso-window { fill: #75919b; stroke: #abc6ce; } + .iso-ambient-shadow { fill: rgba(0, 0, 0, 0.34); } + .iso-contact-shadow, .iso-leaf-shadow { stroke: rgba(0, 0, 0, 0.38); } + } + @media (forced-colors: active) { + .iso-wall-side, .iso-wall-top, .iso-floor-side, .iso-opening-panel { + fill: Canvas; + stroke: CanvasText; + forced-color-adjust: auto; + } + .iso-ambient-shadow, .iso-contact-shadow, .iso-leaf-shadow { display: none; } + } + @supports not (filter: blur(1px)) { + .iso-ambient-shadow, .iso-contact-shadow, .iso-leaf-shadow { display: none; } + } + /* Opaque plan paper (owner 2026-08-03): the scene bg_color / daynight sky + shows ONLY around the plan, never through it. The colour is the + pre-bg_color canvas — the theme card background under an image plan, + plain white for a hand-drawn one (.stage.noplan). On drawn plans the + paper is per-room shapes following the room contours — fill only, + never a stroke, so the paper cannot poke past a wall. Night dimming + comes from the .zoomwrap brightness filter, never from alpha + (docs/SUN.md). */ + .hp-paper { + fill: var(--ha-card-background, var(--card-background-color, #111)); + stroke: none; + } + .stage.noplan .hp-paper, + .stage.mode-plan .hp-paper, + .stage.mode-devices .hp-paper, + .stage.mode-decor .hp-paper { + fill: #ffffff; + } + /* Owner 2026-08-04: «углы границ комнат всё ещё с зубцами». A miter join + on a 30-45° corner shoots a spike far past the wall (and flips to an + ugly bevel once past the miter limit) — the same defect the decor lines + had before they got round caps. Every room border, in EVERY renderer + that reuses these styles (plan view, plan editor, static space-card), + joins its walls with a ROUND join instead: the corner reads as the + stroke's own radius, never as a tooth. The linecap matters only for the + open outlines below, but it costs nothing to state it here. */ + .room { + transition: 0.12s; + cursor: default; /* v1.40.1: rooms are not clickable — the label's link icon is */ + stroke-linejoin: round; + stroke-linecap: round; + } + .room.overlay { + fill: transparent; + stroke: transparent; + stroke-width: calc(2px * var(--hp-cell-visual-scale, 1)); + } + :host([data-pointer-hover]) .stage.mode-view .room.overlay:not(.styled):hover { + stroke: var(--hp-accent); + stroke-opacity: 1; + } + .room.yard { + fill: rgba(75, 140, 90, 0.14); + stroke: #4b8c5a; + stroke-width: calc(2px * var(--hp-cell-visual-scale, 1)); + } + :host([data-pointer-hover]) .stage.mode-view .room.yard:not(.styled):hover { + stroke: var(--hp-accent); + stroke-opacity: 1; + } + .room.styled { + stroke: var(--room-stroke, transparent); + stroke-opacity: var(--room-stroke-op, 0); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + fill: var(--room-fill, transparent); + fill-opacity: var(--room-fill-op, 0); + } + .glow-base-layer, + .glow-base-tunnels, + .glow-pools-frame, + .glow-pools, + .glow-spot { + pointer-events: none; + } + /* The parent isolates all source spots from the room data fill, Glow base, + paper and backdrop. A spot is one circle clipped to the floor its lamp + can see, so the whole spot screen-blends as a single primitive — there is + no mask left to be dropped on a promoted layer. Per-stop alpha already + contains the shared 0.7 ceiling; the spot opacity below only animates + between 0 and 1 and is never another persistent alpha ceiling. */ + .glow-pools-frame, + .glow-pools, + .glow-spot { + isolation: isolate; + } + .glow-pools.blend-screen .glow-spot { + mix-blend-mode: screen; + } + .glow-spot { + opacity: 1; + transition: opacity 500ms ease; + } + .glow-spot.is-entering, + .glow-spot.is-leaving { + opacity: 0; + } + @media (prefers-reduced-motion: reduce) { + .glow-spot { + transition: none; + } + } + /* The explicit late room-hover layer owns the wash and halo. Keeping CSS + filters off room paths prevents Chromium from recompositing the sibling + screen-blended Glow layer for one bright frame on every hover. */ + :host([data-pointer-hover]) .stage.mode-view .room.styled:hover { + stroke: var(--hp-accent); + stroke-opacity: 1; + } + /* doors, windows & gates */ + .op-leaf { + transition: transform 0.6s ease; + } + .op-arc { + stroke-width: calc(1.5px * var(--hp-cell-visual-scale, 1)); + transition: stroke-dashoffset 0.6s ease; + } + /* hover affordance: a rounded outline hugging the wall strip + a grab cursor */ + .op-outline { + fill: none; + stroke: var(--hp-accent); + stroke-width: calc(1.5px * var(--hp-cell-visual-scale, 1)); + opacity: 0; + transition: opacity 0.15s; + pointer-events: none; + } + :host([data-pointer-hover]) .stage.markup g.opening:hover .op-outline { + opacity: 0.9; + } + /* openings are pure status graphics outside Plan mode: no cursor, no hover, + no hit target — View must not interact with them at all */ + .op-hit { + fill: transparent; + pointer-events: none; + cursor: default; + } + .stage.markup .op-hit { + pointer-events: auto; + cursor: grab; + touch-action: none; /* drags, not scrolls, on touch */ + } + .stage.markup .op-hit:active { + cursor: grabbing; + } + .stage.markup .opening.orphan { + pointer-events: auto; + cursor: pointer; + color: var(--error-color, #db4437); + } + .stage.markup .opening.orphan circle { + fill: var(--hp-bg); + stroke: currentColor; + stroke-width: calc(2px * var(--hp-cell-visual-scale, 1)); + } + .stage.markup .opening.orphan text { + fill: currentColor; + font-weight: 800; + font-size: calc(12px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + /* HP-1550-04: in the resize tool the wall handles own the hit test — the + transparent .op-hit of a door at the midpoint of a wall used to sit ON + TOP of the handle and made that wall ungrabbable for both rooms. + Openings are not editable in this tool (they ride along with the wall), + so their hit area goes fully inert; every other Plan tool is untouched. */ + .stage.markup.tool-resize .op-hit { + pointer-events: none; + cursor: default; + } + .stage.mode-view .oplock { + pointer-events: auto; + cursor: pointer; + } + @media (prefers-reduced-motion: reduce) { + .op-leaf, .op-arc { transition: none; } + } + .roomlabel { + pointer-events: none; /* draggable only in plan mode (rule below) */ + position: absolute; + transform: translate(-50%, -50%); + font-size: calc(var(--rl-icon-size, var(--icon-size, 2.5cqw)) * 0.5 * var(--rl-scale, 1) * var(--rl-font, 1) * var(--rl-space, 1)); + font-weight: 700; + letter-spacing: 0.04em; + white-space: nowrap; + cursor: grab; + user-select: none; + z-index: 1; + display: flex; + flex-direction: column; + align-items: center; + gap: 0.15em; + text-align: center; + } + .rlname { + display: inline-flex; + align-items: center; + gap: 0.25em; + font-size: calc(1em * var(--rl-name, 1)); + } + .zoomwrap.slide-left { animation: hp-slide-left 0.18s cubic-bezier(0.2, 0.7, 0.2, 1); } + .zoomwrap.slide-right { animation: hp-slide-right 0.18s cubic-bezier(0.2, 0.7, 0.2, 1); } + @media (prefers-reduced-motion: reduce) { + .zoomwrap.slide-left, + .zoomwrap.slide-right { animation: none; } + } + /* The name is the anchor: the label box is centred on the room point, so + anything that takes part in its layout SHIFTS THE NAME. The gear button + and the metrics hang below as absolutes — the name renders in exactly + the same place in view mode and in the plan editor (owner's request), + and the button sits at the very bottom of the card. */ + /* Standalone, centred on the room, sized from the device icon: icon-size + already rescales with the view, so the button zooms WITH the plan + instead of keeping a constant screen size (owner's spec). */ + .rlgearbtn { + --gear-h: calc(var(--icon-size, 2.5cqw) * 0.77); /* owner: half the previous size */ + position: absolute; + /* dead-centred on the room, both axes (owner's spec) */ + transform: translate(-50%, -50%); + display: inline-flex; + align-items: center; + gap: 0.35em; + height: var(--gear-h); + padding: 0 calc(var(--gear-h) * 0.38); + border: 0; + border-radius: 999px; + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + font: inherit; + font-size: calc(var(--gear-h) * 0.42); + font-weight: 600; + line-height: 1; + white-space: nowrap; + cursor: pointer; + pointer-events: auto; + opacity: 0.92; + box-shadow: var(--shadow-1); + z-index: 2; + } + .rlgearbtn { transition: opacity 0.15s, filter 0.15s; } + :host([data-pointer-hover]) .rlgearbtn:hover { opacity: 1; filter: brightness(1.18); } + .rlgearbtn ha-icon { --mdc-icon-size: calc(var(--gear-h) * 0.55); display: inline-flex; } + .rlgear { + --mdc-icon-size: 0.9em; + display: inline-flex; + margin-right: 0.2em; + opacity: 0.6; + cursor: pointer; + pointer-events: auto; + } + :host([data-pointer-hover]) .rlgear:hover { opacity: 1; } + .rlgo { + --mdc-icon-size: 0.85em; + display: inline-flex; + opacity: 0.55; + } + .stage.mode-view .rlgo { + pointer-events: auto; + cursor: pointer; + } + :host([data-pointer-hover]) .stage.mode-view .rlgo:hover { opacity: 1; } + .roomlabel .rlmetrics { + position: absolute; /* below the name, outside the centring math */ + top: calc(100% + 0.15em); + left: 50%; + transform: translateX(-50%); + white-space: nowrap; + display: flex; + align-items: center; + gap: 0.55em; + font-size: calc(0.75em * var(--rl-meta, 1)); /* feedback: 0.62 was unreadable on a tablet */ + font-weight: 600; + letter-spacing: 0.02em; + opacity: 0.9; + } + .roomlabel .rlm { + display: inline-flex; + align-items: center; + gap: 0.12em; + } + .roomlabel .rlm ha-icon { + --mdc-icon-size: 1.05em; + display: inline-flex; + } + .roomlabel .rlm.lit { opacity: 1; } + .rlhandle { + display: none; + position: absolute; + width: 9px; + height: 9px; + border-radius: 2px; + background: var(--hp-accent); + border: 1px solid var(--card-background-color, #fff); + z-index: 2; + } + .rlhandle.tl { left: -6px; top: -6px; cursor: nwse-resize; } + .rlhandle.br { right: -6px; bottom: -6px; cursor: nwse-resize; } + .rlhandle.tr { right: -6px; top: -6px; cursor: nesw-resize; } + .rlhandle.bl { left: -6px; bottom: -6px; cursor: nesw-resize; } + :host([data-pointer-hover]) .stage.markup .roomlabel:hover .rlhandle { display: block; } + .stage.markup .roomlabel { pointer-events: auto; } + .roomlabel:active { cursor: grabbing; } + .measurelayer { + position: absolute; + inset: 0; + pointer-events: none; + } + .alignline { + stroke: var(--hp-accent); + stroke-width: calc(1.2px * var(--hp-cell-visual-scale, 1)); + stroke-dasharray: + calc(4px * var(--hp-cell-visual-scale, 1)) + calc(4px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + opacity: 0.9; + } + .aligndot { + fill: var(--hp-accent); + pointer-events: none; + } + .measurelabel.on45 { + color: #4bd28f; + border-color: #4bd28f; + } + .measurelabel { + position: absolute; + transform: translate(12px, -150%); + font-size: var(--fs-s); + font-weight: 600; + padding: 1px var(--sp-3); + border-radius: var(--rad-s); + background: rgba(0, 0, 0, 0.72); + color: #fff; + white-space: nowrap; + pointer-events: none; + user-select: none; + z-index: 3; + } + .measurelabel.opdimension { + transform: translate( + calc(-50% + var(--op-label-shift-x, 0px)), + calc(-50% + var(--op-label-shift-y, -12px)) + ); + border: 1px solid var(--hp-open, #ff9800); + } + /* decor (background) layer */ + .decorlayer .dshape { pointer-events: none; } + .stage.mode-decor .decorlayer .dshape { + pointer-events: visiblePainted; + cursor: pointer; + } + .stage.mode-decor.dtool-select .decorlayer .dshape { cursor: move; } + /* …but a DRAWING tool owns the canvas: existing shapes stop being targets + entirely, so a new line can start exactly on the end of an old one + instead of grabbing it (owner, 2026-08-04). Same for the picture tool — + a shape lying over the plan must not block the picture's own drag. + Only select (move) and erase (delete) keep the shapes clickable. */ + .stage.mode-decor.dtool-line .decorlayer .dshape, + .stage.mode-decor.dtool-rect .decorlayer .dshape, + .stage.mode-decor.dtool-ellipse .decorlayer .dshape, + .stage.mode-decor.dtool-text .decorlayer .dshape, + .stage.mode-decor.dtool-furniture .decorlayer .dshape, + .stage.mode-decor.dtool-backdrop .decorlayer .dshape { pointer-events: none; } + /* the furniture tool is a stamp: the press must reach the stage even when + it lands on a sofa that is already there (docs/FURNITURE.md §4) */ + .stage.mode-decor.dtool-furniture { cursor: copy; } + /* ONE exception (owner, 2026-08-04): under the TEXT tool an existing LABEL + is a target again — pressing it opens its editor instead of starting a + new label on top of the old one. Only labels: a line or a rectangle + under the text tool stays inert, so the press reaches the stage and a + new label is created there. */ + .stage.mode-decor.dtool-text .decorlayer .dshape.dtext, + .stage.mode-decor.dtool-select .decorlayer .dshape.dtext, + .stage.mode-decor.dtool-erase .decorlayer .dshape.dtext { + /* A label is one logical decor object. SVG's visiblePainted would hit + only the ink of individual glyphs, so spaces, counters and the area + inside its selection glow behaved like empty canvas. */ + pointer-events: visiblePainted; + pointer-events: bounding-box; + } + .stage.mode-decor.dtool-text .decorlayer .dshape.dtext { + cursor: text; + } + /* Erasing a hairline must not require pixel-perfect aim. The duplicate + geometry is invisible and exists only while Erase is active. A + non-scaling stroke keeps the target comfortably wide at every zoom. */ + .decorlayer .derasehit { + fill: none; + stroke: transparent; + stroke-width: 16px; + stroke-linecap: round; + stroke-linejoin: round; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .stage.mode-decor.dtool-erase .decorlayer .derasehit { + pointer-events: stroke; + } + /* A dashed line must remain selectable across its gaps. This proxy also + makes the only entry to line-style properties — double click in Select — + practical for hairlines at every zoom. */ + .decorlayer .dselecthit { + fill: none; + stroke: transparent; + stroke-width: 16px; + stroke-linecap: round; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .stage.mode-decor.dtool-select .decorlayer .dselecthit { + pointer-events: stroke; + cursor: move; + } + .decorlayer .dsel { + filter: drop-shadow(0 0 3px var(--hp-accent)); + } + .decorlayer .ddraft { + stroke-dasharray: + calc(6px * var(--hp-cell-visual-scale, 1)) + calc(5px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + .decorlayer text { + font-weight: 600; + user-select: none; + dominant-baseline: middle; + text-anchor: middle; + } + .stage.mode-decor { + outline: 2px solid #26a69a; + outline-offset: -2px; + } + /* backdrop transform frame (docs/BACKDROP.md §2). Editor chrome: the + outline never takes a pointer, the four corner handles do — and they are + finger-sized (r = 2 % of the visible view), because this is dragged on a + tablet as often as with a mouse. */ + .bdframe .bdbox { + fill: none; + stroke: var(--hp-accent); + stroke-width: 2; + stroke-dasharray: 10 7; + vector-effect: non-scaling-stroke; + pointer-events: none; + opacity: 0.9; + } + /* the HIT circle: invisible, finger-sized, the only thing that takes a + pointer. The visible bead is .bdknob, a quarter of its radius — the same + visual/hit split .dthandle + .dtknob and .rszhandle + .rszicon use. */ + .bdframe .bdhandle { + fill: transparent; + stroke: none; + pointer-events: all; + touch-action: none; + } + .bdframe .bdknob { + fill: var(--hp-accent); + stroke: #fff; + stroke-width: 1; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + :host([data-pointer-hover]) .bdframe .bdhandle:hover + .bdknob { + fill: #fff; + stroke: var(--hp-accent); + } + .bdframe .bd-nwse { cursor: nwse-resize; } + .bdframe .bd-nesw { cursor: nesw-resize; } + /* the picture itself is the drag target for a move (grab, then grabbing) */ + .stage.mode-decor.bdgrab { cursor: grab; } + .stage.mode-decor.bdgrabbing, + .stage.mode-decor.bdgrabbing .bdframe .bdhandle { cursor: grabbing; } + .measurelabel.bdmeasure { + transform: translate(-50%, -50%); + border: 1px solid var(--hp-accent); + } + /* the selected decor object's frame — same chrome rules as the backdrop's: + the outline never takes a pointer, the handles always do, and they are + finger-sized because this is dragged on a tablet too */ + .dtframe .dtbox { + fill: none; + stroke: var(--hp-accent); + stroke-width: 1.5; + stroke-dasharray: 7 5; + vector-effect: non-scaling-stroke; + pointer-events: none; + opacity: 0.85; + } + .dtframe .dtstem, + .bdframe .dtstem { + stroke: var(--hp-accent); + stroke-width: 1.5; + vector-effect: non-scaling-stroke; + pointer-events: none; + opacity: 0.85; + } + /* the HIT circle: invisible, finger-sized, the only thing that takes a + pointer. The visible bead is .dtknob, a quarter of its radius — the + same visual/hit split .rszhandle + .rszicon use. */ + .dtframe .dthandle { + fill: transparent; + stroke: none; + pointer-events: all; + touch-action: none; + } + .dtframe .dtknob { + fill: var(--hp-accent); + stroke: #fff; + stroke-width: 1; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + :host([data-pointer-hover]) .dtframe .dthandle:hover + .dtknob { + fill: #fff; + stroke: var(--hp-accent); + } + .dtframe .dt-nwse { cursor: nwse-resize; } + .dtframe .dt-nesw { cursor: nesw-resize; } + .dtframe .dtrot { cursor: grab; } + .dtframe .dtendpoint { cursor: crosshair; } + .bdframe .dtrot { cursor: grab; } + .dtarea { + resize: vertical; + min-height: 3.4em; + font: inherit; + line-height: 1.35; + } + .stage.mode-decor.dtool-line, .stage.mode-decor.dtool-rect, + .stage.mode-decor.dtool-ellipse, .stage.mode-decor.dtool-text { + cursor: crosshair; + } + .stage.mode-decor.dtool-erase, + .stage.mode-decor.dtool-erase .decorlayer .dshape { + cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg transform='rotate(-45 12 12)'%3E%3Crect x='7' y='2' width='10' height='18' rx='2' fill='%23fff' stroke='%23111' stroke-width='1.5'/%3E%3Cpath d='M7 13h10v5a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2z' fill='%23ff9f43' stroke='%23111' stroke-width='1.5'/%3E%3C/g%3E%3C/svg%3E") 5 22, pointer; + } + .stage.mode-decor .room, .stage.mode-decor .devlayer { pointer-events: none; } + .stage.mode-decor .oplock { pointer-events: none; } + /* Backdrop-editor de-emphasis is a shared mode-transition coordinate. + It multiplies whole presentation groups and never changes Glow source + alpha, additive blending, or the underlying resolved state. */ + .stage .room, + .stage .devlayer, + .stage .opening, + .stage .room-outline, + .stage .wallbodies, + .stage .opening-tunnels, + .stage .glow-base-layer, + .stage .glow-pools-frame, + .stage .zero-walls { + opacity: var(--hp-mode-architecture-opacity, 1); + } + .opening-preview { + opacity: 0.5; + pointer-events: none; + } + .opening-preview[data-kind="passage"] { + opacity: 1; + } + .passage-preview-cut { + fill: var(--wall-fill, #ffffff); + fill-opacity: 0.35; + stroke: none; + pointer-events: none; + } + .passage-preview-boundary { + stroke: var(--hp-open, #ff9800); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + .opening-preview .op-leaf, + .opening-preview .op-arc { + transition: none; + } + .opening-preview-dot { + fill: var(--hp-open, #ff9800); + pointer-events: none; + } + .opening-dimensions, + .opening-dimension { + pointer-events: none; + } + .opening-dimension-line, + .opening-dimension-tick { + fill: none; + stroke: var(--hp-open, #ff9800); + stroke-width: 1.5; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .opening-dimension-tick { + stroke-width: 2; + } + .stage.edit .room { + pointer-events: none; + } + .stage.markup { + cursor: crosshair; + } + /* room-picking stages: merge (both clicks) and split before a room is chosen */ + .stage.markup.tool-merge, + .stage.markup.tool-split.pickstage, + .stage.markup.tool-delroom { + cursor: pointer; + } + .stage.markup.tool-wallthick { cursor: default; } + .stage.markup.tool-wallthick.wallhot { cursor: pointer; } + /* Solid wall colour sits under the hatch (owner: both, not either/or). */ + .wallbody-fill { + fill: var(--wall-fill, #ffffff); + fill-opacity: var(--wall-fill-op, 1); + fill-rule: evenodd; + stroke: none; + pointer-events: none; + } + .wallbody { + fill: url(#hp-wall-hatch); + fill-rule: evenodd; + stroke: var(--room-stroke, var(--hp-muted)); + stroke-width: calc(0.6px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + /* Thin-on-screen: hatch collapses into noise — fill alone, stroke from fill path's sibling. */ + .wallbody.solid { + fill: none; + } + .wallthick-hover { + fill: var(--accent-color, #03a9f4); + fill-opacity: 0.38; + stroke: var(--accent-color, #03a9f4); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + stroke-linejoin: round; + stroke-linecap: round; + pointer-events: none; + } + .wallthick-hover.isopen { + fill: var(--error-color, #f44336); + stroke: var(--error-color, #f44336); + } + .zero-wall { + stroke: var(--zero-wall-stroke, var(--hp-muted)); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + stroke-dasharray: + calc(7px * var(--hp-cell-visual-scale, 1)) + calc(7px * var(--hp-cell-visual-scale, 1)); + stroke-linecap: butt; + pointer-events: none; + opacity: 0.9; + } + .zero-walls.solid .zero-wall { + stroke-dasharray: none; + } + /* Rooms with zero/thick stretches: the polygon's own stroke is fully off. + The trimmed .room-outline draws normal walls; View hover gets its own + top overlay after the wall bodies. */ + .room.noedge { + stroke-opacity: 0 !important; + } + /* rooms with open boundaries draw their walls as separate M..L subpaths, + so a corner between two of them is two stroke ENDS meeting: round caps + fill it in the same way a round join fills a closed contour's corner + (owner 2026-08-04 — no teeth anywhere on a room border). */ + .room-outline { + fill: none; + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + stroke-linejoin: round; + stroke-linecap: round; + pointer-events: none; + } + /* Plan editor: trimmed outlines use the markup blue */ + .room-outline.outlined { + stroke: rgba(62, 166, 255, 0.55); + stroke-opacity: 1; + } + /* The wash is rendered directly above the resolved room fill but below + tunnels, Glow, sun and walls. Black at 22% reproduces the old + brightness(.78) contract without filtering/promoting an SVG ancestor or + changing the room's hue. The halo/outline are rendered again late, above + the wall bodies. */ + .room-hover-fill { + fill: #000; + fill-opacity: 0.22; + pointer-events: none; + } + .room-hover-halo { + fill: none; + stroke: var(--hp-accent); + stroke-opacity: 0.28; + stroke-width: calc(8px * var(--hp-cell-visual-scale, 1)); + stroke-linejoin: round; + stroke-linecap: round; + pointer-events: none; + } + .room-hover-outline { + fill: none; + stroke: var(--hp-accent); + stroke-width: calc(3px * var(--hp-cell-visual-scale, 1)); + stroke-linejoin: round; + stroke-linecap: round; + pointer-events: none; + } + .stage.markup .room { + pointer-events: none; + } + .stage.markup .devlayer .dev { + display: none; /* in plan mode the icons do not get in the way; labels stay */ + } + /* mode frames: the edit modes are visible at a glance */ + .stage.mode-plan { + outline: 2px solid #ffc14d; + outline-offset: -2px; + } + .stage.mode-devices { + outline: 2px solid var(--hp-accent); + outline-offset: -2px; + } + .room.outlined { + stroke: rgba(62, 166, 255, 0.55); + fill: rgba(62, 166, 255, 0.06); + } + /* AFTER .outlined: same specificity — source order decides (gotcha x4) */ + .room.picked { + stroke: #ffc14d; + stroke-width: calc(3px * var(--hp-cell-visual-scale, 1)); + fill: rgba(255, 193, 77, 0.25); + } + /* Owner 2026-08-04: the grid is a HINT, not content — at full strength the + dots argued with the plan on white paper. Both levels are muted, the + hierarchy is kept (major still denser than fine). */ + .griddot { + fill: var(--hp-accent); + opacity: 0.35; + stroke: rgba(0, 0, 0, 0.35); + stroke-width: 0.4; + } + /* docs/CANVAS.md §7: every coarse node (5x/10x the live step) keeps a + bigger, more opaque dot, so zoomed far out the grid still reads as a + grid instead of a grey wash. */ + .griddot.major { + opacity: 0.5; + stroke-width: 0; + } + /* the contour being drawn in the Plan editor: each wall is its own , + so the round cap IS the corner (matches the finished .room border) */ + .seg { + stroke: var(--hp-accent); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + stroke-linecap: round; + stroke-linejoin: round; + } + .pathline { + stroke: #ffc14d; + stroke-width: calc(3px * var(--hp-cell-visual-scale, 1)); + fill: none; + stroke-linecap: round; + stroke-linejoin: round; + } + .preview { + stroke: #ffc14d; + stroke-width: calc(2px * var(--hp-cell-visual-scale, 1)); + stroke-dasharray: + calc(6px * var(--hp-cell-visual-scale, 1)) + calc(5px * var(--hp-cell-visual-scale, 1)); + opacity: 0.7; + } + .active-axis { + stroke: #ffc14d; + stroke-width: 2; + stroke-linecap: round; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .active-vertex { + fill: #ffc14d; + stroke: #171006; + stroke-width: 2; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .wall-repair-preview { + stroke: #d93025; + stroke-width: 4; + stroke-linecap: round; + stroke-dasharray: 5 4; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .drawwall-preview-fill { + fill: var(--wall-fill, #ffffff); + fill-opacity: calc(var(--wall-fill-op, 1) * 0.55); + fill-rule: evenodd; + stroke: none; + pointer-events: none; + } + .drawwall-preview { + fill: url(#hp-wall-hatch); + fill-opacity: 0.55; + fill-rule: evenodd; + stroke: var(--accent-color, #03a9f4); + stroke-width: calc(0.5px * var(--hp-cell-visual-scale, 1)); + stroke-opacity: 0.7; + pointer-events: none; + } + .drawwall-zero-preview { + fill: none; + stroke: var(--accent-color, #03a9f4); + stroke-width: calc(3px * var(--hp-cell-visual-scale, 1)); + stroke-linecap: butt; + stroke-linejoin: round; + opacity: 0.72; + pointer-events: none; + } + .drawwall-zero-preview.dashed { + stroke-dasharray: + calc(7px * var(--hp-cell-visual-scale, 1)) + calc(7px * var(--hp-cell-visual-scale, 1)); + } + .vertex { + fill: #ffc14d; + stroke: #4a2800; + stroke-width: calc(1px * var(--hp-cell-visual-scale, 1)); + } + .vertex.first { + fill: #4bd28f; + stroke: #04121f; + } + .plan-snap-overlay, + .plan-snap-overlay *, + .hidden-wall-diagnostic, + .hidden-wall-diagnostic * { + pointer-events: none; + } + .plan-snap-line, + .hidden-wall-line { + fill: none; + stroke: color-mix(in srgb, var(--hp-accent) 82%, white 18%); + /* Explicit non-scaling-stroke in the SVG keeps this one screen pixel. */ + stroke-width: 1; + stroke-linecap: round; + opacity: 0.92; + } + .plan-snap-node, + .hidden-wall-node { + fill: var(--ha-card-background, var(--card-background-color, #fff)); + stroke: color-mix(in srgb, var(--hp-accent) 88%, #07131c 12%); + stroke-width: 1; + vector-effect: non-scaling-stroke; + } + .plan-snap-node.active { + fill: #ffc14d; + stroke: #171006; + stroke-width: 2; + } + .plan-snap-node.active.dynamic { + fill: #4bd28f; + stroke: #04121f; + } + .plan-snap-node.conflict { + fill: #fff; + stroke: #d93025; + stroke-width: 3; + } + @media (prefers-color-scheme: dark) { + .plan-snap-line { + stroke: color-mix(in srgb, var(--hp-accent) 72%, white 28%); + } + .hidden-wall-line { + stroke: color-mix(in srgb, var(--hp-accent) 72%, white 28%); + } + .plan-snap-node, + .hidden-wall-node { + fill: #17242c; + stroke: #9bdcf5; + } + .plan-snap-node.active { + fill: #ffc14d; + stroke: #fff4d6; + } + .plan-snap-node.active.dynamic { + fill: #4bd28f; + stroke: #eafff4; + } + } + @media (forced-colors: active) { + .plan-snap-line, + .hidden-wall-line { + stroke: CanvasText; + opacity: 1; + forced-color-adjust: auto; + } + .plan-snap-node, + .hidden-wall-node { + fill: Canvas; + stroke: CanvasText; + forced-color-adjust: auto; + } + .plan-snap-node.active, + .plan-snap-node.active.dynamic { + fill: Highlight; + stroke: HighlightText; + forced-color-adjust: auto; + } + } + /* RGB lights: the bulb takes the light's actual color */ + /* v1.52.0: the RGB tint of the icon/border is gone — a lamp's colour + lives ONLY in its glow spot (owner's rule). The ripple-color fallback + keeps using the light colour; that is set inline via --ripple-color. */ + /* Sun wedges (docs/SUN.md). The layer is present ONLY above the 3° + threshold; crossing it fades the whole layer in or out over EXACTLY + 2 s (owner 2026-08-03 — RAY_FADE_MS in src/sun.ts must match). The + geometry is untouched: this is a plain opacity animation on the group, + so overlapping wedges keep their own blending while it plays. */ + .sunlayer { + animation: hp-sunfade-in 2s linear both; + } + .sunlayer.out { + animation: hp-sunfade-out 2s linear both; + } + @media (prefers-reduced-motion: reduce) { + /* no fade at all: the rays are simply there or simply gone */ + .sunlayer, .sunlayer.out { animation: none; } + .sunlayer.out { opacity: 0; } + } + .devlayer { + position: absolute; + inset: 0; + pointer-events: none; + z-index: 6; + } + .stage.mode-devices .dev { cursor: grab; } + .stage.mode-devices .dev:active { cursor: grabbing; } + .physical-hit { + fill: transparent; + stroke: transparent; + pointer-events: none; + cursor: grab; + } + .stage.tool-select .physical-hit { pointer-events: all; } + .physical-hit:active { cursor: grabbing; } + line.physical-hit { cursor: pointer; } + .physical-hit.selected { + fill: rgba(255, 193, 77, 0.24); + stroke: transparent; + } + line.physical-hit.selected { + stroke: transparent; + } + .physical-drag { + fill: rgba(255, 193, 77, 0.38); + stroke: #ffc14d; + stroke-width: 2.5; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .physical-chrome { pointer-events: none; } + .physical-chrome .frame, + .physical-chrome .stem { + fill: none; + stroke: #ffc14d; + stroke-width: 2; + vector-effect: non-scaling-stroke; + } + .physical-chrome .frame { fill: rgba(255, 193, 77, 0.22); } + .physical-chrome polyline.frame { fill: none; } + .physical-chrome .move-dot { + fill: #ffc14d; + stroke: #24262d; + stroke-width: 1.5; + vector-effect: non-scaling-stroke; + } + .physical-chrome .rotate-handle { + fill: #24262d; + stroke: #ffc14d; + stroke-width: 2.5; + vector-effect: non-scaling-stroke; + pointer-events: all; + cursor: crosshair; + } + .drawwall.invalid input { border-color: var(--error-color, #db4437); } + .drawwall .rangehint { margin-inline-start: 4px; font-size: 0.78em; opacity: 0.72; } + .drawwall.invalid .rangehint { color: var(--error-color, #db4437); opacity: 1; } + .stage.markup.tool-partition, + .stage.markup.tool-column { cursor: crosshair; } + /* room resize tool (docs/RESIZE.md) */ + /* wall handle: invisible finger-sized hit circle (HP-1550-04 hit priority + kept), the visible glyph lives in the sibling .rszicon */ + .rszhandle { + fill: transparent; + stroke: none; + pointer-events: all; + cursor: grab; + touch-action: none; + } + .rszhandle:active { cursor: grabbing; } + .rszhandle.disabled, + .rszhandle.disabled:active { + cursor: not-allowed; + } + /* wall-with-arrows glyph: accent ink over a bg halo, readable on any plan */ + .rszicon { pointer-events: none; } + .rszicon path { + fill: none; + stroke-linecap: round; + stroke-linejoin: round; + vector-effect: non-scaling-stroke; + } + .rszhalo { stroke: var(--hp-bg); stroke-width: 6; } + .rszink { stroke: var(--hp-accent); stroke-width: 2; } + :host([data-pointer-hover]) .rszhandle:hover + .rszicon .rszink { stroke-width: 3; } + .rszicon.disabled { opacity: 0.38; } + :host([data-pointer-hover]) .rszhandle.disabled:hover + .rszicon .rszink { stroke-width: 2; } + .rszmeasurelayer, + .rszmeasurelayer * { pointer-events: none; } + .rszmeasurehalo, + .rszmeasureink, + .rszleader { + fill: none; + stroke-linecap: round; + vector-effect: non-scaling-stroke; + } + .rszmeasurehalo { + stroke: var(--hp-bg); + stroke-width: 7px; + opacity: 0.9; + } + .rszmeasureink { + stroke: var(--hp-accent); + stroke-width: 3px; + } + .rszleader { + stroke: var(--hp-accent); + stroke-width: 2px; + opacity: 0.95; + } + /* the decor draft badge rides the MIDDLE of the shape, so it is centred + horizontally and lifted clear of the line instead of trailing the + cursor the way a wall badge does (owner 2026-08-04) */ + .measurelabel.dmeasure { + transform: translate(-50%, -160%); + } + .measurelabel.rszarea { + transform: translate( + calc(-50% + var(--rsz-label-x, 0px)), + calc(-50% + var(--rsz-label-y, 0px)) + ); + background: rgba(0, 0, 0, 0.6); + border: 1px solid var(--hp-accent); + } + /* width and depth of a piece of furniture while its corner is dragged — + centred on the edge they measure (docs/FURNITURE.md §6) */ + .measurelabel.furnmeasure { + transform: translate(-50%, -50%); + border: 1px solid var(--hp-accent); + } + .alignmsg { margin: 0 0 8px; font-size: 13px; line-height: 1.45; } +`,o` + /* Unified device activity: alarm, short event and continuous state all + share this one renderer. No static rings are allowed. */ + .dev ha-icon { + position: relative; + z-index: 1; + } + .device-pulse { + position: absolute; + left: 50%; + top: 50%; + width: var(--dev-size); + height: var(--dev-size); + transform: translate(-50%, -50%); + pointer-events: none; + z-index: 0; + } + .device-pulse i { + position: absolute; + inset: 0; + border-radius: 50%; + border: 2px solid var(--ripple-color, var(--hp-accent)); + opacity: 0; + } + /* A witnessed edge: exactly three waves over the 3.3 s runtime window. */ + .device-pulse.short i { + animation: hp-pulse-short 1.1s cubic-bezier(.22,.61,.36,1) 1 forwards; + } + .device-pulse.short i:nth-child(2) { animation-delay: 1.1s; } + .device-pulse.short i:nth-child(3) { animation-delay: 2.2s; } + .device-pulse.short.gen2 i { animation-name: hp-pulse-short-b; } + .device-pulse.continuous i:nth-child(n + 2), + .device-pulse.alarm i:nth-child(n + 3) { display: none; } + .device-pulse.continuous i:first-child { + animation: hp-pulse-continuous 3.6s cubic-bezier(.45,.05,.55,.95) infinite; + } + .device-pulse.alarm i { + border-width: 3px; + border-color: #F0410C; + animation: hp-pulse-alarm 2.4s cubic-bezier(.22,.61,.36,1) infinite; + } + .device-pulse.alarm i:nth-child(2) { animation-delay: 1.2s; } + .activity-dot { + position: absolute; + right: 8%; + bottom: 8%; + width: 18%; + height: 18%; + min-width: 4px; + min-height: 4px; + border-radius: 50%; + background: var(--ripple-color, var(--hp-accent)); + border: 1px solid color-mix(in srgb, var(--hp-bg) 82%, transparent); + pointer-events: none; + z-index: 3; + } + .kioskdots { + position: absolute; + left: 50%; + bottom: var(--sp-5); + transform: translateX(-50%); + display: flex; + gap: var(--sp-4); + z-index: 5; + pointer-events: none; + } + .kdot { + width: 9px; + height: 9px; + border-radius: 50%; + background: var(--hp-muted); + opacity: 0.55; + } + .kdot.on { background: var(--hp-accent); opacity: 1; } + .dev.valonly { + /* Saved coordinates remain the centre of a Text shell. The shell may + expand, while the invisible anchor stays one core diameter wide. */ + width: var(--dev-size, var(--icon-size, 2.5cqw)); + } + .dev.valonly .device-core { + width: max-content; + min-width: var(--dev-size, var(--icon-size, 2.5cqw)); + padding-inline: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.16); + border-radius: calc(var(--dev-size, var(--icon-size, 2.5cqw)) / 2); + } + .dev .valtext { + overflow: visible; + font-size: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * var(--value-font-scale, .45)); + font-weight: 600; + white-space: nowrap; + } + @media (prefers-reduced-motion: reduce) { + .device-pulse { display: none; } + } + .dev .newdot { + position: absolute; + top: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * -0.12); + right: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * -0.12); + width: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.34); + height: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.34); + border-radius: 50%; + background: #f0301f; + border: 2px solid var(--card-background-color, var(--hp-bg)); + pointer-events: none; + z-index: 2; + } + .dev { + position: absolute; + /* The surface resolves compatibility icon_size units once. The shared + face receives an effective base and only applies the per-device size. */ + --dev-size: calc(var(--device-base-size, 2.25cqw) * var(--dev-scale, 1)); + /* 101.5/80 is the package shell/core ratio, including its stroke. */ + --device-shell-size: calc(var(--dev-size) * 1.26875); + --device-shell-inset: calc(var(--dev-size) * 0.134375); + --device-shell-stroke-ratio: 0.01875; + --device-shell-border-width: max(1px, calc(var(--dev-size) * var(--device-shell-stroke-ratio))); + --device-core-bg: var(--card-background-color, #fff); + --device-core-fg: var(--primary-text-color, #252525); + --device-core-bg: light-dark(#fff, #252525); + --device-core-fg: light-dark(#252525, #fff); + --device-face-bg: var(--device-core-bg); + --device-face-fg: var(--device-core-fg); + --device-shell-base-stroke: light-dark(#BCBCBC, rgb(37 37 37 / 75%)); + --device-shell-stroke: var(--device-shell-base-stroke); + --device-shell-shadow: + 0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .05) rgb(37 40 45 / 12%), + 0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) + calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%); + --device-core-inset-shadow: 0 0 0 0 transparent; + --device-ring-color: transparent; + --device-ring-width: 0px; + /* The saved point is the exact centre of the icon core. */ + width: var(--dev-size); + height: var(--dev-size); + margin: calc(var(--dev-size) / -2) 0 0 calc(var(--dev-size) / -2); + border: 0; + background: transparent; + display: block; + color: var(--device-core-fg); + cursor: pointer; + pointer-events: auto; + transition: opacity 0.2s; + box-shadow: none; + outline: none; + z-index: 2; + } + .dev.theme-light { + --device-core-bg: #fff; + --device-core-fg: #000; + --device-shell-base-stroke: #BCBCBC; + --device-shell-stroke: var(--device-shell-base-stroke); + --device-shell-shadow: + 0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .05) rgb(37 40 45 / 12%), + 0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) + calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%); + --device-core-inset-shadow: 0 0 0 0 transparent; + } + .dev.theme-dark { + --device-core-bg: #252525; + --device-core-fg: #fff; + --device-shell-base-stroke: rgb(37 37 37 / 75%); + --device-shell-stroke: var(--device-shell-base-stroke); + --device-shell-shadow: + 0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .0375) rgb(37 40 45 / 12%), + 0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) + calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%); + --device-core-inset-shadow: + inset 0 calc(var(--dev-size) * 0.0125) calc(var(--dev-size) * 0.0125) rgb(255 255 255 / 70%); + } + .dev::before { + content: ''; + position: absolute; + left: 50%; + top: 50%; + width: max(44px, var(--device-shell-size)); + height: max(44px, var(--device-shell-size)); + transform: translate(-50%, -50%); + border-radius: 50%; + pointer-events: auto; + z-index: 3; + } + .device-shell { + position: absolute; + box-sizing: border-box; + display: flex; + align-items: center; + gap: calc(var(--dev-size) * 0.1); + padding: 0; + min-width: var(--dev-size); + min-height: var(--dev-size); + border: 0; + background: transparent; + box-shadow: none; + transition: opacity .2s; + pointer-events: none; + } + .device-shell-frame { + position: absolute; + z-index: 0; + box-sizing: border-box; + inset: calc(var(--device-shell-inset) / -1); + border: var(--device-shell-border-width) solid var(--device-shell-stroke); + /* A saturating radius is resolved from the final border box. Using a + second fractional length here lets border-box and radius quantise on + different sides of a device pixel at some zoom/DPR combinations. */ + border-radius: 9999px; + background: transparent; + box-shadow: var(--device-shell-shadow); + transition: border-color .15s, box-shadow .15s, opacity .2s; + pointer-events: auto; + /* Normative production fallback: never add a per-marker backdrop blur. */ + backdrop-filter: none; + } + .device-shell:not(.with-values) { + left: 0; + top: 0; + } + .device-shell:not(.with-values):not(.text-shell) .device-shell-frame { + border-radius: 50%; + } + .device-shell.with-values.pos-right { + left: 0; + top: 50%; + transform: translateY(-50%); + } + .device-shell.with-values.pos-left { + right: 0; + top: 50%; + transform: translateY(-50%); + flex-direction: row-reverse; + } + .device-shell.with-values.pos-bottom { + left: 50%; + top: 0; + transform: translateX(-50%); + flex-direction: column; + } + .device-shell.with-values.pos-top { + left: 50%; + bottom: 0; + transform: translateX(-50%); + flex-direction: column-reverse; + } + .device-core { + position: relative; + z-index: 1; + box-sizing: border-box; + flex: 0 0 auto; + width: var(--dev-size); + height: var(--dev-size); + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + background: var(--device-face-bg); + color: var(--device-face-fg); + box-shadow: + var(--device-core-inset-shadow), + 0 0 0 var(--device-ring-width) var(--device-ring-color); + line-height: 0; + transition: background .15s, color .15s, box-shadow .15s, opacity .2s; + pointer-events: none; + } + .device-sections { + display: flex; + flex-direction: column; + align-items: stretch; + justify-content: center; + gap: calc(var(--dev-size) * .08); + min-width: 0; + pointer-events: none; + } + .device-shell.pos-top .device-sections, + .device-shell.pos-bottom .device-sections { + flex-direction: row; + } + .dev ha-icon { + /* from --dev-size, NOT --icon-size: the per-device size multiplier must + scale the GLYPH with its badge. Pinned to the base size, "make this + icon bigger" grew an empty box around a default-size glyph (user + report via the owner, 2026-07-29). */ + --mdc-icon-size: calc(var(--dev-size, var(--device-base-size, 2.25cqw)) * 0.55); + display: flex; + align-items: center; + justify-content: center; + line-height: 0; + } + .dev.on { + --device-face-bg: #F0A00C; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: #F0A00C; + } + .dev.theme-light.on { --device-face-fg: #fff; } + .dev.theme-dark.on { + --device-face-fg: #252525; + --device-shell-stroke-ratio: .0375; + } + .dev.open { + --device-face-bg: var(--hp-open); + --device-face-fg: light-dark(#fff, #252525); + } + .dev.theme-light.open { --device-face-fg: #fff; } + .dev.theme-dark.open { --device-face-fg: #252525; } + .dev.lock-locked { + --device-face-bg: #66D17A; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: #66D17A; + } + .dev.theme-light.lock-locked { --device-face-fg: #fff; } + .dev.theme-dark.lock-locked { + --device-face-fg: #252525; + --device-shell-stroke-ratio: .025; + } + .dev.lock-unlocked { + --device-face-bg: #F0410C; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: #F0410C; + } + .dev.theme-light.lock-unlocked { --device-face-fg: #fff; } + .dev.theme-dark.lock-unlocked { + --device-face-fg: #252525; + --device-shell-stroke-ratio: .025; + } + /* Interaction wins ordinary state colours. Alarm keeps priority through + the more-specific rule below. Unavailable has no visual hover. */ + :host([data-pointer-hover]) .dev:not(.unavail):hover { + --device-face-bg: #0C82F0; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: var(--device-shell-base-stroke); + } + :host([data-pointer-hover]) .dev.theme-light:not(.unavail):hover { --device-face-fg: #fff; } + :host([data-pointer-hover]) .dev.theme-dark:not(.unavail):hover { --device-face-fg: #252525; } + :host([data-pointer-hover]) .dev:hover, + .dev:focus-visible { z-index: 5; } + .dev.unavail { + opacity: 0.35; + --device-face-bg: #B5BAC1; + --device-shell-stroke: var(--device-shell-base-stroke); + } + .dev.virtual .device-shell-frame { + border-style: dashed; + } + /* "hide from plan" flag, shown only in the device editor with the + "show hidden devices" toggle on (docs/FILTERING.md). BLUE, so a hidden + device cannot be mistaken for an unavailable one (translucent dark) — + and no live-state paint at all: a ghost is configuration, not status + (owner's request). */ + .dev.ghost { + opacity: 0.6; + color: var(--hp-accent); + } + .dev.ghost .device-shell-frame { + border-style: dashed; + border-color: var(--hp-accent); + box-shadow: none; + } + .dev.ghost .device-core { + background: rgba(62, 166, 255, 0.22); /* fallback for old WebViews */ + background: color-mix(in srgb, var(--hp-accent) 30%, var(--card-background-color, #1c2530)); + color: var(--hp-accent); + } + /* HA-disabled is not a user hide: neutral grey + a power-off badge keeps + the two ghosts distinguishable without relying on colour alone. */ + .dev.ghost.ha-disabled { + opacity: 0.62; + color: var(--secondary-text-color, #9aa0aa); + } + .dev.ghost.ha-disabled .device-shell-frame { + border-color: var(--secondary-text-color, #9aa0aa); + } + .dev.ghost.ha-disabled .device-core { + background: rgba(120, 124, 134, 0.2); + background: color-mix(in srgb, var(--secondary-text-color, #9aa0aa) 24%, var(--card-background-color, #1c2530)); + color: var(--secondary-text-color, #9aa0aa); + } + .dev .habadge { + position: absolute; + right: -18%; + bottom: -18%; + display: grid; + place-items: center; + width: 46%; + height: 46%; + min-width: 12px; + min-height: 12px; + border-radius: 50%; + background: var(--card-background-color, #242832); + border: 1px solid currentColor; + } + .dev .habadge ha-icon { width: 72%; height: 72%; } + .dev.sel { + --device-ring-color: #F0A00C; + --device-ring-width: calc(var(--dev-size) * 0.0375); + } + .dev:focus-visible { + --device-ring-color: #0C82F0; + --device-ring-width: calc(var(--dev-size) * 0.0375); + } + .dev:not(.on):not(.open):not(.alarm):not(.lock-locked):not(.lock-unlocked):not(.unavail):focus-visible { + --device-face-fg: #0C82F0; + } + /* Alert stays above focus, selection, hover and ordinary semantic paint. */ + .dev.alarm, + :host([data-pointer-hover]) .dev.alarm:hover, + .dev.alarm:focus-visible { + --device-face-bg: #F0410C; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: #F0410C; + } + .dev.theme-light.alarm { --device-face-fg: #fff; } + .dev.theme-dark.alarm { + --device-face-fg: #252525; + --device-shell-stroke-ratio: .025; + } + .dev .value-badge { + position: relative; + z-index: 2; + box-sizing: border-box; + width: max-content; + min-width: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * .7875); + height: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * .7875); + display: flex; + align-items: center; + justify-content: center; + overflow: visible; + background: var(--device-core-bg); + border: 0; + border-radius: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.39375); + padding: 0 calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.14); + font-size: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * var(--value-font-scale, .45)); + font-weight: 600; + line-height: 1; + color: var(--device-core-fg); + white-space: nowrap; + pointer-events: none; + } + .dev .value-badge.unavailable, + .dev .value-badge.missing { opacity: 0.66; } + .dev .lqi { + position: absolute; + top: calc(50% + var(--device-shell-size) / 2 + var(--dev-size) * .05); + left: 50%; + transform: translateX(-50%); + margin-top: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.05); + font-size: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.38); + font-weight: 600; + line-height: 1; + text-shadow: 0 0 3px rgba(0, 0, 0, 0.9), 0 0 2px rgba(0, 0, 0, 0.9); + white-space: nowrap; + pointer-events: none; + } + .dev .lqi.below-value-badge { + margin-top: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.8875); + } + .temprange { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + margin-left: auto; + color: var(--hp-muted); + font-size: var(--fs-s); + } + /* live vacuum: a round puck, no badge plate, soft pulse (docs/VACUUM.md) */ + .vacpuck { + position: absolute; + /* the base badge, but round and 20% smaller — the owner's wording: + «иконка похожа на иконку базы, только круглая и чуть меньше» */ + --puck-size: calc(var(--device-base-size, 2.25cqw) * 0.8); + width: var(--puck-size); + height: var(--puck-size); + border-radius: 50%; + transform: translate(-50%, -50%); + --vac-core-bg: light-dark(#fff, #252525); + --vac-core-fg: light-dark(#252525, #fff); + background: var(--vac-core-bg); + border: 1px solid #BCBCBC; + box-shadow: + 0 1px 2px rgb(37 40 45 / 12%), + 0 4px 8px -1.07px rgb(37 40 45 / 18%); + color: var(--vac-core-fg); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + z-index: 6; + /* glide between sparse position updates; .jump disables it so the robot + never appears to drive through walls after a data gap */ + transition: left 1.2s linear, top 1.2s linear; + animation: vacpulse 2.2s ease-out infinite; + } + .vacpuck.theme-light { --vac-core-bg: #fff; --vac-core-fg: #252525; } + .vacpuck.theme-dark { --vac-core-bg: #252525; --vac-core-fg: #fff; } + .vacpuck.jump { transition: none; } + .vacpuck.stale { opacity: 0.45; animation: none; } + .vacpuck ha-icon { + --mdc-icon-size: calc(var(--puck-size) * 0.68); + color: var(--vac-core-fg); + /* same centering recipe as .dev ha-icon: without flex + line-height 0 + the glyph sits on its text baseline and appears to float around the + circle (owner report 2026-07-31) */ + display: flex; + align-items: center; + justify-content: center; + line-height: 0; + width: var(--mdc-icon-size); + height: var(--mdc-icon-size); + } + @keyframes vacpulse { + 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--hp-accent) 45%, transparent); } + 70% { box-shadow: 0 0 0 12px transparent; } + 100% { box-shadow: 0 0 0 0 transparent; } + } + @media (prefers-reduced-motion: reduce) { + .vacpuck { animation: none; } + } + .vactrail { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 5; + overflow: visible; + } + .vactrail polyline, + .vactrail path { + fill: none; + stroke-linejoin: round; + stroke-linecap: round; + vector-effect: non-scaling-stroke; + } + /* dark halo + light core: neutral, and one of the two always contrasts + with whatever fill is underneath */ + .vactrail g.prev { opacity: 0.4; } + .vactrail .case { + stroke: rgba(0, 0, 0, 0.4); + stroke-width: 2.25; + } + .vactrail .core { + stroke: rgba(255, 255, 255, 0.82); + stroke-width: 0.9; + } + .devicepreview-empty { + min-height: 82px; + margin: 4px 0 14px; + padding: var(--sp-4); + display: flex; + align-items: center; + justify-content: center; + gap: var(--sp-3); + border: 1px dashed var(--hp-line); + border-radius: var(--rad-m); + color: var(--hp-muted); + text-align: center; + } +`,o` + .hdr { + position: sticky; + top: var(--header-height, 56px); + z-index: 20; + background: var(--card-background-color, var(--hp-bg)); + border-radius: var(--ha-card-border-radius, 12px) var(--ha-card-border-radius, 12px) 0 0; + } + .tabs { + display: flex; + gap: var(--sp-2); + background: rgba(127, 127, 127, 0.12); + padding: var(--sp-2); + border-radius: var(--rad-l); + flex-wrap: wrap; + } + .tab { + border: 0; + background: transparent; + color: var(--hp-muted); + display: inline-flex; + align-items: center; + padding: var(--sp-3) var(--sp-5); + border-radius: var(--rad-m); + font-size: var(--fs-m); + font-weight: 600; + cursor: pointer; + transition: 0.15s; + font-family: inherit; + } + :host([data-pointer-hover]) .tab:hover { + color: var(--hp-txt); + } + .tab.active { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + } + /* docs/CANVAS.md §4.1: objects an order of magnitude away from the plan + do not decide the opening view — one quiet chip says so and offers to + take them in. Never a modal (owner). */ + .farhint { + position: absolute; + left: 50%; + transform: translateX(-50%); + bottom: var(--sp-4); + z-index: 12; + display: flex; + align-items: center; + gap: var(--sp-2); + max-width: calc(100% - var(--sp-8)); + background: var(--card-background-color, var(--hp-bg)); + opacity: 0.94; + color: var(--hp-txt); + border: 1px solid var(--divider-color, #33404d); + border-radius: var(--rad-m); + padding: var(--sp-1) var(--sp-3); + font-size: var(--fs-s); + } + .farhint ha-icon { + --mdc-icon-size: 18px; + color: var(--hp-warn, #e2a03f); + flex: none; + } + .farhint span { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .dropbtn { + display: flex; + align-items: center; + gap: var(--sp-4); + width: 100%; + text-align: left; + border: 1px solid var(--hp-muted); + border-radius: var(--rad-m); + background: transparent; + color: var(--hp-txt); + padding: var(--sp-4) 10px; + cursor: pointer; + font-family: inherit; + font-size: var(--fs-m); + margin-top: var(--sp-3); + } + .dropbtn .ref { color: var(--hp-muted); font-size: var(--fs-s); margin-left: auto; } + .dropbtn ha-icon { --mdc-icon-size: 18px; margin-left: var(--sp-2); } + .dropbtn.open { border-color: var(--hp-accent); } + .droppanel { + border: 1px solid var(--hp-accent); + border-top: none; + border-radius: 0 0 var(--rad-m) var(--rad-m); + padding: var(--sp-3); + margin-top: -4px; + } + .hdr.kioskhide { display: none; } + .decorbar .dcolor { + width: 30px; height: 26px; padding: 0; border: none; background: none; cursor: pointer; + } + .decorbar .dwidth { + font-family: inherit; font-size: var(--fs-s); border-radius: var(--rad-s); + background: var(--hp-bg2, transparent); color: var(--hp-txt); border: 1px solid var(--hp-muted); + padding: var(--sp-2) var(--sp-3); + } + .decorbar .bdhint { + font-size: var(--fs-s); + color: var(--hp-muted); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .decorbar .dfill { + display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-s); cursor: pointer; + } + .decorbar .dfill input[type="checkbox"] { + width: 16px; + height: 16px; + flex: none; + margin: 0; + padding: 0; + } + .decorbar hp-color-opacity { flex: 0 0 auto; } + .modes { + display: inline-flex; + gap: var(--sp-1); + background: rgba(127, 127, 127, 0.12); + border-radius: var(--rad-l); + padding: var(--sp-2); + } + .modetab { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + border: 0; + background: transparent; + color: var(--hp-muted); + padding: var(--sp-3) 10px; /* 10px h-padding kept: +2px would wrap the header modes row */ + border-radius: var(--rad-m); + font-size: var(--fs-m); + font-weight: 600; + cursor: pointer; + font-family: inherit; + transition: background-color 0.14s ease, color 0.14s ease, transform 0.14s ease; + } + .modetab:active { transform: scale(0.97); } + .modetab ha-icon { --mdc-icon-size: 15px; } + /* issue #220: a tab can be dragged to a new position in the editors */ + .tab[data-reorderable] { cursor: grab; } + .tab.dragging { cursor: grabbing; opacity: 0.55; } + .tab.drop-before { box-shadow: inset 2px 0 0 0 var(--primary-color, #03a9f4); } + .tab.drop-after { box-shadow: inset -2px 0 0 0 var(--primary-color, #03a9f4); } + .modetab .closex { + --mdc-icon-size: 13px; + box-sizing: border-box; + display: inline-flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + min-width: 24px; + min-height: 24px; + /* Keep the old 13 × 13 flex footprint (+2 px left margin) while the + pointer target grows around it. Header width, height and wrapping do + not move; only near-misses that used to hit the active tab reach X. */ + margin: -5.5px -5.5px -5.5px -3.5px; + opacity: 0.75; + cursor: pointer; + border-radius: var(--rad-s); + } + :host([data-pointer-hover]) .modetab .closex:hover { opacity: 1; } + .editbar .barclose { + box-sizing: border-box; + width: 40px; + height: 40px; + padding: 0; + margin: 0; + min-width: 40px; + min-height: 40px; + justify-content: center; + gap: 0; + line-height: 0; + } + .editbar .barclose ha-icon { flex: none; margin: 0; } + .modetab.active { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + } + @media (max-width: 720px) { + .modetab .ml { display: none; } + } + .editbar { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + align-items: stretch; + border-bottom: 1px solid var(--hp-line); + font-size: var(--fs-m); + } + .editbar-tools { + display: flex; + align-items: center; + gap: 10px; + padding: var(--sp-4) var(--sp-5); + flex-wrap: wrap; + min-width: 0; + outline: none; + } + .editbar-end { + display: flex; + align-items: center; + padding: var(--sp-4) var(--sp-5); + border-inline-start: 1px solid var(--hp-line); + background: var(--card-background-color, var(--hp-bg)); + position: relative; + z-index: 2; + } + .tab .tabedit { + --mdc-icon-size: 13px; + display: inline-flex; + align-items: center; + margin-left: var(--sp-3); + opacity: 0.4; + } + :host([data-pointer-hover]) .tab:hover .tabedit { + opacity: 0.9; + } + .tab.tabadd { + padding: var(--sp-3) var(--sp-4); + } + .tab.tabadd ha-icon { + --mdc-icon-size: 15px; + } + .rhint { + font-size: var(--fs-s); + color: var(--hp-muted); + margin-bottom: var(--sp-3); + } + .togglehint { + overflow-wrap: anywhere; + } + .togglehint > div + div { + margin-top: var(--sp-1); + } + /* Keep the last editor bar mounted while the row collapses. This makes + both entering and leaving an editor change the card geometry gradually; + the header ResizeObserver keeps the stage fitted throughout. */ + .editorchrome { + display: block; + height: 0; + opacity: 0; + visibility: hidden; + overflow: hidden; + } + .editorchrome:not(.open) { + pointer-events: none; + } + .editorchrome.open { + height: auto; + opacity: 1; + visibility: visible; + overflow: visible; + } + .editorchrome.transitioning { + overflow: hidden; + will-change: height; + pointer-events: none; + } + /* The toolbar is already visible while its height is interpolating. Its + explicit navigation control must remain usable even though all editing + tools stay frozen until the transition settles. */ + .editorchrome.transitioning .barclose { + pointer-events: auto; + } + .editorchrome-inner { + min-height: 0; + transform-origin: top center; + } + .editorchrome.transitioning .editorchrome-inner { + will-change: opacity; + } + @media (prefers-reduced-motion: reduce) { + .modetab { transition: none; } + } + .editbar .warn { + color: #ffc14d; + } + .editbar .sname { + font-weight: 600; + } + .editbar input { + width: 74px; + background: transparent; + border: 1px solid var(--hp-line); + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + font-size: var(--fs-m); + } + .editbar label, + .editbar .hint { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .editbar .drawwall { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + white-space: nowrap; + } + .editbar .wallsgroup { + display: inline-flex; + align-items: center; + gap: 10px; + white-space: nowrap; + } + .editbar .drawwall input { + width: 4.2em; + } + .editbar .drawwall .opl { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .menuwrap { + position: fixed; + inset: 0; + z-index: 80; + } + .menu { + position: fixed; + background: var(--hp-bg); + border: 1px solid var(--hp-accent); + border-radius: var(--rad-l); + box-shadow: var(--shadow-2); + min-width: 210px; + max-width: 300px; + overflow: hidden; + transform: translate(0, 8px); + } + .menu .hd { + padding: var(--sp-4) var(--sp-5); + font-weight: 600; + font-size: var(--fs-m); + border-bottom: 1px solid var(--hp-line); + display: flex; + align-items: center; + gap: var(--sp-3); + } + .menu .hd ha-icon, + .menu .it.all ha-icon { + color: var(--hp-accent); + --mdc-icon-size: 16px; + } + .menu .it { + padding: var(--sp-4) var(--sp-5); + font-size: var(--fs-m); + cursor: pointer; + display: flex; + align-items: center; + gap: var(--sp-4); + } + .menu .it ha-icon { + --mdc-icon-size: 16px; + color: var(--hp-muted); + } + :host([data-pointer-hover]) .menu .it:hover { + background: rgba(127, 127, 127, 0.15); + } + .menu .it.all { + color: var(--hp-accent); + font-weight: 600; + } + .tip { + position: fixed; + pointer-events: none; + background: var(--hp-bg); + border: 1px solid var(--hp-accent); + color: var(--hp-txt); + padding: var(--sp-3) 10px; + border-radius: var(--rad-m); + font-size: var(--fs-m); + box-shadow: var(--shadow-2); + z-index: 60; + max-width: 260px; + } + .tip .m { + color: var(--hp-muted); + font-size: var(--fs-s); + display: block; + } +`,o` + .head { + display: flex; + align-items: center; + gap: 10px; + padding: 10px var(--sp-5); + border-bottom: 1px solid var(--hp-line); + flex-wrap: wrap; + } + .title { + font-size: var(--fs-l); + font-weight: 600; + display: flex; + align-items: center; + gap: var(--sp-3); + white-space: nowrap; + } + .title ha-icon { + color: var(--hp-accent); + --mdc-icon-size: 18px; + } + @media (max-width: 620px) { + .head { gap: var(--sp-3); padding: var(--sp-4) 10px; } + .head .count { display: none; } + .head .title { font-size: var(--fs-m); } + } + .count { + font-size: var(--fs-s); + color: var(--hp-muted); + } + .btn { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + border: 1px solid var(--hp-line); + background: transparent; + color: var(--hp-txt); + padding: var(--sp-3) 10px; + border-radius: var(--rad-m); + cursor: pointer; + transition: 0.15s; + font-family: inherit; + font-size: var(--fs-m); + } + .btn ha-icon { + --mdc-icon-size: 17px; + } + :host([data-pointer-hover]) .btn:hover { + border-color: var(--hp-accent); + } + .btn.on { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + border-color: var(--hp-accent); + } + .btn.ghost { + border: none; + } + .btn[disabled] { + opacity: 0.5; + pointer-events: none; + } + /* the compass dial in the general settings (docs/SUN.md) */ + .sunrow { + display: flex; + align-items: center; + gap: var(--sp-5); + margin: var(--sp-3) 0; + } + .suncol { + flex: 1; + display: flex; + flex-direction: column; + gap: var(--sp-3); + min-width: 0; + } + .recoveryoverlay { + position: absolute; + inset: 0; + /* Above the contextual editor tray (70): recovery is the one state in + which every stage-editing surface must be inert. Dialogs live outside + the stage and retain their own higher card-level stacking context. */ + z-index: 75; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: var(--sp-4); + padding: var(--sp-6); + box-sizing: border-box; + /* The final solid layer guarantees an opaque recovery surface even when + a custom HA theme exposes its card colour as rgba(). */ + background: + linear-gradient(var(--ha-card-background, var(--card-background-color, #111)), + var(--ha-card-background, var(--card-background-color, #111))), + #111; + color: var(--primary-text-color, #fff); + text-align: center; + pointer-events: auto; + transition: opacity 0.15s ease; + } + .recoveryoverlay.phase-entering, + .recoveryoverlay.phase-leaving { + opacity: 0; + } + .recoveryoverlay.phase-fading-in, + .recoveryoverlay.phase-opaque { + opacity: 1; + } + .recoveryoverlay ha-icon { + --mdc-icon-size: 44px; + color: var(--hp-accent); + } + .editorloading { + position: absolute; + z-index: 74; + left: 50%; + top: 50%; + display: flex; + align-items: center; + gap: var(--sp-3); + padding: var(--sp-3) var(--sp-5); + border: 1px solid color-mix(in srgb, var(--hp-accent) 45%, transparent); + border-radius: 999px; + background: color-mix(in srgb, + var(--ha-card-background, var(--card-background-color, #111)) 92%, transparent); + color: var(--primary-text-color); + box-shadow: 0 6px 22px rgb(0 0 0 / 18%); + transform: translate(-50%, -50%); + pointer-events: none; + animation: editor-loading-in 0.15s ease both; + } + .editorloading ha-icon { + --mdc-icon-size: 22px; + color: var(--hp-accent); + animation: editor-loading-spin 0.9s linear infinite; + } + @keyframes editor-loading-in { + from { opacity: 0; transform: translate(-50%, calc(-50% + 4px)); } + to { opacity: 1; transform: translate(-50%, -50%); } + } + @keyframes editor-loading-spin { to { transform: rotate(360deg); } } + @media (prefers-reduced-motion: reduce) { + .recoveryoverlay, + .editorloading, + .editorloading ha-icon { + transition: none; + animation: none; + } + } + .oplock { + --oplock-size: calc(var(--icon-size, 2.5cqw) * 0.62); + --oplock-core-size: calc(var(--oplock-size) / 1.26875); + --oplock-stroke-ratio: 0.01875; + --oplock-stroke-width: max(1px, calc(var(--oplock-core-size) * var(--oplock-stroke-ratio))); + --oplock-core-bg: light-dark(#fff, #252525); + --oplock-core-fg: light-dark(#252525, #fff); + --oplock-shell-stroke: light-dark(#BCBCBC, rgb(37 37 37 / 75%)); + --oplock-shell-shadow: + 0 calc(var(--oplock-core-size) * .025) calc(var(--oplock-core-size) * .05) rgb(37 40 45 / 12%), + 0 calc(var(--oplock-core-size) * .1) calc(var(--oplock-core-size) * .175) + calc(var(--oplock-core-size) * -.025) rgb(37 40 45 / 18%); + --oplock-core-shadow: 0 0 0 0 transparent; + pointer-events: none; /* inert while editing; clickable in View (rule below) */ + position: absolute; + transform: translate(-50%, -50%); + width: var(--oplock-size); + height: var(--oplock-size); + display: grid; + place-items: center; + border: 0; + background: transparent; + z-index: 1; + } + .oplock.theme-light { + --oplock-core-bg: #fff; + --oplock-core-fg: #252525; + --oplock-shell-stroke: #BCBCBC; + } + .oplock.theme-dark { + --oplock-core-bg: #252525; + --oplock-core-fg: #fff; + --oplock-shell-stroke: rgb(37 37 37 / 75%); + --oplock-core-shadow: + inset 0 calc(var(--oplock-core-size) * .0125) + calc(var(--oplock-core-size) * .0125) rgb(255 255 255 / 70%); + } + .oplock-shell { + box-sizing: border-box; + width: 100%; + height: 100%; + border: var(--oplock-stroke-width) solid var(--oplock-shell-stroke); + border-radius: 50%; + background: transparent; + box-shadow: var(--oplock-shell-shadow); + display: grid; + place-items: center; + pointer-events: none; + backdrop-filter: none; + } + .oplock-core { + width: var(--oplock-core-size); + height: var(--oplock-core-size); + border-radius: 50%; + background: var(--oplock-core-bg); + color: var(--oplock-core-fg); + box-shadow: var(--oplock-core-shadow); + display: grid; + place-items: center; + pointer-events: none; + } + .oplock ha-icon { + --mdc-icon-size: calc(var(--oplock-core-size) * 0.55); + display: flex; + line-height: 0; + } + .oplock.locked { + --oplock-core-bg: #66D17A; + --oplock-core-fg: light-dark(#fff, #252525); + --oplock-shell-stroke: #66D17A; + } + .oplock.theme-light.locked { --oplock-core-fg: #fff; } + .oplock.theme-dark.locked { + --oplock-core-fg: #252525; + --oplock-stroke-ratio: .025; + } + .oplock.unlocked { + --oplock-core-bg: #F0410C; + --oplock-core-fg: light-dark(#fff, #252525); + --oplock-shell-stroke: #F0410C; + } + .oplock.theme-light.unlocked { --oplock-core-fg: #fff; } + .oplock.theme-dark.unlocked { + --oplock-core-fg: #252525; + --oplock-stroke-ratio: .025; + } + .oplock.unknown { --oplock-core-fg: var(--hp-muted); } + .btn.lockact { + width: 100%; + justify-content: center; + display: flex; + align-items: center; + gap: var(--sp-3); + margin-top: var(--sp-4); + } + .btn.lockact.warn { + color: var(--error-color, #d33); + border-color: var(--error-color, #d33); + } + .oprow { + display: flex; + align-items: center; + gap: var(--sp-4); + padding: var(--sp-3) 0; + } + .oprow b { margin-left: auto; } + .oprow.ok b { color: #66d17a; } + .oprow.warn b { color: var(--hp-open); } + .bindharow { + display: flex; + align-items: center; + gap: var(--sp-5); + flex-wrap: wrap; + } + .bindharow .entcheck { opacity: 0.9; } + .ctrlchips { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin: var(--sp-2) 0; } + .ctrlchip { + display: inline-flex; align-items: center; gap: var(--sp-2); + background: var(--hp-accent); color: var(--text-primary-color, #fff); + border-radius: var(--rad-l); padding: var(--sp-2) var(--sp-4); font-size: var(--fs-s); + } + .ctrlchip ha-icon { --mdc-icon-size: 14px; cursor: pointer; } + .ctrllist { display: flex; flex-direction: column; gap: var(--sp-1); margin-top: var(--sp-2); } + .ctrlopt { + display: flex; align-items: center; gap: var(--sp-4); text-align: left; + border: 0; background: transparent; color: var(--hp-txt); + padding: var(--sp-3) var(--sp-4); border-radius: var(--rad-s); cursor: pointer; font-family: inherit; font-size: var(--fs-m); + } + :host([data-pointer-hover]) .ctrlopt:hover { + background: var(--secondary-background-color, rgba(128,128,128,0.15)); + } + .ctrlopt .sub { color: var(--hp-muted); font-size: var(--fs-s); margin-left: auto; } + .ctrlopt ha-icon { --mdc-icon-size: 16px; } + .ctrlstates { display: flex; flex-direction: column; gap: var(--sp-2); } + .ctrlstate { display: inline-flex; align-items: center; gap: var(--sp-3); color: var(--hp-muted); } + .ctrlstate.on { color: var(--hp-txt); } + .ctrlstate ha-icon { --mdc-icon-size: 15px; } + .cardpreview { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--sp-2); + margin: var(--sp-4) 0 var(--sp-1); + padding: 10px; + border: 1px dashed var(--hp-muted); + border-radius: var(--rad-m); + } + .cardpreview .cpname { font-weight: 700; letter-spacing: 0.04em; } + .cardpreview .cpmeta { + display: inline-flex; + align-items: center; + gap: 0.3em; + font-weight: 600; + opacity: 0.85; + } + .cardpreview .cpmeta ha-icon { --mdc-icon-size: 1.05em; } + .iconauto { + display: flex; + align-items: center; + gap: var(--sp-3); + font-size: var(--fs-s); + margin: var(--sp-2) 0 0; + } + .iconauto ha-icon { --mdc-icon-size: 18px; } + .iconauto span { flex: 1; } + .iconauto .btn { min-height: 32px; padding: 0 var(--sp-3); } + hp-dialog .dfill { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + cursor: pointer; + } + .wallthick-dlg { + position: absolute; + z-index: 40; + min-width: 200px; + transform: translate(-50%, 8px); + padding: 10px 12px; + border-radius: 10px; + background: var(--card-background-color, #fff); + box-shadow: 0 8px 28px rgba(0,0,0,.22); + display: flex; + flex-direction: column; + gap: 8px; + pointer-events: auto; + } + .wallthick-dlg .row { + display: flex; + align-items: center; + gap: 8px; + } + .wallthick-dlg input[type="number"] { + width: 5.5em; + padding: 4px 6px; + border: 1px solid var(--divider-color, #ccc); + border-radius: 6px; + background: var(--input-fill, transparent); + color: var(--primary-text-color); + } + .areasel, + .namein { + background: var(--hp-bg); + border: 1px solid var(--hp-line); + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + font-size: var(--fs-m); + font-family: inherit; + } + .namein { + width: 130px; + } + .habindingbanner { + display: flex; + align-items: center; + gap: var(--sp-3); + padding: var(--sp-3) var(--sp-4); + margin-bottom: var(--sp-4); + border: 1px solid var(--warning-color, #ff9800); + border-radius: var(--rad-m); + background: color-mix(in srgb, var(--warning-color, #ff9800) 12%, transparent); + color: var(--primary-text-color, #f1f3f6); + } + .habindingbanner > span { flex: 1; min-width: 0; } + .habindingbanner > ha-icon { color: var(--warning-color, #ff9800); flex: 0 0 auto; } + .habindingbanner.limited { + border-color: var(--secondary-text-color, #9aa0aa); + background: color-mix(in srgb, var(--secondary-text-color, #9aa0aa) 10%, transparent); + } + .habindingbanner.limited > ha-icon { color: var(--secondary-text-color, #9aa0aa); } + .srcrow { + display: flex; + align-items: center; + gap: var(--sp-4); + font-size: var(--fs-m); + cursor: pointer; + padding: var(--sp-1) 0; + } + .dispsection { + margin-top: var(--sp-5) !important; + padding-top: var(--sp-4); + border-top: 1px solid var(--hp-line); + font-weight: 600; + color: var(--hp-txt) !important; + } + .colorrow { + display: flex; + align-items: center; + gap: var(--sp-4); + } + .gsrow > hp-color-opacity { + min-width: min(100%, 210px); + justify-content: space-between; + } + .ripple-colorrow > hp-color-opacity { + width: 100%; + justify-content: space-between; + } + .ripple-sizerow > .opl { + min-width: 0; + } + .colorrow input[type='range'] { flex: 1; } + .colorrow .tempin { width: 70px; flex: none; } + /* beat the generic hp-dialog .body .namein { width:100% } rule */ + hp-dialog .body .temprange .tempin { width: 56px; flex: none; padding: var(--sp-2) var(--sp-3); } + hp-dialog .body .colorrow .tempin { width: 72px; flex: none; } + .srcrow { flex-wrap: nowrap; } + /* native HA controls (rendered only when the HA frontend defines them; + old HA and the smoke env keep the plain inputs). ha-switch is taller + than a checkbox - cap its footprint so .srcrow keeps its rhythm. */ + .srcrow ha-switch { flex: none; } + .colorrow ha-slider { flex: 1; min-width: 0; } + .srcrow > span:first-of-type { white-space: nowrap; } + .colorrow .opl { color: var(--hp-muted); font-size: var(--fs-s); } + .colorrow .opv { font-size: var(--fs-s); min-width: 34px; text-align: right; } + .markerlightgroup { + min-width: 0; + margin: var(--sp-5) 0 0; + padding: var(--sp-4); + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + } + .markerlightgroup legend { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: var(--sp-1); + padding: 0 var(--sp-2); + color: var(--hp-txt); + font-weight: 600; + } + .markerlightgroup legend > span { min-width: 0; overflow-wrap: anywhere; } + .markerlightgroup[disabled] > :not(legend) { opacity: .62; } + .markerhelpfield { margin-top: var(--sp-4); } + .markerhelplabel { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: var(--sp-1); + margin-bottom: var(--sp-1); + } + .markerhelplabel > label { min-width: 0; overflow-wrap: anywhere; } + .markerradios { display: grid; gap: var(--sp-1); min-width: 0; } + .markerlightgroup .srcrow > span:first-of-type { + min-width: 0; + white-space: normal; + overflow-wrap: anywhere; + } + .markerglowvalue { margin: var(--sp-3) 0; flex-wrap: wrap; } + .markerglowvalue hp-color-opacity { flex: none; } + .markerlightdisabled { + display: flex; + align-items: center; + gap: var(--sp-2); + margin-top: var(--sp-2) !important; + } + .markerlightdisabled ha-icon { --mdc-icon-size: 18px; flex: none; } + .markerbadgetechnical { + min-width: 0; + margin: var(--sp-1) 0 var(--sp-2) !important; + overflow-wrap: anywhere; + } + .markerbadgetechnical code { white-space: normal; } + .planrow { + display: flex; + align-items: center; + gap: 10px; + } + /* the "already uploaded" picker: a plan is never deleted for being + unreferenced, so it has to be findable again */ + .savedplans { + display: flex; + flex-direction: column; + gap: var(--sp-3); + max-height: 240px; + overflow: auto; + margin: var(--sp-3) 0 var(--sp-1); + padding: var(--sp-3); + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + background: var(--hp-bg2, rgba(255, 255, 255, 0.03)); + /* The same collapse that ate .candlist (v1.53.1): a scroll box is a + flex item whose automatic minimum size is ZERO (overflow != visible), + so inside hp-dialog .body — a flex column taller than its 66vh cap — + it shrank to a 14px sliver: the rows were in the DOM, the owner saw + a thin rounded stripe under the "Already uploaded" button. Don't + shrink, and keep a floor even when the box is empty or loading. */ + flex: 0 0 auto; + min-height: 2.6em; + } + .savedplan { + display: flex; + align-items: center; + gap: 10px; + } + .savedplan.cur { outline: 1px solid var(--hp-accent); border-radius: var(--rad-s); } + .savedplan img { + width: 56px; + height: 40px; + object-fit: contain; + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + background: #fff; + flex: none; + } + .savedmeta { display: flex; flex-direction: column; min-width: 0; flex: 1; } + .savedmeta b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + .savedmeta .muted { font-size: var(--fs-s); } + .savedplan .btn.danger ha-icon { color: #f25a4a; } + .savedplan .btn[disabled] { opacity: 0.4; pointer-events: none; } + .planprev { + max-width: 120px; + max-height: 70px; + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + background: #fff; + } + .planname { + font-size: var(--fs-m); + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .planname.muted { + color: var(--hp-muted); + } + .filebtn { + cursor: pointer; + } + .fileupload { display: inline-flex; min-width: 0; } + .fileupload > input { display: none; } + .btn.danger { + border-color: #b3402a; + color: #ff7a5c; + } + hp-dialog .row .spacer { + flex: 1; + } + hp-dialog .body { + max-height: 66vh; + overflow-y: auto; + } + .descin { + width: 100%; + box-sizing: border-box; + background: var(--hp-bg); + border: 1px solid var(--hp-line); + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + font-size: var(--fs-m); + font-family: inherit; + resize: vertical; + /* flex column of the dialog body squeezes textareas — keep a usable height */ + min-height: 92px; + flex-shrink: 0; + line-height: 1.35; + } + .bindsel { + display: flex; + flex-direction: column; + gap: var(--sp-3); + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + padding: var(--sp-4); + } + .bindsel .opt { + display: flex; + align-items: center; + gap: var(--sp-3); + border: 1px solid var(--hp-line); + background: transparent; + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + cursor: pointer; + font-size: var(--fs-m); + font-family: inherit; + } + .bindsel .opt.on { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + border-color: var(--hp-accent); + } + .curbind { + display: flex; + align-items: center; + gap: var(--sp-3); + font-size: var(--fs-m); + color: var(--hp-txt); + flex-wrap: wrap; + } + .curbind .ref { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .vacbox .vacbtns { display: flex; gap: var(--sp-4); margin: var(--sp-3) 0; flex-wrap: wrap; } + .vacdiag { display: grid; gap: 4px; margin-bottom: var(--sp-3); } + .vacdiag > div { display: flex; justify-content: space-between; gap: var(--sp-5); } + .vacdiag > div > span { color: var(--secondary-text-color); } + .vacdiag > div > b { text-align: right; overflow-wrap: anywhere; } + .vacpicker { margin: var(--sp-3) 0; } + .vacsource-warning { display: grid; gap: 8px; } + .vacsource-warning .btn { justify-self: start; } + .vacpicker > summary { display: inline-flex; width: auto; list-style: none; cursor: pointer; } + .vacpicker > summary::-webkit-details-marker { display: none; } + .vacsource-list { display: grid; gap: 6px; margin-top: 8px; } + .vacsource-list details { padding: 6px 0 0; } + .vacsource-list details > summary { cursor: pointer; font-weight: 600; } + .vacsource { display: flex; align-items: center; justify-content: space-between; gap: 12px; + width: 100%; min-width: 0; padding: 9px 10px; border: 1px solid var(--divider-color); + border-radius: 10px; color: var(--primary-text-color); background: var(--secondary-background-color); + text-align: left; cursor: pointer; } + .vacsource.on { border-color: var(--accent-color); box-shadow: inset 3px 0 var(--accent-color); } + .vacsource > span:first-child { min-width: 0; display: grid; gap: 2px; } + .vacsource small { color: var(--secondary-text-color); overflow-wrap: anywhere; } + .vacsource-meta { color: var(--secondary-text-color); text-align: right; font-size: 0.82em; } + .vacxcme pre { margin: 8px 0 0; white-space: pre-wrap; user-select: text; } + .vacfit { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + z-index: 12; + overflow: visible; + touch-action: none; + cursor: grab; + /* the devlayer is pointer-events: none and every child opts back in — + without this line real clicks flew straight through the overlay + (owner: «уголки не кликабельны»; synthetic smoke events bypass + hit-testing, which is why they lied) */ + pointer-events: auto; + } + .vacfit:active { cursor: grabbing; } + .vacfit polygon { + fill: color-mix(in srgb, var(--hp-accent) 16%, transparent); + stroke: var(--hp-accent); + stroke-width: 2; + vector-effect: non-scaling-stroke; + stroke-dasharray: 6 4; + } + .vacfit text { + fill: var(--hp-accent); + font-size: 26px; + text-anchor: middle; + dominant-baseline: middle; + pointer-events: none; + user-select: none; + } + /* ---- the furniture palette (docs/FURNITURE.md §3) ------------------- */ + .furnpalette { + display: flex; + flex-direction: column; + max-height: 38vh; + border-top: 1px solid var(--hp-border, rgba(255, 255, 255, 0.12)); + background: var(--card-background-color, var(--hp-bg)); + font-size: 0.85em; + } + .furnhd { + display: flex; + align-items: center; + gap: 6px; + padding: 4px 8px; + font-weight: 600; + opacity: 0.9; + } + .furnhd .spacer { flex: 1; } + .furnbody { + overflow: auto; + padding: 0 8px 6px; + } + .furngroup { + margin: 6px 0 3px; + font-size: 0.85em; + text-transform: uppercase; + letter-spacing: 0.04em; + opacity: 0.6; + } + .furnrow { + display: flex; + flex-wrap: wrap; + gap: 4px; + } + .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; } + .vacfitdot { fill: var(--hp-accent); pointer-events: none; } + /* hit target: invisible and finger-sized; .vacfitknob is the visible bead */ + .vacfithandle { + fill: transparent; + stroke: none; + cursor: nwse-resize; + } + .vacfitknob { + fill: var(--hp-bg); + stroke: var(--hp-accent); + stroke-width: 2; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .vaccalbar { + position: fixed; + left: 50%; + bottom: 24px; + transform: translateX(-50%); + display: flex; + gap: var(--sp-5); + align-items: center; + background: var(--hp-bg); + color: var(--hp-txt); + border: 1px solid var(--hp-accent); + border-radius: var(--rad-l); + padding: 10px var(--sp-5); + z-index: 60; + box-shadow: var(--shadow-2); + } + .candlist { + max-height: 160px; + overflow-y: auto; + border-top: 1px solid var(--hp-line); + /* A scrollable box is a flex item that HAPPILY collapses: inside the + dialog body (a flex column) this list rendered its rows into a 1px + sliver — the DOM had 26 candidates and the user saw nothing. In the + binding dropdown it sits inside .droppanel (block context) and never + showed the bug. Field report, 2026-07-30. */ + flex: 0 0 auto; + min-height: 2.6em; + } + .cand { + display: flex; + justify-content: space-between; + gap: var(--sp-4); + padding: var(--sp-3) var(--sp-4); + cursor: pointer; + border-radius: var(--rad-s); + font-size: var(--fs-m); + } + :host([data-pointer-hover]) .cand:hover { + background: rgba(127, 127, 127, 0.15); + } + .cand.sel { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + } + .cand .cs { + color: var(--hp-muted); + font-size: var(--fs-s); + white-space: nowrap; + } + .opening-entity-candidate { + width: 100%; + border: 0; + background: transparent; + color: inherit; + font: inherit; + text-align: left; + } + .opening-entity-candidate.sel { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + } + .opening-entity-empty { cursor: default; } + .cand.sel .cs { + color: var(--text-primary-color, #fff); + opacity: 0.85; + } + .cand.muted { + color: var(--hp-muted); + cursor: default; + } + .pdfedit { + display: flex; + flex-wrap: wrap; + gap: var(--sp-3); + align-items: center; + } + .pdftag { + display: inline-flex; + align-items: center; + gap: var(--sp-2); + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + padding: var(--sp-2) var(--sp-3); + font-size: var(--fs-s); + } + .pdftag a { + color: var(--hp-txt); + text-decoration: none; + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .pdftag .x { + --mdc-icon-size: 15px; + cursor: pointer; + color: var(--hp-muted); + } + :host([data-pointer-hover]) .pdftag .x:hover { + color: #ff7a5c; + } + .entlist { + display: flex; + flex-direction: column; + gap: var(--sp-2); + margin-bottom: 10px; + } + .entrow { + display: flex; + align-items: center; + gap: var(--sp-4); + padding: var(--sp-3) var(--sp-4); + border-radius: var(--rad-m); + background: var(--secondary-background-color, rgba(128, 128, 128, 0.12)); + } + .entrow ha-icon { --mdc-icon-size: 20px; color: var(--hp-muted); } + .entrow.on ha-icon { color: var(--hp-accent); } + .entrow .en { flex: 1; font-size: var(--fs-m); } + .entrow .ev { font-size: var(--fs-m); color: var(--hp-muted); } + .entbtn { + min-width: 74px; + min-height: 32px; + padding: var(--sp-2) var(--sp-5); + border: 1px solid var(--hp-muted); + border-radius: 999px; + background: transparent; + color: var(--hp-txt); + font: inherit; + font-size: var(--fs-m); + cursor: pointer; + } + .entbtn.on { + background: var(--hp-accent); + border-color: var(--hp-accent); + color: var(--text-primary-color, #fff); + font-weight: 600; + } + .inforow { + display: flex; + gap: 10px; + font-size: var(--fs-m); + margin: var(--sp-2) 0; + } + .inforow .k { + color: var(--hp-muted); + min-width: 84px; + } + .inforow a { + color: var(--hp-accent); + word-break: break-all; + } + .infodesc { + font-size: var(--fs-m); + white-space: pre-wrap; + margin-top: var(--sp-3); + } + .infodesc.muted { + color: var(--hp-muted); + } + .pdflist { + display: flex; + flex-direction: column; + gap: var(--sp-2); + } + .pdf { + display: inline-flex; + align-items: center; + gap: var(--sp-2); + color: var(--hp-accent); + text-decoration: none; + } + ha-icon-picker { + display: block; + } + .floorrow { + display: flex; + align-items: center; + gap: var(--sp-4); + padding: var(--sp-3) var(--sp-2); + font-size: var(--fs-m); + cursor: pointer; + } + .floorrow .floorlvl { + color: var(--hp-muted); + font-size: var(--fs-s); + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + padding: 0 var(--sp-3); + } + .rtest { + display: flex; + align-items: center; + gap: var(--sp-4); + margin-bottom: var(--sp-4); + } + .rtest .namein { flex: 1; } + .rtest ha-icon { color: var(--hp-accent); } + .rtesticon { font-size: var(--fs-s); color: var(--hp-muted); } + .rrow { + display: flex; + align-items: center; + gap: var(--sp-3); + margin: var(--sp-1) 0; + } + .rrow .rpat { flex: 2; } + .rrow .ricon { flex: 1.4; } + .rrow .rpat.bad { border-color: #ff7a5c; } + .rrow .rprev { --mdc-icon-size: 18px; color: var(--hp-txt); min-width: 18px; } + .rrow .ract { + --mdc-icon-size: 16px; + color: var(--hp-muted); + cursor: pointer; + } + :host([data-pointer-hover]) .rrow .ract:hover { color: var(--hp-txt); } + :host([data-pointer-hover]) .rrow .ract.del:hover { color: #ff7a5c; } + .gsrow .gsl { + min-width: 150px; + font-size: var(--fs-m); + color: var(--hp-muted); + } + .optimize-live { + display: grid; + justify-items: start; + gap: var(--sp-2); + margin-bottom: var(--sp-3); + } + .optimize-live .alignmsg, .optimize-live .rhint { margin-bottom: 0; } + .optimize-cleanup { min-height: 44px; } + .optimize-selected { color: var(--hp-txt); } + .optimize-details { + margin-top: var(--sp-3); + color: var(--hp-muted); + font-size: var(--fs-s); + overflow-wrap: anywhere; + } + .optimize-details > summary { + width: fit-content; + color: var(--hp-txt); + cursor: pointer; + font-weight: 600; + } + .optimize-details > summary:focus-visible { + outline: 2px solid var(--hp-accent); + outline-offset: 3px; + border-radius: var(--rad-s); + } + .optimize-details ul { margin: var(--sp-3) 0; padding-inline-start: 22px; } + .optimize-details li + li { margin-top: var(--sp-1); } + .btn.alignall { width: 100%; justify-content: center; } + .backupactions { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--sp-3); + } + .backupactions .btn { justify-content: center; min-width: 0; } + .backupupload { display: inline-flex; min-width: 0; } + .backupupload > .btn { width: 100%; justify-content: center; } + .backupupload input { display: none; } + .backupbody { min-width: 0; } + .backupplanonly { margin-inline-start: var(--sp-4) !important; align-items: flex-start !important; } + .backupplanonly > span:first-of-type { display: grid; gap: 2px; white-space: normal; } + .backupplanonly small { color: var(--secondary-text-color); line-height: 1.35; } + .backupplanonlystatus { color: var(--hp-accent) !important; font-weight: 700; } + .backupfile, .backupsummary, .backupcontent { + display: flex; + flex-direction: column; + min-width: 0; + gap: var(--sp-1); + } + .backupfile b, .backupcontent span { + overflow-wrap: anywhere; + } + .backupfile span, .backupsummary span, .backupcontent span { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .backupcounts { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--sp-2) var(--sp-4); + font-size: var(--fs-s); + } + .backupwarn, .backuperror { + border-radius: var(--rad-s); + padding: var(--sp-3); + font-size: var(--fs-s); + line-height: 1.45; + overflow-wrap: anywhere; + } + .backupwarn { background: color-mix(in srgb, var(--hp-accent) 12%, transparent); } + .backuperror { background: rgba(179, 64, 42, .16); color: #ff7a5c; } + .backupdetails { + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + padding: var(--sp-2) var(--sp-3); + font-size: var(--fs-s); + } + .backupdetails summary { cursor: pointer; font-weight: 700; } + .backupdetails > div { display: grid; gap: var(--sp-1); padding-block-start: var(--sp-2); } + .backupdetails code { overflow-wrap: anywhere; color: var(--hp-muted); } + .backupchoices { + display: flex; + flex-direction: column; + gap: var(--sp-2); + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + min-width: 0; + } + .backupchoices label { margin: 0 !important; display: flex; gap: var(--sp-2); } + .backupconfirm { align-items: flex-start !important; } + .backupconfirm > span:first-of-type { + min-width: 0; + white-space: normal; + overflow-wrap: anywhere; + } + @media (max-width: 520px) { + .backupactions, .backupcounts { grid-template-columns: 1fr; } + } + .aboutver { + font-size: var(--fs-s); + color: var(--hp-muted); + margin: var(--sp-2) 0 var(--sp-3); + } + .aboutlink { + display: flex; + align-items: center; + gap: var(--sp-3); + width: fit-content; + color: var(--hp-accent); + text-decoration: none; + font-size: var(--fs-m); + padding: var(--sp-1) 0; + } + :host([data-pointer-hover]) .aboutlink:hover { text-decoration: underline; } + .aboutlink ha-icon { --mdc-icon-size: 18px; line-height: 1; } + hp-dialog .body { + padding: var(--sp-5) var(--sp-6); + display: flex; + flex-direction: column; + gap: var(--sp-3); + } + hp-dialog .tapconfirm-body { + min-width: 0; + overflow-x: hidden; + } + hp-dialog .tapconfirm-body p { + max-width: 100%; + min-width: 0; + margin: 0; + overflow-wrap: anywhere; + white-space: normal; + } + hp-dialog .tapconfirm-line { + color: var(--hp-muted); + } + hp-dialog .body label { + font-size: var(--fs-s); + color: var(--hp-muted); + margin-top: var(--sp-3); + } + hp-dialog .body .namein, + hp-dialog .body .areasel { + width: 100%; + box-sizing: border-box; + } + /* Room settings contains long radio labels, two source pickers and live + previews, so it deliberately uses hp-dialog's medium width. Keep its + content shrinkable as well: the generic srcrow rule is nowrap because + compact switch rows need it, but here that created a horizontal scroll + box even on a wide desktop viewport. */ + hp-dialog.roomdialog .body { + min-width: 0; + overflow-x: hidden; + } + hp-dialog.roomdialog .body > * { + min-width: 0; + max-width: 100%; + box-sizing: border-box; + } + hp-dialog.roomdialog .srcrow { + min-width: 0; + align-items: flex-start; + } + hp-dialog.roomdialog .srcrow > span:first-of-type { + min-width: 0; + white-space: normal; + overflow-wrap: anywhere; + line-height: 1.35; + } + hp-dialog.roomdialog .dropbtn > b, + hp-dialog.roomdialog .dropbtn > .ref { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + hp-dialog .row { + display: flex; + justify-content: flex-end; + gap: var(--sp-4); + width: 100%; + min-width: 0; + box-sizing: border-box; + padding: var(--sp-5) var(--sp-6); + border-top: 1px solid var(--hp-line); + } + /* Stable destructive/commit footer contract. A flex spacer cannot react + when translated labels no longer fit: justify-content then overflows + the destructive button through the left inset. Two real groups wrap + as units instead — destructive actions stay left, while Cancel/Save + move together to a right-aligned second row when necessary. */ + hp-dialog .row.dialog-action-footer { + align-items: center; + justify-content: flex-start; + flex-wrap: wrap; + row-gap: var(--sp-4); + } + hp-dialog .dialog-action-group { + display: flex; + flex: 0 1 auto; + flex-wrap: wrap; + align-items: center; + gap: var(--sp-4); + max-width: 100%; + min-width: 0; + } + hp-dialog .dialog-action-group .btn { + flex: 0 0 auto; + min-height: 44px; + } + hp-dialog .dialog-action-danger { + margin-right: auto; + } + hp-dialog .dialog-action-commit { + margin-left: auto; + justify-content: flex-end; + } + hp-dialog .row.markerfooter { + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + } + hp-dialog .row.roomfooter { + align-items: center; + flex-wrap: wrap; + } + /* Device info can have Edit + Open in HA + Close. It uses a wide dialog; + wrapping remains as a phone fallback, but without a flex spacer (which + used to strand Edit alone on the first line). */ + hp-dialog .row.infofooter { + align-items: center; + justify-content: flex-start; + flex-wrap: wrap; + gap: var(--sp-3); + } + hp-dialog .row.infofooter .btn { + flex-shrink: 0; + } + hp-dialog .row.infofooter .infofooter-close { + margin-left: auto; + } + @media (max-width: 480px) { + hp-dialog .row.infofooter { + padding: var(--sp-4) var(--sp-5); + } + } + .markeractions, + .markersaveactions { + display: flex; + align-items: center; + gap: var(--sp-4); + } + .markeractions:empty { display: none; } + .markersaveactions { margin-left: auto; } + .device-inbox { + display: flex; + flex-direction: column; + gap: var(--sp-4); + padding: var(--sp-5) var(--sp-6); + min-width: 0; + } + .device-inbox-dialog { --hp-dialog-wide-width: 920px; } + .device-inbox-head { + display: grid; + grid-template-columns: minmax(180px, 1fr) auto; + align-items: center; + gap: var(--sp-4); + } + .device-inbox-search { + width: 100%; + min-width: 0; + box-sizing: border-box; + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + background: transparent; + color: var(--hp-txt); + font: inherit; + padding: 11px 14px; + } + .device-inbox-tabs { + display: flex; + gap: var(--sp-2); + overflow-x: auto; + scrollbar-width: thin; + padding-bottom: var(--sp-1); + } + .device-inbox-tabs button { + flex: 0 0 auto; + border: 1px solid var(--hp-line); + border-radius: 999px; + background: transparent; + color: var(--hp-txt); + font: inherit; + padding: 8px 12px; + cursor: pointer; + } + .device-inbox-tabs button.on { + border-color: var(--hp-accent); + background: color-mix(in srgb, var(--hp-accent) 18%, transparent); + } + .device-inbox-tabs button span { color: var(--hp-muted); margin-inline-start: 4px; } + .device-inbox-filters { + display: flex; + flex-wrap: wrap; + gap: var(--sp-4) var(--sp-6); + color: var(--hp-muted); + } + .device-inbox-filters label { + display: inline-flex; + align-items: center; + gap: var(--sp-2); + cursor: pointer; + } + .device-inbox-results { display: grid; gap: var(--sp-3); min-width: 0; } + .device-inbox-row { + display: grid; + grid-template-columns: 42px minmax(180px, 1fr) minmax(180px, auto); + align-items: center; + gap: var(--sp-4); + min-width: 0; + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + padding: var(--sp-4); + background: color-mix(in srgb, var(--hp-txt) 3%, transparent); + } + .device-inbox-icon { --mdc-icon-size: 28px; color: var(--hp-txt); justify-self: center; } + .device-inbox-copy { min-width: 0; } + .device-inbox-name { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2); } + .device-inbox-new { + border-radius: 999px; + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + font-size: var(--fs-s); + padding: 2px 7px; + } + .device-inbox-meta, + .device-inbox-reason, + .device-inbox-copy code { + display: block; + color: var(--hp-muted); + font-size: var(--fs-s); + overflow-wrap: anywhere; + white-space: normal; + } + .device-inbox-status { color: var(--error-color, #db4437); margin-inline-start: var(--sp-2); } + .device-inbox-actions { + display: flex; + justify-content: flex-end; + align-items: center; + flex-wrap: wrap; + gap: var(--sp-2); + } + .device-inbox-actions .btn { min-height: 36px; padding: 7px 10px; } + .device-inbox-menu { position: relative; } + .device-inbox-menu summary { list-style: none; cursor: pointer; } + .device-inbox-menu summary::-webkit-details-marker { display: none; } + .device-inbox-menu-items { + position: absolute; + z-index: 2; + inset-inline-end: 0; + top: calc(100% + var(--sp-1)); + display: grid; + gap: var(--sp-1); + min-width: 180px; + padding: var(--sp-2); + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + background: var(--hp-panel, var(--card-background-color, #fff)); + box-shadow: 0 8px 24px rgba(0, 0, 0, .22); + } + .device-inbox-menu-items .btn { justify-content: flex-start; width: 100%; } + .device-inbox-empty { color: var(--hp-muted); text-align: center; padding: var(--sp-8); } + .device-inbox-more { align-self: center; } + @media (max-width: 680px) { + .device-inbox { padding: var(--sp-4); } + .device-inbox-head { grid-template-columns: minmax(0, 1fr); } + .device-inbox-head .btn { justify-self: stretch; } + .device-inbox-tabs { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + overflow-x: visible; + } + .device-inbox-tabs button { + min-width: 0; + overflow-wrap: anywhere; + } + .device-inbox-row { grid-template-columns: 36px minmax(0, 1fr); } + .device-inbox-actions { grid-column: 1 / -1; justify-content: flex-start; } + } +`];var Zd={"editor.context_actions":"Actions: {object}","editor.tool_options":"Tool options: {tool}","editor.palette":"Palette: {tool}","editor.open_group":"Tool group: {group}","editor.group_active":"{group} — active: {item}","editor.disabled_action":"{action} is unavailable: {reason}","editor.loading":"Loading editor…","editor.loading_aria":"The plan editor is loading","editor.load_failed":"Could not load the editor.","editor.refresh_advice":"Refresh the page and try again.","editor.retry_advice":"Check your connection and press again.","color_picker.title":"Color picker","color_picker.hue":"Hue","color_picker.saturation":"Saturation","color_picker.value":"Brightness","color_picker.hex":"Hex color","color_picker.invalid_hex":"Enter a 3- or 6-digit hex color","btn.properties":"Properties","btn.keep_as_walls":"Keep as walls","btn.delete_room_keep_walls":"Delete room, keep walls","btn.delete_room_with_walls":"Delete room and walls","title.markup_select":"Select and edit walls, columns and saved outlines","title.markup_column":"Column: click a grid point to place a square column","markup.partition":"Partition","markup.column":"Column","markup.hint_column":"click a grid point to place a square column","history.draft_segment":"Add room-draft segment","history.draft_merge":"Join unfinished room outlines","history.draft_segment_delete":"Remove room-draft segment","history.partition_add":"Add partition","history.column_add":"Add column","history.physical_edit":"Change physical object","history.physical_delete":"Delete physical object","history.physical_move":"Move physical object","history.contour_to_partitions":"Convert contour to closed walls","history.wall_chain_finish":"Finish wall chain","history.wall_face_batch":"Create rooms from walls","toast.column_duplicate":"A column with the same centre and outer size already exists","confirm.delete_draft":"Delete the whole unfinished room contour?","confirm.delete_draft_segment":"Delete this draft segment? The remaining contour may split in two.","physical.partition_properties":"Partition properties","physical.column_properties":"Column properties","physical.draft_properties":"Draft segment properties","physical.shape":"Shape","physical.square":"Square","physical.circle":"Circle","physical.diameter":"Diameter","physical.side":"Side","physical.rotation":"Rotation angle","physical.length":"Length","physical.allowed_range":"Allowed: {min}–{max} {unit}","physical.delete_segment":"Delete segment","physical.delete_draft":"Delete entire outline","physical.column_size_title":"Outer side of the square column placed by the click (1–150 cm).","card.title":"House plan","count.devices":"{n} dev.","empty.no_spaces":"No spaces yet.","empty.add_first":"Add the first space and upload a floor plan.","empty.install":'Install the House Plan integration and add it in "Devices & services".',"btn.add_space":"Add space","btn.cancel":"Cancel","btn.save":"Save","btn.close":"Close","btn.delete":"Delete","btn.edit":"Edit","btn.open_in_ha":"Open in HA","btn.reset":"Reset","btn.attach":"Attach…","btn.upload":"Upload…","btn.replace":"Replace…","title.zoom_in":"Zoom in","title.zoom_out":"Zoom out","title.zoom_fit":"Fit all","title.markup":"Room markup: grid, lines, outlines","title.configure_space":"Configure space","title.add_space":"Add space","title.markup_add":"Walls: draw a continuous chain; Shift locks to 45°. Changing tool or leaving the editor finishes it as independent walls","title.markup_merge":"Merge: click one room, then the neighbour it shares a wall with","title.markup_split":"Split a room: click the room, then two points on its walls","title.markup_delroom":"Delete room: click inside a room and confirm","title.need_plan":"Upload a floor-plan image","markup.add":"Walls","markup.merge":"Merge","markup.split":"Split","markup.resize":"Resize","title.markup_resize":"Resize rooms: drag an available horizontal or vertical wall handle","markup.hint_resize":"drag an available wall handle · the wall stops at the first unsafe position · Esc cancels · Ctrl+Z — undo","resize.disabled.diagonal":"This wall is angled; Resize supports only horizontal and vertical walls","resize.disabled.side-angle":"An adjoining wall is angled; Resize requires both adjoining walls to meet this wall at right angles","resize.disabled.duplicate-physical-wall":"A separate partition, unfinished outline, or column overlaps this wall; remove or move it before resizing","resize.disabled.partial-shared":"A neighbouring room uses only part of this wall, so it cannot be moved safely as one shared wall","resize.disabled.unequal-shared":"The neighbouring room uses different endpoints or wall length, so the walls cannot move together safely","resize.disabled.multiple-rooms":"Moving this wall would affect more than two rooms","resize.disabled.thickness-conflict":"The wall thickness cannot be preserved safely","resize.disabled.opening-conflict":"An opening on this wall cannot be moved safely","resize.disabled.invalid-geometry":"This wall cannot be resized without changing the plan structure","resize.limit_stopped":"Wall stopped: the next step would break a junction limit","resize.commit_failed":"Resize was cancelled because the final plan did not pass the geometry check","resize.preview_failed":"Resize stopped at the last safe position because the plan geometry could not be preserved","markup.opening":"Opening","markup.delete_room":"Delete room","history.undo":"Undo","history.redo":"Redo","history.undo_named":"Undo: {name} (Ctrl+Z)","history.redo_named":"Redo: {name} (Ctrl+Shift+Z / Ctrl+Y)","history.undo_empty":"Nothing to undo","history.redo_empty":"Nothing to redo","history.undone":"Undone: {name}","history.redone":"Redone: {name}","history.add_room":"Create room","history.split_room":"Split room","history.merge_rooms":"Merge rooms","history.resize_room":"Resize room","history.wall_thickness":"Change wall thickness","history.add_opening":"Add door or window opening","history.edit_opening":"Edit opening","history.move_opening":"Move opening","history.delete_opening":"Delete opening","history.delete_room":"Delete room","history.delete_room_keep_walls":"Delete room, keep walls","history.delete_room_with_walls":"Delete room and walls","history.decor_add":"Add decor object","history.decor_edit":"Edit decor object","history.decor_move":"Move decor object","history.decor_transform":"Transform decor object","history.decor_delete":"Delete decor object","history.backdrop_transform":"Transform plan backdrop","opening.new":"New opening","opening.edit":"Opening","opening.door":"Door","opening.window":"Window","opening.gate":"Gate","opening.passage":"Open passage","opening.passage_binding_warning":"Saving will remove the open/close sensor and lock.","opening.invalid_passage_fields":"The open passage on plan “{room}” has unsupported settings: {fields}.","opening.type_label":"Type","opening.length_label":"Length, cm","opening.contact_label":"Open/close sensor","opening.lock_label":"Lock","opening.none":"— none —","opening.search_ph":"Search: name or entity id…","opening.invert":"Invert open/closed","opening.flip_h":"Hinge on the other jamb","opening.flip_v":"Opens to the other side","opening.open":"Open","opening.closed":"Closed","opening.locked":"Locked","opening.unlocked":"Unlocked","opening.state_unknown":"unavailable","opening.no_entities":"No sensors bound — a static symbol on the plan.","toast.opening_no_wall":"Click next to a room wall or independent wall","opening.host_partition":"Independent wall","opening.partition_orphan":"The independent wall for this opening no longer exists","opening.partition_jamb_margin":"Leave at least {distance} between the opening and the end of the wall","opening.rebind_partition":"Attach to another independent wall","confirm.delete_partition_openings_title":"Delete wall and openings?","confirm.delete_partition_openings_body":"This wall contains {count} opening(s). They will be deleted together.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.delete":"Delete","markup.hint_points":"points: {n} · Shift — 45° steps · Esc — finish chain · Ctrl+Z — undo a point · closing an area offers a room","markup.hint_start":"click a grid dot to start a wall chain","tip.lqi":"average zigbee signal:","tip.area":"area: {value}","info.device_header":"Device on the plan","info.model":"Model","info.state":"State","info.link":"Link","info.manuals":"Manuals","info.none":"No additional information","marker.new_device":"New device","marker.name_label":"Name (shown on the plan)","marker.name_ph":"Name","marker.binding_label":"Bind to an HA device","marker.binding_disabled":"disabled in Home Assistant","marker.virtual_option":"Virtual device (no binding)","marker.search_ph":"Search device / group…","marker.nothing_found":"nothing found","marker.room_label":"Room","marker.room_override":" (override placement)","marker.room_choose":"— select a room —","marker.room_auto":"— by device area (auto) —","marker.icon_label":"Icon","marker.icon_ph":"mdi:… (empty = auto)","marker.display_label":"Display","display.badge":"Icon + state","display.icon_ripple":"Icon + state and activity","display.static_icon":"Always static icon","marker.display_hint":"Icon + state changes the plate for work, open, alarm and unavailable states. Icon + state and activity additionally shows a short pulse for events and a continuous pulse for ongoing work, movement or presence. Value + state replaces the icon with one unambiguous HA value. A static icon never reacts to device states.","marker.display_hint_badge":"The icon and dynamic plate show device state without the ordinary activity pulse. Red alarms remain visible.","marker.display_hint_icon":"The icon and dynamic plate show device state without the ordinary activity pulse. Red alarms remain visible.","marker.display_hint_icon_ripple":"The icon, dynamic plate and pulse show a short pulse for events and a continuous pulse for work, motion or presence. Red alarms have separate priority.","marker.display_hint_value":"One unambiguous Home Assistant value replaces the icon while the plate continues to show state. Red alarms remain visible.","marker.display_hint_static_icon":"The theme-aware shell and icon always stay the same. State, activity, unavailability and alarms do not change the face.","marker.static_alarm_warning":"This device can report alarms. Static display hides the marker's visual alarm indication.","marker.preview.title":"Display preview","marker.preview.actual":"Now","marker.preview.example":"Example","marker.preview.integration":"Provided by","marker.preview.source":"Display source","marker.preview.current_state":"Current state","marker.preview.result":"On the plan","marker.preview.details":"Source details","marker.preview.select_source":"Choose a Home Assistant device or entity to see its actual display.","marker.preview.unknown_provider":"Unknown integration","marker.preview.virtual_provider":"House Plan · virtual device","marker.preview.no_source":"No active source","marker.preview.no_state":"No current state","marker.preview.mixed_states":"Several different states","marker.preview.multiple_sources":"{n} sources","marker.preview.more_sources":"+{n} more","marker.preview.scaled":"The preview is scaled to {n}% to fit. The saved size is unchanged.","marker.preview.demo_short":"Show short activity","marker.preview.demo_continuous":"Show continuous activity","marker.preview.stop_continuous":"Stop continuous activity","marker.preview.demo_short_notice":"Short activity example; the actual device state is unchanged.","marker.preview.demo_continuous_notice":"Continuous activity example; the actual device state is unchanged.","marker.preview.demo_already_visible":"The current state already shows a real activity or alarm effect.","marker.preview.reduced_motion":"System reduced-motion is enabled, so ordinary activity is shown as a dot.","marker.preview.reason.neutral":"Neutral dark plate","marker.preview.reason.working":"Yellow plate: the device is working now","marker.preview.reason.working_activity":"Yellow plate and activity effect: the device is working now","marker.preview.reason.open":"Orange plate: physically open or unlocked","marker.preview.reason.cover_icon_state":"Neutral plate; the cover entity controls the displayed state and icon","marker.preview.reason.presence":"Activity effect while presence is detected","marker.preview.reason.event":"Short activity effect after a detected event","marker.preview.reason.transition":"Activity effect while the device is moving or changing state","marker.preview.reason.media_neutral":"Media devices stay on a neutral dark plate while available","marker.preview.reason.unavailable":"Subdued neutral plate: unavailable or off","marker.preview.reason.alarm":"Red alarm plate; alarm indication is always shown","marker.preview.reason.live_states_disabled":"Live-state styling is disabled for this card","marker.preview.reason.value_no_state":"No usable state value; the icon is shown instead","marker.preview.reason.value_ambiguous_sources":"Several possible value sources; the icon is shown instead","marker.preview.reason.value_non_scalar":"The source did not return a simple value; the icon is shown instead","marker.preview.reason.value_virtual":"A virtual device has no Home Assistant value; the icon is shown instead","marker.preview.reason.vacuum_live_plan_only":"Live vacuum position and trail are available only on the full plan","marker.preview.reason.hidden_design_preview":"The device is hidden on the plan; this design preview remains visible","marker.preview.reason.composite_power_source":"State comes from the device Power entity; auxiliary switches are ignored","marker.preview.reason.activity_display_disabled":"The selected display mode does not show ordinary activity effects","marker.preview.reason.ha_disabled":"The Home Assistant binding is disabled and will be hidden on the plan","marker.preview.reason.orphaned":"The saved Home Assistant binding can no longer be found","marker.preview.reason.static_icon":"Static mode: device state does not change the icon","marker.activity_color":"Activity pulse color","marker.ripple_size":"Activity pulse size","marker.activity_alarm_note":"Color and size affect ordinary activity only and do not change red alarms.","marker.pulse_a11y_alarm":"Alarm","marker.pulse_a11y_event":"Recent event","marker.pulse_a11y_presence":"Presence detected","marker.pulse_a11y_transition":"Changing state","marker.pulse_a11y_running":"Working","marker.state_a11y_neutral":"Default state","marker.state_a11y_working":"Working","marker.state_a11y_open":"Open","marker.state_a11y_locked":"Locked","marker.state_a11y_unlocked":"Unlocked","marker.state_a11y_alarm":"Alarm","marker.state_a11y_unavailable":"Unavailable","marker.lqi_a11y_low":"LQI {value}, low signal","marker.lqi_a11y_mid":"LQI {value}, medium signal","marker.lqi_a11y_high":"LQI {value}, high signal","marker.size_label":"Icon size / rotation","marker.angle_label":"Rotate","marker.model_label":"Model","marker.model_ph":"e.g. Aqara T&H","marker.link_label":"Link","marker.desc_label":"Description","marker.desc_ph":"Notes, specs…","marker.manuals_label":"Manuals (PDF etc.)","marker.sub_device":"device","marker.sub_z2m_group":" · Z2M group","marker.sub_group":"group","marker.sub_helper":"helper","space.new":"New space","space.header":"Space","space.title_label":"Title","space.title_ph":"e.g. Garage","space.plan_label":"Floor plan (background)","space.no_plan":"no plan image","space.plan_alt":"plan","room.new":"New room","room.name_label":"Display name","room.name_ph":"e.g. Terrace","room.area_label":"Home Assistant area (unassigned)","room.no_area_option":"— no area —","room.default_name":"Room","device.unnamed":"unnamed","device.light_group":"light group","device.fallback":"device","device.virtual":"virtual device","confirm.delete_room":'Delete room "{name}"?',"confirm.delete_room_title":'Delete room "{name}"?',"confirm.delete_room_body":"Choose whether the room's exclusive physical walls should remain. Walls shared with another room are always kept.","confirm.remove_marker":'Delete "{name}" from the plan? The device will disappear completely and stop contributing to plan data. You can add it again later.',"confirm.erase_decor":"Erase the {kind} object? You can undo this action from the editor history.","confirm.delete_space":'Delete space "{title}" with all its rooms and markup?',"space.delete_blocked":"This space is still used by {n} device(s). Move them to another space or delete them first.","toast.pos_save_failed":"Failed to save position: {err}","toast.no_entity":"The device has no suitable entity","toast.ha_disabled_action":"A Home Assistant object that is disabled cannot be used on the plan.","toast.ha_disabled_show_device":"A device disabled in Home Assistant cannot be shown on the plan. Enable it in Home Assistant first.","toast.ha_disabled_show_entity":"An entity disabled in Home Assistant cannot be shown on the plan. Enable it in Home Assistant first.","toast.ha_disabled_add":"A disabled Home Assistant object cannot be added to the plan. Enable it in Home Assistant first.","toast.ha_binding_unverified":"The object status could not be verified through the Home Assistant registry. Display and actions are temporarily unavailable.","toast.markup_needs_server":"Markup is available after the config is moved to the server","toast.space_order_changed":"Order changed. If any card pins its floor by number, check those panels.","toast.conflict":"Config was changed in another window — data refreshed, repeat your last action","toast.cfg_save_failed":"Failed to save config: {err}","toast.room_overlap":"The outline overlaps room “{name}” — rooms must not overlap","toast.contour_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_saved":"Space saved","toast.space_deleted":"Space deleted","toast.delete_failed":"Delete failed: {err}","toast.error":"Error: {err}","toast.toggle_target_unavailable":"Target “{name}” is unavailable — no action was performed","toast.toggle_targets_unavailable":"Targets are unavailable: {names}. No action was performed","toast.file_failed":'File "{name}" was not uploaded: {err}',"toast.files_attached":"Files attached: {n}","err.unknown":"unknown error","err.code":"code {code}","err.too_large":"file larger than {mb} MB","err.bad_ext":"unsupported type (PDF/image expected)","err.unauthorized":"administrator rights required","editor.title":"Title","editor.default_floor":"Initial space","editor.default_floor_missing":"Initial space “{id}” no longer exists. Choose another space.","editor.floor":"Fixed space","editor.floor_none":"— not fixed —","editor.floor_index":"YAML index {index} (preserved)","fixed_floor.loading":"Loading the fixed space…","fixed_floor.invalid_title":"The fixed space is unavailable","fixed_floor.invalid_body":"Check floor in the card configuration. The configured value is: {value}","editor.icon_size":"Icon size, % of plan width","editor.show_temperature":"Show temperature","editor.live_states":"Live states (on/off, open…)","editor.show_signal":"Show zigbee signal (LQI)","editor.language":"Interface language","editor.lang_auto":"Auto (HA profile)","title.icon_rules":"Icon rules: which MDI icon devices get by name","rules.title":"Icon rules","rules.hint":"Rules are checked top-down against “device name + model” (case-insensitive regex); the first match wins. When nothing matches, the entity device class decides, then the generic chip icon.","rules.pattern_ph":"regex, e.g. plug|socket","rules.icon_ph":"mdi:power-socket-de","rules.add":"Add rule","rules.reset":"Reset to defaults","rules.test_ph":"Try a device name…","rules.invalid":"invalid regex","rules.saved":"Icon rules saved","btn.up":"Up","btn.down":"Down","tap.info":"Device card","tap.more_info":"HA more-info dialog","tap.toggle":"Toggle state","marker.tap_label":"Tap action for this device","tap.toggle_note":"The resolved state is shown below. Secure devices are never toggled from the plan.","import.title":"Create spaces from HA floors","import.hint":"Your Home Assistant already knows these floors. Pick the ones to turn into plan spaces — you will upload a floor-plan image for each one next. Rooms are then outlined by hand on the plan.","import.start":"Create {n} space(s)","import.manual":"Start from scratch","import.progress":"Floor {i} of {n}","import.done":"Spaces created. Outline the rooms: click grid dots and close the contour.","btn.skip":"Skip","space.scale_label":"Scale (grid cell size)","space.scale_unit":"cm per cell","space.scale_unit_imperial":"in per cell","space.display_section":"Display","space.show_borders":"Always show room borders","space.zero_wall_style":"Zero-thickness walls","space.zero_wall_dashed":"Dashed","space.zero_wall_solid":"Solid","space.zero_wall_help":"Dashed walls let light through. Solid walls block light even at zero thickness.","space.show_names":"Show room names (drag to move)","space.room_color":"Border & name color","space.opacity":"Opacity","space.fill_label":"Room fill","fill.none":"None","fill.lqi":"Zigbee signal","fill.light":"Lights","fill.custom":"Custom color","space.custom_fill":"Fill color","space.source_file":"I have a floor-plan image","space.source_draw":"No image — I'll outline rooms by hand","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.show_button":"Show button","editor.button_label":"Button label","editor.button_target":"Target dashboard path","marker.sub_entity":"entity","title.general_settings":"General settings","gs.title":"General settings","gs.hint":"Fill colors apply to every space; each color has its own opacity. Which fill mode a space uses is set in that space's dialog.","gs.light_group":"Fill: lights","gs.light_on":"Lights on","gs.light_off":"All lights off","gs.temp_group":"Fill: temperature","gs.temp_cold":"Cold","gs.temp_ok":"Comfortable","gs.temp_hot":"Hot","gs.lqi_group":"Fill: zigbee signal","gs.lqi_low":"Weak signal","gs.lqi_high":"Strong signal","gs.reset":"Reset to defaults","gs.saved":"General settings saved","space.show_lqi":"Show zigbee signal (LQI) next to devices","space.hide_decor":"Hide the decorative layer","space.hide_decor_tip":"Lines, shapes, labels and furniture stay where they are — visible in the backdrop editor, not on the plan.","space.hide_openings":"Hide openings","space.hide_openings_tip":"Door, window and gate symbols are not drawn, but the openings keep working: light passes through, the sun comes in at a window, contact sensors still open them. The plan editor always shows them.","gs.light_none":"No light sources","mode.plan":"Plan editor","mode.devices":"Device editor","display.value":"Value + state","marker.subarea":"no area, manual","device.new":"New device — open its editor to dismiss","opening.unlock_action":"Unlock","opening.lock_action":"Lock","opening.lock_pending":"Working…","title.close_editor":"Close editor (back to view)","devbar.rules":"Icon rules","device_inbox.button":"Devices","device_inbox.title":"Devices on the plan","device_inbox.search":"Search devices, entities and integrations…","device_inbox.add_virtual":"Add virtual device","device_inbox.tab_on_plan":"On plan","device_inbox.tab_available":"Available","device_inbox.tab_hidden":"Hidden","device_inbox.tab_readd":"Available again","device_inbox.only_new":"New only","device_inbox.show_entities":"Show entities","device_inbox.show_hidden":"Show hidden on plan","device_inbox.new":"New","device_inbox.find":"Find on plan","device_inbox.edit":"Edit","device_inbox.hide":"Hide","device_inbox.show":"Show","device_inbox.add":"Add","device_inbox.readd":"Add again","device_inbox.hide_available":"Hide from list","device_inbox.show_more":"Show more","device_inbox.more_actions":"More actions","device_inbox.find_hidden_hint":"Enable “Show hidden on plan” first","device_inbox.show_disabled":"Activate this binding in Home Assistant before showing it","device_inbox.empty_on_plan":"No matching devices are on the plan yet.","device_inbox.empty_available":"No devices are available to add.","device_inbox.empty_hidden":"There are no hidden devices.","device_inbox.empty_readd":"No removed devices are available to add again.","device_inbox.reason_visible_auto":"Discovered automatically","device_inbox.reason_visible_explicit":"Added explicitly","device_inbox.reason_manual_hidden":"Hidden by user","device_inbox.reason_automatic_hidden":"Hidden automatically","device_inbox.reason_service_entry":"Service-only registry entry","device_inbox.reason_excluded_integration":"Integration excluded by device filters","device_inbox.reason_excluded_domain":"Non-spatial entity type","device_inbox.reason_grouped_light":"Represented by a room light group","device_inbox.reason_represented_by_parent":"Represented by its parent device","device_inbox.reason_removed":"Previously removed from the plan","device_inbox.reason_available":"Available to add to the plan","device_inbox.reason_no_bound_room":"HA area is not linked to a plan room","device_inbox.status_ha_disabled":"Disabled in Home Assistant","device_inbox.status_orphaned":"Binding is no longer present in Home Assistant","device_inbox.status_unverified":"Home Assistant registry is temporarily unavailable","device_inbox.saved":"Device list updated","space.roomcard_section":"Room card shows:","space.label_temp":"Temperature","space.label_hum":"Humidity","space.label_lqi":"Average Zigbee signal","space.label_light":"Lights on/off","roomcard.light_on":"On","roomcard.light_off":"Off","roomcard.light_partial":"{on} of {total}","toast.split_pick_inside":"Intermediate cut points must be inside the room","mode.decor":"Background editor","decor.select":"Select","decor.line":"Line","decor.rect":"Rectangle","decor.ellipse":"Oval","decor.text":"Text","decor.erase":"Erase","decor.erase_confirm_title":"Erase object?","decor.color":"Color","decor.width":"Line width","decor.line_style":"Line style","decor.line_style_solid":"Solid","decor.line_style_dashed":"Dashed","decor.fill":"Fill","decor.fill_color":"Fill color","decor.length":"Length","decor.size":"Size","decor.angle":"Rotation angle, °","decor.text_size":"Text size","decor.backdrop_properties":"Plan backdrop properties","decor.text_title":"Text label","decor.object_title":"Edit {kind}","decor.text_label":"Text","decor.live_group":"Insert HA variable","decor.live_entity":"Entity","decor.live_entity_ph":"choose an entity","decor.live_attr":"Value","decor.live_attr_ph":"choose state or attribute","decor.live_state":"State","decor.backdrop":"Backdrop image","decor.backdrop_hint":"Drag to move; pull a corner to resize; use the top handle to rotate. Shift changes proportions or frees the angle.","decor.backdrop_reset":"Reset the picture","decor.backdrop_reset_done":"The picture is back at its original place and size","marker.icon_auto":"Auto: {icon} (by icon rules; pick one to override)","marker.icon_pin_auto":"Pin","mode.plan_tip":"Plan editor — the geometry of the home: draw and split/merge rooms, bind them to HA areas, place doors, windows and gates, move room cards, set the scale","mode.devices_tip":"Device editor — everything about icons: drag to position, click to edit binding/icon/display, add virtual devices, icon rules","mode.decor_tip":"Background editor — purely visual decor under the plan: lines, rectangles, ovals and text labels that never react to clicks","space.glow_enabled":"Light-source glow","gs.glow_group":"Light-source glow","gs.glow_base":"House darkness","gs.glow_light":"Default light color / intensity","gs.wall_group":"Walls","gs.wall_fill":"Wall fill","gs.glow_radius":"Glow radius","gs.unit_m":"m","gs.unit_ft":"ft","marker.controls_label":"Controls other light sources","marker.controls_hint":"With tap action “Toggle”, a click flips every source added here. The marker’s own bound entity is controlled directly and cannot be added; use the switch below to classify it as a light.","marker.controls_filter":"Search lights and switches…","info.controls":"Controls","marker.glow_radius_label":"Glow radius","marker.glow_radius.help":"Sets the glow radius in metres or feet; an empty value uses the radius from general settings.","marker.glow_radius.help.aria":"Help: glow radius","markup.wallthick":"Thickness","markup.select":"Select","title.markup_wallthick":"Thickness — click a wall to set its thickness from 0 to 100 cm.","markup.hint_wallthick":"click a wall · Esc closes without applying","wallthick.field":"Thickness","wallthick.unit_cm":"cm","wallthick.unit_in":"in","wallthick.apply_room":"Apply to all walls of this room","markup.draw_wall_title":"Thickness of each new wall segment (0–100 cm). Shared walls keep the existing value.","room.queue_progress":"Room {current} of {total}","toast.wall_rooms_saved":"Created rooms: {n}","toast.wall_chain_saved":"Wall chain saved","toast.wallthick_pick":"Click a wall","toast.wallthick_set":"Wall thickness set","toast.wallthick_cleared":"Wall thickness removed","toast.physical_range":"Enter a value from {min} to {max} {unit}","toast.zero_wall_opening_conflict":"Remove the opening on this wall segment first.","toast.zero_wall_ambiguous":"The wall segment is ambiguous. Simplify or adjust the junction.","toast.zero_wall_migration_blocked":"The space was not converted: {reason}. No data was changed.","toast.physical_angle":"Enter a rotation angle from 0° up to, but not including, 90°","toast.physical_limit":"The space has reached the limit for this type of geometry","toast.geometry_unsafe":"Change canceled: wall geometry could not be built safely.","junction.limit_angle":"The angle between walls is too sharp: {actual}°, minimum {limit}°.","junction.limit_valence":"Too many walls meet in one node: {actual}, maximum {limit}.","junction.limit_length":"The wall segment is too short: {actual} cm, minimum {limit} cm.","junction.limit_distance":"Walls and nodes are too close: {actual} cm, minimum {limit} cm.","junction.limit_clearance":"No room interior is left: {actual} cm², minimum {limit} cm².","junction.limit_check_failed":"The junction check could not run — the change was not saved","toast.wall_model_migration_blocked":"The wall model could not be updated: {reason}. The plan was not changed. Run “Optimize plans”; if the error repeats, fix the conflicting wall geometry.","toast.wall_model_client_outdated":"Update the card and reload the page before editing the plan.","wall_model.reason.invalid-room":"invalid room contour","wall_model.reason.zero-length":"zero-length wall segment","wall_model.reason.third-owner":"wall shared by more than two rooms","wall_model.reason.duplicate-id":"conflicting wall identifiers","wall_model.reason.thickness-conflict":"conflicting wall thickness values","wall_model.reason.opening-host":"opening cannot be assigned to one wall","toast.delete_room_pick":"Click inside the room you want to delete","toast.plan_snap_ambiguous":"Zoom in to choose the wall node","toast.wall_repair_ambiguous":"The room outline has more than one possible connection. Zoom in and connect it explicitly.","toast.wall_repair_too_large":"The gap is larger than 2 cm. Connect the walls before creating the room.","toast.wall_repair_changed":"The wall geometry changed. Try creating the room again.","toast.opening_on_zero_wall":"Openings cannot sit on a zero-thickness wall","marker.from_ha_option":"Pick from the HA list","marker.show_entities":"Show entities","marker.show_entities_tip":"Adds not only devices to the list, but all their entities too","marker.pick_ph":"Choose a device…","room.open_area":"Open the HA area","view.volumetric":"Volumetric view","view.flat":"Flat view","kiosk.title":"This screen's sizes","kiosk.hint":"Stored on this device only — every wall tablet or TV can have its own comfortable sizes.","kiosk.icon_scale":"Device icon size","kiosk.font_scale":"Room card text size","editor.kiosk":"Wall device (kiosk) mode","editor.cycle":"Auto-switch spaces every N seconds (kiosk, 0 = off)","room.settings_title":"Room settings","room.settings_section":"Room settings (override the space)","room.fill_label":"Fill in THIS room","fill.inherit":"As the space","room.custom_fill_space":"Space color","room.custom_fill_own":"Room color","room.temp_src_label":"Temperature source","room.hum_src_label":"Humidity source","room.src_average":"Average over the room's sensors (default)","room.src_pick":"A specific HA device or entity","room.src_ph":"Choose a source…","toast.room_updated":"Room updated","space.card_font":"Room-card font size (whole space)","room.sizes_section":"Font sizes","room.name_scale":"Room name size","room.label_scale":"Metrics size","preview.room_name":"Living room","toast.cfg_reload_failed":"Could not reload the plan from the server: {err}","toast.locale_load_failed":"Could not load the language pack. English is used until the page reloads.","room.settings_short":"Room settings","room.unnamed":"Unnamed room","marker.use_climate_temp":"Include the device temperature in the room","marker.use_climate_temp_tip":"Adds an air conditioner or thermostat current_temperature to the room average. Configure the external value badge separately below.","marker.value_badge_title":"Value badge","marker.value_badge.help":"Shows one selected value next to the icon. It does not affect room metrics, light, Glow or the tap action.","marker.value_badge.help.aria":"Help: device value badge","marker.value_badge_enabled":"Show a value badge","marker.value_badge_source":"Value","marker.value_badge_source.help":"Choose a specific state, supported attribute, or derived value of this device.","marker.value_badge_source.help.aria":"Help: value badge source","marker.value_badge_position":"Position","marker.value_badge_position.help":"The chosen side stays fixed and does not flip automatically at a plan edge.","marker.value_badge_position.help.aria":"Help: value badge position","marker.value_badge_right":"Right","marker.value_badge_bottom":"Below","marker.value_badge_left":"Left","marker.value_badge_top":"Above","marker.value_badge_empty":"This device has no available values","marker.value_badge_static":"A static icon does not show live values. The setting is preserved.","marker.value_badge_missing":"Source unavailable","marker.value_badge_missing_hint":"The saved source is currently unavailable. Keep it, disable the badge, or choose another value.","marker.value_badge_duplicate":"The same value is already shown inside the icon.","marker.value_badge_state":"State · {name}","marker.value_badge_marker_state":"Light-source state · {name}","marker.value_badge_lqi":"Average Zigbee signal quality","marker.value_badge_attr_current_temperature":"Current temperature · {name}","marker.value_badge_attr_temperature":"Target temperature · {name}","marker.value_badge_attr_current_humidity":"Current humidity · {name}","marker.value_badge_attr_humidity":"Humidity · {name}","marker.value_badge_attr_current_position":"Position · {name}","marker.value_badge_attr_percentage":"Speed · {name}","marker.value_badge_attr_brightness":"Brightness · {name}","marker.value_badge_attr_volume_level":"Volume · {name}","marker.value_badge_attr_battery_level":"Battery · {name}","marker.value_badge_attr_fan_speed":"Fan speed · {name}","marker.light_role_label":"Is this device a light source?","marker.light_role.help":"Controls whether this marker itself is a spatial light source. Linked lights above remain independent room-light controls.","marker.light_role.help.aria":"Help: whether this device is a light source","marker.light_role_auto_yes":"Auto (light source)","marker.light_role_auto_no":"Auto (not a light source)","marker.light_role_always":"Always a light source","marker.light_role_never":"Never a light source","marker.light_entity_label":"Leading light entity","marker.light_entity.help":"For a composite device, choose the entity whose state, colour and brightness represent this plan source. The automatic fallback remains compatible with older plans.","marker.light_entity.help.aria":"Help: leading light entity","marker.light_entity_auto":"Automatic ({entity})","marker.light_entity_none":"no controllable entity","marker.light_entity_missing":"The saved entity {entity} is unavailable. House Plan temporarily uses {fallback}; the saved choice will be restored if it returns.","marker.toggle_entity_label":"Entity to toggle","marker.toggle_entity.help":"For a composite device, choose the exact own light or switch operated by a tap. Automatic keeps the previous target rules and is independent from the leading light entity.","marker.toggle_entity.help.aria":"Help: entity to toggle","marker.toggle_entity_auto":"Automatic ({entity})","marker.toggle_entity_none":"no own controllable entity","marker.toggle_entity_missing":"The saved entity {entity} is no longer among this marker’s selectable channels. House Plan temporarily uses {fallback}; the saved choice will be restored if it returns.","marker.glow_color_label":"Glow colour and brightness","marker.glow_mode.help":"Use live source values, override only its colour, or fix both colour and brightness. The minimum is 1%; to disable the source, choose “Never”.","marker.glow_mode.help.aria":"Help: glow colour and brightness","marker.glow_mode_auto":"From source","marker.glow_mode_color":"Set colour","marker.glow_mode_fixed":"Set colour and brightness","marker.glow_color":"Glow colour","marker.glow_brightness":"Brightness","marker.glow_disabled_never":"Glow settings are unavailable because this marker is explicitly not a light source.","marker.glow_disabled_auto":"Auto mode found no spatial light source for this marker.","marker.glow_disabled_no_entity":"No active controllable Home Assistant entity is available for this spatial source.","marker.glow_passive_hint":"This source has no own Home Assistant data. Set its colour and brightness manually; its radius remains available.","marker.control_broken":"Saved source is missing or no longer marked as a light","marker.control_missing_label":"Missing plan light","marker.control_passive":"passive source","toast.marker_control_cycle":"This link would create a circular chain of light controls.","toast.marker_binding_required":"Choose a Home Assistant device before linking another light source.","confirm.unlock":"Unlock “{name}”?","toast.files_migrate_failed":"Attachments could not be moved to the new binding, links keep pointing at the old files: {err}","space.pick_saved":"Already uploaded","space.pick_saved_hint":"Plans stored on the server, including ones you detached earlier","space.no_saved":"No plans stored on the server yet.","space.loading":"Loading…","space.used_by":"in use: {list}","space.in_use":"A space still uses this plan — detach it first","btn.use":"Use","confirm.delete_plan":'Delete the plan file "{name}" from the server? This cannot be undone.',"toast.plans_list_failed":"Could not list the stored plans: {err}","toast.plan_delete_failed":"Could not delete the plan: {err}","marker.hide":"Hide","marker.hide_tip":'The device will disappear from the plan after saving but will still count toward the room signal. Restore it through the "Devices" catalog in the device editor.',"marker.show":"Show","marker.show_tip":"The device will appear on the plan again after saving.","marker.hidden_ghost":"Device hidden by the user","marker.ha_disabled_device":"The device is disabled in Home Assistant and hidden from the plan.","marker.ha_disabled_entity":"The entity is disabled in Home Assistant and hidden from the plan.","marker.ha_disabled_all_entities":"The device has no active Home Assistant entities, so it is hidden from the plan.","marker.ha_registry_limited":"The full Home Assistant registry is unavailable to this user. The unverified object cannot be shown or used for now.","marker.delete_tip":"Completely delete the device from the plan and every aggregate. You can add it again later.","tap.run":"Run automation/script/scene","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.cal_maps":"Calibrated maps: {maps}","vac.autocal_no_rooms":"The integration reports no room list — open “Fit manually”","vac.autocal_no_match":"Room names did not match (need ≥3 in common) — open “Fit manually”","vac.autocal_done":"Done: bound via {rooms} rooms. Start a cleanup and check","vac.cal_need_pos":"The robot is not reporting coordinates — start a cleanup and pause it","vac.cal_done":"Calibration saved. Start a cleanup and check","vac.cal_cancelled":"Calibration cancelled","vac.fit":"Fit manually","vac.fit_hint":"Drag the robot map into place, stretch by the corners","vac.fit_rotate":"Rotate 90°","vac.fit_mirror":"Mirror","vac.trail_never":"Never","vac.trail_cleaning":"While cleaning","vac.trail_always":"Always","gs.bg_group":"Stage background","gs.bg_color":"Background around the plan","gs.bg_default":"Theme default","gs.bg_theme":"theme default","gs.bg_mode":"Plan background","gs.bg_static":"Static color","gs.bg_daynight":"Follows the Sun","gs.bg_daynight_hint":"The background moves through dawn, day, dusk and night using sun.sun, or your local clock when sun data is unavailable. No compass is needed for the background.","gs.sun_group":"Sun","gs.sun_missing":"The sun.sun entity was not found — the background follows your local clock; window rays are unavailable.","gs.north":"North on the plan","gs.north_ph":"not set","gs.north_hint":"Set north only for window rays (1° steps, 15° with Shift); the Sun background works without it.","gs.north_clear":"Clear","gs.north_letter":"N","gs.sun_rays":"Sunlight through windows","gs.about_group":"About","gs.about_version":"Houseplan Card v{v}","gs.about_github":"GitHub · docs & issues","gs.about_telegram":"Telegram chat","space.bg_color":"Background around the plan","space.bg_inherit":"Inherit general","space.bg_inherited":"inherits general settings","space.bg_mode":"Plan background","space.north":"North on the plan (override)","space.north_inherited":"inherited: {v}","space.sun_rays":"Sunlight through windows","space.sun_inherit":"Inherit general","space.sun_on":"On","space.sun_off":"Off","canvas.far_objects":"{n} object(s) far from the plan","canvas.show_far":"Show","canvas.home_tip":"The plan is over there — click to fit it","gs.grid_group":"Plan maintenance","gs.grid_hint":"Updates data models, aligns plan elements to the grid and merges redundant wall fragments. An exact report is shown before anything is stored.","gs.align_all":"Optimize plans","gs.align_title":"Optimize plans","gs.align_none":"All plans already use the current optimized data model.","gs.optimize_no_automatic_changes":"There are no automatic changes to apply. Review the items below.","gs.align_count":"{n} of {total} elements will move, by at most {cm} cm.","gs.align_where":"The largest shift is in “{s}”.","gs.align_turned":"Openings whose angle is corrected: {n}.","gs.align_removed_drafts":"Invalid outlines collapsed by the grid and removed: {n}.","gs.optimize_redundant_drafts":"Saved wall chains hidden by solid room walls and removed: {n}.","gs.align_preflight_failed":"Could not safely verify the geometry of the following spaces: {spaces}{more}.","gs.align_preflight_hint":"Plans were not changed. Copy the diagnostics with the button below and attach them to the bug report together with a space export.","gs.preflight_reason_prepare-exception":"Could not prepare the space geometry (exception while building the model)","gs.preflight_reason_wall-null":"The wall body did not build (the union came back empty)","gs.preflight_reason_wall-degraded-extra":"The wall body degraded with extra geometry","gs.preflight_reason_wall-failed-core":"The wall body core failed to assemble","gs.preflight_reason_wall-exception":"Wall construction threw an exception","gs.preflight_reason_floor-null":"The floor outline did not build","gs.preflight_reason_floor-exception":"Floor construction threw an exception","gs.preflight_copy":"Copy diagnostics","gs.preflight_copied":"Diagnostics copied","gs.preflight_update_hint":"The card and integration versions differ — update House Plan and retry.","gs.align_preflight_space":"Space {n}","gs.align_preflight_more":", and {n} more","gs.optimize_changes":"Model migrations: {m}; spaces updated: {c}; noisy coordinate values removed: {p}; merged real-wall fragments: {w}; merged zero-thickness wall fragments: {s}; independent walls: {i}.","gs.zero_walls_migrated":"Virtual wall spans converted: {n}.","gs.wall_segments_migrated":"Wall segments stabilised: {n}.","gs.optimize_lattice_summary":"Noisy coordinate values canonicalized: {n}; maximum movement: {cm} cm.","gs.optimize_lattice_space":"{space}: coordinate values canonicalized: {n}; off-grid values left unchanged: {far}.","gs.optimize_coincident_partitions":"Hidden independent wall sections absorbed into room walls: {n}.","gs.optimize_openings_rehosted":"Openings reattached to room walls: {n}.","gs.optimize_walls_straightened":"Walls straightened: {n}; maximum movement: {cm} cm.","gs.optimize_walls_straightened_where":"Largest wall correction: {s}.","gs.optimize_walls_straighten_skipped":"Near-axis walls left unchanged because they could not be repaired safely: {n}.","gs.optimize_glow_migration":"Legacy Glow: {spaces} spaces → no data fill + independent Glow; {rooms} rooms → inherited data fill + independent Glow.","gs.optimize_references":"References repaired: spaces — {spaces}; rooms — {rooms}; positions — {positions}; devices detached from missing spaces — {detached}.","gs.optimize_reference_more":", and {n} more","gs.optimize_orphans_removed":"Forgotten records removed: {total} — room labels: {rooms}; devices: {devices}; group markers: {groups}. They belonged to spaces deleted earlier.","gs.optimize_live_positions":"Old positions in deleted spaces belong to existing objects: {n}{names}. They will be kept.","gs.optimize_live_positions_remove":"Old positions in deleted spaces belong to existing objects: {n}{names}. They are selected for removal.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Remove old positions","gs.optimize_live_keep":"Keep old positions","gs.optimize_live_selected":"Old positions will be removed after Optimize is applied.","gs.optimize_unverified":"Could not safely verify positions: {n}. They were left unchanged.","gs.optimize_registry_limited":"Full administrator access to the Home Assistant registries is required for a safe check.","gs.optimize_vacuum_warning":"Vacuum room mappings that still need review: {n}.","gs.optimize_details":"Details","gs.optimize_details_more":"And {n} more records.","gs.optimize_detail_removed":"will be removed","gs.optimize_detail_live":"will be kept","gs.optimize_detail_unverified":"not verified","gs.optimize_detail_room_label":"room label","gs.optimize_detail_device":"device","gs.optimize_detail_group":"group marker","gs.optimize_detail_unknown":"unknown owner","gs.optimize_detail_item":"{status}: {kind} {id}; old space {space}","gs.align_warn":"Elements deliberately placed between grid nodes will move. One undo is available after the operation, only until the next plan edit.","gs.align_run":"Optimize","gs.align_done":"Plans optimized: {n} elements moved, {m} records maintained, {r} references repaired","gs.optimize_undo":"Undo last optimization","gs.optimize_undone":"The last optimization was undone","decor.furniture":"Furniture","furn.title":"Furniture library","furn.symbol":"Symbol","furn.group_furniture":"Furniture","furn.group_appliance":"Appliances","furn.group_sanitary":"Plumbing","furn.group_other":"Other","furn.width":"Width","furn.depth":"Depth","furn.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_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_kitchen_cabinet":"Kitchen cabinets","furn.cat_kitchen_sink":"Kitchen sinks","furn.cat_nightstand":"Cabinets","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_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","gs.backup_hint":"Download a portable JSON backup or preview and import a backup made by House Plan.","backup.export_open":"Export","backup.import_open":"Import","backup.export_title":"Export House Plan","backup.import_title":"Import House Plan","backup.export_hint":"Choose whether the backup should contain the whole House Plan configuration or only the current space.","backup.full":"Full backup","backup.current_space":"Current space","backup.current_space_title":"Current space: {title}","backup.no_current_space":"No current space","backup.plan_only":"Plan only","backup.plan_only_hint":"Keep rooms, walls, openings, decor and room-label positions without devices or Home Assistant bindings.","backup.plan_only_preview":"This file contains the plan only","backup.privacy_warning":"The archive keeps names, Home Assistant identifiers and exact coordinates. Internal plans and attachments are referenced, not embedded; runtime states and vacuum trails are not included.","backup.download":"Download JSON","backup.export_done":"Backup downloaded","backup.reading":"Checking the backup…","backup.revalidated":"The plan changed after this preview. The summary was refreshed; review it and confirm again.","backup.error.unauthorized":"You do not have permission to export or import this plan.","backup.error.not_ready":"House Plan is not ready yet. Try again in a moment.","backup.error.too_large":"The backup exceeds the 8 MiB limit.","backup.error.invalid_json":"The selected file is not valid JSON.","backup.error.invalid_format":"The selected file is not a House Plan backup.","backup.error.unsupported_export_version":"This backup format is not supported by the installed version.","backup.error.future_model":"The backup was created by a newer House Plan data model.","backup.error.invalid_config":"The backup contains an invalid House Plan configuration.","backup.error.wall_model_migration_blocked":"The backup wall model could not be upgraded safely. Optimize the source plan first, then export it again.","backup.error.invalid_layout":"The backup contains invalid object positions.","backup.error.invalid_content":"The backup contains invalid or inconsistent content references.","backup.error.space_not_found":"The selected space no longer exists.","backup.error.capacity_exceeded":"Adding this backup would exceed the plan limits.","backup.error.preview_expired":"The preview expired. Select the backup file again.","backup.error.preview_owner_mismatch":"This preview belongs to another Home Assistant user.","backup.error.conflict":"The plan changed after the preview. Review the refreshed summary.","backup.error.content_confirmation_required":"Confirm that unavailable local content may be detached.","backup.error.commit_failed":"The backup could not be applied safely. The previous plan was restored or is pending recovery.","backup.error.missing_plan":"A referenced plan file disappeared after the preview. Review the backup again.","backup.error.missing_content":"A referenced local attachment disappeared after the preview. Review the backup again.","backup.error.marker_control_missing":"A linked plan light is missing from the backup.","backup.error.marker_control_not_light":"A linked plan target is no longer marked as a light source.","backup.error.marker_control_self":"A light source cannot control itself.","backup.error.marker_control_cycle":"The backup contains a circular chain of light controls.","backup.error.duplicate_marker_control":"The backup contains a duplicate plan-light link.","backup.error.no_backup":"There is no import or optimization snapshot to restore.","backup.same_source":"Created on this Home Assistant instance","backup.foreign_source":"Created on another Home Assistant instance","backup.created":"Created: {value}","backup.versions":"Card {card}; integration {integration}; data model {model}","backup.count_spaces":"Spaces: {n}","backup.count_rooms":"Rooms: {n}","backup.count_walls":"Walls: {n}","backup.count_openings":"Openings: {n}","backup.count_decor":"Decor objects: {n}","backup.count_markers":"Devices: {n}","backup.count_layout":"Positions: {n}","backup.bindings":"Bindings — devices: {device}, entities: {entity}, virtual: {virtual}; positions without a space: {legacy}","backup.binding_status":"Target status — active: {active}, disabled: {disabled}, missing: {missing}","backup.missing_areas":"Areas missing on the target: {areas}","backup.dropped_marker_links":"Plan-light links outside this transferred space were omitted: {n}.","backup.repaired_target_refs":"Existing references restored by this space import: {n}.","backup.preserved_unresolved_refs":"References that could not be restored unambiguously were preserved: {n}.","backup.preserved_unresolved_hint":"No data was guessed or deleted. After the import, run Optimize plans to inspect the remaining references.","backup.import_details":"Import reference details","backup.import_detail.incoming_remapped":"References updated inside the imported copy: {n}","backup.import_detail.target_repaired":"Existing references restored: {n}","backup.import_detail.preserved_unresolved":"Unresolved references preserved: {n}","backup.import_detail.collisions":"Destination conflicts preserved safely: {n}","backup.import_detail.dropped_links":"Incoming links omitted by transfer rules: {n}","backup.import_detail.bounded_lineages":"Overly nested identifiers left bounded: {n}","backup.replace_warning":"This replaces the current configuration and layout. Uploaded files are never deleted. One undo remains available until the next plan edit.","backup.foreign_bookkeeping":"Instance-specific known/new-device bookkeeping will not be imported.","backup.final_name":"New space name","backup.target_settings":"The target instance's global settings remain unchanged.","backup.duplicates":"Bindings already present: {n}","backup.skip":"Skip duplicate devices","backup.virtual_copy":"Add safe static virtual copies","backup.content":"Referenced content","backup.content_available":"available locally","backup.content_external":"external link","backup.content_detach_required":"will be detached","backup.confirm_detach":"I understand that unavailable internal plans and attachments will be detached from the imported configuration.","backup.replace":"Replace","backup.add":"Add space","backup.space_done":"Space imported: {rooms} rooms, {markers} devices, {refs} existing references restored","backup.full_done":"Backup restored: {spaces} spaces, {rooms} rooms, {markers} devices","backup.undo_import":"Undo last full import","backup.import_undone":"Full import undone"};const Xd=new WeakSet,Jd=new WeakSet;function Qd(e,t,i){const n=i?t.state(i):"ready";return i&&"pending"===n?(Jd.has(e)||(e.inert=!0,e.setAttribute("aria-busy","true"),Jd.add(e)),t.ensure(i).then(()=>{e.isConnected&&e.requestUpdate()}),Xd.has(e)?"warm":"cold"):(Jd.delete(e)&&(e.inert=!1,e.removeAttribute("aria-busy")),i&&(e.setAttribute("lang","fallback"===n?"en":i),Xd.add(e)),"ready")}function eu(){return j``}const tu=[{code:"en",nativeLabel:"English",dictionary:Zd},{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":"Проверьте сеть и нажмите ещё раз.","color_picker.title":"Выбор цвета","color_picker.hue":"Оттенок","color_picker.saturation":"Насыщенность","color_picker.value":"Яркость","color_picker.hex":"Цвет HEX","color_picker.invalid_hex":"Введите цвет HEX из 3 или 6 цифр","btn.properties":"Свойства","btn.keep_as_walls":"Оставить стенами","btn.delete_room_keep_walls":"Удалить комнату, оставить стены","btn.delete_room_with_walls":"Удалить комнату и стены","title.markup_select":"Выбор и редактирование стен, колонн и сохранённых контуров","title.markup_column":"Колонна: кликните точку сетки для квадратной колонны","markup.partition":"Перегородка","markup.column":"Колонна","markup.hint_column":"кликните точку сетки, чтобы поставить квадратную колонну","history.draft_segment":"Добавление сегмента черновика комнаты","history.draft_merge":"Соединение незавершённых контуров комнаты","history.draft_segment_delete":"Удаление сегмента черновика комнаты","history.partition_add":"Добавление перегородки","history.column_add":"Добавление колонны","history.physical_edit":"Изменение физического объекта","history.physical_delete":"Удаление физического объекта","history.physical_move":"Перемещение физического объекта","history.contour_to_partitions":"Преобразование контура в замкнутые стены","history.wall_chain_finish":"Завершение цепочки стен","history.wall_face_batch":"Создание комнат из стен","toast.column_duplicate":"Колонна с тем же центром и внешним размером уже существует","confirm.delete_draft":"Удалить весь незавершённый контур комнаты?","confirm.delete_draft_segment":"Удалить этот сегмент черновика? Оставшийся контур может разделиться на два.","physical.partition_properties":"Свойства перегородки","physical.column_properties":"Свойства колонны","physical.draft_properties":"Свойства сегмента черновика","physical.shape":"Форма","physical.square":"Квадрат","physical.circle":"Круг","physical.diameter":"Диаметр","physical.side":"Сторона","physical.rotation":"Угол поворота","physical.length":"Длина","physical.allowed_range":"Допустимо: {min}–{max} {unit}","physical.delete_segment":"Удалить сегмент","physical.delete_draft":"Удалить весь контур","physical.column_size_title":"Внешняя сторона квадратной колонны, создаваемой кликом (1–150 см).","card.title":"План дома","count.devices":"{n} устр.","empty.no_spaces":"Пространств пока нет.","empty.add_first":"Добавьте первое пространство и загрузите план этажа.","empty.install":"Установите интеграцию House Plan и добавьте запись в «Устройства и службы».","btn.add_space":"Добавить пространство","btn.cancel":"Отмена","btn.save":"Сохранить","btn.close":"Закрыть","btn.delete":"Удалить","btn.edit":"Редактировать","btn.open_in_ha":"Открыть в HA","btn.reset":"Сброс","btn.attach":"Прикрепить…","btn.upload":"Загрузить…","btn.replace":"Заменить…","title.zoom_in":"Приблизить","title.zoom_out":"Отдалить","title.zoom_fit":"Вписать всё","title.markup":"Разметка комнат: сетка, линии, контуры","title.configure_space":"Настроить пространство","title.add_space":"Добавить пространство","title.markup_add":"Стены: рисуйте непрерывную цепочку; Shift фиксирует 45°. Смена инструмента или выход завершает её как независимые стены","title.markup_merge":"Объединить: клик по одной комнате, затем по соседней с общей стеной","title.markup_split":"Разделить комнату: клик по комнате, затем две точки на её стенах","title.markup_delroom":"Удалить комнату: кликните внутри комнаты и подтвердите удаление","title.need_plan":"Загрузите подложку (план этажа)","markup.add":"Стены","markup.merge":"Объединить","markup.split":"Разделить","markup.resize":"Размер","title.markup_resize":"Изменение размера комнат: тяните доступную ручку горизонтальной или вертикальной стены","markup.hint_resize":"тяните доступную ручку стены · стена упирается в первую небезопасную позицию · Esc — отмена · Ctrl+Z — отмена шага","resize.disabled.diagonal":"Стена расположена под углом: Resize поддерживает только горизонтальные и вертикальные стены","resize.disabled.side-angle":"Примыкающая стена расположена под углом: для Resize обе примыкающие стены должны образовывать прямой угол","resize.disabled.duplicate-physical-wall":"Стену перекрывает отдельная перегородка, незавершённый контур или колонна; удалите или переместите её перед изменением размера","resize.disabled.partial-shared":"Соседняя комната использует только часть этой стены, поэтому её нельзя безопасно двигать как одну общую стену","resize.disabled.unequal-shared":"У соседней комнаты другие конечные точки или длина стены, поэтому стены нельзя безопасно двигать вместе","resize.disabled.multiple-rooms":"Перемещение затронуло бы больше двух комнат","resize.disabled.thickness-conflict":"Толщину стены нельзя безопасно сохранить","resize.disabled.opening-conflict":"Проём на этой стене нельзя безопасно переместить","resize.disabled.invalid-geometry":"Эту стену нельзя переместить без изменения структуры плана","resize.limit_stopped":"Стена остановлена: дальше нарушается ограничение стыков","resize.commit_failed":"Изменение размера отменено: итоговый план не прошёл проверку геометрии","resize.preview_failed":"Стена остановлена в последней безопасной позиции: геометрию плана нельзя сохранить без потерь","markup.opening":"Проём","markup.delete_room":"Удалить комнату","history.undo":"Отменить","history.redo":"Повторить","history.undo_named":"Отменить: {name} (Ctrl+Z)","history.redo_named":"Повторить: {name} (Ctrl+Shift+Z / Ctrl+Y)","history.undo_empty":"Нет операций для отмены","history.redo_empty":"Нет операций для повтора","history.undone":"Отменено: {name}","history.redone":"Повторено: {name}","history.add_room":"Создание комнаты","history.split_room":"Разделение комнаты","history.merge_rooms":"Объединение комнат","history.resize_room":"Изменение размера комнаты","history.wall_thickness":"Изменение толщины стены","history.add_opening":"Добавление дверного или оконного проёма","history.edit_opening":"Изменение проёма","history.move_opening":"Перемещение проёма","history.delete_opening":"Удаление проёма","history.delete_room":"Удаление комнаты","history.delete_room_keep_walls":"Удаление комнаты с сохранением стен","history.delete_room_with_walls":"Удаление комнаты и её стен","history.decor_add":"Добавление объекта декора","history.decor_edit":"Изменение объекта декора","history.decor_move":"Перемещение объекта декора","history.decor_transform":"Трансформация объекта декора","history.decor_delete":"Удаление объекта декора","history.backdrop_transform":"Трансформация подложки плана","opening.new":"Новый проём","opening.edit":"Проём","opening.door":"Дверь","opening.window":"Окно","opening.gate":"Ворота","opening.passage":"Открытый проём","opening.passage_binding_warning":"При сохранении датчик открытия и замок будут удалены.","opening.invalid_passage_fields":"У открытого проёма на плане «{room}» есть недопустимые параметры: {fields}.","opening.type_label":"Тип","opening.length_label":"Длина, см","opening.contact_label":"Датчик открытия","opening.lock_label":"Замок","opening.none":"— нет —","opening.search_ph":"Поиск: имя или entity_id…","opening.invert":"Инвертировать открыто/закрыто","opening.flip_h":"Петли с другой стороны","opening.flip_v":"Открывается в другую сторону","opening.open":"Открыто","opening.closed":"Закрыто","opening.locked":"Заперто","opening.unlocked":"Не заперто","opening.state_unknown":"недоступно","opening.no_entities":"Датчики не привязаны — статичный символ на плане.","toast.opening_no_wall":"Кликните рядом со стеной комнаты или независимой стеной","opening.host_partition":"Независимая стена","opening.partition_orphan":"Независимая стена этого проёма больше не существует","opening.partition_jamb_margin":"Оставьте от края проёма до торца стены минимум {distance}","opening.rebind_partition":"Привязать к другой независимой стене","confirm.delete_partition_openings_title":"Удалить стену и проёмы?","confirm.delete_partition_openings_body":"В стене есть проёмы: {count}. Они будут удалены вместе со стеной.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.delete":"Удалить","markup.hint_points":"точек: {n} · Shift — шаг 45° · Esc — завершить цепочку · Ctrl+Z — убрать точку · при замыкании будет предложена комната","markup.hint_start":"кликните точку сетки, чтобы начать цепочку стен","tip.lqi":"средний сигнал zigbee:","tip.area":"площадь: {value}","info.device_header":"Устройство на плане","info.model":"Модель","info.state":"Состояние","info.link":"Ссылка","info.manuals":"Инструкции","info.none":"Нет дополнительной информации","marker.new_device":"Новое устройство","marker.name_label":"Имя (отображается на плане)","marker.name_ph":"Название","marker.binding_label":"Привязка к устройству HA","marker.binding_disabled":"деактивировано в Home Assistant","marker.virtual_option":"Виртуальное устройство (без привязки)","marker.search_ph":"Поиск устройства / группы…","marker.nothing_found":"ничего не найдено","marker.room_label":"Комната","marker.room_override":" (переопределить размещение)","marker.room_choose":"— выберите комнату —","marker.room_auto":"— по зоне устройства (авто) —","marker.icon_label":"Иконка","marker.icon_ph":"mdi:… (пусто = авто)","marker.display_label":"Отображение","display.badge":"Значок + состояние","display.icon_ripple":"Значок + состояние и активность","display.static_icon":"Всегда статичный значок","marker.display_hint":"Значок + состояние меняет подложку при работе, открытии, тревоге и недоступности. Значок + состояние и активность дополнительно показывает короткую пульсацию для событий и постоянную — для работы, движения или присутствия. Значение + состояние заменяет значок одним однозначным значением HA. Статичный значок не реагирует на состояния устройства.","marker.display_hint_badge":"Значок и динамическая подложка показывают состояние устройства без обычной пульсации активности. Красная тревога сохраняется.","marker.display_hint_icon":"Значок и динамическая подложка показывают состояние устройства без обычной пульсации активности. Красная тревога сохраняется.","marker.display_hint_icon_ripple":"Значок, динамическая подложка и пульсация: короткая — для событий, постоянная — для работы, движения или присутствия. Красная тревога имеет отдельный приоритет.","marker.display_hint_value":"Значок заменяется одним однозначным значением Home Assistant; подложка продолжает показывать состояние. Красная тревога сохраняется.","marker.display_hint_static_icon":"Подложка в цветах темы и значок всегда остаются одинаковыми. Состояния, активность, недоступность и тревоги не меняют отображение.","marker.static_alarm_warning":"Это устройство может сообщать о тревогах. Статичный режим скрывает визуальную тревогу маркера.","marker.preview.title":"Предпросмотр отображения","marker.preview.actual":"Сейчас","marker.preview.example":"Пример","marker.preview.integration":"Интеграция","marker.preview.source":"Источник отображения","marker.preview.current_state":"Текущее состояние","marker.preview.result":"На плане","marker.preview.details":"Подробнее об источниках","marker.preview.select_source":"Выберите устройство или сущность Home Assistant, чтобы увидеть фактическое отображение.","marker.preview.unknown_provider":"Интеграция неизвестна","marker.preview.virtual_provider":"House Plan · виртуальное устройство","marker.preview.no_source":"Нет активного источника","marker.preview.no_state":"Нет текущего состояния","marker.preview.mixed_states":"Несколько разных состояний","marker.preview.multiple_sources":"Источников: {n}","marker.preview.more_sources":"ещё {n}","marker.preview.scaled":"Предпросмотр уменьшен до {n}%, чтобы поместиться. Сохранённый размер не изменится.","marker.preview.demo_short":"Показать краткую активность","marker.preview.demo_continuous":"Показать постоянную активность","marker.preview.stop_continuous":"Остановить постоянную активность","marker.preview.demo_short_notice":"Пример краткой активности; фактическое состояние устройства не меняется.","marker.preview.demo_continuous_notice":"Пример постоянной активности; фактическое состояние устройства не меняется.","marker.preview.demo_already_visible":"Текущее состояние уже показывает реальную активность или тревогу.","marker.preview.reduced_motion":"В системе включено уменьшение движения, поэтому обычная активность показана точкой.","marker.preview.reason.neutral":"Нейтральная тёмная подложка","marker.preview.reason.working":"Жёлтая подложка: устройство сейчас работает","marker.preview.reason.working_activity":"Жёлтая подложка и эффект активности: устройство сейчас работает","marker.preview.reason.open":"Оранжевая подложка: физически открыто или разблокировано","marker.preview.reason.cover_icon_state":"Нейтральная подложка; состояние и значок определяет сущность шторы или заслонки","marker.preview.reason.presence":"Эффект активности, пока обнаружено присутствие","marker.preview.reason.event":"Короткий эффект активности после события","marker.preview.reason.transition":"Эффект активности во время движения или смены состояния","marker.preview.reason.media_neutral":"Медиаустройство остаётся на нейтральной тёмной подложке, пока доступно","marker.preview.reason.unavailable":"Приглушённая нейтральная подложка: отключено или недоступно","marker.preview.reason.alarm":"Красная тревожная подложка; тревога отображается всегда","marker.preview.reason.live_states_disabled":"Оформление по живым состояниям отключено в настройках карточки","marker.preview.reason.value_no_state":"Нет подходящего значения состояния — вместо него показан значок","marker.preview.reason.value_ambiguous_sources":"Подходит несколько источников значения — вместо него показан значок","marker.preview.reason.value_non_scalar":"Источник вернул не простое значение — вместо него показан значок","marker.preview.reason.value_virtual":"У виртуального устройства нет значения HA — вместо него показан значок","marker.preview.reason.vacuum_live_plan_only":"Живая позиция и след пылесоса доступны только на полном плане","marker.preview.reason.hidden_design_preview":"Устройство скрыто на плане, но его оформление видно в предпросмотре","marker.preview.reason.composite_power_source":"Состояние берётся из сущности питания устройства; вспомогательные переключатели не учитываются","marker.preview.reason.activity_display_disabled":"Выбранный режим отображения не показывает обычные эффекты активности","marker.preview.reason.ha_disabled":"Привязка отключена в Home Assistant, поэтому устройство будет скрыто на плане","marker.preview.reason.orphaned":"Сохранённая привязка Home Assistant больше не найдена","marker.preview.reason.static_icon":"Статичный режим: состояние устройства не меняет значок","marker.activity_color":"Цвет пульсации активности","marker.ripple_size":"Размер пульсации активности","marker.activity_alarm_note":"Цвет и размер относятся только к обычной активности и не влияют на красную тревогу.","marker.pulse_a11y_alarm":"Тревога","marker.pulse_a11y_event":"Недавнее событие","marker.pulse_a11y_presence":"Обнаружено присутствие","marker.pulse_a11y_transition":"Изменение состояния","marker.pulse_a11y_running":"Работает","marker.state_a11y_neutral":"Обычное состояние","marker.state_a11y_working":"Работает","marker.state_a11y_open":"Открыто","marker.state_a11y_locked":"Заблокировано","marker.state_a11y_unlocked":"Разблокировано","marker.state_a11y_alarm":"Тревога","marker.state_a11y_unavailable":"Недоступно","marker.lqi_a11y_low":"LQI {value}, слабый сигнал","marker.lqi_a11y_mid":"LQI {value}, средний сигнал","marker.lqi_a11y_high":"LQI {value}, сильный сигнал","marker.size_label":"Размер / поворот значка","marker.angle_label":"Поворот","marker.model_label":"Модель","marker.model_ph":"напр. Aqara T&H","marker.link_label":"Ссылка","marker.desc_label":"Описание","marker.desc_ph":"Заметки, характеристики…","marker.manuals_label":"Инструкции (PDF и т.п.)","marker.sub_device":"устройство","marker.sub_z2m_group":" · Z2M-группа","marker.sub_group":"группа","marker.sub_helper":"хелпер","space.new":"Новое пространство","space.header":"Пространство","space.title_label":"Название","space.title_ph":"Например: Гараж","space.plan_label":"Подложка (план)","space.no_plan":"нет подложки","space.plan_alt":"план","room.new":"Новая комната","room.name_label":"Отображаемое имя","room.name_ph":"Например: Терраса","room.area_label":"Зона Home Assistant (свободные)","room.no_area_option":"— без зоны —","room.default_name":"Комната","device.unnamed":"без имени","device.light_group":"группа света","device.fallback":"устройство","device.virtual":"виртуальное устройство","confirm.delete_room":"Удалить комнату «{name}»?","confirm.delete_room_title":"Удалить комнату «{name}»?","confirm.delete_room_body":"Выберите, нужно ли оставить физические стены, принадлежащие только этой комнате. Общие с другой комнатой стены сохраняются всегда.","confirm.remove_marker":"Удалить «{name}» с плана? Устройство исчезнет полностью и перестанет участвовать в данных плана. Позже его можно будет добавить заново.","confirm.erase_decor":"Стереть объект «{kind}»? Действие можно отменить из истории редактора.","confirm.delete_space":"Удалить пространство «{title}» со всеми комнатами и разметкой?","space.delete_blocked":"Это пространство всё ещё используется устройствами: {n}. Сначала перенесите их в другое пространство или удалите.","toast.pos_save_failed":"Не удалось сохранить позицию: {err}","toast.no_entity":"У устройства нет подходящей сущности","toast.ha_disabled_action":"Деактивированный объект Home Assistant нельзя использовать на плане.","toast.ha_disabled_show_device":"Деактивированное в Home Assistant устройство нельзя показать на плане. Сначала активируйте его в Home Assistant.","toast.ha_disabled_show_entity":"Деактивированную в Home Assistant сущность нельзя показать на плане. Сначала активируйте её в Home Assistant.","toast.ha_disabled_add":"Деактивированный объект Home Assistant нельзя добавить на план. Сначала активируйте его в Home Assistant.","toast.ha_binding_unverified":"Статус объекта не удалось подтвердить по реестру Home Assistant. Отображение и действия временно недоступны.","toast.markup_needs_server":"Разметка доступна после переноса конфига на сервер","toast.space_order_changed":"Порядок изменён. Если где-то этаж карточки задан номером, проверьте такие панели.","toast.conflict":"Конфиг изменён в другом окне — данные обновлены, повторите последнее действие","toast.cfg_save_failed":"Не удалось сохранить конфиг: {err}","toast.room_overlap":"Контур накладывается на комнату «{name}» — комнаты не должны накладываться","toast.contour_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_saved":"Пространство сохранено","toast.space_deleted":"Пространство удалено","toast.delete_failed":"Ошибка удаления: {err}","toast.error":"Ошибка: {err}","toast.toggle_target_unavailable":"Цель «{name}» недоступна — действие не выполнено","toast.toggle_targets_unavailable":"Цели недоступны: {names}. Действие не выполнено","toast.file_failed":"Файл «{name}» не загружен: {err}","toast.files_attached":"Прикреплено файлов: {n}","err.unknown":"неизвестная ошибка","err.code":"код {code}","err.too_large":"файл больше {mb} МБ","err.bad_ext":"недопустимый тип (нужен PDF/изображение)","err.unauthorized":"нужны права администратора","editor.title":"Заголовок","editor.default_floor":"Стартовое пространство","editor.default_floor_missing":"Стартовое пространство «{id}» больше не существует. Выберите другое.","editor.floor":"Закреплённое пространство","editor.floor_none":"— не закреплять —","editor.floor_index":"YAML-индекс {index} (сохранён)","fixed_floor.loading":"Загружаем закреплённое пространство…","fixed_floor.invalid_title":"Закреплённое пространство недоступно","fixed_floor.invalid_body":"Проверьте floor в конфигурации карточки. Настроенное значение: {value}","editor.icon_size":"Размер иконок, % ширины плана","editor.show_temperature":"Показывать температуру","editor.live_states":"Живые состояния (вкл/выкл, открыто…)","editor.show_signal":"Показывать сигнал zigbee (LQI)","editor.language":"Язык интерфейса","editor.lang_auto":"Авто (профиль HA)","title.icon_rules":"Правила иконок: какая MDI-иконка достаётся устройству по имени","rules.title":"Правила иконок","rules.hint":"Правила проверяются сверху вниз по строке «имя устройства + модель» (regex без учёта регистра); срабатывает первое совпадение. Если ничего не подошло — решает device class сущности, затем — иконка-заглушка.","rules.pattern_ph":"regex, напр. розетк|plug","rules.icon_ph":"mdi:power-socket-de","rules.add":"Добавить правило","rules.reset":"Сбросить к умолчаниям","rules.test_ph":"Проверьте имя устройства…","rules.invalid":"некорректный regex","rules.saved":"Правила иконок сохранены","btn.up":"Вверх","btn.down":"Вниз","tap.info":"Карточка устройства","tap.more_info":"Диалог HA (more-info)","tap.toggle":"Переключить состояние","marker.tap_label":"Действие по нажатию для этого устройства","tap.toggle_note":"Под селектором показано, какое состояние изменится. Защищённые устройства не переключаются с плана.","import.title":"Создать пространства из этажей HA","import.hint":"Home Assistant уже знает эти этажи. Отметьте, какие превратить в пространства плана — далее для каждого попросим картинку плана. Комнаты затем обводятся вручную по плану.","import.start":"Создать: {n}","import.manual":"Начать с нуля","import.progress":"Этаж {i} из {n}","import.done":"Пространства созданы. Обведите комнаты: кликайте по точкам сетки и замкните контур.","btn.skip":"Пропустить","space.scale_label":"Масштаб (размер клетки сетки)","space.scale_unit":"см на клетку","space.scale_unit_imperial":"дюйм на клетку","space.display_section":"Отображение","space.show_borders":"Всегда отображать границы комнат","space.zero_wall_style":"Стены нулевой толщины","space.zero_wall_dashed":"Пунктирные","space.zero_wall_solid":"Сплошные","space.zero_wall_help":"Пунктирные стены пропускают свет. Сплошные стены блокируют свет, даже при нулевой толщине.","space.show_names":"Отображать названия комнат (перетаскиваются)","space.room_color":"Цвет границ и названий","space.opacity":"Прозрачность","space.fill_label":"Заливка комнат","fill.none":"Нет","fill.lqi":"По силе зигби-сигнала","fill.light":"По освещению","fill.custom":"Свой цвет","space.custom_fill":"Цвет заливки","space.source_file":"У меня есть картинка плана","space.source_draw":"Нет подложки — нарисую комнаты вручную","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.show_button":"Показывать кнопку","editor.button_label":"Текст кнопки","editor.button_target":"Путь дашборда (куда вести)","marker.sub_entity":"сущность","title.general_settings":"Общие настройки","gs.title":"Общие настройки","gs.hint":"Цвета заливок действуют на все пространства; у каждого цвета своя прозрачность. Какой режим заливки использует пространство — задаётся в его диалоге.","gs.light_group":"Заливка: освещение","gs.light_on":"Свет включён","gs.light_off":"Весь свет выключен","gs.temp_group":"Заливка: температура","gs.temp_cold":"Холодно","gs.temp_ok":"Комфорт","gs.temp_hot":"Жарко","gs.lqi_group":"Заливка: зигби-сигнал","gs.lqi_low":"Слабый сигнал","gs.lqi_high":"Сильный сигнал","gs.reset":"Сбросить к умолчаниям","gs.saved":"Общие настройки сохранены","space.show_lqi":"Показывать зигби-сигнал (LQI) у устройств","space.hide_decor":"Скрыть декоративный слой","space.hide_decor_tip":"Линии, фигуры, надписи и мебель остаются на месте — их видно в редакторе подложки, но не на плане.","space.hide_openings":"Скрыть проёмы","space.hide_openings_tip":"Двери, окна и ворота не рисуются, но продолжают работать: свет проходит, солнце светит в окна, датчики открытия срабатывают. В редакторе плана проёмы видно всегда.","gs.light_none":"Нет источников света","mode.plan":"Редактор плана","mode.devices":"Редактор устройств","display.value":"Значение + состояние","marker.subarea":"без зоны, вручную","device.new":"Новое устройство — откройте его редактор, чтобы снять отметку","opening.unlock_action":"Открыть замок","opening.lock_action":"Закрыть замок","opening.lock_pending":"Выполняется…","title.close_editor":"Закрыть редактор (вернуться к просмотру)","devbar.rules":"Правила иконок","device_inbox.button":"Устройства","device_inbox.title":"Устройства на плане","device_inbox.search":"Поиск по устройствам, сущностям и интеграциям…","device_inbox.add_virtual":"Добавить виртуальное устройство","device_inbox.tab_on_plan":"На плане","device_inbox.tab_available":"Доступны","device_inbox.tab_hidden":"Скрытые","device_inbox.tab_readd":"Доступны снова","device_inbox.only_new":"Только новые","device_inbox.show_entities":"Показывать сущности","device_inbox.show_hidden":"Показывать скрытые на плане","device_inbox.new":"Новое","device_inbox.find":"Найти на плане","device_inbox.edit":"Настроить","device_inbox.hide":"Скрыть","device_inbox.show":"Показать","device_inbox.add":"Добавить","device_inbox.readd":"Добавить заново","device_inbox.hide_available":"Скрыть из списка","device_inbox.show_more":"Показать ещё","device_inbox.more_actions":"Другие действия","device_inbox.find_hidden_hint":"Сначала включите «Показывать скрытые на плане»","device_inbox.show_disabled":"Перед показом активируйте эту привязку в Home Assistant","device_inbox.empty_on_plan":"На плане пока нет подходящих устройств.","device_inbox.empty_available":"Нет доступных устройств для добавления.","device_inbox.empty_hidden":"Скрытых устройств нет.","device_inbox.empty_readd":"Нет удалённых устройств, доступных для повторного добавления.","device_inbox.reason_visible_auto":"Найдено автоматически","device_inbox.reason_visible_explicit":"Добавлено явно","device_inbox.reason_manual_hidden":"Скрыто пользователем","device_inbox.reason_automatic_hidden":"Скрыто автоматически","device_inbox.reason_service_entry":"Служебная запись реестра","device_inbox.reason_excluded_integration":"Интеграция исключена фильтрами устройств","device_inbox.reason_excluded_domain":"Непространственный тип сущности","device_inbox.reason_grouped_light":"Представлено группой света комнаты","device_inbox.reason_represented_by_parent":"Представлено родительским устройством","device_inbox.reason_removed":"Ранее удалено с плана","device_inbox.reason_available":"Можно добавить на план","device_inbox.reason_no_bound_room":"Зона HA не связана с комнатой плана","device_inbox.status_ha_disabled":"Отключено в Home Assistant","device_inbox.status_orphaned":"Привязка больше не найдена в Home Assistant","device_inbox.status_unverified":"Реестр Home Assistant временно недоступен","device_inbox.saved":"Список устройств обновлён","space.roomcard_section":"В карточке комнаты:","space.label_temp":"Температура","space.label_hum":"Влажность","space.label_lqi":"Средний Zigbee-сигнал","space.label_light":"Свет вкл/выкл","roomcard.light_on":"Вкл","roomcard.light_off":"Выкл","roomcard.light_partial":"{on} из {total}","toast.split_pick_inside":"Промежуточные точки разреза — внутри комнаты","mode.decor":"Редактор подложки","decor.select":"Выбрать","decor.line":"Линия","decor.rect":"Прямоугольник","decor.ellipse":"Овал","decor.text":"Надпись","decor.erase":"Стереть","decor.erase_confirm_title":"Стереть объект?","decor.color":"Цвет","decor.width":"Толщина линии","decor.line_style":"Стиль линии","decor.line_style_solid":"Сплошная","decor.line_style_dashed":"Пунктирная","decor.fill":"Заливка","decor.fill_color":"Цвет заливки","decor.length":"Длина","decor.size":"Размер","decor.angle":"Угол поворота, °","decor.text_size":"Размер текста","decor.backdrop_properties":"Свойства картинки-подложки","decor.text_title":"Надпись","decor.object_title":"Редактирование: {kind}","decor.text_label":"Текст","decor.live_group":"Вставить переменную HA","decor.live_entity":"Сущность","decor.live_entity_ph":"выберите сущность","decor.live_attr":"Значение","decor.live_attr_ph":"выберите состояние или атрибут","decor.live_state":"Состояние","decor.backdrop":"Картинка-подложка","decor.backdrop_hint":"Тяните картинку — перемещение; угол — размер; верхнюю ручку — поворот. Shift меняет пропорции или снимает шаг угла.","decor.backdrop_reset":"Вернуть картинку","decor.backdrop_reset_done":"Картинка вернулась на своё место и в свой размер","marker.icon_auto":"Авто: {icon} (по правилам иконок; выберите свою, чтобы заменить)","marker.icon_pin_auto":"Закрепить","mode.plan_tip":"Редактор плана — геометрия дома: рисование и объединение/разделение комнат, привязка к зонам HA, двери, окна и ворота, карточки комнат, масштаб","mode.devices_tip":"Редактор устройств — всё про значки: перетаскивание, клик — настройка привязки/иконки/отображения, виртуальные устройства, правила иконок","mode.decor_tip":"Редактор подложки — чисто визуальный декор под планом: линии, прямоугольники, овалы и надписи, не реагирующие на клики","space.glow_enabled":"Свечение источников света","gs.glow_group":"Свечение источников света","gs.glow_base":"Темнота дома","gs.glow_light":"Цвет света по умолчанию / интенсивность","gs.wall_group":"Стены","gs.wall_fill":"Цвет заливки стен","gs.glow_radius":"Радиус свечения","gs.unit_m":"м","gs.unit_ft":"фут","marker.controls_label":"Управляет другими источниками света","marker.controls_hint":"При действии «Переключить» клик разом переключает все добавленные здесь источники. Собственная сущность маркера управляется напрямую и сюда не добавляется; чтобы считать её светом, включите флаг ниже.","marker.controls_filter":"Поиск ламп и выключателей…","info.controls":"Управляет","marker.glow_radius_label":"Радиус свечения","marker.glow_radius.help":"Задаёт радиус свечения в метрах или футах; пустое значение использует радиус из общих настроек.","marker.glow_radius.help.aria":"Подсказка: радиус свечения","markup.wallthick":"Толщина","markup.select":"Выбрать","title.markup_wallthick":"Толщина — клик по стене задаёт толщину от 0 до 100 см.","markup.hint_wallthick":"клик по стене · Esc закрывает без применения","wallthick.field":"Толщина","wallthick.unit_cm":"см","wallthick.unit_in":"дюйм","wallthick.apply_room":"Применить ко всем стенам комнаты","markup.draw_wall_title":"Толщина каждого нового сегмента стены (0–100 см). Общие стены сохраняют существующее значение.","room.queue_progress":"Комната {current} из {total}","toast.wall_rooms_saved":"Создано комнат: {n}","toast.wall_chain_saved":"Цепочка стен сохранена","toast.wallthick_pick":"Кликните по стене","toast.wallthick_set":"Толщина стены задана","toast.wallthick_cleared":"Толщина стены убрана","toast.physical_range":"Введите значение от {min} до {max} {unit}","toast.zero_wall_opening_conflict":"Сначала удалите проём на этом участке стены.","toast.zero_wall_ambiguous":"Не удалось однозначно выбрать участок стены. Уточните геометрию узла.","toast.zero_wall_migration_blocked":"Пространство не преобразовано: {reason}. Данные не изменены.","toast.physical_angle":"Введите угол поворота от 0° до 90°, не включая 90°","toast.physical_limit":"В пространстве достигнут лимит объектов этого типа","toast.geometry_unsafe":"Изменение отменено: геометрию стен нельзя безопасно построить.","junction.limit_angle":"Слишком острый угол между стенами: {actual}°, минимум {limit}°.","junction.limit_valence":"Слишком много стен в одном узле: {actual}, максимум {limit}.","junction.limit_length":"Слишком короткий участок стены: {actual} см, минимум {limit} см.","junction.limit_distance":"Стены и узлы слишком близко: {actual} см, минимум {limit} см.","junction.limit_clearance":"Внутри комнаты не остаётся места: {actual} см², минимум {limit} см².","junction.limit_check_failed":"Проверку стыков выполнить не удалось — изменение не сохранено","toast.wall_model_migration_blocked":"Не удалось обновить модель стен: {reason}. План не изменён. Запустите «Оптимизировать планы»; если ошибка повторится, исправьте конфликтующую геометрию стен.","toast.wall_model_client_outdated":"Обновите карточку и перезагрузите страницу перед редактированием плана.","wall_model.reason.invalid-room":"некорректный контур комнаты","wall_model.reason.zero-length":"отрезок стены нулевой длины","wall_model.reason.third-owner":"стена принадлежит более чем двум комнатам","wall_model.reason.duplicate-id":"конфликт идентификаторов стен","wall_model.reason.thickness-conflict":"конфликт значений толщины стены","wall_model.reason.opening-host":"проём нельзя однозначно привязать к стене","toast.delete_room_pick":"Кликните внутри комнаты, которую нужно удалить","toast.plan_snap_ambiguous":"Увеличьте масштаб, чтобы выбрать узел стены","toast.wall_repair_ambiguous":"У контура несколько возможных соединений. Увеличьте масштаб и соедините стены явно.","toast.wall_repair_too_large":"Разрыв больше 2 см. Соедините стены перед созданием комнаты.","toast.wall_repair_changed":"Геометрия стен изменилась. Попробуйте создать комнату ещё раз.","toast.opening_on_zero_wall":"Проёмы на стене нулевой толщины запрещены","marker.from_ha_option":"Выбрать из списка HA","marker.show_entities":"Показывать сущности","marker.show_entities_tip":"Добавляет в список не только устройства, но и все их сущности","marker.pick_ph":"Выберите устройство…","room.open_area":"Открыть зону в HA","view.volumetric":"Объёмный вид","view.flat":"Плоский вид","kiosk.title":"Размеры на этом экране","kiosk.hint":"Хранится только на этом устройстве — у каждого настенного планшета или ТВ свои удобные размеры.","kiosk.icon_scale":"Размер значков устройств","kiosk.font_scale":"Размер текста карточек комнат","editor.kiosk":"Режим настенного устройства (киоск)","editor.cycle":"Автосмена пространств каждые N секунд (киоск, 0 = выкл)","room.settings_title":"Настройки комнаты","room.settings_section":"Настройки комнаты (переопределяют пространство)","room.fill_label":"Заливка в ЭТОЙ комнате","fill.inherit":"Как у пространства","room.custom_fill_space":"Цвет пространства","room.custom_fill_own":"Цвет комнаты","room.temp_src_label":"Источник температуры","room.hum_src_label":"Источник влажности","room.src_average":"Средняя по датчикам комнаты (по умолчанию)","room.src_pick":"Конкретное устройство или сущность HA","room.src_ph":"Выберите источник…","toast.room_updated":"Комната обновлена","space.card_font":"Размер шрифта карточек комнат (всё пространство)","room.sizes_section":"Размеры шрифтов","room.name_scale":"Размер названия","room.label_scale":"Размер подписей","preview.room_name":"Гостиная","toast.cfg_reload_failed":"Не удалось перечитать план с сервера: {err}","toast.locale_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.light_role_label":"Является источником света","marker.light_role.help":"Определяет, является ли сам маркер пространственным источником света. Привязанные выше лампы остаются независимыми источниками для комнаты.","marker.light_role.help.aria":"Подсказка: является ли устройство источником света","marker.light_role_auto_yes":"Автоматически (источник света)","marker.light_role_auto_no":"Автоматически (не источник света)","marker.light_role_always":"Всегда источник света","marker.light_role_never":"Никогда не источник света","marker.light_entity_label":"Ведущая сущность света","marker.light_entity.help":"Для составного устройства выберите сущность, состояние, цвет и яркость которой представляют этот источник на плане. Автоматический вариант сохраняет совместимость со старыми планами.","marker.light_entity.help.aria":"Подсказка: ведущая сущность света","marker.light_entity_auto":"Автоматически ({entity})","marker.light_entity_none":"нет управляемой сущности","marker.light_entity_missing":"Сохранённая сущность {entity} недоступна. Временно используется {fallback}; выбор восстановится, если сущность вернётся.","marker.toggle_entity_label":"Переключаемая сущность","marker.toggle_entity.help":"Для составного устройства выберите собственную лампу или переключатель, которой управляет нажатие. Автоматический вариант сохраняет прежние правила цели и не зависит от ведущей сущности света.","marker.toggle_entity.help.aria":"Подсказка: переключаемая сущность","marker.toggle_entity_auto":"Автоматически ({entity})","marker.toggle_entity_none":"нет собственной управляемой сущности","marker.toggle_entity_missing":"Сохранённой сущности {entity} больше нет среди выбираемых каналов этого маркера. Временно используется {fallback}; выбор восстановится, если сущность вернётся.","marker.glow_color_label":"Цвет и яркость свечения","marker.glow_mode.help":"Используйте данные источника, задайте только цвет или зафиксируйте цвет и яркость. Минимум — 1%; чтобы отключить источник, выберите «Никогда».","marker.glow_mode.help.aria":"Подсказка: цвет и яркость свечения","marker.glow_mode_auto":"Из источника","marker.glow_mode_color":"Задать цвет","marker.glow_mode_fixed":"Задать цвет и яркость","marker.glow_color":"Цвет свечения","marker.glow_brightness":"Яркость","marker.glow_disabled_never":"Настройки свечения недоступны: маркер явно исключён из источников света.","marker.glow_disabled_auto":"В автоматическом режиме у этого маркера не найден пространственный источник света.","marker.glow_disabled_no_entity":"Для пространственного источника нет активной управляемой сущности Home Assistant.","marker.glow_passive_hint":"У источника нет собственных данных Home Assistant. Задайте цвет и яркость вручную; радиус остаётся доступным.","marker.control_broken":"Сохранённый источник отсутствует или больше не отмечен как источник света","marker.control_missing_label":"Отсутствующий источник на плане","marker.control_passive":"пассивный источник","toast.marker_control_cycle":"Такая связь создаст циклическую цепочку управления светом.","toast.marker_binding_required":"Сначала выберите устройство Home Assistant, затем добавьте управляемый источник света.","confirm.unlock":"Открыть замок «{name}»?","toast.files_migrate_failed":"Не удалось перенести вложения к новой привязке, ссылки остались на старые файлы: {err}","space.pick_saved":"Уже загруженные","space.pick_saved_hint":"Планы, сохранённые на сервере, включая отцеплённые ранее","space.no_saved":"На сервере пока нет сохранённых планов.","space.loading":"Загрузка…","space.used_by":"используется: {list}","space.in_use":"План используется пространством — сначала отцепите его","btn.use":"Выбрать","confirm.delete_plan":"Удалить файл плана «{name}» с сервера? Действие необратимо.","toast.plans_list_failed":"Не удалось получить список планов: {err}","toast.plan_delete_failed":"Не удалось удалить план: {err}","marker.hide":"Скрыть","marker.hide_tip":"Устройство исчезнет с плана после сохранения, но продолжит участвовать в расчёте сигнала комнаты. Вернуть его можно через каталог «Устройства» в редакторе устройств.","marker.show":"Показать","marker.show_tip":"Устройство снова появится на плане после сохранения.","marker.hidden_ghost":"Устройство скрыто пользователем","marker.ha_disabled_device":"Устройство деактивировано в Home Assistant и скрыто с плана.","marker.ha_disabled_entity":"Сущность деактивирована в Home Assistant и скрыта с плана.","marker.ha_disabled_all_entities":"У устройства нет активных сущностей Home Assistant, поэтому оно скрыто с плана.","marker.ha_registry_limited":"Полный реестр Home Assistant недоступен этому пользователю. Неподтверждённый объект временно нельзя показывать или использовать.","marker.delete_tip":"Полностью удалить устройство с плана и из всех расчётов. Позже его можно добавить заново.","tap.run":"Запустить автоматизацию/скрипт/сцену","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.cal_maps":"Откалиброваны карты: {maps}","vac.autocal_no_rooms":"Интеграция не отдаёт список комнат — откройте «Подогнать вручную»","vac.autocal_no_match":"Не совпали имена комнат (нужно ≥3 общих) — откройте «Подогнать вручную»","vac.autocal_done":"Готово: привязка по {rooms} комнатам. Запустите уборку и проверьте","vac.cal_need_pos":"Робот сейчас не отдаёт координаты — запустите уборку и поставьте на паузу","vac.cal_done":"Калибровка сохранена. Запустите уборку и проверьте","vac.cal_cancelled":"Калибровка отменена","vac.fit":"Подогнать вручную","vac.fit_hint":"Перетащите карту робота на место, растяните за уголки","vac.fit_rotate":"Повернуть 90°","vac.fit_mirror":"Отразить","vac.trail_never":"Не показывать никогда","vac.trail_cleaning":"Во время уборки","vac.trail_always":"Показывать всегда","gs.bg_group":"Фон сцены","gs.bg_color":"Цвет фона вокруг плана","gs.bg_default":"Как в теме","gs.bg_theme":"по умолчанию — из темы","gs.bg_mode":"Фон плана","gs.bg_static":"Статичный цвет","gs.bg_daynight":"Следует за Солнцем","gs.bg_daynight_hint":"Фон проходит рассвет, день, закат и ночь по данным sun.sun, а при их недоступности — по локальным часам. Компас для фона не нужен.","gs.sun_group":"Солнце","gs.sun_missing":"Сущность sun.sun не найдена — фон следует локальным часам, а оконные лучи недоступны.","gs.north":"Север на плане","gs.north_ph":"не задан","gs.north_hint":"Север нужен только для оконных лучей (шаг 1°, с Shift 15°); солнечный фон работает без него.","gs.north_clear":"Сбросить","gs.north_letter":"С","gs.sun_rays":"Солнце в окнах","gs.about_group":"О карточке","gs.about_version":"Houseplan Card v{v}","gs.about_github":"GitHub · документация и issues","gs.about_telegram":"Чат в Telegram","space.bg_color":"Цвет фона вокруг плана","space.bg_inherit":"Наследовать общий","space.bg_inherited":"наследуется из общих настроек","space.bg_mode":"Фон плана","space.north":"Север на плане (переопределение)","space.north_inherited":"наследуется: {v}","space.sun_rays":"Солнце в окнах","space.sun_inherit":"Наследовать общий","space.sun_on":"Вкл","space.sun_off":"Выкл","canvas.far_objects":"Объектов далеко от плана: {n}","canvas.show_far":"Показать","canvas.home_tip":"План там — нажмите, чтобы вписать","gs.grid_group":"Обслуживание планов","gs.grid_hint":"Обновляет модели данных, выравнивает элементы по сетке и объединяет лишние фрагменты стен. Перед записью будет показан точный отчёт.","gs.align_all":"Оптимизировать планы","gs.align_title":"Оптимизировать планы","gs.align_none":"Все планы уже используют актуальную и оптимальную модель данных.","gs.optimize_no_automatic_changes":"Автоматических изменений нет. Проверьте пункты ниже.","gs.align_count":"Сдвинется элементов: {n} из {total}, максимум на {cm} см.","gs.align_where":"Наибольший сдвиг — в пространстве «{s}».","gs.align_turned":"Проёмов с исправлением угла: {n}.","gs.align_removed_drafts":"Схлопнувшиеся на сетке некорректные контуры удалены: {n}.","gs.optimize_redundant_drafts":"Сохранённые цепочки стен, полностью скрытые стенами комнат, удалены: {n}.","gs.align_preflight_failed":"Не удалось безопасно проверить геометрию следующих пространств: {spaces}{more}.","gs.align_preflight_hint":"Планы не изменены. Скопируйте диагностику кнопкой ниже и приложите её к отчёту об ошибке вместе с экспортом пространства.","gs.preflight_reason_prepare-exception":"Не удалось подготовить геометрию пространства (исключение при сборке модели)","gs.preflight_reason_wall-null":"Тело стен не построилось (объединение вернуло пустоту)","gs.preflight_reason_wall-degraded-extra":"Тело стен деградировало с лишней геометрией","gs.preflight_reason_wall-failed-core":"Ядро тела стен не собралось","gs.preflight_reason_wall-exception":"Построение стен упало с исключением","gs.preflight_reason_floor-null":"Контур пола не построился","gs.preflight_reason_floor-exception":"Построение пола упало с исключением","gs.preflight_copy":"Скопировать диагностику","gs.preflight_copied":"Диагностика скопирована","gs.preflight_update_hint":"Версии карточки и интеграции различаются — обновите House Plan и повторите.","gs.align_preflight_space":"Пространство {n}","gs.align_preflight_more":" и ещё {n}","gs.optimize_changes":"Миграций модели: {m}; обновлено пространств: {c}; устранён шум координат: {p}; объединено отрезков реальных стен: {w}; объединено отрезков стен нулевой толщины: {s}; независимых: {i}.","gs.zero_walls_migrated":"Преобразовано виртуальных участков: {n}.","gs.wall_segments_migrated":"Стабилизировано сегментов стен: {n}.","gs.optimize_lattice_summary":"Канонизировано шумовых значений координат: {n}; максимальный сдвиг: {cm} см.","gs.optimize_lattice_space":"{space}: канонизировано значений координат: {n}; оставлено значений вне сетки: {far}.","gs.optimize_coincident_partitions":"Скрытые участки независимых стен поглощены стенами комнат: {n}.","gs.optimize_openings_rehosted":"Проёмы перепривязаны к стенам комнат: {n}.","gs.optimize_walls_straightened":"Выпрямлено стен: {n}; максимальное перемещение: {cm} см.","gs.optimize_walls_straightened_where":"Максимальная правка стены: {s}.","gs.optimize_walls_straighten_skipped":"Оставлено почти осевых стен, которые нельзя безопасно выпрямить: {n}.","gs.optimize_glow_migration":"Старый Glow: пространств — {spaces} → без заливки данных + независимый Glow; комнат — {rooms} → наследуемая заливка + независимый Glow.","gs.optimize_references":"Исправлено ссылок: пространства — {spaces}; комнаты — {rooms}; позиции — {positions}; устройств отвязано от отсутствующих пространств — {detached}.","gs.optimize_reference_more":", и ещё {n}","gs.optimize_orphans_removed":"Убрано забытых записей: {total} — подписи комнат: {rooms}; устройства: {devices}; групповые метки: {groups}. Все они принадлежали пространствам, удалённым ранее.","gs.optimize_live_positions":"Старые позиции в удалённых пространствах принадлежат существующим объектам: {n}{names}. Они будут сохранены.","gs.optimize_live_positions_remove":"Старые позиции в удалённых пространствах принадлежат существующим объектам: {n}{names}. Они выбраны для удаления.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Убрать старые позиции","gs.optimize_live_keep":"Сохранить старые позиции","gs.optimize_live_selected":"Старые позиции будут убраны после применения оптимизации.","gs.optimize_unverified":"Не удалось безопасно проверить позиций: {n}. Они оставлены без изменений.","gs.optimize_registry_limited":"Для безопасной проверки нужен полный доступ администратора к реестрам Home Assistant.","gs.optimize_vacuum_warning":"Сопоставления комнат пылесоса требуют проверки: {n}.","gs.optimize_details":"Подробности","gs.optimize_details_more":"И ещё записей: {n}.","gs.optimize_detail_removed":"будет удалено","gs.optimize_detail_live":"будет сохранено","gs.optimize_detail_unverified":"не проверено","gs.optimize_detail_room_label":"подпись комнаты","gs.optimize_detail_device":"устройство","gs.optimize_detail_group":"групповая метка","gs.optimize_detail_unknown":"неизвестный владелец","gs.optimize_detail_item":"{status}: {kind} {id}; прежнее пространство {space}","gs.align_warn":"Элементы, намеренно поставленные между узлами, будут сдвинуты. После операции доступна одна отмена — только до следующего изменения плана.","gs.align_run":"Оптимизировать","gs.align_done":"Планы оптимизированы: сдвинуто элементов — {n}, обслужено записей — {m}, исправлено ссылок — {r}","gs.optimize_undo":"Отменить последнюю оптимизацию","gs.optimize_undone":"Последняя оптимизация отменена","decor.furniture":"Мебель","furn.title":"Библиотека мебели","furn.symbol":"Символ","furn.group_furniture":"Мебель","furn.group_appliance":"Техника","furn.group_sanitary":"Сантехника","furn.group_other":"Прочее","furn.width":"Ширина","furn.depth":"Глубина","furn.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_cooktop":"Варочные панели","furn.cat_dining_table":"Обеденные столы","furn.cat_dishwasher":"Посудомоечные машины","furn.cat_dryer":"Сушильные машины","furn.cat_fireplace":"Камины","furn.cat_fridge":"Холодильники","furn.cat_kitchen_cabinet":"Кухонные шкафы","furn.cat_kitchen_sink":"Кухонные мойки","furn.cat_nightstand":"Тумбы","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_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":"Резервная копия и перенос","gs.backup_hint":"Скачайте переносимую JSON-копию или проверьте и импортируйте копию, созданную House Plan.","backup.export_open":"Экспорт","backup.import_open":"Импорт","backup.export_title":"Экспорт House Plan","backup.import_title":"Импорт House Plan","backup.export_hint":"Выберите, должна ли копия содержать всю конфигурацию House Plan или только текущее пространство.","backup.full":"Полная копия","backup.current_space":"Текущее пространство","backup.current_space_title":"Текущее пространство: {title}","backup.no_current_space":"Нет текущего пространства","backup.plan_only":"Только планировка","backup.plan_only_hint":"Сохранить комнаты, стены, проёмы, декор и позиции подписей комнат без устройств и привязок Home Assistant.","backup.plan_only_preview":"Файл содержит только планировку","backup.privacy_warning":"Архив сохраняет названия, идентификаторы Home Assistant и точные координаты. Внутренние планы и вложения указываются ссылками, но не вкладываются; текущие состояния и маршруты пылесосов не включаются.","backup.download":"Скачать JSON","backup.export_done":"Резервная копия скачана","backup.reading":"Проверяем резервную копию…","backup.revalidated":"После предпросмотра план изменился. Сводка обновлена — проверьте её и подтвердите ещё раз.","backup.error.unauthorized":"У вас нет прав на экспорт или импорт этого плана.","backup.error.not_ready":"House Plan ещё не готов. Повторите попытку через несколько секунд.","backup.error.too_large":"Размер резервной копии превышает 8 МиБ.","backup.error.invalid_json":"Выбранный файл не является корректным JSON.","backup.error.invalid_format":"Выбранный файл не является резервной копией House Plan.","backup.error.unsupported_export_version":"Эта версия формата резервной копии не поддерживается установленной версией.","backup.error.future_model":"Резервная копия создана в более новой версии модели данных House Plan.","backup.error.invalid_config":"Резервная копия содержит некорректную конфигурацию House Plan.","backup.error.wall_model_migration_blocked":"Не удалось безопасно обновить модель стен из резервной копии. Сначала оптимизируйте исходный план и повторите экспорт.","backup.error.invalid_layout":"Резервная копия содержит некорректные позиции объектов.","backup.error.invalid_content":"Резервная копия содержит некорректные или несогласованные ссылки на файлы.","backup.error.space_not_found":"Выбранное пространство больше не существует.","backup.error.capacity_exceeded":"Добавление этой копии превысит ограничения размера плана.","backup.error.preview_expired":"Время предпросмотра истекло. Выберите файл резервной копии заново.","backup.error.preview_owner_mismatch":"Этот предпросмотр принадлежит другому пользователю Home Assistant.","backup.error.conflict":"После предпросмотра план изменился. Проверьте обновлённую сводку.","backup.error.content_confirmation_required":"Подтвердите отсоединение недоступных локальных файлов.","backup.error.commit_failed":"Не удалось безопасно применить копию. Предыдущий план восстановлен или ожидает восстановления.","backup.error.missing_plan":"После предпросмотра исчез связанный файл плана. Проверьте копию ещё раз.","backup.error.missing_content":"После предпросмотра исчез связанный локальный файл. Проверьте копию ещё раз.","backup.error.marker_control_missing":"В резервной копии отсутствует связанный источник света на плане.","backup.error.marker_control_not_light":"Связанная цель больше не отмечена как источник света.","backup.error.marker_control_self":"Источник света не может управлять самим собой.","backup.error.marker_control_cycle":"Резервная копия содержит циклическую цепочку управления светом.","backup.error.duplicate_marker_control":"Резервная копия содержит повторяющуюся связь с источником света.","backup.error.no_backup":"Нет снимка импорта или оптимизации, который можно восстановить.","backup.same_source":"Создано на этом экземпляре Home Assistant","backup.foreign_source":"Создано на другом экземпляре Home Assistant","backup.created":"Создано: {value}","backup.versions":"Карточка {card}; интеграция {integration}; модель данных {model}","backup.count_spaces":"Пространств: {n}","backup.count_rooms":"Комнат: {n}","backup.count_walls":"Стен: {n}","backup.count_openings":"Проёмов: {n}","backup.count_decor":"Объектов декора: {n}","backup.count_markers":"Устройств: {n}","backup.count_layout":"Позиций: {n}","backup.bindings":"Привязки — устройства: {device}, сущности: {entity}, виртуальные: {virtual}; позиций без пространства: {legacy}","backup.binding_status":"Статус на целевом экземпляре — активных: {active}, деактивированных: {disabled}, отсутствующих: {missing}","backup.missing_areas":"На целевом экземпляре отсутствуют зоны: {areas}","backup.dropped_marker_links":"Связи с источниками света вне переносимого пространства пропущены: {n}.","backup.repaired_target_refs":"Существующих ссылок восстановлено этим импортом: {n}.","backup.preserved_unresolved_refs":"Неоднозначные ссылки сохранены без изменений: {n}.","backup.preserved_unresolved_hint":"House Plan ничего не угадывал и не удалял. После импорта запустите «Оптимизировать планы», чтобы проверить оставшиеся ссылки.","backup.import_details":"Подробности восстановления ссылок","backup.import_detail.incoming_remapped":"Ссылок обновлено внутри импортируемой копии: {n}","backup.import_detail.target_repaired":"Существующих ссылок восстановлено: {n}","backup.import_detail.preserved_unresolved":"Неразрешимых ссылок сохранено: {n}","backup.import_detail.collisions":"Конфликтов назначения безопасно сохранено: {n}","backup.import_detail.dropped_links":"Входящих связей пропущено по правилам переноса: {n}","backup.import_detail.bounded_lineages":"Чрезмерно вложенных идентификаторов ограничено: {n}","backup.replace_warning":"Текущая конфигурация и расположение будут заменены. Загруженные файлы не удаляются. Одну отмену можно выполнить до следующего изменения плана.","backup.foreign_bookkeeping":"Служебные списки известных и новых устройств другого экземпляра импортированы не будут.","backup.final_name":"Название нового пространства","backup.target_settings":"Глобальные настройки целевого экземпляра не изменятся.","backup.duplicates":"Уже существующих привязок: {n}","backup.skip":"Пропустить повторяющиеся устройства","backup.virtual_copy":"Добавить безопасные статичные виртуальные копии","backup.content":"Связанное содержимое","backup.content_available":"доступно локально","backup.content_external":"внешняя ссылка","backup.content_detach_required":"будет отвязано","backup.confirm_detach":"Я понимаю, что недоступные внутренние планы и вложения будут отвязаны от импортируемой конфигурации.","backup.replace":"Заменить","backup.add":"Добавить пространство","backup.space_done":"Пространство импортировано: комнат — {rooms}, устройств — {markers}, существующих ссылок восстановлено — {refs}","backup.full_done":"Копия восстановлена: пространств — {spaces}, комнат — {rooms}, устройств — {markers}","backup.undo_import":"Отменить последний полный импорт","backup.import_undone":"Полный импорт отменён"}},{code:"de",nativeLabel:"Deutsch",loadDictionary:async function(e){const t=0===e?await import("./de-CndLXoON.js"):await import(new URL("./de-CndLXoON.js?retry",import.meta.url).href);return{dictionary:t.dictionary,fingerprint:t.fingerprint}}}],iu=Zd,nu=new Set;const ru=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)}}(tu,"817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073",console.warn,function(e){for(const t of nu)t(e)});function ou(e){const t=lu(e)?.code??"en";return ru.dictionary(t)??iu}function su(e){return"string"==typeof e?e.trim().replaceAll("_","-").toLowerCase():""}const au=new Map(tu.map(e=>[su(e.code),e]));function lu(e){return au.get(su(e))}function cu(e,t){const i=[{value:"",label:e},...tu.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:lu(n)?.nativeLabel??n}),i}function hu(e,t){return function(e,t,i,n){const r=new Map(i.map(e=>[su(e),e])),o=r.get(su(e));if(o)return o;const s=su(t),a=r.get(s);return a||(r.get(s.split("-")[0]||"")??n)}(t,e?.locale?.language||e?.language,tu.map(({code:e})=>e),"en")}function du(e,t,i){return Ki(ou(e)[t]??iu[t]??t,i)}function uu(e,t){const i=ou(e)[t]??iu[t];return"string"==typeof i&&i.trim().length>0}function pu(e){const t=e.length/2,i=e.face.cm>0?e.face.cm/e.cellCm*e.gridPitch/2:Sa(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(Sa(16,e.cellCm),i+Sa(8,e.cellCm),n+Sa(8,e.cellCm)),hitHalf:Math.max(Sa(20,e.cellCm),i+Sa(10,e.cellCm),n+Sa(12,e.cellCm))}}function _u(e){if("passage"===e.type)return B``;const t=Math.max(0,Math.min(1,e.amount)),{half:i,jambHalf:n}=pu(e),r=$a(e.cellCm),o=1.75*r,s=e.flipH?-1:1,a=e.flipV?-1:1,l="gate"===e.type?1:a;e.type,e.flipV,e.angle,e.face;let c;if("window"===e.type){const o=Math.PI/2*i,s=e.face.cm>0?B``:B``;c=B` + + + + + + + + + + + + + + ${s} + `}else if("gate"===e.type){const n=10*e.face.side*t;c=B` + + + + + + + + + + + + `}else{const n=Math.PI/2*e.length;c=B` + + + + + + + + `}return B` + + + ${c} + `}const mu={climate:["current_temperature","temperature","current_humidity","humidity"],water_heater:["current_temperature","temperature"],cover:["current_position"],valve:["current_position"],fan:["percentage"],humidifier:["current_humidity","humidity"],light:["brightness"],media_player:["volume_level"],vacuum:["battery_level","fan_speed"],lawn_mower:["battery_level","fan_speed"]};function fu(e){return e?e.sourceLabel?`${e.sourceLabel}: ${e.fullText}`:e.fullText:""}const gu=new WeakMap;function vu(e){return e?"entity_state"===e.kind?`state:${e.entity_id}`:"entity_attribute"===e.kind?`attr:${e.entity_id}:${e.attribute}`:"derived_marker_state"===e.kind?`marker:${e.ref}`:"derived:lqi":""}function yu(e){if("derived:lqi"===e)return{kind:"derived_lqi"};if(e.startsWith("state:"))return{kind:"entity_state",entity_id:e.slice(6)};if(e.startsWith("attr:")){const t=e.slice(5),i=t.lastIndexOf(":");if(i>0)return{kind:"entity_attribute",entity_id:t.slice(0,i),attribute:t.slice(i+1)}}return e.startsWith("marker:marker:")?{kind:"derived_marker_state",ref:e.slice(7)}:null}function bu(e,t){const i=e?.entities?.[t],n=e?.states?.[t];return String(i?.name||i?.original_name||n?.attributes?.friendly_name||t)}function wu(e){return e.replaceAll("_"," ")}function ku(e,t=1){const i=Number(e);return Number.isFinite(i)?`${Math.round(i*t)} %`:null}function xu(e){if("derived_lqi"===e.kind)return"lqi";if("entity_attribute"===e.kind){if(e.attribute.includes("temperature"))return"temperature";if(e.attribute.includes("humidity"))return"humidity"}return"default"}function $u(e,t,i,n=[]){let r=null,o="",s="available";if("entity_state"===i.kind){o=bu(e,i.entity_id);const t=e?.states?.[i.entity_id];if(t)if(Mu(e,i.entity_id))if(["unknown","unavailable"].includes(String(t.state).toLowerCase()))s="unavailable";else{const n=Wi(e,i.entity_id);r=n?ji(n,String(t.attributes?.unit_of_measurement||"")):null,r||(s="unavailable")}else s="unavailable";else s="missing"}else if("entity_attribute"===i.kind){o=`${wu(i.attribute)} · ${bu(e,i.entity_id)}`;const t=e?.states?.[i.entity_id];t?Mu(e,i.entity_id)?(r=function(e,t,i){const n=e?.states?.[t];if(!n||!(i in(n.attributes||{})))return null;const r=Wi(e,t,i);if(r?.formatted)return r.text;const o=n.attributes?.[i];if("brightness"===i)return ku(o,100/255);if("volume_level"===i)return ku(o,100);if(["current_position","percentage","current_humidity","humidity","battery_level"].includes(i))return ku(o);if("current_temperature"===i||"temperature"===i){const t=Number(o);if(!Number.isFinite(t))return null;const i=String(e?.config?.unit_system?.temperature||"°C");return`${Math.round(10*t)/10} ${i}`}return r?.text||(["string","number","boolean"].includes(typeof o)?String(o):null)}(e,i.entity_id,i.attribute),null==r&&(s="unavailable")):s="unavailable":s="missing"}else if("derived_lqi"===i.kind){o="LQI";const i=Ph(e,t.entities);null==i?s="unavailable":r=String(i)}else{o="Light state";const t=n.find(e=>e.ref===i.ref);if(t){const i=t.on?"on":"off",n=e?.localize?.(`state.default.${i}`);r="string"==typeof n&&n?n:i,o=t.name||o}else s="missing"}const a=e?.localize?.("state.default.unavailable")||"Unavailable";return{source:i,sourceLabel:o,text:r??"—",fullText:r??a,availability:s,isLqi:"derived_lqi"===i.kind,tone:xu(i)}}function Su(e,t){if(!0===t.marker?.use_climate_temp){const i=t.entities.find(t=>t.startsWith("climate.")&&Number.isFinite(Number(e?.states?.[t]?.attributes?.current_temperature)));return i?{kind:"entity_attribute",entity_id:i,attribute:"current_temperature"}:null}if("mdi:thermometer"===t.icon||"mdi:air-filter"===t.icon){const i=t.entities.find(t=>dh(e,t)&&Number.isFinite(Number(e?.states?.[t]?.state)));if(i)return{kind:"entity_state",entity_id:i}}return t.primary&&Ih(e,t.primary)&&Number.isFinite(Number(e?.states?.[t.primary]?.state))?{kind:"entity_state",entity_id:t.primary}:null}function Mu(e,t){const i=e?.entities?.[t];if(i&&!th(i))return!1;const n=i?.device_id?e?.devices?.[i.device_id]:null;return!n||th(n)}function Ru(e,t){return Mu(e,t)&&!!e?.states?.[t]}function Tu(e,t,i=[t]){const n=function(e,t){const i=e=>[e.id,e.primary,e.hidden?1:0,e.userHidden?1:0,e.entities.join(","),(e.controls||[]).join(","),e.marker?.binding||"",!0===e.marker?.is_light?1:0,e.marker?.light_entity||"",(e.marker?.controls||[]).join(",")].join("|");return`${i(e)}\n${t.map(i).join("\n")}`}(t,i),r=gu.get(t);if(r&&r.states===(e?.states||null)&&r.entities===(e?.entities||null)&&r.devices===(e?.devices||null)&&r.signature===n)return r.result;const o=new Set(t.entities);for(const e of t.controls||[])e.startsWith("marker:")||o.add(e);const s=[],a=zh(e,i),l=a.filter(e=>e.key.startsWith("marker:")).map(e=>({ref:e.key,on:e.on,name:e.device?.name||e.key})),c=i=>{const n=vu(i);if(s.some(e=>e.key===n))return;const r=$u(e,t,i,l),o="entity_attribute"===i.kind?`${i.entity_id} · ${i.attribute}`:"entity_state"===i.kind?i.entity_id:"derived_marker_state"===i.kind?i.ref:"LQI";s.push({key:n,source:i,label:r.sourceLabel,technical:o,value:r.text,available:"available"===r.availability})};for(const t of[...o].sort()){if(!Ru(e,t))continue;const i=t.split(".")[0],n=e?.entities?.[t];if("button"===i||"event"===i||"config"===n?.entity_category)continue;c({kind:"entity_state",entity_id:t});const r=e?.states?.[t];for(const e of mu[i]||[])e in(r?.attributes||{})&&c({kind:"entity_attribute",entity_id:t,attribute:e})}const h=new Set((t.marker?.controls||t.controls||[]).filter(e=>e.startsWith("marker:")));!0===t.marker?.is_light&&t.marker.id&&h.add(`marker:${t.marker.id}`);const d=new Set(a.map(e=>e.key));for(const e of[...h].sort())d.has(e)&&c({kind:"derived_marker_state",ref:e});return t.virtual||null==Ph(e,t.entities)||c({kind:"derived_lqi"}),gu.set(t,{states:e?.states||null,entities:e?.entities||null,devices:e?.devices||null,signature:n,result:s}),s}function Cu(e,t,i){const n=Su(e,t);if(n&&i.some(e=>e.key===vu(n)))return n;const r=t.primary&&i.find(e=>e.key===`state:${t.primary}`);if(r)return r.source;const o=[e=>e.technical.includes("temperature"),e=>e.technical.includes("humidity"),e=>e.technical.includes("battery")];for(const e of o){const t=i.find(e);if(t)return t.source}return i.find(e=>"derived_lqi"!==e.source.kind)?.source||i[0]?.source||null}function Du(e){return e.touched?{value_badge:{enabled:e.enabled,source:e.source,position:e.position}}:e.originalHas?{value_badge:e.original}:{}}function zu(e,t,i){return{kind:"none",reason:"none",generation:e,expiresAt:null,color:t,diameterScale:i,animated:!1,reducedMotionIndicator:"none"}}function Au(e,t,i,n,r=null){return{kind:t,reason:"short"===t?"event":"running",generation:Math.max(1,Math.trunc(i)),expiresAt:"short"===t?r:null,color:e.color,diameterScale:n?1:e.diameterScale,animated:!n,reducedMotionIndicator:n?"dot":"none"}}const Ou={availability:"available",status:"neutral",activity:"none"};function Pu(e){return e<=40?"low":e<180?"mid":"high"}function Fu(e){return Vt(e)}function Eu(e){return"static_icon"===e.display?"neutral":"alarm"===e.visual.status?"alarm":"unavailable"===e.visual.availability?"unavailable":e.lockState?e.lockState:"working"===e.visual.status?"working":"open"===e.visual.status?"open":"neutral"}const Iu={sourceKind:"none",decisionIds:["source.skipped_static_fast_path"],visualSources:[],criticalSources:[],samples:[]};function Hu(e,t){const i=e?.entities?.[t],n=e?.states?.[t];return String(i?.name||i?.original_name||n?.attributes?.friendly_name||t)}function Nu(e,t){const i=e?.states?.[t];if(!i)return"";if("function"==typeof e?.formatEntityState)try{const t=e.formatEntityState(i);if("string"==typeof t&&t)return t}catch{}return String(i.state??"")}function Lu(e,t){if(t.virtual||"virtual"===t.bindingKind||"virtual"===t.marker?.binding)return"available";const i=t.entities||[];if(0===i.length&&("device"===t.bindingKind||t.marker?.binding?.startsWith("device:"))&&"active"===t.bindingStatus?.kind)return"available";return i.some(t=>{const i=String(e?.states?.[t]?.state??"").trim().toLowerCase();return""!==i&&"unknown"!==i&&"unavailable"!==i})?"available":"unavailable"}function qu(e,t,i,n){return{eid:t,role:i,name:Hu(e,t),state:String(e?.states?.[t]?.state??""),stateText:Nu(e,t),integrationDomain:e?.entities?.[t]?.platform||null,sample:n||Tc(e,t)}}function Wu(e,t,i=[t],n,r=e){const o=t.hidden&&t.userHidden?{...t,hidden:!1}:t;let s="none",a=[];const l=[],c=[...o.entities,...o.allEntities||[]].some(e=>e.startsWith("cover."))?{...o,tapAction:"cover"}:o,h=(d=Sd({hass:e,devices:i,device:c,lightSources:n,registryHass:r}),"cover"!==d?.semantics?null:d.targets[0]?.entityId||d.skippedTargets[0]?.entityId||null);var d;const u=zh(e,[o]),p=gh(o.marker?.binding,o.marker?.controls??o.controls,o.entities),_=new Set(p.filter(e=>e.startsWith("marker:"))),m=!0===o.marker?.is_light||_.size>0?n||zh(e,i):u,f=m.filter(e=>e.device.id===o.id&&"controls"!==e.via),g=u.filter(e=>"controls"!==e.via),v=f.length?f:g,y=Hc(o.marker),b=y?[...v]:[...u.filter(e=>"controls"===e.via),...v];if(_.size)for(const e of m){if(!_.has(e.key))continue;e.stateEids.length>0&&b.some(t=>t.stateEids.some(t=>e.stateEids.includes(t)))||b.some(t=>t.key===e.key)||b.push({...e,via:"controls",castsGlow:!1})}const w=_h(r,o.entities),k=!!h&&("cover"===o.tapAction||o.primary?.startsWith("cover.")||w.some(e=>e.startsWith("cover.")));if(h&&!k&&l.push("source.cover_capability_bypassed"),k)s="cover",l.push("source.cover"),a=[qu(e,h,"cover")];else if(b.length)s=!y&&b.some(e=>"controls"===e.via)?"controls":"light",y?l.push("source.manual_virtual_light"):l.push("controls"===s?"source.controls":"source.owned_light"),"controls"!==s||!o.virtual&&"virtual"!==o.bindingKind||l.push("source.virtual_controller"),a=b.map(i=>{const n="controls"===i.via?"control":"forced"===i.via?"forced_light":"light";if(!i.passive)return qu(e,i.eid,n);const r=i.on?"on":"off";return{eid:i.key,role:n,name:t.name,state:r,stateText:r,integrationDomain:null,sample:{eid:i.key,state:r,availability:"available",status:i.on?"working":"neutral",activity:"none",edge:"none"}}});else{const t=_h(r,o.entities),i=t.length?t:o.entities.filter(t=>!!e?.states?.[t]);if(i.length){s="device_role",l.push("source.device_role");const t=Cc(r===e?e:{...r,states:e?.states||{}},i,o.entities),n=i.some(e=>Sc(r,e));a=t.map(t=>{const i=n?Mc(r,t.eid)?"power_gate":Sc(r,t.eid)?"lifecycle":"device_role":"device_role";return qu(e,t.eid,i,t)})}else o.primary?(s="primary",l.push("source.primary_fallback"),a=[qu(e,o.primary,"primary")]):l.push("source.none")}p.length>0&&"controls"!==s&&"light"!==s&&"cover"!==s&&l.push("source.filtered_saved_controls");const x=[];for(const t of o.entities||[]){const i=Tc(e,t);"alarm"!==i.status||a.some(e=>e.eid===t)||x.push(qu(e,t,"critical",i))}return x.length&&l.push("source.critical_sibling"),{sourceKind:s,decisionIds:l,visualSources:a,criticalSources:x,samples:[...a,...x].map(e=>e.sample)}}function ju(e,t,i,n){if(t.virtual)return{source:null,text:null,fallback:"value_virtual"};if(n){const i=function(e,t){if(!0!==t.marker?.use_climate_temp)return null;for(const i of t.entities){if(!i.startsWith("climate."))continue;const t=Number(e?.states?.[i]?.attributes?.current_temperature);if(Number.isFinite(t))return{eid:i,text:Math.round(10*t)/10+"°"}}return null}(e,t);if(i)return{source:{kind:"temperature",eid:i.eid,attribute:"current_temperature",text:i.text},text:i.text,fallback:null};const n=function(e,t){if("mdi:thermometer"!==t.icon&&"mdi:air-filter"!==t.icon)return null;for(const i of t.entities){if(!dh(e,i))continue;const t=Number(e?.states?.[i]?.state);if(Number.isFinite(t))return{eid:i,text:Math.round(10*t)/10+"°"}}return null}(e,t);if(n)return{source:{kind:"temperature",eid:n.eid,text:n.text},text:n.text,fallback:null};const r=function(e,t){if(!t.primary||!Ih(e,t.primary))return null;const i=Number(e?.states?.[t.primary]?.state);return Number.isFinite(i)?{eid:t.primary,text:`${Math.round(i)}%`}:null}(e,t);if(r)return{source:{kind:"humidity",eid:r.eid,text:r.text},text:r.text,fallback:null}}const r=i.visualSources.filter(e=>!e.eid.startsWith("marker:"));let o=r.map(e=>e.eid);const s=r.find(e=>"power_gate"===e.role);if(s&&(o=[s.eid]),!o.length&&i.visualSources.some(e=>e.eid.startsWith("marker:"))&&(o=_h(e,t.entities),!o.length&&t.primary&&e?.states?.[t.primary]&&(o=[t.primary])),o=[...new Set(o)],1!==o.length)return{source:null,text:null,fallback:o.length?"value_ambiguous_sources":"value_no_state"};const a=o[0],l=function(e,t){const i=e?.states?.[t];if(!i||null==i.state||""===String(i.state).trim())return{text:"",fallback:"value_no_state"};const n=i.state;if(!["string","number","boolean"].includes(typeof n))return{text:"",fallback:"value_non_scalar"};const r=String(n).trim().toLowerCase();if("unknown"===r||"unavailable"===r)return{text:"",fallback:"value_no_state"};const o=Wi(e,t);return o?{text:ji(o,String(i.attributes?.unit_of_measurement||"")),fallback:null}:{text:"",fallback:"value_no_state"}}(e,a);return l.fallback?{source:null,text:null,fallback:l.fallback}:{source:{kind:"entity",eid:a,text:l.text},text:l.text,fallback:null}}function Bu(e,t,i){const n=e.marker?.binding||(e.bindingKind&&e.bindingRef?`${e.bindingKind}:${e.bindingRef}`:e.virtual?"virtual":""),r=[...t.visualSources.map(e=>`${e.role}:${e.eid}`),...t.criticalSources.map(e=>`critical:${e.eid}`)].sort(),o=i?`${i.kind}:${i.eid}:${i.attribute||""}`:"none";return[n,t.sourceKind,...r,`value:${o}`].join("\n")}function Vu(e,t,i){return Bu(t,i||Wu(e,t),null).replace(/\nvalue:none$/,"")}function Uu(e){if(e.effectiveHidden)return[];if("static_icon"===e.display)return["static-icon"];const t=[],{visual:i}=e;return"alarm"===e.pulse.kind?t.push("alarm"):"unavailable"===i.availability?t.push("unavail"):"working"===i.status?t.push("on"):"open"===i.status&&t.push("open"),e.lockState&&t.push(`lock-${e.lockState}`),"none"!==e.pulse.reason&&"alarm"!==e.pulse.reason&&t.push("activity-"+e.pulse.reason),e.pulse.generation%2==0&&(t.push("pulse-gen2"),"short"===e.pulse.kind&&t.push("activity-gen2")),t}function Gu(e,t,i){const n=Ai(t.marker?.display),r="static_icon"===n,o=r&&!1===i.sourceDetails?Iu:Wu(e,t,i.lightDevices||[t],i.lightSources,i.registryHass||e),s=t.bindingStatus,a="ha_disabled"===s?.kind,l="orphaned"===s?.kind,c=a?"ha_disabled":l?"orphaned":"active",h=!0===t.userHidden||!0===t.marker?.hidden,d=Dc(o.samples),u=o.visualSources.find(e=>e.eid.startsWith("lock.")),p=u?["unlocked","open"].includes(u.state.toLowerCase())?"unlocked":"locked"===u.state.toLowerCase()?"locked":null:null,_=!Hc(t.marker)&&gh(t.marker?.binding,t.marker?.controls??t.controls,t.entities).length>0,m="controls"===o.sourceKind||_&&"light"!==o.sourceKind&&"cover"!==o.sourceKind,f=r&&!1===i.sourceDetails?{source:null,text:null,fallback:null}:ju(e,t,o,i.showTemperature),g=Bu(t,o,f.source),v=Vu(e,t,o),y=i.activityRuntime,b=i.now??Date.now(),w=y?.expiresAt||(y?.flashTs?y.flashTs+3300:0),k=y?.sources===v&&y.flashTs&&y.flashKind&&w>b?y.flashKind:null,x=function(e){const t=[],i="ha_disabled"===e.bindingLifecycle||"orphaned"===e.bindingLifecycle;let n=!1;"ha_disabled"===e.bindingLifecycle?(n=!0,t.push("lifecycle.ha_disabled_hidden")):e.userHidden&&!e.designPreview?(n=!0,t.push("lifecycle.user_hidden")):e.userHidden?t.push("lifecycle.user_hidden_preview"):"orphaned"===e.bindingLifecycle?t.push("lifecycle.orphaned_diagnostic"):t.push("lifecycle.active");const r="static_icon"===e.display;let o=e.controllerFace?{...e.sourceVisual,availability:e.controllerAvailability}:e.sourceVisual;t.push(e.controllerFace?"available"===e.controllerAvailability?"availability.controller_available":"availability.controller_unavailable":"availability.source"),n?(o=Ou,t.push("face.hidden")):r?(o=Ou,t.push("face.static")):"alarm"===e.sourceVisual.status||e.liveStates?t.push("face.dynamic"):(o=Ou,t.push("face.live_states_disabled")),!r&&!n&&e.liveStates&&"alarm"!==e.sourceVisual.status&&e.shortActivity&&(o={...o,activity:e.shortActivity},t.push(`activity.short_${e.shortActivity}`)),"alarm"===o.status?t.push("status.alarm"):"unavailable"===o.availability?t.push("status.unavailable"):"working"===o.status?t.push("status.working"):"open"===o.status?t.push("status.open"):t.push("status.neutral");const s="value"===e.display&&!n&&e.valueAvailable?"value":"icon";t.push("value"===s?"content.value":"value"===e.display?"content.value_fallback_icon":"content.icon"),"value"===e.display&&!e.valueAvailable&&e.valueFallback&&t.push(`content.${e.valueFallback}`);const a=e.liveStates&&!r&&!n,l=!r&&!n,c=!n&&!i&&!r&&"available"===o.availability&&("alarm"===o.status||e.liveStates&&"icon_ripple"===e.display),h=l&&e.vacuumLiveRequested;return t.push(a?"diagnostics.dynamic_icon":"diagnostics.base_icon"),t.push(l?"diagnostics.metrics_enabled":"diagnostics.metrics_suppressed"),t.push(c?"activity.pulse_eligible":"activity.pulse_suppressed"),t.push(h?"diagnostics.vacuum_live":"diagnostics.vacuum_static"),{effectiveHidden:n,bindingUnavailable:i,visual:o,face:s,dynamicIcon:a,metrics:l,liveColor:a,pulseEligible:c,vacuumLive:h,decisionIds:t}}({bindingLifecycle:c,userHidden:h,designPreview:!0===i.designPreview,display:n,liveStates:i.liveStates,sourceVisual:d,controllerFace:m,controllerAvailability:m?Lu(e,t):"available",shortActivity:k,valueAvailable:null!=f.text,valueFallback:f.fallback,vacuumLiveRequested:!0===t.marker?.vacuum?.live}),{effectiveHidden:$,visual:S}=x,M="icon_ripple"===n&&!$&&i.liveStates&&"alarm"!==S.status?S.activity:"none",R=x.metrics&&i.showTemperature?!0===t.marker?.use_climate_temp?Eh(e,t.entities):"mdi:thermometer"===t.icon||"mdi:air-filter"===t.icon?Fh(e,t.entities):null:null,T=x.metrics&&i.showTemperature&&t.primary&&Ih(e,t.primary)?Hh(e,t.entities):null,C=x.metrics&&i.showSignal&&!t.virtual?Ph(e,t.entities):null,D=i.lightSources||("derived_marker_state"===t.marker?.value_badge?.source?.kind?zh(e,i.lightDevices||[t]):[]),z=function(e,t,i){const n=null!=t.marker?.value_badge;if(i.effectiveHidden||"static_icon"===i.display)return null;const r=t.marker?.value_badge;if(n)return r?.enabled?r.source?{configured:!0,enabled:!0,position:r.position||"right",...$u(e,t,r.source,i.markerStates)}:{configured:!0,enabled:!0,source:null,sourceLabel:"",text:"—",fullText:e?.localize?.("state.default.unavailable")||"Unavailable",position:r.position||"right",availability:"missing",isLqi:!1,tone:"default"}:null;if(!i.showTemperature||"value"===i.display)return null;const o=Su(e,t);if(!o)return null;let s=null,a="default";if("entity_attribute"===o.kind&&"current_temperature"===o.attribute){const i=Eh(e,t.entities);null!=i&&(s=`${i}°`),a="temperature"}else if("mdi:thermometer"===t.icon||"mdi:air-filter"===t.icon){const i=Fh(e,t.entities);null!=i&&(s=`${i}°`),a="temperature"}else{const i=Hh(e,t.entities);null!=i&&(s=`${i}%`),a="humidity"}return null==s?null:{configured:!1,enabled:!0,source:o,position:"right",sourceLabel:"entity_attribute"===o.kind?`${wu(o.attribute)} · ${bu(e,o.entity_id)}`:"entity_state"===o.kind?bu(e,o.entity_id):"",text:s,fullText:s,availability:"available",isLqi:!1,tone:a}}(e,t,{showTemperature:i.showTemperature,showSignal:i.showSignal,display:n,effectiveHidden:$,markerStates:D.filter(e=>e.key.startsWith("marker:")).map(e=>({ref:e.key,on:e.on,name:e.device.name}))}),A=o.visualSources.find(e=>!e.eid.startsWith("marker:")),O="cover"===o.sourceKind?A?.eid:t.primary||A?.eid,P=O?e?.states?.[O]:null,F=x.dynamicIcon?un(t.icon,O?.split(".")[0],P?.attributes?.device_class,P?.state,!!t.marker?.icon):t.icon,E=x.liveColor&&o.visualSources.filter(e=>!e.eid.startsWith("marker:")).map(t=>function(e){return e&&"on"===e.state?Bt(e.attributes?.rgb_color):null}(e?.states?.[t.eid])).find(e=>!!e)||null,I=Number(t.marker?.size)>0?Number(t.marker.size):1,H=Number(t.marker?.angle)||0,N=Number(t.marker?.ripple_size)>0?Number(t.marker.ripple_size):1.5,L=qt(t.marker?.ripple_color,null),q=r?null:L||E||null,W=function(e){const{display:t,visual:i,semanticActivity:n,liveStates:r,effectiveHidden:o,bindingUnavailable:s=!1,reducedMotion:a=!1}=e,l=Math.max(1,Math.trunc(e.shortGeneration||1)),c=Number.isFinite(e.diameterScale)?Math.max(1,Number(e.diameterScale)):1.5,h=e.color||function(e,t){return"presence"===t?"#1DC21D":"running"===t||"working"===e.status||"open"===e.status?"#F0A00C":"#0C82F0"}(i,n);if(o||s||"unavailable"===i.availability||"static_icon"===t)return zu(l,h,c);if("alarm"===i.status)return{kind:"alarm",reason:"alarm",generation:l,expiresAt:null,color:"#F0410C",diameterScale:1.5,animated:!a,reducedMotionIndicator:"none"};if(!r||"icon_ripple"!==t)return zu(l,h,c);const d=e.now??Date.now(),u=e.shortExpiresAt||null;return e.shortReason&&null!=u&&u>d?{kind:"short",reason:e.shortReason,generation:l,expiresAt:u,color:h,diameterScale:a?1:c,animated:!a,reducedMotionIndicator:a?"dot":"none"}:"presence"===n||"transition"===n||"running"===n?{kind:"continuous",reason:n,generation:l,expiresAt:null,color:h,diameterScale:a?1:c,animated:!a,reducedMotionIndicator:a?"dot":"none"}:zu(l,h,c)}({display:n,visual:S,semanticActivity:d.activity,shortReason:y?.sources===v?y?.flashKind:null,shortGeneration:y?.gen,shortExpiresAt:y?.sources===v?w:null,now:b,liveStates:i.liveStates,effectiveHidden:$,bindingUnavailable:x.bindingUnavailable,reducedMotion:i.reducedMotion,color:q,diameterScale:N}),j="value"===x.face?f.text:null,B="ha_disabled"===s?.kind?s.reason:null,V="ha_disabled"===(U={lifecycle:c,display:n,liveStates:i.liveStates,sourceKind:o.sourceKind,primaryDomain:(t.primary||"").split(".")[0],visual:S,activity:M}).lifecycle?"ha_disabled":"orphaned"===U.lifecycle?"orphaned":"static_icon"===U.display?"static_icon":"alarm"===U.visual.status?"alarm":U.liveStates?"unavailable"===U.visual.availability?"unavailable":"cover"===U.sourceKind?"cover_icon_state":"presence"===U.activity?"presence":"event"===U.activity?"event":"transition"===U.activity?"transition":"working"===U.visual.status?"icon_ripple"===U.display&&"none"!==U.activity?"working_activity":"working":"open"===U.visual.status?"open":"media_player"===U.primaryDomain?"media_neutral":"neutral":"live_states_disabled";var U;const G=[];i.designPreview&&h&&G.push("hidden_design_preview"),r||!0!==t.marker?.vacuum?.live||G.push("vacuum_live_plan_only");const K=o.visualSources.some(t=>"power_gate"===t.role||Mc(e,t.eid)),Y=t.entities.filter(t=>t.startsWith("switch.")&&!e?.entities?.[t]?.entity_category).length;K&&Y>1&&G.push("composite_power_source"),"icon_ripple"!==n&&"static_icon"!==n&&"alarm"!==d.status&&"none"!==d.activity&&G.push("activity_display_disabled");const Z={binding:t.marker?.binding||(t.bindingKind&&t.bindingRef?`${t.bindingKind}:${t.bindingRef}`:t.virtual?"virtual":""),sourceKind:o.sourceKind,visualSources:o.visualSources,criticalSources:o.criticalSources,valueSource:f.source,sourceSignature:g,decisionIds:[...o.decisionIds,...x.decisionIds,...z?["diagnostics.value_badge"]:[],...null==C?[]:[`diagnostics.lqi_${Pu(C)}`],`pulse.${W.kind}_${W.reason}`],visual:S,lockState:p,display:n,icon:F,valueText:j,valueFullText:j,fallbackReason:"value"!==n||j?null:f.fallback,activity:M,activityGeneration:y?.gen||1,pulse:W,classes:[],tempText:null==R?null:String(R),humText:null==T?null:String(T),valueBadge:z,lqiText:null==C||z?.isLqi?null:String(C),lqiColor:null==C?null:Fu(C),lqiBand:null==C?null:Pu(C),lightColor:E,scale:I,angle:H,rippleScale:N,rippleColor:q,userHidden:h,effectiveHidden:$,haDisabled:a,disabledReason:B,orphaned:l,vacuumLive:x.vacuumLive,explanation:{reason:V,notices:G}};return{...Z,classes:Uu(Z)}}function Ku(e,t=new WeakMap){if(null===e||"object"!=typeof e)return e;const i=e,n=t.get(i);if(n)return n;if(Array.isArray(e)){const n=[];t.set(i,n);for(const i of e)n.push(Ku(i,t));return Object.freeze(n)}const r={};t.set(i,r);for(const[i,n]of Object.entries(e))"function"!=typeof n&&(r[i]=Ku(n,t));return Object.freeze(r)}function Yu(e){const t=new Map(e);let i;return i=Object.freeze({get size(){return t.size},get:e=>t.get(e),has:e=>t.has(e),entries:()=>t.entries(),keys:()=>t.keys(),values:()=>t.values(),forEach:(e,n)=>t.forEach((t,r)=>e.call(n,t,r,i)),[Symbol.iterator]:()=>t[Symbol.iterator]()}),i}function Zu(e){const t=new Set(e.entityIds||[]),i=new Set(e.deviceIds||[]),n=new Set(e.areaIds||[]);for(const n of e.devices){for(const e of n.entities||[])t.add(e);n.primary&&t.add(n.primary);for(const e of n.controls||[])t.add(e);n.marker?.vacuum?.source&&t.add(n.marker.vacuum.source),"device"===n.bindingKind&&n.bindingRef&&i.add(n.bindingRef),"entity"===n.bindingKind&&n.bindingRef&&t.add(n.bindingRef)}const r={},o={};for(const[o,s]of Object.entries(e.hass?.entities||{})){const a=s?.device_id?e.hass?.devices?.[s.device_id]:null;(t.has(o)||s?.device_id&&i.has(s.device_id)||n.has(s?.area_id)||n.has(a?.area_id))&&(t.add(o),r[o]=s,s?.device_id&&i.add(s.device_id))}for(const t of i){const i=e.hass?.devices?.[t];i&&(o[t]=i)}const s={};for(const i of t){const t=e.hass?.states?.[i];t&&(s[i]=t)}const a=Object.freeze({states:Ku(s),entities:Ku(r),devices:Ku(o),config:Ku(e.hass?.config),locale:Ku(e.hass?.locale),themes:Ku(e.hass?.themes)});return Object.freeze({sourceSequence:e.sourceSequence,capturedAt:e.capturedAt??Date.now(),hass:a,devices:Ku([...e.devices]),positions:Yu([...e.positions||[]].map(([e,t])=>[e,Object.freeze({x:t.x,y:t.y})])),presentations:Yu([...e.presentations].map(([e,t])=>[e,Ku(t)])),facts:Yu([...e.facts||[]].map(([e,t])=>[e,Ku(t)]))})}const Xu=(e,t)=>`${e}:${t?1:0}`;function Ju(e){return"boolean"==typeof e?.themes?.darkMode?e.themes.darkMode?"theme-dark":"theme-light":""}function Qu(e){const t=[];if(1!==e.scale&&t.push(`--dev-scale:${e.scale}`),"none"!==e.pulse.kind){t.push(`--ripple-scale:${e.pulse.diameterScale}`);const r=(i=e.pulse.color,n=null,"string"==typeof i&&(Lt.test(i)||jt.test(i))?i:n);r&&t.push(`--ripple-color:${r}`)}var i,n;return t}function ep(e){const t=[...String(e)].reduce((e,t)=>/\s/.test(t)?e+.35:e+(t.codePointAt(0)>255?1:.62),0);return t<=8?.45:Math.max(.25,Math.round(3.6/t*1e3)/1e3)}function tp(e,t){const i=e.pulse,n=i.generation%2==0,r=function(e){const t=e.valueBadge;if(!t||!1!==t.configured)return[];const i=[];return null!=e.tempText&&"temperature"!==t.tone&&i.push({kind:"temperature",text:e.tempText,suffix:"°"}),null!=e.humText&&"humidity"!==t.tone&&i.push({kind:"humidity",text:e.humText,suffix:"%"}),i}(e),o=e.valueBadge,s=o?.position||"right",a=!!o||r.length>0,l=["device-shell",null!=e.valueText?"text-shell":"",a?`with-values pos-${s}`:"",r.length?"with-legacy":""].filter(Boolean).join(" ");return j` + ${"none"!==i.kind&&"dot"!==i.reducedMotionIndicator?j``:U} + ${"dot"===i.reducedMotionIndicator?j``:U} + ${t.newDevice?j``:U} + ${e.haDisabled?j``:U} + + ${null!=e.lqiText?j`${e.lqiText}`:U} + `}function ip(e){return!Number.isFinite(e)||e<=0?2.25:e/2.5*2.25}function np({openings:e,geometries:t,fillsByRoomId:i,idPrefix:n="data",groupClass:r="opening-tunnels",dataLayer:o="data"}){const s=e.map((e,r)=>{const o=t[r];if(!o)return U;const s=o.faces.find(e=>-1===e.side),a=o.faces.find(e=>1===e.side);if(!s||!a)return U;const l=i.get(s.roomId)||null,c=i.get(a.roomId)||null;if(!l&&!c)return U;const h=`${s.d} ${a.d}`,d=!!l&&!!c&&l.color===c.color&&l.opacity===c.opacity,u=`translate(${e.rx} ${e.ry}) rotate(${e.angle})`;if(d)return B``;const p=o.maxY-o.minY;if(!(p>0))return U;const _=`${(100*Math.max(0,Math.min(1,-o.minY/p))).toFixed(6)}%`,m=l||{color:"#000000",opacity:0},f=c||{color:"#000000",opacity:0},g=`hp-opening-tunnel-${n.replace(/[^a-zA-Z0-9_-]/g,"-")}-${r}`;return B``});return B``}function rp(e,t,i){const n=i>0?i:1;return{a:[e[0]/n,e[1]/n],b:[t[0]/n,t[1]/n]}}function op(e,t){const i=t>0?t:1;return[e.a[0]*i,e.a[1]*i,e.b[0]*i,e.b[1]*i]}function sp(e){return Array.isArray(e)&&e.length>=2&&Number.isFinite(Number(e[0]))&&Number.isFinite(Number(e[1]))}function ap(e){if(!Array.isArray(e))return[];const t=[];for(const i of e){if(!i||"object"!=typeof i)continue;const e=i;if(!sp(e.a)||!sp(e.b))continue;const n=[Number(e.a[0]),Number(e.a[1])],r=[Number(e.b[0]),Number(e.b[1])];Math.hypot(r[0]-n[0],r[1]-n[1])<.001||t.push({a:n,b:r})}return t}function lp(e,t,i,n,r=!0){const o=(e||[]).filter(e=>e?.id),s=ap(t);if(s.length)return function(e,t,i,n){const r=ap(e);if(!r.length)return[];const o=function(e,t){const i=[],n=(e||[]).filter(e=>e?.id);for(let e=0;e4*n||o>4*n)continue;const s=(e[0]-r)*u+(e[1]-l)*p,c=(e[2]-r)*u+(e[3]-l)*p,h=Math.max(0,Math.min(s,c)),m=Math.min(d,Math.max(s,c));if(m-he.lo-t.lo||e.hi-t.hi);const i=[];for(const e of t){const t=i[i.length-1];t&&e.lo<=t.hi+a?t.hi=Math.max(t.hi,e.hi):i.push({...e})}for(const t of i){const i=[r+u*t.lo,l+p*t.lo],n=[r+u*t.hi,l+p*t.hi];Math.hypot(n[0]-i[0],n[1]-i[1])i.pair===e&&Math.abs(i.ux*s-i.uy*o)<=1e-6&&Math.abs((t[0]-i.origin[0])*i.uy-(t[1]-i.origin[1])*i.ux)<=c&&Math.abs((t[2]-i.origin[0])*i.uy-(t[3]-i.origin[1])*i.ux)<=c);h||(h={pair:e,origin:[t[0],t[1]],ux:o,uy:s,ranges:[]},l.push(h));const d=(t[0]-h.origin[0])*h.ux+(t[1]-h.origin[1])*h.uy,u=(t[2]-h.origin[0])*h.ux+(t[3]-h.origin[1])*h.uy;h.ranges.push({lo:Math.min(d,u),hi:Math.max(d,u)})}const h=[];for(const e of l){e.ranges.sort((e,t)=>e.lo-t.lo||e.hi-t.hi);const t=[];for(const i of e.ranges){const e=t[t.length-1];e&&i.lo<=e.hi+a?e.hi=Math.max(e.hi,i.hi):t.push({...i})}for(const n of t){const t=[e.origin[0]+e.ux*n.lo,e.origin[1]+e.uy*n.lo],r=[e.origin[0]+e.ux*n.hi,e.origin[1]+e.uy*n.hi];Math.hypot(r[0]-t[0],r[1]-t[1])>=a&&h.push(rp(t,r,i))}}return h}(s,e,i,n).map(e=>op(e,i));if(!r)return[];const a=[],l=(e,t)=>(e.open_to||[]).includes(t.id)||(t.open_to||[]).includes(e.id);for(let e=0;er)&&Po([o[0],o[1]],[o[2],o[3]],i))return!0;return!1}const hp=e=>Array.isArray(e)&&e.length>=2&&Number.isFinite(Number(e[0]))&&Number.isFinite(Number(e[1])),dp=(e,t,i)=>[Number(e[0])*i,Number(e[1])*i,Number(t[0])*i,Number(t[1])*i],up=e=>{const t=`${Number(e[0]).toFixed(9)},${Number(e[1]).toFixed(9)}`,i=`${Number(e[2]).toFixed(9)},${Number(e[3]).toFixed(9)}`;return t<=i?`${t}|${i}`:`${i}|${t}`},pp=e=>{const t=new Map;for(const i of e.flat())!Array.isArray(i)||i.length<4||!i.every(Number.isFinite)||Math.hypot(i[2]-i[0],i[3]-i[1])<=1e-9||t.set(up(i),[...i]);return[...t.values()]};function _p(e){return"solid"===e?.zero_wall_style?"solid":"dashed"}function mp(e,t=1,i){const n=[];for(const r of Array.isArray(e?.wall_segments)?e.wall_segments:[])0===Number(r?.cm)&&hp(r?.a)&&hp(r?.b)&&(i&&!i.has(String(r.id||""))||n.push(dp(r.a,r.b,t)));return pp([n])}function fp(e,t=1){const i=[];for(const n of Array.isArray(e?.partitions)?e.partitions:[])0===Number(n?.cm)&&hp(n?.a)&&hp(n?.b)&&i.push(dp(n.a,n.b,t));for(const n of Array.isArray(e?.room_drafts)?e.room_drafts:[]){const e=Array.isArray(n?.points)?n.points:[];for(let r=0;r+1e?.host?.kind===t.kind&&e.host.id===t.id)}const bp=new WeakMap,wp=new WeakMap;function kp(e){const t=Fa(e.cfg),i={};for(const t of e.cfg.spaces||[])for(const e of t.rooms||[])e.area&&(i[e.area]=t.id);const n=e.cfg.settings?.exclude_integrations?new Set(e.cfg.settings.exclude_integrations):Te,r=De(e.cfg.settings?.icon_rules?.length?e.cfg.settings.icon_rules:Ce);return Yh({hass:e.hass,registry:e.registry,areaToSpace:i,markers:e.cfg.markers||[],settings:e.cfg.settings||{},excluded:n,showAll:!!e.cfg.settings?.show_all,firstSpaceId:t[0]?.id||"",loc:t=>du(e.lang,t),iconRules:r})}function xp(e){const t=Fa(e.cfg).find(t=>t.id===e.spaceId);if(!t)return null;const i=nn(e.cfg.spaces.find(t=>t.id===e.spaceId)),n=sn(e.cfg.settings),r=e.iconSize??2.5,o=r>8?2.5:r,s=ip(o),a=e.registry?ih(e.hass,e.registry):e.hass,l=e.registry?nh(e.hass,e.registry):e.hass,c=(e.devices||kp(e)).filter(t=>t.space===e.spaceId),h=c.filter(e=>!e.hidden),d=function(e,t,i){const n={},r=i/100*il(t)*1.3;for(const i of t.rooms){if(!i.area)continue;const t=e.filter(e=>e.area===i.area);if(!t.length)continue;const o=sl(i),s=.1*Math.min(o.w,o.h),a=o.w-2*s,l=o.h-2*s,c=Math.max(1,Math.round(Math.sqrt(t.length*a/Math.max(l,1)))),h=a/c,d=l/Math.max(Math.ceil(t.length/c),1),u=t.map((e,t)=>({x:o.x+s+h*(t%c+.5),y:o.y+s+d*(Math.floor(t/c)+.5)}));Ci(u,o,r,.5*s),t.forEach((e,t)=>n[e.id]=Wa(u[t]))}return n}(c,t,o),u=De(e.cfg.settings?.icon_rules?.length?e.cfg.settings.icon_rules:Ce),p=td(a,u,e.cfg.markers||[]),_=i=>{const n=i.settings?.temp_source;if(n)return Xh(a,n,"temp",e.cfg.markers||[]);const r=Qh(t.id,i);return r?p.get(r)?.temp??null:null},m=[];for(const t of h){const i=e.layout[t.id];if(i&&i.s===e.spaceId){const e=i.x*Ca,t=i.y*Ca;m.push({minX:e,minY:t,maxX:e,maxY:t})}}const f=e.cfg.spaces.find(t=>t.id===e.spaceId)||{},g=Array.isArray(f.walls)?f.walls:[],v=Number(f.cell_cm)>0?Number(f.cell_cm):5,y=vp(f,t,Ca,.02*Na),b=(f.openings||[]).flatMap(e=>{if("partition"!==e.host?.kind)return[];const i=Pd(e,t.partitions,Ca,v,Na).resolved;return i?[i]:[]}),w=zl({partitions:t.partitions,roomDrafts:t.room_drafts,columns:t.wall_columns,cellCm:v,hostedOpenings:b.map(e=>({id:e.opening.id,host:e.host,length:e.length,type:e.opening.type}))}),k=function(e,t,i,n){let r=wp.get(e);r||(r=new Map,wp.set(e,r));const o=r.get(t);if(o?.fingerprint===i)return o.value;const s=n();return r.set(t,{fingerprint:i,value:s}),s}(e.cfg,t.id,w,()=>da(t,v,Na,2e-4*Na,b.map(Id)).all);for(const e of k){const t=e.map(e=>e[0]),i=e.map(e=>e[1]);t.length&&m.push({minX:Math.min(...t),minY:Math.min(...i),maxX:Math.max(...t),maxY:Math.max(...i)})}for(const e of y.lines)m.push({minX:Math.min(e[0],e[2]),minY:Math.min(e[1],e[3]),maxX:Math.max(e[0],e[2]),maxY:Math.max(e[1],e[3])});const x=el(t,m),$=[x.x,x.y,x.w,x.h],S=new Map(t.rooms.map(t=>{const r=Tn(i.fill,t);return[t,ln(r,"lqi"===r&&t.area?id(a,c,t.area):null,"light"===r?Oh(zh(a,c,t,e.virtualLights)):"none","temp"===r?_(t):null,i.tempMin,i.tempMax,n,tn(i.customFill,t))]})),M=new Map;for(const e of t.rooms)e.id&&M.set(e.id,S.get(e)||null);const R=function(e,t=1e3){const i=[];for(const[n,r]of(e||[]).entries()){if("passage"!==r?.type)continue;const e={...r,id:String(r.id||`passage-${n}`),type:"passage",rx:Number(r.x)*t,ry:Number(r.y)*t,rlen:Number(r.length)*t};[e.rx,e.ry,e.rlen,e.angle].every(Number.isFinite)&&e.rlen>0&&i.push(e)}return i}((f.openings||[]).flatMap(e=>{if(!e.host||"wall"===e.host.kind)return[e];const t=b.find(t=>t.opening.id===e.id);return t?[Wd(e,t,Ca)]:[]}),Ca),T=gs(t.rooms,g,y.contour,La,v,Na,Ca),C=b.filter(e=>Ld(e,T,2e-4*Na)).map(e=>({x:e.center[0],y:e.center[1],angle:e.angle,length:e.length})),D=t.rooms.filter(e=>e.area||i.showBorders||"none"!==Tn(i.fill,e)).map(e=>{let n="room "+(t.bg?"overlay":"yard"),r="";const o=Tn(i.fill,e);if(i.showBorders||"none"!==o){n+=" styled";const t=[`--room-stroke:${i.color}`,`--room-stroke-op:${i.showBorders&&!y.contour.length?i.opacity:0}`],o=S.get(e)||null;o?(n+=" filled",t.push(`--room-fill:${o.color}`,`--room-fill-op:${o.opacity.toFixed(3)}`)):t.push("--room-fill:transparent","--room-fill-op:0"),r=t.join(";")}const s=e.id||U,a=e.area||U,l=e.poly?B``:B``;return l}),z=t.rooms.filter(e=>{const t=S.get(e);return Cn(i.glow,e)&&(!t||t.opacity<=0)}).map(e=>e.poly?B``:B``),A=new Map;for(const e of t.rooms)if(e.id){const t=S.get(e)||null;A.set(e.id,Cn(i.glow,e)&&(!t||t.opacity<=0)?{color:n.glow_base.c,opacity:n.glow_base.a,mode:"glow"}:null)}const O=zh(a,h,null,e.virtualLights),P=h.map(n=>{const r=function(e,t,i,n,r){const o=t[e.id];return o&&o.s===e.space?{x:o.x*Ca,y:o.y*Ca}:n[e.id]?n[e.id]:Wa(tl(r))}(n,e.layout,e.cfg,d,t),o=(r.x-$[0])/$[2]*100,s=(r.y-$[1])/$[3]*100,c=i.showLqi??!1!==e.showSignal,u=e.presentations?.get(Xu(n.id,c))||Gu(a,n,{liveStates:!1!==e.liveStates,showTemperature:!1!==e.showTemperature,showSignal:c,activityRuntime:e.activityRuntime?.get(n.id),sourceDetails:!1,lightDevices:h,lightSources:O,registryHass:l,reducedMotion:e.reducedMotion}),p=[`left:${o}%`,`top:${s}%`,...Qu(u)],_=Eu(u),m=[n.name,du(e.lang,`marker.state_a11y_${_}`),"none"!==u.pulse.kind?du(e.lang,`marker.pulse_a11y_${u.pulse.reason}`):"",u.valueFullText||u.valueText||"",fu(u.valueBadge),null!=u.lqiText&&u.lqiBand?du(e.lang,`marker.lqi_a11y_${u.lqiBand}`,{value:u.lqiText}):""].filter(Boolean).join(", ");return j``}),F=i.showNames?t.rooms.filter(e=>e.name).map(n=>{const r=al(n,t.id,e.layout,e.cfg),o=(r.x-$[0])/$[2]*100,s=(r.y-$[1])/$[3]*100,a=Math.min(1,i.opacity+.25);return j`
${n.name}
`}):[],E=t.bg?e.displayUrl?e.displayUrl(t.bg.href):t.bg.href:"",I=e.cfg.spaces.find(t=>t.id===e.spaceId)?.settings||{},H="daynight"===ar(e.cfg?.settings,I)?Zn(a,e.dayCycleNow??new Date):null,N=rn(e.cfg?.settings,i),L=!!(g.length||k.length&&i.showBorders),q=L?zl(R.length?{rooms:t.rooms,walls:g,extras:k,cellCm:v,zero:y.contour,passages:R.map(e=>({x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),hostedCompositeOpenings:C}:{rooms:t.rooms,walls:g,extras:k,cellCm:v,zero:y.contour}):"",W=L?function(e,t,i,n){let r=bp.get(e);r||(r=new Map,bp.set(e,r));const o=r.get(t);if(o?.fingerprint===i)return o.value;const s=n();return r.set(t,{fingerprint:i,value:s}),s}(e.cfg,t.id,q,()=>Ls(t.rooms,g,y.contour,[...R.filter(e=>"partition"!==e.host?.kind).map(e=>({x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),...C],La,v,Na,Ca,k)):null,V=R.length&&g.length?function(e,t,i,n,r,o,s,a=1){return[r,o,s,a].every(Number.isFinite)&&o>0&&a>0&&i?.length?Xs(Bs(e,i,n,r,o,s,a),t):t.map(()=>null)}(t.rooms,R.map(e=>({x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),g,y.contour,La,v,Na,Ca):R.map(()=>null),G=R.length?np({openings:R,geometries:V,fillsByRoomId:M,idPrefix:`${t.id}-static-data`,groupClass:"opening-tunnels static-opening-tunnels",dataLayer:"data"}):U,K=R.length?np({openings:R,geometries:V,fillsByRoomId:A,idPrefix:`${t.id}-static-glow`,groupClass:"opening-tunnels glow-base-tunnels static-opening-tunnels",dataLayer:"glow-base"}):U,Y=g.length&&W?.paperD?[{path:W.paperD}]:Xt(t.rooms),Z=i.showBorders?W:null,X=e.stageWidth&&$[2]?e.stageWidth/$[2]:1,J=mo(v),Q=!!Z&&(_o(Z.depthUnits,X)||fo(J,X)),ee=i.color||"#607d8b",te=i.hideOpenings?[]:b.map(e=>{const t=e.opening,i="passage"!==t.type&&t.contact?a.states?.[t.contact]:null,n=ii(t.type,i?.state,!!t.invert,i?.attributes?.current_position),r=n>0&&!!t.contact,o="gate"===t.type?!t.flip_v:!!t.flip_v,s={type:t.type,length:e.length,angle:e.angle,amount:n,flipH:!!t.flip_h,flipV:!!t.flip_v,base:ee,tone:r?"var(--hp-open)":ee,cellCm:v,gridPitch:Na,face:Hd(e,o)};return B` + ${_u(s)} + `});return j` +
+ ${ur(H)} + + ${Z?B` + + + + `:U} + ${Y.map(e=>"path"in e?B``:"poly"in e?B``:B``)} + ${E?B`e.assetLoaded?.(t.bg.href,E)} + transform=${t.bg.angle?`rotate(${t.bg.angle} ${t.bg.x+t.bg.w/2} ${t.bg.y+t.bg.h/2})`:U} + preserveAspectRatio="none" />`:U} + ${D} + ${i.showBorders&&y.contour.length?B``:U} + ${G} + ${z.length?B``:U} + ${K} + ${Z?B` + ${Z.paths.map(e=>B` + + `)} + `:U} + ${i.showBorders&&y.lines.length?B``:U} + ${te} + + ${""} +
${P}${F}
+
+ `}let $p=null,Sp=null,Mp=0,Rp=-1,Tp=null,Cp=[];const Dp=new Set,zp=(e,t)=>{"function"==typeof e&&t.push(e)};function Ap(){if($p)return $p;try{const e=JSON.parse(localStorage.getItem("houseplan_card_cfg_v1")||"null");if(e&&e.config&&Array.isArray(e.config.spaces)){const t=e.layout||{};return{config:e.config,rev:e.rev||0,configFingerprint:e.config_fingerprint||zl(e.config),layout:t,layoutRev:e.layout_rev||0,layoutFingerprint:e.layout_fingerprint||zl(t),virtualLights:Pc(e.virtual_lights,e.rev||0)}}}catch{}return null}function Op(e,t=!1){if(t&&($p=null,Mp++,Sp))return Sp.catch(()=>null).then(()=>Op(e,!1));if($p)return Promise.resolve($p);if(Sp)return Rp!==Mp?Sp.catch(()=>null).then(()=>Op(e,!1)):Sp;return Rp=Mp,Sp=async function(e,t){const[i,n]=await Promise.all([e.callWS({type:"houseplan/config/get"}),e.callWS({type:"houseplan/layout/get"})]),r=i?.rev??0,o=$p?Fc($p.virtualLights,i?.virtual_lights,r,!!i&&"virtual_lights"in i):Pc(i?.virtual_lights,r),s={config:i?.config??null,rev:r,configFingerprint:zl(i?.config??null),layout:n?.layout??{},layoutRev:n?.rev??0,layoutFingerprint:zl(n?.layout??{}),virtualLights:o};t===Mp&&($p=s);const a=e.connection;if(a?.subscribeEvents&&Tp!==a){for(const e of Cp)e();Cp=[],Tp=a;const e=()=>{$p=null,Mp++,Dp.forEach(e=>e())},t=[];try{if(zp(await a.subscribeEvents(e,"houseplan_config_updated"),t),zp(await a.subscribeEvents(e,"houseplan_layout_updated"),t),zp(await a.subscribeEvents(e=>{if($p){const t=Lc($p.virtualLights,e?.data);if(t===$p.virtualLights)return;$p={...$p,virtualLights:t}}else Mp++;Dp.forEach(e=>e())},"houseplan_virtual_light_updated"),t),Tp===a)Cp=t;else for(const e of t)e()}catch{for(const e of t)e();Tp===a&&(Tp=null)}}return s}(e,Mp).finally(()=>{Sp=null,Rp=-1}),Sp}const Pp=3300;function Fp(e,t){return{sources:e,last:Object.fromEntries(t.map(e=>[e.eid,e.state])),flashTs:0,flashKind:null,timer:0,gen:0,expiresAt:0,alarmActive:"alarm"===Dc(t).status}}function Ep(e,t,i,n){n(e.timer);const r=Fp(t,i);Object.assign(e,r)}function Ip(e,t,i,n,r){e.flashTs&&i-e.flashTs"transition"===e.activity)&&(i(e.timer),e.flashTs=0,e.flashKind=null,e.expiresAt=0);if("alarm"===Dc(t).status){e.alarmActive||(i(e.timer),e.flashTs=0,e.flashKind=null,e.expiresAt=0);for(const i of t)e.last[i.eid]=i.state;return e.alarmActive=!0,null}if(e.alarmActive){for(const i of t)e.last[i.eid]=i.state;return e.alarmActive=!1,null}let n=null;for(const i of t){const t=zc(e.last[i.eid],i);("event"===t||!n&&t)&&(n=t),e.last[i.eid]=i.state}return n}class Np{constructor(e,t=()=>{}){this._host=e,this._onGateChange=t,this._modality="unknown",this._gate=!1,this._media=null,this._connected=!1,this._onMediaChange=()=>this._syncGate()}get modality(){return this._modality}get hoverEnabled(){return this._gate}connect(e=globalThis.window){this._connected||(this._connected=!0,this._modality="unknown",this._media="function"==typeof e?.matchMedia?e.matchMedia("(any-hover: hover) and (any-pointer: fine)"):null,this._media?.addEventListener?.("change",this._onMediaChange),this._setGate(!1))}disconnect(){this._media?.removeEventListener?.("change",this._onMediaChange),this._media=null,this._connected=!1,this._modality="unknown",this._setGate(!1)}note(e){return this._modality=function(e,t){const i="mouse"===(n=t.pointerType)||"touch"===n||"pen"===n?n:null;var n;return i?"mouse"===i&&t.sourceCapabilities?.firesTouchEvents?e:i:e}(this._modality,e),this._syncGate(),this._modality}suspend(){this._setGate(!1)}_syncGate(){var e,t;this._setGate((e=this._modality,t=!!this._media?.matches,"mouse"===e&&t))}_setGate(e){this._gate!==e&&(this._gate=e,this._host.toggleAttribute("data-pointer-hover",e),this._onGateChange(e))}}class Lp extends he{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id}))}catch{this._spaces=[]}finally{this._spacesLoading=!1}}}get _lang(){return hu(this.hass,this._config?.language)}get _schema(){const e=this._spaces||[];return[e.length?{name:"space",selector:{select:{mode:"dropdown",options:e}}}:{name:"space",selector:{text:{}}},{name:"title",selector:{text:{}}},{name:"show_button",selector:{boolean:{}}},{name:"button_label",selector:{text:{}}},{name:"button_target",selector:{text:{}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}}]}render(){if(!this.hass||!this._config)return U;const e=Qd(this,ru,hu(this.hass,this._config.language));if("cold"===e)return eu();if("warm"===e)return V;this._loadSpaces();const t=this._lang,i={space:du(t,"editor.space"),title:du(t,"editor.title"),show_button:du(t,"editor.show_button"),button_label:du(t,"editor.button_label"),button_target:du(t,"editor.button_target"),icon_size:du(t,"editor.icon_size"),show_temperature:du(t,"editor.show_temperature"),live_states:du(t,"editor.live_states"),show_signal:du(t,"editor.show_signal")};return j`i[e.name]||e.name} + @value-changed=${this._valueChanged} + >`}_valueChanged(e){const t={...this._config||{},...e.detail.value};delete t.aspect_ratio;const i=new Event("config-changed",{bubbles:!0,composed:!0});i.detail={config:t},this.dispatchEvent(i)}}Lp.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-space-card-editor")||customElements.define("houseplan-space-card-editor",Lp);const qp=e=>{history.pushState(null,"",e),((e,t,i)=>{const n=new Event(t,{bubbles:!0,composed:!0});n.detail=i??{},e.dispatchEvent(n)})(window,"location-changed",{replace:!1})};class Wp extends he{constructor(){super(...arguments),this._snap=null,this._loading=!1,this._reloadQueued=!1,this._forceReloadQueued=!1,this._reloadRetryTimer=0,this._dayCycleTimer=0,this._dayCycleClockKey="",this._stageWidth=0,this._pendingStageWidth=0,this._stageWidthRaf=0,this._haRegistryConnection=null,this._haRegistryRevision=-1,this._devices=[],this._continuity=this._newContinuityController(),this._continuityHistory=[],this._continuityEpoch=0,this._continuityDataReady=!0,this._continuityPaintToken=-1,this._continuityDisposed=!1,this._renderSnapshotAt=Date.now(),this._hassSequence=0,this._connHooked=null,this._connectionWasLost=!1,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotSequence=-1,this._capturedSnapshotDevices=null,this._capturedSnapshotActivity="",this._capturedSnapshotVirtual="",this._activityRuntime=new Map,this._reducedMotion=!1,this._pointerModality=new Np(this),this._onMotionChange=e=>{this._reducedMotion=e.matches,this._capturedSnapshotSequence=-1,this.requestUpdate()},this._onHaRegistryUpdate=()=>{const e=Jc(this.hass).revision;e!==this._haRegistryRevision&&(this._haRegistryRevision=e,this._refreshDevices(),this._capturedSnapshotSequence=-1,this.requestUpdate())},this._dayCycleTick=()=>{if(!this.isConnected||"hidden"===this.ownerDocument.visibilityState)return;const e=this._dayCycleState();if(!e)return this._dayCycleTimer&&(window.clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),void(this._dayCycleClockKey="");const t=Xn(e);t!==this._dayCycleClockKey&&(this._dayCycleClockKey=t,this.requestUpdate())},this._pageVisibility=e=>{if(this._continuity.visibility(e),this._dayCycleVisibility(e),"hidden"!==e.kind){if(!e.long){const e=Date.now();let t=!1;for(const i of this._activityRuntime.values())!i.flashKind||(i.expiresAt||i.flashTs+3300)>e||(i.flashTs=0,i.flashKind=null,i.expiresAt=0,t=!0);return void(t&&(this._capturedSnapshotSequence=-1,this.requestUpdate()))}Date.now()-this._renderSnapshotAt>1e3&&this._continuity.note("device-snapshot-stale"),this._continuityDataReady=!1,this._continuityPaintToken=-1,this._load(!0)}else this._pointerModality.suspend()},this._onConnLost=()=>{this._connectionWasLost=!0,this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.connectionLost()},this._onConnReady=()=>{!this._connectionWasLost&&this._continuity.hasCompleteFrame?this._beginContinuityCandidate("connection-ready",!1,"plan"):(this._continuityDataReady=!1,this._continuityPaintToken=-1),this._load(!0)},this._onAssetLoaded=(e,t)=>{this._signer.markLoaded(this.hass,e,t),this._continuity.note("asset-ready"),this._continuityPaintToken=-1,"steady"!==this._continuity.state&&this.requestUpdate()},this._loadedOnce=!1,this._signer=new Pl(()=>this.requestUpdate()),this._retryContinuity=()=>{this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.retry(this._continuity.recoveryReason||"plan"),this._load(!0)},this._goToSpace=()=>{const e=(this._config?.button_target||"/plan-doma").replace(/#.*$/,"");qp(`${e}#space=${encodeURIComponent(this._config.space)}`)}}_ensureHaRegistryAuthority(){const e=this.hass?.connection||null;e&&e!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=e,this._haRegistryRevision=-1,this._haRegistryRelease=Xc(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}_newContinuityController(){return new Dl(()=>{this._continuityEpoch++,this.isConnected&&this.requestUpdate()})}_dayCycleState(e=new Date){const t=this._snap?.config;if(!t||!this._config)return null;const i=t.spaces?.find(e=>e.id===this._config?.space)?.settings||{};return"daynight"!==ar(t.settings,i)?null:Zn(this._renderDeviceSnapshot?.hass||this.hass,e)}_syncDayCycleClock(){const e=this._dayCycleState();this._dayCycleClockKey=e?Xn(e):"";const t="clock"===e?.source&&"hidden"!==this.ownerDocument.visibilityState&&this.isConnected;t&&!this._dayCycleTimer?this._dayCycleTimer=window.setInterval(this._dayCycleTick,3e4):!t&&this._dayCycleTimer&&(window.clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_dayCycleVisibility(e){"hidden"!==e.kind?(this._dayCycleTick(),this._syncDayCycleClock()):this._dayCycleTimer&&(window.clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_hookConnection(){const e=this.hass?.connection;e&&e!==this._connHooked&&(this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),e.addEventListener?.("ready",this._onConnReady),e.addEventListener?.("disconnected",this._onConnLost),e.addEventListener?.("reconnect-error",this._onConnLost),this._connHooked=e)}static getConfigElement(){return document.createElement("houseplan-space-card-editor")}static getStubConfig(e){const t=Ap();return{type:"custom:houseplan-space-card",space:Fa(t?.config||null)[0]?.id||"",show_button:!0,live_states:!0,show_temperature:!0,show_signal:!0}}setConfig(e){if(!e||!e.space)throw new Error('houseplan-space-card: "space" is required');this._config={show_button:!0,button_target:"/plan-doma",live_states:!0,show_temperature:!0,show_signal:!0,...e},this._snap=this._snap||Ap()}connectedCallback(){var e;this._continuityDisposed&&(this._continuity=this._newContinuityController(),this._continuityDisposed=!1,this._continuityPaintToken=-1),super.connectedCallback(),this._pointerModality.connect(this.ownerDocument.defaultView),this._motionMedia=window.matchMedia?.("(prefers-reduced-motion: reduce)"),this._reducedMotion=!!this._motionMedia?.matches,this._motionMedia?.addEventListener?.("change",this._onMotionChange),this.hass&&this._ensureHaRegistryAuthority(),this._continuityUnsub?.(),this._continuityUnsub=Tl(this.ownerDocument,this._pageVisibility),this._unsub=(e=()=>{this._beginContinuityCandidate("config-event",!1),this._reloadQueued=!0,this._load()},Dp.add(e),()=>Dp.delete(e)),this._signer.start(()=>this.hass,()=>this._referenced())}disconnectedCallback(){this._pointerModality.disconnect(),this._continuityUnsub?.(),this._continuityUnsub=void 0,this._motionMedia?.removeEventListener?.("change",this._onMotionChange),this._motionMedia=void 0,this._unsub?.(),this._unsub=void 0,window.clearTimeout(this._reloadRetryTimer),this._reloadRetryTimer=0,this._dayCycleTimer&&(window.clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),this._dayCycleClockKey="",this._stageObserver?.disconnect(),this._stageObserver=void 0,this._observedStage=void 0,this._stageWidthRaf&&cancelAnimationFrame(this._stageWidthRaf),this._stageWidthRaf=0,this._pendingStageWidth=0,this._signer.dispose(),this._haRegistryRelease?.(),this._haRegistryRelease=void 0,this._haRegistryConnection=null,this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),this._connHooked=null;for(const e of this._activityRuntime.values())window.clearTimeout(e.timer);this._activityRuntime.clear(),this._continuityHistory=[...this._continuityHistory,...this._continuity.trace].slice(-80),this._continuity.dispose(),this._continuityDisposed=!0,super.disconnectedCallback()}willUpdate(e){e.has("hass")&&this.hass&&(this._hassSequence++,this._renderSnapshotAt=Date.now(),this._continuity.note("hass-snapshot"),this._ensureHaRegistryAuthority(),this._hookConnection()),!this.hass||this._loading||this._snap&&!e.has("hass")||this._snap&&this._loadedOnce||this._load(),(e.has("hass")||e.has("_snap")||e.has("_config")||!this._devices.length)&&this._refreshDevices(),this._captureRenderDeviceSnapshot(),this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._continuity.refreshCompleteFrame(this._frameFingerprint())}_stampActivity(e,t){Ip(e,t,Date.now(),window.clearTimeout.bind(window),e=>window.setTimeout(()=>this.requestUpdate(),e))}_syncActivity(e,t,i=this.hass){if(!1===this._config?.live_states){for(const e of this._activityRuntime.values())window.clearTimeout(e.timer);return void this._activityRuntime.clear()}const n=new Set,r=zh(t,e,null,this._snap?.virtualLights);for(const o of e){if(o.hidden)continue;if("icon_ripple"!==Ai(o.marker?.display))continue;n.add(o.id);const s=Wu(t,o,e,r,i),a=s.samples,l=Vu(t,o,s);let c=this._activityRuntime.get(o.id);if(!c||c.sources!==l){c&&window.clearTimeout(c.timer),c=Fp(l,a),this._activityRuntime.set(o.id,c);continue}const h=Hp(c,a,window.clearTimeout.bind(window));h&&this._stampActivity(c,h)}for(const[e,t]of this._activityRuntime)n.has(e)||(window.clearTimeout(t.timer),this._activityRuntime.delete(e))}_refreshDevices(){if(!this.hass||!this._snap?.config||!this._config)return;const e=Jc(this.hass),t=kp({hass:this.hass,registry:e,cfg:this._snap.config,lang:this._lang});this._syncActivity(t,ih(this.hass,e),this.hass),this._devices=t}_captureRenderDeviceSnapshot(){if(!this.hass)return;const e=Date.now(),t=[...this._activityRuntime.entries()].map(([t,i])=>`${t}:${i.gen}:${i.flashTs}:`+(i.flashKind&&(i.expiresAt||i.flashTs+3300)>e?1:0)).join("|"),i=this._snap?.virtualLights?`${this._snap.virtualLights.configRev}:${this._snap.virtualLights.rev}`:"";if(this._capturedSnapshotSequence===this._hassSequence&&this._capturedSnapshotDevices===this._devices&&this._capturedSnapshotActivity===t&&this._capturedSnapshotVirtual===i)return;const n=ih(this.hass,Jc(this.hass)),r=new Map,o=new Set(["sun.sun"]),s=new Set,a=new Set,l=e=>{if(!e)return;const t=e.indexOf(":");if(t<0)return void o.add(e);const i=e.slice(0,t),n=e.slice(t+1);"device"===i?s.add(n):"entity"===i&&o.add(n)},c=Fa(this._snap?.config||null).find(e=>e.id===this._config?.space);for(const e of c?.rooms||[])e.area&&a.add(e.area),l(e.settings?.temp_source),l(e.settings?.hum_source);const h=this._snap?.config?.spaces?.find(e=>e.id===this._config?.space);for(const e of h?.openings||[])for(const t of ri(e))o.add(t);const d=zh(n,this._devices,null,this._snap?.virtualLights);for(const e of this._devices)for(const t of[!1,!0])r.set(Xu(e.id,t),Gu(n,e,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:t,activityRuntime:this._activityRuntime.get(e.id),sourceDetails:!1,lightDevices:this._devices,lightSources:d,registryHass:this.hass,reducedMotion:this._reducedMotion}));const u=Zu({sourceSequence:this._hassSequence,hass:n,devices:this._devices,presentations:r,entityIds:o,deviceIds:s,areaIds:a});this._capturedSnapshotSequence=this._hassSequence,this._capturedSnapshotDevices=this._devices,this._capturedSnapshotActivity=t,this._capturedSnapshotVirtual=i,this._visibleDeviceSnapshot&&"steady"!==this._continuity.state?this._candidateDeviceSnapshot=u:(this._visibleDeviceSnapshot=u,this._candidateDeviceSnapshot=null)}get _renderDeviceSnapshot(){return this._stagedDeviceSnapshotToken===this._continuity.token?this._candidateDeviceSnapshot||this._visibleDeviceSnapshot:this._visibleDeviceSnapshot||this._candidateDeviceSnapshot}_beginContinuityCandidate(e,t,i="plan"){return this._continuityDataReady=t,this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._continuity.beginCandidate(e,i)}_backdropRaw(){return this._snap?.config&&this._config&&Fa(this._snap.config).find(e=>e.id===this._config.space)?.bg?.href||""}_candidateBackdrop(e){return e&&this._config&&Fa(e).find(e=>e.id===this._config.space)?.bg?.href||""}_assetsReady(){const e=this._backdropRaw();return!e||this._signer.isReady(this.hass,e)}_frameFingerprint(){const e=this._snap;return Al([e?.rev||0,e?.configFingerprint||zl(e?.config),e?.layoutRev||0,e?.layoutFingerprint||zl(e?.layout),e?.virtualLights?`${e.virtualLights.configRev}:${e.virtualLights.rev}`:"",this._config?.space||"",this._stageWidth,this.hass?.themes?.darkMode??this.hass?.themes?.default_theme??""])}_stageValid(){const e=this._observedStage;return!!e&&e.clientWidth>0&&e.clientHeight>0}_settleContinuityFrame(){if(!this._stageValid())return;if(!this._continuity.hasCompleteFrame&&"steady"===this._continuity.state){if(this._assetsReady())return this._renderSnapshotAt=Date.now(),void this._continuity.markCompleteFrame(this._frameFingerprint());this._beginContinuityCandidate("asset-wait",!0,"asset")}if(!this._continuityDataReady)return;if(!["holding","offline-stale","overlay-pending","overlay-visible","candidate-ready"].includes(this._continuity.state))return;const e=this._continuity.token;if(this._candidateDeviceSnapshot&&this._candidateDeviceSnapshot!==this._visibleDeviceSnapshot&&this._stagedDeviceSnapshotToken!==e)return this._stagedDeviceSnapshotToken=e,void this.requestUpdate();this._continuityPaintToken!==e&&(this._continuityPaintToken=e,this._continuity.candidateReady(e)&&this._continuity.commitAfterPaint(e,{updateComplete:()=>this.updateComplete,stageValid:()=>this.isConnected&&this._stageValid(),assetsReady:()=>this._assetsReady(),frameFingerprint:()=>this._frameFingerprint()}).then(t=>{t&&e===this._continuity.token?(this._renderSnapshotAt=Date.now(),this._candidateDeviceSnapshot&&(this._visibleDeviceSnapshot=this._candidateDeviceSnapshot),this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1):e===this._continuity.token&&(this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._candidateDeviceSnapshot=null,this.requestUpdate())}))}updated(){const e=this.renderRoot.querySelector(".hp-static-stage")||void 0;if(e!==this._observedStage)if(this._stageObserver?.disconnect(),this._observedStage=e,e){const t=()=>{const i=e.clientWidth;if(!(i<=0||Math.abs(i-this._stageWidth)<=.5)){if(this._stageWidth<=0)return this._stageWidth=i,void this.requestUpdate();this._pendingStageWidth=i,this._stageWidthRaf||(this._stageWidthRaf=requestAnimationFrame(()=>{this._stageWidthRaf=0;const e=this._pendingStageWidth;this._pendingStageWidth=0,!e||!this._observedStage||this._observedStage.clientWidth<=0||(Math.abs(this._observedStage.clientWidth-e)>.5?t():Math.abs(e-this._stageWidth)<=.5||(this._continuity.hasCompleteFrame&&this._beginContinuityCandidate("stage-resize",!0,"stage-size"),this._stageWidth=e,this.requestUpdate()))}))}};this._stageObserver=new ResizeObserver(t),this._stageObserver.observe(e),t()}else this._stageObserver=void 0;this._syncDayCycleClock(),this._settleContinuityFrame()}async _load(e=!1){if(this.hass){if(this._loading)return this._reloadQueued=!0,void(this._forceReloadQueued||=e);this._loading=!0,this._reloadQueued=!1;try{const t=await Op(this.hass,e),i=!this._snap||this._snap.configFingerprint!==t.configFingerprint,n=!this._snap||this._snap.layoutFingerprint!==t.layoutFingerprint,r=!this._snap||this._snap.virtualLights!==t.virtualLights;if(i&&!await this._signer.prepareImage(this.hass,this._candidateBackdrop(t.config)))return this._continuity.note("asset-failed"),window.clearTimeout(this._reloadRetryTimer),void(this._reloadRetryTimer=window.setTimeout(()=>{this._load(!0)},1e3));window.clearTimeout(this._reloadRetryTimer),this._reloadRetryTimer=0,(i||n)&&this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._beginContinuityCandidate("structural-response",!0),i||n||r?this._snap=t:this._snap&&(this._snap.rev=t.rev,this._snap.layoutRev=t.layoutRev),i&&this._continuity.note("config-candidate",{configRev:t.rev}),n&&this._continuity.note("layout-candidate",{layoutRev:t.layoutRev}),r&&(this._capturedSnapshotSequence=-1),this._loadedOnce=!0,this._connectionWasLost=!1,this._continuityDataReady=!0,this._refreshDevices()}catch{}finally{if(this._loading=!1,this._continuityDataReady=!0,this.requestUpdate(),this._reloadQueued){const e=this._forceReloadQueued;this._reloadQueued=!1,this._forceReloadQueued=!1,this._load(e)}}}}get _lang(){return hu(this.hass,this._config?.language)}getCardSize(){const e=Fa(this._snap?.config||null).find(e=>e.id===this._config?.space);if(e){const t=e.vb[3]/e.vb[2];return Math.max(3,Math.round(8*t))+(!1===this._config?.show_button?0:1)}return 6}_errorCard(e){return j` +
${e}
+
`}_referenced(){return Mn(this._snap?.config)}_renderRecoveryOverlay(){if(!this._continuity.overlayVisible&&"recovery-error"!==this._continuity.state)return U;const e="connection"===this._continuity.recoveryReason;return j`
+ + ${du(this._lang,e?"continuity.restore_connection":"continuity.restore_plan")} + ${"recovery-error"===this._continuity.state?j``:U} +
`}houseplanContinuityTrace(){return[...this._continuityHistory,...this._continuity.trace].slice(-80).map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}render(){if(!this._config||!this.hass)return U;const e=Qd(this,ru,hu(this.hass,this._config.language));if("cold"===e)return eu();if("warm"===e)return V;const t=this._snap?.config;if(!t)return this._errorCard(du(this._lang,"space_card.loading"));const i=this._config.space,n=this._renderDeviceSnapshot,r=xp({hass:n?.hass||this.hass,cfg:t,layout:this._snap?.layout||{},spaceId:i,iconSize:this._config.icon_size,stageWidth:this._stageWidth,lang:this._lang,displayUrl:e=>this._signer.display(this.hass,e),assetLoaded:this._onAssetLoaded,registry:n?{revision:n.sourceSequence,authoritative:!1,access:"limited",entities:{...n.hass.entities},devices:{...n.hass.devices},lastSuccess:n.capturedAt}:Jc(this.hass),devices:[...n?.devices||this._devices],presentations:n?.presentations,activityRuntime:this._activityRuntime,reducedMotion:this._reducedMotion,virtualLights:this._snap?.virtualLights,liveStates:!1!==this._config.live_states,showTemperature:!1!==this._config.show_temperature,showSignal:!1!==this._config.show_signal,inert:this._continuity.overlayBlocksInteraction});if(!r)return this._errorCard(du(this._lang,"space_card.not_found",{id:i}));const o=Fa(t).find(e=>e.id===i),s=void 0!==this._config.title?this._config.title:o?.title||"",a=!1!==this._config.show_button,l=this._config.button_label||du(this._lang,"space_card.button"),c=this._continuity.overlayVisible||"recovery-error"===this._continuity.state?this._continuity.recoveryReason:null;return j` + this._pointerModality.note(e)} + @pointerdown=${e=>this._pointerModality.note(e)} + @pointermove=${e=>this._pointerModality.note(e)}> + ${s?j`
${s}
`:U} +
+ ${r} + ${this._renderRecoveryOverlay()} +
+ ${a?j`
+ +
`:U} +
+ `}}Wp.properties={hass:{attribute:!1},_config:{state:!0},_snap:{state:!0},_continuityEpoch:{state:!0}},Wp.styles=[Yd,o` + .hp-static-title { + font-weight: 700; + padding: 10px 14px 6px; + font-size: 16px; + color: var(--primary-text-color); + } + .hp-static-body { + position: relative; + } + .hp-static-stage { + position: relative; + width: 100%; + container-type: inline-size; + overflow: hidden; + pointer-events: none; /* kill ALL interaction on the schematic (§4) */ + background: var(--ha-card-background, var(--card-background-color, #111)); + } + .hp-static-stage svg { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + display: block; + z-index: 1; + } + /* Opaque plan paper — the scene bg_color/day-cycle environment shows only AROUND + the plan (owner 2026-08-03). The static card keeps its historical + canvas colour: the theme card background. Drawn plans paper the room + contours (per-room shapes, fill only, no stroke) — same contract as + the full card. */ + .hp-paper { + fill: var(--ha-card-background, var(--card-background-color, #111)); + stroke: none; + } + .wallbody-fill { + fill: var(--wall-fill, #ffffff); + fill-opacity: var(--wall-fill-op, 1); + fill-rule: evenodd; + stroke: none; + pointer-events: none; + } + .wallbody { + fill: url(#hp-wall-hatch); + fill-rule: evenodd; + stroke: var(--room-stroke, var(--hp-muted, #607d8b)); + stroke-width: calc(0.6px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + .wallbody.solid { + fill: none; + } + .hp-static-stage .devlayer { + position: absolute; + inset: 0; + z-index: 2; + } + .hp-static-foot { + padding: 8px 12px 12px; + pointer-events: auto; /* the button stays clickable */ + } + .hp-static-btn { + width: 100%; + padding: 9px 14px; + border: none; + border-radius: 10px; + background: var(--primary-color, #3ea6ff); + color: var(--text-primary-color, #fff); + font-size: 14px; + font-weight: 600; + cursor: pointer; + } + :host([data-pointer-hover]) .hp-static-btn:hover { + filter: brightness(1.08); + } + .hp-static-error { + padding: 24px; + text-align: center; + color: var(--secondary-text-color, #9aa4ad); + } + `],customElements.get("houseplan-space-card")||customElements.define("houseplan-space-card",Wp),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 jp=o` + :host { + --hp-editor-tray-bg-fallback: color-mix(in srgb, var(--card-background-color, var(--hp-bg)) 94%, var(--hp-line)); + --hp-editor-tray-bg: color-mix(in srgb, var(--card-background-color, var(--hp-bg)) 86%, transparent); + --hp-editor-tray-border: color-mix(in srgb, var(--hp-line) 82%, var(--hp-accent)); + --hp-editor-tray-blur: 8px; + --hp-editor-tray-shadow: var(--shadow-2); + } + + /* Contextual editor controls float over the stage. Their appearance must + never alter stage height, viewport fitting or the pinned close action. */ + .editor-secondary-host { + position: absolute; + inset: var(--sp-2) var(--sp-4) auto; + z-index: 70; + display: flex; + justify-content: flex-end; + pointer-events: none; + } + .editor-secondary-host.kind-palette, + .editor-secondary-host.kind-group { + justify-content: flex-start; + } + .editor-secondary { + pointer-events: none; + max-width: 100%; + display: flex; + align-items: center; + gap: var(--sp-3); + padding: var(--sp-3) var(--sp-4); + color: var(--hp-txt); + background: var(--card-background-color, var(--hp-bg)); + background: var(--hp-editor-tray-bg-fallback); + border: 1px solid var(--hp-line); + border-color: var(--hp-editor-tray-border); + border-radius: var(--rad-l); + box-shadow: var(--hp-editor-tray-shadow); + opacity: 0; + visibility: hidden; + transform: translateY(-4px); + transition: + opacity 0.1s ease, + transform 0.1s cubic-bezier(0.2, 0.7, 0.2, 1), + visibility 0s linear 0.1s; + touch-action: auto; + } + .editor-secondary-host.open .editor-secondary { + pointer-events: auto; + opacity: 1; + visibility: visible; + transform: translateY(0); + transition-duration: 0.14s, 0.14s, 0s; + transition-delay: 0s; + } + .editor-secondary-host.blocked .editor-secondary { pointer-events: none; } + @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { + .editor-secondary { + background: var(--hp-editor-tray-bg); + -webkit-backdrop-filter: blur(var(--hp-editor-tray-blur)); + backdrop-filter: blur(var(--hp-editor-tray-blur)); + } + } + .editor-secondary-content, + .editor-group-items { + display: flex; + align-items: center; + gap: var(--sp-3); + min-width: 0; + } + .editor-context-label { + max-width: 14rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + padding-inline-end: var(--sp-4); + border-inline-end: 1px solid var(--hp-line); + color: var(--hp-muted); + font-size: var(--fs-s); + } + .editor-secondary.kind-palette { + width: min(760px, 100%); + align-items: stretch; + padding: 0; + overflow: hidden; + } + .editor-secondary.kind-palette .editor-secondary-content, + .editor-secondary.kind-palette .furnpalette { + width: 100%; + } + .editor-secondary.kind-palette .furnpalette { + max-height: 38vh; + border: 0; + background: transparent; + } + .editor-group-launcher .group-chevron { + --mdc-icon-size: 16px; + transition: transform 0.14s ease; + } + .editor-group-launcher[aria-expanded="true"] .group-chevron { transform: rotate(180deg); } + + .editor-secondary .bdhint { + font-size: var(--fs-s); + color: var(--hp-muted); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .editor-secondary .dfill { + display: inline-flex; + align-items: center; + gap: var(--sp-2); + font-size: var(--fs-s); + cursor: pointer; + } + .editor-secondary .dfill input[type="checkbox"] { + width: 16px; + height: 16px; + flex: none; + margin: 0; + padding: 0; + } + .editor-secondary hp-color-opacity { flex: 0 0 auto; } + .editor-secondary input { + width: 74px; + background: transparent; + border: 1px solid var(--hp-line); + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + font-size: var(--fs-m); + } + .editor-secondary label, + .editor-secondary .hint { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .editor-secondary .drawwall { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + white-space: nowrap; + } + .editor-secondary .drawwall input { width: 4.2em; } + .editor-secondary .drawwall .opl { + color: var(--hp-muted); + font-size: var(--fs-s); + } + + @container (min-width: 560px) and (max-width: 899px) { + .editor-secondary-content, + .editor-group-items { + flex-wrap: wrap; + justify-content: flex-end; + } + } + @container (max-width: 559px) { + .editor-secondary-host { inset-inline: var(--sp-4); } + .editor-secondary { max-width: 100%; } + .editor-secondary-content, + .editor-group-items { + overflow-x: auto; + scrollbar-width: thin; + } + .editor-secondary-content > *, + .editor-group-items > * { flex: none; } + .editor-context-label { display: none; } + } + @media (prefers-reduced-motion: reduce) { + .editor-secondary { transition: none; } + .editor-group-launcher .group-chevron { transition: none; } + } +`;function Bp(e){return e instanceof Error?e.name||"Error":typeof e}function Vp(e){return zl({id:e?.id??"",cell_cm:e?.cell_cm,rooms:e?.rooms||[],walls:e?.walls||[],wall_segments:e?.wall_segments||[],open_spans:e?.open_spans||[],openings:e?.openings||[],partitions:e?.partitions||[],room_drafts:e?.room_drafts||[],wall_columns:e?.wall_columns||[]})}function Up(e,t,i={}){const n=(Array.isArray(e?.spaces)?e.spaces:[]).find(e=>String(e?.id||"")===String(t||"")),r=Vp(n);if(!n)return{spaceId:String(t||""),displayName:"",status:"failed",reason:"prepare-exception",fingerprint:r,ok:!1};const o=Jp({...e,spaces:[n]},{...i,fingerprint:()=>r}).spaces[0]||{spaceId:String(t||""),displayName:"",status:"failed",reason:"prepare-exception"};return{...o,fingerprint:r,ok:"failed"!==o.status}}function Gp(e,t,i,n=Na,r=1e3){return(Array.isArray(e?.openings)?e.openings:[]).flatMap(e=>{const o={...e,rx:Number(e.x)*r,ry:Number(e.y)*r,rlen:Number(e.length)*r};if(!e.host||"wall"===e.host.kind)return[o];const s=Pd(e,t.partitions,r,i,n);return s.resolved?[{...e,rx:s.resolved.center[0],ry:s.resolved.center[1],rlen:s.resolved.length,angle:s.resolved.angle,partitionHost:s.resolved}]:[]})}function Kp(e,t=()=>!0){return e.flatMap(e=>e.host&&e.partitionHost&&t(e)?[Id(e.partitionHost)]:[])}function Yp(e,t,i,n,r,o,s=Na,a=1e3){const l=gs(t.rooms,[...i],n,r,o,s,a);return e.flatMap(e=>{const t={x:e.rx,y:e.ry,angle:Number(e.angle)||0,length:e.rlen};return e.host&&"wall"!==e.host.kind?e.partitionHost&&Ld(e.partitionHost,l,2e-4*s)?[t]:[]:[t]})}function Zp(e,t){const i=La,n=Na,r=Ca,o=Number.isFinite(Number(t.cellCm))&&Number(t.cellCm)>0?Number(t.cellCm):5,s=Array.isArray(e?.walls)?e.walls:[],a=function(e,t,i=Na,n=1e3){return lp(t.rooms,e?.open_spans,n,.02*i)}(e,t,n,r),l=function(e,t,i=Na){if(!t.length)return[];const n=e.filter(e=>e?.id),r=.02*i,o=[];for(let e=0;e{const t=[(e[0]+e[2])/2,(e[1]+e[3])/2];return h.some(e=>Fn(t,e)<4*r)}).map(e=>[...e]);d.length&&o.push({a:s,b:a,segs:d})}return o}(t.rooms,a,n).flatMap(e=>e.segs),c=Gp(e,t,o,n,r),h=Kp(c),d=da(t,o,n,2e-4*n,h).all;return{space:t,walls:s,openCuts:l,openings:c,roomOpenings:Yp(c,t,s,l,i,o,n,r),partitionCuts:h,physicalBodies:d,wallKeyPitch:i,cellCm:o,gridPitch:n,coordScale:r}}function Xp(e,t,i){const n="string"==typeof e?.title?e.title.trim():"",r=null==e?.id?"":String(e.id).trim();return{spaceId:r,displayName:n||r||i(t+1)}}function Jp(e,t={}){const i=(t.fingerprint||zl)(e),n=Array.isArray(e?.spaces)?e.spaces:[],r=t.fallbackSpaceName||(e=>`Space ${e}`),o=t.prepareSpace||Zp,s=t.wallPass||Ns,a=t.floorPass||Fs,l=[];for(let i=0;i0||d.physicalBodies.length>0;if(!d.space.rooms.length&&!u){l.push({...h,status:"not-applicable"});continue}let p=null;if(u){try{p=s(d.space.rooms,d.walls,d.openCuts,d.roomOpenings,d.wallKeyPitch,d.cellCm,d.gridPitch,d.coordScale,d.physicalBodies)}catch(e){l.push({...h,status:"failed",reason:"wall-exception",detail:Bp(e)});continue}if(null==p){l.push({...h,status:"failed",reason:"wall-null"});continue}if("degraded-extra"===p.status){l.push({...h,status:"failed",reason:"wall-degraded-extra"});continue}if("failed-core"===p.status){l.push({...h,status:"failed",reason:"wall-failed-core"});continue}t.captureWallGeometry?.(d,p)}if(d.space.rooms.length&&null==p?.paperGeom){let e;try{e=a(d.space.rooms,d.walls,d.openCuts,d.wallKeyPitch,d.cellCm,d.gridPitch,d.coordScale)}catch(e){l.push({...h,status:"failed",reason:"floor-exception",detail:Bp(e)});continue}if(null==e){l.push({...h,status:"failed",reason:"floor-null"});continue}}l.push({...h,status:"ok"})}const c=l.filter(e=>"failed"===e.status);return{fingerprint:i,spaces:l,failures:c,ok:0===c.length}}function Qp(e,t){return e.catch(()=>{}).then(t)}class e_{constructor(e=50){this._undo=[],this._redo=[],this._limit=Math.max(30,Math.floor(e))}get canUndo(){return this._undo.length>0}get canRedo(){return this._redo.length>0}get undoName(){return this._undo[this._undo.length-1]?.name??null}get redoName(){return this._redo[this._redo.length-1]?.name??null}get size(){return this._undo.length}push(e){this._undo.push(e),this._undo.length>this._limit&&this._undo.splice(0,this._undo.length-this._limit),this._redo=[]}undo(){const e=this._undo.pop()??null;return e&&this._redo.push(e),e}redo(){const e=this._redo.pop()??null;return e&&this._undo.push(e),e}clear(){this._undo=[],this._redo=[]}}const t_=new WeakMap;const i_=(e,t,i)=>255===e[i+3]&&t.every((t,n)=>Math.abs(e[i+n]-t)<=2);async function n_(e){const t=e.defaultView;if(!t||!t.CSS?.supports?.("mix-blend-mode","screen"))return!1;const i=[128,32,16],n=[16,64,128],r=[9,19,29],o=`\n \n \n \n \n \n `,s=t.URL.createObjectURL(new Blob([o],{type:"image/svg+xml"}));try{const o=await new Promise((e,i)=>{const n=new t.Image,r=t.setTimeout(()=>i(new Error("SVG blend probe timeout")),1e3);n.onload=()=>{t.clearTimeout(r),e(n)},n.onerror=()=>{t.clearTimeout(r),i(new Error("SVG blend probe failed"))},n.src=s}),a=e.createElement("canvas");a.width=4,a.height=1;const l=a.getContext("2d",{willReadFrequently:!0});if(!l)return!1;l.drawImage(o,0,0,4,1);const c=l.getImageData(0,0,4,1).data;return i_(c,i,0)&&i_(c,function(e,t){return[0,1,2].map(i=>Math.round(255-(255-e[i])*(255-t[i])/255))}(i,n),4)&&i_(c,n,8)&&i_(c,r,12)}catch{return!1}finally{t.URL.revokeObjectURL(s)}}const r_={now:()=>performance.now(),requestFrame:e=>requestAnimationFrame(e),cancelFrame:e=>cancelAnimationFrame(e)},o_=e=>Math.max(0,Math.min(1,e)),s_=(e,t,i)=>e+(t-e)*i,a_=(e,t,i)=>{const n=1-e;return 3*n*n*e*t+3*n*e*e*i+e*e*e};function l_(e,t){return{centerX:e.x+e.w/2,centerY:e.y+e.h/2,pixelsPerUnit:t>0&&e.w>0?t/e.w:1,viewBox:{...e}}}function c_(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 h_(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 d_(e,t,i){const n=h_(e),r=h_(t);if(!n||!r)return i<.5?e:t;const o=o_(i);return`rgba(${Math.round(s_(n[0],r[0],o))}, ${Math.round(s_(n[1],r[1],o))}, ${Math.round(s_(n[2],r[2],o))}, ${s_(n[3],r[3],o).toFixed(3)})`}function u_(e,t,i){const n=(e=>{const t=o_(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,a_(r,.2,.2){const t=this._state;if(!t||t.token!==r)return;const i=o_((e-t.startedAt)/t.duration);t.presented=i>=1?t.to:u_(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)}}function __(e,t){return`${e("editor.load_failed")} ${e(t.terminal?"editor.refresh_advice":"editor.retry_advice")}`}class m_ extends Error{}class f_{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 m_(`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 m_&&(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 g_="houseplan_card_labs_v1",v_=Object.freeze([Object.freeze({id:"iso",issue:89,since:"1.62.0",expires:"1.65.0",summary:"Volumetric plan renderer"})]);function y_(e){const t=/^(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?$/.exec(String(e||"").trim());if(!t)return null;const i=t.slice(1).map(Number);return i.every(e=>Number.isSafeInteger(e))?i:null}function b_(e,t){for(let i=0;i<3;i++)if(e[i]!==t[i])return e[i]e.split(",")).map(e=>e.trim()).filter(Boolean)}function M_(e,t,i,n=v_){const r=function(e,t=v_){const i=y_(e),n=new Map;if(!i||!k_(t))return n;for(const e of t){const t=y_(e.since),r=y_(e.expires);b_(i,t)>=0&&b_(i,r)<0&&n.set(e.id,e)}return n}(i,n),o=new Set(k_(n)?n.map(e=>e.id):[]),s=new Set(function(e){if(!e)return[];try{const t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>"string"==typeof e):[]}catch{return[]}}(t).filter(e=>r.has(e)));let a=!1;const l=e=>{if("off"===e)return s.clear(),void(a=!0);const t=e.startsWith("-"),i=t?e.slice(1):e;o.has(i)&&(a=!0,t||!r.has(i)?s.delete(i):s.add(i))};for(const t of S_(new URLSearchParams(String(e.search||"").replace(/^\?/,""))))l(t);for(const t of S_(x_(e.hash)))l(t);const c=Object.freeze([...s].sort());return{active:c,space:$_(e.hash),persist:a?JSON.stringify(c):void 0,knownUrlOperation:a}}let R_={active:Object.freeze([]),space:""},T_="",C_=!1,D_="";const z_=new Set;function A_(){if("undefined"==typeof window)return R_;const e=M_(window.location,function(){try{return window.localStorage.getItem(g_)}catch{return null}}(),T_);void 0!==e.persist&&function(e){try{window.localStorage.setItem(g_,e)}catch{}}(e.persist),R_={active:e.active,space:e.space},window.__hpLabs=e.active;for(const e of z_)e(R_);return R_}function O_(){A_()}function P_(e){if(T_=e,"undefined"==typeof window)return R_;if(!C_){C_=!0,window.__hpLabsListenerCleanup?.(),window.addEventListener("hashchange",O_),window.addEventListener("popstate",O_);const e=()=>{window.removeEventListener("hashchange",O_),window.removeEventListener("popstate",O_),window.__hpLabsListenerCleanup===e&&delete window.__hpLabsListenerCleanup};window.__hpLabsListenerCleanup=e}return A_()}const F_=Object.freeze({rotDeg:0,tiltDeg:20,xyScale:1,zScale:1,origin:Object.freeze([500,500])});function E_(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 I_(e,t,i=F_){if(!(E_(i)&&Number.isFinite(e[0])&&Number.isFinite(e[1])&&Number.isFinite(t)))throw new Error("invalid isometric projection input");const n=i.rotDeg*Math.PI/180,r=i.tiltDeg*Math.PI/180,o=e[0]-i.origin[0],s=e[1]-i.origin[1],a=(o*Math.cos(n)-s*Math.sin(n))*i.xyScale,l=(o*Math.sin(n)+s*Math.cos(n))*i.xyScale;return[i.origin[0]+a,i.origin[1]+l*Math.cos(r)-t*i.zScale*Math.sin(r)]}function H_(e,t=F_){if(!E_(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 N_(e=F_){return`matrix(${function(e=F_){if(!E_(e))throw new Error("invalid isometric camera");const t=e.rotDeg*Math.PI/180,i=e.tiltDeg*Math.PI/180,n=e.xyScale*Math.cos(t),r=-e.xyScale*Math.sin(t),o=e.xyScale*Math.sin(t)*Math.cos(i),s=e.xyScale*Math.cos(t)*Math.cos(i);return[n,o,r,s,e.origin[0]-n*e.origin[0]-r*e.origin[1],e.origin[1]-o*e.origin[0]-s*e.origin[1]]}(e).map(e=>Number(e.toFixed(12))).join(" ")})`}function L_(e,t=F_){const{rect:i,wallHeight:n}=e,r=e.openingHeight??n,o=e.floorDepth??0;if(!(i.w>=0)||!(i.h>=0)||!Number.isFinite(n)||!Number.isFinite(r)||!Number.isFinite(o)||n<0||r<0||o<0)throw new Error("invalid isometric frame");const s=[[i.x,i.y],[i.x+i.w,i.y],[i.x+i.w,i.y+i.h],[i.x,i.y+i.h]],a=Math.max(n,r),l=s.flatMap(e=>[I_(e,-o,t),I_(e,a,t)]),c=l.map(e=>e[0]),h=l.map(e=>e[1]),d=Math.min(...c),u=Math.min(...h);return{x:d,y:u,w:Math.max(...c)-d,h:Math.max(...h)-u}}const q_=e=>`${Number(e[0].toFixed(4))} ${Number(e[1].toFixed(4))}`;function W_(e){let t=0;for(let i=0;iArray.isArray(e)&&Number.isFinite(e[0])&&Number.isFinite(e[1])).map(e=>[Number(e[0]),Number(e[1])]),i=t[t.length-1];return t.length>1&&t[0][0]===i[0]&&t[0][1]===i[1]&&t.pop(),t}(e);if(i.length<3)return[];const n=!t;return W_(i)>0===n?i:[...i].reverse()}function B_(e,t,i){return e.length?`M ${e.map(e=>q_(I_(e,i,t))).join(" L ")} Z`:""}function V_(e,t,i){const n=t[1]-e[1],r=-(t[0]-e[0]),o=i.rotDeg*Math.PI/180;return n*Math.sin(o)+r*Math.cos(o)}function U_(e,t,i=F_){if(!Number.isFinite(t)||t<0)throw new Error("invalid floor edge height");const n=(e||[]).map(e=>(e||[]).map((e,t)=>function(e,t){const i=j_(e,t);if(!i.length)return i;let n=0;for(let e=1;e0)).filter(e=>e.length>=3&&Math.abs(W_(e))>=1e-9)).filter(e=>e.length&&W_(e[0])>0);n.sort((e,t)=>{const i=e[0][0],n=t[0][0];return i[0]-n[0]||i[1]-n[1]||Math.abs(W_(t[0]))-Math.abs(W_(e[0]))});const r=[],o=[];let s=0;for(let e=0;ee.depth-t.depth||e.component-t.component||e.edge-t.edge),{footprintPath:r.join(" "),sides:o,componentCount:n.length,edgeCount:s}}function G_(e,t){return e^=Math.round(64*(Number.isFinite(t)?t:0)),Math.imul(e,16777619)>>>0}const K_=e=>e.every(Number.isFinite);function Y_(e,t,i,n){const r=e[0]*i,o=e[1]*n,s=t*Math.PI/180;return[r*Math.cos(s)-o*Math.sin(s),r*Math.sin(s)+o*Math.cos(s)]}function Z_(e,t,i,n,r,o,s){const a=e.flipH?-1:1,l="gate"===e.type?1:e.flipV?-1:1,c=(e.type,e.flipV,e.angle,e.face,{ox:0,oy:0}),h=function(e,t){return[e[0]+t[0],e[1]+t[1]]}([e.x+c.ox,e.y+c.oy],Y_(i,e.angle,a,l));return{leaf:t,hinge:h,closedVector:Y_(n,e.angle,a,l),quarterVector:Y_([-n[1],n[0]],e.angle,a,l),turnDeg:r,bottom:o,top:s}}const X_=e=>`${Number(e[0].toFixed(4))} ${Number(e[1].toFixed(4))}`;function J_(e,t,i=F_){const n=Math.max(0,Math.min(1,Number.isFinite(t)?t:0));return e.leaves.map(t=>{const r=function(e,t){const i=e.turnDeg*t*Math.PI/180;return[e.hinge[0]+e.closedVector[0]*Math.cos(i)+e.quarterVector[0]*Math.sin(i),e.hinge[1]+e.closedVector[1]*Math.cos(i)+e.quarterVector[1]*Math.sin(i)]}(t,n),o=I_(t.hinge,t.bottom,i),s=I_(r,t.bottom,i),a=I_(r,t.top,i),l=I_(t.hinge,t.top,i);return{id:e.id,sourceIndex:e.sourceIndex,type:e.type,leaf:t.leaf,d:`M ${X_(o)} L ${X_(s)} L ${X_(a)} L ${X_(l)} Z`,shadowD:`M ${X_(I_(t.hinge,0,i))} L ${X_(I_(r,0,i))}`,depth:Math.max(o[1],s[1])}})}const Q_={window:120,door:90,passage:90,gate:300};function em(e){return Q_[e]}function tm(e,t){return{type:e,lengthCm:em(e),flipH:!1,flipV:!1,revision:t}}function im(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 nm(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 rm(e){const t=new Map;return e.forEach((e,i)=>{if(!e.kind||e.open)return;const n=nm(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 om(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 sm(e){const t=rm(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=nm(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(om),n=t.filter(t=>!t.target.partitionHost||e.renderedLength+2*t.target.physicalHalfWidth<=t.length+1e-9).sort(om);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 f=Math.max(e.gridStep,1e-9),g=l/2;m=Math.abs(m-g)<=f/2?g:Math.round(m/f)*f,m=Math.max(_,Math.min(l-_,m));const v=a.a[0]+d*m,y=a.a[1]+u*m,b=Math.max(0,e.renderedLength)/2,w=m-b,k=m+b,x=Math.max(0,w),$=Math.max(0,l-k),S=[a.a[0]+d*(w-x/2),a.a[1]+u*(w-x/2)],M=[a.a[0]+d*(k+$/2),a.a[1]+u*(k+$/2)];let R=180*Math.atan2(h,c)/Math.PI;R>=90?R-=180:R<-90&&(R+=180);const T=Math.abs(m-g)<=1e-9;return{candidate:{presetRevision:e.preset.revision,geometryRevision:e.geometryRevision,pointer:[e.pointer[0],e.pointer[1]],type:e.preset.type,lengthCm:e.preset.lengthCm,flipH:e.preset.flipH,flipV:e.preset.flipV,x:v,y:y,angle:R,renderedLength:e.renderedLength,target:a,...a.partitionHost?{host:{...a.partitionHost,t:l>0?m/l:0}}:{},measure:{labels:[{distance:x,midpoint:S},{distance:$,midpoint:M}],guide:T?{x:v,y:y,angle:R}:null}},jambBlockedTarget:null}}function am(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 lm(e){return!(!e.canEdit||e.kiosk||e.fixedFloor)&&("view"!==e.mode&&("mouse"===e.pointerType&&e.spaceCount>1))}let cm=0;const hm="1.69.0-beta.2",dm="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073",um=1500,pm=(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}},_m=(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)}},mm=new Map;let fm=0;const gm=e=>`${window.innerWidth}x${window.innerHeight}|${location.pathname}|${JSON.stringify(e??{})}`;let vm=1e4;const ym="houseplan_card_layout_v1",bm="houseplan_card_cfg_v1",wm="houseplan_card_zoom_v1",km="houseplan_card_nav_v1",xm="houseplan_card_kiosk_v1",$m="houseplan_card_view_v1",Sm="hp-dialog, hp-help, hp-color-opacity, hp-device-preview",Mm=1e3,Rm=[[0,1],[45,.88],[70,.62],[86,.32],[100,0]],Tm=(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}},Cm=new Set(["select","draw","column","merge","split","resize","opening","wallthick","delroom"]),Dm=(e,t,i)=>{const n=new Event(t,{bubbles:!0,composed:!0});n.detail=i??{},e.dispatchEvent(n)},zm=e=>{history.pushState(null,"",e),Dm(window,"location-changed",{replace:!1})},Am=(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},Om=e=>{try{e.target?.setPointerCapture?.(e.pointerId)}catch{}};class Pm extends he{constructor(){super(...arguments),this._editorRuntime=null,this._onboardingRuntime=null,this._editorRuntimeLoadingVisible=!1,this._editorModeRequest=0,this._warmModeRequest=0,this._editorRuntimeLoader=new f_({expectedFingerprint:dm,load:async e=>{const t=0===e?await import("./houseplan-editor-runtime-LLPkWHY0.js"):await import((()=>{const e=new URL("./houseplan-editor-runtime-LLPkWHY0.js",import.meta.url);return e.searchParams.set("hp_retry",`${hm}-${++cm}`),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),this._showToast(__(e=>this._t(e),t))}}),this._onboardingRuntimeLoader=new f_({expectedFingerprint:dm,load:async e=>{const t=0===e?await import("./houseplan-onboarding-runtime-BkWWzfSR.js"):await import((()=>{const e=new URL("./houseplan-onboarding-runtime-BkWWzfSR.js",import.meta.url);return e.searchParams.set("hp_retry",`${hm}-${++cm}`),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),this._showToast(__(e=>this._t(e),t))}}),this._space="f1",this._layout={},this._serverStorage=!1,this._loadOk=!1,this._serverCanWrite=null,this._loading=!1,this._loadTries=0,this._serverCfg=null,this._cfgRev=0,this._cfgContentFingerprint="",this._unsubCfg=null,this._unsubLayout=null,this._unsubVirtual=null,this._liveSyncAttempt=null,this._liveSyncGeneration=0,this._liveSyncConnection=null,this._layoutRev=0,this._layoutContentFingerprint="",this._virtualLights=Pc(null),this._canOptimizeUndo=!1,this._undoKind=null,this._devices=[],this._regSignature="",this._defPos={},this._newSyncKey="",this._tip=null,this._hoverRoom=null,this._pointerModality=new Np(this,()=>this._syncPointerHoverTargets()),this._devicePressAnimations=new Map,this._selId=null,this._toast="",this._mode="view",this._pendingNavMode=null,this._decorTool="select",this._decorStyle={...pr},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._furnCategory=null,this._dtBox=null,this._dtDrag=null,this._bdDrag=null,this._slide="",this._reducedMotion=!1,this._onMotionChange=e=>{this._reducedMotion=e.matches,this._cancelDevicePressFeedback(),e.matches&&this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:e.matches&&this._modeTransition.active&&this._cancelModeTransition(!0),this.requestUpdate()},this._editorChromeMode="plan",this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest=0,this._modeTransitionTargetZoom=1,this._modeTransitionEditorCamera=null,this._modeTransition=new p_({frame:e=>this._applyModeTransitionFrame(e),settled:e=>this._settleModeTransition(e)}),this._editorSecondaryCopy={groupActive:(e,t)=>this._t("editor.group_active",{group:e,item:t}),openGroup:e=>this._t("editor.open_group",{group:e}),disabledAction:(e,t)=>this._t("editor.disabled_action",{action:e,reason:t})},this._tool="draw",this._geometryHistory=new e_(50),this._wallDialog=null,this._drawWallField=null,this._activeDraftId=null,this._resumeDraftBySpace={},this._physicalSel=null,this._physicalDialog=null,this._partitionDeleteDialog=null,this._roomDeleteDialog=null,this._physicalDrag=null,this._physicalRotate=null,this._physicalLastTap=null,this._physicalPickCycle=null,this._wallUnionCacheValue=null,this._wallUnionPool=new Map,this._isoGeometryCache=new Map,this._isoFallback=new Set,this._openingTunnelCache=null,this._openingWallIndexCache=new Map,this._openingPlacementIntervalsCache=null,this._openingDimensionContextCache=null,this._planSnapGeometryCache=null,this._planStructuralGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._physicalBodiesCache=null,this._lightPhysicalBodiesCache=null,this._cleanFloorCache=new Map,this._innerContourCache=new Map,this._glowClipCache=new Map,this._glowGeometryWarnings=new Set,this._lightBarrierCache=null,this._lightBarrierPool=new Map,this._glowFeatherUnits=null,this._glowRenderedSources=new Map,this._glowLastAppearance=new Map,this._glowEnteringSources=new Set,this._glowEnterRafs=new Map,this._glowFadeTimers=new Map,this._glowFeatherSuspendUntil=0,this._glowFeatherResumeTimer=0,this._glowSourceSeq=0,this._glowScreenBlend=!1,this._duplicateColumnId=null,this._duplicateColumnTimer=0,this._rszLimitViolation=null,this._path=[],this._cursorPt=null,this._planSnapHover=null,this._mergeSel=null,this._openingPreset=null,this._openingRebindId=null,this._openingPresetRevision=0,this._openingHoverCandidate=null,this._openingJambBlockCm=null,this._openingDialog=null,this._openingInfo=null,this._opDrag=null,this._opMeasure=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._wallFaceBatch=null,this._wallRepairDiagnostic=null,this._wallFaceGraphCache=[],this._areaSel="",this._nameSel="",this._roomDialog=!1,this._roomEditId=null,this._roomFill="",this._roomCustomFill=null,this._roomTempSrc="",this._roomHumSrc="",this._roomSrcOpen=null,this._roomSrcFilter="",this._roomNameScale=1,this._roomLabelScale=1,this._zoom=1,this._view=null,this._zoomBySpace={},this._viewModeSnap=null,this._pointers=new Map,this._panStart=null,this._panLock=null,this._pinchStart=null,this._suppressClick=!1,this._touchContacts=new Map,this._touchSequenceMultitouch=!1,this._touchClickBlockUntil=0,this._connectedPath="",this._routeDepartureHandled=!1,this._onLocationChanged=()=>{this._connectedPath&&location.pathname!==this._connectedPath?this._leaveCardRoute():location.pathname===this._connectedPath&&(this._routeDepartureHandled=!1)},this._touchGestureGuard={capture:!0,handleEvent:e=>this._guardTouchGesture(e)},this._hdrH=118,this._booting=!0,this._bootFading=!1,this._bootSettling=!1,this._bootSettleRaf=0,this._bootLastH=-1,this._bootStart=0,this._bootLastChange=0,this._bootSoft=!1,this._tapConfirm=null,this._onboardingShown=!1,this._rulesDialog=null,this._preflightClipboardFallback=null,this._haIntegrationVersion=null,this._alignDialog=null,this._settingsDialog=null,this._backupExportDialog=null,this._backupImportDialog=null,this._sunRaysCache=null,this._dayCycleTimer=0,this._dayCycleClockKey="",this._compassDrag=!1,this._importDialog=null,this._importQueue=[],this._importTotal=0,this._rulesCompiledSrc="",this._infoCard=null,this._nativeMoreInfoEntity=null,this._deviceInbox=null,this._deviceInboxReturn=null,this._deviceInboxMemo=null,this._markerDialog=null,this._spaceDialog=null,this._keyHandler=e=>this._onKey(e),this._warmVp=null,this._warmVpArmed=!1,this._warmLongReturn=!1,this._warmRevivePending=!1,this._warmGen=++fm,this._warmKey=null,this._warmSlot=null,this._hashApplied=!1,this._navApplied=!1,this._labs={active:Object.freeze([]),space:""},this._viewPreference={},this._renderProjection="flat",this._kioskScale={icon:1,font:1},this._kioskDialog=!1,this._activityRt=new Map,this._vacRt=new Map,this._vacViewKey="",this._vacLastView=null,this._vacRaf=0,this._vacSrvTrails={},this._vacJumpOnce=!1,this._continuity=this._newContinuityController(),this._continuityHistory=[],this._continuityEpoch=0,this._continuityDataReady=!0,this._continuityPaintToken=-1,this._continuityDisposed=!1,this._renderSnapshotAt=Date.now(),this._hassSequence=0,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotSequence=-1,this._capturedSnapshotDevices=null,this._capturedSnapshotLayout=null,this._capturedSnapshotActivity="",this._capturedSnapshotConfigEpoch=-1,this._capturedSnapshotVirtual="",this._lastValidStageSize=null,this._pendingRefitSize=null,this._refitRaf=0,this._pageVisibility=e=>{if(this._continuity.visibility(e),this._dayCycleVisibility(e),"hidden"===e.kind)return this._clearTransientHover(!0),this._cancelDevicePressFeedback(),void(this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:this._cancelModeTransition(!0));if(this._vacJumpOnce=!0,!e.long){const e=Date.now();let t=!1;for(const i of this._activityRt.values())!i.flashKind||(i.expiresAt||i.flashTs+Pp)>e||(i.flashTs=0,i.flashKind=null,i.expiresAt=0,t=!0);return void(t&&this.requestUpdate())}Date.now()-this._renderSnapshotAt>1e3&&this._continuity.note("device-snapshot-stale"),this._continuityDataReady=!1,this._continuityPaintToken=-1,this._resumeSettling=!0,this._loading?this.requestUpdate():this._loadFromServer()},this._resumeSettling=!1,this._viewportInvalidAt=0,this._vacFit=null,this._vacAllCamerasFor=null,this._vacAllCameraCache=null,this._vacCalConfirm=null,this._kioskDots=!1,this._cyclePausedUntil=0,this._swipeStart=null,this._tabDrag=null,this._tabDragRelease=null,this._tabSuppressClick=!1,this._tabOrderWarned=!1,this._lastTap=0,this._onLabsSnapshot=e=>{const t=this._effectiveProjection();this._labs=e;const i=this._effectiveProjection();this._convertProjectionView(t,i),this.requestUpdate()},this._onHashChange=()=>{if(this._hasFixedFloor)return;const e=this._hashSpace();if(e&&this._model.find(t=>t.id===e)&&e!==this._space){if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return;this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._commitSpace(e),this._selId=null,this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,"plan"===this._mode&&"draw"===this._tool&&this._resumeLastDraft(),this._restoreZoom(),this.requestUpdate()}},this._drag=null,this._rlResize=null,this._holdFired=!1,this._retryContinuity=()=>{this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.retry(this._continuity.recoveryReason||"plan"),this._loading||this._loadFromServer()},this._cfgEpoch=0,this._modelCache=null,this._emptySpaceStateActive=!1,this._decorSnapCache=null,this._markerPreviewMemo=null,this._markerPreviewDevicesMemo=null,this._showHidden=!1,this._connHooked=null,this._connectionWasLost=!1,this._haRegistryConnection=null,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._onHaRegistryUpdate=()=>{const e=Jc(this.hass);e.revision===this._haRegistryRev&&this._devices.length||(this._haRegistryRev=e.revision,this._planHassMemo=null,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate())},this._onConnReady=()=>{if(this._loadTries=0,clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,function(e){const t=Uc(e);t&&(Yc(e,t),Zc(e,t))}(this.hass),this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(this._onConnReady,400));!this._connectionWasLost&&this._continuity.hasCompleteFrame?this._beginContinuityCandidate("connection-ready",!1,"plan"):(this._continuityDataReady=!1,this._continuityPaintToken=-1),this._loading||this._loadFromServer()},this._onConnLost=()=>{this._booting&&!this._continuity.hasCompleteFrame||(this._connectionWasLost=!0,this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.connectionLost())},this._signer=new Pl(()=>this.requestUpdate()),this._dirtyPos=new Set,this._sentPos=new Map,this._persistLayout=Am(()=>{if(this._serverStorage){const e=[...this._dirtyPos];this._dirtyPos.clear();for(const t of e){const e=oo(this._layout[t]);e&&(this._layout={...this._layout,[t]:e},this._sentPos.set(t,e),this.hass.callWS({type:"houseplan/layout/update",device_id:t,pos:e}).then(e=>this._noteLayoutRev(e)).catch(e=>this._showToast(this._t("toast.pos_save_failed",{err:this._errText(e)}))).finally(()=>{this._sentPos.get(t)===e&&this._sentPos.delete(t)}))}this._cacheSnapshot()}else this._layout=so(Ur(this._layout)),localStorage.setItem(ym,JSON.stringify(this._layout))},600),this._frame=null,this._showFar=!1,this._writesPending=0,this._writeChain=Promise.resolve(),this._pendingPhysicalWrites=new Map,this._undoGeometry=()=>this._editorRuntimeOrThrow()._undoGeometry(),this._redoGeometry=()=>this._editorRuntimeOrThrow()._redoGeometry(),this._saveConfigDebounced=Am(()=>{this._serverCfg&&this._writeConfig().catch(e=>{const t=!0===e?.physicalGeometryRolledBack;"geometry-unsafe"!==e?.code&&("wall_model_client_outdated"===e?.code?this._showToast(this._t("toast.wall_model_client_outdated")):"conflict"===e?.code?(this._showToast(this._t("toast.conflict")),t||(this._cancelPath(),this._reloadConfigOnly(!0))):this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(e)})),t&&this._reloadRejectedPhysicalWrite())})},500),this._draftSegmentCms=[],this._closingWallCm=null,this._savePhysicalDialog=()=>this._editorRuntimeOrThrow()._savePhysicalDialog(),this._deletePhysicalSelection=()=>this._editorRuntimeOrThrow()._deletePhysicalSelection(),this._confirmPartitionDelete=()=>this._editorRuntimeOrThrow()._confirmPartitionDelete(),this._deleteDraftWhole=()=>this._editorRuntimeOrThrow()._deleteDraftWhole(),this._deleteDraftSegment=()=>this._editorRuntimeOrThrow()._deleteDraftSegment(),this._confirmRoomDelete=e=>this._editorRuntimeOrThrow()._confirmRoomDelete(e),this._rebindPartitionOpening=()=>this._editorRuntimeOrThrow()._rebindPartitionOpening(),this._keepClosedAsPartitions=()=>this._editorRuntimeOrThrow()._keepClosedAsPartitions(),this._toggleServerPlans=async()=>this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._toggleServerPlans():this._editorRuntimeOrThrow()._toggleServerPlans(),this._aspectJob=null,this._dayCycleTick=()=>{if(!this.isConnected||"hidden"===this.ownerDocument.visibilityState)return;const e=this._dayCycleState();if(!e)return this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),void(this._dayCycleClockKey="");const t=Xn(e);t!==this._dayCycleClockKey&&(this._dayCycleClockKey=t,this.requestUpdate())},this._sunShown=!1,this._sunOut=!1,this._sunOutTimer=0,this._openSettingsDialog=()=>{if(this._editorRuntime)return this._editorRuntime._openSettingsDialog();this._ensureEditorRuntime().then(e=>{e&&this._openSettingsDialog()})},this._reportedPreflightFingerprint=null,this._openAlignDialog=()=>this._editorRuntimeOrThrow()._openAlignDialog(),this._toggleOptimizeLivePositions=()=>this._editorRuntimeOrThrow()._toggleOptimizeLivePositions(),this._optimizeUndoBusy=!1,this._openBackupExport=()=>this._editorRuntimeOrThrow()._openBackupExport(),this._openRulesDialog=()=>this._editorRuntimeOrThrow()._openRulesDialog(),this._climateCache=null,this._gearPtCache=new WeakMap}_editorRuntimeOrThrow(){if(!this._editorRuntime)throw new Error("Houseplan editor runtime is not loaded");return this._editorRuntime}async _ensureEditorRuntime(){return this._editorRuntimeLoader.ensure()}async _ensureOnboardingRuntime(){return this._onboardingRuntimeLoader.ensure()}_editorRuntimeStateChanged(e){clearTimeout(this._editorRuntimeLoadingTimer),this._editorRuntimeLoadingTimer=void 0,"loading"!==e?(this._editorRuntimeLoadingVisible=!1,this.requestUpdate()):this._editorRuntimeLoadingTimer=window.setTimeout(()=>{this._editorRuntimeLoadingVisible=!0,this.requestUpdate()},150)}async _requestMode(e,t=!0,i=!1){const n=++this._editorModeRequest;if(i&&(this._warmModeRequest=n,this._refitRaf&&(cancelAnimationFrame(this._refitRaf),this._refitRaf=0),this._pendingRefitSize=null),"view"===e||await this._ensureEditorRuntime()){if(n===this._editorModeRequest&&this.isConnected)return i?(this._adoptMode(e),this._warmRevivePending&&(clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmReviveDialog()),this.requestUpdate(),void this.updateComplete.then(()=>requestAnimationFrame(()=>requestAnimationFrame(()=>{if(this._warmModeRequest!==n||n!==this._editorModeRequest)return;const e=this._stageEl;this._lastValidStageSize=e&&e.clientWidth>0&&e.clientHeight>0?[e.clientWidth,e.clientHeight]:null,this._pendingRefitSize=null,this._warmModeRequest=0})))):void this._setMode(e,t);this._warmModeRequest===n&&(this._warmModeRequest=0)}else this._warmModeRequest===n&&(this._warmModeRequest=0)}get _canEdit(){return!!this._norm&&(!0===this._serverCanWrite||!1!==this._serverCanWrite&&!0===this.hass?.user?.is_admin)}get _kiosk(){return!!this._config?.kiosk}_showKioskDots(){this._kioskDots=!0,clearTimeout(this._kioskDotsTimer),this._kioskDotsTimer=window.setTimeout(()=>this._kioskDots=!1,2500)}get _modeTransitionBusy(){return this._modeTransitionPreparing||this._modeTransition.active}_cssColor(e,t){const i=String(e||"").trim();if(!i)return t;const n=document.createElement("span");n.style.cssText=`position:absolute;visibility:hidden;color:${i}`,this.renderRoot.append(n);const r=getComputedStyle(n).color||t;return n.remove(),r}_currentModeVisual(e=this._mode){const t=this._modeTransition.presented||this._modeTransitionVisual;if(t)return{...t,viewport:{...t.viewport,viewBox:{...t.viewport.viewBox}}};const i=this._stageEl;if(!i||i.clientWidth<=0||i.clientHeight<=0)return null;const n=this.renderRoot.querySelector(".editorchrome"),r=this._viewOr(this._baseVb()),o=this.renderRoot.querySelector(".hp-paper"),s=this.renderRoot.querySelector(".hp-backdrop"),a=this.renderRoot.querySelector(".zoomwrap"),l=a?getComputedStyle(a).filter:"",c=Number(/brightness\(([^)]+)\)/.exec(l)?.[1]);return{presentedMode:e,editorChromeHeight:"view"===e?0:n?.getBoundingClientRect().height||0,stageWidth:i.clientWidth,stageHeight:i.clientHeight,viewport:l_(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=Ti(this._baseVb(),n/Math.max(1,r)),s=Math.min(Pm.ZOOM_MAX,Math.max(Pm.ZOOM_MIN,e)),a=o.w/s,l=o.h/s,c=t??o.x+o.w/2,h=i??o.y+o.h/2;return this._clampView({x:c-a/2,y:h-l/2,w:a,h:l},o)}_targetStageColor(e){return"view"!==e?"rgb(255, 255, 255)":this._cssColor(this._stageBg(this._spaceDisplayForRender()),this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"))}_targetPaperColor(e){return"view"===e&&this._spaceModel()?.bg?this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"):"rgb(255, 255, 255)"}_targetBrightness(e){return 1}_applyModeTransitionFrame(e){e.targetMode===this._mode&&(this._modeTransitionVisual=e.presented,this._view={...e.presented.viewport.viewBox},this.requestUpdate())}_settleModeTransition(e){if(e.targetMode!==this._mode)return;const t=this._modeTransitionRequest;this._view={...e.to.viewport.viewBox},this._zoom=this._modeTransitionTargetZoom,this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._lastValidStageSize=[e.to.stageWidth,e.to.stageHeight],"view"===this._mode&&(this._saveZoom(),this._viewModeSnap=null,this._modeTransitionEditorCamera=null),this.requestUpdate(),this.updateComplete.then(()=>{if(!this.isConnected||t!==this._modeTransitionRequest||this._modeTransitionBusy||e.targetMode!==this._mode)return;const i=this._stageEl;if(i&&i.clientWidth>0&&i.clientHeight>0&&(Math.abs(i.clientWidth-e.to.stageWidth)>.5||Math.abs(i.clientHeight-e.to.stageHeight)>.5)){const e=this._view;this._lastValidStageSize=[i.clientWidth,i.clientHeight],this._applyView(this._zoom,e?e.x+e.w/2:void 0,e?e.y+e.h/2:void 0),this.requestUpdate()}const n=this.renderRoot.activeElement;(!n||!n.isConnected||!!n.closest?.(".editorchrome, .stage"))&&this.renderRoot.querySelector(".modetab.active")?.focus?.({preventScroll:!0})})}_cancelModeTransition(e=!0){const t=!!this._modeTransition.state;this._modeTransitionRequest++,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransition.cancel(e),e&&t||(this._modeTransitionVisual=null)}_adoptMode(e){this._cancelModeTransition(!1),this._mode=e,"view"!==e&&(this._editorChromeMode=e)}_commitViewModeAtomic(e,t,i,n){if(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this._zoom=t,e){const r=this._stageEl?.clientWidth||e.stageWidth,o=Math.max(1,e.stageHeight+e.editorChromeHeight);this._view=this._viewForModeTarget(t,i,n,r,o),this._lastValidStageSize=[r,o]}else this._view=null;this._viewModeSnap=null,this._modeTransitionEditorCamera=null,this._saveZoom(),this.requestUpdate()}_prepareModeTransition(e,t,i,n,r,o){this.updateComplete.then(()=>{if(!this.isConnected||e!==this._modeTransitionRequest||this._mode!==i)return void(e===this._modeTransitionRequest&&(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this.requestUpdate()));const s=this.renderRoot.querySelector(".editorchrome"),a=s?.querySelector(".editorchrome-inner"),l="view"===i?0:a?.scrollHeight||a?.getBoundingClientRect().height||0,c=Math.max(1,t.stageHeight+t.editorChromeHeight),h=Math.max(1,c-l),d=this._stageEl?.clientWidth||t.stageWidth;if(d<=0||h<=0)return this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._applyView(n,r,o),void this.requestUpdate();const u=this._viewForModeTarget(n,r,o,d,h),p={presentedMode:i,editorChromeHeight:l,stageWidth:d,stageHeight:h,viewport:l_(u,d),stageColor:this._targetStageColor(i),paperColor:this._targetPaperColor(i),sceneBrightness:this._targetBrightness(i),architectureOpacity:"decor"===i?.35:1,backdropOpacity:"decor"===i&&"backdrop"!==this._decorTool?.5:1,viewWeight:"view"===i?1:0,editorWeight:"view"===i?0:1,toolbarContentOpacity:"view"===i?0:1};this._modeTransitionPreparing=!1;const _=this._modeTransitionForceAtomic;this._modeTransitionForceAtomic=!1,this._modeTransition.start(t,p,i,this._reducedMotion||_?0:220)})}get _hasFixedFloor(){return!!this._config&&Object.prototype.hasOwnProperty.call(this._config,"floor")}_fixedFloorState(e=this._model,t=this._loadOk){const i=this._config?.floor,n=function(e){if(!e.hasFloor)return{kind:"absent"};const t=e.floor;if("string"==typeof t)return t.length?e.spaceIds.includes(t)?{kind:"valid",id:t,source:"id"}:{kind:"invalid",reason:"unknown-id",value:t}:{kind:"invalid",reason:"empty-id",value:t};if("number"==typeof t){if(!Number.isFinite(t))return{kind:"invalid",reason:"non-finite-index",value:t};if(!Number.isInteger(t))return{kind:"invalid",reason:"fractional-index",value:t};if(t<0)return{kind:"invalid",reason:"negative-index",value:t};const i=e.spaceIds[t];return void 0===i?{kind:"invalid",reason:"out-of-range-index",value:t}:{kind:"valid",id:i,source:"index"}}return{kind:"invalid",reason:"invalid-type",value:t}}({spaceIds:e.map(e=>e.id),hasFloor:this._hasFixedFloor,floor:i});return!this._hasFixedFloor||t?n:"number"==typeof i?"valid"===n.kind||"invalid"===n.kind&&"out-of-range-index"===n.reason?{kind:"pending",value:i}:n:"valid"===n.kind||"invalid"===n.kind&&"unknown-id"!==n.reason?n:{kind:"pending",value:i}}_canCommitSpace(e,t=!1){if(t||!this._hasFixedFloor)return!0;const i=this._fixedFloorState();return"valid"===i.kind&&i.id===e}_commitSpace(e,t=!1){return!!this._canCommitSpace(e,t)&&(e!==this._space&&(this._clearTransientHover(!0),this._cancelDevicePressFeedback()),this._space=e,!0)}_slideTo(e,t){if(e===this._space)return!0;if(!this._canCommitSpace(e))return!1;if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return!1;this._cancelModeTransition(!0);const i=window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;return this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._commitSpace(e),this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._selId=null,this._physicalSel=null,this._editorSecondary?.closeForNavigation(),this._physicalDialog=null,this._physicalDrag=null,"plan"===this._mode&&"draw"===this._tool&&this._resumeLastDraft(),this._restoreZoom(),i||(this._slide=t,clearTimeout(this._slideTimer),this._slideTimer=window.setTimeout(()=>{this._slideTimer=void 0,this._slide="",this.requestUpdate()},190),this.requestUpdate()),!0}get _canReorderTabs(){return lm({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:"mouse",spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})}_tabPointerDown(e,t){lm({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:e.pointerType,spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})&&(Om(e),this._tabDragRelease=e=>this._tabPointerUp(e),window.addEventListener("pointerup",this._tabDragRelease),window.addEventListener("pointercancel",this._tabDragRelease),this._tabDrag={id:t,pointerId:e.pointerId,x:e.clientX,y:e.clientY,moved:!1,targetId:null,placement:null})}_tabDropTargetAt(e,t,i){const n=this._model.map(e=>e.id),r=n.indexOf(i);if(r<0)return null;const o=this.renderRoot.querySelectorAll('[data-hp="space-tab"]');for(const s of o){const o=s.dataset.id||"";if(!o||o===i)continue;const a=s.getBoundingClientRect();if(ea.right||ta.bottom)continue;const l=n.indexOf(o);return l<0?null:{targetId:o,placement:l=4)))return;var i,n;const r=this._tabDropTargetAt(e.clientX,e.clientY,t.id);t.moved&&t.targetId===r?.targetId&&t.placement===r?.placement||(this._tabDrag={...t,moved:!0,targetId:r?.targetId||null,placement:r?.placement||null})}_tabPointerUp(e){const t=this._tabDrag;if(t&&t.pointerId!==e.pointerId)return;const i="pointerup"===e.type&&t?.moved?this._tabDropTargetAt(e.clientX,e.clientY,t.id):null;"pointerup"===e.type&&t?.moved&&this._suppressNextTabClick(),this._endTabDrag(),t?.moved&&i&&this._commitTabOrder(t.id,i.targetId)}_endTabDrag(){this._tabDrag=null,this._tabDragRelease&&(window.removeEventListener("pointerup",this._tabDragRelease),window.removeEventListener("pointercancel",this._tabDragRelease),this._tabDragRelease=null)}_tabClick(e){if(this._tabSuppressClick)return this._tabSuppressClick=!1,clearTimeout(this._tabSuppressClickTimer),void(this._tabSuppressClickTimer=void 0);this._pickSpace(e)}_suppressNextTabClick(){this._tabSuppressClick=!0,clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=window.setTimeout(()=>{this._tabSuppressClick=!1,this._tabSuppressClickTimer=void 0},0)}_commitTabOrder(e,t){const i=this._serverCfg;if(!i||!this._canReorderTabs)return;const n=this._model.map(e=>e.id),r=function(e,t,i){const n=e.indexOf(t),r=e.indexOf(i);if(n<0||r<0||n===r)return e;const o=e.slice();return o.splice(n,1),o.splice(r,0,t),o}(n,e,t);if(r===n)return;const o=new Map(this._devices.map(e=>[String(e.id),String(e.area||"")])),s=function(e,t,i,n=()=>""){if(!i)return[];const r=[];for(const o of e){if(!o||!0===o.removed)continue;const e="string"==typeof o.id?o.id:"";if(!e)continue;if("string"==typeof o.space&&o.space)continue;const s=("string"==typeof o.area?o.area:"")||n(e)||"";s&&t[s]||r.push({id:e,space:i})}return r}(i.markers||[],Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),n[0]||"",e=>o.get(e)||"");if(s.length){const e=new Map(s.map(e=>[e.id,e.space]));for(const t of i.markers||[]){const i=e.get(String(t.id));i&&(t.space=i)}}i.spaces=function(e,t){const i=new Map(t.map((e,t)=>[e,t]));return e.map((e,t)=>({space:e,index:t})).sort((e,t)=>(i.get(String(e.space?.id))??Number.MAX_SAFE_INTEGER)-(i.get(String(t.space?.id))??Number.MAX_SAFE_INTEGER)||e.index-t.index).map(e=>e.space)}(i.spaces||[],r),this._saveConfig(),this._tabOrderWarned||(this._tabOrderWarned=!0,this._showToast(this._t("toast.space_order_changed")))}_pickSpace(e){if(this._endTabDrag(),e===this._space)return;const t=this._model.map(e=>e.id),i=t.indexOf(this._space),n=t.indexOf(e);this._navApplied=!0,this._showFar=!1,this._frame=null,this._slideTo(e,i>=0&&n0&&Date.now()>=this._cyclePausedUntil&&this._model.length>1&&this._zoom<=1.001){const e=this._model.map(e=>e.id),t=e.indexOf(this._space);this._slideTo(e[(t+1)%e.length],"left"),this._showKioskDots()}}_syncCycleTimer(){clearInterval(this._cycleTimer),this._cycleTimer=void 0,this.isConnected&&!this._hasFixedFloor&&this._config?.kiosk&&Number(this._config.cycle)>0&&(this._cycleTimer=window.setInterval(()=>this._cycleTick(),1e3*Number(this._config.cycle)))}get _editing(){return"plan"===this._mode||"devices"===this._mode||"decor"===this._mode}get _markup(){return"plan"===this._mode}get _wallUnionCache(){return this._wallUnionCacheValue}set _wallUnionCache(e){this._wallUnionCacheValue=e,null===e&&this._wallUnionPool.clear()}_newContinuityController(){return new Dl(()=>{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($m,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?H_(i):i;return{x:n[0],y:n[1]}}_convertProjectionView(e,t){if(e===t)return;const i=this._logicalViewCenter(e);this._view=null;const n=i?"iso"===t?I_([i.x,i.y],0):[i.x,i.y]:null;this._applyView(this._zoom,n?.[0],n?.[1]),this._warmPatch({vp:this._warmViewportState()}),this.requestUpdate()}_setProjection(e){if(!this._labsIso||"view"!==this._mode)return;const t=this._effectiveProjection();if(this._viewPreference={...this._viewPreference,[this._space]:e},"iso"===e){const e=this._isoSceneKey();e&&this._isoFallback.delete(e)}this._saveViewPreference();const i=this._effectiveProjection();this._convertProjectionView(t,i)}_hashSpace(){return $_(window.location.hash||"")}connectedCallback(){this._connectedPath=location.pathname,this._routeDepartureHandled=!1,window.addEventListener("location-changed",this._onLocationChanged),window.addEventListener("popstate",this._onLocationChanged),this._continuityDisposed&&(this._continuity=this._newContinuityController(),this._continuityDisposed=!1,this._continuityPaintToken=-1);const e=(t=this.ownerDocument,t_.get(t)?.resolved);var t,i;void 0!==e&&(this._glowScreenBlend=e),this._continuityUnsub?.(),this._continuityUnsub=Tl(this.ownerDocument,this._pageVisibility),this._languageFailureUnsub?.(),this._languageFailureUnsub=(i=()=>{this._showToast(this._t("toast.locale_load_failed"))},nu.add(i),()=>nu.delete(i)),super.connectedCallback(),this._pointerModality.connect(this.ownerDocument.defaultView);const n=this.ownerDocument.defaultView?.MutationObserver;n&&(this._pointerHoverObserver=new n(e=>{for(const t of e)for(const e of t.addedNodes)this._syncPointerHoverSubtree(e)}),this._pointerHoverObserver.observe(this.renderRoot,{childList:!0,subtree:!0})),this._motionMedia=window.matchMedia?.("(prefers-reduced-motion: reduce)"),this._reducedMotion=!!this._motionMedia?.matches,this._motionMedia?.addEventListener?.("change",this._onMotionChange),function(e){const t=t_.get(e);if(t)return t.promise;const i={promise:Promise.resolve(!1)};return i.promise=n_(e).catch(()=>!1).then(e=>(i.resolved=e,e)),t_.set(e,i),i.promise}(this.ownerDocument).then(e=>{e!==this._glowScreenBlend&&(this._glowScreenBlend=e,this.isConnected&&this.requestUpdate())}),this.hass&&this._ensureHaRegistryAuthority(),window.addEventListener("keydown",this._keyHandler),this._signer.start(()=>this.hass,()=>Mn(this._serverCfg)),this._syncCycleTimer(),window.addEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=function(e,t){z_.add(t);const i=P_(e);return"undefined"==typeof window&&t(i),()=>{z_.delete(t)}}(hm,this._onLabsSnapshot),this._booting?this._bootWatch():this._bootFading&&(clearTimeout(this._bootTimer),this._bootTimer=window.setTimeout(()=>{this._bootFading=!1},220)),this._bootSoft&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},um)),!this._loadOk&&this._serverCfg&&this.hass&&this._scheduleLoadRetry(),!this._warmSlot&&this._config&&this._warmAdopt(),this._loadOk&&this._ensureLiveSyncSubscriptions(),this._warmVp&&!this._warmRevivePending&&void 0===this._warmReviveTimer&&(this._warmRevivePending=!0,this._warmReviveTimer=window.setTimeout(()=>this._warmReviveDialog(),0)),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1,this.requestUpdate()}disconnectedCallback(){this._connectedPath&&location.pathname!==this._connectedPath&&this._leaveCardRoute(),window.removeEventListener("location-changed",this._onLocationChanged),window.removeEventListener("popstate",this._onLocationChanged),this._continuityUnsub?.(),this._continuityUnsub=void 0,this._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._dayCycleClockKey="",this._bootSettleRaf&&(cancelAnimationFrame(this._bootSettleRaf),this._bootSettleRaf=0),this._bootSettling=!1;for(const e of this._activityRt.values())clearTimeout(e.timer);window.removeEventListener("keydown",this._keyHandler),this._endTabDrag(),clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=void 0,this._tabSuppressClick=!1,clearInterval(this._cycleTimer),clearTimeout(this._kioskDotsTimer),clearTimeout(this._kioskHoldTimer),clearTimeout(this._reloadRetry),clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),this._connHooked=null,this._haRegistryRelease?.(),this._haRegistryRelease=void 0,this._haRegistryConnection=null,this._signer.dispose(),clearTimeout(this._toastTimer),clearTimeout(this._slideTimer),clearTimeout(this._editorRuntimeLoadingTimer),this._editorRuntimeLoadingTimer=void 0,this._editorRuntimeLoadingVisible=!1,this._modeTransition.dispose(),this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest++,this._slideTimer=void 0,this._slide="",clearTimeout(this._bootTimer),this._bootTimer=void 0,clearTimeout(this._bootSoftTimer),this._saveConfigDebounced.flush(),window.removeEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=void 0,clearTimeout(this._holdTimer),this._roViewport?.disconnect(),this._roViewport=void 0,this._roHdr?.disconnect(),this._roHdr=void 0,this._onWinResize&&(window.removeEventListener("resize",this._onWinResize),this._onWinResize=void 0),this._unsubCfg&&(this._unsubCfg(),this._unsubCfg=null),this._unsubLayout&&(this._unsubLayout(),this._unsubLayout=null),this._unsubVirtual&&(this._unsubVirtual(),this._unsubVirtual=null),this._unsubTrail&&(this._unsubTrail(),this._unsubTrail=void 0),this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=null,clearTimeout(this._layoutSyncTimer),clearTimeout(this._duplicateColumnTimer);for(const e of this._glowFadeTimers.values())clearTimeout(e);for(const e of this._glowEnterRafs.values())cancelAnimationFrame(e);clearTimeout(this._glowFeatherResumeTimer),this._glowFeatherResumeTimer=0,this._glowFeatherSuspendUntil=0,this._glowFadeTimers.clear(),this._glowEnterRafs.clear(),this._glowEnteringSources.clear(),this._glowRenderedSources.clear(),this._glowLastAppearance.clear(),this._glowSourceSeq=0,this._warmSnapshot(),this._warmRevivePending=!1,clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmRelease(),this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._touchContacts.clear(),this._touchSequenceMultitouch=!1,this._touchClickBlockUntil=0,this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._pointerHoverObserver?.disconnect(),this._pointerHoverObserver=void 0,this._pointerModality.disconnect(),this._editorSecondary?.reset(),this._resumeSettling=!1,this._continuityHistory=[...this._continuityHistory,...this._continuity.trace].slice(-80),this._continuity.dispose(),this._continuityDisposed=!0,super.disconnectedCallback()}_onKey(e){if("Escape"===e.key&&this._vacFit)return this._vacFit=null,this._showToast(this._t("vac.cal_cancelled")),void e.stopPropagation();if("Escape"===e.key){if(this._tapConfirm)return void(this._tapConfirm=null);if(this._vacCalConfirm)return void(this._vacCalConfirm=null);if(this._decorEraseConfirm)return void(this._decorEraseConfirm=null);if(this._openingInfo)return void(this._openingInfo=null);if(this._infoCard)return void this._closeInfoCard();if(this._rulesDialog)return void(this._rulesDialog=null);if(this._alignDialog)return this._alignDialog=null,void(this._preflightClipboardFallback=null);if(this._backupImportDialog)return void(this._backupImportDialog=null);if(this._backupExportDialog)return void(this._backupExportDialog=null);if(this._settingsDialog)return void(this._settingsDialog=null);if(this._markerDialog)return void this._closeMarkerDialog();if(this._deviceInbox)return void(this._deviceInbox=null);if(this._openingDialog)return void(this._openingDialog=null);if(this._physicalDialog)return void(this._physicalDialog=null);if(this._backdropDialog)return void(this._backdropDialog=null);if(this._decorShapeDialog)return void(this._decorShapeDialog=null);if(this._decorTextDialog)return void(this._decorTextDialog=null);if(this._spaceDialog&&!this._roomDialog)return this._spaceDialog=null,this._importQueue=[],void(this._importTotal=0);if(this._editorSecondary?.hasOpenGroup)return e.preventDefault(),void this._editorSecondary?.closeGroup(!0)}const t=e.composedPath?.()||[e.target],i=t.some(e=>e?.matches?.('input, textarea, select, [contenteditable="true"]')),n=t.some(e=>e?.classList?.contains?.("editor-secondary")),r=e.ctrlKey||e.metaKey,o=e.key.toLowerCase(),s=/^[a-z]$/.test(o),a="z"===o||!s&&"KeyZ"===e.code,l="y"===o||!s&&"KeyY"===e.code,c=r&&(a&&e.shiftKey||l),h=r&&a&&!e.shiftKey;if("decor"===this._mode){if((h||c)&&i)return;return c?(e.preventDefault(),void this._redoGeometry()):h?(e.preventDefault(),this._decorDraft?void(this._decorDraft=null):this._decorMove||this._dtDrag||this._bdDrag?void this._cancelDecorGesture():void this._undoGeometry()):"Delete"!==e.key&&"Backspace"!==e.key||!this._decorSel||i||n?void("Escape"===e.key&&(e.preventDefault(),this._decorDraft?this._decorDraft=null:this._decorMove||this._dtDrag||this._bdDrag?this._cancelDecorGesture():"furniture"===this._decorTool?(this._furnPalette=null,this._furnCategory=null,this._decorTool="select"):this._decorSel?this._decorSel=null:"select"!==this._decorTool?this._decorTool="select":this._setMode("view"))):(e.preventDefault(),void this._decorDeleteSel())}if(this._markup&&(!h&&!c||!i)){if(("Delete"===e.key||"Backspace"===e.key)&&this._physicalSel&&!i&&!n)return e.preventDefault(),void this._deletePhysicalSelection();if(c)return e.preventDefault(),void this._redoGeometry();if(h)return e.preventDefault(),this._resize?.dragging?void this._rszCancelDrag():this._wallFaceBatch?(this._roomDialogCancel(),void(this._activeDraftId&&this._path.length>1?this._undoActiveDraftPoint():this._undoPoint())):"draw"===this._tool&&this._path.length?void(this._activeDraftId&&this._path.length>1?this._undoActiveDraftPoint():this._undoPoint()):"split"===this._tool&&this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},void(this._splitSel.pts.length||(this._cursorPt=null))):void this._undoGeometry();if("Escape"===e.key)return this._physicalDrag||this._physicalRotate?(e.preventDefault(),void this._cancelPhysicalGesture()):this._roomDialog?(e.preventDefault(),void this._roomDialogCancel()):"draw"===this._tool&&this._path.length?(e.preventDefault(),void this._finishWallChain()):this._physicalSel?(e.preventDefault(),void(this._physicalSel=null)):"resize"===this._tool?(e.preventDefault(),this._resize?.dragging?void this._rszCancelDrag():("exit-tool"===this._resize?.escapeIdle()&&(this._tool="draw"),void this.requestUpdate())):"split"===this._tool?(e.preventDefault(),void(this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},this._splitSel.pts.length||(this._cursorPt=null)):this._splitSel?this._splitSel=null:this._tool="draw")):"merge"===this._tool?(e.preventDefault(),void(this._mergeSel?this._mergeSel=null:this._tool="draw")):this._wallDialog?(e.preventDefault(),void(this._wallDialog=null)):void("opening"!==this._tool&&"wallthick"!==this._tool&&"delroom"!==this._tool&&"column"!==this._tool||(e.preventDefault(),"opening"===this._tool&&this._clearOpeningPlacement(!0),this._tool="draw"))}}_undoPoint(){if(this._path.length){if(this._contourClosed)return this._path=this._path.slice(0,-1),void(this._closingWallCm=null);if(this._activeDraftId&&this._path.length>1&&this._curSpaceCfg){const e=this._geometrySnapshot();this._path=this._path.slice(0,-1),this._draftSegmentCms=this._draftSegmentCms.slice(0,-1);const t=this._curSpaceCfg,i=(t.room_drafts||[]).findIndex(e=>e.id===this._activeDraftId);if(i>=0){const n=Array.isArray(t.room_drafts[i]?.segments)?t.room_drafts[i].segments:[];this._path.length<2?(t.room_drafts.splice(i,1),t.room_drafts.length||delete t.room_drafts,this._activeDraftId=null):t.room_drafts[i]={id:this._activeDraftId,points:this._path.map(e=>[e[0]/Mm,e[1]/Mm]),segments:this._draftSegmentCms.map((e,t)=>({...n[t]||{},cm:e}))},this._commitPhysicalGeometry(this._t("history.draft_segment_delete"),e)}return}this._path=this._path.slice(0,-1)}}_undoActiveDraftPoint(){const e=this._activeDraftId,t=this._path[0]?[...this._path[0]]:null,i=this._geometryHistory.undo();if(!i)return void this._undoPoint();if(!this._applyGeometryState(i.before,!0))return void this._geometryHistory.clear();const n=e?this._spaceModel()?.room_drafts.find(t=>t.id===e):null;n?(this._activeDraftId=n.id,this._path=n.points.map(e=>[...e]),this._draftSegmentCms=this._adoptDraftCms(this._path,n.segments.map(e=>e.cm),n.id),this._resumeDraftBySpace[this._space]=n.id):(this._activeDraftId=null,this._path=t?[t]:[],this._draftSegmentCms=[],e&&this._resumeDraftBySpace[this._space]===e&&delete this._resumeDraftBySpace[this._space]),this._clearPlanSnapHover(),this._showToast(this._t("history.undone",{name:i.name}))}static async getConfigElement(){return await import("./editor-H80bjnWS.js"),document.createElement("houseplan-card-editor")}static getStubConfig(){return{type:"custom:houseplan-card"}}static _warmBootReset(e){for(const e of mm.values())for(const t of e)clearTimeout(t.evict);mm.clear(),vm=e&&e>0?e:1e4}static _warmBootStats(){let e=0,t=0;const i=[];for(const n of mm.values())for(const r of n)e++,r.dlg&&(t++,i.push(r.dlg.kind));return{keys:mm.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(wm)||"{}")||{}}catch{this._zoomBySpace={}}try{const e=JSON.parse(localStorage.getItem($m)||"{}")||{};this._viewPreference=Object.fromEntries(Object.entries(e).filter(e=>"flat"===e[1]||"iso"===e[1]))}catch{this._viewPreference={}}this._labs=P_(hm);try{const e=JSON.parse(localStorage.getItem(xm)||"null");this._kioskScale={icon:zn(e?.icon),font:zn(e?.font)}}catch{}try{const e=JSON.parse(localStorage.getItem(bm)||"null");e&&e.config&&Array.isArray(e.config.spaces)&&(this._serverCfg=e.config,this._cfgEpoch++,this._cfgRev=e.rev||0,this._cfgContentFingerprint=e.config_fingerprint||zl(e.config),this._layout=e.layout||{},this._layoutRev=e.layout_rev||0,this._layoutContentFingerprint=e.layout_fingerprint||zl(this._layout),this._virtualLights=Pc(e.virtual_lights,this._cfgRev),this._serverStorage=!0)}catch{}this._adoptInitialSpace(this._model,this._loadOk),"view"!==this._mode||this._view||(this._zoom=this._zoomBySpace[this._space]||1),this.isConnected&&(this._syncCycleTimer(),this._warmAdopt(),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1)}_warmAdopt(){if(this._config?.kiosk)return;const e=gm(this._config);if(this._warmKey===e&&this._warmSlot)return;this._warmSlot&&this._warmRelease();const t=this.parentNode,i=this._warmIdx(t),n=mm.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>=Sl,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>=Sl,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},um)),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=mm.get(t);if(!e.live&&o&&o.length>1){const t=o.indexOf(e);t>=0&&o.splice(t,1)}},vm+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?I_([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&&Cm.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=gm(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=mm.get(i)||[];for(n.push(this._warmSlot),mm.set(i,n),this._warmTrim(n);mm.size>8;){const e=mm.keys().next().value;if(void 0===e||e===i)break;for(const t of mm.get(e)||[])clearTimeout(t.evict);mm.delete(e)}}Object.assign(this._warmSlot,e)}}_warmViewportState(){const e=this._effectiveProjection();return{space:this._space,mode:this._mode,projection:e,activeLabsIso:this._labsIso,logicalCenter:this._logicalViewCenter(e),zoom:this._zoom,view:this._view?{...this._view}:null,snap:this._viewModeSnap?{...this._viewModeSnap}:null,tool:this._tool,decorTool:this._decorTool,showHidden:this._showHidden,showFar:this._showFar,selId:this._selId,rszSel:this._resize?.selectedRoomId,decorSel:this._decorSel}}_warmDialogState(){const e=(e,t)=>({kind:e,space:this._space,mode:this._mode,data:t});return this._tapConfirm||this._alignDialog||this._mergeDialog||this._importDialog||this._backupExportDialog||this._backupImportDialog?null:this._openingInfo?e("openingInfo",this._openingInfo.id):this._infoCard?e("info",this._infoCard.id):this._rulesDialog?this._rulesDialog.busy?null:e("rules",this._rulesDialog):this._settingsDialog?this._settingsDialog.busy?null:e("settings",this._settingsDialog):this._markerDialog?this._markerDialog.busy?null:e("marker",this._markerDialog):this._openingDialog?e("opening",this._openingDialog):this._backdropDialog?e("backdrop",this._backdropDialog):this._decorShapeDialog?e("decorShape",this._decorShapeDialog):this._decorTextDialog?e("decorText",this._decorTextDialog):this._roomDialog?e("room",{editId:this._roomEditId,fill:this._roomFill,customFill:this._roomCustomFill,tempSrc:this._roomTempSrc,humSrc:this._roomHumSrc,srcOpen:this._roomSrcOpen,srcFilter:this._roomSrcFilter,nameScale:this._roomNameScale,labelScale:this._roomLabelScale,areaSel:this._areaSel,nameSel:this._nameSel,pendingSplit:this._pendingSplit,wallFaceBatch:this._wallFaceBatch,path:this._path}):this._spaceDialog?this._spaceDialog.busy?null:e("space",this._spaceDialog):null}_warmSnapshot(){if(this._booting||this._config?.kiosk||"steady"!==this._continuity.state)return;const e={vp:this._warmViewportState(),frameFingerprint:this._continuity.frameFingerprint,devices:this._devices};if(this._warmRevivePending||(e.dlg=this._warmDialogState()),this.isConnected&&this._warmSlot?.owner===this._warmGen){const t=this.parentNode;e.place=t?new WeakRef(t):null,e.idx=this._warmIdx(t)}this._warmPatch(e)}_warmReviveDialog(){const e=this._warmSlot;if(this._warmReviveTimer=void 0,!e||!e.dlg)return void(this._warmRevivePending=!1);const t=e.dlg,i=e.freed;if(t.mode===this._mode||"view"===t.mode||this._warmVp?.mode!==t.mode||this._editorRuntime){if(this._warmRevivePending=!1,e.dlg=null,e.freed=0,clearTimeout(e.evict),e.evict=0,i&&!(Date.now()-i>vm)&&t.space===this._space&&t.mode===this._mode){switch(t.kind){case"space":this._spaceDialog={...t.data,busy:!1,savedBusy:!1};break;case"marker":this._markerDialog={...t.data,busy:!1};break;case"settings":this._settingsDialog={...t.data,busy:!1};break;case"rules":this._rulesDialog={...t.data,busy:!1};break;case"opening":this._openingDialog={...t.data};break;case"backdrop":this._backdropDialog={...t.data};break;case"decorShape":this._decorShapeDialog={...t.data};break;case"decorText":{this._decorTextDialog={...t.data};const e=String(this._decorTextDialog?.text??"").length;this._decorTextSelection={start:e,end:e};break}case"room":{const e=t.data;this._roomEditId=e.editId,this._roomFill=e.fill,this._roomCustomFill=e.customFill||null,this._roomTempSrc=e.tempSrc,this._roomHumSrc=e.humSrc,this._roomSrcOpen=e.srcOpen,this._roomSrcFilter=e.srcFilter,this._roomNameScale=e.nameScale,this._roomLabelScale=e.labelScale,this._areaSel=e.areaSel,this._nameSel=e.nameSel,this._pendingSplit=e.pendingSplit,this._wallFaceBatch=e.wallFaceBatch||null,this._path=e.path,this._wallFaceBatch&&(this._activeDraftId=this._wallFaceBatch.activeDraftId,this._draftSegmentCms=[...this._wallFaceBatch.activeCms]),this._roomDialog=!0;break}case"info":{const e=this._devices.find(e=>e.id===t.data);e&&(this._infoCard=e);break}case"openingInfo":{const e=(this._curSpaceCfg?.openings||[]).find(e=>e.id===t.data);e&&(this._openingInfo=e);break}}this.requestUpdate()}}else this._warmRevivePending=!0}_cacheSnapshot(){if(this._serverCfg)try{this._cfgContentFingerprint=zl(this._serverCfg),this._layoutContentFingerprint=zl(this._layout),this._virtualLights=function(e,t,i){if(e.configRev===i)return e;const n=new Set((Array.isArray(t?.markers)?t.markers:[]).filter(Hc).map(e=>e.id));return{...e,configRev:i,off:new Set([...e.off].filter(e=>n.has(e)))}}(this._virtualLights,this._serverCfg,this._cfgRev),localStorage.setItem(bm,JSON.stringify({config:this._serverCfg,rev:this._cfgRev,config_fingerprint:this._cfgContentFingerprint,layout:this._layout,layout_rev:this._layoutRev,layout_fingerprint:this._layoutContentFingerprint,virtual_lights:Ec(this._virtualLights)}))}catch{}}_beginContinuityCandidate(e,t,i="plan"){return this._booting&&!this._continuity.hasCompleteFrame?this._continuity.token:(this._continuityDataReady=t,this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._resumeSettling=!0,this._continuity.beginCandidate(e,i))}_continuityStageValid(){const e=this._stageEl;return!!e&&e.clientWidth>0&&e.clientHeight>0}_continuityAssetsReady(){if(!this._model.length)return!1;const e=this._model.length?this._spaceModel():null;return!e?.bg?.href||this._signer.isReady(this.hass,e.bg.href)}_initialSpaceSelection(e,t=this._loadOk){const i=this._fixedFloorState(e,t);return"valid"===i.kind?{id:i.id,source:"fixed"}:this._hasFixedFloor?{id:null,source:"none"}:function(e){const t=new Set(e.spaceIds.filter(e=>!!e));if(!t.size)return{id:null,source:"none"};const i=[["hash",!1===e.acceptHash?null:e.hashSpace],["current",e.preserveCurrent?e.currentSpace:null],["saved",e.savedSpace],["default",e.defaultSpace],["first",e.spaceIds[0]]];for(const[e,n]of i)if(n&&t.has(n))return{id:n,source:e};return{id:null,source:"none"}}({spaceIds:e.map(e=>e.id),hashSpace:this._hashSpace(),acceptHash:!this._hashApplied,currentSpace:this._space,preserveCurrent:this._hashApplied||this._navApplied||this._warmVpArmed,savedSpace:this._savedNav()?.space,defaultSpace:this._config?.default_floor})}_adoptInitialSpace(e,t=this._loadOk){const i=this._initialSpaceSelection(e,t);return i.id?(this._commitSpace(i.id,!0),"hash"===i.source&&(this._hashApplied=!0),"saved"===i.source&&(this._navApplied=!0),i):i}_candidateBackdrop(e,t=this._space){const i=Fa(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 Al([this._cfgRev,this._cfgContentFingerprint||zl(this._serverCfg),this._layoutRev,this._layoutContentFingerprint||zl(this._layout),this._space,this._mode,this._view,t,this._glowScreenBlend?"screen":"normal",this.hass?.themes?.darkMode??this.hass?.themes?.default_theme??""])}_settleContinuityFrame(){if(this._booting||!this._continuityStageValid())return;if(!this._continuity.hasCompleteFrame&&"steady"===this._continuity.state)return void(this._continuityAssetsReady()&&(this._renderSnapshotAt=Date.now(),this._continuity.markCompleteFrame(this._visualFrameFingerprint())));if(!this._continuityDataReady)return;if(!["holding","offline-stale","overlay-pending","overlay-visible","candidate-ready"].includes(this._continuity.state))return;const e=this._continuity.token;if(this._candidateDeviceSnapshot&&this._candidateDeviceSnapshot!==this._visibleDeviceSnapshot&&this._stagedDeviceSnapshotToken!==e)return this._stagedDeviceSnapshotToken=e,void this.requestUpdate();this._continuityPaintToken!==e&&(this._continuityPaintToken=e,this._continuity.candidateReady(e)&&this._continuity.commitAfterPaint(e,{updateComplete:()=>this.updateComplete,stageValid:()=>this.isConnected&&this._continuityStageValid(),assetsReady:()=>this._continuityAssetsReady(),frameFingerprint:()=>this._visualFrameFingerprint()}).then(t=>{t&&e===this._continuity.token?(this._resumeSettling=!1,this._renderSnapshotAt=Date.now(),this._candidateDeviceSnapshot&&(this._visibleDeviceSnapshot=this._candidateDeviceSnapshot),this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._warmSnapshot()):e===this._continuity.token&&(this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._candidateDeviceSnapshot=null,this.requestUpdate())}))}_onBackdropLoaded(e,t){this._signer.markLoaded(this.hass,e,t),this._continuity.note("asset-ready"),this._continuityPaintToken=-1,"steady"!==this._continuity.state&&this.requestUpdate()}_renderRecoveryOverlay(){if(!this._continuity.overlayVisible&&"recovery-error"!==this._continuity.state)return U;const e="connection"===this._continuity.recoveryReason;return j`
e.stopPropagation()} + @click=${e=>e.stopPropagation()} + @wheel=${e=>e.stopPropagation()}> + + ${this._t(e?"continuity.restore_connection":"continuity.restore_plan")} + ${"recovery-error"===this._continuity.state?j``:U} +
`}_renderEditorRuntimeLoading(){return this._editorRuntimeLoadingVisible?j`
+ + ${this._t("editor.loading")} +
`:U}houseplanContinuityTrace(){return[...this._continuityHistory,...this._continuity.trace].slice(-80).map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}getCardSize(){return 12}get _norm(){return!(!this._serverCfg||!this._serverCfg.spaces.length)}_cfgFingerprint(){const e=this._serverCfg?.spaces||[];let t=e.length+":";for(const i of e){t+=(i.id||"")+","+(i.plan_aspect||"")+","+(i.plan_url||"").length+","+(i.plan_x??"")+","+(i.plan_y??"")+","+(i.plan_scale??"")+","+(i.plan_scale_x??"")+","+(i.plan_scale_y??"")+","+(i.plan_angle??"")+","+(i.rooms?.length||0)+","+(i.openings?.length||0)+","+(i.decor?.length||0)+";";for(const e of i.rooms||[]){const i=e.poly?.[0],n=e.poly?.[e.poly.length-1];t+=(e.poly?.length||0)+"."+(e.id||"")+"."+(e.open_to||[]).join("+")+"."+(e.area||"")+"."+JSON.stringify(e.settings||0)+"."+(e.x??"")+","+(e.y??"")+","+(e.w??"")+","+(e.h??"")+","+(i?i[0]+"/"+i[1]:"")+","+(n?n[0]+"/"+n[1]:"")+";"}}return t}get _model(){if(!this._serverCfg)return[];const e=this._cfgEpoch+"|"+this._cfgFingerprint();if(this._modelCache&&this._modelCache.key===e)return this._modelCache.model;const t=this._buildModel();return this._modelCache={key:e,model:t},t}_buildModel(){if(!this._serverCfg)return[];const e=this._renderCfg;return Fa(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?Fl(this._model,this._space):(e=this._model,t=this._space,e.find(e=>e.id===t)??e[0]);var e,t}_spaceModelById(e){return Fl(this._model,e)}_syncEmptySpaceState(){if(!!this._serverCfg&&0===this._serverCfg.spaces.length){if(!this._emptySpaceStateActive){this._emptySpaceStateActive=!0;for(const e of this._pointers.keys())for(const t of this.renderRoot.querySelectorAll("*"))try{t.hasPointerCapture?.(e)&&t.releasePointerCapture(e)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null,this._drag=null,this._rlResize=null,this._vacFit=null,this._compassDrag=!1,this._cancelModeTransition(!1),this._mode="view",this._clearGeometryGesture(),this._geometryHistory.clear(),this._resumeDraftBySpace={},this._tip=null,this._hoverRoom=null,this._openingInfo=null,this._closeInfoCard(),this._deviceInbox=null,this._deviceInboxReturn=null,this._markerDialog=null,this._physicalDialog=null,this._backdropDialog=null,this._decorShapeDialog=null,this._decorTextDialog=null,this._roomDialog=!1,"edit"===this._spaceDialog?.mode&&(this._spaceDialog=null),this._editorSecondary?.closeForNavigation(),this._saveConfigDebounced.cancel(),this._frame=null,this._planSnapGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._decorSnapCache=null,this._commitSpace("",!0)}}else this._emptySpaceStateActive=!1}get _areaToSpace(){const e={};for(const t of this._model)for(const i of t.rooms)i.area&&(e[i.area]={space:t.id,room:i});return e}get _settings(){return this._serverCfg?.settings||{}}get _showAll(){return this._showHidden||!this._settings.filter_seeded&&!!this._settings.show_all}_seedHiddenDevices(){if(!this._serverCfg||!this._norm||!this._canEdit)return;const e=this._serverCfg,t=function(e){const t=e.hass,i=e.registry||Jc(t),n=ih(t,i),r=nh(t,i),{areaToSpace:o,markers:s,settings:a,excluded:l,iconRules:c}=e,h=!1!==a.group_lights,d=Vh(s),u=Nh(n,h).filter(e=>!Uh(n,e.eid,d)),p=new Set(u.map(e=>e.area)),_=ah(n),m=lh(s,r),f=new Set(s.map(e=>e.binding)),g=[];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(f.has("device:"+e.id))continue;if("active"!==sh(t,"device:"+e.id,i).kind)continue;const s=ch(n,e.id,_[e.id]||[],m);if(s.partial&&!s.entityIds.length)continue;const a=s.entityIds,d=hh(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"===Lh(n,t,e.model,a,c)&&(u=!0)}u&&g.push("device:"+e.id)}return g}({hass:this.hass,registry:this._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,firstSpaceId:this._model[0]?.id||"",iconRules:this._iconRules});if(!t.length&&e.settings?.filter_seeded)return;e.markers=e.markers||[];const i=[];for(const n of t){const t="h"+n.slice(n.indexOf(":")+1);e.markers.push({id:t,binding:n,hidden:!0}),i.push(n.slice(n.indexOf(":")+1))}const n={...e.settings||{},filter_seeded:!0};delete n.show_all,i.length&&Array.isArray(n.new_device_ids)&&(n.new_device_ids=n.new_device_ids.filter(e=>!i.includes(e))),e.settings=n,this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate()}get _iconRules(){const e=this._settings.icon_rules;if(!e||!Array.isArray(e)||!e.length)return;const t=JSON.stringify(e);return t!==this._rulesCompiledSrc&&(this._rulesCompiledSrc=t,this._rulesCompiled=De(e)),this._rulesCompiled}get _fillColors(){return sn(this._settings)}get _excluded(){const e=this._settings.exclude_integrations;return e?new Set(e):Te}willUpdate(e){e.has("_serverCfg")&&this._cfgEpoch++,this._syncEmptySpaceState(),e.has("hass")&&this.hass&&(this._hassSequence++,this._renderSnapshotAt=Date.now(),this._continuity.note("hass-snapshot"),this._ensureHaRegistryAuthority(),this._planHassMemo=null,this._hookConnection(),!this._loadOk&&!this._loading&&this._loadTries<8&&this._loadFromServer(),this._maybeRebuildDevices(),this._vacTick(),this._activityTick()),this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._continuity.refreshCompleteFrame(this._visualFrameFingerprint()),this._captureRenderDeviceSnapshot()}updated(){this._pruneDevicePressFeedback(),this._syncDayCycleClock(),this._warmSnapshot(),this._editorRuntime&&this._dtMeasure();const e=this._stageEl;e&&!this._roViewport&&(this._roViewport=new ResizeObserver(()=>this._refitView()),this._roViewport.observe(e)),e&&this._booting&&!this._bootTimer&&this._bootWatch();const t=this.renderRoot.querySelector(".hdr");if(t&&e&&!this._roHdr){const i=()=>{const t=this.renderRoot.querySelector("ha-card");if(!t)return;const i=e.getBoundingClientRect().top-t.getBoundingClientRect().top,n=Math.min(Math.max(t.getBoundingClientRect().top,0),120),r=Math.round(i+n);r>=0&&r!==this._hdrH&&(this._hdrH=r),r>=0&&!this._booting&&!this._config?.kiosk&&e.clientHeight>0&&this._warmPatch({hdrH:r,stageH:e.clientHeight})};this._roHdr=new ResizeObserver(()=>requestAnimationFrame(i)),this._roHdr.observe(t),this._onWinResize=()=>requestAnimationFrame(i),window.addEventListener("resize",this._onWinResize),i()}if(e&&!this._view&&this._refitView(),this._editorSecondary?.afterRender(),this._settleContinuityFrame(),this._serverStorage&&this._loadOk&&0===this._model.length&&!this._spaceDialog&&!this._importDialog&&!this._onboardingShown){this._onboardingShown=!0;const e=function(e){const t=e?.floors;if(!t||"object"!=typeof t)return[];const i=[];for(const e of Object.values(t))e&&e.floor_id&&i.push({id:e.floor_id,name:e.name||e.floor_id,level:e.level??null});return i.sort((e,t)=>{const i=e.level??1e9,n=t.level??1e9;return i!==n?i-n:e.name.localeCompare(t.name)}),i}(this.hass);e.length?this._importDialog={floors:e.map(e=>({...e,checked:!0}))}:this._openSpaceDialog("create")}}_adoptStructuralResponses(e,t,i){const n=e?.config,r=n&&Array.isArray(n.spaces)?n:null,o=zl(r),s=o!==(this._cfgContentFingerprint||zl(this._serverCfg));if(s&&(this._geometryHistory.clear(),this._pendingPhysicalWrites.clear(),this._serverCfg&&this._clearGeometryGesture(),this._serverCfg=r,this._cfgContentFingerprint=o),this._cfgRev=e?.rev??this._cfgRev,e&&("virtual_lights"in e||"config"in e)){const t=Fc(this._virtualLights,e.virtual_lights,this._cfgRev,"virtual_lights"in e);Ic(t)!==Ic(this._virtualLights)&&(this._virtualLights=t,this._capturedSnapshotVirtual="")}let a=!1;if(void 0!==t||void 0!==i){const e=i??t?.layout??{},n=zl(e);a=n!==(this._layoutContentFingerprint||zl(this._layout)),a&&(this._layout=e,this._layoutContentFingerprint=n),this._layoutRev=t?.rev??this._layoutRev}return this._canOptimizeUndo=!(!e?.can_optimize_undo&&!t?.can_optimize_undo),this._haIntegrationVersion="string"==typeof e?.integration_version?e.integration_version:this._haIntegrationVersion,this._undoKind=e?.undo_kind||t?.undo_kind||null,"boolean"==typeof e?.can_write&&(this._serverCanWrite=e.can_write),s&&this._continuity.note("config-candidate",{configRev:this._cfgRev}),a&&this._continuity.note("layout-candidate",{layoutRev:this._layoutRev}),{configChanged:s,layoutChanged:a}}_resumePendingNavMode(){if(!this._pendingNavMode||!this._canEdit||this._config?.kiosk)return!1;const e=this._pendingNavMode;return this._pendingNavMode=null,this._setMode(e,!1),!0}async _loadFromServer(){this._loading=!0,this._loadTries++;const e=this._space,t=!!this._view;try{const[i,n]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]),r=i?.config&&Array.isArray(i.config.spaces)?i.config:null,o=zl(r)!==(this._cfgContentFingerprint||zl(this._serverCfg))||zl(n?.layout??{})!==(this._layoutContentFingerprint||zl(this._layout));if(o){if(!await this._signer.prepareImage(this.hass,this._candidateBackdrop(r)))return this._continuity.note("asset-failed"),void this._scheduleLoadRetry(!0)}o&&this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._beginContinuityCandidate("structural-response",!0),this._connectionWasLost=!1,this._serverStorage=!0,"boolean"==typeof i?.can_write&&(this._serverCanWrite=i.can_write),this._canOptimizeUndo=!(!i?.can_optimize_undo&&!n?.can_optimize_undo),this._haIntegrationVersion="string"==typeof i?.integration_version?i.integration_version:this._haIntegrationVersion,this._adoptStructuralResponses(i,n),this._adoptInitialSpace(this._model,!0),this._resumePendingNavMode(),this._cacheSnapshot(),this._warmVpArmed&&this._space===this._warmVp?.space?this._warmVpArmed=!1:t&&this._space===e||this._restoreZoom(),this._loadOk=!0,this.hass.callWS({type:"houseplan/trail/get"}).then(e=>{this._vacSrvTrails=e?.trails||{},this.requestUpdate()}).catch(()=>{}),this._ensureLiveSyncSubscriptions()}catch(e){if(this._serverCfg)this._scheduleLoadRetry(!0);else if(this._loadTries>=8){this._serverStorage=!1;try{this._layout=JSON.parse(localStorage.getItem(ym)||"{}")||{}}catch{this._layout={}}}}finally{this._loading=!1,this._continuityDataReady=!0,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}}_ensureLiveSyncSubscriptions(){const e=this.hass?.connection;if(!e)return;if(e!==this._liveSyncConnection&&(this._unsubCfg?.(),this._unsubCfg=null,this._unsubLayout?.(),this._unsubLayout=null,this._unsubTrail?.(),this._unsubTrail=void 0,this._unsubVirtual?.(),this._unsubVirtual=null,this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=e),this._liveSyncAttempt)return;const t=this._liveSyncGeneration,i=[],n=(n,r,o,s)=>{n()||i.push(async()=>{const i=await e.subscribeEvents(s,o);t===this._liveSyncGeneration&&this.isConnected&&this.hass?.connection===e&&!n()?r(i):i?.()})};if(n(()=>this._unsubCfg,e=>{this._unsubCfg=e},"houseplan_config_updated",e=>{const t=Number(e?.data?.rev??-1);t!==this._cfgRev&&this._reloadConfigOnly(!1,t)}),n(()=>this._unsubTrail,e=>{this._unsubTrail=e},"houseplan_trail_updated",async()=>{try{const e=await this.hass.callWS({type:"houseplan/trail/get"});this._vacSrvTrails=e?.trails||{},this.requestUpdate()}catch{}}),n(()=>this._unsubLayout,e=>{this._unsubLayout=e},"houseplan_layout_updated",e=>this._onLayoutEvent(Number(e?.data?.rev??-1))),n(()=>this._unsubVirtual,e=>{this._unsubVirtual=e},"houseplan_virtual_light_updated",e=>{const t=Lc(this._virtualLights,e?.data);t!==this._virtualLights&&(this._virtualLights=t,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}),!i.length)return;const r=function(e){return Promise.allSettled(e.map(e=>Promise.resolve().then(e)))}(i).then(()=>{});this._liveSyncAttempt=r,r.finally(()=>{this._liveSyncAttempt===r&&(this._liveSyncAttempt=null)})}async _reloadConfigOnly(e=!1,t){if(!e){if(void 0!==t&&t<=this._cfgRev)return;if(this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(()=>this._reloadConfigOnly(!1,t),400))}this._beginContinuityCandidate("config-reload",!1);try{const e=await this.hass.callWS({type:"houseplan/config/get"}),t=e?.config&&Array.isArray(e.config.spaces)?e.config:null;if(zl(t)!==(this._cfgContentFingerprint||zl(this._serverCfg))&&!await this._signer.prepareImage(this.hass,this._candidateBackdrop(t)))return this._continuity.note("asset-failed"),void this._scheduleLoadRetry(!0);const i=this._space;this._adoptStructuralResponses(e),this._adoptInitialSpace(this._model,!0),this._resumePendingNavMode(),this._cacheSnapshot(),this._space!==i&&this._restoreZoom(),this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}catch(e){this._showToast(this._t("toast.cfg_reload_failed",{err:this._errText(e)}))}finally{this._continuityDataReady=!0,this.requestUpdate()}}_scheduleLoadRetry(e=!1){if(void 0!==this._loadRetryTimer)return;const t=Math.min(8e3,500*2**Math.min(4,Math.max(1,this._loadTries-7)));this._loadRetryTimer=window.setTimeout(()=>{this._loadRetryTimer=void 0,!e&&this._loadOk||this._loading||!this.hass||this._loadFromServer()},t)}_ensureHaRegistryAuthority(){const e=this.hass?.connection||null;e&&e!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=e,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._haRegistryRelease=Xc(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}get _haRegistry(){return Jc(this.hass)}get _planHass(){const e=this._haRegistry,t=eh(this.hass,e),i=this._planHassMemo;if(i&&i.hass===this.hass&&i.sig===t)return i.active;const n=ih(this.hass,e),r=nh(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+Pp)>e?1:0)).join("|"),i=Ic(this._virtualLights);if(this._capturedSnapshotSequence===this._hassSequence&&this._capturedSnapshotDevices===this._devices&&this._capturedSnapshotLayout===this._layout&&this._capturedSnapshotConfigEpoch===this._cfgEpoch&&this._capturedSnapshotVirtual===i&&this._capturedSnapshotActivity===t)return;const n=this._planHass,r=new Map,o=new Map,s=new Set(["sun.sun"]);this._vacFit?.source&&s.add(this._vacFit.source);const a=new Set,l=new Set,c=e=>{if(!e)return;const t=e.indexOf(":");if(t<0)return void s.add(e);const i=e.slice(0,t),n=e.slice(t+1);"device"===i?a.add(n):"entity"===i&&s.add(n)};for(const e of this._model)for(const t of e.rooms)t.area&&l.add(t.area),c(t.settings?.temp_source),c(t.settings?.hum_source);for(const e of this._serverCfg?.spaces||[])for(const t of e.openings||[])for(const e of ri(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=Li(e[1]);t?.entity&&s.add(t.entity)}t.entity&&s.add(t.entity),o.set(`decor:${e.id}:${t.id}`,Vi(t.text,t,n,e=>!!n.entities?.[e]&&!!n.states?.[e]&&!Uh(n,e,Vh(this._markers))))}const h=zh(n,this._devices,null,this._virtualLights);for(const e of this._devices){for(const t of[!1,!0])r.set(Xu(e.id,t),Gu(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?Kl(n?.states?.[t]?.attributes):null,r=this._vacRt.get(e.id);o.set(`vacuum:${e.id}`,{source:t,telemetry:i,mapId:i?this._vacMapId(e,i,n):null,runtime:r?{trail:r.trail,lastTs:r.lastTs,moving:r.moving,jump:r.jump}:null,server:this._vacSrvTrails[e.id]||null})}}const d=Zu({sourceSequence:this._hassSequence,hass:n,devices:this._devices,presentations:r,positions:(u=this._model.length>0,p=this._devices,_=e=>this._livePos(e),u?new Map(p.map(e=>[e.id,_(e)])):new Map),facts:o,entityIds:s,deviceIds:a,areaIds:l});var u,p,_;this._capturedSnapshotSequence=this._hassSequence,this._capturedSnapshotDevices=this._devices,this._capturedSnapshotLayout=this._layout,this._capturedSnapshotActivity=t,this._capturedSnapshotConfigEpoch=this._cfgEpoch,this._capturedSnapshotVirtual=i,this._visibleDeviceSnapshot&&"steady"!==this._continuity.state?this._candidateDeviceSnapshot=d:(this._visibleDeviceSnapshot=d,this._candidateDeviceSnapshot=null)}get _renderDeviceSnapshot(){return this._stagedDeviceSnapshotToken===this._continuity.token?this._candidateDeviceSnapshot||this._visibleDeviceSnapshot:this._visibleDeviceSnapshot||this._candidateDeviceSnapshot}get _renderPlanHass(){return this._renderDeviceSnapshot?.hass||this._planHass}get _renderDevices(){return this._renderDeviceSnapshot?.devices||this._devices}get _fullRegistryHass(){return this._planHass,this._planHassMemo?.full||this.hass}_bindingStatus(e){return sh(this.hass,e,this._haRegistry)}houseplanDiagnostics(){const e=function(e){const t=Jc(e);return{access:t.access,authoritative:t.authoritative,revision:t.revision,lastSuccess:t.lastSuccess,error:t.error}}(this.hass),t={active:0,ha_disabled:0,orphaned:0,unverified:0};for(const e of this._markers)e.removed||"virtual"===e.binding||t[this._bindingStatus(e.binding).kind]++;return{registry:{...e,lastSuccessAgeMs:e.lastSuccess?Math.max(0,Date.now()-e.lastSuccess):null},bindings:t}}_openBindingInHa(e){const[t,i]=e.split(":");if(i)if("device"!==t){if("entity"===t){const e=this._fullRegistryHass.entities?.[i];e?.device_id&&zm("/config/devices/device/"+encodeURIComponent(e.device_id))}}else zm("/config/devices/device/"+encodeURIComponent(i))}_bindingHasHaPage(e){const[t,i]=e.split(":");return!!i&&("device"===t||"entity"===t&&!!this._fullRegistryHass.entities?.[i]?.device_id)}_toggleMarkerDialogVisibility(){const e=this._markerDialog;if(!e)return;const t="ha"===e.bindingMode?this._bindingStatus(e.binding):null,i=e.hideFromPlan||"ha_disabled"===t?.kind;i&&"ha_disabled"===t?.kind?this._showToast(this._t("entity"===t.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device")):i&&"unverified"===t?.kind?this._showToast(this._t("toast.ha_binding_unverified")):this._markerDialog={...e,hideFromPlan:!i}}_hookConnection(){const e=this.hass?.connection;e&&e!==this._connHooked&&(this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),e.addEventListener?.("ready",this._onConnReady),e.addEventListener?.("disconnected",this._onConnLost),e.addEventListener?.("reconnect-error",this._onConnLost),this._connHooked=e)}_display(e){return this._signer.display(this.hass,e)}_resign(){this._signer.resign(this.hass,Mn(this._serverCfg))}_onLayoutEvent(e){e<=this._layoutRev||(clearTimeout(this._layoutSyncTimer),this._layoutSyncTimer=window.setTimeout(()=>{e<=this._layoutRev||this._reloadLayoutOnly()},200))}_noteLayoutRev(e){const t=e?.rev;"number"==typeof t&&t>this._layoutRev&&(this._layoutRev=t)}async _reloadLayoutOnly(){if(!this._serverStorage||!this.hass?.callWS)return;this._beginContinuityCandidate("layout-reload",!1);const e=new Map;for(const t of this._dirtyPos)this._layout[t]&&e.set(t,this._layout[t]);this._persistLayout.pending()&&this._persistLayout.flush();for(const[t,i]of this._sentPos)e.set(t,i);try{const t=await this.hass.callWS({type:"houseplan/layout/get"}),i={...t?.layout||{}};for(const[t,n]of e)i[t]=n;const n=zl(i);n!==(this._layoutContentFingerprint||zl(this._layout))&&(this._layout=i,this._layoutContentFingerprint=n),this._layoutRev=t?.rev??this._layoutRev,this._canOptimizeUndo=!!t?.can_optimize_undo,this._haIntegrationVersion="string"==typeof t?.integration_version?t.integration_version:this._haIntegrationVersion,this._undoKind=t?.undo_kind||null,this._cacheSnapshot(),this.requestUpdate()}catch{}finally{this._continuityDataReady=!0,this.requestUpdate()}}_maybeRebuildDevices(){const e=this.hass;if(!e?.devices||!e?.entities||!e?.areas)return;const t=this._haRegistry,i=eh(e,t)+":"+Object.keys(e.areas).length+":"+(this._norm?"n":"l")+":"+hu(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=Yh({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,sh(e,n,t));!function(e){if("undefined"==typeof localStorage||!e.size)return;const t=oh(),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));Vc=n;try{localStorage.setItem(Bc,JSON.stringify(n))}catch{}}(i),this._haBindingCacheKey=o}this._defPos=this._defaultPositions(),this._syncNewDevices(),this._seedHiddenDevices(),this._syncActivityRuntime();const s=new Set(this._devices.filter(e=>!e.hidden).map(e=>e.id));for(const e of this._vacRt.keys())s.has(e)||this._vacRt.delete(e);if(this._infoCard){const e=this._devices.find(e=>e.id===this._infoCard.id);this._infoCard=e&&"ha_disabled"!==e.bindingStatus?.kind?e:null}const a=this._devices.some(e=>"ha_disabled"===e.bindingStatus?.kind&&"ha_disabled"!==n.get(e.id));a&&("ha_disabled"!==this._infoCard?.bindingStatus?.kind&&"ha_disabled"!==this._devices.find(e=>e.id===this._infoCard?.id)?.bindingStatus?.kind||this._closeInfoCard(),this._drag&&"ha_disabled"===this._devices.find(e=>e.id===this._drag.id)?.bindingStatus?.kind&&(this._drag=null),clearTimeout(this._holdTimer),this._holdFired=!1,this._tip=null,this._tapConfirm=null),this._nativeMoreInfoEntity&&!this._planEntityAvailable(this._nativeMoreInfoEntity)&&(Dm(this,"hass-more-info",{entityId:null}),this._nativeMoreInfoEntity=null)}_syncNewDevices(){if(!this._norm||!this._loadOk||!this._serverCfg)return;const e=this._devices.filter(e=>!e.marker&&!e.virtual).map(e=>e.id).sort(),t=e.join(",");if(t===this._newSyncKey)return;this._newSyncKey=t;const i=this._settings,{fresh:n,known:r}=function(e,t){if(!Array.isArray(t))return{fresh:[],known:[...e]};const i=new Set(t),n=e.filter(e=>!i.has(e));return{fresh:n,known:n.length?[...t,...n]:t}}(e,i.known_devices);if(!Array.isArray(i.known_devices)||n.length){const e=[...new Set([...i.new_device_ids||[],...n])];this._serverCfg={...this._serverCfg,settings:{...i,known_devices:r,new_device_ids:e}},this._saveConfig()}}get _newIds(){const e=this._settings.new_device_ids;return new Set(Array.isArray(e)?e:[])}_ackNewDevice(e){if(!this._newIds.has(e)||!this._serverCfg)return;const t=this._settings;this._serverCfg={...this._serverCfg,settings:{...t,new_device_ids:(t.new_device_ids||[]).filter(t=>t!==e)}},this._saveConfig(),this.requestUpdate()}get _markers(){return this._serverCfg?.markers||[]}_roomLqi(e){if(!e)return null;const t=[];for(const i of this._renderDevices){if(i.area!==e||i.virtual)continue;const n=Ph(this._renderPlanHass,i.entities);null!=n&&t.push(n)}return Ri(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*il(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)}));Ci(p,o,n,.5*s),r.forEach((t,i)=>e[t.id]=Wa(p[i]))}}return e}_pos(e){const t=this._renderDeviceSnapshot?.positions.get(e.id);return t?{x:t.x,y:t.y}:this._livePos(e)}_livePos(e){const t=this._spaceModelById(e.space),i=this._layout[e.id];if(i)if(this._norm){if(i.s===e.space)return{x:i.x*Mm,y:i.y*Mm}}else if(void 0===i.s)return{x:i.x,y:i.y};return this._defPos[e.id]?this._defPos[e.id]:t?Wa(tl(t)):{x:500,y:500}}_savePos(e,t,i){if(this._spaceModelById(e.space)){if(this._norm){const n=this._gridPitch,r=Math.round(t/n)*n,o=Math.round(i/n)*n,s=this._layout[e.id]?.k;this._layout={...this._layout,[e.id]:{s:e.space,x:Ba(r/Mm),y:Ba(o/Mm),...s?{k:s}:{}}}}else this._layout={...this._layout,[e.id]:{x:Math.round(t),y:Math.round(i)}};this._dirtyPos.add(e.id),this._persistLayout()}}_visualSamples(e){return Wu(this._renderPlanHass,e,this._renderDevices,void 0,this._fullRegistryHass).samples}_devicePresentation(e,t=!1!==this._config?.show_signal,i=!1){const n=i?null:this._renderDeviceSnapshot?.presentations.get(Xu(e.id,t));return n||Gu(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,Uu({...i,visual:t}).join(" "))}_liveTemp(e){if(!this._config?.show_temperature)return null;if(!0===e.marker?.use_climate_temp){const t=Eh(this._renderPlanHass,e.entities);if(null!=t)return t}return"mdi:thermometer"!==e.icon&&"mdi:air-filter"!==e.icon?null:Fh(this._renderPlanHass,e.entities)}_bindingEntities(e){if("virtual"===e||!e)return[];const t=this._bindingStatus(e);return"active"===t.kind?t.enabledEntityIds:t.allEntityIds}_bindingHasClimate(e){return this._bindingEntities(e).some(e=>e.startsWith("climate."))}_bindingHasAlarm(e){return this._bindingEntities(e).some(e=>{const t=this._planHass?.states?.[e]||this.hass?.states?.[e],i=this._fullRegistryHass.entities[e]||this.hass?.entities?.[e];return In(e.split(".")[0],t?.attributes?.device_class||i?.device_class||i?.original_device_class)})}_liveHum(e){return this._config?.show_temperature&&e.primary&&Ih(this.hass,e.primary)?Hh(this.hass,e.entities):null}_deviceBindingActive(e,t=!0){if(e.virtual||"virtual"===e.bindingKind)return!0;if(!e.bindingKind||!e.bindingRef)return!1;const i=this._bindingStatus(`${e.bindingKind}:${e.bindingRef}`);return"active"===i.kind||(t&&this._showToast(this._t("ha_disabled"===i.kind?"toast.ha_disabled_action":"toast.ha_binding_unverified")),!1)}_openMoreInfo(e){e?this._planEntityAvailable(e)?(this._nativeMoreInfoEntity=e,Dm(this,"hass-more-info",{entityId:e})):this._showToast(this._t("toast.ha_disabled_action")):this._showToast(this._t("toast.no_entity"))}_interruptViewGesture(e,t){if(clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),void 0!==e)for(const i of[t,this._stageEl])try{i?.hasPointerCapture?.(e)&&i.releasePointerCapture(e)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null}_closeInfoCard(){this._interruptViewGesture(),this._holdFired=!1,this._infoCard=null}_ctxDevice(e,t){"view"===this._mode&&(e.preventDefault(),e.stopPropagation(),this._deviceBindingActive(t)&&(t.primary?this._openMoreInfo(t.primary):this._infoCard=t))}_clickDevice(e,t){if(e.stopPropagation(),this._drag?.moved||this._suppressClick||this._holdFired)return;if("plan"===this._mode)return;if("devices"===this._mode)return void this._openMarkerDialog(t);const i=this._devices.find(e=>e.id===t.id);if(!i)return;const n=wd(i.tapAction,i.primary?.split(".")[0]),r=(e,t)=>{i.marker?.tap_confirm?this._tapConfirm={kind:"run",text:e,exec:t}:t()};if("toggle"===n){const e=this._toggleIntent(i);if(!e)return;if(!Rd(e))return void this._showUnavailableToggleTargets(e);const t=e=>{const t=Rd(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=Lc(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&&!Rd(r)&&this._showUnavailableToggleTargets(r)||(r&&Cd(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||Rd(e)||"configured-targets-missing"!==e.noneReason)return[];if(!e.skippedTargets.length||e.skippedTargets.some(e=>!Td.has(e.reason)&&"secure"!==e.reason))return[];const t=[],i=new Set;for(const n of e.skippedTargets){if(!Td.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 du(hu(this.hass,this._config?.language),e,t)}get _colorPickerLabels(){return{title:this._t("color_picker.title"),hue:this._t("color_picker.hue"),saturation:this._t("color_picker.saturation"),value:this._t("color_picker.value"),hex:this._t("color_picker.hex"),invalidHex:this._t("color_picker.invalid_hex")}}_help(e){return this._editorRuntimeOrThrow()._help(e)}get _stageEl(){return this.renderRoot.querySelector(".stage")}_contentItems(e){const t=[];for(const i of this._devices){if(i.space!==e.id||i.hidden)continue;const n=this._pos(i);t.push({minX:n.x,minY:n.y,maxX:n.x,maxY:n.y})}if(e.id===this._space){for(const e of this._openingsR){const i=Number(e.angle)*Math.PI/180,n=Math.cos(i)*e.rlen/2,r=Math.sin(i)*e.rlen/2,o=Ga([[e.rx-n,e.ry-r],[e.rx+n,e.ry+r]]);o&&t.push(o)}const i=this._decorH;for(const e of this._decorList){const n=Ga("line"===e.kind?[[e.x1*Mm,e.y1*i],[e.x2*Mm,e.y2*i]]:"text"===e.kind?[[e.x*Mm,e.y*i]]:kr({x:e.x*Mm,y:e.y*i,w:e.w*Mm,h:e.h*i,angle:e.angle}));n&&t.push(n)}for(const i of this._physicalBodiesR(e)){const e=Ga(i);e&&t.push(e)}}return Ya(e,t)}_frameOf(){const e=this._spaceModel();if(!e){this._frame=null;const e={x:0,y:0,w:Mm,h:Mm};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=Qa(this._contentItems(e));let r=n.all||el(e),o=this._showFar?r:n.core||el(e);return t&&t.id===e.id&&i&&t.grow&&(o=Tm(t.rect,o),r=Tm(t.all,r)),this._frame={id:e.id,model:e,layout:this._layout,devs:this._devices,far:this._showFar,grow:i,rect:o,all:r,outliers:n.outliers},this._frame}_isoSource(){const e=this._spaceModel();if(!e)return null;const t=this._spaceWalls,i=this._openCuts(),n=this._openingsR.map((e,t)=>({id:String(e.id||t),sourceIndex:t,type:e.type,x:e.rx,y:e.ry,angle:Number(e.angle)||0,length:e.rlen>0?e.rlen:900,flipH:!!e.flip_h,flipV:!!e.flip_v})),r=Sa(64,this._cellCm),o=Sa(10,this._cellCm),s=`${e.id}|${function(e){let t=2166136261;const i=e=>{if("number"!=typeof e)if("string"!=typeof e)if("boolean"!=typeof e)if(Array.isArray(e)){t=G_(t,e.length);for(const t of e)i(t)}else{if(e&&"object"==typeof e){const t=e;for(const e of Object.keys(t).sort())i(e),i(t[e]);return}t=G_(t,-1)}else t=G_(t,e?1:0);else for(const i of e)t=G_(t,i.codePointAt(0)||0);else t=G_(t,e)};return i(e),t.toString(36)}({rooms:e.rooms,walls:t,openCuts:i,openings:n,partitions:e.partitions,roomDrafts:e.room_drafts,columns:e.wall_columns,cellCm:this._cellCm,gridPitch:this._gridPitch,wallKeyPitch:this._wallKeyPitch,camera:F_,wallHeight:r,floorEdgeHeight:o,algorithm:3})}`;return{key:s,build:()=>{const o=da(e,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(e)).all,s=this._roomWallOpeningInputs(this._openingsR,e),a=t.length||o.length?Ns(e.rooms,t,i,s,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm,o):null;if(a&&("failed-core"===a.status||"not-applicable"===a.status))throw new Error("wall boolean geometry failed");const l=a?.paperGeom??Fs(e.rooms,t,i,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm);if(!l)throw new Error("floor boolean geometry failed");const c=a?.openingIndex||Bs(e.rooms,t,i,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm),h=n.map(e=>{const i=this._openingsR[e.sourceIndex],n="gate"===e.type?!e.flipV:e.flipV,o=i?.partitionHost?Hd(i.partitionHost,n):t.length||"gate"===e.type?Ks(c,{x:e.x,y:e.y,angle:e.angle,length:e.length,flip_v:n}):{ox:0,oy:0,cm:0,side:-1};return function(e,t=64){if(!(K_([e.x,e.y,e.angle,e.length,e.face.ox,e.face.oy,t])&&e.length>0&&t>0))throw new Error("invalid isometric opening input");const i=e.length/2;let n;if("passage"===e.type)n=[];else if("gate"===e.type){const r=10*e.face.side;n=[Z_(e,0,[-i,0],[i,0],r,0,.88*t),Z_(e,1,[i,0],[-i,0],-r,0,.88*t)]}else n="window"===e.type?[Z_(e,0,[-i,0],[i,0],-90,.27*t,.78*t),Z_(e,1,[i,0],[-i,0],90,.27*t,.78*t)]:[Z_(e,0,[-i,0],[e.length,0],-90,0,.92*t)];return{id:e.id,sourceIndex:e.sourceIndex,type:e.type,leaves:Object.freeze(n.map(e=>Object.freeze(e)))}}({...e,face:o},r)});return{walls:a?.components.flatMap(e=>e.geom)||[],floor:l,openings:Object.freeze(h)}}}}_isoSceneKey(){if(!this._labsIso||"view"!==this._mode)return null;try{return this._isoSource()?.key??null}catch{return`${this._space}|invalid`}}_isoScene(){const e=this._isoSource();if(!e)return null;const t=this._isoGeometryCache.get(e.key);if(t)return{key:e.key,...t};const i=this._frameOf().rect,n=e.build(),r=Sa(64,this._cellCm),o=Sa(10,this._cellCm),s=function(e){let t=1/0,i=1/0,n=-1/0,r=-1/0;for(const o of e)for(const e of o.leaves){const o=Math.hypot(e.closedVector[0],e.closedVector[1]);t=Math.min(t,e.hinge[0]-o),i=Math.min(i,e.hinge[1]-o),n=Math.max(n,e.hinge[0]+o),r=Math.max(r,e.hinge[1]+o)}return K_([t,i,n,r])?{x:t,y:i,w:n-t,h:r-i}:null}(n.openings),a=L_({rect:s?Tm(i,s):i,wallHeight:r,openingHeight:r,floorDepth:o}),l=function(e,t=F_,i=64){if(!Number.isFinite(i)||i<0)throw new Error("invalid wall height");const n=[],r=[],o=[];let s=0;for(let a=0;a<(e||[]).length;a++){const l=e[a];for(let e=0;e<(l||[]).length;e++){const c=j_(l[e],e>0);if(!(c.length<3||Math.abs(W_(c))<1e-9)){n.push(B_(c,t,i)),s+=c.length;for(let n=0;ne.depth-t.depth||e.polygon-t.polygon||e.ring-t.ring||e.edge-t.edge),{topPath:n.join(" "),sides:r,contactPath:o.join(" "),edgeCount:s}}(n.walls,F_,r),c={geometry:l,floor:U_(n.floor,o),openings:n.openings,frame:a};return _m(this._isoGeometryCache,e.key,c,8),{key:e.key,...c}}_effectiveProjection(){if("iso"!==this._desiredProjection||!this._model.length)return"flat";const e=this._isoSceneKey()||`${this._space}|invalid`;if(this._isoFallback.has(e))return"flat";try{const e=this._isoScene();return e?(t="iso",i=e.key,n=this._isoFallback,"iso"===t&&i&&!n.has(i)?"iso":"flat"):"flat"}catch(t){if(!this._isoFallback.has(e)){this._isoFallback.add(e);const i=e.split("|");console.warn(`HOUSEPLAN ISO FALLBACK: #89, space ${this._space}, fingerprint ${i[i.length-1]}, ${t instanceof Error?t.message:"renderer error"}`)}return"flat"}var t,i,n}_scenePoint(e){return"iso"===this._renderProjection?I_(e,0):e}_floorView(e){if("iso"!==this._renderProjection)return e;const t=H_([e.x,e.y]),i=H_([e.x+e.w,e.y+e.h]);return{x:t[0],y:t[1],w:i[0]-t[0],h:i[1]-t[1]}}_baseVb(){if("iso"===this._effectiveProjection()){if(!this._spaceDisplayForRender().showBorders){const e=L_({rect:this._frameOf().rect,wallHeight:Sa(64,this._cellCm)});return[e.x,e.y,e.w,e.h]}const e=this._isoScene()?.frame??this._frameOf().rect;return[e.x,e.y,e.w,e.h]}const e=this._frameOf().rect;return[e.x,e.y,e.w,e.h]}get _outliers(){return this._showFar?0:this._frameOf().outliers}_fitFar(){this._showFar=!0,this._frame=null,this._resetZoom()}_fitAll(){this._showFar=!0,this._frame=null,this._resetZoom()}_renderFarHint(){return this._kiosk||"view"!==this._mode||this._booting||!this._outliers?U:j`
+ + ${this._t("canvas.far_objects",{n:this._outliers})} + +
`}_renderHomeArrow(){if(this._booting)return U;const e=this._view;if(!e||!e.w||!e.h)return U;const t=this._baseVb(),i=t[0],n=t[1],r=t[2],o=t[3];if(!(i+r<=e.x||i>=e.x+e.w||n+o<=e.y||n>=e.y+e.h))return U;const s=Math.atan2(n+o/2-(e.y+e.h/2),i+r/2-(e.x+e.w/2)),a=50+38*Math.cos(s),l=50+38*Math.sin(s);return j``}_stageAspect(){const e=this._stageEl,t=this._baseVb();return e&&e.clientHeight?e.clientWidth/e.clientHeight:t[2]/t[3]}_viewOr(e){return this._view&&this._view.w?this._view:Ti(e,this._stageAspect())}_roomLabelReferenceViewWidth(e){if(!this._markup)return e.w;const t=this._stageEl,i=this.renderRoot.querySelector(".editorchrome");if(!t||t.clientWidth<=0||t.clientHeight<=0)return e.w;const n=t.clientHeight+(i?.getBoundingClientRect().height||0);return n<=0?e.w:this._viewForModeTarget(this._zoom,void 0,void 0,t.clientWidth,n).w}_screenToVb(e,t){const i=this._stageEl,n=this._viewOr(this._baseVb()),r=i?.clientWidth||1,o=i?.clientHeight||1;return[n.x+e/r*n.w,n.y+t/o*n.h]}_clampView(e,t){const i=(e,t,i,n)=>{const r=1*Math.max(t,n),o=i-r,s=i+n-t+r;return Math.max(Math.min(o,s),Math.min(Math.max(o,s),e))};return{w:e.w,h:e.h,x:i(e.x,e.w,t.x,t.w),y:i(e.y,e.h,t.y,t.h)}}_applyView(e,t,i){const n=this._baseVb(),r=Ti(n,this._stageAspect()),o=Math.min(Pm.ZOOM_MAX,Math.max(Pm.ZOOM_MIN,e)),s=r.w/o,a=r.h/o,l=this._viewOr(n),c=t??l.x+l.w/2,h=i??l.y+l.h/2,d=this._clampView({x:c-s/2,y:h-a/2,w:s,h:a},r);return!(this._view&&Math.abs(this._zoom-o)<1e-9&&Math.abs(this._view.x-d.x)<1e-6&&Math.abs(this._view.y-d.y)<1e-6&&Math.abs(this._view.w-d.w)<1e-6&&Math.abs(this._view.h-d.h)<1e-6)&&("opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1)),this._zoom=o,this._view=d,!0)}_bootWatch(){clearTimeout(this._bootTimer),this._bootStart=Date.now(),this._bootLastH=-1,this._bootLastChange=this._bootStart;const e=()=>{if(!this._booting)return;const t=Date.now(),i=this._stageEl?this._stageEl.clientHeight:0;i!==this._bootLastH&&(this._bootLastH=i,this._bootLastChange=t);const n=t-this._bootStart;n>=1200||n>=700&&i>0&&t-this._bootLastChange>=250?this._bootSettled():this._bootTimer=window.setTimeout(e,100)};this._bootTimer=window.setTimeout(e,100)}_bootSettled(){this._booting&&!this._bootSettling&&(this._bootSettling=!0,this._refitView(),this._bootSettleRaf=requestAnimationFrame(()=>{this._bootSettleRaf=0,this._finishBootSettled()}))}_finishBootSettled(){if(!this._booting)return;this._refitView(),this._booting=!1,this._bootSettling=!1;const e=this._stageEl?.clientHeight??0;!this._config?.kiosk&&e>0&&this._warmPatch({hdrH:this._hdrH,stageH:e,vp:this._warmViewportState()},!0),this._bootFading=!0,this._bootTimer=window.setTimeout(()=>{this._bootFading=!1},220),this._bootSoft=!0,clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},um)}_bootSoftCancel(){this._bootSoft&&(clearTimeout(this._bootSoftTimer),this._bootSoft=!1)}_beginResumeSettle(){this._booting||this._resumeSettling||(this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:this._cancelModeTransition(!0),this._viewportInvalidAt=0,this._beginContinuityCandidate("warm-resume",!1),this._loading?this.requestUpdate():this._loadFromServer())}_refitView(){if(this._modeTransitionBusy||this._warmModeRequest)return;const e=this._stageEl;if(!e||"visible"!==document.visibilityState||e.clientWidth<=0||e.clientHeight<=0)return void(this._viewportInvalidAt||(this._viewportInvalidAt=Date.now()));const t=[e.clientWidth,e.clientHeight],i=this._lastValidStageSize,n=!!i&&Math.abs(i[0]-t[0])<=.5&&Math.abs(i[1]-t[1])<=.5,r=this._viewportInvalidAt?Date.now()-this._viewportInvalidAt:0;if(this._viewportInvalidAt=0,!i)return this._lastValidStageSize=t,void(this._view||this._applyView(this._zoom));n?this._pendingRefitSize=null:(this._pendingRefitSize=t,this._refitRaf||(this._refitRaf=requestAnimationFrame(()=>{this._refitRaf=0;const e=this._pendingRefitSize;this._pendingRefitSize=null;const t=this._stageEl;if(!e||!t||t.clientWidth<=0||t.clientHeight<=0)return;if(Math.abs(t.clientWidth-e[0])>.5||Math.abs(t.clientHeight-e[1])>.5)return void this._refitView();const i=this._lastValidStageSize;if(i&&Math.abs(i[0]-e[0])<=.5&&Math.abs(i[1]-e[1])<=.5)return;this._lastValidStageSize=e;const n=this._view;r>=Sl?this._beginContinuityCandidate("stage-size-restored",!0,"stage-size"):this._continuity.hasCompleteFrame&&this._beginContinuityCandidate("stage-resize",!0,"stage-size"),this._applyView(this._zoom,n?n.x+n.w/2:void 0,n?n.y+n.h/2:void 0)})))}_zoomAt(e,t,i){const n=this._stageEl;if(!n)return;const r=Ti(this._baseVb(),this._stageAspect()),o=Math.min(Pm.ZOOM_MAX,Math.max(Pm.ZOOM_MIN,i));"opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1));const s=n.clientWidth,a=n.clientHeight,l=this._screenToVb(e,t),c=r.w/o,h=r.h/o;this._zoom=o,this._view=this._clampView({x:l[0]-e/s*c,y:l[1]-t/a*h,w:c,h:h},r)}_onWheel(e){const t=this._stageEl;if(!t)return;e.preventDefault();const i=t.getBoundingClientRect(),n=e.deltaY<0?1.15:1/1.15;this._zoomAt(e.clientX-i.left,e.clientY-i.top,this._zoom*n),this._saveZoom()}_stepZoom(e){const t=this._stageEl;t&&(this._zoomAt(t.clientWidth/2,t.clientHeight/2,this._zoom*(e>0?1.4:1/1.4)),this._saveZoom())}_resetZoom(){const e=this._baseVb();"opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1)),this._zoom=1,this._view=Ti(e,this._stageAspect()),this._saveZoom()}_saveZoom(){if("view"===this._mode){this._zoomBySpace={...this._zoomBySpace,[this._space]:this._zoom};try{localStorage.setItem(wm,JSON.stringify(this._zoomBySpace))}catch{}}}_restoreZoom(){const e=this._zoomBySpace[this._space]||1;this._zoom=e;const t=this._stageEl;if(t&&t.clientHeight){const t=this._baseVb();return this._applyView(e,t[0]+t[2]/2,t[1]+t[3]/2),void this.requestUpdate()}this._view=null,requestAnimationFrame(()=>{if(!this._stageEl)return;const t=this._baseVb();this._applyView(e,t[0]+t[2]/2,t[1]+t[3]/2),this.requestUpdate()})}_stagePointerDown(e){if(this._vacFit)return;if(this._kiosk&&(this._cyclePausedUntil=Date.now()+6e4,0===this._pointers.size?(this._swipeStart={x:e.clientX,y:e.clientY,id:e.pointerId},e.target.closest?.(".dev, .roomlabel, .oplock")||(clearTimeout(this._kioskHoldTimer),this._kioskHoldTimer=window.setTimeout(()=>{this._kioskDialog=!0,this._swipeStart=null},3e3))):(this._swipeStart=null,clearTimeout(this._kioskHoldTimer))),this._drag)return;if(this._markup&&e.target.closest?.(".roomlabel, .rlhandle, .rszhandle, .dev, .oplock, .op-hit, button"))return;if("devices"===this._mode&&e.target.closest(".dev"))return;if("decor"===this._mode&&this._decorPointerDown(e))return;this._pointers.set(e.pointerId,{x:e.clientX,y:e.clientY});const t=this._viewOr(this._baseVb());if(1===this._pointers.size)this._panStart={sx:e.clientX,sy:e.clientY,vx:t.x,vy:t.y},this._panLock=null,this._suppressClick=!1;else if(2===this._pointers.size){"opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover();const e=[...this._pointers.values()],t=Math.hypot(e[0].x-e[1].x,e[0].y-e[1].y);this._pinchStart={dist:t,zoom:this._zoom},this._panStart=null,this._panLock=null}}get _swipeZone(){return!this._hasFixedFloor&&this._kiosk&&this._zoom<=1.001&&this._model.length>1}_stagePointerMove(e){if(this._physicalRotate?.pid!==e.pointerId)if(this._physicalDrag?.pid!==e.pointerId)if(this._dtDrag?.pid!==e.pointerId)if(this._bdDrag?.pid!==e.pointerId){if(this._decorDraft?.pid===e.pointerId){const t=this._decorDraft;let i=this._decorSnap(this._svgPoint(e),e.pointerType);if(e.shiftKey&&("rect"===t.kind||"ellipse"===t.kind)){const e=i[0]-t.a[0],n=i[1]-t.a[1],r=Math.max(Math.abs(e),Math.abs(n));i=this._snap([t.a[0]+(e<0?-r:r),t.a[1]+(n<0?-r:r)])}return void(this._decorDraft={...t,b:i})}if(this._decorMove?.pid!==e.pointerId)if(this._pointers.has(e.pointerId)){if(this._pointers.set(e.pointerId,{x:e.clientX,y:e.clientY}),this._markup&&1===this._pointers.size&&this._markupMove(e),this._pinchStart&&this._pointers.size>=2){"opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover();const e=[...this._pointers.values()],t=Math.hypot(e[0].x-e[1].x,e[0].y-e[1].y)/(this._pinchStart.dist||1),i=this._stageEl.getBoundingClientRect(),n=(e[0].x+e[1].x)/2-i.left,r=(e[0].y+e[1].y)/2-i.top;this._zoomAt(n,r,this._pinchStart.zoom*t),this._suppressClick=!0,this._saveZoom()}else if(this._panStart){const t=e.clientX-this._panStart.sx,i=e.clientY-this._panStart.sy;Math.abs(t)+Math.abs(i)>4&&(this._suppressClick=!0,clearTimeout(this._holdTimer),"opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover()),null===this._panLock&&Math.abs(t)+Math.abs(i)>8&&(this._panLock=this._swipeZone&&Math.abs(t)>1.5*Math.abs(i)?"swipe":"pan");const n=this._stageEl;if("pan"===this._panLock&&n){const e=this._baseVb(),r=this._viewOr(e),o=Ti(e,this._stageAspect());this._view=this._clampView({x:this._panStart.vx-t/(n.clientWidth||1)*r.w,y:this._panStart.vy-i/(n.clientHeight||1)*r.h,w:r.w,h:r.h},o)}}}else this._markupMove(e);else this._decorMoveUpdate(e)}else this._bdMove(e);else this._dtMove(e);else this._physicalMove(e);else this._physicalRotateMove(e)}_stagePointerLeave(e){this._markup&&("opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover())}_stagePointerUp(e){if(this._kiosk){clearTimeout(this._kioskHoldTimer);const t=this._swipeStart;if(this._swipeStart=null,t&&t.id===e.pointerId){const i=e.clientX-t.x,n=e.clientY-t.y;if(Math.abs(i)+Math.abs(n)<8){const e=Date.now();e-this._lastTap<350&&this._resetZoom(),this._lastTap=e}const r="pan"===this._panLock?null:function(e,t,i,n,r,o=60){if(i>1.001||n.length<2)return null;if(Math.abs(e)e.id),this._space);r&&this._slideTo(r,i<0?"left":"right")&&(this._saveNav(),this._suppressClick=!0,setTimeout(()=>this._suppressClick=!1,0),this._showKioskDots())}}if(this._physicalDrag?.pid===e.pointerId)return void this._physicalUp(e);if(this._physicalRotate?.pid===e.pointerId)return void this._physicalRotateUp(e);if(this._dtDrag?.pid===e.pointerId)return void this._dtUp();if(this._bdDrag?.pid===e.pointerId)return void this._bdUp();if(this._decorDraft?.pid===e.pointerId)return void this._decorCommitDraft();if(this._decorMove?.pid===e.pointerId)return this._decorMove.moved&&(this._recordGeometry(this._t("history.decor_move"),this._decorMove.before),this._saveConfig()),void(this._decorMove=null);const t=!!this._pinchStart||!!this._panStart;this._pointers.delete(e.pointerId),this._pointers.size<2&&(this._pinchStart=null),0===this._pointers.size&&(this._panStart=null,this._panLock=null,setTimeout(()=>this._suppressClick=!1,0)),t&&0===this._pointers.size&&this.requestUpdate()}_clickRoom(e){!this._suppressClick&&e.area&&zm("/config/areas/area/"+e.area)}_pointerDown(e,t){if("plan"===this._mode)return;if("view"===this._mode){this._holdFired=!1,clearTimeout(this._holdTimer);const i=e.pointerId,n=e.currentTarget;return void(this._holdTimer=window.setTimeout(()=>{this._holdFired=!0,this._interruptViewGesture(i,n),this._infoCard=t},600))}if("ha_disabled"===t.bindingStatus?.kind)return;e.preventDefault();const i=this._pos(t);this._drag={id:t.id,sx:e.clientX,sy:e.clientY,ox:i.x,oy:i.y,moved:!1},Om(e),this._tip=null}_pointerMove(e,t){if(!this._drag||this._drag.id!==t.id)return;const i=this.renderRoot.querySelector(".stage");if(!i)return;const n=this._baseVb(),r=i.getBoundingClientRect(),o=this._viewOr(n),s=(e.clientX-this._drag.sx)/r.width*o.w,a=(e.clientY-this._drag.sy)/r.height*o.h;Math.abs(e.clientX-this._drag.sx)+Math.abs(e.clientY-this._drag.sy)>3&&(this._drag.moved=!0,clearTimeout(this._holdTimer));const l=ja(this._drag.ox+s),c=ja(this._drag.oy+a);this._savePos(t,l,c)}_pointerUp(e,t){if(clearTimeout(this._holdTimer),!this._drag||this._drag.id!==t.id)return;const i=this._drag.moved;this._drag=i?this._drag:null,i&&(this._selId=t.id,window.setTimeout(()=>this._drag=null,0))}_showToast(e){for(const e of this.renderRoot.querySelectorAll("hp-dialog"))e.closeTransientOverlays("toast");this._toast=e,clearTimeout(this._toastTimer),this._toastTimer=window.setTimeout(()=>{this._toast=""},3500)}_syncPointerHoverTargets(){const e=this._pointerModality.hoverEnabled;for(const t of this.renderRoot.querySelectorAll(Sm))t.toggleAttribute("data-pointer-hover",e)}_syncPointerHoverSubtree(e){if(e.nodeType!==Node.ELEMENT_NODE)return;const t=e,i=this._pointerModality.hoverEnabled;t.matches(Sm)&&t.toggleAttribute("data-pointer-hover",i);for(const e of t.querySelectorAll(Sm))e.toggleAttribute("data-pointer-hover",i)}_clearTransientHover(e=!1){e&&this._pointerModality.suspend(),this._tip&&(this._tip=null),this._hoverRoom&&(this._hoverRoom=null)}_notePointer(e){const t=this._pointerModality.modality,i=this._pointerModality.note(e);"touch"!==i&&"pen"!==i||t===i&&!this._tip&&!this._hoverRoom||this._clearTransientHover()}_guardTouchGesture(e){if(this._editorSecondary?.handleOutsideDismiss(e))return;if("click"===e.type){if(!this._suppressClick&&!this._touchSequenceMultitouch&&Date.now()>this._touchClickBlockUntil)return;return e.preventDefault(),void e.stopImmediatePropagation()}const t=e;if(this._notePointer(t),"touch"===t.pointerType)if("pointerdown"!==e.type){if("pointermove"===e.type){const e=this._touchContacts.get(t.pointerId);if(!e)return;const i={...e,x:t.clientX,y:t.clientY};if(this._touchContacts.set(t.pointerId,i),this._touchSequenceMultitouch&&"view"===this._mode&&!this._vacFit&&this._pinchStart&&[...this._touchContacts.values()].every(e=>e.inStage)){this._pointers.set(t.pointerId,{x:t.clientX,y:t.clientY});const e=[...this._touchContacts.values()];if(e.length>=2&&this._stageEl){const[t,i]=e,n=Math.hypot(t.x-i.x,t.y-i.y)/(this._pinchStart.dist||1),r=this._stageEl.getBoundingClientRect();this._zoomAt((t.x+i.x)/2-r.left,(t.y+i.y)/2-r.top,this._pinchStart.zoom*n),this._saveZoom()}}return}if("pointerup"===e.type||"pointercancel"===e.type||"lostpointercapture"===e.type){if(this._clearTransientHover(),this._touchContacts.delete(t.pointerId),this._touchSequenceMultitouch){if(this._touchClickBlockUntil=Date.now()+500,this._pointers.delete(t.pointerId),!this._vacFit&&this._pointers.size>=2){const[e,t]=[...this._pointers.values()];this._pinchStart={dist:Math.hypot(e.x-t.x,e.y-t.y),zoom:this._zoom}}else this._pinchStart=null;0===this._pointers.size&&(this._panStart=null,this._panLock=null)}0===this._touchContacts.size&&(this._touchSequenceMultitouch=!1)}}else if(this._touchContacts.set(t.pointerId,{x:t.clientX,y:t.clientY,inStage:!!t.target?.closest?.(".stage")}),this._touchContacts.size>=2){this._clearTransientHover(),this._touchSequenceMultitouch=!0,this._touchClickBlockUntil=Number.POSITIVE_INFINITY,clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),this._swipeStart=null;const e=[...this._touchContacts.values()];if("view"===this._mode&&!this._vacFit&&e.every(e=>e.inStage)){this._pointers=new Map([...this._touchContacts].map(([e,t])=>[e,{x:t.x,y:t.y}]));const[t,i]=e;this._pinchStart={dist:Math.hypot(t.x-i.x,t.y-i.y),zoom:this._zoom},this._panStart=null,this._panLock=null}else this._vacFit&&(this._pointers.clear(),this._pinchStart=null,this._panStart=null,this._panLock=null)}}_showTip(e,t,i,n,r,o){this._notePointer(e),this._pointerModality.hoverEnabled&&(this._drag||(this._tip={x:e.clientX,y:e.clientY,title:t,meta:i,lqi:n,temp:r,hum:o}))}get _gridPitch(){return Na}get _cellCm(){const e=Number(this._curSpaceCfg?.cell_cm);return Number.isFinite(e)&&e>0?e:5}_fmtLen(e,t){const i=function(e,t,i,n){return Math.hypot(t[0]-e[0],t[1]-e[1])/i*n}(e,t,this._gridPitch,this._cellCm);return Kt(i,"mi"===this.hass?.config?.unit_system?.length)}get _curSpaceCfg(){const e=this._resize?.preview;return e&&e.space===this._space?e.sp:this._serverCfg?.spaces.find(e=>e.id===this._space)}get _renderCfg(){const e=this._resize?.preview;return e&&this._serverCfg?{...this._serverCfg,spaces:this._serverCfg.spaces.map(t=>t.id===e.space?e.sp:t)}:this._serverCfg}get _spaceH(){return this._curSpaceCfg,Mm}get _segments(){const e=this._curSpaceCfg,t=this._spaceH;return Jt(e?.rooms||[]).map(e=>[e[0]*Mm,e[1]*t,e[2]*Mm,e[3]*t])}_savedNav(){if(this._hasFixedFloor)return null;try{return JSON.parse(localStorage.getItem(km)||"null")}catch{return null}}_saveNav(){if(!this._hasFixedFloor)try{localStorage.setItem(km,JSON.stringify({space:this._space}))}catch{}}_leaveCardRoute(){if(this._routeDepartureHandled)return;this._routeDepartureHandled=!0,"view"!==this._mode&&this._setMode("view",!1),this._pendingNavMode=null,this._geometryHistory.clear(),this._activeDraftId=null,this._resumeDraftBySpace={},this._draftSegmentCms=[],this._closingWallCm=null,this._drawWallField=null,this._showHidden=!1,this._tapConfirm=null,this._vacCalConfirm=null,this._decorEraseConfirm=null,this._openingInfo=null,this._closeInfoCard(),this._rulesDialog=null,this._alignDialog=null,this._preflightClipboardFallback=null,this._backupImportDialog=null,this._backupExportDialog=null,this._settingsDialog=null,this._deviceInbox=null,this._deviceInboxReturn=null,this._markerDialog=null,this._openingDialog=null,this._physicalDialog=null,this._wallDialog=null,this._backdropDialog=null,this._decorShapeDialog=null,this._decorTextDialog=null,this._mergeDialog=null,this._roomDialog=!1,this._spaceDialog=null,this._importDialog=null;const e=this._warmSlot;e?.owner===this._warmGen&&(e.vp=this._warmViewportState(),e.dlg=null,e.frameFingerprint="",clearTimeout(e.evict),e.evict=0),this._saveNav()}_setMode(e,t=!0){return this._warmModeRequest=0,this._editorRuntime?this._editorRuntime._setMode(e,t):"view"===e?void this._editorModeRequest++:void this._requestMode(e,t)}_primeDrawWallField(){return this._editorRuntimeOrThrow()._primeDrawWallField()}get _drawWallFieldValue(){return null===this._drawWallField?vo(15,this._imperial):this._drawWallField}get _drawWallCm(){const e=(e=>{const t=String(e??"").trim().replace(",",".");if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(t))return null;const i=Number(t);return Number.isFinite(i)?i:null})(this._drawWallFieldValue);if(null==e||e<0)return null;const t=this._imperial?2.54*e:e,i="column"===this._tool?Js:100;return t>=("column"===this._tool?1:0)&&t<=i?t:null}get _drawWallMaxCm(){return"column"===this._tool?Js:100}_showPhysicalRange(e=this._drawWallMaxCm,t=0){return this._editorRuntimeOrThrow()._showPhysicalRange(e,t)}_draftSegmentCount(e=this._curSpaceCfg){return this._editorRuntimeOrThrow()._draftSegmentCount(e)}_mergeSpacePartitions(e,t){return this._editorRuntimeOrThrow()._mergeSpacePartitions(e,t)}_finishWallChain(){return this._editorRuntimeOrThrow()._finishWallChain()}_activateMarkupTool(e){return this._editorRuntimeOrThrow()._activateMarkupTool(e)}_limitReached(e){return this._editorRuntimeOrThrow()._limitReached(e)}_svgPoint(e){return this._editorRuntimeOrThrow()._svgPoint(e)}_snap(e){return this._editorRuntimeOrThrow()._snap(e)}_snapDrawPoint(e,t=!1){return this._editorRuntimeOrThrow()._snapDrawPoint(e,t)}_planSnapOpeningCuts(e,t){return this._editorRuntimeOrThrow()._planSnapOpeningCuts(e,t)}_planSnapGeometrySnapshot(){return this._editorRuntimeOrThrow()._planSnapGeometrySnapshot()}_hiddenWallDiagnosticSnapshot(){return this._editorRuntimeOrThrow()._hiddenWallDiagnosticSnapshot()}_planStructuralGeometrySnapshot(){return this._editorRuntimeOrThrow()._planStructuralGeometrySnapshot()}_planSnapContextKey(e){return this._editorRuntimeOrThrow()._planSnapContextKey(e)}_resolvePlanDrawPoint(e,t){return this._editorRuntimeOrThrow()._resolvePlanDrawPoint(e,t)}get _activePlanSnapCandidate(){if(!this._markup||"draw"!==this._tool)return null;const e=this._planSnapHover;if(!e)return null;const t=this._planSnapGeometrySnapshot();return e.contextKey===this._planSnapContextKey(t.key)?e.candidate:null}get _activePlanSnapConflicts(){if(!this._markup||"draw"!==this._tool)return[];const e=this._planSnapHover;if(!e)return[];const t=this._planSnapGeometrySnapshot();return e.contextKey===this._planSnapContextKey(t.key)?e.conflicts:[]}_clearPlanSnapHover(e=!0){return this._editorRuntime?this._editorRuntimeOrThrow()._clearPlanSnapHover(e):(this._planSnapHover=null,void(e&&(this._cursorPt=null)))}_samePt(e,t){return si(e,t)}_dropLegacySegments(){return this._editorRuntimeOrThrow()._dropLegacySegments()}_rollbackRejectedPhysicalWrites(e){return this._editorRuntimeOrThrow()._rollbackRejectedPhysicalWrites(e)}async _reloadRejectedPhysicalWrite(){return this._editorRuntimeOrThrow()._reloadRejectedPhysicalWrite()}get _cfgWriting(){return this._writesPending>0}async _sendConfigCandidate(e){const t=ao(e),i=await this.hass.callWS({type:"houseplan/config/set",config:t,expected_rev:this._cfgRev});this._cfgRev=i?.rev??this._cfgRev+1}_writeConfig(){if(this._editorRuntime)return this._editorRuntime._writeConfig();this._writesPending++,this._writeChain=Qp(this._writeChain,async()=>{if(!this._serverCfg)return;const e=ao(this._serverCfg),t=zl(e);t!==zl(this._serverCfg)&&(this._serverCfg=e),this._cfgContentFingerprint=t,await this._sendConfigCandidate(e)});return this._writeChain.finally(()=>{this._writesPending--})}_saveConfig(){this._cfgEpoch++,this._saveConfigDebounced()}_geometrySnapshotFromConfig(e,t){return this._editorRuntimeOrThrow()._geometrySnapshotFromConfig(e,t)}_geometrySnapshot(e=this._space){return this._editorRuntimeOrThrow()._geometrySnapshot(e)}_recordGeometry(e,t){return this._editorRuntimeOrThrow()._recordGeometry(e,t)}_restoreGeometryStateInConfig(e,t,i=!1){return this._editorRuntimeOrThrow()._restoreGeometryStateInConfig(e,t,i)}_restoreGeometryStateLocal(e){return this._editorRuntimeOrThrow()._restoreGeometryStateLocal(e)}_wallModelBlockerLabel(e){return this._editorRuntimeOrThrow()._wallModelBlockerLabel(e)}_hasLegacyZeroWallFields(e=this._serverCfg){return this._editorRuntimeOrThrow()._hasLegacyZeroWallFields(e)}_showWallModelMigrationBlocked(e){return this._editorRuntimeOrThrow()._showWallModelMigrationBlocked(e)}_limitSegmentsOf(e){return this._editorRuntimeOrThrow()._limitSegmentsOf(e)}_junctionLimitViolations(e,t,i){return this._editorRuntimeOrThrow()._junctionLimitViolations(e,t,i)}_junctionLimitLabel(e){return this._editorRuntimeOrThrow()._junctionLimitLabel(e)}_junctionLimitsIntroduced(e,t,i){return this._editorRuntimeOrThrow()._junctionLimitsIntroduced(e,t,i)}_commitPhysicalGeometry(e,t,i=[]){return this._editorRuntimeOrThrow()._commitPhysicalGeometry(e,t,i)}_clearGeometryGesture(){return this._editorRuntime?this._editorRuntimeOrThrow()._clearGeometryGesture():(this._path=[],this._planSnapHover=null,this._cursorPt=null,this._openingHoverCandidate=null,this._openingJambBlockCm=null,this._openingPreset=null,this._openingRebindId=null,this._mergeSel=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._wallFaceBatch=null,this._wallRepairDiagnostic=null,this._roomDeleteDialog=null,this._wallDialog=null,this._physicalDialog=null,this._physicalSel=null,this._physicalDrag=null,this._physicalRotate=null,this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._openingDialog=null,this._resize?.reset(),this._decorDraft=null,this._decorMove=null,this._dtDrag=null,void(this._bdDrag=null))}_stagePointerCancel(e){if(this._editorRuntime)return this._editorRuntime._stagePointerCancel(e)}_applyGeometryState(e,t=!1){return this._editorRuntimeOrThrow()._applyGeometryState(e,t)}_roomAt(e){return this._editorRuntimeOrThrow()._roomAt(e)}_overlapRoom(e){return this._editorRuntimeOrThrow()._overlapRoom(e)}_pointInRoom(e,t){return t.poly?ai(e,t.poly):null!=t.x&&e[0]>=t.x&&e[0]<=t.x+t.w&&e[1]>=t.y&&e[1]<=t.y+t.h}_contourSelfIntersects(e){return this._editorRuntimeOrThrow()._contourSelfIntersects(e)}_canAppendRoomDraftPoint(){return this._editorRuntimeOrThrow()._canAppendRoomDraftPoint()}_markupClick(e){if(this._editorRuntime)return this._editorRuntime._markupClick(e)}_draftEndAt(e,t){return this._editorRuntimeOrThrow()._draftEndAt(e,t)}_mergeDraftEndpoint(e){return this._editorRuntimeOrThrow()._mergeDraftEndpoint(e)}_adoptDraftCms(e,t,i){return this._editorRuntimeOrThrow()._adoptDraftCms(e,t,i)}_draftSegmentsForPath(e,t,i){return this._editorRuntimeOrThrow()._draftSegmentsForPath(e,t,i)}_persistActiveDraftSegment(){return this._editorRuntimeOrThrow()._persistActiveDraftSegment()}_activeWallSourceKey(e){return this._editorRuntimeOrThrow()._activeWallSourceKey(e)}_wallGraphSources(e){return this._editorRuntimeOrThrow()._wallGraphSources(e)}_wallFaceGraph(e,t){return this._editorRuntimeOrThrow()._wallFaceGraph(e,t)}_offerWallFaces(e,t=this._path.length-2,i){return this._editorRuntimeOrThrow()._offerWallFaces(e,t,i)}_beginWallFaceBatch(e){return this._editorRuntimeOrThrow()._beginWallFaceBatch(e)}_offerExistingWallFace(e){return this._editorRuntimeOrThrow()._offerExistingWallFace(e)}_columnClick(e){return this._editorRuntimeOrThrow()._columnClick(e)}_openPhysicalDialog(e,t,i){return this._editorRuntimeOrThrow()._openPhysicalDialog(e,t,i)}_physicalDown(e,t,i){return this._editorRuntimeOrThrow()._physicalDown(e,t,i)}_clampPhysicalDelta(e,t,i){return this._editorRuntimeOrThrow()._clampPhysicalDelta(e,t,i)}_physicalMove(e){return this._editorRuntimeOrThrow()._physicalMove(e)}_physicalUp(e){return this._editorRuntimeOrThrow()._physicalUp(e)}_registerPhysicalTap(e,t,i){return this._editorRuntimeOrThrow()._registerPhysicalTap(e,t,i)}_cancelPhysicalGesture(){return this._editorRuntimeOrThrow()._cancelPhysicalGesture()}_physicalRotateDown(e,t){return this._editorRuntimeOrThrow()._physicalRotateDown(e,t)}_physicalRotateMove(e){return this._editorRuntimeOrThrow()._physicalRotateMove(e)}_physicalRotateUp(e){return this._editorRuntimeOrThrow()._physicalRotateUp(e)}_rszRooms(){return this._editorRuntimeOrThrow()._rszRooms()}_rszOpenings(){return this._editorRuntimeOrThrow()._rszOpenings()}_rszObstacles(){return this._editorRuntimeOrThrow()._rszObstacles()}_rszOptsFor(e,t){return this._editorRuntimeOrThrow()._rszOptsFor(e,t)}_rszResolution(e,t,i){return this._editorRuntimeOrThrow()._rszResolution(e,t,i)}_rszSnapshot(){return this._editorRuntimeOrThrow()._rszSnapshot()}_rszResetController(){return this._editorRuntimeOrThrow()._rszResetController()}_rszProjectPreview(e,t,i,n,r){return this._editorRuntimeOrThrow()._rszProjectPreview(e,t,i,n,r)}_rszAcceptPreview(e,t){return this._editorRuntimeOrThrow()._rszAcceptPreview(e,t)}_rszSpaceCandidateGeometry(e,t){return this._editorRuntimeOrThrow()._rszSpaceCandidateGeometry(e,t)}_rszSpaceCandidateRenderable(e,t){return this._editorRuntimeOrThrow()._rszSpaceCandidateRenderable(e,t)}_rszCandidateRenderable(e){return this._editorRuntimeOrThrow()._rszCandidateRenderable(e)}_rszEdgeDown(e,t,i){return this._editorRuntimeOrThrow()._rszEdgeDown(e,t,i)}_rszReasonText(e){return this._editorRuntimeOrThrow()._rszReasonText(e)}_rszDisabledActivate(e,t){return this._editorRuntimeOrThrow()._rszDisabledActivate(e,t)}_rszDisabledKey(e,t){return this._editorRuntimeOrThrow()._rszDisabledKey(e,t)}_rszMove(e){return this._editorRuntimeOrThrow()._rszMove(e)}_rszUp(e){return this._editorRuntimeOrThrow()._rszUp(e)}_rszCancelDrag(e){return this._editorRuntimeOrThrow()._rszCancelDrag(e)}_rszPointerCancel(e){return this._editorRuntimeOrThrow()._rszPointerCancel(e)}_rszEdgeLabels(e,t,i=this._resize?.rooms){return this._editorRuntimeOrThrow()._rszEdgeLabels(e,t,i)}_rszInnerSpanCms(e,t,i){return this._editorRuntimeOrThrow()._rszInnerSpanCms(e,t,i)}_renderResizeMeasurements(){return this._editorRuntimeOrThrow()._renderResizeMeasurements()}_renderResizeLayer(e){return this._editorRuntimeOrThrow()._renderResizeLayer(e)}get _openingsR(){const e=this._curSpaceCfg,t=this._spaceH,i=this._spaceModel();return i?(e?.openings||[]).flatMap(e=>{const n={...e,rx:e.x*Mm,ry:e.y*t,rlen:e.length*Mm};if(!e.host||"wall"===e.host.kind)return[n];const r=Pd(e,i.partitions,Mm,this._cellCm,this._gridPitch);if(!r.resolved)return"plan"===this._mode?[{...n,orphanReason:r.reason||"invalid-host"}]:[];let[o,s]=r.resolved.center;const a=this._physicalDrag;return a?.moved&&"partition"===a.kind&&a.id===e.host.id&&(o+=a.delta[0],s+=a.delta[1]),[{...e,rx:o,ry:s,rlen:r.resolved.length,angle:r.resolved.angle,partitionHost:r.resolved}]}):[]}_partitionOpeningCuts(e=this._spaceModel(),t=()=>!0){if(!e)return[];return Kp(Gp(this._curSpaceCfg?.id===e.id?this._curSpaceCfg:null,e,this._cellCm,this._gridPitch,Mm),t)}_roomWallOpeningInputs(e=this._openingsR,t=this._spaceModel()){if(!t)return[];const i=this._openCuts();return Yp(e,t,this._spaceWalls,i,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm)}_openingFace(e,t,i){return e.partitionHost?Hd(e.partitionHost,i):Ks(t,{x:e.rx,y:e.ry,angle:e.angle,length:e.rlen,flip_v:i})}_cmToUnits(e){return e/this._cellCm*this._gridPitch}get _decorList(){const e=this._curSpaceCfg;return Array.isArray(e?.decor)?e.decor:[]}get _decorH(){return Mm}_decorResolvedStyle(e){return function(e,t,i,n=pr){const r="rect"===e?.kind||"ellipse"===e?.kind,o=e,s=qt(o?.color,n.color);return{color:s,opacity:_r(o?.opacity,n.opacity),widthCm:br(e,t,i,n.widthCm),fill:!!r&&!0===o?.fill,fillColor:qt(o?.fill_color,o?.fill?s:n.fillColor),fillOpacity:r&&o?.fill?_r(o?.fill_opacity,.25):n.fillOpacity}}(e,this._cellCm,this._gridPitch,pr)}_decorWidthUnits(e){return((e,t,i,n=pr.widthCm)=>{const r=Number(e?.width_cm);if(Number.isFinite(r)&&r>0)return vr(r,t,i);const o=Number(e?.width);return Number.isFinite(o)&&o>0?o:vr(n,t,i)})(e,this._cellCm,this._gridPitch,pr.widthCm)}_decorTextSizeCm(e){if("text"===e?.kind){const t=Number(e.size_cm);return Number.isFinite(t)&&t>0?t:yr(20*Gi(e),this._cellCm,this._gridPitch)}return yr(20,this._cellCm,this._gridPitch)}_decorTextUnits(e){if("text"!==e.kind)return 20;const t=Number(e.size_cm);return Number.isFinite(t)&&t>0?vr(t,this._cellCm,this._gridPitch):20*Gi(e)}_decorSmallField(e){return Math.round(100*(this._imperial?e/2.54:e))/100}_decorSmallCm(e){const t=this._imperial?2.54*e:e;return Number.isFinite(t)?Math.max(.1,Math.min(100,t)):.1}_decorTextCm(e){const t=this._imperial?2.54*e:e;return Number.isFinite(t)?Math.max(.1,Math.min(2e3,t)):.1}_decorLargeField(e){return Math.round(100*(this._imperial?e/30.48:e/100))/100}_decorLargeCm(e){const t=this._imperial?30.48*e:100*e;return Number.isFinite(t)?Math.max(.1,Math.min(Ea*this._cellCm,t)):.1}_angleField(e){const t=Number(e);return Number.isFinite(t)?String(Number(t.toFixed(3))):"0"}_decorBoxOf(e){return"rect"!==e.kind&&"ellipse"!==e.kind&&"furniture"!==e.kind?null:{x:e.x*Mm,y:e.y*this._decorH,w:e.w*Mm,h:e.h*this._decorH,angle:mr(e.angle)||void 0}}_decorSnapGeometry(e){return this._editorRuntimeOrThrow()._decorSnapGeometry(e)}_decorSnap(e,t="mouse",i){return this._editorRuntimeOrThrow()._decorSnap(e,t,i)}_replaceDecor(e,t){return this._editorRuntimeOrThrow()._replaceDecor(e,t)}_cancelDecorGesture(){return this._editorRuntimeOrThrow()._cancelDecorGesture()}_decorPointerDown(e){return this._editorRuntimeOrThrow()._decorPointerDown(e)}_decorCommitDraft(){return this._editorRuntimeOrThrow()._decorCommitDraft()}_decorShapeDown(e,t){if(this._editorRuntime)return this._editorRuntime._decorShapeDown(e,t)}_decorMoveUpdate(e){return this._editorRuntimeOrThrow()._decorMoveUpdate(e)}_decorShapeDbl(e,t){if(this._editorRuntime)return this._editorRuntime._decorShapeDbl(e,t)}_openDecorProperties(e){return this._editorRuntimeOrThrow()._openDecorProperties(e)}_decorOpenText(e){return this._editorRuntimeOrThrow()._decorOpenText(e)}_decorRememberTextSelection(e){return this._editorRuntimeOrThrow()._decorRememberTextSelection(e)}_decorInsertLiveVariable(e){return this._editorRuntimeOrThrow()._decorInsertLiveVariable(e)}_decorSaveText(){return this._editorRuntimeOrThrow()._decorSaveText()}_decorSaveShape(){return this._editorRuntimeOrThrow()._decorSaveShape()}get _dtSel(){return"decor"===this._mode&&"select"===this._decorTool&&this._decorSel&&this._decorList.find(e=>e.id===this._decorSel)||null}_dtPivot(e){return this._editorRuntimeOrThrow()._dtPivot(e)}_dtApply(e,t){return this._editorRuntimeOrThrow()._dtApply(e,t)}_dtStart(e,t,i,n){return this._editorRuntimeOrThrow()._dtStart(e,t,i,n)}_dtMove(e){return this._editorRuntimeOrThrow()._dtMove(e)}_dtUp(){return this._editorRuntimeOrThrow()._dtUp()}_dtMeasure(){return this._editorRuntimeOrThrow()._dtMeasure()}_deleteDecor(e){return this._editorRuntimeOrThrow()._deleteDecor(e)}_decorDeleteSel(){return this._editorRuntimeOrThrow()._decorDeleteSel()}_confirmDecorErase(){return this._editorRuntimeOrThrow()._confirmDecorErase()}get _furnWalls(){const e=this._rawPhysicalBodiesR().flatMap(e=>e.map((t,i)=>{const n=e[(i+1)%e.length];return[t[0],t[1],n[0],n[1]]}));return[...this._segments,...e]}get _furnWallReach(){return 6*this._gridPitch}_furnFieldValue(e){return this._editorRuntimeOrThrow()._furnFieldValue(e)}_furnFieldToCm(e){return this._editorRuntimeOrThrow()._furnFieldToCm(e)}_furnPick(e){return this._editorRuntimeOrThrow()._furnPick(e)}_furnPlace(e,t=!1){return this._editorRuntimeOrThrow()._furnPlace(e,t)}_furnMoveUpdate(e){return this._editorRuntimeOrThrow()._furnMoveUpdate(e)}_decorApplyBox(e,t){return this._editorRuntimeOrThrow()._decorApplyBox(e,t)}get _furnLive(){const e=this._dtDrag;if(!e||"scale"!==e.kind||!e.orig)return null;const t=this._decorList.find(t=>t.id===e.id);if(!t||"furniture"!==t.kind)return null;const i=Mm,n=this._decorH,r=t.w*i,o=t.h*n,s=function(e,t,i,n,r){const o=e+i/2,s=t+n/2,a=(Number(r)||0)*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=(e,t)=>{const i=e-o,n=t-s;return[o+i*l-n*c,s+i*c+n*l]};return[h(e,t),h(e+i,t),h(e+i,t+n),h(e,t+n)]}(t.x*i,t.y*n,r,o,Number(t.angle)||0),a=(e,t)=>[(e[0]+t[0])/2,(e[1]+t[1])/2],l=a(s[0],s[1]),c=a(s[0],s[3]);return[{x:l[0],y:l[1],text:this._fmtLen([0,0],[r,0])},{x:c[0],y:c[1],text:this._fmtLen([0,0],[0,o])}]}_renderFurnPalette(){return this._editorRuntimeOrThrow()._renderFurnPalette()}get _bdBase(){const e=this._curSpaceCfg;return e?.plan_url?{...Da(e.plan_aspect,Mm)}:null}get _bdRect(){const e=this._curSpaceCfg;return e?.plan_url?Oa(e,Mm):null}get _bdParams(){const e=this._curSpaceCfg,t=Number(e?.plan_x),i=Number(e?.plan_y),n=Number(e?.plan_scale),r=Number(e?.plan_scale_x),o=Number(e?.plan_scale_y),s=Number.isFinite(n)&&n>0?n:1;return{dx:Number.isFinite(t)?t:0,dy:Number.isFinite(i)?i:0,sx:Number.isFinite(r)&&r>0?r:s,sy:Number.isFinite(o)&&o>0?o:s,angle:mr(e?.plan_angle)}}_openBackdropDialog(e){if(this._editorRuntime)return this._editorRuntime._openBackdropDialog(e)}_saveBackdropDialog(){return this._editorRuntimeOrThrow()._saveBackdropDialog()}get _bdActive(){return"decor"===this._mode&&!!this._bdRect&&"backdrop"===this._decorTool}get _bdMovable(){return"decor"===this._mode&&"backdrop"===this._decorTool&&!!this._bdRect}_bdApply(e,t,i,n,r){return this._editorRuntimeOrThrow()._bdApply(e,t,i,n,r)}_bdStart(e,t,i=!1){return this._editorRuntimeOrThrow()._bdStart(e,t,i)}_bdMove(e){return this._editorRuntimeOrThrow()._bdMove(e)}get _bdMoved(){if("decor"!==this._mode||!this._bdRect)return!1;const e=this._bdParams;return 0!==e.dx||0!==e.dy||1!==e.sx||1!==e.sy||0!==e.angle}_bdReset(){return this._editorRuntimeOrThrow()._bdReset()}_bdUp(){return this._editorRuntimeOrThrow()._bdUp()}get _bdLive(){if(!this._bdDrag)return null;const e=this._bdRect;return e?{x:e.x+e.w/2,y:e.y+e.h/2,text:`${this._fmtLen([0,0],[e.w,0])} × ${this._fmtLen([0,0],[0,e.h])}`}:null}_renderBackdropFrame(e){return this._editorRuntime?this._editorRuntimeOrThrow()._renderBackdropFrame(e):U}_renderTextFrame(e){const t=this._dtSel,i=this._dtBox;if(!t||!i||i.id!==t.id)return U;const n=.018*Math.max(e.w,e.h),r=n/4;if("line"===t.kind){const e=[t.x1*Mm,t.y1*this._decorH],i=[t.x2*Mm,t.y2*this._decorH];return B` + + ${[e,i].map((e,t)=>B`this._dtStart(e,"scale",void 0,t)}> + `)} + `}const[o,s]=this._dtPivot(t),a=Number(t.angle)||0,l=2.2*n;return B` + + + this._dtStart(e,"rotate")}> + + ${[[-1,-1,"nwse"],[1,-1,"nesw"],[1,1,"nwse"],[-1,1,"nesw"]].map(([e,t,o])=>B`this._dtStart(i,"scale",[e,t])}>`)} + `}_renderDecorLayer(){const e=Mm,t=this._decorH,i="decor"===this._mode,n=i&&"erase"===this._decorTool,r=this._decorList.map(r=>{const o="dshape"+(i&&this._decorSel===r.id?" dsel":""),s=this._decorResolvedStyle(r),a=this._decorWidthUnits(r),l=e=>this._decorShapeDown(e,r),c=e=>this._decorShapeDbl(e,r);if("line"===r.kind)return B` + ${i&&"select"===this._decorTool?B``:U} + ${n?B``:U}`;if("rect"===r.kind){const i=(r.x+r.w/2)*e,h=(r.y+r.h/2)*t,d=mr(r.angle);return B` + ${n?B``:U}`}if("ellipse"===r.kind){const i=(r.x+r.w/2)*e,h=(r.y+r.h/2)*t,d=mr(r.angle);return B` + ${n?B``:U}`}if("furniture"===r.kind){const i=r.w*e,h=r.h*t,d=kl(r.symbol);if(!d)return U;const u=Number(r.angle)||0,p=r.x*e+i/2,_=r.y*t+h/2,m=`${u?`rotate(${u} ${p} ${_}) `:""}translate(${r.x*e} ${r.y*t}) scale(${i/d.viewW} ${h/d.viewH})`;return B` + ${n?B``:U}`}if("text"===r.kind){const i=this._decorTextUnits(r),n=this._renderDeviceSnapshot?.facts.get(`decor:${this._space}:${r.id}`),a=function(e){return String(e??"").replace(/\r\n?/g,"\n").split("\n")}("string"==typeof n?n:Vi(r.text,r,this._renderPlanHass,e=>this._renderEntityAvailable(e))),h=r.x*e,d=r.y*t,u=Number(r.angle)||0,p=d-(a.length-1)*i*1.2/2;return B`${a.map((e,t)=>B`${e}`)}`}return U});let o=U;const s=this._decorDraft;if(s){const e=this._decorStyle,t=vr(e.widthCm,this._cellCm,this._gridPitch);if("line"===s.kind)o=B``;else{const i=Math.min(s.a[0],s.b[0]),n=Math.min(s.a[1],s.b[1]),r=Math.abs(s.b[0]-s.a[0]),a=Math.abs(s.b[1]-s.a[1]);o="rect"===s.kind?B``:B``}}return B`${r}${o}`}get _editorToolbarGroups(){return"plan"!==this._mode?[]:[{id:"opening",label:this._t("markup.opening"),icon:"mdi:door",activeItemId:"opening"===this._tool?this._openingPreset?.type:void 0,items:[{id:"window",label:this._t("opening.window"),icon:"mdi:window-closed-variant",role:"tool",invoke:()=>this._activateOpeningPlacement("window")},{id:"door",label:this._t("opening.door"),icon:"mdi:door-open",role:"tool",invoke:()=>this._activateOpeningPlacement("door")},{id:"passage",label:this._t("opening.passage"),icon:"mdi:arch",role:"tool",invoke:()=>this._activateOpeningPlacement("passage")},{id:"gate",label:this._t("opening.gate"),icon:"mdi:gate",role:"tool",invoke:()=>this._activateOpeningPlacement("gate")}]}]}_renderEditorGroupLauncher(e){return this._editorRuntimeOrThrow()._renderEditorGroupLauncher(e)}get _editorSecondaryContextId(){const e=`editor:${this._mode}:${this._space}:${this._cfgEpoch}`,t=this._editorSecondary?.activeGroup(this._editorToolbarGroups);if(t)return`${e}:group:${t.id}:${this._editorSecondary?.groupGeneration}`;if("plan"===this._mode){const t=this._physicalSel;return t?`${e}:selection:${t.kind}:${t.id}:${t.segment??""}`:`${e}:tool:${this._tool}:${this._path.length}`}return"decor"===this._mode?"furniture"===this._decorTool?`${e}:palette:furniture:${this._furnPalette?.symbol||"none"}`:"select"===this._decorTool&&this._decorSel?`${e}:selection:decor:${this._decorSel}`:`${e}:tool:${this._decorTool}:${this._bdMoved?1:0}:${this._bdDrag?1:0}`:`${e}:none`}_runEditorContext(e,t){return this._editorRuntimeOrThrow()._runEditorContext(e,t)}_renderEditorGroupModel(e){return this._editorRuntimeOrThrow()._renderEditorGroupModel(e)}_renderDrawWallControl(){return this._editorRuntimeOrThrow()._renderDrawWallControl()}_renderPlanSecondary(){return this._editorRuntimeOrThrow()._renderPlanSecondary()}_renderDecorSecondary(){return this._editorRuntimeOrThrow()._renderDecorSecondary()}_withBackdropReset(e){return this._editorRuntimeOrThrow()._withBackdropReset(e)}get _editorSecondaryDialogBlocked(){return!!(this._tapConfirm||this._vacCalConfirm||this._roomDialog||this._mergeDialog||this._openingDialog||this._physicalDialog||this._openingInfo||this._decorTextDialog||this._decorShapeDialog||this._backdropDialog||this._decorEraseConfirm||this._spaceDialog||this._markerDialog||this._deviceInbox||this._infoCard||this._rulesDialog||this._settingsDialog||this._alignDialog||this._importDialog||this._kioskDialog||this._backupExportDialog||this._backupImportDialog||this._wallDialog)}_renderEditorSecondary(){return this._editorRuntimeOrThrow()._renderEditorSecondary()}_renderDecorBar(){return this._editorRuntimeOrThrow()._renderDecorBar()}_renderDecorEraseConfirm(){return this._editorRuntimeOrThrow()._renderDecorEraseConfirm()}_renderDecorTextDialog(){return this._editorRuntimeOrThrow()._renderDecorTextDialog()}_renderDecorShapeDialog(){return this._editorRuntimeOrThrow()._renderDecorShapeDialog()}_renderBackdropDialog(){return this._editorRuntimeOrThrow()._renderBackdropDialog()}_cssPxToRender(e){return this._editorRuntimeOrThrow()._cssPxToRender(e)}_renderZeroWalls(e){if(e&&!e.showBorders&&!this._editing)return B``;const t=this._zeroWalls();if(!t.lines.length)return B``;const i=e?.color||"var(--hp-muted)";return B` + ${t.lines.map(e=>B``)} + `}_zeroWalls(){const e=this._spaceModel();return e?vp(this._curSpaceCfg,e,Mm,.02*this._gridPitch):{style:_p(this._curSpaceCfg),lines:[],contour:[],barriers:[],transmissive:[]}}_openCuts(){return this._zeroWalls().contour}_deleteRoomClick(e){return this._editorRuntimeOrThrow()._deleteRoomClick(e)}get _wallKeyPitch(){return La}get _spaceWalls(){const e=this._curSpaceCfg?.walls;return Array.isArray(e)?e:[]}_cfgOpenCuts(){const e=this._curSpaceCfg,t=this._spaceModel();if(!e||!t)return[];const i=mp(e,1),n=gp(e,t.rooms,Mm,.02*this._gridPitch).map(e=>e.map(e=>e/Mm)),r=new Set;return[...i,...n].filter(e=>{const t=e.map(e=>Number(e).toFixed(9)).join(","),i=[e[2],e[3],e[0],e[1]].map(e=>Number(e).toFixed(9)).join(","),n=t[e[0]/Mm,e[1]/Mm,e[2]/Mm,e[3]/Mm]))}_paperShapes(e){if(!this._spaceWalls.length)return Xt(e);const t=this._wallUnionGeometry();return t?.paperD?[{path:t.paperD}]:Xt(e)}_wallUnionGeometry(){const e=this._spaceModel();if(!e)return null;const t=this._spaceWalls,i=this._physicalBodiesR();if(!t.length&&!i.length)return null;const n=`${this._space}|${this._cfgEpoch}|${e.rooms.length}`;if(!this._wallUnionCache||this._wallUnionCache.key!==n){const r=pm(this._wallUnionPool,n);if(r.hit)this._wallUnionCache=r.value;else{const r=this._openCuts(),o=this._roomWallOpeningInputs(),s=Ls(e.rooms,t,r,o,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm,i);s&&Object.defineProperty(s,"sourceFingerprint",{value:zl([this._curSpaceCfg,this._cellCm,this._gridPitch]),enumerable:!1});const a={key:n,value:s};_m(this._wallUnionPool,n,a,8),this._wallUnionCache=a}}return this._wallUnionCache.value}_thickWallCuts(){const e=this._spaceModel();if(!e)return[];const t=this._spaceWalls;if(!t.length)return[];const i=this._openCuts();return Ws(e.rooms,t,i,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm).map(e=>[e.a[0],e.a[1],e.b[0],e.b[1]])}_innerRoomContour(e,t,i=this._openCuts(),n=this._wallUnionGeometry()?.roomGeom,r=this._wallUnionGeometry()?.multiWallNodes){const o=i.map(e=>e.join(",")).join(";"),s=`${e.id}|${this._cfgEpoch}|${t}|${o}`,a=pm(this._innerContourCache,s);if(a.hit)return a.value;const l=xs(e.rooms,t,this._spaceWalls,i,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm,n,r);return _m(this._innerContourCache,s,l,600),l}_wallThickHit(e){return this._editorRuntimeOrThrow()._wallThickHit(e)}get _wallThickHover(){if(!this._markup||"wallthick"!==this._tool||!this._cursorPt||this._wallDialog)return null;const e=this._wallThickHit(this._cursorPt);if(!e)return null;const t=function(e,t,i){const n=Number.isFinite(e)&&e>0?e:0,r=Number.isFinite(t)&&t>0?t:5,o=Number.isFinite(i)&&i>0?i:0;return n>0?yo(n,r,o)/2:Sa(1.5*o,r)}(e.cm,this._cellCm,this._gridPitch);let i="";for(const n of e.segs)i+=(i?" ":"")+Yo([[n[0],n[1]],[n[2],n[3]]],t,!1);return{segs:e.segs,open:e.open,d:i}}_wallThickClick(e){return this._editorRuntimeOrThrow()._wallThickClick(e)}_wallThickApply(e){return this._editorRuntimeOrThrow()._wallThickApply(e)}_wallHatchDefs(e){const t=mo(this._cellCm);return B` + + + + `}_resolvedRoomFills(e,t){const i=new Map,n=new Map;for(const r of e.rooms){const e=this._roomDialog&&r.id===this._roomEditId?this._roomFill||t.fill:Tn(t.fill,r),o=this._roomDialog&&r.id===this._roomEditId?this._roomCustomFill||t.customFill:tn(t.customFill,r),s=ln(e,"lqi"===e&&r.area?this._roomLqi(r.area):null,"light"===e?Oh(zh(this._renderPlanHass,this._renderDevices,r,this._virtualLights)):"none","temp"===e?this._roomTemp(r):null,t.tempMin,t.tempMax,this._fillColors,o);i.set(r,s),r.id&&n.set(r.id,s)}return{byRoom:i,byId:n}}_spaceDisplayForRender(){const e=nn(this._curSpaceCfg),t=this._spaceDialog;return t&&"edit"===t.mode&&t.spaceId===this._space?{...e,showBorders:t.showBorders,showNames:t.showNames,hideDecor:t.hideDecor,hideOpenings:t.hideOpenings,color:t.roomColor,opacity:t.roomOpacity,fill:t.fillMode,customFill:t.customFill?en(t.customFill):Qi,glow:t.glowEnabled,tempMin:t.tempMin,tempMax:t.tempMax,showLqi:t.showLqi,cardFontScale:t.cardFontScale,labelTemp:t.labelTemp,labelHum:t.labelHum,labelLqi:t.labelLqi,labelLight:t.labelLight}:e}_openingWallIndexFor(e,t){const i=e.rooms.map(e=>`${e.id}:${e.poly?.map(e=>e.join(",")).join("/")||`${e.x},${e.y},${e.w},${e.h}`}`).join(";"),n=this._spaceWalls.map(e=>`${e.key}:${e.a?.join(",")||""}:${e.b?.join(",")||""}:${e.cm}`).join(";"),r=t.map(e=>e.join(",")).join(";"),o=[e.id,this._cfgEpoch,this._wallKeyPitch,this._cellCm,this._gridPitch,i,n,r].join("|");let s=this._openingWallIndexCache.get(o);return s||(s=Bs(e.rooms,this._spaceWalls,t,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm)),_m(this._openingWallIndexCache,o,s,4),{key:o,value:s}}_renderOpeningTunnelFills(e,t,i="data"){if(this._markup||!this._spaceWalls.length||!this._openingsR.length)return B``;if("glow-base"===i&&![...t.byRoom.values()].some(Boolean))return B``;const n=this._openCuts(),r=this._openingsR.map(e=>({x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),o=r.map(e=>`${e.x},${e.y},${e.angle},${e.length}`).join(";"),s=this._openingWallIndexFor(e,n),a=`${s.key}|${o}`;return this._openingTunnelCache&&this._openingTunnelCache.key===a||(this._openingTunnelCache={key:a,value:Xs(s.value,r)}),np({openings:this._openingsR,geometries:this._openingTunnelCache.value,fillsByRoomId:t.byId,idPrefix:`${e.id}-${i}`,groupClass:"data"===i?"opening-tunnels":"opening-tunnels glow-base-tunnels",dataLayer:i})}_resolvedGlowBase(e,t,i){const n=new Map,r=new Map,o=this._fillColors.glow_base;for(const s of e.rooms){const e=i.byRoom.get(s),a=Cn(t.glow,s)&&(!e||e.opacity<=0)?{color:o.c,opacity:o.a,mode:"glow"}:null;n.set(s,a),s.id&&r.set(s.id,a)}return{byRoom:n,byId:r}}_renderGlowBaseRooms(e,t){if(this._markup||![...t.byRoom.values()].some(Boolean))return B``;const i=new Map(e.rooms.map(e=>[e,Zt(e)])),n=this._openCuts(),r=this._wallUnionGeometry()?.roomGeom,o=e=>"M "+e.map(e=>e[0]+" "+e[1]).join(" L ")+" Z",s=e.rooms.map(s=>{const a=t.byRoom.get(s)||null,l=i.get(s)||null;if(!a||!l)return U;const c=this._spaceWalls.length&&s.id&&this._innerRoomContour(e,s.id,n,r)||l,h=yi(c,e.rooms.filter(e=>e!==s).map(e=>i.get(e)).filter(e=>!!e)),d=this._cleanFloor(s,c,e).path;return d||h.length?B``:s.poly||c!==l?B``:B``});return B``}_renderWallBodies(e){if("iso"===this._renderProjection)return B``;if(e&&!e.showBorders&&("view"===this._mode||"devices"===this._mode))return B``;const t=this._wallUnionGeometry();if(!t)return B``;const i=this._stageEl,n=this._viewOr(this._baseVb()),r=i&&i.clientWidth&&n.w?i.clientWidth/n.w:1,o=e?.color||"#607d8b",s=_o(t.depthUnits,r)||fo(mo(this._cellCm),r),a=this._fillColors.wall_fill;return B` + ${t.paths.map(e=>B` + + `)} + `}_isoDecorationLayers(e){const t="undefined"==typeof CSS||"function"!=typeof CSS.supports||CSS.supports("filter","blur(1px)"),i="function"==typeof matchMedia&&matchMedia("(forced-colors: active)").matches;return function(e){const t=!!e.showBorders;return{structural:t,panels:t&&!e.hideOpenings,shadows:t&&e.filtersSupported&&!e.forcedColors,materialNuance:t&&!e.forcedColors,floorSymbols:!e.hideOpenings&&!t}}({showBorders:e.showBorders,hideOpenings:e.hideOpenings,filtersSupported:t,forcedColors:i})}_isoOpeningPanels(e){if(!e.panels)return[];const t=this._isoScene();if(!t)return[];return t.openings.flatMap(e=>{const t=this._openingsR[e.sourceIndex];return t?J_(e,this._openingAmt(t)):[]}).sort((e,t)=>e.depth-t.depth||e.sourceIndex-t.sourceIndex||e.leaf-t.leaf)}_renderIsoDefs(e,t){const i=$a(this._cellCm);return B` + ${"walls"===t&&e.materialNuance?B` + + + + + + `:U} + ${"underlay"===t&&e.shadows?B` + + + `:U} + ${"shadows"===t&&e.shadows?B` + + + + + + `:U} + `}_renderIsoUnderlay(e){if(!e.structural)return B``;const t=this._isoScene()?.floor;return t?B``:B``}_renderIsoShadows(e,t){if(!e.shadows)return B``;const i=this._isoScene()?.geometry;return i?B``:B``}_renderIsoWalls(e,t){if("iso"!==this._renderProjection)return B``;if(!e.structural)return B``;const i=this._isoScene();return i?B` + ${this._renderIsoDefs(e,"walls")} + ${i.geometry.sides.map(e=>B``)} + + ${e.panels?B``:U} + `:B``}_roomHoverPaths(e){const t=this._hoverRoom;if("view"!==this._mode||!t||t.space!==e.id)return null;const i=e.rooms.find(e=>e===t.room||!!e.id&&e.id===t.room.id);if(!i)return null;const n=Zt(i);if(!n)return null;const r=e.rooms.filter(e=>e!==i).map(e=>({room:e,poly:Zt(e)})).filter(e=>!!e.poly),o=yi(n,r.map(e=>e.poly)),s=this._openCuts(),a=.02*this._gridPitch,l=s.filter(e=>{const t=[(e[0]+e[2])/2,(e[1]+e[3])/2];return n.some((e,i)=>Fn(t,[e[0],e[1],...n[(i+1)%n.length]])<=4*a)}),c=this._spaceWalls,h=this._wallUnionGeometry()?.roomGeom,d=c.length&&i.id&&this._innerRoomContour(e,i.id,s,h)||n,u=[{axis:n,face:d}];for(const t of o){const i=r.find(e=>e.poly===t)?.room;let n=t;if(c.length&&i?.id){const r=fs(e.rooms,i.id,c,s,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm);r&&(n=js(r.poly,r.offsets)||t)}u.push({axis:t,face:n})}const p=this._roomWallOpeningInputs(this._openingsR,e).map(e=>{const t=e.angle*Math.PI/180,i=Math.cos(t)*e.length/2,n=Math.sin(t)*e.length/2;return[e.x-i,e.y-n,e.x+i,e.y+n]}),_=l.concat(p),m=u.map(({axis:e,face:t})=>{const i=_.map(i=>((e,t,i)=>{const n=e[2]-e[0],r=e[3]-e[1],o=Math.hypot(n,r);if(o.05)&&Fn([c,h],[i[0],i[1],n[0],n[1]])<=4*a){d=!0;break}}if(!d)return null;let u=null;for(let e=0;e.05)continue;const p=Fn([c,h],[t[0],t[1],n[0],n[1]]);(!u||p!!e);return i.length?xn(t,i,a).map(e=>`M ${e[0]} ${e[1]} L ${e[2]} ${e[3]}`).join(" "):`M ${t.map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`}).filter(Boolean).join(" ");if(!m)return null;const f=e=>`M ${e.map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`;return{fillD:[this._cleanFloor(i,d,e).path||f(d),...o.map(f)].join(" "),outlineD:m}}_renderRoomHoverFill(e){return e?B` + + `:B``}_renderRoomHoverOutline(e){return e?B` + + + `:B``}_renderWallThickUi(){return this._editorRuntime?this._editorRuntimeOrThrow()._renderWallThickUi():B``}_renderWallThickDialog(){return this._editorRuntimeOrThrow()._renderWallThickDialog()}_openingAt(e){return this._editorRuntimeOrThrow()._openingAt(e)}_resolveOpeningPlacement(e){return this._editorRuntimeOrThrow()._resolveOpeningPlacement(e)}_activateOpeningPlacement(e){return this._editorRuntimeOrThrow()._activateOpeningPlacement(e)}_clearOpeningPlacement(e){return this._editorRuntime?this._editorRuntimeOrThrow()._clearOpeningPlacement(e):(this._openingHoverCandidate=null,this._openingJambBlockCm=null,void(e&&(this._openingPreset=null,this._openingRebindId=null)))}_openingClick(e){return this._editorRuntimeOrThrow()._openingClick(e)}_editOpening(e){if(this._editorRuntime)return this._editorRuntimeOrThrow()._editOpening(e)}_opPointerDown(e,t){if(this._editorRuntime)return this._editorRuntimeOrThrow()._opPointerDown(e,t)}_opPointerMove(e,t){if(this._editorRuntime)return this._editorRuntimeOrThrow()._opPointerMove(e,t)}_opRuler(e,t){return this._editorRuntimeOrThrow()._opRuler(e,t)}_opPointerUp(e,t){if(this._editorRuntime)return this._editorRuntimeOrThrow()._opPointerUp(e,t)}_opClick(e,t){if(this._editorRuntime)return this._editorRuntimeOrThrow()._opClick(e,t)}_saveOpening(){return this._editorRuntimeOrThrow()._saveOpening()}_deleteOpening(){return this._editorRuntimeOrThrow()._deleteOpening()}_contactCandidates(){return this._editorRuntimeOrThrow()._contactCandidates()}_lockCandidates(){return this._editorRuntimeOrThrow()._lockCandidates()}_toggleOpeningEntityPicker(e){return this._editorRuntimeOrThrow()._toggleOpeningEntityPicker(e)}_filterOpeningEntities(e,t){return this._editorRuntimeOrThrow()._filterOpeningEntities(e,t)}_selectOpeningEntity(e,t){return this._editorRuntimeOrThrow()._selectOpeningEntity(e,t)}_mergeClick(e){return this._editorRuntimeOrThrow()._mergeClick(e)}_commitMerge(){return this._editorRuntimeOrThrow()._commitMerge()}_splitClick(e){return this._editorRuntimeOrThrow()._splitClick(e)}get _contourClosed(){return this._path.length>=4&&this._samePt(this._path[0],this._path[this._path.length-1])&&(null!=this._closingWallCm||!this._activeDraftId)}_markupMove(e){if(this._markup&&this._editorRuntime)return this._editorRuntime._markupMove(e)}get _openingPreview(){const e=this._openingPreset;if("opening"!==this._tool||!e||!this._cursorPt)return null;const t=this._cursorPt,i=this._openingHoverCandidate;if(i&&am(i,[t[0],t[1]],e.revision,this._cfgEpoch))return i;if(this._openingAt(t))return this._openingHoverCandidate=null,null;const n=this._resolveOpeningPlacement(t);return this._openingHoverCandidate=n,n}get _opMeasureView(){return this._opMeasure||this._openingPreview?.measure||null}_saveRoom(){return this._editorRuntimeOrThrow()._saveRoom()}_decideWallFace(e){return this._editorRuntimeOrThrow()._decideWallFace(e)}_wallSourceCmAt(e,t,i){return this._editorRuntimeOrThrow()._wallSourceCmAt(e,t,i)}_activePathWithRepair(e,t){return this._editorRuntimeOrThrow()._activePathWithRepair(e,t)}_validateWallRepair(e,t){return this._editorRuntimeOrThrow()._validateWallRepair(e,t)}_applyWallRepair(e,t){return this._editorRuntimeOrThrow()._applyWallRepair(e,t)}_applyWallFaceBatch(){return this._editorRuntimeOrThrow()._applyWallFaceBatch()}_commitRoom(){return this._editorRuntimeOrThrow()._commitRoom()}_cancelPath(){return this._editorRuntimeOrThrow()._cancelPath()}_resumeLastDraft(){return this._editorRuntimeOrThrow()._resumeLastDraft()}_roomDialogCancel(){return this._editorRuntimeOrThrow()._roomDialogCancel()}get _freeAreas(){const e=new Set;for(const t of this._serverCfg?.spaces||[])for(const i of t.rooms||[])i.area&&e.add(i.area);for(const t of this._wallFaceBatch?.decisions||[])t.create&&t.area&&e.add(t.area);return Object.values(this.hass?.areas||{}).filter(t=>!e.has(t.area_id)).sort((e,t)=>(e.name||"").localeCompare(t.name||""))}_openDeviceInbox(){return this._editorRuntimeOrThrow()._openDeviceInbox()}_closeMarkerDialog(){return this._editorRuntimeOrThrow()._closeMarkerDialog()}_deviceInboxCandidates(e){return this._editorRuntimeOrThrow()._deviceInboxCandidates(e)}_deviceInboxRows(){return this._editorRuntimeOrThrow()._deviceInboxRows()}_deviceForInboxRow(e){return this._editorRuntimeOrThrow()._deviceForInboxRow(e)}_openInboxMarker(e,t=!1){return this._editorRuntimeOrThrow()._openInboxMarker(e,t)}async _setInboxHidden(e,t){return this._editorRuntimeOrThrow()._setInboxHidden(e,t)}_findInboxDevice(e){return this._editorRuntimeOrThrow()._findInboxDevice(e)}_deviceInboxTabKey(e){return this._editorRuntimeOrThrow()._deviceInboxTabKey(e)}_openMarkerDialog(e){if(this._editorRuntime)return this._editorRuntime._openMarkerDialog(e);this._ensureEditorRuntime().then(t=>{t&&this._openMarkerDialog(e)})}_runCandidates(){return this._editorRuntimeOrThrow()._runCandidates()}_bindingCandidates(){return this._editorRuntimeOrThrow()._bindingCandidates()}_physicalBodiesR(e=this._spaceModel()){if(!e)return[];const t=`${e.id}|${this._cfgEpoch}|${this._cellCm}|${this._gridPitch}`;if(this._physicalBodiesCache?.key===t)return this._physicalBodiesCache.all;const i=da(e,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(e));return this._physicalBodiesCache={key:t,...i},i.all}_rawPhysicalBodiesR(e=this._spaceModel()){if(!e)return[];this._physicalBodiesR(e);const t=this._physicalBodiesCache;return t?[...t.drafts,...t.partitions,...t.columns]:[]}_cleanFloor(e,t,i=this._spaceModel()){if(!i)return{floor:t,geom:null,path:"",area:ga([[[...t,t[0]]]])};const n=e.id||`#${i.rooms.indexOf(e)}`,r=`${i.id}|${this._cfgEpoch}|${n}`;if(!this._resize?.preview){const e=pm(this._cleanFloorCache,r);if(e.hit)return e.value}const o=t.map(e=>e[0]),s=t.map(e=>e[1]),a=[Math.min(...o),Math.min(...s),Math.max(...o),Math.max(...s)],l=this._physicalBodiesR(i).filter(e=>{const t=e.map(e=>e[0]),i=e.map(e=>e[1]);return Math.max(...t)>=a[0]&&Math.min(...t)<=a[2]&&Math.max(...i)>=a[1]&&Math.min(...i)<=a[3]}),c=l.length?fa(t,l):null,h={floor:t,geom:c,path:c?oa(c):"",area:ga(c||[[[...t,t[0]]]])};return this._resize?.preview||_m(this._cleanFloorCache,r,h,600),h}_autoIconForBinding(e){if("virtual"===e)return"mdi:map-marker";const[t,i]=e.split(":");if(!i)return"";const n=this._fullRegistryHass,r=this._bindingStatus(e),o="active"===r.kind?r.enabledEntityIds:r.allEntityIds;if("device"===t){const e=n.devices?.[i];if(!e)return"mdi:help-circle";const t=o;return t.some(e=>e.startsWith("lock."))?"mdi:lock":Lh(n,e.name_by_user||e.name||"",e.model,t,this._iconRules)}if("entity"===t){const e=n.entities?.[i],t=this.hass.states?.[i],r=e?.name||t?.attributes?.friendly_name||i;return i.startsWith("lock.")?"mdi:lock":Lh(n,r,"",[i],this._iconRules)}return""}_allRoomsFlat(){const e=[];for(const t of this._serverCfg?.spaces||[])for(const i of t.rooms||[])i.area?e.push({value:t.id+"#"+i.area,label:(t.title||t.id)+" · "+i.name}):i.id&&e.push({value:t.id+"#@"+i.id,label:(t.title||t.id)+" · "+i.name+" · "+this._t("marker.subarea")});return e}_errText(e){if(!e)return this._t("err.unknown");if("string"==typeof e)return e;if("invalid_passage_fields"===e.code){const t=String(e.message||e.error||"").match(/space=([^;]*);\s*opening=([^;]*);\s*fields=([^;]*)/);if(t){const e=this._serverCfg?.spaces?.find(e=>String(e.id)===t[1]),i={contact:"opening.contact_label",lock:"opening.lock_label",invert:"opening.invert",flip_h:"opening.flip_h",flip_v:"opening.flip_v"},n=t[3].split(",").filter(Boolean).map(e=>i[e]?this._t(i[e]):e).join(", ");return this._t("opening.invalid_passage_fields",{room:e?.title||t[1],fields:n})}}if("invalid_partition_opening_jamb_margin"===e.code){const t=String(e.message||e.error||"").match(/margin_cm=([^;]*)/),i=t?Number(t[1]):NaN;if(Number.isFinite(i))return this._t("opening.partition_jamb_margin",{distance:Kt(i,this._imperial)})}if(e.message)return e.message;if(e.error)return e.error;if(null!=e.code)return this._t("err.code",{code:e.code});try{return JSON.stringify(e)}catch{return String(e)}}_backupErrorText(e){return this._editorRuntimeOrThrow()._backupErrorText(e)}async _pickMarkerFiles(e){return this._editorRuntimeOrThrow()._pickMarkerFiles(e)}_removeMarkerPdf(e){return this._editorRuntimeOrThrow()._removeMarkerPdf(e)}_markerLightFields(e){return this._editorRuntimeOrThrow()._markerLightFields(e)}_markerTapActionFields(e){return this._editorRuntimeOrThrow()._markerTapActionFields(e)}_markerToggleEntityFields(e){return this._editorRuntimeOrThrow()._markerToggleEntityFields(e)}async _saveMarker(){return this._editorRuntimeOrThrow()._saveMarker()}async _deleteMarker(){return this._editorRuntimeOrThrow()._deleteMarker()}_normPos(e,t,i){return{s:e,x:t/Mm,y:i/Mm}}_spaceDialogUsesOnboardingRuntime(e){return"create"===e&&!this._editorRuntime&&(!!this._onboardingRuntime||0===(this._serverCfg?.spaces.length||0)||this._importTotal>0||this._importQueue.length>0)}_spaceRuntimeOrThrow(){if(!this._onboardingRuntime)throw new Error("Houseplan onboarding runtime is not loaded");return this._onboardingRuntime}_openSpaceDialog(e,t){return this._spaceDialogUsesOnboardingRuntime(e)?this._onboardingRuntime?void this._onboardingRuntime._openSpaceDialog(e,t):void this._ensureOnboardingRuntime().then(i=>{i&&this._spaceRuntimeOrThrow()._openSpaceDialog(e,t)}):this._editorRuntime?this._editorRuntime._openSpaceDialog(e,t):void this._ensureEditorRuntime().then(i=>{i&&this._openSpaceDialog(e,t)})}async _pickPlanFile(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._pickPlanFile(e):this._editorRuntimeOrThrow()._pickPlanFile(e)}_useServerPlan(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._useServerPlan(e):this._editorRuntimeOrThrow()._useServerPlan(e)}async _readPlanAspect(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._readPlanAspect(e):this._editorRuntimeOrThrow()._readPlanAspect(e)}async _deleteServerPlan(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._deleteServerPlan(e):this._editorRuntimeOrThrow()._deleteServerPlan(e)}_renderServerPlans(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime(e.mode)?this._onboardingRuntime._renderServerPlans(e):this._editorRuntimeOrThrow()._renderServerPlans(e)}async _saveSpaceDialog(){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._saveSpaceDialog():this._editorRuntimeOrThrow()._saveSpaceDialog()}async _deleteSpace(){return this._editorRuntimeOrThrow()._deleteSpace()}async _saveConfigNow(){return this._editorRuntimeOrThrow()._saveConfigNow()}_startImport(){return this._onboardingRuntime?this._onboardingRuntime._startImport():this._editorRuntimeOrThrow()._startImport()}_openNextImport(){return this._onboardingRuntime?this._onboardingRuntime._openNextImport():this._editorRuntimeOrThrow()._openNextImport()}_skipImport(){return this._onboardingRuntime?this._onboardingRuntime._skipImport():this._editorRuntimeOrThrow()._skipImport()}_renderImportDialog(){return this._onboardingRuntime?this._onboardingRuntime._renderImportDialog():this._editorRuntimeOrThrow()._renderImportDialog()}_sunGlobal(){const e=this._settingsDialog;return e?{...this._settings,north_deg:e.northDeg??void 0,bg_mode:e.bgMode,sun_rays:e.sunRays}:this._settings}_sunSpace(){const e=this._spaceDialog,t=this._curSpaceCfg?.settings||{};return e&&"edit"===e.mode&&e.spaceId===this._space?{...t,north_deg:e.northDeg??void 0,bg_mode:e.bgMode??void 0,sun_rays:e.sunRays??void 0}:t}_effNorth(){return sr(this._sunGlobal(),this._sunSpace())}_effBgMode(){return ar(this._sunGlobal(),this._sunSpace())}_dayCycleState(e=new Date){return(this._modeTransitionVisual?.viewWeight??("view"===this._mode?1:0))<=0||"daynight"!==this._effBgMode()?null:Zn(this._renderPlanHass,e)}_syncDayCycleClock(){const e=this._dayCycleState();this._dayCycleClockKey=e?Xn(e):"";const t="clock"===e?.source&&"hidden"!==this.ownerDocument.visibilityState&&this.isConnected;t&&!this._dayCycleTimer?this._dayCycleTimer=window.setInterval(this._dayCycleTick,3e4):!t&&this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_dayCycleVisibility(e){"hidden"!==e.kind?(this._dayCycleTick(),this._syncDayCycleClock()):this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_effSunRays(){return lr(this._sunGlobal(),this._sunSpace())}_sunNow(){return null!==this._effNorth()?cr(this._renderPlanHass):null}_renderSunRays(e){const t=B``,i=this._modeTransitionVisual?.viewWeight??0;if(this._editing&&i<=0||!this._effSunRays())return this._sunFadeReset(),t;const n=this._effNorth(),r=null!==n?cr(this._renderPlanHass):null;if(!r||r.elevation<=0)return this._sunFadeReset(),t;if(o=r.elevation,Number(o)>=3)this._sunOutTimer&&(clearTimeout(this._sunOutTimer),this._sunOutTimer=0),this._sunOut=!1,this._sunShown=!0;else{if(!this._sunShown)return t;this._sunOut||(this._sunOut=!0,this._sunOutTimer=window.setTimeout(()=>{this._sunOutTimer=0,this._sunShown=!1,this._sunOut=!1,this.requestUpdate()},2e3))}var o;const s=this._zeroWalls(),a=s.barriers.map(e=>e.join(",")).join(";"),l=`${e.id}|${r.azimuth}|${r.elevation}|${n}|${this._cfgEpoch}|${s.style}|${a}`;if(!this._sunRaysCache||this._sunRaysCache.key!==l){const t=e.rooms.map(e=>({id:e.id||"",poly:Zt(e)})).filter(e=>!!e.id&&!!e.poly),i=this._openingsR.filter(e=>"window"===e.type&&"partition"!==e.host?.kind).map(e=>({id:e.id,x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),o=this._spaceWalls,a=this._openCuts(),c=this._openingWallIndexFor(e,a).value,h={},d={},u=this._wallUnionGeometry()?.roomGeom;if(o.length){for(const i of t){const t=this._innerRoomContour(e,i.id,a,u);t&&(h[i.id]=t)}for(const e of i){const t=Ks(c,{x:e.x,y:e.y,angle:e.angle,length:e.length});t.cm>0&&(d[e.id]=yo(t.cm,this._cellCm,this._gridPitch))}}let p=rr(t,i,r.azimuth,r.elevation,n,o.length?h:void 0,o.length?d:void 0);const _=[...this._physicalBodiesR(e),...s.barriers.map(e=>[[e[0],e[1]],[e[2],e[3]]])];_.length&&(p=p.map(e=>{const t=function(e,t,i){return i>0?e.map(e=>function(e){const t=[...e].sort((e,t)=>e[0]-t[0]||e[1]-t[1]);if(t.length<=2)return t;const i=(e,t,i)=>(t[0]-e[0])*(i[1]-e[1])-(t[1]-e[1])*(i[0]-e[0]),n=[];for(const e of t){for(;n.length>=2&&i(n[n.length-2],n[n.length-1],e)<=0;)n.pop();n.push(e)}const r=[];for(let e=t.length-1;e>=0;e--){const n=t[e];for(;r.length>=2&&i(r[r.length-2],r[r.length-1],n)<=0;)r.pop();r.push(n)}return n.slice(0,-1).concat(r.slice(0,-1))}([...e,...e.map(e=>[e[0]+t[0]*i,e[1]+t[1]*i])])).filter(e=>e.length>=3):e}(_,e.dir,e.len),i=e.polys.map(e=>fa(e,t));return{...e,paths:i.map(oa).filter(Boolean),polys:i.flatMap(ya)}}).filter(e=>e.paths?.length||e.polys.length)),this._sunRaysCache={key:l,rays:p,rims:p.map(e=>function(e,t=1e-4){const[i,n]=e.dir,r=-n,o=i,s=[];for(const a of[e.a,e.b]){const l=[];for(const s of e.polys)for(let e=0;et)continue;if(Math.abs((h[0]-a[0])*r+(h[1]-a[1])*o)>t)continue;const d=(c[0]-a[0])*i+(c[1]-a[1])*n,u=(h[0]-a[0])*i+(h[1]-a[1])*n;Math.abs(u-d)<=t||l.push(de[0]-t[0]);const c=[];for(const e of l){const i=c[c.length-1];i&&e[0]<=i[1]+t?i[1]=Math.max(i[1],e[1]):c.push([e[0],e[1]])}for(const[e,t]of c)s.push([[a[0]+i*e,a[1]+n*e],[a[0]+i*t,a[1]+n*t]])}return s}(e))}}const c=this._sunRaysCache.rays,h=this._sunRaysCache.rims;if(!c.length)return t;const d=(u=function(e){const t=Math.min(90,Math.max(-90,Number(e)||0));let i=Jn[Jn.length-1][1];for(let e=1;e + ${c.map((e,t)=>{const i=(e.a[0]+e.b[0])/2,n=(e.a[1]+e.b[1])/2,r=i+e.normal[0]*e.depth,o=n+e.normal[1]*e.depth;return B` + ${p.map(([e,t])=>B``)} + + + ${_.map(([e,t])=>B``)} + `})} + + + ${c.map((e,t)=>e.paths?.length?e.paths.map(e=>B``):e.polys.map(e=>B``))} + ${c.map((e,t)=>(h[t]||[]).map(e=>B``))} + `}_sunFadeReset(){this._sunOutTimer&&(clearTimeout(this._sunOutTimer),this._sunOutTimer=0),this._sunShown=!1,this._sunOut=!1}_compassPoint(e){const t=e.currentTarget.getBoundingClientRect(),i=e.clientX-(t.left+t.width/2),n=e.clientY-(t.top+t.height/2);if(Math.hypot(i,n)<5)return;let r=Math.round(180*Math.atan2(i,-n)/Math.PI);e.shiftKey&&(r=15*Math.round(r/15)),r=(r%360+360)%360,this._settingsDialog={...this._settingsDialog,northDeg:r}}_renderCompass(){const e=this._settingsDialog.northDeg;return j`{e.currentTarget.setPointerCapture(e.pointerId),this._compassDrag=!0,this._compassPoint(e)}} + @pointermove=${e=>{this._compassDrag&&this._compassPoint(e)}} + @pointerup=${()=>this._compassDrag=!1} + @pointercancel=${()=>this._compassDrag=!1}> + + ${[0,45,90,135,180,225,270,315].map(e=>B``)} + + + + ${this._t("gs.north_letter")} + + ${null===e?"—":e+"°"} + `}_stageBg(e){const t=this._settingsDialog,i=this._spaceDialog,n=t?t.bgColor||"":rn(this._settings,{bgColor:null});return(i&&"edit"===i.mode&&i.spaceId===this._space?i.bgColor||"":e.bgColor||"")||n}_stageBgHex(){const e=this._stageEl;if(e){const t=getComputedStyle(e).backgroundColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);if(t)return"#"+t.slice(1,4).map(e=>(+e).toString(16).padStart(2,"0")).join("")}return"#111111"}_preflightDiagnostics(e,t){return this._editorRuntimeOrThrow()._preflightDiagnostics(e,t)}_reportPreflightFailure(e,t){return this._editorRuntimeOrThrow()._reportPreflightFailure(e,t)}_preflightVersionsDiffer(){return this._editorRuntimeOrThrow()._preflightVersionsDiffer()}async _copyPreflightDiagnostics(){return this._editorRuntimeOrThrow()._copyPreflightDiagnostics()}_checkOptimizeGeometry(e){return this._editorRuntimeOrThrow()._checkOptimizeGeometryImpl(e)}_checkSpacePhysicalGeometry(e,t,i){return this._editorRuntimeOrThrow()._checkSpacePhysicalGeometryImpl(e,t,i)}_optimizeReferenceContext(e){return this._editorRuntimeOrThrow()._optimizeReferenceContext(e)}_previewAlignDialog(e){return this._editorRuntimeOrThrow()._previewAlignDialog(e)}async _runAlignToGrid(){return this._editorRuntimeOrThrow()._runAlignToGrid()}async _undoPlanOptimization(){return this._editorRuntimeOrThrow()._undoPlanOptimization()}async _runBackupExport(){return this._editorRuntimeOrThrow()._runBackupExport()}async _pickBackupImport(e){return this._editorRuntimeOrThrow()._pickBackupImport(e)}async _setBackupDuplicatePolicy(e){return this._editorRuntimeOrThrow()._setBackupDuplicatePolicy(e)}async _applyBackupImport(){return this._editorRuntimeOrThrow()._applyBackupImport()}_renderBackupExportDialog(){return this._editorRuntimeOrThrow()._renderBackupExportDialog()}_renderBackupImportDialog(){return this._editorRuntimeOrThrow()._renderBackupImportDialog()}_setFillColor(e,t){return this._editorRuntimeOrThrow()._setFillColor(e,t)}async _saveSettingsDialog(){return this._editorRuntimeOrThrow()._saveSettingsDialog()}_boolInput(e,t,i=!1){return this._editorRuntimeOrThrow()._boolInput(e,t,i)}_rangeInput(e,t,i,n,r,o=!1,s){return this._editorRuntimeOrThrow()._rangeInput(e,t,i,n,r,o,s)}_renderColorRow(e,t){return this._editorRuntimeOrThrow()._renderColorRow(e,t)}get _glowRadiusCm(){const e=Number(this._settings.glow_radius_cm);return Number.isFinite(e)&&e>0?e:300}get _imperial(){return"mi"===this.hass?.config?.unit_system?.length}get _glowRadiusPlaceholder(){const e=this._glowRadiusCm;return this._imperial?String(Math.round(e/30.48*10)/10):String(e/100)}_glowTransition(e,t){let i=this._glowRenderedSources.get(e);if(t){const t=this._glowFadeTimers.get(e);if(null!=t&&(clearTimeout(t),this._glowFadeTimers.delete(e)),null==i){this._suspendGlowFeatherForTransition(),i=++this._glowSourceSeq,this._glowRenderedSources.set(e,i),this._glowEnteringSources.add(e);const t=requestAnimationFrame(()=>{this._glowEnterRafs.get(e)===t&&(this._glowEnterRafs.delete(e),this._glowEnteringSources.delete(e),this.isConnected&&this.requestUpdate())});this._glowEnterRafs.set(e,t)}return{domId:i,entering:this._glowEnteringSources.has(e),leaving:!1}}if(null==i)return null;const n=this._glowEnterRafs.get(e);if(null!=n&&cancelAnimationFrame(n),this._glowEnterRafs.delete(e),this._glowEnteringSources.delete(e),!this._glowFadeTimers.has(e)){this._suspendGlowFeatherForTransition();const t=window.setTimeout(()=>{this._glowFadeTimers.get(e)===t&&(this._glowFadeTimers.delete(e),this._glowRenderedSources.delete(e),this._glowLastAppearance.delete(e),this.isConnected&&this.requestUpdate())},534);this._glowFadeTimers.set(e,t)}return{domId:i,entering:!1,leaving:!0}}_suspendGlowFeatherForTransition(){if(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches)return;this._glowFeatherSuspendUntil=Math.max(this._glowFeatherSuspendUntil,Date.now()+500),clearTimeout(this._glowFeatherResumeTimer);const e=Math.max(0,this._glowFeatherSuspendUntil-Date.now())+17,t=()=>{this._glowFeatherResumeTimer=0,Date.now()=128){const e=this._glowGeometryWarnings.values().next().value;e&&this._glowGeometryWarnings.delete(e)}this._glowGeometryWarnings.add(r),console.warn(`HOUSEPLAN GLOW GEOMETRY FALLBACK: #218, space ${e}, room ${i}, phase ${n}`)}}_lightBarriers(e,t){const i=zl([this._curSpaceCfg,this._cellCm,this._gridPitch]),n=Math.max(this._cmToUnits(10),.5*this._gridPitch),r=e=>t.some(t=>this._pointInRoom(e,t.r)),o=this._openingsR.flatMap(e=>{if("door"!==(t=String(e.type))&&"gate"!==t&&"passage"!==t)return[];var t;const i=e,o=i.angle*Math.PI/180,s=-Math.sin(o),a=Math.cos(o);return r([i.rx+s*n,i.ry+a*n])&&r([i.rx-s*n,i.ry-a*n])?[{opening:i,amount:this._openingAmt(i)}]:[]});const s=zl([i,o.map(({opening:e,amount:t})=>({id:e.id,type:e.type,contact:e.contact,amount:t})).filter(e=>!!e.contact&&("door"===e.type||"gate"===e.type)).map(e=>{const t=Math.max(0,Math.min(1,Number(e.amount)||0));return`${e.id}:${t.toFixed(3)}`}).sort().join("|")]),a=`${e.id}|${s}`,l=pm(this._lightBarrierPool,a);if(l.hit)return this._lightBarrierCache=l.value,l.value.value;const c=this._zeroWalls(),h=this._openCuts(),d=[...c.transmissive],u=o.filter(({amount:e})=>e>0).map(({opening:e,amount:t})=>({...e,rlen:ni(e.rlen,t)})),p=this._roomWallOpeningInputs(u,e);for(const e of p){const t=e.angle*Math.PI/180,i=Math.cos(t)*e.length/2,n=Math.sin(t)*e.length/2;d.push([e.x-i,e.y-n,e.x+i,e.y+n])}const _=o.flatMap(({opening:e,amount:t})=>t>0&&e.partitionHost?[la(Id(e.partitionHost),t)]:[]),m=a;this._lightPhysicalBodiesCache?.key!==m&&(this._lightPhysicalBodiesCache={key:m,all:da(e,this._cellCm,this._gridPitch,2e-4*this._gridPitch,_).all});const f=this._lightPhysicalBodiesCache.all,g=this._spaceWalls,v=.02*this._gridPitch,y=[],b=this._wallUnionGeometry(),w=b?.sourceFingerprint,k=b&&w===i?function(e,t=[],i=[],n={}){if("failed-core"===e.status||"not-applicable"===e.status)return null;const r=e.roomComponents?.length?e.roomComponents:Ss(e.roomGeom)?[{id:"room-primary",geom:e.roomGeom}]:[];let o=r[0]?.geom||null;const s=r.slice(1).map(e=>({...e}));try{for(const i of t){if(!(i.length>0&&e.openingIndex))continue;const t=Gs(e.openingIndex,i,!0);if(!t.negative&&!t.positive)continue;const n=i.angle*Math.PI/180,r=Math.cos(n),a=Math.sin(n),l=-a,c=r,h=i.length/2,d=e.openingPadUnits??1.25*Math.max(e.depthUnits,1),u=$s([[i.x-r*h-l*d,i.y-a*h-c*d],[i.x+r*h-l*d,i.y+a*h-c*d],[i.x+r*h+l*d,i.y+a*h+c*d],[i.x-r*h+l*d,i.y-a*h+c*d]]);o&&(o=Nt(o,u));for(const e of s)e.geom=Nt(e.geom,u)}const r=[...s];let a=s.length;const l=n.mergeExtra||((e,t)=>e?It(e,t):t);for(let e=0;ee.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]))||Math.abs(bi(t))<=1e-9){a++;continue}const n=[$s(t)];try{const t=l(o,n,e);if(!Ss(t))throw new Error("invalid extra union");o=t}catch{a++,Ss(n)&&r.push({id:`policy-extra-${e}`,geom:n})}}r.sort((e,t)=>Es(e.geom).localeCompare(Es(t.geom)));const c=o||[];return{status:a?"degraded-extra":"ok",geom:c,components:[...Ss(c)?[{id:"primary",geom:c}]:[],...r.map((e,t)=>({...e,id:`isolated-${t}`}))]}}catch{return null}}(b,p,f):null,x=k||(g.length||f.length?Ns(e.rooms,g,h,p,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm,f):null);if(!x||"ok"!==x.status&&"degraded-extra"!==x.status)for(const e of f)y.push(...Vd(e));else for(const e of x.components)for(const t of va(e.geom))y.push(...Vd(t));for(const{poly:e}of t)for(const t of d.length?xn(e,d,v):Vd(e))y.push(t);for(const e of c.barriers)y.push(e);const $={occluders:Bd(y),floor:t.map(e=>e.poly),fingerprint:s,masonryGeometry:!x||"ok"!==x.status&&"degraded-extra"!==x.status?[]:x.components.flatMap(e=>e.geom),opaqueBodies:f},S={key:a,value:$};return _m(this._lightBarrierPool,a,S,8),this._lightBarrierCache=S,$}_renderGlowLayer(e,t){const i=this._fillColors,n=this._glowRadiusCm/this._cellCm*this._gridPitch,r=e.rooms.map(e=>({r:e,poly:Zt(e)})).filter(e=>!!e.poly),o=r.filter(({r:e})=>Cn(t.glow,e));if(!o.length)return this._forgetGlowSpace(e.id),B``;const{occluders:s,floor:a,fingerprint:l,masonryGeometry:c,opaqueBodies:h}=this._lightBarriers(e,r),d=zh(this._renderPlanHass,this._renderDevices,null,this._virtualLights).filter(t=>t.device.space===e.id),u=new Map;for(const e of d){if(!e.device.id)continue;const t=u.get(e.device.id)||[];t.push(e),u.set(e.device.id,t)}const p=[],_=new Set;for(const t of this._renderDevices){if(t.space!==e.id)continue;const o=Ah(u.get(t.id)||[]);if(!o)continue;const d=`${e.id}|${t.id}`;_.add(d);const m=vn(o.passive?{state:o.on?"on":"off",attributes:{}}:this._renderPlanHass.states[o.eid],t.marker?.glow_color,i.glow_light.c),f=Number(t.marker?.glow_radius_cm),g=Number.isFinite(f)&&f>0?f/this._cellCm*this._gridPitch:n,v=this._pos(t);if(wa([v.x,v.y],c,h)){this._forgetGlowSource(d);continue}const y=this._glowTransition(d,!!m);if(!y)continue;m&&this._glowLastAppearance.set(d,{c:m.c,alpha:yn(m.bri,i.glow_light.a)});const b=this._glowLastAppearance.get(d);if(!b)continue;let w=null;const k=`${e.id}|${l}|${v.x.toFixed(4)},${v.y.toFixed(4)}|${g.toFixed(4)}`,x=pm(this._glowClipCache,k);if(x.hit)w=x.value;else{const t=Kd([v.x,v.y],g,s,96);w={lit:t.length>=3?ma([t],a,{onBoundsFailure:({boundIndex:t,phase:i})=>{const n=r[t]?.r;this._warnGlowGeometryFallback(e.id,l,n?.id||`#${t}`,i)}}):[]},_m(this._glowClipCache,k,w,256)}p.push({key:d,sourceEid:o.eid,domId:y.domId,entering:y.entering,leaving:y.leaving,pos:v,c:b.c,alpha:b.alpha,geometry:w,r:g})}const m=`${e.id}|`;for(const e of this._glowRenderedSources.keys())e.startsWith(m)&&!_.has(e)&&this._forgetGlowSource(e);if(!p.length)return B``;const f=this._spaceWalls,g=o.length===r.length?[]:this._openCuts(),v=this._wallUnionGeometry()?.roomGeom,y=o.length===r.length?null:o.map(({r:t,poly:i})=>{const n=f.length&&t.id&&this._innerRoomContour(e,t.id,g,v)||i,o=this._cleanFloor(t,n,e).path,s=yi(n,r.filter(e=>e.r!==t).map(e=>e.poly)),a=e=>"M "+e.map(e=>e[0]+" "+e[1]).join(" L ")+" Z";return[o||a(n),...s.map(a)].join(" ")}),b=this._viewOr(this._baseVb()),w=this._stageEl?.clientWidth&&b.w?this._stageEl.clientWidth/b.w:1,k=1/(w>0?w:1),x=!this._pinchStart&&!this._panStart&&Date.now()>=this._glowFeatherSuspendUntil;(null==this._glowFeatherUnits||x)&&(this._glowFeatherUnits=k);const $=this._glowFeatherUnits??k,S=4*$,M=p.reduce((e,t)=>({x:Math.min(e.x,t.pos.x-t.r-S),y:Math.min(e.y,t.pos.y-t.r-S),maxX:Math.max(e.maxX,t.pos.x+t.r+S),maxY:Math.max(e.maxY,t.pos.y+t.r+S),w:0,h:0}),{x:1/0,y:1/0,maxX:-1/0,maxY:-1/0,w:0,h:0});return M.w=M.maxX-M.x,M.h=M.maxY-M.y,B` + ${$e(p,e=>e.key,e=>{const t=e.domId,i=e.geometry;return B` + ${""} + + ${Rm.map(([t,i])=>B` + `)} + + ${""} + ${i?B` + + + `:U}`})} + ${y?B`${y.map(e=>B``)}`:U} + ${""} + + + + + ${""} + + + ${$e(p,e=>e.key,e=>{const t=e.domId;return B` + + + `})} + + `}_renderAlignDialog(){return this._editorRuntimeOrThrow()._renderAlignDialog()}_renderSettingsDialog(){return this._editorRuntimeOrThrow()._renderSettingsDialog()}_rulesSet(e){return this._editorRuntimeOrThrow()._rulesSet(e)}async _saveRules(){return this._editorRuntimeOrThrow()._saveRules()}_renderRulesDialog(){return this._editorRuntimeOrThrow()._renderRulesDialog()}_saveKioskScale(e){this._kioskScale={...this._kioskScale,...e};try{localStorage.setItem(xm,JSON.stringify(this._kioskScale))}catch{}this.requestUpdate()}_renderKioskDialog(){const e=this._kioskScale,t=(t,i)=>{const n=Math.round(100*e[t]);return j` +
+ {const i=Number(e.target.value);Number.isFinite(i)&&this._saveKioskScale({[t]:i/100})}} aria-label=${i} /> + ${n}% +
`};return j`this._kioskDialog=!1}> +
+
${this._t("kiosk.hint")}
+ ${t("icon",this._t("kiosk.icon_scale"))} + ${t("font",this._t("kiosk.font_scale"))} +
+
+ + + +
+
`}_fixedFloorValue(e){if("string"==typeof e)return e||"''";try{const t=JSON.stringify(e);return(void 0===t?String(e):t).slice(0,160)}catch{return String(e).slice(0,160)}}render(){if(!this._config||!this.hass)return U;const e=Qd(this,ru,hu(this.hass,this._config.language));if("cold"===e)return eu();if("warm"===e)return V;const t=!!this._importDialog||!(!this._spaceDialog||!this._spaceDialogUsesOnboardingRuntime(this._spaceDialog.mode)),i="view"!==this._mode||!!(this._roomDialog||this._mergeDialog||this._openingDialog||this._physicalDialog||this._partitionDeleteDialog||this._roomDeleteDialog||this._decorTextDialog||this._decorShapeDialog||this._backdropDialog||this._decorEraseConfirm||this._spaceDialog&&!this._spaceDialogUsesOnboardingRuntime(this._spaceDialog.mode)||this._deviceInbox||this._markerDialog||this._rulesDialog||this._settingsDialog||this._alignDialog||this._backupExportDialog||this._backupImportDialog||this._kioskDialog||this._vacFit||this._vacCalConfirm);t&&!this._onboardingRuntime&&this._ensureOnboardingRuntime(),i&&!this._editorRuntime&&this._ensureEditorRuntime();const n=this._model,r=this.houseplanDiagnostics(),o=this._fixedFloorState(n);if("pending"===o.kind)return j` +
+
${this._config.title||this._t("card.title")}
+
+
+ +

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

+
+
`;if("invalid"===o.kind)return j` +
+
${this._config.title||this._t("card.title")}
+
+ +
`;if(!n.length)return j` +
+
${this._config.title||this._t("card.title")}
+
+
+ +

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

+ ${this._serverStorage?j`

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

+ `:j`

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

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

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

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

${this._tapConfirm.text}

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

${e}

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

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

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

${this._reason(t.fallbackReason)}

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

${this._reason(t)}

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

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

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

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

`:a} +
+
+ ${t.visualSources.length||t.criticalSources.length?o`
+ ${this._t("marker.preview.details")} +
+ ${[...t.visualSources,...t.criticalSources].map(t=>o` +
+ ${t.name}${t.eid} + ${t.stateText||t.state} + ${this._sourceProvider(t.eid)} +
`)} +
+
`:a} + ${"icon_ripple"===t.display?o`
+ + +
`:a} +
`}}io.properties={hass:{attribute:!1},presentation:{attribute:!1},registry:{attribute:!1},deviceName:{attribute:!1}},io.styles=[c,n` + :host { display: block; min-width: 0; } + .devicepreview { + margin: 4px 0 14px; + padding: 14px; + border: 1px solid var(--divider-color, rgba(127, 127, 127, 0.28)); + border-radius: 14px; + background: color-mix(in srgb, var(--card-background-color, #20232b) 92%, var(--primary-color, #03a9f4)); + color: var(--primary-text-color, #fff); + overflow: hidden; + } + .previewhead { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; } + .previewbadge { + padding: 3px 9px; + border-radius: 999px; + color: var(--secondary-text-color, #9aa0aa); + background: color-mix(in srgb, var(--secondary-text-color, #9aa0aa) 12%, transparent); + font-size: 12px; + font-weight: 700; + } + .previewbadge.example { color: var(--warning-color, #ffb300); } + .previewgrid { display: grid; grid-template-columns: minmax(170px, 0.8fr) minmax(240px, 1.2fr); gap: 16px; align-items: stretch; } + .previewstage { + position: relative; + min-height: 168px; + border-radius: 12px; + background: var(--secondary-background-color, rgba(0, 0, 0, 0.16)); + overflow: hidden; + pointer-events: none; + container-type: inline-size; + --icon-size: 54px; + --device-base-size: 48.6px; + } + .previewfit { position: absolute; left: 50%; top: 50%; transform-origin: center; } + .previewstage .dev { left: 0; top: 0; cursor: default; } + :host([data-pointer-hover]) .previewstage .dev:hover { z-index: 2; } + .previewfacts { min-width: 0; display: grid; align-content: start; gap: 8px; } + .previewfacts > div { display: grid; grid-template-columns: minmax(115px, 0.8fr) minmax(0, 1.3fr); gap: 8px; } + .previewfacts span { color: var(--secondary-text-color, #9aa0aa); } + .previewfacts b { min-width: 0; overflow-wrap: anywhere; } + .previewnotice { margin: 2px 0 0; color: var(--secondary-text-color, #9aa0aa); font-size: 13px; } + .previewdetails { margin-top: 12px; } + .previewdetails summary { cursor: pointer; color: var(--secondary-text-color, #9aa0aa); } + .previewtable { display: grid; gap: 8px; margin-top: 9px; } + .previewsource { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 3px 10px; font-size: 13px; } + .previewsource > * { min-width: 0; overflow-wrap: anywhere; } + .previewsource code { color: var(--secondary-text-color, #9aa0aa); } + .previewdemo { + min-height: 40px; + display: inline-flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + border: 1px solid var(--divider-color, rgba(127, 127, 127, 0.35)); + border-radius: 10px; + background: transparent; + color: inherit; + cursor: pointer; + } + .previewdemos { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; } + .previewdemo:focus-visible { outline: 2px solid var(--primary-color, #03a9f4); outline-offset: 2px; } + .previewdemo:disabled { opacity: 0.5; cursor: not-allowed; } + @media (max-width: 640px) { + .previewgrid { grid-template-columns: minmax(0, 1fr); } + .previewstage { min-height: 142px; } + .previewfacts > div { grid-template-columns: minmax(0, 1fr); gap: 2px; } + } + `],customElements.get("hp-device-preview")||customElements.define("hp-device-preview",io);const oo=(t,e)=>[t[0]-e[0],t[1]-e[1]],ao=(t,e)=>[t[0]+e[0],t[1]+e[1]],no=(t,e)=>t[0]*e[0]+t[1]*e[1],ro=t=>Math.hypot(t[0],t[1]);function ho(t){let e=0;for(let s=0;st[1]!=h>t[1]&&t[0]<(r-a)*(t[1]-n)/(h-n)+a&&(s=!s)}return s}([r[0]+n[0]*h,r[1]+n[1]*h],t)&&(n=[-n[0],-n[1]]),n}function po(t){const e=t.length;if(e<3)return!1;for(let s=0;s(t[0]-o[0])*r[1]-(t[1]-o[1])*r[0],l=t=>(t[0]-o[0])*r[0]+(t[1]-o[1])*r[1],c=s,d=n-s;for(const e of t){const t=Math.abs(h(e));if(t<=s)continue;const o=l(e);o<=c||o>=d||tMath.abs(n+(t-p)/g*(r-n));i=Math.min(i,f(u),f(m))}}return i}function uo(t,e,s){if($(t,e,s))return!0;if(y(t,e,s)||y(e,t,s))return!1;let i=0;try{const s=w([[...t.map(t=>[t[0],t[1]]),[t[0][0],t[0][1]]]],[[...e.map(t=>[t[0],t[1]]),[e[0][0],e[0][1]]]]);for(const t of s)t?.[0]&&(i+=k(t[0]))}catch{return!1}return i>Math.max(1e-7,s*s)}function mo(t,e,s){for(const i of e)for(let e=0;es)continue;const l=(t.x-o[0])*h[0]+(t.y-o[1])*h[1];if(l-t.length/2>=-s&&l+t.length/2<=r+s)return!0}return!1}function go(t,e,s){const i=Math.abs(e[0]-t[0]),o=Math.abs(e[1]-t[1]);return i<=s&&o>s?"v":o<=s&&i>s?"h":null}function fo(t,e,s){return Math.abs(t[0]-e[0])<=s&&Math.abs(t[1]-e[1])<=s}function bo(t,e,s,i,o){return fo(t,s,o)&&fo(e,i,o)||fo(t,i,o)&&fo(e,s,o)}function vo(t,e,s,i,o){const a=go(t,e,o);return a&&go(s,i,o)===a?"h"===a?Math.abs(t[1]-s[1])>o||Math.abs(t[1]-i[1])>o?0:Math.max(0,Math.min(Math.max(t[0],e[0]),Math.max(s[0],i[0]))-Math.max(Math.min(t[0],e[0]),Math.min(s[0],i[0]))):Math.abs(t[0]-s[0])>o||Math.abs(t[0]-i[0])>o?0:Math.max(0,Math.min(Math.max(t[1],e[1]),Math.max(s[1],i[1]))-Math.max(Math.min(t[1],e[1]),Math.min(s[1],i[1]))):0}function yo(t,e,s,i){const o=t.length,a=go(t[(e-1+o)%o],t[e],i),n=go(t[(e+1)%o],t[(e+2)%o],i),r="h"===s?"v":"h";return a===r&&n===r}function $o(t){let e=1/0,s=1/0,i=-1/0,o=-1/0;for(const a of t)e=Math.min(e,a[0]),s=Math.min(s,a[1]),i=Math.max(i,a[0]),o=Math.max(o,a[1]);return[e,s,i,o]}function wo(t,e,s){const i=$o(t),o=$o(e);return i[2]o}const xo=(t,e)=>"h"===e?t[0]:t[1],Mo=(t,e)=>"h"===e?t[1]:t[0];function So(t,e,s,i,o){const a=t.find(t=>t.id===e);if(!a)return null;const n=a.poly[s],r=a.poly[(s+1)%a.poly.length],h=go(n,r,o);if(!h)return null;const l=0===i?r:n,c=0===i?n:r,d=xo(l,h),p=xo(c,h),_=Mo(l,h),u=function(t,e,s,i){const o=[];for(const a of t)for(let t=0;ti||Math.abs(Mo(r,e)-s)>i)continue;const h=xo(n,e),l=xo(r,e),c=Math.min(h,l),d=Math.max(h,l);d-c>i&&o.push({roomId:a.id,edge:t,lo:c,hi:d})}return o.sort((t,e)=>t.lo-e.lo||t.hi-e.hi||t.roomId.localeCompare(e.roomId)||t.edge-e.edge)}(t,h,_,o),m=function(t,e,s,i){const o=[e,s];for(const a of t){const t=Math.max(e,a.lo),n=Math.min(s,a.hi);n-t>i&&o.push(t,n)}const a=[...new Set(o)].sort((t,e)=>t-e),n=[];for(let e=0;e+1r>t.lo-i&&rt.roomId))].sort();n.push({lo:s,hi:o,owners:h})}return n}(u,Math.min(d,p),Math.max(d,p),o);return!m.length||m.some(t=>t.owners.length<1||t.owners.length>2)?null:{roomId:e,edge:s,movedEndpoint:i,axis:h,line:_,fixed:d,moving:p,intervals:u,baseline:m}}function Co(t,e,s){const i=[];for(const o of t.intervals){const a=e.polys[o.roomId];if(!a){i.push(o);continue}if(o.edge<0||o.edge>=a.length)continue;const n=a[o.edge],r=a[(o.edge+1)%a.length];if(go(n,r,s)!==t.axis||Math.abs(Mo(n,t.axis)-t.line)>s||Math.abs(Mo(r,t.axis)-t.line)>s)continue;const h=xo(n,t.axis),l=xo(r,t.axis),c=Math.min(h,l),d=Math.max(h,l);d-c>s&&i.push({...o,lo:c,hi:d})}return i}function Do(t,e,s){return new Set(t.filter(t=>e>t.lo-s&&et.roomId)).size}function Po(t,e,s){for(const i of e.sideOwnership){const e=t.polys[i.roomId];if(!e)return!1;const o=e[i.edge],a=e[(i.edge+1)%e.length];if(go(o,a,s)!==i.axis)return!1;const n=xo(0===i.movedEndpoint?o:a,i.axis),r=Co(i,t,s),h=(i.moving>=i.fixed?i.baseline[i.baseline.length-1]:i.baseline[0]).owners.length;if(h<1||h>2)return!1;const l=Math.min(i.fixed,i.moving,n),c=Math.max(i.fixed,i.moving,n),d=[l,c,i.fixed,i.moving,n];for(const t of i.intervals)d.push(t.lo,t.hi);for(const t of r)d.push(t.lo,t.hi);const p=[...new Set(d.filter(t=>t>=l&&t<=c))].sort((t,e)=>t-e),_=Math.min(i.fixed,i.moving),u=Math.max(i.fixed,i.moving),m=Math.min(i.fixed,n),g=Math.max(i.fixed,n);for(let t=0;t+1_-s&&am-s&&a2||d>2)return!1;if(n&&l){if(c!==d)return!1}else if(!n&&l){if(d!==h||c>0&&c!==d)return!1}else if(2===c?2!==d:d>1)return!1}}return!0}function Io(t,e,s,i){const o=[s.n[0]*i,s.n[1]*i],a={polys:{},openings:{},movedSpans:{}};for(const e of s.roomIds){const i=t.find(t=>t.id===e),n=s.edgeByRoom[e];if(!i||null==n)continue;const r=(n+1)%i.poly.length;a.polys[e]=i.poly.map((t,e)=>e===n||e===r?ao(t,o):[...t]),a.movedSpans[e]=[[ao(i.poly[n],o),ao(i.poly[r],o)]]}for(const t of e)s.movingOpeningIds.includes(t.id)&&(a.openings[t.id]=[t.x+o[0],t.y+o[1]]);return a}function To(t,e,s,i,o,a,n,r){if(!function(t,e,s,i){if(lo([t.x,t.y],e,s)>2*i)return!1;const o=ro(oo(s,e));if(o<=i)return!1;const a=[(s[0]-e[0])/o,(s[1]-e[1])/o],n=(t.x-e[0])*a[0]+(t.y-e[1])*a[1];return n>=-i&&n<=o+i}(t,e,s,r))return!0;if(lo([t.x,t.y],i,o)>2*r)return!1;const h=0===a?i:o;return ro(oo([t.x,t.y],h))>=t.length/2+n-r}function Ro(t,e,s,i){const o=i.movingHalf||0;return"circle"===t.kind?lo(t.center,e,s)2)return!1;const r=Io(t,e,s,i);if(Object.keys(r.polys).length!==s.roomIds.length)return!1;if(!Po(r,s,a))return!1;const h=new Set(s.roomIds),l=t=>r.polys[t.id]||t.poly;for(const i of s.roomIds){const h=t.find(t=>t.id===i),l=r.polys[i],c=s.edgeByRoom[i];if(!h||!l||l.length!==s.topology[i]||l.length!==h.poly.length||!po(l))return!1;const d=h.poly.length,p=(c-1+d)%d,_=[p,c,(c+1)%d];for(const t of _)if(v(l[t],l[(t+1)%d]))return!1;const u=ho(h.poly),m=ho(l);if(Math.abs(m)t.id===e),i=r.polys[e];for(const o of t){if(o.id===e||h.has(o.id))continue;const t=l(o);if(!wo(s.poly,o.poly,a)||!wo(i,t,a))if(y(s.poly,o.poly,a)){if(!y(i,t,a))return!1}else if(y(o.poly,s.poly,a)){if(!y(t,i,a))return!1}else if(y(i,t,a)||y(t,i,a)||uo(i,t,a))return!1}}t.find(t=>t.id===s.roomId);const c=r.polys[s.roomId],d=s.edgeByRoom[s.roomId],p=c[d],_=c[(d+1)%c.length];if(Math.abs(i)>a)for(const t of o.obstacles||[])if(Ro(t,p,_,o))return!1;for(const t of e){if(!s.movingOpeningIds.includes(t.id))continue;const e=r.openings[t.id];if(!e||t.hosted)return!1;if(!mo({...t,x:e[0],y:e[1]},[c],2*a))return!1}return!0}const Fo=new WeakMap,Ao=t=>"number"==typeof t&&Number.isFinite(t),No=(t,e)=>{const s=new Map;for(const i of t||[])!Ao(i?.cm)||!e&&i.cm<=0||s.set(i.cm,(s.get(i.cm)||0)+1);return s},Ho=t=>[String(t),"см"].join(" ");function Oo(t,e,s={}){if(s.allowClear)return[];const i=!0===s.exactMultiplicity,o=No(t,i),a=No(e,i),n=[];for(const[t,e]of o){const s=a.get(t)||0;0===s?n.push({invariant:"wall_records",kind:"lost",owner:Ho(t),reference:`было ${e}`,detail:"записи этой толщины исчезли целиком"}):i&&s!==e&&n.push({invariant:"wall_records",kind:"count",owner:Ho(t),reference:`было ${e}, стало ${s}`,detail:"изменилось число записей этой толщины"})}if(i)for(const[t,e]of a)o.has(t)||n.push({invariant:"wall_records",kind:"count",owner:Ho(t),reference:`было 0, стало ${e}`,detail:"появились записи новой толщины"});return n}class Lo{constructor(){this._selectedRoomId=null,this._session=null,this._eligibility=null}get dragging(){return null!==this._session}ownsPointer(t){return this._session?.pointerId===t}get selectedRoomId(){return this._selectedRoomId}get snapshotIdentity(){return this._session?.snapshotIdentity||null}get activePointerId(){return this._session?.pointerId??null}get moved(){return!0===this._session?.moved}get delta(){return this._session?.delta||0}get rooms(){return this._session?.rooms||null}get openings(){return this._session?.openings||null}get plan(){return this._session?.plan||null}get preview(){return this._session?.accepted?.preview||null}get liveLabels(){return this._session?.accepted?.labels||null}selectRoom(t){this._selectedRoomId=t}restoreSelection(t){this._selectedRoomId=t}escapeIdle(){return this._selectedRoomId?(this._selectedRoomId=null,"selection-cleared"):"exit-tool"}resolve(t,e,s){this._eligibility&&this._eligibility.context===t||(this._eligibility={context:t,values:new Map});const i=this._eligibility.values.get(e);if(i)return i;const o=s();return this._eligibility.values.set(e,o),o}begin(t){return!this._session&&(this._session={pointerId:t.pointerId,start:[...t.start],roomId:t.roomId,plan:t.plan,options:t.options,rooms:t.rooms,openings:t.openings,snapshotIdentity:t.snapshotIdentity,before:t.before,moved:!1,delta:0,changedRoomIds:[...t.plan.roomIds],rejectionNotified:!1,wallUnionBefore:t.wallUnionBefore,accepted:null},!0)}move(t){const e=this._session;if(!e||e.pointerId!==t.pointerId)return{kind:"no-op"};const s=(i=e.start,o=t.point,a=e.plan.n,[i?.[0],i?.[1],o?.[0],o?.[1],a?.[0],a?.[1]].every(Number.isFinite)?(o[0]-i[0])*a[0]+(o[1]-i[1])*a[1]:0);var i,o,a;const n=t.snap([e.plan.a[0]+e.plan.n[0]*s,e.plan.a[1]+e.plan.n[1]*s]),r=(n[0]-e.plan.a[0])*e.plan.n[0]+(n[1]-e.plan.a[1])*e.plan.n[1],h=function(t,e,s,i,o,a){if(!Number.isFinite(i)||Math.abs(i)<1e-9)return 0;const n=Math.sign(i),r=Math.abs(i),h=Math.max(Math.abs(o),1e-6);let l=Fo.get(s);l&&l.opts===a||(l={opts:a,values:new Map},Fo.set(s,l));const c=l.values;let d=0;for(let i=Math.min(h,r),o=0;o<4096&&i<=r+1e-9;o++,i=Math.min(r,i+h)){const o=n*i,l=`${o.toFixed(9)}|${h.toFixed(9)}`;let p=c.get(l);if(void 0===p&&(p=zo(t,e,s,o,a),c.size<4096&&c.set(l,p)),!p)break;if(d=o,Math.abs(i-r)<=1e-9)break}return d}(e.rooms,e.openings,e.plan,r,t.step,e.options);if(e.moved&&h===e.delta)return{kind:"no-op"};const l=Io(e.rooms,e.openings,e.plan,h);let c;try{if(c=t.project(e.snapshotIdentity,l.polys,l.openings,e.changedRoomIds,e.rooms),!c.ok)return this._projectionRejected(e);if(Oo(c.value.beforeWalls,c.value.afterWalls,{exactMultiplicity:!0}).length)return this._projectionRejected(e)}catch{return this._projectionRejected(e)}const d=e.accepted,p={preview:c.value.preview,labels:null,artifact:c.value.artifact,beforeWalls:c.value.beforeWalls,afterWalls:c.value.afterWalls};e.accepted=p;try{t.publish(p.preview,p.artifact),p.labels=t.measure(l,e.plan)}catch{e.accepted=d;try{t.publish(d?.preview||null,d?.artifact||null)}catch{}return this._projectionRejected(e)}return e.moved=!0,e.delta=h,{kind:"accepted",preview:c.value.preview,labels:p.labels,artifact:c.value.artifact}}finish(t){const e=this._session;if(!e||e.pointerId!==t.pointerId)return{kind:"no-op"};const s=e.accepted;let i;if(e.moved&&Math.abs(e.delta)>1e-9&&s)if(t.currentSnapshotIdentity!==e.snapshotIdentity)i={kind:"rejected",reason:"stale-snapshot"};else if(zo(e.rooms,e.openings,e.plan,e.delta,e.options))if(Oo(s.beforeWalls,s.afterWalls,{exactMultiplicity:!0}).length)i={kind:"rejected",reason:"wall-records"};else{let o=!1;try{o=t.validatePreview(s.preview)}catch{o=!1}i=o?{kind:"commit",preview:s.preview,before:e.before}:{kind:"rejected",reason:"invalid-candidate"}}else i={kind:"rejected",reason:"invalid-topology"};else i={kind:"no-op"};return this._session=null,"commit"===i.kind&&(this._eligibility=null),i}cancel(t,e){const s=this._session;return!s||void 0!==e&&s.pointerId!==e?{kind:"no-op"}:(this._session=null,this._eligibility=null,{kind:"cancelled",restoreWallUnion:t===s.snapshotIdentity?s.wallUnionBefore:null})}reset(){this._selectedRoomId=null,this._session=null,this._eligibility=null}_projectionRejected(t){const e=!t.rejectionNotified;return t.rejectionNotified=!0,{kind:"rejected",notify:e}}}const Eo=(t,e)=>[(t[0]-e.x)/Math.max(1e-9,e.w)*e.stageWidth,(t[1]-e.y)/Math.max(1e-9,e.h)*e.stageHeight];function Bo(t){const{poly:e,edge:s,text:i,view:o}=t,a=e[s],n=e[(s+1)%e.length],r=[(a[0]+n[0])/2,(a[1]+n[1])/2],h=function(t,e){const s=t[e],i=t[(e+1)%t.length],o=i[0]-s[0],a=i[1]-s[1],n=Math.hypot(o,a)||1;return(t=>{let e=0;for(let s=0;s=0?[-a/n,o/n]:[a/n,-o/n]}(e,s),l=Math.hypot(n[0]-a[0],n[1]-a[1])||1,c=[(n[0]-a[0])/l,(n[1]-a[1])/l],d=Eo(r,o),p=Eo(t.gearCenter,o),_=Math.max(34,7.2*i.length+12),u=Math.abs(h[0])>=Math.abs(h[1])?Math.max(28,_/2+4):Math.max(28,13),m=d[0]+h[0]*u,g=d[1]+h[1]*u,f=e=>{return s=m+c[0]*e,i=g+c[1]*e,o=_,a=18,n=p[0],r=p[1],h=t.gearWidthPx,l=t.gearHeightPx,2*Math.abs(s-n)=Math.abs(c[1])?c[0]:c[1])>0?-1:1,e=Math.max(o.stageWidth,o.stageHeight,64);for(let s=4;s<=e;s+=4){const e=s*t;if(!f(e)){b=e;break}const i=-e;if(!f(i)){b=i;break}}}const v=h[0]*u+c[0]*b,y=h[1]*u+c[1]*b,$=Math.hypot(v,y)||1,w=y/$*12,k=[r[0]+v/$*12*o.w/Math.max(1,o.stageWidth),r[1]+w*o.h/Math.max(1,o.stageHeight)];return{anchor:r,offsetXPx:v,offsetYPx:y,tangentOffsetPx:b,side:Math.abs(h[0])>=Math.abs(h[1])?h[0]<0?"left":"right":h[1]<0?"above":"below",leader:{a:r,b:k}}}const Wo=[{id:"air_conditioner",group:"appliance",art:{d:"M20.5 39h69a2.5 2.5 0 0 1 2.5 2.5V69a2.5 2.5 0 0 1-2.5 2.5h-69A2.5 2.5 0 0 1 18 69V41.5a2.5 2.5 0 0 1 2.5-2.5 M25 63a2.5 2.5 0 0 1 2.5-2.5h55A2.5 2.5 0 0 1 85 63v8.5H25z M25 63a2.5 2.5 0 0 1 2.5-2.5h55A2.5 2.5 0 0 1 85 63v3.5H25z",viewW:110,viewH:110}},{id:"armchair",group:"furniture",art:{d:"M42.5 29h25a10 10 0 0 1 10 10v26.5a10 10 0 0 1-10 10h-25a10 10 0 0 1-10-10V39a10 10 0 0 1 10-10 M77.5 48.5a6 6 0 0 1 2 11.657V71.5a4 4 0 0 1-4 4H34a4 4 0 0 1-4-4V60.157A6.001 6.001 0 0 1 32 48.5a6 6 0 0 1 5.419 3.424A4 4 0 0 1 38 54v7h33.5v-6.5q0-.107.005-.213A6 6 0 0 1 77.5 48.5 M42.75 57h24.5A4.75 4.75 0 0 1 72 61.75a4.75 4.75 0 0 1-4.75 4.75h-24.5A4.75 4.75 0 0 1 38 61.75 4.75 4.75 0 0 1 42.75 57M36.5 75.5h8l-1.674 5.441A1.5 1.5 0 0 1 41.392 82H38a1.5 1.5 0 0 1-1.5-1.5zm36 0h-8l1.674 5.441A1.5 1.5 0 0 0 67.608 82H71a1.5 1.5 0 0 0 1.5-1.5z",viewW:110,viewH:110}},{id:"bathtub",group:"sanitary",art:{d:"M28 75h8l-1.674 5.441a1.5 1.5 0 0 1-1.434 1.059H29.5A1.5 1.5 0 0 1 28 80zm53 0h-8l1.674 5.441a1.5 1.5 0 0 0 1.434 1.059H79.5A1.5 1.5 0 0 0 81 80zM19.5 46.5H90a2.5 2.5 0 0 1 2.5 2.5 2.5 2.5 0 0 1-2.5 2.5H19.5A2.5 2.5 0 0 1 17 49a2.5 2.5 0 0 1 2.5-2.5 M19.5 51.5H90L86.633 68a10 10 0 0 1-9.798 8h-44.17a10 10 0 0 1-9.798-8zM30 36v-2a5 5 0 1 0-10 0v12.5",viewW:110,viewH:110}},{id:"bed",group:"furniture",art:{d:"M16 75.5h8l-1.674 5.441A1.5 1.5 0 0 1 20.892 82H17.5a1.5 1.5 0 0 1-1.5-1.5zm78.5 0h-8l1.674 5.441A1.5 1.5 0 0 0 89.608 82H93a1.5 1.5 0 0 0 1.5-1.5zM25 29h60.5a2.5 2.5 0 0 1 2.5 2.5V68a2.5 2.5 0 0 1-2.5 2.5H25a2.5 2.5 0 0 1-2.5-2.5V31.5A2.5 2.5 0 0 1 25 29 M16 59.5c0-5.523 4.477-10 10-10h58.5c5.523 0 10 4.477 10 10v6H16zm-1 6h80.5a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H15a1 1 0 0 1-1-1v-8a1 1 0 0 1 1-1m15.5-20a5 5 0 0 1 5-5h11a5 5 0 0 1 5 5v4h-21zm28.5 0a5 5 0 0 1 5-5h11a5 5 0 0 1 5 5v4H59z",viewW:110,viewH:110}},{id:"bidet",group:"sanitary",art:{d:"M36 57.5c0 5.523 4.477 10 10 10h18.5c5.523 0 10-4.477 10-10V53H36zm8.5 22a1 1 0 0 0 1 1H65a1 1 0 0 0 1-1v-12H44.5zm-8.5-32a1 1 0 0 1 1-1h36.5a1 1 0 0 1 1 1V53H36zM50.5 41a1 1 0 0 1 1-1H59a1 1 0 0 1 1 1v5.5h-9.5zM53 30a1 1 0 0 1 1-1h2.5a1 1 0 0 1 1 1v10H53zm-4 6a1 1 0 0 1-1-1v-2.5a1 1 0 0 1 1-1h4V36z",viewW:110,viewH:110}},{id:"boiler",group:"appliance",art:{d:"M46.5 81.5h5V86a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1zm12.5 0h5V86a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1zM44 23h22.5a8 8 0 0 1 8 8v42.5a8 8 0 0 1-8 8H44a8 8 0 0 1-8-8V31a8 8 0 0 1 8-8 M36 31a8 8 0 0 1 8-8h22.5a8 8 0 0 1 8 8v42H36z M48.5 42.5a7 7 0 1 0 14 0 7 7 0 1 0-14 0m6.5 0 3.5-3.5",viewW:110,viewH:110}},{id:"chair",group:"furniture",art:{d:"M40.5 39.5C40.5 32.596 46.096 27 53 27h4c6.904 0 12.5 5.596 12.5 12.5v13a5 5 0 0 1-5 5h-19a5 5 0 0 1-5-5z M41.25 54h27.5A3.25 3.25 0 0 1 72 57.25a3.25 3.25 0 0 1-3.25 3.25h-27.5A3.25 3.25 0 0 1 38 57.25 3.25 3.25 0 0 1 41.25 54m28.25 6.5H64l1.88 21.63a1.5 1.5 0 0 0 1.495 1.37H68a1.5 1.5 0 0 0 1.5-1.5zm-29 0H46l-1.88 21.63a1.5 1.5 0 0 1-1.495 1.37H42a1.5 1.5 0 0 1-1.5-1.5z",viewW:110,viewH:110}},{id:"coffee_table",group:"furniture",art:{d:"M25 51h5.238l-1.534 15.646A1.5 1.5 0 0 1 27.211 68H26.5a1.5 1.5 0 0 1-1.5-1.5zm60.238 0H80l1.534 15.646A1.5 1.5 0 0 0 83.027 68h.711a1.5 1.5 0 0 0 1.5-1.5z M24.34 43.485A2.5 2.5 0 0 1 26.625 42h56.75a2.5 2.5 0 0 1 2.285 1.485l2.715 6.109A1 1 0 0 1 87.461 51H22.54a1 1 0 0 1-.914-1.406z M87.5 51h-66v3a1 1 0 0 0 1 1h64a1 1 0 0 0 1-1z",viewW:110,viewH:110}},{id:"computer",group:"appliance",art:{d:"M24.5 38h40a2.5 2.5 0 0 1 2.5 2.5v22a2.5 2.5 0 0 1-2.5 2.5h-40a2.5 2.5 0 0 1-2.5-2.5v-22a2.5 2.5 0 0 1 2.5-2.5m50 0h11a2.5 2.5 0 0 1 2.5 2.5v29a2.5 2.5 0 0 1-2.5 2.5h-11a2.5 2.5 0 0 1-2.5-2.5v-29a2.5 2.5 0 0 1 2.5-2.5M43 65h5v7h-5zm-6 7h16m23-12h8m-8-17h8 M35 56V46h5m-5 7h5 M39.5 53a3.5 3.5 0 1 0 0-7m15.036 8.536a5 5 0 1 1 0-7.071",viewW:110,viewH:110}},{id:"cooktop",group:"appliance",art:{d:"M27.5 29h55a2.5 2.5 0 0 1 2.5 2.5v47a2.5 2.5 0 0 1-2.5 2.5h-55a2.5 2.5 0 0 1-2.5-2.5v-47a2.5 2.5 0 0 1 2.5-2.5 M33.5 66.5a8 8 0 1 0 16 0 8 8 0 1 0-16 0m26.5-23a8 8 0 1 0 16 0 8 8 0 1 0-16 0m3 23a5 5 0 1 0 10 0 5 5 0 1 0-10 0m-29.5-23a8 8 0 1 0 16 0 8 8 0 1 0-16 0",viewW:110,viewH:110}},{id:"dining_table",group:"furniture",art:{d:"M83.5 43H78l6.742 30.82A1.5 1.5 0 0 0 86.207 75h.54a1.5 1.5 0 0 0 1.482-1.732zm-56 0H33l-6.742 30.82A1.5 1.5 0 0 1 24.793 75h-.54a1.5 1.5 0 0 1-1.482-1.732zm-2.62-7.406A2.5 2.5 0 0 1 27.21 34h56.58a2.5 2.5 0 0 1 2.33 1.594l2.35 6.044A1 1 0 0 1 87.538 43H23.462a1 1 0 0 1-.932-1.362z M88.5 43h-66v3a1 1 0 0 0 1 1h64a1 1 0 0 0 1-1z",viewW:110,viewH:110}},{id:"dishwasher",group:"appliance",art:{d:"M31.5 25h47a2.5 2.5 0 0 1 2.5 2.5v55a2.5 2.5 0 0 1-2.5 2.5h-47a2.5 2.5 0 0 1-2.5-2.5v-55a2.5 2.5 0 0 1 2.5-2.5 M31.5 37.5h47A2.5 2.5 0 0 1 81 40v36a2.5 2.5 0 0 1-2.5 2.5h-47A2.5 2.5 0 0 1 29 76V40a2.5 2.5 0 0 1 2.5-2.5M43 42h24m-1.5-11a2 2 0 1 0 4 0 2 2 0 1 0-4 0m7.5 0a2 2 0 1 0 4 0 2 2 0 1 0-4 0m-37.25 0h9.5",viewW:110,viewH:110}},{id:"dryer",group:"appliance",art:{d:"M31.5 25h47a2.5 2.5 0 0 1 2.5 2.5v55a2.5 2.5 0 0 1-2.5 2.5h-47a2.5 2.5 0 0 1-2.5-2.5v-55a2.5 2.5 0 0 1 2.5-2.5 M31.5 37.5h47A2.5 2.5 0 0 1 81 40v42.5a2.5 2.5 0 0 1-2.5 2.5h-47a2.5 2.5 0 0 1-2.5-2.5V40a2.5 2.5 0 0 1 2.5-2.5 M38 60.5a17 17 0 1 0 34 0 17 17 0 1 0-34 0 M43.5 60.5a11.5 11.5 0 1 0 23 0 11.5 11.5 0 1 0-23 0m22-29.5a2 2 0 1 0 4 0 2 2 0 1 0-4 0m7.5 0a2 2 0 1 0 4 0 2 2 0 1 0-4 0m-37.25 0h9.5 M55.994 55.5s-1.329 1.81-1.479 3.143c-.198 1.761 1.599 2.554 1.48 4.321-.1 1.479-1.48 3.536-1.48 3.536m5.979-11s-1.329 1.81-1.479 3.143c-.198 1.761 1.599 2.554 1.48 4.321-.1 1.479-1.48 3.536-1.48 3.536m-8.519-11s-.886 1.81-.986 3.143c-.132 1.761 1.066 2.554.986 4.321-.067 1.479-.986 3.536-.986 3.536",viewW:110,viewH:110}},{id:"exercise",group:"other",art:{d:"m60.752 62.03-5.379-2.312 11.066-25.75a1.5 1.5 0 0 1 1.97-.786l2.624 1.127a1.5 1.5 0 0 1 .786 1.97zm-18.648-4.512-4.353 1.189-4.474-16.382a1.5 1.5 0 0 1 1.052-1.842l1.459-.398a1.5 1.5 0 0 1 1.842 1.052z M41.297 38.173a2.215 2.215 0 0 1 0 4.43H29.781a2.215 2.215 0 0 1 0-4.43zm33.219 38.091a2.657 2.657 0 1 1 0 5.315H28.453a2.657 2.657 0 1 1 0-5.315zm8.641-51.366a1.795 1.795 0 0 1 .68 2.41l-3.03 5.59a5 5 0 0 1-4.396 2.618H65.657a1.772 1.772 0 1 1 0-3.544h9.61a3 3 0 0 0 2.598-1.5l2.84-4.917a1.795 1.795 0 0 1 2.452-.657M29.339 65.787c0-6.699 6.457-11.503 12.873-9.579l24.291 7.288a10 10 0 0 1 7.127 9.578v3.19H29.339zm0 15.852h7.086l-1.394 3.486a1.5 1.5 0 0 1-1.393.943h-2.8a1.5 1.5 0 0 1-1.5-1.5zm44.291 0h-7.087l1.395 3.486a1.5 1.5 0 0 0 1.392.943h2.8a1.5 1.5 0 0 0 1.5-1.5z M35.54 66.077a4.872 4.872 0 1 0 9.743 0 4.872 4.872 0 1 0-9.744 0",viewW:110,viewH:110}},{id:"fireplace",group:"other",art:{d:"M26.672 34.425h55.99v39.47h-55.99Z M23 74.894a1 1 0 0 1 1-1h61.334a1 1 0 0 1 1 1v5.802a1 1 0 0 1-1 1H24a1 1 0 0 1-1-1zM23 29a1 1 0 0 1 1-1h61.334a1 1 0 0 1 1 1v4.425a1 1 0 0 1-1 1H24a1 1 0 0 1-1-1zm15.145 21.44a5 5 0 0 1 5-5h23.043a5 5 0 0 1 5 5v23.454H38.145z M44.57 65.633a2.754 2.754 0 0 1 2.754-2.753H62.01v5.507H47.324a2.754 2.754 0 0 1-2.754-2.754m20.194 5.507a2.754 2.754 0 0 0-2.754-2.753H47.324v5.507H62.01a2.754 2.754 0 0 0 2.754-2.754 M44.57 71.14a2.754 2.754 0 1 0 5.508 0 2.754 2.754 0 1 0-5.508 0m14.688-5.507a2.754 2.754 0 1 0 5.507 0 2.754 2.754 0 1 0-5.507 0",viewW:110,viewH:110}},{id:"fridge",group:"appliance",art:{d:"M35.5 18H75a2.5 2.5 0 0 1 2.5 2.5v64A2.5 2.5 0 0 1 75 87H35.5a2.5 2.5 0 0 1-2.5-2.5v-64a2.5 2.5 0 0 1 2.5-2.5 M33 46.5h44.5v38A2.5 2.5 0 0 1 75 87H35.5a2.5 2.5 0 0 1-2.5-2.5zm2.5 44a1 1 0 0 0 1 1h37a1 1 0 0 0 1-1V87h-39zm3-49.5v-9.5m0 30.5v-9.5",viewW:110,viewH:110}},{id:"hood",group:"appliance",art:{d:"M44.308 57h21.384L83 69H27zM44 37.5a2.5 2.5 0 0 1 2.5-2.5h17a2.5 2.5 0 0 1 2.5 2.5V57H44zM80.5 74h-51a2.5 2.5 0 0 1-2.5-2.5V70a1 1 0 0 1 1-1h54a1 1 0 0 1 1 1v1.5a2.5 2.5 0 0 1-2.5 2.5",viewW:110,viewH:110}},{id:"kitchen_cabinet",group:"furniture",art:{d:"M38 88a1 1 0 0 0 1 1h32a1 1 0 0 0 1-1v-3H38zm17-68h16.5a2.5 2.5 0 0 1 2.5 2.5v17a2.5 2.5 0 0 1-2.5 2.5H55zm-19 2.5a2.5 2.5 0 0 1 2.5-2.5H55v22H38.5a2.5 2.5 0 0 1-2.5-2.5zM59 33v5m-8-5v5m4 47h16.5a2.5 2.5 0 0 0 2.5-2.5v-17a2.5 2.5 0 0 0-2.5-2.5H55zm-19-2.5a2.5 2.5 0 0 0 2.5 2.5H55V63H38.5a2.5 2.5 0 0 0-2.5 2.5zM67 67h-5m-14 0h-5",viewW:110,viewH:110}},{id:"kitchen_sink",group:"sanitary",art:{d:"M21.5 84h68a2.5 2.5 0 0 0 2.5-2.5v-35a2.5 2.5 0 0 0-2.5-2.5h-68a2.5 2.5 0 0 0-2.5 2.5v35a2.5 2.5 0 0 0 2.5 2.5 M26 78h26.5a1 1 0 0 0 1-1V51a1 1 0 0 0-1-1H26a1 1 0 0 0-1 1v26a1 1 0 0 0 1 1m23-24v5m9.5 19H85a1 1 0 0 0 1-1V51a1 1 0 0 0-1-1H58.5a1 1 0 0 0-1 1v26a1 1 0 0 0 1 1m-6-39.5a1 1 0 0 0-1-1H44a1 1 0 0 0-1 1V44h9.5zM58 33v-2a5 5 0 1 0-10 0v6.5M62 54v5",viewW:110,viewH:110}},{id:"nightstand",group:"furniture",art:{d:"M76.5 73.5h-8l1.674 5.441A1.5 1.5 0 0 0 71.608 80H75a1.5 1.5 0 0 0 1.5-1.5zm-42.5 0h8l-1.674 5.441A1.5 1.5 0 0 1 38.892 80H35.5a1.5 1.5 0 0 1-1.5-1.5z M34.5 30.5h41A2.5 2.5 0 0 1 78 33v40.5a2.5 2.5 0 0 1-2.5 2.5h-41a2.5 2.5 0 0 1-2.5-2.5V33a2.5 2.5 0 0 1 2.5-2.5 M32 39.5h46v18H32Zm18.5 9H60M50.5 66H60",viewW:110,viewH:110}},{id:"oven",group:"appliance",art:{d:"M31.5 25h47a2.5 2.5 0 0 1 2.5 2.5v55a2.5 2.5 0 0 1-2.5 2.5h-47a2.5 2.5 0 0 1-2.5-2.5v-55a2.5 2.5 0 0 1 2.5-2.5 M31.5 37.5h47A2.5 2.5 0 0 1 81 40v36a2.5 2.5 0 0 1-2.5 2.5h-47A2.5 2.5 0 0 1 29 76V40a2.5 2.5 0 0 1 2.5-2.5 M40.5 47h29a2.5 2.5 0 0 1 2.5 2.5v20a2.5 2.5 0 0 1-2.5 2.5h-29a2.5 2.5 0 0 1-2.5-2.5v-20a2.5 2.5 0 0 1 2.5-2.5m25-16a2 2 0 1 0 4 0 2 2 0 1 0-4 0m7.5 0a2 2 0 1 0 4 0 2 2 0 1 0-4 0m-37.25 0h9.5M43 42h24",viewW:110,viewH:110}},{id:"plant",group:"other",art:{d:"M45.952 75.849a2.5 2.5 0 0 0 2.485 2.231H63.43a2.5 2.5 0 0 0 2.485-2.231l1.571-14.532H44.381zM60.236 44.78C58.423 36.174 66.805 29.605 77 31.87c0 8.155-8.609 16.763-16.763 12.912m-9.761 5.147c1.517-8.665-7.085-14.943-17.195-12.33.28 8.15 9.178 16.458 17.195 12.33 M55.706 55.88v-2.944m0 0c1.133-5.89 7.09-10.956 12.912-15.404M55.706 52.936c-4.938-4.146-7.982-6.16-14.044-9.061m1.453 12.005h25.636a1 1 0 0 1 1 1v3.437a1 1 0 0 1-1 1H43.115a1 1 0 0 1-1-1v-3.436a1 1 0 0 1 1-1",viewW:110,viewH:110}},{id:"rug",group:"other",art:{d:"M90.27 33.874h-5.622m-59.028 0H20m70.27 5.152h-5.622m-59.028 0H20m70.27 5.154h-5.622m-59.028 0H20m70.27 5.152h-5.622m-59.028 0H20m70.27 5.153h-5.622m-59.028 0H20m70.27 5.153h-5.622m-59.028 0H20m70.27 5.153h-5.622m-59.028 0H20m70.27 5.153h-5.622m-59.028 0H20m70.27 5.153h-5.622m-59.028 0H20M28.12 32h54.025a2.5 2.5 0 0 1 2.5 2.5v40.439a2.5 2.5 0 0 1-2.5 2.5H28.12a2.5 2.5 0 0 1-2.5-2.5V34.5a2.5 2.5 0 0 1 2.5-2.5 M25.62 34.5a2.5 2.5 0 0 1 2.5-2.5h1.717v45.439H28.12a2.5 2.5 0 0 1-2.5-2.5zm59.026 0a2.5 2.5 0 0 0-2.5-2.5H80.43v45.439h1.716a2.5 2.5 0 0 0 2.5-2.5zM37.8 54.485l17.801-8.432 17.801 8.432-17.8 8.432z",viewW:110,viewH:110}},{id:"shelving",group:"furniture",art:{d:"M28 58.5h53V39H28Z M64 58.5h5V47a1 1 0 0 0-1-1h-3a1 1 0 0 0-1 1zM52.5 39h-5V27.5a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1zm-12 0h-5V27.5a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1zm-5 29.5V71a1 1 0 0 1 1 1H49a1 1 0 0 1 1-1v-2.5a1 1 0 0 1-1-1H36.5a1 1 0 0 1-1 1m33.5-10h7v-14a1 1 0 0 0-1-1h-5a1 1 0 0 0-1 1zM47.5 39h-7V25a1 1 0 0 1 1-1h5a1 1 0 0 1 1 1zm-12 34v4a1 1 0 0 1 1 1h14a1 1 0 0 1 1-1v-4a1 1 0 0 1-1-1h-14a1 1 0 0 1-1 1M28 78h53v7H28Z M28 89.5V23a2.5 2.5 0 0 1 2.5-2.5h48A2.5 2.5 0 0 1 81 23v66.5",viewW:110,viewH:110}},{id:"shower",group:"sanitary",art:{d:"M31 84h49a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1H31a1 1 0 0 1-1-1v-3a1 1 0 0 1 1-1m31.5-47.6v-4.686a11.7 11.7 0 0 0-3.441-8.283A11.77 11.77 0 0 0 50.75 20a11.77 11.77 0 0 0-8.309 3.431A11.7 11.7 0 0 0 39 31.714V84 M72 39.25a10.25 10.25 0 1 0-20.5 0zm-17.25 5v2.5m7.25-2.5v2.5m7.25-2.5v2.5m-14.5 3.75V53M62 50.5V53m7.25-2.5V53m-14.5 3.75v2.5m7.25-2.5v2.5m7.25-2.5v2.5M54.75 63v2.5M62 63v2.5m7.25-2.5v2.5",viewW:110,viewH:110}},{id:"sink",group:"sanitary",art:{d:"M30 57c0 5.523 4.477 10 10 10h29.5c5.523 0 10-4.477 10-10v-6.5A2.5 2.5 0 0 0 77 48H32.5a2.5 2.5 0 0 0-2.5 2.5zm14 22a1 1 0 0 0 1 1h19.5a1 1 0 0 0 1-1V67H44zm6-36.5a1 1 0 0 1 1-1h7.5a1 1 0 0 1 1 1V48H50zM45 37v-2a5 5 0 1 1 10 0v6.5",viewW:110,viewH:110}},{id:"sofa",group:"furniture",art:{d:"M59.5 29h24a5 5 0 0 1 5 5v32a5 5 0 0 1-5 5h-24a5 5 0 0 1-5-5V34a5 5 0 0 1 5-5m-34 0h24a5 5 0 0 1 5 5v32a5 5 0 0 1-5 5h-24a5 5 0 0 1-5-5V34a5 5 0 0 1 5-5 M18.5 44a5 5 0 0 1 5 5v12H86V49a5 5 0 0 1 5-5h.5a5 5 0 0 1 5 5v21.5a5 5 0 0 1-5 5H18a5 5 0 0 1-5-5V49a5 5 0 0 1 5-5z M25.25 57h24.5a4.75 4.75 0 0 1 4.75 4.75 4.75 4.75 0 0 1-4.75 4.75h-24.5a4.75 4.75 0 0 1-4.75-4.75A4.75 4.75 0 0 1 25.25 57m34 0h24.5a4.75 4.75 0 0 1 4.75 4.75 4.75 4.75 0 0 1-4.75 4.75h-24.5a4.75 4.75 0 0 1-4.75-4.75A4.75 4.75 0 0 1 59.25 57M18.5 75.5h8l-1.674 5.441A1.5 1.5 0 0 1 23.392 82H20a1.5 1.5 0 0 1-1.5-1.5zm72 0h-8l1.674 5.441A1.5 1.5 0 0 0 85.608 82H89a1.5 1.5 0 0 0 1.5-1.5z",viewW:110,viewH:110}},{id:"stairs",group:"other",art:{d:"M73.47 46.365v-17.62m-10.571 25.55V36.674M52.326 61.783V45.484M42.193 69.273v-15.86M28.979 77.761a1 1 0 0 1 1-1h53.624v6.489a1 1 0 0 1-1 1H29.98a1 1 0 0 1-1-1z M26.777 57.497a1 1 0 0 1 1-1h2.846a1 1 0 0 1 1 1V83.25a1 1 0 0 1-1 1h-2.846a1 1 0 0 1-1-1z m73.113 28.633-41.492 32.93v-4.405l39.9-32.007a.7.7 0 0 1 .428-.151h3.724a1.762 1.762 0 1 1 0 3.524h-2.248a.5.5 0 0 0-.312.109M25.895 53.414a3.084 3.084 0 1 0 6.167 0 3.084 3.084 0 1 0-6.167 0m14.978 16.859a1 1 0 0 1 1-1h41.73v7.488h-42.73zm10.131-7.489a1 1 0 0 1 1-1h31.598v7.488H51.004z M61.576 55.294a1 1 0 0 1 1-1h21.026v7.49H61.576z M72.15 47.806a1 1 0 0 1 1-1h9.454a1 1 0 0 1 1 1v6.489H72.15z",viewW:110,viewH:110}},{id:"toilet",group:"sanitary",art:{d:"M32 26.5a2.5 2.5 0 0 1 2.5-2.5H45a2.5 2.5 0 0 1 2.5 2.5V57H32zM47.5 52h29a2.5 2.5 0 0 1 2.5 2.5V57H47.5zm17.037 20.102C73.95 70.288 79 62.01 79 57H32c.5 7.5 8.072 7 7 11l-2.342 16.862a1 1 0 0 0 .99 1.138H66.72a1 1 0 0 0 .97-1.243z",viewW:110,viewH:110}},{id:"tv",group:"appliance",art:{d:"M23.5 31H86a2.5 2.5 0 0 1 2.5 2.5v34A2.5 2.5 0 0 1 86 70H23.5a2.5 2.5 0 0 1-2.5-2.5v-34a2.5 2.5 0 0 1 2.5-2.5M50 70h9.5v8H50Zm-10 8h30M42.5 45.5h5m5 0h-5m0 0v9.75 m56.75 45.5 5 10 5-10",viewW:110,viewH:110}},{id:"wardrobe",group:"furniture",art:{d:"M28 23a2.5 2.5 0 0 1 2.5-2.5h24V85h-24a2.5 2.5 0 0 1-2.5-2.5zm2 65.5a1 1 0 0 0 1 1h47a1 1 0 0 0 1-1V85H30zM81 23a2.5 2.5 0 0 0-2.5-2.5h-24V85h24a2.5 2.5 0 0 0 2.5-2.5zM50.5 48v9.5m8-9.5v9.5",viewW:110,viewH:110}},{id:"washer",group:"appliance",art:{d:"M31.5 25h47a2.5 2.5 0 0 1 2.5 2.5v55a2.5 2.5 0 0 1-2.5 2.5h-47a2.5 2.5 0 0 1-2.5-2.5v-55a2.5 2.5 0 0 1 2.5-2.5 M31.5 37.5h47A2.5 2.5 0 0 1 81 40v42.5a2.5 2.5 0 0 1-2.5 2.5h-47a2.5 2.5 0 0 1-2.5-2.5V40a2.5 2.5 0 0 1 2.5-2.5 M38 60.5a17 17 0 1 0 34 0 17 17 0 1 0-34 0 M43.5 60.5a11.5 11.5 0 1 0 23 0 11.5 11.5 0 1 0-23 0m22-29.5a2 2 0 1 0 4 0 2 2 0 1 0-4 0m7.5 0a2 2 0 1 0 4 0 2 2 0 1 0-4 0m-37.25 0h9.5",viewW:110,viewH:110}},{id:"work_table",group:"furniture",art:{d:"M88.5 47h-20v14h20zm-12 4h4m7.984-8h-66v4h66zm-66 4h4v26.5a1.5 1.5 0 0 1-1.5 1.5h-1a1.5 1.5 0 0 1-1.5-1.5z M24.866 35.597A2.5 2.5 0 0 1 27.197 34h56.577a2.5 2.5 0 0 1 2.33 1.594l2.35 6.044a1 1 0 0 1-.93 1.362H23.46a1 1 0 0 1-.933-1.361zM88.5 61h-20v12.5A1.5 1.5 0 0 0 70 75h17a1.5 1.5 0 0 0 1.5-1.5zm-12 4h4",viewW:110,viewH:110}}],Go=1e-9,jo=1e7,qo=t=>{const e=Math.sign(t)*Math.floor(Math.abs(t)*jo+.5)/jo;return Object.is(e,-0)?0:e},Uo=t=>`${qo(t[0])},${qo(t[1])}`,Ko=(t,e)=>Math.hypot(e[0]-t[0],e[1]-t[1]),Vo=(t,e)=>Math.atan2(e[1]-t[1],e[0]-t[0]),Jo=t=>Array.isArray(t)&&t.length>=2&&t.every(t=>Number.isFinite(t)),Yo=t=>(t||[]).filter(t=>Jo(t?.a)&&Jo(t?.b)&&Ko(t.a,t.b)>Go);function Xo(t,{minAngleDeg:e=15,maxValence:s=6}={}){const i=new Map;for(const e of Yo(t))for(const[t,s]of[[e.a,e.b],[e.b,e.a]]){const e=i.get(Uo(t))||[];e.push(Vo(t,s)),i.set(Uo(t),e)}const o=[];for(const[t,a]of i){if(a.length>s&&o.push({rule:"valence",subject:t,actual:a.length,limit:s}),a.length<2)continue;const i=[...a].sort((t,e)=>t-e);let n=1/0;for(let t=0;tGo&&s(180*Math.atan2(t.b[1]-t.a[1],t.b[0]-t.a[0])/Math.PI%180+180)%180,Qo=(t,e,s=1)=>{const i=Math.abs(Zo(t)-Zo(e));return Math.min(i,180-i)<=s},ta=t=>{const e=new Map;for(const s of t)for(const t of[s.a,s.b]){const i=e.get(Uo(t));i?i.push(s):e.set(Uo(t),[s])}return e};function ea(t,e,s){const i=Yo(e),o=s??ta(i),a=new Set([t]);let n=Ko(t.a,t.b);const r=[t.a,t.b];for(;r.length;){const e=r.pop();for(const s of o.get(Uo(e))||[])a.has(s)||Qo(s,t)&&Number(s.cm||0)===Number(t.cm||0)&&(a.add(s),n+=Ko(s.a,s.b),r.push(s.a,s.b))}return n}function sa(t,e,s,{minLengthCm:i=20}={}){const o=[],a=Yo(t),n=ta(a);for(const t of a){const r=ea(t,a,n)/s*(e||1),h=Math.max(i,Number(t.cm)>0?Number(t.cm):0);r{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o,n=a<=Go?0:Math.max(0,Math.min(1,((t[0]-e[0])*i+(t[1]-e[1])*o)/a));return Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))};function oa(t,e,s,{minDistanceCm:i=5}={}){const o=Yo(t),a=new Map;for(const t of o)a.set(Uo(t.a),t.a),a.set(Uo(t.b),t.b);const n=((t,e,s)=>t/(e||1)*s)(i,e,s),r=n>Go?n:1,h=(t,e)=>`${Math.floor(t/r)},${Math.floor(e/r)}`,l=new Map;for(const[t,e]of a){const s=h(e[0],e[1]),i=l.get(s);i?i.push([t,e]):l.set(s,[[t,e]])}const c=new Map;for(const t of o){const e=Math.min(t.a[0],t.b[0])-n,s=Math.max(t.a[0],t.b[0])+n,i=Math.min(t.a[1],t.b[1])-n,o=Math.max(t.a[1],t.b[1])+n;for(let a=Math.floor(e/r);a<=Math.floor(s/r);a++)for(let e=Math.floor(i/r);e<=Math.floor(o/r);e++){const s=`${a},${e}`,i=c.get(s);i?i.push(t):c.set(s,[t])}}const d=[];for(const[t,o]of a){const a=Math.floor(o[0]/r),h=Math.floor(o[1]/r);for(let r=-1;r<=1;r++)for(let c=-1;c<=1;c++)for(const[p,_]of l.get(`${a+r},${h+c}`)||[]){if(t>=p)continue;const a=Ko(o,_);a<=2e-7||a{const i=a[(s+1)%a.length];return t+(e[0]*i[1]-i[0]*e[1])},0))/2,r=(s||1)/i,h=n*r*r;return ht.removed).map(t=>t.binding)),c=new Set;for(const t of s)t.id!==n&&("device"===t.bindingKind&&t.bindingRef&&c.add(`device:${t.bindingRef}`),"entity"===t.bindingKind&&t.bindingRef&&c.add(`entity:${t.bindingRef}`));const d=new Set;for(const t of s)"device"===t.bindingKind&&t.name&&d.add(`${t.name.trim()}|${t.area||""}`);const p=[];for(const t of Object.values(e?.devices||{})){if(!t||"service"===t.entry_type)continue;const e=`device:${t.id}`;if(c.has(e))continue;const s=String(t.name_by_user||t.name||t.id).trim();e!==a&&!l.has(e)&&d.has(`${s}|${t.area_id||""}`)||p.push({value:e,label:s,sub:(t.model||r.device)+("Group"===t.model?r.z2mGroup:""),kind:"device",ref:t.id,areaId:t.area_id||"",model:t.model||""})}for(const[t,s]of Object.entries(e?.entities||{})){const i=`entity:${t}`;if(c.has(i))continue;if(M(e,t,h)&&!l.has(i))continue;const o=na.has(s?.platform),a="group"===s?.platform;if(!o&&!a)continue;if(s?.hidden&&!l.has(i))continue;const n=e?.states?.[t];p.push({value:i,label:s?.name||n?.attributes?.friendly_name||t,sub:`${t.split(".")[0]} · ${a?r.group:r.helper}`,kind:"entity",ref:t,areaId:s?.area_id||s?.device_id&&e?.devices?.[s.device_id]?.area_id||"",model:"",parentDeviceId:s?.device_id||void 0})}if(o){const t=new Set(p.map(t=>t.value));for(const[s,i]of Object.entries(e?.entities||{})){const o=`entity:${s}`;if(c.has(o)||t.has(o)||i?.hidden&&!l.has(o))continue;const a=!!i?.device_id&&h.devices.has(i.device_id);if(M(e,s,h)&&!l.has(o)&&!a)continue;const n=e?.states?.[s],d=i?.device_id?e?.devices?.[i.device_id]:null,_=d?String(d.name_by_user||d.name||""):"";p.push({value:o,label:i?.name||n?.attributes?.friendly_name||s,sub:`${s.split(".")[0]} · ${r.entity}${_?` · ${_}`:""}`,kind:"entity",ref:s,areaId:i?.area_id||d?.area_id||"",model:"",parentDeviceId:i?.device_id||void 0})}}return p.sort((t,e)=>t.label.localeCompare(e.label)||t.value.localeCompare(e.value))}const ha={kind:"active",enabledEntityIds:[],allEntityIds:[]};function la(t){return t.startsWith("entity:")?"entity":"device"}function ca(t){const e=t.binding.indexOf(":"),s=e>=0?t.binding.slice(e+1):"",i=Object.keys(t).filter(t=>!["id","binding","hidden"].includes(t));return t.id===`h${s}`&&0===i.length}const da=.001;function pa(t){return!!t&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1])}function _a(t){return`${t[0].toFixed(6)},${t[1].toFixed(6)}`}function ua(t,e,s){return Math.abs(t[0]-e[0])"room"!==t.kind&&s.some(s=>s!==t&&function(t,e,s){const i=t.b[0]-t.a[0],o=t.b[1]-t.a[1],a=Math.hypot(i,o);if(!(a>s))return!1;const n=i/a,r=o/a,h=e=>Math.abs((e[0]-t.a[0])*r-(e[1]-t.a[1])*n);if(h(e.a)>s||h(e.b)>s)return!1;const l=(e.a[0]-t.a[0])*n+(e.a[1]-t.a[1])*r,c=(e.b[0]-t.a[0])*n+(e.b[1]-t.a[1])*r;return Math.min(a,Math.max(l,c))-Math.max(0,Math.min(l,c))>s}(t,s,e))),o=i.map(t=>{const[e,s]=ma(t.a,t.b);return{a:e,b:s,key:`hidden|${fa(t,e,s)}`,sourceKind:t.kind,sourceId:t.id}}).sort((t,e)=>t.key.localeCompare(e.key)),a=i.flatMap(t=>[t.a,t.b].map((e,s)=>({point:[e[0],e[1]],key:`hidden|${ga(t)}|endpoint-${s}`,sourceKind:t.kind,sourceId:t.id}))).sort((t,e)=>t.key.localeCompare(e.key));return{segments:o,endpoints:a}}function $a(t){const e=t.epsilon??da,s=t.roomCuts||[],i=new Map;for(const e of t.partitionCuts||[]){if("string"!=typeof e.hostId||!e.hostId||!pa(e.a)||!pa(e.b))continue;const t=i.get(e.hostId)||[];t.push([e.a[0],e.a[1],e.b[0],e.b[1]]),i.set(e.hostId,t)}const o=[];for(const[e,i]of S(t.space.rooms).entries())i.length<4||o.push({a:[i[0],i[1]],b:[i[2],i[3]],kind:"room",id:`room-edge-${e}`,cuts:s});for(const e of t.space.room_drafts||[])if(e.id!==t.activeDraftId)for(let t=0;t+1va(s,t,e)))continue;const t=_a(s);n.has(t)||n.set(t,{point:[s[0],s[1]],key:t})}}}return{segments:[...a.values()].sort((t,e)=>t.key.localeCompare(e.key)),endpoints:[...n.values()].sort((t,e)=>t.key.localeCompare(e.key))}}function wa(t,e,s){return e.some(e=>pa(e)&&ua(t,e,s))}function ka(t,e,s){if(!s)return!0;const i=t-s.distance;return i<-1e-9||Math.abs(i)<=1e-9&&e.localeCompare(s.key)<0}function xa(t,e,s){const i=s.epsilon??da,o=s.excludePoints||[],a=[...t.endpoints,...(s.extraEndpoints||[]).filter(t=>pa(t.point)).map(t=>({point:[t.point[0],t.point[1]],key:t.key}))],n=new Map;for(const t of a){if(wa(t.point,o,i))continue;const e=_a(t.point),s=n.get(e);(!s||t.key.localeCompare(s.key)<0)&&n.set(e,t)}return[...n.values()].map(t=>({kind:"endpoint",point:[...t.point],key:t.key,distance:Math.hypot(e[0]-t.point[0],e[1]-t.point[1])})).filter(t=>t.distance<=s.tolerance).sort((t,e)=>t.distance-e.distance||t.key.localeCompare(e.key))}function Ma(t,e){if(!t.length)return null;if(e>0){const s=new Set;for(let i=0;i1)return{kind:"ambiguous",candidate:null,conflicts:t.filter(t=>s.has(t.key)).map(t=>({point:[...t.point],key:t.key}))}}return{kind:"resolved",candidate:t[0],conflicts:[]}}function Sa(t,e,s){const i=t.b[0]-t.a[0],o=t.b[1]-t.a[1],a=Math.hypot(i,o);if(!(a>0))return[...t.a];const n=i/a,r=o/a,h=Math.max(0,Math.min(a,(e[0]-t.a[0])*n+(e[1]-t.a[1])*r)),l=s>0?Math.max(0,Math.min(a,Math.round(h/s)*s)):h;return[t.a[0]+n*l,t.a[1]+r*l]}function Ca(t,e,s){if(!(pa(e)&&pa(s.anchor)&&s.tolerance>=0))return{kind:"none",candidate:null,conflicts:[]};const i=s.epsilon??da,o=function(t,e){const s=e[0]-t[0],i=e[1]-t[1];if(!(Math.hypot(s,i)>Number.EPSILON))return null;const o=Math.round(Math.atan2(i,s)/(Math.PI/4))*(Math.PI/4);return[Math.cos(o),Math.sin(o)]}(s.anchor,e);if(!o)return{kind:"none",candidate:null,conflicts:[]};const a=xa(t,e,s).filter(t=>function(t,e,s,i){const o=t[0]-e[0],a=t[1]-e[1];return o*s[0]+a*s[1]>i&&Math.abs(o*s[1]-a*s[0])<=i*Math.max(Math.hypot(o,a),1)}(t.point,s.anchor,o,i)),n=Ma(a,s.distinguishTolerance||0);if(n)return n;let r=null;for(const a of t.segments){const t=a.b[0]-a.a[0],n=a.b[1]-a.a[1],h=a.a[0]-s.anchor[0],l=a.a[1]-s.anchor[1],c=o[0]*n-o[1]*t;let d=null;if(Math.abs(c)<=i*Math.max(Math.hypot(t,n),1)){if(Math.abs(h*o[1]-l*o[0])>i*Math.max(Math.hypot(h,l),1))continue;const t=[a.a,a.b].map(t=>({point:t,along:(t[0]-s.anchor[0])*o[0]+(t[1]-s.anchor[1])*o[1]})).filter(t=>t.along>i).sort((t,e)=>t.along-e.along);t.length&&(d=[...t[0].point])}else{const e=(h*n-l*t)/c,a=(h*o[1]-l*o[0])/c;e>i&&a>=-i&&a<=1+i&&(d=[s.anchor[0]+o[0]*e,s.anchor[1]+o[1]*e])}if(!d)continue;const p=Math.hypot(e[0]-d[0],e[1]-d[1]);p>s.tolerance||wa(d,s.excludePoints||[],i)||!ka(p,a.key,r)||(r={kind:"line",point:d,key:a.key,distance:p,segment:a})}return r?{kind:"resolved",candidate:r,conflicts:[]}:{kind:"none",candidate:null,conflicts:[]}}const Da=.001;function Pa(t,e,s,i){const o=Number.isFinite(t)&&t>0?Math.floor(t):0,a=t=>"number"==typeof t&&Number.isFinite(t)&&t>=0?t:null,n=a(s),r=a(i)??0,h=[];let l=null;for(let t=0;t=2&&Number.isFinite(t[0])&&Number.isFinite(t[1])}function Ra(t,e,s,i){return t*i-e*s}function za(t){let e=0;for(let s=0;st.localeCompare(e)),e[0]}function Oa(t,e,s){const i=[...t];for(let t=!0;t&&i.length>=3;){t=!1;for(let o=0;o=0){i.splice(o,1),t=!0;break}}}return i}function La(t,e){const s=t.map(t=>Math.max(0,Math.min(1,t))).sort((t,e)=>t-e),i=[];for(const t of s)(!i.length||Math.abs(t-i[i.length-1])>e)&&i.push(t);return i}function Ea(t,e){return[t.a[0]+(t.b[0]-t.a[0])*e,t.a[1]+(t.b[1]-t.a[1])*e]}function Ba(t,e,s){const i=function(t,e){const s=e.b[0]-e.a[0],i=e.b[1]-e.a[1],o=s*s+i*i;return o>0?((t[0]-e.a[0])*s+(t[1]-e.a[1])*i)/o:0}(t,e);if(i<-s||i>1+s)return null;const o=Ea(e,i);return Math.hypot(o[0]-t[0],o[1]-t[1])<=s?Math.max(0,Math.min(1,i)):null}function Wa(t,e,s,i,o){const a=t.b[0]-t.a[0],n=t.b[1]-t.a[1],r=e.b[0]-e.a[0],h=e.b[1]-e.a[1],l=e.a[0]-t.a[0],c=e.a[1]-t.a[1],d=Ra(a,n,r,h),p=Math.max(Math.hypot(a,n),Math.hypot(r,h),1);if(Math.abs(d)>o*p){const t=Ra(l,c,r,h)/d,e=Ra(l,c,a,n)/d;return void(t>=-o&&t<=1+o&&e>=-o&&e<=1+o&&(s.push(Math.max(0,Math.min(1,t))),i.push(Math.max(0,Math.min(1,e)))))}if(!(Math.abs(Ra(l,c,a,n))>o*p)){for(const i of[e.a,e.b]){const e=Ba(i,t,o);null!=e&&s.push(e)}for(const s of[t.a,t.b]){const t=Ba(s,e,o);null!=t&&i.push(t)}}}function Ga(t){let e=t+1|0;return e^=e<<13,e^=e>>>17,e^=e<<5,e>>>0}function ja(t,e){return t.minY-e.minY||t.index-e.index}function qa(t){return t.subtreeMaxY=Math.max(t.item.maxY,t.left?.subtreeMaxY??-1/0,t.right?.subtreeMaxY??-1/0),t}function Ua(t){const e=t.right;return t.right=e.left,e.left=qa(t),qa(e)}function Ka(t){const e=t.left;return t.left=e.right,e.right=qa(t),qa(e)}function Va(t,e){return t?(ja(e,t.item)<0?(t.left=Va(t.left,e),t.left.priority0)t.right=Ja(t.right,e);else{if(!t.left)return t.right;if(!t.right)return t.left;t.left.priority=e&&Ya(t.left,e,s,i),t.item.minY<=s&&t.item.maxY>=e&&i.push(t.item),t.item.minY<=s&&Ya(t.right,e,s,i))}function Xa(t,e=.001){const s=Number.isFinite(e)&&e>0?e:Da,i=t.filter(t=>Ta(t.a)&&Ta(t.b)&&"string"==typeof t.key&&t.key.length>0&&Math.hypot(t.b[0]-t.a[0],t.b[1]-t.a[1])>s),o=i.map(()=>[0,1]);!function(t,e,s){const i=t.map((t,e)=>({index:e,minX:Math.min(t.a[0],t.b[0])-s,maxX:Math.max(t.a[0],t.b[0])+s,minY:Math.min(t.a[1],t.b[1])-s,maxY:Math.max(t.a[1],t.b[1])+s})),o=[...i].sort((t,e)=>t.minX-e.minX||t.minY-e.minY||t.index-e.index),a=[...i].sort((t,e)=>t.maxX-e.maxX||t.index-e.index),n=new Set;let r=null,h=0;for(const i of o){for(;ht.index-e.index);for(const a of o)Wa(t[a.index],t[i.index],e[a.index],e[i.index],s);n.add(i.index),r=Va(r,i)}}(i,o,s);const a=new Map;for(let t=0;t({key:t,a:e.a,b:e.b,sourceKeys:[...e.sourceKeys].sort((t,e)=>t.localeCompare(e))})).sort((t,e)=>t.key.localeCompare(e.key))}function Za(t,e=.001){const s=Number.isFinite(e)&&e>0?e:Da,i=Xa(t,s),o=new Map,a=new Map,n=new Map(i.map(t=>[t.key,t]));for(const t of i){const e=Aa(t.a,s),i=Aa(t.b,s);o.set(e,t.a),o.set(i,t.b),a.has(e)||a.set(e,new Set),a.has(i)||a.set(i,new Set),a.get(e).add(i),a.get(i).add(e)}const r=new Map;for(const[t,e]of a){const s=o.get(t);r.set(t,[...e].sort((t,e)=>{const i=o.get(t),a=o.get(e);return Math.atan2(i[1]-s[1],i[0]-s[0])-Math.atan2(a[1]-s[1],a[0]-s[0])||t.localeCompare(e)}))}const h=new Set,l=new Map,c=(t,e)=>`${t}>${e}`;for(const t of i){const e=[Aa(t.a,s),Aa(t.b,s)];for(const[t,a]of[e,[e[1],e[0]]]){if(h.has(c(t,a)))continue;const e=[],d=[];let p=t,_=a,u=!1;for(let s=0;s<=2*i.length+2;s++){const s=c(p,_);if(h.has(s)){u=p===t&&_===a;break}h.add(s),e.push(p),d.push(Na(p,_));const i=r.get(_)||[],o=i.indexOf(p);if(o<0||!i.length)break;if(p=_,_=i[(o-1+i.length)%i.length],p===t&&_===a){u=!0;break}}if(!u||new Set(e).size<3||new Set(e).size!==e.length)continue;const m=e.map(t=>o.get(t)),g=za(m);if(!(g>s*s))continue;const f=Ha(Oa(e,o,s)),b=new Set;for(const t of d)for(const e of n.get(t)?.sourceKeys||[])b.add(e);const v={ring:m,key:f,area:g,atomKeys:[...d],sourceKeys:[...b].sort((t,e)=>t.localeCompare(e))};l.has(f)||l.set(f,v)}}return{atoms:i,faces:[...l.values()].sort((t,e)=>t.area-e.area||t.key.localeCompare(e.key))}}function Qa(t,e,s=.001){if(!Ta(e))return null;const i=t.faces.filter(t=>{if(t.ring.some((i,o)=>function(t,e,s,i){const o=s[0]-e[0],a=s[1]-e[1],n=o*o+a*a;if(!(n>0))return Math.hypot(t[0]-e[0],t[1]-e[1])<=i;const r=((t[0]-e[0])*o+(t[1]-e[1])*a)/n;return!(r<0||r>1)&&Math.hypot(e[0]+o*r-t[0],e[1]+a*r-t[1])<=i}(e,i,t.ring[(o+1)%t.ring.length],s)))return!1;let i=!1;for(let s=0,o=t.ring.length-1;se[1]!=n[1]>e[1]&&e[0]<(n[0]-a[0])*(e[1]-a[1])/(n[1]-a[1])+a[0]&&(i=!i)}return i});return[...i].sort((t,e)=>t.area-e.area||t.key.localeCompare(e.key))[0]||null}function tn(t,e,s){const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o,n=a>0?Math.max(0,Math.min(1,((t[0]-e[0])*i+(t[1]-e[1])*o)/a)):0;return Math.hypot(e[0]+i*n-t[0],e[1]+o*n-t[1])}function en(t,e,s=.5){let i=Math.abs(t-e)%180;return i>90&&(i=180-i),i<=s}function sn(t,e,s,i){const o=t.filter(t=>"outer"===t.kind&&!t.open&&t.cm>0).map(t=>({interval:t,reusePartitionId:e.find(e=>function(t,e,s){return!(Math.abs(t.cm-e.cm)>1e-6)&&(en(180*Math.atan2(t.b[1]-t.a[1],t.b[0]-t.a[0])/Math.PI,180*Math.atan2(e.b[1]-e.a[1],e.b[0]-e.a[0])/Math.PI,.001)&&tn(e.a,t.a,t.b)<=s&&tn(e.b,t.a,t.b)<=s)}(e,t,i))?.id||null})),a=new Map;for(const e of s){if("partition"===e.host?.kind)continue;const s=t.map(t=>{const s=180*Math.atan2(t.b[1]-t.a[1],t.b[0]-t.a[0])/Math.PI;return{interval:t,distance:en(e.angle,s)?tn([e.x,e.y],t.a,t.b):1/0}}).filter(t=>t.distance<=i).sort((t,e)=>t.distance-e.distance||t.interval.key.localeCompare(e.interval.key)),o=s[0]?.interval;"outer"===o?.kind&&!o.open&&o.cm>0&&a.set(e.id,o.key)}return{materialize:o,openingIntervals:a,removeOpeningIds:[...a.keys()].sort((t,e)=>t.localeCompare(e))}}function on(t,e){const s=e.b[0]-e.a[0],i=e.b[1]-e.a[1],o=s*s+i*i;return o>0?Math.max(0,Math.min(1,((t[0]-e.a[0])*s+(t[1]-e.a[1])*i)/o)):0}const an=t=>!t.key.startsWith("static:room|");function nn(t,e){const s=e.b[0]-e.a[0],i=e.b[1]-e.a[1],o=s*s+i*i;if(!(o>0))return null;const a=((t[0]-e.a[0])*s+(t[1]-e.a[1])*i)/o,n=[e.a[0]+s*a,e.a[1]+i*a];return{point:n,t:a,distance:Math.hypot(n[0]-t[0],n[1]-t[1])}}function rn(t,e){return e>0?Math.hypot(t[0]-Math.round(t[0]/e)*e,t[1]-Math.round(t[1]/e)*e):0}function hn(t,e,s){if(an(t.source)!==an(e.source))return an(t.source)?t:e;const i=rn(t.point,s),o=rn(e.point,s);return Math.abs(i-o)>1e-9?i>o?t:e:function(t,e){return t[0]-e[0]||t[1]-e[1]}(t.point,e.point)>0?t:e}function ln(t){return[t.from[0],t.from[1],t.to[0],t.to[1],t.targetKind].map(t=>"number"==typeof t?t.toFixed(6):t).join("|")}function cn(t,e){return t.map(t=>t.key!==e.sourceKey?t:{...t,[e.endpoint]:[...e.to]})}function dn(t,e){const s=e.epsilon??.001;if(!(e.maxDistance>=0)||!e.point&&!e.requiredSourceKey)return{kind:"none"};const i=new Map,o=t.flatMap(t=>[{source:t,endpoint:"a",point:t.a},{source:t,endpoint:"b",point:t.b}]);for(let t=0;ts)||h>e.maxDistance)continue;const l=hn(n,r,e.gridStep||0),c=l===n?r:n;if(!an(l.source))continue;const d={sourceKey:l.source.key,endpoint:l.endpoint,from:[l.point[0],l.point[1]],to:[c.point[0],c.point[1]],targetSourceKey:c.source.key,targetKind:"endpoint",distance:h};i.set(ln(d),d)}for(const a of o)if(an(a.source))for(const o of t){if(o===a.source)continue;const t=nn(a.point,o);if(!t||t.t<=s||t.t>=1-s||!(t.distance>s)||t.distance>e.maxDistance)continue;const n={sourceKey:a.source.key,endpoint:a.endpoint,from:[a.point[0],a.point[1]],to:t.point,targetSourceKey:o.key,targetKind:"line",distance:t.distance};i.set(ln(n),n)}const a=[];for(const o of i.values()){const i=Za(cn(t,o),s),n=e.point?Qa(i,e.point,s):i.faces.find(t=>!e.requiredSourceKey||t.sourceKeys.includes(e.requiredSourceKey))||null;n&&a.push({proposal:o,face:n})}if(a.sort((t,e)=>t.proposal.distance-e.proposal.distance||ln(t.proposal).localeCompare(ln(e.proposal))),!a.length)return{kind:"none"};return new Set(a.map(t=>`${ln(t.proposal)}|${t.face.key}`)).size>1?{kind:"ambiguous",proposals:a.map(t=>t.proposal)}:{kind:"repair",...a[0]}}const pn=(t,e)=>(t.composedPath?.()||[t.target]).some(t=>(t=>!!t&&"function"==typeof t.matches)(t)&&e(t));class _n{constructor(t){this.host=t,this._openGroupId=null,this._groupGeneration=0,this._renderedContext="",this._focusOwned=!1,this._currentModel=null,this._blocked=!1,this._dismissPointerTarget=null,this._globalDismissListening=!1,this._globalDismissGuard=t=>{this.handleOutsideDismiss(t)}}get hasOpenGroup(){return null!==this._openGroupId}get groupGeneration(){return this._groupGeneration}activeGroup(t){return this._openGroupId&&t.find(t=>t.id===this._openGroupId)||null}reset(){this._openGroupId=null,this._contentAnimation?.cancel(),this._contentAnimation=void 0,this._renderedContext="",this._focusOwned=!1,this._currentModel=null,this._blocked=!1,this._dismissPointerTarget=null,clearTimeout(this._dismissTimer),this._dismissTimer=void 0,this._syncGlobalDismissListener()}closeForNavigation(){const t="palette"===this._currentModel?.kind?this._currentModel.dismiss:void 0,e=!!this._openGroupId||!!t;this._openGroupId=null,t?.(),t&&(this._currentModel=null),this._clearDismissClick(),e&&this.host.requestUpdate(),this._syncGlobalDismissListener()}openPalette(){this._openGroupId&&this.closeGroup(!1)}toggleGroup(t,e){this._openGroupId!==e?t.some(t=>t.id===e)&&("palette"===this._currentModel?.kind&&this._currentModel.dismiss?.(),this._groupGeneration+=1,this._openGroupId=e,this.host.clearTip(),this.host.requestUpdate(),this._syncGlobalDismissListener()):this.closeGroup(!1)}closeGroup(t){const e=this._openGroupId;this._openGroupId=null,this.host.requestUpdate(),this._syncGlobalDismissListener(),t&&e&&this.host.updateComplete().then(()=>{const t=this.host.root(),s=[...t.querySelectorAll("[data-editor-group]")].find(t=>t.dataset.editorGroup===e&&null!==t.offsetParent);(s||t.querySelector(".editbar-tools"))?.focus?.()})}renderGroupLauncher(t,e,s){const i=this._openGroupId===t.id,a=t.items.find(e=>e.id===t.activeItemId&&!e.disabled);return o``}renderGroupModel(t,e,s){const i=t.items.find(t=>!t.disabled)?.id,n=t.items.some(e=>e.id===t.activeItemId&&!e.disabled)?t.activeItemId:void 0;return{contextId:e,kind:"group",ariaLabel:s.openGroup(t.label),visibleLabel:t.label,content:o`
this._groupKeydown(t)}> + ${t.items.map(e=>o``)} +
`}}runContext(t,e,s){t===e&&s()}render(t,e){this._currentModel=t,this._blocked=e;const s=t?.kind||"hidden";return o`
+ +
`}afterRender(){const t=this.host.root();this._blocked&&(this._openGroupId?this.closeGroup(!1):"palette"===this._currentModel?.kind&&this._currentModel.dismiss?.()),this._syncGlobalDismissListener();const e=t.querySelector(".editor-secondary"),s=this._renderedContext,i=e?.dataset.contextId||"";if(i&&s&&i!==s&&!window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches&&(this._contentAnimation?.cancel(),this._contentAnimation=e?.querySelector(".editor-secondary-content")?.animate([{opacity:.35,transform:"translateY(-4px)"},{opacity:1,transform:"translateY(0)"}],{duration:100,easing:"ease-out"})),this._renderedContext=i,s&&i!==s&&this._focusOwned){const s=i?e?.querySelector('[tabindex="0"], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled])'):t.querySelector(".editbar-tools");s?.focus?.(),this._focusOwned=!!i}if("palette"===this._currentModel?.kind&&this._currentModel.launcherId){const e=[...t.querySelectorAll("[data-editor-palette]")].find(t=>t.dataset.editorPalette===this._currentModel?.launcherId);e&&null!==e.offsetParent||this._currentModel.dismiss?.()}if(!this._openGroupId)return;const o=[...t.querySelectorAll("[data-editor-group]")].find(t=>t.dataset.editorGroup===this._openGroupId);o&&null!==o.offsetParent||this.closeGroup(!0)}handleOutsideDismiss(t){if(pn(t,t=>t.hasAttribute("data-editor-navigation")))return"pointerdown"===t.type?this.closeForNavigation():"click"===t.type&&this._dismissPointerTarget&&this._clearDismissClick(),!1;if("click"===t.type&&this._dismissPointerTarget){return!!(t.composedPath?.()||[t.target]).includes(this._dismissPointerTarget)&&(this._clearDismissClick(),t.preventDefault(),t.stopImmediatePropagation(),!0)}const e=this._openGroupId||this._blocked||"palette"!==this._currentModel?.kind?null:this._currentModel;if("pointerdown"===t.type&&(this._openGroupId||e)){const s=pn(t,t=>t.classList.contains("editor-secondary")),i=pn(t,t=>!!t.dataset.editorGroup),o=pn(t,t=>!!t.dataset.editorPalette),a=pn(t,t=>t.classList.contains("stage"));if(!(s||i||o||"stay-open-on-canvas"===e?.dismissPolicy&&a))return t.preventDefault(),t.stopImmediatePropagation(),this._dismissPointerTarget=t.target,clearTimeout(this._dismissTimer),this._dismissTimer=window.setTimeout(()=>{this._clearDismissClick()},800),this._openGroupId?this.closeGroup(!1):e?.dismiss?.(),this._syncGlobalDismissListener(),!0}return!1}_activateGroupItem(t,e,s){if(t.id!==this._openGroupId)return;const i=t.items.find(t=>t.id===e);if(!i||i.disabled)return;const o="toggle"===i.role&&"stay-open"===i.closePolicy,a=0===s.detail;o||(this._openGroupId=null,this.host.requestUpdate(),this._syncGlobalDismissListener()),i.invoke(),!o&&a&&this.host.updateComplete().then(()=>{const e=[...this.host.root().querySelectorAll("[data-editor-group]")].find(e=>e.dataset.editorGroup===t.id&&null!==e.offsetParent);e?.focus()})}_groupKeydown(t){if(!["ArrowLeft","ArrowRight","Home","End"].includes(t.key))return;const e=[...t.currentTarget.querySelectorAll(".editor-group-item:not([disabled])")];if(!e.length)return;t.preventDefault();const s=e.indexOf(this.host.root().activeElement),i="Home"===t.key?0:"End"===t.key?e.length-1:"ArrowLeft"===t.key?s<=0?e.length-1:s-1:(s+1)%e.length;e[i]?.focus()}_clearDismissClick(){this._dismissPointerTarget=null,clearTimeout(this._dismissTimer),this._dismissTimer=void 0,this._syncGlobalDismissListener()}_syncGlobalDismissListener(){const t=!this._blocked&&"palette"===this._currentModel?.kind,e=!!this._openGroupId||t||!!this._dismissPointerTarget;e!==this._globalDismissListening&&(this._globalDismissListening=e,e?(window.addEventListener("pointerdown",this._globalDismissGuard,!0),window.addEventListener("click",this._globalDismissGuard,!0)):(window.removeEventListener("pointerdown",this._globalDismissGuard,!0),window.removeEventListener("click",this._globalDismissGuard,!0)))}}const un=t=>t.stopPropagation(),mn=1e-6*I,gn=6*I;function fn(t){return Number.isFinite(t)?Math.round(t/I)*I:t}const bn=(t,e,s,i)=>Math.hypot(s-t,i-e),vn=(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)))),yn=(t,e,s,i,o,a,n)=>{const r=Math.max(Number(i)||0,0)/2,h=Math.PI/180,l=Math.cos(s*h)*r,c=Math.sin(s*h)*r,d=Math.cos(n*h)*r,p=Math.sin(n*h)*r,_=Math.max(bn(t+l,e+c,o+d,a+p),bn(t-l,e-c,o-d,a-p)),u=Math.max(bn(t+l,e+c,o-d,a-p),bn(t-l,e-c,o+d,a+p));return Math.min(_,u)},$n=t=>{const e=Number(t?.cell_cm);return e>0?e:5};function wn(t,e){const s=JSON.parse(JSON.stringify(t||[])),i=JSON.parse(JSON.stringify(e||{}));let o=0,a=0,n=0,r=0,h="",l=0,c=0,d=0;const p=(t,e)=>{Number.isFinite(t)&&Number.isFinite(e)&&t!==e&&Math.abs(e-t)<=mn&&c++},_=(t,e)=>{p(t[0],e[0]),p(t[1],e[1])},u={};let m=5;for(const t of s){const e=$n(t);null!=t?.id&&(u[String(t.id)]=e),e>m&&(m=e)}const g=(t,e,s,i=!1)=>{if(!(t>mn||i))return;o++,t>n&&(n=t);const a=t*T*e;a>r&&(r=a,h=s)};for(const t of s){const e=$n(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=[fn(e[0]),fn(e[1])];return t=Math.max(t,bn(e[0],e[1],s[0],s[1])),_(e,s),s});else if(null!=i.x&&null!=i.y){const e=i.x,s=i.y,o=i.w||0,a=i.h||0,n=fn(e+o),r=fn(s+a),h=fn(e),l=fn(s),c=Math.max(I,n-h),d=Math.max(I,r-l);t=vn(e,s,o,a,h,l,c,d),i.x=h,i.y=l,i.w=c,i.h=d,p(e,h),p(s,l),p(e+o,h+c),p(s+a,l+d)}g(t,e,s)}for(const i of t.room_drafts||[]){a++;let t=0;const o=i.points||[],n=o.map(e=>{const s=[fn(e[0]),fn(e[1])];return t=Math.max(t,bn(e[0],e[1],s[0],s[1])),s}),r=n.length?[n[0]]:[],h=n.length?[[o[0],n[0]]]:[],l=[];for(let t=0;t+1=2)for(const[t,e]of h)_(t,e);g(t,e,s)}if(Array.isArray(t.room_drafts)){const e=t.room_drafts.length;t.room_drafts=t.room_drafts.filter(t=>t.points?.length>=2),d+=e-t.room_drafts.length,t.room_drafts.length||delete t.room_drafts}for(const i of t.partitions||[]){a++;const o=[i.a[0],i.a[1]],n=[i.b[0],i.b[1]],r=[fn(o[0]),fn(o[1])],h=[fn(n[0]),fn(n[1])];let l=Math.max(bn(o[0],o[1],r[0],r[1]),bn(n[0],n[1],h[0],h[1]));const c=bn(r[0],r[1],h[0],h[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>=-mn&&i+e/2<=c+mn});c>mn&&d?(i.a=r,i.b=h,_(o,r),_(n,h)):l=0,g(l,e,s)}for(const i of t.wall_columns||[]){a++;const t=[i.center[0],i.center[1]],o=[fn(t[0]),fn(t[1])],n=bn(t[0],t[1],o[0],o[1]);i.center=o,_(t,o),g(n,e,s)}for(const i of t.decor||[]){a++;let t=0;if("line"===i.kind){const e=[i.x1,i.y1],s=[i.x2,i.y2],o=[fn(e[0]),fn(e[1])],a=[fn(s[0]),fn(s[1])];t=Math.max(bn(e[0],e[1],o[0],o[1]),bn(s[0],s[1],a[0],a[1])),i.x1=o[0],i.y1=o[1],i.x2=a[0],i.y2=a[1],_(e,o),_(s,a)}else{const e=i.x,s=i.y,o=i.w,a=i.h,n=fn(e),r=fn(s);if(null!=i.w&&null!=i.h){const h=fn(e+o),l=fn(s+a),c=Math.max(I,h-n),d=Math.max(I,l-r);t=vn(e,s,o,a,n,r,c,d),i.w=c,i.h=d,p(e+o,n+c),p(s+a,r+d)}else t=bn(e,s,n,r);i.x=n,i.y=r,p(e,n),p(s,r)}g(t,e,s)}for(const i of t.openings||[]){if(a++,"partition"===i.host?.kind){const o=(t.partitions||[]).find(t=>t.id===i.host.id),a=Number(i.host.t);if(!o||!Number.isFinite(a)||a<0||a>1)continue;const n=o.b[0]-o.a[0],r=o.b[1]-o.a[1];if(Math.hypot(n,r)<=mn)continue;const h=o.a[0]+n*a,c=o.a[1]+r*a;let d=180*Math.atan2(r,n)/Math.PI;d>=90?d-=180:d<-90&&(d+=180);const p=Number(i.angle),_=!(Number.isFinite(p)&&p===d),u=yn(i.x,i.y,Number.isFinite(p)?p:d,Number(i.length)||0,h,c,d);i.x=h,i.y=c,i.angle=d,_&&l++,g(u,e,s,_);continue}const o=P([i.x,i.y],t.rooms||[],gn,{step:I,length:Number(i.length)||0});if(!o)continue;const n=Number(i.angle),r=!(Number.isFinite(n)&&n===o.angle),h=yn(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&&l++,g(h,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=fn(s.x),n=fn(s.y),r=bn(s.x,s.y,o,n);i[t]={...s,x:o,y:n},p(s.x,o),p(s.y,n);const h="string"==typeof s.s?s.s:"";g(r,u[h]??m,h)}return{spaces:s,layout:i,report:{moved:o,coordsCanonicalized:c,total:a,maxShift:n,maxShiftCm:r,maxSpace:h,rotated:l,removedDrafts:d},changed:o>0||c>0}}function kn(t,e){const s=e.base+t*e.span;return Math.min(1,Math.max(0,s))}const xn=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),Mn=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1]);function Sn(t,e,s){const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;if(a<=0)return Mn(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 Cn(t,e,s,i,o){for(const i of e)if(i&&!s.has(i.id)&&xn(i.a)&&xn(i.b)&&(Mn(t,i.a)<=o||Mn(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(Mn(s,o)<=i)return[(s[0]+o[0])/2,(s[1]+o[1])/2];return null}function Pn(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&&xn(t.a)&&xn(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;tMn(e,t.at)>s);let c=l[0]??r.a,d=l[l.length-1]??h.b;if(l.length<2&&(c=r.a,d=h.b),d[0]0?(d[0]-c[0])/_:0,m=_>0?(d[1]-c[1])/_:0,g=t=>_>0?((t[0]-c[0])*u+(t[1]-c[1])*m)/_:0;for(const t of[r,h]){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 In(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:kn(t.t,n)},a++;const r=z(s,e,i.coordScale,i.cellCm,i.gridPitch).resolved;r&&Object.assign(s,F(s,r,i.coordScale))}return a}function Tn(t,e){const s=e?.excludeDraftId||null;return{roomPolygons:(t?.rooms||[]).map(t=>R(t)).filter(t=>!!t),columns:t?.wall_columns||[],draftEnds:(t?.room_drafts||[]).flatMap(t=>{if(s&&t?.id===s)return[];const e=t?.points||[];return e.length?[e[0],e[e.length-1]]:[]})}}const Rn=t=>!!t&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),zn=(t,e)=>t[0]-e[0]||t[1]-e[1],Fn=(t,e,s,i)=>[t[0]+e*i,t[1]+s*i],An=(t,e,s,i)=>(t[0]-e[0])*s+(t[1]-e[1])*i,Nn=(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 h=a/r,l=n/r,c=e=>Math.abs((e[0]-t[0])*l-(e[1]-t[1])*h);if(c(s)>o||c(i)>o)return null;const d=An(s,t,h,l),p=An(i,t,h,l),_=Math.max(0,Math.min(d,p)),u=Math.min(r,Math.max(d,p));return u-_>o?{lo:_,hi:u}:null},Hn=(t,e,s)=>Math.min(t.hi,e.hi)-Math.max(t.lo,e.lo)>s,On=t=>{const e=new Set(["id","a","b","cm"]);return Object.keys(t||{}).every(t=>e.has(t))},Ln=(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,h=a/n,l=j(t.cm,s.cellCm,s.gridPitch)/2;return e.some(e=>{const o=e?.center;if(!Rn(o))return!0;const a=An(o,t.a,r,h),c=Math.abs((o[0]-t.a[0])*h-(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<=l+d+i})},En=(t,e,s)=>{if(t.host){const i=z(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},Bn=(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),h=Math.sin(n);if(Math.abs(o*h-a*r)>1e-6)return!1;const l=e.center[0]-t.center[0],c=e.center[1]-t.center[1];if(Math.abs(l*a-c*o)>s)return!1;const d=l*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]}),Gn=(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},jn=(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 qn(t,e,s,i,o){const a=s||[],n=Array.isArray(t?.partitions)?t.partitions:[],r=Array.isArray(t?.openings)?t.openings:[],h=Array.isArray(t?.room_drafts)?t.room_drafts:[],l={walls:a,partitions:n,openings:r,roomDrafts:h,partitionsReconciled:0,openingsRehosted:0,removedDrafts:0};if(!n.length&&!h.length)return l;const c=Math.max(2e-4*o.gridPitch,1e-9);let d=a,p=n,_=r;const u=A(e.rooms,d,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),m=((t,e,s,i)=>{const o=new Map(t.map(t=>[t.id,t])),a=new Set;for(const t of e){if(!o.get(t.id)||!Array.isArray(t.points)||t.points.length<2||t.segments.length!==t.points.length-1)continue;let e=!0;for(let o=0;o+10)){e=!1;break}const h=Math.hypot(n[0]-a[0],n[1]-a[1]);if(!(h>i)){e=!1;break}const l=s.flatMap(t=>{const e=t.cm>0?t.cm:N;if(t.open||"outer"!==t.kind&&"shared"!==t.kind||e+it.lo-e.lo||t.hi-e.hi);let c=0;for(const t of l){if(t.lo>c+i)break;if(c=Math.max(c,t.hi),c>=h-i)break}c!m.has(t.id));let f=0,b=0;const v=new Map(e.partitions.map(t=>[t.id,t]));for(const t of[...n].sort((t,e)=>t.id.localeCompare(e.id))){if(!p.some(e=>e.id===t.id))continue;if(!On(t))continue;const s=v.get(t.id);if(!(s&&Rn(s.a)&&Rn(s.b)&&Number.isFinite(s.cm)&&s.cm>0))continue;const[a,n]=zn(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],h=n[1]-a[1],l=Math.hypot(r,h);if(!(l>c))continue;const u=r/l,g=h/l,y=A(e.rooms,d,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),$=y.flatMap(t=>{if(t.open||"outer"!==t.kind&&"shared"!==t.kind)return[];const e=Nn(a,n,t.a,t.b,c);return e?[{interval:t,range:e}]:[]});if(!$.length)continue;const w=_.filter(t=>"partition"===t.host?.kind&&t.host.id===s.id).map(t=>({opening:t,resolved:z(t,e.partitions,o.coordScale,o.cellCm,o.gridPitch).resolved}));if(w.some(t=>!t.resolved))continue;const k=[0,l];for(const{range:t}of $)k.push(t.lo,t.hi);const x=k.slice(),M=new Map;for(const{opening:t,resolved:e}of w){const s=An(e.center,a,u,g),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(l,i.hi))}const S=[...new Set(x.filter(t=>Number.isFinite(t)&&t>=-c&&t<=l+c).map(t=>Math.max(0,Math.min(l,t)).toFixed(9)))].map(Number).sort((t,e)=>t-e),C=p.map(t=>Wn(t,o.coordScale)).filter(t=>t.id!==s.id),D=e.room_drafts.filter(t=>!m.has(t.id)),P=[];for(let t=0;t+1c))continue;const r=Fn(a,u,g,i),h=Fn(a,u,g,n),l=$.filter(({range:t})=>t.lo<=i+c&&t.hi>=n-c).map(({interval:t})=>t),d=new Map;for(const t of l)d.set(t.roomId,t);const p=[...d.values()],_=new Set(p.map(t=>t.kind)),m=new Set(p.map(t=>t.cm>0?t.cm:N)),f=p[0]?.kind,b=[...d.keys()].sort(),v=1===_.size&&1===m.size&&("outer"===f&&1===b.length||"shared"===f&&2===b.length),y={id:s.id,a:r,b:h,cm:s.cm},w=C.some(t=>!!Nn(r,h,t.a,t.b,c)),k=D.some(t=>t.points.some((e,s)=>s+10?p[0].cm:N:0,I=v?Math.max(M,s.cm):s.cm;P.push({lo:i,hi:n,a:r,b:h,safe:x,signature:x?`${f}|${b.join(",")}|${I}`:"",roomIds:b,roomCm:M,finalCm:I})}if(!P.some(t=>t.safe))continue;const I=new Map;for(const{opening:t,resolved:e}of w){const i=M.get(t.id),a=k.some(t=>t>i.lo+c&&tHn(t,i,c)),r=new Set(n.filter(t=>t.safe).map(t=>t.signature));if(!a&&n.length>0&&n.every(t=>t.safe)&&1===r.size&&H(e,y,c)){I.set(t.id,{resolved:e,signature:[...r][0]});continue}const h=O(s,o.cellCm,o.gridPitch),l={lo:i.lo-h,hi:i.hi+h};for(const t of P)Hn(t,l,c)&&(t.safe=!1,t.signature="")}let T=!0;for(;T;){T=!1;for(const[t,e]of[...I.entries()]){const i=M.get(t),a=P.filter(t=>Hn(t,i,c));if(a.length>0&&a.every(t=>t.safe)&&a.every(t=>t.signature===e.signature))continue;I.delete(t);const n=O(s,o.cellCm,o.gridPitch),r={lo:i.lo-n,hi:i.hi+n};for(const t of P)Hn(t,r,c)&&(t.safe=!1,t.signature="");T=!0}}const R=jn(P,c),j=R.filter(t=>t.safe),q=R.filter(t=>!t.safe);if(!j.length)continue;if(p.length-1+q.length>2e3)continue;let U=d;for(const t of j){const[e,i]=zn(s.a,s.b)<=0?[t.a,t.b]:[t.b,t.a];U=L(U,e,i,t.finalCm,o.pitch,o.coordScale)}if(U=E(e.rooms,U,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),U.length>500)continue;const K=new Set(p.map(t=>t.id));K.delete(s.id);const V=q.map((t,e)=>{const i=[t.a[0]/o.coordScale,t.a[1]/o.coordScale],a=[t.b[0]/o.coordScale,t.b[1]/o.coordScale],n=0===e?s.id:Gn(s.id,i,a,K);return K.add(n),{id:n,a:i,b:a,cm:s.cm}}),J=p.findIndex(t=>t.id===s.id),Y=p.slice();Y.splice(J,1,...V);const X=Y.map(t=>Wn(t,o.coordScale)),Z=new Map;let Q=!0;for(const{opening:t,resolved:e}of w){const s=I.get(t.id);if(s){const e=F(t,s.resolved,o.coordScale),{host:i,...a}=e;Z.set(t.id,a);continue}const i=M.get(t.id),a=V[q.findIndex(t=>t.lo<=i.lo+c&&t.hi>=i.hi-c)],n=a&&X.find(t=>t.id===a.id);if(!a||!n){Q=!1;break}const r=n.b[0]-n.a[0],h=n.b[1]-n.a[1],l=Math.hypot(r,h),d=An(e.center,n.a,r/l,h/l),p={...F(t,e,o.coordScale),host:{kind:"partition",id:a.id,t:d/l}};if(!B(p,X,o.coordScale,o.cellCm,o.gridPitch).resolved){Q=!1;break}Z.set(t.id,p)}if(!Q)continue;const tt=_.map(t=>Z.get(t.id)||t),et=[...I.keys()].map(t=>Z.get(t)),st=et.map(t=>En(t,X,o));if(st.some(t=>!t))continue;let it=!1;for(let t=0;tt.id));for(const t of tt){if(ot.has(t.id))continue;const e=En(t,X,o);e&&st.some(t=>Bn(t,e,c))&&(it=!0)}if(it)continue;const at=W(e.rooms,U,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale);[...I.entries()].every(([t,e])=>{const s=Z.get(t),i=G(at,{x:s.x*o.coordScale,y:s.y*o.coordScale,angle:s.angle,length:s.length*o.coordScale},!0),a=[i.negative,i.positive].filter(t=>!!t?.full),n=e.signature.split("|")[1].split(","),r=new Set(a.map(t=>t.roomId));return a.length===n.length&&r.size===n.length&&n.every(t=>r.has(t))})&&(d=U,p=Y,_=tt,f+=j.length,b+=I.size)}return{walls:d,partitions:p,openings:_,roomDrafts:g,partitionsReconciled:f,openingsRehosted:b,removedDrafts:m.size}}const Un=t=>JSON.parse(JSON.stringify(t)),Kn=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),Vn=(t,e)=>e.length>0&&e.length<=35&&("space"===t?/^[a-z0-9_-]+$/.test(e):/^[A-Za-z0-9_-]+$/.test(e));function Jn(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 Yn=(t,e,s)=>{const i=t.get(e)||[];i.push(s),t.set(e,i)};const Xn=1e-9;class Zn extends Error{constructor(t,e=""){super(e?`${t}: ${e}`:t),this.reason=t,this.name="WallSegmentModelError"}}const Qn=t=>JSON.parse(JSON.stringify(t)),tr=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(Number(t[0]))&&Number.isFinite(Number(t[1])),er=t=>[Number(t[0]),Number(t[1])],sr=t=>`${Number(t[0]).toFixed(12)},${Number(t[1]).toFixed(12)}`,ir=(t,e)=>{const s=sr(t),i=sr(e);return ssr(t)<=sr(e)?[er(t),er(e)]:[er(e),er(t)],ar=(t,e)=>Math.hypot(e[0]-t[0],e[1]-t[1]),nr=t=>{const e=[[Number(t.points[0][0]),Number(t.points[0][1])]],s=[];for(let i=1;i{const s=new Set,i=t=>{const e=Number(t);if(!Number.isFinite(e))return;const i=e/I;Math.abs(i-Math.round(i))>=X&&s.add(e.toFixed(12))};for(const e of Array.isArray(t?.rooms)?t.rooms:[])for(const t of R(e)||[])i(t[0]),i(t[1]);for(const e of[t?.wall_segments,t?.walls])for(const t of Array.isArray(e)?e:[])i(t?.a?.[0]),i(t?.a?.[1]),i(t?.b?.[0]),i(t?.b?.[1]);for(const t of e)i(t?.[0]),i(t?.[1]);return s.size},hr=(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},lr=(t,e,s)=>{const i=Math.max(0,Math.min(1,hr(t,e,s)));return Math.hypot(t[0]-(e[0]+(s[0]-e[0])*i),t[1]-(e[1]+(s[1]-e[1])*i))},cr=(t,e,s,i,o=Xn)=>{const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(r<=o)return 0;const h=e=>Math.abs((e[0]-t[0])*n-(e[1]-t[1])*a)/r;if(h(s)>o||h(i)>o)return 0;const l=hr(s,t,e),c=hr(i,t,e);return Math.max(0,Math.min(1,Math.max(l,c))-Math.max(0,Math.min(l,c)))*r},dr=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]),h=new Uint32Array(64),l=(t,e)=>t>>>e|t<<32-e;for(let t=0;t>>3,o=l(s,17)^l(s,19)^s>>>10;h[t]=h[t-16]+i+h[t-7]+o>>>0}let[e,s,i,o,c,d,p,_]=r;for(let t=0;t<64;t++){const a=_+(l(c,6)^l(c,11)^l(c,25))+(c&d^~c&p)+n[t]+h[t]>>>0,r=e&s^e&i^s&i;_=p,p=d,d=c,c=o+a>>>0,o=i,i=s,s=e,e=a+((l(e,2)^l(e,13)^l(e,22))+r>>>0)>>>0}r[0]=r[0]+e>>>0,r[1]=r[1]+s>>>0,r[2]=r[2]+i>>>0,r[3]=r[3]+o>>>0,r[4]=r[4]+c>>>0,r[5]=r[5]+d>>>0,r[6]=r[6]+p>>>0,r[7]=r[7]+_>>>0}const c=new Uint8Array(32),d=new DataView(c.buffer);for(let t=0;t{const e="abcdefghijklmnopqrstuvwxyz234567";let s=0,i=0,o="";for(const a of t)for(i=i<<8|a,s+=8;s>=5;)o+=e[i>>>s-5&31],s-=5;return s&&(o+=e[i<<5-s&31]),o},_r=(t,e,s,i,o="")=>{const[a,n]=or(e,s),r=`${t}|${sr(a)}|${sr(n)}|${[...i].sort().join(",")}${o}`;return`wall-${pr(dr(r)).slice(0,20)}`};let ur=0;const mr=t=>{for(let e=0;e<1e3;e++){const e=globalThis.crypto?.randomUUID?.(),s=`wall-${e||pr(dr(`${Date.now()}|${ur++}|${Math.random()}`)).slice(0,26)}`;if(!t.has(s))return s}throw new Zn("duplicate-id","id factory exhausted")},gr=t=>{const e=new Map;for(const s of Array.isArray(t?.wall_segments)?t.wall_segments:[])if(s&&"string"==typeof s.id&&tr(s.a)&&tr(s.b)){if(e.has(s.id))throw new Zn("duplicate-id",s.id);e.set(s.id,s)}return e},fr=(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)<=Xn&&Math.abs(e[1]-i[1]-a)<=Xn?[o,a]:null};return i(s.a,s.b)||i(s.b,s.a)},br=(t,e)=>{const s=Array.isArray(t.rooms)?t.rooms:[],i=V(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]),o=i.length?i:J(s,null,1,.04*I,!0),a=[];for(const t of s){const s=R(t),i=Array.isArray(t?.wall_ids)?t.wall_ids:[];if(s&&i.length===s.length)for(let t=0;t"partition"!==t.host?.kind&&[Number(t.x),Number(t.y)].every(Number.isFinite)&&Number.isFinite(Number(t.angle))&&Number(t.length)>0&&o.some(e=>lr([Number(t.x),Number(t.y)],[e[0],e[1]],[e[2],e[3]])<=.04*I)):[],h=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]}}),l=(t,e)=>r.some(s=>{const i=[Number(s.x),Number(s.y)];if(!Z(t,e,Number(s.angle)))return!1;if(lr(i,t,e)>.02*I)return!1;const o=ar(t,e),a=hr(i,t,e)*o,n=Number(s.length)/2;return a+n>=-Xn&&a-n<=o+Xn}),c=new Map,d=[];for(const i of s){const r=String(i?.id||""),p=R(i);if(!r||!p||p.length<3)throw new Zn("invalid-room",r);const _=Y(s,r,n,I,1,[...t.walls||[],...h]);if(!_||_.poly.length<3)throw new Zn("invalid-room",r);const u=Array.isArray(i.wall_ids)?i.wall_ids:[],m=u.length===p.length;let g=null,f=m;if(f)for(let t=0;tXn||Math.abs(i[1]-g[1])>Xn)){f=!1;break}g=i}const b=[];for(let t=0;t<_.poly.length;t++){const s=_.poly[t],i=_.poly[(t+1)%_.poly.length];if(ar(s,i)<=Xn)throw new Zn("zero-length",r);const n=ir(s,i);let h=c.get(n);if(!h){const[t,e]=or(s,i);h={key:n,a:t,b:e,owners:new Set,preferredIds:new Set,positionalIds:new Set,preferredCarriers:new Map,parentKeys:new Set,zeroWall:!1},c.set(n,h)}if(h.owners.add(r),h.owners.size>2)throw new Zn("third-owner",n);const d=m?u[_.parent[t]]:void 0;if("string"==typeof d&&d){const o=e.get(d);f||!o||cr(s,i,o.a,o.b)>Xn?h.preferredIds.add(d):h.positionalIds.add(d),h.preferredCarriers.set(d,{a:er(p[_.parent[t]]),b:er(p[(_.parent[t]+1)%p.length])})}const g=_.parent[t];h.parentKeys.add(K(p[g],p[(g+1)%p.length],I));const v=[(s[0]+i[0])/2,(s[1]+i[1])/2],y=t=>t.some(t=>lr(v,[t[0],t[1]],[t[2],t[3]])<=.04*I);h.zeroWall||=y(a)||y(o)&&!l(s,i),b.push(n)}const v={...i};delete v.wall_ids,d.push({...v,poly:_.poly.map(t=>[t[0],t[1]]),wall_ids:b})}return{atoms:[...c.values()].sort((t,e)=>t.key.localeCompare(e.key)),rooms:d}},vr=(t,e,s,i,o)=>{const a=new Map([...s.values()].map(t=>[ir(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 Zn("duplicate-id",e);r.set(t,i);continue}if(t.preferredIds.size>1)throw new Zn("duplicate-id",[...t.preferredIds].sort().join(","));const i=[...t.preferredIds][0],h=i?s.get(i):void 0;if(h){r.set(t,h);continue}const l=i?t.preferredCarriers.get(i):void 0;if(i&&l){r.set(t,{id:i,a:l.a,b:l.b,cm:0});continue}const c=a.get(t.key);if(c){r.set(t,c);continue}const d=[...s.values()].filter(e=>cr(t.a,t.b,e.a,e.b)>Xn),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)||ar(e.a,e.b)-ar(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 h=new Map;for(const[t,e]of r){const s=h.get(e.id)||[];s.push(t),h.set(e.id,s)}for(const[t,e]of h){const i=s.get(t)||r.get(e[0]);if(!i)throw new Zn("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=lr(o,t.a,t.b)<=Xn?0:1,a=lr(o,e.a,e.b)<=Xn?0:1;if(s!==a)return s-a;return(lr(i.a,t.a,t.b)<=Xn?0:1)-(lr(i.a,e.a,e.b)<=Xn?0:1)||t.key.localeCompare(e.key)}),e[0].id=t}const l=(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(l.has(t.id))throw new Zn("duplicate-id",t.id);l.add(t.id)}const c=e.filter(t=>!t.id);if(i){const e=c.map(e=>{const[s,i]=or(e.a,e.b),o=`${String(t.id||"")}|${sr(s)}|${sr(i)}|${[...e.owners].sort().join(",")}`,a=pr(dr(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 Zn("duplicate-id",t.digest);s.set(t.digest,t.seed);let i=1,o=t.base;for(;l.has(o);)o=`${t.base}-${++i}`;t.atom.id=o,l.add(o)}}else for(const t of c)t.id=mr(l),l.add(t.id)},yr=(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=hr(s,e.a,e.b),o=ar(e.a,e.b),a=Number(t.length)/2;return i>=-Xn&&i<=1+Xn&&lr(s,e.a,e.b)<=.02*I&&Z(e.a,e.b,Number(t.angle))&&Number.isFinite(a)&&a>=0&&i*o-a>=-Xn&&i*o+a<=o+Xn},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,hr(s,n.a,n.b)))}},$r=(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=hr(s,e.a,e.b),a=ar(e.a,e.b);return o>=-Xn&&o<=1+Xn&&lr(s,e.a,e.b)<=.02*I&&Z(e.a,e.b,Number(t.angle))&&Number.isFinite(i)&&i>=0&&o*a-i>=-Xn&&o*a+i<=a+Xn}),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)=>lr(s,t.a,t.b)-lr(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,hr(s,a.a,a.b)))}:null},wr=(t,e,s)=>{const i=gr(t),{atoms:o,rooms:a}=br(t,i);vr(t,o,i,e,s);const n=o.map(e=>{const s=e.id?i.get(e.id):void 0,o=((t,e,s)=>{if(e.zeroWall)return 0;const i=Array.isArray(t.walls)?t.walls:[],o=K(e.a,e.b,I),a=i.filter(t=>Number(t.cm)>0&&(!(t.key!==o&&!e.parentKeys.has(t.key))||!(!tr(t.a)||!tr(t.b))&&cr(e.a,e.b,t.a,t.b)>=ar(e.a,e.b)-Xn)).map(t=>Math.max(1,Math.min(100,Number(t.cm))));if(new Set(a.map(t=>t.toFixed(9))).size>1)throw new Zn("thickness-conflict",e.key);if(a.length)return a[0];const n=Q(i,e.a,e.b,I,1);return n>0?n:Number(s?.cm)>0?Number(s.cm):0})(t,e,s);return{...s||{},id:e.id,a:[...e.a],b:[...e.b],cm:o}}),r=new Map(o.map(t=>[t.key,t.id]));for(const t of a)t.wall_ids=t.wall_ids.map(t=>r.get(t));t.rooms=a,t.wall_segments=n,t.walls=n.filter(t=>t.cm>0).map(t=>({key:K(t.a,t.b,I),cm:t.cm,a:[...t.a],b:[...t.b]})),t.walls.length||delete t.walls,delete t.open_spans;for(const e of t.rooms)delete e.open_to;return((t,e)=>{const s=new Set;for(const e of[t.rooms,t.openings,t.decor,t.room_drafts,t.partitions,t.wall_columns,t.wall_segments])for(const t of Array.isArray(e)?e:[])"string"==typeof t?.id&&t.id&&s.add(t.id);for(const i of Array.isArray(t.room_drafts)?t.room_drafts:[]){const o=Array.isArray(i.segments)?i.segments:[];for(let a=0;a{const i=Array.isArray(t.openings)?t.openings:[];for(const t of i){if("partition"===t.host?.kind)continue;if(!t.host&&!s){const s=yr(t,e);s&&(t.host=s);continue}const i=yr(t,e)??(s?$r(t,e):null);if(i)t.host=i;else{if(!s)throw new Zn("opening-host",t.id);delete t.host}}})(t,n,e),n.reduce((t,e)=>t+(i.has(e.id)?0:1),0)};function kr(t,e={}){const s=JSON.stringify(t),i=Qn(t);U(i);let o=0;const a=Number(i?.model_version||0)<9;for(const t of Array.isArray(i?.spaces)?i.spaces:[]){const s=e.lineageSpaceId===String(t?.id||"")?e.lineageHints:void 0;o+=wr(t,a,s)}return i.model_version=9,U(i),{config:i,changed:s!==JSON.stringify(i),migratedSegments:o}}const xr=t=>!!t&&"object"==typeof t&&!Array.isArray(t);function Mr(t,e){const s=(t,e)=>{if(Array.isArray(t)&&Array.isArray(e)){const i=new Map;for(const e of t)xr(e)&&"string"==typeof e.id&&e.id&&i.set(e.id,e);const o=e.map((e,o)=>{if(xr(e)&&"string"==typeof e.id&&e.id){const t=i.get(e.id);return t?s(t,e):Qn(e)}return o[e,e in t?s(t[e],i):Qn(i)]);for(const e of Object.keys(t))delete t[e];for(const[e,s]of i)t[e]=s;return t}return Qn(e)};return s(t,e)}const Sr=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),Cr=(t,e,s)=>Math.min(s,Math.max(e,t)),Dr=t=>ut({spaces:[t]})[0],Pr=(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,h=Math.max(i*r*.02,1e-9),l=[];for(const e of t||[])for(const t of R(e)||[])l.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*h),p=new Map;for(const n of t||[]){if(!n?.id)continue;const _=mt(t,n.id,e,s,i,o,a,r);if(_)for(let t=0;t<_.orig.length;t++){const e=[];for(let s=0;s<_.parent.length;s++)_.parent[s]===t&&e.push(s);for(let t=1;t+10&&u>0&&n===m&&u!==n))continue;const g=_.poly[i],f=_.poly[(i+1)%_.poly.length],b=Math.hypot(f[0]-g[0],f[1]-g[1]);if(!(b>h&&b<.5*a-1e-9*a))continue;if(d(g,c)||d(f,c))continue;if(d(g,l)&&d(f,l))continue;const v=Pr(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 _=e.slice();const u=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*h,m=(t,e)=>{if(!Array.isArray(t.a)||!Array.isArray(t.b)||t.a.length<2||t.b.length<2)return!1;const s=[Number(t.a[0])*r,Number(t.a[1])*r],i=[Number(t.b[0])*r,Number(t.b[1])*r];return!![...s,...i].every(Number.isFinite)&&(u(s,e.a)&&u(i,e.b)||u(s,e.b)&&u(i,e.a))};for(const t of[...p.values()].filter(t=>1===t.targets.size).sort((t,e)=>Pr(t.a,t.b,r).localeCompare(Pr(e.a,e.b,r)))){const e=[...t.targets][0],s=_.filter(e=>m(e,t));if(new Set(s.map(t=>t.cm)).size>1)continue;let o=!1;_=_.map(s=>m(s,t)?(o=!0,s.cm===e?s:{...s,cm:e}):s),o||(_=L(_,t.a,t.b,e,i,r))}return _}const Tr=t=>{const e=[];for(const s of t||[]){const t=R(s);if(t?.length)for(let s=0;s"string"==typeof t?.id?t.id:"").filter(Boolean),c=new Set(l),d=new Map;for(const t of l){const e=Jn("space",t);e.layers>0&&Vn("space",e.root)&&Yn(d,e.root,t)}const p=new Map,_=new Map,u=new Map,m=new Map;for(const t of r){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const s=new Map;for(const i of Array.isArray(t.rooms)?t.rooms:[]){const t="string"==typeof i?.id?i.id:"";if(!t)continue;const o=Jn("room",t);o.layers>0&&Vn("room",o.root)&&Yn(s,o.root,t),_.has(t)||_.set(t,e),u.has(t)||u.set(t,String(i.name||""));const a="string"==typeof i.area?i.area:"";if(a){const s=m.get(a)||[];s.push({spaceId:e,roomId:t}),m.set(a,s)}}p.set(e,s)}const g=new Set(_.keys()),f=new Map,b=new Map;for(const t of h)"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,$=t=>c.has(t)?null:(()=>{const e=Jn("space",t).root;if(!Vn("space",e))return null;const s=d.get(e)||[];return 1===s.length?s[0]:null})(),w=(t,e)=>{const s=Jn("room",t).root;if(!Vn("room",s))return null;const i=p.get(e)?.get(s)||[];return 1===i.length?i[0]:null},k=t=>{const e=s.effectiveAreaByMarker?.[t]||"",i=e&&m.get(e)||[];return 1===i.length?i[0]:null},x=(t,e,s)=>{if("string"==typeof t.room_id&&t.room_id&&!g.has(t.room_id)){const i=e?w(t.room_id,e):null;i?(t.room_id=i,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?w(s,e):null;o?(i[t]=o,v.roomRefsRemapped++):v.nestedRefsUnresolved++}};for(const t of h){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),h=!0===t.removed;let l=s&&c.has(s)?s:null,d=null,p=!1;if(i){const i=$(s);i?(t.space=i,l=i,p=!0,v.spaceRefsRemapped++):h||"virtual"===t.binding?h||(delete t.space,l=null,v.markersDetached++):(d=k(e),d?(t.space=d.spaceId,l=d.spaceId,v.spaceRefsRemapped++):(delete t.space,l=null,v.markersDetached++))}h&&!p||x(t,l,d),r&&p&&n===s&&l&&(o[e]={...a,s:l},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=$(s);if(i){if(t.startsWith("rl_")){const s=t.slice(3),a=w(s,i);if(a){const s=`rl_${a}`;Kn(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,S=!0===M?.authoritative,C=new Set(M?.deviceIds||[]),D=new Set(M?.entityIds||[]),P=new Set(Array.isArray(i.settings?.known_devices)?i.settings.known_devices.filter(t=>"string"==typeof t):[]),I=(t,e="")=>{const s=String(M?.names?.[t]||e||"").trim();return s&&s!==t?s:""},T=(t,e,s,i="",o)=>({id:t,spaceId:e,kind:s,name:I(t,i),...o?{reason:o}:{}}),R=t=>{"room_label"===t?v.orphanRoomLabelsRemoved++:"group"===t?v.orphanGroupPositionsRemoved++:v.orphanDevicePositionsRemoved++},z=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),h=b.get(t);if(r)a=T(t,i,"device",String(r.name||"")),n="live";else if(h)a=T(t,i,"device",String(h.name||"")),n="absent";else if(t.startsWith("rl_")){const e=t.slice(3);a=T(t,i,"room_label",u.get(e)||""),n=g.has(e)?"live":"absent"}else if(t.startsWith("lg_")){const e=t.slice(3);a=T(t,i,"group"),n=D.has(e)?"live":S?"absent":"unverified","unverified"===n&&(a.reason="registry_unavailable")}else C.has(t)?(a=T(t,i,"device"),n="live"):P.has(t)?(a=T(t,i,"device"),n=S?"absent":"unverified","unverified"===n&&(a.reason="registry_unavailable")):(a=T(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++,R(a.kind),v.removedPositions.push(a);continue}}else v.unverifiedPositions.push(a);v.positionsUnresolved++,z.add(i)}else delete o[t],R(a.kind),v.removedPositions.push(a)}return v.deadSpaceIds=[...z].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=tt(n,a.layout);U(n),et(a.layout);const h=JSON.stringify(t||{}),l=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&&Sr(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(Sr(o,"segments")&&(delete o.segments,e++),Sr(o,"plan_scale")){const t=Number(o.plan_scale);Number.isFinite(t)&&t>=ht&&t<=lt&&(Sr(o,"plan_scale_x")||(o.plan_scale_x=t),Sr(o,"plan_scale_y")||(o.plan_scale_y=t),delete o.plan_scale,e++)}const a=Number(o.cell_cm);Sr(o,"cell_cm")&&(!Number.isFinite(a)||a<.1||a>1e3)&&(o.cell_cm=Number.isFinite(a)&&a>0?Cr(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)Sr(t,"angle")&&(delete t.angle,e++);else if("square"===t.shape&&Sr(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(Sr(t,"width")){const s=Number(t.width);(Sr(t,"width_cm")||Number.isFinite(s))&&(Sr(t,"width_cm")||(t.width_cm=Number(Cr(s/nt*r,.1,100).toFixed(6))),delete t.width,e++)}if("rect"!==t?.kind&&"ellipse"!==t?.kind||!0!==t.fill||(Sr(t,"fill_color")||(t.fill_color=t.color||"#607d8b",e++),Sr(t,"fill_opacity")||(t.fill_opacity=.25,e++)),"text"!==t?.kind)continue;void 0===t.size_cm?(t.size_cm=Number(Cr(ct*dt(t)/nt*r,.1,2e3).toFixed(6)),delete t.scale,delete t.size,e++):(Sr(t,"scale")||Sr(t,"size"))&&(delete t.scale,delete t.size,e++);let s=String(t.text??"");const i=[...s.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!pt(t[1]));if(!(Sr(t,"entity")||Sr(t,"attr")||Sr(t,"unit")))continue;const o=String(t.unit??"").trim(),a="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,n=i||o?"":_t(t.entity,a);if(i||n){if(n){const e=s.indexOf("{}");s=e>=0?s.slice(0,e)+n+s.slice(e+2):`${s}${s?" ":""}${n}`,t.text=s}delete t.entity,delete t.attr,delete t.unit,e++}}}return{total:e,glowSpaces:s,glowRooms:i}})(n);let p=d.total;const _=(u=n.spaces||[],JSON.parse(JSON.stringify(u)));var u;const m=wn(n.spaces||[],a.layout);let g=0,f=0,b=0,v="";const y=m.spaces.map(t=>{const e=st(t);g+=e.report.wallsStraightened,f+=e.report.wallsStraightenSkipped;const s=Number(t?.cell_cm)>0?Number(t.cell_cm):5,i=e.report.maxStraightenShift/I*s;return i>b&&(b=i,v=String(t?.id||"")),e.space}),$=g?wn(y,m.layout):{...m,spaces:y};n.spaces=$.spaces;const w=g?{...m.report,moved:m.report.moved+$.report.moved,coordsCanonicalized:m.report.coordsCanonicalized+$.report.coordsCanonicalized,maxShift:Math.max(m.report.maxShift,$.report.maxShift),maxShiftCm:Math.max(m.report.maxShiftCm,$.report.maxShiftCm),maxSpace:$.report.maxShiftCm>m.report.maxShiftCm?$.report.maxSpace:m.report.maxSpace,rotated:m.report.rotated+$.report.rotated,removedDrafts:m.report.removedDrafts+$.report.removedDrafts}:{...m.report};let k=0,x=0,M=0,S=0,C=0,D=0,P=0,T=0;for(let t=0;t0===Number(t.cm)),walls:e.walls||[]}),a=Dr(e),r=Dr(s);if(!a||!r)continue;const h=Tr(a.rooms),l=Tr(r.rooms),c=.02*nt,d=(e.wall_segments||[]).filter(t=>0===Number(t.cm)).map(t=>({...t,key:K(t.a,t.b,I),cm:0})),p=new Set(d.map(t=>t.key)),u=it(e,a.rooms,ot,c);x+=u.length;for(const t of u){const e=[t[0]/ot,t[1]/ot],s=[t[2]/ot,t[3]/ot],i=K(e,s,I);p.has(i)||(p.add(i),d.push({key:i,a:e,b:s,cm:0}))}const m=d.length,g=at(d,h,l,I,ot),f=(t,e,s)=>{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;if(!(a>0))return Math.hypot(t[0]-e[0],t[1]-e[1]);const n=Math.max(0,Math.min(1,((t[0]-e[0])*i+(t[1]-e[1])*o)/a));return Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))},b=g.filter(t=>{if(!Array.isArray(t.a)||!Array.isArray(t.b))return!1;const e=t.a.map(t=>t*ot),s=t.b.map(t=>t*ot);return l.some(([t,i])=>f(e,t,i)<=4*c&&f(s,t,i)<=4*c)});M+=Math.max(0,m-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]*ot,t.a[1]*ot,t.b[0]*ot,t.b[1]*ot]),$=Array.isArray(e.walls)?e.walls.length:0;let w=at(e.walls,h,l,I,ot);w=Ir(r.rooms,w,y,I,Number(s.cell_cm)>0?Number(s.cell_cm):5,nt,ot),w=E(r.rooms,w,y,I,Number(s.cell_cm)>0?Number(s.cell_cm):5,nt,ot),w=rt(w,s.rooms||[],I,1,y.map(t=>[t[0]/ot,t[1]/ot,t[2]/ot,t[3]/ot])),k+=Math.max(0,$-w.length),w.length?s.walls=w:delete s.walls;const R=Pn(s.partitions||[],{pitch:I,geometry:Tn(s)});R.merged&&(S+=R.merged,s.partitions=R.partitions,In(s.openings,s.partitions,R.openingMoves,{coordScale:ot,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,gridPitch:nt}));const z=Dr(s);if(z){const t=o(s,z,s.walls||[],y,{pitch:I,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,gridPitch:nt,coordScale:ot});t.partitionsReconciled&&(C+=t.partitionsReconciled,D+=t.openingsRehosted,t.partitions.length?s.partitions=t.partitions:delete s.partitions,t.openings.length?s.openings=t.openings:delete s.openings,t.walls.length?s.walls=t.walls:delete s.walls),t.removedDrafts&&(P+=t.removedDrafts,t.roomDrafts.length?s.room_drafts=t.roomDrafts:delete s.room_drafts)}JSON.stringify({zero:(s.wall_segments||[]).filter(t=>0===Number(t.cm)),walls:s.walls||[]})!==i&&T++}let R=0;c<=9&&(R=function(t){const e=kr(t);return Mr(t,e.config),{...e,config:t}}(n).migratedSegments);const z=U(n),F=et($.layout),A=JSON.stringify(z)!==h||JSON.stringify(F)!==l;c<9&&A&&(z.model_version=9);const N=JSON.stringify(z)!==h||JSON.stringify(F)!==l,H=Number.isInteger(Number(z.model_version))?Number(z.model_version):c,O=N?w:{...w,moved:0,coordsCanonicalized:0,maxShift:0,maxShiftCm:0,maxSpace:"",rotated:0,removedDrafts:0},L=N?a.report:{...a.report,spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0};return{config:z,layout:F,report:{...O,modelFrom:c,modelTo:H,migrated:N?p:0,glowSpacesMigrated:N?d.glowSpaces:0,glowRoomsMigrated:N?d.glowRooms:0,canonicalized:N?T:0,wallSegmentsMigrated:N?R:0,legacyZeroWallsMigrated:N?x:0,wallsMerged:N?k:0,spansMerged:N?M:0,partitionsMerged:N?S:0,partitionsReconciled:N?C:0,openingsRehosted:N?D:0,redundantDraftsRemoved:N?P:0,wallsStraightened:N?g:0,wallsStraightenSkipped:f,maxStraightenShiftCm:N?b:0,maxStraightenSpace:N?v:"",latticeCoordinatesCanonicalized:N?r.canonicalized:0,latticeCoordinatesFar:N?r.far:0,latticeMaxShift:N?r.maxShift:0,latticeMaxShiftCm:N?r.maxShiftCm:0,latticeSpaces:N?r.spaces:[],...L},changed:N}}const zr=(t,e)=>t[0]*e[1]-t[1]*e[0],Fr=(t,e)=>t[0]*e[0]+t[1]*e[1],Ar=(t,e)=>[t[0]-e[0],t[1]-e[1]],Nr=(t,e,s)=>[t[0]+e[0]*s,t[1]+e[1]*s];function Hr(t,e,s){return Math.abs(zr(t,e))<=s}function Or(t,e,s){return Math.abs(zr(Ar(t,e),s))}function Lr(t,e,s,i,o){const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(!(r>o&&s>0))return[];const h=[a/r,n/r];return function(t,e,s){const i=e.map(([e,s])=>[Math.max(0,Math.min(e,s)),Math.min(t,Math.max(e,s))]).filter(([t,e])=>e>t+s).sort((t,e)=>t[0]-e[0]||t[1]-e[1]),o=[];for(const t of i){const e=o[o.length-1];!e||t[0]>e[1]+s?o.push([...t]):e[1]=Math.max(e[1],t[1])}const a=[];let n=0;for(const[t,e]of o)t>n+s&&a.push([n,t]),n=Math.max(n,e);return t>n+s&&a.push([n,t]),a}(r,i.flatMap(e=>{const i=e.b[0]-e.a[0],a=e.b[1]-e.a[1],n=Math.hypot(i,a);if(!(n>o&&Hr(h,[i/n,a/n],1e-6)))return[];if(Or(e.a,t,h)>1.1*Math.max(s,o)||Or(e.b,t,h)>1.1*Math.max(s,o))return[];return[[Fr(Ar(e.a,t),h),Fr(Ar(e.b,t),h)]]}),o).flatMap(([e,i])=>{const o=bt({a:Nr(t,h,e),b:Nr(t,h,i),halfDepth:s});return o?[o]:[]})}function Er(t){const e=t.coordScale??1,s=Math.max(t.epsilon??2e-4*t.gridPitch,1e-9),i=[];for(const s of t.rooms||[]){if(!s?.id)continue;const o=mt(t.rooms,s.id,t.walls,t.openCuts,t.pitch,t.cellCm,t.gridPitch,e);if(!o||o.poly.length<3)continue;const a=gt(o.poly,o.offsets);!a||a.length<3||i.push({roomId:s.id,profile:o,inner:a})}i.sort((t,e)=>t.roomId.localeCompare(e.roomId));const o=(t.roomOpenings||[]).map(t=>{const e=t.angle*Math.PI/180,s=[Math.cos(e),Math.sin(e)],i=Math.max(0,t.length)/2;return{a:Nr([t.x,t.y],s,-i),b:Nr([t.x,t.y],s,i)}}),a=[];for(const i of ft(t.rooms,t.walls,t.openCuts,t.pitch,t.cellCm,t.gridPitch,e))for(const t of Lr(i.a,i.b,i.depthUnits/2,o,s))a.push({body:t});const n=new Map;for(const e of t.partitionCuts||[]){const t=n.get(e.hostId)||[];t.push(e),n.set(e.hostId,t)}for(const e of t.partitions||[]){const i=j(e.cm,t.cellCm,t.gridPitch)/2;for(const t of Lr(e.a,e.b,i,n.get(e.id)||[],s))a.push({body:t,partitionId:e.id})}return{rooms:i,boundaries:a,epsilon:s}}function Br(t,e,s,i){const o=t.profile.offsets[e];if(!(o>0))return null;const a=function(t,e){const s=t[e],i=t[(e+1)%t.length],o=i[0]-s[0],a=i[1]-s[1],n=Math.hypot(o,a)||1;return function(t){let e=0;for(let s=0;s=0?[-a/n,o/n]:[a/n,-o/n]}(t.profile.poly,e),n=Nr(s.center,a,o),r=[];for(let e=0;ei&&Hr(s.axis,[h[0]/l,h[1]/l],1e-6)))continue;if(Or(o,n,s.axis)>i||Or(a,n,s.axis)>i)continue;const c=Fr(Ar(o,n),s.axis),d=Fr(Ar(a,n),s.axis);r.push([Math.min(c,d),Math.max(c,d)])}const h=function(t,e){t.sort((t,e)=>t[0]-e[0]||t[1]-e[1]);const s=[];for(const i of t){const t=s[s.length-1];!t||i[0]>t[1]+e?s.push([...i]):t[1]=Math.max(t[1],i[1])}return s}(r,i).find(([t,e])=>t<=i&&e>=-i);if(!h)return null;const[l,c]=h,d=Nr(n,s.axis,-s.half),p=Nr(n,s.axis,s.half),_=Math.max(0,-s.half-l),u=Math.max(0,c-s.half),m=_>0?Nr(n,s.axis,l):d,g=u>0?Nr(n,s.axis,c):p,f=Fr(a,s.normal)>=0?1:-1,b=(e,i,o)=>({from:e,to:i,label:[(e[0]+i[0])/2,(e[1]+i[1])/2],axis:s.axis,labelNormal:a,distance:o,roomId:t.roomId,roomSide:f,source:"room-face"});return{left:b(d,m,_),right:b(p,g,u)}}function Wr(t){const e=Nr(t.center,t.axis,-t.half),s=Nr(t.center,t.axis,t.half),i=Nr(t.center,t.axis,Math.min(-t.half,t.targetLo)),o=Nr(t.center,t.axis,Math.max(t.half,t.targetHi)),a=(e,s)=>({from:e,to:s,label:[(e[0]+s[0])/2,(e[1]+s[1])/2],axis:t.axis,labelNormal:t.normal,distance:Math.hypot(s[0]-e[0],s[1]-e[1]),source:"host-end"});return[a(e,i),a(s,o)]}function Gr(t,e,s,i){const o=Ar(s,e),a=Fr(o,o);if(!(a>i*i))return Math.hypot(...Ar(t,e))<=i;const n=Fr(Ar(t,e),o)/a;if(n<-i||n>1+i)return!1;const r=Nr(e,o,Math.max(0,Math.min(1,n)));return Math.hypot(...Ar(t,r))<=i}function jr(t,e,s){let i=!1;for(let o=0,a=e.length-1;ot[1]!=l>t[1]&&t[0]<(h-n)*(t[1]-r)/(l-r)+n&&(i=!i)}return i}function qr(t,e,s,i,o,a){const n=Ar(i,s),r=zr(e,n);if(Math.abs(r)<=a)return null;const h=Ar(s,t),l=zr(h,n)/r,c=zr(h,e)/r;return l<-a||l>o+a||c<-a||c>1+a?null:Math.max(0,Math.min(o,l))}function Ur(t,e,s){const i=Wr(s),o="partition"===t.host?.kind?t.host.id:void 0;return[{base:i[0],direction:[-s.axis[0],-s.axis[1]]},{base:i[1],direction:s.axis}].map(({base:t,direction:s})=>{const i=t.distance,a=function(t,e,s,i,o,a){let n=null;for(const r of i)if(!o||r.partitionId!==o){if(jr(t,r.body,a))return 0;for(let i=0;iFr(Ar(t,o),s));return{center:o,axis:s,normal:i,half:Math.max(0,t.renderedLength)/2,targetLo:Math.min(...a),targetHi:Math.max(...a)}}(t),i=e.rooms.flatMap(t=>{const i=function(t,e,s){const{profile:i}=t;let o=null;for(let t=0;t0))continue;const a=i.poly[t],n=i.poly[(t+1)%i.poly.length],r=Ar(n,a),h=Math.hypot(r[0],r[1]);if(!(h>s&&Hr(e.axis,[r[0]/h,r[1]/h],1e-6)))continue;if(Or(a,e.center,e.axis)>s||Or(n,e.center,e.axis)>s)continue;const l=Fr(Ar(a,e.center),e.axis),c=Fr(Ar(n,e.center),e.axis),d=Math.min(l,c),p=Math.max(l,c);if(d>-e.half+s||p0?d:p<0?-p:0);(!o||_2)return Wr(s);if(i.length){const t=i.map(({room:t,edge:i})=>Br(t,i,s,e.epsilon));if(t.some(t=>!t))return Wr(s);const o=t;return[...o.map(t=>t.left),...o.map(t=>t.right)]}return Ur(t,e,s)}const Vr="1.69.0-beta.2",Jr={badge:"display.badge",icon_ripple:"display.icon_ripple",value:"display.value",static_icon:"display.static_icon"},Yr={badge:"marker.display_hint_badge",icon_ripple:"marker.display_hint_icon_ripple",value:"marker.display_hint_value",static_icon:"marker.display_hint_static_icon"},Xr=2e3,Zr=1e3,Qr=t=>{const e=String(t??"").trim().replace(",",".");if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(e))return null;const s=Number(e);return Number.isFinite(s)?s:null},th=(t,e,s,i)=>{for(t.delete(e),t.set(e,s);t.size>i;){const e=t.keys().next().value;if(void 0===e)break;t.delete(e)}},eh=1e3,sh=2e3,ih=t=>{try{t.target?.setPointerCapture?.(t.pointerId)}catch{}},oh="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";class ah{constructor(t){this.host=t,this._junctionBaselineCache=new WeakMap,this._undoGeometry=()=>{if(this.host._physicalDrag||this.host._physicalRotate)return void this._cancelPhysicalGesture();if(this.host._decorDraft)return this.host._decorDraft=null,void this.host.requestUpdate();if(this.host._decorMove||this.host._dtDrag||this.host._bdDrag)return void this._cancelDecorGesture();if(this.host._resize.dragging)return void this._rszCancelDrag();const t=this.host._geometryHistory.undo();t&&(this._applyGeometryState(t.before,!0)?this.host._showToast(this.host._t("history.undone",{name:t.name})):this.host._geometryHistory.clear())},this._redoGeometry=()=>{if(this.host._physicalDrag||this.host._physicalRotate)return void this._cancelPhysicalGesture();if(this.host._decorDraft)return this.host._decorDraft=null,void this.host.requestUpdate();if(this.host._decorMove||this.host._dtDrag||this.host._bdDrag)return void this._cancelDecorGesture();if(this.host._resize.dragging)return void this._rszCancelDrag();const t=this.host._geometryHistory.redo();t&&(this._applyGeometryState(t.after,!0)?this.host._showToast(this.host._t("history.redone",{name:t.name})):this.host._geometryHistory.clear())},this._savePhysicalDialog=()=>{const t=this.host._physicalDialog,e=this.host._curSpaceCfg,s=this.host._spaceModel();if(!t||!e||!s)return;const i=Qr(t.cm);if(null==i)return void this._showPhysicalRange("column"===t.kind?vt:100,"column"===t.kind?1:0);const o=this.host._imperial?2.54*i:i,a="column"===t.kind?vt:100,n="column"===t.kind?1:0;if(!Number.isFinite(o)||oa)return void this._showPhysicalRange(a,n);if("column"===t.kind){const e=s.wall_columns.find(e=>e.id===t.id);if(!e)return;const i=Qr(t.angle||"0");if("circle"!==t.shape&&(null==i||i<0||i>=90))return void this.host._showToast(this.host._t("toast.physical_angle"));const a="circle"===t.shape?{id:t.id,shape:"circle",center:e.center,cm:o}:{id:t.id,shape:"square",center:e.center,cm:o,angle:i};if(s.wall_columns.some(e=>e.id!==t.id&&yt(e,a,.02*this.host._gridPitch)))return void this.host._showToast(this.host._t("toast.column_duplicate"))}const r=this._geometrySnapshot();if("partition"===t.kind){const s=(e.partitions||[]).find(e=>e.id===t.id);if(s&&0===o&&$t(e.openings,{kind:"partition",id:t.id}))return void this.host._showToast(this.host._t("toast.zero_wall_opening_conflict"));s&&(s.cm=o)}else if("column"===t.kind){const s=(e.wall_columns||[]).find(e=>e.id===t.id);s&&(s.cm=wt(o),s.shape="circle"===t.shape?"circle":"square","square"===s.shape?s.angle=Qr(t.angle||"0"):delete s.angle)}else{const s=(e.room_drafts||[]).find(e=>e.id===t.id);s?.segments?.[t.segment||0]&&(s.segments[t.segment||0].cm=o)}const h=this._commitPhysicalGeometry(this.host._t("history.physical_edit"),r);this.host._physicalDialog=null,h||this.host.requestUpdate()},this._deletePhysicalSelection=()=>{const t=this.host._physicalSel,e=this.host._curSpaceCfg;if(!t||!e)return;if("draft"===t.kind)return void this._deleteDraftWhole();const s=this._geometrySnapshot();if("partition"===t.kind){const s=(e.openings||[]).filter(e=>"partition"===e.host?.kind&&e.host.id===t.id).sort((t,e)=>(t.host?.t||0)-(e.host?.t||0));if(s.length)return void(this.host._partitionDeleteDialog={id:t.id,openings:s.map(t=>JSON.parse(JSON.stringify(t)))})}const i="partition"===t.kind?"partitions":"column"===t.kind?"wall_columns":"room_drafts";e[i]=(e[i]||[]).filter(e=>e.id!==t.id),e[i].length||delete e[i],this.host._activeDraftId===t.id&&this._cancelPath(),this.host._physicalSel=null,this.host._physicalDialog=null,this._commitPhysicalGeometry(this.host._t("history.physical_delete"),s)},this._confirmPartitionDelete=()=>{const t=this.host._partitionDeleteDialog,e=this.host._curSpaceCfg;if(!t||!e)return;const s=this._geometrySnapshot();e.partitions=(e.partitions||[]).filter(e=>e.id!==t.id),e.partitions.length||delete e.partitions,e.openings=(e.openings||[]).filter(e=>"partition"!==e.host?.kind||e.host.id!==t.id),e.openings.length||delete e.openings,this.host._partitionDeleteDialog=null,this.host._physicalSel=null,this.host._physicalDialog=null,this._commitPhysicalGeometry(this.host._t("history.physical_delete"),s)},this._deleteDraftWhole=()=>{const t="draft"===this.host._physicalDialog?.kind?this.host._physicalDialog.id:"draft"===this.host._physicalSel?.kind?this.host._physicalSel.id:null,e=this.host._curSpaceCfg;if(!t||!e||!confirm(this.host._t("confirm.delete_draft")))return;const s=this._geometrySnapshot();e.room_drafts=(e.room_drafts||[]).filter(e=>e.id!==t),e.room_drafts.length||delete e.room_drafts,this.host._activeDraftId===t&&this._cancelPath(),this.host._physicalSel=null,this.host._physicalDialog=null,this._commitPhysicalGeometry(this.host._t("history.physical_delete"),s)},this._deleteDraftSegment=()=>{const t=this.host._physicalDialog,e=this.host._curSpaceCfg;if(!t||"draft"!==t.kind||!e)return;if(!confirm(this.host._t("confirm.delete_draft_segment")))return;const s=(e.room_drafts||[]).findIndex(e=>e.id===t.id);if(s<0)return;const i=e.room_drafts[s],o=Math.max(0,Math.min(i.segments.length-1,t.segment||0)),a=[],n=i.points.slice(0,o+1),r=i.points.slice(o+1);if(n.length>=2&&a.push({id:i.id,points:n,segments:i.segments.slice(0,o)}),r.length>=2&&a.push({id:a.length?`${i.id}-${Date.now().toString(36)}`:i.id,points:r,segments:i.segments.slice(o+1)}),2===a.length&&e.room_drafts.length>=200)return void this.host._showToast(this.host._t("toast.physical_limit"));const h=this._geometrySnapshot();e.room_drafts.splice(s,1,...a),e.room_drafts.length||delete e.room_drafts,this.host._activeDraftId===i.id&&this._cancelPath(),this.host._physicalDialog=null,this.host._physicalSel=a.length?{kind:"draft",id:a[0].id}:null,this._commitPhysicalGeometry(this.host._t("history.draft_segment_delete"),h)},this._confirmRoomDelete=t=>{const e=this.host._roomDeleteDialog,s=this.host._curSpaceCfg,i=this.host._spaceModel();if(!e||!s||!i)return;const o=i.rooms.find(t=>t.id===e.roomId);if(!o)return void(this.host._roomDeleteDialog=null);const a=this.host._openCuts(),n=sn(A(i.rooms,this.host._spaceWalls,a,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,eh).filter(t=>t.roomId===o.id),i.partitions,this.host._openingsR.map(t=>({...t,x:t.rx,y:t.ry})),.02*this.host._gridPitch),r=new Set(n.materialize.filter(t=>!t.reusePartitionId).map(t=>t.interval.key)).size;if(t&&(s.partitions||[]).length+r>sh)return void this.host._showToast(this.host._t("toast.physical_limit"));const h=this._geometrySnapshot(),l=kt(i.rooms,this.host._spaceWalls,a,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,eh);if(t){s.partitions||=[];const t=new Map,e=new Map,i=t=>{const e=(s.wall_segments||[]).find(e=>{const s=[Number(e.a?.[0])*eh,Number(e.a?.[1])*eh],i=[Number(e.b?.[0])*eh,Number(e.b?.[1])*eh];return this._samePt(t.a,s)&&this._samePt(t.b,i)||this._samePt(t.a,i)&&this._samePt(t.b,s)});return"string"==typeof e?.id&&e.id?e.id:null},o=Date.now().toString(36);for(const a of n.materialize){let n=a.reusePartitionId?s.partitions.find(t=>t.id===a.reusePartitionId):e.get(a.interval.key);n||(n={id:i(a.interval)||`partition-room-${o}-${e.size}`,a:[a.interval.a[0]/eh,a.interval.a[1]/eh],b:[a.interval.b[0]/eh,a.interval.b[1]/eh],cm:a.interval.cm},s.partitions.push(n),e.set(a.interval.key,n)),t.set(a.interval.key,n)}for(const e of s.openings||[]){const s=n.openingIntervals.get(e.id),i=s?t.get(s):null,o=this.host._openingsR.find(t=>t.id===e.id);if(!i||!o)continue;const a={a:[i.a[0]*eh,i.a[1]*eh],b:[i.b[0]*eh,i.b[1]*eh]};e.host={kind:"partition",id:i.id,t:on([o.rx,o.ry],a)}}}else if(n.removeOpeningIds.length){const t=new Set(n.removeOpeningIds);s.openings=(s.openings||[]).filter(e=>!t.has(e.id)),s.openings.length||delete s.openings}s.rooms=s.rooms.filter(t=>t.id!==o.id),this.host._cfgEpoch++;const c=this.host._normalizeWalls(l,this.host._openCuts());c.length?s.walls=c:delete s.walls,this.host._roomDeleteDialog=null,this._commitPhysicalGeometry(this.host._t(t?"history.delete_room_keep_walls":"history.delete_room_with_walls"),h),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate()},this._rebindPartitionOpening=()=>{const t=this.host._openingDialog;if(!t?.id)return;const e=t.id;this._activateMarkupTool("opening"),"opening"===this.host._tool&&(this.host._openingRebindId=e,this.host._openingPreset={type:t.type,lengthCm:t.lengthCm,flipH:t.flipH,flipV:t.flipV,revision:++this.host._openingPresetRevision},this.host._openingDialog=null,this.host._openingHoverCandidate=null)},this._deviceInboxTabKey=t=>{if("ArrowLeft"!==t.key&&"ArrowRight"!==t.key)return;const e=this.host._deviceInbox;if(!e)return;const s=["on_plan","available","hidden","readd"],i="ArrowRight"===t.key?1:-1,o=(s.indexOf(e.tab)+i+s.length)%s.length;this.host._deviceInbox={...e,tab:s[o],limit:100,onlyNew:!1},t.preventDefault()},this._keepClosedAsPartitions=()=>{if(this.host._wallFaceBatch)return void this._decideWallFace(!1);if(!this.host._contourClosed||this.host._pendingSplit||!this.host._curSpaceCfg)return;const t=this.host._curSpaceCfg,e=this.host._path.slice(0,-1);if((t.partitions||[]).length+e.length>sh)return void this.host._showToast(this.host._t("toast.physical_limit"));const s=this._geometrySnapshot(),i=Pa(e.length,[...this.host._draftSegmentCms,this.host._closingWallCm??void 0],this.host._drawWallCm,N);t.partitions||=[];const o=Date.now().toString(36),a=this.host._activeDraftId?(t.room_drafts||[]).find(t=>t.id===this.host._activeDraftId):null,n=this._draftSegmentsForPath(this.host._path,a,i);for(let s=0;st.id!==this.host._activeDraftId),t.room_drafts.length||delete t.room_drafts),this._commitPhysicalGeometry(this.host._t("history.contour_to_partitions"),s),this.host._roomDialog=!1,this.host._path=[],delete this.host._resumeDraftBySpace[this.host._space],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null},this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),e=this.host._spaceDialog;e&&(this.host._spaceDialog={...e,saved:t?.plans||[],savedBusy:!1})}catch(t){const e=this.host._spaceDialog;e&&(this.host._spaceDialog={...e,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}},this._openSettingsDialog=()=>{if(!this.host._norm)return;const t=this.host._glowRadiusCm,e=this.host._imperial?Math.round(t/30.48*10)/10:Math.round(t)/100;this.host._settingsDialog={colors:JSON.parse(JSON.stringify(this.host._fillColors)),glowRadius:e,bgColor:Ct(this.host._settings,{bgColor:null})||null,northDeg:St(this.host._settings,{}),bgMode:Mt(this.host._settings,{}),sunRays:xt(this.host._settings,{}),busy:!1}},this._openAlignDialog=()=>this._previewAlignDialog(!1),this._toggleOptimizeLivePositions=()=>{const t=this.host._alignDialog;t&&!t.busy&&t.report.liveMissingPositions.length&&this._previewAlignDialog(!t.removeLiveMissingPositions)},this._openBackupExport=()=>{this.host._settingsDialog=null,this.host._backupExportDialog={kind:"full",planOnly:!1,busy:!1,error:""}},this._openRulesDialog=()=>{if(!this.host._norm)return;const t=this.host._settings.icon_rules,e=(t&&t.length?t:Dt).map(t=>({...t}));this.host._rulesDialog={rules:e,test:"",busy:!1}},t._editorSecondary=new _n({root:()=>t.renderRoot,requestUpdate:()=>t.requestUpdate(),updateComplete:()=>t.updateComplete,clearTip:()=>{t._tip=null}}),t._resize=new Lo}_help(t){const e=`${t}.aria`,s=d(this.host.hass,this.host._config?.language);return Pt(s,t)&&Pt(s,e)?o``:a}_setMode(t,e=!0){this.host._endTabDrag(),this.host._pendingNavMode=null;const s=this.host._spaceModel();if(!s)return this.host._cancelModeTransition(!1),void(this.host._mode="view");if(this.host._kiosk&&"view"!==t)return;if(this.host._mode===t){if(!e&&"view"===t&&this.host._modeTransitionBusy){const e=this.host._currentModeVisual(t),s=this.host._modeTransitionTargetZoom,i=this.host._modeTransitionTargetCenterX,o=this.host._modeTransitionTargetCenterY;this.host._cancelModeTransition(!1),this.host._commitViewModeAtomic(e,s,i,o)}return}if(this.host._bootSoftCancel(),("plan"===t||"decor"===t)&&!this.host._norm)return void this.host._showToast(this.host._t("toast.markup_needs_server"));if(this.host._wallFaceBatch&&this._roomDialogCancel(),"plan"===this.host._mode&&"draw"===this.host._tool&&!this._finishWallChain())return;this.host._clearTransientHover(!0),this.host._cancelDevicePressFeedback();const i=this.host._mode,o=this.host._effectiveProjection(),a=this.host._currentModeVisual(i),n=this.host._modeTransitionBusy,r=a&&"view"!==i&&"view"!==t?{...a,toolbarContentOpacity:this.host._reducedMotion?1:.35}:a;this.host._cancelModeTransition(!1),this.host._editorSecondary.closeForNavigation(),(this.host._decorMove||this.host._dtDrag||this.host._bdDrag)&&this._cancelDecorGesture();const h=!s.bg&&"view"===t!=("view"===i),l=n&&"view"===i&&"view"!==t?this.host._modeTransitionEditorCamera:null;let c=l?.zoom??(n?this.host._modeTransitionTargetZoom:this.host._zoom),d=l?l.centerX:n?this.host._modeTransitionTargetCenterX:r?.viewport.centerX,p=l?l.centerY:n?this.host._modeTransitionTargetCenterY:r?.viewport.centerY;if("view"===i&&"view"!==t&&!n){const e=this.host._view;if(this.host._viewModeSnap={space:this.host._space,zoom:this.host._zoom,cx:e?this.host._logicalViewCenter(o)?.x:void 0,cy:e?this.host._logicalViewCenter(o)?.y:void 0},"iso"===o){const e=this.host._logicalViewCenter("iso");d=e?.x,p=e?.y,this.host._view=null,this.host._mode=t,this.host._applyView(this.host._zoom,e?.x,e?.y)}h&&(c=1,d=void 0,p=void 0)}if("plan"===i&&this.host._activeDraftId&&(this.host._resumeDraftBySpace[this.host._space]=this.host._activeDraftId),this.host._mode=t,"devices"===i&&"devices"!==t&&(this.host._showHidden=!1,this.host._deviceInbox=null,this.host._deviceInboxReturn=null,this.host._deviceInboxMemo=null),this.host._editorChromeMode="view"===t?i:t,"view"===t){"view"===i||n||(this.host._modeTransitionEditorCamera={zoom:this.host._zoom,centerX:r?.viewport.centerX,centerY:r?.viewport.centerY});const t=this.host._viewModeSnap;if(t&&t.space===this.host._space){c=t.zoom;const e=this.host._labsIso&&"iso"===this.host._viewPreference[this.host._space]?"iso":"flat",s=null!=t.cx&&null!=t.cy&&"iso"===e?It([t.cx,t.cy],0):null;d=s?.[0]??t.cx,p=s?.[1]??t.cy}else t&&(c=this.host._zoomBySpace[this.host._space]||1,d=void 0,p=void 0)}else this.host._modeTransitionEditorCamera={zoom:c,centerX:d,centerY:p};this.host._modeTransitionTargetZoom=c,this.host._modeTransitionTargetCenterX=d,this.host._modeTransitionTargetCenterY=p,("iso"===o||"view"===t&&this.host._labsIso&&"iso"===this.host._viewPreference[this.host._space])&&(this.host._modeTransitionForceAtomic=!0);const _=++this.host._modeTransitionRequest;e?r?(this.host._modeTransitionPreparing=!0,this.host._modeTransitionVisual=r,this.host._prepareModeTransition(_,r,t,c,d,p)):(this.host._modeTransitionPreparing=!1,this.host._modeTransitionVisual=null,this.host._zoom=c,this.host._view=null,requestAnimationFrame(()=>{this.host.isConnected&&_===this.host._modeTransitionRequest&&this.host._mode===t&&(this.host._applyView(c,d,p),"view"===t&&(this.host._viewModeSnap=null,this.host._modeTransitionEditorCamera=null),this.host.requestUpdate())})):"view"===t&&this.host._commitViewModeAtomic(r,c,d,p),this.host._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this.host._tool="draw",this.host._mergeSel=null,this.host._mergeDialog=null,this.host._splitSel=null,this.host._pendingSplit=null,this.host._selId=null,this.host._physicalSel=null,this.host._physicalDialog=null,this.host._physicalDrag=null,this._rszResetController(),this.host._tip=null,this.host._hoverRoom=null,this.host._decorDraft=null,this.host._decorSel=null,this.host._decorMove=null,this.host._backdropDialog=null,this.host._decorTool="select",this.host._bdDrag=null,this.host._dtDrag=null,this.host._dtBox=null,"plan"===t&&(this._primeDrawWallField(),this._resumeLastDraft()),this.host._saveNav()}_primeDrawWallField(){null===this.host._drawWallField&&(this.host._drawWallField=Tt(N,this.host._imperial))}_showPhysicalRange(t=this.host._drawWallMaxCm,e=0){this.host._showToast(this.host._t("toast.physical_range",{min:Tt(e,this.host._imperial),max:Tt(t,this.host._imperial),unit:this.host._t(this.host._imperial?"wallthick.unit_in":"wallthick.unit_cm")}))}_draftSegmentCount(t=this.host._curSpaceCfg){return(t?.room_drafts||[]).reduce((t,e)=>t+(Array.isArray(e.segments)?e.segments.length:0),0)}_mergeSpacePartitions(t,e){const s=t?.partitions||[];if(s.length<2)return 0;const i=Pn(s,{pitch:I,seedIds:e,geometry:Tn(t,{excludeDraftId:this.host._activeDraftId})});return i.merged?(t.partitions=i.partitions,In(t.openings,t.partitions,i.openingMoves,{coordScale:eh,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch}),i.merged):0}_finishWallChain(){if("draw"!==this.host._tool||this.host._wallFaceBatch||this.host._roomDialog)return!0;const t=this.host._curSpaceCfg;if(!t||this.host._path.length<2)return this.host._path=[],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this._clearPlanSnapHover(),!0;const e=Ia(this.host._path,Pa(this.host._path.length-1,this.host._draftSegmentCms,this.host._drawWallCm,N)),s=e.length;if((t.partitions||[]).length+s>sh)return this.host._showToast(this.host._t("toast.physical_limit")),!1;const i=this._geometrySnapshot();t.partitions||=[];const o=Date.now().toString(36),a=[],n=this.host._activeDraftId?(t.room_drafts||[]).find(t=>t.id===this.host._activeDraftId):null,r=this._draftSegmentsForPath(this.host._path,n,e.map(t=>t.cm));for(let i=0;it.id!==this.host._activeDraftId),t.room_drafts.length||delete t.room_drafts),this._commitPhysicalGeometry(this.host._t("history.wall_chain_finish"),i),delete this.host._resumeDraftBySpace[this.host._space],this.host._path=[],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this._clearPlanSnapHover(),!0}_activateMarkupTool(t){t!==this.host._tool&&(this.host._wallFaceBatch&&this._roomDialogCancel(),("draw"!==this.host._tool||this._finishWallChain())&&(this._cancelPath(),"resize"===this.host._tool&&(this.host._resize.dragging?this._rszCancelDrag():this.host._resize.reset()),this.host._tool=t,"draw"===t&&this._resumeLastDraft(),"resize"===t&&this.host._resize.selectRoom(null),"wallthick"===t&&(this.host._wallDialog=null)))}_limitReached(t){const e=this.host._curSpaceCfg;if(!e)return!0;const s="draft"===t?(e.room_drafts||[]).length>=200:"partition"===t?(e.partitions||[]).length>=sh:(e.wall_columns||[]).length>=500;return s&&this.host._showToast(this.host._t("toast.physical_limit")),s}_svgPoint(t){const e=this.host.renderRoot.querySelector(".stage").getBoundingClientRect();return this.host._screenToVb(t.clientX-e.left,t.clientY-e.top)}_snap(t){const e=this.host._gridPitch;return[Rt(zt(t[0],e)),Rt(zt(t[1],e))]}_snapDrawPoint(t,e=!1){const s=this.host._path[this.host._path.length-1],i=e&&s?Ft(s,t,this.host._gridPitch,Ci):t;return this._snap(i)}_planSnapOpeningCuts(t,e){if(!this.host._openingsR.length)return[];const s=this.host._openingWallIndexFor(t,e).value,i=[];for(const e of this.host._roomWallOpeningInputs(this.host._openingsR,t)){const t=G(s,e);if(!t.negative&&!t.positive)continue;const o=e.angle*Math.PI/180,a=Math.cos(o)*e.length/2,n=Math.sin(o)*e.length/2;i.push([e.x-a,e.y-n,e.x+a,e.y+n])}return i}_planSnapGeometrySnapshot(){const t=this.host._spaceModel();if(!t)return{key:`${this.host._space}|empty`,value:{segments:[],endpoints:[]}};const e=[this.host._space,this.host._cfgEpoch,this.host._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this.host._planSnapGeometryCache?.key===e)return this.host._planSnapGeometryCache;const s=this.host._openCuts(),i=$a({space:t,activeDraftId:this.host._activeDraftId,roomCuts:this._planSnapOpeningCuts(t,s),partitionCuts:this._partitionOpeningCuts(t),epsilon:2e-4*this.host._gridPitch});return this.host._planSnapGeometryCache={key:e,value:i},this.host._planSnapGeometryCache}_hiddenWallDiagnosticSnapshot(){const t=this.host._spaceModel();if(!t)return{key:`${this.host._space}|hidden-empty`,value:{segments:[],endpoints:[]}};const e=["hidden",this.host._space,this.host._cfgEpoch,this.host._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this.host._hiddenWallDiagnosticCache?.key===e)return this.host._hiddenWallDiagnosticCache;const s=ya({space:t,activeDraftId:this.host._activeDraftId,epsilon:2e-4*this.host._gridPitch});return this.host._hiddenWallDiagnosticCache={key:e,value:s},this.host._hiddenWallDiagnosticCache}_planStructuralGeometrySnapshot(){const t=this.host._spaceModel();if(!t)return{key:`${this.host._space}|structural-empty`,value:{segments:[],endpoints:[]}};const e=["structural",this.host._space,this.host._cfgEpoch,this.host._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this.host._planStructuralGeometryCache?.key===e)return this.host._planStructuralGeometryCache;const s=$a({space:t,activeDraftId:this.host._activeDraftId,epsilon:2e-4*this.host._gridPitch});return this.host._planStructuralGeometryCache={key:e,value:s},this.host._planStructuralGeometryCache}_planSnapContextKey(t){const e=this.host._path[0],s=this.host._path[this.host._path.length-1];return[t,this.host._tool,this.host._path.length,e?`${e[0]},${e[1]}`:"",s?`${s[0]},${s[1]}`:""].join("|")}_resolvePlanDrawPoint(t,e){const s=this._planSnapGeometrySnapshot(),i=this.host._path[this.host._path.length-1],o="draw"===this.host._tool&&this.host._path.length>=3?[{point:this.host._path[0],key:"closure:first-point"}]:[],a={tolerance:this._cssPxToRender(12),distinguishTolerance:this._cssPxToRender(8),gridStep:this.host._gridPitch,excludePoints:i?[i]:[],extraEndpoints:o,epsilon:2e-4*this.host._gridPitch},n=e&&i?Ca(s.value,t,{...a,anchor:i}):function(t,e,s){if(!(pa(e)&&s.tolerance>=0))return{kind:"none",candidate:null,conflicts:[]};const i=s.epsilon??da,o=s.excludePoints||[],a=Ma(xa(t,e,s),s.distinguishTolerance||0);if(a)return a;let n=null;for(const a of t.segments){const t=[a.a[0],a.a[1],a.b[0],a.b[1]],r=D([e[0],e[1]],t);if(r>s.tolerance)continue;const h=Sa(a,e,s.gridStep);!wa(h,o,i)&&ka(r,a.key,n)&&(n={kind:"line",point:h,key:a.key,distance:r,segment:a})}return n?{kind:"resolved",candidate:n,conflicts:[]}:{kind:"none",candidate:null,conflicts:[]}}(s.value,t,a),r="resolved"===n.kind?n.candidate:null,h=r?[...r.point]:this._snapDrawPoint(t,e),l=i?At(i,h):h;return{point:l,candidate:r&&q(l,r.point)?r:null,conflicts:"ambiguous"===n.kind?n.conflicts:[],ambiguous:"ambiguous"===n.kind,contextKey:this._planSnapContextKey(s.key)}}_clearPlanSnapHover(t=!0){this.host._planSnapHover=null,this._syncPlanSnapActiveMarker(null),this._syncPlanSnapConflictMarkers([]),t&&(this.host._cursorPt=null)}_samePt(t,e){return q(t,e)}_dropLegacySegments(){for(const t of this.host._serverCfg?.markers||[])"ripple"===t.display&&(t.display="icon_ripple");for(const t of this.host._serverCfg?.spaces||[]){delete t.segments;const e=new Set,s=t=>"string"==typeof t&&t.length>=1&&t.length<=64&&!e.has(t),i=t=>(e.add(t),!0),o=t=>Array.isArray(t)&&2===t.length&&t.every(t=>Number.isFinite(Number(t))&&Math.abs(Number(t))<=Xt);if(Array.isArray(t.partitions)&&(t.partitions=t.partitions.filter(t=>t&&s(t.id)&&o(t.a)&&o(t.b)&&Math.hypot(t.a[0]-t.b[0],t.a[1]-t.b[1])>1e-9&&i(t.id)).map(t=>({...t,cm:Number.isFinite(Number(t.cm))?Math.max(0,Math.min(100,Number(t.cm))):15})),t.partitions.length||delete t.partitions),Array.isArray(t.wall_columns)&&(t.wall_columns=t.wall_columns.filter(t=>t&&s(t.id)&&o(t.center)&&i(t.id)).map(t=>({id:t.id,shape:"circle"===t.shape?"circle":"square",center:[Number(t.center[0]),Number(t.center[1])],cm:wt(Number(t.cm)||15),..."circle"===t.shape?{}:{angle:Nt(t.angle)}})),t.wall_columns.length||delete t.wall_columns),Array.isArray(t.room_drafts)&&(t.room_drafts=t.room_drafts.filter(t=>t&&s(t.id)&&Array.isArray(t.points)&&t.points.length>=2&&t.points.every(o)&&i(t.id)).map(t=>{const e=nr(t);return{id:t.id,...e}}).filter(t=>t.points.length>=2),t.room_drafts.length||delete t.room_drafts),Array.isArray(t.walls)){const e=Ht(ut({spaces:[t]}),t.id),s=e?Ot(t,e,eh,.02*nt).contour.map(t=>t.map(t=>t/eh)):V(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]);t.walls=rt(t.walls,t.rooms||[],I,1,s),t.walls.length||delete t.walls}}}_rollbackRejectedPhysicalWrites(t){if(!this.host._serverCfg||!t.length)return!1;let e=!1;for(const[s]of t){const t=this.host._pendingPhysicalWrites.get(s);t&&(e=this._restoreGeometryStateInConfig(this.host._serverCfg,t.before)||e,this.host._pendingPhysicalWrites.delete(s))}return!!e&&(this._clearGeometryGesture(),this.host._geometryHistory.clear(),this.host._cfgEpoch++,this.host._modelCache=null,this.host._wallUnionCache=null,this.host._physicalBodiesCache=null,this.host._frame=null,this.host._regSignature="",this.host._cfgContentFingerprint=Lt(this.host._serverCfg),this.host._maybeRebuildDevices(),this.host.requestUpdate(),!0)}async _reloadRejectedPhysicalWrite(){const t=this.host._writeChain;await t.catch(()=>{}),await this.host._reloadConfigOnly(!0)}_writeConfig(){this.host._writesPending++,this.host._writeChain=Et(this.host._writeChain,async()=>{if(!this.host._serverCfg)return;this._dropLegacySegments();const t=ki(this.host._serverCfg),e=Lt(t),s=[...this.host._pendingPhysicalWrites.entries()];for(const[e,i]of s){const s=t.spaces.find(t=>t.id===e),o=jt(s);if(o===i.fingerprint)continue;let a=!1;try{a=this.host._checkSpacePhysicalGeometry(t,e).ok}catch{a=!1}if(!a)throw this._restoreGeometryStateLocal(i.before),this.host._pendingPhysicalWrites.delete(e),this.host._geometryHistory.clear(),this.host._showToast(this.host._t("toast.geometry_unsafe")),Object.assign(new Error("unsafe wall geometry"),{code:"geometry-unsafe"});i.fingerprint=o}e!==Lt(this.host._serverCfg)&&(this.host._serverCfg=t),this.host._cfgContentFingerprint=e;try{await this.host._sendConfigCandidate(t)}catch(t){if(!this._rollbackRejectedPhysicalWrites(s))throw t;const e=t&&"object"==typeof t?t:Object.assign(new Error(String(t)),{cause:t});throw e.physicalGeometryRolledBack=!0,e}for(const[t,e]of s)this.host._pendingPhysicalWrites.get(t)?.fingerprint===e.fingerprint&&this.host._pendingPhysicalWrites.delete(t)});return this.host._writeChain.finally(()=>{this.host._writesPending--})}_saveConfig(){this.host._cfgEpoch++,this.host._saveConfigDebounced()}_geometrySnapshotFromConfig(t,e){const s=t?.spaces?.find(t=>t.id===e);if(!s)return null;const i=t=>JSON.parse(JSON.stringify(t)),o={};for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])void 0!==s[t]&&(o[t]=s[t]);return{spaceId:e,rooms:i(s.rooms||[]),...Array.isArray(s.openings)?{openings:i(s.openings)}:{},...Array.isArray(s.walls)?{walls:i(s.walls)}:{},...Array.isArray(s.wall_segments)?{wall_segments:i(s.wall_segments)}:{},...Array.isArray(s.open_spans)?{open_spans:i(s.open_spans)}:{},...Array.isArray(s.room_drafts)?{room_drafts:i(s.room_drafts)}:{},...Array.isArray(s.partitions)?{partitions:i(s.partitions)}:{},...Array.isArray(s.wall_columns)?{wall_columns:i(s.wall_columns)}:{},...Array.isArray(s.decor)?{decor:i(s.decor)}:{},plan_transform:o}}_geometrySnapshot(t=this.host._space){return this._geometrySnapshotFromConfig(this.host._serverCfg,t)}_recordGeometry(t,e){if(!e)return;const s=this._geometrySnapshot(e.spaceId);s&&JSON.stringify(e)!==JSON.stringify(s)&&(this.host._geometryHistory.push({name:t,before:e,after:s}),this.host.requestUpdate())}_restoreGeometryStateInConfig(t,e,s=!1){const i=t?.spaces?.find(t=>t.id===e.spaceId);if(!i)return!1;const o=t=>JSON.parse(JSON.stringify(t)),a=new Map((i.rooms||[]).map(t=>[t.id,t]));if(i.rooms=o(e.rooms),s)for(const t of i.rooms){const e=a.get(t.id);!Array.isArray(t.wall_ids)&&Array.isArray(e?.wall_ids)&&e.wall_ids.length===t.poly?.length&&(t.wall_ids=o(e.wall_ids))}const n=(t,e)=>{void 0!==e?i[t]=o(e):s&&"wall_segments"===t||delete i[t]},r=new Map((i.openings||[]).map(t=>[t.id,t])),h=new Map((i.room_drafts||[]).map(t=>[t.id,t]));if(n("openings",e.openings),n("walls",e.walls),n("wall_segments",e.wall_segments),n("open_spans",e.open_spans),n("room_drafts",e.room_drafts),n("partitions",e.partitions),n("wall_columns",e.wall_columns),n("decor",e.decor),s){for(const t of i.openings||[]){const e=r.get(t.id);t.host||"wall"!==e?.host?.kind||(t.host=o(e.host))}for(const t of i.room_drafts||[]){const e=h.get(t.id);for(let s=0;s<(t.segments||[]).length;s++)!t.segments[s]?.id&&e?.segments?.[s]?.id&&(t.segments[s].id=e.segments[s].id)}}for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])delete i[t];return Object.assign(i,o(e.plan_transform||{})),!0}_restoreGeometryStateLocal(t){return!!this._restoreGeometryStateInConfig(this.host._serverCfg,t)&&(this.host._cfgEpoch++,this.host._modelCache=null,this.host._wallUnionCache=null,this.host._physicalBodiesCache=null,this.host._frame=null,this.host.requestUpdate(),!0)}_wallModelBlockerLabel(t){const e=t instanceof Zn?t.reason:"invalid-room";return this.host._t(`wall_model.reason.${e}`)}_hasLegacyZeroWallFields(t=this.host._serverCfg){return(t?.spaces||[]).some(t=>Array.isArray(t?.open_spans)&&t.open_spans.length>0||(t?.rooms||[]).some(t=>Array.isArray(t?.open_to)&&t.open_to.length>0))}_showWallModelMigrationBlocked(t){const e=this._hasLegacyZeroWallFields()?"toast.zero_wall_migration_blocked":"toast.wall_model_migration_blocked";this.host._showToast(this.host._t(e,{reason:this._wallModelBlockerLabel(t)}))}_limitSegmentsOf(t){const e=[];for(const s of t?.wall_segments||[])s?.a&&s?.b&&e.push({id:String(s.id||""),a:s.a,b:s.b,cm:Number(s.cm)});for(const s of t?.partitions||[])s?.a&&s?.b&&e.push({id:String(s.id||""),a:s.a,b:s.b,cm:Number(s.cm)});for(const s of t?.room_drafts||[]){const t=Array.isArray(s?.points)?s.points:[],i=Array.isArray(s?.segments)?s.segments:[];for(let o=0;o+1t?.id===e);if(!i)return[];const o=Number(i.cell_cm)>0?Number(i.cell_cm):5,a=this._limitSegmentsOf(i),n=[...Xo(a),...sa(a,o,I),...oa(a,o,I)];let r=null;try{r=Bt(i.rooms||[],i.walls||[],[],I,o,I,1)}catch{r=null}let h="ok"===s?.status||"degraded-extra"===s?.status?s.roomGeom:null;if(!h&&r&&r.nodes.length)try{const t=Wt(i.rooms||[],i.walls||[],[],[],I,o,I,1);h="ok"===t?.status||"degraded-extra"===t?.status?t.roomGeom:null}catch{h=null}for(const t of i.rooms||[]){const e=String(t?.id||"");if(!e)continue;let s=null;try{s=Gt(i.rooms||[],e,i.walls||[],[],I,o,I,1,h??void 0,r)}catch{s=null}n.push(...aa(e,s,o,I))}return n}_junctionLimitLabel(t){const e=t=>String(Math.round(10*t)/10);return this.host._t(`junction.limit_${t.rule}`,{actual:e(t.actual),limit:e(t.limit)})}_junctionLimitsIntroduced(t,e,s,i){let o;const a=(e?.spaces||[]).find(t=>t?.id===s);let n="";try{n=jt(a)}catch{n=""}const r=e&&"object"==typeof e?this._junctionBaselineCache.get(e):void 0;if(r&&n&&r.fingerprint===n&&r.spaceId===s&&(o=r.violations),!o){try{const t=Number(e?.model_version||0)>=9?e:kr(e).config;o=this.host._junctionLimitViolations(t,s)}catch{return[]}e&&"object"==typeof e&&n&&this._junctionBaselineCache.set(e,{spaceId:s,fingerprint:n,violations:o})}let h=[];try{h=this.host._junctionLimitViolations(t,s,i)}catch{return[{rule:"check_failed",subject:s,actual:0,limit:0}]}return function(t,e){const s=new Map;for(const t of e||[])s.set(t.rule,(s.get(t.rule)||0)+1);const i=new Map;for(const e of t||[])i.set(e.rule,[...i.get(e.rule)||[],e]);const o=[];for(const[t,e]of i){const i=e.length-(s.get(t)||0);i>0&&o.push(...e.slice(0,i))}return o}(h,o)}_commitPhysicalGeometry(t,e,s=[]){if(!e||!this.host._serverCfg)return!1;const i=this.host._serverCfg,o=this._geometrySnapshotFromConfig(i,e.spaceId),a=i.spaces.find(t=>t.id===e.spaceId);if(!a||jt(e)===jt(a))return!1;let n,r=!1;try{r=this.host._checkSpacePhysicalGeometry(i,e.spaceId).ok}catch{r=!1}if(!r)return this._clearGeometryGesture(),this._restoreGeometryStateLocal(e),this.host._showToast(this.host._t("toast.geometry_unsafe")),!1;let h=e;try{if(Number(i.model_version||0)<9){const t=JSON.parse(JSON.stringify(i));if(!this._restoreGeometryStateInConfig(t,e))throw new Zn("invalid-room",e.spaceId);const s=kr(t).config;h=this._geometrySnapshotFromConfig(s,e.spaceId)||e;const a=JSON.parse(JSON.stringify(s));if(!o||!this._restoreGeometryStateInConfig(a,o,!0))throw new Zn("invalid-room",e.spaceId);const r=s.spaces.find(t=>t.id===e.spaceId),l=a.spaces.find(t=>t.id===e.spaceId);if(!Array.isArray(o.wall_segments)&&JSON.stringify(e.rooms)===JSON.stringify(o.rooms))for(const t of l?.wall_segments||[])t.cm=Q(o.walls,t.a,t.b,I,1);const c=((t,e,s)=>{const i=new Map,o=new Map((t?.rooms||[]).map(t=>[t.id,t])),a=new Map((e||[]).map(t=>[t.id,t])),{rooms:n}=br(s,gr(t));for(const t of n){const e=a.get(t.id),n=o.get(t.id),r=R(e),h=(s.rooms||[]).find(e=>e.id===t.id),l=R(h),c=R(n);if(r&&l&&c&&r.length===l.length&&c.length===n?.wall_ids?.length&&t.poly.length===t.wall_ids.length)for(let e=0;e{const o=[];for(let a=0;aXn||lr(r,s,i)>Xn)continue;const h=hr(n,s,i),l=hr(r,s,i);h<-Xn||l>1+Xn||l<=h+Xn||o.push({start:h,id:e[a]})}return o.sort((t,e)=>t.start-e.start)},o=s(c,n.wall_ids,r[e],r[(e+1)%r.length]),a=s(t.poly,t.wall_ids,l[e],l[(e+1)%l.length]);if(o.length&&o.length===a.length)for(let t=0;tt.id===e.spaceId),i=this.host._path.length>=2?this.host._path.map(t=>[t[0]/eh,t[1]/eh]):[];i.push(...s.map(t=>[t[0],t[1]])),l=rr(t)<=rr(h,i)&&this.host._checkSpacePhysicalGeometry(n,e.spaceId).ok}catch{l=!1}if(!l)return this._clearGeometryGesture(),this._restoreGeometryStateLocal(e),this.host._showToast(this.host._t("toast.geometry_unsafe")),!1;const c=JSON.parse(JSON.stringify(i));this._restoreGeometryStateInConfig(c,e);const d=this._junctionLimitsIntroduced(n,c,e.spaceId);if(d.length)return this._clearGeometryGesture(),this._restoreGeometryStateLocal(e),this.host._showToast(this._junctionLimitLabel(d[0])),!1;Mr(i,n),this._recordGeometry(t,h);const p=i.spaces.find(t=>t.id===e.spaceId),_=this.host._pendingPhysicalWrites.get(e.spaceId);return this.host._pendingPhysicalWrites.set(e.spaceId,{before:_?.before||h,fingerprint:jt(p)}),this._saveConfig(),!0}_clearGeometryGesture(){this.host._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!1),this.host._mergeSel=null,this.host._mergeDialog=null,this.host._splitSel=null,this.host._pendingSplit=null,this.host._wallFaceBatch=null,this.host._wallRepairDiagnostic=null,this.host._roomDeleteDialog=null,this.host._wallDialog=null,this.host._physicalDialog=null,this.host._physicalSel=null,this.host._physicalDrag=null,this.host._physicalRotate=null,this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this.host._openingDialog=null,this._rszResetController(),this.host._decorDraft=null,this.host._decorMove=null,this.host._dtDrag=null,this.host._bdDrag=null}_stagePointerCancel(t){if(clearTimeout(this.host._kioskHoldTimer),this.host._swipeStart?.id===t.pointerId&&(this.host._swipeStart=null),this.host._physicalDrag?.pid===t.pointerId||this.host._physicalRotate?.pid===t.pointerId)return void this._cancelPhysicalGesture();if(this.host._decorDraft?.pid===t.pointerId)return this.host._decorDraft=null,void this.host.requestUpdate();if(this.host._decorMove?.pid===t.pointerId||this.host._dtDrag?.pid===t.pointerId||this.host._bdDrag?.pid===t.pointerId)return void this._cancelDecorGesture();"opening"===this.host._tool?(this.host._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this.host._tool&&this._clearPlanSnapHover();const e=!!this.host._pinchStart||!!this.host._panStart;this.host._pointers.delete(t.pointerId),this.host._pointers.size<2&&(this.host._pinchStart=null),0===this.host._pointers.size&&(this.host._panStart=null,this.host._panLock=null),e&&0===this.host._pointers.size&&this.host.requestUpdate()}_applyGeometryState(t,e=!1){if(!this.host._canCommitSpace(t.spaceId))return!1;const s=this._geometrySnapshot(t.spaceId);if(!s||!this._restoreGeometryStateLocal(t))return!1;const i=this.host._serverCfg,o=jt(s)!==jt(t);if(o){let o=!1;try{const s=i?this.host._checkSpacePhysicalGeometry(i,t.spaceId):null;o=!!s?.ok||!(!e||"wall-degraded-extra"!==s?.reason)}catch{o=!1}if(!o)return this._restoreGeometryStateLocal(s),this.host._showToast(this.host._t("toast.geometry_unsafe")),!1}let a;try{a=kr(i).config}catch(t){return this._restoreGeometryStateLocal(s),this._showWallModelMigrationBlocked(t),!1}if(o){let o=!1;try{const s=a?this.host._checkSpacePhysicalGeometry(a,t.spaceId):null;o=!!s?.ok||!(!e||"wall-degraded-extra"!==s?.reason)}catch{o=!1}if(!o)return this._restoreGeometryStateLocal(s),this.host._showToast(this.host._t("toast.geometry_unsafe")),!1;Mr(i,a);const n=i?.spaces.find(e=>e.id===t.spaceId),r=this.host._pendingPhysicalWrites.get(t.spaceId);this.host._pendingPhysicalWrites.set(t.spaceId,{before:r?.before||s,fingerprint:jt(n)})}else Mr(i,a);return this._clearGeometryGesture(),this.host._space!==t.spaceId&&(this.host._commitSpace(t.spaceId),this.host._saveNav(),this.host._restoreZoom()),this.host._modelCache=null,this.host._frame=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this._saveConfig(),this.host.requestUpdate(),!0}_roomAt(t){return this.host._spaceModel()?.rooms.find(e=>{const s=R(e);return!!s&&qt(t,s)})}_overlapRoom(t){return this.host._spaceModel()?.rooms.find(e=>{const s=R(e);return!!s&&$(t,s)})}_pointInRoom(t,e){return e.poly?Ut(t,e.poly):null!=e.x&&t[0]>=e.x&&t[0]<=e.x+e.w&&t[1]>=e.y&&t[1]<=e.y+e.h}_contourSelfIntersects(t){if(!po(t))return!0;const e=t.length,s=.001;for(let i=0;i=500)return this.host._showToast(this.host._t("toast.physical_limit")),!1;const t=this.host._curSpaceCfg;return!(!this.host._activeDraftId&&(t?.room_drafts||[]).length>=200||this._draftSegmentCount(t)>=2e3||(t?.partitions||[]).length+this.host._path.length>sh)||(this.host._showToast(this.host._t("toast.physical_limit")),!1)}_markupClick(t){if(this.host._vacFit)return;if(!this.host._markup)return;const e=this.host._spaceModel();if(!e)return void this._clearGeometryGesture();if(this.host._suppressClick)return;if(this.host._drag||this.host._rlResize)return;const s=t.composedPath?.()||[];if(s.some(t=>t?.classList?.contains?.("roomlabel")||t?.classList?.contains?.("rlhandle")))return;if(s.some(t=>t?.classList?.contains?.("physical-hit")))return;const i=this._svgPoint(t);if("select"===this.host._tool)return void(this.host._physicalSel=null);if("resize"===this.host._tool){if(this.host._resize.dragging||s.some(t=>t?.classList?.contains?.("rszhandle")))return;const t=[...e.rooms].reverse().find(t=>this._pointInRoom(i,t));return this.host._resize.selectRoom(t?.id||null),void this.host.requestUpdate()}if("delroom"===this.host._tool)return void this._deleteRoomClick(i);if("opening"===this.host._tool)return void this._openingClick(i);if("merge"===this.host._tool)return void this._mergeClick(i);if("wallthick"===this.host._tool)return void this._wallThickClick(i);if("split"===this.host._tool)return void this._splitClick(i);if("column"===this.host._tool)return void this._columnClick(i);this.host._wallRepairDiagnostic=null;const o=this._resolvePlanDrawPoint(i,t.shiftKey);if(o.ambiguous)return this.host._planSnapHover={contextKey:o.contextKey,candidate:null,conflicts:o.conflicts},this._syncPlanSnapActiveMarker(null),this._syncPlanSnapConflictMarkers(o.conflicts),void this.host._showToast(this.host._t("toast.plan_snap_ambiguous"));let a=o.point;if(t.ctrlKey||t.metaKey){if(t.preventDefault(),this.host._path.length<3)return;a=At(this.host._path[this.host._path.length-1],this.host._path[0])}if(!this.host._path.length){if(!t.shiftKey&&!o.candidate&&this._offerExistingWallFace(i))return;const e=this._draftEndAt(a);return e?(this.host._activeDraftId=e.draft.id,this.host._resumeDraftBySpace[this.host._space]=e.draft.id,this.host._path=e.reverse?[...e.draft.points].reverse().map(t=>[...t]):e.draft.points.map(t=>[...t]),void(this.host._draftSegmentCms=this._adoptDraftCms(this.host._path,e.reverse?[...e.draft.segments].reverse().map(t=>t.cm):e.draft.segments.map(t=>t.cm),e.draft.id))):(this.host._activeDraftId=null,this.host._draftSegmentCms=[],void(this.host._path=[a]))}const n=this.host._path[this.host._path.length-1];if(this._samePt(a,n))return;const r=this._draftEndAt(a,this.host._activeDraftId||void 0);if(r)return void this._mergeDraftEndpoint(r);if(!this._canAppendRoomDraftPoint())return;const h=this.host._drawWallCm;if(null==h)return void this._showPhysicalRange(100);const l=this.host._path.map(t=>[...t]);this.host._path=[...this.host._path,a],this.host._draftSegmentCms=[...this.host._draftSegmentCms,h],this._persistActiveDraftSegment(),this._offerWallFaces(l)}_draftEndAt(t,e){const s=this.host._spaceModel();if(!s)return null;const i=this.host._viewOr(this.host._baseVb()),o=Math.max(.15*this.host._gridPitch,this.host._stageEl?.clientWidth?i.w/this.host._stageEl.clientWidth*12:0);for(const i of s.room_drafts||[]){if(i.id===e)continue;if(i.points.length<2)continue;const s=i.points[0],a=i.points[i.points.length-1];if(Math.hypot(t[0]-a[0],t[1]-a[1])<=o)return{draft:i,reverse:!1};if(Math.hypot(t[0]-s[0],t[1]-s[1])<=o)return{draft:i,reverse:!0}}return null}_mergeDraftEndpoint(t){const e=this.host._curSpaceCfg;if(!e||!this.host._path.length)return;const s=this.host._path.map(t=>[...t]),i=this._wallGraphSources(s),o=Array.isArray(e.room_drafts)?e.room_drafts:[],a=this.host._activeDraftId?o.find(t=>t.id===this.host._activeDraftId):null,n=o.find(e=>e.id===t.draft.id);if(!n)return;const r=t.reverse?t.draft.points.map(t=>[...t]):[...t.draft.points].reverse().map(t=>[...t]),h=t.reverse?(n.segments||[]).map(t=>({...t})):[...n.segments||[]].reverse().map(t=>({...t})),l=this.host._path[this.host._path.length-1],c=this._samePt(l,r[0]),d=c?null:this.host._drawWallCm;if(!c&&null==d)return void this._showPhysicalRange(100);const p=this._draftSegmentsForPath(this.host._path,a,this.host._draftSegmentCms),_=[...this.host._path.map(t=>[...t]),...c?r.slice(1):r],u=[...p,...null==d?[]:[{cm:d}],...h],m=_.length>=4&&this._samePt(_[0],_[_.length-1]),g=_,f=u;if(g.length>500)return void this.host._showToast(this.host._t("toast.physical_limit"));const b=(a?.segments?.length||0)+(n.segments?.length||0);if(this._draftSegmentCount(e)-b+f.length>2e3)return void this.host._showToast(this.host._t("toast.physical_limit"));if(m){const t=g.slice(0,-1);if(this._contourSelfIntersects(t)||k(t)<=1e-6)return void this.host._showToast(this.host._t("toast.contour_cannot_close"));const e=this._overlapRoom(t);if(e)return void this.host._showToast(this.host._t("toast.room_overlap",{name:e.name||""}))}const v=this._geometrySnapshot(),y=this.host._activeDraftId||t.draft.id,$={...a||n,id:y,points:g.map(t=>[t[0]/eh,t[1]/eh]),segments:f};e.room_drafts=o.filter(e=>e.id!==t.draft.id&&(!this.host._activeDraftId||e.id!==this.host._activeDraftId)),e.room_drafts.push($),this.host._activeDraftId=y,this.host._resumeDraftBySpace[this.host._space]=y,this.host._path=g,this.host._draftSegmentCms=this._adoptDraftCms(g,f.map(t=>Number(t.cm)),y),this.host._physicalSel=null,this._commitPhysicalGeometry(this.host._t("history.draft_merge"),v),null!=d&&this._offerWallFaces(s,s.length-1,i)}_adoptDraftCms(t,e,s){const i=Math.max(0,t.length-1),o=Pa(i,e,this.host._drawWallCm,N);return e.length!==i&&console.debug(`[houseplan] draft ${s??"?"}: восстановлено толщин ${i-e.length} (#234)`),o}_draftSegmentsForPath(t,e,s){const i=Array.isArray(e?.points)?e.points.map(t=>[Number(t?.[0])*eh,Number(t?.[1])*eh]):[],o=Array.isArray(e?.segments)?e.segments:[];return Pa(Math.max(0,t.length-1),s,this.host._drawWallCm,N).map((e,s)=>{const a=t[s],n=t[s+1],r=i.findIndex((t,e)=>{if(e+1>=i.length)return!1;const s=i[e+1];return this._samePt(a,t)&&this._samePt(n,s)||this._samePt(a,s)&&this._samePt(n,t)});return{...r>=0?o[r]:{},cm:e}})}_persistActiveDraftSegment(){if(this.host._path.length<2||!this.host._curSpaceCfg)return;const t=this._geometrySnapshot(),e=this.host._curSpaceCfg;e.room_drafts||=[],this.host._activeDraftId||(this.host._activeDraftId="draft-"+Date.now().toString(36)),this.host._resumeDraftBySpace[this.host._space]=this.host._activeDraftId;const s=e.room_drafts.findIndex(t=>t.id===this.host._activeDraftId),i={...s>=0?e.room_drafts[s]:{},id:this.host._activeDraftId,points:this.host._path.map(t=>[t[0]/eh,t[1]/eh]),segments:this._draftSegmentsForPath(this.host._path,s>=0?e.room_drafts[s]:null,this.host._draftSegmentCms)};s>=0?e.room_drafts[s]=i:e.room_drafts.push(i),this._commitPhysicalGeometry(this.host._t("history.draft_segment"),t)}_activeWallSourceKey(t){return`active:${this.host._activeDraftId||"session"}:${t}`}_wallGraphSources(t){const e=this._planStructuralGeometrySnapshot().value.segments.map(t=>({a:t.a,b:t.b,key:`static:${t.key}`}));for(let s=0;s+1t.key===s);if(i>=0){const[t]=this.host._wallFaceGraphCache.splice(i,1);return this.host._wallFaceGraphCache.push(t),t.value}const o=Za(t,e);return this.host._wallFaceGraphCache.push({key:s,value:o}),this.host._wallFaceGraphCache.length>4&&this.host._wallFaceGraphCache.shift(),o}_offerWallFaces(t,e=this.host._path.length-2,s){if(this.host._path.length<2||this.host._wallFaceBatch||this.host._roomDialog)return;const i=this.host._spaceModel();if(!i)return;const o=this._activeWallSourceKey(e),a=2e-4*this.host._gridPitch;let n,r;try{const e=s||this._wallGraphSources(t);r=this._wallGraphSources(this.host._path),n=function(t,e,s){const i=new Set(t.faces.map(t=>t.key));return e.faces.filter(t=>!i.has(t.key)&&t.sourceKeys.includes(s))}(this._wallFaceGraph(e,a),this._wallFaceGraph(r,a),o)}catch{return}if(!n.length){const t=dn(r,{requiredSourceKey:o,maxDistance:j(2,this.host._cellCm,this.host._gridPitch),gridStep:this.host._gridPitch,epsilon:a});return"ambiguous"===t.kind?(this.host._wallRepairDiagnostic=t.proposals[0]||null,void this.host._showToast(this.host._t(0===this.host._drawWallCm?"toast.zero_wall_ambiguous":"toast.wall_repair_ambiguous"))):void("repair"!==t.kind||this._overlapRoom(t.face.ring)||this._beginWallFaceBatch([{...t.face,repair:t.proposal}]))}for(const t of i.rooms){const e=R(t);if(!t.id||!e)continue;const s=Kt(e,this.host._path,.02*this.host._gridPitch);if(!s)continue;const[i,o]=s,a=k(i)>=k(o)?i:o,r=a===i?o:i,h=[...n].sort((t,e)=>Math.abs(t.area-k(r))-Math.abs(e.area-k(r))||t.key.localeCompare(e.key))[0];if(!h)return;return void this._beginWallFaceBatch([{...h,ring:r.map(t=>[t[0],t[1]]),split:{roomId:t.id,mainPoly:a,newPoly:r},consumeAllActive:!0}])}const h=n.filter(t=>!(t.ring.length<3||this._contourSelfIntersects(t.ring))&&!this._overlapRoom(t.ring));h.length&&this._beginWallFaceBatch(h)}_beginWallFaceBatch(t){this.host._wallRepairDiagnostic=null,this.host._wallFaceBatch={candidates:[...t].sort((t,e)=>t.area-e.area||t.key.localeCompare(e.key)),index:0,decisions:[],activePath:this.host._path.map(t=>[...t]),activeCms:[...this.host._draftSegmentCms],activeDraftId:this.host._activeDraftId},this._clearPlanSnapHover(),this.host._nameSel="",this.host._areaSel="",this._resetRoomDialogFields(),this.host._roomDialog=!0}_offerExistingWallFace(t){if(this.host._path.length||this.host._wallFaceBatch||this.host._roomDialog)return!1;const e=2e-4*this.host._gridPitch;try{let s,i=Qa(this._wallFaceGraph(this._wallGraphSources([]),e),t,e);if(!i){const o=dn(this._wallGraphSources([]),{point:t,maxDistance:j(2,this.host._cellCm,this.host._gridPitch),gridStep:this.host._gridPitch,epsilon:e});if("ambiguous"===o.kind)return this.host._wallRepairDiagnostic=o.proposals[0]||null,this.host._showToast(this.host._t(0===this.host._drawWallCm?"toast.zero_wall_ambiguous":"toast.wall_repair_ambiguous")),!0;if("repair"===o.kind)i=o.face,s=o.proposal;else if("none"===o.kind){const s=dn(this._wallGraphSources([]),{point:t,maxDistance:this._cssPxToRender(12),gridStep:this.host._gridPitch,epsilon:e});if("repair"===s.kind)return this.host._wallRepairDiagnostic=s.proposal,this.host._showToast(this.host._t("toast.wall_repair_too_large")),!0}}return!(!i||i.ring.length<3||this._contourSelfIntersects(i.ring)||this._overlapRoom(i.ring))&&(this._beginWallFaceBatch([{...i,existing:!s,repair:s}]),!0)}catch{return!1}}_columnClick(t){const e=this._snap(t),s=this.host._drawWallCm;if(null==s)return void this._showPhysicalRange(vt,1);if(!this.host._curSpaceCfg||this._limitReached("column"))return;const i=this.host._spaceModel();if(!i)return;const o={id:"column-"+Date.now().toString(36),shape:"square",center:e,cm:wt(s),angle:0},a=(i.wall_columns||[]).find(t=>yt(t,o,.02*this.host._gridPitch));if(a)return clearTimeout(this.host._duplicateColumnTimer),this.host._duplicateColumnId=a.id,this.host._duplicateColumnTimer=window.setTimeout(()=>{this.host._duplicateColumnId=null},900),void this.host._showToast(this.host._t("toast.column_duplicate"));const n=this._geometrySnapshot(),r=this.host._curSpaceCfg;r.wall_columns||=[],r.wall_columns.push({...o,center:[e[0]/eh,e[1]/eh]}),this._commitPhysicalGeometry(this.host._t("history.column_add"),n)}_openPhysicalDialog(t,e,s){const i=this.host._spaceModel();if(i)if("partition"===t){const s=i.partitions.find(t=>t.id===e);s&&(this.host._physicalDialog={kind:t,id:e,cm:Tt(s.cm,this.host._imperial),length:this.host._fmtLen(s.a,s.b)})}else if("column"===t){const s=i.wall_columns.find(t=>t.id===e);s&&(this.host._physicalDialog={kind:t,id:e,cm:Tt(s.cm,this.host._imperial),shape:s.shape,angle:this.host._angleField("square"===s.shape?Nt(s.angle):0)})}else{const o=i.room_drafts.find(t=>t.id===e),a=Math.max(0,Math.min(o?.segments.length?o.segments.length-1:0,s||0));o?.segments[a]&&(this.host._physicalDialog={kind:t,id:e,segment:a,cm:Tt(o.segments[a].cm,this.host._imperial),length:this.host._fmtLen(o.points[a],o.points[a+1])})}}_physicalDown(t,e,s){const i=this.host._spaceModel();if(!i)return;t.stopPropagation(),ih(t);const o=this._svgPoint(t),a=[];for(const t of[...i.wall_columns].reverse())Vt(o,Jt(t,this.host._cellCm,this.host._gridPitch))&&a.push({kind:"column",id:t.id});for(const t of[...i.partitions].reverse()){const e=Yt(t.a,t.b,t.cm,this.host._cellCm,this.host._gridPitch);e&&Vt(o,e)&&a.push({kind:"partition",id:t.id})}a.some(t=>t.kind===e&&t.id===s)||a.unshift({kind:e,id:s});const n=a.map(t=>`${t.kind}:${t.id}`).sort().join("|"),r=performance.now(),h=this.host._physicalPickCycle,l=a.length>1&&h?.signature===n&&r-h.at>380&&r-h.at<=1200&&Math.hypot(t.clientX-h.x,t.clientY-h.y)<=10?(h.index+1)%a.length:Math.max(0,a.findIndex(t=>t.kind===e&&t.id===s));this.host._physicalPickCycle={signature:n,index:l,x:t.clientX,y:t.clientY,at:r},e=a[l].kind,s=a[l].id;const c="partition"===e?i.partitions.find(t=>t.id===s):i.wall_columns.find(t=>t.id===s);c&&(this.host._physicalSel={kind:e,id:s},this.host._physicalDrag={pid:t.pointerId,kind:e,id:s,start:this._svgPoint(t),startClient:[t.clientX,t.clientY],before:this._geometrySnapshot(),moved:!1,base:JSON.parse(JSON.stringify(c)),delta:[0,0]})}_clampPhysicalDelta(t,e,s){const i="partition"===t?[e.a,e.b]:[e.center],o=i.map(t=>t[0]),a=i.map(t=>t[1]);return[Math.max(-Xt*eh-Math.min(...o),Math.min(Xt*eh-Math.max(...o),s[0])),Math.max(-Xt*eh-Math.min(...a),Math.min(Xt*eh-Math.max(...a),s[1]))]}_physicalMove(t){const e=this.host._physicalDrag;if(!e||e.pid!==t.pointerId)return;t.stopPropagation();const s=this._svgPoint(t),i="partition"===e.kind?e.base.a:e.base.center,o=this._snap([i[0]+s[0]-e.start[0],i[1]+s[1]-e.start[1]]),a=this._clampPhysicalDelta(e.kind,e.base,[o[0]-i[0],o[1]-i[1]]);this.host._physicalDrag={...e,delta:a,moved:e.moved||Math.hypot(t.clientX-e.startClient[0],t.clientY-e.startClient[1])>=5}}_physicalUp(t){const e=this.host._physicalDrag;if(!e||e.pid!==t.pointerId)return;if(t.stopPropagation(),this.host._physicalDrag=null,!e.moved)return void this._registerPhysicalTap(e.kind,e.id);const s=this.host._spaceModel();if(!this.host._curSpaceCfg||!s)return;const i=this.host._curSpaceCfg;if("partition"===e.kind){const t=(i.partitions||[]).find(t=>t.id===e.id),s=e.base;if(t){const o={...s,a:[s.a[0]+e.delta[0],s.a[1]+e.delta[1]],b:[s.b[0]+e.delta[0],s.b[1]+e.delta[1]]};t.a=[o.a[0]/eh,o.a[1]/eh],t.b=[o.b[0]/eh,o.b[1]/eh];for(const t of i.openings||[]){if("partition"!==t.host?.kind||t.host.id!==e.id)continue;const s=z(t,[o],eh,this.host._cellCm,this.host._gridPitch).resolved;s&&Object.assign(t,F(t,s,eh))}}}else{const t=(i.wall_columns||[]).find(t=>t.id===e.id),o=e.base,a={...o,center:[o.center[0]+e.delta[0],o.center[1]+e.delta[1]]};if(s.wall_columns.some(t=>t.id!==e.id&&yt(t,a,.02*this.host._gridPitch)))return void this.host._showToast(this.host._t("toast.column_duplicate"));t&&(t.center=[(o.center[0]+e.delta[0])/eh,(o.center[1]+e.delta[1])/eh])}this._commitPhysicalGeometry(this.host._t("history.physical_move"),e.before)}_registerPhysicalTap(t,e,s){const i=performance.now(),o=this.host._physicalLastTap?.kind===t&&this.host._physicalLastTap.id===e&&this.host._physicalLastTap.segment===s&&i-this.host._physicalLastTap.at<=360;this.host._physicalLastTap={kind:t,id:e,segment:s,at:i},o&&(this.host._physicalLastTap=null,this._openPhysicalDialog(t,e,s))}_cancelPhysicalGesture(){this.host._physicalDrag=null,this.host._physicalRotate=null,this.host.requestUpdate()}_physicalRotateDown(t,e){if("square"!==e.shape||!this.host._spaceModel())return;t.preventDefault(),t.stopPropagation(),ih(t);const s=this._svgPoint(t);this.host._physicalSel={kind:"column",id:e.id},this.host._physicalRotate={pid:t.pointerId,id:e.id,center:[...e.center],startAngle:180*Math.atan2(s[1]-e.center[1],s[0]-e.center[0])/Math.PI,baseAngle:Nt(e.angle),angle:Nt(e.angle),before:this._geometrySnapshot(),moved:!1}}_physicalRotateMove(t){const e=this.host._physicalRotate;if(!e||e.pid!==t.pointerId)return;t.preventDefault(),t.stopPropagation();const s=this._svgPoint(t),i=180*Math.atan2(s[1]-e.center[1],s[0]-e.center[0])/Math.PI,o=e.baseAngle+i-e.startAngle,a=Nt(t.shiftKey?o:5*Math.round(o/5));this.host._physicalRotate={...e,angle:a,moved:e.moved||Math.abs(o-e.baseAngle)>=.5}}_physicalRotateUp(t){const e=this.host._physicalRotate;if(!e||e.pid!==t.pointerId)return;t.preventDefault(),t.stopPropagation(),this.host._physicalRotate=null;const s=this.host._spaceModel();if(!e.moved||!this.host._curSpaceCfg||!s)return;const i=s.wall_columns.find(t=>t.id===e.id);if(!i||"square"!==i.shape)return;const o={...i,angle:e.angle};if(s.wall_columns.some(t=>t.id!==e.id&&yt(t,o,.02*this.host._gridPitch)))return void this.host._showToast(this.host._t("toast.column_duplicate"));const a=this.host._curSpaceCfg.wall_columns?.find(t=>t.id===e.id);a&&(a.angle=e.angle,this._commitPhysicalGeometry(this.host._t("history.physical_edit"),e.before))}_rszRooms(){const t=[],e=this.host._spaceModel();if(!e)return t;for(const s of e.rooms){const e=s.id?R(s):null;e&&t.push({id:s.id,poly:e,wall_ids:Array.isArray(s.wall_ids)?[...s.wall_ids]:void 0})}return s=t,i=Math.max(1e-12,1e-12*this.host._gridPitch),s.map(t=>{if(!Array.isArray(t.wall_ids)||t.wall_ids.length!==t.poly.length)return{...t,poly:t.poly.map(t=>[...t])};const e=t.poly.map(t=>[...t]);let s=!0;for(;s&&e.length>3;){s=!1;for(let t=0;t0){e.splice(t,1),s=!0;break}}}return{...t,poly:e}});var s,i}_rszOpenings(){return this.host._openingsR.map(t=>({id:t.id,x:t.rx,y:t.ry,length:t.rlen,hosted:!!t.host,angle:t.angle,type:t.type}))}_rszObstacles(){const t=this.host._spaceModel();if(!t)return[];const e=[];for(const s of t.partitions||[])e.push({kind:"segment",a:[...s.a],b:[...s.b],half:j(s.cm,this.host._cellCm,this.host._gridPitch)/2});for(const s of t.room_drafts||[])for(let t=0;t+1Array.isArray(t.a)&&Array.isArray(t.b)&&t.a.length>=2&&t.b.length>=2).map(t=>({wall:t,a:[t.a[0]*eh,t.a[1]*this.host._spaceH],b:[t.b[0]*eh,t.b[1]*this.host._spaceH]})),o=Math.abs(t[0]-e[0])<=.05*this.host._gridPitch?"v":Math.abs(t[1]-e[1])<=.05*this.host._gridPitch?"h":null,a=i.filter(s=>!!o&&("h"===o?!(Math.abs(s.a[1]-t[1])>.05*this.host._gridPitch||Math.abs(s.b[1]-t[1])>.05*this.host._gridPitch)&&Math.min(Math.max(t[0],e[0]),Math.max(s.a[0],s.b[0]))-Math.max(Math.min(t[0],e[0]),Math.min(s.a[0],s.b[0]))>.05*this.host._gridPitch:!(Math.abs(s.a[0]-t[0])>.05*this.host._gridPitch||Math.abs(s.b[0]-t[0])>.05*this.host._gridPitch)&&Math.min(Math.max(t[1],e[1]),Math.max(s.a[1],s.b[1]))-Math.max(Math.min(t[1],e[1]),Math.min(s.a[1],s.b[1]))>.05*this.host._gridPitch)),n=new Set(a.map(t=>Number(t.wall.cm)).filter(t=>t>0));return{minDim:this.host._cmToUnits(30),eps:.05*this.host._gridPitch,step:this.host._gridPitch,movingHalf:s>0?j(s,this.host._cellCm,this.host._gridPitch)/2:0,obstacles:this._rszObstacles(),thicknessConflict:n.size>1}}_rszResolution(t,e,s){const i=this.host._resize.snapshotIdentity||s||this._rszSnapshot(),o=`${this.host._space}|${this.host._cellCm}|${this.host._gridPitch}|${i}`,a=`${t}:${e}`;return this.host._resize.resolve(o,a,()=>{const s=[...this.host._resize.rooms||this._rszRooms()],i=s.find(e=>e.id===t),o=i?.poly?.[e]||[0,0],a=i?.poly?.[(e+1)%(i?.poly?.length||1)]||[0,0];return function(t,e,s,i,o){const{eps:a}=o,n=t.find(t=>t.id===s);if(!n||i<0||i>=(n.poly?.length||0)||n.poly.length<4||!po(n.poly))return{enabled:!1,reason:"invalid-geometry"};const r=n.poly[i],h=n.poly[(i+1)%n.poly.length],l=go(r,h,a);if(!l)return{enabled:!1,reason:"diagonal"};if(!yo(n.poly,i,l,a))return{enabled:!1,reason:"side-angle"};if(o.thicknessConflict)return{enabled:!1,reason:"thickness-conflict"};for(const t of o.obstacles||[])if(ko(t,r,h,o))return{enabled:!1,reason:"duplicate-physical-wall"};const c=ro(oo(h,r)),d=[],p=new Set;let _=!1,u=!1;for(const e of t)if(e.id!==s)for(let t=0;t1||d.length>1)return{enabled:!1,reason:"multiple-rooms"};const m={[s]:i},g=[s];if(1===d.length){const t=d[0];if(!po(t.room.poly))return{enabled:!1,reason:"invalid-geometry"};if(!yo(t.room.poly,t.edge,l,a))return{enabled:!1,reason:"side-angle"};g.push(t.room.id),m[t.room.id]=t.edge}const f=[];for(const t of e)if(!(lo([t.x,t.y],r,h)>2*a)){if(t.hosted||t.length>c+2*a)return{enabled:!1,reason:"opening-conflict"};f.push(t.id)}const b=Object.fromEntries(g.map(e=>[e,t.find(t=>t.id===e).poly.length])),v=[];for(const e of g){const s=t.find(t=>t.id===e),i=m[e],o=(i-1+s.poly.length)%s.poly.length,n=(i+1)%s.poly.length,r=So(t,e,o,1,a),h=So(t,e,n,0,a);if(!r||!h)return{enabled:!1,reason:"partial-shared"};v.push(r,h)}const y={roomId:s,edge:i,a:[...r],b:[...h],n:co(n.poly,i),roomIds:g,edgeByRoom:m,topology:b,movingOpeningIds:f,sideOwnership:v};if(!zo(t,e,y,0,o))return{enabled:!1,reason:"invalid-geometry"};const $=Math.abs(Number(o.step));if(Number.isFinite($)&&$>a){const s=[-$,$];if(!s.some(s=>zo(t,e,y,s,o))){if(!s.some(s=>Po(Io(t,e,y,s),y,a)))return{enabled:!1,reason:"partial-shared"};const i={...o,obstacles:[]};return s.some(s=>zo(t,e,y,s,i))?{enabled:!1,reason:"duplicate-physical-wall"}:e.length&&s.some(e=>zo(t,[],y,e,o))?{enabled:!1,reason:"opening-conflict"}:{enabled:!1,reason:"invalid-geometry"}}}return{enabled:!0,plan:y}}(s,[...this.host._resize.openings||this._rszOpenings()],t,e,this._rszOptsFor(o,a))})}_rszSnapshot(){return JSON.stringify(this._geometrySnapshot()||{spaceId:this.host._space,rooms:[],openings:[],walls:[],open_spans:[]})}_rszResetController(){const t=null!==this.host._resize.preview;this.host._resize.reset(),t&&this.host._cfgEpoch++}_rszProjectPreview(t,e,s,i,o){this.host._rszLimitViolation=null;const a=this.host._serverCfg?.spaces.find(t=>t.id===this.host._space);if(!a||!this.host._serverCfg)return{ok:!1,reason:"missing-context"};const n=JSON.parse(t),r={...a,rooms:n.rooms,openings:n.openings||[]};for(const t of["walls","wall_segments","open_spans","room_drafts","partitions","wall_columns","decor"])void 0!==n[t]?r[t]=n[t]:delete r[t];for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])void 0!==n.plan_transform?.[t]?r[t]=n.plan_transform[t]:delete r[t];const h=this.host._spaceH;for(const[t,s]of Object.entries(e)){const e=r.rooms.find(e=>e.id===t);e&&(e.poly=s.map(t=>[t[0]/eh,t[1]/h]),delete e.x,delete e.y,delete e.w,delete e.h)}for(const[t,e]of Object.entries(s)){const s=(r.openings||[]).find(e=>e.id===t);s&&(s.x=e[0]/eh,s.y=e[1]/h)}const l=[],c=[];for(const t of i){const e=o.find(e=>e.id===t),s=r.rooms.find(e=>e.id===t);if(!e||!s?.poly)continue;const i=s.poly.map(t=>[t[0]*eh,t[1]*h]);if(e.poly.length!==i.length)continue;const a=Array.isArray(e.wall_ids)?e.wall_ids:[];for(let t=0;tt.id===s):null;o&&(o.a=[i[t][0]/eh,i[t][1]/eh],o.b=[i[(t+1)%i.length][0]/eh,i[(t+1)%i.length][1]/eh])}}if(l.length&&Array.isArray(r.walls)&&r.walls.length){const t=Zt(r.walls,l,c,this.host._wallKeyPitch,eh,"fixed-topology");if(t.rejected)return{ok:!1,reason:"wall-metadata"};r.walls=t.walls}const d=[];for(const t of r.rooms||[]){const e=R(t);if(e&&!(e.length<2))for(let t=0;tJSON.stringify([t?.key,t?.cm,t?.a,t?.b]),_=new Map;for(const t of n.walls||[]){const e=p(t);_.set(e,(_.get(e)||0)+1)}const u=[];for(const t of r.walls||[]){const e=p(t),s=_.get(e)||0;s?_.set(e,s-1):u.push(t)}if(Qt(u,d,this.host._wallKeyPitch,eh,n.walls||[]).length)return{ok:!1,reason:"wall-metadata"};const m=this._rszSpaceCandidateGeometry(this.host._space,r);if(!m.ok)return{ok:!1,reason:"physical-geometry"};const g={...this.host._serverCfg,spaces:(this.host._serverCfg?.spaces||[]).map(t=>t?.id===this.host._space?r:t)},f=this._junctionLimitsIntroduced(g,this.host._serverCfg,this.host._space,m.wallGeometry);return f.length?(this.host._rszLimitViolation=f[0],{ok:!1,reason:"junction-limit"}):{ok:!0,value:{preview:{space:this.host._space,sp:r},beforeWalls:n.walls||[],afterWalls:r.walls||[],artifact:m.wallGeometry}}}_rszAcceptPreview(t,e){if(this.host._cfgEpoch++,!t||!e)return;const s=te(e);if(!s)return;const i=`${this.host._space}|${this.host._cfgEpoch}|${t.sp.rooms.length}`;Object.defineProperty(s,"sourceFingerprint",{value:Lt([t.sp,this.host._cellCm,this.host._gridPitch]),enumerable:!1});const o={key:i,value:s};th(this.host._wallUnionPool,i,o,8),this.host._wallUnionCache=o}_rszSpaceCandidateGeometry(t,e){if(!this.host._serverCfg)return{ok:!1,wallGeometry:null};const s={...this.host._serverCfg,spaces:this.host._serverCfg.spaces.map(s=>s.id===t?e:s)};let i=null;try{return{ok:this.host._checkSpacePhysicalGeometry(s,t,t=>{i=t}).ok,wallGeometry:i}}catch{return{ok:!1,wallGeometry:null}}}_rszSpaceCandidateRenderable(t,e){if(!this.host._serverCfg)return!1;try{const s={...this.host._serverCfg,spaces:this.host._serverCfg.spaces.map(s=>s.id===t?e:s)};return this.host._checkSpacePhysicalGeometry(s,t).ok}catch{return!1}}_rszCandidateRenderable(t){return!!t&&t.space===this.host._space&&this._rszSpaceCandidateRenderable(t.space,t.sp)}_rszEdgeDown(t,e,s){if("resize"!==this.host._tool||this.host._resize.dragging)return;t.stopPropagation(),t.preventDefault();const i=this._rszRooms(),o=this._rszResolution(e,s);if(!o.enabled)return void this.host._showToast(this._rszReasonText(o.reason));ih(t);const a=o.plan,n=this._svgPoint(t),r=`${this.host._space}|${this.host._cfgEpoch}|${i.length}`,h=this.host._wallUnionCache?.key===r?this.host._wallUnionCache.value:null,l=this._rszSnapshot();this.host._resize.begin({pointerId:t.pointerId,start:[n[0],n[1]],roomId:e,plan:a,options:this._rszOptsFor(a.a,a.b),rooms:i,openings:this._rszOpenings(),snapshotIdentity:l,before:JSON.parse(l),wallUnionBefore:h})}_rszReasonText(t){return this.host._t(`resize.disabled.${t}`)}_rszDisabledActivate(t,e){t.stopPropagation(),t.preventDefault(),this.host._showToast(this._rszReasonText(e))}_rszDisabledKey(t,e){"Enter"!==t.key&&" "!==t.key||this._rszDisabledActivate(t,e)}_rszMove(t){if(!this.host._resize.ownsPointer(t.pointerId))return;t.stopPropagation();const e=this._svgPoint(t),s=this.host._resize.move({pointerId:t.pointerId,point:[e[0],e[1]],step:this.host._gridPitch,snap:t=>{const e=this._snap(t);return[e[0],e[1]]},project:(t,e,s,i,o)=>this._rszProjectPreview(t,e,s,i,o),publish:(t,e)=>this._rszAcceptPreview(t,e),measure:(t,e)=>this._rszEdgeLabels(t,e)});if("rejected"===s.kind)return s.notify&&this.host._showToast(this.host._rszLimitViolation?`${this.host._t("resize.limit_stopped")} — `+this._junctionLimitLabel(this.host._rszLimitViolation):this.host._t("resize.preview_failed")),void this.host.requestUpdate();"accepted"===s.kind&&this.host.requestUpdate()}_rszUp(t){if(!this.host._resize.ownsPointer(t.pointerId))return;t.stopPropagation();const e=this.host._resize.finish({pointerId:t.pointerId,currentSnapshotIdentity:this._rszSnapshot(),validatePreview:t=>this._rszCandidateRenderable(t)});if("no-op"===e.kind)return this.host._cfgEpoch++,void this.host.requestUpdate();if("rejected"===e.kind)return this.host._cfgEpoch++,this.host._showToast(this.host._t("resize.commit_failed")),void this.host.requestUpdate();const s=e.preview,i=this.host._serverCfg?.spaces.find(t=>t.id===s.space);i&&(i.rooms=s.sp.rooms,i.openings=s.sp.openings,Array.isArray(s.sp.walls)&&(s.sp.walls.length?i.walls=s.sp.walls:delete i.walls),Array.isArray(s.sp.wall_segments)&&(i.wall_segments=s.sp.wall_segments)),this.host._suppressClick=!0,setTimeout(()=>this.host._suppressClick=!1,0),this._commitPhysicalGeometry(this.host._t("history.resize_room"),e.before),this.host.requestUpdate()}_rszCancelDrag(t){const e=this.host._resize.cancel(this._rszSnapshot(),t);if("no-op"!==e.kind){if(this.host._cfgEpoch++,e.restoreWallUnion){const t=this.host._spaceModel();if(t){const s=`${this.host._space}|${this.host._cfgEpoch}|${t.rooms.length}`,i={key:s,value:e.restoreWallUnion};th(this.host._wallUnionPool,s,i,8),this.host._wallUnionCache=i}}this.host.requestUpdate()}}_rszPointerCancel(t){this.host._resize.ownsPointer(t.pointerId)&&(t.stopPropagation(),this._rszCancelDrag(t.pointerId))}_rszEdgeLabels(t,e,s=this.host._resize.rooms){const i=s,o=[],a=t.polys[e.roomId]||i?.find(t=>t.id===e.roomId).poly;if(!a||!i)return o;const n=a.length,r=this._rszInnerSpanCms(e.roomId,a,t.polys);for(const t of function(t,e){const s=t.length;return[(e-1+s)%s,(e+1)%s]}(a,e.edge)){const e=a[t],s=a[(t+1)%n],i=r?.[t];o.push({kind:"length",x:(e[0]+s[0])/2,y:(e[1]+s[1])/2,text:null==i?this.host._fmtLen(e,s):ee(i,"mi"===this.host.hass?.config?.unit_system?.length),edge:{a:[e[0],e[1]],b:[s[0],s[1]]}})}const h="mi"===this.host.hass?.config?.unit_system?.length,l=e.roomIds,c=this.host._spaceWalls,d=this.host._physicalBodiesR(),p=this.host._baseVb(),_=this.host._view&&this.host._view.w>0&&this.host._view.h>0?this.host._view:{x:p[0],y:p[1],w:p[2],h:p[3]},[u,m]=this.host._lastValidStageSize||[_.w,_.h],g={..._,stageWidth:Math.max(1,u),stageHeight:Math.max(1,m)},f=this.host._spaceModel(),b=this.host._config?.icon_size??2.5,v=f?se(b>8?2.5:b,f,_.w,this.host._kiosk?this.host._kioskScale.icon:1)*g.stageWidth/100:24,y=Math.max(10,.77*v),$=this.host._t("room.settings_short"),w=y*(1.457+.66*Math.max(1,$.length)*.42);for(const s of l){const a=t.polys[s]||i.find(t=>t.id===s).poly,n=c.length&&f&&this.host._innerRoomContour(f,s)||a,r=d.length?ie(oe(n,d))*Math.pow(this.host._cellCm/this.host._gridPitch,2)/1e4:ae(n,this.host._gridPitch,this.host._cellCm),l=ne(r,h),p=Bo({poly:a,edge:e.edgeByRoom[s],text:l,view:g,gearCenter:re(a),gearWidthPx:w,gearHeightPx:y});o.push({kind:"area",roomId:s,x:p.anchor[0],y:p.anchor[1],text:l,placement:p})}return o}_rszInnerSpanCms(t,e,s){const i=Object.keys(s).length?Object.entries(s).map(([t,e])=>({id:t,poly:e})):this.host._spaceModel()?.rooms;if(!i?.length)return null;const o=this.host._spaceWalls;if(!o.length)return null;const a=this.host._openCuts(),n=he(i,t,o,a,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,eh);if(!n||n.length!==e.length)return null;const r=this.host._cellCm/this.host._gridPitch;return e.map((t,s)=>le(e,s,n)*r)}_renderResizeMeasurements(){const t=this.host._resize.liveLabels;if(!t?.length)return a;const e=t.filter(t=>"length"===t.kind),s=t.filter(t=>"area"===t.kind);return ce``}_renderResizeLayer(t){const e=Math.max(.013*t.w,5),s=e/2,i=t=>t.toFixed(1),o=`M ${i(-.7*s)} 0 H ${i(.7*s)} M 0 ${i(-.22*s)} V ${i(-s)} M ${i(-.32*s)} ${i(-.6*s)} L 0 ${i(-s)} L ${i(.32*s)} ${i(-.6*s)} M 0 ${i(.22*s)} V ${i(s)} M ${i(-.32*s)} ${i(.6*s)} L 0 ${i(s)} L ${i(.32*s)} ${i(.6*s)}`,a=[],n=this._rszRooms(),r=this.host._resize.snapshotIdentity||this._rszSnapshot();for(const t of n)for(let s=0;sthis._rszEdgeDown(e,t.id,s)} + @pointermove=${t=>this._rszMove(t)} + @pointerup=${t=>this._rszUp(t)} + @pointercancel=${t=>this._rszPointerCancel(t)} + @lostpointercapture=${t=>this._rszPointerCancel(t)} + @click=${_?t=>this._rszDisabledActivate(t,p.reason):null} + @keydown=${_?t=>this._rszDisabledKey(t,p.reason):null}> + ${u} + `),a.push(ce``)}return ce`${a}`}_partitionOpeningCuts(t=this.host._spaceModel(),e=()=>!0){if(!t)return[];const s=this.host._curSpaceCfg?.id===t.id?this.host._curSpaceCfg:null,i=de(s,t,this.host._cellCm,this.host._gridPitch,eh);return pe(i,e)}_decorSnapGeometry(t){const e=this.host._spaceModel();if(!e)return{points:[],segments:[]};const s=t||"",i=this.host._decorSnapCache;if(i&&i.epoch===this.host._cfgEpoch&&i.space===this.host._space&&i.height===this.host._decorH&&i.exclude===s)return i.geometry;const o=[];for(const e of this.host._decorList)if(e.id!==t)if("line"===e.kind){const t=[e.x1*eh,e.y1*this.host._decorH],s=[e.x2*eh,e.y2*this.host._decorH];o.push({points:[t,s,[(t[0]+s[0])/2,(t[1]+s[1])/2]],segments:[{a:t,b:s}]})}else if("text"===e.kind)o.push({points:[[e.x*eh,e.y*this.host._decorH]],segments:[]});else{const t=this.host._decorBoxOf(e);t&&o.push(_e(t))}for(const t of e.rooms){const e=R(t);e?.length&&o.push({points:e.flatMap((t,s)=>{const i=e[(s+1)%e.length];return[t,[(t[0]+i[0])/2,(t[1]+i[1])/2]]}),segments:e.map((t,s)=>({a:t,b:e[(s+1)%e.length]}))})}const a=ue(o);return this.host._decorSnapCache={epoch:this.host._cfgEpoch,space:this.host._space,height:this.host._decorH,exclude:s,geometry:a},a}_decorSnap(t,e="mouse",s){const i=this.host._stageEl,o=this.host._viewOr(this.host._baseVb()),a="touch"===e||"pen"===e?14:8,n=i?o.w/Math.max(1,i.clientWidth)*a:this.host._gridPitch;return me(t,this._decorSnapGeometry(s),n,t=>this._snap(t)).point}_replaceDecor(t,e){const s=this.host._curSpaceCfg;s&&(s.decor=this.host._decorList.map(s=>s.id===t?{...s,...e}:s),this.host.requestUpdate())}_cancelDecorGesture(){const t=this.host._decorMove?.before||this.host._dtDrag?.before||this.host._bdDrag?.before,e=t&&this.host._serverCfg?.spaces.find(e=>e.id===t.spaceId);if(t&&e){const s=t=>JSON.parse(JSON.stringify(t));void 0!==t.decor?e.decor=s(t.decor):delete e.decor;for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])delete e[t];Object.assign(e,s(t.plan_transform||{})),this.host._cfgEpoch++}this.host._decorMove=null,this.host._dtDrag=null,this.host._bdDrag=null,this.host.requestUpdate()}_decorPointerDown(t){const e=this.host._decorTool;if("select"===e||"erase"===e?t.target.closest?.(".dshape"):null)return!0;if("line"===e||"rect"===e||"ellipse"===e){t.preventDefault();const s=this._decorSnap(this._svgPoint(t),t.pointerType);return this.host._decorDraft={kind:e,a:s,b:s,pid:t.pointerId},ih(t),!0}if("text"===e){const e=this._decorSnap(this._svgPoint(t),t.pointerType);return this.host._decorTextDialog={x:fe(e[0]/eh),y:fe(e[1]/this.host._decorH),text:"",color:this.host._decorStyle.color,opacity:this.host._decorStyle.opacity,angle:"0",sizeCm:ge(ct,this.host._cellCm,this.host._gridPitch)},this.host._decorTextSelection={start:0,end:0},!0}if("furniture"===e)return!!this.host._furnPalette&&(t.preventDefault(),this._furnPlace(this._svgPoint(t),t.shiftKey),!0);if("select"===e&&(this.host._decorSel=null),this.host._bdMovable){const e=this.host._bdRect,s=this._svgPoint(t),i=e.x+e.w/2,o=e.y+e.h/2,a=-be(e.angle)*Math.PI/180,n=s[0]-i,r=s[1]-o,h=[i+n*Math.cos(a)-r*Math.sin(a),o+n*Math.sin(a)+r*Math.cos(a)];if(h[0]>=e.x&&h[0]<=e.x+e.w&&h[1]>=e.y&&h[1]<=e.y+e.h)return t.preventDefault(),this._bdStart(t)}return!1}_decorCommitDraft(){const t=this.host._decorDraft;if(this.host._decorDraft=null,!t)return;const e=.5*this.host._gridPitch;if(!ve(t.kind,t.a,t.b,e))return;const s=eh,i=this.host._decorH,o=this.host._decorStyle,a=this._geometrySnapshot(),n="dc"+Date.now().toString(36)+Math.random().toString(36).slice(2,5),r=fe;let h;if("line"===t.kind)h={id:n,kind:"line",x1:r(t.a[0]/s),y1:r(t.a[1]/i),x2:r(t.b[0]/s),y2:r(t.b[1]/i),...ye(o,!1)};else{const e=r(Math.min(t.a[0],t.b[0])/s),a=r(Math.min(t.a[1],t.b[1])/i),l=Math.abs(t.b[0]-t.a[0])/s,c=Math.abs(t.b[1]-t.a[1])/i;h={id:n,kind:t.kind,x:e,y:a,w:l,h:c,...ye(o,!0)}}this.host._curSpaceCfg.decor=[...this.host._decorList,h],this.host._decorSel=n,this._recordGeometry(this.host._t("history.decor_add"),a),this._saveConfig(),this.host.requestUpdate()}_decorShapeDown(t,e){if("decor"!==this.host._mode)return;const s=this.host._decorTool;if("text"===s){if("text"!==e.kind)return;return t.stopPropagation(),t.preventDefault(),void this._decorOpenText(e)}"select"!==s&&"erase"!==s||(t.stopPropagation(),t.preventDefault(),"erase"!==s?(this.host._decorSel=e.id,this.host._decorMove={id:e.id,start:this._svgPoint(t),orig:JSON.parse(JSON.stringify(e)),pid:t.pointerId,moved:!1,before:this._geometrySnapshot()},ih(t)):this.host._decorEraseConfirm={id:e.id,kind:e.kind})}_decorMoveUpdate(t){const e=this.host._decorMove;if("furniture"===e.orig?.kind)return void this._furnMoveUpdate(t);const s=this._svgPoint(t),i=e.orig,o=("line"===i.kind?i.x1:i.x)*eh,a=("line"===i.kind?i.y1:i.y)*this.host._decorH,n=this._decorSnap([o+(s[0]-e.start[0]),a+(s[1]-e.start[1])],t.pointerType,e.id);let r=(n[0]-o)/eh,h=(n[1]-a)/this.host._decorH;const l=e.orig,c="line"===l.kind?Math.min(l.x1,l.x2):l.x,d="line"===l.kind?Math.min(l.y1,l.y2):l.y,p="line"===l.kind?Math.abs(l.x2-l.x1):l.w||0,_="line"===l.kind?Math.abs(l.y2-l.y1):l.h||0,u=Xt;r=Math.max(-u-c,Math.min(u-c-p,r)),h=Math.max(-u-d,Math.min(u-d-_,h)),(r||h)&&(e.moved=!0);this.host._curSpaceCfg.decor=this.host._decorList.map(t=>{if(t.id!==e.id)return t;const s=e.orig;return"line"===t.kind?{...t,x1:s.x1+r,y1:s.y1+h,x2:s.x2+r,y2:s.y2+h}:{...t,x:s.x+r,y:s.y+h}}),this.host.requestUpdate()}_decorShapeDbl(t,e){"decor"===this.host._mode&&"select"===this.host._decorTool&&(t.preventDefault(),t.stopPropagation(),this.host._decorMove=null,this.host._decorSel=e.id,this._openDecorProperties(e))}_openDecorProperties(t){if("decor"!==this.host._mode||"select"!==this.host._decorTool)return;if("text"===t.kind)return void this._decorOpenText(t);if(!["line","rect","ellipse","furniture"].includes(t.kind))return;const e=this.host._decorResolvedStyle(t),s="line"===t.kind?t:null,i=this.host._decorBoxOf(t);this.host._decorShapeDialog={id:t.id,kind:t.kind,color:e.color,opacity:e.opacity,widthCm:e.widthCm,angle:this.host._angleField(be(s?$e([s.x1*eh,s.y1*this.host._decorH],[s.x2*eh,s.y2*this.host._decorH]):t.angle)),...s?{lengthCm:ge(Math.hypot((s.x2-s.x1)*eh,(s.y2-s.y1)*this.host._decorH),this.host._cellCm,this.host._gridPitch),lineStyle:"dashed"===s.line_style?"dashed":"solid"}:{},...i?{sizeWCm:ge(i.w,this.host._cellCm,this.host._gridPitch),sizeHCm:ge(i.h,this.host._cellCm,this.host._gridPitch)}:{},..."furniture"===t.kind?{symbol:t.symbol}:{},..."rect"===t.kind||"ellipse"===t.kind?{fill:e.fill,fillColor:e.fillColor,fillOpacity:e.fillOpacity}:{}}}_decorOpenText(t){if("text"!==t.kind)return;let e=String(t.text??"");const s=[...e.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!pt(t[1])),i=String(t.unit??"").trim(),o="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,a=s||i?"":_t(t.entity,o),n=!(!String(t.entity??"").trim()||s||a&&!i);if(a&&!n){const t=e.indexOf("{}");e=t>=0?e.slice(0,t)+a+e.slice(t+2):`${e}${e?" ":""}${a}`}this.host._decorTextDialog={id:t.id,x:t.x,y:t.y,text:e,color:h(t.color,this.host._decorStyle.color),opacity:we(t.opacity,this.host._decorStyle.opacity),angle:this.host._angleField(t.angle),sizeCm:this.host._decorTextSizeCm(t),pickerEntity:t.entity||"",preserveLegacy:n||void 0},this.host._decorTextSelection={start:e.length,end:e.length}}_decorRememberTextSelection(t){this.host._decorTextSelection={start:t.selectionStart??t.value.length,end:t.selectionEnd??t.value.length}}_decorInsertLiveVariable(t){const e=this.host._decorTextDialog;if(!e)return;const s=_t(e.pickerEntity,t);if(!s)return;const i=e.text,o=Math.max(0,Math.min(i.length,this.host._decorTextSelection.start)),a=Math.max(o,Math.min(i.length,this.host._decorTextSelection.end));if(i.length-(a-o)+s.length>200)return;const n=i.slice(0,o)+s+i.slice(a),r=o+s.length;this.host._decorTextSelection={start:r,end:r},this.host._decorTextDialog={...e,text:n,preserveLegacy:void 0},this.host.updateComplete.then(()=>{const t=this.host.renderRoot.querySelector("textarea.dtarea");t&&(t.focus(),t.setSelectionRange(r,r))})}_decorSaveText(){const t=this.host._decorTextDialog,e=String(t?.text??"").replace(/\r\n?/g,"\n").trim();if(!t||!e)return void(this.host._decorTextDialog=null);const s=this._geometrySnapshot(),i=this.host._curSpaceCfg,o={color:t.color,opacity:we(t.opacity),size_cm:Number(Math.max(.1,Math.min(Xr,t.sizeCm)).toFixed(4)),...be(t.angle)?{angle:be(t.angle)}:{}};if(t.id)i.decor=this.host._decorList.map(s=>{if(s.id!==t.id)return s;if("text"!==s.kind)return s;if(t.preserveLegacy){const{angle:t,size:i,scale:a,...n}=s;return{...n,text:e,...o}}const{entity:i,attr:a,unit:n,...r}=s,{angle:h,size:l,scale:c,...d}=r;return{...d,text:e,...o}});else{const s="dc"+Date.now().toString(36)+Math.random().toString(36).slice(2,5);i.decor=[...this.host._decorList,{id:s,kind:"text",x:t.x,y:t.y,text:e,...o}],this.host._decorSel=s}this.host._decorTextDialog=null,this._recordGeometry(this.host._t(t.id?"history.decor_edit":"history.decor_add"),s),this._saveConfig(),this.host.requestUpdate()}_decorSaveShape(){const t=this.host._decorShapeDialog;if(!t)return;const e=this._geometrySnapshot(),s={color:t.color,opacity:we(t.opacity),widthCm:Math.max(.1,Math.min(100,Number(t.widthCm)||.1)),fill:!!t.fill,fillColor:t.fillColor||t.color,fillOpacity:we(t.fillOpacity,.25)};this.host._curSpaceCfg.decor=this.host._decorList.map(e=>{if(e.id!==t.id)return e;const i="rect"===t.kind||"ellipse"===t.kind,o=ye(s,i);if("line"===e.kind){const s=(e.x1+e.x2)/2*eh,i=(e.y1+e.y2)/2*this.host._decorH,a=ke(Math.max(.1,Number(t.lengthCm)||.1),this.host._cellCm,this.host._gridPitch),n=be(t.angle)*Math.PI/180,r=Math.cos(n)*a/2,h=Math.sin(n)*a/2,l=this._snap([s-r,i-h]),c=this._snap([s+r,i+h]),{width:d,line_style:p,..._}=e;return{..._,...o,x1:fe(l[0]/eh),y1:fe(l[1]/this.host._decorH),x2:fe(c[0]/eh),y2:fe(c[1]/this.host._decorH),..."dashed"===t.lineStyle?{line_style:"dashed"}:{}}}if("rect"===e.kind||"ellipse"===e.kind||"furniture"===e.kind){const s=e.w*eh,i=e.h*this.host._decorH,a=Math.max(this.host._gridPitch,zt(ke(Number(t.sizeWCm),this.host._cellCm,this.host._gridPitch),this.host._gridPitch)),n=Math.max(this.host._gridPitch,zt(ke(Number(t.sizeHCm),this.host._cellCm,this.host._gridPitch),this.host._gridPitch)),r=e.x*eh+s/2,h=e.y*this.host._decorH+i/2,l=be(t.angle),c=xe({x:r-a/2,y:h-n/2},l,t=>this._snap(t)),{width:d,angle:p,..._}=e;return{..._,...o,x:fe(c[0]/eh),y:fe(c[1]/this.host._decorH),w:a/eh,h:n/this.host._decorH,..."furniture"===e.kind&&t.symbol?{symbol:t.symbol}:{},...l?{angle:l}:{}}}return e}),this.host._decorStyle={...s,fill:"rect"===t.kind||"ellipse"===t.kind?s.fill:this.host._decorStyle.fill,fillColor:"rect"===t.kind||"ellipse"===t.kind?s.fillColor:this.host._decorStyle.fillColor,fillOpacity:"rect"===t.kind||"ellipse"===t.kind?s.fillOpacity:this.host._decorStyle.fillOpacity},this.host._decorShapeDialog=null,this._recordGeometry(this.host._t("history.decor_edit"),e),this._saveConfig(),this.host.requestUpdate()}_dtPivot(t){return"line"===t.kind?[(t.x1+t.x2)/2*eh,(t.y1+t.y2)/2*this.host._decorH]:"furniture"===t.kind||"rect"===t.kind||"ellipse"===t.kind?[(t.x+t.w/2)*eh,(t.y+t.h/2)*this.host._decorH]:[t.x*eh,t.y*this.host._decorH]}_dtApply(t,e){const s=this.host._curSpaceCfg;s&&(s.decor=this.host._decorList.map(s=>{if(s.id!==t)return s;const i={...s};"text"===s.kind&&void 0!==e.textSizeCm&&(delete i.size,delete i.scale);const o={...i};return void 0!==e.textSizeCm&&(o.size_cm=Number(Math.max(.1,Math.min(Xr,e.textSizeCm)).toFixed(4))),void 0!==e.angle&&(e.angle?o.angle=Number(e.angle.toFixed(2)):delete o.angle),o}),this.host._cfgEpoch++,this.host.requestUpdate())}_dtStart(t,e,s,i){const o=this.host._dtSel;if(!o)return;t.stopPropagation(),t.preventDefault();const[a,n]=this._dtPivot(o),r=this._svgPoint(t),h=this.host._decorBoxOf(o);this.host._dtDrag={id:o.id,kind:e,pid:t.pointerId,ax:a,ay:n,r0:Math.hypot(r[0]-a,r[1]-n),a0:180*Math.atan2(r[1]-n,r[0]-a)/Math.PI,textSizeCm0:"text"===o.kind?this.host._decorTextSizeCm(o):1,angle0:"line"===o.kind?0:Number(o.angle)||0,sgx:s?.[0],sgy:s?.[1],orig:h||void 0,origShape:JSON.parse(JSON.stringify(o)),before:this._geometrySnapshot(),lineEnd:i,moved:!1},ih(t)}_dtMove(t){const e=this.host._dtDrag;if(!e)return;const s=this._svgPoint(t);if(void 0!==e.lineEnd&&"line"===e.origShape.kind){const i=this._decorSnap(s,t.pointerType,e.id),o=fe(i[0]/eh),a=fe(i[1]/this.host._decorH),n=e.origShape,r=0===e.lineEnd?n.x1:n.x2,h=0===e.lineEnd?n.y1:n.y2;return(Math.abs(o-r)>1e-9||Math.abs(a-h)>1e-9)&&(e.moved=!0),void this._replaceDecor(e.id,0===e.lineEnd?{x1:o,y1:a}:{x2:o,y2:a})}if("scale"===e.kind&&e.orig){const i=Me(e.orig,e.sgx??1,e.sgy??1,s[0],s[1],!t.shiftKey,this.host._gridPitch,this.host._gridPitch),o=Math.abs(i.x-e.orig.x)>1e-6||Math.abs(i.y-e.orig.y)>1e-6||Math.abs(i.w-e.orig.w)>1e-6||Math.abs(i.h-e.orig.h)>1e-6;if(!o&&!e.moved)return;return e.moved||=o,void this._decorApplyBox(e.id,i)}if("scale"===e.kind){const t=Math.hypot(s[0]-e.ax,s[1]-e.ay);if(e.r0<1e-6)return;const i=Math.max(.1,Math.min(Xr,e.textSizeCm0*(t/e.r0))),o=Math.abs(i-e.textSizeCm0)>1e-6;if(!o&&!e.moved)return;return e.moved||=o,void this._dtApply(e.id,{textSizeCm:i})}const i=180*Math.atan2(s[1]-e.ay,s[0]-e.ax)/Math.PI;let o=e.angle0+(i-e.a0);t.shiftKey||(o=5*Math.round(o/5)),o=(o%360+360)%360,o>180&&(o-=360);const a=Math.abs(o-e.angle0)>1e-6;(a||e.moved)&&(e.moved||=a,this._dtApply(e.id,{angle:o}))}_dtUp(){const t=this.host._dtDrag;this.host._dtDrag=null,t?.moved&&(this._recordGeometry(this.host._t("history.decor_transform"),t.before),this._saveConfig()),this.host.requestUpdate()}_dtMeasure(){const t=this.host._dtSel;if(!t)return void(this.host._dtBox&&(this.host._dtBox=null,this.host.requestUpdate()));let e;if("line"===t.kind){const s=t.x1*eh,i=t.y1*this.host._decorH,o=t.x2*eh,a=t.y2*this.host._decorH;e={id:t.id,x:Math.min(s,o),y:Math.min(i,a),w:Math.abs(o-s),h:Math.abs(a-i)}}else if("furniture"===t.kind||"rect"===t.kind||"ellipse"===t.kind)e={id:t.id,x:t.x*eh,y:t.y*this.host._decorH,w:t.w*eh,h:t.h*this.host._decorH};else{const s=this.host.renderRoot.querySelector(`text.dtext[data-id="${t.id}"]`);if(!s||"function"!=typeof s.getBBox)return;let i;try{i=s.getBBox()}catch{return}if(!i||!i.width&&!i.height)return;e={id:t.id,x:i.x,y:i.y,w:i.width,h:i.height}}const s=this.host._dtBox;s&&s.id===e.id&&Math.abs(s.x-e.x)<.01&&Math.abs(s.y-e.y)<.01&&Math.abs(s.w-e.w)<.01&&Math.abs(s.h-e.h)<.01||(this.host._dtBox=e,this.host.requestUpdate())}_deleteDecor(t){if(!this.host._decorList.some(e=>e.id===t))return;const e=this._geometrySnapshot();this.host._curSpaceCfg.decor=this.host._decorList.filter(e=>e.id!==t),this.host._decorSel===t&&(this.host._decorSel=null),this._recordGeometry(this.host._t("history.decor_delete"),e),this._saveConfig(),this.host.requestUpdate()}_decorDeleteSel(){this.host._decorSel&&this._deleteDecor(this.host._decorSel)}_confirmDecorErase(){const t=this.host._decorEraseConfirm;this.host._decorEraseConfirm=null,t&&this._deleteDecor(t.id)}_furnFieldValue(t){return Math.round(100*(this.host._imperial?t/30.48:t/100))/100}_furnFieldToCm(t){return Se(this.host._imperial?30.48*t:100*t)}_furnPick(t){const e=Ce(t);this.host._furnPalette={symbol:t,w:e.w,h:e.h}}_furnPlace(t,e=!1){const s=this.host._furnPalette,i=this.host._curSpaceCfg;if(!s||!i)return;const o=eh,a=this.host._decorH,n=De(Pe(s.w,this.host._cellCm,this.host._gridPitch,o)),r=De(Pe(s.h,this.host._cellCm,this.host._gridPitch,o)),h=this._geometrySnapshot(),l=this._decorSnap(t);let c=l[0],d=l[1],p=0;const _=e?null:Ie(c,d,r*a,this.host._furnWalls,this.host._furnWallReach,this.host._gridPitch);_&&(c=_.cx,d=_.cy,p=_.angle);const u="df"+Date.now().toString(36)+Math.random().toString(36).slice(2,5),m={id:u,kind:"furniture",symbol:s.symbol,x:fe(c/o-n/2),y:fe(d/a-r/2),w:n,h:r,...ye(this.host._decorStyle,!1)};p&&(m.angle=Number(p.toFixed(2))),i.decor=[...this.host._decorList,m],this.host._decorSel=u,this.host._decorTool="select",this.host._furnPalette=null,this.host._furnCategory=null,this._recordGeometry(this.host._t("history.decor_add"),h),this._saveConfig(),this.host.requestUpdate()}_furnMoveUpdate(t){const e=this.host._decorMove;if("furniture"!==e.orig.kind)return;const s=e.orig,i=this.host._curSpaceCfg;if(!i)return;const o=eh,a=this.host._decorH,n=this._svgPoint(t),r=(s.x+s.w/2)*o+(n[0]-e.start[0]),h=(s.y+s.h/2)*a+(n[1]-e.start[1]);let l,c,d=Number(s.angle)||0;const p=t.shiftKey?null:Ie(r,h,s.h*a,this.host._furnWalls,this.host._furnWallReach,this.host._gridPitch);if(p)l=p.cx/o-s.w/2,c=p.cy/a-s.h/2,d=p.angle;else{const i=this._decorSnap([r-s.w/2*o,h-s.h/2*a],t.pointerType,e.id);l=i[0]/o,c=i[1]/a}l=fe(l),c=fe(c),(Math.abs(l-s.x)>1e-9||Math.abs(c-s.y)>1e-9||Math.abs(d-(Number(s.angle)||0))>1e-9)&&(e.moved=!0),i.decor=this.host._decorList.map(t=>{if(t.id!==e.id)return t;const s={...t,x:l,y:c};return d?s.angle=Number(d.toFixed(2)):delete s.angle,s}),this.host.requestUpdate()}_decorApplyBox(t,e){const s=this.host._curSpaceCfg;if(!s)return;const i=eh,o=this.host._decorH;s.decor=this.host._decorList.map(s=>{if(s.id!==t)return s;const a=xe(e,s.angle,t=>this._snap(t));return{...s,x:fe(a[0]/i),y:fe(a[1]/o),w:Math.max(this.host._gridPitch/i,Math.min(2*Xt,e.w/i)),h:Math.max(this.host._gridPitch/o,Math.min(2*Xt,e.h/o))}}),this.host._cfgEpoch++,this.host.requestUpdate()}_renderFurnPalette(){const t=this.host._furnPalette,e=this.host._furnCategory,s=Te.flatMap(t=>Re(t)),i=Wo.filter(t=>s.some(e=>e.category===t.id)),a=i.find(t=>t.id===e)||null,n=a?s.filter(t=>t.category===a.id):[],r=this.host._t(this.host._imperial?"gs.unit_ft":"gs.unit_m");return o`
t.stopPropagation()}> +
+ ${this.host._t("furn.title")} + + +
+
+ ${a?o` + +
+ ${this.host._t(`furn.cat_${a.id}`)} +
+
+ ${n.map(e=>o``)} +
+ `:Te.map(t=>o` +
${this.host._t(`furn.group_${t}`)}
+
+ ${i.filter(e=>e.group===t).map(t=>o``)} +
`)} +
+ ${t?o`
+ + this.host._furnPalette={...t,w:this._furnFieldToCm(Number(e.target.value))}} /> + + this.host._furnPalette={...t,h:this._furnFieldToCm(Number(e.target.value))}} /> + ${this.host._t("furn.place_hint")} +
`:o`
${this.host._t("furn.pick_hint")}
`} +
`}_openBackdropDialog(t){if(!this.host._bdMovable||!this.host._bdRect)return;t?.preventDefault(),t?.stopPropagation(),this.host._bdDrag=null;const e=this.host._bdRect;this.host._backdropDialog={widthCm:ge(e.w,this.host._cellCm,this.host._gridPitch),heightCm:ge(e.h,this.host._cellCm,this.host._gridPitch),angle:this.host._angleField(e.angle)}}_saveBackdropDialog(){const t=this.host._backdropDialog,e=this.host._bdBase,s=this.host._bdRect;if(!t||!e||!s)return;const i=be(t.angle),o=this._geometrySnapshot(),a=Math.min(e.w*lt,Math.max(e.w*ht,zt(ke(t.widthCm,this.host._cellCm,this.host._gridPitch),this.host._gridPitch))),n=Math.min(e.h*lt,Math.max(e.h*ht,zt(ke(t.heightCm,this.host._cellCm,this.host._gridPitch),this.host._gridPitch))),r=s.x+s.w/2,h=s.y+s.h/2,l=xe({x:r-a/2,y:h-n/2},i,t=>this._snap(t));this._bdApply((l[0]-e.x)/eh,(l[1]-e.y)/eh,a/e.w,n/e.h,i),this.host._backdropDialog=null,this._recordGeometry(this.host._t("history.backdrop_transform"),o),this._saveConfig()}_bdApply(t,e,s,i,o){const a=this.host._curSpaceCfg;if(!a)return;a.plan_x=Number(fe(t).toFixed(6)),a.plan_y=Number(fe(e).toFixed(6)),delete a.plan_scale,a.plan_scale_x=Number(Math.min(lt,Math.max(ht,s)).toFixed(6)),a.plan_scale_y=Number(Math.min(lt,Math.max(ht,i)).toFixed(6));const n=be(o);n?a.plan_angle=Number(n.toFixed(2)):delete a.plan_angle,this.host._cfgEpoch++,this.host.requestUpdate()}_bdStart(t,e,s=!1){const i=this.host._bdBase,o=this.host._bdRect;if(!i||!o)return!1;const a=this._svgPoint(t),n=e?e[0]:0,r=e?e[1]:0,h=n>0?o.x:o.x+o.w,l=r>0?o.y:o.y+o.h;return this.host._bdDrag={kind:s?"rotate":e?"scale":"move",pid:t.pointerId,sx:a[0],sy:a[1],base:i,p0:this.host._bdParams,fx:h,fy:l,sgx:n,sgy:r,rect0:{x:o.x,y:o.y,w:o.w,h:o.h,angle:o.angle},before:this._geometrySnapshot(),moved:!1},ih(t),!0}_bdMove(t){const e=this.host._bdDrag;if(!e)return;const s=this._svgPoint(t),i=e.base;if("move"===e.kind){const t=e.rect0.x,o=e.rect0.y,a=this._snap([t+(s[0]-e.sx),o+(s[1]-e.sy)]),n=Math.abs(a[0]-t)>1e-9||Math.abs(a[1]-o)>1e-9;if(!n&&!e.moved)return;return e.moved||=n,void this._bdApply((a[0]-i.x)/eh,(a[1]-i.y)/eh,e.p0.sx,e.p0.sy,e.p0.angle)}if("rotate"===e.kind){const i=e.rect0.x+e.rect0.w/2,o=e.rect0.y+e.rect0.h/2,a=180*Math.atan2(e.sy-o,e.sx-i)/Math.PI;let n=e.p0.angle+(180*Math.atan2(s[1]-o,s[0]-i)/Math.PI-a);t.shiftKey||(n=5*Math.round(n/5)),n=be(n);const r=Math.abs(n-e.p0.angle)>1e-9;if(!r&&!e.moved)return;return e.moved||=r,void this._bdApply(e.p0.dx,e.p0.dy,e.p0.sx,e.p0.sy,n)}const o=Me(e.rect0,e.sgx,e.sgy,s[0],s[1],!t.shiftKey,this.host._gridPitch,Math.min(i.w,i.h)*ht),a=o.w/Math.max(1e-9,i.w),n=o.h/Math.max(1e-9,i.h),r=Math.abs(a-e.p0.sx)>1e-9||Math.abs(n-e.p0.sy)>1e-9||Math.abs(o.x-e.rect0.x)>1e-9||Math.abs(o.y-e.rect0.y)>1e-9;if(!r&&!e.moved)return;e.moved||=r;const h=xe(o,e.p0.angle,t=>this._snap(t));this._bdApply((h[0]-i.x)/eh,(h[1]-i.y)/eh,a,n,e.p0.angle)}_bdReset(){const t=this.host._curSpaceCfg;if(!t)return;const e=this._geometrySnapshot();delete t.plan_x,delete t.plan_y,delete t.plan_scale,delete t.plan_scale_x,delete t.plan_scale_y,delete t.plan_angle,this.host._bdDrag=null,this._recordGeometry(this.host._t("history.backdrop_transform"),e),this._saveConfig(),this.host._showToast(this.host._t("decor.backdrop_reset_done")),this.host.requestUpdate()}_bdUp(){const t=this.host._bdDrag;this.host._bdDrag=null,t?.moved&&(this._recordGeometry(this.host._t("history.backdrop_transform"),t.before),this._saveConfig()),this.host.requestUpdate()}_renderBackdropFrame(t){const e=this.host._bdRect;if(!this.host._bdActive||!e)return a;const s=.02*Math.max(t.w,t.h),i=s/4,o=e.x+e.w/2,n=e.y+e.h/2,r=be(e.angle),h=2.2*s;return ce` + + + {t.stopPropagation(),t.preventDefault(),this._bdStart(t,void 0,!0)}}> + + ${[[-1,-1,"nwse"],[1,-1,"nesw"],[1,1,"nwse"],[-1,1,"nesw"]].map(([t,o,a])=>{const n=t<0?e.x:e.x+e.w,r=o<0?e.y:e.y+e.h;return ce`{e.stopPropagation(),e.preventDefault(),this._bdStart(e,[t,o])}}>`})} + `}_renderEditorGroupLauncher(t){return this.host._editorSecondary.renderGroupLauncher(t,this.host._editorToolbarGroups,this.host._editorSecondaryCopy)}_runEditorContext(t,e){this.host._editorSecondary.runContext(t,this.host._editorSecondaryContextId,e)}_renderEditorGroupModel(t){return this.host._editorSecondary.renderGroupModel(t,this.host._editorSecondaryContextId,this.host._editorSecondaryCopy)}_renderDrawWallControl(){const t="column"===this.host._tool?1:0;return o``}_renderPlanSecondary(){const t=this.host._editorSecondaryContextId,e=this.host._physicalSel;if(e){if(!("partition"===e.kind?!!this.host._curSpaceCfg.partitions?.some(t=>t.id===e.id):"column"===e.kind?!!this.host._curSpaceCfg.wall_columns?.some(t=>t.id===e.id):!!this.host._curSpaceCfg.room_drafts?.some(t=>t.id===e.id)))return null;const s="partition"===e.kind?this.host._t("markup.partition"):"column"===e.kind?this.host._t("markup.column"):this.host._t("markup.add");return{contextId:t,kind:"selection",ariaLabel:this.host._t("editor.context_actions",{object:s}),visibleLabel:s,content:o` + + `}}const s="draw"===this.host._tool||"column"===this.host._tool,i="column"===this.host._tool?"markup.hint_column":"resize"===this.host._tool?"markup.hint_resize":"wallthick"===this.host._tool?"markup.hint_wallthick":null,n="draw"===this.host._tool?this.host._t(this.host._path.length?"markup.hint_points":"markup.hint_start",this.host._path.length?{n:this.host._path.length}:void 0):"";if(!s&&!i&&!n)return null;const r="draw"===this.host._tool&&this.host._path.length>0;return{contextId:t,kind:r?"operation":"tool",ariaLabel:this.host._t("editor.tool_options",{tool:this.host._t("draw"===this.host._tool?"markup.add":"column"===this.host._tool?"markup.column":"resize"===this.host._tool?"markup.resize":"markup.wallthick")}),content:o` + ${s?this._renderDrawWallControl():a} + ${n?o`${n}`:a} + ${i?o`${this.host._t(i)}`:a} + ${"draw"===this.host._tool&&this.host._path.length?o``:a}`}}_renderDecorSecondary(){const t=this.host._editorSecondaryContextId;if("furniture"===this.host._decorTool)return{contextId:t,kind:"palette",ariaLabel:this.host._t("editor.palette",{tool:this.host._t("decor.furniture")}),launcherId:"furniture",dismissPolicy:this.host._furnPalette?"stay-open-on-canvas":"outside",dismiss:()=>{"furniture"===this.host._decorTool&&(this.host._furnPalette=null,this.host._furnCategory=null,this.host._decorTool="select",this.host.requestUpdate())},content:this._renderFurnPalette()};const e=this.host._dtSel;if(e){const s=this.host._t(`decor.${e.kind}`);return{contextId:t,kind:"selection",ariaLabel:this.host._t("editor.context_actions",{object:s}),visibleLabel:s,content:o` + + `}}const s="line"===this.host._decorTool||"rect"===this.host._decorTool||"ellipse"===this.host._decorTool,i="rect"===this.host._decorTool||"ellipse"===this.host._decorTool,n="backdrop"===this.host._decorTool&&!!this.host._bdRect;return s||n?{contextId:t,kind:"tool",ariaLabel:this.host._t("editor.tool_options",{tool:this.host._t(s?`decor.${this.host._decorTool}`:"decor.backdrop")}),content:o` + ${s?o` + this.host._decorStyle={...this.host._decorStyle,...t.detail}}> + + ${i?o` + this.host._decorStyle={...this.host._decorStyle,fillColor:t.detail.color,fillOpacity:t.detail.opacity}}>`:a} + `:a} + ${n?o`${this.host._t("decor.backdrop_hint")}`:a}`}:null}_withBackdropReset(t){if(!this.host._bdMoved||this.host._bdDrag||"palette"===t?.kind)return t;const e=this.host._editorSecondaryContextId,s=o``;return t?{...t,kind:"selection"===t.kind?"mixed":t.kind,content:o`${t.content}${s}`}:{contextId:e,kind:"tool",ariaLabel:this.host._t("editor.tool_options",{tool:this.host._t("decor.backdrop")}),content:s}}_renderEditorSecondary(){if(!this.host._editing)return a;const t=this.host._editorSecondary.activeGroup(this.host._editorToolbarGroups),e=t?this._renderEditorGroupModel(t):"plan"===this.host._mode?this._renderPlanSecondary():"decor"===this.host._mode?this._withBackdropReset(this._renderDecorSecondary()):null;return this.host._editorSecondary.render(e,this.host._editorSecondaryDialogBlocked)}_renderDecorBar(){const t=[["select","mdi:cursor-default-outline","decor.select"],...this.host._bdRect?[["backdrop","mdi:image-move","decor.backdrop"]]:[],["line","mdi:vector-line","decor.line"],["rect","mdi:rectangle-outline","decor.rect"],["ellipse","mdi:ellipse-outline","decor.ellipse"],["text","mdi:format-text","decor.text"],["furniture","mdi:sofa-outline","decor.furniture"],["erase","mdi:eraser","decor.erase"]],e=this.host._geometryHistory.undoName,s=this.host._geometryHistory.redoName;return o`
+
+ ${t.map(([t,e,s])=>o``)} + ${this.host._editorToolbarGroups.map(t=>this._renderEditorGroupLauncher(t))} + + +
+
+ +
+
`}_renderDecorEraseConfirm(){const t=this.host._decorEraseConfirm,e=this.host._t(`decor.${t.kind}`);return o`this.host._decorEraseConfirm=null}> +

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

`:a} + ${d?o`

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

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

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

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

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

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

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

`:a} + ${m?o`

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

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

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

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

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

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

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

`:a} + ${c?o`

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

`:a} + ${g?o`

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

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

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

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

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

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

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

+
+
+ + + + +
+
`}_renderPhysicalDialog(){const t=this.host._physicalDialog,e="column"===t.kind;return o`this.host._physicalDialog=null}> +
+ ${e?o` + `:a} + +
this.host._physicalDialog={...t,cm:e.target.value}} /> + ${this.host._t(this.host._imperial?"wallthick.unit_in":"wallthick.unit_cm")}
+ ${e&&"square"===t.shape?o` + + this.host._physicalDialog={...t,angle:e.target.value}} />`:a} + ${t.length?o`
${this.host._t("physical.length")}: ${t.length}
`:a} +
+ +
`}_renderMarkupBar(){const t=this.host._geometryHistory.undoName,e=this.host._geometryHistory.redoName,s=t?this.host._t("history.undo_named",{name:t}):this.host._t("history.undo_empty"),i=e?this.host._t("history.redo_named",{name:e}):this.host._t("history.redo_empty");return o`
+
+ + + + + + + + + + ${this.host._editorToolbarGroups.map(t=>this._renderEditorGroupLauncher(t))} + + + + +
+
+ +
+
`}_renderDevicesBar(){return o`
+
+ + + + ${this.host._editorToolbarGroups.map(t=>this._renderEditorGroupLauncher(t))} +
+
+ +
+
`}_renderDeviceInbox(){const t=this.host._deviceInbox,e=this._deviceInboxRows(),s=Object.fromEntries(["on_plan","available","hidden","readd"].map(t=>[t,e.filter(e=>e.category===t).length])),i=function(t,e,s,i=!1){const o=s.trim().toLocaleLowerCase();return t.filter(t=>t.category===e&&(!i||t.isNew)&&(!o||t.searchText.includes(o)))}(e,t.tab,t.search,"on_plan"===t.tab&&t.onlyNew),n=i.slice(0,t.limit),r=t=>this.host._t(`device_inbox.tab_${t}`),h=`device_inbox.empty_${t.tab}`;return o`this.host._deviceInbox=null}> +
+
+ this.host._deviceInbox={...t,search:e.target.value,limit:100}} /> + +
+
this._deviceInboxTabKey(t)}> + ${["on_plan","available","hidden","readd"].map(e=>o` + `)} +
+
+ ${"on_plan"===t.tab?o``:a} + ${"available"===t.tab?o``:a} + +
+
+ ${n.length?n.map(t=>{const e="on_plan"===t.category?t.canFind?o``:o``:"hidden"===t.category?o``:o``,s="active"===t.status.kind?"":this.host._t(`device_inbox.status_${t.status.kind}`);return o`
+ +
+
${t.name} + ${t.isNew?o`${this.host._t("device_inbox.new")}`:a} +
+
+ ${[t.model,t.integration,t.spaceName,t.areaName].filter(Boolean).join(" · ")} +
+
+ ${this.host._t(`device_inbox.reason_${t.reason}`)} + ${s?o`${s}`:a} +
+ ${t.binding} +
+
+ ${e} + ${t.canEdit||t.canHide||"available"===t.category||"hidden"===t.category||this.host._bindingHasHaPage(t.binding)?o` +
+ + + +
+ ${t.canEdit&&("on_plan"!==t.category||t.canFind)?o``:a} + ${t.canHide?o``:a} + ${"available"===t.category?o``:a} + ${"hidden"===t.category?o``:a} + ${this.host._bindingHasHaPage(t.binding)?o``:a} +
+
`:a} +
+
`}):o`
${this.host._t(h)}
`} +
+ ${i.length>n.length?o``:a} +
+
+ +
+
`}_markerValueBadgeFields(t){return Qs({touched:t.valueBadgeTouched,originalHas:t.originalHasValueBadge,original:t.originalValueBadge,enabled:t.valueBadgeEnabled,source:t.valueBadgeSource,position:t.valueBadgePosition})}_markerDraft(t){if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return null;const e=ns(t.room),s=Ze(t.binding,t.devId,()=>"__hp_device_preview__"),i=this.host._markers.find(e=>e.id===s||e.id===t.devId),o=ss(t.binding,t.controls,this.host._bindingEntities(t.binding)),a=this._effectiveStoredTapAction(t),n={id:s,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle||null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===a&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:o.length?o:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=Qr(t.glowRadius);return null==e||e<=0?null:Math.round(this.host._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:t.hideFromPlan,vacuum:i?.vacuum||null};return("virtual"===t.binding||t.room)&&(n.space=e?.space||("virtual"===t.binding?this.host._space:null),n.area=e?.area||null,n.room_id=e?.roomId||null),n}_markerPreviewDevice(t){const e=this._markerDraft(t);if(!e)return null;const s=`${this.host._haRegistry.revision}\n${Lt(this.host._markers)}\n${JSON.stringify(e)}`;if(this.host._markerPreviewMemo?.key===s)return this.host._markerPreviewMemo.device;const i=ti({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 ei(t,{single:t=>{if("via"in t&&"virtual-light"===t.via)return this.host._t("marker.virtual_light_target",{name:t.name});const e=t.entityId||("ref"in t?t.ref:""),s=t.name||e;return this.host._t("marker.toggle_hint_single",{name:s,id:e})},group:t=>this.host._t("marker.toggle_hint_group",{count:t.length,names:t.map(t=>`${t.name} (${t.entityId})`).join(", ")}),currentNext:(t,s)=>"virtual-light"===t.via?this.host._t("marker.virtual_light_current",{state:this.host._t("on"===t.state?"marker.virtual_light_state_on":"marker.virtual_light_state_off"),effect:e(s)}):this.host._t("marker.toggle_hint_current",{state:this._toggleStateText(t.entityId,t.state),effect:e(s)}),groupCurrentNext:(t,s)=>this.host._t("marker.toggle_hint_group_current",{on:t.filter(t=>"on"===t.state).length,count:t.length,effect:e(s)}),skipped:t=>this.host._t("marker.toggle_hint_skipped",{count:t.length,targets:t.map(t=>{const e=t.entityId||t.ref;return`${t.name||e} (${e}: ${s(t.reason)})`}).join(", ")}),none:t=>this.host._t(`marker.toggle_none_${t.replaceAll("-","_")}`)})}_effectiveStoredTapAction(t,e){return t.tapActionTouched?t.tapAction:is(t.originalHasTapAction?t.originalTapAction:null,e)}_effectiveMarkerTapAction(t,e=this._markerPreviewDevice(t)){return this._effectiveStoredTapAction(t,e?.primary?.split(".")[0])}_announceToggleDraft(t){const e=this._markerPreviewDevice(t),s=t.tapActionTouched?t:{...t,tapAction:this._effectiveMarkerTapAction(t,e)},i="toggle"===s.tapAction?this._toggleHintLines(this._toggleIntentForDialog(s)).join(" "):"";return{...s,tapHintAnnouncement:i}}_valueBadgeForBinding(t,e){const s={...t,binding:e,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0},i=this._markerPreviewDevice(s);if(!i)return{valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0};const o=[...this.host._devices.filter(t=>t.id!==i.id),i],a=ts(this.host._planHass,i,o),n=es(this.host._planHass,i,a);return{valueBadgeEnabled:t.valueBadgeEnabled&&!!n,valueBadgeSource:n,valueBadgeTouched:!0}}_markerSpatialSource(t){const e=this._markerPreviewDevice(t);if(!e)return null;const s={...e,hidden:!1};return si(ii(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&&oi(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&&ai(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 ai(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} ${ai(o).join(" ")}`.toLowerCase()})}const o=Object.keys(this.host.hass.states||{}).filter(e=>ni(e)&&!i.has(e)&&ri(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(hi(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=li(s?this.host._planHass.states[s.eid]:void 0,null,this.host._fillColors.glow_light.c),o=!e.glowColorDrafted,a="fixed"===t&&!e.glowBrightnessDrafted;this.host._markerDialog={...e,glowMode:t,glowColor:o?i.c:e.glowColor,glowBrightness:a?Math.max(1,Math.round(100*i.bri)):e.glowBrightness,glowColorDrafted:!0,glowBrightnessDrafted:e.glowBrightnessDrafted||"fixed"===t,glowTouched:!0}}_renderMarkerDialog(){const t=this.host._markerDialog,e="virtual"===t.bindingMode,s=this._bindingCandidates();this.host._bindingEntities(t.binding);const i=e?null:this.host._bindingStatus(t.binding),n=!e&&this.host._bindingHasHaPage(t.binding),r=this._markerPreviewDevice(t),h=this._effectiveMarkerTapAction(t,r),l=r?ps(this.host._serverCfg?.spaces.find(t=>t.id===r.space)):null,c=r?this._markerPreviewDevices(r):this.host._devices,d="toggle"===h&&r?this._toggleIntent(r,c):null,p=this._toggleHintLines(d),_=r?ci(this.host._planHass,r,{liveStates:!1!==this.host._config?.live_states,showTemperature:!1!==this.host._config?.show_temperature,showSignal:l?.showLqi??!1!==this.host._config?.show_signal,designPreview:!0,activityRuntime:this.host._activityRt.get(r.id),lightDevices:c,registryHass:this.host._fullRegistryHass,reducedMotion:this.host._reducedMotion}):null,u=r?ts(this.host._planHass,r,c):[],m=r?es(this.host._planHass,r,u):null,g=t.valueBadgeTouched?t.valueBadgeEnabled:!!_?.valueBadge,f=t.valueBadgeTouched?t.valueBadgeSource:_?.valueBadge?.source||t.valueBadgeSource,b=t.valueBadgeTouched?t.valueBadgePosition:_?.valueBadge?.position||t.valueBadgePosition,v=di(f),y=!!f&&!u.some(t=>t.key===v),$=u.find(t=>t.key===v),w=_?.valueSource?_.valueSource.attribute?`attr:${_.valueSource.eid}:${_.valueSource.attribute}`:`state:${_.valueSource.eid}`:"",k=this._markerAutoHasSpatialSource(t),x=!!r&&pi(this.host._planHass,{...r}),M=_i(t.lightRole,k,x,t.glowMode),S=!M.sourceExists,C=!M.fromSourceEnabled,D=M.passive,P=M.effectiveMode,I="never"===t.lightRole?this.host._t("marker.glow_disabled_never"):"auto"!==t.lightRole||k?D?this.host._t("marker.glow_passive_hint"):this.host._t("marker.glow_disabled_no_entity"):this.host._t("marker.glow_disabled_auto"),T=r?ai(r):[],R=r&&ui(r)||"",z=!!t.lightEntity&&!T.includes(t.lightEntity),F=r?mi(r):[],A=!!t.toggleEntity&&!F.includes(t.toggleEntity),N="toggle"===h?this._toggleIntentForDialog({...t,toggleEntity:"",toggleEntityTouched:!0}):null,H=N?[...N.targets,...N.skippedTargets].map(t=>t.entityId||("ref"in t?t.ref:"")).filter(Boolean).join(", "):"",O=(()=>{if(e)return null;const i=s.find(e=>e.value===t.binding);if(i)return i.label;const[o,a]=t.binding.split(":");return"device"===o?this.host._fullRegistryHass.devices[a]?.name_by_user||this.host._fullRegistryHass.devices[a]?.name||a:this.host._fullRegistryHass.entities[a]?.name||this.host.hass.states[a]?.attributes?.friendly_name||a})();return o`this._closeMarkerDialog()}> +
+ ${"ha_disabled"===i?.kind?o`
+ + ${this.host._t(`marker.ha_disabled_${i.reason}`)} + ${n?o``:a} +
`:"unverified"===i?.kind&&t.binding?o`
+ + ${this.host._t("marker.ha_registry_limited")} +
`:a} + + this.host._markerDialog={...t,name:e.target.value}} /> + + +
+ +
+ + +
+ ${"ha"===t.bindingMode?o` + ${t.bindingOpen?o`
+ this.host._markerDialog={...t,bindingFilter:e.target.value}} /> +
+ ${s.map(e=>o`
{const s={...t,binding:e.value,bindingOpen:!1,controls:ss(e.value,t.controls,this.host._bindingEntities(e.value)),autoIcon:this.host._autoIconForBinding(e.value)};this.host._markerDialog=this._announceToggleDraft({...s,...this._valueBadgeForBinding(s,e.value)})}}> + ${e.label}${e.sub} +
`)} + ${s.length?a:o`
${this.host._t("marker.nothing_found")}
`} +
+
`:a}`:a} +
+ + + + + ${this._renderVacSection(t)} + + + + ${"toggle"===h&&(F.length>1||A)?o`
+
+ + ${this._help("marker.toggle_entity.help")} +
+ + ${A?o`

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

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

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

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

+ ${I} +

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

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

`:a} + + + +

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

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

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

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

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

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

${$.technical}

`:a} + ${y?o`

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

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

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

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

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

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

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

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

+ ${s} +

`:a} + + this.host._nameSel=t.target.value} /> + + + + + + ${[["","fill.inherit"],...wi.map(t=>[t,"fill."+t])].map(([t,e])=>o``)} + ${"custom"===r?o`
+ ${this.host._roomCustomFill?this.host._t("room.custom_fill_own"):this.host._t("room.custom_fill_space")} + {this.host._roomCustomFill={c:t.detail.color,a:t.detail.opacity}}}> + ${this.host._roomCustomFill?o``:a} +
`:a} + ${this._renderRoomSource("temp")} + ${this._renderRoomSource("hum")} + + + +
+ ${this._rangeInput(50,300,5,Math.round(100*this.host._roomNameScale),t=>{this.host._roomNameScale=t/100,this.host.requestUpdate()})} + ${Math.round(100*this.host._roomNameScale)}% +
+ +
+ ${this._rangeInput(50,300,5,Math.round(100*this.host._roomLabelScale),t=>{this.host._roomLabelScale=t/100,this.host.requestUpdate()})} + ${Math.round(100*this.host._roomLabelScale)}% +
+ ${this.host._renderCardPreview(ps(this.host._curSpaceCfg).cardFontScale,this.host._roomNameScale,this.host._roomLabelScale)} +
+
+ + + ${t?o``:o`${this.host._pendingSplit?a:o``} + `} +
+
`}}export{oh as EDITOR_RUNTIME_FINGERPRINT,ah as HouseplanEditorRuntime}; diff --git a/custom_components/houseplan/frontend/houseplan-assets/houseplan-onboarding-runtime-BkWWzfSR.js b/custom_components/houseplan/frontend/houseplan-assets/houseplan-onboarding-runtime-BkWWzfSR.js new file mode 100644 index 00000000..a4cff7d0 --- /dev/null +++ b/custom_components/houseplan/frontend/houseplan-assets/houseplan-onboarding-runtime-BkWWzfSR.js @@ -0,0 +1,217 @@ +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";import{bU as t,bV as s,bW as e,bX as o,aq as a,bY as l,c1 as i,bZ as h,b_ as n,b$ as c,c0 as r,b as p,A as _,cS as d,ap as u,ar as g,cT as m}from"./houseplan-card-BrUCyMoE.js";import{i as b,c as $,a as v,s as f,t as y}from"./space-deletion-CLA5ezlL.js";const w=1e3,D=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},S="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";class C{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_openSpaceDialog(p,_){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===p){const i=this.host._serverCfg.spaces.find(t=>t.id===_);if(!i)return;const h=t(i),n=i.settings?.custom_fill&&"object"==typeof i.settings.custom_fill?s(i.settings.custom_fill):null,c="none"===h.fill?{...n||e,a:0}:n;return void(this.host._spaceDialog={mode:p,spaceId:_,title:i.title,planUrl:i.plan_url||null,planFile:null,source:i.plan_url?"file":"draw",showBorders:h.showBorders,showNames:h.showNames,zeroWallStyle:l(i),displayTouched:!0,hideDecor:h.hideDecor,hideOpenings:h.hideOpenings,roomColor:h.color,roomOpacity:h.opacity,fillMode:"none"===h.fill?"custom":h.fill,customFill:c,glowEnabled:h.glow,bgColor:h.bgColor,bgMode:"static"===i.settings?.bg_mode||"daynight"===i.settings?.bg_mode?i.settings.bg_mode:null,northDeg:a({},i.settings),sunRays:"boolean"==typeof i.settings?.sun_rays?i.settings.sun_rays:null,tempMin:h.tempMin,tempMax:h.tempMax,showLqi:h.showLqi??this.host._config?.show_signal??!0,cardFontScale:h.cardFontScale,labelTemp:h.labelTemp,labelHum:h.labelHum,labelLqi:h.labelLqi,labelLight:h.labelLight,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,cellCmInput:o(Number(i.cell_cm)>0?Number(i.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const d=i(this.host._imperial);this.host._spaceDialog={mode:p,title:"",planUrl:null,planFile:null,...b(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:r,roomOpacity:c,fillMode:"custom",customFill:{...e,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:n,tempMax:h,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:d,cellCmInput:o(d,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;const o={"image/svg+xml":"svg","image/png":"png","image/jpeg":"jpg","image/webp":"webp"}[e.type]||(e.name.toLowerCase().endsWith(".svg")?"svg":"");if(!o)return void this.host._showToast(this.host._t("toast.plan_formats"));const a=new Uint8Array(await e.arrayBuffer());let l="";for(let t=0;t{const s=new Image;s.onload=()=>t(s.naturalWidth&&s.naturalHeight?s.naturalWidth/s.naturalHeight:1.414),s.onerror=()=>t(1.414),s.src=h});URL.revokeObjectURL(h),this.host._spaceDialog={...this.host._spaceDialog,planFile:{ext:o,b64:i,aspect:n,name:e.name}}}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),o=this.host._spaceDialog;return o&&o.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...o,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){if(confirm(this.host._t("confirm.delete_plan",{name:t})))try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return p`
${this.host._t("space.loading")}
`;const s=t.saved||[];if(!s.length)return p`
${this.host._t("space.no_saved")}
`;return p`
+ ${s.map(s=>{return p` +
+ +
+ ${s.name} + ${e=s.size,e>=1048576?`${(e/1048576).toFixed(1)} MB`:`${Math.round(e/1024)} KB`}${s.used_by.length?` · ${this.host._t("space.used_by",{list:s.used_by.join(", ")})}`:""} +
+ + +
`;var e})} +
`}async _saveConfigNow(){this.host._cfgEpoch++;try{await this.host._writeConfig()}catch(t){const s=t;throw s?.physicalGeometryRolledBack?await this.host._reloadRejectedPhysicalWrite():"conflict"===s?.code&&await this.host._reloadConfigOnly(),t}}async _saveSpaceDialog(){const t=this.host._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this.host._showToast(this.host._t("toast.plan_required"));const s="create"===t.mode&&0===(this.host._serverCfg?.spaces.length||0);this.host._spaceDialog={...t,busy:!0};try{const e="create"===t.mode?`s${Date.now().toString(36)}`:t.spaceId;let o=null;if("file"===t.source&&t.planFile){o={url:(await this.host.hass.callWS({type:"houseplan/plan/set",space_id:e,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let a=t.savedAspect||null;!o&&"file"===t.source&&t.planUrl&&!a&&this.host._aspectJob&&(a=await this.host._aspectJob||null);const l=this.host._serverCfg;let i=l.spaces.find(t=>t.id===e);if("create"===t.mode)i=$(e,t.title.trim()),l.spaces.push(i);else{if(!i)throw new Error(`space ${e} is gone from the config`);i.title=t.title.trim()}if(!i)throw new Error(`space ${e} is unavailable`);if(o?(i.plan_url=o.url,i.plan_aspect=o.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==i.plan_url&&(i.plan_url=t.planUrl,i.plan_aspect=a),"draw"===t.source&&(i.plan_url=null,i.plan_aspect=null,delete i.plan_x,delete i.plan_y,delete i.plan_scale,delete i.plan_scale_x,delete i.plan_scale_y,delete i.plan_angle),i.settings={...i.settings||{},show_borders:t.showBorders,show_names:t.showNames,hide_decor:t.hideDecor||void 0,hide_openings:t.hideOpenings||void 0,room_color:t.roomColor,room_opacity:t.roomOpacity,bg_color:t.bgColor||void 0,bg_mode:t.bgMode||void 0,north_deg:t.northDeg??void 0,sun_rays:t.sunRays??void 0,fill_mode:t.fillMode,custom_fill:t.customFill||void 0,glow_enabled:t.glowEnabled,temp_min:Number.isFinite(t.tempMin)?Math.min(t.tempMin,t.tempMax):n,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):h,show_lqi:t.showLqi,card_font_scale:1!==t.cardFontScale?t.cardFontScale:void 0,label_temp:t.labelTemp,label_hum:t.labelHum,label_lqi:t.labelLqi,label_light:t.labelLight},i.zero_wall_style=t.zeroWallStyle,i.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(.1,Math.min(w,t.cellCm)):5,await this._saveConfigNow(),this.host._spaceDialog=null,"create"===t.mode&&this.host._commitSpace(i.id),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._importQueue.length)this._openNextImport();else if(s||this.host._importTotal>0){const t=this.host._importTotal>0;this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),await this.host._requestMode("plan"),this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this.host._primeDrawWallField(),this.host._showToast(this.host._t(s&&!t?"toast.space_added_onboard":"import.done"))}else this.host._showToast(this.host._t("create"===t.mode?"toast.space_added":"toast.space_saved")),"create"===t.mode&&("plan"!==this.host._mode?await this.host._requestMode("plan"):(this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this.host._primeDrawWallField(),this.host._saveNav()))}catch(t){const s=t;"conflict"!==s?.code&&await this.host._reloadConfigOnly(!0),this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteSpace(){const t=this.host._spaceDialog;if(!t||"edit"!==t.mode)return;const s=this.host._serverCfg;if(!s)return;const e=s.spaces.find(s=>s.id===t.spaceId);if(!e)return;const o=v(s,this.host._layout||{},t.spaceId||""),a=1===s.spaces.length&&s.spaces[0]?.id===t.spaceId;if(!o.count||a){if(confirm(this.host._t("confirm.delete_space",{title:e.title}))){this.host._spaceDialog={...t,deleteBlockers:0,busy:!0};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),this.host._persistLayout.pending()&&this.host._persistLayout.flush(),await this.host._writeChain;const s=await this.host.hass.callWS({type:"houseplan/space/delete",space_id:t.spaceId,expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev}),[e,o]=await Promise.all([this.host.hass.callWS({type:"houseplan/config/get"}),this.host.hass.callWS({type:"houseplan/layout/get"})]);this.host._adoptStructuralResponses(e,o),this.host._cfgRev=s?.config_rev??this.host._cfgRev,this.host._layoutRev=s?.layout_rev??this.host._layoutRev,this.host._spaceDialog=null,this.host._space===t.spaceId&&this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||""),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.space_deleted"))}catch(s){const e=s;"conflict"!==e?.code&&"space_in_use"!==e?.code||await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]);const o=this.host._serverCfg;if(this.host._spaceDialog&&o){const s=v(o,this.host._layout||{},t.spaceId||""),e=1===o.spaces.length&&o.spaces[0]?.id===t.spaceId;this.host._spaceDialog={...this.host._spaceDialog,busy:!1,deleteBlockers:e?0:s.count}}this.host._showToast(this.host._t("toast.delete_failed",{err:this.host._errText(s)}))}}}else this.host._spaceDialog={...t,deleteBlockers:o.count}}_startImport(){const t=this.host._importDialog;if(!t)return;const s=t.floors.filter(t=>t.checked).map(t=>t.name);this.host._importDialog=null,s.length?(this.host._importQueue=s,this.host._importTotal=s.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this.host._importQueue.shift();if(void 0===t)return;const s=i(this.host._imperial);this.host._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...b(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:r,roomOpacity:c,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:n,tempMax:h,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:s,cellCmInput:o(s,this.host._imperial),cellCmTouched:!1,busy:!1}}_skipImport(){this.host._spaceDialog=null,this.host._importQueue.length?this._openNextImport():this.host._importTotal>0&&this.host._model.length&&(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this.host._requestMode("plan").then(()=>{this.host._showToast(this.host._t("import.done"))}))}_renderImportDialog(){const t=this.host._importDialog,s=t.floors.filter(t=>t.checked).length;return p`this.host._importDialog=null}> +
+
${this.host._t("import.hint")}
+ ${t.floors.map((s,e)=>p``)} +
+
+ + + +
+
`}_boolInput(t,s){return p`s(t.target.checked)} />`}_rangeInput(t,s,e,o,a){return p`a(Number(t.target.value))} />`}_renderSpaceDialog(){return this._renderSpaceDialogBody(this.host._spaceDialog)}_renderSpaceDialogBody(t){const s=this.host._importTotal>0&&"create"===t.mode?this.host._t("import.progress",{i:this.host._importTotal-this.host._importQueue.length,n:this.host._importTotal}):"",l=()=>{this.host._spaceDialog=null,this.host._importQueue=[],this.host._importTotal=0};return p` +
+ + this.host._spaceDialog={...t,title:s.target.value}} /> + + + ${"file"===t.source?p`
+ ${t.planFile?p`${t.planFile.name}`:t.planUrl?p`${this.host._t("space.plan_alt")}`:p`${this.host._t("space.no_plan")}`} + + + this._pickPlanFile(t)} /> + + +
+ ${t.pickSaved?this._renderServerPlans(t):_}`:_} + + + +
+ {const e=s.target.value,o=D(e),a=null==o?null:d(o,this.host._imperial);this.host._spaceDialog={...t,cellCmInput:e,cellCmTouched:!0,cellCm:null!=a&&a>0?Math.max(.1,Math.min(w,a)):t.cellCm}}} /> + ${this.host._t(this.host._imperial?"space.scale_unit_imperial":"space.scale_unit")} +
+ + + + + +
${this.host._t("space.zero_wall_help")}
+ + + +
${this.host._t("space.hide_decor_tip")}
+ +
${this.host._t("space.hide_openings_tip")}
+ + ${[["labelTemp","space.label_temp"],["labelHum","space.label_hum"],["labelLqi","space.label_lqi"],["labelLight","space.label_light"]].map(([s,e])=>p``)} + +
+ ${this._rangeInput(50,300,5,Math.round(100*t.cardFontScale),s=>{this.host._spaceDialog={...t,cardFontScale:s/100}})} + ${Math.round(100*t.cardFontScale)}% +
+ ${this.host._renderCardPreview(t.cardFontScale,1,1)} +
+ {this.host._spaceDialog={...t,roomColor:s.detail.color,roomOpacity:s.detail.opacity}}}> +
+ + + ${"static"===(t.bgMode??u(this.host._settings,{}))?p` +
+ {this.host._spaceDialog={...t,bgColor:s.detail.color}}}> + ${t.bgColor?p``:p`${this.host._t("space.bg_inherited")}`} +
`:_} + +
+ {const e=s.target.value.trim(),o=""===e?null:Math.round(Number(e));this.host._spaceDialog={...t,northDeg:null!==o&&Number.isFinite(o)?Math.min(359,Math.max(0,o)):null}}} /> + ${null===t.northDeg?this.host._t("space.north_inherited",{v:null===a(this.host._settings,{})?"—":`${a(this.host._settings,{})}°`}):"°"} +
+ + + + ${m.map(t=>[t,`fill.${t}`]).map(([s,o])=>p` + ${"custom"===s&&"custom"===t.fillMode?p` +
+ ${this.host._t("space.custom_fill")} + {this.host._spaceDialog={...t,customFill:{c:s.detail.color,a:s.detail.opacity}}}}> + ${t.customFill?p``:_} +
`:_}`)} + + ${t.deleteBlockers?p``:_} +
+ +
`}}export{C as HouseplanOnboardingRuntime,S as ONBOARDING_RUNTIME_FINGERPRINT}; diff --git a/custom_components/houseplan/frontend/houseplan-assets/space-deletion-CLA5ezlL.js b/custom_components/houseplan/frontend/houseplan-assets/space-deletion-CLA5ezlL.js new file mode 100644 index 00000000..822c577d --- /dev/null +++ b/custom_components/houseplan/frontend/houseplan-assets/space-deletion-CLA5ezlL.js @@ -0,0 +1 @@ +function e(e,o){return{id:e,title:o,plan_url:null,view_box:[0,0,1,1],rooms:[],wall_segments:[]}}function o(e="file"){const o="draw"===e;return{source:e,showBorders:o,showNames:o,displayTouched:!1}}function r(e,o){if(e.displayTouched)return{...e,source:o};const r="draw"===o;return{...e,source:o,showBorders:r,showNames:r}}function s(e,o,r){return{...e,[o]:r,displayTouched:!0}}function a(e,o,r){const s=(e?.spaces||[]).find(e=>e?.id===r),a=new Set((s?.rooms||[]).map(e=>String(e?.id||"")).filter(Boolean)),t=[...new Set((e?.markers||[]).filter(e=>!0!==e?.removed&&"string"==typeof e?.id).filter(e=>e.space===r||"string"==typeof e.room_id&&a.has(e.room_id)||o?.[e.id]?.s===r).map(e=>e.id))].sort((e,o)=>e.localeCompare(o));return{markerIds:t,count:t.length}}globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";export{a,e as c,o as i,r as s,s as t}; diff --git a/custom_components/houseplan/frontend/houseplan-card.js b/custom_components/houseplan/frontend/houseplan-card.js index a9cc9074..89defeea 100644 --- a/custom_components/houseplan/frontend/houseplan-card.js +++ b/custom_components/houseplan/frontend/houseplan-card.js @@ -1 +1 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="e6c51f2467ae4e22a792e536ae954291ab5a46915e728b216c8c45bc6816b209";try{await import("./houseplan-assets/houseplan-card-DI__VUPO.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).":"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 entry: the main chunk is unavailable",e)} +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";try{await import("./houseplan-assets/houseplan-card-BrUCyMoE.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).":"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 entry: the main chunk is unavailable",e)} diff --git a/demo/golden/harness.mjs b/demo/golden/harness.mjs index d7a506c7..0fc6ceb5 100644 --- a/demo/golden/harness.mjs +++ b/demo/golden/harness.mjs @@ -1274,41 +1274,6 @@ export async function prepareGoldenScenario(page, scenario) { if (!palette.querySelector(selector)) throw new Error(`golden furniture palette level is empty: ${scenario.id}`); } - if (scenario.furniturePlacementPreview) { - const { symbol, widthCm, depthCm, pointer, free = false } = scenario.furniturePlacementPreview; - if (typeof symbol !== 'string' || !(widthCm > 0) || !(depthCm > 0) - || !Array.isArray(pointer) || pointer.length !== 2 || !pointer.every(Number.isFinite)) { - throw new Error(`invalid golden furniturePlacementPreview: ${scenario.id}`); - } - card._decorSel = null; - card._decorTool = 'furniture'; - card._furnCategory = null; - card._furnPalette = { symbol, w: widthCm, h: depthCm }; - card.requestUpdate(); - await card.updateComplete; - await frame(); - const svgRoot = card.renderRoot.querySelector('.stage svg'); - const stageEl = card.renderRoot.querySelector('.stage'); - const screen = new DOMPoint(pointer[0] * 1000, pointer[1] * card._spaceH) - .matrixTransform(svgRoot.getScreenCTM()); - stageEl.dispatchEvent(new PointerEvent('pointermove', { - bubbles: true, composed: true, pointerId: 993, pointerType: 'mouse', - clientX: screen.x, clientY: screen.y, shiftKey: free, - })); - await card.updateComplete; - await frame(); - const preview = card.renderRoot.querySelector('.furniture-placement-preview'); - const wall = card.renderRoot.querySelector('[data-hp="wall"]'); - const previewBeforeWall = !!wall - && !!(preview?.compareDocumentPosition(wall) & Node.DOCUMENT_POSITION_FOLLOWING); - if (!preview || preview.getAttribute('data-symbol') !== symbol - || preview.getAttribute('aria-hidden') !== 'true' - || getComputedStyle(preview).pointerEvents !== 'none' - || Math.abs(Number(getComputedStyle(preview).opacity) - 0.55) > 1e-6 - || !preview.closest('.decorlayer') || !previewBeforeWall) { - throw new Error(`golden furniture placement preview contract is incomplete: ${scenario.id}`); - } - } if (scenario.hoverRoom) { const room = card._spaceModel().rooms.find((item) => item.id === scenario.hoverRoom); if (!room) throw new Error(`golden hover room missing: ${scenario.hoverRoom}`); diff --git a/demo/golden/matrix.mjs b/demo/golden/matrix.mjs index 66873fbb..0c0ca6a7 100644 --- a/demo/golden/matrix.mjs +++ b/demo/golden/matrix.mjs @@ -418,9 +418,6 @@ export const GOLDEN_SCENARIOS = Object.freeze([ { id: 'furniture-variants-light', fixture: 'visual', space: 'golden-geometry', mode: 'decor', furniturePalette: 'variants', furnitureCategory: 'coffee_table', language: 'ru', theme: 'light', viewport: { width: 900, height: 820 }, ...page }, - { id: 'furniture-placement-preview-light', fixture: 'visual', space: 'golden-geometry', mode: 'decor', - furniturePlacementPreview: { symbol: 'sofa', widthCm: 180, depthCm: 90, pointer: [0.35, 0.90] }, - language: 'ru', theme: 'light', viewport: { width: 1000, height: 900 }, ...stage }, { id: 'furniture-plan-art-dark', fixture: 'visual', space: 'golden-geometry', mode: 'view', decorOverride: [ ...decorLayerFixture.filter((shape) => shape.kind !== 'furniture'), diff --git a/demo/smoke_furniture.mjs b/demo/smoke_furniture.mjs index da2ddc3e..54491a36 100644 --- a/demo/smoke_furniture.mjs +++ b/demo/smoke_furniture.mjs @@ -4,14 +4,12 @@ // 2) выбранный символ ставится кликом по плану в РЕАЛЬНОМ размере — через // cell_cm пространства, и сразу оказывается выделенным в «выбрать»; // 3) поля ширины/глубины в палитре меняют размер ДО размещения; -// 4) мышь показывает точный полупрозрачный будущий символ без записи в -// конфиг; touch/pen не рисуют hover и сохраняют только чистый tap; -// 5) магнит к стене: предмет прижимается к ближайшей стене и доворачивается -// по ней; Shift временно обходит магнит, сохраняя grid snap; -// 6) у выделенного предмета та же рамка, что у текстового блока, — угловые +// 4) магнит к стене: предмет прижимается к ближайшей стене и доворачивается +// по ней; Shift не отключает обязательную привязку (docs/CANVAS.md §9.4); +// 5) у выделенного предмета та же рамка, что у текстового блока, — угловые // ручки (НЕзависимые ширина и глубина) и ручка поворота с шагом 5°; -// 7) во время растягивания угла показываются живые плашки размеров; -// 8) фигура пишется в конфиг и переживает пересборку, хуки card-mod на месте. +// 6) во время растягивания угла показываются живые плашки размеров; +// 7) фигура пишется в конфиг и переживает пересборку, хуки card-mod на месте. // ПАДАЕТ на сборке до этой задачи: инструмента «Мебель» нет, палитры нет, // kind:'furniture' не рисуется, магнита и плашек не существует. Смок при этом // null-safe — он показывает СПИСОК провалов, а не одно исключение. @@ -61,16 +59,6 @@ const res = await page.evaluate(async () => { await c.updateComplete; out.toolIsSelected = c._decorTool === 'furniture'; const pal = () => sr().querySelector('.furnpalette'); - const openFurniture = async () => { - if (c._decorTool !== 'furniture') { - c._editorSecondary.openPalette(); - c._decorTool = 'furniture'; - c._furnPalette = null; - c._furnCategory = null; - c.requestUpdate(); - await c.updateComplete; - } - }; out.paletteOpens = !!pal(); const groups = [...(pal()?.querySelectorAll('.furngroup') || [])] .map((g) => g.getAttribute('data-group')); @@ -138,67 +126,9 @@ const res = await page.evaluate(async () => { out.fieldsShowMetres = +(wIn()?.value ?? NaN) === 1.8 && +(hIn()?.value ?? NaN) === 0.9; out.selectedItemIsMarked = !!item('sofa')?.classList.contains('on'); - // ================= 3. точное превью без мутации ========================== - const ghost = () => sr().querySelector('.furniture-placement-preview'); - const beforePreview = { - decor: c._decorList.length, - epoch: c._cfgEpoch, - undo: c._geometryHistory.undoName, - redo: c._geometryHistory.redoName, - }; - ev('pointermove', stageEl(), 300, 300, { pointerType: 'mouse' }); - await c.updateComplete; - const firstPreview = c._furniturePreviewPlacement - ? JSON.parse(JSON.stringify(c._furniturePreviewPlacement)) : null; - const firstTransform = ghost()?.getAttribute('transform'); - out.mouseHoverShowsRealSymbol = ghost()?.getAttribute('data-symbol') === 'sofa' - && (ghost()?.getAttribute('d') || '').length > 20; - out.previewIsTransientAndInert = ghost()?.getAttribute('aria-hidden') === 'true' - && getComputedStyle(ghost()).pointerEvents === 'none' - && near(Number(getComputedStyle(ghost()).opacity), 0.55, 1e-6); - out.previewDoesNotMutateConfigOrHistory = c._decorList.length === beforePreview.decor - && c._cfgEpoch === beforePreview.epoch - && c._geometryHistory.undoName === beforePreview.undo - && c._geometryHistory.redoName === beforePreview.redo; - if (wIn()) { - wIn().value = '1.85'; - wIn().dispatchEvent(new Event('input', { bubbles: true })); - } - await c.updateComplete; - out.sizeUpdatesPreviewWithoutPointerMove = c._furniturePreviewPlacement?.w > firstPreview?.w - && ghost()?.getAttribute('transform') !== firstTransform; - if (wIn()) { - wIn().value = '1.8'; - wIn().dispatchEvent(new Event('input', { bubbles: true })); - } - await c.updateComplete; - stageEl().dispatchEvent(new PointerEvent('pointerleave', { - bubbles: true, composed: true, pointerId: 11, pointerType: 'mouse', - })); - await c.updateComplete; - out.pointerLeaveClearsPreview = !ghost() && c._furnPreviewInput === null; - - // Unknown/stale symbols fail dark: neither an invisible ghost nor a decor - // record is allowed. Restoring a valid selection resumes the same session. - c._furnPalette = { symbol: 'future_unknown_symbol', w: 180, h: 90 }; - await c.updateComplete; - ev('pointermove', stageEl(), 300, 300, { pointerType: 'mouse' }); - await c.updateComplete; - const beforeUnknown = c._decorList.length; - ev('pointerdown', stageEl(), 300, 300, { pointerType: 'mouse' }); - await c.updateComplete; - out.unknownSymbolFailsDark = !ghost() && c._decorList.length === beforeUnknown - && c._decorTool === 'furniture'; - c._furnPalette = { symbol: 'sofa', w: 180, h: 90 }; - await c.updateComplete; - - // ================= 4. размещение в реальном размере ====================== + // ================= 3. размещение в реальном размере ====================== // середина комнаты r1 (40..550 × 140..580) — до стен дальше порога магнита - ev('pointermove', stageEl(), 300, 300, { pointerType: 'mouse' }); - await c.updateComplete; - const committedPreview = c._furniturePreviewPlacement - ? JSON.parse(JSON.stringify(c._furniturePreviewPlacement)) : null; - ev('pointerdown', stageEl(), 300, 300, { pointerType: 'mouse' }); + ev('pointerdown', stageEl(), 300, 300); await c.updateComplete; const sofa = c._decorList.find((s) => s.kind === 'furniture'); const sofaId = sofa?.id ?? null; @@ -210,10 +140,6 @@ const res = await page.evaluate(async () => { && near((sofa.x + sofa.w / 2) * 1000, 300, 1e-6) && near((sofa.y + sofa.h / 2) * 1000, 300, 1e-6); out.noAngleWhenStraight = !!sofa && sofa.angle === undefined; - out.previewAndCommitAreIdentical = !!sofa && !!committedPreview - && ['x', 'y', 'w', 'h'].every((k) => near(sofa[k], committedPreview[k], 1e-12)) - && (sofa.angle || 0) === committedPreview.angle; - out.previewClearsAfterCommit = !ghost() && c._furnPreviewInput === null; out.selectedRightAway = !!sofaId && c._decorSel === sofaId; out.toolWentBackToSelect = c._decorTool === 'select'; out.paletteDisarmed = c._furnPalette === null; @@ -228,8 +154,8 @@ const res = await page.evaluate(async () => { && /scale\(/.test(attr(sofaId, 'transform') || '') && attr(sofaId, 'vector-effect') === 'non-scaling-stroke'; - // ================= 5. свой размер до размещения ========================== - await openFurniture(); + // ================= 4. свой размер до размещения ========================== + c._decorTool = 'furniture'; await c.updateComplete; category('toilet')?.click(); await c.updateComplete; pick('toilet'); await c.updateComplete; if (wIn()) { @@ -244,8 +170,8 @@ const res = await page.evaluate(async () => { out.typedSizeIsUsed = near((wc?.w ?? NaN) * 1000, cmToUnits(50), 1e-6) && near((wc?.h ?? NaN) * 1000, cmToUnits(70), 1e-6); - // ================= 6. магнит к стене ===================================== - await openFurniture(); + // ================= 5. магнит к стене ===================================== + c._decorTool = 'furniture'; await c.updateComplete; category('bed')?.click(); await c.updateComplete; pick('bed_double'); await c.updateComplete; ev('pointerdown', stageEl(), 300, 150); // 10 единиц от стены y=140 @@ -258,42 +184,19 @@ const res = await page.evaluate(async () => { out.wallMagnetQuantisesAlongTheWall = !!bed && Math.abs((bed.x + bed.w / 2) * 1000 - 300) <= PITCH + 1e-6; - // Shift обходит магнит, но оставляет обычную привязку декора к сетке. - await openFurniture(); + // …Shift больше не отключает магнит + c._decorTool = 'furniture'; await c.updateComplete; category('bed')?.click(); await c.updateComplete; pick('bed_single'); await c.updateComplete; ev('pointerdown', stageEl(), 301.7, 151.3, { shiftKey: true }); await c.updateComplete; const free = c._decorList.find((s) => s.symbol === 'bed_single'); - out.shiftBypassesTheWallMagnet = !!free + out.shiftKeepsTheMagnet = !!free && !near((free.y + free.h / 2) * 1000, 151.3, 1e-6) && free.angle === undefined; - // Coarse pointers have no hover. A cancelled/dragged/second-contact gesture - // must not become an accidental furniture save. Keep this after the palette - // click checks because these synthetic pointer streams deliberately have no - // browser-generated compatibility click tail. - await openFurniture(); - category('chair')?.click(); await c.updateComplete; - pick('chair'); await c.updateComplete; - const beforeTouch = c._decorList.length; - ev('pointerdown', stageEl(), 330, 330, { pointerType: 'touch', pointerId: 21 }); - ev('pointermove', stageEl(), 350, 350, { pointerType: 'touch', pointerId: 21 }); - ev('pointerup', stageEl(), 350, 350, { pointerType: 'touch', pointerId: 21 }); - ev('pointerdown', stageEl(), 330, 330, { pointerType: 'touch', pointerId: 22 }); - ev('pointercancel', stageEl(), 330, 330, { pointerType: 'touch', pointerId: 22 }); - ev('pointerdown', stageEl(), 330, 330, { pointerType: 'touch', pointerId: 23 }); - ev('pointerdown', stageEl(), 340, 340, { pointerType: 'touch', pointerId: 24, isPrimary: false }); - ev('pointerup', stageEl(), 330, 330, { pointerType: 'touch', pointerId: 23 }); - ev('pointerup', stageEl(), 340, 340, { pointerType: 'touch', pointerId: 24, isPrimary: false }); - await c.updateComplete; - out.touchCancelMoveAndSecondContactDoNotSave = c._decorList.length === beforeTouch - && !ghost() && c._furnTouchPending === null; - // …магнит работает и при ПЕРЕТАСКИВАНИИ: тянем диван к левой стене (x=40) - c._editorRuntime._clearFurniturePreview(); - c._decorTool = 'select'; c._furnPalette = null; c._furnCategory = null; - c._decorSel = sofaId; c.requestUpdate(); + c._decorTool = 'select'; c._decorSel = sofaId; c.requestUpdate(); await c.updateComplete; await sleep(40); await c.updateComplete; ev('pointerdown', el(sofaId), 300, 300); out.dragStarted = !!sofaId && c._decorMove?.id === sofaId; @@ -310,7 +213,7 @@ const res = await page.evaluate(async () => { ev('pointerup', stageEl(), 300, 300, { shiftKey: true }); await c.updateComplete; - // ================= 7. рамка, углы, плашки, поворот ======================= + // ================= 6. рамка, углы, плашки, поворот ======================= c._decorSel = sofaId; c.requestUpdate(); await c.updateComplete; await sleep(60); await c.updateComplete; const frame = () => sr().querySelector('.dtframe'); @@ -382,7 +285,7 @@ const res = await page.evaluate(async () => { await c.updateComplete; out.rotationIsRendered = /rotate\(/.test(attr(sofaId, 'transform') || ''); - // ================= 8. конфиг и пересборка ================================ + // ================= 7. конфиг и пересборка ================================ const stored = JSON.parse(JSON.stringify(sofaNow())); out.storedShapeIsComplete = stored.kind === 'furniture' && typeof stored.symbol === 'string' && ['x', 'y', 'w', 'h'].every((k) => Number.isFinite(stored[k])); @@ -402,7 +305,7 @@ const res = await page.evaluate(async () => { )?.value === stored.symbol; c._decorShapeDialog = null; - // ================= 9. инертность и удаление ============================== + // ================= 8. инертность и удаление ============================== c._decorTool = 'furniture'; c._furnPalette = null; await c.updateComplete; out.inertUnderTheStamp = pe(sofaId) === 'none'; const n0 = c._decorList.length; diff --git a/dist/houseplan-assets.json b/dist/houseplan-assets.json index 665f05bc..e5d92202 100644 --- a/dist/houseplan-assets.json +++ b/dist/houseplan-assets.json @@ -1,111 +1,111 @@ { "schema": 1, - "fingerprint": "e6c51f2467ae4e22a792e536ae954291ab5a46915e728b216c8c45bc6816b209", + "fingerprint": "817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073", "entry": "houseplan-card.js", "initialViewFiles": [ - "houseplan-assets/houseplan-card-DI__VUPO.js", + "houseplan-assets/houseplan-card-BrUCyMoE.js", "houseplan-card.js" ], - "initialViewGzipBytes": 272469, + "initialViewGzipBytes": 271841, "lazyFiles": [ - "houseplan-assets/de-gTJXGK7s.js", - "houseplan-assets/editor-LGCA8WjH.js", - "houseplan-assets/houseplan-editor-runtime-Cu2NFP8N.js", - "houseplan-assets/houseplan-onboarding-runtime-B4PXZ4um.js", - "houseplan-assets/space-deletion-Do1Uuvoz.js" + "houseplan-assets/de-CndLXoON.js", + "houseplan-assets/editor-H80bjnWS.js", + "houseplan-assets/houseplan-editor-runtime-LLPkWHY0.js", + "houseplan-assets/houseplan-onboarding-runtime-BkWWzfSR.js", + "houseplan-assets/space-deletion-CLA5ezlL.js" ], - "lazyGzipBytes": 166314, + "lazyGzipBytes": 165904, "lazyEditorFiles": [ - "houseplan-assets/editor-LGCA8WjH.js", - "houseplan-assets/houseplan-editor-runtime-Cu2NFP8N.js", - "houseplan-assets/space-deletion-Do1Uuvoz.js" + "houseplan-assets/editor-H80bjnWS.js", + "houseplan-assets/houseplan-editor-runtime-LLPkWHY0.js", + "houseplan-assets/space-deletion-CLA5ezlL.js" ], - "lazyEditorGzipBytes": 137196, + "lazyEditorGzipBytes": 136806, "lazyOnboardingFiles": [ - "houseplan-assets/houseplan-onboarding-runtime-B4PXZ4um.js", - "houseplan-assets/space-deletion-Do1Uuvoz.js" + "houseplan-assets/houseplan-onboarding-runtime-BkWWzfSR.js", + "houseplan-assets/space-deletion-CLA5ezlL.js" ], - "lazyOnboardingGzipBytes": 7204, + "lazyOnboardingGzipBytes": 7193, "lazyLocaleFiles": [ - "houseplan-assets/de-gTJXGK7s.js" + "houseplan-assets/de-CndLXoON.js" ], - "lazyLocaleGzipBytes": 22468, + "lazyLocaleGzipBytes": 22454, "files": [ { - "path": "houseplan-assets/de-gTJXGK7s.js", - "sha256": "2ed2a8aad10d9eaa16fe3fe2e591c2d736d948b2fd35aca01fcffb33264e1284", + "path": "houseplan-assets/de-CndLXoON.js", + "sha256": "c3fb30be483664a92a555e2a916d2d6201a5d950d77385a34869445625732be1", "rawBytes": 73919, - "gzipBytes": 22468, + "gzipBytes": 22454, "isEntry": false, "imports": [], "dynamicImports": [] }, { - "path": "houseplan-assets/editor-LGCA8WjH.js", - "sha256": "0f4ce2555703ec01ee188cf84badfdee661587e849c1b604ec88354c3f94894f", + "path": "houseplan-assets/editor-H80bjnWS.js", + "sha256": "bcd9f271360a94dfbf63d5bcdf3c965aed1e1b17d0c543ac0b554d5527b90250", "rawBytes": 3831, - "gzipBytes": 1585, + "gzipBytes": 1580, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-DI__VUPO.js" + "houseplan-assets/houseplan-card-BrUCyMoE.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/houseplan-card-DI__VUPO.js", - "sha256": "35a537b289b388f34a5f6efc01a95254207be9880fa9fd931723ccfa258ad602", - "rawBytes": 960284, - "gzipBytes": 271715, + "path": "houseplan-assets/houseplan-card-BrUCyMoE.js", + "sha256": "bdcf3f7e9306428b2583f1e662541bebebcf2f106b48a53df117c6c9c54c5cde", + "rawBytes": 958245, + "gzipBytes": 271090, "isEntry": false, "imports": [], "dynamicImports": [ - "houseplan-assets/de-gTJXGK7s.js", - "houseplan-assets/editor-LGCA8WjH.js", - "houseplan-assets/houseplan-editor-runtime-Cu2NFP8N.js", - "houseplan-assets/houseplan-onboarding-runtime-B4PXZ4um.js" + "houseplan-assets/de-CndLXoON.js", + "houseplan-assets/editor-H80bjnWS.js", + "houseplan-assets/houseplan-editor-runtime-LLPkWHY0.js", + "houseplan-assets/houseplan-onboarding-runtime-BkWWzfSR.js" ] }, { - "path": "houseplan-assets/houseplan-editor-runtime-Cu2NFP8N.js", - "sha256": "4eb656ee069026534dace297817908e97d0e82e63ba1059d0c3d6c283d913344", - "rawBytes": 522188, - "gzipBytes": 135057, + "path": "houseplan-assets/houseplan-editor-runtime-LLPkWHY0.js", + "sha256": "e49282b51d104baff861b3c21261e66dcbfd58807e0db444b04f1f171499e24d", + "rawBytes": 520292, + "gzipBytes": 134677, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-DI__VUPO.js", - "houseplan-assets/space-deletion-Do1Uuvoz.js" + "houseplan-assets/houseplan-card-BrUCyMoE.js", + "houseplan-assets/space-deletion-CLA5ezlL.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/houseplan-onboarding-runtime-B4PXZ4um.js", - "sha256": "73ad6471b2395b982d233754598fcb6fb296c29b01a188cce724c2861e044187", + "path": "houseplan-assets/houseplan-onboarding-runtime-BkWWzfSR.js", + "sha256": "5446043fbf2a383f84df3751b1fd97ecac72d8bcf3c254da80ad4176538c91da", "rawBytes": 26356, - "gzipBytes": 6650, + "gzipBytes": 6644, "isEntry": false, "imports": [ - "houseplan-assets/houseplan-card-DI__VUPO.js", - "houseplan-assets/space-deletion-Do1Uuvoz.js" + "houseplan-assets/houseplan-card-BrUCyMoE.js", + "houseplan-assets/space-deletion-CLA5ezlL.js" ], "dynamicImports": [] }, { - "path": "houseplan-assets/space-deletion-Do1Uuvoz.js", - "sha256": "258cd7b7338ca746122d6afcfc63f81d34be23a7bd31f1599ed8d45ec0daa5b6", - "rawBytes": 911, - "gzipBytes": 554, + "path": "houseplan-assets/space-deletion-CLA5ezlL.js", + "sha256": "ec0519abd52ab649e2ed8f5744cc8284d96d8a83f3c9517df7f5070be63a66e9", + "rawBytes": 906, + "gzipBytes": 549, "isEntry": false, "imports": [], "dynamicImports": [] }, { "path": "houseplan-card.js", - "sha256": "031ef9710a85647066f82b62cd7a294c752493c0391cf59b1688380f7cac2a18", + "sha256": "9bb7a0cb60837b9a006d1c0d125c820ab083b270a9c6130147cd5c8c8b47cff1", "rawBytes": 1089, - "gzipBytes": 754, + "gzipBytes": 751, "isEntry": true, "imports": [ - "houseplan-assets/houseplan-card-DI__VUPO.js" + "houseplan-assets/houseplan-card-BrUCyMoE.js" ], "dynamicImports": [] } diff --git a/dist/houseplan-assets/de-CndLXoON.js b/dist/houseplan-assets/de-CndLXoON.js new file mode 100644 index 00000000..749f9cb3 --- /dev/null +++ b/dist/houseplan-assets/de-CndLXoON.js @@ -0,0 +1 @@ +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";var e={"editor.context_actions":"Aktionen: {object}","editor.tool_options":"Werkzeugoptionen: {tool}","editor.palette":"Palette: {tool}","editor.open_group":"Werkzeuggruppe: {group}","editor.group_active":"{group} — aktiv: {item}","editor.disabled_action":"{action} ist nicht verfügbar: {reason}","editor.loading":"Editor wird geladen…","editor.loading_aria":"Der Plan-Editor wird geladen","editor.load_failed":"Der Editor konnte nicht geladen werden.","editor.refresh_advice":"Seite aktualisieren und erneut versuchen.","editor.retry_advice":"Verbindung prüfen und erneut drücken.","color_picker.title":"Farbwähler","color_picker.hue":"Farbton","color_picker.saturation":"Sättigung","color_picker.value":"Helligkeit","color_picker.hex":"Hex-Farbe","color_picker.invalid_hex":"Geben Sie eine 3- oder 6-stellige Hex-Farbe ein","btn.properties":"Eigenschaften","btn.keep_as_walls":"Als Wände behalten","btn.delete_room_keep_walls":"Raum löschen, Wände behalten","btn.delete_room_with_walls":"Raum und Wände löschen","title.markup_select":"Wände, Säulen und gespeicherte Umrisse auswählen und bearbeiten","title.markup_column":"Säule: Klicken Sie auf einen Rasterpunkt, um eine quadratische Säule zu platzieren","markup.partition":"Trennwand","markup.column":"Säule","markup.hint_column":"Klicken Sie auf einen Rasterpunkt, um eine quadratische Säule zu platzieren","history.draft_segment":"Raum-Entwurfsegment hinzufügen","history.draft_merge":"Unvollständige Raumumrisse verbinden","history.draft_segment_delete":"Raum-Entwurfssegment entfernen","history.partition_add":"Trennwand hinzufügen","history.column_add":"Säule hinzufügen","history.physical_edit":"Physisches Objekt ändern","history.physical_delete":"Physisches Objekt löschen","history.physical_move":"Physisches Objekt verschieben","history.contour_to_partitions":"Umriss in geschlossene Wände umwandeln","history.wall_chain_finish":"Wandkette fertigstellen","history.wall_face_batch":"Räume aus Wänden erstellen","toast.column_duplicate":"Eine Säule mit demselben Zentrum und äußerer Größe existiert bereits","confirm.delete_draft":"Sofort den gesamten unvollständigen Raumumriss löschen?","confirm.delete_draft_segment":"Dieses Entwurfssegment löschen? Der verbleibende Umriss könnte sich in zwei teilen.","physical.partition_properties":"Eigenschaften der Trennwand","physical.column_properties":"Eigenschaften der Säule","physical.draft_properties":"Eigenschaften des Entwurfssegments","physical.shape":"Form","physical.square":"Quadrat","physical.circle":"Kreis","physical.diameter":"Durchmesser","physical.side":"Seite","physical.rotation":"Drehwinkel","physical.length":"Länge","physical.allowed_range":"Erlaubt: {min}–{max} {unit}","physical.delete_segment":"Segment löschen","physical.delete_draft":"Gesamten Umriss löschen","physical.column_size_title":"Außenmaß der per Klick platzierten quadratischen Säule (1–150 cm).","card.title":"Hausplan","count.devices":"{n} Entwicklung","empty.no_spaces":"Noch keine Bereiche.","empty.add_first":"Ersten Bereich hinzufügen und einen Grundriss hochladen.","empty.install":"Installieren Sie die House Plan-Integration und fügen Sie sie unter „Geräte & Dienste“ hinzu.","btn.add_space":"Bereich hinzufügen","btn.cancel":"Abbrechen","btn.save":"Speichern","btn.close":"Schließen","btn.delete":"Löschen","btn.edit":"Bearbeiten","btn.open_in_ha":"In HA öffnen","btn.reset":"Zurücksetzen","btn.attach":"Anhängen…","btn.upload":"Hochladen…","btn.replace":"Ersetzen…","title.zoom_in":"Zoomen","title.zoom_out":"Herauszoomen","title.zoom_fit":"Alles anpassen","title.markup":"Raum-Markierung: Gitter, Linien, Konturen","title.configure_space":"Bereich konfigurieren","title.add_space":"Bereich hinzufügen","title.markup_add":"Wände: eine durchgehende Kette zeichnen; Shift sperrt auf 45°. Werkzeugwechsel oder Verlassen des Editors beendet die Kette und wandelt sie in unabhängige Wände","title.markup_merge":"Zusammenführen: Klicken Sie auf einen Raum und dann auf den Nachbarraum, mit dem er eine Wand teilt","title.markup_split":"Raum teilen: Klicken Sie auf den Raum und dann auf zwei Punkte an seinen Wänden","title.markup_delroom":"Raum löschen: Klicken Sie in einen Raum und bestätigen Sie","title.need_plan":"Einen Grundriss hochladen","markup.add":"Wände","markup.merge":"Zusammenführen","markup.split":"Teilen","markup.resize":"Größe ändern","title.markup_resize":"Räume vergrößern/verkleinern: Ziehen Sie einen verfügbaren horizontalen oder vertikalen Wandgriff","markup.hint_resize":"Ziehen Sie einen verfügbaren Wandgriff · die Wand stoppt an der ersten unsicheren Position · Esc bricht ab · Strg+Z — rückgängig","resize.disabled.diagonal":"Diese Wand ist geneigt; Größe ändern unterstützt nur horizontale und vertikale Wände","resize.disabled.side-angle":"Eine angrenzende Wand ist geneigt; Größe ändern erfordert, dass beide angrenzenden Wände diese Wand im rechten Winkel treffen","resize.disabled.duplicate-physical-wall":"Eine separate Trennwand, unfertige Kontur oder ein Pfeiler überlappt diese Wand; entfernen oder verschieben Sie sie, bevor Sie die Größe ändern","resize.disabled.partial-shared":"Ein angrenzender Raum nutzt nur einen Teil dieser Wand, daher kann sie nicht sicher als gemeinsame Wand verschoben werden","resize.disabled.unequal-shared":"Der angrenzende Raum nutzt andere Endpunkte oder Wandlängen, daher können die Wände nicht gemeinsam sicher bewegt werden","resize.disabled.multiple-rooms":"Das Verschieben dieser Wand würde mehr als zwei Räume betreffen","resize.disabled.thickness-conflict":"Die Wandstärke kann nicht sicher beibehalten werden","resize.disabled.opening-conflict":"Eine Öffnung an dieser Wand kann nicht sicher verschoben werden","resize.disabled.invalid-geometry":"Diese Wand kann nicht ohne Änderung der Planstruktur geändert werden","resize.limit_stopped":"Wand gestoppt: der nächste Schritt würde ein Anschlusslimit verletzen","resize.commit_failed":"Größenänderung wurde abgebrochen, da der endgültige Plan die Geometrieprüfung nicht bestanden hat","resize.preview_failed":"Größenänderung am letzten sicheren Punkt gestoppt, da die Plan-Geometrie nicht beibehalten werden konnte","markup.opening":"Öffnung","markup.delete_room":"Raum löschen","history.undo":"Rückgängig","history.redo":"Wiederholen","history.undo_named":"Rückgängig: {name} (Strg+Z)","history.redo_named":"Wiederholen: {name} (Strg+Shift+Z / Strg+Y)","history.undo_empty":"Nichts zu widerrufen","history.redo_empty":"Nichts zu wiederholen","history.undone":"Rückgängig gemacht: {name}","history.redone":"Wiederholt: {name}","history.add_room":"Raum erstellen","history.split_room":"Raum teilen","history.merge_rooms":"Räume zusammenführen","history.resize_room":"Raumgröße ändern","history.wall_thickness":"Wandstärke ändern","history.add_opening":"Tür- oder Fensteröffnung hinzufügen","history.edit_opening":"Öffnung bearbeiten","history.move_opening":"Öffnung verschieben","history.delete_opening":"Öffnung löschen","history.delete_room":"Raum löschen","history.delete_room_keep_walls":"Raum löschen, Wände behalten","history.delete_room_with_walls":"Raum und Wände löschen","history.decor_add":"Dekorobjekt hinzufügen","history.decor_edit":"Dekorobjekt bearbeiten","history.decor_move":"Dekorobjekt verschieben","history.decor_transform":"Dekorobjekt transformieren","history.decor_delete":"Dekorobjekt löschen","history.backdrop_transform":"Plan-Hintergrund transformieren","opening.new":"Neue Öffnung","opening.edit":"Öffnung","opening.door":"Tür","opening.window":"Fenster","opening.gate":"Tor","opening.passage":"Offener Durchgang","opening.passage_binding_warning":"Das Speichern entfernt den Öffnungs-/Schließsensor und das Schloss.","opening.invalid_passage_fields":"Der offene Durchgang auf dem Plan „{room}“ hat nicht unterstützte Einstellungen: {fields}.","opening.type_label":"Typ","opening.length_label":"Länge, cm","opening.contact_label":"Öffnungs-/Schließsensor","opening.lock_label":"Schloss","opening.none":"— keine —","opening.search_ph":"Suche: Name oder Entitäts-ID…","opening.invert":"Geöffnet/geschlossen invertieren","opening.flip_h":"Scharnier an der anderen Zarge","opening.flip_v":"Öffnet zur anderen Seite","opening.open":"Offen","opening.closed":"Geschlossen","opening.locked":"Verriegelt","opening.unlocked":"Entriegelt","opening.state_unknown":"nicht verfügbar","opening.no_entities":"Keine Sensoren gebunden — ein statisches Symbol auf dem Plan.","toast.opening_no_wall":"Neben eine Raumwand oder eine unabhängige Wand klicken","opening.host_partition":"Unabhängige Wand","opening.partition_orphan":"Die unabhängige Wand für diese Öffnung existiert nicht mehr","opening.partition_jamb_margin":"Mindestens {distance} zwischen der Öffnung und dem Wandende lassen","opening.rebind_partition":"An eine andere unabhängige Wand anfügen","confirm.delete_partition_openings_title":"Wand und Öffnungen löschen?","confirm.delete_partition_openings_body":"Diese Wand enthält {count} Öffnung(en). Sie werden zusammen gelöscht.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.delete":"Löschen","markup.hint_points":"Punkte: {n} · Shift — 45° Schritte · Esc — Kette beenden · Ctrl+Z — Punkt rückgängig machen · Schließen eines Bereichs erstellt einen Raum","markup.hint_start":"Klicken Sie auf einen Rasterpunkt, um eine Wandkette zu starten","tip.lqi":"durchschnittliches Zigbee-Signal:","tip.area":"Bereich: {value}","info.device_header":"Gerät im Plan","info.model":"Modell","info.state":"Status","info.link":"Verbindung","info.manuals":"Handbücher","info.none":"Keine zusätzlichen Informationen","marker.new_device":"Neues Gerät","marker.name_label":"Name (im Plan angezeigt)","marker.name_ph":"Name","marker.binding_label":"An ein HA-Gerät binden","marker.binding_disabled":"in Home Assistant deaktiviert","marker.virtual_option":"Virtuelles Gerät (keine Bindung)","marker.search_ph":"Gerät/Gruppe suchen…","marker.nothing_found":"Nichts gefunden","marker.room_label":"Raum","marker.room_override":" (Platzierung überschreiben)","marker.room_choose":"— Raum auswählen —","marker.room_auto":"— nach Gerätebereich (auto) —","marker.icon_label":"Symbol","marker.icon_ph":"mdi:… (leer = automatisch)","marker.display_label":"Anzeige","display.badge":"Symbol + Zustand","display.icon_ripple":"Symbol + Zustand und Aktivität","display.static_icon":"Immer statisches Symbol","marker.display_hint":"Symbol + Zustand ändert die Platte für die Zustände Arbeit, geöffnet, Alarm und nicht verfügbar. Symbol + Zustand und Aktivität zeigt zusätzlich einen kurzen Impuls für Ereignisse und einen kontinuierlichen Impuls für laufende Arbeit, Bewegung oder Präsenz. Wert + Zustand ersetzt das Symbol durch einen eindeutigen HA-Wert. Ein statisches Symbol reagiert niemals auf Gerätezustände.","marker.display_hint_badge":"Das Symbol und die dynamische Platte zeigen den Gerätezustand ohne den üblichen Aktivitätspuls. Rote Alarme bleiben sichtbar.","marker.display_hint_icon":"Das Symbol und die dynamische Platte zeigen den Gerätezustand ohne den üblichen Aktivitätspuls. Rote Alarme bleiben sichtbar.","marker.display_hint_icon_ripple":"Das Symbol, die dynamische Platte und der Puls zeigen einen kurzen Puls für Ereignisse und einen kontinuierlichen Puls für Arbeit, Bewegung oder Anwesenheit. Rote Alarme haben eine separate Priorität.","marker.display_hint_value":"Ein eindeutiger Home Assistant-Wert ersetzt das Symbol, während die Platte weiterhin den Zustand anzeigt. Rote Alarme bleiben sichtbar.","marker.display_hint_static_icon":"Die themenabhängige Hülle und das Symbol bleiben immer gleich. Zustand, Aktivität, Nichtverfügbarkeit und Alarme verändern nicht das Erscheinungsbild.","marker.static_alarm_warning":"Dieses Gerät kann Alarme melden. Die statische Anzeige verbirgt die visuelle Alarmanzeige des Markers.","marker.preview.title":"Anzeigevorschau","marker.preview.actual":"Jetzt","marker.preview.example":"Beispiel","marker.preview.integration":"Bereitgestellt von","marker.preview.source":"Anzeigquelle","marker.preview.current_state":"Aktueller Zustand","marker.preview.result":"Auf dem Plan","marker.preview.details":"Quelldetails","marker.preview.select_source":"Ein Home-Assistant-Gerät oder eine Entität auswählen, um die tatsächliche Anzeige zu sehen.","marker.preview.unknown_provider":"Unbekannte Integration","marker.preview.virtual_provider":"House Plan · virtuelles Gerät","marker.preview.no_source":"Keine aktive Quelle","marker.preview.no_state":"Kein aktueller Zustand","marker.preview.mixed_states":"Mehrere verschiedene Zustände","marker.preview.multiple_sources":"{n}-Quellen","marker.preview.more_sources":"+{n} mehr","marker.preview.scaled":"Die Vorschau wird auf {n}% skaliert, um zu passen. Die gespeicherte Größe bleibt unverändert.","marker.preview.demo_short":"Kurze Aktivität anzeigen","marker.preview.demo_continuous":"Kontinuierliche Aktivität anzeigen","marker.preview.stop_continuous":"Kontinuierliche Aktivität stoppen","marker.preview.demo_short_notice":"Kurzes Aktivitätsbeispiel; der tatsächliche Gerätezustand bleibt unverändert.","marker.preview.demo_continuous_notice":"Kontinuierliches Aktivitätsbeispiel; der tatsächliche Gerätezustand bleibt unverändert.","marker.preview.demo_already_visible":"Der aktuelle Zustand zeigt bereits eine echte Aktivitäts- oder Alarmeffekt.","marker.preview.reduced_motion":"Systemweit reduzierte Bewegungen sind aktiviert, daher wird gewöhnliche Aktivität als Punkt angezeigt.","marker.preview.reason.neutral":"Neutrale dunkle Platte","marker.preview.reason.working":"Gelbe Platte: Das Gerät arbeitet jetzt","marker.preview.reason.working_activity":"Gelbe Platte und Aktivitätseffekt: das Gerät funktioniert jetzt","marker.preview.reason.open":"Orange Platte: physisch geöffnet oder entriegelt","marker.preview.reason.cover_icon_state":"Neutrale Platte; die Abdeckungseinheit steuert den angezeigten Zustand und das Symbol","marker.preview.reason.presence":"Aktivitätseffekt, während Präsenz erkannt wird","marker.preview.reason.event":"Kurzer Aktivitätseffekt nach einem erkannten Ereignis","marker.preview.reason.transition":"Aktivitätseffekt, während das Gerät sich bewegt oder den Zustand ändert","marker.preview.reason.media_neutral":"Mediengeräte bleiben im verfügbaren Zustand auf einer neutralen dunklen Platte","marker.preview.reason.unavailable":"Gedämpfte neutrale Platte: nicht verfügbar oder ausgeschaltet","marker.preview.reason.alarm":"Rote Alarmplatte; Alarmanzeige wird immer angezeigt","marker.preview.reason.live_states_disabled":"Live-Zustandsstil ist für diese Karte deaktiviert","marker.preview.reason.value_no_state":"Kein nutzbarer Zustandswert; stattdessen wird das Symbol angezeigt","marker.preview.reason.value_ambiguous_sources":"Mehrere mögliche Wertequellen; stattdessen wird das Symbol angezeigt","marker.preview.reason.value_non_scalar":"Die Quelle lieferte keinen einfachen Wert; stattdessen wird das Symbol angezeigt","marker.preview.reason.value_virtual":"Ein virtuelles Gerät hat keinen Home Assistant-Wert; stattdessen wird das Symbol angezeigt","marker.preview.reason.vacuum_live_plan_only":"Echtzeitposition und -spur des Staubsaugers sind nur im vollständigen Plan verfügbar","marker.preview.reason.hidden_design_preview":"Das Gerät ist im Plan ausgeblendet; diese Designvorschau bleibt sichtbar","marker.preview.reason.composite_power_source":"Der Status stammt vom Power-Entity des Geräts; Hilfsschalter werden ignoriert","marker.preview.reason.activity_display_disabled":"Der gewählte Anzeigemodus zeigt gewöhnliche Aktivitätseffekte nicht an","marker.preview.reason.ha_disabled":"Die Home Assistant-Verbindung ist deaktiviert und wird im Plan ausgeblendet","marker.preview.reason.orphaned":"Die gespeicherte Home Assistant-Verbindung konnte nicht mehr gefunden werden","marker.preview.reason.static_icon":"Statischer Modus: Der Gerätestatus ändert das Symbol nicht","marker.activity_color":"Aktivitätspulsfarbe","marker.ripple_size":"Aktivitätspulsgröße","marker.activity_alarm_note":"Farbe und Größe betreffen nur gewöhnliche Aktivität und ändern keine roten Alarme.","marker.pulse_a11y_alarm":"Alarm","marker.pulse_a11y_event":"Kürzliches Ereignis","marker.pulse_a11y_presence":"Anwesenheit erkannt","marker.pulse_a11y_transition":"Statusänderung","marker.pulse_a11y_running":"Arbeitet","marker.state_a11y_neutral":"Standardzustand","marker.state_a11y_working":"Funktionierend","marker.state_a11y_open":"Offen","marker.state_a11y_locked":"Verschlossen","marker.state_a11y_unlocked":"Entriegelt","marker.state_a11y_alarm":"Alarm","marker.state_a11y_unavailable":"Nicht verfügbar","marker.lqi_a11y_low":"LQI {value}, schwaches Signal","marker.lqi_a11y_mid":"LQI {value}, mittleres Signal","marker.lqi_a11y_high":"LQI {value}, starkes Signal","marker.size_label":"Symbolgröße / Drehung","marker.angle_label":"Drehen","marker.model_label":"Modell","marker.model_ph":"z.B. Aqara T&H","marker.link_label":"Link","marker.desc_label":"Beschreibung","marker.desc_ph":"Notizen, Spezifikationen…","marker.manuals_label":"Handbücher (PDF usw.)","marker.sub_device":"Gerät","marker.sub_z2m_group":"· Z2M Gruppe","marker.sub_group":"Gruppe","marker.sub_helper":"Helfer","space.new":"Neuer Bereich","space.header":"Bereich","space.title_label":"Titel","space.title_ph":"z.B. Garage","space.plan_label":"Grundriss (Hintergrund)","space.no_plan":"Kein Planbild","space.plan_alt":"Grundriss","room.new":"Neuer Raum","room.name_label":"Anzeigename","room.name_ph":"z.B. Terrasse","room.area_label":"Home Assistant Bereich (nicht zugewiesen)","room.no_area_option":"— kein Bereich —","room.default_name":"Raum","device.unnamed":"unbenannt","device.light_group":"Lichtgruppe","device.fallback":"Gerät","device.virtual":"Virtuelles Gerät","confirm.delete_room":'Raum "{name}" löschen?',"confirm.delete_room_title":'Raum "{name}" löschen?',"confirm.delete_room_body":"Festlegen, ob die ausschließlich zu diesem Raum gehörenden physischen Wände erhalten bleiben. Mit einem anderen Raum geteilte Wände bleiben immer erhalten.","confirm.remove_marker":"„{name}“ aus dem Plan löschen? Das Gerät verschwindet vollständig und trägt nicht mehr zu den Plandaten bei. Es kann später erneut hinzugefügt werden.","confirm.erase_decor":"Das Objekt „{kind}“ löschen? Diese Aktion kann im Editor rückgängig gemacht werden.","confirm.delete_space":"Bereich „{title}“ mit allen Räumen und Markierungen löschen?","space.delete_blocked":"Dieser Bereich wird noch von {n} Gerät(en) verwendet. Die Geräte zuerst in einen anderen Bereich verschieben oder löschen.","toast.pos_save_failed":"Position nicht gespeichert: {err}","toast.no_entity":"Das Gerät hat keine geeignete Entität","toast.ha_disabled_action":"Ein deaktiviertes Home Assistant-Objekt kann im Plan nicht verwendet werden.","toast.ha_disabled_show_device":"Ein in Home Assistant deaktiviertes Gerät kann im Plan nicht angezeigt werden. Aktivieren Sie es zuerst in Home Assistant.","toast.ha_disabled_show_entity":"Eine in Home Assistant deaktivierte Entität kann im Plan nicht angezeigt werden. Aktivieren Sie sie zuerst in Home Assistant.","toast.ha_disabled_add":"Ein deaktiviertes Home Assistant-Objekt kann nicht dem Plan hinzugefügt werden. Aktivieren Sie es zuerst in Home Assistant.","toast.ha_binding_unverified":"Der Status des Objekts konnte über das Home Assistant-Register nicht überprüft werden. Anzeige und Aktionen sind vorübergehend nicht verfügbar.","toast.markup_needs_server":"Markup ist verfügbar, nachdem die Konfiguration auf den Server verschoben wurde.","toast.space_order_changed":"Reihenfolge geändert. Wenn eine Karte ihr Stockwerk nach Nummer festlegt, überprüfen Sie diese Paneele.","toast.conflict":"Die Konfiguration wurde in einem anderen Fenster geändert — Daten aktualisiert, wiederholen Sie Ihre letzte Aktion.","toast.cfg_save_failed":"Speichern der Konfiguration fehlgeschlagen: {err}","toast.room_overlap":"Die Umrisse überlappen den Raum „{name}“ — Räume dürfen sich nicht überlappen","toast.contour_cannot_close":"Die Kontur kann nicht geschlossen werden, da sie entartet ist oder sich selbst schneidet","toast.merge_not_adjacent":"Es können nur Räume zusammengeführt werden, die eine Wand teilen","toast.rooms_merged":"Räume zu „{name}“ zusammengeführt","toast.split_pick_wall":"Beginnen Sie den Schnitt an der Wand des Raumes","toast.split_bad_cut":"Der Schnitt muss wand-zu-wand innerhalb des Raumes verlaufen, ohne Wände oder sich selbst zu kreuzen","merge.header":"Räume zusammenführen","merge.hint":"Der zusammengeführte Raum behält einen Namen und eine Fläche. Die andere Fläche wird freigegeben — ihre Geräte verlassen den Plan, bis ein anderer Raum sie beansprucht.","merge.keep":"Behalten","merge.no_area":"keine Fläche","toast.room_saved":"Raum gespeichert ({n}). Hinzugefügte Geräte: {added}. Zeichnen Sie die nächste Kontur oder verlassen Sie die Markierung.","toast.room_saved_no_area":"Raum gespeichert ({n}, keine Fläche). Zeichnen Sie die nächste Kontur oder verlassen Sie die Markierung.","toast.marker_needs_server":"Die Gerätebearbeitung ist verfügbar, nachdem die Konfiguration auf den Server verschoben wurde","toast.virtual_name_required":"Einen Namen für das virtuelle Gerät eingeben","toast.marker_saved":"Gerät gespeichert","toast.marker_removed":"Gerät aus dem Plan gelöscht","toast.integration_missing":"Die House Plan-Integration ist nicht installiert — Verwaltung nicht verfügbar","toast.plan_formats":"Unterstützte Formate: SVG, PNG, JPG, WebP","toast.plan_required":"Grundriss hochladen — erforderlich","toast.space_added_onboard":"Bereich hinzugefügt. Räume einzeichnen: Rasterpunkte anklicken und die Kontur schließen.","toast.space_added":"Bereich hinzugefügt","toast.space_saved":"Bereich gespeichert","toast.space_deleted":"Bereich gelöscht","toast.delete_failed":"Löschen fehlgeschlagen: {err}","toast.error":"Fehler: {err}","toast.toggle_target_unavailable":"Ziel „{name}“ ist nicht verfügbar — keine Aktion durchgeführt","toast.toggle_targets_unavailable":"Ziele nicht verfügbar: {names}. Keine Aktion durchgeführt","toast.file_failed":'Datei "{name}" wurde nicht hochgeladen: {err}',"toast.files_attached":"Dateien angehängt: {n}","err.unknown":"unbekannter Fehler","err.code":"Code {code}","err.too_large":"Datei größer als {mb} MB","err.bad_ext":"nicht unterstützter Typ (PDF/Bild erwartet)","err.unauthorized":"Administratorrechte erforderlich","editor.title":"Titel","editor.default_floor":"Anfangsbereich","editor.default_floor_missing":"Anfangsbereich „{id}“ existiert nicht mehr. Wählen Sie einen anderen Bereich.","editor.floor":"Fester Bereich","editor.floor_none":"— nicht fest —","editor.floor_index":"YAML-Index {index} (beibehalten)","fixed_floor.loading":"Lade den festen Bereich…","fixed_floor.invalid_title":"Der feste Bereich ist nicht verfügbar","fixed_floor.invalid_body":"Überprüfen Sie die Etage in der Kartenkonfiguration. Der konfigurierte Wert ist: {value}","editor.icon_size":"Symbolgröße, % der Planbreite","editor.show_temperature":"Temperatur anzeigen","editor.live_states":"Live-Zustände (ein/aus, offen…)","editor.show_signal":"Zigbee-Signal anzeigen (LQI)","editor.language":"Schnittstellensprache","editor.lang_auto":"Automatisch (HA-Profil)","title.icon_rules":"Symbolregeln: welche MDI-Symbole Geräte nach Namen erhalten","rules.title":"Symbolregeln","rules.hint":'Regeln werden von oben anhand von "Gerätename + Modell" (Großschreibungs-unempfindliches Regex) überprüft; das erste Match gewinnt. Wenn nichts übereinstimmt, entscheidet die Entität-Geräteklasse, dann das generische Chip-Symbol.',"rules.pattern_ph":"regex, z. B. Stecker|Steckdose","rules.icon_ph":"mdi:power-socket-de","rules.add":"Regel hinzufügen","rules.reset":"Zurücksetzen auf Standardeinstellungen","rules.test_ph":"Versuch mal einen Gerätenamen...","rules.invalid":"ungültiges regex","rules.saved":"Icon-Regeln gespeichert","btn.up":"Nach oben","btn.down":"Nach unten","tap.info":"Gerätekarte","tap.more_info":"HA Mehr-Info-Dialog","tap.toggle":"Zustand umschalten","marker.tap_label":"Tap-Aktion für dieses Gerät","tap.toggle_note":"Der aufgelöste Zustand ist unten dargestellt. Sichere Geräte werden niemals aus dem Plan umgeschaltet.","import.title":"Bereiche aus HA-Etagen erstellen","import.hint":"Home Assistant kennt diese Etagen bereits. Die Etagen auswählen, die zu Planbereichen werden sollen; anschließend für jeden Bereich einen Grundriss hochladen. Die Räume werden danach von Hand eingezeichnet.","import.start":"{n} Bereich(e) erstellen","import.manual":"Von Grund auf neu starten","import.progress":"Etage {i} von {n}","import.done":"Bereiche erstellt. Räume einzeichnen: Rasterpunkte anklicken und die Kontur schließen.","btn.skip":"Überspringen","space.scale_label":"Maßstab (Rasterzellen-Größe)","space.scale_unit":"cm pro Zelle","space.scale_unit_imperial":"Zoll pro Zelle","space.display_section":"Anzeige","space.show_borders":"Raumgrenzen immer anzeigen","space.zero_wall_style":"Wände ohne Dicke","space.zero_wall_dashed":"Gestrichelt","space.zero_wall_solid":"Durchgezogen","space.zero_wall_help":"Gestrichelte Wände lassen Licht durch. Durchgezogene Wände blockieren Licht auch bei einer Dicke von 0.","space.show_names":"Raumnamen anzeigen (zum Verschieben ziehen)","space.room_color":"Farbe der Begrenzung & des Namens","space.opacity":"Deckkraft","space.fill_label":"Raumausfüllung","fill.none":"Keine","fill.lqi":"Zigbee-Signal","fill.light":"Lichter","fill.custom":"Benutzerdefinierte Farbe","space.custom_fill":"Füllfarbe","space.source_file":"Ich habe einen Grundriss als Bild","space.source_draw":"Kein Bild – ich werde die Räume von Hand umreißen","fill.temp":"Temperatur","tip.temp_avg":"Durchschnittstemperatur:","tip.hum_avg":"Durchschnittliche Luftfeuchtigkeit:","space_card.button":"Grundriss öffnen","space_card.not_found":"Bereich „{id}“ nicht gefunden","space_card.loading":"Laden…","continuity.restore_plan":"Grundriss wiederherstellen…","continuity.restore_connection":"Geräteverbindung wiederherstellen…","continuity.retry":"Erneut versuchen","editor.space":"Bereich","editor.show_button":"Schaltfläche anzeigen","editor.button_label":"Beschriftung der Schaltfläche","editor.button_target":"Ziel-Dashboard-Pfad","marker.sub_entity":"Entität","title.general_settings":"Allgemeine Einstellungen","gs.title":"Allgemeine Einstellungen","gs.hint":"Füllfarben gelten für jeden Bereich; jede Farbe hat ihre eigene Deckkraft. Der Füllmodus wird in den Einstellungen des jeweiligen Bereichs festgelegt.","gs.light_group":"Füllung: Licht","gs.light_on":"Lichter an","gs.light_off":"Alle Lichter aus","gs.temp_group":"Füllung: Temperatur","gs.temp_cold":"Kalt","gs.temp_ok":"Angenehm","gs.temp_hot":"Heiß","gs.lqi_group":"Füllung: Zigbee-Signal","gs.lqi_low":"Schwaches Signal","gs.lqi_high":"Starkes Signal","gs.reset":"Auf Standard zurücksetzen","gs.saved":"Allgemeine Einstellungen gespeichert","space.show_lqi":"Zigbee-Signal (LQI) neben Geräten anzeigen","space.hide_decor":"Dekorationsschicht ausblenden","space.hide_decor_tip":"Linien, Formen, Beschriftungen und Möbel bleiben an ihrem Platz — im Hintergrundeditor sichtbar, aber nicht auf dem Plan.","space.hide_openings":"Öffnungen ausblenden","space.hide_openings_tip":"Tür-, Fenster- und Tor-Symbole werden nicht gezeichnet, aber die Öffnungen funktionieren weiterhin: Licht fällt hindurch, die Sonne kommt durch ein Fenster herein, Kontaktsensoren öffnen sie weiterhin. Der Planeditor zeigt sie immer an.","gs.light_none":"Keine Lichtquellen","mode.plan":"Planeditor","mode.devices":"Geräteeditor","display.value":"Wert + Zustand","marker.subarea":"kein Bereich, manuell","device.new":"Neues Gerät — Editor öffnen, um zu schließen","opening.unlock_action":"Entsperren","opening.lock_action":"Sperren","opening.lock_pending":"Wird ausgeführt…","title.close_editor":"Editor schließen (zur Ansicht zurück)","devbar.rules":"Symbolregeln","device_inbox.button":"Geräte","device_inbox.title":"Geräte auf dem Plan","device_inbox.search":"Geräte, Entitäten und Integrationen suchen…","device_inbox.add_virtual":"Virtuelles Gerät hinzufügen","device_inbox.tab_on_plan":"Auf Plan","device_inbox.tab_available":"Verfügbar","device_inbox.tab_hidden":"Versteckt","device_inbox.tab_readd":"Wieder verfügbar","device_inbox.only_new":"Nur neu","device_inbox.show_entities":"Entitäten anzeigen","device_inbox.show_hidden":"Versteckte auf Plan anzeigen","device_inbox.new":"Neu","device_inbox.find":"Auf dem Plan finden","device_inbox.edit":"Bearbeiten","device_inbox.hide":"Ausblenden","device_inbox.show":"Anzeigen","device_inbox.add":"Hinzufügen","device_inbox.readd":"Wieder hinzufügen","device_inbox.hide_available":"Aus der Liste ausblenden","device_inbox.show_more":"Mehr anzeigen","device_inbox.more_actions":"Weitere Aktionen","device_inbox.find_hidden_hint":"Zuerst „Versteckte auf Plan anzeigen“ aktivieren","device_inbox.show_disabled":"Diese Bindung in Home Assistant aktivieren, bevor sie angezeigt wird","device_inbox.empty_on_plan":"Es befinden sich noch keine passenden Geräte auf dem Plan.","device_inbox.empty_available":"Es sind keine Geräte zum Hinzufügen verfügbar.","device_inbox.empty_hidden":"Es gibt keine versteckten Geräte.","device_inbox.empty_readd":"Es sind keine entfernten Geräte verfügbar, um sie erneut hinzuzufügen.","device_inbox.reason_visible_auto":"Automatisch erkannt","device_inbox.reason_visible_explicit":"Explizit hinzugefügt","device_inbox.reason_manual_hidden":"Vom Benutzer versteckt","device_inbox.reason_automatic_hidden":"Automatisch versteckt","device_inbox.reason_service_entry":"Nur Service-Registry-Eintrag","device_inbox.reason_excluded_integration":"Integration durch Gerätefilter ausgeschlossen","device_inbox.reason_excluded_domain":"Nicht-räumlicher Entitätstyp","device_inbox.reason_grouped_light":"Dargestellt durch eine Raumlichtgruppe","device_inbox.reason_represented_by_parent":"Dargestellt durch sein übergeordnetes Gerät","device_inbox.reason_removed":"Zuvor aus dem Plan entfernt","device_inbox.reason_available":"Zum Hinzufügen zum Plan verfügbar","device_inbox.reason_no_bound_room":"HA-Bereich ist nicht mit einem Planraum verknüpft","device_inbox.status_ha_disabled":"In Home Assistant deaktiviert","device_inbox.status_orphaned":"Bindung ist in Home Assistant nicht mehr vorhanden","device_inbox.status_unverified":"Home Assistant-Register vorübergehend nicht verfügbar","device_inbox.saved":"Geräteliste aktualisiert","space.roomcard_section":"Raumkarte zeigt:","space.label_temp":"Temperatur","space.label_hum":"Luftfeuchtigkeit","space.label_lqi":"Durchschnittliches Zigbee-Signal","space.label_light":"Lichter ein/aus","roomcard.light_on":"Ein","roomcard.light_off":"Aus","roomcard.light_partial":"{on} von {total}","toast.split_pick_inside":"Zwischenliegende Schnittpunkte müssen innerhalb des Raumes liegen","mode.decor":"Hintergrundeditor","decor.select":"Auswählen","decor.line":"Linie","decor.rect":"Rechteck","decor.ellipse":"Oval","decor.text":"Text","decor.erase":"Löschen","decor.erase_confirm_title":"Objekt löschen?","decor.color":"Farbe","decor.width":"Linienbreite","decor.line_style":"Linienstil","decor.line_style_solid":"Durchgehend","decor.line_style_dashed":"Gepunktet","decor.fill":"Füllen","decor.fill_color":"Füllfarbe","decor.length":"Länge","decor.size":"Größe","decor.angle":"Rotationswinkel, °","decor.text_size":"Textgröße","decor.backdrop_properties":"Eigenschaften des Planhintergrunds","decor.text_title":"Textbeschriftung","decor.object_title":"{kind} bearbeiten","decor.text_label":"Text","decor.live_group":"HA-Variable einfügen","decor.live_entity":"Entität","decor.live_entity_ph":"Wählen Sie eine Entität","decor.live_attr":"Wert","decor.live_attr_ph":"Wählen Sie Status oder Attribut","decor.live_state":"Status","decor.backdrop":"Hintergrundbild","decor.backdrop_hint":"Ziehen zum Verschieben; eine Ecke ziehen zum Größenändern; den oberen Griff zum Drehen verwenden. Shift ändert das Verhältnis oder befreit den Winkel.","decor.backdrop_reset":"Bild zurücksetzen","decor.backdrop_reset_done":"Das Bild ist wieder an seinem ursprünglichen Platz und in seiner ursprünglichen Größe","marker.icon_auto":"Auto: {icon} (nach Symbolregeln; wählen Sie eines zur Überschreibung)","marker.icon_pin_auto":"Anheften","mode.plan_tip":"Planungseditor — die Geometrie des Hauses: Räume zeichnen und teilen/zusammenführen, sie mit HA-Bereichen verbinden, Türen, Fenster und Tore platzieren, Raumkarten verschieben, Maßstab festlegen","mode.devices_tip":"Geräteeditor — alles über Symbole: ziehen zum Positionieren, klicken zum Bearbeiten von Bindung/Symbol/Anzeige, virtuelle Geräte hinzufügen, Symbolregeln","mode.decor_tip":"Hintergrundeditor — rein visuelle Dekoration unter dem Plan: Linien, Rechtecke, Ellipsen und Textbeschriftungen, die niemals auf Klicks reagieren","space.glow_enabled":"Lichtquellen-Glühen","gs.glow_group":"Glow von Lichtquellen","gs.glow_base":"Grunddunkelheit des Hauses","gs.glow_light":"Standardlichtfarbe / Intensität","gs.wall_group":"Wände","gs.wall_fill":"Wandfüllung","gs.glow_radius":"Glow-Radius","gs.unit_m":"m","gs.unit_ft":"ft","marker.controls_label":"Steuert andere Lichtquellen","marker.controls_hint":"Mit der Tippen-Aktion „Umschalten“ wechselt ein Klick jede hier hinzugefügte Quelle. Die eigene zugeordnete Entität des Markers wird direkt gesteuert und kann nicht hinzugefügt werden; verwenden Sie den untenstehenden Schalter, um ihn als Licht zu klassifizieren.","marker.controls_filter":"Suchlichter und Schalter…","info.controls":"Steuerungen","marker.glow_radius_label":"Leuchtradius","marker.glow_radius.help":"Legt den Leuchtradius in Metern oder Fuß fest; ein leerer Wert verwendet den Radius aus den allgemeinen Einstellungen.","marker.glow_radius.help.aria":"Hilfe: Leuchtradius","markup.wallthick":"Dicke","markup.select":"Auswählen","title.markup_wallthick":"Dicke — klicken Sie auf eine Wand, um ihre Dicke von 0 bis 100 cm festzulegen.","markup.hint_wallthick":"klicken Sie auf eine Wand · Esc schließt ohne Anwendung","wallthick.field":"Dicke","wallthick.unit_cm":"cm","wallthick.unit_in":"in","wallthick.apply_room":"Auf alle Wände dieses Raums anwenden","markup.draw_wall_title":"Dicke jedes neuen Wandsegments (0–100 cm). Gemeinsame Wände behalten den bestehenden Wert.","room.queue_progress":"Raum {current} von {total}","toast.wall_rooms_saved":"Erstellte Räume: {n}","toast.wall_chain_saved":"Wandkette gespeichert","toast.wallthick_pick":"Eine Wand anklicken","toast.wallthick_set":"Wandstärke eingestellt","toast.wallthick_cleared":"Wandstärke entfernt","toast.physical_range":"Einen Wert von {min} bis {max} {unit} eingeben","toast.zero_wall_opening_conflict":"Entfernen Sie zuerst die Öffnung an diesem Wandsegment.","toast.zero_wall_ambiguous":"Das Wandsegment ist mehrdeutig. Vereinfachen oder passen Sie den Anschluss an.","toast.zero_wall_migration_blocked":"Der Bereich wurde nicht konvertiert: {reason}. Es wurden keine Daten geändert.","toast.physical_angle":"Einen Drehwinkel von 0° bis unter 90° eingeben","toast.physical_limit":"Der Bereich hat das Limit für diesen Geometrietyp erreicht","toast.geometry_unsafe":"Änderung abgebrochen: Wandgeometrie konnte nicht sicher erstellt werden.","junction.limit_angle":"Der Winkel zwischen den Wänden ist zu spitz: {actual}°, mindestens {limit}°.","junction.limit_valence":"Zu viele Wände treffen in einem Knoten aufeinander: {actual}, maximal {limit}.","junction.limit_length":"Das Wandsegment ist zu kurz: {actual} cm, mindestens {limit} cm.","junction.limit_distance":"Wände und Knoten sind zu dicht beieinander: {actual} cm, Minimum {limit} cm.","junction.limit_clearance":"Kein Wohnbereich ist übrig: {actual} cm², Minimum {limit} cm².","junction.limit_check_failed":"Die Überprüfung der Verbindungen konnte nicht durchgeführt werden — die Änderung wurde nicht gespeichert.","toast.wall_model_migration_blocked":"Das Wandmodell konnte nicht aktualisiert werden: {reason}. Der Plan wurde nicht geändert. Führen Sie „Pläne optimieren“ aus; wenn der Fehler erneut auftritt, beheben Sie die widersprüchliche Wandgeometrie.","toast.wall_model_client_outdated":"Aktualisieren Sie die Karte und laden Sie die Seite neu, bevor Sie den Plan bearbeiten.","wall_model.reason.invalid-room":"ungültiger Raumkontur","wall_model.reason.zero-length":"Wandsegment mit null Länge","wall_model.reason.third-owner":"Wand, die von mehr als zwei Räumen geteilt wird","wall_model.reason.duplicate-id":"widersprüchliche Wandkennungen","wall_model.reason.thickness-conflict":"widersprüchliche Wandstärkenwerte","wall_model.reason.opening-host":"Öffnung kann nicht einer Wand zugewiesen werden","toast.delete_room_pick":"Klicken Sie in den Raum, den Sie löschen möchten","toast.plan_snap_ambiguous":"Zoomen Sie hinein, um den Wandknoten auszuwählen","toast.wall_repair_ambiguous":"Der Raumumriss hat mehr als eine mögliche Verbindung. Zoomen Sie hinein und verbinden Sie ihn explizit.","toast.wall_repair_too_large":"Die Lücke ist größer als 2 cm. Verbinden Sie die Wände, bevor Sie den Raum erstellen.","toast.wall_repair_changed":"Die Wandgeometrie hat sich geändert. Versuchen Sie erneut, den Raum zu erstellen.","toast.opening_on_zero_wall":"Öffnungen können nicht auf einer Wand mit null Dicke sitzen.","marker.from_ha_option":"Wählen Sie aus der HA-Liste.","marker.show_entities":"Entitäten anzeigen.","marker.show_entities_tip":"Fügt nicht nur Geräte zur Liste hinzu, sondern auch alle ihre Entitäten.","marker.pick_ph":"Wählen Sie ein Gerät…","room.open_area":"Öffnen Sie den HA-Bereich.","view.volumetric":"Volumetrische Ansicht.","view.flat":"Flache Ansicht.","kiosk.title":"Die Größen dieses Bildschirms.","kiosk.hint":"Nur auf diesem Gerät gespeichert – jedes Wandtablet oder TV kann seine eigenen komfortablen Größen haben.","kiosk.icon_scale":"Gerätesymbolgröße.","kiosk.font_scale":"Textgröße der Raumkarte.","editor.kiosk":"Wandgeräte- (Kiosk-)Modus.","editor.cycle":"Bereiche automatisch alle N Sekunden wechseln (Kiosk, 0 = aus)","room.settings_title":"Raumeinstellungen.","room.settings_section":"Raumeinstellungen (überschreibt den Bereich)","room.fill_label":"Diesen Raum ausfüllen","fill.inherit":"Als den Bereich","room.custom_fill_space":"Bereichsfarbe","room.custom_fill_own":"Raumfarbe","room.temp_src_label":"Temperaturquelle","room.hum_src_label":"Luftfeuchtigkeitsquelle","room.src_average":"Durchschnitt über die Sensoren des Raums (Standard)","room.src_pick":"Ein bestimmtes HA-Gerät oder Entität","room.src_ph":"Quelle wählen…","toast.room_updated":"Raum aktualisiert","space.card_font":"Schriftgröße der Raumkarte (gesamter Bereich)","room.sizes_section":"Schriftgrößen","room.name_scale":"Raumname Größe","room.label_scale":"Metrikgröße","preview.room_name":"Wohnzimmer","toast.cfg_reload_failed":"Der Plan konnte nicht vom Server neu geladen werden: {err}","toast.locale_load_failed":"Das Sprachpaket konnte nicht geladen werden. Bis zum Neuladen der Seite wird Englisch verwendet.","room.settings_short":"Raumeinstellungen","room.unnamed":"Unbenannter Raum","marker.use_climate_temp":"Geräte-Temperatur im Raum berücksichtigen","marker.use_climate_temp_tip":"Fügt die aktuelle Temperatur einer Klimaanlage oder eines Thermostats zum Raumdurchschnitt hinzu. Das externe Wert-Label unten separat konfigurieren.","marker.value_badge_title":"Wert-Label","marker.value_badge.help":"Zeigt einen ausgewählten Wert neben dem Symbol an. Dies beeinflusst nicht die Raumkennzahlen, Licht, Glanz oder die Tippaktion.","marker.value_badge.help.aria":"Hilfe: Gerätewert-Badge","marker.value_badge_enabled":"Zeige ein Wert-Badge","marker.value_badge_source":"Wert","marker.value_badge_source.help":"Wählen Sie einen bestimmten Zustand, ein unterstütztes Attribut oder einen abgeleiteten Wert dieses Geräts.","marker.value_badge_source.help.aria":"Hilfe: Quelle des Wert-Badges","marker.value_badge_position":"Position","marker.value_badge_position.help":"Die gewählte Seite bleibt fest und dreht sich nicht automatisch an einem Planrand.","marker.value_badge_position.help.aria":"Hilfe: Position des Wert-Badges","marker.value_badge_right":"Rechts","marker.value_badge_bottom":"Unten","marker.value_badge_left":"Links","marker.value_badge_top":"Oben","marker.value_badge_empty":"Für dieses Gerät stehen keine Werte zur Verfügung","marker.value_badge_static":"Ein statisches Symbol zeigt keine Live-Werte an. Die Einstellung wird beibehalten.","marker.value_badge_missing":"Quelle nicht verfügbar","marker.value_badge_missing_hint":"Die gespeicherte Quelle ist derzeit nicht verfügbar. Behalten Sie sie bei, deaktivieren Sie das Badge oder wählen Sie einen anderen Wert.","marker.value_badge_duplicate":"Derselbe Wert wird bereits im Symbol angezeigt.","marker.value_badge_state":"Status · {name}","marker.value_badge_marker_state":"Lichtquellstatus · {name}","marker.value_badge_lqi":"Durchschnittliche Zigbee-Signalqualität","marker.value_badge_attr_current_temperature":"Aktuelle Temperatur · {name}","marker.value_badge_attr_temperature":"Zieltemperatur · {name}","marker.value_badge_attr_current_humidity":"Aktuelle Luftfeuchtigkeit · {name}","marker.value_badge_attr_humidity":"Luftfeuchtigkeit · {name}","marker.value_badge_attr_current_position":"Position · {name}","marker.value_badge_attr_percentage":"Geschwindigkeit · {name}","marker.value_badge_attr_brightness":"Helligkeit · {name}","marker.value_badge_attr_volume_level":"Lautstärke · {name}","marker.value_badge_attr_battery_level":"Batterie · {name}","marker.value_badge_attr_fan_speed":"Lüftergeschwindigkeit · {name}","marker.light_role_label":"Ist dieses Gerät eine Lichtquelle?","marker.light_role.help":"Steuert, ob dieser Marker selbst eine räumliche Lichtquelle ist. Verknüpfte Lichter oben bleiben unabhängige Raumlichtsteuerungen.","marker.light_role.help.aria":"Hilfe: ob dieses Gerät eine Lichtquelle ist","marker.light_role_auto_yes":"Automatisch (Lichtquelle)","marker.light_role_auto_no":"Automatisch (keine Lichtquelle)","marker.light_role_always":"Immer eine Lichtquelle","marker.light_role_never":"Nie eine Lichtquelle","marker.light_entity_label":"Führende Lichtereinheit","marker.light_entity.help":"Für ein Verbundgerät wählen Sie die Entität, deren Zustand, Farbe und Helligkeit diese Planquelle darstellen. Der automatische Rückgriff bleibt mit älteren Plänen kompatibel.","marker.light_entity.help.aria":"Hilfe: führende Lichtentität","marker.light_entity_auto":"Automatisch ({entity})","marker.light_entity_none":"keine steuerbare Entität","marker.light_entity_missing":"Die gespeicherte Entität {entity} ist nicht verfügbar. House Plan verwendet vorübergehend {fallback}; die gespeicherte Auswahl wird wiederhergestellt, wenn sie zurückkehrt.","marker.toggle_entity_label":"Zu toggelnde Entität","marker.toggle_entity.help":"Für ein Verbundgerät wählen Sie das genaue eigene Licht oder den Schalter, der durch Tippen bedient wird. Automatisch behält die vorherigen Zielregeln bei und ist unabhängig von der führenden Lichtentität.","marker.toggle_entity.help.aria":"Hilfe: zu toggelnde Entität","marker.toggle_entity_auto":"Automatisch ({entity})","marker.toggle_entity_none":"keine eigene steuerbare Entität","marker.toggle_entity_missing":"Die gespeicherte Entität {entity} ist nicht mehr unter den auswählbaren Kanälen dieses Markers. House Plan verwendet vorübergehend {fallback}; die gespeicherte Auswahl wird wiederhergestellt, wenn sie zurückkehrt.","marker.glow_color_label":"Leuchtfarbe und Helligkeit","marker.glow_mode.help":"Verwenden Sie Live-Quellwerte, überschreiben Sie nur deren Farbe oder fixieren Sie sowohl Farbe als auch Helligkeit. Das Minimum beträgt 1 %; um die Quelle zu deaktivieren, wählen Sie „Nie“.","marker.glow_mode.help.aria":"Hilfe: Leuchtfarbe und Helligkeit","marker.glow_mode_auto":"Von Quelle","marker.glow_mode_color":"Farbe einstellen","marker.glow_mode_fixed":"Farbe und Helligkeit einstellen","marker.glow_color":"Leuchtfarbe","marker.glow_brightness":"Helligkeit","marker.glow_disabled_never":"Leuchteinstellungen sind nicht verfügbar, da dieser Marker ausdrücklich keine Lichtquelle ist.","marker.glow_disabled_auto":"Im Automatikmodus wurde keine räumliche Lichtquelle für diesen Marker gefunden.","marker.glow_disabled_no_entity":"Keine aktive steuerbare Home Assistant-Entität ist für diese räumliche Quelle verfügbar.","marker.glow_passive_hint":"Diese Quelle hat keine eigenen Home Assistant-Daten. Stellen Sie ihre Farbe und Helligkeit manuell ein; ihr Radius bleibt verfügbar.","marker.control_broken":"Gespeicherte Quelle fehlt oder ist nicht mehr als Licht markiert","marker.control_missing_label":"Fehlendes Planlicht","marker.control_passive":"passive Quelle","toast.marker_control_cycle":"Dieser Link würde eine kreisförmige Kette von Lichtsteuerungen erzeugen.","toast.marker_binding_required":"Wählen Sie ein Home Assistant-Gerät, bevor Sie eine andere Lichtquelle verlinken.","confirm.unlock":"„{name}“ entsperren?","toast.files_migrate_failed":"Anhänge konnten nicht zur neuen Bindung verschoben werden, Links zeigen weiterhin auf die alten Dateien: {err}","space.pick_saved":"Bereits hochgeladen","space.pick_saved_hint":"Auf dem Server gespeicherte Pläne, einschließlich solcher, die Sie zuvor getrennt haben","space.no_saved":"Noch keine Pläne auf dem Server gespeichert.","space.loading":"Laden…","space.used_by":"in Benutzung: {list}","space.in_use":"Ein Bereich verwendet diesen Plan noch — zuerst die Verknüpfung lösen","btn.use":"Verwenden","confirm.delete_plan":"Plandatei „{name}“ vom Server löschen? Dies kann nicht rückgängig gemacht werden.","toast.plans_list_failed":"Konnte die gespeicherten Pläne nicht auflisten: {err}","toast.plan_delete_failed":"Konnte den Plan nicht löschen: {err}","marker.hide":"Ausblenden","marker.hide_tip":'Das Gerät wird nach dem Speichern aus dem Plan verschwinden, aber weiterhin zum Signalsignal des Raums zählen. Stellen Sie es über den Katalog "Geräte" im Geräte-Editor wieder her.',"marker.show":"Anzeigen","marker.show_tip":"Das Gerät wird nach dem Speichern wieder im Plan erscheinen.","marker.hidden_ghost":"Vom Benutzer ausgeblendetes Gerät","marker.ha_disabled_device":"Das Gerät ist in Home Assistant deaktiviert und im Plan ausgeblendet.","marker.ha_disabled_entity":"Die Entität ist in Home Assistant deaktiviert und im Plan ausgeblendet.","marker.ha_disabled_all_entities":"Das Gerät hat keine aktiven Home Assistant-Entitäten, daher ist es im Plan ausgeblendet.","marker.ha_registry_limited":"Das vollständige Home Assistant-Register ist für diesen Benutzer nicht verfügbar. Das nicht verifizierte Objekt kann vorerst nicht angezeigt oder verwendet werden.","marker.delete_tip":"Löschen Sie das Gerät vollständig aus dem Plan und allen Aggregaten. Sie können es später wieder hinzufügen.","tap.run":"Führen Sie Automation/Skript/Szene aus","marker.run_target_label":"Was ausführen","marker.run_search_ph":"Suchen: Automation, Skript oder Szene…","marker.run_target_gone":"Ziel {id} nicht gefunden — erneut auswählen","marker.tap_confirm":"Um Bestätigung bitten","marker.tap_confirm_tip":"Vor der Ausführung ein Bestätigungsdialogfeld anzeigen — eine Vorsichtsmaßnahme gegen versehentliche Berührungen.","marker.toggle_hint_single":"Ziel: {name} ({id}).","marker.virtual_light_target":"Virtuelles Licht: {name}.","marker.virtual_light_current":"Manueller Zustand: {state} → {effect}.","marker.virtual_light_state_on":"ein","marker.virtual_light_state_off":"aus","marker.toggle_hint_group":"Wird {count}-Quelle(n) umschalten: {names}.","marker.toggle_hint_current":"Jetzt: {state} → {effect}.","marker.toggle_hint_group_current":"Derzeit an: {on} von {count} → {effect}.","marker.toggle_hint_skipped":"Wird übersprungen ({count}): {targets}.","marker.toggle_effect_turn_on":"wird eingeschaltet","marker.toggle_effect_turn_off":"wird ausgeschaltet","marker.toggle_effect_open":"wird geöffnet","marker.toggle_effect_close":"wird geschlossen","marker.toggle_effect_stop":"wird gestoppt","marker.toggle_effect_toggle":"Zustand wird umgeschaltet","marker.toggle_skip_missing":"nicht gefunden","marker.toggle_skip_ha_disabled":"in HA deaktiviert","marker.toggle_skip_unavailable":"nicht verfügbar","marker.toggle_skip_unsupported":"Umschalten wird nicht unterstützt","marker.toggle_skip_secure":"aus Sicherheitsgründen blockiert","marker.toggle_none_no_binding":"Dieses Gerät hat keine Bindung, daher gibt es keinen Zustand, der umgeschaltet werden könnte. Tippen bewirkt nichts.","marker.toggle_none_no_actionable_entity":"Dieses Gerät hat keinen Zustand, der umgeschaltet werden könnte. Tippen bewirkt nichts.","marker.toggle_none_configured_targets_missing":"Die konfigurierten Ziele sind nicht verfügbar. Die eigene Entität des Geräts wird nicht ersetzt.","marker.toggle_none_ha_disabled":"Das Ziel ist in Home Assistant deaktiviert und kann im Plan nicht verwendet werden.","marker.toggle_none_unavailable":"Das Ziel ist derzeit nicht verfügbar. Tippen bewirkt nichts.","marker.toggle_none_unsupported":"Home Assistant bietet keine sichere Umschaltfunktion für dieses Gerät. Tippen bewirkt nichts.","marker.toggle_none_secure":"Das Umschalten von Schlössern, Alarmen und gesicherten Toren über den Plan ist aus Sicherheitsgründen gesperrt.","run.automation":"Automatisierung","run.script":"Skript","run.scene":"Szene","confirm.tap_run":'"{name}" ausführen?',"confirm.tap_toggle":'"{name}" umschalten?',"confirm.current_state":"Aktueller Zustand: {state}","confirm.expected_state":"Nach dem Umschalten: {state}","confirm.group_current":"an {on} von {total}","confirm.group_all_on":"alle sind eingeschaltet","confirm.group_all_off":"alle sind ausgeschaltet","confirm.unavailable_targets":"Nicht verfügbar: {count}","confirm.expected_by_ha":"Home Assistant ermittelt den Zustand","confirm.state_on":"Ein","confirm.state_off":"Aus","confirm.state_open":"Offen","confirm.state_closed":"Geschlossen","confirm.state_opening":"Wird geöffnet","confirm.state_closing":"Wird geschlossen","confirm.state_stopped":"Gestoppt","confirm.state_unknown":"Unbekannt","toast.run_started":"Gestartet: {name}","toast.run_target_missing":"Ausführungsziel nicht gefunden — überprüfen Sie die Geräteeinstellungen","toast.run_target_required":"Wählen Sie eine Automatisierung, ein Skript oder eine Szene aus","toast.tap_target_changed":"Das Ziel der Aktion hat sich geändert. Versuchen Sie es erneut.","toast.virtual_light_toggle_failed":"Das virtuelle Licht konnte nicht umgeschaltet werden: {err}","toast.value_badge_source_required":"Einen Wert für den Badge auswählen","btn.run":"Ausführen","vac.section":"Roboterstaubsauger: aktuelle Position","vac.autocal":"Automatisch einrichten","vac.live":"Aktuelle Position im Plan","vac.trail":"Roboterpfad anzeigen","vac.cal_maps":"Kalibrierte Karten: {maps}","vac.autocal_no_rooms":'Die Integration meldet keine Raumliste — öffnen Sie "Manuell anpassen"',"vac.autocal_no_match":'Raumnamen stimmten nicht überein (mindestens 3 müssen übereinstimmen) — öffnen Sie "Manuell anpassen"',"vac.autocal_done":"Fertig: über {rooms} Räume zugeordnet. Eine Reinigung starten und das Ergebnis prüfen.","vac.cal_need_pos":"Der Roboter meldet keine Koordinaten — starten Sie eine Reinigung und pausieren Sie sie","vac.cal_done":"Kalibrierung gespeichert. Eine Reinigung starten und das Ergebnis prüfen.","vac.cal_cancelled":"Kalibrierung abgebrochen","vac.fit":"Manuell anpassen","vac.fit_hint":"Roboterkarte an die richtige Position ziehen und an den Ecken skalieren","vac.fit_rotate":"90° drehen","vac.fit_mirror":"Spiegeln","vac.trail_never":"Nie","vac.trail_cleaning":"Beim Reinigen","vac.trail_always":"Immer","gs.bg_group":"Bühnenhintergrund","gs.bg_color":"Hintergrund um den Plan","gs.bg_default":"Standardthema","gs.bg_theme":"Standardthema","gs.bg_mode":"Planhintergrund","gs.bg_static":"Statische Farbe","gs.bg_daynight":"Folgt der Sonne","gs.bg_daynight_hint":"Der Hintergrund wechselt durch Morgendämmerung, Tag, Abenddämmerung und Nacht mithilfe von sun.sun oder Ihrer lokalen Uhr, wenn keine Sonnendaten verfügbar sind. Für den Hintergrund ist kein Kompass erforderlich.","gs.sun_group":"Sonne","gs.sun_missing":"Die sun.sun-Entität wurde nicht gefunden — der Hintergrund folgt Ihrer lokalen Uhr; Fensterstrahlen sind nicht verfügbar.","gs.north":"Norden auf dem Plan","gs.north_ph":"nicht gesetzt","gs.north_hint":"Norden nur für Fensterstrahlen einstellen (1° Schritte, 15° mit Shift); der Sonnenhintergrund funktioniert auch ohne ihn.","gs.north_clear":"Löschen","gs.north_letter":"N","gs.sun_rays":"Sonnenlicht durch Fenster","gs.about_group":"Über","gs.about_version":"House Plan Card v{v}","gs.about_github":"GitHub · Dokumentation & Probleme","gs.about_telegram":"Telegram-Chat","space.bg_color":"Hintergrund rund um den Plan","space.bg_inherit":"Allgemein erben","space.bg_inherited":"erbt allgemeine Einstellungen","space.bg_mode":"Planhintergrund","space.north":"Norden auf dem Plan (überschreiben)","space.north_inherited":"geerbt: {v}","space.sun_rays":"Sonnenlicht durch Fenster","space.sun_inherit":"Allgemein erben","space.sun_on":"Ein","space.sun_off":"Aus","canvas.far_objects":"{n} Objekt(e) weit vom Plan entfernt","canvas.show_far":"Anzeigen","canvas.home_tip":"Der Plan ist dort drüben — klicken, um ihn anzupassen","gs.grid_group":"Planwartung","gs.grid_hint":"Aktualisiert Datenmodelle, richtet Planelemente am Raster aus und fasst redundante Wandfragmente zusammen. Ein exakter Bericht wird angezeigt, bevor etwas gespeichert wird.","gs.align_all":"Pläne optimieren","gs.align_title":"Pläne optimieren","gs.align_none":"Alle Pläne verwenden bereits das aktuelle optimierte Datenmodell.","gs.optimize_no_automatic_changes":"Es gibt keine automatischen Änderungen, die angewendet werden müssen. Überprüfen Sie die unten stehenden Punkte.","gs.align_count":"{n} von {total} Elementen werden sich um höchstens {cm} cm bewegen.","gs.align_where":"Die größte Verschiebung ist in „{s}“.","gs.align_turned":"Öffnungen, deren Winkel korrigiert wurde: {n}.","gs.align_removed_drafts":"Ungültige Umrisse vom Raster zusammengeklappt und entfernt: {n}.","gs.optimize_redundant_drafts":"Gespeicherte Wandketten, die durch feste Raumwände verdeckt waren, wurden entfernt: {n}.","gs.align_preflight_failed":"Die Geometrie der folgenden Bereiche konnte nicht sicher überprüft werden: {spaces}{more}.","gs.align_preflight_hint":"Pläne wurden nicht geändert. Kopieren Sie die Diagnosen mit dem untenstehenden Button und fügen Sie sie zusammen mit einem Raumexport dem Fehlerbericht bei.","gs.preflight_reason_prepare-exception":"Die Bereichsgeometrie konnte nicht vorbereitet werden (Ausnahme beim Erstellen des Modells)","gs.preflight_reason_wall-null":"Der Wandkörper wurde nicht erstellt (die Vereinigung lieferte leer zurück)","gs.preflight_reason_wall-degraded-extra":"Der Wandkörper wurde mit zusätzlicher Geometrie beschädigt","gs.preflight_reason_wall-failed-core":"Der Kern des Wandkörpers konnte nicht zusammengesetzt werden","gs.preflight_reason_wall-exception":"Die Wandkonstruktion warf eine Ausnahme","gs.preflight_reason_floor-null":"Der Fußbodenumriss wurde nicht erstellt","gs.preflight_reason_floor-exception":"Bodenaufbau hat eine Ausnahme ausgelöst","gs.preflight_copy":"Diagnosen kopieren","gs.preflight_copied":"Diagnosen kopiert","gs.preflight_update_hint":"Die Karten- und Integrationsversionen unterscheiden sich — Hausplan aktualisieren und erneut versuchen.","gs.align_preflight_space":"Bereich {n}","gs.align_preflight_more":", und {n} mehr","gs.optimize_changes":"Modellmigrationen: {m}; aktualisierte Bereiche: {c}; entfernte verrauschte Koordinatenwerte: {p}; zusammengeführte Fragmente realer Wände: {w}; zusammengeführte Fragmente von Wänden ohne Dicke: {s}; unabhängige Wände: {i}.","gs.zero_walls_migrated":"Virtuelle Wandspannweiten konvertiert: {n}.","gs.wall_segments_migrated":"Wandsegmente stabilisiert: {n}.","gs.optimize_lattice_summary":"Rauschen in den Koordinatenwerten kanonisiert: {n}; maximale Bewegung: {cm} cm.","gs.optimize_lattice_space":"{space}: Koordinatenwerte kanonisiert: {n}; außerhalb des Rasters liegende Werte unverändert gelassen: {far}.","gs.optimize_coincident_partitions":"Versteckte unabhängige Wandabschnitte in Raumwände integriert: {n}.","gs.optimize_openings_rehosted":"Öffnungen wieder an Raumwände angebracht: {n}.","gs.optimize_walls_straightened":"Wände begradigt: {n}; maximale Bewegung: {cm} cm.","gs.optimize_walls_straightened_where":"Größte Wandkorrektur: {s}.","gs.optimize_walls_straighten_skipped":"Nahe Achsenwände unverändert gelassen, da sie nicht sicher repariert werden konnten: {n}.","gs.optimize_glow_migration":"Legacy Glow: {spaces} Bereiche → keine Datenfüllung + unabhängiges Glow; {rooms} Räume → geerbte Datenfüllung + unabhängiges Glow.","gs.optimize_references":"Referenzen repariert: Bereiche — {spaces}; Räume — {rooms}; Positionen — {positions}; Geräte aus fehlenden Bereichen gelöst — {detached}.","gs.optimize_reference_more":", und {n} mehr","gs.optimize_orphans_removed":"Vergessene Einträge entfernt: {total} — Raumbezeichnungen: {rooms}; Geräte: {devices}; Gruppenmarkierungen: {groups}. Sie gehörten zu zuvor gelöschten Bereichen.","gs.optimize_live_positions":"Alte Positionen in gelöschten Bereichen gehören zu vorhandenen Objekten: {n}{names}. Sie werden beibehalten.","gs.optimize_live_positions_remove":"Alte Positionen in gelöschten Bereichen gehören zu vorhandenen Objekten: {n}{names}. Sie sind zur Entfernung ausgewählt.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Alte Positionen entfernen","gs.optimize_live_keep":"Alte Positionen beibehalten","gs.optimize_live_selected":"Alte Positionen werden nach der Anwendung von Optimieren entfernt.","gs.optimize_unverified":"Positionen konnten nicht sicher überprüft werden: {n}. Sie wurden unverändert belassen.","gs.optimize_registry_limited":"Voller Administratorzugriff auf die Home Assistant-Registries ist für eine sichere Überprüfung erforderlich.","gs.optimize_vacuum_warning":"Raumzuordnungen, die noch überprüft werden müssen: {n}.","gs.optimize_details":"Details","gs.optimize_details_more":"Und {n} weitere Einträge.","gs.optimize_detail_removed":"wird entfernt","gs.optimize_detail_live":"wird beibehalten","gs.optimize_detail_unverified":"nicht überprüft","gs.optimize_detail_room_label":"Raumkennzeichnung","gs.optimize_detail_device":"Gerät","gs.optimize_detail_group":"Gruppenkennzeichen","gs.optimize_detail_unknown":"unbekannter Eigentümer","gs.optimize_detail_item":"{status}: {kind} {id}; alter Bereich {space}","gs.align_warn":"Absichtlich zwischen Rasterknoten platzierte Elemente werden sich bewegen. Nach der Operation ist nur eine Rückgängig-Funktion verfügbar, und zwar nur bis zur nächsten Planbearbeitung.","gs.align_run":"Optimieren","gs.align_done":"Pläne optimiert: {n} Elemente bewegt, {m} Datensätze beibehalten, {r} Verweise repariert","gs.optimize_undo":"Letzte Optimierung rückgängig machen","gs.optimize_undone":"Die letzte Optimierung wurde rückgängig gemacht","decor.furniture":"Möbel","furn.title":"Möbelbibliothek","furn.symbol":"Symbol","furn.group_furniture":"Möbel","furn.group_appliance":"Geräte","furn.group_sanitary":"Sanitär","furn.group_other":"Sonstiges","furn.width":"Breite","furn.depth":"Tiefe","furn.back_to_categories":"Alle Kategorien","furn.pick_hint":"Wählen Sie eine Kategorie und dann ein Symbol.","furn.place_hint":"Klicken Sie auf den Plan — das Element wird an der nächsten Wand platziert. Mit Shift wird es frei platziert.","furn.cat_air_conditioner":"Klimaanlagen","furn.cat_armchair":"Sessel","furn.cat_bathtub":"Badewannen","furn.cat_bed":"Betten","furn.cat_bidet":"Bidets","furn.cat_boiler":"Warmwasserbereiter","furn.cat_chair":"Stühle","furn.cat_coffee_table":"Couchtische","furn.cat_cooktop":"Kochfelder","furn.cat_dining_table":"Esstische","furn.cat_dishwasher":"Geschirrspüler","furn.cat_dryer":"Wäschetrockner","furn.cat_fireplace":"Kamine","furn.cat_fridge":"Kühlschränke","furn.cat_kitchen_cabinet":"Küchenschränke","furn.cat_kitchen_sink":"Küchenspülen","furn.cat_nightstand":"Schränke","furn.cat_plant":"Pflanzen","furn.cat_rug":"Teppiche","furn.cat_shelving":"Regale","furn.cat_shower":"Duschen","furn.cat_sink":"Waschbecken","furn.cat_sofa":"Sofas","furn.cat_stairs":"Treppen","furn.cat_toilet":"Toiletten","furn.cat_tv":"Fernseher","furn.cat_wardrobe":"Kleiderschränke","furn.cat_washer":"Waschmaschinen","furn.cat_work_table":"Schreibtische","furn.sym_sofa":"Zweisitzer-Sofa","furn.sym_sofa_three_seat":"Dreisitzer-Sofa","furn.sym_sofa_corner_right":"Ecksofa rechts","furn.sym_armchair":"Polstersessel","furn.sym_armchair_office":"Bürostuhl","furn.sym_coffee_table":"Rechteckiger Couchtisch","furn.sym_coffee_table_round":"Runder Couchtisch","furn.sym_coffee_table_oval":"Ovaler Couchtisch","furn.sym_coffee_table_rounded":"Abgerundeter Couchtisch","furn.sym_table_dining":"Rechteckiger Esstisch","furn.sym_table_round":"Rundtisch","furn.sym_table_dining_oval":"Ovaler Esstisch","furn.sym_table_dining_rounded":"Abgerundeter Esstisch","furn.sym_chair":"Stuhl","furn.sym_chair_bar":"Barhocker","furn.sym_desk":"Rechteckiger Schreibtisch","furn.sym_desk_corner":"Eckschreibtisch","furn.sym_bed_double":"Doppelbett","furn.sym_bed_single":"Einzelbett","furn.sym_nightstand":"Nachttisch","furn.sym_cabinet_tv":"TV-Schrank","furn.sym_cabinet_shoe":"Schuhschrank","furn.sym_cabinet_sink":"Waschtischunterschrank","furn.sym_wardrobe":"Kleiderschrank","furn.sym_bookshelf":"Bücherschrank","furn.sym_wall_unit":"Schrankwand","furn.sym_kitchen_floor":"Küchen-Unterschrank","furn.sym_kitchen_floor_corner":"Küchen-Eckunterschrank","furn.sym_kitchen_wall":"Küchen-Hängeschrank","furn.sym_kitchen_wall_corner":"Küchen-Eckhängeschrank","furn.sym_shelf_floor":"Standregal","furn.sym_shelf_wall":"Wandregal","furn.sym_fridge":"Kühlschrank","furn.sym_stove":"Vierflammiges Kochfeld","furn.sym_cooktop_two":"Zweiflammiges Kochfeld","furn.sym_dishwasher":"Geschirrspüler","furn.sym_washer":"Waschmaschine","furn.sym_dryer":"Wäschetrockner","furn.sym_tv":"Fernseher mit Standfuß","furn.sym_tv_wall":"Wandfernseher","furn.sym_ac":"Klimaanlage","furn.sym_water_heater":"Wassererhitzer","furn.sym_toilet":"Stand-WC","furn.sym_toilet_built_in":"Wand-WC","furn.sym_bathtub":"Rechteckige Badewanne","furn.sym_bathtub_corner":"Eckbadewanne","furn.sym_shower":"Dusche","furn.sym_sink":"Waschbecken","furn.sym_kitchen_sink":"Einzel-Küchenspüle","furn.sym_kitchen_sink_double":"Doppel-Küchenspüle","furn.sym_bidet":"Stand-Bidet","furn.sym_bidet_built_in":"Wand-Bidet","furn.sym_stairs":"Treppe","furn.sym_fireplace":"Kamin","furn.sym_plant":"Pflanze","furn.sym_rug":"Teppich","common.yes":"Ja","common.no":"Nein","vac.diag_source":"Quelle","vac.diag_platform":"Integration","vac.diag_status":"Status","vac.diag_position":"Position","vac.diag_rooms":"Räume","vac.diag_rooms_value":"{total} · {matched} Namen stimmen überein · {readiness}","vac.autocal_ready":"Auto-Kalibrierung verfügbar","vac.autocal_not_ready":"3 übereinstimmende Namen erforderlich","vac.diag_path":"Integrationspfad","vac.diag_map":"Karten-ID","vac.source_none":"nicht ausgewählt","vac.source_status_ok":"Bereit","vac.source_status_missing":"Fehlend","vac.source_status_disabled":"In Home Assistant deaktiviert","vac.source_status_unavailable":"Nicht verfügbar","vac.source_status_unverified":"Kann mit den aktuellen Berechtigungen nicht verifizieren","vac.source_status_unsupported":"Keine Positionsdaten","vac.source_status_none":"Keine Quelle","vac.source_banner_missing":"Die gespeicherte Quelle existiert nicht mehr. Sie wurde nicht automatisch ersetzt; wählen Sie eine andere Quelle oder stellen Sie sie in Home Assistant wieder her.","vac.source_banner_disabled":"Die gespeicherte Quelle ist in Home Assistant deaktiviert. Aktivieren Sie sie dort oder wählen Sie eine andere Quelle.","vac.source_banner_unverified":"Die aktuellen Home Assistant-Berechtigungen können diese gespeicherte Quelle nicht verifizieren. Sie bleibt angepinnt und wird nicht automatisch ersetzt.","vac.choose_source":"Quelle wählen","vac.source_auto":"Automatisch","vac.source_auto_hint":"Verwenden Sie eine kompatible Entität von diesem Gerät","vac.all_cameras":"Alle Kameras","vac.all_cameras_warn":"Eine Kamera liefert möglicherweise keine Roboter-Daten. Wählen Sie eine nur, wenn es Ihre Saugroboter-Karte ist.","vac.all_cameras_empty":"Keine anderen Kamera-Entitäten gefunden.","vac.platform_unknown":"unbekannte Integration","vac.cap_position":"Position","vac.cap_rooms_short":"Räume","vac.cap_path":"Pfad","vac.cap_map":"Karten-ID","vac.cap_none":"Keine Roboter-Daten erkannt","vac.xcme_hint":"Aktivieren Sie diese Xiaomi Cloud Map Extractor-Attribute:","vac.documentation":"Dokumentation","vac.residual_title":"Automatische Kalibrierung überprüfen","vac.residual_message":"Die zugeordneten Räume weichen um bis zu {error} voneinander ab. Diese ungefähre Kalibrierung anwenden, manuell verfeinern oder ohne Änderung der gespeicherten Einrichtung abbrechen.","vac.apply_proposal":"Anwenden","gs.backup_group":"Sichern und übertragen","gs.backup_hint":"Laden Sie ein tragbares JSON-Backup herunter oder sehen Sie eine Vorschau und importieren Sie ein Backup, das mit House Plan erstellt wurde.","backup.export_open":"Exportieren","backup.import_open":"Importieren","backup.export_title":"House Plan exportieren","backup.import_title":"House Plan importieren","backup.export_hint":"Wählen Sie, ob das Backup die gesamte House Plan-Konfiguration oder nur den aktuellen Bereich enthalten soll.","backup.full":"Vollständiges Backup","backup.current_space":"Aktueller Bereich","backup.current_space_title":"Aktueller Bereich: {title}","backup.no_current_space":"Kein aktueller Bereich","backup.plan_only":"Nur Plan","backup.plan_only_hint":"Räume, Wände, Öffnungen, Dekor und Raumbezeichnungspositionen ohne Geräte oder Home Assistant-Bindungen beibehalten.","backup.plan_only_preview":"Diese Datei enthält nur den Plan.","backup.privacy_warning":"Das Archiv enthält Namen, Home Assistant-Kennungen und genaue Koordinaten. Interne Pläne und Anhänge werden referenziert, nicht eingebettet; Laufzeitzustände und Staubsaugerspuren sind nicht enthalten.","backup.download":"JSON herunterladen","backup.export_done":"Backup heruntergeladen","backup.reading":"Überprüfe das Backup…","backup.revalidated":"Der Plan wurde nach dieser Vorschau geändert. Die Zusammenfassung wurde aktualisiert; überprüfen Sie sie und bestätigen Sie erneut.","backup.error.unauthorized":"Sie haben keine Berechtigung, diesen Plan zu exportieren oder zu importieren.","backup.error.not_ready":"Der Hausplan ist noch nicht fertig. Versuchen Sie es in einem Moment erneut.","backup.error.too_large":"Das Backup überschreitet das 8-MiB-Limit.","backup.error.invalid_json":"Die ausgewählte Datei ist kein gültiges JSON.","backup.error.invalid_format":"Die ausgewählte Datei ist kein House Plan-Backup.","backup.error.unsupported_export_version":"Dieses Backup-Format wird von der installierten Version nicht unterstützt.","backup.error.future_model":"Das Backup wurde mit einem neueren House-Plan-Datenmodell erstellt.","backup.error.invalid_config":"Das Backup enthält eine ungültige House-Plan-Konfiguration.","backup.error.wall_model_migration_blocked":"Das Backup-Wandmodell konnte nicht sicher aktualisiert werden. Optimieren Sie zuerst den Quellplan und exportieren Sie ihn dann erneut.","backup.error.invalid_layout":"Das Backup enthält ungültige Objektpositionen.","backup.error.invalid_content":"Das Backup enthält ungültige oder inkonsistente Inhaltsreferenzen.","backup.error.space_not_found":"Der ausgewählte Bereich existiert nicht mehr.","backup.error.capacity_exceeded":"Durch das Hinzufügen dieses Backups würden die Planlimits überschritten.","backup.error.preview_expired":"Die Vorschau ist abgelaufen. Wählen Sie die Backup-Datei erneut aus.","backup.error.preview_owner_mismatch":"Diese Vorschau gehört zu einem anderen Home-Assistant-Benutzer.","backup.error.conflict":"Der Plan hat sich nach der Vorschau geändert. Überprüfen Sie die aktualisierte Zusammenfassung.","backup.error.content_confirmation_required":"Bestätigen Sie, dass nicht verfügbare lokale Inhalte getrennt werden können.","backup.error.commit_failed":"Das Backup konnte nicht sicher angewendet werden. Der vorherige Plan wurde wiederhergestellt oder wartet auf die Wiederherstellung.","backup.error.missing_plan":"Eine referenzierte Plan-Datei ist nach der Vorschau verschwunden. Überprüfen Sie das Backup erneut.","backup.error.missing_content":"Ein referenziertes lokales Anhangselement ist nach der Vorschau verschwunden. Überprüfen Sie das Backup erneut.","backup.error.marker_control_missing":"Ein verknüpftes Planlicht fehlt im Backup.","backup.error.marker_control_not_light":"Ein verknüpftes Planziel ist nicht mehr als Lichtquelle markiert.","backup.error.marker_control_self":"Eine Lichtquelle kann sich nicht selbst steuern.","backup.error.marker_control_cycle":"Das Backup enthält eine kreisförmige Kette von Lichtsteuerungen.","backup.error.duplicate_marker_control":"Das Backup enthält eine doppelte Plan-Licht-Verknüpfung.","backup.error.no_backup":"Es gibt keinen Import- oder Optimierungssnapshot zur Wiederherstellung.","backup.same_source":"Erstellt auf dieser Home Assistant-Instanz","backup.foreign_source":"Erstellt auf einer anderen Home Assistant-Instanz","backup.created":"Erstellt: {value}","backup.versions":"Karte {card}; Integration {integration}; Datenmodell {model}","backup.count_spaces":"Bereiche: {n}","backup.count_rooms":"Räume: {n}","backup.count_walls":"Wände: {n}","backup.count_openings":"Öffnungen: {n}","backup.count_decor":"Dekorationsobjekte: {n}","backup.count_markers":"Geräte: {n}","backup.count_layout":"Positionen: {n}","backup.bindings":"Verknüpfungen — Geräte: {device}, Entitäten: {entity}, virtuell: {virtual}; Positionen ohne Bereich: {legacy}","backup.binding_status":"Zielstatus — aktiv: {active}, deaktiviert: {disabled}, fehlt: {missing}","backup.missing_areas":"Auf dem Ziel fehlende Bereiche: {areas}","backup.dropped_marker_links":"Planlicht-Verknüpfungen außerhalb dieses übertragenen Bereichs wurden ausgelassen: {n}.","backup.repaired_target_refs":"Durch den Import dieses Bereichs wiederhergestellte vorhandene Referenzen: {n}.","backup.preserved_unresolved_refs":"Referenzen, die nicht eindeutig wiederhergestellt werden konnten, wurden beibehalten: {n}.","backup.preserved_unresolved_hint":"Es wurden keine Daten geraten oder gelöscht. Führen Sie nach dem Import Optimierungspläne aus, um die verbleibenden Referenzen zu überprüfen.","backup.import_details":"Importieren von Referenzdetails","backup.import_detail.incoming_remapped":"Referenzen innerhalb der importierten Kopie aktualisiert: {n}","backup.import_detail.target_repaired":"Vorhandene Referenzen wiederhergestellt: {n}","backup.import_detail.preserved_unresolved":"Unaufgelöste Referenzen beibehalten: {n}","backup.import_detail.collisions":"Zielkonflikte sicher beibehalten: {n}","backup.import_detail.dropped_links":"Eingehende Links durch Übertragungsregeln ausgelassen: {n}","backup.import_detail.bounded_lineages":"Übermäßig verschachtelte Kennungen begrenzt belassen: {n}","backup.replace_warning":"Dies ersetzt die aktuelle Konfiguration und das Layout. Hochgeladene Dateien werden niemals gelöscht. Eine Rückgängig-Möglichkeit bleibt bis zur nächsten Planbearbeitung verfügbar.","backup.foreign_bookkeeping":"Instanzspezifische bekannte/neue Gerätebuchführung wird nicht importiert.","backup.final_name":"Name des neuen Bereichs","backup.target_settings":"Die globalen Einstellungen der Zielinstanz bleiben unverändert.","backup.duplicates":"Bindungen bereits vorhanden: {n}","backup.skip":"Doppelte Geräte überspringen","backup.virtual_copy":"Sichere statische virtuelle Kopien hinzufügen","backup.content":"Referenzierter Inhalt","backup.content_available":"lokal verfügbar","backup.content_external":"externer Link","backup.content_detach_required":"wird getrennt","backup.confirm_detach":"Ich verstehe, dass nicht verfügbare interne Pläne und Anhänge von der importierten Konfiguration getrennt werden.","backup.replace":"Ersetzen","backup.add":"Bereich hinzufügen","backup.space_done":"Bereich importiert: {rooms} Räume, {markers} Geräte, {refs} bestehende Referenzen wiederhergestellt","backup.full_done":"Backup wiederhergestellt: {spaces} Bereiche, {rooms} Räume, {markers} Geräte","backup.undo_import":"Letzten vollständigen Import rückgängig machen","backup.import_undone":"Vollständiger Import rückgängig gemacht"};const n="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";export{e as dictionary,n as fingerprint}; diff --git a/dist/houseplan-assets/editor-H80bjnWS.js b/dist/houseplan-assets/editor-H80bjnWS.js new file mode 100644 index 00000000..c96d3dc2 --- /dev/null +++ b/dist/houseplan-assets/editor-H80bjnWS.js @@ -0,0 +1,14 @@ +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";import{c as e,l as o,t,c_ as s,A as a,c$ as i,d0 as l,d1 as n,E as r,b as c}from"./houseplan-card-BrUCyMoE.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`h[e.name]||e.name} + @value-changed=${this._valueChanged} + >`;return c` + ${d(f.slice(0,3))} + ${_?c``:a} + ${d(f.slice(3))} + `}_valueChanged(e){const o={...this._config,...e.detail.value};""===o.floor?delete o.floor:o.floor===this._floorToken&&(o.floor=this._config?.floor);const t=new Event("config-changed",{bubbles:!0,composed:!0});t.detail={config:o},this.dispatchEvent(t)}}h.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",h); diff --git a/dist/houseplan-assets/houseplan-card-BrUCyMoE.js b/dist/houseplan-assets/houseplan-card-BrUCyMoE.js new file mode 100644 index 00000000..8a05b20e --- /dev/null +++ b/dist/houseplan-assets/houseplan-card-BrUCyMoE.js @@ -0,0 +1,5247 @@ +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";const e=globalThis,t=e.ShadowRoot&&(void 0===e.ShadyCSS||e.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,i=Symbol(),n=new WeakMap;let r=class{constructor(e,t,n){if(this._$cssResult$=!0,n!==i)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const i=this.t;if(t&&void 0===e){const t=void 0!==i&&1===i.length;t&&(e=n.get(i)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),t&&n.set(i,e))}return e}toString(){return this.cssText}};const o=(e,...t)=>{const n=1===e.length?e[0]:t.reduce((t,i,n)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+e[n+1],e[0]);return new r(n,e,i)},s=t?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const i of e.cssRules)t+=i.cssText;return(e=>new r("string"==typeof e?e:e+"",void 0,i))(t)})(e):e,{is:a,defineProperty:l,getOwnPropertyDescriptor:c,getOwnPropertyNames:h,getOwnPropertySymbols:d,getPrototypeOf:u}=Object,p=globalThis,_=p.trustedTypes,m=_?_.emptyScript:"",f=p.reactiveElementPolyfillSupport,g=(e,t)=>e,v={toAttribute(e,t){switch(t){case Boolean:e=e?m:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let i=e;switch(t){case Boolean:i=null!==e;break;case Number:i=null===e?null:Number(e);break;case Object:case Array:try{i=JSON.parse(e)}catch(e){i=null}}return i}},y=(e,t)=>!a(e,t),b={attribute:!0,type:String,converter:v,reflect:!1,useDefault:!1,hasChanged:y};Symbol.metadata??=Symbol("metadata"),p.litPropertyMetadata??=new WeakMap;let w=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=b){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const i=Symbol(),n=this.getPropertyDescriptor(e,i,t);void 0!==n&&l(this.prototype,e,n)}}static getPropertyDescriptor(e,t,i){const{get:n,set:r}=c(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:n,set(t){const o=n?.call(this);r?.call(this,t),this.requestUpdate(e,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??b}static _$Ei(){if(this.hasOwnProperty(g("elementProperties")))return;const e=u(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(g("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(g("properties"))){const e=this.properties,t=[...h(e),...d(e)];for(const i of t)this.createProperty(i,e[i])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,i]of t)this.elementProperties.set(e,i)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const i=this._$Eu(e,t);void 0!==i&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const i=new Set(e.flat(1/0).reverse());for(const e of i)t.unshift(s(e))}else void 0!==e&&t.push(s(e));return t}static _$Eu(e,t){const i=t.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof e?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const i of t.keys())this.hasOwnProperty(i)&&(e.set(i,this[i]),delete this[i]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const i=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((i,n)=>{if(t)i.adoptedStyleSheets=n.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const t of n){const n=document.createElement("style"),r=e.litNonce;void 0!==r&&n.setAttribute("nonce",r),n.textContent=t.cssText,i.appendChild(n)}})(i,this.constructor.elementStyles),i}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,i){this._$AK(e,i)}_$ET(e,t){const i=this.constructor.elementProperties.get(e),n=this.constructor._$Eu(e,i);if(void 0!==n&&!0===i.reflect){const r=(void 0!==i.converter?.toAttribute?i.converter:v).toAttribute(t,i.type);this._$Em=e,null==r?this.removeAttribute(n):this.setAttribute(n,r),this._$Em=null}}_$AK(e,t){const i=this.constructor,n=i._$Eh.get(e);if(void 0!==n&&this._$Em!==n){const e=i.getPropertyOptions(n),r="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:v;this._$Em=n;const o=r.fromAttribute(t,e.type);this[n]=o??this._$Ej?.get(n)??o,this._$Em=null}}requestUpdate(e,t,i,n=!1,r){if(void 0!==e){const o=this.constructor;if(!1===n&&(r=this[e]),i??=o.getPropertyOptions(e),!((i.hasChanged??y)(r,t)||i.useDefault&&i.reflect&&r===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,i))))return;this.C(e,t,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:i,reflect:n,wrapped:r},o){i&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==r||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||i||(t=void 0),this._$AL.set(e,t)),!0===n&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,i]of e){const{wrapped:e}=i,n=this[t];!0!==e||this._$AL.has(t)||void 0===n||this.C(t,void 0,i,n)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};w.elementStyles=[],w.shadowRootOptions={mode:"open"},w[g("elementProperties")]=new Map,w[g("finalized")]=new Map,f?.({ReactiveElement:w}),(p.reactiveElementVersions??=[]).push("2.1.2");const k=globalThis,x=e=>e,$=k.trustedTypes,S=$?$.createPolicy("lit-html",{createHTML:e=>e}):void 0,M="$lit$",R=`lit$${Math.random().toFixed(9).slice(2)}$`,T="?"+R,C=`<${T}>`,D=document,z=()=>D.createComment(""),A=e=>null===e||"object"!=typeof e&&"function"!=typeof e,O=Array.isArray,P="[ \t\n\f\r]",F=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,E=/-->/g,I=/>/g,H=RegExp(`>|${P}(?:([^\\s"'>=/]+)(${P}*=${P}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),N=/'/g,L=/"/g,q=/^(?:script|style|textarea|title)$/i,W=e=>(t,...i)=>({_$litType$:e,strings:t,values:i}),j=W(1),B=W(2),V=Symbol.for("lit-noChange"),U=Symbol.for("lit-nothing"),G=new WeakMap,K=D.createTreeWalker(D,129);function Y(e,t){if(!O(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==S?S.createHTML(t):t}const Z=(e,t)=>{const i=e.length-1,n=[];let r,o=2===t?"":3===t?"":"",s=F;for(let t=0;t"===l[0]?(s=r??F,c=-1):void 0===l[1]?c=-2:(c=s.lastIndex-l[2].length,a=l[1],s=void 0===l[3]?H:'"'===l[3]?L:N):s===L||s===N?s=H:s===E||s===I?s=F:(s=H,r=void 0);const d=s===H&&e[t+1].startsWith("/>")?" ":"";o+=s===F?i+C:c>=0?(n.push(a),i.slice(0,c)+M+i.slice(c)+R+d):i+R+(-2===c?t:d)}return[Y(e,o+(e[i]||"")+(2===t?"":3===t?"":"")),n]};class X{constructor({strings:e,_$litType$:t},i){let n;this.parts=[];let r=0,o=0;const s=e.length-1,a=this.parts,[l,c]=Z(e,t);if(this.el=X.createElement(l,i),K.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(n=K.nextNode())&&a.length0){n.textContent=$?$.emptyScript:"";for(let i=0;iO(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==U&&A(this._$AH)?this._$AA.nextSibling.data=e:this.T(D.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:i}=e,n="number"==typeof i?this._$AC(e):(void 0===i.el&&(i.el=X.createElement(Y(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===n)this._$AH.p(t);else{const e=new Q(n,this),i=e.u(this.options);e.p(t),this.T(i),this._$AH=e}}_$AC(e){let t=G.get(e.strings);return void 0===t&&G.set(e.strings,t=new X(e)),t}k(e){O(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let i,n=0;for(const r of e)n===t.length?t.push(i=new ee(this.O(z()),this.O(z()),this,this.options)):i=t[n],i._$AI(r),n++;n2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=U}_$AI(e,t=this,i,n){const r=this.strings;let o=!1;if(void 0===r)e=J(this,e,t,0),o=!A(e)||e!==this._$AH&&e!==V,o&&(this._$AH=e);else{const n=e;let s,a;for(e=r[0],s=0;s{const n=i?.renderBefore??t;let r=n._$litPart$;if(void 0===r){const e=i?.renderBefore??null;n._$litPart$=r=new ee(t.insertBefore(z(),e),e,void 0,i??{})}return r._$AI(e),r},ce=globalThis;let he=class extends w{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const e=super.createRenderRoot();return this.renderOptions.renderBefore??=e.firstChild,e}update(e){const t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=le(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return V}};he._$litElement$=!0,he.finalized=!0,ce.litElementHydrateSupport?.({LitElement:he});const de=ce.litElementPolyfillSupport;de?.({LitElement:he}),(ce.litElementVersions??=[]).push("4.2.2");const ue=2,pe=e=>(...t)=>({_$litDirective$:e,values:t});let _e=class{constructor(e){}get _$AU(){return this._$AM._$AU}_$AT(e,t,i){this._$Ct=e,this._$AM=t,this._$Ci=i}_$AS(e,t){return this.update(e,t)}update(e,t){return this.render(...t)}};const{I:me}=se,fe=e=>e,ge=()=>document.createComment(""),ve=(e,t,i)=>{const n=e._$AA.parentNode,r=void 0===t?e._$AB:t._$AA;if(void 0===i){const t=n.insertBefore(ge(),r),o=n.insertBefore(ge(),r);i=new me(t,o,e,e.options)}else{const t=i._$AB.nextSibling,o=i._$AM,s=o!==e;if(s){let t;i._$AQ?.(e),i._$AM=e,void 0!==i._$AP&&(t=e._$AU)!==o._$AU&&i._$AP(t)}if(t!==r||s){let e=i._$AA;for(;e!==t;){const t=fe(e).nextSibling;fe(n).insertBefore(e,r),e=t}}}return i},ye=(e,t,i=e)=>(e._$AI(t,i),e),be={},we=(e,t=be)=>e._$AH=t,ke=e=>{e._$AR(),e._$AA.remove()},xe=(e,t,i)=>{const n=new Map;for(let r=t;r<=i;r++)n.set(e[r],r);return n},$e=pe(class extends _e{constructor(e){if(super(e),e.type!==ue)throw Error("repeat() can only be used in text expressions")}dt(e,t,i){let n;void 0===i?i=t:void 0!==t&&(n=t);const r=[],o=[];let s=0;for(const t of e)r[s]=n?n(t,s):s,o[s]=i(t,s),s++;return{values:o,keys:r}}render(e,t,i){return this.dt(e,t,i).values}update(e,[t,i,n]){const r=(e=>e._$AH)(e),{values:o,keys:s}=this.dt(t,i,n);if(!Array.isArray(r))return this.ut=s,o;const a=this.ut??=[],l=[];let c,h,d=0,u=r.length-1,p=0,_=o.length-1;for(;d<=u&&p<=_;)if(null===r[d])d++;else if(null===r[u])u--;else if(a[d]===s[p])l[p]=ye(r[d],o[p]),d++,p++;else if(a[u]===s[_])l[_]=ye(r[u],o[_]),u--,_--;else if(a[d]===s[_])l[_]=ye(r[d],o[_]),ve(e,l[_+1],r[d]),d++,_--;else if(a[u]===s[p])l[p]=ye(r[u],o[p]),ve(e,r[d],r[u]),u--,p++;else if(void 0===c&&(c=xe(s,p,_),h=xe(a,d,u)),c.has(a[d]))if(c.has(a[u])){const t=h.get(s[p]),i=void 0!==t?r[t]:null;if(null===i){const t=ve(e,r[d]);ye(t,o[p]),l[p]=t}else l[p]=ye(i,o[p]),ve(e,r[d],i),r[t]=null;p++}else ke(r[u]),u--;else ke(r[d]),d++;for(;p<=_;){const t=ve(e,l[_+1]);ye(t,o[p]),l[p++]=t}for(;d<=u;){const e=r[d++];null!==e&&ke(e)}return this.ut=s,we(e,l),V}}),Se=new WeakMap;let Me=0;class Re extends he{constructor(){super(...arguments),this.title="",this.icon="",this.wide=!1,this.dismissOnScrim=!1,this.hass=null,this._opener=null,this._focusRoot=null,this._useHaDialog=!1,this._closing=!1,this._overlays=[],this._titleId="hp-dialog-title-"+ ++Me,this._focusInitial=()=>{const e=this._focusableElements(),t=e.find(e=>e.hasAttribute("autofocus"))||e[0]||(this._useHaDialog?null:this.renderRoot.querySelector(".close"))||this.renderRoot.querySelector(".surface")||this.renderRoot.querySelector("ha-dialog");t?.focus({preventScroll:!0})},this._requestClose=()=>{this._closing||(this._closing=!0,this.dispatchEvent(new CustomEvent("hp-close",{bubbles:!0,composed:!0})))},this._onKeyDown=e=>{if("Escape"===e.key){e.preventDefault(),e.stopImmediatePropagation(),this._pruneOverlays();const t=this._overlays[this._overlays.length-1];return t?void this._closeOverlay(t,"escape"):void this._requestClose()}if("Tab"!==e.key||this._useHaDialog)return;const t=this.renderRoot.querySelector(".close"),i=t?[t,...this._focusableElements()]:this._focusableElements();if(!i.length)return e.preventDefault(),void this.renderRoot.querySelector(".surface")?.focus({preventScroll:!0});const n=this._deepActiveElement(),r=i[0],o=i[i.length-1];!e.shiftKey||n!==r&&i.includes(n)?e.shiftKey||n!==o||(e.preventDefault(),r.focus()):(e.preventDefault(),o.focus())},this._onFallbackCancel=e=>{e.preventDefault(),this._requestClose()},this._onFallbackClick=e=>{this.dismissOnScrim&&e.target===e.currentTarget&&this._requestClose()}}connectedCallback(){super.connectedCallback(),this._opener=this._deepActiveElement();const e=this.getRootNode();this._focusRoot=e;const t=Se.get(e)||{dialogs:new Set,opener:this._opener};t.dialogs.add(this),Se.set(e,t),this._useHaDialog=!!customElements.get("ha-dialog"),this.addEventListener("keydown",this._onKeyDown,!0)}disconnectedCallback(){this.removeEventListener("keydown",this._onKeyDown,!0);const e=[...this._overlays];this._overlays=[];for(const t of e.reverse())t.close("disconnect");const t=this._focusRoot,i=this._opener;this._opener=null,this._focusRoot=null;const n=t?Se.get(t):void 0;n?.dialogs.delete(this),super.disconnectedCallback(),t&&n&&requestAnimationFrame(()=>{const e=Se.get(t);if(!e)return;if(!e.dialogs.size)return e.opener?.isConnected&&e.opener.focus({preventScroll:!0}),void Se.delete(t);const n=i?.closest("hp-dialog");i?.isConnected&&n&&e.dialogs.has(n)&&i.focus({preventScroll:!0})})}firstUpdated(e){if(super.firstUpdated(e),!this._useHaDialog){const e=this.renderRoot.querySelector("dialog");e&&!e.open&&e.showModal()}queueMicrotask(()=>this._focusInitial())}_deepActiveElement(){let e=document.activeElement;for(;e?.shadowRoot?.activeElement;)e=e.shadowRoot.activeElement;return e&&e!==document.body?e:null}_focusableElements(){const e=["[autofocus]","a[href]","button:not([disabled])",'input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])",'[contenteditable="true"]','[tabindex]:not([tabindex="-1"])'].join(","),t=[],i=new Set,n=r=>{if(!i.has(r)){if(i.add(r),r instanceof HTMLElement){if(r.matches(e)&&t.push(r),r instanceof HTMLSlotElement){for(const e of r.assignedNodes({flatten:!0}))n(e);return}if(r.shadowRoot){for(const e of r.shadowRoot.childNodes)n(e);return}}for(const e of r.childNodes)n(e)}};for(const e of this.childNodes)n(e);const r=this.overlayPortal();return r&&n(r),t.filter(e=>{let t=e;for(;t;){const e=getComputedStyle(t);if(t.hidden||t.inert||"true"===t.getAttribute("aria-hidden")||"none"===e.display||"hidden"===e.visibility)return!1;if(t=t.assignedSlot||t.parentElement||(t.getRootNode()instanceof ShadowRoot?t.getRootNode().host:null),t===this)break}return!0})}_pruneOverlays(){this._overlays=this._overlays.filter(e=>e.owner.isConnected)}_closeOverlay(e,t){const i=this._overlays.findIndex(t=>t.token===e.token);i>=0&&this._overlays.splice(i,1),e.close(t)}registerOverlay(e){this._pruneOverlays();const t=this._overlays.find(t=>t.owner===e.owner);t&&this._overlays.splice(this._overlays.indexOf(t),1);const i=e.group||"transient";for(const e of[...this._overlays].reverse())e.group===i&&this._closeOverlay(e,"exclusive");const n={...e,group:i,token:Symbol("hp-overlay")};this._overlays.push(n);let r=!1;return()=>{if(r)return;r=!0;const e=this._overlays.findIndex(e=>e.token===n.token);e>=0&&this._overlays.splice(e,1)}}closeTransientOverlays(e="outside"){this._pruneOverlays();const t=[...this._overlays].filter(e=>"transient"===(e.group||"transient"));for(const i of t.reverse())this._closeOverlay(i,e);return t.length>0}overlayPortal(){return this.renderRoot.querySelector(".overlay-portal")}render(){const e=j` + ${this.icon?j``:U} + ${this.title} + `;return this._useHaDialog?j` + ${e} + + +
`:j` +
+
+ ${e} + +
+
+ +
+
+
`}}Re.properties={title:{type:String},icon:{type:String},wide:{type:Boolean,reflect:!0},dismissOnScrim:{type:Boolean,attribute:"dismiss-on-scrim"},hass:{attribute:!1}},Re.styles=o` + :host { + display: contents; + color: var(--primary-text-color, #e6e7eb); + font: inherit; + } + + ha-dialog { + --dialog-content-padding: 0; + --dialog-surface-background: var(--card-background-color, var(--hp-bg, #202126)); + --ha-dialog-border-radius: var(--rad-l, 18px); + /* HA's ha-dialog-header defaults this custom property to a one-line + fixed height. Our localized slot is intentionally allowed to wrap, + so leaving that default in place clips every line after the first at + the bottom of the header. auto is HA's public sizing hook and also + stays harmless on older ha-dialog implementations that do not consume + it. */ + --ha-dialog-header-title-height: auto; + color: inherit; + } + + ha-dialog::part(dialog) { + border: 1px solid var(--hp-accent, #d89300); + box-shadow: var(--shadow-3, 0 18px 48px rgb(0 0 0 / 0.34)); + overflow: hidden; + } + + /* The HA header slot is a flex item with a constrained inline size. The + old inline-flex title kept its min-content width, so HA clipped the last + word instead of giving it a second line. Keep every wrapper shrinkable + and let the text wrap; this applies to every hp-dialog, including long + device names and translated titles. */ + .header-title-slot { + display: block; + flex: 1 1 auto; + width: 100%; + max-width: 100%; + min-width: 0; + box-sizing: border-box; + white-space: normal; + } + + .title { + display: flex; + flex: 1 1 auto; + align-items: center; + gap: var(--sp-4, 12px); + width: 100%; + max-width: 100%; + min-width: 0; + font-weight: 600; + line-height: 1.25; + white-space: normal; + } + + .title ha-icon { + flex: none; + color: var(--hp-accent, #d89300); + } + + .title-text { + flex: 1 1 auto; + min-width: 0; + max-width: 100%; + white-space: normal; + overflow-wrap: anywhere; + word-break: normal; + } + + .footer { + /* ha-dialog lays out its footer slot as a flex row. display: contents + exposed the consumer's action row as a shrink-to-fit flex item, so a + wide device dialog got a half-width divider and its Hide action slid + toward the centre. Keep one full-width slot item in both HA and the + native fallback. */ + display: block; + width: 100%; + min-width: 0; + box-sizing: border-box; + } + + ::slotted([slot='footer']) { + width: 100%; + box-sizing: border-box; + } + + dialog { + width: auto; + max-width: none; + max-height: none; + margin: auto; + padding: 0; + border: 0; + overflow: visible; + color: inherit; + background: transparent; + } + + dialog::backdrop { + background: rgb(0 0 0 / 0.45); + } + + .surface { + width: min(360px, 92vw); + max-height: 92vh; + display: flex; + flex-direction: column; + overflow: hidden; + box-sizing: border-box; + color: inherit; + background: var(--card-background-color, var(--hp-bg, #202126)); + border: 1px solid var(--hp-accent, #d89300); + border-radius: var(--rad-l, 18px); + box-shadow: var(--shadow-3, 0 18px 48px rgb(0 0 0 / 0.34)); + } + + :host([wide]) .surface { + width: min(var(--hp-dialog-wide-width, 500px), 94vw); + } + + .header { + min-height: 56px; + display: flex; + align-items: center; + gap: var(--sp-4, 12px); + padding: var(--sp-4, 12px) var(--sp-5, 16px); + box-sizing: border-box; + border-bottom: 1px solid var(--hp-line, rgb(255 255 255 / 0.12)); + } + + .header .title { + flex: 1; + } + + .close { + width: 40px; + height: 40px; + flex: none; + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0; + color: inherit; + background: transparent; + border: 0; + border-radius: 50%; + cursor: pointer; + } + + :host([data-pointer-hover]) .close:hover, + .close:focus-visible { + background: rgb(127 127 127 / 0.16); + } + + .content { + min-height: 0; + display: flex; + flex-direction: column; + } + + .overlay-portal { + position: fixed; + z-index: 2147483647; + inset: 0; + overflow: visible; + pointer-events: none; + } + + .overlay-portal:empty { + display: none; + } + + .overlay-portal > * { + pointer-events: auto; + } + `,customElements.get("hp-dialog")||customElements.define("hp-dialog",Re);const Te=new Set(["hacs","sun","backup","hassio","met","telegram_bot","mobile_app","systemmonitor","better_thermostat","adaptive_lighting","yandex_pogoda","upnp_serial_number"]),Ce=[{pattern:"протечк|leak|water sensor",icon:"mdi:water-alert"},{pattern:"клапан|valve",icon:"mdi:pipe-valve"},{pattern:"дым|smoke",icon:"mdi:smoke-detector"},{pattern:"термоголов|trv|radiator",icon:"mdi:radiator"},{pattern:"чайник|kettle|термопот",icon:"mdi:kettle"},{pattern:"сауна|sauna|harvia|парная|парилк",icon:"mdi:hot-tub"},{pattern:"температ|temperature|thermometer|climate sensor",icon:"mdi:thermometer"},{pattern:"qingping|air monitor|молекул|air quality",icon:"mdi:air-filter"},{pattern:"штор|curtain|blind|shade",icon:"mdi:roller-shade"},{pattern:"розетк|plug|socket|outlet",icon:"mdi:power-socket-de"},{pattern:"выключат|switch",icon:"mdi:light-switch"},{pattern:"лампа|лампочк|bulb|gx53|светильник|rgb|lamp|light strip",icon:"mdi:lightbulb"},{pattern:"камер|camera",icon:"mdi:cctv"},{pattern:"замок|ttlock|lock|sn609|sn9161",icon:"mdi:lock"},{pattern:"ворота|garage|gate",icon:"mdi:garage-variant"},{pattern:"калитк|door|открыт|contact",icon:"mdi:door"},{pattern:"счётчик|счетчик|kws|meter",icon:"mdi:meter-electric"},{pattern:"вводный автомат|breaker|wifimcbn",icon:"mdi:electric-switch"},{pattern:"myheat|котёл|котел|boiler|отоплен|heating",icon:"mdi:water-boiler"},{pattern:"холодильник|fridge",icon:"mdi:fridge"},{pattern:"стиральн|washer|washing",icon:"mdi:washing-machine"},{pattern:"сушилк|dryer",icon:"mdi:tumble-dryer"},{pattern:"пылесос|vacuum|dreame|roborock",icon:"mdi:robot-vacuum"},{pattern:"soundbar",icon:"mdi:soundbar"},{pattern:"колонк|станц|speaker|яндекс|yandex|алиса|alice",icon:"mdi:speaker"},{pattern:"tv|телевизор|hyundaitv|mitv|television",icon:"mdi:television"},{pattern:"keenetic|роутер|router|mesh|access point",icon:"mdi:router-wireless"},{pattern:"ибп|ups|kirpich",icon:"mdi:battery-charging-high"},{pattern:"slzb|координат|zigbee|coordinator",icon:"mdi:zigbee"},{pattern:"motion|движен|presence|присутств",icon:"mdi:motion-sensor"},{pattern:"humidity|влажн",icon:"mdi:water-percent"}];function De(e){const t=[];for(const i of e)if(i&&"string"==typeof i.pattern&&i.icon)try{t.push({re:new RegExp(i.pattern,"i"),icon:i.icon})}catch{}return t}function ze(e){try{return new RegExp(e,"i"),!0}catch{return!1}}const Ae=De(Ce),Oe={temperature:"mdi:thermometer",humidity:"mdi:water-percent",motion:"mdi:motion-sensor",occupancy:"mdi:motion-sensor",presence:"mdi:motion-sensor",door:"mdi:door",window:"mdi:window-closed",garage_door:"mdi:garage-variant",smoke:"mdi:smoke-detector",moisture:"mdi:water-alert",gas:"mdi:gas-cylinder",power:"mdi:meter-electric",energy:"mdi:meter-electric",illuminance:"mdi:brightness-5",co2:"mdi:molecule-co2",pm25:"mdi:air-filter",battery:"mdi:battery"},Pe="mdi:chip";function Fe(e,t,i){const n=((e||"")+" "+(t||"")).toLowerCase();for(const{re:e,icon:t}of i??Ae)if(e.test(n))return t;return Pe}const Ee=["light","switch","cover","valve","lock","climate","fan","media_player","camera","vacuum","humidifier","water_heater","alarm_control_panel","sensor","binary_sensor","event","button","number","select","update"];var Ie=/^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i,He=Math.ceil,Ne=Math.floor,Le="[BigNumber Error] ",qe=Le+"Number primitive has more than 15 significant digits: ",We=1e14,je=14,Be=9007199254740991,Ve=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],Ue=1e7,Ge=1e9;function Ke(e){var t=0|e;return e>0||e===t?t:t-1}function Ye(e){for(var t,i,n=1,r=e.length,o=e[0]+"";nc^i?1:-1;for(a=(l=r.length)<(c=o.length)?l:c,s=0;so[s]^i?1:-1;return l==c?0:l>c^i?1:-1}function Xe(e,t,i,n){if(ei||e!==Ne(e))throw Error(Le+(n||"Argument")+("number"==typeof e?ei?" out of range: ":" not an integer: ":" not a primitive number: ")+String(e))}function Je(e){var t=e.c.length-1;return Ke(e.e/je)==t&&e.c[t]%2!=0}function Qe(e,t){return(e.length>1?e.charAt(0)+"."+e.slice(1):e)+(t<0?"e":"e+")+t}function et(e,t,i){var n,r;if(t<0){for(r=i+".";++t;r+=i);e=r+e}else if(++t>(n=e.length)){for(r=i,t-=n;--t;r+=i);e+=r}else ty?u.c=u.e=null:e.e=10;l/=10,a++);return void(a>y?u.c=u.e=null:(u.e=a,u.c=[e]))}d=String(e)}else{if(!Ie.test(d=String(e)))return r(u,d,c);u.s=45==d.charCodeAt(0)?(d=d.slice(1),-1):1}(a=d.indexOf("."))>-1&&(d=d.replace(".","")),(l=d.search(/e/i))>0?(a<0&&(a=l),a+=+d.slice(l+1),d=d.substring(0,l)):a<0&&(a=d.length)}else{if(Xe(t,2,$.length,"Base"),10==t&&S)return D(u=new M(e),_+u.e+1,m);if(d=String(e),c="number"==typeof e){if(0*e!=0)return r(u,d,c,t);if(u.s=1/e<0?(d=d.slice(1),-1):1,M.DEBUG&&d.replace(/^0\.0*|\./,"").length>15)throw Error(qe+e)}else u.s=45===d.charCodeAt(0)?(d=d.slice(1),-1):1;for(i=$.slice(0,t),a=l=0,h=d.length;la){a=h;continue}}else if(!s&&(d==d.toUpperCase()&&(d=d.toLowerCase())||d==d.toLowerCase()&&(d=d.toUpperCase()))){s=!0,l=-1,a=0;continue}return r(u,String(e),c,t)}c=!1,(a=(d=n(d,t,10,u.s)).indexOf("."))>-1?d=d.replace(".",""):a=d.length}for(l=0;48===d.charCodeAt(l);l++);for(h=d.length;48===d.charCodeAt(--h););if(d=d.slice(l,++h)){if(h-=l,c&&M.DEBUG&&h>15&&(e>Be||e!==Ne(e)))throw Error(qe+u.s*e);if((a=a-l-1)>y)u.c=u.e=null;else if(a=g)?Qe(l,s):et(l,s,"0");else if(o=(e=D(new M(e),t,i)).e,a=(l=Ye(e.c)).length,1==n||2==n&&(t<=o||o<=f)){for(;as),l=et(l,o,"0"),o+1>a){if(--t>0)for(l+=".";t--;l+="0");}else if((t+=o-a)>0)for(o+1==a&&(l+=".");t--;l+="0");return e.s<0&&r?"-"+l:l}function T(e,t){for(var i,n,r=1,o=new M(e[0]);r=10;r/=10,n++);return(i=n+i*je-1)>y?e.c=e.e=null:i=10;a/=10,r++);if((o=t-r)<0)o+=je,s=t,l=d[c=0],h=Ne(l/u[r-s-1]%10);else if((c=He((o+1)/je))>=d.length){if(!n)break e;for(;d.length<=c;d.push(0));l=h=0,r=1,s=(o%=je)-je+1}else{for(l=a=d[c],r=1;a>=10;a/=10,r++);h=(s=(o%=je)-je+r)<0?0:Ne(l/u[r-s-1]%10)}if(n=n||t<0||null!=d[c+1]||(s<0?l:l%u[r-s-1]),n=i<4?(h||n)&&(0==i||i==(e.s<0?3:2)):h>5||5==h&&(4==i||n||6==i&&(o>0?s>0?l/u[r-s]:0:d[c-1])%10&1||i==(e.s<0?8:7)),t<1||!d[0])return d.length=0,n?(t-=e.e+1,d[0]=u[(je-t%je)%je],e.e=-t||0):d[0]=e.e=0,e;if(0==o?(d.length=c,a=1,c--):(d.length=c+1,a=u[je-o],d[c]=s>0?Ne(l/u[r-s]%u[s])*a:0),n)for(;;){if(0==c){for(o=1,s=d[0];s>=10;s/=10,o++);for(s=d[0]+=a,a=1;s>=10;s/=10,a++);o!=a&&(e.e++,d[0]==We&&(d[0]=1));break}if(d[c]+=a,d[c]!=We)break;d[c--]=0,a=1}for(o=d.length;0===d[--o];d.pop());}e.e>y?e.c=e.e=null:e.e=g?Qe(t,i):et(t,i,"0"),e.s<0?"-"+t:t)}return M.clone=e,M.ROUND_UP=0,M.ROUND_DOWN=1,M.ROUND_CEIL=2,M.ROUND_FLOOR=3,M.ROUND_HALF_UP=4,M.ROUND_HALF_DOWN=5,M.ROUND_HALF_EVEN=6,M.ROUND_HALF_CEIL=7,M.ROUND_HALF_FLOOR=8,M.EUCLID=9,M.config=M.set=function(e){var t,i;if(null!=e){if("object"!=typeof e)throw Error(Le+"Object expected: "+e);if(e.hasOwnProperty(t="DECIMAL_PLACES")&&(Xe(i=e[t],0,Ge,t),_=i),e.hasOwnProperty(t="ROUNDING_MODE")&&(Xe(i=e[t],0,8,t),m=i),e.hasOwnProperty(t="EXPONENTIAL_AT")&&((i=e[t])&&i.pop?(Xe(i[0],-Ge,0,t),Xe(i[1],0,Ge,t),f=i[0],g=i[1]):(Xe(i,-Ge,Ge,t),f=-(g=i<0?-i:i))),e.hasOwnProperty(t="RANGE"))if((i=e[t])&&i.pop)Xe(i[0],-Ge,-1,t),Xe(i[1],1,Ge,t),v=i[0],y=i[1];else{if(Xe(i,-Ge,Ge,t),!i)throw Error(Le+t+" cannot be zero: "+i);v=-(y=i<0?-i:i)}if(e.hasOwnProperty(t="CRYPTO")){if((i=e[t])!==!!i)throw Error(Le+t+" not true or false: "+i);if(i){if("undefined"==typeof crypto||!crypto||!crypto.getRandomValues&&!crypto.randomBytes)throw b=!i,Error(Le+"crypto unavailable");b=i}else b=i}if(e.hasOwnProperty(t="MODULO_MODE")&&(Xe(i=e[t],0,9,t),w=i),e.hasOwnProperty(t="POW_PRECISION")&&(Xe(i=e[t],0,Ge,t),k=i),e.hasOwnProperty(t="FORMAT")){if("object"!=typeof(i=e[t]))throw Error(Le+t+" not an object: "+i);x=i}if(e.hasOwnProperty(t="ALPHABET")){if("string"!=typeof(i=e[t])||/^.?$|[+\-.\s]|(.).*\1/.test(i))throw Error(Le+t+" invalid: "+i);S="0123456789"==i.slice(0,10),$=i}}return{DECIMAL_PLACES:_,ROUNDING_MODE:m,EXPONENTIAL_AT:[f,g],RANGE:[v,y],CRYPTO:b,MODULO_MODE:w,POW_PRECISION:k,FORMAT:x,ALPHABET:$}},M.isBigNumber=function(e){if(!e||!0!==e._isBigNumber)return!1;if(!M.DEBUG)return!0;var t,i,n=e.c,r=e.e,o=e.s;e:if("[object Array]"=={}.toString.call(n)){if((1===o||-1===o)&&r>=-Ge&&r<=Ge&&r===Ne(r)){if(0===n[0]){if(0===r&&1===n.length)return!0;break e}if((t=(r+1)%je)<1&&(t+=je),String(n[0]).length==t){for(t=0;t=We||i!==Ne(i))break e;if(0!==i)return!0}}}else if(null===n&&null===r&&(null===o||1===o||-1===o))return!0;throw Error(Le+"Invalid BigNumber: "+e)},M.maximum=M.max=function(){return T(arguments,-1)},M.minimum=M.min=function(){return T(arguments,1)},M.random=(o=9007199254740992,s=Math.random()*o&2097151?function(){return Ne(Math.random()*o)}:function(){return 8388608*(1073741824*Math.random()|0)+(8388608*Math.random()|0)},function(e){var t,i,n,r,o,a=0,l=[],c=new M(p);if(null==e?e=_:Xe(e,0,Ge),r=He(e/je),b)if(crypto.getRandomValues){for(t=crypto.getRandomValues(new Uint32Array(r*=2));a>>11))>=9e15?(i=crypto.getRandomValues(new Uint32Array(2)),t[a]=i[0],t[a+1]=i[1]):(l.push(o%1e14),a+=2);a=r/2}else{if(!crypto.randomBytes)throw b=!1,Error(Le+"crypto unavailable");for(t=crypto.randomBytes(r*=7);a=9e15?crypto.randomBytes(7).copy(t,a):(l.push(o%1e14),a+=7);a=r/7}if(!b)for(;a=10;o/=10,a++);ai-1&&(null==s[r+1]&&(s[r+1]=0),s[r+1]+=s[r]/i|0,s[r]%=i)}return s.reverse()}return function(n,r,o,s,a){var l,c,h,d,u,p,f,g,v=n.indexOf("."),y=_,b=m;for(v>=0&&(d=k,k=0,n=n.replace(".",""),p=(g=new M(r)).pow(n.length-v),k=d,g.c=t(et(Ye(p.c),p.e,"0"),10,o,e),g.e=g.c.length),h=d=(f=t(n,r,o,a?(l=$,e):(l=e,$))).length;0==f[--d];f.pop());if(!f[0])return l.charAt(0);if(v<0?--h:(p.c=f,p.e=h,p.s=s,f=(p=i(p,g,y,b,o)).c,u=p.r,h=p.e),v=f[c=h+y+1],d=o/2,u=u||c<0||null!=f[c+1],u=b<4?(null!=v||u)&&(0==b||b==(p.s<0?3:2)):v>d||v==d&&(4==b||u||6==b&&1&f[c-1]||b==(p.s<0?8:7)),c<1||!f[0])n=u?et(l.charAt(1),-y,l.charAt(0)):l.charAt(0);else{if(f.length=c,u)for(--o;++f[--c]>o;)f[c]=0,c||(++h,f=[1].concat(f));for(d=f.length;!f[--d];);for(v=0,n="";v<=d;n+=l.charAt(f[v++]));n=et(n,h,l.charAt(0))}return n}}(),i=function(){function e(e,t,i){var n,r,o,s,a=0,l=e.length,c=t%Ue,h=t/Ue|0;for(e=e.slice();l--;)a=((r=c*(o=e[l]%Ue)+(n=h*o+(s=e[l]/Ue|0)*c)%Ue*Ue+a)/i|0)+(n/Ue|0)+h*s,e[l]=r%i;return a&&(e=[a].concat(e)),e}function t(e,t,i,n){var r,o;if(i!=n)o=i>n?1:-1;else for(r=o=0;rt[r]?1:-1;break}return o}function i(e,t,i,n){for(var r=0;i--;)e[i]-=r,r=e[i]1;e.splice(0,1));}return function(n,r,o,s,a){var l,c,h,d,u,p,_,m,f,g,v,y,b,w,k,x,$,S=n.s==r.s?1:-1,R=n.c,T=r.c;if(!(R&&R[0]&&T&&T[0]))return new M(n.s&&r.s&&(R?!T||R[0]!=T[0]:T)?R&&0==R[0]||!T?0*S:S/0:NaN);for(f=(m=new M(S)).c=[],S=o+(c=n.e-r.e)+1,a||(a=We,c=Ke(n.e/je)-Ke(r.e/je),S=S/je|0),h=0;T[h]==(R[h]||0);h++);if(T[h]>(R[h]||0)&&c--,S<0)f.push(1),d=!0;else{for(w=R.length,x=T.length,h=0,S+=2,(u=Ne(a/(T[0]+1)))>1&&(T=e(T,u,a),R=e(R,u,a),x=T.length,w=R.length),b=x,v=(g=R.slice(0,x)).length;v=a/2&&k++;do{if(u=0,(l=t(T,g,x,v))<0){if(y=g[0],x!=v&&(y=y*a+(g[1]||0)),(u=Ne(y/k))>1)for(u>=a&&(u=a-1),_=(p=e(T,u,a)).length,v=g.length;1==t(p,g,_,v);)u--,i(p,x<_?$:T,_,a),_=p.length,l=1;else 0==u&&(l=u=1),_=(p=T.slice()).length;if(_=10;S/=10,h++);D(m,o+(m.e=h+c*je-1)+1,s,d)}else m.e=c,m.r=+d;return m}}(),a=/^(-?)0([xbo])(?=\w[\w.]*$)/i,l=/^([^.]+)\.$/,c=/^\.([^.]+)$/,h=/^-?(Infinity|NaN)$/,d=/^\s*\+(?=[\w.])|^\s+|\s+$/g,r=function(e,t,i,n){var r,o=i?t:t.replace(d,"");if(h.test(o))e.s=isNaN(o)?null:o<0?-1:1;else{if(!i&&(o=o.replace(a,function(e,t,i){return r="x"==(i=i.toLowerCase())?16:"b"==i?2:8,n&&n!=r?e:t}),n&&(r=n,o=o.replace(l,"$1").replace(c,"0.$1")),t!=o))return new M(o,r);if(M.DEBUG)throw Error(Le+"Not a"+(n?" base "+n:"")+" number: "+t);e.s=null}e.c=e.e=null},u.absoluteValue=u.abs=function(){var e=new M(this);return e.s<0&&(e.s=1),e},u.comparedTo=function(e,t){return Ze(this,new M(e,t))},u.decimalPlaces=u.dp=function(e,t){var i,n,r,o=this;if(null!=e)return Xe(e,0,Ge),null==t?t=m:Xe(t,0,8),D(new M(o),e+o.e+1,t);if(!(i=o.c))return null;if(n=((r=i.length-1)-Ke(this.e/je))*je,r=i[r])for(;r%10==0;r/=10,n--);return n<0&&(n=0),n},u.dividedBy=u.div=function(e,t){return i(this,new M(e,t),_,m)},u.dividedToIntegerBy=u.idiv=function(e,t){return i(this,new M(e,t),0,1)},u.exponentiatedBy=u.pow=function(e,t){var i,n,r,o,s,a,l,c,h=this;if((e=new M(e)).c&&!e.isInteger())throw Error(Le+"Exponent not an integer: "+z(e));if(null!=t&&(t=new M(t)),s=e.e>14,!h.c||!h.c[0]||1==h.c[0]&&!h.e&&1==h.c.length||!e.c||!e.c[0])return c=new M(Math.pow(+z(h),s?e.s*(2-Je(e)):+z(e))),t?c.mod(t):c;if(a=e.s<0,t){if(t.c?!t.c[0]:!t.s)return new M(NaN);(n=!a&&h.isInteger()&&t.isInteger())&&(h=h.mod(t))}else{if(e.e>9&&(h.e>0||h.e<-1||(0==h.e?h.c[0]>1||s&&h.c[1]>=24e7:h.c[0]<8e13||s&&h.c[0]<=9999975e7)))return o=h.s<0&&Je(e)?-0:0,h.e>-1&&(o=1/o),new M(a?1/o:o);k&&(o=He(k/je+2))}for(s?(i=new M(.5),a&&(e.s=1),l=Je(e)):l=(r=Math.abs(+z(e)))%2,c=new M(p);;){if(l){if(!(c=c.times(h)).c)break;o?c.c.length>o&&(c.c.length=o):n&&(c=c.mod(t))}if(r){if(0===(r=Ne(r/2)))break;l=r%2}else if(D(e=e.times(i),e.e+1,1),e.e>14)l=Je(e);else{if(0===(r=+z(e)))break;l=r%2}h=h.times(h),o?h.c&&h.c.length>o&&(h.c.length=o):n&&(h=h.mod(t))}return n?c:(a&&(c=p.div(c)),t?c.mod(t):o?D(c,k,m,void 0):c)},u.integerValue=function(e){var t=new M(this);return null==e?e=m:Xe(e,0,8),D(t,t.e+1,e)},u.isEqualTo=u.eq=function(e,t){return 0===Ze(this,new M(e,t))},u.isFinite=function(){return!!this.c},u.isGreaterThan=u.gt=function(e,t){return Ze(this,new M(e,t))>0},u.isGreaterThanOrEqualTo=u.gte=function(e,t){return 1===(t=Ze(this,new M(e,t)))||0===t},u.isInteger=function(){return!!this.c&&Ke(this.e/je)>this.c.length-2},u.isLessThan=u.lt=function(e,t){return Ze(this,new M(e,t))<0},u.isLessThanOrEqualTo=u.lte=function(e,t){return-1===(t=Ze(this,new M(e,t)))||0===t},u.isNaN=function(){return!this.s},u.isNegative=function(){return this.s<0},u.isPositive=function(){return this.s>0},u.isZero=function(){return!!this.c&&0==this.c[0]},u.minus=function(e,t){var i,n,r,o,s=this,a=s.s;if(t=(e=new M(e,t)).s,!a||!t)return new M(NaN);if(a!=t)return e.s=-t,s.plus(e);var l=s.e/je,c=e.e/je,h=s.c,d=e.c;if(!l||!c){if(!h||!d)return h?(e.s=-t,e):new M(d?s:NaN);if(!h[0]||!d[0])return d[0]?(e.s=-t,e):new M(h[0]?s:3==m?-0:0)}if(l=Ke(l),c=Ke(c),h=h.slice(),a=l-c){for((o=a<0)?(a=-a,r=h):(c=l,r=d),r.reverse(),t=a;t--;r.push(0));r.reverse()}else for(n=(o=(a=h.length)<(t=d.length))?a:t,a=t=0;t0)for(;t--;h[i++]=0);for(t=We-1;n>a;){if(h[--n]=0;){for(i=0,u=y[r]%f,p=y[r]/f|0,o=r+(s=l);o>r;)i=((c=u*(c=v[--s]%f)+(a=p*c+(h=v[s]/f|0)*u)%f*f+_[o]+i)/m|0)+(a/f|0)+p*h,_[o--]=c%m;_[o]=i}return i?++n:_.splice(0,1),C(e,_,n)},u.negated=function(){var e=new M(this);return e.s=-e.s||null,e},u.plus=function(e,t){var i,n=this,r=n.s;if(t=(e=new M(e,t)).s,!r||!t)return new M(NaN);if(r!=t)return e.s=-t,n.minus(e);var o=n.e/je,s=e.e/je,a=n.c,l=e.c;if(!o||!s){if(!a||!l)return new M(r/0);if(!a[0]||!l[0])return l[0]?e:new M(a[0]?n:0*r)}if(o=Ke(o),s=Ke(s),a=a.slice(),r=o-s){for(r>0?(s=o,i=l):(r=-r,i=a),i.reverse();r--;i.push(0));i.reverse()}for((r=a.length)-(t=l.length)<0&&(i=l,l=a,a=i,t=r),r=0;t;)r=(a[--t]=a[t]+l[t]+r)/We|0,a[t]=We===a[t]?0:a[t]%We;return r&&(a=[r].concat(a),++s),C(e,a,s)},u.precision=u.sd=function(e,t){var i,n,r,o=this;if(null!=e&&e!==!!e)return Xe(e,1,Ge),null==t?t=m:Xe(t,0,8),D(new M(o),e,t);if(!(i=o.c))return null;if(n=(r=i.length-1)*je+1,r=i[r]){for(;r%10==0;r/=10,n--);for(r=i[0];r>=10;r/=10,n++);}return e&&o.e+1>n&&(n=o.e+1),n},u.shiftedBy=function(e){return Xe(e,-9007199254740991,Be),this.times("1e"+e)},u.squareRoot=u.sqrt=function(){var e,t,n,r,o,s=this,a=s.c,l=s.s,c=s.e,h=_+4,d=new M("0.5");if(1!==l||!a||!a[0])return new M(!l||l<0&&(!a||a[0])?NaN:a?s:1/0);if(0==(l=Math.sqrt(+z(s)))||l==1/0?(((t=Ye(a)).length+c)%2==0&&(t+="0"),l=Math.sqrt(+t),c=Ke((c+1)/2)-(c<0||c%2),n=new M(t=l==1/0?"5e"+c:(t=l.toExponential()).slice(0,t.indexOf("e")+1)+c)):n=new M(l+""),n.c[0])for((l=(c=n.e)+h)<3&&(l=0);;)if(o=n,n=d.times(o.plus(i(s,o,h,1))),Ye(o.c).slice(0,l)===(t=Ye(n.c)).slice(0,l)){if(n.e0&&_>0){for(o=_%a||a,h=p.substr(0,o);o<_;o+=a)h+=c+p.substr(o,a);l>0&&(h+=c+p.slice(o)),u&&(h="-"+h)}n=d?h+(i.decimalSeparator||"")+((l=+i.fractionGroupSize)?d.replace(new RegExp("\\d{"+l+"}\\B","g"),"$&"+(i.fractionGroupSeparator||"")):d):h}return(i.prefix||"")+n+(i.suffix||"")},u.toFraction=function(e){var t,n,r,o,s,a,l,c,h,d,u,_,f=this,g=f.c;if(null!=e&&(!(l=new M(e)).isInteger()&&(l.c||1!==l.s)||l.lt(p)))throw Error(Le+"Argument "+(l.isInteger()?"out of range: ":"not an integer: ")+z(l));if(!g)return new M(f);for(t=new M(p),h=n=new M(p),r=c=new M(p),_=Ye(g),s=t.e=_.length-f.e-1,t.c[0]=Ve[(a=s%je)<0?je+a:a],e=!e||l.comparedTo(t)>0?s>0?t:h:l,a=y,y=1/0,l=new M(_),c.c[0]=0;d=i(l,t,0,1),1!=(o=n.plus(d.times(r))).comparedTo(e);)n=r,r=o,h=c.plus(d.times(o=h)),c=o,t=l.minus(d.times(o=t)),l=o;return o=i(e.minus(n),r,0,1),c=c.plus(o.times(h)),n=n.plus(o.times(r)),c.s=h.s=f.s,u=i(h,r,s*=2,m).minus(f).abs().comparedTo(i(c,n,s,m).minus(f).abs())<1?[h,r]:[c,n],y=a,u},u.toNumber=function(){return+z(this)},u.toPrecision=function(e,t){return null!=e&&Xe(e,1,Ge),R(this,e,t,2)},u.toString=function(e){var t,i=this,r=i.s,o=i.e;return null===o?r?(t="Infinity",r<0&&(t="-"+t)):t="NaN":(null==e?t=o<=f||o>=g?Qe(Ye(i.c),o):et(Ye(i.c),o,"0"):10===e&&S?t=et(Ye((i=D(new M(i),_+o+1,m)).c),i.e,"0"):(Xe(e,2,$.length,"Base"),t=n(et(Ye(i.c),o,"0"),10,e,r,!0)),r<0&&i.c[0]&&(t="-"+t)),t},u.valueOf=u.toJSON=function(){return z(this)},u._isBigNumber=!0,u[Symbol.toStringTag]="BigNumber",u[Symbol.for("nodejs.util.inspect.custom")]=u.valueOf,null!=t&&M.set(t),M}(),it=class{key;left=null;right=null;constructor(e){this.key=e}},nt=class extends it{constructor(e){super(e)}},rt=class{size=0;modificationCount=0;splayCount=0;splay(e){const t=this.root;if(null==t)return this.compare(e,e),-1;let i=null,n=null,r=null,o=null,s=t;const a=this.compare;let l;for(;;)if(l=a(s.key,e),l>0){let t=s.left;if(null==t)break;if(l=a(t.key,e),l>0&&(s.left=t.right,t.right=s,s=t,t=s.left,null==t))break;null==i?n=s:i.left=s,i=s,s=t}else{if(!(l<0))break;{let t=s.right;if(null==t)break;if(l=a(t.key,e),l<0&&(s.right=t.left,t.left=s,s=t,t=s.right,null==t))break;null==r?o=s:r.right=s,r=s,s=t}}return null!=r&&(r.right=s.left,s.left=o),null!=i&&(i.left=s.right,s.right=n),this.root!==s&&(this.root=s,this.splayCount++),l}splayMin(e){let t=e,i=t.left;for(;null!=i;){const e=i;t.left=e.right,e.right=t,t=e,i=t.left}return t}splayMax(e){let t=e,i=t.right;for(;null!=i;){const e=i;t.right=e.left,e.left=t,t=e,i=t.right}return t}_delete(e){if(null==this.root)return null;if(0!=this.splay(e))return null;let t=this.root;const i=t,n=t.left;if(this.size--,null==n)this.root=t.right;else{const e=t.right;t=this.splayMax(n),t.right=e,this.root=t}return this.modificationCount++,i}addNewRoot(e,t){this.size++,this.modificationCount++;const i=this.root;null!=i?(t<0?(e.left=i,e.right=i.right,i.right=null):(e.right=i,e.left=i.left,i.left=null),this.root=e):this.root=e}_first(){const e=this.root;return null==e?null:(this.root=this.splayMin(e),this.root)}_last(){const e=this.root;return null==e?null:(this.root=this.splayMax(e),this.root)}clear(){this.root=null,this.size=0,this.modificationCount++}has(e){return this.validKey(e)&&0==this.splay(e)}defaultCompare(){return(e,t)=>et?1:0}wrap(){return{getRoot:()=>this.root,setRoot:e=>{this.root=e},getSize:()=>this.size,getModificationCount:()=>this.modificationCount,getSplayCount:()=>this.splayCount,setSplayCount:e=>{this.splayCount=e},splay:e=>this.splay(e),has:e=>this.has(e)}}},ot=class e extends rt{root=null;compare;validKey;constructor(e,t){super(),this.compare=e??this.defaultCompare(),this.validKey=t??(e=>null!=e&&null!=e)}delete(e){return!!this.validKey(e)&&null!=this._delete(e)}deleteAll(e){for(const t of e)this.delete(t)}forEach(e){const t=this[Symbol.iterator]();let i;for(;i=t.next(),!i.done;)e(i.value,i.value,this)}add(e){const t=this.splay(e);return 0!=t&&this.addNewRoot(new nt(e),t),this}addAndReturn(e){const t=this.splay(e);return 0!=t&&this.addNewRoot(new nt(e),t),this.root.key}addAll(e){for(const t of e)this.add(t)}isEmpty(){return null==this.root}isNotEmpty(){return null!=this.root}single(){if(0==this.size)throw"Bad state: No element";if(this.size>1)throw"Bad state: Too many element";return this.root.key}first(){if(0==this.size)throw"Bad state: No element";return this._first().key}last(){if(0==this.size)throw"Bad state: No element";return this._last().key}lastBefore(e){if(null==e)throw"Invalid arguments(s)";if(null==this.root)return null;if(this.splay(e)<0)return this.root.key;let t=this.root.left;if(null==t)return null;let i=t.right;for(;null!=i;)t=i,i=t.right;return t.key}firstAfter(e){if(null==e)throw"Invalid arguments(s)";if(null==this.root)return null;if(this.splay(e)>0)return this.root.key;let t=this.root.right;if(null==t)return null;let i=t.left;for(;null!=i;)t=i,i=t.left;return t.key}retainAll(t){const i=new e(this.compare,this.validKey),n=this.modificationCount;for(const e of t){if(n!=this.modificationCount)throw"Concurrent modification during iteration.";this.validKey(e)&&0==this.splay(e)&&i.add(this.root.key)}i.size!=this.size&&(this.root=i.root,this.size=i.size,this.modificationCount++)}lookup(e){if(!this.validKey(e))return null;return 0!=this.splay(e)?null:this.root.key}intersection(t){const i=new e(this.compare,this.validKey);for(const e of this)t.has(e)&&i.add(e);return i}difference(t){const i=new e(this.compare,this.validKey);for(const e of this)t.has(e)||i.add(e);return i}union(e){const t=this.clone();return t.addAll(e),t}clone(){const t=new e(this.compare,this.validKey);return t.size=this.size,t.root=this.copyNode(this.root),t}copyNode(e){if(null==e)return null;const t=new nt(e.key);return function e(t,i){let n,r;do{if(n=t.left,r=t.right,null!=n){const t=new nt(n.key);i.left=t,e(n,t)}if(null!=r){const e=new nt(r.key);i.right=e,t=r,i=e}}while(null!=r)}(e,t),t}toSet(){return this.clone()}entries(){return new lt(this.wrap())}keys(){return this[Symbol.iterator]()}values(){return this[Symbol.iterator]()}[Symbol.iterator](){return new at(this.wrap())}[Symbol.toStringTag]="[object Set]"},st=class{tree;path=new Array;modificationCount=null;splayCount;constructor(e){this.tree=e,this.splayCount=e.getSplayCount()}[Symbol.iterator](){return this}next(){return this.moveNext()?{done:!1,value:this.current()}:{done:!0,value:null}}current(){if(!this.path.length)return null;const e=this.path[this.path.length-1];return this.getValue(e)}rebuildPath(e){this.path.splice(0,this.path.length),this.tree.splay(e),this.path.push(this.tree.getRoot()),this.splayCount=this.tree.getSplayCount()}findLeftMostDescendent(e){for(;null!=e;)this.path.push(e),e=e.left}moveNext(){if(this.modificationCount!=this.tree.getModificationCount()){if(null==this.modificationCount){this.modificationCount=this.tree.getModificationCount();let e=this.tree.getRoot();for(;null!=e;)this.path.push(e),e=e.left;return this.path.length>0}throw"Concurrent modification during iteration."}if(!this.path.length)return!1;this.splayCount!=this.tree.getSplayCount()&&this.rebuildPath(this.path[this.path.length-1].key);let e=this.path[this.path.length-1],t=e.right;if(null!=t){for(;null!=t;)this.path.push(t),t=t.left;return!0}for(this.path.pop();this.path.length&&this.path[this.path.length-1].right===e;)e=this.path.pop();return this.path.length>0}},at=class extends st{getValue(e){return e.key}},lt=class extends st{getValue(e){return[e.key,e.key]}},ct=e=>()=>e,ht=e=>{const t=e?(t,i)=>i.minus(t).abs().isLessThanOrEqualTo(e):ct(!1);return(e,i)=>t(e,i)?0:e.comparedTo(i)};function dt(e){const t=e?(t,i,n,r,o)=>t.exponentiatedBy(2).isLessThanOrEqualTo(r.minus(i).exponentiatedBy(2).plus(o.minus(n).exponentiatedBy(2)).times(e)):ct(!1);return(e,i,n)=>{const r=e.x,o=e.y,s=n.x,a=n.y,l=o.minus(a).times(i.x.minus(s)).minus(r.minus(s).times(i.y.minus(a)));return t(l,r,o,s,a)?0:l.comparedTo(0)}}var ut=e=>e,pt=e=>{if(e){const t=new ot(ht(e)),i=new ot(ht(e)),n=(e,t)=>t.addAndReturn(e),r=e=>({x:n(e.x,t),y:n(e.y,i)});return r({x:new tt(0),y:new tt(0)}),r}return ut},_t=e=>({set:e=>{mt=_t(e)},reset:()=>_t(e),compare:ht(e),snap:pt(e),orient:dt(e)}),mt=_t(),ft=(e,t)=>e.ll.x.isLessThanOrEqualTo(t.x)&&t.x.isLessThanOrEqualTo(e.ur.x)&&e.ll.y.isLessThanOrEqualTo(t.y)&&t.y.isLessThanOrEqualTo(e.ur.y),gt=(e,t)=>{if(t.ur.x.isLessThan(e.ll.x)||e.ur.x.isLessThan(t.ll.x)||t.ur.y.isLessThan(e.ll.y)||e.ur.y.isLessThan(t.ll.y))return null;const i=e.ll.x.isLessThan(t.ll.x)?t.ll.x:e.ll.x,n=e.ur.x.isLessThan(t.ur.x)?e.ur.x:t.ur.x;return{ll:{x:i,y:e.ll.y.isLessThan(t.ll.y)?t.ll.y:e.ll.y},ur:{x:n,y:e.ur.y.isLessThan(t.ur.y)?e.ur.y:t.ur.y}}},vt=(e,t)=>e.x.times(t.y).minus(e.y.times(t.x)),yt=(e,t)=>e.x.times(t.x).plus(e.y.times(t.y)),bt=e=>yt(e,e).sqrt(),wt=(e,t,i)=>{const n={x:t.x.minus(e.x),y:t.y.minus(e.y)},r={x:i.x.minus(e.x),y:i.y.minus(e.y)};return vt(r,n).div(bt(r)).div(bt(n))},kt=(e,t,i)=>{const n={x:t.x.minus(e.x),y:t.y.minus(e.y)},r={x:i.x.minus(e.x),y:i.y.minus(e.y)};return yt(r,n).div(bt(r)).div(bt(n))},xt=(e,t,i)=>t.y.isZero()?null:{x:e.x.plus(t.x.div(t.y).times(i.minus(e.y))),y:i},$t=(e,t,i)=>t.x.isZero()?null:{x:i,y:e.y.plus(t.y.div(t.x).times(i.minus(e.x)))},St=class e{point;isLeft;segment;otherSE;consumedBy;static compare(t,i){const n=e.comparePoints(t.point,i.point);return 0!==n?n:(t.point!==i.point&&t.link(i),t.isLeft!==i.isLeft?t.isLeft?1:-1:Ot.compare(t.segment,i.segment))}static comparePoints(e,t){return e.x.isLessThan(t.x)?-1:e.x.isGreaterThan(t.x)?1:e.y.isLessThan(t.y)?-1:e.y.isGreaterThan(t.y)?1:0}constructor(e,t){void 0===e.events?e.events=[this]:e.events.push(this),this.point=e,this.isLeft=t}link(e){if(e.point===this.point)throw new Error("Tried to link already linked events");const t=e.point.events;for(let e=0,i=t.length;e{const n=i.otherSE;t.set(i,{sine:wt(this.point,e.point,n.point),cosine:kt(this.point,e.point,n.point)})};return(e,n)=>{t.has(e)||i(e),t.has(n)||i(n);const{sine:r,cosine:o}=t.get(e),{sine:s,cosine:a}=t.get(n);return r.isGreaterThanOrEqualTo(0)&&s.isGreaterThanOrEqualTo(0)?o.isLessThan(a)?1:o.isGreaterThan(a)?-1:0:r.isLessThan(0)&&s.isLessThan(0)?o.isLessThan(a)?-1:o.isGreaterThan(a)?1:0:s.isLessThan(r)?-1:s.isGreaterThan(r)?1:0}}},Mt=class e{events;poly;_isExteriorRing;_enclosingRing;static factory(t){const i=[];for(let n=0,r=t.length;n0&&(e=i)}let t=e.segment.prevInResult(),i=t?t.prevInResult():null;for(;;){if(!t)return null;if(!i)return t.ringOut;if(i.ringOut!==t.ringOut)return i.ringOut?.enclosingRing()!==t.ringOut?t.ringOut:t.ringOut?.enclosingRing();t=i.prevInResult(),i=t?t.prevInResult():null}}},Rt=class{exteriorRing;interiorRings;constructor(e){this.exteriorRing=e,e.poly=this,this.interiorRings=[]}addInterior(e){this.interiorRings.push(e),e.poly=this}getGeom(){const e=this.exteriorRing.getGeom();if(null===e)return null;const t=[e];for(let e=0,i=this.interiorRings.length;e0?(this.tree.delete(t),i.push(e)):(this.segments.push(t),t.prev=n)}else{if(n&&r){const e=n.getIntersection(r);if(null!==e){if(!n.isAnEndpoint(e)){const t=this._splitSafely(n,e);for(let e=0,n=t.length;e0)return-1;const n=t.comparePoint(e.rightSE.point);return 0!==n?n:-1}if(i.isGreaterThan(n)){if(s.isLessThan(a)&&s.isLessThan(c))return-1;if(s.isGreaterThan(a)&&s.isGreaterThan(c))return 1;const i=t.comparePoint(e.leftSE.point);if(0!==i)return i;const n=e.comparePoint(t.rightSE.point);return n<0?1:n>0?-1:1}if(s.isLessThan(a))return-1;if(s.isGreaterThan(a))return 1;if(r.isLessThan(o)){const i=t.comparePoint(e.rightSE.point);if(0!==i)return i}if(r.isGreaterThan(o)){const i=e.comparePoint(t.rightSE.point);if(i<0)return 1;if(i>0)return-1}if(!r.eq(o)){const e=l.minus(s),t=r.minus(i),h=c.minus(a),d=o.minus(n);if(e.isGreaterThan(t)&&h.isLessThan(d))return 1;if(e.isLessThan(t)&&h.isGreaterThan(d))return-1}return r.isGreaterThan(o)?1:r.isLessThan(o)||l.isLessThan(c)?-1:l.isGreaterThan(c)?1:e.idt.id?1:0}constructor(e,t,i,n){this.id=++At,this.leftSE=e,e.segment=this,e.otherSE=t,this.rightSE=t,t.segment=this,t.otherSE=e,this.rings=i,this.windings=n}static fromRing(t,i,n){let r,o,s;const a=St.comparePoints(t,i);if(a<0)r=t,o=i,s=1;else{if(!(a>0))throw new Error(`Tried to create degenerate segment at [${t.x}, ${t.y}]`);r=i,o=t,s=-1}const l=new St(r,!0),c=new St(o,!1);return new e(l,c,[n],[s])}replaceRightSE(e){this.rightSE=e,this.rightSE.segment=this,this.rightSE.otherSE=this.leftSE,this.leftSE.otherSE=this.rightSE}bbox(){const e=this.leftSE.point.y,t=this.rightSE.point.y;return{ll:{x:this.leftSE.point.x,y:e.isLessThan(t)?e:t},ur:{x:this.rightSE.point.x,y:e.isGreaterThan(t)?e:t}}}vector(){return{x:this.rightSE.point.x.minus(this.leftSE.point.x),y:this.rightSE.point.y.minus(this.leftSE.point.y)}}isAnEndpoint(e){return e.x.eq(this.leftSE.point.x)&&e.y.eq(this.leftSE.point.y)||e.x.eq(this.rightSE.point.x)&&e.y.eq(this.rightSE.point.y)}comparePoint(e){return mt.orient(this.leftSE.point,e,this.rightSE.point)}getIntersection(e){const t=this.bbox(),i=e.bbox(),n=gt(t,i);if(null===n)return null;const r=this.leftSE.point,o=this.rightSE.point,s=e.leftSE.point,a=e.rightSE.point,l=ft(t,s)&&0===this.comparePoint(s),c=ft(i,r)&&0===e.comparePoint(r),h=ft(t,a)&&0===this.comparePoint(a),d=ft(i,o)&&0===e.comparePoint(o);if(c&&l)return d&&!h?o:!d&&h?a:null;if(c)return h&&r.x.eq(a.x)&&r.y.eq(a.y)?null:r;if(l)return d&&o.x.eq(s.x)&&o.y.eq(s.y)?null:s;if(d&&h)return null;if(d)return o;if(h)return a;const u=((e,t,i,n)=>{if(t.x.isZero())return $t(i,n,e.x);if(n.x.isZero())return $t(e,t,i.x);if(t.y.isZero())return xt(i,n,e.y);if(n.y.isZero())return xt(e,t,i.y);const r=vt(t,n);if(r.isZero())return null;const o={x:i.x.minus(e.x),y:i.y.minus(e.y)},s=vt(o,t).div(r),a=vt(o,n).div(r),l=e.x.plus(a.times(t.x)),c=i.x.plus(s.times(n.x)),h=e.y.plus(a.times(t.y)),d=i.y.plus(s.times(n.y));return{x:l.plus(c).div(2),y:h.plus(d).div(2)}})(r,this.vector(),s,e.vector());return null===u?null:ft(n,u)?mt.snap(u):null}split(t){const i=[],n=void 0!==t.events,r=new St(t,!0),o=new St(t,!1),s=this.rightSE;this.replaceRightSE(o),i.push(o),i.push(r);const a=new e(r,s,this.rings.slice(),this.windings.slice());return St.comparePoints(a.leftSE.point,a.rightSE.point)>0&&a.swapEvents(),St.comparePoints(this.leftSE.point,this.rightSE.point)>0&&this.swapEvents(),n&&(r.checkForConsuming(),o.checkForConsuming()),i}swapEvents(){const e=this.rightSE;this.rightSE=this.leftSE,this.leftSE=e,this.leftSE.isLeft=!0,this.rightSE.isLeft=!1;for(let e=0,t=this.windings.length;e0){const e=i;i=n,n=e}if(i.prev===n){const e=i;i=n,n=e}for(let e=0,t=n.rings.length;e1===e.length&&e[0].isSubject;this._isInResult=i(e)!==i(t);break}}return this._isInResult}},Pt=class{poly;isExterior;segments;bbox;constructor(e,t,i){if(!Array.isArray(e)||0===e.length)throw new Error("Input geometry is not a valid Polygon or MultiPolygon");if(this.poly=t,this.isExterior=i,this.segments=[],"number"!=typeof e[0][0]||"number"!=typeof e[0][1])throw new Error("Input geometry is not a valid Polygon or MultiPolygon");const n=mt.snap({x:new tt(e[0][0]),y:new tt(e[0][1])});this.bbox={ll:{x:n.x,y:n.y},ur:{x:n.x,y:n.y}};let r=n;for(let t=1,i=e.length;tzt.run("union",e,t),Ht=(e,...t)=>zt.run("intersection",e,t),Nt=(e,...t)=>zt.run("difference",e,t);mt.set;const Lt=/^#[0-9a-fA-F]{6}$/;function qt(e,t){return"string"==typeof e&&Lt.test(e)?e:t}const Wt="(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])",jt=new RegExp(`^rgb\\(${Wt}, ${Wt}, ${Wt}\\)$`);function Bt(e){if(!Array.isArray(e)||e.length<3)return null;const t=e.slice(0,3);if(!t.every(e=>"number"==typeof e&&Number.isFinite(e)))return null;const[i,n,r]=t.map(e=>Math.round(Math.min(255,Math.max(0,e))));return`rgb(${i}, ${n}, ${r})`}function Vt(e){const t=Math.max(0,Math.min(120,(e-40)/140*120));return`hsl(${Math.round(t)}, 85%, 55%)`}function Ut(e,t){if(!(Number.isFinite(e)&&t>0))return e;const i=Math.round(e/t)*t;return Math.abs(i-e)<=1e-9*t?e:i}function Gt(e,t,i,n=1/0){if(!(i>0&&e?.every(Number.isFinite)&&t?.every(Number.isFinite)))return[t[0],t[1]];const r=t[0]-e[0],o=t[1]-e[1];if(Math.abs(r)+Math.abs(o)<=1e-12)return[e[0],e[1]];const s=Math.PI/4;let a=Math.atan2(o,r);a<0&&(a+=2*Math.PI);const l=Math.floor(a/s+.5)%8,[c,h]=[[1,0],[1,1],[0,1],[-1,1],[-1,0],[-1,-1],[0,-1],[1,-1]][l],d=c*c+h*h;let u=Math.max(0,Math.round((r*c+o*h)/(i*d)));if(Number.isFinite(n)&&n>=0){const t=(e,t)=>{if(!t)return 1/0;const r=t>0?n-e:e+n;return Math.max(0,Math.floor((r+1e-9*i)/i))};u=Math.min(u,t(e[0],c),t(e[1],h))}return[e[0]+c*u*i,e[1]+h*u*i]}function Kt(e,t){if(t){const t=e/2.54;let i=Math.floor(t/12),n=Math.round(t-12*i);return 12===n&&(i+=1,n=0),`${i}′ ${n}″`}return`${(e/100).toFixed(2)} m`}function Yt(e,t,i=1){const n=e[0].toFixed(i),r=e[1].toFixed(i),o=t[0].toFixed(i),s=t[1].toFixed(i),a=n=3?e.poly:e&&null!=e.x&&null!=e.y&&null!=e.w&&null!=e.h?[[e.x,e.y],[e.x+e.w,e.y],[e.x+e.w,e.y+e.h],[e.x,e.y+e.h]]:null}function Xt(e){const t=[];for(const i of e||[])i?.poly?.length>=3?t.push({poly:i.poly.map(e=>e.join(",")).join(" ")}):i&&null!=i.x&&null!=i.y&&null!=i.w&&null!=i.h&&t.push({rect:{x:i.x,y:i.y,w:i.w,h:i.h,rx:.03*Math.min(i.w,i.h)}});return t}function Jt(e){const t=[],i=new Set;for(const n of e||[]){const e=Zt(n);if(e)for(let n=0;n=90?e-=180:e<-90&&(e+=180),n.step&&n.step>0){const i=Math.sqrt(d),o=Math.min(Math.max(n.length||0,0)/2,i/2);let a=Math.round(u*i/n.step)*n.step;Math.abs(u*i-i/2)<=n.step/2&&(a=i/2),a=Math.max(o,Math.min(i-o,a));const l=a/i;r={x:t+l*c,y:s+l*h,angle:e}}else r={x:p[0],y:p[1],angle:e}}}return r}function ei(e,t,i){let n=null,r=1/0;for(let o=0;o=r)continue;r=_;const m=Math.sqrt(u),f=(i>0?Math.max(0,Math.min(m,Math.round(p*m/i)*i)):p*m)/m;n=[s+f*h,a+f*d]}return n}function ti(e,t,i,n,r,o=1){const s=t*Math.PI/180,a=[Math.cos(s),Math.sin(s)];let l=null,c=o;for(const t of Jt(n)){const i=[[t[0],t[1]],[t[2],t[3]]],n=t=>Math.abs(a[0]*(t[1]-e[1])-a[1]*(t[0]-e[0]));if(n(i[0])>o||n(i[1])>o)continue;const r=(i[0][0]-e[0])*a[0]+(i[0][1]-e[1])*a[1],s=(i[1][0]-e[0])*a[0]+(i[1][1]-e[1])*a[1],h=Math.min(r,s),d=Math.max(r,s),u=h>0?h:d<0?-d:0;u[e[0]+a[0]*t,e[1]+a[1]*t],f=(h+d)/2;return{wallA:m(h),wallB:m(d),sideA:p,sideB:_,midA:m((h-u)/2),midB:m((u+d)/2),wallCenter:m(f),centered:Math.abs(f)<=r}}function ii(e,t,i=!1,n){if("passage"===e)return 1;if(null==t||"unavailable"===t||"unknown"===t)return"window"===e?0:1;const r="string"==typeof n?n.trim()?Number(n):NaN:Number(n),o=null!=n&&Number.isFinite(r)?Math.max(0,Math.min(1,r/100)):function(e){return["on","open","home","detected","playing","cleaning"].includes(String(e))}(t)?1:0;return i?1-o:o}function ni(e,t){return(Number.isFinite(e)&&e>0?e:0)*(Number.isFinite(t)?Math.max(0,Math.min(1,t)):0)}function ri(e){return"passage"===e.type?[]:[e.contact,e.lock].filter(e=>"string"==typeof e&&e.length>0)}function oi(e,t,i=200){const n=t.trim().toLowerCase();return(n?e.filter(e=>e.label.toLowerCase().includes(n)||e.value.toLowerCase().includes(n)):e).slice(0,Math.max(0,i))}function si(e,t,i=.001){return Math.abs(e[0]-t[0])e[1]!=l>e[1]&&e[0]<(a-o)*(e[1]-s)/(l-s)+o&&(i=!i)}return i}function li(e,t,i){const n=i[0]-t[0],r=i[1]-t[1],o=n*n+r*r;let s=o?((e[0]-t[0])*n+(e[1]-t[1])*r)/o:0;return s=Math.max(0,Math.min(1,s)),Math.hypot(e[0]-(t[0]+s*n),e[1]-(t[1]+s*r))}function ci(e,t){if(!t||t.length<2)return null;let i=null,n=1/0;for(let r=0;rr&&s<-r||o<-r&&s>r)&&(a>r&&l<-r||a<-r&&l>r)}function _i(e,t=24){const i=e.map(e=>e[0]),n=e.map(e=>e[1]),r=Math.min(...i),o=Math.max(...i),s=Math.min(...n),a=Math.max(...n),l=Math.max(o-r,a-s)||1;let c=0,h=0,d=0;for(let t=0;t1e-9?[h/(3*c),d/(3*c)]:[(r+o)/2,(s+a)/2],p=(t,i)=>{const n=((t,i)=>{if(!ai([t,i],e))return-1/0;let n=1/0;for(let r=0;rm&&(m=c,_=[n,l])}if(_){const[e,i]=_,n=(o-r)/t,l=(a-s)/t;for(let t=-4;t<=4;t++)for(let r=-4;r<=4;r++){const o=e+n*t/4,s=i+l*r/4,a=p(o,s);a>m&&(m=a,_=[o,s])}}return _||mi(e)||e[0]}function mi(e,t=1e-6){if(!e||e.length<3)return null;const i=e.length,n=[e.reduce((e,t)=>e+t[0],0)/i,e.reduce((e,t)=>e+t[1],0)/i];if(di(n,e,t))return n;for(let n=0;ngi(e,t,i));return n.filter(e=>!n.some(t=>t!==e&&gi(t,e,i)))}function bi(e){if(!e||e.length<3)return 0;let t=0;for(let i=0;i[e[0],e[1]]),[e[0][0],e[0][1]]]]}function ki(e,t){if(!e||!t||e.length<3||t.length<3)return null;const i=It(wi(e),wi(t));if(1!==i.length)return null;if(1!==i[0].length)return null;const n=i[0][0].slice(0,-1).map(e=>[e[0],e[1]]);return n.length>=3?n:null}function xi(e,t,i){for(let n=0;n1&&si(i[0],i[i.length-1],t)&&i.pop(),i}function Si(e,t,i=1e-6){if(!e||e.length<3||!t||t.length<2)return null;const n=t[0],r=t[t.length-1];if(si(n,r,i))return null;const o=xi(e,n,i),s=xi(e,r,i);if(o<0||s<0)return null;const a=t.slice(1,-1);for(const t of a)if(!di(t,e,i))return null;for(let i=0;i{const s=[t];let a=(n+1)%e.length;for(let t=0;t<=e.length&&(s.push(e[a]),a!==o);t++)a=(a+1)%e.length;return s.push(r),$i(s,i)};let c,h;if(o===s){const s=$i([...t],i);if(s.length<3||bi(s)<=i)return null;const a=[];for(let i=0;i=0?t:[...t].reverse();for(const e of i)a.push(e)}c=$i(a,i),h=s}else c=$i([...l(n,o,r,s),...[...a].reverse()],i),h=$i([...l(r,s,n,o),...a],i);return c.length<3||h.length<3||bi(c)<=i||bi(h)<=i||Math.abs(bi(c)+bi(h)-bi(e))>Math.max(i,1e-6*bi(e))?null:[c,h]}function Mi(e,t,i){const[n,r]=e.split(":");return"device"===n?r:"entity"===n?"lg_"+r:t&&t.startsWith("v_")?t:i()}function Ri(e){return e.length?Math.round(e.reduce((e,t)=>e+t,0)/e.length):null}function Ti(e,t){if(t>e[2]/e[3]){const i=e[3],n=e[3]*t;return{x:e[0]-(n-e[2])/2,y:e[1],w:n,h:i}}const i=e[2],n=e[2]/t;return{x:e[0],y:e[1]-(n-e[3])/2,w:i,h:n}}function Ci(e,t,i,n){if(e.length<2)return;const r=t.x+n,o=t.x+t.w-n,s=t.y+n,a=t.y+t.h-n;for(let t=0;t<60;t++){let t=!1;for(let n=0;n=0)i=t.slice(0,r).trim(),n=t.slice(r+1).trim();else{const e=t.split(".");e.length>2&&(i=e.slice(0,2).join("."),n=e.slice(2).join("."))}return/^[a-z0-9_]+\.[a-z0-9_]+$/.test(i)?r>=0&&!n||n&&!/^[a-zA-Z0-9_.-]+$/.test(n)?null:n?{entity:i,attr:n}:{entity:i}:null}function qi(e,t){const i=String(e??"").trim(),n=String(t??"").trim(),r=Li(n?`${i}:${n}`:i);return r?`{${r.entity}${r.attr?`:${r.attr}`:""}}`:""}function Wi(e,t,i){const n=String(t??"").trim();if(!n)return null;const r=e?.states?.[n];if(!r)return null;const o=String(i??"").trim(),s=e=>e.slice(0,60);if(o){const t=function(e){if(null==e)return null;if(Array.isArray(e)){const t=e.map(e=>null==e?"":String(e)).join(", ");return t?t.slice(0,60):null}if("object"==typeof e)return null;const t=String(e);return""===t?null:t.slice(0,60)}(r.attributes?.[o]);if(null===t)return null;const i=e?.formatEntityAttributeValue;if("function"==typeof i)try{const t=i.call(e,r,o);if("string"==typeof t&&""!==t)return{text:s(t),formatted:!0}}catch{}return{text:t,formatted:!1}}const a=r.state;if(null==a||""===a)return null;const l=e?.formatEntityState;if("function"==typeof l)try{const t=l.call(e,r);if("string"==typeof t&&""!==t)return{text:s(t),formatted:!0}}catch{}return{text:s(String(a)),formatted:!1}}function ji(e,t,i){const n=String(t??"").trim(),r=String(i??"").trim()||n;if(!r)return e.text;const o=e.formatted&&n?function(e,t){if(!t)return e;const i=e.replace(/\s+$/,"");return i.endsWith(t)?i.slice(0,i.length-t.length).replace(/\s+$/,""):e}(e.text,n):e.text;return`${o} ${r}`}function Bi(e,t){const i=(t?.entity||"").trim();if(!i)return"";const n=e?.states?.[i],r=n?.state;if(!n||null==r||""===r||"unavailable"===r||"unknown"===r)return Hi;const o=(t?.attr||"").trim(),s=Wi(e,i,o||null);if(null===s)return Hi;return ji(s,o?"":String(n.attributes?.unit_of_measurement??"").trim(),t?.unit)}function Vi(e,t,i,n=()=>!0){const r=e??"";let o=!1;const s=r.replace(/\{([^{}\r\n]+)\}/g,(e,t)=>{const r=Li(t);return r?(o=!0,n(r.entity||"")?Bi(i,r):Hi):e});if(o)return s;const a=(t?.entity||"").trim();if(!a)return r;if(!n(a)){const e=r.indexOf(Ni);return e>=0?r.slice(0,e)+Hi+r.slice(e+2):r?`${r} ${Hi}`:Hi}const l=Bi(i,t),c=r.indexOf(Ni);return c>=0?r.slice(0,c)+l+r.slice(c+2):r?`${r} ${l}`:l}const Ui=20;function Gi(e){const t=Number(e?.scale);if(Number.isFinite(t)&&t>0)return Math.min(20,Math.max(.15,t));return{s:.7,m:1,l:1.5}[String(e?.size??"")]??1}function Ki(e,t){if(!t)return e;let i=e;for(const[e,n]of Object.entries(t))i=i.split("{"+e+"}").join(String(n));return i}const Yi="#55606c",Zi=.55,Xi=20,Ji=25,Qi={c:"#607d8b",a:.18};function en(e,t=Qi){const i=e&&"object"==typeof e?e:null,n=i?.a;return{c:qt(i?.c,t.c),a:"number"==typeof n&&Number.isFinite(n)?Math.min(1,Math.max(0,n)):t.a}}function tn(e,t){const i=en(e),n=t?.settings?.custom_fill;return n&&"object"==typeof n?en(n,i):i}function nn(e){const t=e?.settings||{},i=!e?.plan_url,n="glow"===t.fill_mode;return{showBorders:t.show_borders??i,showNames:t.show_names??i,color:qt(t.room_color,Yi),opacity:"number"==typeof t.room_opacity?Math.min(1,Math.max(0,t.room_opacity)):.55,fill:["lqi","light","temp","custom"].includes(t.fill_mode)?t.fill_mode:"none",customFill:en(t.custom_fill),glow:"boolean"==typeof t.glow_enabled?t.glow_enabled:n,tempMin:"number"==typeof t.temp_min?t.temp_min:20,tempMax:"number"==typeof t.temp_max?t.temp_max:25,showLqi:"boolean"==typeof t.show_lqi?t.show_lqi:null,cardFontScale:"number"==typeof t.card_font_scale&&t.card_font_scale>0?Math.min(3,Math.max(.5,t.card_font_scale)):1,labelTemp:!0===t.label_temp,labelHum:!0===t.label_hum,labelLqi:!0===t.label_lqi,labelLight:!0===t.label_light,bgColor:qt(t.bg_color,null),hideDecor:!0===t.hide_decor,hideOpenings:!0===t.hide_openings}}function rn(e,t){if(t.bgColor)return t.bgColor;const i=e?.bg_color;return qt(i,"")}const on={light_on:{c:"#ffd45c",a:.18},light_off:{c:"#9aa0a6",a:.14},light_none:{c:"#6b7480",a:0},temp_cold:{c:"#4fc3f7",a:.18},temp_ok:{c:"#66d17a",a:.18},temp_hot:{c:"#ffd45c",a:.18},lqi_low:{c:"#f25a4a",a:.18},lqi_high:{c:"#4bd28f",a:.18},glow_base:{c:"#0d1b2a",a:.5},glow_light:{c:"#ffd9a0",a:.85},wall_fill:{c:"#ffffff",a:1}};function sn(e){const t={},i=e?.fill_colors||{};for(const e of Object.keys(on)){const n=on[e],r=i[e];t[e]={c:qt(r?.c,n.c),a:r&&"number"==typeof r.a?Math.min(1,Math.max(0,r.a)):n.a}}return t}function an(e,t,i){const n=Math.min(1,Math.max(0,i)),r=[1,3,5].map(t=>parseInt(e.slice(t,t+2),16)),o=[1,3,5].map(e=>parseInt(t.slice(e,e+2),16)),s=r.map((e,t)=>Math.round(e+(o[t]-e)*n));return"#"+s.map(e=>e.toString(16).padStart(2,"0")).join("")}function ln(e,t,i,n,r,o,s,a=Qi){const l=function(e,t,i,n,r,o,s,a=Qi){if("custom"===e)return en(a);if("lqi"===e){if(null==t)return null;const e=(t-40)/140;return{c:an(s.lqi_low.c,s.lqi_high.c,e),a:s.lqi_low.a+(s.lqi_high.a-s.lqi_low.a)*Math.min(1,Math.max(0,e))}}if("light"===e)return"none"===i?s.light_none.a>0?s.light_none:null:"on"===i?s.light_on:s.light_off;if("temp"===e){if(null==n)return null;const e=Math.min(r,o),t=Math.max(r,o);return nt?s.temp_hot:s.temp_ok}return null}(e,t,i,n,r,o,s,a);return l?{color:l.c,opacity:l.a,mode:e}:null}const cn={blind:["mdi:blinds","mdi:blinds-open"],shade:["mdi:blinds","mdi:blinds-open"],shutter:["mdi:window-shutter","mdi:window-shutter-open"],curtain:["mdi:curtains-closed","mdi:curtains"],window:["mdi:window-closed","mdi:window-open"],awning:["mdi:awning-outline","mdi:awning"],door:["mdi:door-closed","mdi:door-open"],garage:["mdi:garage","mdi:garage-open"],gate:["mdi:gate","mdi:gate-open"],damper:["mdi:circle-slice-8","mdi:circle-outline"]},hn=[["mdi:roller-shade-closed","mdi:roller-shade"],["mdi:blinds-horizontal-closed","mdi:blinds-horizontal"],["mdi:garage-variant","mdi:garage-open-variant"],["mdi:door","mdi:door-open"]];function dn(e){for(const t of[...Object.values(cn),...hn])if(e===t[0]||e===t[1])return t;return null}function un(e,t,i,n,r){if(!n||"unavailable"===n||"unknown"===n)return e;if(r){const i="cover"===t?dn(e):null;return i?"closed"===n?i[0]:i[1]:e}if("binary_sensor"===t){if("door"===i)return"on"===n?"mdi:door-open":"mdi:door-closed";if("window"===i)return"on"===n?"mdi:window-open":"mdi:window-closed";if("garage_door"===i)return"on"===n?"mdi:garage-open-variant":"mdi:garage-variant"}if("cover"===t){const t=cn[String(i||"")];if(t)return"closed"===n?t[0]:t[1];const r=dn(e);return r?"closed"===n?r[0]:r[1]:e}return"lock"===t?"locked"===n?"mdi:lock":"mdi:lock-open-variant":"light"===t&&"mdi:lightbulb"===e&&"on"===n?"mdi:lightbulb-on":e}function pn(e){const t=Math.min(4e4,Math.max(1e3,e))/100,i=t<=66?255:329.698727446*Math.pow(t-60,-.1332047592),n=t<=66?99.4708025861*Math.log(t)-161.1195681661:288.1221695283*Math.pow(t-60,-.0755148492),r=t>=66?255:t<=19?0:138.5177312231*Math.log(t-10)-305.0447927307,o=e=>Math.round(Math.min(255,Math.max(0,e)));return[o(i),o(n),o(r)]}const _n=1/2.2;function mn(e){const t=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/.exec(e);return t?"#"+t.slice(1).map(e=>Math.min(255,Number(e)).toString(16).padStart(2,"0")).join(""):null}function fn(e){if(!e||"object"!=typeof e||Array.isArray(e))return null;const t=e;if(Object.keys(t).some(e=>"c"!==e&&"bri"!==e))return null;const i=qt(t.c,null);return i?void 0===t.bri||null===t.bri?{c:i}:"number"!=typeof t.bri||!Number.isFinite(t.bri)||t.bri<.01||t.bri>1?null:{c:i,bri:t.bri}:null}function gn(e,t,i){const n=fn(t),r=e?.attributes||{},o=n?.bri??function(e){const t=e?.attributes?.brightness,i="number"==typeof t?t:"string"==typeof t&&""!==t.trim()?Number(t):Number.NaN;return Number.isFinite(i)?Math.max(0,Math.min(1,i/255)):1}(e);if(n)return{c:n.c,bri:o};const s=Bt(r.rgb_color);if(s)return{c:mn(s)||qt(i,"#ffd9a0"),bri:o};const a=Number(r.color_temp_kelvin)||(Number(r.color_temp)>0?1e6/Number(r.color_temp):NaN);return Number.isFinite(a)&&a>0?{c:(l=pn(a),"#"+l.slice(0,3).map(e=>Math.min(255,Math.max(0,Math.round(Number(e)||0))).toString(16).padStart(2,"0")).join("")),bri:o}:{c:qt(i,"#ffd9a0"),bri:o};var l}function vn(e,t,i){return"on"===e?.state?gn(e,t,i):null}function yn(e,t=1){const i=Math.max(0,Math.min(1,Number.isFinite(e)?e:1)),n=.7*Math.max(0,Math.min(1,Number.isFinite(t)?t:1))*(.4+.6*Math.pow(i,_n));return Math.max(0,Math.min(1,n))}function bn(e){return e.startsWith("light.")||e.startsWith("switch.")}function wn(e,t,i=1e-6){const n=[];if(!e||!t||e.length<3||t.length<3)return n;for(let r=0;ru||l>u)continue;const p=(r[0]-o[0])*h+(r[1]-o[1])*d,_=(s[0]-o[0])*h+(s[1]-o[1])*d,m=Math.max(0,Math.min(p,_)),f=Math.min(c,Math.max(p,_));f-m>i&&n.push([o[0]+h*m,o[1]+d*m,o[0]+h*f,o[1]+d*f])}}return n}function kn(e,t,i=1e-6){const n=[];for(const r of e){const e=[r[0],r[1]],o=[r[2],r[3]],s=o[0]-e[0],a=o[1]-e[1],l=Math.hypot(s,a);if(lo||r>o)continue;const s=(n[0]-e[0])*c+(n[1]-e[1])*h,a=(n[2]-e[0])*c+(n[3]-e[1])*h,u=Math.max(0,Math.min(s,a)),p=Math.min(l,Math.max(s,a));p-u>i&&d.push([u,p])}if(!d.length){n.push([e[0],e[1],o[0],o[1]]);continue}d.sort((e,t)=>e[0]-t[0]);let u=0;for(const[t,r]of d)t-u>i&&n.push([e[0]+c*u,e[1]+h*u,e[0]+c*t,e[1]+h*t]),u=Math.max(u,r);l-u>i&&n.push([e[0]+c*u,e[1]+h*u,o[0],o[1]])}return n}function xn(e,t,i=1e-6){const n=[];for(let t=0;t{if("string"!=typeof e||!e)return;const i=Rn(e);i.startsWith("/api/houseplan/content/")&&t.add(i)};for(const t of e?.spaces||[]){i(t?.plan_url);for(const e of t?.markers||[])for(const t of e?.pdfs||[])i(t?.url)}for(const t of e?.markers||[])for(const e of t?.pdfs||[])i(e?.url);return t}function Rn(e){return e?e.startsWith("/houseplan_files/plans/")?"/api/houseplan/content/plans/_/"+e.slice(23):e.startsWith("/houseplan_files/files/")?"/api/houseplan/content/files/"+e.slice(23):e:""}function Tn(e,t){const i=t?.settings?.fill_mode;return"none"===i||"lqi"===i||"light"===i||"temp"===i||"custom"===i?i:e}function Cn(e,t){const i=t?.settings;return"boolean"==typeof i?.glow?i.glow:"glow"===i?.fill_mode||e}function Dn(e,t,i,n){if(!t||!i||t===i)return e;const r="/files/"+t+"/",o="/files/"+i+"/";return e.map(e=>{if(!e.url.includes(r))return e;const t=e.url.split(r)[1]||"",[i,s]=[t.split("?")[0],t.includes("?")?"?"+t.split("?")[1]:""];if(n){const t=n[decodeURIComponent(i)]??n[i];return t?{...e,url:e.url.split(r+i)[0]+o+encodeURIComponent(t)+s}:e}return{...e,url:e.url.split(r).join(o)}})}function zn(e,t=1){const i=Number(e);return Number.isFinite(i)&&i>0?Math.min(3,Math.max(.5,i)):t}function An(e,t,i){let n=null,r=null;for(const o of t){if(!(Math.abs(o[0]-e[0])<1e-6&&Math.abs(o[1]-e[1])<1e-6)){if(Math.abs(o[0]-e[0])<=i){const t=Math.abs(o[1]-e[1]);t>1e-6&&(!n||t1e-6&&(!r||t"number"==typeof e&&Number.isFinite(e),Vn=(e,t,i)=>Math.min(i,Math.max(t,e));function Un(e){return e.elevation<=-6?"night":e.elevation>=6?"day":e.rising?"dawn":"dusk"}function Gn(e){const t=(Math.floor(Number(e)||0)%1440+1440)%1440;return t>=300&&t<480?"dawn":t>=480&&t<1080?"day":t>=1080&&t<1260?"dusk":"night"}function Kn(e){const t=Un(e),i=e.azimuth*Math.PI/180;return{sunX:50-42*Math.sin(i),sunY:78-Vn(e.elevation,0,90)/90*64,sunOpacity:"night"===t?0:Vn((e.elevation+6)/12,0,1)}}function Yn(e){const t=(Math.floor(Number(e)||0)%1440+1440)%1440;if(t<300||t>=1260)return{sunX:50,sunY:78,sunOpacity:0};const i=(t-300)/960,n=(t-300)/120,r=(1260-t)/120;return{sunX:8+84*i,sunY:78-64*Math.sin(i*Math.PI),sunOpacity:Math.max(.18,Math.min(n,r,1))}}function Zn(e,t=new Date){const i=function(e){const t=e?.states?.["sun.sun"]?.attributes;return t&&Bn(t.azimuth)&&Bn(t.elevation)&&"boolean"==typeof t.rising?{azimuth:qn(t.azimuth),elevation:t.elevation,rising:t.rising}:null}(e);if(i)return{phase:Un(i),source:"sun",...Kn(i)};const n="number"==typeof t?t:function(e=new Date){return 60*e.getHours()+e.getMinutes()}(t);return{phase:Gn(n),source:"clock",...Yn(n)}}function Xn(e){return`${e.source}|${e.phase}|${e.sunX.toFixed(2)}|${e.sunY.toFixed(2)}|`+e.sunOpacity.toFixed(3)}const Jn=[[-90,"#070c14"],[-12,"#070c14"],[-4,"#131a28"],[0,"#4a3527"],[10,"#e8ddcf"],[30,"#ffffff"],[90,"#ffffff"]],Qn=e=>Math.min(1,Math.max(0,e));function er(e,t,i=6){const n=e.angle*Math.PI/180,r=[Math.sin(n),-Math.cos(n)],o=n=>{const o=[e.x+r[0]*i*n,e.y+r[1]*i*n];return t.find(e=>e.poly.length>=3&&ai(o,e.poly))||null},s=o(1),a=o(-1);return s&&a?null:s||a?s?{normal:[-r[0],-r[1]],roomId:s.id}:{normal:r,roomId:a.id}:null}function tr(e,t,i){return i>0&&e[0]*t[0]+e[1]*t[1]>.05}function ir(e,t,i,n){return[[e[0],e[1]],[t[0],t[1]],[t[0]+i[0]*n,t[1]+i[1]*n],[e[0]+i[0]*n,e[1]+i[1]*n]]}function nr(e,t){try{const i=Ht([[...e.map(e=>[e[0],e[1]]),[e[0][0],e[0][1]]]],[[...t.map(e=>[e[0],e[1]]),[t[0][0],t[0][1]]]]),n=[];for(const e of i){const t=e?.[0];!Array.isArray(t)||t.length<4||n.push(t.slice(0,t.length-1).map(e=>[e[0],e[1]]))}return n}catch{return[]}}function rr(e,t,i,n,r,o,s){if(!(n>0))return[];const a=Wn(i,r),l=[-a[0],-a[1]],c=function(e){const t=Math.min(90,Math.max(0,e));return.7*(.8+1.7*Math.pow(1-t/90,1.6))}(n),h=[];for(const i of t){if(!(i.length>0))continue;const t=er(i,e);if(!t||!tr(t.normal,a,n))continue;const r=e.find(e=>e.id===t.roomId);if(!r)continue;const d=o&&o[t.roomId]||r.poly,u=i.angle*Math.PI/180,p=i.length/2,_=[-t.normal[0],-t.normal[1]],m=Math.max(0,s?.[i.id]||0),f=i.x+_[0]*m/2,g=i.y+_[1]*m/2,v=Math.cos(u)*p,y=Math.sin(u)*p,b=[f-v,g-y],w=[f+v,g+y],k=c*i.length,x=nr(ir(b,w,l,k),d);if(!x.length)continue;const $=l[0]*_[0]+l[1]*_[1];h.push({openingId:i.id,roomId:t.roomId,polys:x,a:b,b:w,dir:l,len:k,normal:_,depth:k*$})}return h}const or=e=>"number"==typeof e&&Number.isInteger(e)&&e>=0&&e<=359?e:null;function sr(e,t){const i=or(t?.north_deg);return null!==i?i:or(e?.north_deg)}function ar(e,t){const i=e=>"static"===e||"daynight"===e?e:null;return i(t?.bg_mode)??i(e?.bg_mode)??"static"}function lr(e,t){const i=t?.sun_rays;return"boolean"==typeof i?i:!0===e?.sun_rays}function cr(e){const t=e?.states?.["sun.sun"]?.attributes,i=Number(t?.azimuth),n=Number(t?.elevation);return Number.isFinite(i)&&Number.isFinite(n)?{azimuth:i,elevation:n}:null}const hr=["dawn","day","dusk","night"];function dr(e){if(!e)return"";const t=jn[e.phase];return[`--hp-day-cycle-outline-near:${t.outlineNear}`,`--hp-day-cycle-outline-mid:${t.outlineMid}`,`--hp-day-cycle-outline-far:${t.outlineFar}`].join(";")}function ur(e,t=1){if(!e)return U;const i=[`--hp-day-cycle-sun-x:${e.sunX.toFixed(2)}%`,`--hp-day-cycle-sun-y:${e.sunY.toFixed(2)}%`,`--hp-day-cycle-sun-opacity:${e.sunOpacity.toFixed(3)}`,`opacity:${Math.min(1,Math.max(0,t)).toFixed(4)}`].join(";");return j``}const pr={color:"#607d8b",opacity:1,widthCm:3.6,fill:!1,fillColor:"#607d8b",fillOpacity:.25},_r=(e,t=1)=>{const i=Number(e);return Number.isFinite(i)?Math.min(1,Math.max(0,i)):t},mr=e=>{let t=Number(e);return Number.isFinite(t)?(t=(t%360+360)%360,t>180?t-360:t):0};function fr(e,t,i){return mr(t)?[e.x,e.y]:i([e.x,e.y])}function gr(e,t,i,n){const r=Math.abs(i[0]-t[0]),o=Math.abs(i[1]-t[1]);return"line"===e?Math.hypot(r,o)>=n:r>=n&&o>=n}const vr=(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},yr=(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},br=(e,t,i,n=pr.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?yr(o,t,i):n};function wr(e,t){return{color:e.color,opacity:_r(e.opacity),width_cm:Math.max(.1,Math.min(100,Number(e.widthCm)||.1)),...t?{fill:e.fill,fill_color:e.fillColor,fill_opacity:_r(e.fillOpacity,.25)}:{}}}function kr(e){const t=e.x+e.w/2,i=e.y+e.h/2,n=mr(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 xr(e){const t=kr(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 $r(e,t,i,n,r,o,s,a){const l=mr(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,f=i>0?-e.h/2:e.h/2,g=p+m*c+f*d,v=_+m*h+f*u,y=n-g,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:g+(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:mr(e.angle)||void 0}}const Sr=(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 Mr(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 Tr=Math.tan(.25*Math.PI/180);function Cr(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>Tr?null:{axis:r,major:o,minor:s,angleDegrees:180*Math.atan2(s,o)/Math.PI}}function Dr(e,t){const i=Cr(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 zr=e=>`${e[0]},${e[1]}`,Ar=(e,t)=>e[0]===t[0]&&e[1]===t[1],Or=(e,t)=>{const i=zr(e),n=zr(t);return i{let t=0;for(let i=0;i{if(e.length<3)return!1;for(let t=0;t1e-12},Er=e=>{for(let t=0;t+1Ar(e,t.from)?[...t.to]:[...e],Hr=(e,t)=>e.map(e=>Array.isArray(e?.poly)?{...e,poly:e.poly.map(e=>Ir(e,t))}:e),Nr=(e,t,i)=>{const n=e.flatMap((e,t)=>Zt(e)?.some(e=>Ar(e,i.from))?[t]:[]);if(!n.length)return!1;for(const i of n){const n=Zt(e[i]),r=Zt(t[i]);if(!n||!r)continue;if(!Fr(r))return!1;const o=Math.sign(Pr(n)),s=Math.sign(Pr(r));if(o&&s&&o!==s)return!1}const r=new Set;for(const e of n){const i=Zt(t[e]);if(i)for(let n=0;n{let i=0;for(const n of e){const e=Zt(n);if(e)for(let n=0;n{const{a:i,b:n,axis:r}=e,o="horizontal"===r?{from:n,to:[n[0],i[1]]}:{from:n,to:[i[0],n[1]]},s="horizontal"===r?{from:i,to:[i[0],n[1]]}:{from:i,to:[n[0],i[1]]};return[{move:o,preservedDegree:Lr(t,i)},{move:s,preservedDegree:Lr(t,n)}].sort((e,t)=>t.preservedDegree-e.preservedDegree||zr(e.move.to).localeCompare(zr(t.move.to))||zr(e.move.from).localeCompare(zr(t.move.from))).map(e=>e.move)};function Wr(e){const t=JSON.parse(JSON.stringify(e||{}));let i=Array.isArray(t.rooms)?t.rooms:[];const n=new Map;for(const e of i){const t=Zt(e);if(t)for(let e=0;ee.key.localeCompare(t.key))){let t=null;for(const n of qr(e,i)){const e=a.get(zr(n.from));if(e&&e!==zr(n.to))continue;const r=Hr(i,n);if(Nr(i,r,n)){t=n,i=r;break}}t?(a.set(zr(t.from),zr(t.to)),r++,s=Math.max(s,Math.hypot(t.to[0]-t.from[0],t.to[1]-t.from[1]))):o++}t.rooms=i;for(const e of t.room_drafts||[]){if(!Array.isArray(e?.points)||e.points.length<2)continue;const t=e.points.map(e=>[...e]),i=t.slice(0,-1).flatMap((i,n)=>{const r=t[n+1],o=Cr(i,r);return o?[{key:`${String(e.id||"")}:${n}`,a:[...i],b:[...r],axis:o.axis}]:[]});let n=t;for(const e of i){let t=null;for(const i of qr(e,[{poly:n}])){const e=n.map(e=>Ir(e,i)),r=e.length>=4&&Ar(e[0],e[e.length-1]),o=r?e.slice(0,-1):e;if(r?Fr(o):Er(o)){t=i,n=e;break}}t?(r++,s=Math.max(s,Math.hypot(t.to[0]-t.from[0],t.to[1]-t.from[1]))):o++}e.points=n}for(const e of t.partitions||[]){if(!Array.isArray(e?.a)||!Array.isArray(e?.b))continue;const i=Cr(e.a,e.b);if(!i)continue;const n={key:String(e.id||Or(e.a,e.b)),a:[...e.a],b:[...e.b],axis:i.axis};let a=null;for(const i of qr(n,[{poly:[e.a,e.b]}])){const n=Ir(e.a,i),r=Ir(e.b,i),o=Math.hypot(r[0]-n[0],r[1]-n[1]);if(!(o>0))continue;const s=(t.openings||[]).filter(t=>"partition"===t?.host?.kind&&t.host.id===e.id).every(e=>{const t=Number(e.host.t),i=Number(e.length);return Number.isFinite(t)&&t>=0&&t<=1&&Number.isFinite(i)&&i>0&&t*o-i/2>=-1e-12&&t*o+i/2<=o+1e-12});if(s){a=i,e.a=n,e.b=r;break}}a?(r++,s=Math.max(s,Math.hypot(a.to[0]-a.from[0],a.to[1]-a.from[1]))):o++}return{space:t,report:{wallsStraightened:r,wallsStraightenSkipped:o,maxStraightenShift:s},changed:r>0}}const jr=10**9,Br=240,Vr=1e-4;function Ur(e){if(Array.isArray(e))return e.map(e=>Ur(e));if(null!==e&&"object"==typeof e){const t={};for(const[i,n]of Object.entries(e))t[i]=Ur(n);return t}return e}function Gr(e){if("number"!=typeof e||!Number.isFinite(e))return e;const t=(e<0||Object.is(e,-0)?-1:1)*(Math.floor(Math.abs(e)*jr+.5)/jr);return 0===t?0:t}function Kr(e){if("number"!=typeof e||!Number.isFinite(e))return e;const t=e*Br,i=Math.round(t);if(Math.abs(t-i)null!==Zr(e)):[]}function Jr(e,t){for(const i of t)Object.prototype.hasOwnProperty.call(e,i)&&(e[i]=Gr(e[i]))}function Qr(e,t){for(const i of t)Object.prototype.hasOwnProperty.call(e,i)&&(e[i]=Kr(e[i]))}function eo(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 Xr(e.rooms))t(i,["x","y","w","h"]),r(i.poly);for(const t of Xr(e.walls))n(t.a),n(t.b);for(const t of Xr(e.wall_segments))n(t.a),n(t.b);for(const i of Xr(e.openings))t(i,["x","y"]);for(const i of Xr(e.decor))"line"===i.kind?t(i,["x1","y1","x2","y2"]):"rect"===i.kind||"ellipse"===i.kind||"furniture"===i.kind?t(i,["x","y","w","h"]):"text"===i.kind&&t(i,["x","y"]);for(const t of Xr(e.room_drafts))r(t.points);for(const t of Xr(e.partitions))n(t.a),n(t.b);for(const t of Xr(e.wall_columns))n(t.center);for(const t of Xr(e.open_spans))n(t.a),n(t.b)}const r=Zr(t);if(!r)return;const o=new Map;if(n)for(const e of Xr(n.spaces))null!=e.id&&o.set(String(e.id),e);for(const e of Object.values(r)){const t=Zr(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 no(e){const t=Number(e?.cell_cm);return t>0?t:5}function ro(e,t={}){const i={canonicalized:0,far:0,maxShift:0,maxShiftCm:0,spaces:[],bySpace:new Map},n=Xr(Zr(e)?.spaces);let r=5;for(const e of n)r=Math.max(r,no(e));io(e,t,(e,t)=>{const n=e*Br,o=Math.abs(n-Math.round(n)),s=Kr(e),a=o>0&&o=Vr))return;const l=a&&"number"==typeof s?Math.abs(s-e):0;if(a?i.canonicalized++:i.far++,i.maxShift=Math.max(i.maxShift,l),i.maxShiftCm=Math.max(i.maxShiftCm,l*Br*(t?no(t):r)),!t?.id||!a)return;const c=String(t.id);let h=i.bySpace.get(c);h||(h={spaceId:c,space:String(t.title||c),canonicalized:0,far:0,maxShift:0,maxShiftCm:0},i.bySpace.set(c,h)),h.canonicalized++,h.maxShift=Math.max(h.maxShift,l),h.maxShiftCm=Math.max(h.maxShiftCm,l*Br*no(t))}),i.bySpace.size&&io(e,t,(e,t)=>{if(!t?.id)return;const n=i.bySpace.get(String(t.id));if(!n)return;const r=e*Br;Math.abs(r-Math.round(r))>=Vr&&n.far++}),i.spaces=[...i.bySpace.values()];const{bySpace:o,...s}=i;return s}function oo(e){return function(e){const t=e,i=Zr(t);i&&Qr(i,["x","y"]);return t}(Ur(e))}function so(e){const t=e,i=Zr(t);if(!i)return t;for(const e of Object.values(i)){const t=Zr(e);t&&Qr(t,["x","y"])}return t}function ao(e){return lo(Ur(e))}function lo(e){const t=e,i=Zr(t);if(!i)return t;for(const e of Xr(i.spaces)){Jr(e,["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"]);for(const t of Xr(e.rooms))Qr(t,["x","y","w","h"]),to(t.poly);for(const t of Xr(e.walls))eo(t.a),eo(t.b);for(const t of Xr(e.wall_segments))eo(t.a),eo(t.b);for(const t of Xr(e.openings)){Qr(t,["x","y"]),Jr(t,["angle","length"]);const e=Zr(t.host);e&&Jr(e,["t"])}for(const t of Xr(e.decor))"line"===t.kind?Qr(t,["x1","y1","x2","y2"]):"rect"===t.kind||"ellipse"===t.kind||"furniture"===t.kind?(Qr(t,["x","y","w","h"]),Jr(t,["angle"])):"text"===t.kind&&(Qr(t,["x","y"]),Jr(t,["scale","angle"]));for(const t of Xr(e.room_drafts))to(t.points);for(const t of Xr(e.partitions))eo(t.a),eo(t.b);for(const t of Xr(e.wall_columns))eo(t.center),"square"===t.shape&&Jr(t,["angle"]);for(const t of Xr(e.open_spans))eo(t.a),eo(t.b)}for(const e of Xr(i.markers))Jr(e,["angle"]);return t}const co=15,ho=8;function uo(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 po=Math.sin(.25*Math.PI/180);function _o(e,t){return Number.isFinite(e)&&e>0&&Number.isFinite(t)&&t>0&&e*t<3}function mo(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 go(e){return Number.isFinite(e)?Math.max(1,Math.min(100,e)):1}function vo(e,t){return!Number.isFinite(e)||e<0?"":String(t?Math.round(e/2.54*100)/100:Math.round(100*e)/100)}function yo(e,t,i){if(!Number.isFinite(e)||e<=0)return 0;const n=Number(t)>0?Number(t):5;return go(e)/n*i}function bo(e,t){return t>0&&Number.isFinite(e)?Math.round(e/t)*t:e}function wo(e){return Math.max(1e-6*Math.abs(e),1e-9)}function ko(e,t){if(!(t>0&&Number.isFinite(e)))return e;const i=bo(e,t);return Math.abs(i-e)<=wo(t)?i:e}function xo(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 $o(e,t,i){const n=[ko(e[0],i),ko(e[1],i)],r=[ko(t[0],i),ko(t[1],i)],o=bo((n[0]+r[0])/2,i),s=bo((n[1]+r[1])/2,i),[a,l]=xo(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 So(e,t,i,n){return 1===n?$o(e,t,i):$o([e[0]/n,e[1]/n],[t[0]/n,t[1]/n],i)}function Mo(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 Ro(e,t,i,n,r){const o=r>0?r:1;return{key:So(e,t,n,o),cm:go(i),a:[e[0]/o,e[1]/o],b:[t[0]/o,t[1]/o]}}function To(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 Co(e,t){const[i,n]=xo(e,t);let r=Math.atan2(n,i);return r<0&&(r+=Math.PI),r}function Do(e,t){let i=Math.abs(e-t);return i>Math.PI/2&&(i=Math.PI-i),i<.02}function zo(e,t,i,n,r=1){if(!e?.length)return null;const o=So(t,i,n,r),s=e.find(e=>e.key===o);if(s)return s;const a=r>0?r:1,l=wo(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=Mo(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=Co(t,i),p=Math.max(.5*n,1e-9)*a;for(const t of To(e,a))if(Do(t.ang,u)&&Math.hypot(t.x-h,t.y-d)<=p)return t.w;return null}function Ao(e,t,i,n,r=1){const o=zo(e,t,i,n,r);if(o&&o.cm>0)return go(o.cm);const s=function(e,t,i,n,r){if(!e?.length)return null;const o=r>0?r:1,s=Math.hypot(i[0]-t[0],i[1]-t[1]);if(s<1e-12)return null;const a=Co(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=Mo(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||!Do(Co(e[0],e[1]),a))continue;if(ws(t[0],t[1],e[0][0],e[0][1],e[1][0],e[1][1])>l||ws(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=Mo(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 Do(Co(i,o),Co(t,n))&&ws(i[0],i[1],t[0],t[1],n[0],n[1])<=l&&ws(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(!Do(Co(i,o),Co(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 Po(e,t,i,n=8){const[r,o]=xo(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 Fo(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,f=(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)},g=(e,t)=>{const[i,n]=xo(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]=g(e,t),s=go(i);if(y.some(e=>e.entry.cm===s&&m(e.span[0],r)&&m(e.span[1],o)))return;const l=Ro(r,o,s,n,a);v.push(l),y.push({entry:l,span:[r,o]})};for(const t of e){const e=Mo(t,a);if(e){const[i,n]=g(e[0],e[1]),r=n[0]-i[0],s=n[1]-i[1],a=r*r+s*s,d=Math.sqrt(a);if(d<=c){v.push({...t,cm:go(t.cm)});continue}const u=[];for(const e of h){if(!Do(Co(i,n),Co(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=[f(o,l[0].move),f(s,l[0].move)],g=l.slice(1).some(e=>{const t=f(o,e.move),i=f(s,e.move);return!m(h[0],t)||!m(h[1],i)});y.push(g?[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=[To([t],a)[0]];1!==a&&i.push(To([t],1)[0]);const n=i.filter(Boolean).some(e=>h.some(t=>{if(!Do(e.ang,Co(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&&ws(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=To([t],a)[0];if(e){const t=new Set;for(const i of h){if(!Do(e.ang,Co(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(ws(e.x,e.y,i.oa[0],i.oa[1],i.ob[0],i.ob[1])>l)continue;const o=f([e.x,e.y],i),[s,c]=xo(i.na,i.nb),h=Math.max(n*a,1e-6);t.add(So([o[0]-s*h,o[1]-c*h],[o[0]+s*h,o[1]+c*h],n,a))}1===t.size&&(i=[...t][0])}}v.push({...t,key:i||t.key,cm:go(t.cm)})}return v}function Eo(e,t,i,n,r=1,o="affine"){return Fo(e,t,i,n,r,o)}function Io(e,t,i,n,r=1,o="fixed-topology"){let s=!1;const a=Fo(e,t,i,n,r,o,()=>{s=!0});return{walls:s?(e||[]).map(e=>({...e})):a,rejected:s}}function Ho(e,t,i,n=1,r=[]){const o=n>0?n:1,s=Math.abs(i),a=Math.max(s*o*Vr,1e-9),l=(r||[]).flatMap(e=>{const t=Mo(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=Mo(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 f=0;for(const[e,t]of m){if(e>f+a)break;if(f=Math.max(f,t),f>=u-a)break}fe.key!==s);return null==n||n<1?a:[...a,Ro(t,i,n,r,o)]}function Lo(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=as(e,t,i,n,r,o);if(!s)return[];const a=[];for(let e=0;e0||(c=No(c,t,i,n,r,s)))}return c}function Wo(e){const{a:t,b:i,halfDepth:n}=e;if(!Array.isArray(t)||!Array.isArray(i)||t.length<2||i.length<2||![t[0],t[1],i[0],i[1]].every(Number.isFinite))return null;const r=i[0]-t[0],o=i[1]-t[1],s=Math.hypot(r,o);if(!(s>1e-9&&n>0&&Number.isFinite(n)))return null;const a=-o/s*n,l=r/s*n;return[[t[0]+a,t[1]+l],[i[0]+a,i[1]+l],[i[0]-a,i[1]-l],[t[0]-a,t[1]-l]]}function jo(e,t,i){return Math.hypot(e[0]-t[0],e[1]-t[1])<=i}function Bo(e,t,i){const n=t.b[0]-t.a[0],r=t.b[1]-t.a[1],o=n*n+r*r;if(!(o>i*i))return!1;const s=((e[0]-t.a[0])*n+(e[1]-t.a[1])*r)/o;if(!(s>0&&s<1))return!1;const a=[t.a[0]+n*s,t.a[1]+r*s];return Math.hypot(e[0]-a[0],e[1]-a[1])<=i}function Vo(e,t,i,n){const r=Math.hypot(t,i);if(!(r>1e-9&&n>0))return;const o=[t/r,i/r],s=e.find(e=>Math.abs(e.u[0]*o[1]-e.u[1]*o[0])<1e-9&&e.u[0]*o[0]+e.u[1]*o[1]>1-1e-9);s?s.halfDepth=Math.max(s.halfDepth,n):e.push({u:o,halfDepth:n})}function Uo(e,t){try{const i=Nt($s(e),$s(t));let n=null,r=0;for(const e of i||[]){const t=e?.[0]||[],i=Math.abs(Jo(t));t.length>=4&&i>r&&(r=i,n=t.slice(0,-1).map(e=>[e[0],e[1]]))}return n}catch{return null}}function Go(e,t=1e-6){const i=(e||[]).map((e,t)=>({segment:e,index:t})).filter(({segment:e})=>e&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&e.a.every(Number.isFinite)&&e.b.every(Number.isFinite)&&Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>1e-9);if(i.length<2)return[];const n=Math.max(Number.isFinite(t)?t:0,1e-9),r=i.flatMap(({segment:e})=>[e.a,e.b]).map(e=>[e[0],e[1]]).sort((e,t)=>e[0]-t[0]||e[1]-t[1]),o=[];for(const e of r)o.some(t=>jo(t,e,n))||o.push(e);const s=[];for(const e of o){const t=[];let r=!1;for(const{segment:o,index:s}of i){const i=Math.hypot(o.b[0]-o.a[0],o.b[1]-o.a[1]);jo(e,o.a,n)?t.push({u:[(o.b[0]-o.a[0])/i,(o.b[1]-o.a[1])/i],halfDepth:o.halfDepth,length:i,index:s}):jo(e,o.b,n)?t.push({u:[(o.a[0]-o.b[0])/i,(o.a[1]-o.b[1])/i],halfDepth:o.halfDepth,length:i,index:s}):Bo(e,o,n)&&(r=!0)}if(r||2!==t.length)continue;const[o,a]=t,l=o.u[0]*a.u[1]-o.u[1]*a.u[0];if(Math.abs(l)<1e-9)continue;const c=l<0?1:-1,h=[-o.u[1],o.u[0]],d=[-a.u[1],a.u[0]],u=[e[0]+h[0]*o.halfDepth*c,e[1]+h[1]*o.halfDepth*c],p=[e[0]-d[0]*a.halfDepth*c,e[1]-d[1]*a.halfDepth*c];if(!ts(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(Jo(h))>n*n&&s.push({segmentIndex:t.index,wedge:h})}}return s}function Ko(e,t=1e-6){const i=(e||[]).filter(e=>e&&Array.isArray(e.a)&&Array.isArray(e.b)&&e.a.length>=2&&e.b.length>=2&&e.a.every(Number.isFinite)&&e.b.every(Number.isFinite)&&Number.isFinite(e.halfDepth)&&e.halfDepth>0&&Math.hypot(e.b[0]-e.a[0],e.b[1]-e.a[1])>1e-9);if(i.length<2)return[];const n=Math.max(Number.isFinite(t)?t:0,1e-9),r=i.flatMap(e=>[e.a,e.b]).map(e=>[e[0],e[1]]).sort((e,t)=>e[0]-t[0]||e[1]-t[1]),o=[];for(const e of r)o.some(t=>jo(t,e,n))||o.push(e);const s=[],a=i.map((e,t)=>({roomId:"",a:[e.a[0],e.a[1]],b:[e.b[0],e.b[1]],key:`join-${t}`,kind:"outer",cm:0,open:!1,half:e.halfDepth})),l=us(a,n);for(const e of ps(l).fans)s.push(e);const c=e=>!!_s(l,e);for(const e of o){if(c(e))continue;const t=[];for(const r of i)jo(e,r.a,n)?Vo(t,r.b[0]-r.a[0],r.b[1]-r.a[1],r.halfDepth):jo(e,r.b,n)?Vo(t,r.a[0]-r.b[0],r.a[1]-r.b[1],r.halfDepth):Bo(e,r,n)&&(Vo(t,r.a[0]-e[0],r.a[1]-e[1],r.halfDepth),Vo(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 Yo(e,t,i,n){if(!(t>0)||!e||e.length<2)return"";if(i&&e.length>=3){let i=e;const r=e[e.length-1];if(e.length>=4&&Math.hypot(e[0][0]-r[0],e[0][1]-r[1])<1e-9&&(i=e.slice(0,-1)),i.length>=3){const e=i.map((e,i)=>n?.[i]||t),r=js(i,e),o=rs(i,e);if(r&&o)return`${os(r)} ${os(ss(o))}`}}const r=[];for(let i=0;i=1e-9&&a>0&&r.push({a:o,b:s,halfDepth:a})}const o=r.map(Wo);for(const{segmentIndex:e,wedge:t}of Go(r)){const i=o[e];if(!i)continue;const n=Uo(i,t);n&&(o[e]=n)}const s=[...o.filter(e=>!!e),...Ko(r)],a=function(e){let t=null;try{for(const i of e){if(i.length<3)continue;const e=$s(i);t=t?It(t,e):[e]}return t}catch{return null}}(s);return a?Es(a):s.map(e=>os(e)).join(" ")}function Zo(e,t,i,n,r=1){if(!i.length)return!1;const o=Xo(n,r),s=(e[0]+t[0])/2,a=(e[1]+t[1])/2,[l,c]=xo(e,t);for(const e of i){const[t,i]=xo([e[0],e[1]],[e[2],e[3]]);if(!(Math.abs(l*i-c*t)>.05)&&ws(s,a,e[0],e[1],e[2],e[3])<=o)return!0}return!1}function Xo(e,t){return Math.max(e*(t>0?t:1)*.04,1e-9)}function Jo(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 es(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 ts(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 is(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=Qo(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=Qo(e,t),_=ts(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,f=(_((r+1)%n)??c)-m;return f>0?f:0}function ns(e,t,i,n,r,o,s,a=1){const l=(e||[]).find(e=>e?.id===t),c=Zt(l);if(!c||c.length<3)return null;const h=fs(e,t,i,n,r,o,s,a);if(!h)return c.map(()=>0);const d=4*Xo(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]+f*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(es(w,k)){const t=e[o],i=[t[0]+p*d,t[1]+_*d],n=[t[0]+m*u,t[1]+f*u];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}const S=ts(x,w,$,k),M=Math.max(d,u,1e-9),R=_s(i,e[o])?.limit??4*M;if(S){const i=Math.hypot(S[0]-e[o][0],S[1]-e[o][1]);if(Number.isFinite(i)&&i<=R){r.push(S);continue}if(Hs(e,t,o)){r.push(S);continue}}d>0&&r.push([e[o][0]+p*d,e[o][1]+_*d]),u>0&&r.push([e[o][0]+m*u,e[o][1]+f*u]),d>0||u>0||r.push([e[o][0],e[o][1]])}return r.length>=3?r:null}function os(e,t=!0){if(!e.length)return"";let i=`M ${e[0][0]} ${e[0][1]}`;for(let t=1;te?.id===t),a=Zt(s);if(!a||a.length<3)return null;const l=Xo(n,r),c=[];for(const i of e||[]){if(!i||i.id===t)continue;const e=Zt(i);if(e)for(const t of wn(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=Mo(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 ls(e,t,i,n){const r=t.poly.length,o=new Array(r).fill(0);if(!e?.length)return o;const s=new Set,a=[];for(let l=0;l0?(o[l]=go(c.cm),s.add(c.key)):a.push(l)}if(!a.length)return o;const l=n>0?n:1,c=Math.max(.5*i,1e-9)*l,h=To(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=Co(n,s);let u=null;for(const e of h){const t=Mo(e.w,l);if(!t||!Do(Co(t[0],t[1]),d))continue;if(ws(n[0],n[1],t[0][0],t[0][1],t[1][0],t[1][1])>c||ws(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||ws(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(ws(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]=cs(e.point,n),r=hs(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=ds(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]=cs(i.point,n),o=hs(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 ds(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]=cs(e.point,n),r=hs(t,i),o=p.get(r)||[];o.push(e),p.set(r,o)}return{epsilon:n,coordinateScale:r,nodes:d,index:p}}function ps(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(Jo(e))>i&&t.fans.push(e)};if(_){const e=1.5*Math.max(o.halfDepth,s.halfDepth);m(uo([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 f=(e,t)=>Math.min(t,Math.sqrt(Math.max(c**2-e**2,0)),2*Math.max(o.halfDepth,s.halfDepth)),g=[h[0]+o.u[0]*f(o.halfDepth,o.thickLength),h[1]+o.u[1]*f(o.halfDepth,o.thickLength)],v=[d[0]+s.u[0]*f(s.halfDepth,s.thickLength),d[1]+s.u[1]*f(s.halfDepth,s.thickLength)];m([[r[0],r[1]],h,g,v,d])}}return t}function _s(e,t){return!e||!Array.isArray(t)||t.length<2||!t.slice(0,2).every(Number.isFinite)?null:ds(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 ms(e,t,i,n,r,o,s){return us(gs(e,t,i,n,r,o,s),4*Xo(n,s),s)}function fs(e,t,i,n,r,o,s,a=1){const l=as(e,t,n,r,a,i);if(!l)return null;const c=function(e,t,i){const n=(e||[]).find(e=>e?.id===t),r=Zt(n);if(!r)return[];const o=[];for(const n of e||[]){if(!n||n.id===t)continue;const e=Zt(n);if(e)for(const t of wn(r,e,i))o.push(t)}return o}(e,t,Xo(r,a)),h=function(e,t,i,n,r){const o=Xo(n,r),s=[];for(let a=0;aws(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=ls(i,l,r,a),u=d.map((e,t)=>h[t]&&e>0?yo(e,o,s)/2:0);return{...l,kinds:h,cms:d,offsets:u}}function gs(e,t,i,n,r,o,s=1){const a=[];for(const l of e||[]){if(!l?.id)continue;const c=fs(e,l.id,t,i,n,r,o,s);if(c)for(let e=0;e0&&(a=No(a,e.a,e.b,e.cm,n,s));return a}function ys(e,t,i,n,r,o,s=1){if(!t?.length)return[];const a=gs(e,t,i,n,r,o,s),l=new Map;for(const e of a){if(e.open||!e.kind||!e.roomId)continue;const t=l.get(e.key)||new Set;t.add(e.roomId),l.set(e.key,t)}const c=e=>{const t=[...l.get(e)||[]].sort();return 1!==t.length&&2!==t.length?`ambiguous:${e}`:`${1===t.length?"outer":"shared"}:${t.join("|")}`},h=[],d=new Set;for(const e of a)!e.open&&e.cm>0&&!d.has(e.key)&&(d.add(e.key),h.push({...e,ownerSignature:c(e.key)}));const u=[];for(const a of e||[]){if(!a?.id)continue;const l=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(So(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:So(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,f=4*Xo(n,s);for(const e of u){const t=h.filter(t=>!m.has(t.key)&&t.cm===e.cm&&t.ownerSignature===e.ownerSignature&&Do(Co(t.a,t.b),Co(e.a,e.b))&&ws(t.a[0],t.a[1],e.a[0],e.a[1],e.b[0],e.b[1])<=f&&ws(t.b[0],t.b[1],e.a[0],e.a[1],e.b[0],e.b[1])<=f);if(t.length){for(const e of t)m.add(e.key);_.has(e.key)||(_.add(e.key),p.push(Ro(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(Ro(e.a,e.b,e.cm,n,s)));return p}function bs(e,t,i,n,r,o,s,a=1){const l=Xo(r,a),c=(n[0]+n[2])/2,h=(n[1]+n[3])/2,d=Co([n[0],n[1]],[n[2],n[3]]);let u=null;for(const n of gs(e,t,i,r,o,s,a)){if(!Do(Co(n.a,n.b),d))continue;const e=ws(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(Jo(r));r.length>=3&&o>i&&(t=r,i=o)}return t}function xs(e,t,i,n,r,o,s,a=1,l,c){const h=(e||[]).find(e=>e?.id===t),d=Zt(h);if(!d||d.length<3)return null;if(!i?.length)return d.map(e=>[e[0],e[1]]);const u=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||ms(e,i,n,r,o,s,a),_=rs(u.poly,u.offsets,p);if(!_)return d.map(e=>[e[0],e[1]]);if(!p.nodes.length)return _;const m=void 0===l?Ns(e,i,n,[],r,o,s,a):null,f=l??("ok"===m?.status||"degraded-extra"===m?.status?m.roomGeom:void 0);if(f)try{const e=ks(Nt($s(u.poly),f));if(e)return e}catch{}return function(e,t){try{return ks(Ht($s(e),$s(t)))}catch{return null}}(_,u.poly)||d.map(e=>[e[0],e[1]])}function $s(e){const t=e.map(e=>[e[0],e[1]]);return t.push([e[0][0],e[0][1]]),[t]}function Ss(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(bi(e[0]))>1e-9)}function Ms(e,t,i,n){const r=n?new Set(n):null;let o=null;for(let n=0;nt.epsilon))continue;const l=zs([[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=$s(l);o=o?It(o,c):c}}return o}function Rs(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=zs([[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=Ht($s(s),i);Array.isArray(a)&&0!==a.length&&(n=n?It(n,a):a)}return n}function Ts(e,t,i=2*(4*e.halfDepth+2*t.epsilon)){const n=function(e,t=po){const i=new Set,n=Number.isFinite(t)&&t>=0?t:po;for(let t=0;te-t)}(e);return n.length?Ms(e,t,i,n):null}function Cs(e,t,i,n,r){const o=function(e){let t=null;for(const i of e){const e=$s(i);try{t=t?It(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=ts(p,s.u,_,a.u);if(!m)continue;const f=Math.hypot(m[0]-r.point[0],m[1]-r.point[1]);if(!Number.isFinite(f)||f<=r.limit)continue;const g=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=zs([[p[0]+s.u[0]*g,p[1]+s.u[1]*g],[_[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=f-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=zs([[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?Nt(o,r):o}function Ds(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=Ts(i,e);n&&(t=t?It(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=Cs(e,t,!1,!0,r);c&&(s=Nt(s,c));let h=Ms(e,t,a);const d=Cs(e,t,!0,!0,r);d&&(h=Nt(h,d)),r&&(h=It(h,r));const u=.02*Math.min(...e.rays.map(e=>e.halfDepth));if(h=It(h,$s([[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=Ht(h,$s(l));n?p=Ht(p,n):i&&(p=Ht(p,i));const _=$s(l),m=Nt(s,_),f=i?Nt(Ht(s,_),i):null,g=Rs(e,t,_);o=It(m,...f?[f]:[],...g?[g]:[],p)}catch{}}if(r)try{let e=r;n?e=Ht(e,n):i&&(e=Ht(e,i)),o=It(o,e)}catch{}return o}function zs(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(Jo(r))>n*n?r:null}function As(e,t,i,n){if(ws(e[0],e[1],t[0],t[1],i[0],i[1])>n)return!1;const r=i[0]-t[0],o=i[1]-t[1],s=(e[0]-t[0])*r+(e[1]-t[1])*o,a=r*r+o*o,l=n*Math.sqrt(a);return s>=-l&&s<=a+l}function Os(e,t,i){const n=[],r=[];for(let o=0;oi*i))continue;const d=i/Math.sqrt(h),u=[0,1];for(const e of t)for(const t of[e.a,e.b]){if(!As(t,s,a,i))continue;const e=((t[0]-s[0])*l+(t[1]-s[1])*c)/h;e>d&&e<1-d&&u.push(e)}u.sort((e,t)=>e-t);const p=u.filter((e,t)=>0===t||Math.abs(e-u[t-1])>d);for(let e=0;e=3&&r.length===n.length?{poly:n,offsets:r}:null}function Ps(e,t,i,n,r,o,s,a){const l=(e||[]).map(Zt).filter(e=>!!e&&e.length>=3);if(!l.length)return null;let c=It($s(l[0]));for(let e=1;e"outer"===e.kind&&e.half>0),u=4*Xo(n,s),p=a||us(h,u,s);let _=null;for(const e of function(e){const t=[];for(const i of Array.isArray(e)?e:[])if(Array.isArray(i))for(const e of i){if(!Array.isArray(e)||e.length<4)continue;const i=e.slice(0,-1).map(e=>[e[0],e[1]]);i.length>=3&&t.push(i)}return t}(c)){const t=Os(e,d,u);if(!t||!t.offsets.some(e=>e>0))continue;const i=js(t.poly,t.offsets,p),n=rs(t.poly,t.offsets,p);if(!i||!n)continue;const r=Nt($s(i),$s(n));_=_?It(_,r):r}return{centre:c,shell:_||[]}}function Fs(e,t,i,n,r,o,s=1){try{const a=Ps(e,t,i,n,r,o,s,ms(e,t,i,n,r,o,s));if(!a)return[];return a.shell?.length?It(a.centre,a.shell):a.centre}catch{return null}}function Es(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?" ":"")+os(i.map(e=>[e[0],e[1]])))}return t}const Is=15;function Hs(e,t,i){const n=e?.length||0;if(n<3||t?.length!==n)return!1;const r=e[(i-1+n)%n],o=e[i],s=e[(i+1)%n],a=[r[0]-o[0],r[1]-o[1]],l=[s[0]-o[0],s[1]-o[1]],c=Math.hypot(a[0],a[1]),h=Math.hypot(l[0],l[1]);if(!(c>1e-9&&h>1e-9))return!1;const d=Math.max(-1,Math.min(1,(a[0]*l[0]+a[1]*l[1])/(c*h))),u=Math.acos(d);if(!(u>1e-9))return!1;if(u>=Is*Math.PI/180)return!1;const p=Math.max(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 f=(_+p*d)/m,g=(p+_*d)/m;return Number.isFinite(f)&&Number.isFinite(g)&&f>0&&g>0&&fe>0))continue;for(const e of l.offsets)e>0&&(u=Math.max(u,2*e));const c=js(l.poly,l.offsets,d),p=rs(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*Xo(n,s),c=new Map;for(const a of gs(e,t,i,n,r,o,s))!a.open&&a.half>0&&!c.has(a.key)&&c.set(a.key,a);const h=[...c.values()];if(h.length<2)return[];const d=a||us(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(!g)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(Jo(y))>l*l&&p.push(y)}}return p}(e,t,i,r,o,s,a,d),_=n.length?Bs(e,t,i,r,o,s,a):null;let m="exterior";try{const v=Ps(e,t,i,r,o,s,a,d);m="paper";const y=v?v.shell?.length?It(v.centre,v.shell):v.centre:[],b=e=>{const t=$s(e.outset);if(!e.inset)return t;const i=$s(e.inset);return Nt(t,i)};m="room-rings";let w=null;for(const e of h)try{const t=b(e);w=w?It(w,t):t}catch{}if(m="edge-bodies",v)for(const n of Ws(e,t,i,r,o,s,a))try{const e=Ht($s(n.quad),v.centre);w=w?It(w,e):e}catch{}m="junctions",w=function(e,t,i=1,n=It){let r=e;for(const e of t||[]){const t=zs(e,i);if(t)try{const e=$s(t);r=r?n(r,e):e}catch{}}return r}(w,p,a),m="facade-clip",w&&v&&(w=Ht(w,v.centre)),m="exterior-shell";const k=[];let x=0;if(v?.shell?.length)if(w)try{const e=It(w,v.shell);if(!Ss(e))throw new Error("invalid shell union");w=e}catch{if(!Ss(w)||!Ss(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=Ds(w,{...d,nodes:t},v?.centre,y)}}if(m="junction-corners",d.nodes.length){const n=ps(d),l=function(e,t,i,n,r,o,s,a){try{const l=Ps(e,t,i,n,r,o,s,{epsilon:a.epsilon,coordinateScale:a.coordinateScale,nodes:[],index:new Map});return l?l.shell?.length?It(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=[$s(e)];if(l&&(t=Ht(t,l)),!t?.length)continue;w=w?It(w,t):t}catch{}f=w,g=Math.max(d.epsilon,1e-9)**2,w=Array.isArray(f)?f.map(e=>{if(!Array.isArray(e)||!e.length)return e;const[t,...i]=e;return Math.abs(Jo(t||[]))<=g?null:[t,...i.filter(e=>Math.abs(Jo(e||[]))>g)]}).filter(e=>!!e):f}const $=w||[],S=[...Ss($)?[{id:"room-primary",geom:$}]:[],...k.map((e,t)=>({id:`room-isolated-${t}`,geom:e.geom}))];m="openings";for(const e of n){if(!(e.length>0))continue;const t=Gs(_,e,!0);if(!t.negative&&!t.positive)continue;const i=e.angle*Math.PI/180,n=Math.cos(i),o=Math.sin(i),s=-o,l=n,c=e.length/2,h=1.25*Math.max(u,r*a),d=[[e.x-n*c-s*h,e.y-o*c-l*h],[e.x+n*c-s*h,e.y+o*c-l*h],[e.x+n*c+s*h,e.y+o*c+l*h],[e.x-n*c+s*h,e.y-o*c+l*h]];w&&(w=Nt(w,$s(d)));for(const e of k)e.geom=Nt(e.geom,$s(d))}m="extras";const M=[];let R=0;const T=c.mergeExtra||((e,t)=>e?It(e,t):t);for(let e=0;ee.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]))||Math.abs(bi(t))<=1e-9){R++;continue}const i=[$s(t)];try{const t=T(w,i,e);if(!Ss(t))throw new Error("invalid extra union");w=t}catch{R++,Ss(i)&&M.push({id:`extra-${e}`,geom:i})}}M.push(...k),M.sort((e,t)=>Es(e.geom).localeCompare(Es(t.geom)));const C=w||[];return{status:R||x?"degraded-extra":"ok",geom:C,components:[...Ss(C)?[{id:"primary",geom:C}]:[],...M.map((e,t)=>({...e,id:`isolated-${t}`}))],roomGeom:$,roomComponents:S,paperGeom:y,depthUnits:u,openingPadUnits:1.25*Math.max(u,r*a),openingIndex:_,multiWallNodes:d,degradedExtraCount:R+x}}catch{return c.onCoreFailure?.(m),{status:"failed-core",geom:[],components:[],roomGeom:[],paperGeom:[],roomComponents:[],depthUnits:u,openingIndex:null,multiWallNodes:d,degradedExtraCount:0}}var f,g}function Ls(e,t,i,n=[],r,o,s,a=1,l=[],c={}){if(!t?.length&&!l.length)return null;return qs(Ns(e,t,i,n,r,o,s,a,l,c))}function qs(e){if("failed-core"===e.status||"not-applicable"===e.status)return null;const t=e.components.map(e=>({id:e.id,d:Es(e.geom),fillRule:"evenodd"})).filter(e=>!!e.d),i=t[0]?.d||"",n=Es(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 Ws(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=So(t,i,n,s);if(a.has(p))continue;a.add(p);const _=yo(u,r,o),[m,f]=Qo(d,e),g=-m,v=-f,y=_/2,b=[[t[0]+g*y,t[1]+v*y],[i[0]+g*y,i[1]+v*y],[i[0]+m*y,i[1]+f*y],[t[0]+m*y,t[1]+f*y]];l.push({key:p,kind:c,cm:u,quad:b,a:[t[0],t[1]],b:[i[0],i[1]],depthUnits:_})}}return l}function js(e,t,i){const n=e?.length||0;if(n<3||t.length!==n)return null;if(t.every(e=>!(e>0)))return e.map(e=>[e[0],e[1]]);ss(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(es(w,k)){const t=e[o],i=[t[0]-c*a,t[1]-h*a],n=[t[0]-d*l,t[1]-u*l];r.push(i),Math.hypot(n[0]-i[0],n[1]-i[1])>1e-9&&r.push(n);continue}const S=ts(x,w,$,k),M=Math.max(a,l,1e-9),R=_s(i,e[o])?.limit??4*M;if(S){const i=Math.hypot(S[0]-e[o][0],S[1]-e[o][1]);if(Number.isFinite(i)&&i<=R){r.push(S);continue}if(Hs(e,t,o)){r.push([e[o][0],e[o][1]]);continue}}a>0&&r.push([e[o][0]-c*a,e[o][1]-h*a]),l>0&&r.push([e[o][0]-d*l,e[o][1]-u*l])}return r.length>=3?r:null}function Bs(e,t,i,n,r,o,s=1){const a=[];for(const l of e||[]){if(!l?.id)continue;const c=fs(e,l.id,t,i,n,r,o,s);if(!c)continue;const h=Math.abs(bi(c.poly));for(let e=0;e[Math.max(t,e.x0),Math.min(i,e.x1)]).filter(e=>e[1]-e[0]>n).sort((e,t)=>e[0]-t[0]||e[1]-t[1]);if(!r.length)return{coverage:0,full:!1};let o=r[0][0],s=r[0][1],a=0,l=o<=t+n;for(let e=1;e=i-n,{coverage:a,full:l}}function Us(e,t){return Number(t.full)-Number(e.full)||e.faceDistance-t.faceDistance||e.area-t.area||e.roomId.localeCompare(t.roomId)}function Gs(e,t,i=!1){const n=Number(t?.x),r=Number(t?.y),o=Number(t?.angle),s=Number(t?.length);if(!([n,r,o,s].every(Number.isFinite)&&s>0))return{negative:null,positive:null};const a=o*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=-c,d=l,u=s/2,p=Math.max(1e-9,e.adjacencyEps),_=new Map;let m=0;for(const t of e.edges){if(i&&!(t.half>0))continue;if(!Po(t.a,t.b,o))continue;const[e,s]=xo(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,f=(t.b[0]-n)*l+(t.b[1]-r)*c,g=Math.max(-u,Math.min(a,f)),v=Math.min(u,Math.max(a,f));if(v-g<=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:g,x1:v,half:t.half,cm:t.cm,key:t.key,axis:[e,s]},$=_.get(k);$?($.pieces.push(x),$.faceDistance=Math.min($.faceDistance,w)):_.set(k,{roomId:t.roomId,side:y,order:m++,pieces:[x],faceDistance:w,area:t.area,coverage:0,full:!1})}for(const e of _.values()){const t=Vs(e.pieces,-u,u,p);e.coverage=t.coverage,e.full=t.full}const f=e=>{const t=[..._.values()].filter(t=>t.side===e&&t.coverage>p);return t.sort(Us),t[0]||null};return{negative:f(-1),positive:f(1)}}function Ks(e,t){const i=Gs(e,t),n=[i.negative,i.positive].filter(e=>!!e);if(!n.length)return{ox:0,oy:0,cm:0,side:-1};const r=i.negative&&i.positive?-1:n[0].side,o=t.flip_v?-r:r,s=(-1===o?i.negative:i.positive)||n[0],a=[...s.pieces].sort((e,t)=>(e.x0<=0&&e.x1>=0?0:Math.min(Math.abs(e.x0),Math.abs(e.x1)))-(t.x0<=0&&t.x1>=0?0:Math.min(Math.abs(t.x0),Math.abs(t.x1)))||t.x1-t.x0-(e.x1-e.x0)||e.key.localeCompare(t.key))[0];if(!(a.half>0&&a.cm>0))return{ox:0,oy:0,cm:0,side:o};const l=t.angle*Math.PI/180,c=-Math.sin(l),h=Math.cos(l);return{ox:c*o*a.half,oy:h*o*a.half,cm:a.cm,side:o}}function Ys(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 Zs(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),f=`${r.key}|${t}`,g=n.get(f)||[];let v=[[_,m]];for(const[e,t]of g){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(f,b)}return a}function Xs(e,t){const i=new Map;return t.map(t=>function(e,t,i){const n=Gs(e,t,!0),r=n.negative,o=n.positive;if(!r&&!o)return null;let s;if(r&&o)s=[{candidate:r,side:-1},{candidate:o,side:1}];else{const e=r||o;s=[{candidate:e,side:-1},{candidate:e,side:1}]}const a=s.map(({candidate:e,side:n})=>({candidate:e,side:n,pieces:Zs(t,n,e.pieces,i)})),l=a.map(({candidate:e,side:t,pieces:i})=>({side:t,roomId:e.roomId,d:Ys(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 Js=150,Qs=1e-6;function ea(e){return Number.isFinite(e)?Math.max(1,Math.min(Js,e)):1}function ta(e){return((Number.isFinite(Number(e))?Number(e):0)%90+90)%90}const ia=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]},na=(e,t)=>e[0]===t[0]&&e[1]===t[1];function ra(e,t=1e-6){const i=Number.isFinite(t)&&t>0?t:Qs,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&&na(n[n.length-1],a)||n.push(a)}return n.length>1&&na(n[0],n[n.length-1])&&n.pop(),n.length<3||new Set(n.map(e=>`${e[0]},${e[1]}`)).size<3?null:bi(n)>i*i?n:null}function oa(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 sa(e,t,i,n,r){return Wo({a:e,b:t,halfDepth:yo(i,n,r)/2})}function aa(e,t,i){const n=Number(t)>0?Number(t):5,r=ea(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=ta(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 la(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=[ia(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=Nt(n,ia(u))}return ya(n)}catch{return[e]}}function ha(e,t){try{const i=Nt([[...e.map(e=>[e[0],e[1]]),[e[0][0],e[0][1]]]],[[...t.map(e=>[e[0],e[1]]),[t[0][0],t[0][1]]]]);let n=null,r=0;for(const e of i||[]){const t=e?.[0]||[],i=Math.abs(bi(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=[],a=new Map;for(const e of r){const t=a.get(e.hostId)||[];t.push(e),a.set(e.hostId,t)}const l=[],c=[],h=[];for(const n of e.room_drafts||[])for(let e=0;e+10))continue;const a={a:n.points[e],b:n.points[e+1],halfDepth:s},c=Wo(a);c&&(o.push(a),l.push(c))}const d=[];for(const n of e.partitions||[]){const e={a:n.a,b:n.b,halfDepth:yo(n.cm,t,i)/2};if(!(e.halfDepth>0))continue;const r=Wo(e);r&&(s.push(e),c.push(r),d.push({id:n.id,body:r}))}const u=[...o,...s];for(const{segmentIndex:e,wedge:t}of Go(u,n)){const i=e=o.length&&(d[i.at].body=n))}for(const e of d)h.push(...ca(e.body,a.get(e.id)||[],n));const p=(e.wall_columns||[]).map(e=>aa(e,t,i)),_=Ko([...o,...s],n).flatMap(e=>ca(e,r,n));return{drafts:l,partitions:c,columns:p,patches:_,all:[...l,...h,..._,...p]}}function ua(e){try{const t=e.map(e=>ra(e)).filter(e=>!!e).map(e=>ia(e));return t.length?It(t[0],...t.slice(1)):null}catch{return null}}const pa=e=>`M ${e.map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`;function _a(e){const t=[];for(const i of e||[]){if(ga([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 ma(e,t,i={}){const n=ua(e.filter(e=>e.length>=3)),r=t.some(e=>!ra(e))?null:ua(t);if(!n)return[];if(r)try{return _a(Ht(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 ya(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 ba(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 wa(e,t,i){return function(e,t){for(const i of t||[]){const t=i?.[0];if(!t?.length||!ba(e,t))continue;let n=!1;for(let t=1;tba(e,t))}function ka(e,t,i){if(Math.hypot(e.center[0]-t.center[0],e.center[1]-t.center[1])>i)return!1;if(Math.abs(ea(e.cm)-ea(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(ta(e.angle)-ta(t.angle));return Math.min(n,90-n)<=1e-6}const xa=2.54;function $a(e){const t="number"==typeof e?e:NaN;return!Number.isFinite(t)||t<=0||5===t?1:5/t}function Sa(e,t){return e*$a(t)}function Ma(e){return e?xa:1}function Ra(e,t){if(!t)return String(e);const i=e/xa;return String(Math.round(1e6*i)/1e6)}function Ta(e,t){return t?e*xa:e}const Ca=1e3;function Da(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 za=.01,Aa=100;function Oa(e,t=1e3){const i=Da(e?.plan_aspect,t),n=Number(e?.plan_scale),r=Number.isFinite(n)&&n>0?Math.min(Aa,Math.max(za,n)):1,o=Number(e?.plan_scale_x),s=Number(e?.plan_scale_y),a=Number.isFinite(o)&&o>0?Math.min(Aa,Math.max(za,o)):r,l=Number.isFinite(s)&&s>0?Math.min(Aa,Math.max(za,s)):r,c=Number(e?.plan_x),h=Number(e?.plan_y),d=mr(e?.plan_angle);return{x:i.x+(Number.isFinite(c)?Ba(c):0)*t,y:i.y+(Number.isFinite(h)?Ba(h):0)*t,w:i.w*a,h:i.h*l,...d?{angle:d}:{}}}function Pa(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 Fa(e){return e&&Array.isArray(e.spaces)?e.spaces.map(e=>{const t=Ca,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]*Ca,i[1]*t,i[2]*Ca,i[3]*t],bg:e.plan_url?{href:Rn(e.plan_url),...Oa(e,Ca)}:null,rooms:(e.rooms||[]).map(e=>{const i={...e,...Pa(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*Ca:void 0,y:null!=i.y?i.y*t:void 0,w:null!=i.w?i.w*Ca:void 0,h:null!=i.h?i.h*t:void 0,poly:i.poly?i.poly.map(e=>[e[0]*Ca,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])*Ca,Number(e.a?.[1])*t],b:[Number(e.b?.[0])*Ca,Number(e.b?.[1])*t],cm:Number(e.cm)})),room_drafts:(e.room_drafts||[]).map(e=>({id:e.id,points:(e.points||[]).map(e=>[e[0]*Ca,e[1]*t]),segments:(e.segments||[]).map(e=>({..."string"==typeof e.id&&e.id?{id:e.id}:{},cm:Number(e.cm)}))})),partitions:(e.partitions||[]).map(e=>({id:e.id,a:[e.a[0]*Ca,e.a[1]*t],b:[e.b[0]*Ca,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]*Ca,e.center[1]*t],cm:Number(e.cm),..."circle"===e.shape?{}:{angle:ta(e.angle)}}))}}):[]}const Ea=5e3,Ia=Ea*Ca,Ha=240,Na=Ca/Ha,La=1/Ha;function qa(e){if(!Number.isFinite(e))return e;const t=Math.round(e*Ha/Ca)*Ca/Ha;return Math.abs(t-e)<=1e-9*Na?e:t}function Wa(e){return{x:qa(e.x),y:qa(e.y)}}function ja(e){return Number.isFinite(e)?Math.min(Ia,Math.max(-Ia,e)):0}function Ba(e){return Number.isFinite(e)?Math.min(Ea,Math.max(-Ea,e)):0}const Va=1/3,Ua=200;function Ga(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 Ka(e){return e.poly&&e.poly.length?Ga(e.poly):null==e.x||null==e.y?null:Ga([[e.x,e.y],[e.x+(e.w||0),e.y+(e.h||0)]])}function Ya(e,t){const i=[];for(const t of e.rooms||[]){const e=Ka(t);e&&i.push(e)}if(e.bg){const t=Ga(kr(e.bg));t&&i.push(t)}for(const e of t||[])if(Array.isArray(e)){const t=Ga([e]);t&&i.push(t)}else i.push(e);return i}const Za=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},Xa=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 Ja(e,t){let{x:i,y:n,w:r,h:o}=e;r<30&&(i=i+r/2-100,r=Ua),o<30&&(n=n+o/2-100,o=Ua);const s=Math.max(r,o)*t;return{x:i-s,y:n-s,w:r+2*s,h:o+2*s}}function Qa(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)<=Ia&&Math.abs(e.maxX)<=Ia&&Math.abs(e.minY)<=Ia&&Math.abs(e.maxY)<=Ia);if(!o.length)return{core:null,all:null,outliers:0};const s=Xa(o);if(o.length<4){const e=Ja(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=Za(a),h=Za(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*Va?o.filter((e,t)=>!p[t]):o;return{core:Ja(Xa(m)||s,i),all:Ja(s,i),outliers:m===o?0:_}}function el(e,t,i=.05){const n=Qa(Ya(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,Ca,Ca];return{x:r[0],y:r[1],w:r[2],h:r[3]}}function tl(e){const t=el(e);return{x:t.x+t.w/2,y:t.y+t.h/2}}function il(e){const t=[];for(const i of e.rooms||[]){const e=Ka(i);e&&t.push(e)}const i=Qa(t,{pad:0}).core,n=Ca*$a(e.cellCm??5);return i?Math.max(n,Math.min(Ia,Math.max(i.w,i.h))):n}function nl(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*il(t)*o/r}const rl=[1,2,5,10,20,50,100,200,500,1e3];function ol(e,t,i=7){if(!(e>0&&t>0&&Number.isFinite(t)))return null;const n=rl.find(n=>e*n*t>=i);if(void 0===n)return null;const r=rl.find(e=>e>=5*n)??5*n;return{fine:n,coarse:r}}function sl(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){const r=i["rl_"+(e.id||"")];if(r&&r.s===t)return{x:r.x*Ca,y:r.y*Ca};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 Wa({x:o[0],y:o[1]})}const ll=["furniture","appliance","sanitary","other"],cl=[{id:"sofa",group:"furniture",category:"sofa",w:220,h:90,g:[["r",0,0,1,1],["l",.09,.26,.91,.26],["l",.09,.26,.09,1],["l",.91,.26,.91,1],["l",.5,.26,.5,1]]},{id:"armchair",group:"furniture",category:"armchair",w:90,h:85,g:[["r",0,0,1,1],["l",.14,.28,.86,.28],["l",.14,.28,.14,1],["l",.86,.28,.86,1]]},{id:"coffee_table",group:"furniture",category:"coffee_table",w:110,h:60,g:[["r",0,0,1,1],["r",.08,.14,.84,.72]]},{id:"table_dining",group:"furniture",category:"dining_table",w:140,h:80,g:[["r",0,0,1,1],["r",.06,.11,.88,.78]]},{id:"table_round",group:"furniture",category:"dining_table",w:120,h:120,g:[["e",.5,.5,.5,.5],["e",.5,.5,.41,.41]]},{id:"chair",group:"furniture",category:"chair",w:45,h:45,g:[["r",0,0,1,.18],["r",.06,.18,.88,.8]]},{id:"desk",group:"furniture",category:"work_table",w:120,h:60,g:[["r",0,0,1,1],["r",.63,.07,.31,.86],["l",.63,.5,.94,.5]]},{id:"bed_double",group:"furniture",category:"bed",w:160,h:200,g:[["r",0,0,1,1],["r",0,0,1,.07],["r",.06,.1,.4,.15],["r",.54,.1,.4,.15],["l",0,.33,1,.33]]},{id:"bed_single",group:"furniture",category:"bed",w:90,h:200,g:[["r",0,0,1,1],["r",0,0,1,.07],["r",.15,.1,.7,.15],["l",0,.33,1,.33]]},{id:"nightstand",group:"furniture",category:"nightstand",w:45,h:40,g:[["r",0,0,1,1],["r",.12,.14,.76,.33],["r",.12,.53,.76,.33]]},{id:"wardrobe",group:"furniture",category:"wardrobe",w:100,h:60,g:[["r",0,0,1,1],["l",0,.72,1,.72],["l",.5,.72,.5,1]]},{id:"bookshelf",group:"furniture",category:"wardrobe",w:80,h:30,g:[["r",0,0,1,1],["l",.34,0,.34,1],["l",.67,0,.67,1]]},{id:"fridge",group:"appliance",category:"fridge",w:60,h:65,g:[["r",0,0,1,1],["l",0,.36,1,.36],["l",.83,.44,.83,.64]]},{id:"stove",group:"appliance",category:"cooktop",w:60,h:60,g:[["r",0,0,1,1],["e",.29,.31,.15,.15],["e",.71,.31,.15,.15],["e",.29,.71,.15,.15],["e",.71,.71,.15,.15]]},{id:"dishwasher",group:"appliance",category:"dishwasher",w:60,h:60,g:[["r",0,0,1,1],["r",.1,.12,.8,.76],["e",.5,.5,.27,.27],["e",.5,.5,.13,.13]]},{id:"washer",group:"appliance",category:"washer",w:60,h:60,g:[["r",0,0,1,1],["l",.08,.17,.92,.17],["e",.5,.57,.3,.3],["e",.5,.57,.14,.14]]},{id:"dryer",group:"appliance",category:"dryer",w:60,h:60,g:[["r",0,0,1,1],["l",.08,.17,.92,.17],["e",.5,.57,.3,.3],["p",.36,.5,.5,.64,.64,.5]]},{id:"tv",group:"appliance",category:"tv",w:120,h:30,g:[["r",0,0,1,.42],["l",.5,.42,.5,.72],["l",.3,.72,.7,.72]]},{id:"ac",group:"appliance",category:"air_conditioner",w:90,h:25,g:[["r",0,0,1,1],["l",.05,.55,.95,.55],["l",.05,.79,.95,.79]]},{id:"water_heater",group:"appliance",category:"boiler",w:45,h:45,g:[["e",.5,.5,.5,.5],["e",.5,.5,.31,.31]]},{id:"toilet",group:"sanitary",category:"toilet",w:40,h:70,g:[["r",.06,0,.88,.2],["e",.5,.58,.37,.35],["e",.5,.58,.22,.2]]},{id:"bathtub",group:"sanitary",category:"bathtub",w:170,h:75,g:[["r",0,0,1,1],["r",.05,.11,.77,.78],["e",.89,.5,.045,.1]]},{id:"shower",group:"sanitary",category:"shower",w:90,h:90,g:[["r",0,0,1,1],["l",0,0,1,1],["l",1,0,0,1],["e",.5,.5,.08,.08]]},{id:"sink",group:"sanitary",category:"sink",w:60,h:45,g:[["r",0,0,1,1],["e",.5,.6,.34,.3],["e",.5,.15,.07,.07]]},{id:"kitchen_sink",group:"sanitary",category:"kitchen_sink",w:80,h:60,g:[["r",0,0,1,1],["r",.06,.24,.44,.64],["r",.54,.24,.4,.64],["e",.5,.12,.06,.06]]},{id:"bidet",group:"sanitary",category:"bidet",w:40,h:55,g:[["e",.5,.5,.44,.5],["e",.5,.5,.26,.3]]},{id:"stairs",group:"other",category:"stairs",w:100,h:280,g:[["r",0,0,1,1],["l",0,.111,1,.111],["l",0,.222,1,.222],["l",0,.333,1,.333],["l",0,.444,1,.444],["l",0,.556,1,.556],["l",0,.667,1,.667],["l",0,.778,1,.778],["l",0,.889,1,.889],["l",.5,.93,.5,.06],["p",.38,.16,.5,.06,.62,.16]]},{id:"fireplace",group:"other",category:"fireplace",w:120,h:40,g:[["r",0,0,1,1],["p",.22,1,.22,.42,.78,.42,.78,1]]},{id:"plant",group:"other",category:"plant",w:40,h:40,g:[["e",.5,.5,.22,.22],["l",.5,.28,.5,.02],["l",.5,.72,.5,.98],["l",.28,.5,.02,.5],["l",.72,.5,.98,.5],["l",.34,.34,.13,.13],["l",.66,.66,.87,.87],["l",.66,.34,.87,.13],["l",.34,.66,.13,.87]]},{id:"rug",group:"other",category:"rug",w:200,h:140,g:[["r",0,0,1,1],["r",.06,.09,.88,.82]]}],hl=new Set(["fridge","dishwasher","washer","dryer","ac","water_heater","shower","sink","stairs","fireplace","plant","rug"]),dl=[...[{id:"coffee_table",group:"furniture",category:"coffee_table",w:120,h:60,art:{d:"M3.84 5.884c0-1.21 1.048-2.192 2.34-2.192h107.64c1.293 0 2.34.981 2.34 2.192v48.23c0 1.212-1.047 2.193-2.34 2.193H6.18c-1.292 0-2.34-.981-2.34-2.192z M103.056 15.093V9.83a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877m0 35.078v-5.262a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877m-93.6-35.077V9.83a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877m0 35.078v-5.262a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877",viewW:120,viewH:60}},{id:"coffee_table_round",group:"furniture",category:"coffee_table",w:80,h:80,art:{d:"M3.765 40a36.235 36.235 0 1 0 72.47 0 36.235 36.235 0 1 0-72.47 0 m56.26 26.96-3.843-3.843a.906.906 0 0 1 0-1.28l3.843-3.844a.906.906 0 0 1 1.281 0l3.844 3.843a.906.906 0 0 1 0 1.281l-3.844 3.844a.906.906 0 0 1-1.28 0m-.001 34.66-3.843-3.843a.906.906 0 0 1 0-1.281l3.843-3.844a.906.906 0 0 1 1.281 0l3.843 3.844a.906.906 0 0 1 0 1.28l-3.843 3.844a.906.906 0 0 1-1.281 0m-34.423-34.66-3.843-3.843a.906.906 0 0 1 0-1.281l3.843-3.844a.906.906 0 0 1 1.281 0l3.844 3.844a.906.906 0 0 1 0 1.28l-3.844 3.844a.906.906 0 0 1-1.28 0m-.001 34.66-3.843-3.843a.906.906 0 0 1 0-1.281l3.843-3.843a.906.906 0 0 1 1.281 0l3.844 3.843a.906.906 0 0 1 0 1.281l-3.844 3.843a.906.906 0 0 1-1.28 0",viewW:80,viewH:80}},{id:"coffee_table_oval",group:"furniture",category:"coffee_table",w:120,h:60,art:{d:"M3.84 30c0-14.53 12.572-26.308 28.08-26.308h56.16c15.509 0 28.08 11.778 28.08 26.308s-12.571 26.307-28.08 26.307H31.92C16.412 56.307 3.84 44.53 3.84 30 M80.592 15.093V9.83a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877m0 35.077v-5.262a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877M31.92 15.093V9.83a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.876h-5.616a.936.877 0 0 1-.936-.876m0 35.077v-5.262a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.876h-5.616a.936.877 0 0 1-.936-.876",viewW:120,viewH:60}},{id:"coffee_table_rounded",group:"furniture",category:"coffee_table",w:120,h:60,art:{d:"M3.84 12.461c0-4.843 4.19-8.77 9.36-8.77h93.6c5.17 0 9.36 3.927 9.36 8.77v35.077c0 4.843-4.19 8.77-9.36 8.77H13.2c-5.17 0-9.36-3.927-9.36-8.77z M103.056 15.093V9.83a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877m0 35.078v-5.262a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877m-93.6-35.077V9.83a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877m0 35.078v-5.262a.936.877 0 0 1 .936-.877h5.616a.936.877 0 0 1 .936.877v5.262a.936.877 0 0 1-.936.877h-5.616a.936.877 0 0 1-.936-.877",viewW:120,viewH:60}},{id:"table_dining",group:"furniture",category:"dining_table",w:160,h:90,art:{d:"M3.879 6.08c0-1.265 1.065-2.29 2.378-2.29h147.484c1.314 0 2.38 1.025 2.38 2.29v77.84c0 1.265-1.066 2.29-2.38 2.29H6.257c-1.313 0-2.378-1.025-2.378-2.29z M138.994 19.358v-5.495a.952.916 0 0 1 .951-.915h5.71a.952.916 0 0 1 .95.915v5.495a.952.916 0 0 1-.95.916h-5.71a.952.916 0 0 1-.951-.916m-.001 56.778v-5.495a.952.916 0 0 1 .952-.915h5.709a.952.916 0 0 1 .951.915v5.495a.952.916 0 0 1-.951.916h-5.71a.952.916 0 0 1-.95-.916m-125.6-56.778v-5.495a.952.916 0 0 1 .951-.916h5.71a.952.916 0 0 1 .95.916v5.495a.952.916 0 0 1-.95.915h-5.71a.952.916 0 0 1-.951-.915m-.001 56.779v-5.495a.952.916 0 0 1 .952-.916h5.709a.952.916 0 0 1 .951.916v5.495a.952.916 0 0 1-.951.915h-5.71a.952.916 0 0 1-.95-.915",viewW:160,viewH:90}},{id:"table_round",group:"furniture",category:"dining_table",w:110,h:110,art:{d:"M3.826 55a51.174 51.174 0 1 0 102.349 0A51.174 51.174 0 1 0 3.826 55 m81.005 32.303-3.947-3.947a.93.93 0 0 1 0-1.316l3.947-3.948a.93.93 0 0 1 1.316 0l3.948 3.948a.93.93 0 0 1 0 1.316l-3.948 3.947a.93.93 0 0 1-1.316 0m0 54.897-3.947-3.948a.93.93 0 0 1 0-1.316l3.947-3.947a.93.93 0 0 1 1.316 0l3.948 3.947a.93.93 0 0 1 0 1.316L82.32 87.2a.93.93 0 0 1-1.316 0M27.04 32.304l-3.947-3.948a.93.93 0 0 1 0-1.315l3.948-3.948a.93.93 0 0 1 1.315 0l3.948 3.948a.93.93 0 0 1 0 1.315l-3.948 3.948a.93.93 0 0 1-1.315 0m-.001 54.604-3.947-3.948a.93.93 0 0 1 0-1.316l3.948-3.947a.93.93 0 0 1 1.315 0l3.948 3.947a.93.93 0 0 1 0 1.316l-3.948 3.948a.93.93 0 0 1-1.315 0",viewW:110,viewH:110}},{id:"table_dining_oval",group:"furniture",category:"dining_table",w:180,h:100,art:{d:"M3.892 50c0-25.51 21.418-46.19 47.838-46.19h76.54c26.42 0 47.839 20.68 47.839 46.19S154.69 96.19 128.27 96.19H51.73C25.31 96.19 3.892 75.51 3.892 50 M122.53 19.514V13.97a.957.924 0 0 1 .956-.924h5.74a.957.924 0 0 1 .958.924v5.543a.957.924 0 0 1-.957.924h-5.74a.957.924 0 0 1-.958-.924m.001 66.516v-5.543a.957.924 0 0 1 .957-.924h5.74a.957.924 0 0 1 .957.924v5.543a.957.924 0 0 1-.957.924h-5.74a.957.924 0 0 1-.957-.924M49.816 19.515v-5.543a.957.924 0 0 1 .957-.924h5.74a.957.924 0 0 1 .958.924v5.542a.957.924 0 0 1-.957.924h-5.74a.957.924 0 0 1-.958-.924m0 66.516v-5.543a.957.924 0 0 1 .957-.924h5.74a.957.924 0 0 1 .957.924v5.543a.957.924 0 0 1-.957.923h-5.74a.957.924 0 0 1-.957-.924",viewW:180,viewH:100}},{id:"table_dining_rounded",group:"furniture",category:"dining_table",w:160,h:90,art:{d:"M3.879 17.527c0-7.587 6.39-13.737 14.272-13.737h123.696c7.883 0 14.273 6.15 14.273 13.737v54.947c0 7.587-6.39 13.737-14.273 13.737H18.151c-7.882 0-14.272-6.15-14.272-13.737z M138.994 19.358v-5.495a.952.916 0 0 1 .951-.915h5.71a.952.916 0 0 1 .95.915v5.495a.952.916 0 0 1-.95.916h-5.71a.952.916 0 0 1-.951-.916m-.001 56.778v-5.495a.952.916 0 0 1 .952-.915h5.709a.952.916 0 0 1 .951.915v5.495a.952.916 0 0 1-.951.916h-5.71a.952.916 0 0 1-.95-.916m-125.6-56.778v-5.495a.952.916 0 0 1 .951-.916h5.71a.952.916 0 0 1 .95.916v5.495a.952.916 0 0 1-.95.915h-5.71a.952.916 0 0 1-.951-.915m-.001 56.779v-5.495a.952.916 0 0 1 .952-.916h5.709a.952.916 0 0 1 .951.916v5.495a.952.916 0 0 1-.951.915h-5.71a.952.916 0 0 1-.95-.915",viewW:160,viewH:90}},{id:"desk",group:"furniture",category:"work_table",w:140,h:70,art:{d:"M3.862 5.967c0-1.234 1.057-2.234 2.362-2.234h127.552c1.305 0 2.362 1 2.362 2.234v58.066c0 1.234-1.057 2.233-2.362 2.233H6.224c-1.305 0-2.362-1-2.362-2.233z M9.531 15.346v-5.36a.945.893 0 0 1 .945-.893h5.67a.945.893 0 0 1 .944.893v5.36a.945.893 0 0 1-.945.894h-5.669a.945.893 0 0 1-.945-.894m113.379.001v-5.36a.945.893 0 0 1 .945-.894h5.67a.945.893 0 0 1 .944.894v5.36a.945.893 0 0 1-.945.893h-5.669a.945.893 0 0 1-.945-.893M9.53 60.013v-5.36a.945.893 0 0 1 .946-.893h5.669a.945.893 0 0 1 .945.893v5.36a.945.893 0 0 1-.945.894h-5.67a.945.893 0 0 1-.944-.894m113.38.001v-5.36a.945.893 0 0 1 .945-.894h5.669a.945.893 0 0 1 .945.894v5.36a.945.893 0 0 1-.945.893h-5.67a.945.893 0 0 1-.944-.893m-97.318-2.681h88.814",viewW:140,viewH:70}},{id:"desk_corner",group:"furniture",category:"work_table",w:160,h:160,art:{d:"M156.12 66.202a2.38 2.38 0 0 1-2.379 2.38H94.272c-13.138 0-23.788 10.65-23.788 23.787v61.372a2.38 2.38 0 0 1-2.379 2.38H6.257a2.38 2.38 0 0 1-2.378-2.38V6.257A2.38 2.38 0 0 1 6.257 3.88h147.484a2.38 2.38 0 0 1 2.38 2.378z M9.588 16.249v-5.71a.95.95 0 0 1 .951-.95h5.71a.95.95 0 0 1 .95.95v5.71a.95.95 0 0 1-.95.951h-5.71a.95.95 0 0 1-.951-.951m133.212.001v-5.71a.95.95 0 0 1 .951-.951h5.71a.95.95 0 0 1 .95.951v5.71a.95.95 0 0 1-.95.951h-5.71a.95.95 0 0 1-.951-.951m0 45.672v-5.71a.95.95 0 0 1 .952-.951h5.709a.95.95 0 0 1 .951.951v5.71a.95.95 0 0 1-.951.951h-5.71a.95.95 0 0 1-.95-.951M9.587 149.46v-5.708a.95.95 0 0 1 .952-.952h5.709a.95.95 0 0 1 .951.952v5.709a.95.95 0 0 1-.951.951h-5.71a.95.95 0 0 1-.951-.951m47.576 0v-5.709a.95.95 0 0 1 .952-.951h5.709a.95.95 0 0 1 .951.951v5.71a.95.95 0 0 1-.951.95h-5.71a.95.95 0 0 1-.951-.95m51.382-90.396H95.569a34.6 34.6 0 0 0-34.6 34.6v12.976",viewW:160,viewH:160}},{id:"chair",group:"furniture",category:"chair",w:50,h:50,art:{d:"M39.452 12.433H10.548a4.398 4.398 0 1 1 0-8.796h28.904a4.398 4.398 0 0 1 0 8.796m-28.904 0H8.035a4.4 4.4 0 0 0-4.398 4.399V40.08a6.283 6.283 0 0 0 6.283 6.284h30.16a6.283 6.283 0 0 0 6.284-6.284V16.832c0-2.43-1.97-4.399-4.399-4.399h-2.513",viewW:50,viewH:50}},{id:"chair_bar",group:"furniture",category:"chair",w:45,h:48,art:{d:"M38.579 17.168c1.326 2.526 1.947 6.015 1.947 9.071 0 10.018-8.07 18.139-18.025 18.139S4.475 36.257 4.475 26.239c0-3.056.586-6.552 1.912-9.078m32.192.007a3.59 3.59 0 0 1-3.333-.976m3.333.976a3.6 3.6 0 0 0 1.765-.976m-33.827.996-.13-.027a3.6 3.6 0 0 1-1.731-.969m30.59 0a18 18 0 0 0-5.848-3.932 17.93 17.93 0 0 0-13.796 0 18 18 0 0 0-5.848 3.932 3.59 3.59 0 0 1-3.237.996m28.729-.996a3.59 3.59 0 0 0 5.098 0m-33.827.996a3.6 3.6 0 0 1-1.861-.996 3.644 3.644 0 0 1 0-5.13 25.2 25.2 0 0 1 8.187-5.505A25.1 25.1 0 0 1 22.5 3.623a25.1 25.1 0 0 1 9.657 1.934 25.2 25.2 0 0 1 8.187 5.505 3.644 3.644 0 0 1 0 5.13",viewW:45,viewH:48}},{id:"armchair",group:"furniture",category:"armchair",w:90,h:90,art:{d:"M75.702 13.011q.012-.225.012-.453c0-4.843-3.917-8.768-8.748-8.768H23.034c-4.83 0-8.747 3.925-8.747 8.768q0 .228.011.453M77.132 72.09q.59.091 1.206.092c4.348 0 7.873-3.533 7.873-7.892V20.45c0-4.359-3.525-7.892-7.873-7.892-.924 0-1.812.16-2.636.453a7.89 7.89 0 0 0-5.237 7.438v.148m0 0a8.7 8.7 0 0 1-3.499.73H23.034a8.7 8.7 0 0 1-3.499-.73m50.93 0V64.29a7.89 7.89 0 0 0 6.667 7.8M14.298 13.01a7.89 7.89 0 0 1 5.237 7.438v.148m0 0V64.29a7.89 7.89 0 0 1-6.666 7.8q-.59.091-1.206.092c-4.348 0-7.873-3.533-7.873-7.892V20.45c0-4.359 3.525-7.892 7.873-7.892.924 0 1.811.16 2.635.453M77.132 72.09c-1.585 8.05-8.667 14.12-17.164 14.12H30.032c-8.496 0-15.578-6.07-17.163-14.12",viewW:90,viewH:90}},{id:"armchair_office",group:"furniture",category:"armchair",w:65,h:65,art:{d:"M56.968 18.845q0-.368-.05-.72M49.051 13.8H15.95a5.04 5.04 0 0 1-5.038-5.043 5.04 5.04 0 0 1 5.038-5.043h33.103a5.04 5.04 0 0 1 5.038 5.043 5.04 5.04 0 0 1-5.038 5.043m-33.103 0h-2.88a5.04 5.04 0 0 0-4.986 4.323M49.052 13.8h2.879a5.04 5.04 0 0 1 4.986 4.324m.051 24.826a4.32 4.32 0 0 0 4.318-4.323v-16.18a4.32 4.32 0 0 0-4.369-4.322m.051 24.826a4.32 4.32 0 0 1-4.318-4.323V22.447a4.32 4.32 0 0 1 4.267-4.322m-11.84 37.24h4.695c.736 0 1.446-.111 2.115-.317a7.21 7.21 0 0 0 5.081-6.889v-5.208M8.084 18.124h-.051a4.32 4.32 0 0 0-4.318 4.323v16.18a4.32 4.32 0 0 0 4.318 4.324 4.32 4.32 0 0 0 4.317-4.323V22.447a4.32 4.32 0 0 0-4.266-4.323m11.935 37.24h-4.79a7.2 7.2 0 0 1-2.04-.294 7.21 7.21 0 0 1-5.156-6.91v-5.21m37.045 12.414 5.177 5.183c.969.97 2.534.987 3.524.038a2.526 2.526 0 0 0 .038-3.605l-1.93-1.932m-6.81.316H20.02m-6.83-.294-1.909 1.91c-.998 1-.98 2.627.038 3.605.99.949 2.555.932 3.524-.038l5.177-5.183",viewW:65,viewH:65}},{id:"sofa",group:"furniture",category:"sofa",w:180,h:90,art:{d:"M90 19.365v57.111m0-57.11V7.683m0 11.681c0 2.151-1.836 3.894-4.1 3.894H30.544a10.7 10.7 0 0 1-4.136-.825M90 19.365c0 2.151 1.836 3.894 4.1 3.894h55.356c1.472 0 2.871-.294 4.137-.825M90 76.476c0 5.376-4.59 9.735-10.25 9.735H30.543c-5.266 0-9.605-3.772-10.185-8.625M90 76.476c0 5.376 4.59 9.735 10.25 9.735h49.206c5.266 0 9.605-3.772 10.185-8.625M90 7.684c0-2.15-1.837-3.894-4.101-3.894H30.544c-5.661 0-10.25 4.358-10.25 9.735q0 .416.036.825M90 7.684c0-2.15 1.836-3.894 4.1-3.894h55.356c5.661 0 10.25 4.358 10.25 9.735q0 .416-.036.825m0 0a10.7 10.7 0 0 1 4.137-.825h2.05c5.662 0 10.252 4.358 10.252 9.734v45.43c0 5.376-4.59 9.734-10.251 9.734h-2.05c-1.484 0-2.894-.3-4.167-.837m0 0c-3.585-1.517-6.084-4.93-6.084-8.898V23.26q0-.417.036-.825c.32-3.622 2.728-6.68 6.077-8.084m-139.34 0c3.35 1.404 5.758 4.462 6.078 8.084q.036.408.036.825v45.43c0 3.967-2.5 7.38-6.085 8.897a10.7 10.7 0 0 1-4.166.837h-2.05c-5.662 0-10.251-4.358-10.251-9.735V23.26c0-5.376 4.59-9.734 10.25-9.734h2.05c1.473 0 2.872.294 4.138.825",viewW:180,viewH:90}},{id:"sofa_three_seat",group:"furniture",category:"sofa",w:240,h:90,art:{d:"M86.553 18.593V76.96m0-58.366V7.491m0 11.102c0 2.044-1.762 3.701-3.935 3.701H29.496c-1.413 0-2.756-.28-3.97-.784m61.027-2.917c0 2.044 1.762 3.701 3.935 3.701h59.024c2.174 0 3.935-1.657 3.935-3.7M86.553 76.958c0 5.11-4.404 9.252-9.837 9.252h-47.22c-5.054 0-9.218-3.585-9.775-8.198m66.832-1.054c0 5.11 4.404 9.252 9.837 9.252h47.22c5.433 0 9.837-4.142 9.837-9.252m0-58.366V76.96m0-58.366V7.491m0 11.102c0 2.044 1.762 3.701 3.936 3.701h53.122c1.413 0 2.756-.28 3.97-.784m-61.028 55.449c0 5.11 4.405 9.252 9.838 9.252h47.22c5.054 0 9.218-3.585 9.775-8.198M86.553 7.491c0-2.044-1.762-3.701-3.935-3.701H29.496c-5.433 0-9.838 4.142-9.838 9.252q0 .396.035.784m66.86-6.335c0-2.044 1.762-3.701 3.935-3.701h59.024c2.174 0 3.935 1.657 3.935 3.7m0 0c0-2.043 1.762-3.7 3.936-3.7h53.122c5.433 0 9.838 4.142 9.838 9.252 0 .258.022.517 0 .77m-.063 64.201c1.22.512 2.574.796 3.998.796h1.967c5.433 0 9.837-4.142 9.837-9.252V22.294c0-5.11-4.404-9.252-9.837-9.252h-1.967c-5.153 0-9.38 3.725-9.803 8.468q-.036.387-.035.784v47.263c0 3.771 2.399 7.015 5.84 8.456M19.693 13.826a10.3 10.3 0 0 0-3.97-.784h-1.967c-5.433 0-9.838 4.142-9.838 9.252v47.263c0 5.11 4.405 9.252 9.838 9.252h1.967c1.424 0 2.777-.284 3.998-.796 3.441-1.441 5.84-4.685 5.84-8.456V22.294a9 9 0 0 0-.035-.784c-.307-3.443-2.618-6.349-5.833-7.684",viewW:240,viewH:90}},{id:"sofa_corner_right",group:"furniture",category:"sofa",w:260,h:170,art:{d:"M93.673 20.687V83.69m0-63.004v-12.6m0 12.6c0 2.32-1.913 4.2-4.273 4.2H31.704a10.8 10.8 0 0 1-4.311-.89m66.28-3.31c0 2.32 1.914 4.2 4.274 4.2h64.106c2.36 0 4.274-1.88 4.274-4.2M93.673 83.692c0 5.8-4.783 10.501-10.684 10.501H31.704c-5.489 0-10.011-4.068-10.616-9.304m72.585-1.197c0 5.8 4.784 10.501 10.684 10.501h51.286c5.9 0 10.684-4.701 10.684-10.5m0-63.005V83.69m0-63.004v-12.6m0 12.6c0 2.32 1.914 4.2 4.273 4.2h57.696c1.534 0 2.993-.317 4.312-.89m-66.28 59.695v71.923c0 5.799 4.782 10.5 10.684 10.5h51.284c5.49 0 10.012-4.068 10.616-9.304V84.888M93.673 8.086c0-2.32-1.913-4.2-4.273-4.2H31.704c-5.9 0-10.684 4.7-10.684 10.5q0 .45.038.89m72.615-7.19c0-2.32 1.914-4.2 4.274-4.2h64.106c2.36 0 4.274 1.88 4.274 4.2m0 0c0-2.32 1.914-4.2 4.273-4.2h57.696c5.9 0 10.685 4.7 10.685 10.5 0 .293.024.587 0 .874m-.07 69.628c1.327.58 2.797.904 4.344.904h2.136c5.901 0 10.684-4.702 10.684-10.501V24.887c0-5.8-4.783-10.5-10.684-10.5h-2.136c-5.596 0-10.187 4.227-10.647 9.61q-.038.44-.038.89V75.29c0 4.28 2.605 7.961 6.342 9.597M21.059 15.276a10.8 10.8 0 0 0-4.312-.89H14.61c-5.9 0-10.684 4.701-10.684 10.5v50.405c0 5.8 4.783 10.5 10.684 10.5h2.137c1.546 0 3.016-.322 4.342-.903 3.737-1.636 6.342-5.317 6.342-9.597V24.887q0-.45-.037-.89c-.334-3.907-2.844-7.206-6.335-8.72",viewW:260,viewH:170}},{id:"bed_single",group:"furniture",category:"bed",w:90,h:200,art:{d:"M3.79 14.024c0 5.59 4.318 10.122 9.645 10.122h63.13c5.328 0 9.646-4.532 9.646-10.122m-22.797 46.93V46.23c0-5.082-3.926-9.201-8.769-9.201h-19.29c-4.842 0-8.768 4.12-8.768 9.201v14.723m-22.797 0h82.42m0 22.085H3.79m8.768 113.06h64.885c4.842 0 8.768-4.12 8.768-9.202V13.104c0-5.082-3.926-9.202-8.768-9.202H12.558c-4.843 0-8.768 4.12-8.768 9.202v173.792c0 5.082 3.925 9.202 8.768 9.202",viewW:90,viewH:200}},{id:"bed_double",group:"furniture",category:"bed",w:160,h:200,art:{d:"M3.879 14.073c0 5.618 4.516 10.172 10.088 10.172h132.065c5.571 0 10.088-4.554 10.088-10.172m-81.165 47.16V46.438c0-5.107-4.106-9.247-9.171-9.247H45.607c-5.065 0-9.17 4.14-9.17 9.247v14.795m89.877 0V46.438c0-5.107-4.107-9.247-9.172-9.247H96.966c-5.065 0-9.171 4.14-9.171 9.247v14.795m-83.916 0H156.12m0 22.192H3.88m9.17 112.673h133.9c5.065 0 9.171-4.14 9.171-9.247V13.15c0-5.107-4.106-9.247-9.171-9.247H13.05c-5.064 0-9.17 4.14-9.17 9.247v173.7c0 5.107 4.106 9.247 9.17 9.247",viewW:160,viewH:200}},{id:"nightstand",group:"furniture",category:"nightstand",w:50,h:40,art:{d:"M5.773 3.555h38.454a2.136 2.056 0 0 1 2.137 2.056v28.777a2.136 2.056 0 0 1-2.137 2.056H5.773a2.136 2.056 0 0 1-2.136-2.056V5.611a2.136 2.056 0 0 1 2.136-2.056",viewW:50,viewH:40}},{id:"cabinet_tv",group:"furniture",category:"nightstand",w:140,h:45,art:{d:"M56.772 17.88h5.315m0 0h5.315m-5.315 0v9.214m9.832-9.214 5.315 9.45 5.314-9.45M6.224 41.4h127.552c1.305 0 2.362-.94 2.362-2.1V5.7c0-1.16-1.057-2.1-2.362-2.1H6.224c-1.305 0-2.362.94-2.362 2.1v33.6c0 1.16 1.057 2.1 2.362 2.1",viewW:140,viewH:45}},{id:"cabinet_shoe",group:"furniture",category:"nightstand",w:80,h:35,art:{d:"m39.722 16.231 1.505-1.596m1.134 3.15 1.53-1.738M6.03 31.5h67.94c1.251 0 2.265-.895 2.265-2v-24c0-1.105-1.014-2-2.264-2H6.03c-1.251 0-2.265.895-2.265 2v24c0 1.105 1.014 2 2.265 2m41.966-14.305L46.92 17.1a3.4 3.4 0 0 1-1.813-.706l-4.583-3.62c-1.264-1-3.277-.326-3.475 1.161-.185 1.39-1.983 2.1-3.28 1.299l-1.532-.947c-.968-.513-2.2.103-2.2 1.1v3.463c0 1.559 1.43 2.823 3.196 2.823h14.51c1.404 0 2.542-1.005 2.542-2.245 0-1.153-.99-2.118-2.289-2.233",viewW:80,viewH:35}},{id:"cabinet_sink",group:"furniture",category:"nightstand",w:80,h:50,art:{d:"M3.765 5.773c0-1.18 1.014-2.136 2.265-2.136h67.94c1.251 0 2.265.956 2.265 2.136v38.454c0 1.18-1.014 2.137-2.264 2.137H6.03c-1.251 0-2.265-.957-2.265-2.137z M36.088 32.135c2.525 1.88 6.205 1.88 8.73 0s3.167-5.101 1.52-7.637l-5.879-8.043-5.893 8.043c-1.644 2.536-1.003 5.755 1.522 7.637",viewW:80,viewH:50}},{id:"bookshelf",group:"furniture",category:"wardrobe",w:100,h:35,art:{d:"M57.12 20.488H45.473c-.514 0-1.008.124-1.372.345s-.568.52-.568.832m4.076-8.236h5.434M6.119 3.5h87.762c1.276 0 2.31.895 2.31 2v24c0 1.105-1.034 2-2.31 2H6.12c-1.275 0-2.31-.895-2.31-2v-24c0-1.105 1.035-2 2.31-2m51 6.4v14.118H45.474a2.04 2.04 0 0 1-1.372-.517 1.7 1.7 0 0 1-.568-1.248V11.665c0-.468.204-.917.568-1.248a2.04 2.04 0 0 1 1.372-.517z",viewW:100,viewH:35}},{id:"wall_unit",group:"furniture",category:"wardrobe",w:240,h:45,art:{d:"M6.336 41.4h227.328a2.418 2.1 0 0 0 2.418-2.1V5.7a2.418 2.1 0 0 0-2.418-2.1H6.336a2.418 2.1 0 0 0-2.418 2.1v33.6a2.418 2.1 0 0 0 2.418 2.1m43.744-5.88V9.48m46.432 26.04V9.48m46.433 26.04V9.48m46.433 26.04V9.48",viewW:240,viewH:45}},{id:"wardrobe",group:"furniture",category:"wardrobe",w:180,h:60,art:{d:"M93.87 20.25a3.3 3.3 0 0 0-1.072-2.407 3.8 3.8 0 0 0-2.586-.997c-.97 0-1.9.358-2.587.997a3.3 3.3 0 0 0-1.071 2.407c0 2.838 1.225 5.107 3.658 6.81h-.015m0 0 14.58 7.537c.57.295 1.046.726 1.377 1.25.331.523.505 1.12.505 1.727v1.401a3.3 3.3 0 0 1-1.071 2.407 3.8 3.8 0 0 1-2.587.998H77.393a3.8 3.8 0 0 1-2.586-.998 3.3 3.3 0 0 1-1.072-2.407v-1.4c0-.608.174-1.205.505-1.728a3.55 3.55 0 0 1 1.377-1.25zM6.284 3.691h167.433c1.32 0 2.392.981 2.392 2.192v48.23c0 1.212-1.071 2.193-2.392 2.193H6.284c-1.321 0-2.392-.981-2.392-2.192V5.885c0-1.212 1.07-2.193 2.392-2.193",viewW:180,viewH:60}},{id:"kitchen_floor",group:"furniture",category:"kitchen_cabinet",w:60,h:60,art:{d:"M3.692 5.884c0-1.21.981-2.192 2.192-2.192h48.23c1.212 0 2.193.981 2.193 2.192v48.23a2.19 2.19 0 0 1-2.192 2.193H5.885a2.19 2.19 0 0 1-2.193-2.192z",viewW:60,viewH:60}},{id:"kitchen_floor_corner",group:"furniture",category:"kitchen_cabinet",w:90,h:90,art:{d:"M45.944 41.767a2.29 2.29 0 0 0 2.29 2.29H83.92a2.29 2.29 0 0 1 2.29 2.29V83.92a2.29 2.29 0 0 1-2.29 2.29H6.08a2.29 2.29 0 0 1-2.29-2.29V6.08a2.29 2.29 0 0 1 2.29-2.29h37.576a2.29 2.29 0 0 1 2.29 2.29z",viewW:90,viewH:90}},{id:"kitchen_wall",group:"furniture",category:"kitchen_cabinet",w:60,h:35,art:{d:"m4.444 31.033 50.75-27.007m-50.752-.06 50.75 27.008M5.884 31.5h48.23c1.212 0 2.193-.895 2.193-2v-24c0-1.105-.981-2-2.192-2H5.885c-1.212 0-2.193.895-2.193 2v24c0 1.105.981 2 2.192 2",viewW:60,viewH:35}},{id:"kitchen_wall_corner",group:"furniture",category:"kitchen_cabinet",w:60,h:60,art:{d:"M3.772 29.59 29.88 4.383M4.57 55.43 55.43 30M4.175 4.383l26.701 23.863m-27.184.877L55.43 55.43M28.41 3.692H5.884c-1.21 0-2.192.981-2.192 2.192v48.23c0 1.212.981 2.193 2.192 2.193h48.23a2.19 2.19 0 0 0 2.193-2.192V31.589c0-1.21-.981-2.192-2.192-2.192h-21.32a2.19 2.19 0 0 1-2.193-2.192V5.885a2.19 2.19 0 0 0-2.192-2.193",viewW:60,viewH:60}},{id:"shelf_floor",group:"furniture",category:"shelving",w:100,h:35,art:{d:"M6.12 31.5h87.76a2.31 2 0 0 0 2.31-2v-24a2.31 2 0 0 0-2.31-2H6.12a2.31 2 0 0 0-2.31 2v24a2.31 2 0 0 0 2.31 2 M9.089 25.933c-.494.112-.776.546-.63.97s.664.675 1.157.564l-.263-.767zM90.912 9.067c.493-.112.775-.546.63-.97s-.664-.675-1.158-.564l.264.767zM11.875 26.956c.493-.112.775-.546.63-.97s-.664-.676-1.158-.564l.264.767zm3.988-2.556c-.493.112-.775.546-.63.969s.664.676 1.158.564l-.264-.766zm5.045.511c.493-.112.775-.545.63-.969s-.664-.676-1.158-.564l.264.766zm3.988-2.555c-.493.111-.775.545-.63.968.146.424.664.677 1.158.565l-.264-.767zm5.044.51c.494-.111.776-.545.63-.968-.145-.424-.664-.676-1.157-.565l.263.767zm3.99-2.555c-.495.112-.777.546-.63.97.145.423.663.675 1.157.563l-.264-.766zm5.043.511c.494-.112.776-.545.63-.969s-.664-.676-1.158-.564l.264.767zm3.989-2.555c-.494.111-.776.545-.63.969s.664.676 1.157.564l-.263-.767zm5.044.51c.494-.11.776-.545.63-.968-.146-.424-.664-.676-1.158-.565l.264.767zm3.989-2.555c-.494.112-.776.546-.63.97.145.423.664.675 1.157.564l-.264-.767zm5.044.511c.493-.111.775-.545.63-.969s-.664-.676-1.158-.564l.264.767zm3.988-2.555c-.493.112-.775.545-.63.969s.664.676 1.158.564l-.264-.767zm5.045.51c.493-.11.775-.545.63-.968-.146-.424-.664-.676-1.158-.564l.264.766zm3.988-2.555c-.493.112-.775.546-.63.97s.664.675 1.158.564l-.264-.767zm5.044.511c.494-.111.776-.545.63-.968-.145-.424-.664-.677-1.157-.565l.264.767zm3.99-2.555c-.494.112-.777.545-.63.969.145.423.663.676 1.157.564l-.264-.766zm5.043.511c.494-.112.776-.546.63-.969s-.664-.676-1.157-.564l.263.766zm3.989-2.556c-.494.112-.776.546-.63.97s.664.676 1.158.564l-.264-.767zM9.353 26.7l.263.767 2.259-.511-.264-.767-.264-.767-2.258.511zm6.774-1.533.264.766 4.517-1.022-.264-.767-.264-.766-4.517 1.022zm9.033-2.045.264.767 4.516-1.022-.264-.767-.263-.767-4.517 1.023zm9.033-2.044.264.766 4.516-1.022-.264-.766-.264-.767-4.516 1.022zm9.033-2.045.263.767 4.517-1.022-.264-.767-.264-.767-4.516 1.023zm9.032-2.044.264.767 4.517-1.023-.264-.766-.264-.767-4.516 1.022zm9.033-2.045.264.767 4.517-1.022-.264-.767-.264-.766-4.517 1.022zm9.033-2.044.264.767 4.516-1.023-.263-.766-.264-.767-4.517 1.022zm9.033-2.044.264.766 4.516-1.022-.264-.767-.263-.766-4.517 1.022zM88.39 8.81l.264.767 2.258-.511-.264-.767-.264-.767-2.258.511z M9.089 9.067c-.494-.112-.776-.546-.63-.97s.664-.675 1.157-.564l-.263.767zm81.823 16.866c.493.112.775.546.63.97s-.664.675-1.158.564l.264-.767zM11.875 8.044c.493.112.775.546.63.97s-.664.676-1.158.564l.264-.767zm3.988 2.556c-.493-.112-.775-.546-.63-.969s.664-.676 1.158-.564l-.264.766zm5.045-.511c.493.112.775.545.63.969s-.664.676-1.158.564l.264-.766zm3.988 2.555c-.493-.111-.775-.545-.63-.968.146-.424.664-.677 1.158-.565l-.264.767zm5.044-.51c.494.111.776.545.63.968-.145.424-.664.676-1.157.565l.263-.767zm3.99 2.555c-.495-.112-.777-.546-.63-.97.145-.423.663-.675 1.157-.563l-.264.766zm5.043-.511c.494.112.776.545.63.969s-.664.676-1.158.564l.264-.767zm3.989 2.555c-.494-.111-.776-.545-.63-.969s.664-.676 1.157-.564l-.263.767zm5.044-.51c.494.11.776.545.63.968-.146.424-.664.676-1.158.565l.264-.767zm3.989 2.555c-.494-.112-.776-.546-.63-.97.145-.423.664-.675 1.157-.564l-.264.767zm5.044-.511c.493.111.775.545.63.969s-.664.676-1.158.564l.264-.767zm3.988 2.555c-.493-.112-.775-.545-.63-.969s.664-.676 1.158-.564l-.264.767zm5.045-.51c.493.11.775.545.63.968-.146.424-.664.676-1.158.564l.264-.766zm3.988 2.555c-.493-.112-.775-.546-.63-.97s.664-.675 1.158-.564l-.264.767zm5.044-.511c.494.111.776.545.63.968-.145.424-.664.677-1.157.565l.264-.767zm3.99 2.555c-.494-.112-.777-.545-.63-.969.145-.423.663-.676 1.157-.564l-.264.766zm5.043-.511c.494.112.776.546.63.969s-.664.676-1.157.564l.263-.766zm3.989 2.556c-.494-.112-.776-.546-.63-.97s.664-.676 1.158-.564l-.264.767zM9.353 8.3l.263-.767 2.259.511-.264.767-.264.767-2.258-.511zm6.774 1.533.264-.766 4.517 1.022-.264.767-.264.766-4.517-1.022zm9.033 2.045.264-.767 4.516 1.022-.264.767-.263.767-4.517-1.023zm9.033 2.044.264-.766 4.516 1.022-.264.766-.264.767-4.516-1.022zm9.033 2.045.263-.767 4.517 1.022-.264.767-.264.767-4.516-1.023zm9.032 2.044.264-.767 4.517 1.023-.264.766-.264.767-4.516-1.022zm9.033 2.045.264-.767 4.517 1.022-.264.767-.264.766-4.517-1.022zm9.033 2.044.264-.767 4.516 1.023-.263.766-.264.767-4.517-1.022zm9.033 2.044.264-.766 4.516 1.022-.264.767-.263.766-4.517-1.022zm9.033 2.045.264-.767 2.258.511-.264.767-.264.767-2.258-.511z",viewW:100,viewH:35}},{id:"shelf_wall",group:"furniture",category:"shelving",w:100,h:25,art:{d:"M18.36 3.15v2.567c0 1.012-1.034 1.833-2.31 1.833h-.924c-1.275 0-2.309-.82-2.309-1.833V3.15m73.905 0v2.567c0 1.012-1.034 1.833-2.31 1.833h-.924c-1.275 0-2.31-.82-2.31-1.833V3.15m-75.29 0H93.65c1.276 0 2.31.82 2.31 1.833V19.65c0 1.012-1.034 1.833-2.31 1.833H5.888c-1.275 0-2.31-.82-2.31-1.833V4.983c0-1.012 1.035-1.833 2.31-1.833",viewW:100,viewH:25}},{id:"cooktop_two",group:"appliance",category:"cooktop",w:30,h:50,art:{d:"M15 30.982v-1.71m3.086 5.128h1.542M15 39.527v-1.709M10.372 34.4h1.542M5.84 46.364h18.322c1.331 0 2.41-1.196 2.41-2.67V6.306c0-1.475-1.079-2.67-2.41-2.67H5.839c-1.331 0-2.41 1.195-2.41 2.67v37.386c0 1.475 1.079 2.67 2.41 2.67m14.56-29.91c0 3.304-2.417 5.982-5.4 5.982-2.981 0-5.4-2.678-5.4-5.981s2.419-5.982 5.4-5.982c2.983 0 5.4 2.678 5.4 5.982M18.858 34.4c0 2.36-1.727 4.273-3.857 4.273s-3.857-1.913-3.857-4.273S12.87 30.127 15 30.127s3.857 1.913 3.857 4.273",viewW:30,viewH:50}},{id:"stove",group:"appliance",category:"cooktop",w:60,h:60,art:{d:"M41.4 35.261a.877.877 0 1 0-1.754 0zm4.384 6.138a.877.877 0 1 0 0-1.753zM41.4 44.03a.877.877 0 1 0-1.753 0zm-4.384-2.63a.877.877 0 1 0 0-1.754zM5.885 3.691v.877h48.23V2.815H5.885zm50.422 2.192h-.877v48.23h1.754V5.885zm-2.192 50.423v-.877H5.885v1.754h48.23zM3.692 54.115h.877V5.885H2.815v48.23zm2.192 2.192v-.877a1.315 1.315 0 0 1-1.315-1.315H2.815a3.07 3.07 0 0 0 3.07 3.069zm50.423-2.192h-.877c0 .726-.589 1.315-1.315 1.315v1.754a3.07 3.07 0 0 0 3.069-3.07zM54.115 3.692v.877c.726 0 1.315.589 1.315 1.315h1.754a3.07 3.07 0 0 0-3.07-3.069zm-48.23 0v-.877a3.07 3.07 0 0 0-3.07 3.07h1.754c0-.727.589-1.316 1.315-1.316zm19.73 36.83h-.877a5.26 5.26 0 0 1-5.262 5.262v1.754a7.015 7.015 0 0 0 7.016-7.015zm-6.139 6.139v-.877a5.26 5.26 0 0 1-5.261-5.261h-1.754a7.015 7.015 0 0 0 7.015 7.015zm-6.138-6.138h.877a5.26 5.26 0 0 1 5.261-5.262v-1.754a7.015 7.015 0 0 0-7.015 7.016zm6.138-6.139v.877a5.26 5.26 0 0 1 5.262 5.262h1.754a7.015 7.015 0 0 0-7.016-7.016zm27.185-14.908h-.877a5.26 5.26 0 0 1-5.261 5.262v1.754a7.015 7.015 0 0 0 7.015-7.016zm-6.138 6.139v-.877a5.26 5.26 0 0 1-5.262-5.262h-1.754a7.015 7.015 0 0 0 7.016 7.016zm-6.139-6.139h.877a5.26 5.26 0 0 1 5.262-5.261v-1.754a7.015 7.015 0 0 0-7.016 7.015zm6.139-6.138v.877a5.26 5.26 0 0 1 5.261 5.261h1.754a7.015 7.015 0 0 0-7.015-7.015zm4.384 27.185h-.877a3.51 3.51 0 0 1-3.507 3.507v1.754a5.26 5.26 0 0 0 5.261-5.261zm-4.384 4.384v-.877a3.51 3.51 0 0 1-3.508-3.507H35.26a5.26 5.26 0 0 0 5.262 5.261zm-4.385-4.384h.877a3.51 3.51 0 0 1 3.508-3.508V35.26a5.26 5.26 0 0 0-5.262 5.262zm4.385-4.385v.877a3.51 3.51 0 0 1 3.507 3.508h1.754a5.26 5.26 0 0 0-5.261-5.262zm0 .877h.876V35.26h-1.753v1.754zm3.508 3.508v.876h1.753v-1.753h-1.753zm-3.508 5.261h.876V44.03h-1.753v1.754zm-5.261-5.261v.876h1.753v-1.753h-1.753zm-9.647-21.047h-.877a5.26 5.26 0 0 1-5.262 5.262v1.754a7.015 7.015 0 0 0 7.016-7.016zm-6.139 6.139v-.877a5.26 5.26 0 0 1-5.261-5.262h-1.754a7.015 7.015 0 0 0 7.015 7.016zm-6.138-6.139h.877a5.26 5.26 0 0 1 5.261-5.261v-1.754a7.015 7.015 0 0 0-7.015 7.015zm6.138-6.138v.877a5.26 5.26 0 0 1 5.262 5.261h1.754a7.015 7.015 0 0 0-7.016-7.015z",viewW:60,viewH:60}},{id:"tv",group:"appliance",category:"tv",w:120,h:28,art:{d:"M45.134 10.766H6.18c-1.292 0-2.34.848-2.34 1.894v2.68c0 1.045 1.048 1.893 2.34 1.893h38.954m0-6.467V5.288c0-1.046 1.048-1.894 2.34-1.894h26.704c1.292 0 2.34.848 2.34 1.894v5.478m-31.384 0h31.384m0 0h37.302c1.293 0 2.34.848 2.34 1.894v2.68c0 1.045-1.047 1.893-2.34 1.893H76.518m-31.384 0v5.479c0 1.046 1.048 1.894 2.34 1.894h26.704c1.292 0 2.34-.848 2.34-1.894v-5.479m-31.384 0h31.384",viewW:120,viewH:28}},{id:"tv_wall",group:"appliance",category:"tv",w:120,h:15,art:{d:"M35.664 11.4c-.517 0-.936.269-.936.6s.419.6.936.6zm49.553 1.2c.517 0 .936-.269.936-.6s-.42-.6-.936-.6zM6.18 3v.6h107.64V2.4H6.18zm109.98 1.5h-.936v1.8h1.872V4.5zm-2.34 3.3v-.6H6.18v1.2h107.64zM3.84 6.3h.936V4.5H2.904v1.8zm2.34 1.5v-.6c-.775 0-1.404-.403-1.404-.9H2.904c0 1.16 1.467 2.1 3.276 2.1zm109.98-1.5h-.936c0 .497-.629.9-1.404.9v1.2c1.81 0 3.276-.94 3.276-2.1zM113.82 3v.6c.775 0 1.404.403 1.404.9h1.872c0-1.16-1.467-2.1-3.276-2.1zM6.18 3v-.6c-1.81 0-3.276.94-3.276 2.1h1.872c0-.497.629-.9 1.404-.9zm61.308 4.2h-.936V12h1.872V7.2zM52.512 12h.936V7.2h-1.872V12zm-16.848 0v.6h49.553v-1.2H35.664z",viewW:120,viewH:15}},{id:"toilet",group:"sanitary",category:"toilet",w:40,h:70,art:{d:"M3.555 48.976c0 9.55 7.125 17.29 15.914 17.29h1.061c8.79 0 15.914-7.74 15.914-17.29V5.966c0-1.233-.92-2.233-2.056-2.233H5.611c-1.135 0-2.056 1-2.056 2.234z M7.666 49.12c0 7.003 5.225 12.68 11.67 12.68h1.327c6.445 0 11.67-5.677 11.67-12.68V31.873c0-1.233-.92-2.233-2.056-2.233H9.722c-1.135 0-2.056 1-2.056 2.233zM33.792 3.733c1.465 0 2.652 1.29 2.652 2.882v12.103c0 1.592-1.187 2.882-2.652 2.882H6.208c-1.465 0-2.653-1.29-2.653-2.882V6.615c0-1.591 1.188-2.882 2.653-2.882z M24.11 50.186c0 2.467-1.84 4.467-4.11 4.467s-4.111-2-4.111-4.467 1.84-4.466 4.11-4.466 4.112 2 4.112 4.466",viewW:40,viewH:70}},{id:"toilet_built_in",group:"sanitary",category:"toilet",w:40,h:55,art:{d:"M3.555 34.56c0 9.263 7.125 16.774 15.914 16.774h1.061c8.79 0 15.914-7.51 15.914-16.775V5.833c0-1.196-.92-2.166-2.056-2.166H5.611c-1.135 0-2.056.97-2.056 2.166z M7.666 34.7c0 6.793 5.225 12.3 11.67 12.3h1.327c6.445 0 11.67-5.507 11.67-12.3V14.5c0-1.197-.92-2.167-2.056-2.167H9.722c-1.135 0-2.056.97-2.056 2.167z M24.11 35.733c0 2.394-1.84 4.334-4.11 4.334s-4.111-1.94-4.111-4.334 1.84-4.333 4.11-4.333 4.112 1.94 4.112 4.333",viewW:40,viewH:55}},{id:"bathtub",group:"sanitary",category:"bathtub",w:170,h:75,art:{d:"M3.885 6c0-1.243 1.068-2.25 2.386-2.25h157.458c1.318 0 2.386 1.007 2.386 2.25v63c0 1.243-1.068 2.25-2.386 2.25H6.27c-1.318 0-2.386-1.007-2.386-2.25z M13.428 37.5c0-13.669 11.75-24.75 26.243-24.75h90.658c14.493 0 26.243 11.081 26.243 24.75s-11.75 24.75-26.243 24.75H39.67c-14.493 0-26.243-11.081-26.243-24.75 M31.56 37.5c0 2.237-1.923 4.05-4.295 4.05s-4.294-1.813-4.294-4.05 1.923-4.05 4.294-4.05c2.372 0 4.295 1.813 4.295 4.05",viewW:170,viewH:75}},{id:"bathtub_corner",group:"sanitary",category:"bathtub",w:140,h:140,art:{d:"M3.862 6.224a2.36 2.36 0 0 1 2.362-2.362H133.97c1.197 0 2.168.97 2.168 2.168 0 71.857-58.251 130.108-130.108 130.108a2.17 2.17 0 0 1-2.168-2.168z M13.31 32.207c0-10.437 8.46-18.897 18.897-18.897h87.628a2.13 2.13 0 0 1 2.13 2.13c0 58.833-47.692 106.526-106.524 106.526a2.13 2.13 0 0 1-2.13-2.131z M32.207 27.483a4.724 4.724 0 1 1-9.449 0 4.724 4.724 0 0 1 9.449 0",viewW:140,viewH:140}},{id:"bidet",group:"sanitary",category:"bidet",w:40,h:60,art:{d:"M22.466 3.692v10.085c0 1.21-.92 2.192-2.055 2.192h-.822c-1.136 0-2.056-.981-2.056-2.192V3.692m4.933 8.77h2.878c1.135 0 2.056-.982 2.056-2.193v-.877c0-1.21-.92-2.192-2.056-2.192h-2.878m-4.933 5.262h-2.878c-1.135 0-2.055-.982-2.055-2.193v-.877c0-1.21.92-2.192 2.055-2.192h2.878M5.611 3.692h28.777c1.136 0 2.056.981 2.056 2.192v33.45c0 9.374-7.125 16.973-15.914 16.973h-1.06c-8.79 0-15.915-7.599-15.915-16.972V5.885c0-1.212.92-2.193 2.056-2.193m4.11 15.785h20.556c1.136 0 2.056.981 2.056 2.192v17.807c0 6.874-5.225 12.447-11.67 12.447h-1.327c-6.445 0-11.67-5.573-11.67-12.447V21.67c0-1.21.92-2.192 2.056-2.192m13.567 7.892c0 1.937-1.472 3.508-3.288 3.508-1.817 0-3.29-1.57-3.29-3.508s1.473-3.507 3.29-3.507 3.288 1.57 3.288 3.507",viewW:40,viewH:60}},{id:"bidet_built_in",group:"sanitary",category:"bidet",w:40,h:50,art:{d:"M17.318 12.182h-8.06c-.88 0-1.592.74-1.592 1.654v16.126c0 6.698 5.225 12.129 11.67 12.129h1.327c6.445 0 11.67-5.43 11.67-12.13V13.837c0-.914-.713-1.654-1.591-1.654H22.68m-.215-8.545v9.827c0 1.18-.92 2.136-2.055 2.136h-.822c-1.136 0-2.056-.956-2.056-2.136V3.637m10.689 8.545V3.637m-16.445 0v8.545M5.611 3.637h28.777c1.136 0 2.056.956 2.056 2.136v24.051c0 9.135-7.125 16.54-15.914 16.54h-1.06c-8.79 0-15.915-7.405-15.915-16.54V5.773c0-1.18.92-2.136 2.056-2.136M23.289 23.29c0 1.888-1.473 3.418-3.29 3.418s-3.288-1.53-3.288-3.418 1.472-3.418 3.289-3.418c1.816 0 3.288 1.53 3.288 3.418",viewW:40,viewH:50}},{id:"kitchen_sink",group:"sanitary",category:"kitchen_sink",w:60,h:50,art:{d:"M38.188 8.7h10.598c1.211 0 2.193.956 2.193 2.136v28.2c0 1.18-.982 2.136-2.193 2.136H11.08c-1.21 0-2.192-.956-2.192-2.136v-28.2c0-1.18.981-2.136 2.192-2.136h10.599m10.885-5.128V15.11c0 1.18-.981 2.136-2.192 2.136h-.877c-1.21 0-2.192-.957-2.192-2.136V3.572m5.261 7.691h3.07c1.21 0 2.192-.956 2.192-2.136v-.855c0-1.18-.982-2.136-2.192-2.136h-3.07m-5.261 5.127h-3.07c-1.21 0-2.192-.956-2.192-2.136v-.855c0-1.18.982-2.136 2.193-2.136h3.069M5.817 46.299h48.231c1.21 0 2.192-.956 2.192-2.136V5.709c0-1.18-.981-2.137-2.192-2.137H5.818c-1.211 0-2.193.957-2.193 2.137v38.454c0 1.18.982 2.136 2.192 2.136M33.44 25.79c0 1.888-1.57 3.418-3.507 3.418s-3.508-1.53-3.508-3.418c0-1.887 1.57-3.418 3.508-3.418s3.507 1.53 3.507 3.418",viewW:60,viewH:50}},{id:"kitchen_sink_double",group:"sanitary",category:"kitchen_sink",w:90,h:50,art:{d:"M53.173 12.182c-.468 0-.847.354-.847.79s.38.79.847.79zm21.979 1.58c.467 0 .846-.353.846-.79 0-.436-.379-.79-.846-.79zM6.01 3.572v.79h77.842v-1.58H6.01zM86.14 5.71h-.847v38.454h1.694V5.709zM83.85 46.3v-.79H6.01v1.58h77.842zM3.72 44.163h.847V5.709H2.873v38.454zm2.29 2.136v-.79c-.797 0-1.443-.603-1.443-1.346H2.873c0 1.616 1.404 2.926 3.137 2.926zm80.131-2.136h-.847c0 .743-.646 1.346-1.442 1.346v1.58c1.732 0 3.136-1.31 3.136-2.926zm-2.29-40.59v.79c.797 0 1.443.602 1.443 1.346h1.694c0-1.617-1.404-2.927-3.136-2.927zm-77.841 0v-.79c-1.733 0-3.137 1.31-3.137 2.926h1.694c0-.744.646-1.347 1.443-1.347zm5.494 37.599v.79h28.39v-1.58h-28.39zm30.68-2.136h.846v-28.2h-1.694v28.2zm-32.97-28.2h-.846v28.2h1.694v-28.2zM39.895 8.7v-.79h-5.669v1.58h5.669zm-22.721 0v-.79h-5.669v1.58h5.669zm-7.958 2.136h.847c0-.744.645-1.346 1.442-1.346V7.91c-1.732 0-3.136 1.31-3.136 2.926zm32.968 0h.847c0-1.616-1.404-2.927-3.136-2.927v1.58c.797 0 1.442.603 1.442 1.347zm-2.29 30.336v.79c1.733 0 3.137-1.31 3.137-2.926h-1.694c0 .743-.645 1.346-1.442 1.346zm-28.389 0v-.79c-.797 0-1.442-.603-1.442-1.346H8.368c0 1.616 1.404 2.926 3.136 2.926zm13.737-23.927v.79h.916v-1.58h-.916zm3.205-2.136h.847V3.572H27.6V15.11zM22.952 3.572h-.847V15.11h1.693V3.572zm3.205 13.673v.79c1.732 0 3.136-1.31 3.136-2.926H27.6c0 .743-.646 1.346-1.443 1.346zm-.916 0v-.79c-.797 0-1.443-.603-1.443-1.346h-1.693c0 1.616 1.404 2.926 3.136 2.926zm3.205-5.982v.79h3.206v-1.58h-3.206zm5.495-2.136h.847v-.855h-1.694v.855zm-2.29-2.991v-.79h-3.205v1.58h3.206zm2.29 2.136h.847c0-1.616-1.404-2.926-3.136-2.926v1.58c.796 0 1.442.603 1.442 1.346zm-2.29 2.991v.79c1.733 0 3.137-1.31 3.137-2.926h-1.694c0 .743-.646 1.346-1.442 1.346zm-11.905 0v.79h3.206v-1.58h-3.206zm3.206-5.127v-.79h-3.206v1.58h3.206zm-5.495 2.136h-.847v.855h1.694v-.855zm2.29-2.136v-.79c-1.733 0-3.137 1.31-3.137 2.926h1.694c0-.743.646-1.346 1.442-1.346zm0 5.127v-.79c-.797 0-1.443-.603-1.443-1.346H16.61c0 1.616 1.404 2.926 3.136 2.926zm9.615 14.527h-.847c0 1.452-1.26 2.628-2.816 2.628v1.58c2.49 0 4.51-1.884 4.51-4.208zM25.7 29.208v-.79c-1.555 0-2.816-1.176-2.816-2.628H21.19c0 2.324 2.02 4.209 4.51 4.209zm-3.663-3.418h.847c0-1.451 1.26-2.628 2.816-2.628v-1.58c-2.49 0-4.51 1.884-4.51 4.208zm3.663-3.418v.79c1.555 0 2.816 1.177 2.816 2.628h1.694c0-2.324-2.02-4.208-4.51-4.208zm24.268 18.8v.79h28.39v-1.58h-28.39zm30.68-2.136h.846v-28.2H79.8v28.2zM78.356 8.7v-.79h-28.39v1.58h28.39zm-30.68 2.136h-.846v28.2h1.694v-28.2zm2.29-2.136v-.79c-1.732 0-3.136 1.31-3.136 2.926h1.694c0-.744.646-1.346 1.442-1.346zm30.68 2.136h.846c0-1.616-1.404-2.927-3.136-2.927v1.58c.797 0 1.443.603 1.443 1.347zm-2.29 30.336v.79c1.732 0 3.136-1.31 3.136-2.926H79.8c0 .743-.646 1.346-1.443 1.346zm-28.39 0v-.79c-.796 0-1.442-.603-1.442-1.346H46.83c0 1.616 1.404 2.926 3.136 2.926zm3.206-28.2v.79h21.979v-1.58h-21.98z",viewW:90,viewH:50}}].map(e=>({id:e.id,group:e.group,category:e.category,w:e.w,h:e.h,art:e.art})),...cl.filter(e=>hl.has(e.id))],ul=new Map(dl.map(e=>[e.id,e]));function pl(e){return e&&ul.get(e)||null}function _l(e){return dl.filter(t=>t.group===e)}function ml(e){const t=pl(e);return t?{w:t.w,h:t.h}:{w:60,h:60}}function fl(e,t,i=Na,n=1e3){const r=Number(t)>0?Number(t):5;return(Number(e)||0)/r*i/n}const gl=5e-4,vl=Ea;function yl(e){return Number.isFinite(e)?Math.max(gl,Math.min(vl,e)):gl}function bl(e){return Number.isFinite(e)?Math.max(1,Math.min(1e4,e)):1}const wl=e=>{const t=Math.round(1e3*e)/1e3;return Object.is(t,-0)?"0":String(t)};function kl(e){const t=pl(e);if(!t)return null;if(t.art)return t.art;const i=function(e,t,i){if(!e.g)return"";const n=e=>wl(e*t),r=e=>wl(e*i),o=[];for(const s of e.g)if("r"===s[0]){const[,e,t,i,a]=s;o.push(`M${n(e)} ${r(t)}H${n(e+i)}V${r(t+a)}H${n(e)}Z`)}else if("l"===s[0]){const[,e,t,i,a]=s;o.push(`M${n(e)} ${r(t)}L${n(i)} ${r(a)}`)}else if("e"===s[0]){const[,e,a,l,c]=s;o.push(`M${n(e-l)} ${r(a)}A${wl(l*t)} ${wl(c*i)} 0 0 1 ${n(e+l)} ${r(a)}A${wl(l*t)} ${wl(c*i)} 0 0 1 ${n(e-l)} ${r(a)}Z`)}else{const e=s.slice(1);if(e.length<4)continue;let t=`M${n(e[0])} ${r(e[1])}`;for(let i=2;i+1{let t=(e%360+360)%360;return t>180&&(t-=360),t};function $l(e,t,i,n,r,o=0){let s=null,a=r;for(const r of n){const[n,l,c,h]=r,d=c-n,u=h-l,p=d*d+u*u;if(!p)continue;const _=Math.sqrt(p);let m=((e-n)*d+(t-l)*u)/p;m=Math.max(0,Math.min(1,m));let f=n+m*d,g=l+m*u;const v=Math.hypot(e-f,t-g);if(!(v0){const e=Math.round(m*_/o)*o;f=n+e/_*d,g=l+e/_*u}s={cx:f+y*(i/2),cy:g+b*(i/2),angle:xl(180*Math.atan2(-y,b)/Math.PI),dist:v}}return s}const Sl=15e3,Ml=2e3,Rl=new WeakMap;function Tl(e,t){let i=Rl.get(e);if(!i){const t=new Set;i={hiddenAt:"hidden"===e.visibilityState?Date.now():0,token:0,subscribers:t,onVisibility:()=>{const t=Rl.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>=Sl};for(const e of[...t.subscribers])e(r)},onPageShow:t=>{const i=Rl.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)}},Rl.set(e,i),e.addEventListener("visibilitychange",i.onVisibility),e.defaultView?.addEventListener("pageshow",i.onPageShow)}return i.subscribers.add(t),()=>{const i=Rl.get(e);i&&(i.subscribers.delete(t),i.subscribers.size||(e.removeEventListener("visibilitychange",i.onVisibility),e.defaultView?.removeEventListener("pageshow",i.onPageShow),Rl.delete(e)))}}const Cl={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 Dl{constructor(e,t=Cl){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}),Ml)}),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 zl(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 Al(e){return zl(e)}const Ol=new WeakMap;class Pl{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=Ol.get(e);return t||(t={signed:{},queued:new Set,inFlight:new Map,retry:new Map,listeners:new Set,settlers:new Set,references:new Map},Ol.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=Rn(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),Ml);o.src=n}),i.preload}prepareImage(e,t){const i=Rn(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.at<$n)return this.preloadCurrentImage(n,i,t);this.display(e,i);const r=n.retry.get(i);return r&&r.notBefore>this.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),Ml);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),Ml);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<$n&&(o[e]=t);i.signed=o,i.retry.clear(),this.sign(e,[...t].filter(e=>!!o[e]&&!o[e].pending))}markLoaded(e,t,i){const n=Rn(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=Rn(t);if(!i.startsWith("/api/houseplan/content/"))return!0;const n=this.bind(e).signed[i];return!!n&&this.now()-n.at<$n&&n.loaded}get entries(){const e={};for(const[t,i]of Object.entries(this.shared?.signed||{}))e[t]={url:i.url,at:i.at};return e}get inFlightUrls(){return[...this.shared?.inFlight.keys()||[]]}}function Fl(e,t){if(t)return e.find(e=>e.id===t)}var El="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 Il(e,t,i){return[e[0]*t+e[1]*i+e[2],e[3]*t+e[4]*i+e[5]]}function Hl(e,t){let i=0;for(const[n,r]of t){const t=Il(e,n[0],n[1]);i=Math.max(i,Math.hypot(t[0]-r[0],t[1]-r[1]))}return i}const Nl=e=>{if(null==e||""===e)return null;const t=Number(e);return Number.isFinite(t)?t:null},Ll=e=>{const t=e,i=Nl(Array.isArray(t)?t[0]:t?.x),n=Nl(Array.isArray(t)?t[1]:t?.y);return null==i||null==n?null:[i,n]};function ql(e){if(!Array.isArray(e))return null;const t=[];for(const i of e){const e=Ll(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 Wl(e){if(!Array.isArray(e))return null;const t=[];for(const i of e){const e=Ll(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=ql(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 jl(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(Ll).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 Ul=e=>Number.isFinite(e[0])&&Number.isFinite(e[1]),Gl=(e,t)=>e[0]===t[0]&&e[1]===t[1];function Kl(e){if(!e)return null;const t=e.vacuum_position||e.robot_position||null,i=t&&null!=Nl(t.x)&&null!=Nl(t.y)?{x:Nl(t.x),y:Nl(t.y),a:Nl(t.a??t.angle??t.theta)}:null,n=jl(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=[[Nl(t.cx),Nl(t.cy)],[Nl(t.center?.x),Nl(t.center?.y)],[Nl(t.x),Nl(t.y)]].find(([e,t])=>null!=e&&null!=t);let o=n?.[0]??null,s=n?.[1]??null;const a=Wl(t.outline),l=Nl(t.x0),c=Nl(t.y0),h=Nl(t.x1),d=Nl(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 Yl(e,t,i){return![e,t,i].every(Number.isFinite)||e<0||t<=0||i<=0?Number.POSITIVE_INFINITY:e/t*i}const Zl=40;function Xl(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=!!Ll(n.vacuum_position??n.robot_position),a=!(!n.rooms||"object"!=typeof n.rooms),l=jl(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 Jl=e=>e.toLowerCase().replace(/[\s_\-.,]+/g,"");function Ql(e,t){const i=new Set(t.map(Jl).filter(Boolean)),n=new Set;for(const t of e){const e=Jl(t.name||"");e&&i.has(e)&&n.add(e)}return n.size}function ec(e,t){const i=new Map(t.map(e=>[Jl(e.name),e])),n=[],r=[];for(const t of e){const e=i.get(Jl(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,f]]of e){if(![p,_,m,f].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*f,d+=_*f,u+=f}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]),f=_([h,d,u]);if(!m||!f)return null;const g=[m[0],m[1],m[2],f[0],f[1],f[2]];return g.every(Number.isFinite)?g:null}(n);return o?{matrix:o,matched:r,residual:Hl(o,n)}:null}function tc(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 ic(e){return"cleaning"===e||"returning"===e||"on"===e}const nc={0:[1,0],90:[0,1],180:[-1,0],270:[0,-1]};function rc(e){const[t,i]=nc[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 oc(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 sc(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=rc(c),[d,u]=Il(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 ac(e,t,i,n){const[r,o]=Il(rc(t),i,n),s=rc({...e,ox:0,oy:0}),[a,l]=Il(s,i,n);return{...e,ox:r-a,oy:o-l}}function lc(e){const t=e?.trail_mode;return"never"===t||"cleaning"===t||"always"===t?t:!1===e?.trail?"never":"cleaning"}const cc={availability:"available",status:"alarm",activity:"none"},hc=new Set(["motion","vibration","sound"]),dc=new Set(["occupancy","presence"]),uc=new Set(["door","window","garage_door","opening"]),pc=new Set(["running","power"]),_c=new Set(["smoke","gas","carbon_monoxide","moisture","safety","tamper","problem"]);const mc=new Set(["running","working","washing","rinsing","spinning","drying","heating","cooling","cleaning","cooking","playing","recording","pumping","irrigating","humidifying","dehumidifying","fan","preheating","defrosting"]),fc=new Set([...mc,"start","started","run","active","in_progress","wash","rinse","spin","dry"]),gc=new Set(["off","idle","paused","standby","docked","finished","complete","completed","stopped","ready","sleeping","stop","end","done","inactive"]),vc=new Set(["heat","cool","heat_cool","auto","dry","fan_only"]),yc=e=>""===e||"unknown"===e||"unavailable"===e||"__missing__"===e,bc=e=>String(e??"").trim().toLowerCase(),wc=e=>bc(e).replace(/[\s-]+/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,""),kc=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]]),xc=new Set(["wifi","connection","signal","battery"]);function $c(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=>bc(e))||o.push(e?.states?.[t]?.attributes?.friendly_name);const s=o.map(wc).filter(Boolean);if(s.some(e=>e.split("_").some(e=>xc.has(e))))return null;let a=null;for(const e of s)for(const[t,i]of kc)(e===t||e.endsWith(`_${t}`))&&(a=null==a?i:Math.min(a,i));return a}const Sc=(e,t)=>null!=$c(e,t);function Mc(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(bc).some(e=>["power","main power","power switch","питание"].includes(e)))return!0;const o=bc(n?.attributes?.friendly_name);return/(?:^|[\s._-])(?:main[\s._-]+)?power$/.test(o)||/(?:^|[\s._-])питание$/.test(o)}function Rc(e){for(const t of["hvac_action","action","current_operation","run_state","job_state","operation","activity"]){const i=bc(e?.[t]);if(mc.has(i)||gc.has(i))return i}return""}function Tc(e,t){const i=e?.states?.[t],n=i?bc(i.state):"__missing__",r=String(t||"").split(".")[0],o=bc(i?.attributes?.device_class),s={eid:t,state:n,availability:yc(n)?"unavailable":"available",status:"neutral",activity:"none",edge:"none"};if("unavailable"===s.availability)return s;if(function(e,t,i){return"alarm_control_panel"===e?"triggered"===i:"on"===i&&In(e,t)}(r,o,n))return{...s,status:"alarm"};if("binary_sensor"===r)return hc.has(o)?{...s,edge:"rising"}:dc.has(o)?{...s,activity:"on"===n?"presence":"none"}:uc.has(o)?{...s,status:"on"===n?"open":"neutral",edge:"rising"}:"moving"===o?{...s,activity:"on"===n?"transition":"none"}:pc.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=Rc(i.attributes),t=Array.isArray(i.attributes?.hvac_modes)?i.attributes.hvac_modes.map(bc):[],r=!gc.has(n)&&(vc.has(n)||mc.has(n)||t.includes(n));return(e?mc.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=Rc(i.attributes);return mc.has(a)||mc.has(n)&&!gc.has(n)?{...s,status:"working",activity:"running"}:s}function Cc(e,t,i){const n=i.filter(t=>t.startsWith("switch.")&&!e?.entities?.[t]?.entity_category),r=t.find(t=>Mc(e,t));if(!(n.length>1&&!!r))return t.map(t=>Tc(e,t));const o=t.find(t=>t!==r&&Sc(e,t)),s=Tc(e,r);return"unavailable"===s.availability||"off"===s.state?t.map(t=>({eid:t,state:e?.states?.[t]?bc(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?bc(i.state):"__missing__",r={eid:t,state:n,availability:yc(n)?"unavailable":"available",status:"neutral",activity:"none",edge:"none"};if("unavailable"===r.availability)return r;const o=Rc(i?.attributes);return mc.has(o)||fc.has(n)&&!gc.has(n)?{...r,status:"working",activity:"running"}:r}(e,t);return{...t===r?s:Tc(e,t),status:"neutral",activity:"none",edge:"none"}})}function Dc(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 cc;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 zc(e,t){if(!(e=>!!e&&!yc(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 Ac=(e,t=0)=>{const i=Number(e);return Number.isInteger(i)&&i>=0?i:t},Oc=(e,t)=>{const i={rev:0,configRev:Ac(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 Pc(e,t=0){return Oc(e,t).snapshot}function Fc(e,t,i,n){const r=Oc(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=Gc(i,"id"),o=Gc(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 Yc(e,t){void 0===t.reloadTimer&&(t.reloadTimer=globalThis.setTimeout(()=>{t.reloadTimer=void 0,Kc(e,t)},80))}async function Zc(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,()=>Yc(e,t),"device_registry_updated")),t.unsubEntity||(t.unsubEntity=await i.call(e.connection,()=>Yc(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 Xc(e,t){const i=Uc(e);if(!i)return()=>{};const n=0===i.refs;i.refs++,i.listeners.add(t),("pending"===i.access||n)&&Kc(e,i),Zc(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 Jc(e){const t=Uc(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&&Yc(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 Qc(e){if(!e||"object"!=typeof e&&"function"!=typeof e)return 0;let t=Wc.get(e);return t||(t=jc++,Wc.set(e,t)),t}function eh(e,t=Jc(e)){return[t.revision,t.access,Qc(t.devices),Qc(t.entities)].join(":")}function th(e){return!!e&&null==e.disabled_by}function ih(e,t=Jc(e)){const i={},n={},r={};for(const[e,n]of Object.entries(t.devices||{}))th(n)&&(i[e]=n);for(const[e,i]of Object.entries(t.entities||{})){if(!th(i))continue;const r=i.device_id?t.devices?.[i.device_id]:null;t.authoritative&&i.device_id&&!r||(r&&!th(r)||(n[e]=i))}for(const[i,n]of Object.entries(e?.states||{})){const e=t.entities?.[i];if(e&&!th(e))continue;const o=e?.device_id?t.devices?.[e.device_id]:null;t.authoritative&&e?.device_id&&!o||(o&&!th(o)||(r[i]=n))}return{...e,devices:i,entities:n,states:r}}function nh(e,t=Jc(e)){return{...e,devices:t.devices||{},entities:t.entities||{}}}function rh(e,t){const i=[];for(const[n,r]of Object.entries(e||{}))r?.device_id===t&&i.push(n);return i}function oh(){if(Vc)return Vc;if("undefined"==typeof localStorage)return{};try{const e=JSON.parse(localStorage.getItem(Bc)||"{}");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 Vc=i,Vc}catch{return{}}}function sh(e,t,i=Jc(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=rh(a,o);if(!th(e))return{kind:"ha_disabled",reason:"device",enabledEntityIds:[],allEntityIds:t};const i=t.filter(e=>th(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&&!th(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&&!th(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 oh()[e]||null}(t);if("device"===r){const t=s[o],i=rh(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 ah(e){const t={};for(const[i,n]of Object.entries(e.entities)){if(!n?.device_id||!th(n))continue;const r=e.devices?.[n.device_id];r&&!th(r)||(t[n.device_id]=t[n.device_id]||[]).push(i)}return t}function lh(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 ch(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 hh(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 dh(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 uh=["vacuum","lawn_mower","climate","media_player","light","cover","lock","valve","alarm_control_panel","water_heater","fan","humidifier","siren","camera","remote"],ph=e=>[...e.filter(e=>!e.reg?.hidden),...e.filter(e=>!!e.reg?.hidden)];function _h(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 uh){const t=r.filter(t=>t.eid.startsWith(e+"."));if(t.length)return ph(t).map(e=>e.eid)}const o=r.filter(t=>function(e,t){if(!t.startsWith("binary_sensor."))return!1;const i=bc(e?.states?.[t]?.attributes?.device_class||e?.entities?.[t]?.device_class||e?.entities?.[t]?.original_device_class);return hc.has(i)||dc.has(i)||uc.has(i)||pc.has(i)||"moving"===i||_c.has(i)}(e,t.eid));if(o.length)return ph(o).map(e=>e.eid);const s=r.filter(e=>e.eid.startsWith("switch."));if(s.length){const t=ph(s),n=t.find(t=>Mc(e,t.eid));if(s.length>1&&n){const t=i.filter(t=>t.eid!==n.eid&&"config"!==t.reg?.entity_category&&null!=$c(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=ph(o.filter(i=>$c(e,i.eid)===t));if(i.length)return[i[0].eid,n.eid]}}return[(n||t[0]).eid]}const a=[];for(const e of Ee)a.push(...ph(r.filter(t=>t.eid.startsWith(e+"."))));return a.push(...ph(r.filter(e=>!Ee.includes(e.eid.split(".")[0])))),a.map(e=>e.eid)}function mh(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=>dh(e,t.eid));if(i)return i.eid}const o=_h(e,t);return o.find(bn)||o[0]}function fh(e,t,i=[]){return[...new Set(gh(e,t,i))].filter(e=>bn(e))}function gh(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 vh(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 yh(e){const t=e.marker?.binding?.startsWith("entity:")?e.marker.binding.slice(7):null,i=e.entities.filter(bn),n=e.primary&&bn(e.primary)?e.primary:null;return[...new Set([t,n,...i].filter(e=>!!e&&bn(e)))]}function bh(e){const t=yh(e),i=e.marker?.light_entity;return i&&t.includes(i)?i:t[0]||null}function wh(e,t){if(!1===t.marker?.is_light)return[];if(!0===t.marker?.is_light){return[{eid:bh(t),via:"forced"}]}const i=t.primary||_h(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 kh=new WeakMap,xh=new WeakMap;function $h(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 Sh(e){const t=$h(e),i=kh.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,gh(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(bn):t.controls.filter(bn)),n=bh(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 kh.set(e,a),a}function Mh(e){return Sh(e).incomingByMarker}function Rh(e,t){const i=fh(t.marker?.binding,t.controls??t.marker?.controls,t.entities),n=gh(t.marker?.binding,t.marker?.controls??t.controls,t.entities);return(null!=t.marker?.is_light||!i.length&&!n.some(e=>e.startsWith("marker:")))&&wh(e,t).length>0}function Th(e,t){return wh(e,t).some(e=>!!e.eid)}function Ch(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 Dh(e,t){const i=fh(t.marker?.binding,t.controls??t.marker?.controls,t.entities).map(e=>({eid:e,via:"controls"})),n=Rh(e,t)?wh(e,t):[];for(const e of n)e.eid&&i.some(t=>t.eid===e.eid)||i.push(e);return i}function zh(e,t,i,n){if(null!=i)return zh(e,t,null,n).filter(e=>vh(e.device,i));const r=$h(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=Ic(n),a=xh.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}=Sh(t),u=null==i?l:l.filter(e=>vh(e,i)),p=new Map,_=new Map;for(const t of u){const i=Dh(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(bn):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&&Hc(i.device.marker)&&(i.on=Nc(i.device.marker,n))}const f=new Map,g=e=>{const t=f.get(e.key);(!t||e.castsGlow&&!t.castsGlow)&&f.set(e.key,e)};for(const t of l){const n=h.get(t)||[],r=null==i||vh(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)g(e);continue}if(!bn(i)||!m.get(t)?.has(i))continue;const n=_.get(i);n?g(n):r&&g({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)||[])g(e)}const v=[...f.values()];return xh.set(t,{graphFingerprint:r,stateFingerprint:o,virtualLightFingerprint:s,registry:e?.entities,sources:v}),v}function Ah(e){const t=e.filter(e=>e.castsGlow);return t.find(e=>e.on)||t[0]||null}function Oh(e){return e.length?e.some(e=>e.on)?"on":"off":"none"}function Ph(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 Ri(i)}function Fh(e,t){for(const i of t){if(!dh(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 Eh(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 Ih(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 Hh(e,t){for(const i of t){if(!Ih(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 Nh(e,t){if(!t)return[];const i=[];for(const[t,n]of Object.entries(e.entities)){if(!t.startsWith("light.")||n.hidden||!th(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(!th(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 Lh(e,t,i,n,r){const o=Fe(t,i,r);if(o!==Pe)return o;const s=[];for(const t of n){const i=e.states[t]?.attributes?.device_class;i&&s.push(i)}return function(e){for(const t of e){const e=Oe[t];if(e)return e}return null}(s)??Pe}function qh(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 Wh(e,t,i){if(!t||!i||t===i)return[...e];const n=`marker:${t}`,r=`marker:${i}`;return e.map(e=>{const t=Array.isArray(e.controls)?e.controls.map(e=>e===n?r:e):e.controls,i="derived_marker_state"===e.value_badge?.source?.kind&&e.value_badge.source.ref===n?{...e.value_badge,source:{...e.value_badge.source,ref:r}}:e.value_badge;return t===e.controls&&i===e.value_badge?e:{...e,controls:t,value_badge:i}})}function jh(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 Bh(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 Vh(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 Uh(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 Gh(e,t,i,n,r){const o=fh(t.binding,t.controls,e.entities).filter(e=>!Uh(i,e,n)).filter(e=>"active"===sh(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 Kh(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 Yh(e){const t=e.hass,i=e.registry||Jc(t),n=ih(t,i),r=nh(t,i),{areaToSpace:o,markers:s,settings:a,excluded:l,showAll:c,firstSpaceId:h,loc:d,iconRules:u}=e,p=!1!==a.group_lights,_=Vh(s),m=Nh(n,p).filter(e=>!Uh(n,e.eid,_)),f=new Set(m.map(e=>e.area)),g=ah(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=lh(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=sh(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 _=ch(n,e.id,g[e.id]||[],y);if(_.partial&&!_.entityIds.length)continue;const m=_.entityIds,v=_.partial?{kind:"active",enabledEntityIds:m,allEntityIds:m}:s,$=hh(n,e,m),S=!a.filter_seeded;if(S&&!c){if(l.has($))continue;if("Group"===e.model)continue;if(/scene/i.test(e.model||""))continue;if(/bridge/i.test((e.model||"")+(e.name||"")))continue;if("myheat"===$&&e.via_device_id)continue}const M=(e.name_by_user||e.name||d("device.unnamed")).trim(),R=M+"|"+r;let T=Lh(n,M,e.model,m,u);if(m.some(e=>e.startsWith("lock."))&&(T="mdi:lock"),S&&!c&&p&&"mdi:lightbulb"===T&&f.has(r))continue;k[R]=(k[R]||0)+1;const C=k[R]>1?M+" "+k[R]:M,D={id:e.id,name:C,model:e.model||"",area:r,space:o[r],icon:T,entities:m,allEntities:v.allEntityIds,bindingStatus:v,bindingKind:"device",bindingRef:e.id,pdfs:[]};D.primary=mh(n,m,T),"mdi:thermometer"!==T&&"mdi:air-filter"!==T||(D.temp=Fh(n,m)),D.primary&&Ih(n,D.primary)&&(D.hum=Hh(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?sh(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}=Kh(e,s?.area_id,o,h),m="active"===t.kind?t.enabledEntityIds:[];let f=s?Lh(n,s.name_by_user||s.name||"",s.model,m,u):"mdi:help-circle";m.some(e=>e.startsWith("lock."))&&(f="mdi:lock");const g={id:e.id,name:s?.name_by_user||s?.name||d("device.fallback"),model:s?.model||"",area:a,space:p,icon:f,entities:m,allEntities:t.allEntityIds.length?t.allEntityIds:s&&v[s.id]||[],bindingStatus:t,bindingKind:"device",bindingRef:l};g.primary=mh(n,m,f),"mdi:thermometer"!==f&&"mdi:air-filter"!==f||(g.temp=Fh(n,m)),g.primary&&Ih(n,g.primary)&&(g.hum=Hh(n,m)),Gh(g,e,r,_,i),x.push(g)}else if("entity"===s){if(Uh(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}=Kh(e,a,o,h),m=n.states[l],f=s?.name||m?.attributes?.friendly_name||l;let g=Lh(n,f,"",[l],u);l.startsWith("lock.")&&(g="mdi:lock");const v={id:e.id,name:f,model:"",area:d,space:p,icon:g,entities:"active"===t.kind?[l]:[],allEntities:[l],bindingStatus:t,primary:"active"===t.kind?l:void 0,bindingKind:"entity",bindingRef:l};"mdi:thermometer"!==g&&"mdi:air-filter"!==g||!v.entities.length||(v.temp=Fh(n,v.entities)),v.entities.length&&Ih(n,l)&&(v.hum=Hh(n,v.entities)),Gh(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};Gh(s,e,r,_,i),x.push(s)}}return x}function Zh(e){const{marker:t,siblingMarkers:i=[],...n}=e;return Yh({...n,markers:[...i.filter(e=>e.id!==t.id),t]}).find(e=>e.id===t.id)||null}function Xh(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=Vh(i);return"device"===r?s.devices.has(o):"entity"===r&&Uh(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?Fh(e,t):Hh(e,t)}return null}const Jh=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 Qh(e,t){return t.area?t.area:e&&t.id?`@room/${encodeURIComponent(e)}/${encodeURIComponent(t.id)}`:null}function ed(e){return null===e.area&&e.space&&e.room_id?Qh(e.space,{id:e.room_id,area:null}):e.area||null}function td(e,t,i){const n=new Map;if(!e?.entities)return n;const r=Vh(i),o=new Set,s=new Map,a=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&&o.add(n);const r=ed(e);r&&("entity"!==i||s.has(n)?"device"!==i||a.has(n)||a.set(n,r):s.set(n,r))}const l=new Map;for(const[t,i]of Object.entries(e.entities)){if(i.device_id&&r.devices.has(i.device_id)&&!r.liveEntities.has(t)||!i.device_id&&r.entities.has(t)&&!r.liveEntities.has(t))continue;const n=i.device_id?e.devices?.[i.device_id]:null;if(!th(i)||n&&!th(n))continue;const c=s.get(t)||(i.device_id?a.get(i.device_id):null)||i.area_id||n?.area_id||null;if(!c)continue;if(i.entity_category)continue;if(!(o.size>0&&t.startsWith("climate.")&&(o.has(t)||i.device_id&&o.has(i.device_id)))){if(Te.has(i.platform))continue;if(Jh.test(t))continue}let h=l.get(c);h||(h=new Map,l.set(c,h));const d=i.device_id||t;let u=h.get(d);if(!u){const r=e.states?.[t];u={name:(n?n.name_by_user||n.name:i.name||r?.attributes?.friendly_name||t)||t,model:n?.model,ents:[]},h.set(d,u)}u.ents.push(t)}for(const[i,r]of l){const s=[],a=[];for(const[i,n]of r){const r=Lh(e,n.name,n.model,n.ents,t),l="mdi:thermometer"===r||"mdi:air-filter"===r;if(l){const t=Fh(e,n.ents);null!=t&&s.push(t)}if(o.size>0&&(o.has(i)||n.ents.some(e=>o.has(e)))){const t=Eh(e,n.ents);null!=t&&s.push(t)}if(l||"mdi:water-percent"===r){const t=Hh(e,n.ents);null!=t&&a.push(t)}}(s.length||a.length)&&n.set(i,{temp:s.length?Math.round(s.reduce((e,t)=>e+t,0)/s.length*10)/10:null,hum:a.length?Math.round(a.reduce((e,t)=>e+t,0)/a.length):null})}return n}function id(e,t,i){const n=[];for(const r of t){if(r.area!==i||r.virtual)continue;const t=Ph(e,r.entities);null!=t&&n.push(t)}return Ri(n)}const nd={offStates:["off"],unknownUsesToggle:!0},rd={light:nd,switch:nd,fan:nd,humidifier:nd,input_boolean:nd,automation:nd,remote:nd,group:nd,climate:{...nd,featureMasks:{turn_on:256,turn_off:128,toggle:384}},media_player:{...nd,featureMasks:{turn_on:128,turn_off:256,toggle:384}},siren:{...nd,featureMasks:{turn_on:1,turn_off:2,toggle:3}},vacuum:{...nd,featureMasks:{turn_on:1,turn_off:2,toggle:3}},water_heater:{...nd,featureMasks:{turn_on:8,turn_off:8,toggle:8}},camera:{...nd,featureMasks:{turn_on:1,turn_off:1,toggle:1}}};function od(e){return e.slice(0,e.indexOf("."))}function sd(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 ad(e,t,i){return sd(e,t,i)?{domain:t,service:i}:sd(e,"homeassistant",i)?{domain:"homeassistant",service:i}:null}function ld(e,t){return e?.entities?.[t]||null}function cd(e,t,i){const n=e?.states?.[i],r=ld(t,i);return n?.attributes?.friendly_name||r?.name||r?.original_name||i}function hd(e,t){const i=ld(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 dd(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 ud(e,t,i){const n=od(i);if("lock"===n||"alarm_control_panel"===n)return!0;if("cover"!==n)return!1;const r=e?.states?.[i],o=ld(t,i),s=String(r?.attributes?.device_class||o?.device_class||o?.original_device_class||"");return Ei.has(s)}function pd(e,t,i,n,r){return{ref:i,entityId:n,name:n?cd(e,t,n):null,reason:r}}function _d(e,t,i,n,r,o=null){return{target:null,skipped:pd(e,t,i,n,r),semantics:o,nextEffect:null,command:null}}function md(e,t,i,n,r=i){const o=od(i);if("cover"!==o&&"valve"!==o)return function(e,t,i,n,r=i){const o=od(i),s=e?.states?.[i];if(hd(t,i))return _d(e,t,r,i,"ha-disabled","power");if(ud(e,t,i))return _d(e,t,r,i,"secure");if(!s)return _d(e,t,r,i,"missing","power");if("unavailable"===s.state)return _d(e,t,r,i,"unavailable","power");const a=rd[o];if(!a)return _d(e,t,r,i,"unsupported");let l,c;if("unknown"===s.state||""===s.state){if(!a.unknownUsesToggle)return _d(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&&!dd(s,h))return _d(e,t,r,i,"unsupported","power");const d=ad(e,o,c);return d?{target:{entityId:i,name:cd(e,t,i),state:String(s.state||""),via:n},skipped:null,semantics:"power",nextEffect:l,command:{...d,data:{entity_id:i}}}:_d(e,t,r,i,"unsupported","power")}(e,t,i,n,r);if(hd(t,i))return _d(e,t,r,i,"ha-disabled",o);if(ud(e,t,i))return _d(e,t,r,i,"secure",o);const s=e?.states?.[i];if(!s)return _d(e,t,r,i,"missing",o);if("unavailable"===s.state)return _d(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&&dd(i,r.feature)&&sd(e,t,r.service)?r:dd(i,3)&&sd(e,t,"toggle")?{service:"toggle",effect:"toggle"}:null}(e,o,s);if(!a)return _d(e,t,r,i,"unsupported",o);return{target:{entityId:i,name:cd(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 fd(e){return"entity"===e.bindingKind?e.bindingRef&&bn(e.bindingRef)?[e.bindingRef]:[]:"virtual"===e.bindingKind?[]:yh(e)}function gd(e){const t=e.marker?.toggle_entity;return t&&fd(e).includes(t)?t:null}function vd(e,t,i){const n=function(e,t){if("entity"===e.bindingKind&&e.bindingRef){const t=e.marker?.light_entity?bh(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&&bn(e.primary)?bh(e):null;return[...new Set([n,..._h(t,i)].filter(e=>!!e))]}(i,t);if(!n.length)return null;const r="entity"===i.bindingKind?"binding":"device-role";if("binding"===r)return md(e,t,n[0],r);let o=null,s=null;for(const i of n){const n=md(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 yd(e){const t=e.skipped?.reason;return"missing"===t?"unavailable":t||"unsupported"}function bd(e,t){return{origin:e,kind:"none",semantics:null,targets:[],skippedTargets:[],noneReason:t,nextEffect:null,command:null}}function wd(e,t){return"cover"===e||"toggle"===e?"toggle":"more-info"===e||"run"===e||"info"===e?e:(null==e||""===e)&&"light"===t?"toggle":"info"}function kd(e,t){return{origin:e,kind:"single",semantics:t.semantics,targets:t.target?[t.target]:[],skippedTargets:t.skipped?[t.skipped]:[],noneReason:t.command?null:yd(t),nextEffect:t.nextEffect,command:t.command}}function xd(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=md(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=ad(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=>pd(e,t,i.entityId,i.entityId,"unsupported"))],noneReason:"unsupported",nextEffect:null,command:null}}function $d(e){return String(e.marker?.id||e.id||"")}function Sd(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&&Hc(o)){const t=String(o?.id||i.id||""),n=Mh(e.devices).get(t);if(n)return function(e,t){const i=e.registryHass||e.hass;return xd(e.hass,i,t.driverEids.map(e=>({entityId:e,via:"control-marker-driver",ref:`marker:${t.markerId}`})))}(e,n);const s=Nc(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(gh(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=gh(n.marker?.binding,n.marker?.controls??n.controls,n.entities),a=e.lightSources||zh(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=Mh(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:")){bn(e)?d.push({entityId:e,via:"control-entity",ref:e}):u.push(pd(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?cd(i,o,n):null),reason:"ha-disabled"})}else u.push(pd(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=$d(n),_=c.get(a)?.controllers.find(e=>$d(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(pd(i,o,e,null,s?"missing":"unsupported"))}return xd(i,o,d,u)}(e,gd(i))}if("legacy-cover"===r){const e=i.entities.find(e=>e.startsWith("cover."))||i.allEntities?.find(e=>e.startsWith("cover."));return e?kd(r,md(t,n,e,"device-role")):bd(r,"no-actionable-entity")}const s=gd(i),a=s?md(t,n,s,"entity"===i.bindingKind?"binding":"device-role"):vd(t,n,i);return a?kd(r,a):bd(r,i.virtual||"virtual"===i.bindingKind?"no-actionable-entity":"no-binding")}function Md(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 Rd(e){return e?e.operation?e.operation:e.command?{kind:"ha-service",command:e.command}:null:null}const Td=new Set(["missing","ha-disabled","unavailable"]);function Cd(e,t){const i=Rd(e),n=Rd(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=Md(e),n=Md(t);return i.length===n.length&&i.every((e,t)=>e===n[t])}(i.command,n.command))}function Dd(e,t){const i=e.targets[0]||e.skippedTargets[0],n=[];return"group"===e.kind?e.targets.length&&n.push(t.group(e.targets)):i&&n.push(t.single(i)),e.nextEffect&&e.targets.length&&n.push("group"===e.kind?t.groupCurrentNext(e.targets,e.nextEffect):t.currentNext(e.targets[0],e.nextEffect)),e.skippedTargets.length&&n.push(t.skipped(e.skippedTargets)),!e.command&&e.noneReason&&n.push(t.none(e.noneReason)),n}const zd=e=>!!e&&e.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]);function Ad(e,t=5,i=5){return yo(e.cm,t,i)/2}function Od(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(!zd(a.a)||!zd(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:yo(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 Pd(e,t,i=1,n=5,r=5){return Od(e,t,i,n,r,0)}function Fd(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 Pd(e,t,i,n,r);const a=Od(e,t,i,n,r,Ad(s,n,r));return"does-not-fit"===a.reason?{resolved:null,reason:"does-not-fit-jamb"}:a}function Ed(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 Id(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 Hd(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 Nd(e,t,i){return e.flatMap(e=>!zd(e.a)||!zd(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:yo(e.cm,t,i)/2,partitionHost:{kind:"partition",id:e.id}}])}function Ld(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 qd(e,t,i=1e-9){const n=e.length/(2*e.axis.length),r=e.t-n,o=e.t+n;return t.some(t=>{if(t.host.id!==e.host.id||t.opening.id===e.opening.id)return!1;const n=t.length/(2*t.axis.length);return Math.max(r,t.t-n)[]);for(let i=0;i=1-1e-9||u<=1e-9||u>=1-1e-9||(t[i].push(d),t[s].push(u))}}const i=[];for(let n=0;ne-t),1];for(let e=1;e{const i=t[2]-t[0],n=t[3]-t[1],r=i*i+n*n;if(!(r>0))return Math.hypot(e[0]-t[0],e[1]-t[1]);const o=Math.max(0,Math.min(1,((e[0]-t[0])*i+(e[1]-t[1])*n)/r));return Math.hypot(e[0]-(t[0]+o*i),e[1]-(t[1]+o*n))},Gd=(e,t,i,n)=>{const r=n[2]-n[0],o=n[3]-n[1],s=t*o-i*r;if(Math.abs(s)<1e-12)return 1/0;const a=n[0]-e[0],l=n[1]-e[1],c=(a*o-l*r)/s;if(!(c>1e-9))return 1/0;const h=(a*i-l*t)/s;return h<-1e-9||h>1+1e-9?1/0:c};function Kd(e,t,i,n=96){if(!(t>0&&Number.isFinite(e[0])&&Number.isFinite(e[1])))return[];const r=[];for(const n of i){if(!n||n.length<4)continue;if(![n[0],n[1],n[2],n[3]].every(Number.isFinite))continue;const i=Ud(e,n);if(i<1e-7)return[];i>t||r.push(n)}const o=[],s=Math.max(12,Math.round(n));for(let e=0;ee-t);const l=[];let c=Number.NEGATIVE_INFINITY;for(const i of o){if(i-c<1e-9)continue;c=i;const n=Math.cos(i),o=Math.sin(i);let s=t;for(const t of r){const i=Gd(e,n,o,t);i=3?l:[]}const Yd=[o` + :host { + --hp-bg: var(--card-background-color, #16212e); + --hp-line: var(--divider-color, #2b3d4f); + --hp-txt: var(--primary-text-color, #e6edf3); + --hp-muted: var(--secondary-text-color, #8aa0b3); + --hp-accent: var(--primary-color, #3ea6ff); + --hp-on: #ffd45c; + --hp-open: #ff9f43; + /* design tokens (UI chrome only). The icon/plan scale math stays on + --icon-size/--dev-size cqw units and never uses these. */ + /* spacing scale, fact-based; stray 3/5/7/9/13/14px values are unified + onto the nearest step (max +-2px, the whole point of the pass) */ + --sp-1: 2px; + --sp-2: 4px; + --sp-3: 6px; + --sp-4: 8px; + --sp-5: 12px; + --sp-6: 16px; + /* px radii of dialogs/buttons/plates (the 22% badge radius is scale math) */ + --rad-s: 6px; + --rad-m: 8px; + --rad-l: 12px; + /* font tiers: fine print+labels / body+buttons / title */ + --fs-s: 12px; + --fs-m: 13px; + --fs-l: 15px; + /* elevation: badge / floating panel (menu, tip, toast) / dialog */ + --shadow-1: 0 1px 3px rgba(0, 0, 0, 0.45); + --shadow-2: 0 6px 22px rgba(0, 0, 0, 0.45); + --shadow-3: 0 8px 30px rgba(0, 0, 0, 0.5); + } + ha-card { + overflow: visible; /* overflow:hidden breaks position:sticky on the header */ + } + .empty { + padding: 40px 24px; + color: var(--hp-txt); + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + gap: var(--sp-4); + } + .empty .big { + --mdc-icon-size: 56px; + color: var(--hp-accent); + opacity: 0.7; + } + .empty .muted { + color: var(--hp-muted); + font-size: var(--fs-m); + margin: 0; + } + .empty .btn { + margin-top: var(--sp-4); + } + @keyframes fixedfloor-spin { + to { transform: rotate(360deg); } + } + .spacer { + flex: 1; + } + .bootveil { + position: absolute; + inset: 0; + z-index: 40; + display: flex; + align-items: center; + justify-content: center; + background: var(--hp-bg, #16212e); + opacity: 1; + transition: opacity 0.15s ease; + pointer-events: none; + } + .bootveil.off { + opacity: 0; + } + .bootveil .boothouse { + position: static; /* the main .zoomwrap SVG is pinned to inset:0 — not this icon */ + width: 56px; + height: 56px; + fill: var(--hp-accent); + opacity: 0.85; + animation: hp-boot-pulse 1.3s ease-in-out infinite; + } + @keyframes hp-boot-pulse { + 0%, 100% { opacity: 0.3; transform: scale(0.94); } + 50% { opacity: 0.9; transform: scale(1); } + } + @media (prefers-reduced-motion: reduce) { + .bootveil .boothouse { + animation: none; + opacity: 0.7; + } + } + @keyframes hp-pulse-short { + 0% { transform: scale(1); opacity: 0.55; } + 70% { opacity: 0.22; } + 100% { transform: scale(var(--ripple-scale, 1.5)); opacity: 0; } + } + /* Alternate identity: a rapid retrigger restarts the browser timeline. */ + @keyframes hp-pulse-short-b { + 0% { transform: scale(1); opacity: 0.55; } + 70% { opacity: 0.22; } + 100% { transform: scale(var(--ripple-scale, 1.5)); opacity: 0; } + } + @keyframes hp-pulse-continuous { + 0% { transform: scale(1); opacity: 0.55; } + 65% { opacity: 0.18; } + 100% { transform: scale(var(--ripple-scale, 1.5)); opacity: 0; } + } + @keyframes hp-pulse-alarm { + 0% { transform: scale(1); opacity: 0.72; } + 100% { transform: scale(1.5); opacity: 0; } + } + /* Space changes keep their direction, but travel only a few percent: the + motion explains what changed without making the whole plan fly around. */ + @keyframes hp-slide-left { + 0% { transform: translateX(4%); opacity: 0.72; } + 100% { transform: translateX(0); opacity: 1; } + } + @keyframes hp-slide-right { + 0% { transform: translateX(-4%); opacity: 0.72; } + 100% { transform: translateX(0); opacity: 1; } + } + @keyframes hp-sunfade-in { + from { opacity: 0; } + to { opacity: 1; } + } + @keyframes hp-sunfade-out { + from { opacity: 1; } + to { opacity: 0; } + } + .sr-only { + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; + } + .toast { + position: fixed; + pointer-events: none; + left: 50%; + bottom: 22px; + transform: translateX(-50%); + background: var(--hp-bg); + border: 1px solid var(--hp-accent); + color: var(--hp-txt); + padding: var(--sp-4) var(--sp-6); + border-radius: var(--rad-l); + font-size: var(--fs-m); + box-shadow: var(--shadow-2); + z-index: 120; + max-width: 90vw; + } +`,o` + .fixedfloor-loading { + animation: fixedfloor-spin 1.1s linear infinite; + } + .fixedfloor-error p { + max-width: 42rem; + margin: 0; + overflow-wrap: anywhere; + } + @media (prefers-reduced-motion: reduce) { + .fixedfloor-loading { animation: none; } + } + .stage.noplan { + background: #ffffff; + } + /* Editors always keep the white drawing sheet — even when a backdrop + image is loaded. Without this, a picture plan painted the theme card + colour under the grid (owner 2026-08-05). View keeps the historical + theme / .noplan split. */ + .stage.mode-plan, + .stage.mode-devices, + .stage.mode-decor { + background: #ffffff; + } + .stage { + position: relative; + width: 100%; + container-type: inline-size; + overflow: hidden; + touch-action: none; /* custom pinch/pan gestures */ + background: var(--ha-card-background, var(--card-background-color, #111)); + } + .zoomwrap { + position: absolute; + inset: 0; + z-index: 1; + } + .stage.mode-transition, + .stage.mode-transition .zoomwrap { + transition: none !important; + } + .stage.mode-transition .hp-view-only-layer, + .stage.mode-transition .hp-editor-only-layer { + pointer-events: none; + will-change: opacity; + } + .stage.mode-transition .hp-paper { + fill: var(--hp-mode-paper) !important; + } + /* Four-phase environment (#146): constant layers cross-fade because CSS + gradients themselves are not reliably interpolated. Everything stays + behind the plan; the plan tree is never dimmed, tinted or faded. */ + .hp-day-cycle-env { + position: absolute; + inset: 0; + z-index: 0; + overflow: hidden; + pointer-events: none; + isolation: isolate; + } + .hp-day-cycle-bg { + position: absolute; + inset: 0; + opacity: 0; + overflow: hidden; + transition: opacity 1100ms cubic-bezier(.22, .61, .36, 1); + } + .hp-day-cycle-bg.active { opacity: 1; } + .hp-day-cycle-sun { + position: absolute; + left: var(--hp-day-cycle-sun-x); + top: var(--hp-day-cycle-sun-y); + width: clamp(140px, 25cqw, 250px); + height: clamp(140px, 25cqw, 250px); + transform: translate(-50%, -50%); + border-radius: 50%; + filter: blur(10px); + opacity: var(--hp-day-cycle-sun-opacity); + transition: + left 1100ms cubic-bezier(.22, .61, .36, 1), + top 1100ms cubic-bezier(.22, .61, .36, 1), + opacity 1100ms cubic-bezier(.22, .61, .36, 1); + } + .stage.mode-transition .hp-day-cycle-env { transition: none; } + .stage.daycycle .hp-paperg, + .hp-static-stage.daycycle .hp-paperg { + filter: + drop-shadow(0 0 1px var(--hp-day-cycle-outline-near)) + drop-shadow(0 0 5px var(--hp-day-cycle-outline-mid)) + drop-shadow(0 0 10px var(--hp-day-cycle-outline-far)); + transition: filter 1100ms cubic-bezier(.22, .61, .36, 1); + } + @media (prefers-reduced-motion: reduce) { + .hp-day-cycle-bg, + .hp-day-cycle-sun, + .stage.daycycle .hp-paperg, + .hp-static-stage.daycycle .hp-paperg { + transition: none; + } + } + .sunlayer { + pointer-events: none; + } + .compass { + width: 120px; + height: 120px; + flex: none; + touch-action: none; + cursor: grab; + user-select: none; + } + .compass:active { + cursor: grabbing; + } + .compass .cring { + fill: rgba(255, 255, 255, 0.04); + stroke: var(--divider-color, #444); + stroke-width: 2; + } + .compass .ctick { + stroke: var(--secondary-text-color, #9aa4ad); + stroke-width: 2; + } + .compass .ctick.minor { + stroke-width: 1; + opacity: 0.6; + } + .compass .cneedle line { + stroke: var(--primary-color, #3ea6ff); + stroke-width: 2.5; + stroke-linecap: round; + } + .compass .cneedle path { + fill: var(--primary-color, #3ea6ff); + } + .compass .cneedle text { + fill: var(--text-primary-color, #fff); + font-size: 11px; + font-weight: 700; + } + .compass .cdeg { + fill: var(--secondary-text-color, #9aa4ad); + font-size: 13px; + } + .compass.unset .cneedle { + opacity: 0.35; + } + /* HP-1552: first-open boot veil — the plan hides until the stage height settles */ + .stage.hpboot .zoomwrap, + .stage.hpboot .zoombadge { + visibility: hidden; + } + /* AUD-1552-02: post-veil grace — HA chrome landing after the cap moves + the stage height smoothly; the viewport ResizeObserver refits the plan + along the transition, so a late panel glides instead of jumping. */ + .stage.hpsettle { + transition: height 0.25s ease; + } + @media (prefers-reduced-motion: reduce) { + .stage.hpsettle { + transition: none; + } + } + .zoomctl { + display: inline-flex; + gap: var(--sp-1); + background: rgba(127, 127, 127, 0.12); + border-radius: var(--rad-m); + padding: var(--sp-1); + } + .zoomctl .zb { + border: none; + padding: var(--sp-3) var(--sp-4); + } + .zoomctl .zb[disabled] { + opacity: 0.4; + pointer-events: none; + } + .projection-toggle { + min-width: 44px; + min-height: 44px; + justify-content: center; + padding: var(--sp-3); + } + /* docs/CANVAS.md §5: the plane has no edges, so you can pan until nothing + is on screen. One pointer home, one click back. */ + .homearrow { + position: absolute; + z-index: 12; + transform: translate(-50%, -50%); + width: 40px; + height: 40px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + background: var(--card-background-color, var(--hp-bg)); + color: var(--hp-accent); + border: 1px solid var(--hp-accent); + opacity: 0.9; + padding: 0; + } + .homearrow ha-icon { + --mdc-icon-size: 22px; + line-height: 1; + } + .zoombadge { + position: absolute; + z-index: 12; + left: var(--sp-4); + bottom: var(--sp-4); + background: var(--card-background-color, var(--hp-bg)); + opacity: 0.92; + color: var(--hp-txt); + border: 1px solid var(--hp-accent); + border-radius: var(--rad-m); + padding: var(--sp-1) var(--sp-4); + font-size: var(--fs-s); + font-weight: 600; + pointer-events: none; + } + /* Only the plan canvas owns the whole zoom wrapper. Context trays now live + inside .stage as well, and may contain small SVG previews (furniture in + particular); the old descendant-wide stage-SVG selector stretched every + preview over the tray and stacked them into one blocking artefact. The + vacuum trail/fit overlays have their own explicit geometry below. */ + .zoomwrap > svg { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + display: block; + } + .plan-svg { z-index: 1; } + .iso-underlay-svg { z-index: 0; overflow: visible; } + .iso-shadows-svg { z-index: 3; overflow: visible; } + .iso-walls-svg { + z-index: 4; + overflow: visible; + } + .iso-underlay-svg, + .iso-shadows-svg, + .iso-walls-svg, + .iso-underlay, + .iso-shadows, + .iso-walls, + .iso-openings { + pointer-events: none; + } + .iso-side-hi { stop-color: #b9bdbe; } + .iso-side-lo { stop-color: #969c9f; } + .iso-top-hi { stop-color: #fafaf7; } + .iso-top-lo { stop-color: #e2e4e2; } + .iso-wall-side { + fill: url(#hp-iso-wall-side) #a8acae; + stroke: #92989b; + stroke-width: 0.7; + vector-effect: non-scaling-stroke; + } + .iso-wall-top { + fill: url(#hp-iso-wall-top) #f3f3f1; + stroke: #d7d9d8; + stroke-width: 0.8; + vector-effect: non-scaling-stroke; + } + .iso-floor-side { + fill: #858b8d; + stroke: #71787b; + stroke-width: 0.7; + vector-effect: non-scaling-stroke; + } + .iso-opening-panel { + fill: #d7d9d7; + fill-opacity: 0.96; + stroke: #7f878b; + stroke-width: 0.9; + vector-effect: non-scaling-stroke; + } + .iso-opening-panel.iso-window { + fill: #dfeff4; + fill-opacity: 0.72; + stroke: #8aa7b1; + } + .iso-ambient-shadow { + fill: rgba(15, 21, 25, 0.22); + filter: url(#hp-iso-ambient-shadow); + } + .iso-contact-shadow { + fill: none; + stroke: rgba(22, 28, 31, 0.25); + stroke-width: 3; + filter: url(#hp-iso-contact-shadow); + vector-effect: non-scaling-stroke; + } + .iso-leaf-shadow { + fill: none; + stroke: rgba(18, 23, 27, 0.24); + stroke-width: 4; + filter: url(#hp-iso-leaf-shadow); + vector-effect: non-scaling-stroke; + } + @media (prefers-color-scheme: dark) { + .iso-side-hi { stop-color: #4c555a; } + .iso-side-lo { stop-color: #343c40; } + .iso-top-hi { stop-color: #687176; } + .iso-top-lo { stop-color: #50585d; } + .iso-wall-side { stroke: #30373b; } + .iso-wall-top { stroke: #7b858a; } + .iso-floor-side { fill: #2d3438; stroke: #20272a; } + .iso-opening-panel { fill: #626b70; stroke: #899399; } + .iso-opening-panel.iso-window { fill: #75919b; stroke: #abc6ce; } + .iso-ambient-shadow { fill: rgba(0, 0, 0, 0.34); } + .iso-contact-shadow, .iso-leaf-shadow { stroke: rgba(0, 0, 0, 0.38); } + } + @media (forced-colors: active) { + .iso-wall-side, .iso-wall-top, .iso-floor-side, .iso-opening-panel { + fill: Canvas; + stroke: CanvasText; + forced-color-adjust: auto; + } + .iso-ambient-shadow, .iso-contact-shadow, .iso-leaf-shadow { display: none; } + } + @supports not (filter: blur(1px)) { + .iso-ambient-shadow, .iso-contact-shadow, .iso-leaf-shadow { display: none; } + } + /* Opaque plan paper (owner 2026-08-03): the scene bg_color / daynight sky + shows ONLY around the plan, never through it. The colour is the + pre-bg_color canvas — the theme card background under an image plan, + plain white for a hand-drawn one (.stage.noplan). On drawn plans the + paper is per-room shapes following the room contours — fill only, + never a stroke, so the paper cannot poke past a wall. Night dimming + comes from the .zoomwrap brightness filter, never from alpha + (docs/SUN.md). */ + .hp-paper { + fill: var(--ha-card-background, var(--card-background-color, #111)); + stroke: none; + } + .stage.noplan .hp-paper, + .stage.mode-plan .hp-paper, + .stage.mode-devices .hp-paper, + .stage.mode-decor .hp-paper { + fill: #ffffff; + } + /* Owner 2026-08-04: «углы границ комнат всё ещё с зубцами». A miter join + on a 30-45° corner shoots a spike far past the wall (and flips to an + ugly bevel once past the miter limit) — the same defect the decor lines + had before they got round caps. Every room border, in EVERY renderer + that reuses these styles (plan view, plan editor, static space-card), + joins its walls with a ROUND join instead: the corner reads as the + stroke's own radius, never as a tooth. The linecap matters only for the + open outlines below, but it costs nothing to state it here. */ + .room { + transition: 0.12s; + cursor: default; /* v1.40.1: rooms are not clickable — the label's link icon is */ + stroke-linejoin: round; + stroke-linecap: round; + } + .room.overlay { + fill: transparent; + stroke: transparent; + stroke-width: calc(2px * var(--hp-cell-visual-scale, 1)); + } + :host([data-pointer-hover]) .stage.mode-view .room.overlay:not(.styled):hover { + stroke: var(--hp-accent); + stroke-opacity: 1; + } + .room.yard { + fill: rgba(75, 140, 90, 0.14); + stroke: #4b8c5a; + stroke-width: calc(2px * var(--hp-cell-visual-scale, 1)); + } + :host([data-pointer-hover]) .stage.mode-view .room.yard:not(.styled):hover { + stroke: var(--hp-accent); + stroke-opacity: 1; + } + .room.styled { + stroke: var(--room-stroke, transparent); + stroke-opacity: var(--room-stroke-op, 0); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + fill: var(--room-fill, transparent); + fill-opacity: var(--room-fill-op, 0); + } + .glow-base-layer, + .glow-base-tunnels, + .glow-pools-frame, + .glow-pools, + .glow-spot { + pointer-events: none; + } + /* The parent isolates all source spots from the room data fill, Glow base, + paper and backdrop. A spot is one circle clipped to the floor its lamp + can see, so the whole spot screen-blends as a single primitive — there is + no mask left to be dropped on a promoted layer. Per-stop alpha already + contains the shared 0.7 ceiling; the spot opacity below only animates + between 0 and 1 and is never another persistent alpha ceiling. */ + .glow-pools-frame, + .glow-pools, + .glow-spot { + isolation: isolate; + } + .glow-pools.blend-screen .glow-spot { + mix-blend-mode: screen; + } + .glow-spot { + opacity: 1; + transition: opacity 500ms ease; + } + .glow-spot.is-entering, + .glow-spot.is-leaving { + opacity: 0; + } + @media (prefers-reduced-motion: reduce) { + .glow-spot { + transition: none; + } + } + /* The explicit late room-hover layer owns the wash and halo. Keeping CSS + filters off room paths prevents Chromium from recompositing the sibling + screen-blended Glow layer for one bright frame on every hover. */ + :host([data-pointer-hover]) .stage.mode-view .room.styled:hover { + stroke: var(--hp-accent); + stroke-opacity: 1; + } + /* doors, windows & gates */ + .op-leaf { + transition: transform 0.6s ease; + } + .op-arc { + stroke-width: calc(1.5px * var(--hp-cell-visual-scale, 1)); + transition: stroke-dashoffset 0.6s ease; + } + /* hover affordance: a rounded outline hugging the wall strip + a grab cursor */ + .op-outline { + fill: none; + stroke: var(--hp-accent); + stroke-width: calc(1.5px * var(--hp-cell-visual-scale, 1)); + opacity: 0; + transition: opacity 0.15s; + pointer-events: none; + } + :host([data-pointer-hover]) .stage.markup g.opening:hover .op-outline { + opacity: 0.9; + } + /* openings are pure status graphics outside Plan mode: no cursor, no hover, + no hit target — View must not interact with them at all */ + .op-hit { + fill: transparent; + pointer-events: none; + cursor: default; + } + .stage.markup .op-hit { + pointer-events: auto; + cursor: grab; + touch-action: none; /* drags, not scrolls, on touch */ + } + .stage.markup .op-hit:active { + cursor: grabbing; + } + .stage.markup .opening.orphan { + pointer-events: auto; + cursor: pointer; + color: var(--error-color, #db4437); + } + .stage.markup .opening.orphan circle { + fill: var(--hp-bg); + stroke: currentColor; + stroke-width: calc(2px * var(--hp-cell-visual-scale, 1)); + } + .stage.markup .opening.orphan text { + fill: currentColor; + font-weight: 800; + font-size: calc(12px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + /* HP-1550-04: in the resize tool the wall handles own the hit test — the + transparent .op-hit of a door at the midpoint of a wall used to sit ON + TOP of the handle and made that wall ungrabbable for both rooms. + Openings are not editable in this tool (they ride along with the wall), + so their hit area goes fully inert; every other Plan tool is untouched. */ + .stage.markup.tool-resize .op-hit { + pointer-events: none; + cursor: default; + } + .stage.mode-view .oplock { + pointer-events: auto; + cursor: pointer; + } + @media (prefers-reduced-motion: reduce) { + .op-leaf, .op-arc { transition: none; } + } + .roomlabel { + pointer-events: none; /* draggable only in plan mode (rule below) */ + position: absolute; + transform: translate(-50%, -50%); + font-size: calc(var(--rl-icon-size, var(--icon-size, 2.5cqw)) * 0.5 * var(--rl-scale, 1) * var(--rl-font, 1) * var(--rl-space, 1)); + font-weight: 700; + letter-spacing: 0.04em; + white-space: nowrap; + cursor: grab; + user-select: none; + z-index: 1; + display: flex; + flex-direction: column; + align-items: center; + gap: 0.15em; + text-align: center; + } + .rlname { + display: inline-flex; + align-items: center; + gap: 0.25em; + font-size: calc(1em * var(--rl-name, 1)); + } + .zoomwrap.slide-left { animation: hp-slide-left 0.18s cubic-bezier(0.2, 0.7, 0.2, 1); } + .zoomwrap.slide-right { animation: hp-slide-right 0.18s cubic-bezier(0.2, 0.7, 0.2, 1); } + @media (prefers-reduced-motion: reduce) { + .zoomwrap.slide-left, + .zoomwrap.slide-right { animation: none; } + } + /* The name is the anchor: the label box is centred on the room point, so + anything that takes part in its layout SHIFTS THE NAME. The gear button + and the metrics hang below as absolutes — the name renders in exactly + the same place in view mode and in the plan editor (owner's request), + and the button sits at the very bottom of the card. */ + /* Standalone, centred on the room, sized from the device icon: icon-size + already rescales with the view, so the button zooms WITH the plan + instead of keeping a constant screen size (owner's spec). */ + .rlgearbtn { + --gear-h: calc(var(--icon-size, 2.5cqw) * 0.77); /* owner: half the previous size */ + position: absolute; + /* dead-centred on the room, both axes (owner's spec) */ + transform: translate(-50%, -50%); + display: inline-flex; + align-items: center; + gap: 0.35em; + height: var(--gear-h); + padding: 0 calc(var(--gear-h) * 0.38); + border: 0; + border-radius: 999px; + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + font: inherit; + font-size: calc(var(--gear-h) * 0.42); + font-weight: 600; + line-height: 1; + white-space: nowrap; + cursor: pointer; + pointer-events: auto; + opacity: 0.92; + box-shadow: var(--shadow-1); + z-index: 2; + } + .rlgearbtn { transition: opacity 0.15s, filter 0.15s; } + :host([data-pointer-hover]) .rlgearbtn:hover { opacity: 1; filter: brightness(1.18); } + .rlgearbtn ha-icon { --mdc-icon-size: calc(var(--gear-h) * 0.55); display: inline-flex; } + .rlgear { + --mdc-icon-size: 0.9em; + display: inline-flex; + margin-right: 0.2em; + opacity: 0.6; + cursor: pointer; + pointer-events: auto; + } + :host([data-pointer-hover]) .rlgear:hover { opacity: 1; } + .rlgo { + --mdc-icon-size: 0.85em; + display: inline-flex; + opacity: 0.55; + } + .stage.mode-view .rlgo { + pointer-events: auto; + cursor: pointer; + } + :host([data-pointer-hover]) .stage.mode-view .rlgo:hover { opacity: 1; } + .roomlabel .rlmetrics { + position: absolute; /* below the name, outside the centring math */ + top: calc(100% + 0.15em); + left: 50%; + transform: translateX(-50%); + white-space: nowrap; + display: flex; + align-items: center; + gap: 0.55em; + font-size: calc(0.75em * var(--rl-meta, 1)); /* feedback: 0.62 was unreadable on a tablet */ + font-weight: 600; + letter-spacing: 0.02em; + opacity: 0.9; + } + .roomlabel .rlm { + display: inline-flex; + align-items: center; + gap: 0.12em; + } + .roomlabel .rlm ha-icon { + --mdc-icon-size: 1.05em; + display: inline-flex; + } + .roomlabel .rlm.lit { opacity: 1; } + .rlhandle { + display: none; + position: absolute; + width: 9px; + height: 9px; + border-radius: 2px; + background: var(--hp-accent); + border: 1px solid var(--card-background-color, #fff); + z-index: 2; + } + .rlhandle.tl { left: -6px; top: -6px; cursor: nwse-resize; } + .rlhandle.br { right: -6px; bottom: -6px; cursor: nwse-resize; } + .rlhandle.tr { right: -6px; top: -6px; cursor: nesw-resize; } + .rlhandle.bl { left: -6px; bottom: -6px; cursor: nesw-resize; } + :host([data-pointer-hover]) .stage.markup .roomlabel:hover .rlhandle { display: block; } + .stage.markup .roomlabel { pointer-events: auto; } + .roomlabel:active { cursor: grabbing; } + .measurelayer { + position: absolute; + inset: 0; + pointer-events: none; + } + .alignline { + stroke: var(--hp-accent); + stroke-width: calc(1.2px * var(--hp-cell-visual-scale, 1)); + stroke-dasharray: + calc(4px * var(--hp-cell-visual-scale, 1)) + calc(4px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + opacity: 0.9; + } + .aligndot { + fill: var(--hp-accent); + pointer-events: none; + } + .measurelabel.on45 { + color: #4bd28f; + border-color: #4bd28f; + } + .measurelabel { + position: absolute; + transform: translate(12px, -150%); + font-size: var(--fs-s); + font-weight: 600; + padding: 1px var(--sp-3); + border-radius: var(--rad-s); + background: rgba(0, 0, 0, 0.72); + color: #fff; + white-space: nowrap; + pointer-events: none; + user-select: none; + z-index: 3; + } + .measurelabel.opdimension { + transform: translate( + calc(-50% + var(--op-label-shift-x, 0px)), + calc(-50% + var(--op-label-shift-y, -12px)) + ); + border: 1px solid var(--hp-open, #ff9800); + } + /* decor (background) layer */ + .decorlayer .dshape { pointer-events: none; } + .stage.mode-decor .decorlayer .dshape { + pointer-events: visiblePainted; + cursor: pointer; + } + .stage.mode-decor.dtool-select .decorlayer .dshape { cursor: move; } + /* …but a DRAWING tool owns the canvas: existing shapes stop being targets + entirely, so a new line can start exactly on the end of an old one + instead of grabbing it (owner, 2026-08-04). Same for the picture tool — + a shape lying over the plan must not block the picture's own drag. + Only select (move) and erase (delete) keep the shapes clickable. */ + .stage.mode-decor.dtool-line .decorlayer .dshape, + .stage.mode-decor.dtool-rect .decorlayer .dshape, + .stage.mode-decor.dtool-ellipse .decorlayer .dshape, + .stage.mode-decor.dtool-text .decorlayer .dshape, + .stage.mode-decor.dtool-furniture .decorlayer .dshape, + .stage.mode-decor.dtool-backdrop .decorlayer .dshape { pointer-events: none; } + /* the furniture tool is a stamp: the press must reach the stage even when + it lands on a sofa that is already there (docs/FURNITURE.md §4) */ + .stage.mode-decor.dtool-furniture { cursor: copy; } + /* ONE exception (owner, 2026-08-04): under the TEXT tool an existing LABEL + is a target again — pressing it opens its editor instead of starting a + new label on top of the old one. Only labels: a line or a rectangle + under the text tool stays inert, so the press reaches the stage and a + new label is created there. */ + .stage.mode-decor.dtool-text .decorlayer .dshape.dtext, + .stage.mode-decor.dtool-select .decorlayer .dshape.dtext, + .stage.mode-decor.dtool-erase .decorlayer .dshape.dtext { + /* A label is one logical decor object. SVG's visiblePainted would hit + only the ink of individual glyphs, so spaces, counters and the area + inside its selection glow behaved like empty canvas. */ + pointer-events: visiblePainted; + pointer-events: bounding-box; + } + .stage.mode-decor.dtool-text .decorlayer .dshape.dtext { + cursor: text; + } + /* Erasing a hairline must not require pixel-perfect aim. The duplicate + geometry is invisible and exists only while Erase is active. A + non-scaling stroke keeps the target comfortably wide at every zoom. */ + .decorlayer .derasehit { + fill: none; + stroke: transparent; + stroke-width: 16px; + stroke-linecap: round; + stroke-linejoin: round; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .stage.mode-decor.dtool-erase .decorlayer .derasehit { + pointer-events: stroke; + } + /* A dashed line must remain selectable across its gaps. This proxy also + makes the only entry to line-style properties — double click in Select — + practical for hairlines at every zoom. */ + .decorlayer .dselecthit { + fill: none; + stroke: transparent; + stroke-width: 16px; + stroke-linecap: round; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .stage.mode-decor.dtool-select .decorlayer .dselecthit { + pointer-events: stroke; + cursor: move; + } + .decorlayer .dsel { + filter: drop-shadow(0 0 3px var(--hp-accent)); + } + .decorlayer .ddraft { + stroke-dasharray: + calc(6px * var(--hp-cell-visual-scale, 1)) + calc(5px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + .decorlayer text { + font-weight: 600; + user-select: none; + dominant-baseline: middle; + text-anchor: middle; + } + .stage.mode-decor { + outline: 2px solid #26a69a; + outline-offset: -2px; + } + /* backdrop transform frame (docs/BACKDROP.md §2). Editor chrome: the + outline never takes a pointer, the four corner handles do — and they are + finger-sized (r = 2 % of the visible view), because this is dragged on a + tablet as often as with a mouse. */ + .bdframe .bdbox { + fill: none; + stroke: var(--hp-accent); + stroke-width: 2; + stroke-dasharray: 10 7; + vector-effect: non-scaling-stroke; + pointer-events: none; + opacity: 0.9; + } + /* the HIT circle: invisible, finger-sized, the only thing that takes a + pointer. The visible bead is .bdknob, a quarter of its radius — the same + visual/hit split .dthandle + .dtknob and .rszhandle + .rszicon use. */ + .bdframe .bdhandle { + fill: transparent; + stroke: none; + pointer-events: all; + touch-action: none; + } + .bdframe .bdknob { + fill: var(--hp-accent); + stroke: #fff; + stroke-width: 1; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + :host([data-pointer-hover]) .bdframe .bdhandle:hover + .bdknob { + fill: #fff; + stroke: var(--hp-accent); + } + .bdframe .bd-nwse { cursor: nwse-resize; } + .bdframe .bd-nesw { cursor: nesw-resize; } + /* the picture itself is the drag target for a move (grab, then grabbing) */ + .stage.mode-decor.bdgrab { cursor: grab; } + .stage.mode-decor.bdgrabbing, + .stage.mode-decor.bdgrabbing .bdframe .bdhandle { cursor: grabbing; } + .measurelabel.bdmeasure { + transform: translate(-50%, -50%); + border: 1px solid var(--hp-accent); + } + /* the selected decor object's frame — same chrome rules as the backdrop's: + the outline never takes a pointer, the handles always do, and they are + finger-sized because this is dragged on a tablet too */ + .dtframe .dtbox { + fill: none; + stroke: var(--hp-accent); + stroke-width: 1.5; + stroke-dasharray: 7 5; + vector-effect: non-scaling-stroke; + pointer-events: none; + opacity: 0.85; + } + .dtframe .dtstem, + .bdframe .dtstem { + stroke: var(--hp-accent); + stroke-width: 1.5; + vector-effect: non-scaling-stroke; + pointer-events: none; + opacity: 0.85; + } + /* the HIT circle: invisible, finger-sized, the only thing that takes a + pointer. The visible bead is .dtknob, a quarter of its radius — the + same visual/hit split .rszhandle + .rszicon use. */ + .dtframe .dthandle { + fill: transparent; + stroke: none; + pointer-events: all; + touch-action: none; + } + .dtframe .dtknob { + fill: var(--hp-accent); + stroke: #fff; + stroke-width: 1; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + :host([data-pointer-hover]) .dtframe .dthandle:hover + .dtknob { + fill: #fff; + stroke: var(--hp-accent); + } + .dtframe .dt-nwse { cursor: nwse-resize; } + .dtframe .dt-nesw { cursor: nesw-resize; } + .dtframe .dtrot { cursor: grab; } + .dtframe .dtendpoint { cursor: crosshair; } + .bdframe .dtrot { cursor: grab; } + .dtarea { + resize: vertical; + min-height: 3.4em; + font: inherit; + line-height: 1.35; + } + .stage.mode-decor.dtool-line, .stage.mode-decor.dtool-rect, + .stage.mode-decor.dtool-ellipse, .stage.mode-decor.dtool-text { + cursor: crosshair; + } + .stage.mode-decor.dtool-erase, + .stage.mode-decor.dtool-erase .decorlayer .dshape { + cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg transform='rotate(-45 12 12)'%3E%3Crect x='7' y='2' width='10' height='18' rx='2' fill='%23fff' stroke='%23111' stroke-width='1.5'/%3E%3Cpath d='M7 13h10v5a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2z' fill='%23ff9f43' stroke='%23111' stroke-width='1.5'/%3E%3C/g%3E%3C/svg%3E") 5 22, pointer; + } + .stage.mode-decor .room, .stage.mode-decor .devlayer { pointer-events: none; } + .stage.mode-decor .oplock { pointer-events: none; } + /* Backdrop-editor de-emphasis is a shared mode-transition coordinate. + It multiplies whole presentation groups and never changes Glow source + alpha, additive blending, or the underlying resolved state. */ + .stage .room, + .stage .devlayer, + .stage .opening, + .stage .room-outline, + .stage .wallbodies, + .stage .opening-tunnels, + .stage .glow-base-layer, + .stage .glow-pools-frame, + .stage .zero-walls { + opacity: var(--hp-mode-architecture-opacity, 1); + } + .opening-preview { + opacity: 0.5; + pointer-events: none; + } + .opening-preview[data-kind="passage"] { + opacity: 1; + } + .passage-preview-cut { + fill: var(--wall-fill, #ffffff); + fill-opacity: 0.35; + stroke: none; + pointer-events: none; + } + .passage-preview-boundary { + stroke: var(--hp-open, #ff9800); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + .opening-preview .op-leaf, + .opening-preview .op-arc { + transition: none; + } + .opening-preview-dot { + fill: var(--hp-open, #ff9800); + pointer-events: none; + } + .opening-dimensions, + .opening-dimension { + pointer-events: none; + } + .opening-dimension-line, + .opening-dimension-tick { + fill: none; + stroke: var(--hp-open, #ff9800); + stroke-width: 1.5; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .opening-dimension-tick { + stroke-width: 2; + } + .stage.edit .room { + pointer-events: none; + } + .stage.markup { + cursor: crosshair; + } + /* room-picking stages: merge (both clicks) and split before a room is chosen */ + .stage.markup.tool-merge, + .stage.markup.tool-split.pickstage, + .stage.markup.tool-delroom { + cursor: pointer; + } + .stage.markup.tool-wallthick { cursor: default; } + .stage.markup.tool-wallthick.wallhot { cursor: pointer; } + /* Solid wall colour sits under the hatch (owner: both, not either/or). */ + .wallbody-fill { + fill: var(--wall-fill, #ffffff); + fill-opacity: var(--wall-fill-op, 1); + fill-rule: evenodd; + stroke: none; + pointer-events: none; + } + .wallbody { + fill: url(#hp-wall-hatch); + fill-rule: evenodd; + stroke: var(--room-stroke, var(--hp-muted)); + stroke-width: calc(0.6px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + /* Thin-on-screen: hatch collapses into noise — fill alone, stroke from fill path's sibling. */ + .wallbody.solid { + fill: none; + } + .wallthick-hover { + fill: var(--accent-color, #03a9f4); + fill-opacity: 0.38; + stroke: var(--accent-color, #03a9f4); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + stroke-linejoin: round; + stroke-linecap: round; + pointer-events: none; + } + .wallthick-hover.isopen { + fill: var(--error-color, #f44336); + stroke: var(--error-color, #f44336); + } + .zero-wall { + stroke: var(--zero-wall-stroke, var(--hp-muted)); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + stroke-dasharray: + calc(7px * var(--hp-cell-visual-scale, 1)) + calc(7px * var(--hp-cell-visual-scale, 1)); + stroke-linecap: butt; + pointer-events: none; + opacity: 0.9; + } + .zero-walls.solid .zero-wall { + stroke-dasharray: none; + } + /* Rooms with zero/thick stretches: the polygon's own stroke is fully off. + The trimmed .room-outline draws normal walls; View hover gets its own + top overlay after the wall bodies. */ + .room.noedge { + stroke-opacity: 0 !important; + } + /* rooms with open boundaries draw their walls as separate M..L subpaths, + so a corner between two of them is two stroke ENDS meeting: round caps + fill it in the same way a round join fills a closed contour's corner + (owner 2026-08-04 — no teeth anywhere on a room border). */ + .room-outline { + fill: none; + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + stroke-linejoin: round; + stroke-linecap: round; + pointer-events: none; + } + /* Plan editor: trimmed outlines use the markup blue */ + .room-outline.outlined { + stroke: rgba(62, 166, 255, 0.55); + stroke-opacity: 1; + } + /* The wash is rendered directly above the resolved room fill but below + tunnels, Glow, sun and walls. Black at 22% reproduces the old + brightness(.78) contract without filtering/promoting an SVG ancestor or + changing the room's hue. The halo/outline are rendered again late, above + the wall bodies. */ + .room-hover-fill { + fill: #000; + fill-opacity: 0.22; + pointer-events: none; + } + .room-hover-halo { + fill: none; + stroke: var(--hp-accent); + stroke-opacity: 0.28; + stroke-width: calc(8px * var(--hp-cell-visual-scale, 1)); + stroke-linejoin: round; + stroke-linecap: round; + pointer-events: none; + } + .room-hover-outline { + fill: none; + stroke: var(--hp-accent); + stroke-width: calc(3px * var(--hp-cell-visual-scale, 1)); + stroke-linejoin: round; + stroke-linecap: round; + pointer-events: none; + } + .stage.markup .room { + pointer-events: none; + } + .stage.markup .devlayer .dev { + display: none; /* in plan mode the icons do not get in the way; labels stay */ + } + /* mode frames: the edit modes are visible at a glance */ + .stage.mode-plan { + outline: 2px solid #ffc14d; + outline-offset: -2px; + } + .stage.mode-devices { + outline: 2px solid var(--hp-accent); + outline-offset: -2px; + } + .room.outlined { + stroke: rgba(62, 166, 255, 0.55); + fill: rgba(62, 166, 255, 0.06); + } + /* AFTER .outlined: same specificity — source order decides (gotcha x4) */ + .room.picked { + stroke: #ffc14d; + stroke-width: calc(3px * var(--hp-cell-visual-scale, 1)); + fill: rgba(255, 193, 77, 0.25); + } + /* Owner 2026-08-04: the grid is a HINT, not content — at full strength the + dots argued with the plan on white paper. Both levels are muted, the + hierarchy is kept (major still denser than fine). */ + .griddot { + fill: var(--hp-accent); + opacity: 0.35; + stroke: rgba(0, 0, 0, 0.35); + stroke-width: 0.4; + } + /* docs/CANVAS.md §7: every coarse node (5x/10x the live step) keeps a + bigger, more opaque dot, so zoomed far out the grid still reads as a + grid instead of a grey wash. */ + .griddot.major { + opacity: 0.5; + stroke-width: 0; + } + /* the contour being drawn in the Plan editor: each wall is its own , + so the round cap IS the corner (matches the finished .room border) */ + .seg { + stroke: var(--hp-accent); + stroke-width: calc(2.5px * var(--hp-cell-visual-scale, 1)); + stroke-linecap: round; + stroke-linejoin: round; + } + .pathline { + stroke: #ffc14d; + stroke-width: calc(3px * var(--hp-cell-visual-scale, 1)); + fill: none; + stroke-linecap: round; + stroke-linejoin: round; + } + .preview { + stroke: #ffc14d; + stroke-width: calc(2px * var(--hp-cell-visual-scale, 1)); + stroke-dasharray: + calc(6px * var(--hp-cell-visual-scale, 1)) + calc(5px * var(--hp-cell-visual-scale, 1)); + opacity: 0.7; + } + .active-axis { + stroke: #ffc14d; + stroke-width: 2; + stroke-linecap: round; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .active-vertex { + fill: #ffc14d; + stroke: #171006; + stroke-width: 2; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .wall-repair-preview { + stroke: #d93025; + stroke-width: 4; + stroke-linecap: round; + stroke-dasharray: 5 4; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .drawwall-preview-fill { + fill: var(--wall-fill, #ffffff); + fill-opacity: calc(var(--wall-fill-op, 1) * 0.55); + fill-rule: evenodd; + stroke: none; + pointer-events: none; + } + .drawwall-preview { + fill: url(#hp-wall-hatch); + fill-opacity: 0.55; + fill-rule: evenodd; + stroke: var(--accent-color, #03a9f4); + stroke-width: calc(0.5px * var(--hp-cell-visual-scale, 1)); + stroke-opacity: 0.7; + pointer-events: none; + } + .drawwall-zero-preview { + fill: none; + stroke: var(--accent-color, #03a9f4); + stroke-width: calc(3px * var(--hp-cell-visual-scale, 1)); + stroke-linecap: butt; + stroke-linejoin: round; + opacity: 0.72; + pointer-events: none; + } + .drawwall-zero-preview.dashed { + stroke-dasharray: + calc(7px * var(--hp-cell-visual-scale, 1)) + calc(7px * var(--hp-cell-visual-scale, 1)); + } + .vertex { + fill: #ffc14d; + stroke: #4a2800; + stroke-width: calc(1px * var(--hp-cell-visual-scale, 1)); + } + .vertex.first { + fill: #4bd28f; + stroke: #04121f; + } + .plan-snap-overlay, + .plan-snap-overlay *, + .hidden-wall-diagnostic, + .hidden-wall-diagnostic * { + pointer-events: none; + } + .plan-snap-line, + .hidden-wall-line { + fill: none; + stroke: color-mix(in srgb, var(--hp-accent) 82%, white 18%); + /* Explicit non-scaling-stroke in the SVG keeps this one screen pixel. */ + stroke-width: 1; + stroke-linecap: round; + opacity: 0.92; + } + .plan-snap-node, + .hidden-wall-node { + fill: var(--ha-card-background, var(--card-background-color, #fff)); + stroke: color-mix(in srgb, var(--hp-accent) 88%, #07131c 12%); + stroke-width: 1; + vector-effect: non-scaling-stroke; + } + .plan-snap-node.active { + fill: #ffc14d; + stroke: #171006; + stroke-width: 2; + } + .plan-snap-node.active.dynamic { + fill: #4bd28f; + stroke: #04121f; + } + .plan-snap-node.conflict { + fill: #fff; + stroke: #d93025; + stroke-width: 3; + } + @media (prefers-color-scheme: dark) { + .plan-snap-line { + stroke: color-mix(in srgb, var(--hp-accent) 72%, white 28%); + } + .hidden-wall-line { + stroke: color-mix(in srgb, var(--hp-accent) 72%, white 28%); + } + .plan-snap-node, + .hidden-wall-node { + fill: #17242c; + stroke: #9bdcf5; + } + .plan-snap-node.active { + fill: #ffc14d; + stroke: #fff4d6; + } + .plan-snap-node.active.dynamic { + fill: #4bd28f; + stroke: #eafff4; + } + } + @media (forced-colors: active) { + .plan-snap-line, + .hidden-wall-line { + stroke: CanvasText; + opacity: 1; + forced-color-adjust: auto; + } + .plan-snap-node, + .hidden-wall-node { + fill: Canvas; + stroke: CanvasText; + forced-color-adjust: auto; + } + .plan-snap-node.active, + .plan-snap-node.active.dynamic { + fill: Highlight; + stroke: HighlightText; + forced-color-adjust: auto; + } + } + /* RGB lights: the bulb takes the light's actual color */ + /* v1.52.0: the RGB tint of the icon/border is gone — a lamp's colour + lives ONLY in its glow spot (owner's rule). The ripple-color fallback + keeps using the light colour; that is set inline via --ripple-color. */ + /* Sun wedges (docs/SUN.md). The layer is present ONLY above the 3° + threshold; crossing it fades the whole layer in or out over EXACTLY + 2 s (owner 2026-08-03 — RAY_FADE_MS in src/sun.ts must match). The + geometry is untouched: this is a plain opacity animation on the group, + so overlapping wedges keep their own blending while it plays. */ + .sunlayer { + animation: hp-sunfade-in 2s linear both; + } + .sunlayer.out { + animation: hp-sunfade-out 2s linear both; + } + @media (prefers-reduced-motion: reduce) { + /* no fade at all: the rays are simply there or simply gone */ + .sunlayer, .sunlayer.out { animation: none; } + .sunlayer.out { opacity: 0; } + } + .devlayer { + position: absolute; + inset: 0; + pointer-events: none; + z-index: 6; + } + .stage.mode-devices .dev { cursor: grab; } + .stage.mode-devices .dev:active { cursor: grabbing; } + .physical-hit { + fill: transparent; + stroke: transparent; + pointer-events: none; + cursor: grab; + } + .stage.tool-select .physical-hit { pointer-events: all; } + .physical-hit:active { cursor: grabbing; } + line.physical-hit { cursor: pointer; } + .physical-hit.selected { + fill: rgba(255, 193, 77, 0.24); + stroke: transparent; + } + line.physical-hit.selected { + stroke: transparent; + } + .physical-drag { + fill: rgba(255, 193, 77, 0.38); + stroke: #ffc14d; + stroke-width: 2.5; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .physical-chrome { pointer-events: none; } + .physical-chrome .frame, + .physical-chrome .stem { + fill: none; + stroke: #ffc14d; + stroke-width: 2; + vector-effect: non-scaling-stroke; + } + .physical-chrome .frame { fill: rgba(255, 193, 77, 0.22); } + .physical-chrome polyline.frame { fill: none; } + .physical-chrome .move-dot { + fill: #ffc14d; + stroke: #24262d; + stroke-width: 1.5; + vector-effect: non-scaling-stroke; + } + .physical-chrome .rotate-handle { + fill: #24262d; + stroke: #ffc14d; + stroke-width: 2.5; + vector-effect: non-scaling-stroke; + pointer-events: all; + cursor: crosshair; + } + .drawwall.invalid input { border-color: var(--error-color, #db4437); } + .drawwall .rangehint { margin-inline-start: 4px; font-size: 0.78em; opacity: 0.72; } + .drawwall.invalid .rangehint { color: var(--error-color, #db4437); opacity: 1; } + .stage.markup.tool-partition, + .stage.markup.tool-column { cursor: crosshair; } + /* room resize tool (docs/RESIZE.md) */ + /* wall handle: invisible finger-sized hit circle (HP-1550-04 hit priority + kept), the visible glyph lives in the sibling .rszicon */ + .rszhandle { + fill: transparent; + stroke: none; + pointer-events: all; + cursor: grab; + touch-action: none; + } + .rszhandle:active { cursor: grabbing; } + .rszhandle.disabled, + .rszhandle.disabled:active { + cursor: not-allowed; + } + /* wall-with-arrows glyph: accent ink over a bg halo, readable on any plan */ + .rszicon { pointer-events: none; } + .rszicon path { + fill: none; + stroke-linecap: round; + stroke-linejoin: round; + vector-effect: non-scaling-stroke; + } + .rszhalo { stroke: var(--hp-bg); stroke-width: 6; } + .rszink { stroke: var(--hp-accent); stroke-width: 2; } + :host([data-pointer-hover]) .rszhandle:hover + .rszicon .rszink { stroke-width: 3; } + .rszicon.disabled { opacity: 0.38; } + :host([data-pointer-hover]) .rszhandle.disabled:hover + .rszicon .rszink { stroke-width: 2; } + .rszmeasurelayer, + .rszmeasurelayer * { pointer-events: none; } + .rszmeasurehalo, + .rszmeasureink, + .rszleader { + fill: none; + stroke-linecap: round; + vector-effect: non-scaling-stroke; + } + .rszmeasurehalo { + stroke: var(--hp-bg); + stroke-width: 7px; + opacity: 0.9; + } + .rszmeasureink { + stroke: var(--hp-accent); + stroke-width: 3px; + } + .rszleader { + stroke: var(--hp-accent); + stroke-width: 2px; + opacity: 0.95; + } + /* the decor draft badge rides the MIDDLE of the shape, so it is centred + horizontally and lifted clear of the line instead of trailing the + cursor the way a wall badge does (owner 2026-08-04) */ + .measurelabel.dmeasure { + transform: translate(-50%, -160%); + } + .measurelabel.rszarea { + transform: translate( + calc(-50% + var(--rsz-label-x, 0px)), + calc(-50% + var(--rsz-label-y, 0px)) + ); + background: rgba(0, 0, 0, 0.6); + border: 1px solid var(--hp-accent); + } + /* width and depth of a piece of furniture while its corner is dragged — + centred on the edge they measure (docs/FURNITURE.md §6) */ + .measurelabel.furnmeasure { + transform: translate(-50%, -50%); + border: 1px solid var(--hp-accent); + } + .alignmsg { margin: 0 0 8px; font-size: 13px; line-height: 1.45; } +`,o` + /* Unified device activity: alarm, short event and continuous state all + share this one renderer. No static rings are allowed. */ + .dev ha-icon { + position: relative; + z-index: 1; + } + .device-pulse { + position: absolute; + left: 50%; + top: 50%; + width: var(--dev-size); + height: var(--dev-size); + transform: translate(-50%, -50%); + pointer-events: none; + z-index: 0; + } + .device-pulse i { + position: absolute; + inset: 0; + border-radius: 50%; + border: 2px solid var(--ripple-color, var(--hp-accent)); + opacity: 0; + } + /* A witnessed edge: exactly three waves over the 3.3 s runtime window. */ + .device-pulse.short i { + animation: hp-pulse-short 1.1s cubic-bezier(.22,.61,.36,1) 1 forwards; + } + .device-pulse.short i:nth-child(2) { animation-delay: 1.1s; } + .device-pulse.short i:nth-child(3) { animation-delay: 2.2s; } + .device-pulse.short.gen2 i { animation-name: hp-pulse-short-b; } + .device-pulse.continuous i:nth-child(n + 2), + .device-pulse.alarm i:nth-child(n + 3) { display: none; } + .device-pulse.continuous i:first-child { + animation: hp-pulse-continuous 3.6s cubic-bezier(.45,.05,.55,.95) infinite; + } + .device-pulse.alarm i { + border-width: 3px; + border-color: #F0410C; + animation: hp-pulse-alarm 2.4s cubic-bezier(.22,.61,.36,1) infinite; + } + .device-pulse.alarm i:nth-child(2) { animation-delay: 1.2s; } + .activity-dot { + position: absolute; + right: 8%; + bottom: 8%; + width: 18%; + height: 18%; + min-width: 4px; + min-height: 4px; + border-radius: 50%; + background: var(--ripple-color, var(--hp-accent)); + border: 1px solid color-mix(in srgb, var(--hp-bg) 82%, transparent); + pointer-events: none; + z-index: 3; + } + .kioskdots { + position: absolute; + left: 50%; + bottom: var(--sp-5); + transform: translateX(-50%); + display: flex; + gap: var(--sp-4); + z-index: 5; + pointer-events: none; + } + .kdot { + width: 9px; + height: 9px; + border-radius: 50%; + background: var(--hp-muted); + opacity: 0.55; + } + .kdot.on { background: var(--hp-accent); opacity: 1; } + .dev.valonly { + /* Saved coordinates remain the centre of a Text shell. The shell may + expand, while the invisible anchor stays one core diameter wide. */ + width: var(--dev-size, var(--icon-size, 2.5cqw)); + } + .dev.valonly .device-core { + width: max-content; + min-width: var(--dev-size, var(--icon-size, 2.5cqw)); + padding-inline: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.16); + border-radius: calc(var(--dev-size, var(--icon-size, 2.5cqw)) / 2); + } + .dev .valtext { + overflow: visible; + font-size: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * var(--value-font-scale, .45)); + font-weight: 600; + white-space: nowrap; + } + @media (prefers-reduced-motion: reduce) { + .device-pulse { display: none; } + } + .dev .newdot { + position: absolute; + top: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * -0.12); + right: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * -0.12); + width: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.34); + height: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.34); + border-radius: 50%; + background: #f0301f; + border: 2px solid var(--card-background-color, var(--hp-bg)); + pointer-events: none; + z-index: 2; + } + .dev { + position: absolute; + /* The surface resolves compatibility icon_size units once. The shared + face receives an effective base and only applies the per-device size. */ + --dev-size: calc(var(--device-base-size, 2.25cqw) * var(--dev-scale, 1)); + /* 101.5/80 is the package shell/core ratio, including its stroke. */ + --device-shell-size: calc(var(--dev-size) * 1.26875); + --device-shell-inset: calc(var(--dev-size) * 0.134375); + --device-shell-stroke-ratio: 0.01875; + --device-shell-border-width: max(1px, calc(var(--dev-size) * var(--device-shell-stroke-ratio))); + --device-core-bg: var(--card-background-color, #fff); + --device-core-fg: var(--primary-text-color, #252525); + --device-core-bg: light-dark(#fff, #252525); + --device-core-fg: light-dark(#252525, #fff); + --device-face-bg: var(--device-core-bg); + --device-face-fg: var(--device-core-fg); + --device-shell-base-stroke: light-dark(#BCBCBC, rgb(37 37 37 / 75%)); + --device-shell-stroke: var(--device-shell-base-stroke); + --device-shell-shadow: + 0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .05) rgb(37 40 45 / 12%), + 0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) + calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%); + --device-core-inset-shadow: 0 0 0 0 transparent; + --device-ring-color: transparent; + --device-ring-width: 0px; + /* The saved point is the exact centre of the icon core. */ + width: var(--dev-size); + height: var(--dev-size); + margin: calc(var(--dev-size) / -2) 0 0 calc(var(--dev-size) / -2); + border: 0; + background: transparent; + display: block; + color: var(--device-core-fg); + cursor: pointer; + pointer-events: auto; + transition: opacity 0.2s; + box-shadow: none; + outline: none; + z-index: 2; + } + .dev.theme-light { + --device-core-bg: #fff; + --device-core-fg: #000; + --device-shell-base-stroke: #BCBCBC; + --device-shell-stroke: var(--device-shell-base-stroke); + --device-shell-shadow: + 0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .05) rgb(37 40 45 / 12%), + 0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) + calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%); + --device-core-inset-shadow: 0 0 0 0 transparent; + } + .dev.theme-dark { + --device-core-bg: #252525; + --device-core-fg: #fff; + --device-shell-base-stroke: rgb(37 37 37 / 75%); + --device-shell-stroke: var(--device-shell-base-stroke); + --device-shell-shadow: + 0 calc(var(--dev-size) * .025) calc(var(--dev-size) * .0375) rgb(37 40 45 / 12%), + 0 calc(var(--dev-size) * .1) calc(var(--dev-size) * .175) + calc(var(--dev-size) * -.025) rgb(37 40 45 / 18%); + --device-core-inset-shadow: + inset 0 calc(var(--dev-size) * 0.0125) calc(var(--dev-size) * 0.0125) rgb(255 255 255 / 70%); + } + .dev::before { + content: ''; + position: absolute; + left: 50%; + top: 50%; + width: max(44px, var(--device-shell-size)); + height: max(44px, var(--device-shell-size)); + transform: translate(-50%, -50%); + border-radius: 50%; + pointer-events: auto; + z-index: 3; + } + .device-shell { + position: absolute; + box-sizing: border-box; + display: flex; + align-items: center; + gap: calc(var(--dev-size) * 0.1); + padding: 0; + min-width: var(--dev-size); + min-height: var(--dev-size); + border: 0; + background: transparent; + box-shadow: none; + transition: opacity .2s; + pointer-events: none; + } + .device-shell-frame { + position: absolute; + z-index: 0; + box-sizing: border-box; + inset: calc(var(--device-shell-inset) / -1); + border: var(--device-shell-border-width) solid var(--device-shell-stroke); + /* A saturating radius is resolved from the final border box. Using a + second fractional length here lets border-box and radius quantise on + different sides of a device pixel at some zoom/DPR combinations. */ + border-radius: 9999px; + background: transparent; + box-shadow: var(--device-shell-shadow); + transition: border-color .15s, box-shadow .15s, opacity .2s; + pointer-events: auto; + /* Normative production fallback: never add a per-marker backdrop blur. */ + backdrop-filter: none; + } + .device-shell:not(.with-values) { + left: 0; + top: 0; + } + .device-shell:not(.with-values):not(.text-shell) .device-shell-frame { + border-radius: 50%; + } + .device-shell.with-values.pos-right { + left: 0; + top: 50%; + transform: translateY(-50%); + } + .device-shell.with-values.pos-left { + right: 0; + top: 50%; + transform: translateY(-50%); + flex-direction: row-reverse; + } + .device-shell.with-values.pos-bottom { + left: 50%; + top: 0; + transform: translateX(-50%); + flex-direction: column; + } + .device-shell.with-values.pos-top { + left: 50%; + bottom: 0; + transform: translateX(-50%); + flex-direction: column-reverse; + } + .device-core { + position: relative; + z-index: 1; + box-sizing: border-box; + flex: 0 0 auto; + width: var(--dev-size); + height: var(--dev-size); + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + background: var(--device-face-bg); + color: var(--device-face-fg); + box-shadow: + var(--device-core-inset-shadow), + 0 0 0 var(--device-ring-width) var(--device-ring-color); + line-height: 0; + transition: background .15s, color .15s, box-shadow .15s, opacity .2s; + pointer-events: none; + } + .device-sections { + display: flex; + flex-direction: column; + align-items: stretch; + justify-content: center; + gap: calc(var(--dev-size) * .08); + min-width: 0; + pointer-events: none; + } + .device-shell.pos-top .device-sections, + .device-shell.pos-bottom .device-sections { + flex-direction: row; + } + .dev ha-icon { + /* from --dev-size, NOT --icon-size: the per-device size multiplier must + scale the GLYPH with its badge. Pinned to the base size, "make this + icon bigger" grew an empty box around a default-size glyph (user + report via the owner, 2026-07-29). */ + --mdc-icon-size: calc(var(--dev-size, var(--device-base-size, 2.25cqw)) * 0.55); + display: flex; + align-items: center; + justify-content: center; + line-height: 0; + } + .dev.on { + --device-face-bg: #F0A00C; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: #F0A00C; + } + .dev.theme-light.on { --device-face-fg: #fff; } + .dev.theme-dark.on { + --device-face-fg: #252525; + --device-shell-stroke-ratio: .0375; + } + .dev.open { + --device-face-bg: var(--hp-open); + --device-face-fg: light-dark(#fff, #252525); + } + .dev.theme-light.open { --device-face-fg: #fff; } + .dev.theme-dark.open { --device-face-fg: #252525; } + .dev.lock-locked { + --device-face-bg: #66D17A; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: #66D17A; + } + .dev.theme-light.lock-locked { --device-face-fg: #fff; } + .dev.theme-dark.lock-locked { + --device-face-fg: #252525; + --device-shell-stroke-ratio: .025; + } + .dev.lock-unlocked { + --device-face-bg: #F0410C; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: #F0410C; + } + .dev.theme-light.lock-unlocked { --device-face-fg: #fff; } + .dev.theme-dark.lock-unlocked { + --device-face-fg: #252525; + --device-shell-stroke-ratio: .025; + } + /* Interaction wins ordinary state colours. Alarm keeps priority through + the more-specific rule below. Unavailable has no visual hover. */ + :host([data-pointer-hover]) .dev:not(.unavail):hover { + --device-face-bg: #0C82F0; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: var(--device-shell-base-stroke); + } + :host([data-pointer-hover]) .dev.theme-light:not(.unavail):hover { --device-face-fg: #fff; } + :host([data-pointer-hover]) .dev.theme-dark:not(.unavail):hover { --device-face-fg: #252525; } + :host([data-pointer-hover]) .dev:hover, + .dev:focus-visible { z-index: 5; } + .dev.unavail { + opacity: 0.35; + --device-face-bg: #B5BAC1; + --device-shell-stroke: var(--device-shell-base-stroke); + } + .dev.virtual .device-shell-frame { + border-style: dashed; + } + /* "hide from plan" flag, shown only in the device editor with the + "show hidden devices" toggle on (docs/FILTERING.md). BLUE, so a hidden + device cannot be mistaken for an unavailable one (translucent dark) — + and no live-state paint at all: a ghost is configuration, not status + (owner's request). */ + .dev.ghost { + opacity: 0.6; + color: var(--hp-accent); + } + .dev.ghost .device-shell-frame { + border-style: dashed; + border-color: var(--hp-accent); + box-shadow: none; + } + .dev.ghost .device-core { + background: rgba(62, 166, 255, 0.22); /* fallback for old WebViews */ + background: color-mix(in srgb, var(--hp-accent) 30%, var(--card-background-color, #1c2530)); + color: var(--hp-accent); + } + /* HA-disabled is not a user hide: neutral grey + a power-off badge keeps + the two ghosts distinguishable without relying on colour alone. */ + .dev.ghost.ha-disabled { + opacity: 0.62; + color: var(--secondary-text-color, #9aa0aa); + } + .dev.ghost.ha-disabled .device-shell-frame { + border-color: var(--secondary-text-color, #9aa0aa); + } + .dev.ghost.ha-disabled .device-core { + background: rgba(120, 124, 134, 0.2); + background: color-mix(in srgb, var(--secondary-text-color, #9aa0aa) 24%, var(--card-background-color, #1c2530)); + color: var(--secondary-text-color, #9aa0aa); + } + .dev .habadge { + position: absolute; + right: -18%; + bottom: -18%; + display: grid; + place-items: center; + width: 46%; + height: 46%; + min-width: 12px; + min-height: 12px; + border-radius: 50%; + background: var(--card-background-color, #242832); + border: 1px solid currentColor; + } + .dev .habadge ha-icon { width: 72%; height: 72%; } + .dev.sel { + --device-ring-color: #F0A00C; + --device-ring-width: calc(var(--dev-size) * 0.0375); + } + .dev:focus-visible { + --device-ring-color: #0C82F0; + --device-ring-width: calc(var(--dev-size) * 0.0375); + } + .dev:not(.on):not(.open):not(.alarm):not(.lock-locked):not(.lock-unlocked):not(.unavail):focus-visible { + --device-face-fg: #0C82F0; + } + /* Alert stays above focus, selection, hover and ordinary semantic paint. */ + .dev.alarm, + :host([data-pointer-hover]) .dev.alarm:hover, + .dev.alarm:focus-visible { + --device-face-bg: #F0410C; + --device-face-fg: light-dark(#fff, #252525); + --device-shell-stroke: #F0410C; + } + .dev.theme-light.alarm { --device-face-fg: #fff; } + .dev.theme-dark.alarm { + --device-face-fg: #252525; + --device-shell-stroke-ratio: .025; + } + .dev .value-badge { + position: relative; + z-index: 2; + box-sizing: border-box; + width: max-content; + min-width: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * .7875); + height: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * .7875); + display: flex; + align-items: center; + justify-content: center; + overflow: visible; + background: var(--device-core-bg); + border: 0; + border-radius: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.39375); + padding: 0 calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.14); + font-size: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * var(--value-font-scale, .45)); + font-weight: 600; + line-height: 1; + color: var(--device-core-fg); + white-space: nowrap; + pointer-events: none; + } + .dev .value-badge.unavailable, + .dev .value-badge.missing { opacity: 0.66; } + .dev .lqi { + position: absolute; + top: calc(50% + var(--device-shell-size) / 2 + var(--dev-size) * .05); + left: 50%; + transform: translateX(-50%); + margin-top: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.05); + font-size: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.38); + font-weight: 600; + line-height: 1; + text-shadow: 0 0 3px rgba(0, 0, 0, 0.9), 0 0 2px rgba(0, 0, 0, 0.9); + white-space: nowrap; + pointer-events: none; + } + .dev .lqi.below-value-badge { + margin-top: calc(var(--dev-size, var(--icon-size, 2.5cqw)) * 0.8875); + } + .temprange { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + margin-left: auto; + color: var(--hp-muted); + font-size: var(--fs-s); + } + /* live vacuum: a round puck, no badge plate, soft pulse (docs/VACUUM.md) */ + .vacpuck { + position: absolute; + /* the base badge, but round and 20% smaller — the owner's wording: + «иконка похожа на иконку базы, только круглая и чуть меньше» */ + --puck-size: calc(var(--device-base-size, 2.25cqw) * 0.8); + width: var(--puck-size); + height: var(--puck-size); + border-radius: 50%; + transform: translate(-50%, -50%); + --vac-core-bg: light-dark(#fff, #252525); + --vac-core-fg: light-dark(#252525, #fff); + background: var(--vac-core-bg); + border: 1px solid #BCBCBC; + box-shadow: + 0 1px 2px rgb(37 40 45 / 12%), + 0 4px 8px -1.07px rgb(37 40 45 / 18%); + color: var(--vac-core-fg); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + z-index: 6; + /* glide between sparse position updates; .jump disables it so the robot + never appears to drive through walls after a data gap */ + transition: left 1.2s linear, top 1.2s linear; + animation: vacpulse 2.2s ease-out infinite; + } + .vacpuck.theme-light { --vac-core-bg: #fff; --vac-core-fg: #252525; } + .vacpuck.theme-dark { --vac-core-bg: #252525; --vac-core-fg: #fff; } + .vacpuck.jump { transition: none; } + .vacpuck.stale { opacity: 0.45; animation: none; } + .vacpuck ha-icon { + --mdc-icon-size: calc(var(--puck-size) * 0.68); + color: var(--vac-core-fg); + /* same centering recipe as .dev ha-icon: without flex + line-height 0 + the glyph sits on its text baseline and appears to float around the + circle (owner report 2026-07-31) */ + display: flex; + align-items: center; + justify-content: center; + line-height: 0; + width: var(--mdc-icon-size); + height: var(--mdc-icon-size); + } + @keyframes vacpulse { + 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--hp-accent) 45%, transparent); } + 70% { box-shadow: 0 0 0 12px transparent; } + 100% { box-shadow: 0 0 0 0 transparent; } + } + @media (prefers-reduced-motion: reduce) { + .vacpuck { animation: none; } + } + .vactrail { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 5; + overflow: visible; + } + .vactrail polyline, + .vactrail path { + fill: none; + stroke-linejoin: round; + stroke-linecap: round; + vector-effect: non-scaling-stroke; + } + /* dark halo + light core: neutral, and one of the two always contrasts + with whatever fill is underneath */ + .vactrail g.prev { opacity: 0.4; } + .vactrail .case { + stroke: rgba(0, 0, 0, 0.4); + stroke-width: 2.25; + } + .vactrail .core { + stroke: rgba(255, 255, 255, 0.82); + stroke-width: 0.9; + } + .devicepreview-empty { + min-height: 82px; + margin: 4px 0 14px; + padding: var(--sp-4); + display: flex; + align-items: center; + justify-content: center; + gap: var(--sp-3); + border: 1px dashed var(--hp-line); + border-radius: var(--rad-m); + color: var(--hp-muted); + text-align: center; + } +`,o` + .hdr { + position: sticky; + top: var(--header-height, 56px); + z-index: 20; + background: var(--card-background-color, var(--hp-bg)); + border-radius: var(--ha-card-border-radius, 12px) var(--ha-card-border-radius, 12px) 0 0; + } + .tabs { + display: flex; + gap: var(--sp-2); + background: rgba(127, 127, 127, 0.12); + padding: var(--sp-2); + border-radius: var(--rad-l); + flex-wrap: wrap; + } + .tab { + border: 0; + background: transparent; + color: var(--hp-muted); + display: inline-flex; + align-items: center; + padding: var(--sp-3) var(--sp-5); + border-radius: var(--rad-m); + font-size: var(--fs-m); + font-weight: 600; + cursor: pointer; + transition: 0.15s; + font-family: inherit; + } + :host([data-pointer-hover]) .tab:hover { + color: var(--hp-txt); + } + .tab.active { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + } + /* docs/CANVAS.md §4.1: objects an order of magnitude away from the plan + do not decide the opening view — one quiet chip says so and offers to + take them in. Never a modal (owner). */ + .farhint { + position: absolute; + left: 50%; + transform: translateX(-50%); + bottom: var(--sp-4); + z-index: 12; + display: flex; + align-items: center; + gap: var(--sp-2); + max-width: calc(100% - var(--sp-8)); + background: var(--card-background-color, var(--hp-bg)); + opacity: 0.94; + color: var(--hp-txt); + border: 1px solid var(--divider-color, #33404d); + border-radius: var(--rad-m); + padding: var(--sp-1) var(--sp-3); + font-size: var(--fs-s); + } + .farhint ha-icon { + --mdc-icon-size: 18px; + color: var(--hp-warn, #e2a03f); + flex: none; + } + .farhint span { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .dropbtn { + display: flex; + align-items: center; + gap: var(--sp-4); + width: 100%; + text-align: left; + border: 1px solid var(--hp-muted); + border-radius: var(--rad-m); + background: transparent; + color: var(--hp-txt); + padding: var(--sp-4) 10px; + cursor: pointer; + font-family: inherit; + font-size: var(--fs-m); + margin-top: var(--sp-3); + } + .dropbtn .ref { color: var(--hp-muted); font-size: var(--fs-s); margin-left: auto; } + .dropbtn ha-icon { --mdc-icon-size: 18px; margin-left: var(--sp-2); } + .dropbtn.open { border-color: var(--hp-accent); } + .droppanel { + border: 1px solid var(--hp-accent); + border-top: none; + border-radius: 0 0 var(--rad-m) var(--rad-m); + padding: var(--sp-3); + margin-top: -4px; + } + .hdr.kioskhide { display: none; } + .decorbar .dcolor { + width: 30px; height: 26px; padding: 0; border: none; background: none; cursor: pointer; + } + .decorbar .dwidth { + font-family: inherit; font-size: var(--fs-s); border-radius: var(--rad-s); + background: var(--hp-bg2, transparent); color: var(--hp-txt); border: 1px solid var(--hp-muted); + padding: var(--sp-2) var(--sp-3); + } + .decorbar .bdhint { + font-size: var(--fs-s); + color: var(--hp-muted); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .decorbar .dfill { + display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-s); cursor: pointer; + } + .decorbar .dfill input[type="checkbox"] { + width: 16px; + height: 16px; + flex: none; + margin: 0; + padding: 0; + } + .decorbar hp-color-opacity { flex: 0 0 auto; } + .modes { + display: inline-flex; + gap: var(--sp-1); + background: rgba(127, 127, 127, 0.12); + border-radius: var(--rad-l); + padding: var(--sp-2); + } + .modetab { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + border: 0; + background: transparent; + color: var(--hp-muted); + padding: var(--sp-3) 10px; /* 10px h-padding kept: +2px would wrap the header modes row */ + border-radius: var(--rad-m); + font-size: var(--fs-m); + font-weight: 600; + cursor: pointer; + font-family: inherit; + transition: background-color 0.14s ease, color 0.14s ease, transform 0.14s ease; + } + .modetab:active { transform: scale(0.97); } + .modetab ha-icon { --mdc-icon-size: 15px; } + /* issue #220: a tab can be dragged to a new position in the editors */ + .tab[data-reorderable] { cursor: grab; } + .tab.dragging { cursor: grabbing; opacity: 0.55; } + .tab.drop-before { box-shadow: inset 2px 0 0 0 var(--primary-color, #03a9f4); } + .tab.drop-after { box-shadow: inset -2px 0 0 0 var(--primary-color, #03a9f4); } + .modetab .closex { + --mdc-icon-size: 13px; + box-sizing: border-box; + display: inline-flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + min-width: 24px; + min-height: 24px; + /* Keep the old 13 × 13 flex footprint (+2 px left margin) while the + pointer target grows around it. Header width, height and wrapping do + not move; only near-misses that used to hit the active tab reach X. */ + margin: -5.5px -5.5px -5.5px -3.5px; + opacity: 0.75; + cursor: pointer; + border-radius: var(--rad-s); + } + :host([data-pointer-hover]) .modetab .closex:hover { opacity: 1; } + .editbar .barclose { + box-sizing: border-box; + width: 40px; + height: 40px; + padding: 0; + margin: 0; + min-width: 40px; + min-height: 40px; + justify-content: center; + gap: 0; + line-height: 0; + } + .editbar .barclose ha-icon { flex: none; margin: 0; } + .modetab.active { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + } + @media (max-width: 720px) { + .modetab .ml { display: none; } + } + .editbar { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + align-items: stretch; + border-bottom: 1px solid var(--hp-line); + font-size: var(--fs-m); + } + .editbar-tools { + display: flex; + align-items: center; + gap: 10px; + padding: var(--sp-4) var(--sp-5); + flex-wrap: wrap; + min-width: 0; + outline: none; + } + .editbar-end { + display: flex; + align-items: center; + padding: var(--sp-4) var(--sp-5); + border-inline-start: 1px solid var(--hp-line); + background: var(--card-background-color, var(--hp-bg)); + position: relative; + z-index: 2; + } + .tab .tabedit { + --mdc-icon-size: 13px; + display: inline-flex; + align-items: center; + margin-left: var(--sp-3); + opacity: 0.4; + } + :host([data-pointer-hover]) .tab:hover .tabedit { + opacity: 0.9; + } + .tab.tabadd { + padding: var(--sp-3) var(--sp-4); + } + .tab.tabadd ha-icon { + --mdc-icon-size: 15px; + } + .rhint { + font-size: var(--fs-s); + color: var(--hp-muted); + margin-bottom: var(--sp-3); + } + .togglehint { + overflow-wrap: anywhere; + } + .togglehint > div + div { + margin-top: var(--sp-1); + } + /* Keep the last editor bar mounted while the row collapses. This makes + both entering and leaving an editor change the card geometry gradually; + the header ResizeObserver keeps the stage fitted throughout. */ + .editorchrome { + display: block; + height: 0; + opacity: 0; + visibility: hidden; + overflow: hidden; + } + .editorchrome:not(.open) { + pointer-events: none; + } + .editorchrome.open { + height: auto; + opacity: 1; + visibility: visible; + overflow: visible; + } + .editorchrome.transitioning { + overflow: hidden; + will-change: height; + pointer-events: none; + } + /* The toolbar is already visible while its height is interpolating. Its + explicit navigation control must remain usable even though all editing + tools stay frozen until the transition settles. */ + .editorchrome.transitioning .barclose { + pointer-events: auto; + } + .editorchrome-inner { + min-height: 0; + transform-origin: top center; + } + .editorchrome.transitioning .editorchrome-inner { + will-change: opacity; + } + @media (prefers-reduced-motion: reduce) { + .modetab { transition: none; } + } + .editbar .warn { + color: #ffc14d; + } + .editbar .sname { + font-weight: 600; + } + .editbar input { + width: 74px; + background: transparent; + border: 1px solid var(--hp-line); + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + font-size: var(--fs-m); + } + .editbar label, + .editbar .hint { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .editbar .drawwall { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + white-space: nowrap; + } + .editbar .wallsgroup { + display: inline-flex; + align-items: center; + gap: 10px; + white-space: nowrap; + } + .editbar .drawwall input { + width: 4.2em; + } + .editbar .drawwall .opl { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .menuwrap { + position: fixed; + inset: 0; + z-index: 80; + } + .menu { + position: fixed; + background: var(--hp-bg); + border: 1px solid var(--hp-accent); + border-radius: var(--rad-l); + box-shadow: var(--shadow-2); + min-width: 210px; + max-width: 300px; + overflow: hidden; + transform: translate(0, 8px); + } + .menu .hd { + padding: var(--sp-4) var(--sp-5); + font-weight: 600; + font-size: var(--fs-m); + border-bottom: 1px solid var(--hp-line); + display: flex; + align-items: center; + gap: var(--sp-3); + } + .menu .hd ha-icon, + .menu .it.all ha-icon { + color: var(--hp-accent); + --mdc-icon-size: 16px; + } + .menu .it { + padding: var(--sp-4) var(--sp-5); + font-size: var(--fs-m); + cursor: pointer; + display: flex; + align-items: center; + gap: var(--sp-4); + } + .menu .it ha-icon { + --mdc-icon-size: 16px; + color: var(--hp-muted); + } + :host([data-pointer-hover]) .menu .it:hover { + background: rgba(127, 127, 127, 0.15); + } + .menu .it.all { + color: var(--hp-accent); + font-weight: 600; + } + .tip { + position: fixed; + pointer-events: none; + background: var(--hp-bg); + border: 1px solid var(--hp-accent); + color: var(--hp-txt); + padding: var(--sp-3) 10px; + border-radius: var(--rad-m); + font-size: var(--fs-m); + box-shadow: var(--shadow-2); + z-index: 60; + max-width: 260px; + } + .tip .m { + color: var(--hp-muted); + font-size: var(--fs-s); + display: block; + } +`,o` + .head { + display: flex; + align-items: center; + gap: 10px; + padding: 10px var(--sp-5); + border-bottom: 1px solid var(--hp-line); + flex-wrap: wrap; + } + .title { + font-size: var(--fs-l); + font-weight: 600; + display: flex; + align-items: center; + gap: var(--sp-3); + white-space: nowrap; + } + .title ha-icon { + color: var(--hp-accent); + --mdc-icon-size: 18px; + } + @media (max-width: 620px) { + .head { gap: var(--sp-3); padding: var(--sp-4) 10px; } + .head .count { display: none; } + .head .title { font-size: var(--fs-m); } + } + .count { + font-size: var(--fs-s); + color: var(--hp-muted); + } + .btn { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + border: 1px solid var(--hp-line); + background: transparent; + color: var(--hp-txt); + padding: var(--sp-3) 10px; + border-radius: var(--rad-m); + cursor: pointer; + transition: 0.15s; + font-family: inherit; + font-size: var(--fs-m); + } + .btn ha-icon { + --mdc-icon-size: 17px; + } + :host([data-pointer-hover]) .btn:hover { + border-color: var(--hp-accent); + } + .btn.on { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + border-color: var(--hp-accent); + } + .btn.ghost { + border: none; + } + .btn[disabled] { + opacity: 0.5; + pointer-events: none; + } + /* the compass dial in the general settings (docs/SUN.md) */ + .sunrow { + display: flex; + align-items: center; + gap: var(--sp-5); + margin: var(--sp-3) 0; + } + .suncol { + flex: 1; + display: flex; + flex-direction: column; + gap: var(--sp-3); + min-width: 0; + } + .recoveryoverlay { + position: absolute; + inset: 0; + /* Above the contextual editor tray (70): recovery is the one state in + which every stage-editing surface must be inert. Dialogs live outside + the stage and retain their own higher card-level stacking context. */ + z-index: 75; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: var(--sp-4); + padding: var(--sp-6); + box-sizing: border-box; + /* The final solid layer guarantees an opaque recovery surface even when + a custom HA theme exposes its card colour as rgba(). */ + background: + linear-gradient(var(--ha-card-background, var(--card-background-color, #111)), + var(--ha-card-background, var(--card-background-color, #111))), + #111; + color: var(--primary-text-color, #fff); + text-align: center; + pointer-events: auto; + transition: opacity 0.15s ease; + } + .recoveryoverlay.phase-entering, + .recoveryoverlay.phase-leaving { + opacity: 0; + } + .recoveryoverlay.phase-fading-in, + .recoveryoverlay.phase-opaque { + opacity: 1; + } + .recoveryoverlay ha-icon { + --mdc-icon-size: 44px; + color: var(--hp-accent); + } + .editorloading { + position: absolute; + z-index: 74; + left: 50%; + top: 50%; + display: flex; + align-items: center; + gap: var(--sp-3); + padding: var(--sp-3) var(--sp-5); + border: 1px solid color-mix(in srgb, var(--hp-accent) 45%, transparent); + border-radius: 999px; + background: color-mix(in srgb, + var(--ha-card-background, var(--card-background-color, #111)) 92%, transparent); + color: var(--primary-text-color); + box-shadow: 0 6px 22px rgb(0 0 0 / 18%); + transform: translate(-50%, -50%); + pointer-events: none; + animation: editor-loading-in 0.15s ease both; + } + .editorloading ha-icon { + --mdc-icon-size: 22px; + color: var(--hp-accent); + animation: editor-loading-spin 0.9s linear infinite; + } + @keyframes editor-loading-in { + from { opacity: 0; transform: translate(-50%, calc(-50% + 4px)); } + to { opacity: 1; transform: translate(-50%, -50%); } + } + @keyframes editor-loading-spin { to { transform: rotate(360deg); } } + @media (prefers-reduced-motion: reduce) { + .recoveryoverlay, + .editorloading, + .editorloading ha-icon { + transition: none; + animation: none; + } + } + .oplock { + --oplock-size: calc(var(--icon-size, 2.5cqw) * 0.62); + --oplock-core-size: calc(var(--oplock-size) / 1.26875); + --oplock-stroke-ratio: 0.01875; + --oplock-stroke-width: max(1px, calc(var(--oplock-core-size) * var(--oplock-stroke-ratio))); + --oplock-core-bg: light-dark(#fff, #252525); + --oplock-core-fg: light-dark(#252525, #fff); + --oplock-shell-stroke: light-dark(#BCBCBC, rgb(37 37 37 / 75%)); + --oplock-shell-shadow: + 0 calc(var(--oplock-core-size) * .025) calc(var(--oplock-core-size) * .05) rgb(37 40 45 / 12%), + 0 calc(var(--oplock-core-size) * .1) calc(var(--oplock-core-size) * .175) + calc(var(--oplock-core-size) * -.025) rgb(37 40 45 / 18%); + --oplock-core-shadow: 0 0 0 0 transparent; + pointer-events: none; /* inert while editing; clickable in View (rule below) */ + position: absolute; + transform: translate(-50%, -50%); + width: var(--oplock-size); + height: var(--oplock-size); + display: grid; + place-items: center; + border: 0; + background: transparent; + z-index: 1; + } + .oplock.theme-light { + --oplock-core-bg: #fff; + --oplock-core-fg: #252525; + --oplock-shell-stroke: #BCBCBC; + } + .oplock.theme-dark { + --oplock-core-bg: #252525; + --oplock-core-fg: #fff; + --oplock-shell-stroke: rgb(37 37 37 / 75%); + --oplock-core-shadow: + inset 0 calc(var(--oplock-core-size) * .0125) + calc(var(--oplock-core-size) * .0125) rgb(255 255 255 / 70%); + } + .oplock-shell { + box-sizing: border-box; + width: 100%; + height: 100%; + border: var(--oplock-stroke-width) solid var(--oplock-shell-stroke); + border-radius: 50%; + background: transparent; + box-shadow: var(--oplock-shell-shadow); + display: grid; + place-items: center; + pointer-events: none; + backdrop-filter: none; + } + .oplock-core { + width: var(--oplock-core-size); + height: var(--oplock-core-size); + border-radius: 50%; + background: var(--oplock-core-bg); + color: var(--oplock-core-fg); + box-shadow: var(--oplock-core-shadow); + display: grid; + place-items: center; + pointer-events: none; + } + .oplock ha-icon { + --mdc-icon-size: calc(var(--oplock-core-size) * 0.55); + display: flex; + line-height: 0; + } + .oplock.locked { + --oplock-core-bg: #66D17A; + --oplock-core-fg: light-dark(#fff, #252525); + --oplock-shell-stroke: #66D17A; + } + .oplock.theme-light.locked { --oplock-core-fg: #fff; } + .oplock.theme-dark.locked { + --oplock-core-fg: #252525; + --oplock-stroke-ratio: .025; + } + .oplock.unlocked { + --oplock-core-bg: #F0410C; + --oplock-core-fg: light-dark(#fff, #252525); + --oplock-shell-stroke: #F0410C; + } + .oplock.theme-light.unlocked { --oplock-core-fg: #fff; } + .oplock.theme-dark.unlocked { + --oplock-core-fg: #252525; + --oplock-stroke-ratio: .025; + } + .oplock.unknown { --oplock-core-fg: var(--hp-muted); } + .btn.lockact { + width: 100%; + justify-content: center; + display: flex; + align-items: center; + gap: var(--sp-3); + margin-top: var(--sp-4); + } + .btn.lockact.warn { + color: var(--error-color, #d33); + border-color: var(--error-color, #d33); + } + .oprow { + display: flex; + align-items: center; + gap: var(--sp-4); + padding: var(--sp-3) 0; + } + .oprow b { margin-left: auto; } + .oprow.ok b { color: #66d17a; } + .oprow.warn b { color: var(--hp-open); } + .bindharow { + display: flex; + align-items: center; + gap: var(--sp-5); + flex-wrap: wrap; + } + .bindharow .entcheck { opacity: 0.9; } + .ctrlchips { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin: var(--sp-2) 0; } + .ctrlchip { + display: inline-flex; align-items: center; gap: var(--sp-2); + background: var(--hp-accent); color: var(--text-primary-color, #fff); + border-radius: var(--rad-l); padding: var(--sp-2) var(--sp-4); font-size: var(--fs-s); + } + .ctrlchip ha-icon { --mdc-icon-size: 14px; cursor: pointer; } + .ctrllist { display: flex; flex-direction: column; gap: var(--sp-1); margin-top: var(--sp-2); } + .ctrlopt { + display: flex; align-items: center; gap: var(--sp-4); text-align: left; + border: 0; background: transparent; color: var(--hp-txt); + padding: var(--sp-3) var(--sp-4); border-radius: var(--rad-s); cursor: pointer; font-family: inherit; font-size: var(--fs-m); + } + :host([data-pointer-hover]) .ctrlopt:hover { + background: var(--secondary-background-color, rgba(128,128,128,0.15)); + } + .ctrlopt .sub { color: var(--hp-muted); font-size: var(--fs-s); margin-left: auto; } + .ctrlopt ha-icon { --mdc-icon-size: 16px; } + .ctrlstates { display: flex; flex-direction: column; gap: var(--sp-2); } + .ctrlstate { display: inline-flex; align-items: center; gap: var(--sp-3); color: var(--hp-muted); } + .ctrlstate.on { color: var(--hp-txt); } + .ctrlstate ha-icon { --mdc-icon-size: 15px; } + .cardpreview { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--sp-2); + margin: var(--sp-4) 0 var(--sp-1); + padding: 10px; + border: 1px dashed var(--hp-muted); + border-radius: var(--rad-m); + } + .cardpreview .cpname { font-weight: 700; letter-spacing: 0.04em; } + .cardpreview .cpmeta { + display: inline-flex; + align-items: center; + gap: 0.3em; + font-weight: 600; + opacity: 0.85; + } + .cardpreview .cpmeta ha-icon { --mdc-icon-size: 1.05em; } + .iconauto { + display: flex; + align-items: center; + gap: var(--sp-3); + font-size: var(--fs-s); + margin: var(--sp-2) 0 0; + } + .iconauto ha-icon { --mdc-icon-size: 18px; } + .iconauto span { flex: 1; } + .iconauto .btn { min-height: 32px; padding: 0 var(--sp-3); } + hp-dialog .dfill { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + cursor: pointer; + } + .wallthick-dlg { + position: absolute; + z-index: 40; + min-width: 200px; + transform: translate(-50%, 8px); + padding: 10px 12px; + border-radius: 10px; + background: var(--card-background-color, #fff); + box-shadow: 0 8px 28px rgba(0,0,0,.22); + display: flex; + flex-direction: column; + gap: 8px; + pointer-events: auto; + } + .wallthick-dlg .row { + display: flex; + align-items: center; + gap: 8px; + } + .wallthick-dlg input[type="number"] { + width: 5.5em; + padding: 4px 6px; + border: 1px solid var(--divider-color, #ccc); + border-radius: 6px; + background: var(--input-fill, transparent); + color: var(--primary-text-color); + } + .areasel, + .namein { + background: var(--hp-bg); + border: 1px solid var(--hp-line); + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + font-size: var(--fs-m); + font-family: inherit; + } + .namein { + width: 130px; + } + .habindingbanner { + display: flex; + align-items: center; + gap: var(--sp-3); + padding: var(--sp-3) var(--sp-4); + margin-bottom: var(--sp-4); + border: 1px solid var(--warning-color, #ff9800); + border-radius: var(--rad-m); + background: color-mix(in srgb, var(--warning-color, #ff9800) 12%, transparent); + color: var(--primary-text-color, #f1f3f6); + } + .habindingbanner > span { flex: 1; min-width: 0; } + .habindingbanner > ha-icon { color: var(--warning-color, #ff9800); flex: 0 0 auto; } + .habindingbanner.limited { + border-color: var(--secondary-text-color, #9aa0aa); + background: color-mix(in srgb, var(--secondary-text-color, #9aa0aa) 10%, transparent); + } + .habindingbanner.limited > ha-icon { color: var(--secondary-text-color, #9aa0aa); } + .srcrow { + display: flex; + align-items: center; + gap: var(--sp-4); + font-size: var(--fs-m); + cursor: pointer; + padding: var(--sp-1) 0; + } + .dispsection { + margin-top: var(--sp-5) !important; + padding-top: var(--sp-4); + border-top: 1px solid var(--hp-line); + font-weight: 600; + color: var(--hp-txt) !important; + } + .colorrow { + display: flex; + align-items: center; + gap: var(--sp-4); + } + .gsrow > hp-color-opacity { + min-width: min(100%, 210px); + justify-content: space-between; + } + .ripple-colorrow > hp-color-opacity { + width: 100%; + justify-content: space-between; + } + .ripple-sizerow > .opl { + min-width: 0; + } + .colorrow input[type='range'] { flex: 1; } + .colorrow .tempin { width: 70px; flex: none; } + /* beat the generic hp-dialog .body .namein { width:100% } rule */ + hp-dialog .body .temprange .tempin { width: 56px; flex: none; padding: var(--sp-2) var(--sp-3); } + hp-dialog .body .colorrow .tempin { width: 72px; flex: none; } + .srcrow { flex-wrap: nowrap; } + /* native HA controls (rendered only when the HA frontend defines them; + old HA and the smoke env keep the plain inputs). ha-switch is taller + than a checkbox - cap its footprint so .srcrow keeps its rhythm. */ + .srcrow ha-switch { flex: none; } + .colorrow ha-slider { flex: 1; min-width: 0; } + .srcrow > span:first-of-type { white-space: nowrap; } + .colorrow .opl { color: var(--hp-muted); font-size: var(--fs-s); } + .colorrow .opv { font-size: var(--fs-s); min-width: 34px; text-align: right; } + .markerlightgroup { + min-width: 0; + margin: var(--sp-5) 0 0; + padding: var(--sp-4); + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + } + .markerlightgroup legend { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: var(--sp-1); + padding: 0 var(--sp-2); + color: var(--hp-txt); + font-weight: 600; + } + .markerlightgroup legend > span { min-width: 0; overflow-wrap: anywhere; } + .markerlightgroup[disabled] > :not(legend) { opacity: .62; } + .markerhelpfield { margin-top: var(--sp-4); } + .markerhelplabel { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: var(--sp-1); + margin-bottom: var(--sp-1); + } + .markerhelplabel > label { min-width: 0; overflow-wrap: anywhere; } + .markerradios { display: grid; gap: var(--sp-1); min-width: 0; } + .markerlightgroup .srcrow > span:first-of-type { + min-width: 0; + white-space: normal; + overflow-wrap: anywhere; + } + .markerglowvalue { margin: var(--sp-3) 0; flex-wrap: wrap; } + .markerglowvalue hp-color-opacity { flex: none; } + .markerlightdisabled { + display: flex; + align-items: center; + gap: var(--sp-2); + margin-top: var(--sp-2) !important; + } + .markerlightdisabled ha-icon { --mdc-icon-size: 18px; flex: none; } + .markerbadgetechnical { + min-width: 0; + margin: var(--sp-1) 0 var(--sp-2) !important; + overflow-wrap: anywhere; + } + .markerbadgetechnical code { white-space: normal; } + .planrow { + display: flex; + align-items: center; + gap: 10px; + } + /* the "already uploaded" picker: a plan is never deleted for being + unreferenced, so it has to be findable again */ + .savedplans { + display: flex; + flex-direction: column; + gap: var(--sp-3); + max-height: 240px; + overflow: auto; + margin: var(--sp-3) 0 var(--sp-1); + padding: var(--sp-3); + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + background: var(--hp-bg2, rgba(255, 255, 255, 0.03)); + /* The same collapse that ate .candlist (v1.53.1): a scroll box is a + flex item whose automatic minimum size is ZERO (overflow != visible), + so inside hp-dialog .body — a flex column taller than its 66vh cap — + it shrank to a 14px sliver: the rows were in the DOM, the owner saw + a thin rounded stripe under the "Already uploaded" button. Don't + shrink, and keep a floor even when the box is empty or loading. */ + flex: 0 0 auto; + min-height: 2.6em; + } + .savedplan { + display: flex; + align-items: center; + gap: 10px; + } + .savedplan.cur { outline: 1px solid var(--hp-accent); border-radius: var(--rad-s); } + .savedplan img { + width: 56px; + height: 40px; + object-fit: contain; + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + background: #fff; + flex: none; + } + .savedmeta { display: flex; flex-direction: column; min-width: 0; flex: 1; } + .savedmeta b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + .savedmeta .muted { font-size: var(--fs-s); } + .savedplan .btn.danger ha-icon { color: #f25a4a; } + .savedplan .btn[disabled] { opacity: 0.4; pointer-events: none; } + .planprev { + max-width: 120px; + max-height: 70px; + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + background: #fff; + } + .planname { + font-size: var(--fs-m); + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .planname.muted { + color: var(--hp-muted); + } + .filebtn { + cursor: pointer; + } + .fileupload { display: inline-flex; min-width: 0; } + .fileupload > input { display: none; } + .btn.danger { + border-color: #b3402a; + color: #ff7a5c; + } + hp-dialog .row .spacer { + flex: 1; + } + hp-dialog .body { + max-height: 66vh; + overflow-y: auto; + } + .descin { + width: 100%; + box-sizing: border-box; + background: var(--hp-bg); + border: 1px solid var(--hp-line); + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + font-size: var(--fs-m); + font-family: inherit; + resize: vertical; + /* flex column of the dialog body squeezes textareas — keep a usable height */ + min-height: 92px; + flex-shrink: 0; + line-height: 1.35; + } + .bindsel { + display: flex; + flex-direction: column; + gap: var(--sp-3); + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + padding: var(--sp-4); + } + .bindsel .opt { + display: flex; + align-items: center; + gap: var(--sp-3); + border: 1px solid var(--hp-line); + background: transparent; + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + cursor: pointer; + font-size: var(--fs-m); + font-family: inherit; + } + .bindsel .opt.on { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + border-color: var(--hp-accent); + } + .curbind { + display: flex; + align-items: center; + gap: var(--sp-3); + font-size: var(--fs-m); + color: var(--hp-txt); + flex-wrap: wrap; + } + .curbind .ref { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .vacbox .vacbtns { display: flex; gap: var(--sp-4); margin: var(--sp-3) 0; flex-wrap: wrap; } + .vacdiag { display: grid; gap: 4px; margin-bottom: var(--sp-3); } + .vacdiag > div { display: flex; justify-content: space-between; gap: var(--sp-5); } + .vacdiag > div > span { color: var(--secondary-text-color); } + .vacdiag > div > b { text-align: right; overflow-wrap: anywhere; } + .vacpicker { margin: var(--sp-3) 0; } + .vacsource-warning { display: grid; gap: 8px; } + .vacsource-warning .btn { justify-self: start; } + .vacpicker > summary { display: inline-flex; width: auto; list-style: none; cursor: pointer; } + .vacpicker > summary::-webkit-details-marker { display: none; } + .vacsource-list { display: grid; gap: 6px; margin-top: 8px; } + .vacsource-list details { padding: 6px 0 0; } + .vacsource-list details > summary { cursor: pointer; font-weight: 600; } + .vacsource { display: flex; align-items: center; justify-content: space-between; gap: 12px; + width: 100%; min-width: 0; padding: 9px 10px; border: 1px solid var(--divider-color); + border-radius: 10px; color: var(--primary-text-color); background: var(--secondary-background-color); + text-align: left; cursor: pointer; } + .vacsource.on { border-color: var(--accent-color); box-shadow: inset 3px 0 var(--accent-color); } + .vacsource > span:first-child { min-width: 0; display: grid; gap: 2px; } + .vacsource small { color: var(--secondary-text-color); overflow-wrap: anywhere; } + .vacsource-meta { color: var(--secondary-text-color); text-align: right; font-size: 0.82em; } + .vacxcme pre { margin: 8px 0 0; white-space: pre-wrap; user-select: text; } + .vacfit { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + z-index: 12; + overflow: visible; + touch-action: none; + cursor: grab; + /* the devlayer is pointer-events: none and every child opts back in — + without this line real clicks flew straight through the overlay + (owner: «уголки не кликабельны»; synthetic smoke events bypass + hit-testing, which is why they lied) */ + pointer-events: auto; + } + .vacfit:active { cursor: grabbing; } + .vacfit polygon { + fill: color-mix(in srgb, var(--hp-accent) 16%, transparent); + stroke: var(--hp-accent); + stroke-width: 2; + vector-effect: non-scaling-stroke; + stroke-dasharray: 6 4; + } + .vacfit text { + fill: var(--hp-accent); + font-size: 26px; + text-anchor: middle; + dominant-baseline: middle; + pointer-events: none; + user-select: none; + } + /* ---- the furniture palette (docs/FURNITURE.md §3) ------------------- */ + .furnpalette { + display: flex; + flex-direction: column; + max-height: 38vh; + border-top: 1px solid var(--hp-border, rgba(255, 255, 255, 0.12)); + background: var(--card-background-color, var(--hp-bg)); + font-size: 0.85em; + } + .furnhd { + display: flex; + align-items: center; + gap: 6px; + padding: 4px 8px; + font-weight: 600; + opacity: 0.9; + } + .furnhd .spacer { flex: 1; } + .furnbody { + overflow: auto; + padding: 0 8px 6px; + } + .furngroup { + margin: 6px 0 3px; + font-size: 0.85em; + text-transform: uppercase; + letter-spacing: 0.04em; + opacity: 0.6; + } + .furnrow { + display: flex; + flex-wrap: wrap; + gap: 4px; + } + .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; } + .vacfitdot { fill: var(--hp-accent); pointer-events: none; } + /* hit target: invisible and finger-sized; .vacfitknob is the visible bead */ + .vacfithandle { + fill: transparent; + stroke: none; + cursor: nwse-resize; + } + .vacfitknob { + fill: var(--hp-bg); + stroke: var(--hp-accent); + stroke-width: 2; + vector-effect: non-scaling-stroke; + pointer-events: none; + } + .vaccalbar { + position: fixed; + left: 50%; + bottom: 24px; + transform: translateX(-50%); + display: flex; + gap: var(--sp-5); + align-items: center; + background: var(--hp-bg); + color: var(--hp-txt); + border: 1px solid var(--hp-accent); + border-radius: var(--rad-l); + padding: 10px var(--sp-5); + z-index: 60; + box-shadow: var(--shadow-2); + } + .candlist { + max-height: 160px; + overflow-y: auto; + border-top: 1px solid var(--hp-line); + /* A scrollable box is a flex item that HAPPILY collapses: inside the + dialog body (a flex column) this list rendered its rows into a 1px + sliver — the DOM had 26 candidates and the user saw nothing. In the + binding dropdown it sits inside .droppanel (block context) and never + showed the bug. Field report, 2026-07-30. */ + flex: 0 0 auto; + min-height: 2.6em; + } + .cand { + display: flex; + justify-content: space-between; + gap: var(--sp-4); + padding: var(--sp-3) var(--sp-4); + cursor: pointer; + border-radius: var(--rad-s); + font-size: var(--fs-m); + } + :host([data-pointer-hover]) .cand:hover { + background: rgba(127, 127, 127, 0.15); + } + .cand.sel { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + } + .cand .cs { + color: var(--hp-muted); + font-size: var(--fs-s); + white-space: nowrap; + } + .opening-entity-candidate { + width: 100%; + border: 0; + background: transparent; + color: inherit; + font: inherit; + text-align: left; + } + .opening-entity-candidate.sel { + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + } + .opening-entity-empty { cursor: default; } + .cand.sel .cs { + color: var(--text-primary-color, #fff); + opacity: 0.85; + } + .cand.muted { + color: var(--hp-muted); + cursor: default; + } + .pdfedit { + display: flex; + flex-wrap: wrap; + gap: var(--sp-3); + align-items: center; + } + .pdftag { + display: inline-flex; + align-items: center; + gap: var(--sp-2); + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + padding: var(--sp-2) var(--sp-3); + font-size: var(--fs-s); + } + .pdftag a { + color: var(--hp-txt); + text-decoration: none; + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .pdftag .x { + --mdc-icon-size: 15px; + cursor: pointer; + color: var(--hp-muted); + } + :host([data-pointer-hover]) .pdftag .x:hover { + color: #ff7a5c; + } + .entlist { + display: flex; + flex-direction: column; + gap: var(--sp-2); + margin-bottom: 10px; + } + .entrow { + display: flex; + align-items: center; + gap: var(--sp-4); + padding: var(--sp-3) var(--sp-4); + border-radius: var(--rad-m); + background: var(--secondary-background-color, rgba(128, 128, 128, 0.12)); + } + .entrow ha-icon { --mdc-icon-size: 20px; color: var(--hp-muted); } + .entrow.on ha-icon { color: var(--hp-accent); } + .entrow .en { flex: 1; font-size: var(--fs-m); } + .entrow .ev { font-size: var(--fs-m); color: var(--hp-muted); } + .entbtn { + min-width: 74px; + min-height: 32px; + padding: var(--sp-2) var(--sp-5); + border: 1px solid var(--hp-muted); + border-radius: 999px; + background: transparent; + color: var(--hp-txt); + font: inherit; + font-size: var(--fs-m); + cursor: pointer; + } + .entbtn.on { + background: var(--hp-accent); + border-color: var(--hp-accent); + color: var(--text-primary-color, #fff); + font-weight: 600; + } + .inforow { + display: flex; + gap: 10px; + font-size: var(--fs-m); + margin: var(--sp-2) 0; + } + .inforow .k { + color: var(--hp-muted); + min-width: 84px; + } + .inforow a { + color: var(--hp-accent); + word-break: break-all; + } + .infodesc { + font-size: var(--fs-m); + white-space: pre-wrap; + margin-top: var(--sp-3); + } + .infodesc.muted { + color: var(--hp-muted); + } + .pdflist { + display: flex; + flex-direction: column; + gap: var(--sp-2); + } + .pdf { + display: inline-flex; + align-items: center; + gap: var(--sp-2); + color: var(--hp-accent); + text-decoration: none; + } + ha-icon-picker { + display: block; + } + .floorrow { + display: flex; + align-items: center; + gap: var(--sp-4); + padding: var(--sp-3) var(--sp-2); + font-size: var(--fs-m); + cursor: pointer; + } + .floorrow .floorlvl { + color: var(--hp-muted); + font-size: var(--fs-s); + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + padding: 0 var(--sp-3); + } + .rtest { + display: flex; + align-items: center; + gap: var(--sp-4); + margin-bottom: var(--sp-4); + } + .rtest .namein { flex: 1; } + .rtest ha-icon { color: var(--hp-accent); } + .rtesticon { font-size: var(--fs-s); color: var(--hp-muted); } + .rrow { + display: flex; + align-items: center; + gap: var(--sp-3); + margin: var(--sp-1) 0; + } + .rrow .rpat { flex: 2; } + .rrow .ricon { flex: 1.4; } + .rrow .rpat.bad { border-color: #ff7a5c; } + .rrow .rprev { --mdc-icon-size: 18px; color: var(--hp-txt); min-width: 18px; } + .rrow .ract { + --mdc-icon-size: 16px; + color: var(--hp-muted); + cursor: pointer; + } + :host([data-pointer-hover]) .rrow .ract:hover { color: var(--hp-txt); } + :host([data-pointer-hover]) .rrow .ract.del:hover { color: #ff7a5c; } + .gsrow .gsl { + min-width: 150px; + font-size: var(--fs-m); + color: var(--hp-muted); + } + .optimize-live { + display: grid; + justify-items: start; + gap: var(--sp-2); + margin-bottom: var(--sp-3); + } + .optimize-live .alignmsg, .optimize-live .rhint { margin-bottom: 0; } + .optimize-cleanup { min-height: 44px; } + .optimize-selected { color: var(--hp-txt); } + .optimize-details { + margin-top: var(--sp-3); + color: var(--hp-muted); + font-size: var(--fs-s); + overflow-wrap: anywhere; + } + .optimize-details > summary { + width: fit-content; + color: var(--hp-txt); + cursor: pointer; + font-weight: 600; + } + .optimize-details > summary:focus-visible { + outline: 2px solid var(--hp-accent); + outline-offset: 3px; + border-radius: var(--rad-s); + } + .optimize-details ul { margin: var(--sp-3) 0; padding-inline-start: 22px; } + .optimize-details li + li { margin-top: var(--sp-1); } + .btn.alignall { width: 100%; justify-content: center; } + .backupactions { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--sp-3); + } + .backupactions .btn { justify-content: center; min-width: 0; } + .backupupload { display: inline-flex; min-width: 0; } + .backupupload > .btn { width: 100%; justify-content: center; } + .backupupload input { display: none; } + .backupbody { min-width: 0; } + .backupplanonly { margin-inline-start: var(--sp-4) !important; align-items: flex-start !important; } + .backupplanonly > span:first-of-type { display: grid; gap: 2px; white-space: normal; } + .backupplanonly small { color: var(--secondary-text-color); line-height: 1.35; } + .backupplanonlystatus { color: var(--hp-accent) !important; font-weight: 700; } + .backupfile, .backupsummary, .backupcontent { + display: flex; + flex-direction: column; + min-width: 0; + gap: var(--sp-1); + } + .backupfile b, .backupcontent span { + overflow-wrap: anywhere; + } + .backupfile span, .backupsummary span, .backupcontent span { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .backupcounts { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--sp-2) var(--sp-4); + font-size: var(--fs-s); + } + .backupwarn, .backuperror { + border-radius: var(--rad-s); + padding: var(--sp-3); + font-size: var(--fs-s); + line-height: 1.45; + overflow-wrap: anywhere; + } + .backupwarn { background: color-mix(in srgb, var(--hp-accent) 12%, transparent); } + .backuperror { background: rgba(179, 64, 42, .16); color: #ff7a5c; } + .backupdetails { + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + padding: var(--sp-2) var(--sp-3); + font-size: var(--fs-s); + } + .backupdetails summary { cursor: pointer; font-weight: 700; } + .backupdetails > div { display: grid; gap: var(--sp-1); padding-block-start: var(--sp-2); } + .backupdetails code { overflow-wrap: anywhere; color: var(--hp-muted); } + .backupchoices { + display: flex; + flex-direction: column; + gap: var(--sp-2); + border: 1px solid var(--hp-line); + border-radius: var(--rad-s); + min-width: 0; + } + .backupchoices label { margin: 0 !important; display: flex; gap: var(--sp-2); } + .backupconfirm { align-items: flex-start !important; } + .backupconfirm > span:first-of-type { + min-width: 0; + white-space: normal; + overflow-wrap: anywhere; + } + @media (max-width: 520px) { + .backupactions, .backupcounts { grid-template-columns: 1fr; } + } + .aboutver { + font-size: var(--fs-s); + color: var(--hp-muted); + margin: var(--sp-2) 0 var(--sp-3); + } + .aboutlink { + display: flex; + align-items: center; + gap: var(--sp-3); + width: fit-content; + color: var(--hp-accent); + text-decoration: none; + font-size: var(--fs-m); + padding: var(--sp-1) 0; + } + :host([data-pointer-hover]) .aboutlink:hover { text-decoration: underline; } + .aboutlink ha-icon { --mdc-icon-size: 18px; line-height: 1; } + hp-dialog .body { + padding: var(--sp-5) var(--sp-6); + display: flex; + flex-direction: column; + gap: var(--sp-3); + } + hp-dialog .tapconfirm-body { + min-width: 0; + overflow-x: hidden; + } + hp-dialog .tapconfirm-body p { + max-width: 100%; + min-width: 0; + margin: 0; + overflow-wrap: anywhere; + white-space: normal; + } + hp-dialog .tapconfirm-line { + color: var(--hp-muted); + } + hp-dialog .body label { + font-size: var(--fs-s); + color: var(--hp-muted); + margin-top: var(--sp-3); + } + hp-dialog .body .namein, + hp-dialog .body .areasel { + width: 100%; + box-sizing: border-box; + } + /* Room settings contains long radio labels, two source pickers and live + previews, so it deliberately uses hp-dialog's medium width. Keep its + content shrinkable as well: the generic srcrow rule is nowrap because + compact switch rows need it, but here that created a horizontal scroll + box even on a wide desktop viewport. */ + hp-dialog.roomdialog .body { + min-width: 0; + overflow-x: hidden; + } + hp-dialog.roomdialog .body > * { + min-width: 0; + max-width: 100%; + box-sizing: border-box; + } + hp-dialog.roomdialog .srcrow { + min-width: 0; + align-items: flex-start; + } + hp-dialog.roomdialog .srcrow > span:first-of-type { + min-width: 0; + white-space: normal; + overflow-wrap: anywhere; + line-height: 1.35; + } + hp-dialog.roomdialog .dropbtn > b, + hp-dialog.roomdialog .dropbtn > .ref { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + hp-dialog .row { + display: flex; + justify-content: flex-end; + gap: var(--sp-4); + width: 100%; + min-width: 0; + box-sizing: border-box; + padding: var(--sp-5) var(--sp-6); + border-top: 1px solid var(--hp-line); + } + /* Stable destructive/commit footer contract. A flex spacer cannot react + when translated labels no longer fit: justify-content then overflows + the destructive button through the left inset. Two real groups wrap + as units instead — destructive actions stay left, while Cancel/Save + move together to a right-aligned second row when necessary. */ + hp-dialog .row.dialog-action-footer { + align-items: center; + justify-content: flex-start; + flex-wrap: wrap; + row-gap: var(--sp-4); + } + hp-dialog .dialog-action-group { + display: flex; + flex: 0 1 auto; + flex-wrap: wrap; + align-items: center; + gap: var(--sp-4); + max-width: 100%; + min-width: 0; + } + hp-dialog .dialog-action-group .btn { + flex: 0 0 auto; + min-height: 44px; + } + hp-dialog .dialog-action-danger { + margin-right: auto; + } + hp-dialog .dialog-action-commit { + margin-left: auto; + justify-content: flex-end; + } + hp-dialog .row.markerfooter { + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + } + hp-dialog .row.roomfooter { + align-items: center; + flex-wrap: wrap; + } + /* Device info can have Edit + Open in HA + Close. It uses a wide dialog; + wrapping remains as a phone fallback, but without a flex spacer (which + used to strand Edit alone on the first line). */ + hp-dialog .row.infofooter { + align-items: center; + justify-content: flex-start; + flex-wrap: wrap; + gap: var(--sp-3); + } + hp-dialog .row.infofooter .btn { + flex-shrink: 0; + } + hp-dialog .row.infofooter .infofooter-close { + margin-left: auto; + } + @media (max-width: 480px) { + hp-dialog .row.infofooter { + padding: var(--sp-4) var(--sp-5); + } + } + .markeractions, + .markersaveactions { + display: flex; + align-items: center; + gap: var(--sp-4); + } + .markeractions:empty { display: none; } + .markersaveactions { margin-left: auto; } + .device-inbox { + display: flex; + flex-direction: column; + gap: var(--sp-4); + padding: var(--sp-5) var(--sp-6); + min-width: 0; + } + .device-inbox-dialog { --hp-dialog-wide-width: 920px; } + .device-inbox-head { + display: grid; + grid-template-columns: minmax(180px, 1fr) auto; + align-items: center; + gap: var(--sp-4); + } + .device-inbox-search { + width: 100%; + min-width: 0; + box-sizing: border-box; + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + background: transparent; + color: var(--hp-txt); + font: inherit; + padding: 11px 14px; + } + .device-inbox-tabs { + display: flex; + gap: var(--sp-2); + overflow-x: auto; + scrollbar-width: thin; + padding-bottom: var(--sp-1); + } + .device-inbox-tabs button { + flex: 0 0 auto; + border: 1px solid var(--hp-line); + border-radius: 999px; + background: transparent; + color: var(--hp-txt); + font: inherit; + padding: 8px 12px; + cursor: pointer; + } + .device-inbox-tabs button.on { + border-color: var(--hp-accent); + background: color-mix(in srgb, var(--hp-accent) 18%, transparent); + } + .device-inbox-tabs button span { color: var(--hp-muted); margin-inline-start: 4px; } + .device-inbox-filters { + display: flex; + flex-wrap: wrap; + gap: var(--sp-4) var(--sp-6); + color: var(--hp-muted); + } + .device-inbox-filters label { + display: inline-flex; + align-items: center; + gap: var(--sp-2); + cursor: pointer; + } + .device-inbox-results { display: grid; gap: var(--sp-3); min-width: 0; } + .device-inbox-row { + display: grid; + grid-template-columns: 42px minmax(180px, 1fr) minmax(180px, auto); + align-items: center; + gap: var(--sp-4); + min-width: 0; + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + padding: var(--sp-4); + background: color-mix(in srgb, var(--hp-txt) 3%, transparent); + } + .device-inbox-icon { --mdc-icon-size: 28px; color: var(--hp-txt); justify-self: center; } + .device-inbox-copy { min-width: 0; } + .device-inbox-name { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2); } + .device-inbox-new { + border-radius: 999px; + background: var(--hp-accent); + color: var(--text-primary-color, #fff); + font-size: var(--fs-s); + padding: 2px 7px; + } + .device-inbox-meta, + .device-inbox-reason, + .device-inbox-copy code { + display: block; + color: var(--hp-muted); + font-size: var(--fs-s); + overflow-wrap: anywhere; + white-space: normal; + } + .device-inbox-status { color: var(--error-color, #db4437); margin-inline-start: var(--sp-2); } + .device-inbox-actions { + display: flex; + justify-content: flex-end; + align-items: center; + flex-wrap: wrap; + gap: var(--sp-2); + } + .device-inbox-actions .btn { min-height: 36px; padding: 7px 10px; } + .device-inbox-menu { position: relative; } + .device-inbox-menu summary { list-style: none; cursor: pointer; } + .device-inbox-menu summary::-webkit-details-marker { display: none; } + .device-inbox-menu-items { + position: absolute; + z-index: 2; + inset-inline-end: 0; + top: calc(100% + var(--sp-1)); + display: grid; + gap: var(--sp-1); + min-width: 180px; + padding: var(--sp-2); + border: 1px solid var(--hp-line); + border-radius: var(--rad-m); + background: var(--hp-panel, var(--card-background-color, #fff)); + box-shadow: 0 8px 24px rgba(0, 0, 0, .22); + } + .device-inbox-menu-items .btn { justify-content: flex-start; width: 100%; } + .device-inbox-empty { color: var(--hp-muted); text-align: center; padding: var(--sp-8); } + .device-inbox-more { align-self: center; } + @media (max-width: 680px) { + .device-inbox { padding: var(--sp-4); } + .device-inbox-head { grid-template-columns: minmax(0, 1fr); } + .device-inbox-head .btn { justify-self: stretch; } + .device-inbox-tabs { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + overflow-x: visible; + } + .device-inbox-tabs button { + min-width: 0; + overflow-wrap: anywhere; + } + .device-inbox-row { grid-template-columns: 36px minmax(0, 1fr); } + .device-inbox-actions { grid-column: 1 / -1; justify-content: flex-start; } + } +`];var Zd={"editor.context_actions":"Actions: {object}","editor.tool_options":"Tool options: {tool}","editor.palette":"Palette: {tool}","editor.open_group":"Tool group: {group}","editor.group_active":"{group} — active: {item}","editor.disabled_action":"{action} is unavailable: {reason}","editor.loading":"Loading editor…","editor.loading_aria":"The plan editor is loading","editor.load_failed":"Could not load the editor.","editor.refresh_advice":"Refresh the page and try again.","editor.retry_advice":"Check your connection and press again.","color_picker.title":"Color picker","color_picker.hue":"Hue","color_picker.saturation":"Saturation","color_picker.value":"Brightness","color_picker.hex":"Hex color","color_picker.invalid_hex":"Enter a 3- or 6-digit hex color","btn.properties":"Properties","btn.keep_as_walls":"Keep as walls","btn.delete_room_keep_walls":"Delete room, keep walls","btn.delete_room_with_walls":"Delete room and walls","title.markup_select":"Select and edit walls, columns and saved outlines","title.markup_column":"Column: click a grid point to place a square column","markup.partition":"Partition","markup.column":"Column","markup.hint_column":"click a grid point to place a square column","history.draft_segment":"Add room-draft segment","history.draft_merge":"Join unfinished room outlines","history.draft_segment_delete":"Remove room-draft segment","history.partition_add":"Add partition","history.column_add":"Add column","history.physical_edit":"Change physical object","history.physical_delete":"Delete physical object","history.physical_move":"Move physical object","history.contour_to_partitions":"Convert contour to closed walls","history.wall_chain_finish":"Finish wall chain","history.wall_face_batch":"Create rooms from walls","toast.column_duplicate":"A column with the same centre and outer size already exists","confirm.delete_draft":"Delete the whole unfinished room contour?","confirm.delete_draft_segment":"Delete this draft segment? The remaining contour may split in two.","physical.partition_properties":"Partition properties","physical.column_properties":"Column properties","physical.draft_properties":"Draft segment properties","physical.shape":"Shape","physical.square":"Square","physical.circle":"Circle","physical.diameter":"Diameter","physical.side":"Side","physical.rotation":"Rotation angle","physical.length":"Length","physical.allowed_range":"Allowed: {min}–{max} {unit}","physical.delete_segment":"Delete segment","physical.delete_draft":"Delete entire outline","physical.column_size_title":"Outer side of the square column placed by the click (1–150 cm).","card.title":"House plan","count.devices":"{n} dev.","empty.no_spaces":"No spaces yet.","empty.add_first":"Add the first space and upload a floor plan.","empty.install":'Install the House Plan integration and add it in "Devices & services".',"btn.add_space":"Add space","btn.cancel":"Cancel","btn.save":"Save","btn.close":"Close","btn.delete":"Delete","btn.edit":"Edit","btn.open_in_ha":"Open in HA","btn.reset":"Reset","btn.attach":"Attach…","btn.upload":"Upload…","btn.replace":"Replace…","title.zoom_in":"Zoom in","title.zoom_out":"Zoom out","title.zoom_fit":"Fit all","title.markup":"Room markup: grid, lines, outlines","title.configure_space":"Configure space","title.add_space":"Add space","title.markup_add":"Walls: draw a continuous chain; Shift locks to 45°. Changing tool or leaving the editor finishes it as independent walls","title.markup_merge":"Merge: click one room, then the neighbour it shares a wall with","title.markup_split":"Split a room: click the room, then two points on its walls","title.markup_delroom":"Delete room: click inside a room and confirm","title.need_plan":"Upload a floor-plan image","markup.add":"Walls","markup.merge":"Merge","markup.split":"Split","markup.resize":"Resize","title.markup_resize":"Resize rooms: drag an available horizontal or vertical wall handle","markup.hint_resize":"drag an available wall handle · the wall stops at the first unsafe position · Esc cancels · Ctrl+Z — undo","resize.disabled.diagonal":"This wall is angled; Resize supports only horizontal and vertical walls","resize.disabled.side-angle":"An adjoining wall is angled; Resize requires both adjoining walls to meet this wall at right angles","resize.disabled.duplicate-physical-wall":"A separate partition, unfinished outline, or column overlaps this wall; remove or move it before resizing","resize.disabled.partial-shared":"A neighbouring room uses only part of this wall, so it cannot be moved safely as one shared wall","resize.disabled.unequal-shared":"The neighbouring room uses different endpoints or wall length, so the walls cannot move together safely","resize.disabled.multiple-rooms":"Moving this wall would affect more than two rooms","resize.disabled.thickness-conflict":"The wall thickness cannot be preserved safely","resize.disabled.opening-conflict":"An opening on this wall cannot be moved safely","resize.disabled.invalid-geometry":"This wall cannot be resized without changing the plan structure","resize.limit_stopped":"Wall stopped: the next step would break a junction limit","resize.commit_failed":"Resize was cancelled because the final plan did not pass the geometry check","resize.preview_failed":"Resize stopped at the last safe position because the plan geometry could not be preserved","markup.opening":"Opening","markup.delete_room":"Delete room","history.undo":"Undo","history.redo":"Redo","history.undo_named":"Undo: {name} (Ctrl+Z)","history.redo_named":"Redo: {name} (Ctrl+Shift+Z / Ctrl+Y)","history.undo_empty":"Nothing to undo","history.redo_empty":"Nothing to redo","history.undone":"Undone: {name}","history.redone":"Redone: {name}","history.add_room":"Create room","history.split_room":"Split room","history.merge_rooms":"Merge rooms","history.resize_room":"Resize room","history.wall_thickness":"Change wall thickness","history.add_opening":"Add door or window opening","history.edit_opening":"Edit opening","history.move_opening":"Move opening","history.delete_opening":"Delete opening","history.delete_room":"Delete room","history.delete_room_keep_walls":"Delete room, keep walls","history.delete_room_with_walls":"Delete room and walls","history.decor_add":"Add decor object","history.decor_edit":"Edit decor object","history.decor_move":"Move decor object","history.decor_transform":"Transform decor object","history.decor_delete":"Delete decor object","history.backdrop_transform":"Transform plan backdrop","opening.new":"New opening","opening.edit":"Opening","opening.door":"Door","opening.window":"Window","opening.gate":"Gate","opening.passage":"Open passage","opening.passage_binding_warning":"Saving will remove the open/close sensor and lock.","opening.invalid_passage_fields":"The open passage on plan “{room}” has unsupported settings: {fields}.","opening.type_label":"Type","opening.length_label":"Length, cm","opening.contact_label":"Open/close sensor","opening.lock_label":"Lock","opening.none":"— none —","opening.search_ph":"Search: name or entity id…","opening.invert":"Invert open/closed","opening.flip_h":"Hinge on the other jamb","opening.flip_v":"Opens to the other side","opening.open":"Open","opening.closed":"Closed","opening.locked":"Locked","opening.unlocked":"Unlocked","opening.state_unknown":"unavailable","opening.no_entities":"No sensors bound — a static symbol on the plan.","toast.opening_no_wall":"Click next to a room wall or independent wall","opening.host_partition":"Independent wall","opening.partition_orphan":"The independent wall for this opening no longer exists","opening.partition_jamb_margin":"Leave at least {distance} between the opening and the end of the wall","opening.rebind_partition":"Attach to another independent wall","confirm.delete_partition_openings_title":"Delete wall and openings?","confirm.delete_partition_openings_body":"This wall contains {count} opening(s). They will be deleted together.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.delete":"Delete","markup.hint_points":"points: {n} · Shift — 45° steps · Esc — finish chain · Ctrl+Z — undo a point · closing an area offers a room","markup.hint_start":"click a grid dot to start a wall chain","tip.lqi":"average zigbee signal:","tip.area":"area: {value}","info.device_header":"Device on the plan","info.model":"Model","info.state":"State","info.link":"Link","info.manuals":"Manuals","info.none":"No additional information","marker.new_device":"New device","marker.name_label":"Name (shown on the plan)","marker.name_ph":"Name","marker.binding_label":"Bind to an HA device","marker.binding_disabled":"disabled in Home Assistant","marker.virtual_option":"Virtual device (no binding)","marker.search_ph":"Search device / group…","marker.nothing_found":"nothing found","marker.room_label":"Room","marker.room_override":" (override placement)","marker.room_choose":"— select a room —","marker.room_auto":"— by device area (auto) —","marker.icon_label":"Icon","marker.icon_ph":"mdi:… (empty = auto)","marker.display_label":"Display","display.badge":"Icon + state","display.icon_ripple":"Icon + state and activity","display.static_icon":"Always static icon","marker.display_hint":"Icon + state changes the plate for work, open, alarm and unavailable states. Icon + state and activity additionally shows a short pulse for events and a continuous pulse for ongoing work, movement or presence. Value + state replaces the icon with one unambiguous HA value. A static icon never reacts to device states.","marker.display_hint_badge":"The icon and dynamic plate show device state without the ordinary activity pulse. Red alarms remain visible.","marker.display_hint_icon":"The icon and dynamic plate show device state without the ordinary activity pulse. Red alarms remain visible.","marker.display_hint_icon_ripple":"The icon, dynamic plate and pulse show a short pulse for events and a continuous pulse for work, motion or presence. Red alarms have separate priority.","marker.display_hint_value":"One unambiguous Home Assistant value replaces the icon while the plate continues to show state. Red alarms remain visible.","marker.display_hint_static_icon":"The theme-aware shell and icon always stay the same. State, activity, unavailability and alarms do not change the face.","marker.static_alarm_warning":"This device can report alarms. Static display hides the marker's visual alarm indication.","marker.preview.title":"Display preview","marker.preview.actual":"Now","marker.preview.example":"Example","marker.preview.integration":"Provided by","marker.preview.source":"Display source","marker.preview.current_state":"Current state","marker.preview.result":"On the plan","marker.preview.details":"Source details","marker.preview.select_source":"Choose a Home Assistant device or entity to see its actual display.","marker.preview.unknown_provider":"Unknown integration","marker.preview.virtual_provider":"House Plan · virtual device","marker.preview.no_source":"No active source","marker.preview.no_state":"No current state","marker.preview.mixed_states":"Several different states","marker.preview.multiple_sources":"{n} sources","marker.preview.more_sources":"+{n} more","marker.preview.scaled":"The preview is scaled to {n}% to fit. The saved size is unchanged.","marker.preview.demo_short":"Show short activity","marker.preview.demo_continuous":"Show continuous activity","marker.preview.stop_continuous":"Stop continuous activity","marker.preview.demo_short_notice":"Short activity example; the actual device state is unchanged.","marker.preview.demo_continuous_notice":"Continuous activity example; the actual device state is unchanged.","marker.preview.demo_already_visible":"The current state already shows a real activity or alarm effect.","marker.preview.reduced_motion":"System reduced-motion is enabled, so ordinary activity is shown as a dot.","marker.preview.reason.neutral":"Neutral dark plate","marker.preview.reason.working":"Yellow plate: the device is working now","marker.preview.reason.working_activity":"Yellow plate and activity effect: the device is working now","marker.preview.reason.open":"Orange plate: physically open or unlocked","marker.preview.reason.cover_icon_state":"Neutral plate; the cover entity controls the displayed state and icon","marker.preview.reason.presence":"Activity effect while presence is detected","marker.preview.reason.event":"Short activity effect after a detected event","marker.preview.reason.transition":"Activity effect while the device is moving or changing state","marker.preview.reason.media_neutral":"Media devices stay on a neutral dark plate while available","marker.preview.reason.unavailable":"Subdued neutral plate: unavailable or off","marker.preview.reason.alarm":"Red alarm plate; alarm indication is always shown","marker.preview.reason.live_states_disabled":"Live-state styling is disabled for this card","marker.preview.reason.value_no_state":"No usable state value; the icon is shown instead","marker.preview.reason.value_ambiguous_sources":"Several possible value sources; the icon is shown instead","marker.preview.reason.value_non_scalar":"The source did not return a simple value; the icon is shown instead","marker.preview.reason.value_virtual":"A virtual device has no Home Assistant value; the icon is shown instead","marker.preview.reason.vacuum_live_plan_only":"Live vacuum position and trail are available only on the full plan","marker.preview.reason.hidden_design_preview":"The device is hidden on the plan; this design preview remains visible","marker.preview.reason.composite_power_source":"State comes from the device Power entity; auxiliary switches are ignored","marker.preview.reason.activity_display_disabled":"The selected display mode does not show ordinary activity effects","marker.preview.reason.ha_disabled":"The Home Assistant binding is disabled and will be hidden on the plan","marker.preview.reason.orphaned":"The saved Home Assistant binding can no longer be found","marker.preview.reason.static_icon":"Static mode: device state does not change the icon","marker.activity_color":"Activity pulse color","marker.ripple_size":"Activity pulse size","marker.activity_alarm_note":"Color and size affect ordinary activity only and do not change red alarms.","marker.pulse_a11y_alarm":"Alarm","marker.pulse_a11y_event":"Recent event","marker.pulse_a11y_presence":"Presence detected","marker.pulse_a11y_transition":"Changing state","marker.pulse_a11y_running":"Working","marker.state_a11y_neutral":"Default state","marker.state_a11y_working":"Working","marker.state_a11y_open":"Open","marker.state_a11y_locked":"Locked","marker.state_a11y_unlocked":"Unlocked","marker.state_a11y_alarm":"Alarm","marker.state_a11y_unavailable":"Unavailable","marker.lqi_a11y_low":"LQI {value}, low signal","marker.lqi_a11y_mid":"LQI {value}, medium signal","marker.lqi_a11y_high":"LQI {value}, high signal","marker.size_label":"Icon size / rotation","marker.angle_label":"Rotate","marker.model_label":"Model","marker.model_ph":"e.g. Aqara T&H","marker.link_label":"Link","marker.desc_label":"Description","marker.desc_ph":"Notes, specs…","marker.manuals_label":"Manuals (PDF etc.)","marker.sub_device":"device","marker.sub_z2m_group":" · Z2M group","marker.sub_group":"group","marker.sub_helper":"helper","space.new":"New space","space.header":"Space","space.title_label":"Title","space.title_ph":"e.g. Garage","space.plan_label":"Floor plan (background)","space.no_plan":"no plan image","space.plan_alt":"plan","room.new":"New room","room.name_label":"Display name","room.name_ph":"e.g. Terrace","room.area_label":"Home Assistant area (unassigned)","room.no_area_option":"— no area —","room.default_name":"Room","device.unnamed":"unnamed","device.light_group":"light group","device.fallback":"device","device.virtual":"virtual device","confirm.delete_room":'Delete room "{name}"?',"confirm.delete_room_title":'Delete room "{name}"?',"confirm.delete_room_body":"Choose whether the room's exclusive physical walls should remain. Walls shared with another room are always kept.","confirm.remove_marker":'Delete "{name}" from the plan? The device will disappear completely and stop contributing to plan data. You can add it again later.',"confirm.erase_decor":"Erase the {kind} object? You can undo this action from the editor history.","confirm.delete_space":'Delete space "{title}" with all its rooms and markup?',"space.delete_blocked":"This space is still used by {n} device(s). Move them to another space or delete them first.","toast.pos_save_failed":"Failed to save position: {err}","toast.no_entity":"The device has no suitable entity","toast.ha_disabled_action":"A Home Assistant object that is disabled cannot be used on the plan.","toast.ha_disabled_show_device":"A device disabled in Home Assistant cannot be shown on the plan. Enable it in Home Assistant first.","toast.ha_disabled_show_entity":"An entity disabled in Home Assistant cannot be shown on the plan. Enable it in Home Assistant first.","toast.ha_disabled_add":"A disabled Home Assistant object cannot be added to the plan. Enable it in Home Assistant first.","toast.ha_binding_unverified":"The object status could not be verified through the Home Assistant registry. Display and actions are temporarily unavailable.","toast.markup_needs_server":"Markup is available after the config is moved to the server","toast.space_order_changed":"Order changed. If any card pins its floor by number, check those panels.","toast.conflict":"Config was changed in another window — data refreshed, repeat your last action","toast.cfg_save_failed":"Failed to save config: {err}","toast.room_overlap":"The outline overlaps room “{name}” — rooms must not overlap","toast.contour_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_saved":"Space saved","toast.space_deleted":"Space deleted","toast.delete_failed":"Delete failed: {err}","toast.error":"Error: {err}","toast.toggle_target_unavailable":"Target “{name}” is unavailable — no action was performed","toast.toggle_targets_unavailable":"Targets are unavailable: {names}. No action was performed","toast.file_failed":'File "{name}" was not uploaded: {err}',"toast.files_attached":"Files attached: {n}","err.unknown":"unknown error","err.code":"code {code}","err.too_large":"file larger than {mb} MB","err.bad_ext":"unsupported type (PDF/image expected)","err.unauthorized":"administrator rights required","editor.title":"Title","editor.default_floor":"Initial space","editor.default_floor_missing":"Initial space “{id}” no longer exists. Choose another space.","editor.floor":"Fixed space","editor.floor_none":"— not fixed —","editor.floor_index":"YAML index {index} (preserved)","fixed_floor.loading":"Loading the fixed space…","fixed_floor.invalid_title":"The fixed space is unavailable","fixed_floor.invalid_body":"Check floor in the card configuration. The configured value is: {value}","editor.icon_size":"Icon size, % of plan width","editor.show_temperature":"Show temperature","editor.live_states":"Live states (on/off, open…)","editor.show_signal":"Show zigbee signal (LQI)","editor.language":"Interface language","editor.lang_auto":"Auto (HA profile)","title.icon_rules":"Icon rules: which MDI icon devices get by name","rules.title":"Icon rules","rules.hint":"Rules are checked top-down against “device name + model” (case-insensitive regex); the first match wins. When nothing matches, the entity device class decides, then the generic chip icon.","rules.pattern_ph":"regex, e.g. plug|socket","rules.icon_ph":"mdi:power-socket-de","rules.add":"Add rule","rules.reset":"Reset to defaults","rules.test_ph":"Try a device name…","rules.invalid":"invalid regex","rules.saved":"Icon rules saved","btn.up":"Up","btn.down":"Down","tap.info":"Device card","tap.more_info":"HA more-info dialog","tap.toggle":"Toggle state","marker.tap_label":"Tap action for this device","tap.toggle_note":"The resolved state is shown below. Secure devices are never toggled from the plan.","import.title":"Create spaces from HA floors","import.hint":"Your Home Assistant already knows these floors. Pick the ones to turn into plan spaces — you will upload a floor-plan image for each one next. Rooms are then outlined by hand on the plan.","import.start":"Create {n} space(s)","import.manual":"Start from scratch","import.progress":"Floor {i} of {n}","import.done":"Spaces created. Outline the rooms: click grid dots and close the contour.","btn.skip":"Skip","space.scale_label":"Scale (grid cell size)","space.scale_unit":"cm per cell","space.scale_unit_imperial":"in per cell","space.display_section":"Display","space.show_borders":"Always show room borders","space.zero_wall_style":"Zero-thickness walls","space.zero_wall_dashed":"Dashed","space.zero_wall_solid":"Solid","space.zero_wall_help":"Dashed walls let light through. Solid walls block light even at zero thickness.","space.show_names":"Show room names (drag to move)","space.room_color":"Border & name color","space.opacity":"Opacity","space.fill_label":"Room fill","fill.none":"None","fill.lqi":"Zigbee signal","fill.light":"Lights","fill.custom":"Custom color","space.custom_fill":"Fill color","space.source_file":"I have a floor-plan image","space.source_draw":"No image — I'll outline rooms by hand","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.show_button":"Show button","editor.button_label":"Button label","editor.button_target":"Target dashboard path","marker.sub_entity":"entity","title.general_settings":"General settings","gs.title":"General settings","gs.hint":"Fill colors apply to every space; each color has its own opacity. Which fill mode a space uses is set in that space's dialog.","gs.light_group":"Fill: lights","gs.light_on":"Lights on","gs.light_off":"All lights off","gs.temp_group":"Fill: temperature","gs.temp_cold":"Cold","gs.temp_ok":"Comfortable","gs.temp_hot":"Hot","gs.lqi_group":"Fill: zigbee signal","gs.lqi_low":"Weak signal","gs.lqi_high":"Strong signal","gs.reset":"Reset to defaults","gs.saved":"General settings saved","space.show_lqi":"Show zigbee signal (LQI) next to devices","space.hide_decor":"Hide the decorative layer","space.hide_decor_tip":"Lines, shapes, labels and furniture stay where they are — visible in the backdrop editor, not on the plan.","space.hide_openings":"Hide openings","space.hide_openings_tip":"Door, window and gate symbols are not drawn, but the openings keep working: light passes through, the sun comes in at a window, contact sensors still open them. The plan editor always shows them.","gs.light_none":"No light sources","mode.plan":"Plan editor","mode.devices":"Device editor","display.value":"Value + state","marker.subarea":"no area, manual","device.new":"New device — open its editor to dismiss","opening.unlock_action":"Unlock","opening.lock_action":"Lock","opening.lock_pending":"Working…","title.close_editor":"Close editor (back to view)","devbar.rules":"Icon rules","device_inbox.button":"Devices","device_inbox.title":"Devices on the plan","device_inbox.search":"Search devices, entities and integrations…","device_inbox.add_virtual":"Add virtual device","device_inbox.tab_on_plan":"On plan","device_inbox.tab_available":"Available","device_inbox.tab_hidden":"Hidden","device_inbox.tab_readd":"Available again","device_inbox.only_new":"New only","device_inbox.show_entities":"Show entities","device_inbox.show_hidden":"Show hidden on plan","device_inbox.new":"New","device_inbox.find":"Find on plan","device_inbox.edit":"Edit","device_inbox.hide":"Hide","device_inbox.show":"Show","device_inbox.add":"Add","device_inbox.readd":"Add again","device_inbox.hide_available":"Hide from list","device_inbox.show_more":"Show more","device_inbox.more_actions":"More actions","device_inbox.find_hidden_hint":"Enable “Show hidden on plan” first","device_inbox.show_disabled":"Activate this binding in Home Assistant before showing it","device_inbox.empty_on_plan":"No matching devices are on the plan yet.","device_inbox.empty_available":"No devices are available to add.","device_inbox.empty_hidden":"There are no hidden devices.","device_inbox.empty_readd":"No removed devices are available to add again.","device_inbox.reason_visible_auto":"Discovered automatically","device_inbox.reason_visible_explicit":"Added explicitly","device_inbox.reason_manual_hidden":"Hidden by user","device_inbox.reason_automatic_hidden":"Hidden automatically","device_inbox.reason_service_entry":"Service-only registry entry","device_inbox.reason_excluded_integration":"Integration excluded by device filters","device_inbox.reason_excluded_domain":"Non-spatial entity type","device_inbox.reason_grouped_light":"Represented by a room light group","device_inbox.reason_represented_by_parent":"Represented by its parent device","device_inbox.reason_removed":"Previously removed from the plan","device_inbox.reason_available":"Available to add to the plan","device_inbox.reason_no_bound_room":"HA area is not linked to a plan room","device_inbox.status_ha_disabled":"Disabled in Home Assistant","device_inbox.status_orphaned":"Binding is no longer present in Home Assistant","device_inbox.status_unverified":"Home Assistant registry is temporarily unavailable","device_inbox.saved":"Device list updated","space.roomcard_section":"Room card shows:","space.label_temp":"Temperature","space.label_hum":"Humidity","space.label_lqi":"Average Zigbee signal","space.label_light":"Lights on/off","roomcard.light_on":"On","roomcard.light_off":"Off","roomcard.light_partial":"{on} of {total}","toast.split_pick_inside":"Intermediate cut points must be inside the room","mode.decor":"Background editor","decor.select":"Select","decor.line":"Line","decor.rect":"Rectangle","decor.ellipse":"Oval","decor.text":"Text","decor.erase":"Erase","decor.erase_confirm_title":"Erase object?","decor.color":"Color","decor.width":"Line width","decor.line_style":"Line style","decor.line_style_solid":"Solid","decor.line_style_dashed":"Dashed","decor.fill":"Fill","decor.fill_color":"Fill color","decor.length":"Length","decor.size":"Size","decor.angle":"Rotation angle, °","decor.text_size":"Text size","decor.backdrop_properties":"Plan backdrop properties","decor.text_title":"Text label","decor.object_title":"Edit {kind}","decor.text_label":"Text","decor.live_group":"Insert HA variable","decor.live_entity":"Entity","decor.live_entity_ph":"choose an entity","decor.live_attr":"Value","decor.live_attr_ph":"choose state or attribute","decor.live_state":"State","decor.backdrop":"Backdrop image","decor.backdrop_hint":"Drag to move; pull a corner to resize; use the top handle to rotate. Shift changes proportions or frees the angle.","decor.backdrop_reset":"Reset the picture","decor.backdrop_reset_done":"The picture is back at its original place and size","marker.icon_auto":"Auto: {icon} (by icon rules; pick one to override)","marker.icon_pin_auto":"Pin","mode.plan_tip":"Plan editor — the geometry of the home: draw and split/merge rooms, bind them to HA areas, place doors, windows and gates, move room cards, set the scale","mode.devices_tip":"Device editor — everything about icons: drag to position, click to edit binding/icon/display, add virtual devices, icon rules","mode.decor_tip":"Background editor — purely visual decor under the plan: lines, rectangles, ovals and text labels that never react to clicks","space.glow_enabled":"Light-source glow","gs.glow_group":"Light-source glow","gs.glow_base":"House darkness","gs.glow_light":"Default light color / intensity","gs.wall_group":"Walls","gs.wall_fill":"Wall fill","gs.glow_radius":"Glow radius","gs.unit_m":"m","gs.unit_ft":"ft","marker.controls_label":"Controls other light sources","marker.controls_hint":"With tap action “Toggle”, a click flips every source added here. The marker’s own bound entity is controlled directly and cannot be added; use the switch below to classify it as a light.","marker.controls_filter":"Search lights and switches…","info.controls":"Controls","marker.glow_radius_label":"Glow radius","marker.glow_radius.help":"Sets the glow radius in metres or feet; an empty value uses the radius from general settings.","marker.glow_radius.help.aria":"Help: glow radius","markup.wallthick":"Thickness","markup.select":"Select","title.markup_wallthick":"Thickness — click a wall to set its thickness from 0 to 100 cm.","markup.hint_wallthick":"click a wall · Esc closes without applying","wallthick.field":"Thickness","wallthick.unit_cm":"cm","wallthick.unit_in":"in","wallthick.apply_room":"Apply to all walls of this room","markup.draw_wall_title":"Thickness of each new wall segment (0–100 cm). Shared walls keep the existing value.","room.queue_progress":"Room {current} of {total}","toast.wall_rooms_saved":"Created rooms: {n}","toast.wall_chain_saved":"Wall chain saved","toast.wallthick_pick":"Click a wall","toast.wallthick_set":"Wall thickness set","toast.wallthick_cleared":"Wall thickness removed","toast.physical_range":"Enter a value from {min} to {max} {unit}","toast.zero_wall_opening_conflict":"Remove the opening on this wall segment first.","toast.zero_wall_ambiguous":"The wall segment is ambiguous. Simplify or adjust the junction.","toast.zero_wall_migration_blocked":"The space was not converted: {reason}. No data was changed.","toast.physical_angle":"Enter a rotation angle from 0° up to, but not including, 90°","toast.physical_limit":"The space has reached the limit for this type of geometry","toast.geometry_unsafe":"Change canceled: wall geometry could not be built safely.","junction.limit_angle":"The angle between walls is too sharp: {actual}°, minimum {limit}°.","junction.limit_valence":"Too many walls meet in one node: {actual}, maximum {limit}.","junction.limit_length":"The wall segment is too short: {actual} cm, minimum {limit} cm.","junction.limit_distance":"Walls and nodes are too close: {actual} cm, minimum {limit} cm.","junction.limit_clearance":"No room interior is left: {actual} cm², minimum {limit} cm².","junction.limit_check_failed":"The junction check could not run — the change was not saved","toast.wall_model_migration_blocked":"The wall model could not be updated: {reason}. The plan was not changed. Run “Optimize plans”; if the error repeats, fix the conflicting wall geometry.","toast.wall_model_client_outdated":"Update the card and reload the page before editing the plan.","wall_model.reason.invalid-room":"invalid room contour","wall_model.reason.zero-length":"zero-length wall segment","wall_model.reason.third-owner":"wall shared by more than two rooms","wall_model.reason.duplicate-id":"conflicting wall identifiers","wall_model.reason.thickness-conflict":"conflicting wall thickness values","wall_model.reason.opening-host":"opening cannot be assigned to one wall","toast.delete_room_pick":"Click inside the room you want to delete","toast.plan_snap_ambiguous":"Zoom in to choose the wall node","toast.wall_repair_ambiguous":"The room outline has more than one possible connection. Zoom in and connect it explicitly.","toast.wall_repair_too_large":"The gap is larger than 2 cm. Connect the walls before creating the room.","toast.wall_repair_changed":"The wall geometry changed. Try creating the room again.","toast.opening_on_zero_wall":"Openings cannot sit on a zero-thickness wall","marker.from_ha_option":"Pick from the HA list","marker.show_entities":"Show entities","marker.show_entities_tip":"Adds not only devices to the list, but all their entities too","marker.pick_ph":"Choose a device…","room.open_area":"Open the HA area","view.volumetric":"Volumetric view","view.flat":"Flat view","kiosk.title":"This screen's sizes","kiosk.hint":"Stored on this device only — every wall tablet or TV can have its own comfortable sizes.","kiosk.icon_scale":"Device icon size","kiosk.font_scale":"Room card text size","editor.kiosk":"Wall device (kiosk) mode","editor.cycle":"Auto-switch spaces every N seconds (kiosk, 0 = off)","room.settings_title":"Room settings","room.settings_section":"Room settings (override the space)","room.fill_label":"Fill in THIS room","fill.inherit":"As the space","room.custom_fill_space":"Space color","room.custom_fill_own":"Room color","room.temp_src_label":"Temperature source","room.hum_src_label":"Humidity source","room.src_average":"Average over the room's sensors (default)","room.src_pick":"A specific HA device or entity","room.src_ph":"Choose a source…","toast.room_updated":"Room updated","space.card_font":"Room-card font size (whole space)","room.sizes_section":"Font sizes","room.name_scale":"Room name size","room.label_scale":"Metrics size","preview.room_name":"Living room","toast.cfg_reload_failed":"Could not reload the plan from the server: {err}","toast.locale_load_failed":"Could not load the language pack. English is used until the page reloads.","room.settings_short":"Room settings","room.unnamed":"Unnamed room","marker.use_climate_temp":"Include the device temperature in the room","marker.use_climate_temp_tip":"Adds an air conditioner or thermostat current_temperature to the room average. Configure the external value badge separately below.","marker.value_badge_title":"Value badge","marker.value_badge.help":"Shows one selected value next to the icon. It does not affect room metrics, light, Glow or the tap action.","marker.value_badge.help.aria":"Help: device value badge","marker.value_badge_enabled":"Show a value badge","marker.value_badge_source":"Value","marker.value_badge_source.help":"Choose a specific state, supported attribute, or derived value of this device.","marker.value_badge_source.help.aria":"Help: value badge source","marker.value_badge_position":"Position","marker.value_badge_position.help":"The chosen side stays fixed and does not flip automatically at a plan edge.","marker.value_badge_position.help.aria":"Help: value badge position","marker.value_badge_right":"Right","marker.value_badge_bottom":"Below","marker.value_badge_left":"Left","marker.value_badge_top":"Above","marker.value_badge_empty":"This device has no available values","marker.value_badge_static":"A static icon does not show live values. The setting is preserved.","marker.value_badge_missing":"Source unavailable","marker.value_badge_missing_hint":"The saved source is currently unavailable. Keep it, disable the badge, or choose another value.","marker.value_badge_duplicate":"The same value is already shown inside the icon.","marker.value_badge_state":"State · {name}","marker.value_badge_marker_state":"Light-source state · {name}","marker.value_badge_lqi":"Average Zigbee signal quality","marker.value_badge_attr_current_temperature":"Current temperature · {name}","marker.value_badge_attr_temperature":"Target temperature · {name}","marker.value_badge_attr_current_humidity":"Current humidity · {name}","marker.value_badge_attr_humidity":"Humidity · {name}","marker.value_badge_attr_current_position":"Position · {name}","marker.value_badge_attr_percentage":"Speed · {name}","marker.value_badge_attr_brightness":"Brightness · {name}","marker.value_badge_attr_volume_level":"Volume · {name}","marker.value_badge_attr_battery_level":"Battery · {name}","marker.value_badge_attr_fan_speed":"Fan speed · {name}","marker.light_role_label":"Is this device a light source?","marker.light_role.help":"Controls whether this marker itself is a spatial light source. Linked lights above remain independent room-light controls.","marker.light_role.help.aria":"Help: whether this device is a light source","marker.light_role_auto_yes":"Auto (light source)","marker.light_role_auto_no":"Auto (not a light source)","marker.light_role_always":"Always a light source","marker.light_role_never":"Never a light source","marker.light_entity_label":"Leading light entity","marker.light_entity.help":"For a composite device, choose the entity whose state, colour and brightness represent this plan source. The automatic fallback remains compatible with older plans.","marker.light_entity.help.aria":"Help: leading light entity","marker.light_entity_auto":"Automatic ({entity})","marker.light_entity_none":"no controllable entity","marker.light_entity_missing":"The saved entity {entity} is unavailable. House Plan temporarily uses {fallback}; the saved choice will be restored if it returns.","marker.toggle_entity_label":"Entity to toggle","marker.toggle_entity.help":"For a composite device, choose the exact own light or switch operated by a tap. Automatic keeps the previous target rules and is independent from the leading light entity.","marker.toggle_entity.help.aria":"Help: entity to toggle","marker.toggle_entity_auto":"Automatic ({entity})","marker.toggle_entity_none":"no own controllable entity","marker.toggle_entity_missing":"The saved entity {entity} is no longer among this marker’s selectable channels. House Plan temporarily uses {fallback}; the saved choice will be restored if it returns.","marker.glow_color_label":"Glow colour and brightness","marker.glow_mode.help":"Use live source values, override only its colour, or fix both colour and brightness. The minimum is 1%; to disable the source, choose “Never”.","marker.glow_mode.help.aria":"Help: glow colour and brightness","marker.glow_mode_auto":"From source","marker.glow_mode_color":"Set colour","marker.glow_mode_fixed":"Set colour and brightness","marker.glow_color":"Glow colour","marker.glow_brightness":"Brightness","marker.glow_disabled_never":"Glow settings are unavailable because this marker is explicitly not a light source.","marker.glow_disabled_auto":"Auto mode found no spatial light source for this marker.","marker.glow_disabled_no_entity":"No active controllable Home Assistant entity is available for this spatial source.","marker.glow_passive_hint":"This source has no own Home Assistant data. Set its colour and brightness manually; its radius remains available.","marker.control_broken":"Saved source is missing or no longer marked as a light","marker.control_missing_label":"Missing plan light","marker.control_passive":"passive source","toast.marker_control_cycle":"This link would create a circular chain of light controls.","toast.marker_binding_required":"Choose a Home Assistant device before linking another light source.","confirm.unlock":"Unlock “{name}”?","toast.files_migrate_failed":"Attachments could not be moved to the new binding, links keep pointing at the old files: {err}","space.pick_saved":"Already uploaded","space.pick_saved_hint":"Plans stored on the server, including ones you detached earlier","space.no_saved":"No plans stored on the server yet.","space.loading":"Loading…","space.used_by":"in use: {list}","space.in_use":"A space still uses this plan — detach it first","btn.use":"Use","confirm.delete_plan":'Delete the plan file "{name}" from the server? This cannot be undone.',"toast.plans_list_failed":"Could not list the stored plans: {err}","toast.plan_delete_failed":"Could not delete the plan: {err}","marker.hide":"Hide","marker.hide_tip":'The device will disappear from the plan after saving but will still count toward the room signal. Restore it through the "Devices" catalog in the device editor.',"marker.show":"Show","marker.show_tip":"The device will appear on the plan again after saving.","marker.hidden_ghost":"Device hidden by the user","marker.ha_disabled_device":"The device is disabled in Home Assistant and hidden from the plan.","marker.ha_disabled_entity":"The entity is disabled in Home Assistant and hidden from the plan.","marker.ha_disabled_all_entities":"The device has no active Home Assistant entities, so it is hidden from the plan.","marker.ha_registry_limited":"The full Home Assistant registry is unavailable to this user. The unverified object cannot be shown or used for now.","marker.delete_tip":"Completely delete the device from the plan and every aggregate. You can add it again later.","tap.run":"Run automation/script/scene","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.cal_maps":"Calibrated maps: {maps}","vac.autocal_no_rooms":"The integration reports no room list — open “Fit manually”","vac.autocal_no_match":"Room names did not match (need ≥3 in common) — open “Fit manually”","vac.autocal_done":"Done: bound via {rooms} rooms. Start a cleanup and check","vac.cal_need_pos":"The robot is not reporting coordinates — start a cleanup and pause it","vac.cal_done":"Calibration saved. Start a cleanup and check","vac.cal_cancelled":"Calibration cancelled","vac.fit":"Fit manually","vac.fit_hint":"Drag the robot map into place, stretch by the corners","vac.fit_rotate":"Rotate 90°","vac.fit_mirror":"Mirror","vac.trail_never":"Never","vac.trail_cleaning":"While cleaning","vac.trail_always":"Always","gs.bg_group":"Stage background","gs.bg_color":"Background around the plan","gs.bg_default":"Theme default","gs.bg_theme":"theme default","gs.bg_mode":"Plan background","gs.bg_static":"Static color","gs.bg_daynight":"Follows the Sun","gs.bg_daynight_hint":"The background moves through dawn, day, dusk and night using sun.sun, or your local clock when sun data is unavailable. No compass is needed for the background.","gs.sun_group":"Sun","gs.sun_missing":"The sun.sun entity was not found — the background follows your local clock; window rays are unavailable.","gs.north":"North on the plan","gs.north_ph":"not set","gs.north_hint":"Set north only for window rays (1° steps, 15° with Shift); the Sun background works without it.","gs.north_clear":"Clear","gs.north_letter":"N","gs.sun_rays":"Sunlight through windows","gs.about_group":"About","gs.about_version":"Houseplan Card v{v}","gs.about_github":"GitHub · docs & issues","gs.about_telegram":"Telegram chat","space.bg_color":"Background around the plan","space.bg_inherit":"Inherit general","space.bg_inherited":"inherits general settings","space.bg_mode":"Plan background","space.north":"North on the plan (override)","space.north_inherited":"inherited: {v}","space.sun_rays":"Sunlight through windows","space.sun_inherit":"Inherit general","space.sun_on":"On","space.sun_off":"Off","canvas.far_objects":"{n} object(s) far from the plan","canvas.show_far":"Show","canvas.home_tip":"The plan is over there — click to fit it","gs.grid_group":"Plan maintenance","gs.grid_hint":"Updates data models, aligns plan elements to the grid and merges redundant wall fragments. An exact report is shown before anything is stored.","gs.align_all":"Optimize plans","gs.align_title":"Optimize plans","gs.align_none":"All plans already use the current optimized data model.","gs.optimize_no_automatic_changes":"There are no automatic changes to apply. Review the items below.","gs.align_count":"{n} of {total} elements will move, by at most {cm} cm.","gs.align_where":"The largest shift is in “{s}”.","gs.align_turned":"Openings whose angle is corrected: {n}.","gs.align_removed_drafts":"Invalid outlines collapsed by the grid and removed: {n}.","gs.optimize_redundant_drafts":"Saved wall chains hidden by solid room walls and removed: {n}.","gs.align_preflight_failed":"Could not safely verify the geometry of the following spaces: {spaces}{more}.","gs.align_preflight_hint":"Plans were not changed. Copy the diagnostics with the button below and attach them to the bug report together with a space export.","gs.preflight_reason_prepare-exception":"Could not prepare the space geometry (exception while building the model)","gs.preflight_reason_wall-null":"The wall body did not build (the union came back empty)","gs.preflight_reason_wall-degraded-extra":"The wall body degraded with extra geometry","gs.preflight_reason_wall-failed-core":"The wall body core failed to assemble","gs.preflight_reason_wall-exception":"Wall construction threw an exception","gs.preflight_reason_floor-null":"The floor outline did not build","gs.preflight_reason_floor-exception":"Floor construction threw an exception","gs.preflight_copy":"Copy diagnostics","gs.preflight_copied":"Diagnostics copied","gs.preflight_update_hint":"The card and integration versions differ — update House Plan and retry.","gs.align_preflight_space":"Space {n}","gs.align_preflight_more":", and {n} more","gs.optimize_changes":"Model migrations: {m}; spaces updated: {c}; noisy coordinate values removed: {p}; merged real-wall fragments: {w}; merged zero-thickness wall fragments: {s}; independent walls: {i}.","gs.zero_walls_migrated":"Virtual wall spans converted: {n}.","gs.wall_segments_migrated":"Wall segments stabilised: {n}.","gs.optimize_lattice_summary":"Noisy coordinate values canonicalized: {n}; maximum movement: {cm} cm.","gs.optimize_lattice_space":"{space}: coordinate values canonicalized: {n}; off-grid values left unchanged: {far}.","gs.optimize_coincident_partitions":"Hidden independent wall sections absorbed into room walls: {n}.","gs.optimize_openings_rehosted":"Openings reattached to room walls: {n}.","gs.optimize_walls_straightened":"Walls straightened: {n}; maximum movement: {cm} cm.","gs.optimize_walls_straightened_where":"Largest wall correction: {s}.","gs.optimize_walls_straighten_skipped":"Near-axis walls left unchanged because they could not be repaired safely: {n}.","gs.optimize_glow_migration":"Legacy Glow: {spaces} spaces → no data fill + independent Glow; {rooms} rooms → inherited data fill + independent Glow.","gs.optimize_references":"References repaired: spaces — {spaces}; rooms — {rooms}; positions — {positions}; devices detached from missing spaces — {detached}.","gs.optimize_reference_more":", and {n} more","gs.optimize_orphans_removed":"Forgotten records removed: {total} — room labels: {rooms}; devices: {devices}; group markers: {groups}. They belonged to spaces deleted earlier.","gs.optimize_live_positions":"Old positions in deleted spaces belong to existing objects: {n}{names}. They will be kept.","gs.optimize_live_positions_remove":"Old positions in deleted spaces belong to existing objects: {n}{names}. They are selected for removal.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Remove old positions","gs.optimize_live_keep":"Keep old positions","gs.optimize_live_selected":"Old positions will be removed after Optimize is applied.","gs.optimize_unverified":"Could not safely verify positions: {n}. They were left unchanged.","gs.optimize_registry_limited":"Full administrator access to the Home Assistant registries is required for a safe check.","gs.optimize_vacuum_warning":"Vacuum room mappings that still need review: {n}.","gs.optimize_details":"Details","gs.optimize_details_more":"And {n} more records.","gs.optimize_detail_removed":"will be removed","gs.optimize_detail_live":"will be kept","gs.optimize_detail_unverified":"not verified","gs.optimize_detail_room_label":"room label","gs.optimize_detail_device":"device","gs.optimize_detail_group":"group marker","gs.optimize_detail_unknown":"unknown owner","gs.optimize_detail_item":"{status}: {kind} {id}; old space {space}","gs.align_warn":"Elements deliberately placed between grid nodes will move. One undo is available after the operation, only until the next plan edit.","gs.align_run":"Optimize","gs.align_done":"Plans optimized: {n} elements moved, {m} records maintained, {r} references repaired","gs.optimize_undo":"Undo last optimization","gs.optimize_undone":"The last optimization was undone","decor.furniture":"Furniture","furn.title":"Furniture library","furn.symbol":"Symbol","furn.group_furniture":"Furniture","furn.group_appliance":"Appliances","furn.group_sanitary":"Plumbing","furn.group_other":"Other","furn.width":"Width","furn.depth":"Depth","furn.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_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_kitchen_cabinet":"Kitchen cabinets","furn.cat_kitchen_sink":"Kitchen sinks","furn.cat_nightstand":"Cabinets","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_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","gs.backup_hint":"Download a portable JSON backup or preview and import a backup made by House Plan.","backup.export_open":"Export","backup.import_open":"Import","backup.export_title":"Export House Plan","backup.import_title":"Import House Plan","backup.export_hint":"Choose whether the backup should contain the whole House Plan configuration or only the current space.","backup.full":"Full backup","backup.current_space":"Current space","backup.current_space_title":"Current space: {title}","backup.no_current_space":"No current space","backup.plan_only":"Plan only","backup.plan_only_hint":"Keep rooms, walls, openings, decor and room-label positions without devices or Home Assistant bindings.","backup.plan_only_preview":"This file contains the plan only","backup.privacy_warning":"The archive keeps names, Home Assistant identifiers and exact coordinates. Internal plans and attachments are referenced, not embedded; runtime states and vacuum trails are not included.","backup.download":"Download JSON","backup.export_done":"Backup downloaded","backup.reading":"Checking the backup…","backup.revalidated":"The plan changed after this preview. The summary was refreshed; review it and confirm again.","backup.error.unauthorized":"You do not have permission to export or import this plan.","backup.error.not_ready":"House Plan is not ready yet. Try again in a moment.","backup.error.too_large":"The backup exceeds the 8 MiB limit.","backup.error.invalid_json":"The selected file is not valid JSON.","backup.error.invalid_format":"The selected file is not a House Plan backup.","backup.error.unsupported_export_version":"This backup format is not supported by the installed version.","backup.error.future_model":"The backup was created by a newer House Plan data model.","backup.error.invalid_config":"The backup contains an invalid House Plan configuration.","backup.error.wall_model_migration_blocked":"The backup wall model could not be upgraded safely. Optimize the source plan first, then export it again.","backup.error.invalid_layout":"The backup contains invalid object positions.","backup.error.invalid_content":"The backup contains invalid or inconsistent content references.","backup.error.space_not_found":"The selected space no longer exists.","backup.error.capacity_exceeded":"Adding this backup would exceed the plan limits.","backup.error.preview_expired":"The preview expired. Select the backup file again.","backup.error.preview_owner_mismatch":"This preview belongs to another Home Assistant user.","backup.error.conflict":"The plan changed after the preview. Review the refreshed summary.","backup.error.content_confirmation_required":"Confirm that unavailable local content may be detached.","backup.error.commit_failed":"The backup could not be applied safely. The previous plan was restored or is pending recovery.","backup.error.missing_plan":"A referenced plan file disappeared after the preview. Review the backup again.","backup.error.missing_content":"A referenced local attachment disappeared after the preview. Review the backup again.","backup.error.marker_control_missing":"A linked plan light is missing from the backup.","backup.error.marker_control_not_light":"A linked plan target is no longer marked as a light source.","backup.error.marker_control_self":"A light source cannot control itself.","backup.error.marker_control_cycle":"The backup contains a circular chain of light controls.","backup.error.duplicate_marker_control":"The backup contains a duplicate plan-light link.","backup.error.no_backup":"There is no import or optimization snapshot to restore.","backup.same_source":"Created on this Home Assistant instance","backup.foreign_source":"Created on another Home Assistant instance","backup.created":"Created: {value}","backup.versions":"Card {card}; integration {integration}; data model {model}","backup.count_spaces":"Spaces: {n}","backup.count_rooms":"Rooms: {n}","backup.count_walls":"Walls: {n}","backup.count_openings":"Openings: {n}","backup.count_decor":"Decor objects: {n}","backup.count_markers":"Devices: {n}","backup.count_layout":"Positions: {n}","backup.bindings":"Bindings — devices: {device}, entities: {entity}, virtual: {virtual}; positions without a space: {legacy}","backup.binding_status":"Target status — active: {active}, disabled: {disabled}, missing: {missing}","backup.missing_areas":"Areas missing on the target: {areas}","backup.dropped_marker_links":"Plan-light links outside this transferred space were omitted: {n}.","backup.repaired_target_refs":"Existing references restored by this space import: {n}.","backup.preserved_unresolved_refs":"References that could not be restored unambiguously were preserved: {n}.","backup.preserved_unresolved_hint":"No data was guessed or deleted. After the import, run Optimize plans to inspect the remaining references.","backup.import_details":"Import reference details","backup.import_detail.incoming_remapped":"References updated inside the imported copy: {n}","backup.import_detail.target_repaired":"Existing references restored: {n}","backup.import_detail.preserved_unresolved":"Unresolved references preserved: {n}","backup.import_detail.collisions":"Destination conflicts preserved safely: {n}","backup.import_detail.dropped_links":"Incoming links omitted by transfer rules: {n}","backup.import_detail.bounded_lineages":"Overly nested identifiers left bounded: {n}","backup.replace_warning":"This replaces the current configuration and layout. Uploaded files are never deleted. One undo remains available until the next plan edit.","backup.foreign_bookkeeping":"Instance-specific known/new-device bookkeeping will not be imported.","backup.final_name":"New space name","backup.target_settings":"The target instance's global settings remain unchanged.","backup.duplicates":"Bindings already present: {n}","backup.skip":"Skip duplicate devices","backup.virtual_copy":"Add safe static virtual copies","backup.content":"Referenced content","backup.content_available":"available locally","backup.content_external":"external link","backup.content_detach_required":"will be detached","backup.confirm_detach":"I understand that unavailable internal plans and attachments will be detached from the imported configuration.","backup.replace":"Replace","backup.add":"Add space","backup.space_done":"Space imported: {rooms} rooms, {markers} devices, {refs} existing references restored","backup.full_done":"Backup restored: {spaces} spaces, {rooms} rooms, {markers} devices","backup.undo_import":"Undo last full import","backup.import_undone":"Full import undone"};const Xd=new WeakSet,Jd=new WeakSet;function Qd(e,t,i){const n=i?t.state(i):"ready";return i&&"pending"===n?(Jd.has(e)||(e.inert=!0,e.setAttribute("aria-busy","true"),Jd.add(e)),t.ensure(i).then(()=>{e.isConnected&&e.requestUpdate()}),Xd.has(e)?"warm":"cold"):(Jd.delete(e)&&(e.inert=!1,e.removeAttribute("aria-busy")),i&&(e.setAttribute("lang","fallback"===n?"en":i),Xd.add(e)),"ready")}function eu(){return j``}const tu=[{code:"en",nativeLabel:"English",dictionary:Zd},{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":"Проверьте сеть и нажмите ещё раз.","color_picker.title":"Выбор цвета","color_picker.hue":"Оттенок","color_picker.saturation":"Насыщенность","color_picker.value":"Яркость","color_picker.hex":"Цвет HEX","color_picker.invalid_hex":"Введите цвет HEX из 3 или 6 цифр","btn.properties":"Свойства","btn.keep_as_walls":"Оставить стенами","btn.delete_room_keep_walls":"Удалить комнату, оставить стены","btn.delete_room_with_walls":"Удалить комнату и стены","title.markup_select":"Выбор и редактирование стен, колонн и сохранённых контуров","title.markup_column":"Колонна: кликните точку сетки для квадратной колонны","markup.partition":"Перегородка","markup.column":"Колонна","markup.hint_column":"кликните точку сетки, чтобы поставить квадратную колонну","history.draft_segment":"Добавление сегмента черновика комнаты","history.draft_merge":"Соединение незавершённых контуров комнаты","history.draft_segment_delete":"Удаление сегмента черновика комнаты","history.partition_add":"Добавление перегородки","history.column_add":"Добавление колонны","history.physical_edit":"Изменение физического объекта","history.physical_delete":"Удаление физического объекта","history.physical_move":"Перемещение физического объекта","history.contour_to_partitions":"Преобразование контура в замкнутые стены","history.wall_chain_finish":"Завершение цепочки стен","history.wall_face_batch":"Создание комнат из стен","toast.column_duplicate":"Колонна с тем же центром и внешним размером уже существует","confirm.delete_draft":"Удалить весь незавершённый контур комнаты?","confirm.delete_draft_segment":"Удалить этот сегмент черновика? Оставшийся контур может разделиться на два.","physical.partition_properties":"Свойства перегородки","physical.column_properties":"Свойства колонны","physical.draft_properties":"Свойства сегмента черновика","physical.shape":"Форма","physical.square":"Квадрат","physical.circle":"Круг","physical.diameter":"Диаметр","physical.side":"Сторона","physical.rotation":"Угол поворота","physical.length":"Длина","physical.allowed_range":"Допустимо: {min}–{max} {unit}","physical.delete_segment":"Удалить сегмент","physical.delete_draft":"Удалить весь контур","physical.column_size_title":"Внешняя сторона квадратной колонны, создаваемой кликом (1–150 см).","card.title":"План дома","count.devices":"{n} устр.","empty.no_spaces":"Пространств пока нет.","empty.add_first":"Добавьте первое пространство и загрузите план этажа.","empty.install":"Установите интеграцию House Plan и добавьте запись в «Устройства и службы».","btn.add_space":"Добавить пространство","btn.cancel":"Отмена","btn.save":"Сохранить","btn.close":"Закрыть","btn.delete":"Удалить","btn.edit":"Редактировать","btn.open_in_ha":"Открыть в HA","btn.reset":"Сброс","btn.attach":"Прикрепить…","btn.upload":"Загрузить…","btn.replace":"Заменить…","title.zoom_in":"Приблизить","title.zoom_out":"Отдалить","title.zoom_fit":"Вписать всё","title.markup":"Разметка комнат: сетка, линии, контуры","title.configure_space":"Настроить пространство","title.add_space":"Добавить пространство","title.markup_add":"Стены: рисуйте непрерывную цепочку; Shift фиксирует 45°. Смена инструмента или выход завершает её как независимые стены","title.markup_merge":"Объединить: клик по одной комнате, затем по соседней с общей стеной","title.markup_split":"Разделить комнату: клик по комнате, затем две точки на её стенах","title.markup_delroom":"Удалить комнату: кликните внутри комнаты и подтвердите удаление","title.need_plan":"Загрузите подложку (план этажа)","markup.add":"Стены","markup.merge":"Объединить","markup.split":"Разделить","markup.resize":"Размер","title.markup_resize":"Изменение размера комнат: тяните доступную ручку горизонтальной или вертикальной стены","markup.hint_resize":"тяните доступную ручку стены · стена упирается в первую небезопасную позицию · Esc — отмена · Ctrl+Z — отмена шага","resize.disabled.diagonal":"Стена расположена под углом: Resize поддерживает только горизонтальные и вертикальные стены","resize.disabled.side-angle":"Примыкающая стена расположена под углом: для Resize обе примыкающие стены должны образовывать прямой угол","resize.disabled.duplicate-physical-wall":"Стену перекрывает отдельная перегородка, незавершённый контур или колонна; удалите или переместите её перед изменением размера","resize.disabled.partial-shared":"Соседняя комната использует только часть этой стены, поэтому её нельзя безопасно двигать как одну общую стену","resize.disabled.unequal-shared":"У соседней комнаты другие конечные точки или длина стены, поэтому стены нельзя безопасно двигать вместе","resize.disabled.multiple-rooms":"Перемещение затронуло бы больше двух комнат","resize.disabled.thickness-conflict":"Толщину стены нельзя безопасно сохранить","resize.disabled.opening-conflict":"Проём на этой стене нельзя безопасно переместить","resize.disabled.invalid-geometry":"Эту стену нельзя переместить без изменения структуры плана","resize.limit_stopped":"Стена остановлена: дальше нарушается ограничение стыков","resize.commit_failed":"Изменение размера отменено: итоговый план не прошёл проверку геометрии","resize.preview_failed":"Стена остановлена в последней безопасной позиции: геометрию плана нельзя сохранить без потерь","markup.opening":"Проём","markup.delete_room":"Удалить комнату","history.undo":"Отменить","history.redo":"Повторить","history.undo_named":"Отменить: {name} (Ctrl+Z)","history.redo_named":"Повторить: {name} (Ctrl+Shift+Z / Ctrl+Y)","history.undo_empty":"Нет операций для отмены","history.redo_empty":"Нет операций для повтора","history.undone":"Отменено: {name}","history.redone":"Повторено: {name}","history.add_room":"Создание комнаты","history.split_room":"Разделение комнаты","history.merge_rooms":"Объединение комнат","history.resize_room":"Изменение размера комнаты","history.wall_thickness":"Изменение толщины стены","history.add_opening":"Добавление дверного или оконного проёма","history.edit_opening":"Изменение проёма","history.move_opening":"Перемещение проёма","history.delete_opening":"Удаление проёма","history.delete_room":"Удаление комнаты","history.delete_room_keep_walls":"Удаление комнаты с сохранением стен","history.delete_room_with_walls":"Удаление комнаты и её стен","history.decor_add":"Добавление объекта декора","history.decor_edit":"Изменение объекта декора","history.decor_move":"Перемещение объекта декора","history.decor_transform":"Трансформация объекта декора","history.decor_delete":"Удаление объекта декора","history.backdrop_transform":"Трансформация подложки плана","opening.new":"Новый проём","opening.edit":"Проём","opening.door":"Дверь","opening.window":"Окно","opening.gate":"Ворота","opening.passage":"Открытый проём","opening.passage_binding_warning":"При сохранении датчик открытия и замок будут удалены.","opening.invalid_passage_fields":"У открытого проёма на плане «{room}» есть недопустимые параметры: {fields}.","opening.type_label":"Тип","opening.length_label":"Длина, см","opening.contact_label":"Датчик открытия","opening.lock_label":"Замок","opening.none":"— нет —","opening.search_ph":"Поиск: имя или entity_id…","opening.invert":"Инвертировать открыто/закрыто","opening.flip_h":"Петли с другой стороны","opening.flip_v":"Открывается в другую сторону","opening.open":"Открыто","opening.closed":"Закрыто","opening.locked":"Заперто","opening.unlocked":"Не заперто","opening.state_unknown":"недоступно","opening.no_entities":"Датчики не привязаны — статичный символ на плане.","toast.opening_no_wall":"Кликните рядом со стеной комнаты или независимой стеной","opening.host_partition":"Независимая стена","opening.partition_orphan":"Независимая стена этого проёма больше не существует","opening.partition_jamb_margin":"Оставьте от края проёма до торца стены минимум {distance}","opening.rebind_partition":"Привязать к другой независимой стене","confirm.delete_partition_openings_title":"Удалить стену и проёмы?","confirm.delete_partition_openings_body":"В стене есть проёмы: {count}. Они будут удалены вместе со стеной.","confirm.delete_partition_openings_item":"• {type}, {length}","markup.delete":"Удалить","markup.hint_points":"точек: {n} · Shift — шаг 45° · Esc — завершить цепочку · Ctrl+Z — убрать точку · при замыкании будет предложена комната","markup.hint_start":"кликните точку сетки, чтобы начать цепочку стен","tip.lqi":"средний сигнал zigbee:","tip.area":"площадь: {value}","info.device_header":"Устройство на плане","info.model":"Модель","info.state":"Состояние","info.link":"Ссылка","info.manuals":"Инструкции","info.none":"Нет дополнительной информации","marker.new_device":"Новое устройство","marker.name_label":"Имя (отображается на плане)","marker.name_ph":"Название","marker.binding_label":"Привязка к устройству HA","marker.binding_disabled":"деактивировано в Home Assistant","marker.virtual_option":"Виртуальное устройство (без привязки)","marker.search_ph":"Поиск устройства / группы…","marker.nothing_found":"ничего не найдено","marker.room_label":"Комната","marker.room_override":" (переопределить размещение)","marker.room_choose":"— выберите комнату —","marker.room_auto":"— по зоне устройства (авто) —","marker.icon_label":"Иконка","marker.icon_ph":"mdi:… (пусто = авто)","marker.display_label":"Отображение","display.badge":"Значок + состояние","display.icon_ripple":"Значок + состояние и активность","display.static_icon":"Всегда статичный значок","marker.display_hint":"Значок + состояние меняет подложку при работе, открытии, тревоге и недоступности. Значок + состояние и активность дополнительно показывает короткую пульсацию для событий и постоянную — для работы, движения или присутствия. Значение + состояние заменяет значок одним однозначным значением HA. Статичный значок не реагирует на состояния устройства.","marker.display_hint_badge":"Значок и динамическая подложка показывают состояние устройства без обычной пульсации активности. Красная тревога сохраняется.","marker.display_hint_icon":"Значок и динамическая подложка показывают состояние устройства без обычной пульсации активности. Красная тревога сохраняется.","marker.display_hint_icon_ripple":"Значок, динамическая подложка и пульсация: короткая — для событий, постоянная — для работы, движения или присутствия. Красная тревога имеет отдельный приоритет.","marker.display_hint_value":"Значок заменяется одним однозначным значением Home Assistant; подложка продолжает показывать состояние. Красная тревога сохраняется.","marker.display_hint_static_icon":"Подложка в цветах темы и значок всегда остаются одинаковыми. Состояния, активность, недоступность и тревоги не меняют отображение.","marker.static_alarm_warning":"Это устройство может сообщать о тревогах. Статичный режим скрывает визуальную тревогу маркера.","marker.preview.title":"Предпросмотр отображения","marker.preview.actual":"Сейчас","marker.preview.example":"Пример","marker.preview.integration":"Интеграция","marker.preview.source":"Источник отображения","marker.preview.current_state":"Текущее состояние","marker.preview.result":"На плане","marker.preview.details":"Подробнее об источниках","marker.preview.select_source":"Выберите устройство или сущность Home Assistant, чтобы увидеть фактическое отображение.","marker.preview.unknown_provider":"Интеграция неизвестна","marker.preview.virtual_provider":"House Plan · виртуальное устройство","marker.preview.no_source":"Нет активного источника","marker.preview.no_state":"Нет текущего состояния","marker.preview.mixed_states":"Несколько разных состояний","marker.preview.multiple_sources":"Источников: {n}","marker.preview.more_sources":"ещё {n}","marker.preview.scaled":"Предпросмотр уменьшен до {n}%, чтобы поместиться. Сохранённый размер не изменится.","marker.preview.demo_short":"Показать краткую активность","marker.preview.demo_continuous":"Показать постоянную активность","marker.preview.stop_continuous":"Остановить постоянную активность","marker.preview.demo_short_notice":"Пример краткой активности; фактическое состояние устройства не меняется.","marker.preview.demo_continuous_notice":"Пример постоянной активности; фактическое состояние устройства не меняется.","marker.preview.demo_already_visible":"Текущее состояние уже показывает реальную активность или тревогу.","marker.preview.reduced_motion":"В системе включено уменьшение движения, поэтому обычная активность показана точкой.","marker.preview.reason.neutral":"Нейтральная тёмная подложка","marker.preview.reason.working":"Жёлтая подложка: устройство сейчас работает","marker.preview.reason.working_activity":"Жёлтая подложка и эффект активности: устройство сейчас работает","marker.preview.reason.open":"Оранжевая подложка: физически открыто или разблокировано","marker.preview.reason.cover_icon_state":"Нейтральная подложка; состояние и значок определяет сущность шторы или заслонки","marker.preview.reason.presence":"Эффект активности, пока обнаружено присутствие","marker.preview.reason.event":"Короткий эффект активности после события","marker.preview.reason.transition":"Эффект активности во время движения или смены состояния","marker.preview.reason.media_neutral":"Медиаустройство остаётся на нейтральной тёмной подложке, пока доступно","marker.preview.reason.unavailable":"Приглушённая нейтральная подложка: отключено или недоступно","marker.preview.reason.alarm":"Красная тревожная подложка; тревога отображается всегда","marker.preview.reason.live_states_disabled":"Оформление по живым состояниям отключено в настройках карточки","marker.preview.reason.value_no_state":"Нет подходящего значения состояния — вместо него показан значок","marker.preview.reason.value_ambiguous_sources":"Подходит несколько источников значения — вместо него показан значок","marker.preview.reason.value_non_scalar":"Источник вернул не простое значение — вместо него показан значок","marker.preview.reason.value_virtual":"У виртуального устройства нет значения HA — вместо него показан значок","marker.preview.reason.vacuum_live_plan_only":"Живая позиция и след пылесоса доступны только на полном плане","marker.preview.reason.hidden_design_preview":"Устройство скрыто на плане, но его оформление видно в предпросмотре","marker.preview.reason.composite_power_source":"Состояние берётся из сущности питания устройства; вспомогательные переключатели не учитываются","marker.preview.reason.activity_display_disabled":"Выбранный режим отображения не показывает обычные эффекты активности","marker.preview.reason.ha_disabled":"Привязка отключена в Home Assistant, поэтому устройство будет скрыто на плане","marker.preview.reason.orphaned":"Сохранённая привязка Home Assistant больше не найдена","marker.preview.reason.static_icon":"Статичный режим: состояние устройства не меняет значок","marker.activity_color":"Цвет пульсации активности","marker.ripple_size":"Размер пульсации активности","marker.activity_alarm_note":"Цвет и размер относятся только к обычной активности и не влияют на красную тревогу.","marker.pulse_a11y_alarm":"Тревога","marker.pulse_a11y_event":"Недавнее событие","marker.pulse_a11y_presence":"Обнаружено присутствие","marker.pulse_a11y_transition":"Изменение состояния","marker.pulse_a11y_running":"Работает","marker.state_a11y_neutral":"Обычное состояние","marker.state_a11y_working":"Работает","marker.state_a11y_open":"Открыто","marker.state_a11y_locked":"Заблокировано","marker.state_a11y_unlocked":"Разблокировано","marker.state_a11y_alarm":"Тревога","marker.state_a11y_unavailable":"Недоступно","marker.lqi_a11y_low":"LQI {value}, слабый сигнал","marker.lqi_a11y_mid":"LQI {value}, средний сигнал","marker.lqi_a11y_high":"LQI {value}, сильный сигнал","marker.size_label":"Размер / поворот значка","marker.angle_label":"Поворот","marker.model_label":"Модель","marker.model_ph":"напр. Aqara T&H","marker.link_label":"Ссылка","marker.desc_label":"Описание","marker.desc_ph":"Заметки, характеристики…","marker.manuals_label":"Инструкции (PDF и т.п.)","marker.sub_device":"устройство","marker.sub_z2m_group":" · Z2M-группа","marker.sub_group":"группа","marker.sub_helper":"хелпер","space.new":"Новое пространство","space.header":"Пространство","space.title_label":"Название","space.title_ph":"Например: Гараж","space.plan_label":"Подложка (план)","space.no_plan":"нет подложки","space.plan_alt":"план","room.new":"Новая комната","room.name_label":"Отображаемое имя","room.name_ph":"Например: Терраса","room.area_label":"Зона Home Assistant (свободные)","room.no_area_option":"— без зоны —","room.default_name":"Комната","device.unnamed":"без имени","device.light_group":"группа света","device.fallback":"устройство","device.virtual":"виртуальное устройство","confirm.delete_room":"Удалить комнату «{name}»?","confirm.delete_room_title":"Удалить комнату «{name}»?","confirm.delete_room_body":"Выберите, нужно ли оставить физические стены, принадлежащие только этой комнате. Общие с другой комнатой стены сохраняются всегда.","confirm.remove_marker":"Удалить «{name}» с плана? Устройство исчезнет полностью и перестанет участвовать в данных плана. Позже его можно будет добавить заново.","confirm.erase_decor":"Стереть объект «{kind}»? Действие можно отменить из истории редактора.","confirm.delete_space":"Удалить пространство «{title}» со всеми комнатами и разметкой?","space.delete_blocked":"Это пространство всё ещё используется устройствами: {n}. Сначала перенесите их в другое пространство или удалите.","toast.pos_save_failed":"Не удалось сохранить позицию: {err}","toast.no_entity":"У устройства нет подходящей сущности","toast.ha_disabled_action":"Деактивированный объект Home Assistant нельзя использовать на плане.","toast.ha_disabled_show_device":"Деактивированное в Home Assistant устройство нельзя показать на плане. Сначала активируйте его в Home Assistant.","toast.ha_disabled_show_entity":"Деактивированную в Home Assistant сущность нельзя показать на плане. Сначала активируйте её в Home Assistant.","toast.ha_disabled_add":"Деактивированный объект Home Assistant нельзя добавить на план. Сначала активируйте его в Home Assistant.","toast.ha_binding_unverified":"Статус объекта не удалось подтвердить по реестру Home Assistant. Отображение и действия временно недоступны.","toast.markup_needs_server":"Разметка доступна после переноса конфига на сервер","toast.space_order_changed":"Порядок изменён. Если где-то этаж карточки задан номером, проверьте такие панели.","toast.conflict":"Конфиг изменён в другом окне — данные обновлены, повторите последнее действие","toast.cfg_save_failed":"Не удалось сохранить конфиг: {err}","toast.room_overlap":"Контур накладывается на комнату «{name}» — комнаты не должны накладываться","toast.contour_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_saved":"Пространство сохранено","toast.space_deleted":"Пространство удалено","toast.delete_failed":"Ошибка удаления: {err}","toast.error":"Ошибка: {err}","toast.toggle_target_unavailable":"Цель «{name}» недоступна — действие не выполнено","toast.toggle_targets_unavailable":"Цели недоступны: {names}. Действие не выполнено","toast.file_failed":"Файл «{name}» не загружен: {err}","toast.files_attached":"Прикреплено файлов: {n}","err.unknown":"неизвестная ошибка","err.code":"код {code}","err.too_large":"файл больше {mb} МБ","err.bad_ext":"недопустимый тип (нужен PDF/изображение)","err.unauthorized":"нужны права администратора","editor.title":"Заголовок","editor.default_floor":"Стартовое пространство","editor.default_floor_missing":"Стартовое пространство «{id}» больше не существует. Выберите другое.","editor.floor":"Закреплённое пространство","editor.floor_none":"— не закреплять —","editor.floor_index":"YAML-индекс {index} (сохранён)","fixed_floor.loading":"Загружаем закреплённое пространство…","fixed_floor.invalid_title":"Закреплённое пространство недоступно","fixed_floor.invalid_body":"Проверьте floor в конфигурации карточки. Настроенное значение: {value}","editor.icon_size":"Размер иконок, % ширины плана","editor.show_temperature":"Показывать температуру","editor.live_states":"Живые состояния (вкл/выкл, открыто…)","editor.show_signal":"Показывать сигнал zigbee (LQI)","editor.language":"Язык интерфейса","editor.lang_auto":"Авто (профиль HA)","title.icon_rules":"Правила иконок: какая MDI-иконка достаётся устройству по имени","rules.title":"Правила иконок","rules.hint":"Правила проверяются сверху вниз по строке «имя устройства + модель» (regex без учёта регистра); срабатывает первое совпадение. Если ничего не подошло — решает device class сущности, затем — иконка-заглушка.","rules.pattern_ph":"regex, напр. розетк|plug","rules.icon_ph":"mdi:power-socket-de","rules.add":"Добавить правило","rules.reset":"Сбросить к умолчаниям","rules.test_ph":"Проверьте имя устройства…","rules.invalid":"некорректный regex","rules.saved":"Правила иконок сохранены","btn.up":"Вверх","btn.down":"Вниз","tap.info":"Карточка устройства","tap.more_info":"Диалог HA (more-info)","tap.toggle":"Переключить состояние","marker.tap_label":"Действие по нажатию для этого устройства","tap.toggle_note":"Под селектором показано, какое состояние изменится. Защищённые устройства не переключаются с плана.","import.title":"Создать пространства из этажей HA","import.hint":"Home Assistant уже знает эти этажи. Отметьте, какие превратить в пространства плана — далее для каждого попросим картинку плана. Комнаты затем обводятся вручную по плану.","import.start":"Создать: {n}","import.manual":"Начать с нуля","import.progress":"Этаж {i} из {n}","import.done":"Пространства созданы. Обведите комнаты: кликайте по точкам сетки и замкните контур.","btn.skip":"Пропустить","space.scale_label":"Масштаб (размер клетки сетки)","space.scale_unit":"см на клетку","space.scale_unit_imperial":"дюйм на клетку","space.display_section":"Отображение","space.show_borders":"Всегда отображать границы комнат","space.zero_wall_style":"Стены нулевой толщины","space.zero_wall_dashed":"Пунктирные","space.zero_wall_solid":"Сплошные","space.zero_wall_help":"Пунктирные стены пропускают свет. Сплошные стены блокируют свет, даже при нулевой толщине.","space.show_names":"Отображать названия комнат (перетаскиваются)","space.room_color":"Цвет границ и названий","space.opacity":"Прозрачность","space.fill_label":"Заливка комнат","fill.none":"Нет","fill.lqi":"По силе зигби-сигнала","fill.light":"По освещению","fill.custom":"Свой цвет","space.custom_fill":"Цвет заливки","space.source_file":"У меня есть картинка плана","space.source_draw":"Нет подложки — нарисую комнаты вручную","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.show_button":"Показывать кнопку","editor.button_label":"Текст кнопки","editor.button_target":"Путь дашборда (куда вести)","marker.sub_entity":"сущность","title.general_settings":"Общие настройки","gs.title":"Общие настройки","gs.hint":"Цвета заливок действуют на все пространства; у каждого цвета своя прозрачность. Какой режим заливки использует пространство — задаётся в его диалоге.","gs.light_group":"Заливка: освещение","gs.light_on":"Свет включён","gs.light_off":"Весь свет выключен","gs.temp_group":"Заливка: температура","gs.temp_cold":"Холодно","gs.temp_ok":"Комфорт","gs.temp_hot":"Жарко","gs.lqi_group":"Заливка: зигби-сигнал","gs.lqi_low":"Слабый сигнал","gs.lqi_high":"Сильный сигнал","gs.reset":"Сбросить к умолчаниям","gs.saved":"Общие настройки сохранены","space.show_lqi":"Показывать зигби-сигнал (LQI) у устройств","space.hide_decor":"Скрыть декоративный слой","space.hide_decor_tip":"Линии, фигуры, надписи и мебель остаются на месте — их видно в редакторе подложки, но не на плане.","space.hide_openings":"Скрыть проёмы","space.hide_openings_tip":"Двери, окна и ворота не рисуются, но продолжают работать: свет проходит, солнце светит в окна, датчики открытия срабатывают. В редакторе плана проёмы видно всегда.","gs.light_none":"Нет источников света","mode.plan":"Редактор плана","mode.devices":"Редактор устройств","display.value":"Значение + состояние","marker.subarea":"без зоны, вручную","device.new":"Новое устройство — откройте его редактор, чтобы снять отметку","opening.unlock_action":"Открыть замок","opening.lock_action":"Закрыть замок","opening.lock_pending":"Выполняется…","title.close_editor":"Закрыть редактор (вернуться к просмотру)","devbar.rules":"Правила иконок","device_inbox.button":"Устройства","device_inbox.title":"Устройства на плане","device_inbox.search":"Поиск по устройствам, сущностям и интеграциям…","device_inbox.add_virtual":"Добавить виртуальное устройство","device_inbox.tab_on_plan":"На плане","device_inbox.tab_available":"Доступны","device_inbox.tab_hidden":"Скрытые","device_inbox.tab_readd":"Доступны снова","device_inbox.only_new":"Только новые","device_inbox.show_entities":"Показывать сущности","device_inbox.show_hidden":"Показывать скрытые на плане","device_inbox.new":"Новое","device_inbox.find":"Найти на плане","device_inbox.edit":"Настроить","device_inbox.hide":"Скрыть","device_inbox.show":"Показать","device_inbox.add":"Добавить","device_inbox.readd":"Добавить заново","device_inbox.hide_available":"Скрыть из списка","device_inbox.show_more":"Показать ещё","device_inbox.more_actions":"Другие действия","device_inbox.find_hidden_hint":"Сначала включите «Показывать скрытые на плане»","device_inbox.show_disabled":"Перед показом активируйте эту привязку в Home Assistant","device_inbox.empty_on_plan":"На плане пока нет подходящих устройств.","device_inbox.empty_available":"Нет доступных устройств для добавления.","device_inbox.empty_hidden":"Скрытых устройств нет.","device_inbox.empty_readd":"Нет удалённых устройств, доступных для повторного добавления.","device_inbox.reason_visible_auto":"Найдено автоматически","device_inbox.reason_visible_explicit":"Добавлено явно","device_inbox.reason_manual_hidden":"Скрыто пользователем","device_inbox.reason_automatic_hidden":"Скрыто автоматически","device_inbox.reason_service_entry":"Служебная запись реестра","device_inbox.reason_excluded_integration":"Интеграция исключена фильтрами устройств","device_inbox.reason_excluded_domain":"Непространственный тип сущности","device_inbox.reason_grouped_light":"Представлено группой света комнаты","device_inbox.reason_represented_by_parent":"Представлено родительским устройством","device_inbox.reason_removed":"Ранее удалено с плана","device_inbox.reason_available":"Можно добавить на план","device_inbox.reason_no_bound_room":"Зона HA не связана с комнатой плана","device_inbox.status_ha_disabled":"Отключено в Home Assistant","device_inbox.status_orphaned":"Привязка больше не найдена в Home Assistant","device_inbox.status_unverified":"Реестр Home Assistant временно недоступен","device_inbox.saved":"Список устройств обновлён","space.roomcard_section":"В карточке комнаты:","space.label_temp":"Температура","space.label_hum":"Влажность","space.label_lqi":"Средний Zigbee-сигнал","space.label_light":"Свет вкл/выкл","roomcard.light_on":"Вкл","roomcard.light_off":"Выкл","roomcard.light_partial":"{on} из {total}","toast.split_pick_inside":"Промежуточные точки разреза — внутри комнаты","mode.decor":"Редактор подложки","decor.select":"Выбрать","decor.line":"Линия","decor.rect":"Прямоугольник","decor.ellipse":"Овал","decor.text":"Надпись","decor.erase":"Стереть","decor.erase_confirm_title":"Стереть объект?","decor.color":"Цвет","decor.width":"Толщина линии","decor.line_style":"Стиль линии","decor.line_style_solid":"Сплошная","decor.line_style_dashed":"Пунктирная","decor.fill":"Заливка","decor.fill_color":"Цвет заливки","decor.length":"Длина","decor.size":"Размер","decor.angle":"Угол поворота, °","decor.text_size":"Размер текста","decor.backdrop_properties":"Свойства картинки-подложки","decor.text_title":"Надпись","decor.object_title":"Редактирование: {kind}","decor.text_label":"Текст","decor.live_group":"Вставить переменную HA","decor.live_entity":"Сущность","decor.live_entity_ph":"выберите сущность","decor.live_attr":"Значение","decor.live_attr_ph":"выберите состояние или атрибут","decor.live_state":"Состояние","decor.backdrop":"Картинка-подложка","decor.backdrop_hint":"Тяните картинку — перемещение; угол — размер; верхнюю ручку — поворот. Shift меняет пропорции или снимает шаг угла.","decor.backdrop_reset":"Вернуть картинку","decor.backdrop_reset_done":"Картинка вернулась на своё место и в свой размер","marker.icon_auto":"Авто: {icon} (по правилам иконок; выберите свою, чтобы заменить)","marker.icon_pin_auto":"Закрепить","mode.plan_tip":"Редактор плана — геометрия дома: рисование и объединение/разделение комнат, привязка к зонам HA, двери, окна и ворота, карточки комнат, масштаб","mode.devices_tip":"Редактор устройств — всё про значки: перетаскивание, клик — настройка привязки/иконки/отображения, виртуальные устройства, правила иконок","mode.decor_tip":"Редактор подложки — чисто визуальный декор под планом: линии, прямоугольники, овалы и надписи, не реагирующие на клики","space.glow_enabled":"Свечение источников света","gs.glow_group":"Свечение источников света","gs.glow_base":"Темнота дома","gs.glow_light":"Цвет света по умолчанию / интенсивность","gs.wall_group":"Стены","gs.wall_fill":"Цвет заливки стен","gs.glow_radius":"Радиус свечения","gs.unit_m":"м","gs.unit_ft":"фут","marker.controls_label":"Управляет другими источниками света","marker.controls_hint":"При действии «Переключить» клик разом переключает все добавленные здесь источники. Собственная сущность маркера управляется напрямую и сюда не добавляется; чтобы считать её светом, включите флаг ниже.","marker.controls_filter":"Поиск ламп и выключателей…","info.controls":"Управляет","marker.glow_radius_label":"Радиус свечения","marker.glow_radius.help":"Задаёт радиус свечения в метрах или футах; пустое значение использует радиус из общих настроек.","marker.glow_radius.help.aria":"Подсказка: радиус свечения","markup.wallthick":"Толщина","markup.select":"Выбрать","title.markup_wallthick":"Толщина — клик по стене задаёт толщину от 0 до 100 см.","markup.hint_wallthick":"клик по стене · Esc закрывает без применения","wallthick.field":"Толщина","wallthick.unit_cm":"см","wallthick.unit_in":"дюйм","wallthick.apply_room":"Применить ко всем стенам комнаты","markup.draw_wall_title":"Толщина каждого нового сегмента стены (0–100 см). Общие стены сохраняют существующее значение.","room.queue_progress":"Комната {current} из {total}","toast.wall_rooms_saved":"Создано комнат: {n}","toast.wall_chain_saved":"Цепочка стен сохранена","toast.wallthick_pick":"Кликните по стене","toast.wallthick_set":"Толщина стены задана","toast.wallthick_cleared":"Толщина стены убрана","toast.physical_range":"Введите значение от {min} до {max} {unit}","toast.zero_wall_opening_conflict":"Сначала удалите проём на этом участке стены.","toast.zero_wall_ambiguous":"Не удалось однозначно выбрать участок стены. Уточните геометрию узла.","toast.zero_wall_migration_blocked":"Пространство не преобразовано: {reason}. Данные не изменены.","toast.physical_angle":"Введите угол поворота от 0° до 90°, не включая 90°","toast.physical_limit":"В пространстве достигнут лимит объектов этого типа","toast.geometry_unsafe":"Изменение отменено: геометрию стен нельзя безопасно построить.","junction.limit_angle":"Слишком острый угол между стенами: {actual}°, минимум {limit}°.","junction.limit_valence":"Слишком много стен в одном узле: {actual}, максимум {limit}.","junction.limit_length":"Слишком короткий участок стены: {actual} см, минимум {limit} см.","junction.limit_distance":"Стены и узлы слишком близко: {actual} см, минимум {limit} см.","junction.limit_clearance":"Внутри комнаты не остаётся места: {actual} см², минимум {limit} см².","junction.limit_check_failed":"Проверку стыков выполнить не удалось — изменение не сохранено","toast.wall_model_migration_blocked":"Не удалось обновить модель стен: {reason}. План не изменён. Запустите «Оптимизировать планы»; если ошибка повторится, исправьте конфликтующую геометрию стен.","toast.wall_model_client_outdated":"Обновите карточку и перезагрузите страницу перед редактированием плана.","wall_model.reason.invalid-room":"некорректный контур комнаты","wall_model.reason.zero-length":"отрезок стены нулевой длины","wall_model.reason.third-owner":"стена принадлежит более чем двум комнатам","wall_model.reason.duplicate-id":"конфликт идентификаторов стен","wall_model.reason.thickness-conflict":"конфликт значений толщины стены","wall_model.reason.opening-host":"проём нельзя однозначно привязать к стене","toast.delete_room_pick":"Кликните внутри комнаты, которую нужно удалить","toast.plan_snap_ambiguous":"Увеличьте масштаб, чтобы выбрать узел стены","toast.wall_repair_ambiguous":"У контура несколько возможных соединений. Увеличьте масштаб и соедините стены явно.","toast.wall_repair_too_large":"Разрыв больше 2 см. Соедините стены перед созданием комнаты.","toast.wall_repair_changed":"Геометрия стен изменилась. Попробуйте создать комнату ещё раз.","toast.opening_on_zero_wall":"Проёмы на стене нулевой толщины запрещены","marker.from_ha_option":"Выбрать из списка HA","marker.show_entities":"Показывать сущности","marker.show_entities_tip":"Добавляет в список не только устройства, но и все их сущности","marker.pick_ph":"Выберите устройство…","room.open_area":"Открыть зону в HA","view.volumetric":"Объёмный вид","view.flat":"Плоский вид","kiosk.title":"Размеры на этом экране","kiosk.hint":"Хранится только на этом устройстве — у каждого настенного планшета или ТВ свои удобные размеры.","kiosk.icon_scale":"Размер значков устройств","kiosk.font_scale":"Размер текста карточек комнат","editor.kiosk":"Режим настенного устройства (киоск)","editor.cycle":"Автосмена пространств каждые N секунд (киоск, 0 = выкл)","room.settings_title":"Настройки комнаты","room.settings_section":"Настройки комнаты (переопределяют пространство)","room.fill_label":"Заливка в ЭТОЙ комнате","fill.inherit":"Как у пространства","room.custom_fill_space":"Цвет пространства","room.custom_fill_own":"Цвет комнаты","room.temp_src_label":"Источник температуры","room.hum_src_label":"Источник влажности","room.src_average":"Средняя по датчикам комнаты (по умолчанию)","room.src_pick":"Конкретное устройство или сущность HA","room.src_ph":"Выберите источник…","toast.room_updated":"Комната обновлена","space.card_font":"Размер шрифта карточек комнат (всё пространство)","room.sizes_section":"Размеры шрифтов","room.name_scale":"Размер названия","room.label_scale":"Размер подписей","preview.room_name":"Гостиная","toast.cfg_reload_failed":"Не удалось перечитать план с сервера: {err}","toast.locale_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.light_role_label":"Является источником света","marker.light_role.help":"Определяет, является ли сам маркер пространственным источником света. Привязанные выше лампы остаются независимыми источниками для комнаты.","marker.light_role.help.aria":"Подсказка: является ли устройство источником света","marker.light_role_auto_yes":"Автоматически (источник света)","marker.light_role_auto_no":"Автоматически (не источник света)","marker.light_role_always":"Всегда источник света","marker.light_role_never":"Никогда не источник света","marker.light_entity_label":"Ведущая сущность света","marker.light_entity.help":"Для составного устройства выберите сущность, состояние, цвет и яркость которой представляют этот источник на плане. Автоматический вариант сохраняет совместимость со старыми планами.","marker.light_entity.help.aria":"Подсказка: ведущая сущность света","marker.light_entity_auto":"Автоматически ({entity})","marker.light_entity_none":"нет управляемой сущности","marker.light_entity_missing":"Сохранённая сущность {entity} недоступна. Временно используется {fallback}; выбор восстановится, если сущность вернётся.","marker.toggle_entity_label":"Переключаемая сущность","marker.toggle_entity.help":"Для составного устройства выберите собственную лампу или переключатель, которой управляет нажатие. Автоматический вариант сохраняет прежние правила цели и не зависит от ведущей сущности света.","marker.toggle_entity.help.aria":"Подсказка: переключаемая сущность","marker.toggle_entity_auto":"Автоматически ({entity})","marker.toggle_entity_none":"нет собственной управляемой сущности","marker.toggle_entity_missing":"Сохранённой сущности {entity} больше нет среди выбираемых каналов этого маркера. Временно используется {fallback}; выбор восстановится, если сущность вернётся.","marker.glow_color_label":"Цвет и яркость свечения","marker.glow_mode.help":"Используйте данные источника, задайте только цвет или зафиксируйте цвет и яркость. Минимум — 1%; чтобы отключить источник, выберите «Никогда».","marker.glow_mode.help.aria":"Подсказка: цвет и яркость свечения","marker.glow_mode_auto":"Из источника","marker.glow_mode_color":"Задать цвет","marker.glow_mode_fixed":"Задать цвет и яркость","marker.glow_color":"Цвет свечения","marker.glow_brightness":"Яркость","marker.glow_disabled_never":"Настройки свечения недоступны: маркер явно исключён из источников света.","marker.glow_disabled_auto":"В автоматическом режиме у этого маркера не найден пространственный источник света.","marker.glow_disabled_no_entity":"Для пространственного источника нет активной управляемой сущности Home Assistant.","marker.glow_passive_hint":"У источника нет собственных данных Home Assistant. Задайте цвет и яркость вручную; радиус остаётся доступным.","marker.control_broken":"Сохранённый источник отсутствует или больше не отмечен как источник света","marker.control_missing_label":"Отсутствующий источник на плане","marker.control_passive":"пассивный источник","toast.marker_control_cycle":"Такая связь создаст циклическую цепочку управления светом.","toast.marker_binding_required":"Сначала выберите устройство Home Assistant, затем добавьте управляемый источник света.","confirm.unlock":"Открыть замок «{name}»?","toast.files_migrate_failed":"Не удалось перенести вложения к новой привязке, ссылки остались на старые файлы: {err}","space.pick_saved":"Уже загруженные","space.pick_saved_hint":"Планы, сохранённые на сервере, включая отцеплённые ранее","space.no_saved":"На сервере пока нет сохранённых планов.","space.loading":"Загрузка…","space.used_by":"используется: {list}","space.in_use":"План используется пространством — сначала отцепите его","btn.use":"Выбрать","confirm.delete_plan":"Удалить файл плана «{name}» с сервера? Действие необратимо.","toast.plans_list_failed":"Не удалось получить список планов: {err}","toast.plan_delete_failed":"Не удалось удалить план: {err}","marker.hide":"Скрыть","marker.hide_tip":"Устройство исчезнет с плана после сохранения, но продолжит участвовать в расчёте сигнала комнаты. Вернуть его можно через каталог «Устройства» в редакторе устройств.","marker.show":"Показать","marker.show_tip":"Устройство снова появится на плане после сохранения.","marker.hidden_ghost":"Устройство скрыто пользователем","marker.ha_disabled_device":"Устройство деактивировано в Home Assistant и скрыто с плана.","marker.ha_disabled_entity":"Сущность деактивирована в Home Assistant и скрыта с плана.","marker.ha_disabled_all_entities":"У устройства нет активных сущностей Home Assistant, поэтому оно скрыто с плана.","marker.ha_registry_limited":"Полный реестр Home Assistant недоступен этому пользователю. Неподтверждённый объект временно нельзя показывать или использовать.","marker.delete_tip":"Полностью удалить устройство с плана и из всех расчётов. Позже его можно добавить заново.","tap.run":"Запустить автоматизацию/скрипт/сцену","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.cal_maps":"Откалиброваны карты: {maps}","vac.autocal_no_rooms":"Интеграция не отдаёт список комнат — откройте «Подогнать вручную»","vac.autocal_no_match":"Не совпали имена комнат (нужно ≥3 общих) — откройте «Подогнать вручную»","vac.autocal_done":"Готово: привязка по {rooms} комнатам. Запустите уборку и проверьте","vac.cal_need_pos":"Робот сейчас не отдаёт координаты — запустите уборку и поставьте на паузу","vac.cal_done":"Калибровка сохранена. Запустите уборку и проверьте","vac.cal_cancelled":"Калибровка отменена","vac.fit":"Подогнать вручную","vac.fit_hint":"Перетащите карту робота на место, растяните за уголки","vac.fit_rotate":"Повернуть 90°","vac.fit_mirror":"Отразить","vac.trail_never":"Не показывать никогда","vac.trail_cleaning":"Во время уборки","vac.trail_always":"Показывать всегда","gs.bg_group":"Фон сцены","gs.bg_color":"Цвет фона вокруг плана","gs.bg_default":"Как в теме","gs.bg_theme":"по умолчанию — из темы","gs.bg_mode":"Фон плана","gs.bg_static":"Статичный цвет","gs.bg_daynight":"Следует за Солнцем","gs.bg_daynight_hint":"Фон проходит рассвет, день, закат и ночь по данным sun.sun, а при их недоступности — по локальным часам. Компас для фона не нужен.","gs.sun_group":"Солнце","gs.sun_missing":"Сущность sun.sun не найдена — фон следует локальным часам, а оконные лучи недоступны.","gs.north":"Север на плане","gs.north_ph":"не задан","gs.north_hint":"Север нужен только для оконных лучей (шаг 1°, с Shift 15°); солнечный фон работает без него.","gs.north_clear":"Сбросить","gs.north_letter":"С","gs.sun_rays":"Солнце в окнах","gs.about_group":"О карточке","gs.about_version":"Houseplan Card v{v}","gs.about_github":"GitHub · документация и issues","gs.about_telegram":"Чат в Telegram","space.bg_color":"Цвет фона вокруг плана","space.bg_inherit":"Наследовать общий","space.bg_inherited":"наследуется из общих настроек","space.bg_mode":"Фон плана","space.north":"Север на плане (переопределение)","space.north_inherited":"наследуется: {v}","space.sun_rays":"Солнце в окнах","space.sun_inherit":"Наследовать общий","space.sun_on":"Вкл","space.sun_off":"Выкл","canvas.far_objects":"Объектов далеко от плана: {n}","canvas.show_far":"Показать","canvas.home_tip":"План там — нажмите, чтобы вписать","gs.grid_group":"Обслуживание планов","gs.grid_hint":"Обновляет модели данных, выравнивает элементы по сетке и объединяет лишние фрагменты стен. Перед записью будет показан точный отчёт.","gs.align_all":"Оптимизировать планы","gs.align_title":"Оптимизировать планы","gs.align_none":"Все планы уже используют актуальную и оптимальную модель данных.","gs.optimize_no_automatic_changes":"Автоматических изменений нет. Проверьте пункты ниже.","gs.align_count":"Сдвинется элементов: {n} из {total}, максимум на {cm} см.","gs.align_where":"Наибольший сдвиг — в пространстве «{s}».","gs.align_turned":"Проёмов с исправлением угла: {n}.","gs.align_removed_drafts":"Схлопнувшиеся на сетке некорректные контуры удалены: {n}.","gs.optimize_redundant_drafts":"Сохранённые цепочки стен, полностью скрытые стенами комнат, удалены: {n}.","gs.align_preflight_failed":"Не удалось безопасно проверить геометрию следующих пространств: {spaces}{more}.","gs.align_preflight_hint":"Планы не изменены. Скопируйте диагностику кнопкой ниже и приложите её к отчёту об ошибке вместе с экспортом пространства.","gs.preflight_reason_prepare-exception":"Не удалось подготовить геометрию пространства (исключение при сборке модели)","gs.preflight_reason_wall-null":"Тело стен не построилось (объединение вернуло пустоту)","gs.preflight_reason_wall-degraded-extra":"Тело стен деградировало с лишней геометрией","gs.preflight_reason_wall-failed-core":"Ядро тела стен не собралось","gs.preflight_reason_wall-exception":"Построение стен упало с исключением","gs.preflight_reason_floor-null":"Контур пола не построился","gs.preflight_reason_floor-exception":"Построение пола упало с исключением","gs.preflight_copy":"Скопировать диагностику","gs.preflight_copied":"Диагностика скопирована","gs.preflight_update_hint":"Версии карточки и интеграции различаются — обновите House Plan и повторите.","gs.align_preflight_space":"Пространство {n}","gs.align_preflight_more":" и ещё {n}","gs.optimize_changes":"Миграций модели: {m}; обновлено пространств: {c}; устранён шум координат: {p}; объединено отрезков реальных стен: {w}; объединено отрезков стен нулевой толщины: {s}; независимых: {i}.","gs.zero_walls_migrated":"Преобразовано виртуальных участков: {n}.","gs.wall_segments_migrated":"Стабилизировано сегментов стен: {n}.","gs.optimize_lattice_summary":"Канонизировано шумовых значений координат: {n}; максимальный сдвиг: {cm} см.","gs.optimize_lattice_space":"{space}: канонизировано значений координат: {n}; оставлено значений вне сетки: {far}.","gs.optimize_coincident_partitions":"Скрытые участки независимых стен поглощены стенами комнат: {n}.","gs.optimize_openings_rehosted":"Проёмы перепривязаны к стенам комнат: {n}.","gs.optimize_walls_straightened":"Выпрямлено стен: {n}; максимальное перемещение: {cm} см.","gs.optimize_walls_straightened_where":"Максимальная правка стены: {s}.","gs.optimize_walls_straighten_skipped":"Оставлено почти осевых стен, которые нельзя безопасно выпрямить: {n}.","gs.optimize_glow_migration":"Старый Glow: пространств — {spaces} → без заливки данных + независимый Glow; комнат — {rooms} → наследуемая заливка + независимый Glow.","gs.optimize_references":"Исправлено ссылок: пространства — {spaces}; комнаты — {rooms}; позиции — {positions}; устройств отвязано от отсутствующих пространств — {detached}.","gs.optimize_reference_more":", и ещё {n}","gs.optimize_orphans_removed":"Убрано забытых записей: {total} — подписи комнат: {rooms}; устройства: {devices}; групповые метки: {groups}. Все они принадлежали пространствам, удалённым ранее.","gs.optimize_live_positions":"Старые позиции в удалённых пространствах принадлежат существующим объектам: {n}{names}. Они будут сохранены.","gs.optimize_live_positions_remove":"Старые позиции в удалённых пространствах принадлежат существующим объектам: {n}{names}. Они выбраны для удаления.","gs.optimize_live_names":": {names}{more}","gs.optimize_live_remove":"Убрать старые позиции","gs.optimize_live_keep":"Сохранить старые позиции","gs.optimize_live_selected":"Старые позиции будут убраны после применения оптимизации.","gs.optimize_unverified":"Не удалось безопасно проверить позиций: {n}. Они оставлены без изменений.","gs.optimize_registry_limited":"Для безопасной проверки нужен полный доступ администратора к реестрам Home Assistant.","gs.optimize_vacuum_warning":"Сопоставления комнат пылесоса требуют проверки: {n}.","gs.optimize_details":"Подробности","gs.optimize_details_more":"И ещё записей: {n}.","gs.optimize_detail_removed":"будет удалено","gs.optimize_detail_live":"будет сохранено","gs.optimize_detail_unverified":"не проверено","gs.optimize_detail_room_label":"подпись комнаты","gs.optimize_detail_device":"устройство","gs.optimize_detail_group":"групповая метка","gs.optimize_detail_unknown":"неизвестный владелец","gs.optimize_detail_item":"{status}: {kind} {id}; прежнее пространство {space}","gs.align_warn":"Элементы, намеренно поставленные между узлами, будут сдвинуты. После операции доступна одна отмена — только до следующего изменения плана.","gs.align_run":"Оптимизировать","gs.align_done":"Планы оптимизированы: сдвинуто элементов — {n}, обслужено записей — {m}, исправлено ссылок — {r}","gs.optimize_undo":"Отменить последнюю оптимизацию","gs.optimize_undone":"Последняя оптимизация отменена","decor.furniture":"Мебель","furn.title":"Библиотека мебели","furn.symbol":"Символ","furn.group_furniture":"Мебель","furn.group_appliance":"Техника","furn.group_sanitary":"Сантехника","furn.group_other":"Прочее","furn.width":"Ширина","furn.depth":"Глубина","furn.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_cooktop":"Варочные панели","furn.cat_dining_table":"Обеденные столы","furn.cat_dishwasher":"Посудомоечные машины","furn.cat_dryer":"Сушильные машины","furn.cat_fireplace":"Камины","furn.cat_fridge":"Холодильники","furn.cat_kitchen_cabinet":"Кухонные шкафы","furn.cat_kitchen_sink":"Кухонные мойки","furn.cat_nightstand":"Тумбы","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_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":"Резервная копия и перенос","gs.backup_hint":"Скачайте переносимую JSON-копию или проверьте и импортируйте копию, созданную House Plan.","backup.export_open":"Экспорт","backup.import_open":"Импорт","backup.export_title":"Экспорт House Plan","backup.import_title":"Импорт House Plan","backup.export_hint":"Выберите, должна ли копия содержать всю конфигурацию House Plan или только текущее пространство.","backup.full":"Полная копия","backup.current_space":"Текущее пространство","backup.current_space_title":"Текущее пространство: {title}","backup.no_current_space":"Нет текущего пространства","backup.plan_only":"Только планировка","backup.plan_only_hint":"Сохранить комнаты, стены, проёмы, декор и позиции подписей комнат без устройств и привязок Home Assistant.","backup.plan_only_preview":"Файл содержит только планировку","backup.privacy_warning":"Архив сохраняет названия, идентификаторы Home Assistant и точные координаты. Внутренние планы и вложения указываются ссылками, но не вкладываются; текущие состояния и маршруты пылесосов не включаются.","backup.download":"Скачать JSON","backup.export_done":"Резервная копия скачана","backup.reading":"Проверяем резервную копию…","backup.revalidated":"После предпросмотра план изменился. Сводка обновлена — проверьте её и подтвердите ещё раз.","backup.error.unauthorized":"У вас нет прав на экспорт или импорт этого плана.","backup.error.not_ready":"House Plan ещё не готов. Повторите попытку через несколько секунд.","backup.error.too_large":"Размер резервной копии превышает 8 МиБ.","backup.error.invalid_json":"Выбранный файл не является корректным JSON.","backup.error.invalid_format":"Выбранный файл не является резервной копией House Plan.","backup.error.unsupported_export_version":"Эта версия формата резервной копии не поддерживается установленной версией.","backup.error.future_model":"Резервная копия создана в более новой версии модели данных House Plan.","backup.error.invalid_config":"Резервная копия содержит некорректную конфигурацию House Plan.","backup.error.wall_model_migration_blocked":"Не удалось безопасно обновить модель стен из резервной копии. Сначала оптимизируйте исходный план и повторите экспорт.","backup.error.invalid_layout":"Резервная копия содержит некорректные позиции объектов.","backup.error.invalid_content":"Резервная копия содержит некорректные или несогласованные ссылки на файлы.","backup.error.space_not_found":"Выбранное пространство больше не существует.","backup.error.capacity_exceeded":"Добавление этой копии превысит ограничения размера плана.","backup.error.preview_expired":"Время предпросмотра истекло. Выберите файл резервной копии заново.","backup.error.preview_owner_mismatch":"Этот предпросмотр принадлежит другому пользователю Home Assistant.","backup.error.conflict":"После предпросмотра план изменился. Проверьте обновлённую сводку.","backup.error.content_confirmation_required":"Подтвердите отсоединение недоступных локальных файлов.","backup.error.commit_failed":"Не удалось безопасно применить копию. Предыдущий план восстановлен или ожидает восстановления.","backup.error.missing_plan":"После предпросмотра исчез связанный файл плана. Проверьте копию ещё раз.","backup.error.missing_content":"После предпросмотра исчез связанный локальный файл. Проверьте копию ещё раз.","backup.error.marker_control_missing":"В резервной копии отсутствует связанный источник света на плане.","backup.error.marker_control_not_light":"Связанная цель больше не отмечена как источник света.","backup.error.marker_control_self":"Источник света не может управлять самим собой.","backup.error.marker_control_cycle":"Резервная копия содержит циклическую цепочку управления светом.","backup.error.duplicate_marker_control":"Резервная копия содержит повторяющуюся связь с источником света.","backup.error.no_backup":"Нет снимка импорта или оптимизации, который можно восстановить.","backup.same_source":"Создано на этом экземпляре Home Assistant","backup.foreign_source":"Создано на другом экземпляре Home Assistant","backup.created":"Создано: {value}","backup.versions":"Карточка {card}; интеграция {integration}; модель данных {model}","backup.count_spaces":"Пространств: {n}","backup.count_rooms":"Комнат: {n}","backup.count_walls":"Стен: {n}","backup.count_openings":"Проёмов: {n}","backup.count_decor":"Объектов декора: {n}","backup.count_markers":"Устройств: {n}","backup.count_layout":"Позиций: {n}","backup.bindings":"Привязки — устройства: {device}, сущности: {entity}, виртуальные: {virtual}; позиций без пространства: {legacy}","backup.binding_status":"Статус на целевом экземпляре — активных: {active}, деактивированных: {disabled}, отсутствующих: {missing}","backup.missing_areas":"На целевом экземпляре отсутствуют зоны: {areas}","backup.dropped_marker_links":"Связи с источниками света вне переносимого пространства пропущены: {n}.","backup.repaired_target_refs":"Существующих ссылок восстановлено этим импортом: {n}.","backup.preserved_unresolved_refs":"Неоднозначные ссылки сохранены без изменений: {n}.","backup.preserved_unresolved_hint":"House Plan ничего не угадывал и не удалял. После импорта запустите «Оптимизировать планы», чтобы проверить оставшиеся ссылки.","backup.import_details":"Подробности восстановления ссылок","backup.import_detail.incoming_remapped":"Ссылок обновлено внутри импортируемой копии: {n}","backup.import_detail.target_repaired":"Существующих ссылок восстановлено: {n}","backup.import_detail.preserved_unresolved":"Неразрешимых ссылок сохранено: {n}","backup.import_detail.collisions":"Конфликтов назначения безопасно сохранено: {n}","backup.import_detail.dropped_links":"Входящих связей пропущено по правилам переноса: {n}","backup.import_detail.bounded_lineages":"Чрезмерно вложенных идентификаторов ограничено: {n}","backup.replace_warning":"Текущая конфигурация и расположение будут заменены. Загруженные файлы не удаляются. Одну отмену можно выполнить до следующего изменения плана.","backup.foreign_bookkeeping":"Служебные списки известных и новых устройств другого экземпляра импортированы не будут.","backup.final_name":"Название нового пространства","backup.target_settings":"Глобальные настройки целевого экземпляра не изменятся.","backup.duplicates":"Уже существующих привязок: {n}","backup.skip":"Пропустить повторяющиеся устройства","backup.virtual_copy":"Добавить безопасные статичные виртуальные копии","backup.content":"Связанное содержимое","backup.content_available":"доступно локально","backup.content_external":"внешняя ссылка","backup.content_detach_required":"будет отвязано","backup.confirm_detach":"Я понимаю, что недоступные внутренние планы и вложения будут отвязаны от импортируемой конфигурации.","backup.replace":"Заменить","backup.add":"Добавить пространство","backup.space_done":"Пространство импортировано: комнат — {rooms}, устройств — {markers}, существующих ссылок восстановлено — {refs}","backup.full_done":"Копия восстановлена: пространств — {spaces}, комнат — {rooms}, устройств — {markers}","backup.undo_import":"Отменить последний полный импорт","backup.import_undone":"Полный импорт отменён"}},{code:"de",nativeLabel:"Deutsch",loadDictionary:async function(e){const t=0===e?await import("./de-CndLXoON.js"):await import(new URL("./de-CndLXoON.js?retry",import.meta.url).href);return{dictionary:t.dictionary,fingerprint:t.fingerprint}}}],iu=Zd,nu=new Set;const ru=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)}}(tu,"817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073",console.warn,function(e){for(const t of nu)t(e)});function ou(e){const t=lu(e)?.code??"en";return ru.dictionary(t)??iu}function su(e){return"string"==typeof e?e.trim().replaceAll("_","-").toLowerCase():""}const au=new Map(tu.map(e=>[su(e.code),e]));function lu(e){return au.get(su(e))}function cu(e,t){const i=[{value:"",label:e},...tu.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:lu(n)?.nativeLabel??n}),i}function hu(e,t){return function(e,t,i,n){const r=new Map(i.map(e=>[su(e),e])),o=r.get(su(e));if(o)return o;const s=su(t),a=r.get(s);return a||(r.get(s.split("-")[0]||"")??n)}(t,e?.locale?.language||e?.language,tu.map(({code:e})=>e),"en")}function du(e,t,i){return Ki(ou(e)[t]??iu[t]??t,i)}function uu(e,t){const i=ou(e)[t]??iu[t];return"string"==typeof i&&i.trim().length>0}function pu(e){const t=e.length/2,i=e.face.cm>0?e.face.cm/e.cellCm*e.gridPitch/2:Sa(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(Sa(16,e.cellCm),i+Sa(8,e.cellCm),n+Sa(8,e.cellCm)),hitHalf:Math.max(Sa(20,e.cellCm),i+Sa(10,e.cellCm),n+Sa(12,e.cellCm))}}function _u(e){if("passage"===e.type)return B``;const t=Math.max(0,Math.min(1,e.amount)),{half:i,jambHalf:n}=pu(e),r=$a(e.cellCm),o=1.75*r,s=e.flipH?-1:1,a=e.flipV?-1:1,l="gate"===e.type?1:a;e.type,e.flipV,e.angle,e.face;let c;if("window"===e.type){const o=Math.PI/2*i,s=e.face.cm>0?B``:B``;c=B` + + + + + + + + + + + + + + ${s} + `}else if("gate"===e.type){const n=10*e.face.side*t;c=B` + + + + + + + + + + + + `}else{const n=Math.PI/2*e.length;c=B` + + + + + + + + `}return B` + + + ${c} + `}const mu={climate:["current_temperature","temperature","current_humidity","humidity"],water_heater:["current_temperature","temperature"],cover:["current_position"],valve:["current_position"],fan:["percentage"],humidifier:["current_humidity","humidity"],light:["brightness"],media_player:["volume_level"],vacuum:["battery_level","fan_speed"],lawn_mower:["battery_level","fan_speed"]};function fu(e){return e?e.sourceLabel?`${e.sourceLabel}: ${e.fullText}`:e.fullText:""}const gu=new WeakMap;function vu(e){return e?"entity_state"===e.kind?`state:${e.entity_id}`:"entity_attribute"===e.kind?`attr:${e.entity_id}:${e.attribute}`:"derived_marker_state"===e.kind?`marker:${e.ref}`:"derived:lqi":""}function yu(e){if("derived:lqi"===e)return{kind:"derived_lqi"};if(e.startsWith("state:"))return{kind:"entity_state",entity_id:e.slice(6)};if(e.startsWith("attr:")){const t=e.slice(5),i=t.lastIndexOf(":");if(i>0)return{kind:"entity_attribute",entity_id:t.slice(0,i),attribute:t.slice(i+1)}}return e.startsWith("marker:marker:")?{kind:"derived_marker_state",ref:e.slice(7)}:null}function bu(e,t){const i=e?.entities?.[t],n=e?.states?.[t];return String(i?.name||i?.original_name||n?.attributes?.friendly_name||t)}function wu(e){return e.replaceAll("_"," ")}function ku(e,t=1){const i=Number(e);return Number.isFinite(i)?`${Math.round(i*t)} %`:null}function xu(e){if("derived_lqi"===e.kind)return"lqi";if("entity_attribute"===e.kind){if(e.attribute.includes("temperature"))return"temperature";if(e.attribute.includes("humidity"))return"humidity"}return"default"}function $u(e,t,i,n=[]){let r=null,o="",s="available";if("entity_state"===i.kind){o=bu(e,i.entity_id);const t=e?.states?.[i.entity_id];if(t)if(Mu(e,i.entity_id))if(["unknown","unavailable"].includes(String(t.state).toLowerCase()))s="unavailable";else{const n=Wi(e,i.entity_id);r=n?ji(n,String(t.attributes?.unit_of_measurement||"")):null,r||(s="unavailable")}else s="unavailable";else s="missing"}else if("entity_attribute"===i.kind){o=`${wu(i.attribute)} · ${bu(e,i.entity_id)}`;const t=e?.states?.[i.entity_id];t?Mu(e,i.entity_id)?(r=function(e,t,i){const n=e?.states?.[t];if(!n||!(i in(n.attributes||{})))return null;const r=Wi(e,t,i);if(r?.formatted)return r.text;const o=n.attributes?.[i];if("brightness"===i)return ku(o,100/255);if("volume_level"===i)return ku(o,100);if(["current_position","percentage","current_humidity","humidity","battery_level"].includes(i))return ku(o);if("current_temperature"===i||"temperature"===i){const t=Number(o);if(!Number.isFinite(t))return null;const i=String(e?.config?.unit_system?.temperature||"°C");return`${Math.round(10*t)/10} ${i}`}return r?.text||(["string","number","boolean"].includes(typeof o)?String(o):null)}(e,i.entity_id,i.attribute),null==r&&(s="unavailable")):s="unavailable":s="missing"}else if("derived_lqi"===i.kind){o="LQI";const i=Ph(e,t.entities);null==i?s="unavailable":r=String(i)}else{o="Light state";const t=n.find(e=>e.ref===i.ref);if(t){const i=t.on?"on":"off",n=e?.localize?.(`state.default.${i}`);r="string"==typeof n&&n?n:i,o=t.name||o}else s="missing"}const a=e?.localize?.("state.default.unavailable")||"Unavailable";return{source:i,sourceLabel:o,text:r??"—",fullText:r??a,availability:s,isLqi:"derived_lqi"===i.kind,tone:xu(i)}}function Su(e,t){if(!0===t.marker?.use_climate_temp){const i=t.entities.find(t=>t.startsWith("climate.")&&Number.isFinite(Number(e?.states?.[t]?.attributes?.current_temperature)));return i?{kind:"entity_attribute",entity_id:i,attribute:"current_temperature"}:null}if("mdi:thermometer"===t.icon||"mdi:air-filter"===t.icon){const i=t.entities.find(t=>dh(e,t)&&Number.isFinite(Number(e?.states?.[t]?.state)));if(i)return{kind:"entity_state",entity_id:i}}return t.primary&&Ih(e,t.primary)&&Number.isFinite(Number(e?.states?.[t.primary]?.state))?{kind:"entity_state",entity_id:t.primary}:null}function Mu(e,t){const i=e?.entities?.[t];if(i&&!th(i))return!1;const n=i?.device_id?e?.devices?.[i.device_id]:null;return!n||th(n)}function Ru(e,t){return Mu(e,t)&&!!e?.states?.[t]}function Tu(e,t,i=[t]){const n=function(e,t){const i=e=>[e.id,e.primary,e.hidden?1:0,e.userHidden?1:0,e.entities.join(","),(e.controls||[]).join(","),e.marker?.binding||"",!0===e.marker?.is_light?1:0,e.marker?.light_entity||"",(e.marker?.controls||[]).join(",")].join("|");return`${i(e)}\n${t.map(i).join("\n")}`}(t,i),r=gu.get(t);if(r&&r.states===(e?.states||null)&&r.entities===(e?.entities||null)&&r.devices===(e?.devices||null)&&r.signature===n)return r.result;const o=new Set(t.entities);for(const e of t.controls||[])e.startsWith("marker:")||o.add(e);const s=[],a=zh(e,i),l=a.filter(e=>e.key.startsWith("marker:")).map(e=>({ref:e.key,on:e.on,name:e.device?.name||e.key})),c=i=>{const n=vu(i);if(s.some(e=>e.key===n))return;const r=$u(e,t,i,l),o="entity_attribute"===i.kind?`${i.entity_id} · ${i.attribute}`:"entity_state"===i.kind?i.entity_id:"derived_marker_state"===i.kind?i.ref:"LQI";s.push({key:n,source:i,label:r.sourceLabel,technical:o,value:r.text,available:"available"===r.availability})};for(const t of[...o].sort()){if(!Ru(e,t))continue;const i=t.split(".")[0],n=e?.entities?.[t];if("button"===i||"event"===i||"config"===n?.entity_category)continue;c({kind:"entity_state",entity_id:t});const r=e?.states?.[t];for(const e of mu[i]||[])e in(r?.attributes||{})&&c({kind:"entity_attribute",entity_id:t,attribute:e})}const h=new Set((t.marker?.controls||t.controls||[]).filter(e=>e.startsWith("marker:")));!0===t.marker?.is_light&&t.marker.id&&h.add(`marker:${t.marker.id}`);const d=new Set(a.map(e=>e.key));for(const e of[...h].sort())d.has(e)&&c({kind:"derived_marker_state",ref:e});return t.virtual||null==Ph(e,t.entities)||c({kind:"derived_lqi"}),gu.set(t,{states:e?.states||null,entities:e?.entities||null,devices:e?.devices||null,signature:n,result:s}),s}function Cu(e,t,i){const n=Su(e,t);if(n&&i.some(e=>e.key===vu(n)))return n;const r=t.primary&&i.find(e=>e.key===`state:${t.primary}`);if(r)return r.source;const o=[e=>e.technical.includes("temperature"),e=>e.technical.includes("humidity"),e=>e.technical.includes("battery")];for(const e of o){const t=i.find(e);if(t)return t.source}return i.find(e=>"derived_lqi"!==e.source.kind)?.source||i[0]?.source||null}function Du(e){return e.touched?{value_badge:{enabled:e.enabled,source:e.source,position:e.position}}:e.originalHas?{value_badge:e.original}:{}}function zu(e,t,i){return{kind:"none",reason:"none",generation:e,expiresAt:null,color:t,diameterScale:i,animated:!1,reducedMotionIndicator:"none"}}function Au(e,t,i,n,r=null){return{kind:t,reason:"short"===t?"event":"running",generation:Math.max(1,Math.trunc(i)),expiresAt:"short"===t?r:null,color:e.color,diameterScale:n?1:e.diameterScale,animated:!n,reducedMotionIndicator:n?"dot":"none"}}const Ou={availability:"available",status:"neutral",activity:"none"};function Pu(e){return e<=40?"low":e<180?"mid":"high"}function Fu(e){return Vt(e)}function Eu(e){return"static_icon"===e.display?"neutral":"alarm"===e.visual.status?"alarm":"unavailable"===e.visual.availability?"unavailable":e.lockState?e.lockState:"working"===e.visual.status?"working":"open"===e.visual.status?"open":"neutral"}const Iu={sourceKind:"none",decisionIds:["source.skipped_static_fast_path"],visualSources:[],criticalSources:[],samples:[]};function Hu(e,t){const i=e?.entities?.[t],n=e?.states?.[t];return String(i?.name||i?.original_name||n?.attributes?.friendly_name||t)}function Nu(e,t){const i=e?.states?.[t];if(!i)return"";if("function"==typeof e?.formatEntityState)try{const t=e.formatEntityState(i);if("string"==typeof t&&t)return t}catch{}return String(i.state??"")}function Lu(e,t){if(t.virtual||"virtual"===t.bindingKind||"virtual"===t.marker?.binding)return"available";const i=t.entities||[];if(0===i.length&&("device"===t.bindingKind||t.marker?.binding?.startsWith("device:"))&&"active"===t.bindingStatus?.kind)return"available";return i.some(t=>{const i=String(e?.states?.[t]?.state??"").trim().toLowerCase();return""!==i&&"unknown"!==i&&"unavailable"!==i})?"available":"unavailable"}function qu(e,t,i,n){return{eid:t,role:i,name:Hu(e,t),state:String(e?.states?.[t]?.state??""),stateText:Nu(e,t),integrationDomain:e?.entities?.[t]?.platform||null,sample:n||Tc(e,t)}}function Wu(e,t,i=[t],n,r=e){const o=t.hidden&&t.userHidden?{...t,hidden:!1}:t;let s="none",a=[];const l=[],c=[...o.entities,...o.allEntities||[]].some(e=>e.startsWith("cover."))?{...o,tapAction:"cover"}:o,h=(d=Sd({hass:e,devices:i,device:c,lightSources:n,registryHass:r}),"cover"!==d?.semantics?null:d.targets[0]?.entityId||d.skippedTargets[0]?.entityId||null);var d;const u=zh(e,[o]),p=gh(o.marker?.binding,o.marker?.controls??o.controls,o.entities),_=new Set(p.filter(e=>e.startsWith("marker:"))),m=!0===o.marker?.is_light||_.size>0?n||zh(e,i):u,f=m.filter(e=>e.device.id===o.id&&"controls"!==e.via),g=u.filter(e=>"controls"!==e.via),v=f.length?f:g,y=Hc(o.marker),b=y?[...v]:[...u.filter(e=>"controls"===e.via),...v];if(_.size)for(const e of m){if(!_.has(e.key))continue;e.stateEids.length>0&&b.some(t=>t.stateEids.some(t=>e.stateEids.includes(t)))||b.some(t=>t.key===e.key)||b.push({...e,via:"controls",castsGlow:!1})}const w=_h(r,o.entities),k=!!h&&("cover"===o.tapAction||o.primary?.startsWith("cover.")||w.some(e=>e.startsWith("cover.")));if(h&&!k&&l.push("source.cover_capability_bypassed"),k)s="cover",l.push("source.cover"),a=[qu(e,h,"cover")];else if(b.length)s=!y&&b.some(e=>"controls"===e.via)?"controls":"light",y?l.push("source.manual_virtual_light"):l.push("controls"===s?"source.controls":"source.owned_light"),"controls"!==s||!o.virtual&&"virtual"!==o.bindingKind||l.push("source.virtual_controller"),a=b.map(i=>{const n="controls"===i.via?"control":"forced"===i.via?"forced_light":"light";if(!i.passive)return qu(e,i.eid,n);const r=i.on?"on":"off";return{eid:i.key,role:n,name:t.name,state:r,stateText:r,integrationDomain:null,sample:{eid:i.key,state:r,availability:"available",status:i.on?"working":"neutral",activity:"none",edge:"none"}}});else{const t=_h(r,o.entities),i=t.length?t:o.entities.filter(t=>!!e?.states?.[t]);if(i.length){s="device_role",l.push("source.device_role");const t=Cc(r===e?e:{...r,states:e?.states||{}},i,o.entities),n=i.some(e=>Sc(r,e));a=t.map(t=>{const i=n?Mc(r,t.eid)?"power_gate":Sc(r,t.eid)?"lifecycle":"device_role":"device_role";return qu(e,t.eid,i,t)})}else o.primary?(s="primary",l.push("source.primary_fallback"),a=[qu(e,o.primary,"primary")]):l.push("source.none")}p.length>0&&"controls"!==s&&"light"!==s&&"cover"!==s&&l.push("source.filtered_saved_controls");const x=[];for(const t of o.entities||[]){const i=Tc(e,t);"alarm"!==i.status||a.some(e=>e.eid===t)||x.push(qu(e,t,"critical",i))}return x.length&&l.push("source.critical_sibling"),{sourceKind:s,decisionIds:l,visualSources:a,criticalSources:x,samples:[...a,...x].map(e=>e.sample)}}function ju(e,t,i,n){if(t.virtual)return{source:null,text:null,fallback:"value_virtual"};if(n){const i=function(e,t){if(!0!==t.marker?.use_climate_temp)return null;for(const i of t.entities){if(!i.startsWith("climate."))continue;const t=Number(e?.states?.[i]?.attributes?.current_temperature);if(Number.isFinite(t))return{eid:i,text:Math.round(10*t)/10+"°"}}return null}(e,t);if(i)return{source:{kind:"temperature",eid:i.eid,attribute:"current_temperature",text:i.text},text:i.text,fallback:null};const n=function(e,t){if("mdi:thermometer"!==t.icon&&"mdi:air-filter"!==t.icon)return null;for(const i of t.entities){if(!dh(e,i))continue;const t=Number(e?.states?.[i]?.state);if(Number.isFinite(t))return{eid:i,text:Math.round(10*t)/10+"°"}}return null}(e,t);if(n)return{source:{kind:"temperature",eid:n.eid,text:n.text},text:n.text,fallback:null};const r=function(e,t){if(!t.primary||!Ih(e,t.primary))return null;const i=Number(e?.states?.[t.primary]?.state);return Number.isFinite(i)?{eid:t.primary,text:`${Math.round(i)}%`}:null}(e,t);if(r)return{source:{kind:"humidity",eid:r.eid,text:r.text},text:r.text,fallback:null}}const r=i.visualSources.filter(e=>!e.eid.startsWith("marker:"));let o=r.map(e=>e.eid);const s=r.find(e=>"power_gate"===e.role);if(s&&(o=[s.eid]),!o.length&&i.visualSources.some(e=>e.eid.startsWith("marker:"))&&(o=_h(e,t.entities),!o.length&&t.primary&&e?.states?.[t.primary]&&(o=[t.primary])),o=[...new Set(o)],1!==o.length)return{source:null,text:null,fallback:o.length?"value_ambiguous_sources":"value_no_state"};const a=o[0],l=function(e,t){const i=e?.states?.[t];if(!i||null==i.state||""===String(i.state).trim())return{text:"",fallback:"value_no_state"};const n=i.state;if(!["string","number","boolean"].includes(typeof n))return{text:"",fallback:"value_non_scalar"};const r=String(n).trim().toLowerCase();if("unknown"===r||"unavailable"===r)return{text:"",fallback:"value_no_state"};const o=Wi(e,t);return o?{text:ji(o,String(i.attributes?.unit_of_measurement||"")),fallback:null}:{text:"",fallback:"value_no_state"}}(e,a);return l.fallback?{source:null,text:null,fallback:l.fallback}:{source:{kind:"entity",eid:a,text:l.text},text:l.text,fallback:null}}function Bu(e,t,i){const n=e.marker?.binding||(e.bindingKind&&e.bindingRef?`${e.bindingKind}:${e.bindingRef}`:e.virtual?"virtual":""),r=[...t.visualSources.map(e=>`${e.role}:${e.eid}`),...t.criticalSources.map(e=>`critical:${e.eid}`)].sort(),o=i?`${i.kind}:${i.eid}:${i.attribute||""}`:"none";return[n,t.sourceKind,...r,`value:${o}`].join("\n")}function Vu(e,t,i){return Bu(t,i||Wu(e,t),null).replace(/\nvalue:none$/,"")}function Uu(e){if(e.effectiveHidden)return[];if("static_icon"===e.display)return["static-icon"];const t=[],{visual:i}=e;return"alarm"===e.pulse.kind?t.push("alarm"):"unavailable"===i.availability?t.push("unavail"):"working"===i.status?t.push("on"):"open"===i.status&&t.push("open"),e.lockState&&t.push(`lock-${e.lockState}`),"none"!==e.pulse.reason&&"alarm"!==e.pulse.reason&&t.push("activity-"+e.pulse.reason),e.pulse.generation%2==0&&(t.push("pulse-gen2"),"short"===e.pulse.kind&&t.push("activity-gen2")),t}function Gu(e,t,i){const n=Ai(t.marker?.display),r="static_icon"===n,o=r&&!1===i.sourceDetails?Iu:Wu(e,t,i.lightDevices||[t],i.lightSources,i.registryHass||e),s=t.bindingStatus,a="ha_disabled"===s?.kind,l="orphaned"===s?.kind,c=a?"ha_disabled":l?"orphaned":"active",h=!0===t.userHidden||!0===t.marker?.hidden,d=Dc(o.samples),u=o.visualSources.find(e=>e.eid.startsWith("lock.")),p=u?["unlocked","open"].includes(u.state.toLowerCase())?"unlocked":"locked"===u.state.toLowerCase()?"locked":null:null,_=!Hc(t.marker)&&gh(t.marker?.binding,t.marker?.controls??t.controls,t.entities).length>0,m="controls"===o.sourceKind||_&&"light"!==o.sourceKind&&"cover"!==o.sourceKind,f=r&&!1===i.sourceDetails?{source:null,text:null,fallback:null}:ju(e,t,o,i.showTemperature),g=Bu(t,o,f.source),v=Vu(e,t,o),y=i.activityRuntime,b=i.now??Date.now(),w=y?.expiresAt||(y?.flashTs?y.flashTs+3300:0),k=y?.sources===v&&y.flashTs&&y.flashKind&&w>b?y.flashKind:null,x=function(e){const t=[],i="ha_disabled"===e.bindingLifecycle||"orphaned"===e.bindingLifecycle;let n=!1;"ha_disabled"===e.bindingLifecycle?(n=!0,t.push("lifecycle.ha_disabled_hidden")):e.userHidden&&!e.designPreview?(n=!0,t.push("lifecycle.user_hidden")):e.userHidden?t.push("lifecycle.user_hidden_preview"):"orphaned"===e.bindingLifecycle?t.push("lifecycle.orphaned_diagnostic"):t.push("lifecycle.active");const r="static_icon"===e.display;let o=e.controllerFace?{...e.sourceVisual,availability:e.controllerAvailability}:e.sourceVisual;t.push(e.controllerFace?"available"===e.controllerAvailability?"availability.controller_available":"availability.controller_unavailable":"availability.source"),n?(o=Ou,t.push("face.hidden")):r?(o=Ou,t.push("face.static")):"alarm"===e.sourceVisual.status||e.liveStates?t.push("face.dynamic"):(o=Ou,t.push("face.live_states_disabled")),!r&&!n&&e.liveStates&&"alarm"!==e.sourceVisual.status&&e.shortActivity&&(o={...o,activity:e.shortActivity},t.push(`activity.short_${e.shortActivity}`)),"alarm"===o.status?t.push("status.alarm"):"unavailable"===o.availability?t.push("status.unavailable"):"working"===o.status?t.push("status.working"):"open"===o.status?t.push("status.open"):t.push("status.neutral");const s="value"===e.display&&!n&&e.valueAvailable?"value":"icon";t.push("value"===s?"content.value":"value"===e.display?"content.value_fallback_icon":"content.icon"),"value"===e.display&&!e.valueAvailable&&e.valueFallback&&t.push(`content.${e.valueFallback}`);const a=e.liveStates&&!r&&!n,l=!r&&!n,c=!n&&!i&&!r&&"available"===o.availability&&("alarm"===o.status||e.liveStates&&"icon_ripple"===e.display),h=l&&e.vacuumLiveRequested;return t.push(a?"diagnostics.dynamic_icon":"diagnostics.base_icon"),t.push(l?"diagnostics.metrics_enabled":"diagnostics.metrics_suppressed"),t.push(c?"activity.pulse_eligible":"activity.pulse_suppressed"),t.push(h?"diagnostics.vacuum_live":"diagnostics.vacuum_static"),{effectiveHidden:n,bindingUnavailable:i,visual:o,face:s,dynamicIcon:a,metrics:l,liveColor:a,pulseEligible:c,vacuumLive:h,decisionIds:t}}({bindingLifecycle:c,userHidden:h,designPreview:!0===i.designPreview,display:n,liveStates:i.liveStates,sourceVisual:d,controllerFace:m,controllerAvailability:m?Lu(e,t):"available",shortActivity:k,valueAvailable:null!=f.text,valueFallback:f.fallback,vacuumLiveRequested:!0===t.marker?.vacuum?.live}),{effectiveHidden:$,visual:S}=x,M="icon_ripple"===n&&!$&&i.liveStates&&"alarm"!==S.status?S.activity:"none",R=x.metrics&&i.showTemperature?!0===t.marker?.use_climate_temp?Eh(e,t.entities):"mdi:thermometer"===t.icon||"mdi:air-filter"===t.icon?Fh(e,t.entities):null:null,T=x.metrics&&i.showTemperature&&t.primary&&Ih(e,t.primary)?Hh(e,t.entities):null,C=x.metrics&&i.showSignal&&!t.virtual?Ph(e,t.entities):null,D=i.lightSources||("derived_marker_state"===t.marker?.value_badge?.source?.kind?zh(e,i.lightDevices||[t]):[]),z=function(e,t,i){const n=null!=t.marker?.value_badge;if(i.effectiveHidden||"static_icon"===i.display)return null;const r=t.marker?.value_badge;if(n)return r?.enabled?r.source?{configured:!0,enabled:!0,position:r.position||"right",...$u(e,t,r.source,i.markerStates)}:{configured:!0,enabled:!0,source:null,sourceLabel:"",text:"—",fullText:e?.localize?.("state.default.unavailable")||"Unavailable",position:r.position||"right",availability:"missing",isLqi:!1,tone:"default"}:null;if(!i.showTemperature||"value"===i.display)return null;const o=Su(e,t);if(!o)return null;let s=null,a="default";if("entity_attribute"===o.kind&&"current_temperature"===o.attribute){const i=Eh(e,t.entities);null!=i&&(s=`${i}°`),a="temperature"}else if("mdi:thermometer"===t.icon||"mdi:air-filter"===t.icon){const i=Fh(e,t.entities);null!=i&&(s=`${i}°`),a="temperature"}else{const i=Hh(e,t.entities);null!=i&&(s=`${i}%`),a="humidity"}return null==s?null:{configured:!1,enabled:!0,source:o,position:"right",sourceLabel:"entity_attribute"===o.kind?`${wu(o.attribute)} · ${bu(e,o.entity_id)}`:"entity_state"===o.kind?bu(e,o.entity_id):"",text:s,fullText:s,availability:"available",isLqi:!1,tone:a}}(e,t,{showTemperature:i.showTemperature,showSignal:i.showSignal,display:n,effectiveHidden:$,markerStates:D.filter(e=>e.key.startsWith("marker:")).map(e=>({ref:e.key,on:e.on,name:e.device.name}))}),A=o.visualSources.find(e=>!e.eid.startsWith("marker:")),O="cover"===o.sourceKind?A?.eid:t.primary||A?.eid,P=O?e?.states?.[O]:null,F=x.dynamicIcon?un(t.icon,O?.split(".")[0],P?.attributes?.device_class,P?.state,!!t.marker?.icon):t.icon,E=x.liveColor&&o.visualSources.filter(e=>!e.eid.startsWith("marker:")).map(t=>function(e){return e&&"on"===e.state?Bt(e.attributes?.rgb_color):null}(e?.states?.[t.eid])).find(e=>!!e)||null,I=Number(t.marker?.size)>0?Number(t.marker.size):1,H=Number(t.marker?.angle)||0,N=Number(t.marker?.ripple_size)>0?Number(t.marker.ripple_size):1.5,L=qt(t.marker?.ripple_color,null),q=r?null:L||E||null,W=function(e){const{display:t,visual:i,semanticActivity:n,liveStates:r,effectiveHidden:o,bindingUnavailable:s=!1,reducedMotion:a=!1}=e,l=Math.max(1,Math.trunc(e.shortGeneration||1)),c=Number.isFinite(e.diameterScale)?Math.max(1,Number(e.diameterScale)):1.5,h=e.color||function(e,t){return"presence"===t?"#1DC21D":"running"===t||"working"===e.status||"open"===e.status?"#F0A00C":"#0C82F0"}(i,n);if(o||s||"unavailable"===i.availability||"static_icon"===t)return zu(l,h,c);if("alarm"===i.status)return{kind:"alarm",reason:"alarm",generation:l,expiresAt:null,color:"#F0410C",diameterScale:1.5,animated:!a,reducedMotionIndicator:"none"};if(!r||"icon_ripple"!==t)return zu(l,h,c);const d=e.now??Date.now(),u=e.shortExpiresAt||null;return e.shortReason&&null!=u&&u>d?{kind:"short",reason:e.shortReason,generation:l,expiresAt:u,color:h,diameterScale:a?1:c,animated:!a,reducedMotionIndicator:a?"dot":"none"}:"presence"===n||"transition"===n||"running"===n?{kind:"continuous",reason:n,generation:l,expiresAt:null,color:h,diameterScale:a?1:c,animated:!a,reducedMotionIndicator:a?"dot":"none"}:zu(l,h,c)}({display:n,visual:S,semanticActivity:d.activity,shortReason:y?.sources===v?y?.flashKind:null,shortGeneration:y?.gen,shortExpiresAt:y?.sources===v?w:null,now:b,liveStates:i.liveStates,effectiveHidden:$,bindingUnavailable:x.bindingUnavailable,reducedMotion:i.reducedMotion,color:q,diameterScale:N}),j="value"===x.face?f.text:null,B="ha_disabled"===s?.kind?s.reason:null,V="ha_disabled"===(U={lifecycle:c,display:n,liveStates:i.liveStates,sourceKind:o.sourceKind,primaryDomain:(t.primary||"").split(".")[0],visual:S,activity:M}).lifecycle?"ha_disabled":"orphaned"===U.lifecycle?"orphaned":"static_icon"===U.display?"static_icon":"alarm"===U.visual.status?"alarm":U.liveStates?"unavailable"===U.visual.availability?"unavailable":"cover"===U.sourceKind?"cover_icon_state":"presence"===U.activity?"presence":"event"===U.activity?"event":"transition"===U.activity?"transition":"working"===U.visual.status?"icon_ripple"===U.display&&"none"!==U.activity?"working_activity":"working":"open"===U.visual.status?"open":"media_player"===U.primaryDomain?"media_neutral":"neutral":"live_states_disabled";var U;const G=[];i.designPreview&&h&&G.push("hidden_design_preview"),r||!0!==t.marker?.vacuum?.live||G.push("vacuum_live_plan_only");const K=o.visualSources.some(t=>"power_gate"===t.role||Mc(e,t.eid)),Y=t.entities.filter(t=>t.startsWith("switch.")&&!e?.entities?.[t]?.entity_category).length;K&&Y>1&&G.push("composite_power_source"),"icon_ripple"!==n&&"static_icon"!==n&&"alarm"!==d.status&&"none"!==d.activity&&G.push("activity_display_disabled");const Z={binding:t.marker?.binding||(t.bindingKind&&t.bindingRef?`${t.bindingKind}:${t.bindingRef}`:t.virtual?"virtual":""),sourceKind:o.sourceKind,visualSources:o.visualSources,criticalSources:o.criticalSources,valueSource:f.source,sourceSignature:g,decisionIds:[...o.decisionIds,...x.decisionIds,...z?["diagnostics.value_badge"]:[],...null==C?[]:[`diagnostics.lqi_${Pu(C)}`],`pulse.${W.kind}_${W.reason}`],visual:S,lockState:p,display:n,icon:F,valueText:j,valueFullText:j,fallbackReason:"value"!==n||j?null:f.fallback,activity:M,activityGeneration:y?.gen||1,pulse:W,classes:[],tempText:null==R?null:String(R),humText:null==T?null:String(T),valueBadge:z,lqiText:null==C||z?.isLqi?null:String(C),lqiColor:null==C?null:Fu(C),lqiBand:null==C?null:Pu(C),lightColor:E,scale:I,angle:H,rippleScale:N,rippleColor:q,userHidden:h,effectiveHidden:$,haDisabled:a,disabledReason:B,orphaned:l,vacuumLive:x.vacuumLive,explanation:{reason:V,notices:G}};return{...Z,classes:Uu(Z)}}function Ku(e,t=new WeakMap){if(null===e||"object"!=typeof e)return e;const i=e,n=t.get(i);if(n)return n;if(Array.isArray(e)){const n=[];t.set(i,n);for(const i of e)n.push(Ku(i,t));return Object.freeze(n)}const r={};t.set(i,r);for(const[i,n]of Object.entries(e))"function"!=typeof n&&(r[i]=Ku(n,t));return Object.freeze(r)}function Yu(e){const t=new Map(e);let i;return i=Object.freeze({get size(){return t.size},get:e=>t.get(e),has:e=>t.has(e),entries:()=>t.entries(),keys:()=>t.keys(),values:()=>t.values(),forEach:(e,n)=>t.forEach((t,r)=>e.call(n,t,r,i)),[Symbol.iterator]:()=>t[Symbol.iterator]()}),i}function Zu(e){const t=new Set(e.entityIds||[]),i=new Set(e.deviceIds||[]),n=new Set(e.areaIds||[]);for(const n of e.devices){for(const e of n.entities||[])t.add(e);n.primary&&t.add(n.primary);for(const e of n.controls||[])t.add(e);n.marker?.vacuum?.source&&t.add(n.marker.vacuum.source),"device"===n.bindingKind&&n.bindingRef&&i.add(n.bindingRef),"entity"===n.bindingKind&&n.bindingRef&&t.add(n.bindingRef)}const r={},o={};for(const[o,s]of Object.entries(e.hass?.entities||{})){const a=s?.device_id?e.hass?.devices?.[s.device_id]:null;(t.has(o)||s?.device_id&&i.has(s.device_id)||n.has(s?.area_id)||n.has(a?.area_id))&&(t.add(o),r[o]=s,s?.device_id&&i.add(s.device_id))}for(const t of i){const i=e.hass?.devices?.[t];i&&(o[t]=i)}const s={};for(const i of t){const t=e.hass?.states?.[i];t&&(s[i]=t)}const a=Object.freeze({states:Ku(s),entities:Ku(r),devices:Ku(o),config:Ku(e.hass?.config),locale:Ku(e.hass?.locale),themes:Ku(e.hass?.themes)});return Object.freeze({sourceSequence:e.sourceSequence,capturedAt:e.capturedAt??Date.now(),hass:a,devices:Ku([...e.devices]),positions:Yu([...e.positions||[]].map(([e,t])=>[e,Object.freeze({x:t.x,y:t.y})])),presentations:Yu([...e.presentations].map(([e,t])=>[e,Ku(t)])),facts:Yu([...e.facts||[]].map(([e,t])=>[e,Ku(t)]))})}const Xu=(e,t)=>`${e}:${t?1:0}`;function Ju(e){return"boolean"==typeof e?.themes?.darkMode?e.themes.darkMode?"theme-dark":"theme-light":""}function Qu(e){const t=[];if(1!==e.scale&&t.push(`--dev-scale:${e.scale}`),"none"!==e.pulse.kind){t.push(`--ripple-scale:${e.pulse.diameterScale}`);const r=(i=e.pulse.color,n=null,"string"==typeof i&&(Lt.test(i)||jt.test(i))?i:n);r&&t.push(`--ripple-color:${r}`)}var i,n;return t}function ep(e){const t=[...String(e)].reduce((e,t)=>/\s/.test(t)?e+.35:e+(t.codePointAt(0)>255?1:.62),0);return t<=8?.45:Math.max(.25,Math.round(3.6/t*1e3)/1e3)}function tp(e,t){const i=e.pulse,n=i.generation%2==0,r=function(e){const t=e.valueBadge;if(!t||!1!==t.configured)return[];const i=[];return null!=e.tempText&&"temperature"!==t.tone&&i.push({kind:"temperature",text:e.tempText,suffix:"°"}),null!=e.humText&&"humidity"!==t.tone&&i.push({kind:"humidity",text:e.humText,suffix:"%"}),i}(e),o=e.valueBadge,s=o?.position||"right",a=!!o||r.length>0,l=["device-shell",null!=e.valueText?"text-shell":"",a?`with-values pos-${s}`:"",r.length?"with-legacy":""].filter(Boolean).join(" ");return j` + ${"none"!==i.kind&&"dot"!==i.reducedMotionIndicator?j``:U} + ${"dot"===i.reducedMotionIndicator?j``:U} + ${t.newDevice?j``:U} + ${e.haDisabled?j``:U} + + ${null!=e.lqiText?j`${e.lqiText}`:U} + `}function ip(e){return!Number.isFinite(e)||e<=0?2.25:e/2.5*2.25}function np({openings:e,geometries:t,fillsByRoomId:i,idPrefix:n="data",groupClass:r="opening-tunnels",dataLayer:o="data"}){const s=e.map((e,r)=>{const o=t[r];if(!o)return U;const s=o.faces.find(e=>-1===e.side),a=o.faces.find(e=>1===e.side);if(!s||!a)return U;const l=i.get(s.roomId)||null,c=i.get(a.roomId)||null;if(!l&&!c)return U;const h=`${s.d} ${a.d}`,d=!!l&&!!c&&l.color===c.color&&l.opacity===c.opacity,u=`translate(${e.rx} ${e.ry}) rotate(${e.angle})`;if(d)return B``;const p=o.maxY-o.minY;if(!(p>0))return U;const _=`${(100*Math.max(0,Math.min(1,-o.minY/p))).toFixed(6)}%`,m=l||{color:"#000000",opacity:0},f=c||{color:"#000000",opacity:0},g=`hp-opening-tunnel-${n.replace(/[^a-zA-Z0-9_-]/g,"-")}-${r}`;return B``});return B``}function rp(e,t,i){const n=i>0?i:1;return{a:[e[0]/n,e[1]/n],b:[t[0]/n,t[1]/n]}}function op(e,t){const i=t>0?t:1;return[e.a[0]*i,e.a[1]*i,e.b[0]*i,e.b[1]*i]}function sp(e){return Array.isArray(e)&&e.length>=2&&Number.isFinite(Number(e[0]))&&Number.isFinite(Number(e[1]))}function ap(e){if(!Array.isArray(e))return[];const t=[];for(const i of e){if(!i||"object"!=typeof i)continue;const e=i;if(!sp(e.a)||!sp(e.b))continue;const n=[Number(e.a[0]),Number(e.a[1])],r=[Number(e.b[0]),Number(e.b[1])];Math.hypot(r[0]-n[0],r[1]-n[1])<.001||t.push({a:n,b:r})}return t}function lp(e,t,i,n,r=!0){const o=(e||[]).filter(e=>e?.id),s=ap(t);if(s.length)return function(e,t,i,n){const r=ap(e);if(!r.length)return[];const o=function(e,t){const i=[],n=(e||[]).filter(e=>e?.id);for(let e=0;e4*n||o>4*n)continue;const s=(e[0]-r)*u+(e[1]-l)*p,c=(e[2]-r)*u+(e[3]-l)*p,h=Math.max(0,Math.min(s,c)),m=Math.min(d,Math.max(s,c));if(m-he.lo-t.lo||e.hi-t.hi);const i=[];for(const e of t){const t=i[i.length-1];t&&e.lo<=t.hi+a?t.hi=Math.max(t.hi,e.hi):i.push({...e})}for(const t of i){const i=[r+u*t.lo,l+p*t.lo],n=[r+u*t.hi,l+p*t.hi];Math.hypot(n[0]-i[0],n[1]-i[1])i.pair===e&&Math.abs(i.ux*s-i.uy*o)<=1e-6&&Math.abs((t[0]-i.origin[0])*i.uy-(t[1]-i.origin[1])*i.ux)<=c&&Math.abs((t[2]-i.origin[0])*i.uy-(t[3]-i.origin[1])*i.ux)<=c);h||(h={pair:e,origin:[t[0],t[1]],ux:o,uy:s,ranges:[]},l.push(h));const d=(t[0]-h.origin[0])*h.ux+(t[1]-h.origin[1])*h.uy,u=(t[2]-h.origin[0])*h.ux+(t[3]-h.origin[1])*h.uy;h.ranges.push({lo:Math.min(d,u),hi:Math.max(d,u)})}const h=[];for(const e of l){e.ranges.sort((e,t)=>e.lo-t.lo||e.hi-t.hi);const t=[];for(const i of e.ranges){const e=t[t.length-1];e&&i.lo<=e.hi+a?e.hi=Math.max(e.hi,i.hi):t.push({...i})}for(const n of t){const t=[e.origin[0]+e.ux*n.lo,e.origin[1]+e.uy*n.lo],r=[e.origin[0]+e.ux*n.hi,e.origin[1]+e.uy*n.hi];Math.hypot(r[0]-t[0],r[1]-t[1])>=a&&h.push(rp(t,r,i))}}return h}(s,e,i,n).map(e=>op(e,i));if(!r)return[];const a=[],l=(e,t)=>(e.open_to||[]).includes(t.id)||(t.open_to||[]).includes(e.id);for(let e=0;er)&&Po([o[0],o[1]],[o[2],o[3]],i))return!0;return!1}const hp=e=>Array.isArray(e)&&e.length>=2&&Number.isFinite(Number(e[0]))&&Number.isFinite(Number(e[1])),dp=(e,t,i)=>[Number(e[0])*i,Number(e[1])*i,Number(t[0])*i,Number(t[1])*i],up=e=>{const t=`${Number(e[0]).toFixed(9)},${Number(e[1]).toFixed(9)}`,i=`${Number(e[2]).toFixed(9)},${Number(e[3]).toFixed(9)}`;return t<=i?`${t}|${i}`:`${i}|${t}`},pp=e=>{const t=new Map;for(const i of e.flat())!Array.isArray(i)||i.length<4||!i.every(Number.isFinite)||Math.hypot(i[2]-i[0],i[3]-i[1])<=1e-9||t.set(up(i),[...i]);return[...t.values()]};function _p(e){return"solid"===e?.zero_wall_style?"solid":"dashed"}function mp(e,t=1,i){const n=[];for(const r of Array.isArray(e?.wall_segments)?e.wall_segments:[])0===Number(r?.cm)&&hp(r?.a)&&hp(r?.b)&&(i&&!i.has(String(r.id||""))||n.push(dp(r.a,r.b,t)));return pp([n])}function fp(e,t=1){const i=[];for(const n of Array.isArray(e?.partitions)?e.partitions:[])0===Number(n?.cm)&&hp(n?.a)&&hp(n?.b)&&i.push(dp(n.a,n.b,t));for(const n of Array.isArray(e?.room_drafts)?e.room_drafts:[]){const e=Array.isArray(n?.points)?n.points:[];for(let r=0;r+1e?.host?.kind===t.kind&&e.host.id===t.id)}const bp=new WeakMap,wp=new WeakMap;function kp(e){const t=Fa(e.cfg),i={};for(const t of e.cfg.spaces||[])for(const e of t.rooms||[])e.area&&(i[e.area]=t.id);const n=e.cfg.settings?.exclude_integrations?new Set(e.cfg.settings.exclude_integrations):Te,r=De(e.cfg.settings?.icon_rules?.length?e.cfg.settings.icon_rules:Ce);return Yh({hass:e.hass,registry:e.registry,areaToSpace:i,markers:e.cfg.markers||[],settings:e.cfg.settings||{},excluded:n,showAll:!!e.cfg.settings?.show_all,firstSpaceId:t[0]?.id||"",loc:t=>du(e.lang,t),iconRules:r})}function xp(e){const t=Fa(e.cfg).find(t=>t.id===e.spaceId);if(!t)return null;const i=nn(e.cfg.spaces.find(t=>t.id===e.spaceId)),n=sn(e.cfg.settings),r=e.iconSize??2.5,o=r>8?2.5:r,s=ip(o),a=e.registry?ih(e.hass,e.registry):e.hass,l=e.registry?nh(e.hass,e.registry):e.hass,c=(e.devices||kp(e)).filter(t=>t.space===e.spaceId),h=c.filter(e=>!e.hidden),d=function(e,t,i){const n={},r=i/100*il(t)*1.3;for(const i of t.rooms){if(!i.area)continue;const t=e.filter(e=>e.area===i.area);if(!t.length)continue;const o=sl(i),s=.1*Math.min(o.w,o.h),a=o.w-2*s,l=o.h-2*s,c=Math.max(1,Math.round(Math.sqrt(t.length*a/Math.max(l,1)))),h=a/c,d=l/Math.max(Math.ceil(t.length/c),1),u=t.map((e,t)=>({x:o.x+s+h*(t%c+.5),y:o.y+s+d*(Math.floor(t/c)+.5)}));Ci(u,o,r,.5*s),t.forEach((e,t)=>n[e.id]=Wa(u[t]))}return n}(c,t,o),u=De(e.cfg.settings?.icon_rules?.length?e.cfg.settings.icon_rules:Ce),p=td(a,u,e.cfg.markers||[]),_=i=>{const n=i.settings?.temp_source;if(n)return Xh(a,n,"temp",e.cfg.markers||[]);const r=Qh(t.id,i);return r?p.get(r)?.temp??null:null},m=[];for(const t of h){const i=e.layout[t.id];if(i&&i.s===e.spaceId){const e=i.x*Ca,t=i.y*Ca;m.push({minX:e,minY:t,maxX:e,maxY:t})}}const f=e.cfg.spaces.find(t=>t.id===e.spaceId)||{},g=Array.isArray(f.walls)?f.walls:[],v=Number(f.cell_cm)>0?Number(f.cell_cm):5,y=vp(f,t,Ca,.02*Na),b=(f.openings||[]).flatMap(e=>{if("partition"!==e.host?.kind)return[];const i=Pd(e,t.partitions,Ca,v,Na).resolved;return i?[i]:[]}),w=zl({partitions:t.partitions,roomDrafts:t.room_drafts,columns:t.wall_columns,cellCm:v,hostedOpenings:b.map(e=>({id:e.opening.id,host:e.host,length:e.length,type:e.opening.type}))}),k=function(e,t,i,n){let r=wp.get(e);r||(r=new Map,wp.set(e,r));const o=r.get(t);if(o?.fingerprint===i)return o.value;const s=n();return r.set(t,{fingerprint:i,value:s}),s}(e.cfg,t.id,w,()=>da(t,v,Na,2e-4*Na,b.map(Id)).all);for(const e of k){const t=e.map(e=>e[0]),i=e.map(e=>e[1]);t.length&&m.push({minX:Math.min(...t),minY:Math.min(...i),maxX:Math.max(...t),maxY:Math.max(...i)})}for(const e of y.lines)m.push({minX:Math.min(e[0],e[2]),minY:Math.min(e[1],e[3]),maxX:Math.max(e[0],e[2]),maxY:Math.max(e[1],e[3])});const x=el(t,m),$=[x.x,x.y,x.w,x.h],S=new Map(t.rooms.map(t=>{const r=Tn(i.fill,t);return[t,ln(r,"lqi"===r&&t.area?id(a,c,t.area):null,"light"===r?Oh(zh(a,c,t,e.virtualLights)):"none","temp"===r?_(t):null,i.tempMin,i.tempMax,n,tn(i.customFill,t))]})),M=new Map;for(const e of t.rooms)e.id&&M.set(e.id,S.get(e)||null);const R=function(e,t=1e3){const i=[];for(const[n,r]of(e||[]).entries()){if("passage"!==r?.type)continue;const e={...r,id:String(r.id||`passage-${n}`),type:"passage",rx:Number(r.x)*t,ry:Number(r.y)*t,rlen:Number(r.length)*t};[e.rx,e.ry,e.rlen,e.angle].every(Number.isFinite)&&e.rlen>0&&i.push(e)}return i}((f.openings||[]).flatMap(e=>{if(!e.host||"wall"===e.host.kind)return[e];const t=b.find(t=>t.opening.id===e.id);return t?[Wd(e,t,Ca)]:[]}),Ca),T=gs(t.rooms,g,y.contour,La,v,Na,Ca),C=b.filter(e=>Ld(e,T,2e-4*Na)).map(e=>({x:e.center[0],y:e.center[1],angle:e.angle,length:e.length})),D=t.rooms.filter(e=>e.area||i.showBorders||"none"!==Tn(i.fill,e)).map(e=>{let n="room "+(t.bg?"overlay":"yard"),r="";const o=Tn(i.fill,e);if(i.showBorders||"none"!==o){n+=" styled";const t=[`--room-stroke:${i.color}`,`--room-stroke-op:${i.showBorders&&!y.contour.length?i.opacity:0}`],o=S.get(e)||null;o?(n+=" filled",t.push(`--room-fill:${o.color}`,`--room-fill-op:${o.opacity.toFixed(3)}`)):t.push("--room-fill:transparent","--room-fill-op:0"),r=t.join(";")}const s=e.id||U,a=e.area||U,l=e.poly?B``:B``;return l}),z=t.rooms.filter(e=>{const t=S.get(e);return Cn(i.glow,e)&&(!t||t.opacity<=0)}).map(e=>e.poly?B``:B``),A=new Map;for(const e of t.rooms)if(e.id){const t=S.get(e)||null;A.set(e.id,Cn(i.glow,e)&&(!t||t.opacity<=0)?{color:n.glow_base.c,opacity:n.glow_base.a,mode:"glow"}:null)}const O=zh(a,h,null,e.virtualLights),P=h.map(n=>{const r=function(e,t,i,n,r){const o=t[e.id];return o&&o.s===e.space?{x:o.x*Ca,y:o.y*Ca}:n[e.id]?n[e.id]:Wa(tl(r))}(n,e.layout,e.cfg,d,t),o=(r.x-$[0])/$[2]*100,s=(r.y-$[1])/$[3]*100,c=i.showLqi??!1!==e.showSignal,u=e.presentations?.get(Xu(n.id,c))||Gu(a,n,{liveStates:!1!==e.liveStates,showTemperature:!1!==e.showTemperature,showSignal:c,activityRuntime:e.activityRuntime?.get(n.id),sourceDetails:!1,lightDevices:h,lightSources:O,registryHass:l,reducedMotion:e.reducedMotion}),p=[`left:${o}%`,`top:${s}%`,...Qu(u)],_=Eu(u),m=[n.name,du(e.lang,`marker.state_a11y_${_}`),"none"!==u.pulse.kind?du(e.lang,`marker.pulse_a11y_${u.pulse.reason}`):"",u.valueFullText||u.valueText||"",fu(u.valueBadge),null!=u.lqiText&&u.lqiBand?du(e.lang,`marker.lqi_a11y_${u.lqiBand}`,{value:u.lqiText}):""].filter(Boolean).join(", ");return j``}),F=i.showNames?t.rooms.filter(e=>e.name).map(n=>{const r=al(n,t.id,e.layout,e.cfg),o=(r.x-$[0])/$[2]*100,s=(r.y-$[1])/$[3]*100,a=Math.min(1,i.opacity+.25);return j`
${n.name}
`}):[],E=t.bg?e.displayUrl?e.displayUrl(t.bg.href):t.bg.href:"",I=e.cfg.spaces.find(t=>t.id===e.spaceId)?.settings||{},H="daynight"===ar(e.cfg?.settings,I)?Zn(a,e.dayCycleNow??new Date):null,N=rn(e.cfg?.settings,i),L=!!(g.length||k.length&&i.showBorders),q=L?zl(R.length?{rooms:t.rooms,walls:g,extras:k,cellCm:v,zero:y.contour,passages:R.map(e=>({x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),hostedCompositeOpenings:C}:{rooms:t.rooms,walls:g,extras:k,cellCm:v,zero:y.contour}):"",W=L?function(e,t,i,n){let r=bp.get(e);r||(r=new Map,bp.set(e,r));const o=r.get(t);if(o?.fingerprint===i)return o.value;const s=n();return r.set(t,{fingerprint:i,value:s}),s}(e.cfg,t.id,q,()=>Ls(t.rooms,g,y.contour,[...R.filter(e=>"partition"!==e.host?.kind).map(e=>({x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),...C],La,v,Na,Ca,k)):null,V=R.length&&g.length?function(e,t,i,n,r,o,s,a=1){return[r,o,s,a].every(Number.isFinite)&&o>0&&a>0&&i?.length?Xs(Bs(e,i,n,r,o,s,a),t):t.map(()=>null)}(t.rooms,R.map(e=>({x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),g,y.contour,La,v,Na,Ca):R.map(()=>null),G=R.length?np({openings:R,geometries:V,fillsByRoomId:M,idPrefix:`${t.id}-static-data`,groupClass:"opening-tunnels static-opening-tunnels",dataLayer:"data"}):U,K=R.length?np({openings:R,geometries:V,fillsByRoomId:A,idPrefix:`${t.id}-static-glow`,groupClass:"opening-tunnels glow-base-tunnels static-opening-tunnels",dataLayer:"glow-base"}):U,Y=g.length&&W?.paperD?[{path:W.paperD}]:Xt(t.rooms),Z=i.showBorders?W:null,X=e.stageWidth&&$[2]?e.stageWidth/$[2]:1,J=mo(v),Q=!!Z&&(_o(Z.depthUnits,X)||fo(J,X)),ee=i.color||"#607d8b",te=i.hideOpenings?[]:b.map(e=>{const t=e.opening,i="passage"!==t.type&&t.contact?a.states?.[t.contact]:null,n=ii(t.type,i?.state,!!t.invert,i?.attributes?.current_position),r=n>0&&!!t.contact,o="gate"===t.type?!t.flip_v:!!t.flip_v,s={type:t.type,length:e.length,angle:e.angle,amount:n,flipH:!!t.flip_h,flipV:!!t.flip_v,base:ee,tone:r?"var(--hp-open)":ee,cellCm:v,gridPitch:Na,face:Hd(e,o)};return B` + ${_u(s)} + `});return j` +
+ ${ur(H)} + + ${Z?B` + + + + `:U} + ${Y.map(e=>"path"in e?B``:"poly"in e?B``:B``)} + ${E?B`e.assetLoaded?.(t.bg.href,E)} + transform=${t.bg.angle?`rotate(${t.bg.angle} ${t.bg.x+t.bg.w/2} ${t.bg.y+t.bg.h/2})`:U} + preserveAspectRatio="none" />`:U} + ${D} + ${i.showBorders&&y.contour.length?B``:U} + ${G} + ${z.length?B``:U} + ${K} + ${Z?B` + ${Z.paths.map(e=>B` + + `)} + `:U} + ${i.showBorders&&y.lines.length?B``:U} + ${te} + + ${""} +
${P}${F}
+
+ `}let $p=null,Sp=null,Mp=0,Rp=-1,Tp=null,Cp=[];const Dp=new Set,zp=(e,t)=>{"function"==typeof e&&t.push(e)};function Ap(){if($p)return $p;try{const e=JSON.parse(localStorage.getItem("houseplan_card_cfg_v1")||"null");if(e&&e.config&&Array.isArray(e.config.spaces)){const t=e.layout||{};return{config:e.config,rev:e.rev||0,configFingerprint:e.config_fingerprint||zl(e.config),layout:t,layoutRev:e.layout_rev||0,layoutFingerprint:e.layout_fingerprint||zl(t),virtualLights:Pc(e.virtual_lights,e.rev||0)}}}catch{}return null}function Op(e,t=!1){if(t&&($p=null,Mp++,Sp))return Sp.catch(()=>null).then(()=>Op(e,!1));if($p)return Promise.resolve($p);if(Sp)return Rp!==Mp?Sp.catch(()=>null).then(()=>Op(e,!1)):Sp;return Rp=Mp,Sp=async function(e,t){const[i,n]=await Promise.all([e.callWS({type:"houseplan/config/get"}),e.callWS({type:"houseplan/layout/get"})]),r=i?.rev??0,o=$p?Fc($p.virtualLights,i?.virtual_lights,r,!!i&&"virtual_lights"in i):Pc(i?.virtual_lights,r),s={config:i?.config??null,rev:r,configFingerprint:zl(i?.config??null),layout:n?.layout??{},layoutRev:n?.rev??0,layoutFingerprint:zl(n?.layout??{}),virtualLights:o};t===Mp&&($p=s);const a=e.connection;if(a?.subscribeEvents&&Tp!==a){for(const e of Cp)e();Cp=[],Tp=a;const e=()=>{$p=null,Mp++,Dp.forEach(e=>e())},t=[];try{if(zp(await a.subscribeEvents(e,"houseplan_config_updated"),t),zp(await a.subscribeEvents(e,"houseplan_layout_updated"),t),zp(await a.subscribeEvents(e=>{if($p){const t=Lc($p.virtualLights,e?.data);if(t===$p.virtualLights)return;$p={...$p,virtualLights:t}}else Mp++;Dp.forEach(e=>e())},"houseplan_virtual_light_updated"),t),Tp===a)Cp=t;else for(const e of t)e()}catch{for(const e of t)e();Tp===a&&(Tp=null)}}return s}(e,Mp).finally(()=>{Sp=null,Rp=-1}),Sp}const Pp=3300;function Fp(e,t){return{sources:e,last:Object.fromEntries(t.map(e=>[e.eid,e.state])),flashTs:0,flashKind:null,timer:0,gen:0,expiresAt:0,alarmActive:"alarm"===Dc(t).status}}function Ep(e,t,i,n){n(e.timer);const r=Fp(t,i);Object.assign(e,r)}function Ip(e,t,i,n,r){e.flashTs&&i-e.flashTs"transition"===e.activity)&&(i(e.timer),e.flashTs=0,e.flashKind=null,e.expiresAt=0);if("alarm"===Dc(t).status){e.alarmActive||(i(e.timer),e.flashTs=0,e.flashKind=null,e.expiresAt=0);for(const i of t)e.last[i.eid]=i.state;return e.alarmActive=!0,null}if(e.alarmActive){for(const i of t)e.last[i.eid]=i.state;return e.alarmActive=!1,null}let n=null;for(const i of t){const t=zc(e.last[i.eid],i);("event"===t||!n&&t)&&(n=t),e.last[i.eid]=i.state}return n}class Np{constructor(e,t=()=>{}){this._host=e,this._onGateChange=t,this._modality="unknown",this._gate=!1,this._media=null,this._connected=!1,this._onMediaChange=()=>this._syncGate()}get modality(){return this._modality}get hoverEnabled(){return this._gate}connect(e=globalThis.window){this._connected||(this._connected=!0,this._modality="unknown",this._media="function"==typeof e?.matchMedia?e.matchMedia("(any-hover: hover) and (any-pointer: fine)"):null,this._media?.addEventListener?.("change",this._onMediaChange),this._setGate(!1))}disconnect(){this._media?.removeEventListener?.("change",this._onMediaChange),this._media=null,this._connected=!1,this._modality="unknown",this._setGate(!1)}note(e){return this._modality=function(e,t){const i="mouse"===(n=t.pointerType)||"touch"===n||"pen"===n?n:null;var n;return i?"mouse"===i&&t.sourceCapabilities?.firesTouchEvents?e:i:e}(this._modality,e),this._syncGate(),this._modality}suspend(){this._setGate(!1)}_syncGate(){var e,t;this._setGate((e=this._modality,t=!!this._media?.matches,"mouse"===e&&t))}_setGate(e){this._gate!==e&&(this._gate=e,this._host.toggleAttribute("data-pointer-hover",e),this._onGateChange(e))}}class Lp extends he{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id}))}catch{this._spaces=[]}finally{this._spacesLoading=!1}}}get _lang(){return hu(this.hass,this._config?.language)}get _schema(){const e=this._spaces||[];return[e.length?{name:"space",selector:{select:{mode:"dropdown",options:e}}}:{name:"space",selector:{text:{}}},{name:"title",selector:{text:{}}},{name:"show_button",selector:{boolean:{}}},{name:"button_label",selector:{text:{}}},{name:"button_target",selector:{text:{}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}}]}render(){if(!this.hass||!this._config)return U;const e=Qd(this,ru,hu(this.hass,this._config.language));if("cold"===e)return eu();if("warm"===e)return V;this._loadSpaces();const t=this._lang,i={space:du(t,"editor.space"),title:du(t,"editor.title"),show_button:du(t,"editor.show_button"),button_label:du(t,"editor.button_label"),button_target:du(t,"editor.button_target"),icon_size:du(t,"editor.icon_size"),show_temperature:du(t,"editor.show_temperature"),live_states:du(t,"editor.live_states"),show_signal:du(t,"editor.show_signal")};return j`i[e.name]||e.name} + @value-changed=${this._valueChanged} + >`}_valueChanged(e){const t={...this._config||{},...e.detail.value};delete t.aspect_ratio;const i=new Event("config-changed",{bubbles:!0,composed:!0});i.detail={config:t},this.dispatchEvent(i)}}Lp.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-space-card-editor")||customElements.define("houseplan-space-card-editor",Lp);const qp=e=>{history.pushState(null,"",e),((e,t,i)=>{const n=new Event(t,{bubbles:!0,composed:!0});n.detail=i??{},e.dispatchEvent(n)})(window,"location-changed",{replace:!1})};class Wp extends he{constructor(){super(...arguments),this._snap=null,this._loading=!1,this._reloadQueued=!1,this._forceReloadQueued=!1,this._reloadRetryTimer=0,this._dayCycleTimer=0,this._dayCycleClockKey="",this._stageWidth=0,this._pendingStageWidth=0,this._stageWidthRaf=0,this._haRegistryConnection=null,this._haRegistryRevision=-1,this._devices=[],this._continuity=this._newContinuityController(),this._continuityHistory=[],this._continuityEpoch=0,this._continuityDataReady=!0,this._continuityPaintToken=-1,this._continuityDisposed=!1,this._renderSnapshotAt=Date.now(),this._hassSequence=0,this._connHooked=null,this._connectionWasLost=!1,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotSequence=-1,this._capturedSnapshotDevices=null,this._capturedSnapshotActivity="",this._capturedSnapshotVirtual="",this._activityRuntime=new Map,this._reducedMotion=!1,this._pointerModality=new Np(this),this._onMotionChange=e=>{this._reducedMotion=e.matches,this._capturedSnapshotSequence=-1,this.requestUpdate()},this._onHaRegistryUpdate=()=>{const e=Jc(this.hass).revision;e!==this._haRegistryRevision&&(this._haRegistryRevision=e,this._refreshDevices(),this._capturedSnapshotSequence=-1,this.requestUpdate())},this._dayCycleTick=()=>{if(!this.isConnected||"hidden"===this.ownerDocument.visibilityState)return;const e=this._dayCycleState();if(!e)return this._dayCycleTimer&&(window.clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),void(this._dayCycleClockKey="");const t=Xn(e);t!==this._dayCycleClockKey&&(this._dayCycleClockKey=t,this.requestUpdate())},this._pageVisibility=e=>{if(this._continuity.visibility(e),this._dayCycleVisibility(e),"hidden"!==e.kind){if(!e.long){const e=Date.now();let t=!1;for(const i of this._activityRuntime.values())!i.flashKind||(i.expiresAt||i.flashTs+3300)>e||(i.flashTs=0,i.flashKind=null,i.expiresAt=0,t=!0);return void(t&&(this._capturedSnapshotSequence=-1,this.requestUpdate()))}Date.now()-this._renderSnapshotAt>1e3&&this._continuity.note("device-snapshot-stale"),this._continuityDataReady=!1,this._continuityPaintToken=-1,this._load(!0)}else this._pointerModality.suspend()},this._onConnLost=()=>{this._connectionWasLost=!0,this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.connectionLost()},this._onConnReady=()=>{!this._connectionWasLost&&this._continuity.hasCompleteFrame?this._beginContinuityCandidate("connection-ready",!1,"plan"):(this._continuityDataReady=!1,this._continuityPaintToken=-1),this._load(!0)},this._onAssetLoaded=(e,t)=>{this._signer.markLoaded(this.hass,e,t),this._continuity.note("asset-ready"),this._continuityPaintToken=-1,"steady"!==this._continuity.state&&this.requestUpdate()},this._loadedOnce=!1,this._signer=new Pl(()=>this.requestUpdate()),this._retryContinuity=()=>{this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.retry(this._continuity.recoveryReason||"plan"),this._load(!0)},this._goToSpace=()=>{const e=(this._config?.button_target||"/plan-doma").replace(/#.*$/,"");qp(`${e}#space=${encodeURIComponent(this._config.space)}`)}}_ensureHaRegistryAuthority(){const e=this.hass?.connection||null;e&&e!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=e,this._haRegistryRevision=-1,this._haRegistryRelease=Xc(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}_newContinuityController(){return new Dl(()=>{this._continuityEpoch++,this.isConnected&&this.requestUpdate()})}_dayCycleState(e=new Date){const t=this._snap?.config;if(!t||!this._config)return null;const i=t.spaces?.find(e=>e.id===this._config?.space)?.settings||{};return"daynight"!==ar(t.settings,i)?null:Zn(this._renderDeviceSnapshot?.hass||this.hass,e)}_syncDayCycleClock(){const e=this._dayCycleState();this._dayCycleClockKey=e?Xn(e):"";const t="clock"===e?.source&&"hidden"!==this.ownerDocument.visibilityState&&this.isConnected;t&&!this._dayCycleTimer?this._dayCycleTimer=window.setInterval(this._dayCycleTick,3e4):!t&&this._dayCycleTimer&&(window.clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_dayCycleVisibility(e){"hidden"!==e.kind?(this._dayCycleTick(),this._syncDayCycleClock()):this._dayCycleTimer&&(window.clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_hookConnection(){const e=this.hass?.connection;e&&e!==this._connHooked&&(this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),e.addEventListener?.("ready",this._onConnReady),e.addEventListener?.("disconnected",this._onConnLost),e.addEventListener?.("reconnect-error",this._onConnLost),this._connHooked=e)}static getConfigElement(){return document.createElement("houseplan-space-card-editor")}static getStubConfig(e){const t=Ap();return{type:"custom:houseplan-space-card",space:Fa(t?.config||null)[0]?.id||"",show_button:!0,live_states:!0,show_temperature:!0,show_signal:!0}}setConfig(e){if(!e||!e.space)throw new Error('houseplan-space-card: "space" is required');this._config={show_button:!0,button_target:"/plan-doma",live_states:!0,show_temperature:!0,show_signal:!0,...e},this._snap=this._snap||Ap()}connectedCallback(){var e;this._continuityDisposed&&(this._continuity=this._newContinuityController(),this._continuityDisposed=!1,this._continuityPaintToken=-1),super.connectedCallback(),this._pointerModality.connect(this.ownerDocument.defaultView),this._motionMedia=window.matchMedia?.("(prefers-reduced-motion: reduce)"),this._reducedMotion=!!this._motionMedia?.matches,this._motionMedia?.addEventListener?.("change",this._onMotionChange),this.hass&&this._ensureHaRegistryAuthority(),this._continuityUnsub?.(),this._continuityUnsub=Tl(this.ownerDocument,this._pageVisibility),this._unsub=(e=()=>{this._beginContinuityCandidate("config-event",!1),this._reloadQueued=!0,this._load()},Dp.add(e),()=>Dp.delete(e)),this._signer.start(()=>this.hass,()=>this._referenced())}disconnectedCallback(){this._pointerModality.disconnect(),this._continuityUnsub?.(),this._continuityUnsub=void 0,this._motionMedia?.removeEventListener?.("change",this._onMotionChange),this._motionMedia=void 0,this._unsub?.(),this._unsub=void 0,window.clearTimeout(this._reloadRetryTimer),this._reloadRetryTimer=0,this._dayCycleTimer&&(window.clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),this._dayCycleClockKey="",this._stageObserver?.disconnect(),this._stageObserver=void 0,this._observedStage=void 0,this._stageWidthRaf&&cancelAnimationFrame(this._stageWidthRaf),this._stageWidthRaf=0,this._pendingStageWidth=0,this._signer.dispose(),this._haRegistryRelease?.(),this._haRegistryRelease=void 0,this._haRegistryConnection=null,this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),this._connHooked=null;for(const e of this._activityRuntime.values())window.clearTimeout(e.timer);this._activityRuntime.clear(),this._continuityHistory=[...this._continuityHistory,...this._continuity.trace].slice(-80),this._continuity.dispose(),this._continuityDisposed=!0,super.disconnectedCallback()}willUpdate(e){e.has("hass")&&this.hass&&(this._hassSequence++,this._renderSnapshotAt=Date.now(),this._continuity.note("hass-snapshot"),this._ensureHaRegistryAuthority(),this._hookConnection()),!this.hass||this._loading||this._snap&&!e.has("hass")||this._snap&&this._loadedOnce||this._load(),(e.has("hass")||e.has("_snap")||e.has("_config")||!this._devices.length)&&this._refreshDevices(),this._captureRenderDeviceSnapshot(),this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._continuity.refreshCompleteFrame(this._frameFingerprint())}_stampActivity(e,t){Ip(e,t,Date.now(),window.clearTimeout.bind(window),e=>window.setTimeout(()=>this.requestUpdate(),e))}_syncActivity(e,t,i=this.hass){if(!1===this._config?.live_states){for(const e of this._activityRuntime.values())window.clearTimeout(e.timer);return void this._activityRuntime.clear()}const n=new Set,r=zh(t,e,null,this._snap?.virtualLights);for(const o of e){if(o.hidden)continue;if("icon_ripple"!==Ai(o.marker?.display))continue;n.add(o.id);const s=Wu(t,o,e,r,i),a=s.samples,l=Vu(t,o,s);let c=this._activityRuntime.get(o.id);if(!c||c.sources!==l){c&&window.clearTimeout(c.timer),c=Fp(l,a),this._activityRuntime.set(o.id,c);continue}const h=Hp(c,a,window.clearTimeout.bind(window));h&&this._stampActivity(c,h)}for(const[e,t]of this._activityRuntime)n.has(e)||(window.clearTimeout(t.timer),this._activityRuntime.delete(e))}_refreshDevices(){if(!this.hass||!this._snap?.config||!this._config)return;const e=Jc(this.hass),t=kp({hass:this.hass,registry:e,cfg:this._snap.config,lang:this._lang});this._syncActivity(t,ih(this.hass,e),this.hass),this._devices=t}_captureRenderDeviceSnapshot(){if(!this.hass)return;const e=Date.now(),t=[...this._activityRuntime.entries()].map(([t,i])=>`${t}:${i.gen}:${i.flashTs}:`+(i.flashKind&&(i.expiresAt||i.flashTs+3300)>e?1:0)).join("|"),i=this._snap?.virtualLights?`${this._snap.virtualLights.configRev}:${this._snap.virtualLights.rev}`:"";if(this._capturedSnapshotSequence===this._hassSequence&&this._capturedSnapshotDevices===this._devices&&this._capturedSnapshotActivity===t&&this._capturedSnapshotVirtual===i)return;const n=ih(this.hass,Jc(this.hass)),r=new Map,o=new Set(["sun.sun"]),s=new Set,a=new Set,l=e=>{if(!e)return;const t=e.indexOf(":");if(t<0)return void o.add(e);const i=e.slice(0,t),n=e.slice(t+1);"device"===i?s.add(n):"entity"===i&&o.add(n)},c=Fa(this._snap?.config||null).find(e=>e.id===this._config?.space);for(const e of c?.rooms||[])e.area&&a.add(e.area),l(e.settings?.temp_source),l(e.settings?.hum_source);const h=this._snap?.config?.spaces?.find(e=>e.id===this._config?.space);for(const e of h?.openings||[])for(const t of ri(e))o.add(t);const d=zh(n,this._devices,null,this._snap?.virtualLights);for(const e of this._devices)for(const t of[!1,!0])r.set(Xu(e.id,t),Gu(n,e,{liveStates:!1!==this._config?.live_states,showTemperature:!1!==this._config?.show_temperature,showSignal:t,activityRuntime:this._activityRuntime.get(e.id),sourceDetails:!1,lightDevices:this._devices,lightSources:d,registryHass:this.hass,reducedMotion:this._reducedMotion}));const u=Zu({sourceSequence:this._hassSequence,hass:n,devices:this._devices,presentations:r,entityIds:o,deviceIds:s,areaIds:a});this._capturedSnapshotSequence=this._hassSequence,this._capturedSnapshotDevices=this._devices,this._capturedSnapshotActivity=t,this._capturedSnapshotVirtual=i,this._visibleDeviceSnapshot&&"steady"!==this._continuity.state?this._candidateDeviceSnapshot=u:(this._visibleDeviceSnapshot=u,this._candidateDeviceSnapshot=null)}get _renderDeviceSnapshot(){return this._stagedDeviceSnapshotToken===this._continuity.token?this._candidateDeviceSnapshot||this._visibleDeviceSnapshot:this._visibleDeviceSnapshot||this._candidateDeviceSnapshot}_beginContinuityCandidate(e,t,i="plan"){return this._continuityDataReady=t,this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._continuity.beginCandidate(e,i)}_backdropRaw(){return this._snap?.config&&this._config&&Fa(this._snap.config).find(e=>e.id===this._config.space)?.bg?.href||""}_candidateBackdrop(e){return e&&this._config&&Fa(e).find(e=>e.id===this._config.space)?.bg?.href||""}_assetsReady(){const e=this._backdropRaw();return!e||this._signer.isReady(this.hass,e)}_frameFingerprint(){const e=this._snap;return Al([e?.rev||0,e?.configFingerprint||zl(e?.config),e?.layoutRev||0,e?.layoutFingerprint||zl(e?.layout),e?.virtualLights?`${e.virtualLights.configRev}:${e.virtualLights.rev}`:"",this._config?.space||"",this._stageWidth,this.hass?.themes?.darkMode??this.hass?.themes?.default_theme??""])}_stageValid(){const e=this._observedStage;return!!e&&e.clientWidth>0&&e.clientHeight>0}_settleContinuityFrame(){if(!this._stageValid())return;if(!this._continuity.hasCompleteFrame&&"steady"===this._continuity.state){if(this._assetsReady())return this._renderSnapshotAt=Date.now(),void this._continuity.markCompleteFrame(this._frameFingerprint());this._beginContinuityCandidate("asset-wait",!0,"asset")}if(!this._continuityDataReady)return;if(!["holding","offline-stale","overlay-pending","overlay-visible","candidate-ready"].includes(this._continuity.state))return;const e=this._continuity.token;if(this._candidateDeviceSnapshot&&this._candidateDeviceSnapshot!==this._visibleDeviceSnapshot&&this._stagedDeviceSnapshotToken!==e)return this._stagedDeviceSnapshotToken=e,void this.requestUpdate();this._continuityPaintToken!==e&&(this._continuityPaintToken=e,this._continuity.candidateReady(e)&&this._continuity.commitAfterPaint(e,{updateComplete:()=>this.updateComplete,stageValid:()=>this.isConnected&&this._stageValid(),assetsReady:()=>this._assetsReady(),frameFingerprint:()=>this._frameFingerprint()}).then(t=>{t&&e===this._continuity.token?(this._renderSnapshotAt=Date.now(),this._candidateDeviceSnapshot&&(this._visibleDeviceSnapshot=this._candidateDeviceSnapshot),this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1):e===this._continuity.token&&(this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._candidateDeviceSnapshot=null,this.requestUpdate())}))}updated(){const e=this.renderRoot.querySelector(".hp-static-stage")||void 0;if(e!==this._observedStage)if(this._stageObserver?.disconnect(),this._observedStage=e,e){const t=()=>{const i=e.clientWidth;if(!(i<=0||Math.abs(i-this._stageWidth)<=.5)){if(this._stageWidth<=0)return this._stageWidth=i,void this.requestUpdate();this._pendingStageWidth=i,this._stageWidthRaf||(this._stageWidthRaf=requestAnimationFrame(()=>{this._stageWidthRaf=0;const e=this._pendingStageWidth;this._pendingStageWidth=0,!e||!this._observedStage||this._observedStage.clientWidth<=0||(Math.abs(this._observedStage.clientWidth-e)>.5?t():Math.abs(e-this._stageWidth)<=.5||(this._continuity.hasCompleteFrame&&this._beginContinuityCandidate("stage-resize",!0,"stage-size"),this._stageWidth=e,this.requestUpdate()))}))}};this._stageObserver=new ResizeObserver(t),this._stageObserver.observe(e),t()}else this._stageObserver=void 0;this._syncDayCycleClock(),this._settleContinuityFrame()}async _load(e=!1){if(this.hass){if(this._loading)return this._reloadQueued=!0,void(this._forceReloadQueued||=e);this._loading=!0,this._reloadQueued=!1;try{const t=await Op(this.hass,e),i=!this._snap||this._snap.configFingerprint!==t.configFingerprint,n=!this._snap||this._snap.layoutFingerprint!==t.layoutFingerprint,r=!this._snap||this._snap.virtualLights!==t.virtualLights;if(i&&!await this._signer.prepareImage(this.hass,this._candidateBackdrop(t.config)))return this._continuity.note("asset-failed"),window.clearTimeout(this._reloadRetryTimer),void(this._reloadRetryTimer=window.setTimeout(()=>{this._load(!0)},1e3));window.clearTimeout(this._reloadRetryTimer),this._reloadRetryTimer=0,(i||n)&&this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._beginContinuityCandidate("structural-response",!0),i||n||r?this._snap=t:this._snap&&(this._snap.rev=t.rev,this._snap.layoutRev=t.layoutRev),i&&this._continuity.note("config-candidate",{configRev:t.rev}),n&&this._continuity.note("layout-candidate",{layoutRev:t.layoutRev}),r&&(this._capturedSnapshotSequence=-1),this._loadedOnce=!0,this._connectionWasLost=!1,this._continuityDataReady=!0,this._refreshDevices()}catch{}finally{if(this._loading=!1,this._continuityDataReady=!0,this.requestUpdate(),this._reloadQueued){const e=this._forceReloadQueued;this._reloadQueued=!1,this._forceReloadQueued=!1,this._load(e)}}}}get _lang(){return hu(this.hass,this._config?.language)}getCardSize(){const e=Fa(this._snap?.config||null).find(e=>e.id===this._config?.space);if(e){const t=e.vb[3]/e.vb[2];return Math.max(3,Math.round(8*t))+(!1===this._config?.show_button?0:1)}return 6}_errorCard(e){return j` +
${e}
+
`}_referenced(){return Mn(this._snap?.config)}_renderRecoveryOverlay(){if(!this._continuity.overlayVisible&&"recovery-error"!==this._continuity.state)return U;const e="connection"===this._continuity.recoveryReason;return j`
+ + ${du(this._lang,e?"continuity.restore_connection":"continuity.restore_plan")} + ${"recovery-error"===this._continuity.state?j``:U} +
`}houseplanContinuityTrace(){return[...this._continuityHistory,...this._continuity.trace].slice(-80).map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}render(){if(!this._config||!this.hass)return U;const e=Qd(this,ru,hu(this.hass,this._config.language));if("cold"===e)return eu();if("warm"===e)return V;const t=this._snap?.config;if(!t)return this._errorCard(du(this._lang,"space_card.loading"));const i=this._config.space,n=this._renderDeviceSnapshot,r=xp({hass:n?.hass||this.hass,cfg:t,layout:this._snap?.layout||{},spaceId:i,iconSize:this._config.icon_size,stageWidth:this._stageWidth,lang:this._lang,displayUrl:e=>this._signer.display(this.hass,e),assetLoaded:this._onAssetLoaded,registry:n?{revision:n.sourceSequence,authoritative:!1,access:"limited",entities:{...n.hass.entities},devices:{...n.hass.devices},lastSuccess:n.capturedAt}:Jc(this.hass),devices:[...n?.devices||this._devices],presentations:n?.presentations,activityRuntime:this._activityRuntime,reducedMotion:this._reducedMotion,virtualLights:this._snap?.virtualLights,liveStates:!1!==this._config.live_states,showTemperature:!1!==this._config.show_temperature,showSignal:!1!==this._config.show_signal,inert:this._continuity.overlayBlocksInteraction});if(!r)return this._errorCard(du(this._lang,"space_card.not_found",{id:i}));const o=Fa(t).find(e=>e.id===i),s=void 0!==this._config.title?this._config.title:o?.title||"",a=!1!==this._config.show_button,l=this._config.button_label||du(this._lang,"space_card.button"),c=this._continuity.overlayVisible||"recovery-error"===this._continuity.state?this._continuity.recoveryReason:null;return j` + this._pointerModality.note(e)} + @pointerdown=${e=>this._pointerModality.note(e)} + @pointermove=${e=>this._pointerModality.note(e)}> + ${s?j`
${s}
`:U} +
+ ${r} + ${this._renderRecoveryOverlay()} +
+ ${a?j`
+ +
`:U} +
+ `}}Wp.properties={hass:{attribute:!1},_config:{state:!0},_snap:{state:!0},_continuityEpoch:{state:!0}},Wp.styles=[Yd,o` + .hp-static-title { + font-weight: 700; + padding: 10px 14px 6px; + font-size: 16px; + color: var(--primary-text-color); + } + .hp-static-body { + position: relative; + } + .hp-static-stage { + position: relative; + width: 100%; + container-type: inline-size; + overflow: hidden; + pointer-events: none; /* kill ALL interaction on the schematic (§4) */ + background: var(--ha-card-background, var(--card-background-color, #111)); + } + .hp-static-stage svg { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + display: block; + z-index: 1; + } + /* Opaque plan paper — the scene bg_color/day-cycle environment shows only AROUND + the plan (owner 2026-08-03). The static card keeps its historical + canvas colour: the theme card background. Drawn plans paper the room + contours (per-room shapes, fill only, no stroke) — same contract as + the full card. */ + .hp-paper { + fill: var(--ha-card-background, var(--card-background-color, #111)); + stroke: none; + } + .wallbody-fill { + fill: var(--wall-fill, #ffffff); + fill-opacity: var(--wall-fill-op, 1); + fill-rule: evenodd; + stroke: none; + pointer-events: none; + } + .wallbody { + fill: url(#hp-wall-hatch); + fill-rule: evenodd; + stroke: var(--room-stroke, var(--hp-muted, #607d8b)); + stroke-width: calc(0.6px * var(--hp-cell-visual-scale, 1)); + pointer-events: none; + } + .wallbody.solid { + fill: none; + } + .hp-static-stage .devlayer { + position: absolute; + inset: 0; + z-index: 2; + } + .hp-static-foot { + padding: 8px 12px 12px; + pointer-events: auto; /* the button stays clickable */ + } + .hp-static-btn { + width: 100%; + padding: 9px 14px; + border: none; + border-radius: 10px; + background: var(--primary-color, #3ea6ff); + color: var(--text-primary-color, #fff); + font-size: 14px; + font-weight: 600; + cursor: pointer; + } + :host([data-pointer-hover]) .hp-static-btn:hover { + filter: brightness(1.08); + } + .hp-static-error { + padding: 24px; + text-align: center; + color: var(--secondary-text-color, #9aa4ad); + } + `],customElements.get("houseplan-space-card")||customElements.define("houseplan-space-card",Wp),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 jp=o` + :host { + --hp-editor-tray-bg-fallback: color-mix(in srgb, var(--card-background-color, var(--hp-bg)) 94%, var(--hp-line)); + --hp-editor-tray-bg: color-mix(in srgb, var(--card-background-color, var(--hp-bg)) 86%, transparent); + --hp-editor-tray-border: color-mix(in srgb, var(--hp-line) 82%, var(--hp-accent)); + --hp-editor-tray-blur: 8px; + --hp-editor-tray-shadow: var(--shadow-2); + } + + /* Contextual editor controls float over the stage. Their appearance must + never alter stage height, viewport fitting or the pinned close action. */ + .editor-secondary-host { + position: absolute; + inset: var(--sp-2) var(--sp-4) auto; + z-index: 70; + display: flex; + justify-content: flex-end; + pointer-events: none; + } + .editor-secondary-host.kind-palette, + .editor-secondary-host.kind-group { + justify-content: flex-start; + } + .editor-secondary { + pointer-events: none; + max-width: 100%; + display: flex; + align-items: center; + gap: var(--sp-3); + padding: var(--sp-3) var(--sp-4); + color: var(--hp-txt); + background: var(--card-background-color, var(--hp-bg)); + background: var(--hp-editor-tray-bg-fallback); + border: 1px solid var(--hp-line); + border-color: var(--hp-editor-tray-border); + border-radius: var(--rad-l); + box-shadow: var(--hp-editor-tray-shadow); + opacity: 0; + visibility: hidden; + transform: translateY(-4px); + transition: + opacity 0.1s ease, + transform 0.1s cubic-bezier(0.2, 0.7, 0.2, 1), + visibility 0s linear 0.1s; + touch-action: auto; + } + .editor-secondary-host.open .editor-secondary { + pointer-events: auto; + opacity: 1; + visibility: visible; + transform: translateY(0); + transition-duration: 0.14s, 0.14s, 0s; + transition-delay: 0s; + } + .editor-secondary-host.blocked .editor-secondary { pointer-events: none; } + @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { + .editor-secondary { + background: var(--hp-editor-tray-bg); + -webkit-backdrop-filter: blur(var(--hp-editor-tray-blur)); + backdrop-filter: blur(var(--hp-editor-tray-blur)); + } + } + .editor-secondary-content, + .editor-group-items { + display: flex; + align-items: center; + gap: var(--sp-3); + min-width: 0; + } + .editor-context-label { + max-width: 14rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + padding-inline-end: var(--sp-4); + border-inline-end: 1px solid var(--hp-line); + color: var(--hp-muted); + font-size: var(--fs-s); + } + .editor-secondary.kind-palette { + width: min(760px, 100%); + align-items: stretch; + padding: 0; + overflow: hidden; + } + .editor-secondary.kind-palette .editor-secondary-content, + .editor-secondary.kind-palette .furnpalette { + width: 100%; + } + .editor-secondary.kind-palette .furnpalette { + max-height: 38vh; + border: 0; + background: transparent; + } + .editor-group-launcher .group-chevron { + --mdc-icon-size: 16px; + transition: transform 0.14s ease; + } + .editor-group-launcher[aria-expanded="true"] .group-chevron { transform: rotate(180deg); } + + .editor-secondary .bdhint { + font-size: var(--fs-s); + color: var(--hp-muted); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .editor-secondary .dfill { + display: inline-flex; + align-items: center; + gap: var(--sp-2); + font-size: var(--fs-s); + cursor: pointer; + } + .editor-secondary .dfill input[type="checkbox"] { + width: 16px; + height: 16px; + flex: none; + margin: 0; + padding: 0; + } + .editor-secondary hp-color-opacity { flex: 0 0 auto; } + .editor-secondary input { + width: 74px; + background: transparent; + border: 1px solid var(--hp-line); + color: var(--hp-txt); + border-radius: var(--rad-s); + padding: var(--sp-3) var(--sp-4); + font-size: var(--fs-m); + } + .editor-secondary label, + .editor-secondary .hint { + color: var(--hp-muted); + font-size: var(--fs-s); + } + .editor-secondary .drawwall { + display: inline-flex; + align-items: center; + gap: var(--sp-3); + white-space: nowrap; + } + .editor-secondary .drawwall input { width: 4.2em; } + .editor-secondary .drawwall .opl { + color: var(--hp-muted); + font-size: var(--fs-s); + } + + @container (min-width: 560px) and (max-width: 899px) { + .editor-secondary-content, + .editor-group-items { + flex-wrap: wrap; + justify-content: flex-end; + } + } + @container (max-width: 559px) { + .editor-secondary-host { inset-inline: var(--sp-4); } + .editor-secondary { max-width: 100%; } + .editor-secondary-content, + .editor-group-items { + overflow-x: auto; + scrollbar-width: thin; + } + .editor-secondary-content > *, + .editor-group-items > * { flex: none; } + .editor-context-label { display: none; } + } + @media (prefers-reduced-motion: reduce) { + .editor-secondary { transition: none; } + .editor-group-launcher .group-chevron { transition: none; } + } +`;function Bp(e){return e instanceof Error?e.name||"Error":typeof e}function Vp(e){return zl({id:e?.id??"",cell_cm:e?.cell_cm,rooms:e?.rooms||[],walls:e?.walls||[],wall_segments:e?.wall_segments||[],open_spans:e?.open_spans||[],openings:e?.openings||[],partitions:e?.partitions||[],room_drafts:e?.room_drafts||[],wall_columns:e?.wall_columns||[]})}function Up(e,t,i={}){const n=(Array.isArray(e?.spaces)?e.spaces:[]).find(e=>String(e?.id||"")===String(t||"")),r=Vp(n);if(!n)return{spaceId:String(t||""),displayName:"",status:"failed",reason:"prepare-exception",fingerprint:r,ok:!1};const o=Jp({...e,spaces:[n]},{...i,fingerprint:()=>r}).spaces[0]||{spaceId:String(t||""),displayName:"",status:"failed",reason:"prepare-exception"};return{...o,fingerprint:r,ok:"failed"!==o.status}}function Gp(e,t,i,n=Na,r=1e3){return(Array.isArray(e?.openings)?e.openings:[]).flatMap(e=>{const o={...e,rx:Number(e.x)*r,ry:Number(e.y)*r,rlen:Number(e.length)*r};if(!e.host||"wall"===e.host.kind)return[o];const s=Pd(e,t.partitions,r,i,n);return s.resolved?[{...e,rx:s.resolved.center[0],ry:s.resolved.center[1],rlen:s.resolved.length,angle:s.resolved.angle,partitionHost:s.resolved}]:[]})}function Kp(e,t=()=>!0){return e.flatMap(e=>e.host&&e.partitionHost&&t(e)?[Id(e.partitionHost)]:[])}function Yp(e,t,i,n,r,o,s=Na,a=1e3){const l=gs(t.rooms,[...i],n,r,o,s,a);return e.flatMap(e=>{const t={x:e.rx,y:e.ry,angle:Number(e.angle)||0,length:e.rlen};return e.host&&"wall"!==e.host.kind?e.partitionHost&&Ld(e.partitionHost,l,2e-4*s)?[t]:[]:[t]})}function Zp(e,t){const i=La,n=Na,r=Ca,o=Number.isFinite(Number(t.cellCm))&&Number(t.cellCm)>0?Number(t.cellCm):5,s=Array.isArray(e?.walls)?e.walls:[],a=function(e,t,i=Na,n=1e3){return lp(t.rooms,e?.open_spans,n,.02*i)}(e,t,n,r),l=function(e,t,i=Na){if(!t.length)return[];const n=e.filter(e=>e?.id),r=.02*i,o=[];for(let e=0;e{const t=[(e[0]+e[2])/2,(e[1]+e[3])/2];return h.some(e=>Fn(t,e)<4*r)}).map(e=>[...e]);d.length&&o.push({a:s,b:a,segs:d})}return o}(t.rooms,a,n).flatMap(e=>e.segs),c=Gp(e,t,o,n,r),h=Kp(c),d=da(t,o,n,2e-4*n,h).all;return{space:t,walls:s,openCuts:l,openings:c,roomOpenings:Yp(c,t,s,l,i,o,n,r),partitionCuts:h,physicalBodies:d,wallKeyPitch:i,cellCm:o,gridPitch:n,coordScale:r}}function Xp(e,t,i){const n="string"==typeof e?.title?e.title.trim():"",r=null==e?.id?"":String(e.id).trim();return{spaceId:r,displayName:n||r||i(t+1)}}function Jp(e,t={}){const i=(t.fingerprint||zl)(e),n=Array.isArray(e?.spaces)?e.spaces:[],r=t.fallbackSpaceName||(e=>`Space ${e}`),o=t.prepareSpace||Zp,s=t.wallPass||Ns,a=t.floorPass||Fs,l=[];for(let i=0;i0||d.physicalBodies.length>0;if(!d.space.rooms.length&&!u){l.push({...h,status:"not-applicable"});continue}let p=null;if(u){try{p=s(d.space.rooms,d.walls,d.openCuts,d.roomOpenings,d.wallKeyPitch,d.cellCm,d.gridPitch,d.coordScale,d.physicalBodies)}catch(e){l.push({...h,status:"failed",reason:"wall-exception",detail:Bp(e)});continue}if(null==p){l.push({...h,status:"failed",reason:"wall-null"});continue}if("degraded-extra"===p.status){l.push({...h,status:"failed",reason:"wall-degraded-extra"});continue}if("failed-core"===p.status){l.push({...h,status:"failed",reason:"wall-failed-core"});continue}t.captureWallGeometry?.(d,p)}if(d.space.rooms.length&&null==p?.paperGeom){let e;try{e=a(d.space.rooms,d.walls,d.openCuts,d.wallKeyPitch,d.cellCm,d.gridPitch,d.coordScale)}catch(e){l.push({...h,status:"failed",reason:"floor-exception",detail:Bp(e)});continue}if(null==e){l.push({...h,status:"failed",reason:"floor-null"});continue}}l.push({...h,status:"ok"})}const c=l.filter(e=>"failed"===e.status);return{fingerprint:i,spaces:l,failures:c,ok:0===c.length}}function Qp(e,t){return e.catch(()=>{}).then(t)}class e_{constructor(e=50){this._undo=[],this._redo=[],this._limit=Math.max(30,Math.floor(e))}get canUndo(){return this._undo.length>0}get canRedo(){return this._redo.length>0}get undoName(){return this._undo[this._undo.length-1]?.name??null}get redoName(){return this._redo[this._redo.length-1]?.name??null}get size(){return this._undo.length}push(e){this._undo.push(e),this._undo.length>this._limit&&this._undo.splice(0,this._undo.length-this._limit),this._redo=[]}undo(){const e=this._undo.pop()??null;return e&&this._redo.push(e),e}redo(){const e=this._redo.pop()??null;return e&&this._undo.push(e),e}clear(){this._undo=[],this._redo=[]}}const t_=new WeakMap;const i_=(e,t,i)=>255===e[i+3]&&t.every((t,n)=>Math.abs(e[i+n]-t)<=2);async function n_(e){const t=e.defaultView;if(!t||!t.CSS?.supports?.("mix-blend-mode","screen"))return!1;const i=[128,32,16],n=[16,64,128],r=[9,19,29],o=`\n \n \n \n \n \n `,s=t.URL.createObjectURL(new Blob([o],{type:"image/svg+xml"}));try{const o=await new Promise((e,i)=>{const n=new t.Image,r=t.setTimeout(()=>i(new Error("SVG blend probe timeout")),1e3);n.onload=()=>{t.clearTimeout(r),e(n)},n.onerror=()=>{t.clearTimeout(r),i(new Error("SVG blend probe failed"))},n.src=s}),a=e.createElement("canvas");a.width=4,a.height=1;const l=a.getContext("2d",{willReadFrequently:!0});if(!l)return!1;l.drawImage(o,0,0,4,1);const c=l.getImageData(0,0,4,1).data;return i_(c,i,0)&&i_(c,function(e,t){return[0,1,2].map(i=>Math.round(255-(255-e[i])*(255-t[i])/255))}(i,n),4)&&i_(c,n,8)&&i_(c,r,12)}catch{return!1}finally{t.URL.revokeObjectURL(s)}}const r_={now:()=>performance.now(),requestFrame:e=>requestAnimationFrame(e),cancelFrame:e=>cancelAnimationFrame(e)},o_=e=>Math.max(0,Math.min(1,e)),s_=(e,t,i)=>e+(t-e)*i,a_=(e,t,i)=>{const n=1-e;return 3*n*n*e*t+3*n*e*e*i+e*e*e};function l_(e,t){return{centerX:e.x+e.w/2,centerY:e.y+e.h/2,pixelsPerUnit:t>0&&e.w>0?t/e.w:1,viewBox:{...e}}}function c_(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 h_(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 d_(e,t,i){const n=h_(e),r=h_(t);if(!n||!r)return i<.5?e:t;const o=o_(i);return`rgba(${Math.round(s_(n[0],r[0],o))}, ${Math.round(s_(n[1],r[1],o))}, ${Math.round(s_(n[2],r[2],o))}, ${s_(n[3],r[3],o).toFixed(3)})`}function u_(e,t,i){const n=(e=>{const t=o_(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,a_(r,.2,.2){const t=this._state;if(!t||t.token!==r)return;const i=o_((e-t.startedAt)/t.duration);t.presented=i>=1?t.to:u_(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)}}function __(e,t){return`${e("editor.load_failed")} ${e(t.terminal?"editor.refresh_advice":"editor.retry_advice")}`}class m_ extends Error{}class f_{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 m_(`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 m_&&(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 g_="houseplan_card_labs_v1",v_=Object.freeze([Object.freeze({id:"iso",issue:89,since:"1.62.0",expires:"1.65.0",summary:"Volumetric plan renderer"})]);function y_(e){const t=/^(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?$/.exec(String(e||"").trim());if(!t)return null;const i=t.slice(1).map(Number);return i.every(e=>Number.isSafeInteger(e))?i:null}function b_(e,t){for(let i=0;i<3;i++)if(e[i]!==t[i])return e[i]e.split(",")).map(e=>e.trim()).filter(Boolean)}function M_(e,t,i,n=v_){const r=function(e,t=v_){const i=y_(e),n=new Map;if(!i||!k_(t))return n;for(const e of t){const t=y_(e.since),r=y_(e.expires);b_(i,t)>=0&&b_(i,r)<0&&n.set(e.id,e)}return n}(i,n),o=new Set(k_(n)?n.map(e=>e.id):[]),s=new Set(function(e){if(!e)return[];try{const t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>"string"==typeof e):[]}catch{return[]}}(t).filter(e=>r.has(e)));let a=!1;const l=e=>{if("off"===e)return s.clear(),void(a=!0);const t=e.startsWith("-"),i=t?e.slice(1):e;o.has(i)&&(a=!0,t||!r.has(i)?s.delete(i):s.add(i))};for(const t of S_(new URLSearchParams(String(e.search||"").replace(/^\?/,""))))l(t);for(const t of S_(x_(e.hash)))l(t);const c=Object.freeze([...s].sort());return{active:c,space:$_(e.hash),persist:a?JSON.stringify(c):void 0,knownUrlOperation:a}}let R_={active:Object.freeze([]),space:""},T_="",C_=!1,D_="";const z_=new Set;function A_(){if("undefined"==typeof window)return R_;const e=M_(window.location,function(){try{return window.localStorage.getItem(g_)}catch{return null}}(),T_);void 0!==e.persist&&function(e){try{window.localStorage.setItem(g_,e)}catch{}}(e.persist),R_={active:e.active,space:e.space},window.__hpLabs=e.active;for(const e of z_)e(R_);return R_}function O_(){A_()}function P_(e){if(T_=e,"undefined"==typeof window)return R_;if(!C_){C_=!0,window.__hpLabsListenerCleanup?.(),window.addEventListener("hashchange",O_),window.addEventListener("popstate",O_);const e=()=>{window.removeEventListener("hashchange",O_),window.removeEventListener("popstate",O_),window.__hpLabsListenerCleanup===e&&delete window.__hpLabsListenerCleanup};window.__hpLabsListenerCleanup=e}return A_()}const F_=Object.freeze({rotDeg:0,tiltDeg:20,xyScale:1,zScale:1,origin:Object.freeze([500,500])});function E_(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 I_(e,t,i=F_){if(!(E_(i)&&Number.isFinite(e[0])&&Number.isFinite(e[1])&&Number.isFinite(t)))throw new Error("invalid isometric projection input");const n=i.rotDeg*Math.PI/180,r=i.tiltDeg*Math.PI/180,o=e[0]-i.origin[0],s=e[1]-i.origin[1],a=(o*Math.cos(n)-s*Math.sin(n))*i.xyScale,l=(o*Math.sin(n)+s*Math.cos(n))*i.xyScale;return[i.origin[0]+a,i.origin[1]+l*Math.cos(r)-t*i.zScale*Math.sin(r)]}function H_(e,t=F_){if(!E_(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 N_(e=F_){return`matrix(${function(e=F_){if(!E_(e))throw new Error("invalid isometric camera");const t=e.rotDeg*Math.PI/180,i=e.tiltDeg*Math.PI/180,n=e.xyScale*Math.cos(t),r=-e.xyScale*Math.sin(t),o=e.xyScale*Math.sin(t)*Math.cos(i),s=e.xyScale*Math.cos(t)*Math.cos(i);return[n,o,r,s,e.origin[0]-n*e.origin[0]-r*e.origin[1],e.origin[1]-o*e.origin[0]-s*e.origin[1]]}(e).map(e=>Number(e.toFixed(12))).join(" ")})`}function L_(e,t=F_){const{rect:i,wallHeight:n}=e,r=e.openingHeight??n,o=e.floorDepth??0;if(!(i.w>=0)||!(i.h>=0)||!Number.isFinite(n)||!Number.isFinite(r)||!Number.isFinite(o)||n<0||r<0||o<0)throw new Error("invalid isometric frame");const s=[[i.x,i.y],[i.x+i.w,i.y],[i.x+i.w,i.y+i.h],[i.x,i.y+i.h]],a=Math.max(n,r),l=s.flatMap(e=>[I_(e,-o,t),I_(e,a,t)]),c=l.map(e=>e[0]),h=l.map(e=>e[1]),d=Math.min(...c),u=Math.min(...h);return{x:d,y:u,w:Math.max(...c)-d,h:Math.max(...h)-u}}const q_=e=>`${Number(e[0].toFixed(4))} ${Number(e[1].toFixed(4))}`;function W_(e){let t=0;for(let i=0;iArray.isArray(e)&&Number.isFinite(e[0])&&Number.isFinite(e[1])).map(e=>[Number(e[0]),Number(e[1])]),i=t[t.length-1];return t.length>1&&t[0][0]===i[0]&&t[0][1]===i[1]&&t.pop(),t}(e);if(i.length<3)return[];const n=!t;return W_(i)>0===n?i:[...i].reverse()}function B_(e,t,i){return e.length?`M ${e.map(e=>q_(I_(e,i,t))).join(" L ")} Z`:""}function V_(e,t,i){const n=t[1]-e[1],r=-(t[0]-e[0]),o=i.rotDeg*Math.PI/180;return n*Math.sin(o)+r*Math.cos(o)}function U_(e,t,i=F_){if(!Number.isFinite(t)||t<0)throw new Error("invalid floor edge height");const n=(e||[]).map(e=>(e||[]).map((e,t)=>function(e,t){const i=j_(e,t);if(!i.length)return i;let n=0;for(let e=1;e0)).filter(e=>e.length>=3&&Math.abs(W_(e))>=1e-9)).filter(e=>e.length&&W_(e[0])>0);n.sort((e,t)=>{const i=e[0][0],n=t[0][0];return i[0]-n[0]||i[1]-n[1]||Math.abs(W_(t[0]))-Math.abs(W_(e[0]))});const r=[],o=[];let s=0;for(let e=0;ee.depth-t.depth||e.component-t.component||e.edge-t.edge),{footprintPath:r.join(" "),sides:o,componentCount:n.length,edgeCount:s}}function G_(e,t){return e^=Math.round(64*(Number.isFinite(t)?t:0)),Math.imul(e,16777619)>>>0}const K_=e=>e.every(Number.isFinite);function Y_(e,t,i,n){const r=e[0]*i,o=e[1]*n,s=t*Math.PI/180;return[r*Math.cos(s)-o*Math.sin(s),r*Math.sin(s)+o*Math.cos(s)]}function Z_(e,t,i,n,r,o,s){const a=e.flipH?-1:1,l="gate"===e.type?1:e.flipV?-1:1,c=(e.type,e.flipV,e.angle,e.face,{ox:0,oy:0}),h=function(e,t){return[e[0]+t[0],e[1]+t[1]]}([e.x+c.ox,e.y+c.oy],Y_(i,e.angle,a,l));return{leaf:t,hinge:h,closedVector:Y_(n,e.angle,a,l),quarterVector:Y_([-n[1],n[0]],e.angle,a,l),turnDeg:r,bottom:o,top:s}}const X_=e=>`${Number(e[0].toFixed(4))} ${Number(e[1].toFixed(4))}`;function J_(e,t,i=F_){const n=Math.max(0,Math.min(1,Number.isFinite(t)?t:0));return e.leaves.map(t=>{const r=function(e,t){const i=e.turnDeg*t*Math.PI/180;return[e.hinge[0]+e.closedVector[0]*Math.cos(i)+e.quarterVector[0]*Math.sin(i),e.hinge[1]+e.closedVector[1]*Math.cos(i)+e.quarterVector[1]*Math.sin(i)]}(t,n),o=I_(t.hinge,t.bottom,i),s=I_(r,t.bottom,i),a=I_(r,t.top,i),l=I_(t.hinge,t.top,i);return{id:e.id,sourceIndex:e.sourceIndex,type:e.type,leaf:t.leaf,d:`M ${X_(o)} L ${X_(s)} L ${X_(a)} L ${X_(l)} Z`,shadowD:`M ${X_(I_(t.hinge,0,i))} L ${X_(I_(r,0,i))}`,depth:Math.max(o[1],s[1])}})}const Q_={window:120,door:90,passage:90,gate:300};function em(e){return Q_[e]}function tm(e,t){return{type:e,lengthCm:em(e),flipH:!1,flipV:!1,revision:t}}function im(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 nm(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 rm(e){const t=new Map;return e.forEach((e,i)=>{if(!e.kind||e.open)return;const n=nm(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 om(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 sm(e){const t=rm(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=nm(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(om),n=t.filter(t=>!t.target.partitionHost||e.renderedLength+2*t.target.physicalHalfWidth<=t.length+1e-9).sort(om);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 f=Math.max(e.gridStep,1e-9),g=l/2;m=Math.abs(m-g)<=f/2?g:Math.round(m/f)*f,m=Math.max(_,Math.min(l-_,m));const v=a.a[0]+d*m,y=a.a[1]+u*m,b=Math.max(0,e.renderedLength)/2,w=m-b,k=m+b,x=Math.max(0,w),$=Math.max(0,l-k),S=[a.a[0]+d*(w-x/2),a.a[1]+u*(w-x/2)],M=[a.a[0]+d*(k+$/2),a.a[1]+u*(k+$/2)];let R=180*Math.atan2(h,c)/Math.PI;R>=90?R-=180:R<-90&&(R+=180);const T=Math.abs(m-g)<=1e-9;return{candidate:{presetRevision:e.preset.revision,geometryRevision:e.geometryRevision,pointer:[e.pointer[0],e.pointer[1]],type:e.preset.type,lengthCm:e.preset.lengthCm,flipH:e.preset.flipH,flipV:e.preset.flipV,x:v,y:y,angle:R,renderedLength:e.renderedLength,target:a,...a.partitionHost?{host:{...a.partitionHost,t:l>0?m/l:0}}:{},measure:{labels:[{distance:x,midpoint:S},{distance:$,midpoint:M}],guide:T?{x:v,y:y,angle:R}:null}},jambBlockedTarget:null}}function am(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 lm(e){return!(!e.canEdit||e.kiosk||e.fixedFloor)&&("view"!==e.mode&&("mouse"===e.pointerType&&e.spaceCount>1))}let cm=0;const hm="1.69.0-beta.2",dm="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073",um=1500,pm=(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}},_m=(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)}},mm=new Map;let fm=0;const gm=e=>`${window.innerWidth}x${window.innerHeight}|${location.pathname}|${JSON.stringify(e??{})}`;let vm=1e4;const ym="houseplan_card_layout_v1",bm="houseplan_card_cfg_v1",wm="houseplan_card_zoom_v1",km="houseplan_card_nav_v1",xm="houseplan_card_kiosk_v1",$m="houseplan_card_view_v1",Sm="hp-dialog, hp-help, hp-color-opacity, hp-device-preview",Mm=1e3,Rm=[[0,1],[45,.88],[70,.62],[86,.32],[100,0]],Tm=(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}},Cm=new Set(["select","draw","column","merge","split","resize","opening","wallthick","delroom"]),Dm=(e,t,i)=>{const n=new Event(t,{bubbles:!0,composed:!0});n.detail=i??{},e.dispatchEvent(n)},zm=e=>{history.pushState(null,"",e),Dm(window,"location-changed",{replace:!1})},Am=(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},Om=e=>{try{e.target?.setPointerCapture?.(e.pointerId)}catch{}};class Pm extends he{constructor(){super(...arguments),this._editorRuntime=null,this._onboardingRuntime=null,this._editorRuntimeLoadingVisible=!1,this._editorModeRequest=0,this._warmModeRequest=0,this._editorRuntimeLoader=new f_({expectedFingerprint:dm,load:async e=>{const t=0===e?await import("./houseplan-editor-runtime-LLPkWHY0.js"):await import((()=>{const e=new URL("./houseplan-editor-runtime-LLPkWHY0.js",import.meta.url);return e.searchParams.set("hp_retry",`${hm}-${++cm}`),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),this._showToast(__(e=>this._t(e),t))}}),this._onboardingRuntimeLoader=new f_({expectedFingerprint:dm,load:async e=>{const t=0===e?await import("./houseplan-onboarding-runtime-BkWWzfSR.js"):await import((()=>{const e=new URL("./houseplan-onboarding-runtime-BkWWzfSR.js",import.meta.url);return e.searchParams.set("hp_retry",`${hm}-${++cm}`),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),this._showToast(__(e=>this._t(e),t))}}),this._space="f1",this._layout={},this._serverStorage=!1,this._loadOk=!1,this._serverCanWrite=null,this._loading=!1,this._loadTries=0,this._serverCfg=null,this._cfgRev=0,this._cfgContentFingerprint="",this._unsubCfg=null,this._unsubLayout=null,this._unsubVirtual=null,this._liveSyncAttempt=null,this._liveSyncGeneration=0,this._liveSyncConnection=null,this._layoutRev=0,this._layoutContentFingerprint="",this._virtualLights=Pc(null),this._canOptimizeUndo=!1,this._undoKind=null,this._devices=[],this._regSignature="",this._defPos={},this._newSyncKey="",this._tip=null,this._hoverRoom=null,this._pointerModality=new Np(this,()=>this._syncPointerHoverTargets()),this._devicePressAnimations=new Map,this._selId=null,this._toast="",this._mode="view",this._pendingNavMode=null,this._decorTool="select",this._decorStyle={...pr},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._furnCategory=null,this._dtBox=null,this._dtDrag=null,this._bdDrag=null,this._slide="",this._reducedMotion=!1,this._onMotionChange=e=>{this._reducedMotion=e.matches,this._cancelDevicePressFeedback(),e.matches&&this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:e.matches&&this._modeTransition.active&&this._cancelModeTransition(!0),this.requestUpdate()},this._editorChromeMode="plan",this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest=0,this._modeTransitionTargetZoom=1,this._modeTransitionEditorCamera=null,this._modeTransition=new p_({frame:e=>this._applyModeTransitionFrame(e),settled:e=>this._settleModeTransition(e)}),this._editorSecondaryCopy={groupActive:(e,t)=>this._t("editor.group_active",{group:e,item:t}),openGroup:e=>this._t("editor.open_group",{group:e}),disabledAction:(e,t)=>this._t("editor.disabled_action",{action:e,reason:t})},this._tool="draw",this._geometryHistory=new e_(50),this._wallDialog=null,this._drawWallField=null,this._activeDraftId=null,this._resumeDraftBySpace={},this._physicalSel=null,this._physicalDialog=null,this._partitionDeleteDialog=null,this._roomDeleteDialog=null,this._physicalDrag=null,this._physicalRotate=null,this._physicalLastTap=null,this._physicalPickCycle=null,this._wallUnionCacheValue=null,this._wallUnionPool=new Map,this._isoGeometryCache=new Map,this._isoFallback=new Set,this._openingTunnelCache=null,this._openingWallIndexCache=new Map,this._openingPlacementIntervalsCache=null,this._openingDimensionContextCache=null,this._planSnapGeometryCache=null,this._planStructuralGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._physicalBodiesCache=null,this._lightPhysicalBodiesCache=null,this._cleanFloorCache=new Map,this._innerContourCache=new Map,this._glowClipCache=new Map,this._glowGeometryWarnings=new Set,this._lightBarrierCache=null,this._lightBarrierPool=new Map,this._glowFeatherUnits=null,this._glowRenderedSources=new Map,this._glowLastAppearance=new Map,this._glowEnteringSources=new Set,this._glowEnterRafs=new Map,this._glowFadeTimers=new Map,this._glowFeatherSuspendUntil=0,this._glowFeatherResumeTimer=0,this._glowSourceSeq=0,this._glowScreenBlend=!1,this._duplicateColumnId=null,this._duplicateColumnTimer=0,this._rszLimitViolation=null,this._path=[],this._cursorPt=null,this._planSnapHover=null,this._mergeSel=null,this._openingPreset=null,this._openingRebindId=null,this._openingPresetRevision=0,this._openingHoverCandidate=null,this._openingJambBlockCm=null,this._openingDialog=null,this._openingInfo=null,this._opDrag=null,this._opMeasure=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._wallFaceBatch=null,this._wallRepairDiagnostic=null,this._wallFaceGraphCache=[],this._areaSel="",this._nameSel="",this._roomDialog=!1,this._roomEditId=null,this._roomFill="",this._roomCustomFill=null,this._roomTempSrc="",this._roomHumSrc="",this._roomSrcOpen=null,this._roomSrcFilter="",this._roomNameScale=1,this._roomLabelScale=1,this._zoom=1,this._view=null,this._zoomBySpace={},this._viewModeSnap=null,this._pointers=new Map,this._panStart=null,this._panLock=null,this._pinchStart=null,this._suppressClick=!1,this._touchContacts=new Map,this._touchSequenceMultitouch=!1,this._touchClickBlockUntil=0,this._connectedPath="",this._routeDepartureHandled=!1,this._onLocationChanged=()=>{this._connectedPath&&location.pathname!==this._connectedPath?this._leaveCardRoute():location.pathname===this._connectedPath&&(this._routeDepartureHandled=!1)},this._touchGestureGuard={capture:!0,handleEvent:e=>this._guardTouchGesture(e)},this._hdrH=118,this._booting=!0,this._bootFading=!1,this._bootSettling=!1,this._bootSettleRaf=0,this._bootLastH=-1,this._bootStart=0,this._bootLastChange=0,this._bootSoft=!1,this._tapConfirm=null,this._onboardingShown=!1,this._rulesDialog=null,this._preflightClipboardFallback=null,this._haIntegrationVersion=null,this._alignDialog=null,this._settingsDialog=null,this._backupExportDialog=null,this._backupImportDialog=null,this._sunRaysCache=null,this._dayCycleTimer=0,this._dayCycleClockKey="",this._compassDrag=!1,this._importDialog=null,this._importQueue=[],this._importTotal=0,this._rulesCompiledSrc="",this._infoCard=null,this._nativeMoreInfoEntity=null,this._deviceInbox=null,this._deviceInboxReturn=null,this._deviceInboxMemo=null,this._markerDialog=null,this._spaceDialog=null,this._keyHandler=e=>this._onKey(e),this._warmVp=null,this._warmVpArmed=!1,this._warmLongReturn=!1,this._warmRevivePending=!1,this._warmGen=++fm,this._warmKey=null,this._warmSlot=null,this._hashApplied=!1,this._navApplied=!1,this._labs={active:Object.freeze([]),space:""},this._viewPreference={},this._renderProjection="flat",this._kioskScale={icon:1,font:1},this._kioskDialog=!1,this._activityRt=new Map,this._vacRt=new Map,this._vacViewKey="",this._vacLastView=null,this._vacRaf=0,this._vacSrvTrails={},this._vacJumpOnce=!1,this._continuity=this._newContinuityController(),this._continuityHistory=[],this._continuityEpoch=0,this._continuityDataReady=!0,this._continuityPaintToken=-1,this._continuityDisposed=!1,this._renderSnapshotAt=Date.now(),this._hassSequence=0,this._visibleDeviceSnapshot=null,this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._capturedSnapshotSequence=-1,this._capturedSnapshotDevices=null,this._capturedSnapshotLayout=null,this._capturedSnapshotActivity="",this._capturedSnapshotConfigEpoch=-1,this._capturedSnapshotVirtual="",this._lastValidStageSize=null,this._pendingRefitSize=null,this._refitRaf=0,this._pageVisibility=e=>{if(this._continuity.visibility(e),this._dayCycleVisibility(e),"hidden"===e.kind)return this._clearTransientHover(!0),this._cancelDevicePressFeedback(),void(this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:this._cancelModeTransition(!0));if(this._vacJumpOnce=!0,!e.long){const e=Date.now();let t=!1;for(const i of this._activityRt.values())!i.flashKind||(i.expiresAt||i.flashTs+Pp)>e||(i.flashTs=0,i.flashKind=null,i.expiresAt=0,t=!0);return void(t&&this.requestUpdate())}Date.now()-this._renderSnapshotAt>1e3&&this._continuity.note("device-snapshot-stale"),this._continuityDataReady=!1,this._continuityPaintToken=-1,this._resumeSettling=!0,this._loading?this.requestUpdate():this._loadFromServer()},this._resumeSettling=!1,this._viewportInvalidAt=0,this._vacFit=null,this._vacAllCamerasFor=null,this._vacAllCameraCache=null,this._vacCalConfirm=null,this._kioskDots=!1,this._cyclePausedUntil=0,this._swipeStart=null,this._tabDrag=null,this._tabDragRelease=null,this._tabSuppressClick=!1,this._tabOrderWarned=!1,this._lastTap=0,this._onLabsSnapshot=e=>{const t=this._effectiveProjection();this._labs=e;const i=this._effectiveProjection();this._convertProjectionView(t,i),this.requestUpdate()},this._onHashChange=()=>{if(this._hasFixedFloor)return;const e=this._hashSpace();if(e&&this._model.find(t=>t.id===e)&&e!==this._space){if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return;this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._commitSpace(e),this._selId=null,this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,"plan"===this._mode&&"draw"===this._tool&&this._resumeLastDraft(),this._restoreZoom(),this.requestUpdate()}},this._drag=null,this._rlResize=null,this._holdFired=!1,this._retryContinuity=()=>{this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.retry(this._continuity.recoveryReason||"plan"),this._loading||this._loadFromServer()},this._cfgEpoch=0,this._modelCache=null,this._emptySpaceStateActive=!1,this._decorSnapCache=null,this._markerPreviewMemo=null,this._markerPreviewDevicesMemo=null,this._showHidden=!1,this._connHooked=null,this._connectionWasLost=!1,this._haRegistryConnection=null,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._onHaRegistryUpdate=()=>{const e=Jc(this.hass);e.revision===this._haRegistryRev&&this._devices.length||(this._haRegistryRev=e.revision,this._planHassMemo=null,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate())},this._onConnReady=()=>{if(this._loadTries=0,clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,function(e){const t=Uc(e);t&&(Yc(e,t),Zc(e,t))}(this.hass),this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(this._onConnReady,400));!this._connectionWasLost&&this._continuity.hasCompleteFrame?this._beginContinuityCandidate("connection-ready",!1,"plan"):(this._continuityDataReady=!1,this._continuityPaintToken=-1),this._loading||this._loadFromServer()},this._onConnLost=()=>{this._booting&&!this._continuity.hasCompleteFrame||(this._connectionWasLost=!0,this._continuityDataReady=!1,this._continuityPaintToken=-1,this._continuity.connectionLost())},this._signer=new Pl(()=>this.requestUpdate()),this._dirtyPos=new Set,this._sentPos=new Map,this._persistLayout=Am(()=>{if(this._serverStorage){const e=[...this._dirtyPos];this._dirtyPos.clear();for(const t of e){const e=oo(this._layout[t]);e&&(this._layout={...this._layout,[t]:e},this._sentPos.set(t,e),this.hass.callWS({type:"houseplan/layout/update",device_id:t,pos:e}).then(e=>this._noteLayoutRev(e)).catch(e=>this._showToast(this._t("toast.pos_save_failed",{err:this._errText(e)}))).finally(()=>{this._sentPos.get(t)===e&&this._sentPos.delete(t)}))}this._cacheSnapshot()}else this._layout=so(Ur(this._layout)),localStorage.setItem(ym,JSON.stringify(this._layout))},600),this._frame=null,this._showFar=!1,this._writesPending=0,this._writeChain=Promise.resolve(),this._pendingPhysicalWrites=new Map,this._undoGeometry=()=>this._editorRuntimeOrThrow()._undoGeometry(),this._redoGeometry=()=>this._editorRuntimeOrThrow()._redoGeometry(),this._saveConfigDebounced=Am(()=>{this._serverCfg&&this._writeConfig().catch(e=>{const t=!0===e?.physicalGeometryRolledBack;"geometry-unsafe"!==e?.code&&("wall_model_client_outdated"===e?.code?this._showToast(this._t("toast.wall_model_client_outdated")):"conflict"===e?.code?(this._showToast(this._t("toast.conflict")),t||(this._cancelPath(),this._reloadConfigOnly(!0))):this._showToast(this._t("toast.cfg_save_failed",{err:this._errText(e)})),t&&this._reloadRejectedPhysicalWrite())})},500),this._draftSegmentCms=[],this._closingWallCm=null,this._savePhysicalDialog=()=>this._editorRuntimeOrThrow()._savePhysicalDialog(),this._deletePhysicalSelection=()=>this._editorRuntimeOrThrow()._deletePhysicalSelection(),this._confirmPartitionDelete=()=>this._editorRuntimeOrThrow()._confirmPartitionDelete(),this._deleteDraftWhole=()=>this._editorRuntimeOrThrow()._deleteDraftWhole(),this._deleteDraftSegment=()=>this._editorRuntimeOrThrow()._deleteDraftSegment(),this._confirmRoomDelete=e=>this._editorRuntimeOrThrow()._confirmRoomDelete(e),this._rebindPartitionOpening=()=>this._editorRuntimeOrThrow()._rebindPartitionOpening(),this._keepClosedAsPartitions=()=>this._editorRuntimeOrThrow()._keepClosedAsPartitions(),this._toggleServerPlans=async()=>this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._toggleServerPlans():this._editorRuntimeOrThrow()._toggleServerPlans(),this._aspectJob=null,this._dayCycleTick=()=>{if(!this.isConnected||"hidden"===this.ownerDocument.visibilityState)return;const e=this._dayCycleState();if(!e)return this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0),void(this._dayCycleClockKey="");const t=Xn(e);t!==this._dayCycleClockKey&&(this._dayCycleClockKey=t,this.requestUpdate())},this._sunShown=!1,this._sunOut=!1,this._sunOutTimer=0,this._openSettingsDialog=()=>{if(this._editorRuntime)return this._editorRuntime._openSettingsDialog();this._ensureEditorRuntime().then(e=>{e&&this._openSettingsDialog()})},this._reportedPreflightFingerprint=null,this._openAlignDialog=()=>this._editorRuntimeOrThrow()._openAlignDialog(),this._toggleOptimizeLivePositions=()=>this._editorRuntimeOrThrow()._toggleOptimizeLivePositions(),this._optimizeUndoBusy=!1,this._openBackupExport=()=>this._editorRuntimeOrThrow()._openBackupExport(),this._openRulesDialog=()=>this._editorRuntimeOrThrow()._openRulesDialog(),this._climateCache=null,this._gearPtCache=new WeakMap}_editorRuntimeOrThrow(){if(!this._editorRuntime)throw new Error("Houseplan editor runtime is not loaded");return this._editorRuntime}async _ensureEditorRuntime(){return this._editorRuntimeLoader.ensure()}async _ensureOnboardingRuntime(){return this._onboardingRuntimeLoader.ensure()}_editorRuntimeStateChanged(e){clearTimeout(this._editorRuntimeLoadingTimer),this._editorRuntimeLoadingTimer=void 0,"loading"!==e?(this._editorRuntimeLoadingVisible=!1,this.requestUpdate()):this._editorRuntimeLoadingTimer=window.setTimeout(()=>{this._editorRuntimeLoadingVisible=!0,this.requestUpdate()},150)}async _requestMode(e,t=!0,i=!1){const n=++this._editorModeRequest;if(i&&(this._warmModeRequest=n,this._refitRaf&&(cancelAnimationFrame(this._refitRaf),this._refitRaf=0),this._pendingRefitSize=null),"view"===e||await this._ensureEditorRuntime()){if(n===this._editorModeRequest&&this.isConnected)return i?(this._adoptMode(e),this._warmRevivePending&&(clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmReviveDialog()),this.requestUpdate(),void this.updateComplete.then(()=>requestAnimationFrame(()=>requestAnimationFrame(()=>{if(this._warmModeRequest!==n||n!==this._editorModeRequest)return;const e=this._stageEl;this._lastValidStageSize=e&&e.clientWidth>0&&e.clientHeight>0?[e.clientWidth,e.clientHeight]:null,this._pendingRefitSize=null,this._warmModeRequest=0})))):void this._setMode(e,t);this._warmModeRequest===n&&(this._warmModeRequest=0)}else this._warmModeRequest===n&&(this._warmModeRequest=0)}get _canEdit(){return!!this._norm&&(!0===this._serverCanWrite||!1!==this._serverCanWrite&&!0===this.hass?.user?.is_admin)}get _kiosk(){return!!this._config?.kiosk}_showKioskDots(){this._kioskDots=!0,clearTimeout(this._kioskDotsTimer),this._kioskDotsTimer=window.setTimeout(()=>this._kioskDots=!1,2500)}get _modeTransitionBusy(){return this._modeTransitionPreparing||this._modeTransition.active}_cssColor(e,t){const i=String(e||"").trim();if(!i)return t;const n=document.createElement("span");n.style.cssText=`position:absolute;visibility:hidden;color:${i}`,this.renderRoot.append(n);const r=getComputedStyle(n).color||t;return n.remove(),r}_currentModeVisual(e=this._mode){const t=this._modeTransition.presented||this._modeTransitionVisual;if(t)return{...t,viewport:{...t.viewport,viewBox:{...t.viewport.viewBox}}};const i=this._stageEl;if(!i||i.clientWidth<=0||i.clientHeight<=0)return null;const n=this.renderRoot.querySelector(".editorchrome"),r=this._viewOr(this._baseVb()),o=this.renderRoot.querySelector(".hp-paper"),s=this.renderRoot.querySelector(".hp-backdrop"),a=this.renderRoot.querySelector(".zoomwrap"),l=a?getComputedStyle(a).filter:"",c=Number(/brightness\(([^)]+)\)/.exec(l)?.[1]);return{presentedMode:e,editorChromeHeight:"view"===e?0:n?.getBoundingClientRect().height||0,stageWidth:i.clientWidth,stageHeight:i.clientHeight,viewport:l_(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=Ti(this._baseVb(),n/Math.max(1,r)),s=Math.min(Pm.ZOOM_MAX,Math.max(Pm.ZOOM_MIN,e)),a=o.w/s,l=o.h/s,c=t??o.x+o.w/2,h=i??o.y+o.h/2;return this._clampView({x:c-a/2,y:h-l/2,w:a,h:l},o)}_targetStageColor(e){return"view"!==e?"rgb(255, 255, 255)":this._cssColor(this._stageBg(this._spaceDisplayForRender()),this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"))}_targetPaperColor(e){return"view"===e&&this._spaceModel()?.bg?this._cssColor("var(--ha-card-background, var(--card-background-color, #111))","rgb(17, 17, 17)"):"rgb(255, 255, 255)"}_targetBrightness(e){return 1}_applyModeTransitionFrame(e){e.targetMode===this._mode&&(this._modeTransitionVisual=e.presented,this._view={...e.presented.viewport.viewBox},this.requestUpdate())}_settleModeTransition(e){if(e.targetMode!==this._mode)return;const t=this._modeTransitionRequest;this._view={...e.to.viewport.viewBox},this._zoom=this._modeTransitionTargetZoom,this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._lastValidStageSize=[e.to.stageWidth,e.to.stageHeight],"view"===this._mode&&(this._saveZoom(),this._viewModeSnap=null,this._modeTransitionEditorCamera=null),this.requestUpdate(),this.updateComplete.then(()=>{if(!this.isConnected||t!==this._modeTransitionRequest||this._modeTransitionBusy||e.targetMode!==this._mode)return;const i=this._stageEl;if(i&&i.clientWidth>0&&i.clientHeight>0&&(Math.abs(i.clientWidth-e.to.stageWidth)>.5||Math.abs(i.clientHeight-e.to.stageHeight)>.5)){const e=this._view;this._lastValidStageSize=[i.clientWidth,i.clientHeight],this._applyView(this._zoom,e?e.x+e.w/2:void 0,e?e.y+e.h/2:void 0),this.requestUpdate()}const n=this.renderRoot.activeElement;(!n||!n.isConnected||!!n.closest?.(".editorchrome, .stage"))&&this.renderRoot.querySelector(".modetab.active")?.focus?.({preventScroll:!0})})}_cancelModeTransition(e=!0){const t=!!this._modeTransition.state;this._modeTransitionRequest++,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransition.cancel(e),e&&t||(this._modeTransitionVisual=null)}_adoptMode(e){this._cancelModeTransition(!1),this._mode=e,"view"!==e&&(this._editorChromeMode=e)}_commitViewModeAtomic(e,t,i,n){if(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this._zoom=t,e){const r=this._stageEl?.clientWidth||e.stageWidth,o=Math.max(1,e.stageHeight+e.editorChromeHeight);this._view=this._viewForModeTarget(t,i,n,r,o),this._lastValidStageSize=[r,o]}else this._view=null;this._viewModeSnap=null,this._modeTransitionEditorCamera=null,this._saveZoom(),this.requestUpdate()}_prepareModeTransition(e,t,i,n,r,o){this.updateComplete.then(()=>{if(!this.isConnected||e!==this._modeTransitionRequest||this._mode!==i)return void(e===this._modeTransitionRequest&&(this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._modeTransitionForceAtomic=!1,this.requestUpdate()));const s=this.renderRoot.querySelector(".editorchrome"),a=s?.querySelector(".editorchrome-inner"),l="view"===i?0:a?.scrollHeight||a?.getBoundingClientRect().height||0,c=Math.max(1,t.stageHeight+t.editorChromeHeight),h=Math.max(1,c-l),d=this._stageEl?.clientWidth||t.stageWidth;if(d<=0||h<=0)return this._modeTransitionPreparing=!1,this._modeTransitionVisual=null,this._applyView(n,r,o),void this.requestUpdate();const u=this._viewForModeTarget(n,r,o,d,h),p={presentedMode:i,editorChromeHeight:l,stageWidth:d,stageHeight:h,viewport:l_(u,d),stageColor:this._targetStageColor(i),paperColor:this._targetPaperColor(i),sceneBrightness:this._targetBrightness(i),architectureOpacity:"decor"===i?.35:1,backdropOpacity:"decor"===i&&"backdrop"!==this._decorTool?.5:1,viewWeight:"view"===i?1:0,editorWeight:"view"===i?0:1,toolbarContentOpacity:"view"===i?0:1};this._modeTransitionPreparing=!1;const _=this._modeTransitionForceAtomic;this._modeTransitionForceAtomic=!1,this._modeTransition.start(t,p,i,this._reducedMotion||_?0:220)})}get _hasFixedFloor(){return!!this._config&&Object.prototype.hasOwnProperty.call(this._config,"floor")}_fixedFloorState(e=this._model,t=this._loadOk){const i=this._config?.floor,n=function(e){if(!e.hasFloor)return{kind:"absent"};const t=e.floor;if("string"==typeof t)return t.length?e.spaceIds.includes(t)?{kind:"valid",id:t,source:"id"}:{kind:"invalid",reason:"unknown-id",value:t}:{kind:"invalid",reason:"empty-id",value:t};if("number"==typeof t){if(!Number.isFinite(t))return{kind:"invalid",reason:"non-finite-index",value:t};if(!Number.isInteger(t))return{kind:"invalid",reason:"fractional-index",value:t};if(t<0)return{kind:"invalid",reason:"negative-index",value:t};const i=e.spaceIds[t];return void 0===i?{kind:"invalid",reason:"out-of-range-index",value:t}:{kind:"valid",id:i,source:"index"}}return{kind:"invalid",reason:"invalid-type",value:t}}({spaceIds:e.map(e=>e.id),hasFloor:this._hasFixedFloor,floor:i});return!this._hasFixedFloor||t?n:"number"==typeof i?"valid"===n.kind||"invalid"===n.kind&&"out-of-range-index"===n.reason?{kind:"pending",value:i}:n:"valid"===n.kind||"invalid"===n.kind&&"unknown-id"!==n.reason?n:{kind:"pending",value:i}}_canCommitSpace(e,t=!1){if(t||!this._hasFixedFloor)return!0;const i=this._fixedFloorState();return"valid"===i.kind&&i.id===e}_commitSpace(e,t=!1){return!!this._canCommitSpace(e,t)&&(e!==this._space&&(this._clearTransientHover(!0),this._cancelDevicePressFeedback()),this._space=e,!0)}_slideTo(e,t){if(e===this._space)return!0;if(!this._canCommitSpace(e))return!1;if(this._wallFaceBatch&&this._roomDialogCancel(),"plan"===this._mode&&"draw"===this._tool&&!this._finishWallChain())return!1;this._cancelModeTransition(!0);const i=window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;return this._activeDraftId&&(this._resumeDraftBySpace[this._space]=this._activeDraftId),this._commitSpace(e),this._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._tool="draw",this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._selId=null,this._physicalSel=null,this._editorSecondary?.closeForNavigation(),this._physicalDialog=null,this._physicalDrag=null,"plan"===this._mode&&"draw"===this._tool&&this._resumeLastDraft(),this._restoreZoom(),i||(this._slide=t,clearTimeout(this._slideTimer),this._slideTimer=window.setTimeout(()=>{this._slideTimer=void 0,this._slide="",this.requestUpdate()},190),this.requestUpdate()),!0}get _canReorderTabs(){return lm({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:"mouse",spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})}_tabPointerDown(e,t){lm({canEdit:this._canEdit,kiosk:this._kiosk,mode:this._mode,pointerType:e.pointerType,spaceCount:this._model.length,fixedFloor:this._hasFixedFloor})&&(Om(e),this._tabDragRelease=e=>this._tabPointerUp(e),window.addEventListener("pointerup",this._tabDragRelease),window.addEventListener("pointercancel",this._tabDragRelease),this._tabDrag={id:t,pointerId:e.pointerId,x:e.clientX,y:e.clientY,moved:!1,targetId:null,placement:null})}_tabDropTargetAt(e,t,i){const n=this._model.map(e=>e.id),r=n.indexOf(i);if(r<0)return null;const o=this.renderRoot.querySelectorAll('[data-hp="space-tab"]');for(const s of o){const o=s.dataset.id||"";if(!o||o===i)continue;const a=s.getBoundingClientRect();if(ea.right||ta.bottom)continue;const l=n.indexOf(o);return l<0?null:{targetId:o,placement:l=4)))return;var i,n;const r=this._tabDropTargetAt(e.clientX,e.clientY,t.id);t.moved&&t.targetId===r?.targetId&&t.placement===r?.placement||(this._tabDrag={...t,moved:!0,targetId:r?.targetId||null,placement:r?.placement||null})}_tabPointerUp(e){const t=this._tabDrag;if(t&&t.pointerId!==e.pointerId)return;const i="pointerup"===e.type&&t?.moved?this._tabDropTargetAt(e.clientX,e.clientY,t.id):null;"pointerup"===e.type&&t?.moved&&this._suppressNextTabClick(),this._endTabDrag(),t?.moved&&i&&this._commitTabOrder(t.id,i.targetId)}_endTabDrag(){this._tabDrag=null,this._tabDragRelease&&(window.removeEventListener("pointerup",this._tabDragRelease),window.removeEventListener("pointercancel",this._tabDragRelease),this._tabDragRelease=null)}_tabClick(e){if(this._tabSuppressClick)return this._tabSuppressClick=!1,clearTimeout(this._tabSuppressClickTimer),void(this._tabSuppressClickTimer=void 0);this._pickSpace(e)}_suppressNextTabClick(){this._tabSuppressClick=!0,clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=window.setTimeout(()=>{this._tabSuppressClick=!1,this._tabSuppressClickTimer=void 0},0)}_commitTabOrder(e,t){const i=this._serverCfg;if(!i||!this._canReorderTabs)return;const n=this._model.map(e=>e.id),r=function(e,t,i){const n=e.indexOf(t),r=e.indexOf(i);if(n<0||r<0||n===r)return e;const o=e.slice();return o.splice(n,1),o.splice(r,0,t),o}(n,e,t);if(r===n)return;const o=new Map(this._devices.map(e=>[String(e.id),String(e.area||"")])),s=function(e,t,i,n=()=>""){if(!i)return[];const r=[];for(const o of e){if(!o||!0===o.removed)continue;const e="string"==typeof o.id?o.id:"";if(!e)continue;if("string"==typeof o.space&&o.space)continue;const s=("string"==typeof o.area?o.area:"")||n(e)||"";s&&t[s]||r.push({id:e,space:i})}return r}(i.markers||[],Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),n[0]||"",e=>o.get(e)||"");if(s.length){const e=new Map(s.map(e=>[e.id,e.space]));for(const t of i.markers||[]){const i=e.get(String(t.id));i&&(t.space=i)}}i.spaces=function(e,t){const i=new Map(t.map((e,t)=>[e,t]));return e.map((e,t)=>({space:e,index:t})).sort((e,t)=>(i.get(String(e.space?.id))??Number.MAX_SAFE_INTEGER)-(i.get(String(t.space?.id))??Number.MAX_SAFE_INTEGER)||e.index-t.index).map(e=>e.space)}(i.spaces||[],r),this._saveConfig(),this._tabOrderWarned||(this._tabOrderWarned=!0,this._showToast(this._t("toast.space_order_changed")))}_pickSpace(e){if(this._endTabDrag(),e===this._space)return;const t=this._model.map(e=>e.id),i=t.indexOf(this._space),n=t.indexOf(e);this._navApplied=!0,this._showFar=!1,this._frame=null,this._slideTo(e,i>=0&&n0&&Date.now()>=this._cyclePausedUntil&&this._model.length>1&&this._zoom<=1.001){const e=this._model.map(e=>e.id),t=e.indexOf(this._space);this._slideTo(e[(t+1)%e.length],"left"),this._showKioskDots()}}_syncCycleTimer(){clearInterval(this._cycleTimer),this._cycleTimer=void 0,this.isConnected&&!this._hasFixedFloor&&this._config?.kiosk&&Number(this._config.cycle)>0&&(this._cycleTimer=window.setInterval(()=>this._cycleTick(),1e3*Number(this._config.cycle)))}get _editing(){return"plan"===this._mode||"devices"===this._mode||"decor"===this._mode}get _markup(){return"plan"===this._mode}get _wallUnionCache(){return this._wallUnionCacheValue}set _wallUnionCache(e){this._wallUnionCacheValue=e,null===e&&this._wallUnionPool.clear()}_newContinuityController(){return new Dl(()=>{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($m,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?H_(i):i;return{x:n[0],y:n[1]}}_convertProjectionView(e,t){if(e===t)return;const i=this._logicalViewCenter(e);this._view=null;const n=i?"iso"===t?I_([i.x,i.y],0):[i.x,i.y]:null;this._applyView(this._zoom,n?.[0],n?.[1]),this._warmPatch({vp:this._warmViewportState()}),this.requestUpdate()}_setProjection(e){if(!this._labsIso||"view"!==this._mode)return;const t=this._effectiveProjection();if(this._viewPreference={...this._viewPreference,[this._space]:e},"iso"===e){const e=this._isoSceneKey();e&&this._isoFallback.delete(e)}this._saveViewPreference();const i=this._effectiveProjection();this._convertProjectionView(t,i)}_hashSpace(){return $_(window.location.hash||"")}connectedCallback(){this._connectedPath=location.pathname,this._routeDepartureHandled=!1,window.addEventListener("location-changed",this._onLocationChanged),window.addEventListener("popstate",this._onLocationChanged),this._continuityDisposed&&(this._continuity=this._newContinuityController(),this._continuityDisposed=!1,this._continuityPaintToken=-1);const e=(t=this.ownerDocument,t_.get(t)?.resolved);var t,i;void 0!==e&&(this._glowScreenBlend=e),this._continuityUnsub?.(),this._continuityUnsub=Tl(this.ownerDocument,this._pageVisibility),this._languageFailureUnsub?.(),this._languageFailureUnsub=(i=()=>{this._showToast(this._t("toast.locale_load_failed"))},nu.add(i),()=>nu.delete(i)),super.connectedCallback(),this._pointerModality.connect(this.ownerDocument.defaultView);const n=this.ownerDocument.defaultView?.MutationObserver;n&&(this._pointerHoverObserver=new n(e=>{for(const t of e)for(const e of t.addedNodes)this._syncPointerHoverSubtree(e)}),this._pointerHoverObserver.observe(this.renderRoot,{childList:!0,subtree:!0})),this._motionMedia=window.matchMedia?.("(prefers-reduced-motion: reduce)"),this._reducedMotion=!!this._motionMedia?.matches,this._motionMedia?.addEventListener?.("change",this._onMotionChange),function(e){const t=t_.get(e);if(t)return t.promise;const i={promise:Promise.resolve(!1)};return i.promise=n_(e).catch(()=>!1).then(e=>(i.resolved=e,e)),t_.set(e,i),i.promise}(this.ownerDocument).then(e=>{e!==this._glowScreenBlend&&(this._glowScreenBlend=e,this.isConnected&&this.requestUpdate())}),this.hass&&this._ensureHaRegistryAuthority(),window.addEventListener("keydown",this._keyHandler),this._signer.start(()=>this.hass,()=>Mn(this._serverCfg)),this._syncCycleTimer(),window.addEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=function(e,t){z_.add(t);const i=P_(e);return"undefined"==typeof window&&t(i),()=>{z_.delete(t)}}(hm,this._onLabsSnapshot),this._booting?this._bootWatch():this._bootFading&&(clearTimeout(this._bootTimer),this._bootTimer=window.setTimeout(()=>{this._bootFading=!1},220)),this._bootSoft&&(clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},um)),!this._loadOk&&this._serverCfg&&this.hass&&this._scheduleLoadRetry(),!this._warmSlot&&this._config&&this._warmAdopt(),this._loadOk&&this._ensureLiveSyncSubscriptions(),this._warmVp&&!this._warmRevivePending&&void 0===this._warmReviveTimer&&(this._warmRevivePending=!0,this._warmReviveTimer=window.setTimeout(()=>this._warmReviveDialog(),0)),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1,this.requestUpdate()}disconnectedCallback(){this._connectedPath&&location.pathname!==this._connectedPath&&this._leaveCardRoute(),window.removeEventListener("location-changed",this._onLocationChanged),window.removeEventListener("popstate",this._onLocationChanged),this._continuityUnsub?.(),this._continuityUnsub=void 0,this._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._dayCycleClockKey="",this._bootSettleRaf&&(cancelAnimationFrame(this._bootSettleRaf),this._bootSettleRaf=0),this._bootSettling=!1;for(const e of this._activityRt.values())clearTimeout(e.timer);window.removeEventListener("keydown",this._keyHandler),this._endTabDrag(),clearTimeout(this._tabSuppressClickTimer),this._tabSuppressClickTimer=void 0,this._tabSuppressClick=!1,clearInterval(this._cycleTimer),clearTimeout(this._kioskDotsTimer),clearTimeout(this._kioskHoldTimer),clearTimeout(this._reloadRetry),clearTimeout(this._loadRetryTimer),this._loadRetryTimer=void 0,this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),this._connHooked=null,this._haRegistryRelease?.(),this._haRegistryRelease=void 0,this._haRegistryConnection=null,this._signer.dispose(),clearTimeout(this._toastTimer),clearTimeout(this._slideTimer),clearTimeout(this._editorRuntimeLoadingTimer),this._editorRuntimeLoadingTimer=void 0,this._editorRuntimeLoadingVisible=!1,this._modeTransition.dispose(),this._modeTransitionVisual=null,this._modeTransitionPreparing=!1,this._modeTransitionForceAtomic=!1,this._modeTransitionRequest++,this._slideTimer=void 0,this._slide="",clearTimeout(this._bootTimer),this._bootTimer=void 0,clearTimeout(this._bootSoftTimer),this._saveConfigDebounced.flush(),window.removeEventListener("hashchange",this._onHashChange),this._labsUnsub?.(),this._labsUnsub=void 0,clearTimeout(this._holdTimer),this._roViewport?.disconnect(),this._roViewport=void 0,this._roHdr?.disconnect(),this._roHdr=void 0,this._onWinResize&&(window.removeEventListener("resize",this._onWinResize),this._onWinResize=void 0),this._unsubCfg&&(this._unsubCfg(),this._unsubCfg=null),this._unsubLayout&&(this._unsubLayout(),this._unsubLayout=null),this._unsubVirtual&&(this._unsubVirtual(),this._unsubVirtual=null),this._unsubTrail&&(this._unsubTrail(),this._unsubTrail=void 0),this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=null,clearTimeout(this._layoutSyncTimer),clearTimeout(this._duplicateColumnTimer);for(const e of this._glowFadeTimers.values())clearTimeout(e);for(const e of this._glowEnterRafs.values())cancelAnimationFrame(e);clearTimeout(this._glowFeatherResumeTimer),this._glowFeatherResumeTimer=0,this._glowFeatherSuspendUntil=0,this._glowFadeTimers.clear(),this._glowEnterRafs.clear(),this._glowEnteringSources.clear(),this._glowRenderedSources.clear(),this._glowLastAppearance.clear(),this._glowSourceSeq=0,this._warmSnapshot(),this._warmRevivePending=!1,clearTimeout(this._warmReviveTimer),this._warmReviveTimer=void 0,this._warmRelease(),this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this._touchContacts.clear(),this._touchSequenceMultitouch=!1,this._touchClickBlockUntil=0,this._clearTransientHover(!0),this._cancelDevicePressFeedback(),this._pointerHoverObserver?.disconnect(),this._pointerHoverObserver=void 0,this._pointerModality.disconnect(),this._editorSecondary?.reset(),this._resumeSettling=!1,this._continuityHistory=[...this._continuityHistory,...this._continuity.trace].slice(-80),this._continuity.dispose(),this._continuityDisposed=!0,super.disconnectedCallback()}_onKey(e){if("Escape"===e.key&&this._vacFit)return this._vacFit=null,this._showToast(this._t("vac.cal_cancelled")),void e.stopPropagation();if("Escape"===e.key){if(this._tapConfirm)return void(this._tapConfirm=null);if(this._vacCalConfirm)return void(this._vacCalConfirm=null);if(this._decorEraseConfirm)return void(this._decorEraseConfirm=null);if(this._openingInfo)return void(this._openingInfo=null);if(this._infoCard)return void this._closeInfoCard();if(this._rulesDialog)return void(this._rulesDialog=null);if(this._alignDialog)return this._alignDialog=null,void(this._preflightClipboardFallback=null);if(this._backupImportDialog)return void(this._backupImportDialog=null);if(this._backupExportDialog)return void(this._backupExportDialog=null);if(this._settingsDialog)return void(this._settingsDialog=null);if(this._markerDialog)return void this._closeMarkerDialog();if(this._deviceInbox)return void(this._deviceInbox=null);if(this._openingDialog)return void(this._openingDialog=null);if(this._physicalDialog)return void(this._physicalDialog=null);if(this._backdropDialog)return void(this._backdropDialog=null);if(this._decorShapeDialog)return void(this._decorShapeDialog=null);if(this._decorTextDialog)return void(this._decorTextDialog=null);if(this._spaceDialog&&!this._roomDialog)return this._spaceDialog=null,this._importQueue=[],void(this._importTotal=0);if(this._editorSecondary?.hasOpenGroup)return e.preventDefault(),void this._editorSecondary?.closeGroup(!0)}const t=e.composedPath?.()||[e.target],i=t.some(e=>e?.matches?.('input, textarea, select, [contenteditable="true"]')),n=t.some(e=>e?.classList?.contains?.("editor-secondary")),r=e.ctrlKey||e.metaKey,o=e.key.toLowerCase(),s=/^[a-z]$/.test(o),a="z"===o||!s&&"KeyZ"===e.code,l="y"===o||!s&&"KeyY"===e.code,c=r&&(a&&e.shiftKey||l),h=r&&a&&!e.shiftKey;if("decor"===this._mode){if((h||c)&&i)return;return c?(e.preventDefault(),void this._redoGeometry()):h?(e.preventDefault(),this._decorDraft?void(this._decorDraft=null):this._decorMove||this._dtDrag||this._bdDrag?void this._cancelDecorGesture():void this._undoGeometry()):"Delete"!==e.key&&"Backspace"!==e.key||!this._decorSel||i||n?void("Escape"===e.key&&(e.preventDefault(),this._decorDraft?this._decorDraft=null:this._decorMove||this._dtDrag||this._bdDrag?this._cancelDecorGesture():"furniture"===this._decorTool?(this._furnPalette=null,this._furnCategory=null,this._decorTool="select"):this._decorSel?this._decorSel=null:"select"!==this._decorTool?this._decorTool="select":this._setMode("view"))):(e.preventDefault(),void this._decorDeleteSel())}if(this._markup&&(!h&&!c||!i)){if(("Delete"===e.key||"Backspace"===e.key)&&this._physicalSel&&!i&&!n)return e.preventDefault(),void this._deletePhysicalSelection();if(c)return e.preventDefault(),void this._redoGeometry();if(h)return e.preventDefault(),this._resize?.dragging?void this._rszCancelDrag():this._wallFaceBatch?(this._roomDialogCancel(),void(this._activeDraftId&&this._path.length>1?this._undoActiveDraftPoint():this._undoPoint())):"draw"===this._tool&&this._path.length?void(this._activeDraftId&&this._path.length>1?this._undoActiveDraftPoint():this._undoPoint()):"split"===this._tool&&this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},void(this._splitSel.pts.length||(this._cursorPt=null))):void this._undoGeometry();if("Escape"===e.key)return this._physicalDrag||this._physicalRotate?(e.preventDefault(),void this._cancelPhysicalGesture()):this._roomDialog?(e.preventDefault(),void this._roomDialogCancel()):"draw"===this._tool&&this._path.length?(e.preventDefault(),void this._finishWallChain()):this._physicalSel?(e.preventDefault(),void(this._physicalSel=null)):"resize"===this._tool?(e.preventDefault(),this._resize?.dragging?void this._rszCancelDrag():("exit-tool"===this._resize?.escapeIdle()&&(this._tool="draw"),void this.requestUpdate())):"split"===this._tool?(e.preventDefault(),void(this._splitSel?.pts?.length?(this._splitSel={...this._splitSel,pts:this._splitSel.pts.slice(0,-1)},this._splitSel.pts.length||(this._cursorPt=null)):this._splitSel?this._splitSel=null:this._tool="draw")):"merge"===this._tool?(e.preventDefault(),void(this._mergeSel?this._mergeSel=null:this._tool="draw")):this._wallDialog?(e.preventDefault(),void(this._wallDialog=null)):void("opening"!==this._tool&&"wallthick"!==this._tool&&"delroom"!==this._tool&&"column"!==this._tool||(e.preventDefault(),"opening"===this._tool&&this._clearOpeningPlacement(!0),this._tool="draw"))}}_undoPoint(){if(this._path.length){if(this._contourClosed)return this._path=this._path.slice(0,-1),void(this._closingWallCm=null);if(this._activeDraftId&&this._path.length>1&&this._curSpaceCfg){const e=this._geometrySnapshot();this._path=this._path.slice(0,-1),this._draftSegmentCms=this._draftSegmentCms.slice(0,-1);const t=this._curSpaceCfg,i=(t.room_drafts||[]).findIndex(e=>e.id===this._activeDraftId);if(i>=0){const n=Array.isArray(t.room_drafts[i]?.segments)?t.room_drafts[i].segments:[];this._path.length<2?(t.room_drafts.splice(i,1),t.room_drafts.length||delete t.room_drafts,this._activeDraftId=null):t.room_drafts[i]={id:this._activeDraftId,points:this._path.map(e=>[e[0]/Mm,e[1]/Mm]),segments:this._draftSegmentCms.map((e,t)=>({...n[t]||{},cm:e}))},this._commitPhysicalGeometry(this._t("history.draft_segment_delete"),e)}return}this._path=this._path.slice(0,-1)}}_undoActiveDraftPoint(){const e=this._activeDraftId,t=this._path[0]?[...this._path[0]]:null,i=this._geometryHistory.undo();if(!i)return void this._undoPoint();if(!this._applyGeometryState(i.before,!0))return void this._geometryHistory.clear();const n=e?this._spaceModel()?.room_drafts.find(t=>t.id===e):null;n?(this._activeDraftId=n.id,this._path=n.points.map(e=>[...e]),this._draftSegmentCms=this._adoptDraftCms(this._path,n.segments.map(e=>e.cm),n.id),this._resumeDraftBySpace[this._space]=n.id):(this._activeDraftId=null,this._path=t?[t]:[],this._draftSegmentCms=[],e&&this._resumeDraftBySpace[this._space]===e&&delete this._resumeDraftBySpace[this._space]),this._clearPlanSnapHover(),this._showToast(this._t("history.undone",{name:i.name}))}static async getConfigElement(){return await import("./editor-H80bjnWS.js"),document.createElement("houseplan-card-editor")}static getStubConfig(){return{type:"custom:houseplan-card"}}static _warmBootReset(e){for(const e of mm.values())for(const t of e)clearTimeout(t.evict);mm.clear(),vm=e&&e>0?e:1e4}static _warmBootStats(){let e=0,t=0;const i=[];for(const n of mm.values())for(const r of n)e++,r.dlg&&(t++,i.push(r.dlg.kind));return{keys:mm.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(wm)||"{}")||{}}catch{this._zoomBySpace={}}try{const e=JSON.parse(localStorage.getItem($m)||"{}")||{};this._viewPreference=Object.fromEntries(Object.entries(e).filter(e=>"flat"===e[1]||"iso"===e[1]))}catch{this._viewPreference={}}this._labs=P_(hm);try{const e=JSON.parse(localStorage.getItem(xm)||"null");this._kioskScale={icon:zn(e?.icon),font:zn(e?.font)}}catch{}try{const e=JSON.parse(localStorage.getItem(bm)||"null");e&&e.config&&Array.isArray(e.config.spaces)&&(this._serverCfg=e.config,this._cfgEpoch++,this._cfgRev=e.rev||0,this._cfgContentFingerprint=e.config_fingerprint||zl(e.config),this._layout=e.layout||{},this._layoutRev=e.layout_rev||0,this._layoutContentFingerprint=e.layout_fingerprint||zl(this._layout),this._virtualLights=Pc(e.virtual_lights,this._cfgRev),this._serverStorage=!0)}catch{}this._adoptInitialSpace(this._model,this._loadOk),"view"!==this._mode||this._view||(this._zoom=this._zoomBySpace[this._space]||1),this.isConnected&&(this._syncCycleTimer(),this._warmAdopt(),this._warmLongReturn&&this._beginResumeSettle(),this._warmLongReturn=!1)}_warmAdopt(){if(this._config?.kiosk)return;const e=gm(this._config);if(this._warmKey===e&&this._warmSlot)return;this._warmSlot&&this._warmRelease();const t=this.parentNode,i=this._warmIdx(t),n=mm.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>=Sl,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>=Sl,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},um)),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=mm.get(t);if(!e.live&&o&&o.length>1){const t=o.indexOf(e);t>=0&&o.splice(t,1)}},vm+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?I_([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&&Cm.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=gm(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=mm.get(i)||[];for(n.push(this._warmSlot),mm.set(i,n),this._warmTrim(n);mm.size>8;){const e=mm.keys().next().value;if(void 0===e||e===i)break;for(const t of mm.get(e)||[])clearTimeout(t.evict);mm.delete(e)}}Object.assign(this._warmSlot,e)}}_warmViewportState(){const e=this._effectiveProjection();return{space:this._space,mode:this._mode,projection:e,activeLabsIso:this._labsIso,logicalCenter:this._logicalViewCenter(e),zoom:this._zoom,view:this._view?{...this._view}:null,snap:this._viewModeSnap?{...this._viewModeSnap}:null,tool:this._tool,decorTool:this._decorTool,showHidden:this._showHidden,showFar:this._showFar,selId:this._selId,rszSel:this._resize?.selectedRoomId,decorSel:this._decorSel}}_warmDialogState(){const e=(e,t)=>({kind:e,space:this._space,mode:this._mode,data:t});return this._tapConfirm||this._alignDialog||this._mergeDialog||this._importDialog||this._backupExportDialog||this._backupImportDialog?null:this._openingInfo?e("openingInfo",this._openingInfo.id):this._infoCard?e("info",this._infoCard.id):this._rulesDialog?this._rulesDialog.busy?null:e("rules",this._rulesDialog):this._settingsDialog?this._settingsDialog.busy?null:e("settings",this._settingsDialog):this._markerDialog?this._markerDialog.busy?null:e("marker",this._markerDialog):this._openingDialog?e("opening",this._openingDialog):this._backdropDialog?e("backdrop",this._backdropDialog):this._decorShapeDialog?e("decorShape",this._decorShapeDialog):this._decorTextDialog?e("decorText",this._decorTextDialog):this._roomDialog?e("room",{editId:this._roomEditId,fill:this._roomFill,customFill:this._roomCustomFill,tempSrc:this._roomTempSrc,humSrc:this._roomHumSrc,srcOpen:this._roomSrcOpen,srcFilter:this._roomSrcFilter,nameScale:this._roomNameScale,labelScale:this._roomLabelScale,areaSel:this._areaSel,nameSel:this._nameSel,pendingSplit:this._pendingSplit,wallFaceBatch:this._wallFaceBatch,path:this._path}):this._spaceDialog?this._spaceDialog.busy?null:e("space",this._spaceDialog):null}_warmSnapshot(){if(this._booting||this._config?.kiosk||"steady"!==this._continuity.state)return;const e={vp:this._warmViewportState(),frameFingerprint:this._continuity.frameFingerprint,devices:this._devices};if(this._warmRevivePending||(e.dlg=this._warmDialogState()),this.isConnected&&this._warmSlot?.owner===this._warmGen){const t=this.parentNode;e.place=t?new WeakRef(t):null,e.idx=this._warmIdx(t)}this._warmPatch(e)}_warmReviveDialog(){const e=this._warmSlot;if(this._warmReviveTimer=void 0,!e||!e.dlg)return void(this._warmRevivePending=!1);const t=e.dlg,i=e.freed;if(t.mode===this._mode||"view"===t.mode||this._warmVp?.mode!==t.mode||this._editorRuntime){if(this._warmRevivePending=!1,e.dlg=null,e.freed=0,clearTimeout(e.evict),e.evict=0,i&&!(Date.now()-i>vm)&&t.space===this._space&&t.mode===this._mode){switch(t.kind){case"space":this._spaceDialog={...t.data,busy:!1,savedBusy:!1};break;case"marker":this._markerDialog={...t.data,busy:!1};break;case"settings":this._settingsDialog={...t.data,busy:!1};break;case"rules":this._rulesDialog={...t.data,busy:!1};break;case"opening":this._openingDialog={...t.data};break;case"backdrop":this._backdropDialog={...t.data};break;case"decorShape":this._decorShapeDialog={...t.data};break;case"decorText":{this._decorTextDialog={...t.data};const e=String(this._decorTextDialog?.text??"").length;this._decorTextSelection={start:e,end:e};break}case"room":{const e=t.data;this._roomEditId=e.editId,this._roomFill=e.fill,this._roomCustomFill=e.customFill||null,this._roomTempSrc=e.tempSrc,this._roomHumSrc=e.humSrc,this._roomSrcOpen=e.srcOpen,this._roomSrcFilter=e.srcFilter,this._roomNameScale=e.nameScale,this._roomLabelScale=e.labelScale,this._areaSel=e.areaSel,this._nameSel=e.nameSel,this._pendingSplit=e.pendingSplit,this._wallFaceBatch=e.wallFaceBatch||null,this._path=e.path,this._wallFaceBatch&&(this._activeDraftId=this._wallFaceBatch.activeDraftId,this._draftSegmentCms=[...this._wallFaceBatch.activeCms]),this._roomDialog=!0;break}case"info":{const e=this._devices.find(e=>e.id===t.data);e&&(this._infoCard=e);break}case"openingInfo":{const e=(this._curSpaceCfg?.openings||[]).find(e=>e.id===t.data);e&&(this._openingInfo=e);break}}this.requestUpdate()}}else this._warmRevivePending=!0}_cacheSnapshot(){if(this._serverCfg)try{this._cfgContentFingerprint=zl(this._serverCfg),this._layoutContentFingerprint=zl(this._layout),this._virtualLights=function(e,t,i){if(e.configRev===i)return e;const n=new Set((Array.isArray(t?.markers)?t.markers:[]).filter(Hc).map(e=>e.id));return{...e,configRev:i,off:new Set([...e.off].filter(e=>n.has(e)))}}(this._virtualLights,this._serverCfg,this._cfgRev),localStorage.setItem(bm,JSON.stringify({config:this._serverCfg,rev:this._cfgRev,config_fingerprint:this._cfgContentFingerprint,layout:this._layout,layout_rev:this._layoutRev,layout_fingerprint:this._layoutContentFingerprint,virtual_lights:Ec(this._virtualLights)}))}catch{}}_beginContinuityCandidate(e,t,i="plan"){return this._booting&&!this._continuity.hasCompleteFrame?this._continuity.token:(this._continuityDataReady=t,this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._resumeSettling=!0,this._continuity.beginCandidate(e,i))}_continuityStageValid(){const e=this._stageEl;return!!e&&e.clientWidth>0&&e.clientHeight>0}_continuityAssetsReady(){if(!this._model.length)return!1;const e=this._model.length?this._spaceModel():null;return!e?.bg?.href||this._signer.isReady(this.hass,e.bg.href)}_initialSpaceSelection(e,t=this._loadOk){const i=this._fixedFloorState(e,t);return"valid"===i.kind?{id:i.id,source:"fixed"}:this._hasFixedFloor?{id:null,source:"none"}:function(e){const t=new Set(e.spaceIds.filter(e=>!!e));if(!t.size)return{id:null,source:"none"};const i=[["hash",!1===e.acceptHash?null:e.hashSpace],["current",e.preserveCurrent?e.currentSpace:null],["saved",e.savedSpace],["default",e.defaultSpace],["first",e.spaceIds[0]]];for(const[e,n]of i)if(n&&t.has(n))return{id:n,source:e};return{id:null,source:"none"}}({spaceIds:e.map(e=>e.id),hashSpace:this._hashSpace(),acceptHash:!this._hashApplied,currentSpace:this._space,preserveCurrent:this._hashApplied||this._navApplied||this._warmVpArmed,savedSpace:this._savedNav()?.space,defaultSpace:this._config?.default_floor})}_adoptInitialSpace(e,t=this._loadOk){const i=this._initialSpaceSelection(e,t);return i.id?(this._commitSpace(i.id,!0),"hash"===i.source&&(this._hashApplied=!0),"saved"===i.source&&(this._navApplied=!0),i):i}_candidateBackdrop(e,t=this._space){const i=Fa(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 Al([this._cfgRev,this._cfgContentFingerprint||zl(this._serverCfg),this._layoutRev,this._layoutContentFingerprint||zl(this._layout),this._space,this._mode,this._view,t,this._glowScreenBlend?"screen":"normal",this.hass?.themes?.darkMode??this.hass?.themes?.default_theme??""])}_settleContinuityFrame(){if(this._booting||!this._continuityStageValid())return;if(!this._continuity.hasCompleteFrame&&"steady"===this._continuity.state)return void(this._continuityAssetsReady()&&(this._renderSnapshotAt=Date.now(),this._continuity.markCompleteFrame(this._visualFrameFingerprint())));if(!this._continuityDataReady)return;if(!["holding","offline-stale","overlay-pending","overlay-visible","candidate-ready"].includes(this._continuity.state))return;const e=this._continuity.token;if(this._candidateDeviceSnapshot&&this._candidateDeviceSnapshot!==this._visibleDeviceSnapshot&&this._stagedDeviceSnapshotToken!==e)return this._stagedDeviceSnapshotToken=e,void this.requestUpdate();this._continuityPaintToken!==e&&(this._continuityPaintToken=e,this._continuity.candidateReady(e)&&this._continuity.commitAfterPaint(e,{updateComplete:()=>this.updateComplete,stageValid:()=>this.isConnected&&this._continuityStageValid(),assetsReady:()=>this._continuityAssetsReady(),frameFingerprint:()=>this._visualFrameFingerprint()}).then(t=>{t&&e===this._continuity.token?(this._resumeSettling=!1,this._renderSnapshotAt=Date.now(),this._candidateDeviceSnapshot&&(this._visibleDeviceSnapshot=this._candidateDeviceSnapshot),this._candidateDeviceSnapshot=null,this._stagedDeviceSnapshotToken=-1,this._warmSnapshot()):e===this._continuity.token&&(this._continuityPaintToken=-1,this._stagedDeviceSnapshotToken=-1,this._candidateDeviceSnapshot=null,this.requestUpdate())}))}_onBackdropLoaded(e,t){this._signer.markLoaded(this.hass,e,t),this._continuity.note("asset-ready"),this._continuityPaintToken=-1,"steady"!==this._continuity.state&&this.requestUpdate()}_renderRecoveryOverlay(){if(!this._continuity.overlayVisible&&"recovery-error"!==this._continuity.state)return U;const e="connection"===this._continuity.recoveryReason;return j`
e.stopPropagation()} + @click=${e=>e.stopPropagation()} + @wheel=${e=>e.stopPropagation()}> + + ${this._t(e?"continuity.restore_connection":"continuity.restore_plan")} + ${"recovery-error"===this._continuity.state?j``:U} +
`}_renderEditorRuntimeLoading(){return this._editorRuntimeLoadingVisible?j`
+ + ${this._t("editor.loading")} +
`:U}houseplanContinuityTrace(){return[...this._continuityHistory,...this._continuity.trace].slice(-80).map(e=>({...e,...e.stage?{stage:[...e.stage]}:{}}))}getCardSize(){return 12}get _norm(){return!(!this._serverCfg||!this._serverCfg.spaces.length)}_cfgFingerprint(){const e=this._serverCfg?.spaces||[];let t=e.length+":";for(const i of e){t+=(i.id||"")+","+(i.plan_aspect||"")+","+(i.plan_url||"").length+","+(i.plan_x??"")+","+(i.plan_y??"")+","+(i.plan_scale??"")+","+(i.plan_scale_x??"")+","+(i.plan_scale_y??"")+","+(i.plan_angle??"")+","+(i.rooms?.length||0)+","+(i.openings?.length||0)+","+(i.decor?.length||0)+";";for(const e of i.rooms||[]){const i=e.poly?.[0],n=e.poly?.[e.poly.length-1];t+=(e.poly?.length||0)+"."+(e.id||"")+"."+(e.open_to||[]).join("+")+"."+(e.area||"")+"."+JSON.stringify(e.settings||0)+"."+(e.x??"")+","+(e.y??"")+","+(e.w??"")+","+(e.h??"")+","+(i?i[0]+"/"+i[1]:"")+","+(n?n[0]+"/"+n[1]:"")+";"}}return t}get _model(){if(!this._serverCfg)return[];const e=this._cfgEpoch+"|"+this._cfgFingerprint();if(this._modelCache&&this._modelCache.key===e)return this._modelCache.model;const t=this._buildModel();return this._modelCache={key:e,model:t},t}_buildModel(){if(!this._serverCfg)return[];const e=this._renderCfg;return Fa(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?Fl(this._model,this._space):(e=this._model,t=this._space,e.find(e=>e.id===t)??e[0]);var e,t}_spaceModelById(e){return Fl(this._model,e)}_syncEmptySpaceState(){if(!!this._serverCfg&&0===this._serverCfg.spaces.length){if(!this._emptySpaceStateActive){this._emptySpaceStateActive=!0;for(const e of this._pointers.keys())for(const t of this.renderRoot.querySelectorAll("*"))try{t.hasPointerCapture?.(e)&&t.releasePointerCapture(e)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null,this._drag=null,this._rlResize=null,this._vacFit=null,this._compassDrag=!1,this._cancelModeTransition(!1),this._mode="view",this._clearGeometryGesture(),this._geometryHistory.clear(),this._resumeDraftBySpace={},this._tip=null,this._hoverRoom=null,this._openingInfo=null,this._closeInfoCard(),this._deviceInbox=null,this._deviceInboxReturn=null,this._markerDialog=null,this._physicalDialog=null,this._backdropDialog=null,this._decorShapeDialog=null,this._decorTextDialog=null,this._roomDialog=!1,"edit"===this._spaceDialog?.mode&&(this._spaceDialog=null),this._editorSecondary?.closeForNavigation(),this._saveConfigDebounced.cancel(),this._frame=null,this._planSnapGeometryCache=null,this._hiddenWallDiagnosticCache=null,this._decorSnapCache=null,this._commitSpace("",!0)}}else this._emptySpaceStateActive=!1}get _areaToSpace(){const e={};for(const t of this._model)for(const i of t.rooms)i.area&&(e[i.area]={space:t.id,room:i});return e}get _settings(){return this._serverCfg?.settings||{}}get _showAll(){return this._showHidden||!this._settings.filter_seeded&&!!this._settings.show_all}_seedHiddenDevices(){if(!this._serverCfg||!this._norm||!this._canEdit)return;const e=this._serverCfg,t=function(e){const t=e.hass,i=e.registry||Jc(t),n=ih(t,i),r=nh(t,i),{areaToSpace:o,markers:s,settings:a,excluded:l,iconRules:c}=e,h=!1!==a.group_lights,d=Vh(s),u=Nh(n,h).filter(e=>!Uh(n,e.eid,d)),p=new Set(u.map(e=>e.area)),_=ah(n),m=lh(s,r),f=new Set(s.map(e=>e.binding)),g=[];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(f.has("device:"+e.id))continue;if("active"!==sh(t,"device:"+e.id,i).kind)continue;const s=ch(n,e.id,_[e.id]||[],m);if(s.partial&&!s.entityIds.length)continue;const a=s.entityIds,d=hh(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"===Lh(n,t,e.model,a,c)&&(u=!0)}u&&g.push("device:"+e.id)}return g}({hass:this.hass,registry:this._haRegistry,areaToSpace:Object.fromEntries(Object.entries(this._areaToSpace).map(([e,t])=>[e,t.space])),markers:this._markers,settings:this._settings,excluded:this._excluded,firstSpaceId:this._model[0]?.id||"",iconRules:this._iconRules});if(!t.length&&e.settings?.filter_seeded)return;e.markers=e.markers||[];const i=[];for(const n of t){const t="h"+n.slice(n.indexOf(":")+1);e.markers.push({id:t,binding:n,hidden:!0}),i.push(n.slice(n.indexOf(":")+1))}const n={...e.settings||{},filter_seeded:!0};delete n.show_all,i.length&&Array.isArray(n.new_device_ids)&&(n.new_device_ids=n.new_device_ids.filter(e=>!i.includes(e))),e.settings=n,this._regSignature="",this._maybeRebuildDevices(),this._saveConfig(),this.requestUpdate()}get _iconRules(){const e=this._settings.icon_rules;if(!e||!Array.isArray(e)||!e.length)return;const t=JSON.stringify(e);return t!==this._rulesCompiledSrc&&(this._rulesCompiledSrc=t,this._rulesCompiled=De(e)),this._rulesCompiled}get _fillColors(){return sn(this._settings)}get _excluded(){const e=this._settings.exclude_integrations;return e?new Set(e):Te}willUpdate(e){e.has("_serverCfg")&&this._cfgEpoch++,this._syncEmptySpaceState(),e.has("hass")&&this.hass&&(this._hassSequence++,this._renderSnapshotAt=Date.now(),this._continuity.note("hass-snapshot"),this._ensureHaRegistryAuthority(),this._planHassMemo=null,this._hookConnection(),!this._loadOk&&!this._loading&&this._loadTries<8&&this._loadFromServer(),this._maybeRebuildDevices(),this._vacTick(),this._activityTick()),this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._continuity.refreshCompleteFrame(this._visualFrameFingerprint()),this._captureRenderDeviceSnapshot()}updated(){this._pruneDevicePressFeedback(),this._syncDayCycleClock(),this._warmSnapshot(),this._editorRuntime&&this._dtMeasure();const e=this._stageEl;e&&!this._roViewport&&(this._roViewport=new ResizeObserver(()=>this._refitView()),this._roViewport.observe(e)),e&&this._booting&&!this._bootTimer&&this._bootWatch();const t=this.renderRoot.querySelector(".hdr");if(t&&e&&!this._roHdr){const i=()=>{const t=this.renderRoot.querySelector("ha-card");if(!t)return;const i=e.getBoundingClientRect().top-t.getBoundingClientRect().top,n=Math.min(Math.max(t.getBoundingClientRect().top,0),120),r=Math.round(i+n);r>=0&&r!==this._hdrH&&(this._hdrH=r),r>=0&&!this._booting&&!this._config?.kiosk&&e.clientHeight>0&&this._warmPatch({hdrH:r,stageH:e.clientHeight})};this._roHdr=new ResizeObserver(()=>requestAnimationFrame(i)),this._roHdr.observe(t),this._onWinResize=()=>requestAnimationFrame(i),window.addEventListener("resize",this._onWinResize),i()}if(e&&!this._view&&this._refitView(),this._editorSecondary?.afterRender(),this._settleContinuityFrame(),this._serverStorage&&this._loadOk&&0===this._model.length&&!this._spaceDialog&&!this._importDialog&&!this._onboardingShown){this._onboardingShown=!0;const e=function(e){const t=e?.floors;if(!t||"object"!=typeof t)return[];const i=[];for(const e of Object.values(t))e&&e.floor_id&&i.push({id:e.floor_id,name:e.name||e.floor_id,level:e.level??null});return i.sort((e,t)=>{const i=e.level??1e9,n=t.level??1e9;return i!==n?i-n:e.name.localeCompare(t.name)}),i}(this.hass);e.length?this._importDialog={floors:e.map(e=>({...e,checked:!0}))}:this._openSpaceDialog("create")}}_adoptStructuralResponses(e,t,i){const n=e?.config,r=n&&Array.isArray(n.spaces)?n:null,o=zl(r),s=o!==(this._cfgContentFingerprint||zl(this._serverCfg));if(s&&(this._geometryHistory.clear(),this._pendingPhysicalWrites.clear(),this._serverCfg&&this._clearGeometryGesture(),this._serverCfg=r,this._cfgContentFingerprint=o),this._cfgRev=e?.rev??this._cfgRev,e&&("virtual_lights"in e||"config"in e)){const t=Fc(this._virtualLights,e.virtual_lights,this._cfgRev,"virtual_lights"in e);Ic(t)!==Ic(this._virtualLights)&&(this._virtualLights=t,this._capturedSnapshotVirtual="")}let a=!1;if(void 0!==t||void 0!==i){const e=i??t?.layout??{},n=zl(e);a=n!==(this._layoutContentFingerprint||zl(this._layout)),a&&(this._layout=e,this._layoutContentFingerprint=n),this._layoutRev=t?.rev??this._layoutRev}return this._canOptimizeUndo=!(!e?.can_optimize_undo&&!t?.can_optimize_undo),this._haIntegrationVersion="string"==typeof e?.integration_version?e.integration_version:this._haIntegrationVersion,this._undoKind=e?.undo_kind||t?.undo_kind||null,"boolean"==typeof e?.can_write&&(this._serverCanWrite=e.can_write),s&&this._continuity.note("config-candidate",{configRev:this._cfgRev}),a&&this._continuity.note("layout-candidate",{layoutRev:this._layoutRev}),{configChanged:s,layoutChanged:a}}_resumePendingNavMode(){if(!this._pendingNavMode||!this._canEdit||this._config?.kiosk)return!1;const e=this._pendingNavMode;return this._pendingNavMode=null,this._setMode(e,!1),!0}async _loadFromServer(){this._loading=!0,this._loadTries++;const e=this._space,t=!!this._view;try{const[i,n]=await Promise.all([this.hass.callWS({type:"houseplan/config/get"}),this.hass.callWS({type:"houseplan/layout/get"})]),r=i?.config&&Array.isArray(i.config.spaces)?i.config:null,o=zl(r)!==(this._cfgContentFingerprint||zl(this._serverCfg))||zl(n?.layout??{})!==(this._layoutContentFingerprint||zl(this._layout));if(o){if(!await this._signer.prepareImage(this.hass,this._candidateBackdrop(r)))return this._continuity.note("asset-failed"),void this._scheduleLoadRetry(!0)}o&&this._continuity.hasCompleteFrame&&"steady"===this._continuity.state&&this._beginContinuityCandidate("structural-response",!0),this._connectionWasLost=!1,this._serverStorage=!0,"boolean"==typeof i?.can_write&&(this._serverCanWrite=i.can_write),this._canOptimizeUndo=!(!i?.can_optimize_undo&&!n?.can_optimize_undo),this._haIntegrationVersion="string"==typeof i?.integration_version?i.integration_version:this._haIntegrationVersion,this._adoptStructuralResponses(i,n),this._adoptInitialSpace(this._model,!0),this._resumePendingNavMode(),this._cacheSnapshot(),this._warmVpArmed&&this._space===this._warmVp?.space?this._warmVpArmed=!1:t&&this._space===e||this._restoreZoom(),this._loadOk=!0,this.hass.callWS({type:"houseplan/trail/get"}).then(e=>{this._vacSrvTrails=e?.trails||{},this.requestUpdate()}).catch(()=>{}),this._ensureLiveSyncSubscriptions()}catch(e){if(this._serverCfg)this._scheduleLoadRetry(!0);else if(this._loadTries>=8){this._serverStorage=!1;try{this._layout=JSON.parse(localStorage.getItem(ym)||"{}")||{}}catch{this._layout={}}}}finally{this._loading=!1,this._continuityDataReady=!0,this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}}_ensureLiveSyncSubscriptions(){const e=this.hass?.connection;if(!e)return;if(e!==this._liveSyncConnection&&(this._unsubCfg?.(),this._unsubCfg=null,this._unsubLayout?.(),this._unsubLayout=null,this._unsubTrail?.(),this._unsubTrail=void 0,this._unsubVirtual?.(),this._unsubVirtual=null,this._liveSyncGeneration++,this._liveSyncAttempt=null,this._liveSyncConnection=e),this._liveSyncAttempt)return;const t=this._liveSyncGeneration,i=[],n=(n,r,o,s)=>{n()||i.push(async()=>{const i=await e.subscribeEvents(s,o);t===this._liveSyncGeneration&&this.isConnected&&this.hass?.connection===e&&!n()?r(i):i?.()})};if(n(()=>this._unsubCfg,e=>{this._unsubCfg=e},"houseplan_config_updated",e=>{const t=Number(e?.data?.rev??-1);t!==this._cfgRev&&this._reloadConfigOnly(!1,t)}),n(()=>this._unsubTrail,e=>{this._unsubTrail=e},"houseplan_trail_updated",async()=>{try{const e=await this.hass.callWS({type:"houseplan/trail/get"});this._vacSrvTrails=e?.trails||{},this.requestUpdate()}catch{}}),n(()=>this._unsubLayout,e=>{this._unsubLayout=e},"houseplan_layout_updated",e=>this._onLayoutEvent(Number(e?.data?.rev??-1))),n(()=>this._unsubVirtual,e=>{this._unsubVirtual=e},"houseplan_virtual_light_updated",e=>{const t=Lc(this._virtualLights,e?.data);t!==this._virtualLights&&(this._virtualLights=t,this._capturedSnapshotVirtual="",this._cacheSnapshot(),this.requestUpdate())}),!i.length)return;const r=function(e){return Promise.allSettled(e.map(e=>Promise.resolve().then(e)))}(i).then(()=>{});this._liveSyncAttempt=r,r.finally(()=>{this._liveSyncAttempt===r&&(this._liveSyncAttempt=null)})}async _reloadConfigOnly(e=!1,t){if(!e){if(void 0!==t&&t<=this._cfgRev)return;if(this._saveConfigDebounced.pending()&&this._saveConfigDebounced.flush(),this._cfgWriting)return clearTimeout(this._reloadRetry),void(this._reloadRetry=window.setTimeout(()=>this._reloadConfigOnly(!1,t),400))}this._beginContinuityCandidate("config-reload",!1);try{const e=await this.hass.callWS({type:"houseplan/config/get"}),t=e?.config&&Array.isArray(e.config.spaces)?e.config:null;if(zl(t)!==(this._cfgContentFingerprint||zl(this._serverCfg))&&!await this._signer.prepareImage(this.hass,this._candidateBackdrop(t)))return this._continuity.note("asset-failed"),void this._scheduleLoadRetry(!0);const i=this._space;this._adoptStructuralResponses(e),this._adoptInitialSpace(this._model,!0),this._resumePendingNavMode(),this._cacheSnapshot(),this._space!==i&&this._restoreZoom(),this._regSignature="",this._maybeRebuildDevices(),this.requestUpdate()}catch(e){this._showToast(this._t("toast.cfg_reload_failed",{err:this._errText(e)}))}finally{this._continuityDataReady=!0,this.requestUpdate()}}_scheduleLoadRetry(e=!1){if(void 0!==this._loadRetryTimer)return;const t=Math.min(8e3,500*2**Math.min(4,Math.max(1,this._loadTries-7)));this._loadRetryTimer=window.setTimeout(()=>{this._loadRetryTimer=void 0,!e&&this._loadOk||this._loading||!this.hass||this._loadFromServer()},t)}_ensureHaRegistryAuthority(){const e=this.hass?.connection||null;e&&e!==this._haRegistryConnection&&(this._haRegistryRelease?.(),this._haRegistryConnection=e,this._haRegistryRev=-1,this._haBindingCacheKey="",this._planHassMemo=null,this._haRegistryRelease=Xc(this.hass,this._onHaRegistryUpdate),this._onHaRegistryUpdate())}get _haRegistry(){return Jc(this.hass)}get _planHass(){const e=this._haRegistry,t=eh(this.hass,e),i=this._planHassMemo;if(i&&i.hass===this.hass&&i.sig===t)return i.active;const n=ih(this.hass,e),r=nh(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+Pp)>e?1:0)).join("|"),i=Ic(this._virtualLights);if(this._capturedSnapshotSequence===this._hassSequence&&this._capturedSnapshotDevices===this._devices&&this._capturedSnapshotLayout===this._layout&&this._capturedSnapshotConfigEpoch===this._cfgEpoch&&this._capturedSnapshotVirtual===i&&this._capturedSnapshotActivity===t)return;const n=this._planHass,r=new Map,o=new Map,s=new Set(["sun.sun"]);this._vacFit?.source&&s.add(this._vacFit.source);const a=new Set,l=new Set,c=e=>{if(!e)return;const t=e.indexOf(":");if(t<0)return void s.add(e);const i=e.slice(0,t),n=e.slice(t+1);"device"===i?a.add(n):"entity"===i&&s.add(n)};for(const e of this._model)for(const t of e.rooms)t.area&&l.add(t.area),c(t.settings?.temp_source),c(t.settings?.hum_source);for(const e of this._serverCfg?.spaces||[])for(const t of e.openings||[])for(const e of ri(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=Li(e[1]);t?.entity&&s.add(t.entity)}t.entity&&s.add(t.entity),o.set(`decor:${e.id}:${t.id}`,Vi(t.text,t,n,e=>!!n.entities?.[e]&&!!n.states?.[e]&&!Uh(n,e,Vh(this._markers))))}const h=zh(n,this._devices,null,this._virtualLights);for(const e of this._devices){for(const t of[!1,!0])r.set(Xu(e.id,t),Gu(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?Kl(n?.states?.[t]?.attributes):null,r=this._vacRt.get(e.id);o.set(`vacuum:${e.id}`,{source:t,telemetry:i,mapId:i?this._vacMapId(e,i,n):null,runtime:r?{trail:r.trail,lastTs:r.lastTs,moving:r.moving,jump:r.jump}:null,server:this._vacSrvTrails[e.id]||null})}}const d=Zu({sourceSequence:this._hassSequence,hass:n,devices:this._devices,presentations:r,positions:(u=this._model.length>0,p=this._devices,_=e=>this._livePos(e),u?new Map(p.map(e=>[e.id,_(e)])):new Map),facts:o,entityIds:s,deviceIds:a,areaIds:l});var u,p,_;this._capturedSnapshotSequence=this._hassSequence,this._capturedSnapshotDevices=this._devices,this._capturedSnapshotLayout=this._layout,this._capturedSnapshotActivity=t,this._capturedSnapshotConfigEpoch=this._cfgEpoch,this._capturedSnapshotVirtual=i,this._visibleDeviceSnapshot&&"steady"!==this._continuity.state?this._candidateDeviceSnapshot=d:(this._visibleDeviceSnapshot=d,this._candidateDeviceSnapshot=null)}get _renderDeviceSnapshot(){return this._stagedDeviceSnapshotToken===this._continuity.token?this._candidateDeviceSnapshot||this._visibleDeviceSnapshot:this._visibleDeviceSnapshot||this._candidateDeviceSnapshot}get _renderPlanHass(){return this._renderDeviceSnapshot?.hass||this._planHass}get _renderDevices(){return this._renderDeviceSnapshot?.devices||this._devices}get _fullRegistryHass(){return this._planHass,this._planHassMemo?.full||this.hass}_bindingStatus(e){return sh(this.hass,e,this._haRegistry)}houseplanDiagnostics(){const e=function(e){const t=Jc(e);return{access:t.access,authoritative:t.authoritative,revision:t.revision,lastSuccess:t.lastSuccess,error:t.error}}(this.hass),t={active:0,ha_disabled:0,orphaned:0,unverified:0};for(const e of this._markers)e.removed||"virtual"===e.binding||t[this._bindingStatus(e.binding).kind]++;return{registry:{...e,lastSuccessAgeMs:e.lastSuccess?Math.max(0,Date.now()-e.lastSuccess):null},bindings:t}}_openBindingInHa(e){const[t,i]=e.split(":");if(i)if("device"!==t){if("entity"===t){const e=this._fullRegistryHass.entities?.[i];e?.device_id&&zm("/config/devices/device/"+encodeURIComponent(e.device_id))}}else zm("/config/devices/device/"+encodeURIComponent(i))}_bindingHasHaPage(e){const[t,i]=e.split(":");return!!i&&("device"===t||"entity"===t&&!!this._fullRegistryHass.entities?.[i]?.device_id)}_toggleMarkerDialogVisibility(){const e=this._markerDialog;if(!e)return;const t="ha"===e.bindingMode?this._bindingStatus(e.binding):null,i=e.hideFromPlan||"ha_disabled"===t?.kind;i&&"ha_disabled"===t?.kind?this._showToast(this._t("entity"===t.reason?"toast.ha_disabled_show_entity":"toast.ha_disabled_show_device")):i&&"unverified"===t?.kind?this._showToast(this._t("toast.ha_binding_unverified")):this._markerDialog={...e,hideFromPlan:!i}}_hookConnection(){const e=this.hass?.connection;e&&e!==this._connHooked&&(this._connHooked?.removeEventListener?.("ready",this._onConnReady),this._connHooked?.removeEventListener?.("disconnected",this._onConnLost),this._connHooked?.removeEventListener?.("reconnect-error",this._onConnLost),e.addEventListener?.("ready",this._onConnReady),e.addEventListener?.("disconnected",this._onConnLost),e.addEventListener?.("reconnect-error",this._onConnLost),this._connHooked=e)}_display(e){return this._signer.display(this.hass,e)}_resign(){this._signer.resign(this.hass,Mn(this._serverCfg))}_onLayoutEvent(e){e<=this._layoutRev||(clearTimeout(this._layoutSyncTimer),this._layoutSyncTimer=window.setTimeout(()=>{e<=this._layoutRev||this._reloadLayoutOnly()},200))}_noteLayoutRev(e){const t=e?.rev;"number"==typeof t&&t>this._layoutRev&&(this._layoutRev=t)}async _reloadLayoutOnly(){if(!this._serverStorage||!this.hass?.callWS)return;this._beginContinuityCandidate("layout-reload",!1);const e=new Map;for(const t of this._dirtyPos)this._layout[t]&&e.set(t,this._layout[t]);this._persistLayout.pending()&&this._persistLayout.flush();for(const[t,i]of this._sentPos)e.set(t,i);try{const t=await this.hass.callWS({type:"houseplan/layout/get"}),i={...t?.layout||{}};for(const[t,n]of e)i[t]=n;const n=zl(i);n!==(this._layoutContentFingerprint||zl(this._layout))&&(this._layout=i,this._layoutContentFingerprint=n),this._layoutRev=t?.rev??this._layoutRev,this._canOptimizeUndo=!!t?.can_optimize_undo,this._haIntegrationVersion="string"==typeof t?.integration_version?t.integration_version:this._haIntegrationVersion,this._undoKind=t?.undo_kind||null,this._cacheSnapshot(),this.requestUpdate()}catch{}finally{this._continuityDataReady=!0,this.requestUpdate()}}_maybeRebuildDevices(){const e=this.hass;if(!e?.devices||!e?.entities||!e?.areas)return;const t=this._haRegistry,i=eh(e,t)+":"+Object.keys(e.areas).length+":"+(this._norm?"n":"l")+":"+hu(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=Yh({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,sh(e,n,t));!function(e){if("undefined"==typeof localStorage||!e.size)return;const t=oh(),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));Vc=n;try{localStorage.setItem(Bc,JSON.stringify(n))}catch{}}(i),this._haBindingCacheKey=o}this._defPos=this._defaultPositions(),this._syncNewDevices(),this._seedHiddenDevices(),this._syncActivityRuntime();const s=new Set(this._devices.filter(e=>!e.hidden).map(e=>e.id));for(const e of this._vacRt.keys())s.has(e)||this._vacRt.delete(e);if(this._infoCard){const e=this._devices.find(e=>e.id===this._infoCard.id);this._infoCard=e&&"ha_disabled"!==e.bindingStatus?.kind?e:null}const a=this._devices.some(e=>"ha_disabled"===e.bindingStatus?.kind&&"ha_disabled"!==n.get(e.id));a&&("ha_disabled"!==this._infoCard?.bindingStatus?.kind&&"ha_disabled"!==this._devices.find(e=>e.id===this._infoCard?.id)?.bindingStatus?.kind||this._closeInfoCard(),this._drag&&"ha_disabled"===this._devices.find(e=>e.id===this._drag.id)?.bindingStatus?.kind&&(this._drag=null),clearTimeout(this._holdTimer),this._holdFired=!1,this._tip=null,this._tapConfirm=null),this._nativeMoreInfoEntity&&!this._planEntityAvailable(this._nativeMoreInfoEntity)&&(Dm(this,"hass-more-info",{entityId:null}),this._nativeMoreInfoEntity=null)}_syncNewDevices(){if(!this._norm||!this._loadOk||!this._serverCfg)return;const e=this._devices.filter(e=>!e.marker&&!e.virtual).map(e=>e.id).sort(),t=e.join(",");if(t===this._newSyncKey)return;this._newSyncKey=t;const i=this._settings,{fresh:n,known:r}=function(e,t){if(!Array.isArray(t))return{fresh:[],known:[...e]};const i=new Set(t),n=e.filter(e=>!i.has(e));return{fresh:n,known:n.length?[...t,...n]:t}}(e,i.known_devices);if(!Array.isArray(i.known_devices)||n.length){const e=[...new Set([...i.new_device_ids||[],...n])];this._serverCfg={...this._serverCfg,settings:{...i,known_devices:r,new_device_ids:e}},this._saveConfig()}}get _newIds(){const e=this._settings.new_device_ids;return new Set(Array.isArray(e)?e:[])}_ackNewDevice(e){if(!this._newIds.has(e)||!this._serverCfg)return;const t=this._settings;this._serverCfg={...this._serverCfg,settings:{...t,new_device_ids:(t.new_device_ids||[]).filter(t=>t!==e)}},this._saveConfig(),this.requestUpdate()}get _markers(){return this._serverCfg?.markers||[]}_roomLqi(e){if(!e)return null;const t=[];for(const i of this._renderDevices){if(i.area!==e||i.virtual)continue;const n=Ph(this._renderPlanHass,i.entities);null!=n&&t.push(n)}return Ri(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*il(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)}));Ci(p,o,n,.5*s),r.forEach((t,i)=>e[t.id]=Wa(p[i]))}}return e}_pos(e){const t=this._renderDeviceSnapshot?.positions.get(e.id);return t?{x:t.x,y:t.y}:this._livePos(e)}_livePos(e){const t=this._spaceModelById(e.space),i=this._layout[e.id];if(i)if(this._norm){if(i.s===e.space)return{x:i.x*Mm,y:i.y*Mm}}else if(void 0===i.s)return{x:i.x,y:i.y};return this._defPos[e.id]?this._defPos[e.id]:t?Wa(tl(t)):{x:500,y:500}}_savePos(e,t,i){if(this._spaceModelById(e.space)){if(this._norm){const n=this._gridPitch,r=Math.round(t/n)*n,o=Math.round(i/n)*n,s=this._layout[e.id]?.k;this._layout={...this._layout,[e.id]:{s:e.space,x:Ba(r/Mm),y:Ba(o/Mm),...s?{k:s}:{}}}}else this._layout={...this._layout,[e.id]:{x:Math.round(t),y:Math.round(i)}};this._dirtyPos.add(e.id),this._persistLayout()}}_visualSamples(e){return Wu(this._renderPlanHass,e,this._renderDevices,void 0,this._fullRegistryHass).samples}_devicePresentation(e,t=!1!==this._config?.show_signal,i=!1){const n=i?null:this._renderDeviceSnapshot?.presentations.get(Xu(e.id,t));return n||Gu(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,Uu({...i,visual:t}).join(" "))}_liveTemp(e){if(!this._config?.show_temperature)return null;if(!0===e.marker?.use_climate_temp){const t=Eh(this._renderPlanHass,e.entities);if(null!=t)return t}return"mdi:thermometer"!==e.icon&&"mdi:air-filter"!==e.icon?null:Fh(this._renderPlanHass,e.entities)}_bindingEntities(e){if("virtual"===e||!e)return[];const t=this._bindingStatus(e);return"active"===t.kind?t.enabledEntityIds:t.allEntityIds}_bindingHasClimate(e){return this._bindingEntities(e).some(e=>e.startsWith("climate."))}_bindingHasAlarm(e){return this._bindingEntities(e).some(e=>{const t=this._planHass?.states?.[e]||this.hass?.states?.[e],i=this._fullRegistryHass.entities[e]||this.hass?.entities?.[e];return In(e.split(".")[0],t?.attributes?.device_class||i?.device_class||i?.original_device_class)})}_liveHum(e){return this._config?.show_temperature&&e.primary&&Ih(this.hass,e.primary)?Hh(this.hass,e.entities):null}_deviceBindingActive(e,t=!0){if(e.virtual||"virtual"===e.bindingKind)return!0;if(!e.bindingKind||!e.bindingRef)return!1;const i=this._bindingStatus(`${e.bindingKind}:${e.bindingRef}`);return"active"===i.kind||(t&&this._showToast(this._t("ha_disabled"===i.kind?"toast.ha_disabled_action":"toast.ha_binding_unverified")),!1)}_openMoreInfo(e){e?this._planEntityAvailable(e)?(this._nativeMoreInfoEntity=e,Dm(this,"hass-more-info",{entityId:e})):this._showToast(this._t("toast.ha_disabled_action")):this._showToast(this._t("toast.no_entity"))}_interruptViewGesture(e,t){if(clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),void 0!==e)for(const i of[t,this._stageEl])try{i?.hasPointerCapture?.(e)&&i.releasePointerCapture(e)}catch{}this._pointers.clear(),this._panStart=null,this._panLock=null,this._pinchStart=null,this._swipeStart=null}_closeInfoCard(){this._interruptViewGesture(),this._holdFired=!1,this._infoCard=null}_ctxDevice(e,t){"view"===this._mode&&(e.preventDefault(),e.stopPropagation(),this._deviceBindingActive(t)&&(t.primary?this._openMoreInfo(t.primary):this._infoCard=t))}_clickDevice(e,t){if(e.stopPropagation(),this._drag?.moved||this._suppressClick||this._holdFired)return;if("plan"===this._mode)return;if("devices"===this._mode)return void this._openMarkerDialog(t);const i=this._devices.find(e=>e.id===t.id);if(!i)return;const n=wd(i.tapAction,i.primary?.split(".")[0]),r=(e,t)=>{i.marker?.tap_confirm?this._tapConfirm={kind:"run",text:e,exec:t}:t()};if("toggle"===n){const e=this._toggleIntent(i);if(!e)return;if(!Rd(e))return void this._showUnavailableToggleTargets(e);const t=e=>{const t=Rd(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=Lc(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&&!Rd(r)&&this._showUnavailableToggleTargets(r)||(r&&Cd(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||Rd(e)||"configured-targets-missing"!==e.noneReason)return[];if(!e.skippedTargets.length||e.skippedTargets.some(e=>!Td.has(e.reason)&&"secure"!==e.reason))return[];const t=[],i=new Set;for(const n of e.skippedTargets){if(!Td.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 du(hu(this.hass,this._config?.language),e,t)}get _colorPickerLabels(){return{title:this._t("color_picker.title"),hue:this._t("color_picker.hue"),saturation:this._t("color_picker.saturation"),value:this._t("color_picker.value"),hex:this._t("color_picker.hex"),invalidHex:this._t("color_picker.invalid_hex")}}_help(e){return this._editorRuntimeOrThrow()._help(e)}get _stageEl(){return this.renderRoot.querySelector(".stage")}_contentItems(e){const t=[];for(const i of this._devices){if(i.space!==e.id||i.hidden)continue;const n=this._pos(i);t.push({minX:n.x,minY:n.y,maxX:n.x,maxY:n.y})}if(e.id===this._space){for(const e of this._openingsR){const i=Number(e.angle)*Math.PI/180,n=Math.cos(i)*e.rlen/2,r=Math.sin(i)*e.rlen/2,o=Ga([[e.rx-n,e.ry-r],[e.rx+n,e.ry+r]]);o&&t.push(o)}const i=this._decorH;for(const e of this._decorList){const n=Ga("line"===e.kind?[[e.x1*Mm,e.y1*i],[e.x2*Mm,e.y2*i]]:"text"===e.kind?[[e.x*Mm,e.y*i]]:kr({x:e.x*Mm,y:e.y*i,w:e.w*Mm,h:e.h*i,angle:e.angle}));n&&t.push(n)}for(const i of this._physicalBodiesR(e)){const e=Ga(i);e&&t.push(e)}}return Ya(e,t)}_frameOf(){const e=this._spaceModel();if(!e){this._frame=null;const e={x:0,y:0,w:Mm,h:Mm};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=Qa(this._contentItems(e));let r=n.all||el(e),o=this._showFar?r:n.core||el(e);return t&&t.id===e.id&&i&&t.grow&&(o=Tm(t.rect,o),r=Tm(t.all,r)),this._frame={id:e.id,model:e,layout:this._layout,devs:this._devices,far:this._showFar,grow:i,rect:o,all:r,outliers:n.outliers},this._frame}_isoSource(){const e=this._spaceModel();if(!e)return null;const t=this._spaceWalls,i=this._openCuts(),n=this._openingsR.map((e,t)=>({id:String(e.id||t),sourceIndex:t,type:e.type,x:e.rx,y:e.ry,angle:Number(e.angle)||0,length:e.rlen>0?e.rlen:900,flipH:!!e.flip_h,flipV:!!e.flip_v})),r=Sa(64,this._cellCm),o=Sa(10,this._cellCm),s=`${e.id}|${function(e){let t=2166136261;const i=e=>{if("number"!=typeof e)if("string"!=typeof e)if("boolean"!=typeof e)if(Array.isArray(e)){t=G_(t,e.length);for(const t of e)i(t)}else{if(e&&"object"==typeof e){const t=e;for(const e of Object.keys(t).sort())i(e),i(t[e]);return}t=G_(t,-1)}else t=G_(t,e?1:0);else for(const i of e)t=G_(t,i.codePointAt(0)||0);else t=G_(t,e)};return i(e),t.toString(36)}({rooms:e.rooms,walls:t,openCuts:i,openings:n,partitions:e.partitions,roomDrafts:e.room_drafts,columns:e.wall_columns,cellCm:this._cellCm,gridPitch:this._gridPitch,wallKeyPitch:this._wallKeyPitch,camera:F_,wallHeight:r,floorEdgeHeight:o,algorithm:3})}`;return{key:s,build:()=>{const o=da(e,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(e)).all,s=this._roomWallOpeningInputs(this._openingsR,e),a=t.length||o.length?Ns(e.rooms,t,i,s,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm,o):null;if(a&&("failed-core"===a.status||"not-applicable"===a.status))throw new Error("wall boolean geometry failed");const l=a?.paperGeom??Fs(e.rooms,t,i,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm);if(!l)throw new Error("floor boolean geometry failed");const c=a?.openingIndex||Bs(e.rooms,t,i,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm),h=n.map(e=>{const i=this._openingsR[e.sourceIndex],n="gate"===e.type?!e.flipV:e.flipV,o=i?.partitionHost?Hd(i.partitionHost,n):t.length||"gate"===e.type?Ks(c,{x:e.x,y:e.y,angle:e.angle,length:e.length,flip_v:n}):{ox:0,oy:0,cm:0,side:-1};return function(e,t=64){if(!(K_([e.x,e.y,e.angle,e.length,e.face.ox,e.face.oy,t])&&e.length>0&&t>0))throw new Error("invalid isometric opening input");const i=e.length/2;let n;if("passage"===e.type)n=[];else if("gate"===e.type){const r=10*e.face.side;n=[Z_(e,0,[-i,0],[i,0],r,0,.88*t),Z_(e,1,[i,0],[-i,0],-r,0,.88*t)]}else n="window"===e.type?[Z_(e,0,[-i,0],[i,0],-90,.27*t,.78*t),Z_(e,1,[i,0],[-i,0],90,.27*t,.78*t)]:[Z_(e,0,[-i,0],[e.length,0],-90,0,.92*t)];return{id:e.id,sourceIndex:e.sourceIndex,type:e.type,leaves:Object.freeze(n.map(e=>Object.freeze(e)))}}({...e,face:o},r)});return{walls:a?.components.flatMap(e=>e.geom)||[],floor:l,openings:Object.freeze(h)}}}}_isoSceneKey(){if(!this._labsIso||"view"!==this._mode)return null;try{return this._isoSource()?.key??null}catch{return`${this._space}|invalid`}}_isoScene(){const e=this._isoSource();if(!e)return null;const t=this._isoGeometryCache.get(e.key);if(t)return{key:e.key,...t};const i=this._frameOf().rect,n=e.build(),r=Sa(64,this._cellCm),o=Sa(10,this._cellCm),s=function(e){let t=1/0,i=1/0,n=-1/0,r=-1/0;for(const o of e)for(const e of o.leaves){const o=Math.hypot(e.closedVector[0],e.closedVector[1]);t=Math.min(t,e.hinge[0]-o),i=Math.min(i,e.hinge[1]-o),n=Math.max(n,e.hinge[0]+o),r=Math.max(r,e.hinge[1]+o)}return K_([t,i,n,r])?{x:t,y:i,w:n-t,h:r-i}:null}(n.openings),a=L_({rect:s?Tm(i,s):i,wallHeight:r,openingHeight:r,floorDepth:o}),l=function(e,t=F_,i=64){if(!Number.isFinite(i)||i<0)throw new Error("invalid wall height");const n=[],r=[],o=[];let s=0;for(let a=0;a<(e||[]).length;a++){const l=e[a];for(let e=0;e<(l||[]).length;e++){const c=j_(l[e],e>0);if(!(c.length<3||Math.abs(W_(c))<1e-9)){n.push(B_(c,t,i)),s+=c.length;for(let n=0;ne.depth-t.depth||e.polygon-t.polygon||e.ring-t.ring||e.edge-t.edge),{topPath:n.join(" "),sides:r,contactPath:o.join(" "),edgeCount:s}}(n.walls,F_,r),c={geometry:l,floor:U_(n.floor,o),openings:n.openings,frame:a};return _m(this._isoGeometryCache,e.key,c,8),{key:e.key,...c}}_effectiveProjection(){if("iso"!==this._desiredProjection||!this._model.length)return"flat";const e=this._isoSceneKey()||`${this._space}|invalid`;if(this._isoFallback.has(e))return"flat";try{const e=this._isoScene();return e?(t="iso",i=e.key,n=this._isoFallback,"iso"===t&&i&&!n.has(i)?"iso":"flat"):"flat"}catch(t){if(!this._isoFallback.has(e)){this._isoFallback.add(e);const i=e.split("|");console.warn(`HOUSEPLAN ISO FALLBACK: #89, space ${this._space}, fingerprint ${i[i.length-1]}, ${t instanceof Error?t.message:"renderer error"}`)}return"flat"}var t,i,n}_scenePoint(e){return"iso"===this._renderProjection?I_(e,0):e}_floorView(e){if("iso"!==this._renderProjection)return e;const t=H_([e.x,e.y]),i=H_([e.x+e.w,e.y+e.h]);return{x:t[0],y:t[1],w:i[0]-t[0],h:i[1]-t[1]}}_baseVb(){if("iso"===this._effectiveProjection()){if(!this._spaceDisplayForRender().showBorders){const e=L_({rect:this._frameOf().rect,wallHeight:Sa(64,this._cellCm)});return[e.x,e.y,e.w,e.h]}const e=this._isoScene()?.frame??this._frameOf().rect;return[e.x,e.y,e.w,e.h]}const e=this._frameOf().rect;return[e.x,e.y,e.w,e.h]}get _outliers(){return this._showFar?0:this._frameOf().outliers}_fitFar(){this._showFar=!0,this._frame=null,this._resetZoom()}_fitAll(){this._showFar=!0,this._frame=null,this._resetZoom()}_renderFarHint(){return this._kiosk||"view"!==this._mode||this._booting||!this._outliers?U:j`
+ + ${this._t("canvas.far_objects",{n:this._outliers})} + +
`}_renderHomeArrow(){if(this._booting)return U;const e=this._view;if(!e||!e.w||!e.h)return U;const t=this._baseVb(),i=t[0],n=t[1],r=t[2],o=t[3];if(!(i+r<=e.x||i>=e.x+e.w||n+o<=e.y||n>=e.y+e.h))return U;const s=Math.atan2(n+o/2-(e.y+e.h/2),i+r/2-(e.x+e.w/2)),a=50+38*Math.cos(s),l=50+38*Math.sin(s);return j``}_stageAspect(){const e=this._stageEl,t=this._baseVb();return e&&e.clientHeight?e.clientWidth/e.clientHeight:t[2]/t[3]}_viewOr(e){return this._view&&this._view.w?this._view:Ti(e,this._stageAspect())}_roomLabelReferenceViewWidth(e){if(!this._markup)return e.w;const t=this._stageEl,i=this.renderRoot.querySelector(".editorchrome");if(!t||t.clientWidth<=0||t.clientHeight<=0)return e.w;const n=t.clientHeight+(i?.getBoundingClientRect().height||0);return n<=0?e.w:this._viewForModeTarget(this._zoom,void 0,void 0,t.clientWidth,n).w}_screenToVb(e,t){const i=this._stageEl,n=this._viewOr(this._baseVb()),r=i?.clientWidth||1,o=i?.clientHeight||1;return[n.x+e/r*n.w,n.y+t/o*n.h]}_clampView(e,t){const i=(e,t,i,n)=>{const r=1*Math.max(t,n),o=i-r,s=i+n-t+r;return Math.max(Math.min(o,s),Math.min(Math.max(o,s),e))};return{w:e.w,h:e.h,x:i(e.x,e.w,t.x,t.w),y:i(e.y,e.h,t.y,t.h)}}_applyView(e,t,i){const n=this._baseVb(),r=Ti(n,this._stageAspect()),o=Math.min(Pm.ZOOM_MAX,Math.max(Pm.ZOOM_MIN,e)),s=r.w/o,a=r.h/o,l=this._viewOr(n),c=t??l.x+l.w/2,h=i??l.y+l.h/2,d=this._clampView({x:c-s/2,y:h-a/2,w:s,h:a},r);return!(this._view&&Math.abs(this._zoom-o)<1e-9&&Math.abs(this._view.x-d.x)<1e-6&&Math.abs(this._view.y-d.y)<1e-6&&Math.abs(this._view.w-d.w)<1e-6&&Math.abs(this._view.h-d.h)<1e-6)&&("opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1)),this._zoom=o,this._view=d,!0)}_bootWatch(){clearTimeout(this._bootTimer),this._bootStart=Date.now(),this._bootLastH=-1,this._bootLastChange=this._bootStart;const e=()=>{if(!this._booting)return;const t=Date.now(),i=this._stageEl?this._stageEl.clientHeight:0;i!==this._bootLastH&&(this._bootLastH=i,this._bootLastChange=t);const n=t-this._bootStart;n>=1200||n>=700&&i>0&&t-this._bootLastChange>=250?this._bootSettled():this._bootTimer=window.setTimeout(e,100)};this._bootTimer=window.setTimeout(e,100)}_bootSettled(){this._booting&&!this._bootSettling&&(this._bootSettling=!0,this._refitView(),this._bootSettleRaf=requestAnimationFrame(()=>{this._bootSettleRaf=0,this._finishBootSettled()}))}_finishBootSettled(){if(!this._booting)return;this._refitView(),this._booting=!1,this._bootSettling=!1;const e=this._stageEl?.clientHeight??0;!this._config?.kiosk&&e>0&&this._warmPatch({hdrH:this._hdrH,stageH:e,vp:this._warmViewportState()},!0),this._bootFading=!0,this._bootTimer=window.setTimeout(()=>{this._bootFading=!1},220),this._bootSoft=!0,clearTimeout(this._bootSoftTimer),this._bootSoftTimer=window.setTimeout(()=>{this._bootSoft=!1},um)}_bootSoftCancel(){this._bootSoft&&(clearTimeout(this._bootSoftTimer),this._bootSoft=!1)}_beginResumeSettle(){this._booting||this._resumeSettling||(this._modeTransitionPreparing?this._modeTransitionForceAtomic=!0:this._cancelModeTransition(!0),this._viewportInvalidAt=0,this._beginContinuityCandidate("warm-resume",!1),this._loading?this.requestUpdate():this._loadFromServer())}_refitView(){if(this._modeTransitionBusy||this._warmModeRequest)return;const e=this._stageEl;if(!e||"visible"!==document.visibilityState||e.clientWidth<=0||e.clientHeight<=0)return void(this._viewportInvalidAt||(this._viewportInvalidAt=Date.now()));const t=[e.clientWidth,e.clientHeight],i=this._lastValidStageSize,n=!!i&&Math.abs(i[0]-t[0])<=.5&&Math.abs(i[1]-t[1])<=.5,r=this._viewportInvalidAt?Date.now()-this._viewportInvalidAt:0;if(this._viewportInvalidAt=0,!i)return this._lastValidStageSize=t,void(this._view||this._applyView(this._zoom));n?this._pendingRefitSize=null:(this._pendingRefitSize=t,this._refitRaf||(this._refitRaf=requestAnimationFrame(()=>{this._refitRaf=0;const e=this._pendingRefitSize;this._pendingRefitSize=null;const t=this._stageEl;if(!e||!t||t.clientWidth<=0||t.clientHeight<=0)return;if(Math.abs(t.clientWidth-e[0])>.5||Math.abs(t.clientHeight-e[1])>.5)return void this._refitView();const i=this._lastValidStageSize;if(i&&Math.abs(i[0]-e[0])<=.5&&Math.abs(i[1]-e[1])<=.5)return;this._lastValidStageSize=e;const n=this._view;r>=Sl?this._beginContinuityCandidate("stage-size-restored",!0,"stage-size"):this._continuity.hasCompleteFrame&&this._beginContinuityCandidate("stage-resize",!0,"stage-size"),this._applyView(this._zoom,n?n.x+n.w/2:void 0,n?n.y+n.h/2:void 0)})))}_zoomAt(e,t,i){const n=this._stageEl;if(!n)return;const r=Ti(this._baseVb(),this._stageAspect()),o=Math.min(Pm.ZOOM_MAX,Math.max(Pm.ZOOM_MIN,i));"opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1));const s=n.clientWidth,a=n.clientHeight,l=this._screenToVb(e,t),c=r.w/o,h=r.h/o;this._zoom=o,this._view=this._clampView({x:l[0]-e/s*c,y:l[1]-t/a*h,w:c,h:h},r)}_onWheel(e){const t=this._stageEl;if(!t)return;e.preventDefault();const i=t.getBoundingClientRect(),n=e.deltaY<0?1.15:1/1.15;this._zoomAt(e.clientX-i.left,e.clientY-i.top,this._zoom*n),this._saveZoom()}_stepZoom(e){const t=this._stageEl;t&&(this._zoomAt(t.clientWidth/2,t.clientHeight/2,this._zoom*(e>0?1.4:1/1.4)),this._saveZoom())}_resetZoom(){const e=this._baseVb();"opening"===this._tool&&(this._cursorPt=null,this._clearOpeningPlacement(!1)),this._zoom=1,this._view=Ti(e,this._stageAspect()),this._saveZoom()}_saveZoom(){if("view"===this._mode){this._zoomBySpace={...this._zoomBySpace,[this._space]:this._zoom};try{localStorage.setItem(wm,JSON.stringify(this._zoomBySpace))}catch{}}}_restoreZoom(){const e=this._zoomBySpace[this._space]||1;this._zoom=e;const t=this._stageEl;if(t&&t.clientHeight){const t=this._baseVb();return this._applyView(e,t[0]+t[2]/2,t[1]+t[3]/2),void this.requestUpdate()}this._view=null,requestAnimationFrame(()=>{if(!this._stageEl)return;const t=this._baseVb();this._applyView(e,t[0]+t[2]/2,t[1]+t[3]/2),this.requestUpdate()})}_stagePointerDown(e){if(this._vacFit)return;if(this._kiosk&&(this._cyclePausedUntil=Date.now()+6e4,0===this._pointers.size?(this._swipeStart={x:e.clientX,y:e.clientY,id:e.pointerId},e.target.closest?.(".dev, .roomlabel, .oplock")||(clearTimeout(this._kioskHoldTimer),this._kioskHoldTimer=window.setTimeout(()=>{this._kioskDialog=!0,this._swipeStart=null},3e3))):(this._swipeStart=null,clearTimeout(this._kioskHoldTimer))),this._drag)return;if(this._markup&&e.target.closest?.(".roomlabel, .rlhandle, .rszhandle, .dev, .oplock, .op-hit, button"))return;if("devices"===this._mode&&e.target.closest(".dev"))return;if("decor"===this._mode&&this._decorPointerDown(e))return;this._pointers.set(e.pointerId,{x:e.clientX,y:e.clientY});const t=this._viewOr(this._baseVb());if(1===this._pointers.size)this._panStart={sx:e.clientX,sy:e.clientY,vx:t.x,vy:t.y},this._panLock=null,this._suppressClick=!1;else if(2===this._pointers.size){"opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover();const e=[...this._pointers.values()],t=Math.hypot(e[0].x-e[1].x,e[0].y-e[1].y);this._pinchStart={dist:t,zoom:this._zoom},this._panStart=null,this._panLock=null}}get _swipeZone(){return!this._hasFixedFloor&&this._kiosk&&this._zoom<=1.001&&this._model.length>1}_stagePointerMove(e){if(this._physicalRotate?.pid!==e.pointerId)if(this._physicalDrag?.pid!==e.pointerId)if(this._dtDrag?.pid!==e.pointerId)if(this._bdDrag?.pid!==e.pointerId){if(this._decorDraft?.pid===e.pointerId){const t=this._decorDraft;let i=this._decorSnap(this._svgPoint(e),e.pointerType);if(e.shiftKey&&("rect"===t.kind||"ellipse"===t.kind)){const e=i[0]-t.a[0],n=i[1]-t.a[1],r=Math.max(Math.abs(e),Math.abs(n));i=this._snap([t.a[0]+(e<0?-r:r),t.a[1]+(n<0?-r:r)])}return void(this._decorDraft={...t,b:i})}if(this._decorMove?.pid!==e.pointerId)if(this._pointers.has(e.pointerId)){if(this._pointers.set(e.pointerId,{x:e.clientX,y:e.clientY}),this._markup&&1===this._pointers.size&&this._markupMove(e),this._pinchStart&&this._pointers.size>=2){"opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover();const e=[...this._pointers.values()],t=Math.hypot(e[0].x-e[1].x,e[0].y-e[1].y)/(this._pinchStart.dist||1),i=this._stageEl.getBoundingClientRect(),n=(e[0].x+e[1].x)/2-i.left,r=(e[0].y+e[1].y)/2-i.top;this._zoomAt(n,r,this._pinchStart.zoom*t),this._suppressClick=!0,this._saveZoom()}else if(this._panStart){const t=e.clientX-this._panStart.sx,i=e.clientY-this._panStart.sy;Math.abs(t)+Math.abs(i)>4&&(this._suppressClick=!0,clearTimeout(this._holdTimer),"opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover()),null===this._panLock&&Math.abs(t)+Math.abs(i)>8&&(this._panLock=this._swipeZone&&Math.abs(t)>1.5*Math.abs(i)?"swipe":"pan");const n=this._stageEl;if("pan"===this._panLock&&n){const e=this._baseVb(),r=this._viewOr(e),o=Ti(e,this._stageAspect());this._view=this._clampView({x:this._panStart.vx-t/(n.clientWidth||1)*r.w,y:this._panStart.vy-i/(n.clientHeight||1)*r.h,w:r.w,h:r.h},o)}}}else this._markupMove(e);else this._decorMoveUpdate(e)}else this._bdMove(e);else this._dtMove(e);else this._physicalMove(e);else this._physicalRotateMove(e)}_stagePointerLeave(e){this._markup&&("opening"===this._tool?(this._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this._tool&&this._clearPlanSnapHover())}_stagePointerUp(e){if(this._kiosk){clearTimeout(this._kioskHoldTimer);const t=this._swipeStart;if(this._swipeStart=null,t&&t.id===e.pointerId){const i=e.clientX-t.x,n=e.clientY-t.y;if(Math.abs(i)+Math.abs(n)<8){const e=Date.now();e-this._lastTap<350&&this._resetZoom(),this._lastTap=e}const r="pan"===this._panLock?null:function(e,t,i,n,r,o=60){if(i>1.001||n.length<2)return null;if(Math.abs(e)e.id),this._space);r&&this._slideTo(r,i<0?"left":"right")&&(this._saveNav(),this._suppressClick=!0,setTimeout(()=>this._suppressClick=!1,0),this._showKioskDots())}}if(this._physicalDrag?.pid===e.pointerId)return void this._physicalUp(e);if(this._physicalRotate?.pid===e.pointerId)return void this._physicalRotateUp(e);if(this._dtDrag?.pid===e.pointerId)return void this._dtUp();if(this._bdDrag?.pid===e.pointerId)return void this._bdUp();if(this._decorDraft?.pid===e.pointerId)return void this._decorCommitDraft();if(this._decorMove?.pid===e.pointerId)return this._decorMove.moved&&(this._recordGeometry(this._t("history.decor_move"),this._decorMove.before),this._saveConfig()),void(this._decorMove=null);const t=!!this._pinchStart||!!this._panStart;this._pointers.delete(e.pointerId),this._pointers.size<2&&(this._pinchStart=null),0===this._pointers.size&&(this._panStart=null,this._panLock=null,setTimeout(()=>this._suppressClick=!1,0)),t&&0===this._pointers.size&&this.requestUpdate()}_clickRoom(e){!this._suppressClick&&e.area&&zm("/config/areas/area/"+e.area)}_pointerDown(e,t){if("plan"===this._mode)return;if("view"===this._mode){this._holdFired=!1,clearTimeout(this._holdTimer);const i=e.pointerId,n=e.currentTarget;return void(this._holdTimer=window.setTimeout(()=>{this._holdFired=!0,this._interruptViewGesture(i,n),this._infoCard=t},600))}if("ha_disabled"===t.bindingStatus?.kind)return;e.preventDefault();const i=this._pos(t);this._drag={id:t.id,sx:e.clientX,sy:e.clientY,ox:i.x,oy:i.y,moved:!1},Om(e),this._tip=null}_pointerMove(e,t){if(!this._drag||this._drag.id!==t.id)return;const i=this.renderRoot.querySelector(".stage");if(!i)return;const n=this._baseVb(),r=i.getBoundingClientRect(),o=this._viewOr(n),s=(e.clientX-this._drag.sx)/r.width*o.w,a=(e.clientY-this._drag.sy)/r.height*o.h;Math.abs(e.clientX-this._drag.sx)+Math.abs(e.clientY-this._drag.sy)>3&&(this._drag.moved=!0,clearTimeout(this._holdTimer));const l=ja(this._drag.ox+s),c=ja(this._drag.oy+a);this._savePos(t,l,c)}_pointerUp(e,t){if(clearTimeout(this._holdTimer),!this._drag||this._drag.id!==t.id)return;const i=this._drag.moved;this._drag=i?this._drag:null,i&&(this._selId=t.id,window.setTimeout(()=>this._drag=null,0))}_showToast(e){for(const e of this.renderRoot.querySelectorAll("hp-dialog"))e.closeTransientOverlays("toast");this._toast=e,clearTimeout(this._toastTimer),this._toastTimer=window.setTimeout(()=>{this._toast=""},3500)}_syncPointerHoverTargets(){const e=this._pointerModality.hoverEnabled;for(const t of this.renderRoot.querySelectorAll(Sm))t.toggleAttribute("data-pointer-hover",e)}_syncPointerHoverSubtree(e){if(e.nodeType!==Node.ELEMENT_NODE)return;const t=e,i=this._pointerModality.hoverEnabled;t.matches(Sm)&&t.toggleAttribute("data-pointer-hover",i);for(const e of t.querySelectorAll(Sm))e.toggleAttribute("data-pointer-hover",i)}_clearTransientHover(e=!1){e&&this._pointerModality.suspend(),this._tip&&(this._tip=null),this._hoverRoom&&(this._hoverRoom=null)}_notePointer(e){const t=this._pointerModality.modality,i=this._pointerModality.note(e);"touch"!==i&&"pen"!==i||t===i&&!this._tip&&!this._hoverRoom||this._clearTransientHover()}_guardTouchGesture(e){if(this._editorSecondary?.handleOutsideDismiss(e))return;if("click"===e.type){if(!this._suppressClick&&!this._touchSequenceMultitouch&&Date.now()>this._touchClickBlockUntil)return;return e.preventDefault(),void e.stopImmediatePropagation()}const t=e;if(this._notePointer(t),"touch"===t.pointerType)if("pointerdown"!==e.type){if("pointermove"===e.type){const e=this._touchContacts.get(t.pointerId);if(!e)return;const i={...e,x:t.clientX,y:t.clientY};if(this._touchContacts.set(t.pointerId,i),this._touchSequenceMultitouch&&"view"===this._mode&&!this._vacFit&&this._pinchStart&&[...this._touchContacts.values()].every(e=>e.inStage)){this._pointers.set(t.pointerId,{x:t.clientX,y:t.clientY});const e=[...this._touchContacts.values()];if(e.length>=2&&this._stageEl){const[t,i]=e,n=Math.hypot(t.x-i.x,t.y-i.y)/(this._pinchStart.dist||1),r=this._stageEl.getBoundingClientRect();this._zoomAt((t.x+i.x)/2-r.left,(t.y+i.y)/2-r.top,this._pinchStart.zoom*n),this._saveZoom()}}return}if("pointerup"===e.type||"pointercancel"===e.type||"lostpointercapture"===e.type){if(this._clearTransientHover(),this._touchContacts.delete(t.pointerId),this._touchSequenceMultitouch){if(this._touchClickBlockUntil=Date.now()+500,this._pointers.delete(t.pointerId),!this._vacFit&&this._pointers.size>=2){const[e,t]=[...this._pointers.values()];this._pinchStart={dist:Math.hypot(e.x-t.x,e.y-t.y),zoom:this._zoom}}else this._pinchStart=null;0===this._pointers.size&&(this._panStart=null,this._panLock=null)}0===this._touchContacts.size&&(this._touchSequenceMultitouch=!1)}}else if(this._touchContacts.set(t.pointerId,{x:t.clientX,y:t.clientY,inStage:!!t.target?.closest?.(".stage")}),this._touchContacts.size>=2){this._clearTransientHover(),this._touchSequenceMultitouch=!0,this._touchClickBlockUntil=Number.POSITIVE_INFINITY,clearTimeout(this._holdTimer),clearTimeout(this._kioskHoldTimer),this._swipeStart=null;const e=[...this._touchContacts.values()];if("view"===this._mode&&!this._vacFit&&e.every(e=>e.inStage)){this._pointers=new Map([...this._touchContacts].map(([e,t])=>[e,{x:t.x,y:t.y}]));const[t,i]=e;this._pinchStart={dist:Math.hypot(t.x-i.x,t.y-i.y),zoom:this._zoom},this._panStart=null,this._panLock=null}else this._vacFit&&(this._pointers.clear(),this._pinchStart=null,this._panStart=null,this._panLock=null)}}_showTip(e,t,i,n,r,o){this._notePointer(e),this._pointerModality.hoverEnabled&&(this._drag||(this._tip={x:e.clientX,y:e.clientY,title:t,meta:i,lqi:n,temp:r,hum:o}))}get _gridPitch(){return Na}get _cellCm(){const e=Number(this._curSpaceCfg?.cell_cm);return Number.isFinite(e)&&e>0?e:5}_fmtLen(e,t){const i=function(e,t,i,n){return Math.hypot(t[0]-e[0],t[1]-e[1])/i*n}(e,t,this._gridPitch,this._cellCm);return Kt(i,"mi"===this.hass?.config?.unit_system?.length)}get _curSpaceCfg(){const e=this._resize?.preview;return e&&e.space===this._space?e.sp:this._serverCfg?.spaces.find(e=>e.id===this._space)}get _renderCfg(){const e=this._resize?.preview;return e&&this._serverCfg?{...this._serverCfg,spaces:this._serverCfg.spaces.map(t=>t.id===e.space?e.sp:t)}:this._serverCfg}get _spaceH(){return this._curSpaceCfg,Mm}get _segments(){const e=this._curSpaceCfg,t=this._spaceH;return Jt(e?.rooms||[]).map(e=>[e[0]*Mm,e[1]*t,e[2]*Mm,e[3]*t])}_savedNav(){if(this._hasFixedFloor)return null;try{return JSON.parse(localStorage.getItem(km)||"null")}catch{return null}}_saveNav(){if(!this._hasFixedFloor)try{localStorage.setItem(km,JSON.stringify({space:this._space}))}catch{}}_leaveCardRoute(){if(this._routeDepartureHandled)return;this._routeDepartureHandled=!0,"view"!==this._mode&&this._setMode("view",!1),this._pendingNavMode=null,this._geometryHistory.clear(),this._activeDraftId=null,this._resumeDraftBySpace={},this._draftSegmentCms=[],this._closingWallCm=null,this._drawWallField=null,this._showHidden=!1,this._tapConfirm=null,this._vacCalConfirm=null,this._decorEraseConfirm=null,this._openingInfo=null,this._closeInfoCard(),this._rulesDialog=null,this._alignDialog=null,this._preflightClipboardFallback=null,this._backupImportDialog=null,this._backupExportDialog=null,this._settingsDialog=null,this._deviceInbox=null,this._deviceInboxReturn=null,this._markerDialog=null,this._openingDialog=null,this._physicalDialog=null,this._wallDialog=null,this._backdropDialog=null,this._decorShapeDialog=null,this._decorTextDialog=null,this._mergeDialog=null,this._roomDialog=!1,this._spaceDialog=null,this._importDialog=null;const e=this._warmSlot;e?.owner===this._warmGen&&(e.vp=this._warmViewportState(),e.dlg=null,e.frameFingerprint="",clearTimeout(e.evict),e.evict=0),this._saveNav()}_setMode(e,t=!0){return this._warmModeRequest=0,this._editorRuntime?this._editorRuntime._setMode(e,t):"view"===e?void this._editorModeRequest++:void this._requestMode(e,t)}_primeDrawWallField(){return this._editorRuntimeOrThrow()._primeDrawWallField()}get _drawWallFieldValue(){return null===this._drawWallField?vo(15,this._imperial):this._drawWallField}get _drawWallCm(){const e=(e=>{const t=String(e??"").trim().replace(",",".");if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(t))return null;const i=Number(t);return Number.isFinite(i)?i:null})(this._drawWallFieldValue);if(null==e||e<0)return null;const t=this._imperial?2.54*e:e,i="column"===this._tool?Js:100;return t>=("column"===this._tool?1:0)&&t<=i?t:null}get _drawWallMaxCm(){return"column"===this._tool?Js:100}_showPhysicalRange(e=this._drawWallMaxCm,t=0){return this._editorRuntimeOrThrow()._showPhysicalRange(e,t)}_draftSegmentCount(e=this._curSpaceCfg){return this._editorRuntimeOrThrow()._draftSegmentCount(e)}_mergeSpacePartitions(e,t){return this._editorRuntimeOrThrow()._mergeSpacePartitions(e,t)}_finishWallChain(){return this._editorRuntimeOrThrow()._finishWallChain()}_activateMarkupTool(e){return this._editorRuntimeOrThrow()._activateMarkupTool(e)}_limitReached(e){return this._editorRuntimeOrThrow()._limitReached(e)}_svgPoint(e){return this._editorRuntimeOrThrow()._svgPoint(e)}_snap(e){return this._editorRuntimeOrThrow()._snap(e)}_snapDrawPoint(e,t=!1){return this._editorRuntimeOrThrow()._snapDrawPoint(e,t)}_planSnapOpeningCuts(e,t){return this._editorRuntimeOrThrow()._planSnapOpeningCuts(e,t)}_planSnapGeometrySnapshot(){return this._editorRuntimeOrThrow()._planSnapGeometrySnapshot()}_hiddenWallDiagnosticSnapshot(){return this._editorRuntimeOrThrow()._hiddenWallDiagnosticSnapshot()}_planStructuralGeometrySnapshot(){return this._editorRuntimeOrThrow()._planStructuralGeometrySnapshot()}_planSnapContextKey(e){return this._editorRuntimeOrThrow()._planSnapContextKey(e)}_resolvePlanDrawPoint(e,t){return this._editorRuntimeOrThrow()._resolvePlanDrawPoint(e,t)}get _activePlanSnapCandidate(){if(!this._markup||"draw"!==this._tool)return null;const e=this._planSnapHover;if(!e)return null;const t=this._planSnapGeometrySnapshot();return e.contextKey===this._planSnapContextKey(t.key)?e.candidate:null}get _activePlanSnapConflicts(){if(!this._markup||"draw"!==this._tool)return[];const e=this._planSnapHover;if(!e)return[];const t=this._planSnapGeometrySnapshot();return e.contextKey===this._planSnapContextKey(t.key)?e.conflicts:[]}_clearPlanSnapHover(e=!0){return this._editorRuntime?this._editorRuntimeOrThrow()._clearPlanSnapHover(e):(this._planSnapHover=null,void(e&&(this._cursorPt=null)))}_samePt(e,t){return si(e,t)}_dropLegacySegments(){return this._editorRuntimeOrThrow()._dropLegacySegments()}_rollbackRejectedPhysicalWrites(e){return this._editorRuntimeOrThrow()._rollbackRejectedPhysicalWrites(e)}async _reloadRejectedPhysicalWrite(){return this._editorRuntimeOrThrow()._reloadRejectedPhysicalWrite()}get _cfgWriting(){return this._writesPending>0}async _sendConfigCandidate(e){const t=ao(e),i=await this.hass.callWS({type:"houseplan/config/set",config:t,expected_rev:this._cfgRev});this._cfgRev=i?.rev??this._cfgRev+1}_writeConfig(){if(this._editorRuntime)return this._editorRuntime._writeConfig();this._writesPending++,this._writeChain=Qp(this._writeChain,async()=>{if(!this._serverCfg)return;const e=ao(this._serverCfg),t=zl(e);t!==zl(this._serverCfg)&&(this._serverCfg=e),this._cfgContentFingerprint=t,await this._sendConfigCandidate(e)});return this._writeChain.finally(()=>{this._writesPending--})}_saveConfig(){this._cfgEpoch++,this._saveConfigDebounced()}_geometrySnapshotFromConfig(e,t){return this._editorRuntimeOrThrow()._geometrySnapshotFromConfig(e,t)}_geometrySnapshot(e=this._space){return this._editorRuntimeOrThrow()._geometrySnapshot(e)}_recordGeometry(e,t){return this._editorRuntimeOrThrow()._recordGeometry(e,t)}_restoreGeometryStateInConfig(e,t,i=!1){return this._editorRuntimeOrThrow()._restoreGeometryStateInConfig(e,t,i)}_restoreGeometryStateLocal(e){return this._editorRuntimeOrThrow()._restoreGeometryStateLocal(e)}_wallModelBlockerLabel(e){return this._editorRuntimeOrThrow()._wallModelBlockerLabel(e)}_hasLegacyZeroWallFields(e=this._serverCfg){return this._editorRuntimeOrThrow()._hasLegacyZeroWallFields(e)}_showWallModelMigrationBlocked(e){return this._editorRuntimeOrThrow()._showWallModelMigrationBlocked(e)}_limitSegmentsOf(e){return this._editorRuntimeOrThrow()._limitSegmentsOf(e)}_junctionLimitViolations(e,t,i){return this._editorRuntimeOrThrow()._junctionLimitViolations(e,t,i)}_junctionLimitLabel(e){return this._editorRuntimeOrThrow()._junctionLimitLabel(e)}_junctionLimitsIntroduced(e,t,i){return this._editorRuntimeOrThrow()._junctionLimitsIntroduced(e,t,i)}_commitPhysicalGeometry(e,t,i=[]){return this._editorRuntimeOrThrow()._commitPhysicalGeometry(e,t,i)}_clearGeometryGesture(){return this._editorRuntime?this._editorRuntimeOrThrow()._clearGeometryGesture():(this._path=[],this._planSnapHover=null,this._cursorPt=null,this._openingHoverCandidate=null,this._openingJambBlockCm=null,this._openingPreset=null,this._openingRebindId=null,this._mergeSel=null,this._mergeDialog=null,this._splitSel=null,this._pendingSplit=null,this._wallFaceBatch=null,this._wallRepairDiagnostic=null,this._roomDeleteDialog=null,this._wallDialog=null,this._physicalDialog=null,this._physicalSel=null,this._physicalDrag=null,this._physicalRotate=null,this._activeDraftId=null,this._draftSegmentCms=[],this._closingWallCm=null,this._openingDialog=null,this._resize?.reset(),this._decorDraft=null,this._decorMove=null,this._dtDrag=null,void(this._bdDrag=null))}_stagePointerCancel(e){if(this._editorRuntime)return this._editorRuntime._stagePointerCancel(e)}_applyGeometryState(e,t=!1){return this._editorRuntimeOrThrow()._applyGeometryState(e,t)}_roomAt(e){return this._editorRuntimeOrThrow()._roomAt(e)}_overlapRoom(e){return this._editorRuntimeOrThrow()._overlapRoom(e)}_pointInRoom(e,t){return t.poly?ai(e,t.poly):null!=t.x&&e[0]>=t.x&&e[0]<=t.x+t.w&&e[1]>=t.y&&e[1]<=t.y+t.h}_contourSelfIntersects(e){return this._editorRuntimeOrThrow()._contourSelfIntersects(e)}_canAppendRoomDraftPoint(){return this._editorRuntimeOrThrow()._canAppendRoomDraftPoint()}_markupClick(e){if(this._editorRuntime)return this._editorRuntime._markupClick(e)}_draftEndAt(e,t){return this._editorRuntimeOrThrow()._draftEndAt(e,t)}_mergeDraftEndpoint(e){return this._editorRuntimeOrThrow()._mergeDraftEndpoint(e)}_adoptDraftCms(e,t,i){return this._editorRuntimeOrThrow()._adoptDraftCms(e,t,i)}_draftSegmentsForPath(e,t,i){return this._editorRuntimeOrThrow()._draftSegmentsForPath(e,t,i)}_persistActiveDraftSegment(){return this._editorRuntimeOrThrow()._persistActiveDraftSegment()}_activeWallSourceKey(e){return this._editorRuntimeOrThrow()._activeWallSourceKey(e)}_wallGraphSources(e){return this._editorRuntimeOrThrow()._wallGraphSources(e)}_wallFaceGraph(e,t){return this._editorRuntimeOrThrow()._wallFaceGraph(e,t)}_offerWallFaces(e,t=this._path.length-2,i){return this._editorRuntimeOrThrow()._offerWallFaces(e,t,i)}_beginWallFaceBatch(e){return this._editorRuntimeOrThrow()._beginWallFaceBatch(e)}_offerExistingWallFace(e){return this._editorRuntimeOrThrow()._offerExistingWallFace(e)}_columnClick(e){return this._editorRuntimeOrThrow()._columnClick(e)}_openPhysicalDialog(e,t,i){return this._editorRuntimeOrThrow()._openPhysicalDialog(e,t,i)}_physicalDown(e,t,i){return this._editorRuntimeOrThrow()._physicalDown(e,t,i)}_clampPhysicalDelta(e,t,i){return this._editorRuntimeOrThrow()._clampPhysicalDelta(e,t,i)}_physicalMove(e){return this._editorRuntimeOrThrow()._physicalMove(e)}_physicalUp(e){return this._editorRuntimeOrThrow()._physicalUp(e)}_registerPhysicalTap(e,t,i){return this._editorRuntimeOrThrow()._registerPhysicalTap(e,t,i)}_cancelPhysicalGesture(){return this._editorRuntimeOrThrow()._cancelPhysicalGesture()}_physicalRotateDown(e,t){return this._editorRuntimeOrThrow()._physicalRotateDown(e,t)}_physicalRotateMove(e){return this._editorRuntimeOrThrow()._physicalRotateMove(e)}_physicalRotateUp(e){return this._editorRuntimeOrThrow()._physicalRotateUp(e)}_rszRooms(){return this._editorRuntimeOrThrow()._rszRooms()}_rszOpenings(){return this._editorRuntimeOrThrow()._rszOpenings()}_rszObstacles(){return this._editorRuntimeOrThrow()._rszObstacles()}_rszOptsFor(e,t){return this._editorRuntimeOrThrow()._rszOptsFor(e,t)}_rszResolution(e,t,i){return this._editorRuntimeOrThrow()._rszResolution(e,t,i)}_rszSnapshot(){return this._editorRuntimeOrThrow()._rszSnapshot()}_rszResetController(){return this._editorRuntimeOrThrow()._rszResetController()}_rszProjectPreview(e,t,i,n,r){return this._editorRuntimeOrThrow()._rszProjectPreview(e,t,i,n,r)}_rszAcceptPreview(e,t){return this._editorRuntimeOrThrow()._rszAcceptPreview(e,t)}_rszSpaceCandidateGeometry(e,t){return this._editorRuntimeOrThrow()._rszSpaceCandidateGeometry(e,t)}_rszSpaceCandidateRenderable(e,t){return this._editorRuntimeOrThrow()._rszSpaceCandidateRenderable(e,t)}_rszCandidateRenderable(e){return this._editorRuntimeOrThrow()._rszCandidateRenderable(e)}_rszEdgeDown(e,t,i){return this._editorRuntimeOrThrow()._rszEdgeDown(e,t,i)}_rszReasonText(e){return this._editorRuntimeOrThrow()._rszReasonText(e)}_rszDisabledActivate(e,t){return this._editorRuntimeOrThrow()._rszDisabledActivate(e,t)}_rszDisabledKey(e,t){return this._editorRuntimeOrThrow()._rszDisabledKey(e,t)}_rszMove(e){return this._editorRuntimeOrThrow()._rszMove(e)}_rszUp(e){return this._editorRuntimeOrThrow()._rszUp(e)}_rszCancelDrag(e){return this._editorRuntimeOrThrow()._rszCancelDrag(e)}_rszPointerCancel(e){return this._editorRuntimeOrThrow()._rszPointerCancel(e)}_rszEdgeLabels(e,t,i=this._resize?.rooms){return this._editorRuntimeOrThrow()._rszEdgeLabels(e,t,i)}_rszInnerSpanCms(e,t,i){return this._editorRuntimeOrThrow()._rszInnerSpanCms(e,t,i)}_renderResizeMeasurements(){return this._editorRuntimeOrThrow()._renderResizeMeasurements()}_renderResizeLayer(e){return this._editorRuntimeOrThrow()._renderResizeLayer(e)}get _openingsR(){const e=this._curSpaceCfg,t=this._spaceH,i=this._spaceModel();return i?(e?.openings||[]).flatMap(e=>{const n={...e,rx:e.x*Mm,ry:e.y*t,rlen:e.length*Mm};if(!e.host||"wall"===e.host.kind)return[n];const r=Pd(e,i.partitions,Mm,this._cellCm,this._gridPitch);if(!r.resolved)return"plan"===this._mode?[{...n,orphanReason:r.reason||"invalid-host"}]:[];let[o,s]=r.resolved.center;const a=this._physicalDrag;return a?.moved&&"partition"===a.kind&&a.id===e.host.id&&(o+=a.delta[0],s+=a.delta[1]),[{...e,rx:o,ry:s,rlen:r.resolved.length,angle:r.resolved.angle,partitionHost:r.resolved}]}):[]}_partitionOpeningCuts(e=this._spaceModel(),t=()=>!0){if(!e)return[];return Kp(Gp(this._curSpaceCfg?.id===e.id?this._curSpaceCfg:null,e,this._cellCm,this._gridPitch,Mm),t)}_roomWallOpeningInputs(e=this._openingsR,t=this._spaceModel()){if(!t)return[];const i=this._openCuts();return Yp(e,t,this._spaceWalls,i,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm)}_openingFace(e,t,i){return e.partitionHost?Hd(e.partitionHost,i):Ks(t,{x:e.rx,y:e.ry,angle:e.angle,length:e.rlen,flip_v:i})}_cmToUnits(e){return e/this._cellCm*this._gridPitch}get _decorList(){const e=this._curSpaceCfg;return Array.isArray(e?.decor)?e.decor:[]}get _decorH(){return Mm}_decorResolvedStyle(e){return function(e,t,i,n=pr){const r="rect"===e?.kind||"ellipse"===e?.kind,o=e,s=qt(o?.color,n.color);return{color:s,opacity:_r(o?.opacity,n.opacity),widthCm:br(e,t,i,n.widthCm),fill:!!r&&!0===o?.fill,fillColor:qt(o?.fill_color,o?.fill?s:n.fillColor),fillOpacity:r&&o?.fill?_r(o?.fill_opacity,.25):n.fillOpacity}}(e,this._cellCm,this._gridPitch,pr)}_decorWidthUnits(e){return((e,t,i,n=pr.widthCm)=>{const r=Number(e?.width_cm);if(Number.isFinite(r)&&r>0)return vr(r,t,i);const o=Number(e?.width);return Number.isFinite(o)&&o>0?o:vr(n,t,i)})(e,this._cellCm,this._gridPitch,pr.widthCm)}_decorTextSizeCm(e){if("text"===e?.kind){const t=Number(e.size_cm);return Number.isFinite(t)&&t>0?t:yr(20*Gi(e),this._cellCm,this._gridPitch)}return yr(20,this._cellCm,this._gridPitch)}_decorTextUnits(e){if("text"!==e.kind)return 20;const t=Number(e.size_cm);return Number.isFinite(t)&&t>0?vr(t,this._cellCm,this._gridPitch):20*Gi(e)}_decorSmallField(e){return Math.round(100*(this._imperial?e/2.54:e))/100}_decorSmallCm(e){const t=this._imperial?2.54*e:e;return Number.isFinite(t)?Math.max(.1,Math.min(100,t)):.1}_decorTextCm(e){const t=this._imperial?2.54*e:e;return Number.isFinite(t)?Math.max(.1,Math.min(2e3,t)):.1}_decorLargeField(e){return Math.round(100*(this._imperial?e/30.48:e/100))/100}_decorLargeCm(e){const t=this._imperial?30.48*e:100*e;return Number.isFinite(t)?Math.max(.1,Math.min(Ea*this._cellCm,t)):.1}_angleField(e){const t=Number(e);return Number.isFinite(t)?String(Number(t.toFixed(3))):"0"}_decorBoxOf(e){return"rect"!==e.kind&&"ellipse"!==e.kind&&"furniture"!==e.kind?null:{x:e.x*Mm,y:e.y*this._decorH,w:e.w*Mm,h:e.h*this._decorH,angle:mr(e.angle)||void 0}}_decorSnapGeometry(e){return this._editorRuntimeOrThrow()._decorSnapGeometry(e)}_decorSnap(e,t="mouse",i){return this._editorRuntimeOrThrow()._decorSnap(e,t,i)}_replaceDecor(e,t){return this._editorRuntimeOrThrow()._replaceDecor(e,t)}_cancelDecorGesture(){return this._editorRuntimeOrThrow()._cancelDecorGesture()}_decorPointerDown(e){return this._editorRuntimeOrThrow()._decorPointerDown(e)}_decorCommitDraft(){return this._editorRuntimeOrThrow()._decorCommitDraft()}_decorShapeDown(e,t){if(this._editorRuntime)return this._editorRuntime._decorShapeDown(e,t)}_decorMoveUpdate(e){return this._editorRuntimeOrThrow()._decorMoveUpdate(e)}_decorShapeDbl(e,t){if(this._editorRuntime)return this._editorRuntime._decorShapeDbl(e,t)}_openDecorProperties(e){return this._editorRuntimeOrThrow()._openDecorProperties(e)}_decorOpenText(e){return this._editorRuntimeOrThrow()._decorOpenText(e)}_decorRememberTextSelection(e){return this._editorRuntimeOrThrow()._decorRememberTextSelection(e)}_decorInsertLiveVariable(e){return this._editorRuntimeOrThrow()._decorInsertLiveVariable(e)}_decorSaveText(){return this._editorRuntimeOrThrow()._decorSaveText()}_decorSaveShape(){return this._editorRuntimeOrThrow()._decorSaveShape()}get _dtSel(){return"decor"===this._mode&&"select"===this._decorTool&&this._decorSel&&this._decorList.find(e=>e.id===this._decorSel)||null}_dtPivot(e){return this._editorRuntimeOrThrow()._dtPivot(e)}_dtApply(e,t){return this._editorRuntimeOrThrow()._dtApply(e,t)}_dtStart(e,t,i,n){return this._editorRuntimeOrThrow()._dtStart(e,t,i,n)}_dtMove(e){return this._editorRuntimeOrThrow()._dtMove(e)}_dtUp(){return this._editorRuntimeOrThrow()._dtUp()}_dtMeasure(){return this._editorRuntimeOrThrow()._dtMeasure()}_deleteDecor(e){return this._editorRuntimeOrThrow()._deleteDecor(e)}_decorDeleteSel(){return this._editorRuntimeOrThrow()._decorDeleteSel()}_confirmDecorErase(){return this._editorRuntimeOrThrow()._confirmDecorErase()}get _furnWalls(){const e=this._rawPhysicalBodiesR().flatMap(e=>e.map((t,i)=>{const n=e[(i+1)%e.length];return[t[0],t[1],n[0],n[1]]}));return[...this._segments,...e]}get _furnWallReach(){return 6*this._gridPitch}_furnFieldValue(e){return this._editorRuntimeOrThrow()._furnFieldValue(e)}_furnFieldToCm(e){return this._editorRuntimeOrThrow()._furnFieldToCm(e)}_furnPick(e){return this._editorRuntimeOrThrow()._furnPick(e)}_furnPlace(e,t=!1){return this._editorRuntimeOrThrow()._furnPlace(e,t)}_furnMoveUpdate(e){return this._editorRuntimeOrThrow()._furnMoveUpdate(e)}_decorApplyBox(e,t){return this._editorRuntimeOrThrow()._decorApplyBox(e,t)}get _furnLive(){const e=this._dtDrag;if(!e||"scale"!==e.kind||!e.orig)return null;const t=this._decorList.find(t=>t.id===e.id);if(!t||"furniture"!==t.kind)return null;const i=Mm,n=this._decorH,r=t.w*i,o=t.h*n,s=function(e,t,i,n,r){const o=e+i/2,s=t+n/2,a=(Number(r)||0)*Math.PI/180,l=Math.cos(a),c=Math.sin(a),h=(e,t)=>{const i=e-o,n=t-s;return[o+i*l-n*c,s+i*c+n*l]};return[h(e,t),h(e+i,t),h(e+i,t+n),h(e,t+n)]}(t.x*i,t.y*n,r,o,Number(t.angle)||0),a=(e,t)=>[(e[0]+t[0])/2,(e[1]+t[1])/2],l=a(s[0],s[1]),c=a(s[0],s[3]);return[{x:l[0],y:l[1],text:this._fmtLen([0,0],[r,0])},{x:c[0],y:c[1],text:this._fmtLen([0,0],[0,o])}]}_renderFurnPalette(){return this._editorRuntimeOrThrow()._renderFurnPalette()}get _bdBase(){const e=this._curSpaceCfg;return e?.plan_url?{...Da(e.plan_aspect,Mm)}:null}get _bdRect(){const e=this._curSpaceCfg;return e?.plan_url?Oa(e,Mm):null}get _bdParams(){const e=this._curSpaceCfg,t=Number(e?.plan_x),i=Number(e?.plan_y),n=Number(e?.plan_scale),r=Number(e?.plan_scale_x),o=Number(e?.plan_scale_y),s=Number.isFinite(n)&&n>0?n:1;return{dx:Number.isFinite(t)?t:0,dy:Number.isFinite(i)?i:0,sx:Number.isFinite(r)&&r>0?r:s,sy:Number.isFinite(o)&&o>0?o:s,angle:mr(e?.plan_angle)}}_openBackdropDialog(e){if(this._editorRuntime)return this._editorRuntime._openBackdropDialog(e)}_saveBackdropDialog(){return this._editorRuntimeOrThrow()._saveBackdropDialog()}get _bdActive(){return"decor"===this._mode&&!!this._bdRect&&"backdrop"===this._decorTool}get _bdMovable(){return"decor"===this._mode&&"backdrop"===this._decorTool&&!!this._bdRect}_bdApply(e,t,i,n,r){return this._editorRuntimeOrThrow()._bdApply(e,t,i,n,r)}_bdStart(e,t,i=!1){return this._editorRuntimeOrThrow()._bdStart(e,t,i)}_bdMove(e){return this._editorRuntimeOrThrow()._bdMove(e)}get _bdMoved(){if("decor"!==this._mode||!this._bdRect)return!1;const e=this._bdParams;return 0!==e.dx||0!==e.dy||1!==e.sx||1!==e.sy||0!==e.angle}_bdReset(){return this._editorRuntimeOrThrow()._bdReset()}_bdUp(){return this._editorRuntimeOrThrow()._bdUp()}get _bdLive(){if(!this._bdDrag)return null;const e=this._bdRect;return e?{x:e.x+e.w/2,y:e.y+e.h/2,text:`${this._fmtLen([0,0],[e.w,0])} × ${this._fmtLen([0,0],[0,e.h])}`}:null}_renderBackdropFrame(e){return this._editorRuntime?this._editorRuntimeOrThrow()._renderBackdropFrame(e):U}_renderTextFrame(e){const t=this._dtSel,i=this._dtBox;if(!t||!i||i.id!==t.id)return U;const n=.018*Math.max(e.w,e.h),r=n/4;if("line"===t.kind){const e=[t.x1*Mm,t.y1*this._decorH],i=[t.x2*Mm,t.y2*this._decorH];return B` + + ${[e,i].map((e,t)=>B`this._dtStart(e,"scale",void 0,t)}> + `)} + `}const[o,s]=this._dtPivot(t),a=Number(t.angle)||0,l=2.2*n;return B` + + + this._dtStart(e,"rotate")}> + + ${[[-1,-1,"nwse"],[1,-1,"nesw"],[1,1,"nwse"],[-1,1,"nesw"]].map(([e,t,o])=>B`this._dtStart(i,"scale",[e,t])}>`)} + `}_renderDecorLayer(){const e=Mm,t=this._decorH,i="decor"===this._mode,n=i&&"erase"===this._decorTool,r=this._decorList.map(r=>{const o="dshape"+(i&&this._decorSel===r.id?" dsel":""),s=this._decorResolvedStyle(r),a=this._decorWidthUnits(r),l=e=>this._decorShapeDown(e,r),c=e=>this._decorShapeDbl(e,r);if("line"===r.kind)return B` + ${i&&"select"===this._decorTool?B``:U} + ${n?B``:U}`;if("rect"===r.kind){const i=(r.x+r.w/2)*e,h=(r.y+r.h/2)*t,d=mr(r.angle);return B` + ${n?B``:U}`}if("ellipse"===r.kind){const i=(r.x+r.w/2)*e,h=(r.y+r.h/2)*t,d=mr(r.angle);return B` + ${n?B``:U}`}if("furniture"===r.kind){const i=r.w*e,h=r.h*t,d=kl(r.symbol);if(!d)return U;const u=Number(r.angle)||0,p=r.x*e+i/2,_=r.y*t+h/2,m=`${u?`rotate(${u} ${p} ${_}) `:""}translate(${r.x*e} ${r.y*t}) scale(${i/d.viewW} ${h/d.viewH})`;return B` + ${n?B``:U}`}if("text"===r.kind){const i=this._decorTextUnits(r),n=this._renderDeviceSnapshot?.facts.get(`decor:${this._space}:${r.id}`),a=function(e){return String(e??"").replace(/\r\n?/g,"\n").split("\n")}("string"==typeof n?n:Vi(r.text,r,this._renderPlanHass,e=>this._renderEntityAvailable(e))),h=r.x*e,d=r.y*t,u=Number(r.angle)||0,p=d-(a.length-1)*i*1.2/2;return B`${a.map((e,t)=>B`${e}`)}`}return U});let o=U;const s=this._decorDraft;if(s){const e=this._decorStyle,t=vr(e.widthCm,this._cellCm,this._gridPitch);if("line"===s.kind)o=B``;else{const i=Math.min(s.a[0],s.b[0]),n=Math.min(s.a[1],s.b[1]),r=Math.abs(s.b[0]-s.a[0]),a=Math.abs(s.b[1]-s.a[1]);o="rect"===s.kind?B``:B``}}return B`${r}${o}`}get _editorToolbarGroups(){return"plan"!==this._mode?[]:[{id:"opening",label:this._t("markup.opening"),icon:"mdi:door",activeItemId:"opening"===this._tool?this._openingPreset?.type:void 0,items:[{id:"window",label:this._t("opening.window"),icon:"mdi:window-closed-variant",role:"tool",invoke:()=>this._activateOpeningPlacement("window")},{id:"door",label:this._t("opening.door"),icon:"mdi:door-open",role:"tool",invoke:()=>this._activateOpeningPlacement("door")},{id:"passage",label:this._t("opening.passage"),icon:"mdi:arch",role:"tool",invoke:()=>this._activateOpeningPlacement("passage")},{id:"gate",label:this._t("opening.gate"),icon:"mdi:gate",role:"tool",invoke:()=>this._activateOpeningPlacement("gate")}]}]}_renderEditorGroupLauncher(e){return this._editorRuntimeOrThrow()._renderEditorGroupLauncher(e)}get _editorSecondaryContextId(){const e=`editor:${this._mode}:${this._space}:${this._cfgEpoch}`,t=this._editorSecondary?.activeGroup(this._editorToolbarGroups);if(t)return`${e}:group:${t.id}:${this._editorSecondary?.groupGeneration}`;if("plan"===this._mode){const t=this._physicalSel;return t?`${e}:selection:${t.kind}:${t.id}:${t.segment??""}`:`${e}:tool:${this._tool}:${this._path.length}`}return"decor"===this._mode?"furniture"===this._decorTool?`${e}:palette:furniture:${this._furnPalette?.symbol||"none"}`:"select"===this._decorTool&&this._decorSel?`${e}:selection:decor:${this._decorSel}`:`${e}:tool:${this._decorTool}:${this._bdMoved?1:0}:${this._bdDrag?1:0}`:`${e}:none`}_runEditorContext(e,t){return this._editorRuntimeOrThrow()._runEditorContext(e,t)}_renderEditorGroupModel(e){return this._editorRuntimeOrThrow()._renderEditorGroupModel(e)}_renderDrawWallControl(){return this._editorRuntimeOrThrow()._renderDrawWallControl()}_renderPlanSecondary(){return this._editorRuntimeOrThrow()._renderPlanSecondary()}_renderDecorSecondary(){return this._editorRuntimeOrThrow()._renderDecorSecondary()}_withBackdropReset(e){return this._editorRuntimeOrThrow()._withBackdropReset(e)}get _editorSecondaryDialogBlocked(){return!!(this._tapConfirm||this._vacCalConfirm||this._roomDialog||this._mergeDialog||this._openingDialog||this._physicalDialog||this._openingInfo||this._decorTextDialog||this._decorShapeDialog||this._backdropDialog||this._decorEraseConfirm||this._spaceDialog||this._markerDialog||this._deviceInbox||this._infoCard||this._rulesDialog||this._settingsDialog||this._alignDialog||this._importDialog||this._kioskDialog||this._backupExportDialog||this._backupImportDialog||this._wallDialog)}_renderEditorSecondary(){return this._editorRuntimeOrThrow()._renderEditorSecondary()}_renderDecorBar(){return this._editorRuntimeOrThrow()._renderDecorBar()}_renderDecorEraseConfirm(){return this._editorRuntimeOrThrow()._renderDecorEraseConfirm()}_renderDecorTextDialog(){return this._editorRuntimeOrThrow()._renderDecorTextDialog()}_renderDecorShapeDialog(){return this._editorRuntimeOrThrow()._renderDecorShapeDialog()}_renderBackdropDialog(){return this._editorRuntimeOrThrow()._renderBackdropDialog()}_cssPxToRender(e){return this._editorRuntimeOrThrow()._cssPxToRender(e)}_renderZeroWalls(e){if(e&&!e.showBorders&&!this._editing)return B``;const t=this._zeroWalls();if(!t.lines.length)return B``;const i=e?.color||"var(--hp-muted)";return B` + ${t.lines.map(e=>B``)} + `}_zeroWalls(){const e=this._spaceModel();return e?vp(this._curSpaceCfg,e,Mm,.02*this._gridPitch):{style:_p(this._curSpaceCfg),lines:[],contour:[],barriers:[],transmissive:[]}}_openCuts(){return this._zeroWalls().contour}_deleteRoomClick(e){return this._editorRuntimeOrThrow()._deleteRoomClick(e)}get _wallKeyPitch(){return La}get _spaceWalls(){const e=this._curSpaceCfg?.walls;return Array.isArray(e)?e:[]}_cfgOpenCuts(){const e=this._curSpaceCfg,t=this._spaceModel();if(!e||!t)return[];const i=mp(e,1),n=gp(e,t.rooms,Mm,.02*this._gridPitch).map(e=>e.map(e=>e/Mm)),r=new Set;return[...i,...n].filter(e=>{const t=e.map(e=>Number(e).toFixed(9)).join(","),i=[e[2],e[3],e[0],e[1]].map(e=>Number(e).toFixed(9)).join(","),n=t[e[0]/Mm,e[1]/Mm,e[2]/Mm,e[3]/Mm]))}_paperShapes(e){if(!this._spaceWalls.length)return Xt(e);const t=this._wallUnionGeometry();return t?.paperD?[{path:t.paperD}]:Xt(e)}_wallUnionGeometry(){const e=this._spaceModel();if(!e)return null;const t=this._spaceWalls,i=this._physicalBodiesR();if(!t.length&&!i.length)return null;const n=`${this._space}|${this._cfgEpoch}|${e.rooms.length}`;if(!this._wallUnionCache||this._wallUnionCache.key!==n){const r=pm(this._wallUnionPool,n);if(r.hit)this._wallUnionCache=r.value;else{const r=this._openCuts(),o=this._roomWallOpeningInputs(),s=Ls(e.rooms,t,r,o,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm,i);s&&Object.defineProperty(s,"sourceFingerprint",{value:zl([this._curSpaceCfg,this._cellCm,this._gridPitch]),enumerable:!1});const a={key:n,value:s};_m(this._wallUnionPool,n,a,8),this._wallUnionCache=a}}return this._wallUnionCache.value}_thickWallCuts(){const e=this._spaceModel();if(!e)return[];const t=this._spaceWalls;if(!t.length)return[];const i=this._openCuts();return Ws(e.rooms,t,i,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm).map(e=>[e.a[0],e.a[1],e.b[0],e.b[1]])}_innerRoomContour(e,t,i=this._openCuts(),n=this._wallUnionGeometry()?.roomGeom,r=this._wallUnionGeometry()?.multiWallNodes){const o=i.map(e=>e.join(",")).join(";"),s=`${e.id}|${this._cfgEpoch}|${t}|${o}`,a=pm(this._innerContourCache,s);if(a.hit)return a.value;const l=xs(e.rooms,t,this._spaceWalls,i,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm,n,r);return _m(this._innerContourCache,s,l,600),l}_wallThickHit(e){return this._editorRuntimeOrThrow()._wallThickHit(e)}get _wallThickHover(){if(!this._markup||"wallthick"!==this._tool||!this._cursorPt||this._wallDialog)return null;const e=this._wallThickHit(this._cursorPt);if(!e)return null;const t=function(e,t,i){const n=Number.isFinite(e)&&e>0?e:0,r=Number.isFinite(t)&&t>0?t:5,o=Number.isFinite(i)&&i>0?i:0;return n>0?yo(n,r,o)/2:Sa(1.5*o,r)}(e.cm,this._cellCm,this._gridPitch);let i="";for(const n of e.segs)i+=(i?" ":"")+Yo([[n[0],n[1]],[n[2],n[3]]],t,!1);return{segs:e.segs,open:e.open,d:i}}_wallThickClick(e){return this._editorRuntimeOrThrow()._wallThickClick(e)}_wallThickApply(e){return this._editorRuntimeOrThrow()._wallThickApply(e)}_wallHatchDefs(e){const t=mo(this._cellCm);return B` + + + + `}_resolvedRoomFills(e,t){const i=new Map,n=new Map;for(const r of e.rooms){const e=this._roomDialog&&r.id===this._roomEditId?this._roomFill||t.fill:Tn(t.fill,r),o=this._roomDialog&&r.id===this._roomEditId?this._roomCustomFill||t.customFill:tn(t.customFill,r),s=ln(e,"lqi"===e&&r.area?this._roomLqi(r.area):null,"light"===e?Oh(zh(this._renderPlanHass,this._renderDevices,r,this._virtualLights)):"none","temp"===e?this._roomTemp(r):null,t.tempMin,t.tempMax,this._fillColors,o);i.set(r,s),r.id&&n.set(r.id,s)}return{byRoom:i,byId:n}}_spaceDisplayForRender(){const e=nn(this._curSpaceCfg),t=this._spaceDialog;return t&&"edit"===t.mode&&t.spaceId===this._space?{...e,showBorders:t.showBorders,showNames:t.showNames,hideDecor:t.hideDecor,hideOpenings:t.hideOpenings,color:t.roomColor,opacity:t.roomOpacity,fill:t.fillMode,customFill:t.customFill?en(t.customFill):Qi,glow:t.glowEnabled,tempMin:t.tempMin,tempMax:t.tempMax,showLqi:t.showLqi,cardFontScale:t.cardFontScale,labelTemp:t.labelTemp,labelHum:t.labelHum,labelLqi:t.labelLqi,labelLight:t.labelLight}:e}_openingWallIndexFor(e,t){const i=e.rooms.map(e=>`${e.id}:${e.poly?.map(e=>e.join(",")).join("/")||`${e.x},${e.y},${e.w},${e.h}`}`).join(";"),n=this._spaceWalls.map(e=>`${e.key}:${e.a?.join(",")||""}:${e.b?.join(",")||""}:${e.cm}`).join(";"),r=t.map(e=>e.join(",")).join(";"),o=[e.id,this._cfgEpoch,this._wallKeyPitch,this._cellCm,this._gridPitch,i,n,r].join("|");let s=this._openingWallIndexCache.get(o);return s||(s=Bs(e.rooms,this._spaceWalls,t,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm)),_m(this._openingWallIndexCache,o,s,4),{key:o,value:s}}_renderOpeningTunnelFills(e,t,i="data"){if(this._markup||!this._spaceWalls.length||!this._openingsR.length)return B``;if("glow-base"===i&&![...t.byRoom.values()].some(Boolean))return B``;const n=this._openCuts(),r=this._openingsR.map(e=>({x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),o=r.map(e=>`${e.x},${e.y},${e.angle},${e.length}`).join(";"),s=this._openingWallIndexFor(e,n),a=`${s.key}|${o}`;return this._openingTunnelCache&&this._openingTunnelCache.key===a||(this._openingTunnelCache={key:a,value:Xs(s.value,r)}),np({openings:this._openingsR,geometries:this._openingTunnelCache.value,fillsByRoomId:t.byId,idPrefix:`${e.id}-${i}`,groupClass:"data"===i?"opening-tunnels":"opening-tunnels glow-base-tunnels",dataLayer:i})}_resolvedGlowBase(e,t,i){const n=new Map,r=new Map,o=this._fillColors.glow_base;for(const s of e.rooms){const e=i.byRoom.get(s),a=Cn(t.glow,s)&&(!e||e.opacity<=0)?{color:o.c,opacity:o.a,mode:"glow"}:null;n.set(s,a),s.id&&r.set(s.id,a)}return{byRoom:n,byId:r}}_renderGlowBaseRooms(e,t){if(this._markup||![...t.byRoom.values()].some(Boolean))return B``;const i=new Map(e.rooms.map(e=>[e,Zt(e)])),n=this._openCuts(),r=this._wallUnionGeometry()?.roomGeom,o=e=>"M "+e.map(e=>e[0]+" "+e[1]).join(" L ")+" Z",s=e.rooms.map(s=>{const a=t.byRoom.get(s)||null,l=i.get(s)||null;if(!a||!l)return U;const c=this._spaceWalls.length&&s.id&&this._innerRoomContour(e,s.id,n,r)||l,h=yi(c,e.rooms.filter(e=>e!==s).map(e=>i.get(e)).filter(e=>!!e)),d=this._cleanFloor(s,c,e).path;return d||h.length?B``:s.poly||c!==l?B``:B``});return B``}_renderWallBodies(e){if("iso"===this._renderProjection)return B``;if(e&&!e.showBorders&&("view"===this._mode||"devices"===this._mode))return B``;const t=this._wallUnionGeometry();if(!t)return B``;const i=this._stageEl,n=this._viewOr(this._baseVb()),r=i&&i.clientWidth&&n.w?i.clientWidth/n.w:1,o=e?.color||"#607d8b",s=_o(t.depthUnits,r)||fo(mo(this._cellCm),r),a=this._fillColors.wall_fill;return B` + ${t.paths.map(e=>B` + + `)} + `}_isoDecorationLayers(e){const t="undefined"==typeof CSS||"function"!=typeof CSS.supports||CSS.supports("filter","blur(1px)"),i="function"==typeof matchMedia&&matchMedia("(forced-colors: active)").matches;return function(e){const t=!!e.showBorders;return{structural:t,panels:t&&!e.hideOpenings,shadows:t&&e.filtersSupported&&!e.forcedColors,materialNuance:t&&!e.forcedColors,floorSymbols:!e.hideOpenings&&!t}}({showBorders:e.showBorders,hideOpenings:e.hideOpenings,filtersSupported:t,forcedColors:i})}_isoOpeningPanels(e){if(!e.panels)return[];const t=this._isoScene();if(!t)return[];return t.openings.flatMap(e=>{const t=this._openingsR[e.sourceIndex];return t?J_(e,this._openingAmt(t)):[]}).sort((e,t)=>e.depth-t.depth||e.sourceIndex-t.sourceIndex||e.leaf-t.leaf)}_renderIsoDefs(e,t){const i=$a(this._cellCm);return B` + ${"walls"===t&&e.materialNuance?B` + + + + + + `:U} + ${"underlay"===t&&e.shadows?B` + + + `:U} + ${"shadows"===t&&e.shadows?B` + + + + + + `:U} + `}_renderIsoUnderlay(e){if(!e.structural)return B``;const t=this._isoScene()?.floor;return t?B``:B``}_renderIsoShadows(e,t){if(!e.shadows)return B``;const i=this._isoScene()?.geometry;return i?B``:B``}_renderIsoWalls(e,t){if("iso"!==this._renderProjection)return B``;if(!e.structural)return B``;const i=this._isoScene();return i?B` + ${this._renderIsoDefs(e,"walls")} + ${i.geometry.sides.map(e=>B``)} + + ${e.panels?B``:U} + `:B``}_roomHoverPaths(e){const t=this._hoverRoom;if("view"!==this._mode||!t||t.space!==e.id)return null;const i=e.rooms.find(e=>e===t.room||!!e.id&&e.id===t.room.id);if(!i)return null;const n=Zt(i);if(!n)return null;const r=e.rooms.filter(e=>e!==i).map(e=>({room:e,poly:Zt(e)})).filter(e=>!!e.poly),o=yi(n,r.map(e=>e.poly)),s=this._openCuts(),a=.02*this._gridPitch,l=s.filter(e=>{const t=[(e[0]+e[2])/2,(e[1]+e[3])/2];return n.some((e,i)=>Fn(t,[e[0],e[1],...n[(i+1)%n.length]])<=4*a)}),c=this._spaceWalls,h=this._wallUnionGeometry()?.roomGeom,d=c.length&&i.id&&this._innerRoomContour(e,i.id,s,h)||n,u=[{axis:n,face:d}];for(const t of o){const i=r.find(e=>e.poly===t)?.room;let n=t;if(c.length&&i?.id){const r=fs(e.rooms,i.id,c,s,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm);r&&(n=js(r.poly,r.offsets)||t)}u.push({axis:t,face:n})}const p=this._roomWallOpeningInputs(this._openingsR,e).map(e=>{const t=e.angle*Math.PI/180,i=Math.cos(t)*e.length/2,n=Math.sin(t)*e.length/2;return[e.x-i,e.y-n,e.x+i,e.y+n]}),_=l.concat(p),m=u.map(({axis:e,face:t})=>{const i=_.map(i=>((e,t,i)=>{const n=e[2]-e[0],r=e[3]-e[1],o=Math.hypot(n,r);if(o.05)&&Fn([c,h],[i[0],i[1],n[0],n[1]])<=4*a){d=!0;break}}if(!d)return null;let u=null;for(let e=0;e.05)continue;const p=Fn([c,h],[t[0],t[1],n[0],n[1]]);(!u||p!!e);return i.length?xn(t,i,a).map(e=>`M ${e[0]} ${e[1]} L ${e[2]} ${e[3]}`).join(" "):`M ${t.map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`}).filter(Boolean).join(" ");if(!m)return null;const f=e=>`M ${e.map(e=>`${e[0]} ${e[1]}`).join(" L ")} Z`;return{fillD:[this._cleanFloor(i,d,e).path||f(d),...o.map(f)].join(" "),outlineD:m}}_renderRoomHoverFill(e){return e?B` + + `:B``}_renderRoomHoverOutline(e){return e?B` + + + `:B``}_renderWallThickUi(){return this._editorRuntime?this._editorRuntimeOrThrow()._renderWallThickUi():B``}_renderWallThickDialog(){return this._editorRuntimeOrThrow()._renderWallThickDialog()}_openingAt(e){return this._editorRuntimeOrThrow()._openingAt(e)}_resolveOpeningPlacement(e){return this._editorRuntimeOrThrow()._resolveOpeningPlacement(e)}_activateOpeningPlacement(e){return this._editorRuntimeOrThrow()._activateOpeningPlacement(e)}_clearOpeningPlacement(e){return this._editorRuntime?this._editorRuntimeOrThrow()._clearOpeningPlacement(e):(this._openingHoverCandidate=null,this._openingJambBlockCm=null,void(e&&(this._openingPreset=null,this._openingRebindId=null)))}_openingClick(e){return this._editorRuntimeOrThrow()._openingClick(e)}_editOpening(e){if(this._editorRuntime)return this._editorRuntimeOrThrow()._editOpening(e)}_opPointerDown(e,t){if(this._editorRuntime)return this._editorRuntimeOrThrow()._opPointerDown(e,t)}_opPointerMove(e,t){if(this._editorRuntime)return this._editorRuntimeOrThrow()._opPointerMove(e,t)}_opRuler(e,t){return this._editorRuntimeOrThrow()._opRuler(e,t)}_opPointerUp(e,t){if(this._editorRuntime)return this._editorRuntimeOrThrow()._opPointerUp(e,t)}_opClick(e,t){if(this._editorRuntime)return this._editorRuntimeOrThrow()._opClick(e,t)}_saveOpening(){return this._editorRuntimeOrThrow()._saveOpening()}_deleteOpening(){return this._editorRuntimeOrThrow()._deleteOpening()}_contactCandidates(){return this._editorRuntimeOrThrow()._contactCandidates()}_lockCandidates(){return this._editorRuntimeOrThrow()._lockCandidates()}_toggleOpeningEntityPicker(e){return this._editorRuntimeOrThrow()._toggleOpeningEntityPicker(e)}_filterOpeningEntities(e,t){return this._editorRuntimeOrThrow()._filterOpeningEntities(e,t)}_selectOpeningEntity(e,t){return this._editorRuntimeOrThrow()._selectOpeningEntity(e,t)}_mergeClick(e){return this._editorRuntimeOrThrow()._mergeClick(e)}_commitMerge(){return this._editorRuntimeOrThrow()._commitMerge()}_splitClick(e){return this._editorRuntimeOrThrow()._splitClick(e)}get _contourClosed(){return this._path.length>=4&&this._samePt(this._path[0],this._path[this._path.length-1])&&(null!=this._closingWallCm||!this._activeDraftId)}_markupMove(e){if(this._markup&&this._editorRuntime)return this._editorRuntime._markupMove(e)}get _openingPreview(){const e=this._openingPreset;if("opening"!==this._tool||!e||!this._cursorPt)return null;const t=this._cursorPt,i=this._openingHoverCandidate;if(i&&am(i,[t[0],t[1]],e.revision,this._cfgEpoch))return i;if(this._openingAt(t))return this._openingHoverCandidate=null,null;const n=this._resolveOpeningPlacement(t);return this._openingHoverCandidate=n,n}get _opMeasureView(){return this._opMeasure||this._openingPreview?.measure||null}_saveRoom(){return this._editorRuntimeOrThrow()._saveRoom()}_decideWallFace(e){return this._editorRuntimeOrThrow()._decideWallFace(e)}_wallSourceCmAt(e,t,i){return this._editorRuntimeOrThrow()._wallSourceCmAt(e,t,i)}_activePathWithRepair(e,t){return this._editorRuntimeOrThrow()._activePathWithRepair(e,t)}_validateWallRepair(e,t){return this._editorRuntimeOrThrow()._validateWallRepair(e,t)}_applyWallRepair(e,t){return this._editorRuntimeOrThrow()._applyWallRepair(e,t)}_applyWallFaceBatch(){return this._editorRuntimeOrThrow()._applyWallFaceBatch()}_commitRoom(){return this._editorRuntimeOrThrow()._commitRoom()}_cancelPath(){return this._editorRuntimeOrThrow()._cancelPath()}_resumeLastDraft(){return this._editorRuntimeOrThrow()._resumeLastDraft()}_roomDialogCancel(){return this._editorRuntimeOrThrow()._roomDialogCancel()}get _freeAreas(){const e=new Set;for(const t of this._serverCfg?.spaces||[])for(const i of t.rooms||[])i.area&&e.add(i.area);for(const t of this._wallFaceBatch?.decisions||[])t.create&&t.area&&e.add(t.area);return Object.values(this.hass?.areas||{}).filter(t=>!e.has(t.area_id)).sort((e,t)=>(e.name||"").localeCompare(t.name||""))}_openDeviceInbox(){return this._editorRuntimeOrThrow()._openDeviceInbox()}_closeMarkerDialog(){return this._editorRuntimeOrThrow()._closeMarkerDialog()}_deviceInboxCandidates(e){return this._editorRuntimeOrThrow()._deviceInboxCandidates(e)}_deviceInboxRows(){return this._editorRuntimeOrThrow()._deviceInboxRows()}_deviceForInboxRow(e){return this._editorRuntimeOrThrow()._deviceForInboxRow(e)}_openInboxMarker(e,t=!1){return this._editorRuntimeOrThrow()._openInboxMarker(e,t)}async _setInboxHidden(e,t){return this._editorRuntimeOrThrow()._setInboxHidden(e,t)}_findInboxDevice(e){return this._editorRuntimeOrThrow()._findInboxDevice(e)}_deviceInboxTabKey(e){return this._editorRuntimeOrThrow()._deviceInboxTabKey(e)}_openMarkerDialog(e){if(this._editorRuntime)return this._editorRuntime._openMarkerDialog(e);this._ensureEditorRuntime().then(t=>{t&&this._openMarkerDialog(e)})}_runCandidates(){return this._editorRuntimeOrThrow()._runCandidates()}_bindingCandidates(){return this._editorRuntimeOrThrow()._bindingCandidates()}_physicalBodiesR(e=this._spaceModel()){if(!e)return[];const t=`${e.id}|${this._cfgEpoch}|${this._cellCm}|${this._gridPitch}`;if(this._physicalBodiesCache?.key===t)return this._physicalBodiesCache.all;const i=da(e,this._cellCm,this._gridPitch,2e-4*this._gridPitch,this._partitionOpeningCuts(e));return this._physicalBodiesCache={key:t,...i},i.all}_rawPhysicalBodiesR(e=this._spaceModel()){if(!e)return[];this._physicalBodiesR(e);const t=this._physicalBodiesCache;return t?[...t.drafts,...t.partitions,...t.columns]:[]}_cleanFloor(e,t,i=this._spaceModel()){if(!i)return{floor:t,geom:null,path:"",area:ga([[[...t,t[0]]]])};const n=e.id||`#${i.rooms.indexOf(e)}`,r=`${i.id}|${this._cfgEpoch}|${n}`;if(!this._resize?.preview){const e=pm(this._cleanFloorCache,r);if(e.hit)return e.value}const o=t.map(e=>e[0]),s=t.map(e=>e[1]),a=[Math.min(...o),Math.min(...s),Math.max(...o),Math.max(...s)],l=this._physicalBodiesR(i).filter(e=>{const t=e.map(e=>e[0]),i=e.map(e=>e[1]);return Math.max(...t)>=a[0]&&Math.min(...t)<=a[2]&&Math.max(...i)>=a[1]&&Math.min(...i)<=a[3]}),c=l.length?fa(t,l):null,h={floor:t,geom:c,path:c?oa(c):"",area:ga(c||[[[...t,t[0]]]])};return this._resize?.preview||_m(this._cleanFloorCache,r,h,600),h}_autoIconForBinding(e){if("virtual"===e)return"mdi:map-marker";const[t,i]=e.split(":");if(!i)return"";const n=this._fullRegistryHass,r=this._bindingStatus(e),o="active"===r.kind?r.enabledEntityIds:r.allEntityIds;if("device"===t){const e=n.devices?.[i];if(!e)return"mdi:help-circle";const t=o;return t.some(e=>e.startsWith("lock."))?"mdi:lock":Lh(n,e.name_by_user||e.name||"",e.model,t,this._iconRules)}if("entity"===t){const e=n.entities?.[i],t=this.hass.states?.[i],r=e?.name||t?.attributes?.friendly_name||i;return i.startsWith("lock.")?"mdi:lock":Lh(n,r,"",[i],this._iconRules)}return""}_allRoomsFlat(){const e=[];for(const t of this._serverCfg?.spaces||[])for(const i of t.rooms||[])i.area?e.push({value:t.id+"#"+i.area,label:(t.title||t.id)+" · "+i.name}):i.id&&e.push({value:t.id+"#@"+i.id,label:(t.title||t.id)+" · "+i.name+" · "+this._t("marker.subarea")});return e}_errText(e){if(!e)return this._t("err.unknown");if("string"==typeof e)return e;if("invalid_passage_fields"===e.code){const t=String(e.message||e.error||"").match(/space=([^;]*);\s*opening=([^;]*);\s*fields=([^;]*)/);if(t){const e=this._serverCfg?.spaces?.find(e=>String(e.id)===t[1]),i={contact:"opening.contact_label",lock:"opening.lock_label",invert:"opening.invert",flip_h:"opening.flip_h",flip_v:"opening.flip_v"},n=t[3].split(",").filter(Boolean).map(e=>i[e]?this._t(i[e]):e).join(", ");return this._t("opening.invalid_passage_fields",{room:e?.title||t[1],fields:n})}}if("invalid_partition_opening_jamb_margin"===e.code){const t=String(e.message||e.error||"").match(/margin_cm=([^;]*)/),i=t?Number(t[1]):NaN;if(Number.isFinite(i))return this._t("opening.partition_jamb_margin",{distance:Kt(i,this._imperial)})}if(e.message)return e.message;if(e.error)return e.error;if(null!=e.code)return this._t("err.code",{code:e.code});try{return JSON.stringify(e)}catch{return String(e)}}_backupErrorText(e){return this._editorRuntimeOrThrow()._backupErrorText(e)}async _pickMarkerFiles(e){return this._editorRuntimeOrThrow()._pickMarkerFiles(e)}_removeMarkerPdf(e){return this._editorRuntimeOrThrow()._removeMarkerPdf(e)}_markerLightFields(e){return this._editorRuntimeOrThrow()._markerLightFields(e)}_markerTapActionFields(e){return this._editorRuntimeOrThrow()._markerTapActionFields(e)}_markerToggleEntityFields(e){return this._editorRuntimeOrThrow()._markerToggleEntityFields(e)}async _saveMarker(){return this._editorRuntimeOrThrow()._saveMarker()}async _deleteMarker(){return this._editorRuntimeOrThrow()._deleteMarker()}_normPos(e,t,i){return{s:e,x:t/Mm,y:i/Mm}}_spaceDialogUsesOnboardingRuntime(e){return"create"===e&&!this._editorRuntime&&(!!this._onboardingRuntime||0===(this._serverCfg?.spaces.length||0)||this._importTotal>0||this._importQueue.length>0)}_spaceRuntimeOrThrow(){if(!this._onboardingRuntime)throw new Error("Houseplan onboarding runtime is not loaded");return this._onboardingRuntime}_openSpaceDialog(e,t){return this._spaceDialogUsesOnboardingRuntime(e)?this._onboardingRuntime?void this._onboardingRuntime._openSpaceDialog(e,t):void this._ensureOnboardingRuntime().then(i=>{i&&this._spaceRuntimeOrThrow()._openSpaceDialog(e,t)}):this._editorRuntime?this._editorRuntime._openSpaceDialog(e,t):void this._ensureEditorRuntime().then(i=>{i&&this._openSpaceDialog(e,t)})}async _pickPlanFile(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._pickPlanFile(e):this._editorRuntimeOrThrow()._pickPlanFile(e)}_useServerPlan(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._useServerPlan(e):this._editorRuntimeOrThrow()._useServerPlan(e)}async _readPlanAspect(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._readPlanAspect(e):this._editorRuntimeOrThrow()._readPlanAspect(e)}async _deleteServerPlan(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._deleteServerPlan(e):this._editorRuntimeOrThrow()._deleteServerPlan(e)}_renderServerPlans(e){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime(e.mode)?this._onboardingRuntime._renderServerPlans(e):this._editorRuntimeOrThrow()._renderServerPlans(e)}async _saveSpaceDialog(){return this._onboardingRuntime&&this._spaceDialogUsesOnboardingRuntime("create")?this._onboardingRuntime._saveSpaceDialog():this._editorRuntimeOrThrow()._saveSpaceDialog()}async _deleteSpace(){return this._editorRuntimeOrThrow()._deleteSpace()}async _saveConfigNow(){return this._editorRuntimeOrThrow()._saveConfigNow()}_startImport(){return this._onboardingRuntime?this._onboardingRuntime._startImport():this._editorRuntimeOrThrow()._startImport()}_openNextImport(){return this._onboardingRuntime?this._onboardingRuntime._openNextImport():this._editorRuntimeOrThrow()._openNextImport()}_skipImport(){return this._onboardingRuntime?this._onboardingRuntime._skipImport():this._editorRuntimeOrThrow()._skipImport()}_renderImportDialog(){return this._onboardingRuntime?this._onboardingRuntime._renderImportDialog():this._editorRuntimeOrThrow()._renderImportDialog()}_sunGlobal(){const e=this._settingsDialog;return e?{...this._settings,north_deg:e.northDeg??void 0,bg_mode:e.bgMode,sun_rays:e.sunRays}:this._settings}_sunSpace(){const e=this._spaceDialog,t=this._curSpaceCfg?.settings||{};return e&&"edit"===e.mode&&e.spaceId===this._space?{...t,north_deg:e.northDeg??void 0,bg_mode:e.bgMode??void 0,sun_rays:e.sunRays??void 0}:t}_effNorth(){return sr(this._sunGlobal(),this._sunSpace())}_effBgMode(){return ar(this._sunGlobal(),this._sunSpace())}_dayCycleState(e=new Date){return(this._modeTransitionVisual?.viewWeight??("view"===this._mode?1:0))<=0||"daynight"!==this._effBgMode()?null:Zn(this._renderPlanHass,e)}_syncDayCycleClock(){const e=this._dayCycleState();this._dayCycleClockKey=e?Xn(e):"";const t="clock"===e?.source&&"hidden"!==this.ownerDocument.visibilityState&&this.isConnected;t&&!this._dayCycleTimer?this._dayCycleTimer=window.setInterval(this._dayCycleTick,3e4):!t&&this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_dayCycleVisibility(e){"hidden"!==e.kind?(this._dayCycleTick(),this._syncDayCycleClock()):this._dayCycleTimer&&(clearInterval(this._dayCycleTimer),this._dayCycleTimer=0)}_effSunRays(){return lr(this._sunGlobal(),this._sunSpace())}_sunNow(){return null!==this._effNorth()?cr(this._renderPlanHass):null}_renderSunRays(e){const t=B``,i=this._modeTransitionVisual?.viewWeight??0;if(this._editing&&i<=0||!this._effSunRays())return this._sunFadeReset(),t;const n=this._effNorth(),r=null!==n?cr(this._renderPlanHass):null;if(!r||r.elevation<=0)return this._sunFadeReset(),t;if(o=r.elevation,Number(o)>=3)this._sunOutTimer&&(clearTimeout(this._sunOutTimer),this._sunOutTimer=0),this._sunOut=!1,this._sunShown=!0;else{if(!this._sunShown)return t;this._sunOut||(this._sunOut=!0,this._sunOutTimer=window.setTimeout(()=>{this._sunOutTimer=0,this._sunShown=!1,this._sunOut=!1,this.requestUpdate()},2e3))}var o;const s=this._zeroWalls(),a=s.barriers.map(e=>e.join(",")).join(";"),l=`${e.id}|${r.azimuth}|${r.elevation}|${n}|${this._cfgEpoch}|${s.style}|${a}`;if(!this._sunRaysCache||this._sunRaysCache.key!==l){const t=e.rooms.map(e=>({id:e.id||"",poly:Zt(e)})).filter(e=>!!e.id&&!!e.poly),i=this._openingsR.filter(e=>"window"===e.type&&"partition"!==e.host?.kind).map(e=>({id:e.id,x:e.rx,y:e.ry,angle:e.angle,length:e.rlen})),o=this._spaceWalls,a=this._openCuts(),c=this._openingWallIndexFor(e,a).value,h={},d={},u=this._wallUnionGeometry()?.roomGeom;if(o.length){for(const i of t){const t=this._innerRoomContour(e,i.id,a,u);t&&(h[i.id]=t)}for(const e of i){const t=Ks(c,{x:e.x,y:e.y,angle:e.angle,length:e.length});t.cm>0&&(d[e.id]=yo(t.cm,this._cellCm,this._gridPitch))}}let p=rr(t,i,r.azimuth,r.elevation,n,o.length?h:void 0,o.length?d:void 0);const _=[...this._physicalBodiesR(e),...s.barriers.map(e=>[[e[0],e[1]],[e[2],e[3]]])];_.length&&(p=p.map(e=>{const t=function(e,t,i){return i>0?e.map(e=>function(e){const t=[...e].sort((e,t)=>e[0]-t[0]||e[1]-t[1]);if(t.length<=2)return t;const i=(e,t,i)=>(t[0]-e[0])*(i[1]-e[1])-(t[1]-e[1])*(i[0]-e[0]),n=[];for(const e of t){for(;n.length>=2&&i(n[n.length-2],n[n.length-1],e)<=0;)n.pop();n.push(e)}const r=[];for(let e=t.length-1;e>=0;e--){const n=t[e];for(;r.length>=2&&i(r[r.length-2],r[r.length-1],n)<=0;)r.pop();r.push(n)}return n.slice(0,-1).concat(r.slice(0,-1))}([...e,...e.map(e=>[e[0]+t[0]*i,e[1]+t[1]*i])])).filter(e=>e.length>=3):e}(_,e.dir,e.len),i=e.polys.map(e=>fa(e,t));return{...e,paths:i.map(oa).filter(Boolean),polys:i.flatMap(ya)}}).filter(e=>e.paths?.length||e.polys.length)),this._sunRaysCache={key:l,rays:p,rims:p.map(e=>function(e,t=1e-4){const[i,n]=e.dir,r=-n,o=i,s=[];for(const a of[e.a,e.b]){const l=[];for(const s of e.polys)for(let e=0;et)continue;if(Math.abs((h[0]-a[0])*r+(h[1]-a[1])*o)>t)continue;const d=(c[0]-a[0])*i+(c[1]-a[1])*n,u=(h[0]-a[0])*i+(h[1]-a[1])*n;Math.abs(u-d)<=t||l.push(de[0]-t[0]);const c=[];for(const e of l){const i=c[c.length-1];i&&e[0]<=i[1]+t?i[1]=Math.max(i[1],e[1]):c.push([e[0],e[1]])}for(const[e,t]of c)s.push([[a[0]+i*e,a[1]+n*e],[a[0]+i*t,a[1]+n*t]])}return s}(e))}}const c=this._sunRaysCache.rays,h=this._sunRaysCache.rims;if(!c.length)return t;const d=(u=function(e){const t=Math.min(90,Math.max(-90,Number(e)||0));let i=Jn[Jn.length-1][1];for(let e=1;e + ${c.map((e,t)=>{const i=(e.a[0]+e.b[0])/2,n=(e.a[1]+e.b[1])/2,r=i+e.normal[0]*e.depth,o=n+e.normal[1]*e.depth;return B` + ${p.map(([e,t])=>B``)} + + + ${_.map(([e,t])=>B``)} + `})} + + + ${c.map((e,t)=>e.paths?.length?e.paths.map(e=>B``):e.polys.map(e=>B``))} + ${c.map((e,t)=>(h[t]||[]).map(e=>B``))} + `}_sunFadeReset(){this._sunOutTimer&&(clearTimeout(this._sunOutTimer),this._sunOutTimer=0),this._sunShown=!1,this._sunOut=!1}_compassPoint(e){const t=e.currentTarget.getBoundingClientRect(),i=e.clientX-(t.left+t.width/2),n=e.clientY-(t.top+t.height/2);if(Math.hypot(i,n)<5)return;let r=Math.round(180*Math.atan2(i,-n)/Math.PI);e.shiftKey&&(r=15*Math.round(r/15)),r=(r%360+360)%360,this._settingsDialog={...this._settingsDialog,northDeg:r}}_renderCompass(){const e=this._settingsDialog.northDeg;return j`{e.currentTarget.setPointerCapture(e.pointerId),this._compassDrag=!0,this._compassPoint(e)}} + @pointermove=${e=>{this._compassDrag&&this._compassPoint(e)}} + @pointerup=${()=>this._compassDrag=!1} + @pointercancel=${()=>this._compassDrag=!1}> + + ${[0,45,90,135,180,225,270,315].map(e=>B``)} + + + + ${this._t("gs.north_letter")} + + ${null===e?"—":e+"°"} + `}_stageBg(e){const t=this._settingsDialog,i=this._spaceDialog,n=t?t.bgColor||"":rn(this._settings,{bgColor:null});return(i&&"edit"===i.mode&&i.spaceId===this._space?i.bgColor||"":e.bgColor||"")||n}_stageBgHex(){const e=this._stageEl;if(e){const t=getComputedStyle(e).backgroundColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);if(t)return"#"+t.slice(1,4).map(e=>(+e).toString(16).padStart(2,"0")).join("")}return"#111111"}_preflightDiagnostics(e,t){return this._editorRuntimeOrThrow()._preflightDiagnostics(e,t)}_reportPreflightFailure(e,t){return this._editorRuntimeOrThrow()._reportPreflightFailure(e,t)}_preflightVersionsDiffer(){return this._editorRuntimeOrThrow()._preflightVersionsDiffer()}async _copyPreflightDiagnostics(){return this._editorRuntimeOrThrow()._copyPreflightDiagnostics()}_checkOptimizeGeometry(e){return this._editorRuntimeOrThrow()._checkOptimizeGeometryImpl(e)}_checkSpacePhysicalGeometry(e,t,i){return this._editorRuntimeOrThrow()._checkSpacePhysicalGeometryImpl(e,t,i)}_optimizeReferenceContext(e){return this._editorRuntimeOrThrow()._optimizeReferenceContext(e)}_previewAlignDialog(e){return this._editorRuntimeOrThrow()._previewAlignDialog(e)}async _runAlignToGrid(){return this._editorRuntimeOrThrow()._runAlignToGrid()}async _undoPlanOptimization(){return this._editorRuntimeOrThrow()._undoPlanOptimization()}async _runBackupExport(){return this._editorRuntimeOrThrow()._runBackupExport()}async _pickBackupImport(e){return this._editorRuntimeOrThrow()._pickBackupImport(e)}async _setBackupDuplicatePolicy(e){return this._editorRuntimeOrThrow()._setBackupDuplicatePolicy(e)}async _applyBackupImport(){return this._editorRuntimeOrThrow()._applyBackupImport()}_renderBackupExportDialog(){return this._editorRuntimeOrThrow()._renderBackupExportDialog()}_renderBackupImportDialog(){return this._editorRuntimeOrThrow()._renderBackupImportDialog()}_setFillColor(e,t){return this._editorRuntimeOrThrow()._setFillColor(e,t)}async _saveSettingsDialog(){return this._editorRuntimeOrThrow()._saveSettingsDialog()}_boolInput(e,t,i=!1){return this._editorRuntimeOrThrow()._boolInput(e,t,i)}_rangeInput(e,t,i,n,r,o=!1,s){return this._editorRuntimeOrThrow()._rangeInput(e,t,i,n,r,o,s)}_renderColorRow(e,t){return this._editorRuntimeOrThrow()._renderColorRow(e,t)}get _glowRadiusCm(){const e=Number(this._settings.glow_radius_cm);return Number.isFinite(e)&&e>0?e:300}get _imperial(){return"mi"===this.hass?.config?.unit_system?.length}get _glowRadiusPlaceholder(){const e=this._glowRadiusCm;return this._imperial?String(Math.round(e/30.48*10)/10):String(e/100)}_glowTransition(e,t){let i=this._glowRenderedSources.get(e);if(t){const t=this._glowFadeTimers.get(e);if(null!=t&&(clearTimeout(t),this._glowFadeTimers.delete(e)),null==i){this._suspendGlowFeatherForTransition(),i=++this._glowSourceSeq,this._glowRenderedSources.set(e,i),this._glowEnteringSources.add(e);const t=requestAnimationFrame(()=>{this._glowEnterRafs.get(e)===t&&(this._glowEnterRafs.delete(e),this._glowEnteringSources.delete(e),this.isConnected&&this.requestUpdate())});this._glowEnterRafs.set(e,t)}return{domId:i,entering:this._glowEnteringSources.has(e),leaving:!1}}if(null==i)return null;const n=this._glowEnterRafs.get(e);if(null!=n&&cancelAnimationFrame(n),this._glowEnterRafs.delete(e),this._glowEnteringSources.delete(e),!this._glowFadeTimers.has(e)){this._suspendGlowFeatherForTransition();const t=window.setTimeout(()=>{this._glowFadeTimers.get(e)===t&&(this._glowFadeTimers.delete(e),this._glowRenderedSources.delete(e),this._glowLastAppearance.delete(e),this.isConnected&&this.requestUpdate())},534);this._glowFadeTimers.set(e,t)}return{domId:i,entering:!1,leaving:!0}}_suspendGlowFeatherForTransition(){if(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches)return;this._glowFeatherSuspendUntil=Math.max(this._glowFeatherSuspendUntil,Date.now()+500),clearTimeout(this._glowFeatherResumeTimer);const e=Math.max(0,this._glowFeatherSuspendUntil-Date.now())+17,t=()=>{this._glowFeatherResumeTimer=0,Date.now()=128){const e=this._glowGeometryWarnings.values().next().value;e&&this._glowGeometryWarnings.delete(e)}this._glowGeometryWarnings.add(r),console.warn(`HOUSEPLAN GLOW GEOMETRY FALLBACK: #218, space ${e}, room ${i}, phase ${n}`)}}_lightBarriers(e,t){const i=zl([this._curSpaceCfg,this._cellCm,this._gridPitch]),n=Math.max(this._cmToUnits(10),.5*this._gridPitch),r=e=>t.some(t=>this._pointInRoom(e,t.r)),o=this._openingsR.flatMap(e=>{if("door"!==(t=String(e.type))&&"gate"!==t&&"passage"!==t)return[];var t;const i=e,o=i.angle*Math.PI/180,s=-Math.sin(o),a=Math.cos(o);return r([i.rx+s*n,i.ry+a*n])&&r([i.rx-s*n,i.ry-a*n])?[{opening:i,amount:this._openingAmt(i)}]:[]});const s=zl([i,o.map(({opening:e,amount:t})=>({id:e.id,type:e.type,contact:e.contact,amount:t})).filter(e=>!!e.contact&&("door"===e.type||"gate"===e.type)).map(e=>{const t=Math.max(0,Math.min(1,Number(e.amount)||0));return`${e.id}:${t.toFixed(3)}`}).sort().join("|")]),a=`${e.id}|${s}`,l=pm(this._lightBarrierPool,a);if(l.hit)return this._lightBarrierCache=l.value,l.value.value;const c=this._zeroWalls(),h=this._openCuts(),d=[...c.transmissive],u=o.filter(({amount:e})=>e>0).map(({opening:e,amount:t})=>({...e,rlen:ni(e.rlen,t)})),p=this._roomWallOpeningInputs(u,e);for(const e of p){const t=e.angle*Math.PI/180,i=Math.cos(t)*e.length/2,n=Math.sin(t)*e.length/2;d.push([e.x-i,e.y-n,e.x+i,e.y+n])}const _=o.flatMap(({opening:e,amount:t})=>t>0&&e.partitionHost?[la(Id(e.partitionHost),t)]:[]),m=a;this._lightPhysicalBodiesCache?.key!==m&&(this._lightPhysicalBodiesCache={key:m,all:da(e,this._cellCm,this._gridPitch,2e-4*this._gridPitch,_).all});const f=this._lightPhysicalBodiesCache.all,g=this._spaceWalls,v=.02*this._gridPitch,y=[],b=this._wallUnionGeometry(),w=b?.sourceFingerprint,k=b&&w===i?function(e,t=[],i=[],n={}){if("failed-core"===e.status||"not-applicable"===e.status)return null;const r=e.roomComponents?.length?e.roomComponents:Ss(e.roomGeom)?[{id:"room-primary",geom:e.roomGeom}]:[];let o=r[0]?.geom||null;const s=r.slice(1).map(e=>({...e}));try{for(const i of t){if(!(i.length>0&&e.openingIndex))continue;const t=Gs(e.openingIndex,i,!0);if(!t.negative&&!t.positive)continue;const n=i.angle*Math.PI/180,r=Math.cos(n),a=Math.sin(n),l=-a,c=r,h=i.length/2,d=e.openingPadUnits??1.25*Math.max(e.depthUnits,1),u=$s([[i.x-r*h-l*d,i.y-a*h-c*d],[i.x+r*h-l*d,i.y+a*h-c*d],[i.x+r*h+l*d,i.y+a*h+c*d],[i.x-r*h+l*d,i.y-a*h+c*d]]);o&&(o=Nt(o,u));for(const e of s)e.geom=Nt(e.geom,u)}const r=[...s];let a=s.length;const l=n.mergeExtra||((e,t)=>e?It(e,t):t);for(let e=0;ee.length>=2&&Number.isFinite(e[0])&&Number.isFinite(e[1]))||Math.abs(bi(t))<=1e-9){a++;continue}const n=[$s(t)];try{const t=l(o,n,e);if(!Ss(t))throw new Error("invalid extra union");o=t}catch{a++,Ss(n)&&r.push({id:`policy-extra-${e}`,geom:n})}}r.sort((e,t)=>Es(e.geom).localeCompare(Es(t.geom)));const c=o||[];return{status:a?"degraded-extra":"ok",geom:c,components:[...Ss(c)?[{id:"primary",geom:c}]:[],...r.map((e,t)=>({...e,id:`isolated-${t}`}))]}}catch{return null}}(b,p,f):null,x=k||(g.length||f.length?Ns(e.rooms,g,h,p,this._wallKeyPitch,this._cellCm,this._gridPitch,Mm,f):null);if(!x||"ok"!==x.status&&"degraded-extra"!==x.status)for(const e of f)y.push(...Vd(e));else for(const e of x.components)for(const t of va(e.geom))y.push(...Vd(t));for(const{poly:e}of t)for(const t of d.length?xn(e,d,v):Vd(e))y.push(t);for(const e of c.barriers)y.push(e);const $={occluders:Bd(y),floor:t.map(e=>e.poly),fingerprint:s,masonryGeometry:!x||"ok"!==x.status&&"degraded-extra"!==x.status?[]:x.components.flatMap(e=>e.geom),opaqueBodies:f},S={key:a,value:$};return _m(this._lightBarrierPool,a,S,8),this._lightBarrierCache=S,$}_renderGlowLayer(e,t){const i=this._fillColors,n=this._glowRadiusCm/this._cellCm*this._gridPitch,r=e.rooms.map(e=>({r:e,poly:Zt(e)})).filter(e=>!!e.poly),o=r.filter(({r:e})=>Cn(t.glow,e));if(!o.length)return this._forgetGlowSpace(e.id),B``;const{occluders:s,floor:a,fingerprint:l,masonryGeometry:c,opaqueBodies:h}=this._lightBarriers(e,r),d=zh(this._renderPlanHass,this._renderDevices,null,this._virtualLights).filter(t=>t.device.space===e.id),u=new Map;for(const e of d){if(!e.device.id)continue;const t=u.get(e.device.id)||[];t.push(e),u.set(e.device.id,t)}const p=[],_=new Set;for(const t of this._renderDevices){if(t.space!==e.id)continue;const o=Ah(u.get(t.id)||[]);if(!o)continue;const d=`${e.id}|${t.id}`;_.add(d);const m=vn(o.passive?{state:o.on?"on":"off",attributes:{}}:this._renderPlanHass.states[o.eid],t.marker?.glow_color,i.glow_light.c),f=Number(t.marker?.glow_radius_cm),g=Number.isFinite(f)&&f>0?f/this._cellCm*this._gridPitch:n,v=this._pos(t);if(wa([v.x,v.y],c,h)){this._forgetGlowSource(d);continue}const y=this._glowTransition(d,!!m);if(!y)continue;m&&this._glowLastAppearance.set(d,{c:m.c,alpha:yn(m.bri,i.glow_light.a)});const b=this._glowLastAppearance.get(d);if(!b)continue;let w=null;const k=`${e.id}|${l}|${v.x.toFixed(4)},${v.y.toFixed(4)}|${g.toFixed(4)}`,x=pm(this._glowClipCache,k);if(x.hit)w=x.value;else{const t=Kd([v.x,v.y],g,s,96);w={lit:t.length>=3?ma([t],a,{onBoundsFailure:({boundIndex:t,phase:i})=>{const n=r[t]?.r;this._warnGlowGeometryFallback(e.id,l,n?.id||`#${t}`,i)}}):[]},_m(this._glowClipCache,k,w,256)}p.push({key:d,sourceEid:o.eid,domId:y.domId,entering:y.entering,leaving:y.leaving,pos:v,c:b.c,alpha:b.alpha,geometry:w,r:g})}const m=`${e.id}|`;for(const e of this._glowRenderedSources.keys())e.startsWith(m)&&!_.has(e)&&this._forgetGlowSource(e);if(!p.length)return B``;const f=this._spaceWalls,g=o.length===r.length?[]:this._openCuts(),v=this._wallUnionGeometry()?.roomGeom,y=o.length===r.length?null:o.map(({r:t,poly:i})=>{const n=f.length&&t.id&&this._innerRoomContour(e,t.id,g,v)||i,o=this._cleanFloor(t,n,e).path,s=yi(n,r.filter(e=>e.r!==t).map(e=>e.poly)),a=e=>"M "+e.map(e=>e[0]+" "+e[1]).join(" L ")+" Z";return[o||a(n),...s.map(a)].join(" ")}),b=this._viewOr(this._baseVb()),w=this._stageEl?.clientWidth&&b.w?this._stageEl.clientWidth/b.w:1,k=1/(w>0?w:1),x=!this._pinchStart&&!this._panStart&&Date.now()>=this._glowFeatherSuspendUntil;(null==this._glowFeatherUnits||x)&&(this._glowFeatherUnits=k);const $=this._glowFeatherUnits??k,S=4*$,M=p.reduce((e,t)=>({x:Math.min(e.x,t.pos.x-t.r-S),y:Math.min(e.y,t.pos.y-t.r-S),maxX:Math.max(e.maxX,t.pos.x+t.r+S),maxY:Math.max(e.maxY,t.pos.y+t.r+S),w:0,h:0}),{x:1/0,y:1/0,maxX:-1/0,maxY:-1/0,w:0,h:0});return M.w=M.maxX-M.x,M.h=M.maxY-M.y,B` + ${$e(p,e=>e.key,e=>{const t=e.domId,i=e.geometry;return B` + ${""} + + ${Rm.map(([t,i])=>B` + `)} + + ${""} + ${i?B` + + + `:U}`})} + ${y?B`${y.map(e=>B``)}`:U} + ${""} + + + + + ${""} + + + ${$e(p,e=>e.key,e=>{const t=e.domId;return B` + + + `})} + + `}_renderAlignDialog(){return this._editorRuntimeOrThrow()._renderAlignDialog()}_renderSettingsDialog(){return this._editorRuntimeOrThrow()._renderSettingsDialog()}_rulesSet(e){return this._editorRuntimeOrThrow()._rulesSet(e)}async _saveRules(){return this._editorRuntimeOrThrow()._saveRules()}_renderRulesDialog(){return this._editorRuntimeOrThrow()._renderRulesDialog()}_saveKioskScale(e){this._kioskScale={...this._kioskScale,...e};try{localStorage.setItem(xm,JSON.stringify(this._kioskScale))}catch{}this.requestUpdate()}_renderKioskDialog(){const e=this._kioskScale,t=(t,i)=>{const n=Math.round(100*e[t]);return j` +
+ {const i=Number(e.target.value);Number.isFinite(i)&&this._saveKioskScale({[t]:i/100})}} aria-label=${i} /> + ${n}% +
`};return j`this._kioskDialog=!1}> +
+
${this._t("kiosk.hint")}
+ ${t("icon",this._t("kiosk.icon_scale"))} + ${t("font",this._t("kiosk.font_scale"))} +
+
+ + + +
+
`}_fixedFloorValue(e){if("string"==typeof e)return e||"''";try{const t=JSON.stringify(e);return(void 0===t?String(e):t).slice(0,160)}catch{return String(e).slice(0,160)}}render(){if(!this._config||!this.hass)return U;const e=Qd(this,ru,hu(this.hass,this._config.language));if("cold"===e)return eu();if("warm"===e)return V;const t=!!this._importDialog||!(!this._spaceDialog||!this._spaceDialogUsesOnboardingRuntime(this._spaceDialog.mode)),i="view"!==this._mode||!!(this._roomDialog||this._mergeDialog||this._openingDialog||this._physicalDialog||this._partitionDeleteDialog||this._roomDeleteDialog||this._decorTextDialog||this._decorShapeDialog||this._backdropDialog||this._decorEraseConfirm||this._spaceDialog&&!this._spaceDialogUsesOnboardingRuntime(this._spaceDialog.mode)||this._deviceInbox||this._markerDialog||this._rulesDialog||this._settingsDialog||this._alignDialog||this._backupExportDialog||this._backupImportDialog||this._kioskDialog||this._vacFit||this._vacCalConfirm);t&&!this._onboardingRuntime&&this._ensureOnboardingRuntime(),i&&!this._editorRuntime&&this._ensureEditorRuntime();const n=this._model,r=this.houseplanDiagnostics(),o=this._fixedFloorState(n);if("pending"===o.kind)return j` +
+
${this._config.title||this._t("card.title")}
+
+
+ +

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

+
+
`;if("invalid"===o.kind)return j` +
+
${this._config.title||this._t("card.title")}
+
+ +
`;if(!n.length)return j` +
+
${this._config.title||this._t("card.title")}
+
+
+ +

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

+ ${this._serverStorage?j`

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

+ `:j`

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

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

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

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

${this._tapConfirm.text}

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

${e}

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

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

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

${this._reason(t.fallbackReason)}

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

${this._reason(t)}

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

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

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

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

`:a} +
+
+ ${t.visualSources.length||t.criticalSources.length?o`
+ ${this._t("marker.preview.details")} +
+ ${[...t.visualSources,...t.criticalSources].map(t=>o` +
+ ${t.name}${t.eid} + ${t.stateText||t.state} + ${this._sourceProvider(t.eid)} +
`)} +
+
`:a} + ${"icon_ripple"===t.display?o`
+ + +
`:a} +
`}}io.properties={hass:{attribute:!1},presentation:{attribute:!1},registry:{attribute:!1},deviceName:{attribute:!1}},io.styles=[c,n` + :host { display: block; min-width: 0; } + .devicepreview { + margin: 4px 0 14px; + padding: 14px; + border: 1px solid var(--divider-color, rgba(127, 127, 127, 0.28)); + border-radius: 14px; + background: color-mix(in srgb, var(--card-background-color, #20232b) 92%, var(--primary-color, #03a9f4)); + color: var(--primary-text-color, #fff); + overflow: hidden; + } + .previewhead { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; } + .previewbadge { + padding: 3px 9px; + border-radius: 999px; + color: var(--secondary-text-color, #9aa0aa); + background: color-mix(in srgb, var(--secondary-text-color, #9aa0aa) 12%, transparent); + font-size: 12px; + font-weight: 700; + } + .previewbadge.example { color: var(--warning-color, #ffb300); } + .previewgrid { display: grid; grid-template-columns: minmax(170px, 0.8fr) minmax(240px, 1.2fr); gap: 16px; align-items: stretch; } + .previewstage { + position: relative; + min-height: 168px; + border-radius: 12px; + background: var(--secondary-background-color, rgba(0, 0, 0, 0.16)); + overflow: hidden; + pointer-events: none; + container-type: inline-size; + --icon-size: 54px; + --device-base-size: 48.6px; + } + .previewfit { position: absolute; left: 50%; top: 50%; transform-origin: center; } + .previewstage .dev { left: 0; top: 0; cursor: default; } + :host([data-pointer-hover]) .previewstage .dev:hover { z-index: 2; } + .previewfacts { min-width: 0; display: grid; align-content: start; gap: 8px; } + .previewfacts > div { display: grid; grid-template-columns: minmax(115px, 0.8fr) minmax(0, 1.3fr); gap: 8px; } + .previewfacts span { color: var(--secondary-text-color, #9aa0aa); } + .previewfacts b { min-width: 0; overflow-wrap: anywhere; } + .previewnotice { margin: 2px 0 0; color: var(--secondary-text-color, #9aa0aa); font-size: 13px; } + .previewdetails { margin-top: 12px; } + .previewdetails summary { cursor: pointer; color: var(--secondary-text-color, #9aa0aa); } + .previewtable { display: grid; gap: 8px; margin-top: 9px; } + .previewsource { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 3px 10px; font-size: 13px; } + .previewsource > * { min-width: 0; overflow-wrap: anywhere; } + .previewsource code { color: var(--secondary-text-color, #9aa0aa); } + .previewdemo { + min-height: 40px; + display: inline-flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + border: 1px solid var(--divider-color, rgba(127, 127, 127, 0.35)); + border-radius: 10px; + background: transparent; + color: inherit; + cursor: pointer; + } + .previewdemos { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; } + .previewdemo:focus-visible { outline: 2px solid var(--primary-color, #03a9f4); outline-offset: 2px; } + .previewdemo:disabled { opacity: 0.5; cursor: not-allowed; } + @media (max-width: 640px) { + .previewgrid { grid-template-columns: minmax(0, 1fr); } + .previewstage { min-height: 142px; } + .previewfacts > div { grid-template-columns: minmax(0, 1fr); gap: 2px; } + } + `],customElements.get("hp-device-preview")||customElements.define("hp-device-preview",io);const oo=(t,e)=>[t[0]-e[0],t[1]-e[1]],ao=(t,e)=>[t[0]+e[0],t[1]+e[1]],no=(t,e)=>t[0]*e[0]+t[1]*e[1],ro=t=>Math.hypot(t[0],t[1]);function ho(t){let e=0;for(let s=0;st[1]!=h>t[1]&&t[0]<(r-a)*(t[1]-n)/(h-n)+a&&(s=!s)}return s}([r[0]+n[0]*h,r[1]+n[1]*h],t)&&(n=[-n[0],-n[1]]),n}function po(t){const e=t.length;if(e<3)return!1;for(let s=0;s(t[0]-o[0])*r[1]-(t[1]-o[1])*r[0],l=t=>(t[0]-o[0])*r[0]+(t[1]-o[1])*r[1],c=s,d=n-s;for(const e of t){const t=Math.abs(h(e));if(t<=s)continue;const o=l(e);o<=c||o>=d||tMath.abs(n+(t-p)/g*(r-n));i=Math.min(i,f(u),f(m))}}return i}function uo(t,e,s){if($(t,e,s))return!0;if(y(t,e,s)||y(e,t,s))return!1;let i=0;try{const s=w([[...t.map(t=>[t[0],t[1]]),[t[0][0],t[0][1]]]],[[...e.map(t=>[t[0],t[1]]),[e[0][0],e[0][1]]]]);for(const t of s)t?.[0]&&(i+=k(t[0]))}catch{return!1}return i>Math.max(1e-7,s*s)}function mo(t,e,s){for(const i of e)for(let e=0;es)continue;const l=(t.x-o[0])*h[0]+(t.y-o[1])*h[1];if(l-t.length/2>=-s&&l+t.length/2<=r+s)return!0}return!1}function go(t,e,s){const i=Math.abs(e[0]-t[0]),o=Math.abs(e[1]-t[1]);return i<=s&&o>s?"v":o<=s&&i>s?"h":null}function fo(t,e,s){return Math.abs(t[0]-e[0])<=s&&Math.abs(t[1]-e[1])<=s}function bo(t,e,s,i,o){return fo(t,s,o)&&fo(e,i,o)||fo(t,i,o)&&fo(e,s,o)}function vo(t,e,s,i,o){const a=go(t,e,o);return a&&go(s,i,o)===a?"h"===a?Math.abs(t[1]-s[1])>o||Math.abs(t[1]-i[1])>o?0:Math.max(0,Math.min(Math.max(t[0],e[0]),Math.max(s[0],i[0]))-Math.max(Math.min(t[0],e[0]),Math.min(s[0],i[0]))):Math.abs(t[0]-s[0])>o||Math.abs(t[0]-i[0])>o?0:Math.max(0,Math.min(Math.max(t[1],e[1]),Math.max(s[1],i[1]))-Math.max(Math.min(t[1],e[1]),Math.min(s[1],i[1]))):0}function yo(t,e,s,i){const o=t.length,a=go(t[(e-1+o)%o],t[e],i),n=go(t[(e+1)%o],t[(e+2)%o],i),r="h"===s?"v":"h";return a===r&&n===r}function $o(t){let e=1/0,s=1/0,i=-1/0,o=-1/0;for(const a of t)e=Math.min(e,a[0]),s=Math.min(s,a[1]),i=Math.max(i,a[0]),o=Math.max(o,a[1]);return[e,s,i,o]}function wo(t,e,s){const i=$o(t),o=$o(e);return i[2]o}const xo=(t,e)=>"h"===e?t[0]:t[1],Mo=(t,e)=>"h"===e?t[1]:t[0];function So(t,e,s,i,o){const a=t.find(t=>t.id===e);if(!a)return null;const n=a.poly[s],r=a.poly[(s+1)%a.poly.length],h=go(n,r,o);if(!h)return null;const l=0===i?r:n,c=0===i?n:r,d=xo(l,h),p=xo(c,h),_=Mo(l,h),u=function(t,e,s,i){const o=[];for(const a of t)for(let t=0;ti||Math.abs(Mo(r,e)-s)>i)continue;const h=xo(n,e),l=xo(r,e),c=Math.min(h,l),d=Math.max(h,l);d-c>i&&o.push({roomId:a.id,edge:t,lo:c,hi:d})}return o.sort((t,e)=>t.lo-e.lo||t.hi-e.hi||t.roomId.localeCompare(e.roomId)||t.edge-e.edge)}(t,h,_,o),m=function(t,e,s,i){const o=[e,s];for(const a of t){const t=Math.max(e,a.lo),n=Math.min(s,a.hi);n-t>i&&o.push(t,n)}const a=[...new Set(o)].sort((t,e)=>t-e),n=[];for(let e=0;e+1r>t.lo-i&&rt.roomId))].sort();n.push({lo:s,hi:o,owners:h})}return n}(u,Math.min(d,p),Math.max(d,p),o);return!m.length||m.some(t=>t.owners.length<1||t.owners.length>2)?null:{roomId:e,edge:s,movedEndpoint:i,axis:h,line:_,fixed:d,moving:p,intervals:u,baseline:m}}function Co(t,e,s){const i=[];for(const o of t.intervals){const a=e.polys[o.roomId];if(!a){i.push(o);continue}if(o.edge<0||o.edge>=a.length)continue;const n=a[o.edge],r=a[(o.edge+1)%a.length];if(go(n,r,s)!==t.axis||Math.abs(Mo(n,t.axis)-t.line)>s||Math.abs(Mo(r,t.axis)-t.line)>s)continue;const h=xo(n,t.axis),l=xo(r,t.axis),c=Math.min(h,l),d=Math.max(h,l);d-c>s&&i.push({...o,lo:c,hi:d})}return i}function Do(t,e,s){return new Set(t.filter(t=>e>t.lo-s&&et.roomId)).size}function Po(t,e,s){for(const i of e.sideOwnership){const e=t.polys[i.roomId];if(!e)return!1;const o=e[i.edge],a=e[(i.edge+1)%e.length];if(go(o,a,s)!==i.axis)return!1;const n=xo(0===i.movedEndpoint?o:a,i.axis),r=Co(i,t,s),h=(i.moving>=i.fixed?i.baseline[i.baseline.length-1]:i.baseline[0]).owners.length;if(h<1||h>2)return!1;const l=Math.min(i.fixed,i.moving,n),c=Math.max(i.fixed,i.moving,n),d=[l,c,i.fixed,i.moving,n];for(const t of i.intervals)d.push(t.lo,t.hi);for(const t of r)d.push(t.lo,t.hi);const p=[...new Set(d.filter(t=>t>=l&&t<=c))].sort((t,e)=>t-e),_=Math.min(i.fixed,i.moving),u=Math.max(i.fixed,i.moving),m=Math.min(i.fixed,n),g=Math.max(i.fixed,n);for(let t=0;t+1_-s&&am-s&&a2||d>2)return!1;if(n&&l){if(c!==d)return!1}else if(!n&&l){if(d!==h||c>0&&c!==d)return!1}else if(2===c?2!==d:d>1)return!1}}return!0}function Io(t,e,s,i){const o=[s.n[0]*i,s.n[1]*i],a={polys:{},openings:{},movedSpans:{}};for(const e of s.roomIds){const i=t.find(t=>t.id===e),n=s.edgeByRoom[e];if(!i||null==n)continue;const r=(n+1)%i.poly.length;a.polys[e]=i.poly.map((t,e)=>e===n||e===r?ao(t,o):[...t]),a.movedSpans[e]=[[ao(i.poly[n],o),ao(i.poly[r],o)]]}for(const t of e)s.movingOpeningIds.includes(t.id)&&(a.openings[t.id]=[t.x+o[0],t.y+o[1]]);return a}function To(t,e,s,i,o,a,n,r){if(!function(t,e,s,i){if(lo([t.x,t.y],e,s)>2*i)return!1;const o=ro(oo(s,e));if(o<=i)return!1;const a=[(s[0]-e[0])/o,(s[1]-e[1])/o],n=(t.x-e[0])*a[0]+(t.y-e[1])*a[1];return n>=-i&&n<=o+i}(t,e,s,r))return!0;if(lo([t.x,t.y],i,o)>2*r)return!1;const h=0===a?i:o;return ro(oo([t.x,t.y],h))>=t.length/2+n-r}function Ro(t,e,s,i){const o=i.movingHalf||0;return"circle"===t.kind?lo(t.center,e,s)2)return!1;const r=Io(t,e,s,i);if(Object.keys(r.polys).length!==s.roomIds.length)return!1;if(!Po(r,s,a))return!1;const h=new Set(s.roomIds),l=t=>r.polys[t.id]||t.poly;for(const i of s.roomIds){const h=t.find(t=>t.id===i),l=r.polys[i],c=s.edgeByRoom[i];if(!h||!l||l.length!==s.topology[i]||l.length!==h.poly.length||!po(l))return!1;const d=h.poly.length,p=(c-1+d)%d,_=[p,c,(c+1)%d];for(const t of _)if(v(l[t],l[(t+1)%d]))return!1;const u=ho(h.poly),m=ho(l);if(Math.abs(m)t.id===e),i=r.polys[e];for(const o of t){if(o.id===e||h.has(o.id))continue;const t=l(o);if(!wo(s.poly,o.poly,a)||!wo(i,t,a))if(y(s.poly,o.poly,a)){if(!y(i,t,a))return!1}else if(y(o.poly,s.poly,a)){if(!y(t,i,a))return!1}else if(y(i,t,a)||y(t,i,a)||uo(i,t,a))return!1}}t.find(t=>t.id===s.roomId);const c=r.polys[s.roomId],d=s.edgeByRoom[s.roomId],p=c[d],_=c[(d+1)%c.length];if(Math.abs(i)>a)for(const t of o.obstacles||[])if(Ro(t,p,_,o))return!1;for(const t of e){if(!s.movingOpeningIds.includes(t.id))continue;const e=r.openings[t.id];if(!e||t.hosted)return!1;if(!mo({...t,x:e[0],y:e[1]},[c],2*a))return!1}return!0}const Fo=new WeakMap,Ao=t=>"number"==typeof t&&Number.isFinite(t),No=(t,e)=>{const s=new Map;for(const i of t||[])!Ao(i?.cm)||!e&&i.cm<=0||s.set(i.cm,(s.get(i.cm)||0)+1);return s},Ho=t=>[String(t),"см"].join(" ");function Oo(t,e,s={}){if(s.allowClear)return[];const i=!0===s.exactMultiplicity,o=No(t,i),a=No(e,i),n=[];for(const[t,e]of o){const s=a.get(t)||0;0===s?n.push({invariant:"wall_records",kind:"lost",owner:Ho(t),reference:`было ${e}`,detail:"записи этой толщины исчезли целиком"}):i&&s!==e&&n.push({invariant:"wall_records",kind:"count",owner:Ho(t),reference:`было ${e}, стало ${s}`,detail:"изменилось число записей этой толщины"})}if(i)for(const[t,e]of a)o.has(t)||n.push({invariant:"wall_records",kind:"count",owner:Ho(t),reference:`было 0, стало ${e}`,detail:"появились записи новой толщины"});return n}class Lo{constructor(){this._selectedRoomId=null,this._session=null,this._eligibility=null}get dragging(){return null!==this._session}ownsPointer(t){return this._session?.pointerId===t}get selectedRoomId(){return this._selectedRoomId}get snapshotIdentity(){return this._session?.snapshotIdentity||null}get activePointerId(){return this._session?.pointerId??null}get moved(){return!0===this._session?.moved}get delta(){return this._session?.delta||0}get rooms(){return this._session?.rooms||null}get openings(){return this._session?.openings||null}get plan(){return this._session?.plan||null}get preview(){return this._session?.accepted?.preview||null}get liveLabels(){return this._session?.accepted?.labels||null}selectRoom(t){this._selectedRoomId=t}restoreSelection(t){this._selectedRoomId=t}escapeIdle(){return this._selectedRoomId?(this._selectedRoomId=null,"selection-cleared"):"exit-tool"}resolve(t,e,s){this._eligibility&&this._eligibility.context===t||(this._eligibility={context:t,values:new Map});const i=this._eligibility.values.get(e);if(i)return i;const o=s();return this._eligibility.values.set(e,o),o}begin(t){return!this._session&&(this._session={pointerId:t.pointerId,start:[...t.start],roomId:t.roomId,plan:t.plan,options:t.options,rooms:t.rooms,openings:t.openings,snapshotIdentity:t.snapshotIdentity,before:t.before,moved:!1,delta:0,changedRoomIds:[...t.plan.roomIds],rejectionNotified:!1,wallUnionBefore:t.wallUnionBefore,accepted:null},!0)}move(t){const e=this._session;if(!e||e.pointerId!==t.pointerId)return{kind:"no-op"};const s=(i=e.start,o=t.point,a=e.plan.n,[i?.[0],i?.[1],o?.[0],o?.[1],a?.[0],a?.[1]].every(Number.isFinite)?(o[0]-i[0])*a[0]+(o[1]-i[1])*a[1]:0);var i,o,a;const n=t.snap([e.plan.a[0]+e.plan.n[0]*s,e.plan.a[1]+e.plan.n[1]*s]),r=(n[0]-e.plan.a[0])*e.plan.n[0]+(n[1]-e.plan.a[1])*e.plan.n[1],h=function(t,e,s,i,o,a){if(!Number.isFinite(i)||Math.abs(i)<1e-9)return 0;const n=Math.sign(i),r=Math.abs(i),h=Math.max(Math.abs(o),1e-6);let l=Fo.get(s);l&&l.opts===a||(l={opts:a,values:new Map},Fo.set(s,l));const c=l.values;let d=0;for(let i=Math.min(h,r),o=0;o<4096&&i<=r+1e-9;o++,i=Math.min(r,i+h)){const o=n*i,l=`${o.toFixed(9)}|${h.toFixed(9)}`;let p=c.get(l);if(void 0===p&&(p=zo(t,e,s,o,a),c.size<4096&&c.set(l,p)),!p)break;if(d=o,Math.abs(i-r)<=1e-9)break}return d}(e.rooms,e.openings,e.plan,r,t.step,e.options);if(e.moved&&h===e.delta)return{kind:"no-op"};const l=Io(e.rooms,e.openings,e.plan,h);let c;try{if(c=t.project(e.snapshotIdentity,l.polys,l.openings,e.changedRoomIds,e.rooms),!c.ok)return this._projectionRejected(e);if(Oo(c.value.beforeWalls,c.value.afterWalls,{exactMultiplicity:!0}).length)return this._projectionRejected(e)}catch{return this._projectionRejected(e)}const d=e.accepted,p={preview:c.value.preview,labels:null,artifact:c.value.artifact,beforeWalls:c.value.beforeWalls,afterWalls:c.value.afterWalls};e.accepted=p;try{t.publish(p.preview,p.artifact),p.labels=t.measure(l,e.plan)}catch{e.accepted=d;try{t.publish(d?.preview||null,d?.artifact||null)}catch{}return this._projectionRejected(e)}return e.moved=!0,e.delta=h,{kind:"accepted",preview:c.value.preview,labels:p.labels,artifact:c.value.artifact}}finish(t){const e=this._session;if(!e||e.pointerId!==t.pointerId)return{kind:"no-op"};const s=e.accepted;let i;if(e.moved&&Math.abs(e.delta)>1e-9&&s)if(t.currentSnapshotIdentity!==e.snapshotIdentity)i={kind:"rejected",reason:"stale-snapshot"};else if(zo(e.rooms,e.openings,e.plan,e.delta,e.options))if(Oo(s.beforeWalls,s.afterWalls,{exactMultiplicity:!0}).length)i={kind:"rejected",reason:"wall-records"};else{let o=!1;try{o=t.validatePreview(s.preview)}catch{o=!1}i=o?{kind:"commit",preview:s.preview,before:e.before}:{kind:"rejected",reason:"invalid-candidate"}}else i={kind:"rejected",reason:"invalid-topology"};else i={kind:"no-op"};return this._session=null,"commit"===i.kind&&(this._eligibility=null),i}cancel(t,e){const s=this._session;return!s||void 0!==e&&s.pointerId!==e?{kind:"no-op"}:(this._session=null,this._eligibility=null,{kind:"cancelled",restoreWallUnion:t===s.snapshotIdentity?s.wallUnionBefore:null})}reset(){this._selectedRoomId=null,this._session=null,this._eligibility=null}_projectionRejected(t){const e=!t.rejectionNotified;return t.rejectionNotified=!0,{kind:"rejected",notify:e}}}const Eo=(t,e)=>[(t[0]-e.x)/Math.max(1e-9,e.w)*e.stageWidth,(t[1]-e.y)/Math.max(1e-9,e.h)*e.stageHeight];function Bo(t){const{poly:e,edge:s,text:i,view:o}=t,a=e[s],n=e[(s+1)%e.length],r=[(a[0]+n[0])/2,(a[1]+n[1])/2],h=function(t,e){const s=t[e],i=t[(e+1)%t.length],o=i[0]-s[0],a=i[1]-s[1],n=Math.hypot(o,a)||1;return(t=>{let e=0;for(let s=0;s=0?[-a/n,o/n]:[a/n,-o/n]}(e,s),l=Math.hypot(n[0]-a[0],n[1]-a[1])||1,c=[(n[0]-a[0])/l,(n[1]-a[1])/l],d=Eo(r,o),p=Eo(t.gearCenter,o),_=Math.max(34,7.2*i.length+12),u=Math.abs(h[0])>=Math.abs(h[1])?Math.max(28,_/2+4):Math.max(28,13),m=d[0]+h[0]*u,g=d[1]+h[1]*u,f=e=>{return s=m+c[0]*e,i=g+c[1]*e,o=_,a=18,n=p[0],r=p[1],h=t.gearWidthPx,l=t.gearHeightPx,2*Math.abs(s-n)=Math.abs(c[1])?c[0]:c[1])>0?-1:1,e=Math.max(o.stageWidth,o.stageHeight,64);for(let s=4;s<=e;s+=4){const e=s*t;if(!f(e)){b=e;break}const i=-e;if(!f(i)){b=i;break}}}const v=h[0]*u+c[0]*b,y=h[1]*u+c[1]*b,$=Math.hypot(v,y)||1,w=y/$*12,k=[r[0]+v/$*12*o.w/Math.max(1,o.stageWidth),r[1]+w*o.h/Math.max(1,o.stageHeight)];return{anchor:r,offsetXPx:v,offsetYPx:y,tangentOffsetPx:b,side:Math.abs(h[0])>=Math.abs(h[1])?h[0]<0?"left":"right":h[1]<0?"above":"below",leader:{a:r,b:k}}}const Wo=[{id:"air_conditioner",group:"appliance",art:{d:"M20.5 39h69a2.5 2.5 0 0 1 2.5 2.5V69a2.5 2.5 0 0 1-2.5 2.5h-69A2.5 2.5 0 0 1 18 69V41.5a2.5 2.5 0 0 1 2.5-2.5 M25 63a2.5 2.5 0 0 1 2.5-2.5h55A2.5 2.5 0 0 1 85 63v8.5H25z M25 63a2.5 2.5 0 0 1 2.5-2.5h55A2.5 2.5 0 0 1 85 63v3.5H25z",viewW:110,viewH:110}},{id:"armchair",group:"furniture",art:{d:"M42.5 29h25a10 10 0 0 1 10 10v26.5a10 10 0 0 1-10 10h-25a10 10 0 0 1-10-10V39a10 10 0 0 1 10-10 M77.5 48.5a6 6 0 0 1 2 11.657V71.5a4 4 0 0 1-4 4H34a4 4 0 0 1-4-4V60.157A6.001 6.001 0 0 1 32 48.5a6 6 0 0 1 5.419 3.424A4 4 0 0 1 38 54v7h33.5v-6.5q0-.107.005-.213A6 6 0 0 1 77.5 48.5 M42.75 57h24.5A4.75 4.75 0 0 1 72 61.75a4.75 4.75 0 0 1-4.75 4.75h-24.5A4.75 4.75 0 0 1 38 61.75 4.75 4.75 0 0 1 42.75 57M36.5 75.5h8l-1.674 5.441A1.5 1.5 0 0 1 41.392 82H38a1.5 1.5 0 0 1-1.5-1.5zm36 0h-8l1.674 5.441A1.5 1.5 0 0 0 67.608 82H71a1.5 1.5 0 0 0 1.5-1.5z",viewW:110,viewH:110}},{id:"bathtub",group:"sanitary",art:{d:"M28 75h8l-1.674 5.441a1.5 1.5 0 0 1-1.434 1.059H29.5A1.5 1.5 0 0 1 28 80zm53 0h-8l1.674 5.441a1.5 1.5 0 0 0 1.434 1.059H79.5A1.5 1.5 0 0 0 81 80zM19.5 46.5H90a2.5 2.5 0 0 1 2.5 2.5 2.5 2.5 0 0 1-2.5 2.5H19.5A2.5 2.5 0 0 1 17 49a2.5 2.5 0 0 1 2.5-2.5 M19.5 51.5H90L86.633 68a10 10 0 0 1-9.798 8h-44.17a10 10 0 0 1-9.798-8zM30 36v-2a5 5 0 1 0-10 0v12.5",viewW:110,viewH:110}},{id:"bed",group:"furniture",art:{d:"M16 75.5h8l-1.674 5.441A1.5 1.5 0 0 1 20.892 82H17.5a1.5 1.5 0 0 1-1.5-1.5zm78.5 0h-8l1.674 5.441A1.5 1.5 0 0 0 89.608 82H93a1.5 1.5 0 0 0 1.5-1.5zM25 29h60.5a2.5 2.5 0 0 1 2.5 2.5V68a2.5 2.5 0 0 1-2.5 2.5H25a2.5 2.5 0 0 1-2.5-2.5V31.5A2.5 2.5 0 0 1 25 29 M16 59.5c0-5.523 4.477-10 10-10h58.5c5.523 0 10 4.477 10 10v6H16zm-1 6h80.5a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H15a1 1 0 0 1-1-1v-8a1 1 0 0 1 1-1m15.5-20a5 5 0 0 1 5-5h11a5 5 0 0 1 5 5v4h-21zm28.5 0a5 5 0 0 1 5-5h11a5 5 0 0 1 5 5v4H59z",viewW:110,viewH:110}},{id:"bidet",group:"sanitary",art:{d:"M36 57.5c0 5.523 4.477 10 10 10h18.5c5.523 0 10-4.477 10-10V53H36zm8.5 22a1 1 0 0 0 1 1H65a1 1 0 0 0 1-1v-12H44.5zm-8.5-32a1 1 0 0 1 1-1h36.5a1 1 0 0 1 1 1V53H36zM50.5 41a1 1 0 0 1 1-1H59a1 1 0 0 1 1 1v5.5h-9.5zM53 30a1 1 0 0 1 1-1h2.5a1 1 0 0 1 1 1v10H53zm-4 6a1 1 0 0 1-1-1v-2.5a1 1 0 0 1 1-1h4V36z",viewW:110,viewH:110}},{id:"boiler",group:"appliance",art:{d:"M46.5 81.5h5V86a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1zm12.5 0h5V86a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1zM44 23h22.5a8 8 0 0 1 8 8v42.5a8 8 0 0 1-8 8H44a8 8 0 0 1-8-8V31a8 8 0 0 1 8-8 M36 31a8 8 0 0 1 8-8h22.5a8 8 0 0 1 8 8v42H36z M48.5 42.5a7 7 0 1 0 14 0 7 7 0 1 0-14 0m6.5 0 3.5-3.5",viewW:110,viewH:110}},{id:"chair",group:"furniture",art:{d:"M40.5 39.5C40.5 32.596 46.096 27 53 27h4c6.904 0 12.5 5.596 12.5 12.5v13a5 5 0 0 1-5 5h-19a5 5 0 0 1-5-5z M41.25 54h27.5A3.25 3.25 0 0 1 72 57.25a3.25 3.25 0 0 1-3.25 3.25h-27.5A3.25 3.25 0 0 1 38 57.25 3.25 3.25 0 0 1 41.25 54m28.25 6.5H64l1.88 21.63a1.5 1.5 0 0 0 1.495 1.37H68a1.5 1.5 0 0 0 1.5-1.5zm-29 0H46l-1.88 21.63a1.5 1.5 0 0 1-1.495 1.37H42a1.5 1.5 0 0 1-1.5-1.5z",viewW:110,viewH:110}},{id:"coffee_table",group:"furniture",art:{d:"M25 51h5.238l-1.534 15.646A1.5 1.5 0 0 1 27.211 68H26.5a1.5 1.5 0 0 1-1.5-1.5zm60.238 0H80l1.534 15.646A1.5 1.5 0 0 0 83.027 68h.711a1.5 1.5 0 0 0 1.5-1.5z M24.34 43.485A2.5 2.5 0 0 1 26.625 42h56.75a2.5 2.5 0 0 1 2.285 1.485l2.715 6.109A1 1 0 0 1 87.461 51H22.54a1 1 0 0 1-.914-1.406z M87.5 51h-66v3a1 1 0 0 0 1 1h64a1 1 0 0 0 1-1z",viewW:110,viewH:110}},{id:"computer",group:"appliance",art:{d:"M24.5 38h40a2.5 2.5 0 0 1 2.5 2.5v22a2.5 2.5 0 0 1-2.5 2.5h-40a2.5 2.5 0 0 1-2.5-2.5v-22a2.5 2.5 0 0 1 2.5-2.5m50 0h11a2.5 2.5 0 0 1 2.5 2.5v29a2.5 2.5 0 0 1-2.5 2.5h-11a2.5 2.5 0 0 1-2.5-2.5v-29a2.5 2.5 0 0 1 2.5-2.5M43 65h5v7h-5zm-6 7h16m23-12h8m-8-17h8 M35 56V46h5m-5 7h5 M39.5 53a3.5 3.5 0 1 0 0-7m15.036 8.536a5 5 0 1 1 0-7.071",viewW:110,viewH:110}},{id:"cooktop",group:"appliance",art:{d:"M27.5 29h55a2.5 2.5 0 0 1 2.5 2.5v47a2.5 2.5 0 0 1-2.5 2.5h-55a2.5 2.5 0 0 1-2.5-2.5v-47a2.5 2.5 0 0 1 2.5-2.5 M33.5 66.5a8 8 0 1 0 16 0 8 8 0 1 0-16 0m26.5-23a8 8 0 1 0 16 0 8 8 0 1 0-16 0m3 23a5 5 0 1 0 10 0 5 5 0 1 0-10 0m-29.5-23a8 8 0 1 0 16 0 8 8 0 1 0-16 0",viewW:110,viewH:110}},{id:"dining_table",group:"furniture",art:{d:"M83.5 43H78l6.742 30.82A1.5 1.5 0 0 0 86.207 75h.54a1.5 1.5 0 0 0 1.482-1.732zm-56 0H33l-6.742 30.82A1.5 1.5 0 0 1 24.793 75h-.54a1.5 1.5 0 0 1-1.482-1.732zm-2.62-7.406A2.5 2.5 0 0 1 27.21 34h56.58a2.5 2.5 0 0 1 2.33 1.594l2.35 6.044A1 1 0 0 1 87.538 43H23.462a1 1 0 0 1-.932-1.362z M88.5 43h-66v3a1 1 0 0 0 1 1h64a1 1 0 0 0 1-1z",viewW:110,viewH:110}},{id:"dishwasher",group:"appliance",art:{d:"M31.5 25h47a2.5 2.5 0 0 1 2.5 2.5v55a2.5 2.5 0 0 1-2.5 2.5h-47a2.5 2.5 0 0 1-2.5-2.5v-55a2.5 2.5 0 0 1 2.5-2.5 M31.5 37.5h47A2.5 2.5 0 0 1 81 40v36a2.5 2.5 0 0 1-2.5 2.5h-47A2.5 2.5 0 0 1 29 76V40a2.5 2.5 0 0 1 2.5-2.5M43 42h24m-1.5-11a2 2 0 1 0 4 0 2 2 0 1 0-4 0m7.5 0a2 2 0 1 0 4 0 2 2 0 1 0-4 0m-37.25 0h9.5",viewW:110,viewH:110}},{id:"dryer",group:"appliance",art:{d:"M31.5 25h47a2.5 2.5 0 0 1 2.5 2.5v55a2.5 2.5 0 0 1-2.5 2.5h-47a2.5 2.5 0 0 1-2.5-2.5v-55a2.5 2.5 0 0 1 2.5-2.5 M31.5 37.5h47A2.5 2.5 0 0 1 81 40v42.5a2.5 2.5 0 0 1-2.5 2.5h-47a2.5 2.5 0 0 1-2.5-2.5V40a2.5 2.5 0 0 1 2.5-2.5 M38 60.5a17 17 0 1 0 34 0 17 17 0 1 0-34 0 M43.5 60.5a11.5 11.5 0 1 0 23 0 11.5 11.5 0 1 0-23 0m22-29.5a2 2 0 1 0 4 0 2 2 0 1 0-4 0m7.5 0a2 2 0 1 0 4 0 2 2 0 1 0-4 0m-37.25 0h9.5 M55.994 55.5s-1.329 1.81-1.479 3.143c-.198 1.761 1.599 2.554 1.48 4.321-.1 1.479-1.48 3.536-1.48 3.536m5.979-11s-1.329 1.81-1.479 3.143c-.198 1.761 1.599 2.554 1.48 4.321-.1 1.479-1.48 3.536-1.48 3.536m-8.519-11s-.886 1.81-.986 3.143c-.132 1.761 1.066 2.554.986 4.321-.067 1.479-.986 3.536-.986 3.536",viewW:110,viewH:110}},{id:"exercise",group:"other",art:{d:"m60.752 62.03-5.379-2.312 11.066-25.75a1.5 1.5 0 0 1 1.97-.786l2.624 1.127a1.5 1.5 0 0 1 .786 1.97zm-18.648-4.512-4.353 1.189-4.474-16.382a1.5 1.5 0 0 1 1.052-1.842l1.459-.398a1.5 1.5 0 0 1 1.842 1.052z M41.297 38.173a2.215 2.215 0 0 1 0 4.43H29.781a2.215 2.215 0 0 1 0-4.43zm33.219 38.091a2.657 2.657 0 1 1 0 5.315H28.453a2.657 2.657 0 1 1 0-5.315zm8.641-51.366a1.795 1.795 0 0 1 .68 2.41l-3.03 5.59a5 5 0 0 1-4.396 2.618H65.657a1.772 1.772 0 1 1 0-3.544h9.61a3 3 0 0 0 2.598-1.5l2.84-4.917a1.795 1.795 0 0 1 2.452-.657M29.339 65.787c0-6.699 6.457-11.503 12.873-9.579l24.291 7.288a10 10 0 0 1 7.127 9.578v3.19H29.339zm0 15.852h7.086l-1.394 3.486a1.5 1.5 0 0 1-1.393.943h-2.8a1.5 1.5 0 0 1-1.5-1.5zm44.291 0h-7.087l1.395 3.486a1.5 1.5 0 0 0 1.392.943h2.8a1.5 1.5 0 0 0 1.5-1.5z M35.54 66.077a4.872 4.872 0 1 0 9.743 0 4.872 4.872 0 1 0-9.744 0",viewW:110,viewH:110}},{id:"fireplace",group:"other",art:{d:"M26.672 34.425h55.99v39.47h-55.99Z M23 74.894a1 1 0 0 1 1-1h61.334a1 1 0 0 1 1 1v5.802a1 1 0 0 1-1 1H24a1 1 0 0 1-1-1zM23 29a1 1 0 0 1 1-1h61.334a1 1 0 0 1 1 1v4.425a1 1 0 0 1-1 1H24a1 1 0 0 1-1-1zm15.145 21.44a5 5 0 0 1 5-5h23.043a5 5 0 0 1 5 5v23.454H38.145z M44.57 65.633a2.754 2.754 0 0 1 2.754-2.753H62.01v5.507H47.324a2.754 2.754 0 0 1-2.754-2.754m20.194 5.507a2.754 2.754 0 0 0-2.754-2.753H47.324v5.507H62.01a2.754 2.754 0 0 0 2.754-2.754 M44.57 71.14a2.754 2.754 0 1 0 5.508 0 2.754 2.754 0 1 0-5.508 0m14.688-5.507a2.754 2.754 0 1 0 5.507 0 2.754 2.754 0 1 0-5.507 0",viewW:110,viewH:110}},{id:"fridge",group:"appliance",art:{d:"M35.5 18H75a2.5 2.5 0 0 1 2.5 2.5v64A2.5 2.5 0 0 1 75 87H35.5a2.5 2.5 0 0 1-2.5-2.5v-64a2.5 2.5 0 0 1 2.5-2.5 M33 46.5h44.5v38A2.5 2.5 0 0 1 75 87H35.5a2.5 2.5 0 0 1-2.5-2.5zm2.5 44a1 1 0 0 0 1 1h37a1 1 0 0 0 1-1V87h-39zm3-49.5v-9.5m0 30.5v-9.5",viewW:110,viewH:110}},{id:"hood",group:"appliance",art:{d:"M44.308 57h21.384L83 69H27zM44 37.5a2.5 2.5 0 0 1 2.5-2.5h17a2.5 2.5 0 0 1 2.5 2.5V57H44zM80.5 74h-51a2.5 2.5 0 0 1-2.5-2.5V70a1 1 0 0 1 1-1h54a1 1 0 0 1 1 1v1.5a2.5 2.5 0 0 1-2.5 2.5",viewW:110,viewH:110}},{id:"kitchen_cabinet",group:"furniture",art:{d:"M38 88a1 1 0 0 0 1 1h32a1 1 0 0 0 1-1v-3H38zm17-68h16.5a2.5 2.5 0 0 1 2.5 2.5v17a2.5 2.5 0 0 1-2.5 2.5H55zm-19 2.5a2.5 2.5 0 0 1 2.5-2.5H55v22H38.5a2.5 2.5 0 0 1-2.5-2.5zM59 33v5m-8-5v5m4 47h16.5a2.5 2.5 0 0 0 2.5-2.5v-17a2.5 2.5 0 0 0-2.5-2.5H55zm-19-2.5a2.5 2.5 0 0 0 2.5 2.5H55V63H38.5a2.5 2.5 0 0 0-2.5 2.5zM67 67h-5m-14 0h-5",viewW:110,viewH:110}},{id:"kitchen_sink",group:"sanitary",art:{d:"M21.5 84h68a2.5 2.5 0 0 0 2.5-2.5v-35a2.5 2.5 0 0 0-2.5-2.5h-68a2.5 2.5 0 0 0-2.5 2.5v35a2.5 2.5 0 0 0 2.5 2.5 M26 78h26.5a1 1 0 0 0 1-1V51a1 1 0 0 0-1-1H26a1 1 0 0 0-1 1v26a1 1 0 0 0 1 1m23-24v5m9.5 19H85a1 1 0 0 0 1-1V51a1 1 0 0 0-1-1H58.5a1 1 0 0 0-1 1v26a1 1 0 0 0 1 1m-6-39.5a1 1 0 0 0-1-1H44a1 1 0 0 0-1 1V44h9.5zM58 33v-2a5 5 0 1 0-10 0v6.5M62 54v5",viewW:110,viewH:110}},{id:"nightstand",group:"furniture",art:{d:"M76.5 73.5h-8l1.674 5.441A1.5 1.5 0 0 0 71.608 80H75a1.5 1.5 0 0 0 1.5-1.5zm-42.5 0h8l-1.674 5.441A1.5 1.5 0 0 1 38.892 80H35.5a1.5 1.5 0 0 1-1.5-1.5z M34.5 30.5h41A2.5 2.5 0 0 1 78 33v40.5a2.5 2.5 0 0 1-2.5 2.5h-41a2.5 2.5 0 0 1-2.5-2.5V33a2.5 2.5 0 0 1 2.5-2.5 M32 39.5h46v18H32Zm18.5 9H60M50.5 66H60",viewW:110,viewH:110}},{id:"oven",group:"appliance",art:{d:"M31.5 25h47a2.5 2.5 0 0 1 2.5 2.5v55a2.5 2.5 0 0 1-2.5 2.5h-47a2.5 2.5 0 0 1-2.5-2.5v-55a2.5 2.5 0 0 1 2.5-2.5 M31.5 37.5h47A2.5 2.5 0 0 1 81 40v36a2.5 2.5 0 0 1-2.5 2.5h-47A2.5 2.5 0 0 1 29 76V40a2.5 2.5 0 0 1 2.5-2.5 M40.5 47h29a2.5 2.5 0 0 1 2.5 2.5v20a2.5 2.5 0 0 1-2.5 2.5h-29a2.5 2.5 0 0 1-2.5-2.5v-20a2.5 2.5 0 0 1 2.5-2.5m25-16a2 2 0 1 0 4 0 2 2 0 1 0-4 0m7.5 0a2 2 0 1 0 4 0 2 2 0 1 0-4 0m-37.25 0h9.5M43 42h24",viewW:110,viewH:110}},{id:"plant",group:"other",art:{d:"M45.952 75.849a2.5 2.5 0 0 0 2.485 2.231H63.43a2.5 2.5 0 0 0 2.485-2.231l1.571-14.532H44.381zM60.236 44.78C58.423 36.174 66.805 29.605 77 31.87c0 8.155-8.609 16.763-16.763 12.912m-9.761 5.147c1.517-8.665-7.085-14.943-17.195-12.33.28 8.15 9.178 16.458 17.195 12.33 M55.706 55.88v-2.944m0 0c1.133-5.89 7.09-10.956 12.912-15.404M55.706 52.936c-4.938-4.146-7.982-6.16-14.044-9.061m1.453 12.005h25.636a1 1 0 0 1 1 1v3.437a1 1 0 0 1-1 1H43.115a1 1 0 0 1-1-1v-3.436a1 1 0 0 1 1-1",viewW:110,viewH:110}},{id:"rug",group:"other",art:{d:"M90.27 33.874h-5.622m-59.028 0H20m70.27 5.152h-5.622m-59.028 0H20m70.27 5.154h-5.622m-59.028 0H20m70.27 5.152h-5.622m-59.028 0H20m70.27 5.153h-5.622m-59.028 0H20m70.27 5.153h-5.622m-59.028 0H20m70.27 5.153h-5.622m-59.028 0H20m70.27 5.153h-5.622m-59.028 0H20m70.27 5.153h-5.622m-59.028 0H20M28.12 32h54.025a2.5 2.5 0 0 1 2.5 2.5v40.439a2.5 2.5 0 0 1-2.5 2.5H28.12a2.5 2.5 0 0 1-2.5-2.5V34.5a2.5 2.5 0 0 1 2.5-2.5 M25.62 34.5a2.5 2.5 0 0 1 2.5-2.5h1.717v45.439H28.12a2.5 2.5 0 0 1-2.5-2.5zm59.026 0a2.5 2.5 0 0 0-2.5-2.5H80.43v45.439h1.716a2.5 2.5 0 0 0 2.5-2.5zM37.8 54.485l17.801-8.432 17.801 8.432-17.8 8.432z",viewW:110,viewH:110}},{id:"shelving",group:"furniture",art:{d:"M28 58.5h53V39H28Z M64 58.5h5V47a1 1 0 0 0-1-1h-3a1 1 0 0 0-1 1zM52.5 39h-5V27.5a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1zm-12 0h-5V27.5a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1zm-5 29.5V71a1 1 0 0 1 1 1H49a1 1 0 0 1 1-1v-2.5a1 1 0 0 1-1-1H36.5a1 1 0 0 1-1 1m33.5-10h7v-14a1 1 0 0 0-1-1h-5a1 1 0 0 0-1 1zM47.5 39h-7V25a1 1 0 0 1 1-1h5a1 1 0 0 1 1 1zm-12 34v4a1 1 0 0 1 1 1h14a1 1 0 0 1 1-1v-4a1 1 0 0 1-1-1h-14a1 1 0 0 1-1 1M28 78h53v7H28Z M28 89.5V23a2.5 2.5 0 0 1 2.5-2.5h48A2.5 2.5 0 0 1 81 23v66.5",viewW:110,viewH:110}},{id:"shower",group:"sanitary",art:{d:"M31 84h49a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1H31a1 1 0 0 1-1-1v-3a1 1 0 0 1 1-1m31.5-47.6v-4.686a11.7 11.7 0 0 0-3.441-8.283A11.77 11.77 0 0 0 50.75 20a11.77 11.77 0 0 0-8.309 3.431A11.7 11.7 0 0 0 39 31.714V84 M72 39.25a10.25 10.25 0 1 0-20.5 0zm-17.25 5v2.5m7.25-2.5v2.5m7.25-2.5v2.5m-14.5 3.75V53M62 50.5V53m7.25-2.5V53m-14.5 3.75v2.5m7.25-2.5v2.5m7.25-2.5v2.5M54.75 63v2.5M62 63v2.5m7.25-2.5v2.5",viewW:110,viewH:110}},{id:"sink",group:"sanitary",art:{d:"M30 57c0 5.523 4.477 10 10 10h29.5c5.523 0 10-4.477 10-10v-6.5A2.5 2.5 0 0 0 77 48H32.5a2.5 2.5 0 0 0-2.5 2.5zm14 22a1 1 0 0 0 1 1h19.5a1 1 0 0 0 1-1V67H44zm6-36.5a1 1 0 0 1 1-1h7.5a1 1 0 0 1 1 1V48H50zM45 37v-2a5 5 0 1 1 10 0v6.5",viewW:110,viewH:110}},{id:"sofa",group:"furniture",art:{d:"M59.5 29h24a5 5 0 0 1 5 5v32a5 5 0 0 1-5 5h-24a5 5 0 0 1-5-5V34a5 5 0 0 1 5-5m-34 0h24a5 5 0 0 1 5 5v32a5 5 0 0 1-5 5h-24a5 5 0 0 1-5-5V34a5 5 0 0 1 5-5 M18.5 44a5 5 0 0 1 5 5v12H86V49a5 5 0 0 1 5-5h.5a5 5 0 0 1 5 5v21.5a5 5 0 0 1-5 5H18a5 5 0 0 1-5-5V49a5 5 0 0 1 5-5z M25.25 57h24.5a4.75 4.75 0 0 1 4.75 4.75 4.75 4.75 0 0 1-4.75 4.75h-24.5a4.75 4.75 0 0 1-4.75-4.75A4.75 4.75 0 0 1 25.25 57m34 0h24.5a4.75 4.75 0 0 1 4.75 4.75 4.75 4.75 0 0 1-4.75 4.75h-24.5a4.75 4.75 0 0 1-4.75-4.75A4.75 4.75 0 0 1 59.25 57M18.5 75.5h8l-1.674 5.441A1.5 1.5 0 0 1 23.392 82H20a1.5 1.5 0 0 1-1.5-1.5zm72 0h-8l1.674 5.441A1.5 1.5 0 0 0 85.608 82H89a1.5 1.5 0 0 0 1.5-1.5z",viewW:110,viewH:110}},{id:"stairs",group:"other",art:{d:"M73.47 46.365v-17.62m-10.571 25.55V36.674M52.326 61.783V45.484M42.193 69.273v-15.86M28.979 77.761a1 1 0 0 1 1-1h53.624v6.489a1 1 0 0 1-1 1H29.98a1 1 0 0 1-1-1z M26.777 57.497a1 1 0 0 1 1-1h2.846a1 1 0 0 1 1 1V83.25a1 1 0 0 1-1 1h-2.846a1 1 0 0 1-1-1z m73.113 28.633-41.492 32.93v-4.405l39.9-32.007a.7.7 0 0 1 .428-.151h3.724a1.762 1.762 0 1 1 0 3.524h-2.248a.5.5 0 0 0-.312.109M25.895 53.414a3.084 3.084 0 1 0 6.167 0 3.084 3.084 0 1 0-6.167 0m14.978 16.859a1 1 0 0 1 1-1h41.73v7.488h-42.73zm10.131-7.489a1 1 0 0 1 1-1h31.598v7.488H51.004z M61.576 55.294a1 1 0 0 1 1-1h21.026v7.49H61.576z M72.15 47.806a1 1 0 0 1 1-1h9.454a1 1 0 0 1 1 1v6.489H72.15z",viewW:110,viewH:110}},{id:"toilet",group:"sanitary",art:{d:"M32 26.5a2.5 2.5 0 0 1 2.5-2.5H45a2.5 2.5 0 0 1 2.5 2.5V57H32zM47.5 52h29a2.5 2.5 0 0 1 2.5 2.5V57H47.5zm17.037 20.102C73.95 70.288 79 62.01 79 57H32c.5 7.5 8.072 7 7 11l-2.342 16.862a1 1 0 0 0 .99 1.138H66.72a1 1 0 0 0 .97-1.243z",viewW:110,viewH:110}},{id:"tv",group:"appliance",art:{d:"M23.5 31H86a2.5 2.5 0 0 1 2.5 2.5v34A2.5 2.5 0 0 1 86 70H23.5a2.5 2.5 0 0 1-2.5-2.5v-34a2.5 2.5 0 0 1 2.5-2.5M50 70h9.5v8H50Zm-10 8h30M42.5 45.5h5m5 0h-5m0 0v9.75 m56.75 45.5 5 10 5-10",viewW:110,viewH:110}},{id:"wardrobe",group:"furniture",art:{d:"M28 23a2.5 2.5 0 0 1 2.5-2.5h24V85h-24a2.5 2.5 0 0 1-2.5-2.5zm2 65.5a1 1 0 0 0 1 1h47a1 1 0 0 0 1-1V85H30zM81 23a2.5 2.5 0 0 0-2.5-2.5h-24V85h24a2.5 2.5 0 0 0 2.5-2.5zM50.5 48v9.5m8-9.5v9.5",viewW:110,viewH:110}},{id:"washer",group:"appliance",art:{d:"M31.5 25h47a2.5 2.5 0 0 1 2.5 2.5v55a2.5 2.5 0 0 1-2.5 2.5h-47a2.5 2.5 0 0 1-2.5-2.5v-55a2.5 2.5 0 0 1 2.5-2.5 M31.5 37.5h47A2.5 2.5 0 0 1 81 40v42.5a2.5 2.5 0 0 1-2.5 2.5h-47a2.5 2.5 0 0 1-2.5-2.5V40a2.5 2.5 0 0 1 2.5-2.5 M38 60.5a17 17 0 1 0 34 0 17 17 0 1 0-34 0 M43.5 60.5a11.5 11.5 0 1 0 23 0 11.5 11.5 0 1 0-23 0m22-29.5a2 2 0 1 0 4 0 2 2 0 1 0-4 0m7.5 0a2 2 0 1 0 4 0 2 2 0 1 0-4 0m-37.25 0h9.5",viewW:110,viewH:110}},{id:"work_table",group:"furniture",art:{d:"M88.5 47h-20v14h20zm-12 4h4m7.984-8h-66v4h66zm-66 4h4v26.5a1.5 1.5 0 0 1-1.5 1.5h-1a1.5 1.5 0 0 1-1.5-1.5z M24.866 35.597A2.5 2.5 0 0 1 27.197 34h56.577a2.5 2.5 0 0 1 2.33 1.594l2.35 6.044a1 1 0 0 1-.93 1.362H23.46a1 1 0 0 1-.933-1.361zM88.5 61h-20v12.5A1.5 1.5 0 0 0 70 75h17a1.5 1.5 0 0 0 1.5-1.5zm-12 4h4",viewW:110,viewH:110}}],Go=1e-9,jo=1e7,qo=t=>{const e=Math.sign(t)*Math.floor(Math.abs(t)*jo+.5)/jo;return Object.is(e,-0)?0:e},Uo=t=>`${qo(t[0])},${qo(t[1])}`,Ko=(t,e)=>Math.hypot(e[0]-t[0],e[1]-t[1]),Vo=(t,e)=>Math.atan2(e[1]-t[1],e[0]-t[0]),Jo=t=>Array.isArray(t)&&t.length>=2&&t.every(t=>Number.isFinite(t)),Yo=t=>(t||[]).filter(t=>Jo(t?.a)&&Jo(t?.b)&&Ko(t.a,t.b)>Go);function Xo(t,{minAngleDeg:e=15,maxValence:s=6}={}){const i=new Map;for(const e of Yo(t))for(const[t,s]of[[e.a,e.b],[e.b,e.a]]){const e=i.get(Uo(t))||[];e.push(Vo(t,s)),i.set(Uo(t),e)}const o=[];for(const[t,a]of i){if(a.length>s&&o.push({rule:"valence",subject:t,actual:a.length,limit:s}),a.length<2)continue;const i=[...a].sort((t,e)=>t-e);let n=1/0;for(let t=0;tGo&&s(180*Math.atan2(t.b[1]-t.a[1],t.b[0]-t.a[0])/Math.PI%180+180)%180,Qo=(t,e,s=1)=>{const i=Math.abs(Zo(t)-Zo(e));return Math.min(i,180-i)<=s},ta=t=>{const e=new Map;for(const s of t)for(const t of[s.a,s.b]){const i=e.get(Uo(t));i?i.push(s):e.set(Uo(t),[s])}return e};function ea(t,e,s){const i=Yo(e),o=s??ta(i),a=new Set([t]);let n=Ko(t.a,t.b);const r=[t.a,t.b];for(;r.length;){const e=r.pop();for(const s of o.get(Uo(e))||[])a.has(s)||Qo(s,t)&&Number(s.cm||0)===Number(t.cm||0)&&(a.add(s),n+=Ko(s.a,s.b),r.push(s.a,s.b))}return n}function sa(t,e,s,{minLengthCm:i=20}={}){const o=[],a=Yo(t),n=ta(a);for(const t of a){const r=ea(t,a,n)/s*(e||1),h=Math.max(i,Number(t.cm)>0?Number(t.cm):0);r{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o,n=a<=Go?0:Math.max(0,Math.min(1,((t[0]-e[0])*i+(t[1]-e[1])*o)/a));return Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))};function oa(t,e,s,{minDistanceCm:i=5}={}){const o=Yo(t),a=new Map;for(const t of o)a.set(Uo(t.a),t.a),a.set(Uo(t.b),t.b);const n=((t,e,s)=>t/(e||1)*s)(i,e,s),r=n>Go?n:1,h=(t,e)=>`${Math.floor(t/r)},${Math.floor(e/r)}`,l=new Map;for(const[t,e]of a){const s=h(e[0],e[1]),i=l.get(s);i?i.push([t,e]):l.set(s,[[t,e]])}const c=new Map;for(const t of o){const e=Math.min(t.a[0],t.b[0])-n,s=Math.max(t.a[0],t.b[0])+n,i=Math.min(t.a[1],t.b[1])-n,o=Math.max(t.a[1],t.b[1])+n;for(let a=Math.floor(e/r);a<=Math.floor(s/r);a++)for(let e=Math.floor(i/r);e<=Math.floor(o/r);e++){const s=`${a},${e}`,i=c.get(s);i?i.push(t):c.set(s,[t])}}const d=[];for(const[t,o]of a){const a=Math.floor(o[0]/r),h=Math.floor(o[1]/r);for(let r=-1;r<=1;r++)for(let c=-1;c<=1;c++)for(const[p,_]of l.get(`${a+r},${h+c}`)||[]){if(t>=p)continue;const a=Ko(o,_);a<=2e-7||a{const i=a[(s+1)%a.length];return t+(e[0]*i[1]-i[0]*e[1])},0))/2,r=(s||1)/i,h=n*r*r;return ht.removed).map(t=>t.binding)),c=new Set;for(const t of s)t.id!==n&&("device"===t.bindingKind&&t.bindingRef&&c.add(`device:${t.bindingRef}`),"entity"===t.bindingKind&&t.bindingRef&&c.add(`entity:${t.bindingRef}`));const d=new Set;for(const t of s)"device"===t.bindingKind&&t.name&&d.add(`${t.name.trim()}|${t.area||""}`);const p=[];for(const t of Object.values(e?.devices||{})){if(!t||"service"===t.entry_type)continue;const e=`device:${t.id}`;if(c.has(e))continue;const s=String(t.name_by_user||t.name||t.id).trim();e!==a&&!l.has(e)&&d.has(`${s}|${t.area_id||""}`)||p.push({value:e,label:s,sub:(t.model||r.device)+("Group"===t.model?r.z2mGroup:""),kind:"device",ref:t.id,areaId:t.area_id||"",model:t.model||""})}for(const[t,s]of Object.entries(e?.entities||{})){const i=`entity:${t}`;if(c.has(i))continue;if(M(e,t,h)&&!l.has(i))continue;const o=na.has(s?.platform),a="group"===s?.platform;if(!o&&!a)continue;if(s?.hidden&&!l.has(i))continue;const n=e?.states?.[t];p.push({value:i,label:s?.name||n?.attributes?.friendly_name||t,sub:`${t.split(".")[0]} · ${a?r.group:r.helper}`,kind:"entity",ref:t,areaId:s?.area_id||s?.device_id&&e?.devices?.[s.device_id]?.area_id||"",model:"",parentDeviceId:s?.device_id||void 0})}if(o){const t=new Set(p.map(t=>t.value));for(const[s,i]of Object.entries(e?.entities||{})){const o=`entity:${s}`;if(c.has(o)||t.has(o)||i?.hidden&&!l.has(o))continue;const a=!!i?.device_id&&h.devices.has(i.device_id);if(M(e,s,h)&&!l.has(o)&&!a)continue;const n=e?.states?.[s],d=i?.device_id?e?.devices?.[i.device_id]:null,_=d?String(d.name_by_user||d.name||""):"";p.push({value:o,label:i?.name||n?.attributes?.friendly_name||s,sub:`${s.split(".")[0]} · ${r.entity}${_?` · ${_}`:""}`,kind:"entity",ref:s,areaId:i?.area_id||d?.area_id||"",model:"",parentDeviceId:i?.device_id||void 0})}}return p.sort((t,e)=>t.label.localeCompare(e.label)||t.value.localeCompare(e.value))}const ha={kind:"active",enabledEntityIds:[],allEntityIds:[]};function la(t){return t.startsWith("entity:")?"entity":"device"}function ca(t){const e=t.binding.indexOf(":"),s=e>=0?t.binding.slice(e+1):"",i=Object.keys(t).filter(t=>!["id","binding","hidden"].includes(t));return t.id===`h${s}`&&0===i.length}const da=.001;function pa(t){return!!t&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1])}function _a(t){return`${t[0].toFixed(6)},${t[1].toFixed(6)}`}function ua(t,e,s){return Math.abs(t[0]-e[0])"room"!==t.kind&&s.some(s=>s!==t&&function(t,e,s){const i=t.b[0]-t.a[0],o=t.b[1]-t.a[1],a=Math.hypot(i,o);if(!(a>s))return!1;const n=i/a,r=o/a,h=e=>Math.abs((e[0]-t.a[0])*r-(e[1]-t.a[1])*n);if(h(e.a)>s||h(e.b)>s)return!1;const l=(e.a[0]-t.a[0])*n+(e.a[1]-t.a[1])*r,c=(e.b[0]-t.a[0])*n+(e.b[1]-t.a[1])*r;return Math.min(a,Math.max(l,c))-Math.max(0,Math.min(l,c))>s}(t,s,e))),o=i.map(t=>{const[e,s]=ma(t.a,t.b);return{a:e,b:s,key:`hidden|${fa(t,e,s)}`,sourceKind:t.kind,sourceId:t.id}}).sort((t,e)=>t.key.localeCompare(e.key)),a=i.flatMap(t=>[t.a,t.b].map((e,s)=>({point:[e[0],e[1]],key:`hidden|${ga(t)}|endpoint-${s}`,sourceKind:t.kind,sourceId:t.id}))).sort((t,e)=>t.key.localeCompare(e.key));return{segments:o,endpoints:a}}function $a(t){const e=t.epsilon??da,s=t.roomCuts||[],i=new Map;for(const e of t.partitionCuts||[]){if("string"!=typeof e.hostId||!e.hostId||!pa(e.a)||!pa(e.b))continue;const t=i.get(e.hostId)||[];t.push([e.a[0],e.a[1],e.b[0],e.b[1]]),i.set(e.hostId,t)}const o=[];for(const[e,i]of S(t.space.rooms).entries())i.length<4||o.push({a:[i[0],i[1]],b:[i[2],i[3]],kind:"room",id:`room-edge-${e}`,cuts:s});for(const e of t.space.room_drafts||[])if(e.id!==t.activeDraftId)for(let t=0;t+1va(s,t,e)))continue;const t=_a(s);n.has(t)||n.set(t,{point:[s[0],s[1]],key:t})}}}return{segments:[...a.values()].sort((t,e)=>t.key.localeCompare(e.key)),endpoints:[...n.values()].sort((t,e)=>t.key.localeCompare(e.key))}}function wa(t,e,s){return e.some(e=>pa(e)&&ua(t,e,s))}function ka(t,e,s){if(!s)return!0;const i=t-s.distance;return i<-1e-9||Math.abs(i)<=1e-9&&e.localeCompare(s.key)<0}function xa(t,e,s){const i=s.epsilon??da,o=s.excludePoints||[],a=[...t.endpoints,...(s.extraEndpoints||[]).filter(t=>pa(t.point)).map(t=>({point:[t.point[0],t.point[1]],key:t.key}))],n=new Map;for(const t of a){if(wa(t.point,o,i))continue;const e=_a(t.point),s=n.get(e);(!s||t.key.localeCompare(s.key)<0)&&n.set(e,t)}return[...n.values()].map(t=>({kind:"endpoint",point:[...t.point],key:t.key,distance:Math.hypot(e[0]-t.point[0],e[1]-t.point[1])})).filter(t=>t.distance<=s.tolerance).sort((t,e)=>t.distance-e.distance||t.key.localeCompare(e.key))}function Ma(t,e){if(!t.length)return null;if(e>0){const s=new Set;for(let i=0;i1)return{kind:"ambiguous",candidate:null,conflicts:t.filter(t=>s.has(t.key)).map(t=>({point:[...t.point],key:t.key}))}}return{kind:"resolved",candidate:t[0],conflicts:[]}}function Sa(t,e,s){const i=t.b[0]-t.a[0],o=t.b[1]-t.a[1],a=Math.hypot(i,o);if(!(a>0))return[...t.a];const n=i/a,r=o/a,h=Math.max(0,Math.min(a,(e[0]-t.a[0])*n+(e[1]-t.a[1])*r)),l=s>0?Math.max(0,Math.min(a,Math.round(h/s)*s)):h;return[t.a[0]+n*l,t.a[1]+r*l]}function Ca(t,e,s){if(!(pa(e)&&pa(s.anchor)&&s.tolerance>=0))return{kind:"none",candidate:null,conflicts:[]};const i=s.epsilon??da,o=function(t,e){const s=e[0]-t[0],i=e[1]-t[1];if(!(Math.hypot(s,i)>Number.EPSILON))return null;const o=Math.round(Math.atan2(i,s)/(Math.PI/4))*(Math.PI/4);return[Math.cos(o),Math.sin(o)]}(s.anchor,e);if(!o)return{kind:"none",candidate:null,conflicts:[]};const a=xa(t,e,s).filter(t=>function(t,e,s,i){const o=t[0]-e[0],a=t[1]-e[1];return o*s[0]+a*s[1]>i&&Math.abs(o*s[1]-a*s[0])<=i*Math.max(Math.hypot(o,a),1)}(t.point,s.anchor,o,i)),n=Ma(a,s.distinguishTolerance||0);if(n)return n;let r=null;for(const a of t.segments){const t=a.b[0]-a.a[0],n=a.b[1]-a.a[1],h=a.a[0]-s.anchor[0],l=a.a[1]-s.anchor[1],c=o[0]*n-o[1]*t;let d=null;if(Math.abs(c)<=i*Math.max(Math.hypot(t,n),1)){if(Math.abs(h*o[1]-l*o[0])>i*Math.max(Math.hypot(h,l),1))continue;const t=[a.a,a.b].map(t=>({point:t,along:(t[0]-s.anchor[0])*o[0]+(t[1]-s.anchor[1])*o[1]})).filter(t=>t.along>i).sort((t,e)=>t.along-e.along);t.length&&(d=[...t[0].point])}else{const e=(h*n-l*t)/c,a=(h*o[1]-l*o[0])/c;e>i&&a>=-i&&a<=1+i&&(d=[s.anchor[0]+o[0]*e,s.anchor[1]+o[1]*e])}if(!d)continue;const p=Math.hypot(e[0]-d[0],e[1]-d[1]);p>s.tolerance||wa(d,s.excludePoints||[],i)||!ka(p,a.key,r)||(r={kind:"line",point:d,key:a.key,distance:p,segment:a})}return r?{kind:"resolved",candidate:r,conflicts:[]}:{kind:"none",candidate:null,conflicts:[]}}const Da=.001;function Pa(t,e,s,i){const o=Number.isFinite(t)&&t>0?Math.floor(t):0,a=t=>"number"==typeof t&&Number.isFinite(t)&&t>=0?t:null,n=a(s),r=a(i)??0,h=[];let l=null;for(let t=0;t=2&&Number.isFinite(t[0])&&Number.isFinite(t[1])}function Ra(t,e,s,i){return t*i-e*s}function za(t){let e=0;for(let s=0;st.localeCompare(e)),e[0]}function Oa(t,e,s){const i=[...t];for(let t=!0;t&&i.length>=3;){t=!1;for(let o=0;o=0){i.splice(o,1),t=!0;break}}}return i}function La(t,e){const s=t.map(t=>Math.max(0,Math.min(1,t))).sort((t,e)=>t-e),i=[];for(const t of s)(!i.length||Math.abs(t-i[i.length-1])>e)&&i.push(t);return i}function Ea(t,e){return[t.a[0]+(t.b[0]-t.a[0])*e,t.a[1]+(t.b[1]-t.a[1])*e]}function Ba(t,e,s){const i=function(t,e){const s=e.b[0]-e.a[0],i=e.b[1]-e.a[1],o=s*s+i*i;return o>0?((t[0]-e.a[0])*s+(t[1]-e.a[1])*i)/o:0}(t,e);if(i<-s||i>1+s)return null;const o=Ea(e,i);return Math.hypot(o[0]-t[0],o[1]-t[1])<=s?Math.max(0,Math.min(1,i)):null}function Wa(t,e,s,i,o){const a=t.b[0]-t.a[0],n=t.b[1]-t.a[1],r=e.b[0]-e.a[0],h=e.b[1]-e.a[1],l=e.a[0]-t.a[0],c=e.a[1]-t.a[1],d=Ra(a,n,r,h),p=Math.max(Math.hypot(a,n),Math.hypot(r,h),1);if(Math.abs(d)>o*p){const t=Ra(l,c,r,h)/d,e=Ra(l,c,a,n)/d;return void(t>=-o&&t<=1+o&&e>=-o&&e<=1+o&&(s.push(Math.max(0,Math.min(1,t))),i.push(Math.max(0,Math.min(1,e)))))}if(!(Math.abs(Ra(l,c,a,n))>o*p)){for(const i of[e.a,e.b]){const e=Ba(i,t,o);null!=e&&s.push(e)}for(const s of[t.a,t.b]){const t=Ba(s,e,o);null!=t&&i.push(t)}}}function Ga(t){let e=t+1|0;return e^=e<<13,e^=e>>>17,e^=e<<5,e>>>0}function ja(t,e){return t.minY-e.minY||t.index-e.index}function qa(t){return t.subtreeMaxY=Math.max(t.item.maxY,t.left?.subtreeMaxY??-1/0,t.right?.subtreeMaxY??-1/0),t}function Ua(t){const e=t.right;return t.right=e.left,e.left=qa(t),qa(e)}function Ka(t){const e=t.left;return t.left=e.right,e.right=qa(t),qa(e)}function Va(t,e){return t?(ja(e,t.item)<0?(t.left=Va(t.left,e),t.left.priority0)t.right=Ja(t.right,e);else{if(!t.left)return t.right;if(!t.right)return t.left;t.left.priority=e&&Ya(t.left,e,s,i),t.item.minY<=s&&t.item.maxY>=e&&i.push(t.item),t.item.minY<=s&&Ya(t.right,e,s,i))}function Xa(t,e=.001){const s=Number.isFinite(e)&&e>0?e:Da,i=t.filter(t=>Ta(t.a)&&Ta(t.b)&&"string"==typeof t.key&&t.key.length>0&&Math.hypot(t.b[0]-t.a[0],t.b[1]-t.a[1])>s),o=i.map(()=>[0,1]);!function(t,e,s){const i=t.map((t,e)=>({index:e,minX:Math.min(t.a[0],t.b[0])-s,maxX:Math.max(t.a[0],t.b[0])+s,minY:Math.min(t.a[1],t.b[1])-s,maxY:Math.max(t.a[1],t.b[1])+s})),o=[...i].sort((t,e)=>t.minX-e.minX||t.minY-e.minY||t.index-e.index),a=[...i].sort((t,e)=>t.maxX-e.maxX||t.index-e.index),n=new Set;let r=null,h=0;for(const i of o){for(;ht.index-e.index);for(const a of o)Wa(t[a.index],t[i.index],e[a.index],e[i.index],s);n.add(i.index),r=Va(r,i)}}(i,o,s);const a=new Map;for(let t=0;t({key:t,a:e.a,b:e.b,sourceKeys:[...e.sourceKeys].sort((t,e)=>t.localeCompare(e))})).sort((t,e)=>t.key.localeCompare(e.key))}function Za(t,e=.001){const s=Number.isFinite(e)&&e>0?e:Da,i=Xa(t,s),o=new Map,a=new Map,n=new Map(i.map(t=>[t.key,t]));for(const t of i){const e=Aa(t.a,s),i=Aa(t.b,s);o.set(e,t.a),o.set(i,t.b),a.has(e)||a.set(e,new Set),a.has(i)||a.set(i,new Set),a.get(e).add(i),a.get(i).add(e)}const r=new Map;for(const[t,e]of a){const s=o.get(t);r.set(t,[...e].sort((t,e)=>{const i=o.get(t),a=o.get(e);return Math.atan2(i[1]-s[1],i[0]-s[0])-Math.atan2(a[1]-s[1],a[0]-s[0])||t.localeCompare(e)}))}const h=new Set,l=new Map,c=(t,e)=>`${t}>${e}`;for(const t of i){const e=[Aa(t.a,s),Aa(t.b,s)];for(const[t,a]of[e,[e[1],e[0]]]){if(h.has(c(t,a)))continue;const e=[],d=[];let p=t,_=a,u=!1;for(let s=0;s<=2*i.length+2;s++){const s=c(p,_);if(h.has(s)){u=p===t&&_===a;break}h.add(s),e.push(p),d.push(Na(p,_));const i=r.get(_)||[],o=i.indexOf(p);if(o<0||!i.length)break;if(p=_,_=i[(o-1+i.length)%i.length],p===t&&_===a){u=!0;break}}if(!u||new Set(e).size<3||new Set(e).size!==e.length)continue;const m=e.map(t=>o.get(t)),g=za(m);if(!(g>s*s))continue;const f=Ha(Oa(e,o,s)),b=new Set;for(const t of d)for(const e of n.get(t)?.sourceKeys||[])b.add(e);const v={ring:m,key:f,area:g,atomKeys:[...d],sourceKeys:[...b].sort((t,e)=>t.localeCompare(e))};l.has(f)||l.set(f,v)}}return{atoms:i,faces:[...l.values()].sort((t,e)=>t.area-e.area||t.key.localeCompare(e.key))}}function Qa(t,e,s=.001){if(!Ta(e))return null;const i=t.faces.filter(t=>{if(t.ring.some((i,o)=>function(t,e,s,i){const o=s[0]-e[0],a=s[1]-e[1],n=o*o+a*a;if(!(n>0))return Math.hypot(t[0]-e[0],t[1]-e[1])<=i;const r=((t[0]-e[0])*o+(t[1]-e[1])*a)/n;return!(r<0||r>1)&&Math.hypot(e[0]+o*r-t[0],e[1]+a*r-t[1])<=i}(e,i,t.ring[(o+1)%t.ring.length],s)))return!1;let i=!1;for(let s=0,o=t.ring.length-1;se[1]!=n[1]>e[1]&&e[0]<(n[0]-a[0])*(e[1]-a[1])/(n[1]-a[1])+a[0]&&(i=!i)}return i});return[...i].sort((t,e)=>t.area-e.area||t.key.localeCompare(e.key))[0]||null}function tn(t,e,s){const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o,n=a>0?Math.max(0,Math.min(1,((t[0]-e[0])*i+(t[1]-e[1])*o)/a)):0;return Math.hypot(e[0]+i*n-t[0],e[1]+o*n-t[1])}function en(t,e,s=.5){let i=Math.abs(t-e)%180;return i>90&&(i=180-i),i<=s}function sn(t,e,s,i){const o=t.filter(t=>"outer"===t.kind&&!t.open&&t.cm>0).map(t=>({interval:t,reusePartitionId:e.find(e=>function(t,e,s){return!(Math.abs(t.cm-e.cm)>1e-6)&&(en(180*Math.atan2(t.b[1]-t.a[1],t.b[0]-t.a[0])/Math.PI,180*Math.atan2(e.b[1]-e.a[1],e.b[0]-e.a[0])/Math.PI,.001)&&tn(e.a,t.a,t.b)<=s&&tn(e.b,t.a,t.b)<=s)}(e,t,i))?.id||null})),a=new Map;for(const e of s){if("partition"===e.host?.kind)continue;const s=t.map(t=>{const s=180*Math.atan2(t.b[1]-t.a[1],t.b[0]-t.a[0])/Math.PI;return{interval:t,distance:en(e.angle,s)?tn([e.x,e.y],t.a,t.b):1/0}}).filter(t=>t.distance<=i).sort((t,e)=>t.distance-e.distance||t.interval.key.localeCompare(e.interval.key)),o=s[0]?.interval;"outer"===o?.kind&&!o.open&&o.cm>0&&a.set(e.id,o.key)}return{materialize:o,openingIntervals:a,removeOpeningIds:[...a.keys()].sort((t,e)=>t.localeCompare(e))}}function on(t,e){const s=e.b[0]-e.a[0],i=e.b[1]-e.a[1],o=s*s+i*i;return o>0?Math.max(0,Math.min(1,((t[0]-e.a[0])*s+(t[1]-e.a[1])*i)/o)):0}const an=t=>!t.key.startsWith("static:room|");function nn(t,e){const s=e.b[0]-e.a[0],i=e.b[1]-e.a[1],o=s*s+i*i;if(!(o>0))return null;const a=((t[0]-e.a[0])*s+(t[1]-e.a[1])*i)/o,n=[e.a[0]+s*a,e.a[1]+i*a];return{point:n,t:a,distance:Math.hypot(n[0]-t[0],n[1]-t[1])}}function rn(t,e){return e>0?Math.hypot(t[0]-Math.round(t[0]/e)*e,t[1]-Math.round(t[1]/e)*e):0}function hn(t,e,s){if(an(t.source)!==an(e.source))return an(t.source)?t:e;const i=rn(t.point,s),o=rn(e.point,s);return Math.abs(i-o)>1e-9?i>o?t:e:function(t,e){return t[0]-e[0]||t[1]-e[1]}(t.point,e.point)>0?t:e}function ln(t){return[t.from[0],t.from[1],t.to[0],t.to[1],t.targetKind].map(t=>"number"==typeof t?t.toFixed(6):t).join("|")}function cn(t,e){return t.map(t=>t.key!==e.sourceKey?t:{...t,[e.endpoint]:[...e.to]})}function dn(t,e){const s=e.epsilon??.001;if(!(e.maxDistance>=0)||!e.point&&!e.requiredSourceKey)return{kind:"none"};const i=new Map,o=t.flatMap(t=>[{source:t,endpoint:"a",point:t.a},{source:t,endpoint:"b",point:t.b}]);for(let t=0;ts)||h>e.maxDistance)continue;const l=hn(n,r,e.gridStep||0),c=l===n?r:n;if(!an(l.source))continue;const d={sourceKey:l.source.key,endpoint:l.endpoint,from:[l.point[0],l.point[1]],to:[c.point[0],c.point[1]],targetSourceKey:c.source.key,targetKind:"endpoint",distance:h};i.set(ln(d),d)}for(const a of o)if(an(a.source))for(const o of t){if(o===a.source)continue;const t=nn(a.point,o);if(!t||t.t<=s||t.t>=1-s||!(t.distance>s)||t.distance>e.maxDistance)continue;const n={sourceKey:a.source.key,endpoint:a.endpoint,from:[a.point[0],a.point[1]],to:t.point,targetSourceKey:o.key,targetKind:"line",distance:t.distance};i.set(ln(n),n)}const a=[];for(const o of i.values()){const i=Za(cn(t,o),s),n=e.point?Qa(i,e.point,s):i.faces.find(t=>!e.requiredSourceKey||t.sourceKeys.includes(e.requiredSourceKey))||null;n&&a.push({proposal:o,face:n})}if(a.sort((t,e)=>t.proposal.distance-e.proposal.distance||ln(t.proposal).localeCompare(ln(e.proposal))),!a.length)return{kind:"none"};return new Set(a.map(t=>`${ln(t.proposal)}|${t.face.key}`)).size>1?{kind:"ambiguous",proposals:a.map(t=>t.proposal)}:{kind:"repair",...a[0]}}const pn=(t,e)=>(t.composedPath?.()||[t.target]).some(t=>(t=>!!t&&"function"==typeof t.matches)(t)&&e(t));class _n{constructor(t){this.host=t,this._openGroupId=null,this._groupGeneration=0,this._renderedContext="",this._focusOwned=!1,this._currentModel=null,this._blocked=!1,this._dismissPointerTarget=null,this._globalDismissListening=!1,this._globalDismissGuard=t=>{this.handleOutsideDismiss(t)}}get hasOpenGroup(){return null!==this._openGroupId}get groupGeneration(){return this._groupGeneration}activeGroup(t){return this._openGroupId&&t.find(t=>t.id===this._openGroupId)||null}reset(){this._openGroupId=null,this._contentAnimation?.cancel(),this._contentAnimation=void 0,this._renderedContext="",this._focusOwned=!1,this._currentModel=null,this._blocked=!1,this._dismissPointerTarget=null,clearTimeout(this._dismissTimer),this._dismissTimer=void 0,this._syncGlobalDismissListener()}closeForNavigation(){const t="palette"===this._currentModel?.kind?this._currentModel.dismiss:void 0,e=!!this._openGroupId||!!t;this._openGroupId=null,t?.(),t&&(this._currentModel=null),this._clearDismissClick(),e&&this.host.requestUpdate(),this._syncGlobalDismissListener()}openPalette(){this._openGroupId&&this.closeGroup(!1)}toggleGroup(t,e){this._openGroupId!==e?t.some(t=>t.id===e)&&("palette"===this._currentModel?.kind&&this._currentModel.dismiss?.(),this._groupGeneration+=1,this._openGroupId=e,this.host.clearTip(),this.host.requestUpdate(),this._syncGlobalDismissListener()):this.closeGroup(!1)}closeGroup(t){const e=this._openGroupId;this._openGroupId=null,this.host.requestUpdate(),this._syncGlobalDismissListener(),t&&e&&this.host.updateComplete().then(()=>{const t=this.host.root(),s=[...t.querySelectorAll("[data-editor-group]")].find(t=>t.dataset.editorGroup===e&&null!==t.offsetParent);(s||t.querySelector(".editbar-tools"))?.focus?.()})}renderGroupLauncher(t,e,s){const i=this._openGroupId===t.id,a=t.items.find(e=>e.id===t.activeItemId&&!e.disabled);return o``}renderGroupModel(t,e,s){const i=t.items.find(t=>!t.disabled)?.id,n=t.items.some(e=>e.id===t.activeItemId&&!e.disabled)?t.activeItemId:void 0;return{contextId:e,kind:"group",ariaLabel:s.openGroup(t.label),visibleLabel:t.label,content:o`
this._groupKeydown(t)}> + ${t.items.map(e=>o``)} +
`}}runContext(t,e,s){t===e&&s()}render(t,e){this._currentModel=t,this._blocked=e;const s=t?.kind||"hidden";return o`
+ +
`}afterRender(){const t=this.host.root();this._blocked&&(this._openGroupId?this.closeGroup(!1):"palette"===this._currentModel?.kind&&this._currentModel.dismiss?.()),this._syncGlobalDismissListener();const e=t.querySelector(".editor-secondary"),s=this._renderedContext,i=e?.dataset.contextId||"";if(i&&s&&i!==s&&!window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches&&(this._contentAnimation?.cancel(),this._contentAnimation=e?.querySelector(".editor-secondary-content")?.animate([{opacity:.35,transform:"translateY(-4px)"},{opacity:1,transform:"translateY(0)"}],{duration:100,easing:"ease-out"})),this._renderedContext=i,s&&i!==s&&this._focusOwned){const s=i?e?.querySelector('[tabindex="0"], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled])'):t.querySelector(".editbar-tools");s?.focus?.(),this._focusOwned=!!i}if("palette"===this._currentModel?.kind&&this._currentModel.launcherId){const e=[...t.querySelectorAll("[data-editor-palette]")].find(t=>t.dataset.editorPalette===this._currentModel?.launcherId);e&&null!==e.offsetParent||this._currentModel.dismiss?.()}if(!this._openGroupId)return;const o=[...t.querySelectorAll("[data-editor-group]")].find(t=>t.dataset.editorGroup===this._openGroupId);o&&null!==o.offsetParent||this.closeGroup(!0)}handleOutsideDismiss(t){if(pn(t,t=>t.hasAttribute("data-editor-navigation")))return"pointerdown"===t.type?this.closeForNavigation():"click"===t.type&&this._dismissPointerTarget&&this._clearDismissClick(),!1;if("click"===t.type&&this._dismissPointerTarget){return!!(t.composedPath?.()||[t.target]).includes(this._dismissPointerTarget)&&(this._clearDismissClick(),t.preventDefault(),t.stopImmediatePropagation(),!0)}const e=this._openGroupId||this._blocked||"palette"!==this._currentModel?.kind?null:this._currentModel;if("pointerdown"===t.type&&(this._openGroupId||e)){const s=pn(t,t=>t.classList.contains("editor-secondary")),i=pn(t,t=>!!t.dataset.editorGroup),o=pn(t,t=>!!t.dataset.editorPalette),a=pn(t,t=>t.classList.contains("stage"));if(!(s||i||o||"stay-open-on-canvas"===e?.dismissPolicy&&a))return t.preventDefault(),t.stopImmediatePropagation(),this._dismissPointerTarget=t.target,clearTimeout(this._dismissTimer),this._dismissTimer=window.setTimeout(()=>{this._clearDismissClick()},800),this._openGroupId?this.closeGroup(!1):e?.dismiss?.(),this._syncGlobalDismissListener(),!0}return!1}_activateGroupItem(t,e,s){if(t.id!==this._openGroupId)return;const i=t.items.find(t=>t.id===e);if(!i||i.disabled)return;const o="toggle"===i.role&&"stay-open"===i.closePolicy,a=0===s.detail;o||(this._openGroupId=null,this.host.requestUpdate(),this._syncGlobalDismissListener()),i.invoke(),!o&&a&&this.host.updateComplete().then(()=>{const e=[...this.host.root().querySelectorAll("[data-editor-group]")].find(e=>e.dataset.editorGroup===t.id&&null!==e.offsetParent);e?.focus()})}_groupKeydown(t){if(!["ArrowLeft","ArrowRight","Home","End"].includes(t.key))return;const e=[...t.currentTarget.querySelectorAll(".editor-group-item:not([disabled])")];if(!e.length)return;t.preventDefault();const s=e.indexOf(this.host.root().activeElement),i="Home"===t.key?0:"End"===t.key?e.length-1:"ArrowLeft"===t.key?s<=0?e.length-1:s-1:(s+1)%e.length;e[i]?.focus()}_clearDismissClick(){this._dismissPointerTarget=null,clearTimeout(this._dismissTimer),this._dismissTimer=void 0,this._syncGlobalDismissListener()}_syncGlobalDismissListener(){const t=!this._blocked&&"palette"===this._currentModel?.kind,e=!!this._openGroupId||t||!!this._dismissPointerTarget;e!==this._globalDismissListening&&(this._globalDismissListening=e,e?(window.addEventListener("pointerdown",this._globalDismissGuard,!0),window.addEventListener("click",this._globalDismissGuard,!0)):(window.removeEventListener("pointerdown",this._globalDismissGuard,!0),window.removeEventListener("click",this._globalDismissGuard,!0)))}}const un=t=>t.stopPropagation(),mn=1e-6*I,gn=6*I;function fn(t){return Number.isFinite(t)?Math.round(t/I)*I:t}const bn=(t,e,s,i)=>Math.hypot(s-t,i-e),vn=(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)))),yn=(t,e,s,i,o,a,n)=>{const r=Math.max(Number(i)||0,0)/2,h=Math.PI/180,l=Math.cos(s*h)*r,c=Math.sin(s*h)*r,d=Math.cos(n*h)*r,p=Math.sin(n*h)*r,_=Math.max(bn(t+l,e+c,o+d,a+p),bn(t-l,e-c,o-d,a-p)),u=Math.max(bn(t+l,e+c,o-d,a-p),bn(t-l,e-c,o+d,a+p));return Math.min(_,u)},$n=t=>{const e=Number(t?.cell_cm);return e>0?e:5};function wn(t,e){const s=JSON.parse(JSON.stringify(t||[])),i=JSON.parse(JSON.stringify(e||{}));let o=0,a=0,n=0,r=0,h="",l=0,c=0,d=0;const p=(t,e)=>{Number.isFinite(t)&&Number.isFinite(e)&&t!==e&&Math.abs(e-t)<=mn&&c++},_=(t,e)=>{p(t[0],e[0]),p(t[1],e[1])},u={};let m=5;for(const t of s){const e=$n(t);null!=t?.id&&(u[String(t.id)]=e),e>m&&(m=e)}const g=(t,e,s,i=!1)=>{if(!(t>mn||i))return;o++,t>n&&(n=t);const a=t*T*e;a>r&&(r=a,h=s)};for(const t of s){const e=$n(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=[fn(e[0]),fn(e[1])];return t=Math.max(t,bn(e[0],e[1],s[0],s[1])),_(e,s),s});else if(null!=i.x&&null!=i.y){const e=i.x,s=i.y,o=i.w||0,a=i.h||0,n=fn(e+o),r=fn(s+a),h=fn(e),l=fn(s),c=Math.max(I,n-h),d=Math.max(I,r-l);t=vn(e,s,o,a,h,l,c,d),i.x=h,i.y=l,i.w=c,i.h=d,p(e,h),p(s,l),p(e+o,h+c),p(s+a,l+d)}g(t,e,s)}for(const i of t.room_drafts||[]){a++;let t=0;const o=i.points||[],n=o.map(e=>{const s=[fn(e[0]),fn(e[1])];return t=Math.max(t,bn(e[0],e[1],s[0],s[1])),s}),r=n.length?[n[0]]:[],h=n.length?[[o[0],n[0]]]:[],l=[];for(let t=0;t+1=2)for(const[t,e]of h)_(t,e);g(t,e,s)}if(Array.isArray(t.room_drafts)){const e=t.room_drafts.length;t.room_drafts=t.room_drafts.filter(t=>t.points?.length>=2),d+=e-t.room_drafts.length,t.room_drafts.length||delete t.room_drafts}for(const i of t.partitions||[]){a++;const o=[i.a[0],i.a[1]],n=[i.b[0],i.b[1]],r=[fn(o[0]),fn(o[1])],h=[fn(n[0]),fn(n[1])];let l=Math.max(bn(o[0],o[1],r[0],r[1]),bn(n[0],n[1],h[0],h[1]));const c=bn(r[0],r[1],h[0],h[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>=-mn&&i+e/2<=c+mn});c>mn&&d?(i.a=r,i.b=h,_(o,r),_(n,h)):l=0,g(l,e,s)}for(const i of t.wall_columns||[]){a++;const t=[i.center[0],i.center[1]],o=[fn(t[0]),fn(t[1])],n=bn(t[0],t[1],o[0],o[1]);i.center=o,_(t,o),g(n,e,s)}for(const i of t.decor||[]){a++;let t=0;if("line"===i.kind){const e=[i.x1,i.y1],s=[i.x2,i.y2],o=[fn(e[0]),fn(e[1])],a=[fn(s[0]),fn(s[1])];t=Math.max(bn(e[0],e[1],o[0],o[1]),bn(s[0],s[1],a[0],a[1])),i.x1=o[0],i.y1=o[1],i.x2=a[0],i.y2=a[1],_(e,o),_(s,a)}else{const e=i.x,s=i.y,o=i.w,a=i.h,n=fn(e),r=fn(s);if(null!=i.w&&null!=i.h){const h=fn(e+o),l=fn(s+a),c=Math.max(I,h-n),d=Math.max(I,l-r);t=vn(e,s,o,a,n,r,c,d),i.w=c,i.h=d,p(e+o,n+c),p(s+a,r+d)}else t=bn(e,s,n,r);i.x=n,i.y=r,p(e,n),p(s,r)}g(t,e,s)}for(const i of t.openings||[]){if(a++,"partition"===i.host?.kind){const o=(t.partitions||[]).find(t=>t.id===i.host.id),a=Number(i.host.t);if(!o||!Number.isFinite(a)||a<0||a>1)continue;const n=o.b[0]-o.a[0],r=o.b[1]-o.a[1];if(Math.hypot(n,r)<=mn)continue;const h=o.a[0]+n*a,c=o.a[1]+r*a;let d=180*Math.atan2(r,n)/Math.PI;d>=90?d-=180:d<-90&&(d+=180);const p=Number(i.angle),_=!(Number.isFinite(p)&&p===d),u=yn(i.x,i.y,Number.isFinite(p)?p:d,Number(i.length)||0,h,c,d);i.x=h,i.y=c,i.angle=d,_&&l++,g(u,e,s,_);continue}const o=P([i.x,i.y],t.rooms||[],gn,{step:I,length:Number(i.length)||0});if(!o)continue;const n=Number(i.angle),r=!(Number.isFinite(n)&&n===o.angle),h=yn(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&&l++,g(h,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=fn(s.x),n=fn(s.y),r=bn(s.x,s.y,o,n);i[t]={...s,x:o,y:n},p(s.x,o),p(s.y,n);const h="string"==typeof s.s?s.s:"";g(r,u[h]??m,h)}return{spaces:s,layout:i,report:{moved:o,coordsCanonicalized:c,total:a,maxShift:n,maxShiftCm:r,maxSpace:h,rotated:l,removedDrafts:d},changed:o>0||c>0}}function kn(t,e){const s=e.base+t*e.span;return Math.min(1,Math.max(0,s))}const xn=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),Mn=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1]);function Sn(t,e,s){const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;if(a<=0)return Mn(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 Cn(t,e,s,i,o){for(const i of e)if(i&&!s.has(i.id)&&xn(i.a)&&xn(i.b)&&(Mn(t,i.a)<=o||Mn(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(Mn(s,o)<=i)return[(s[0]+o[0])/2,(s[1]+o[1])/2];return null}function Pn(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&&xn(t.a)&&xn(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;tMn(e,t.at)>s);let c=l[0]??r.a,d=l[l.length-1]??h.b;if(l.length<2&&(c=r.a,d=h.b),d[0]0?(d[0]-c[0])/_:0,m=_>0?(d[1]-c[1])/_:0,g=t=>_>0?((t[0]-c[0])*u+(t[1]-c[1])*m)/_:0;for(const t of[r,h]){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 In(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:kn(t.t,n)},a++;const r=z(s,e,i.coordScale,i.cellCm,i.gridPitch).resolved;r&&Object.assign(s,F(s,r,i.coordScale))}return a}function Tn(t,e){const s=e?.excludeDraftId||null;return{roomPolygons:(t?.rooms||[]).map(t=>R(t)).filter(t=>!!t),columns:t?.wall_columns||[],draftEnds:(t?.room_drafts||[]).flatMap(t=>{if(s&&t?.id===s)return[];const e=t?.points||[];return e.length?[e[0],e[e.length-1]]:[]})}}const Rn=t=>!!t&&t.length>=2&&Number.isFinite(t[0])&&Number.isFinite(t[1]),zn=(t,e)=>t[0]-e[0]||t[1]-e[1],Fn=(t,e,s,i)=>[t[0]+e*i,t[1]+s*i],An=(t,e,s,i)=>(t[0]-e[0])*s+(t[1]-e[1])*i,Nn=(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 h=a/r,l=n/r,c=e=>Math.abs((e[0]-t[0])*l-(e[1]-t[1])*h);if(c(s)>o||c(i)>o)return null;const d=An(s,t,h,l),p=An(i,t,h,l),_=Math.max(0,Math.min(d,p)),u=Math.min(r,Math.max(d,p));return u-_>o?{lo:_,hi:u}:null},Hn=(t,e,s)=>Math.min(t.hi,e.hi)-Math.max(t.lo,e.lo)>s,On=t=>{const e=new Set(["id","a","b","cm"]);return Object.keys(t||{}).every(t=>e.has(t))},Ln=(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,h=a/n,l=j(t.cm,s.cellCm,s.gridPitch)/2;return e.some(e=>{const o=e?.center;if(!Rn(o))return!0;const a=An(o,t.a,r,h),c=Math.abs((o[0]-t.a[0])*h-(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<=l+d+i})},En=(t,e,s)=>{if(t.host){const i=z(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},Bn=(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),h=Math.sin(n);if(Math.abs(o*h-a*r)>1e-6)return!1;const l=e.center[0]-t.center[0],c=e.center[1]-t.center[1];if(Math.abs(l*a-c*o)>s)return!1;const d=l*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]}),Gn=(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},jn=(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 qn(t,e,s,i,o){const a=s||[],n=Array.isArray(t?.partitions)?t.partitions:[],r=Array.isArray(t?.openings)?t.openings:[],h=Array.isArray(t?.room_drafts)?t.room_drafts:[],l={walls:a,partitions:n,openings:r,roomDrafts:h,partitionsReconciled:0,openingsRehosted:0,removedDrafts:0};if(!n.length&&!h.length)return l;const c=Math.max(2e-4*o.gridPitch,1e-9);let d=a,p=n,_=r;const u=A(e.rooms,d,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),m=((t,e,s,i)=>{const o=new Map(t.map(t=>[t.id,t])),a=new Set;for(const t of e){if(!o.get(t.id)||!Array.isArray(t.points)||t.points.length<2||t.segments.length!==t.points.length-1)continue;let e=!0;for(let o=0;o+10)){e=!1;break}const h=Math.hypot(n[0]-a[0],n[1]-a[1]);if(!(h>i)){e=!1;break}const l=s.flatMap(t=>{const e=t.cm>0?t.cm:N;if(t.open||"outer"!==t.kind&&"shared"!==t.kind||e+it.lo-e.lo||t.hi-e.hi);let c=0;for(const t of l){if(t.lo>c+i)break;if(c=Math.max(c,t.hi),c>=h-i)break}c!m.has(t.id));let f=0,b=0;const v=new Map(e.partitions.map(t=>[t.id,t]));for(const t of[...n].sort((t,e)=>t.id.localeCompare(e.id))){if(!p.some(e=>e.id===t.id))continue;if(!On(t))continue;const s=v.get(t.id);if(!(s&&Rn(s.a)&&Rn(s.b)&&Number.isFinite(s.cm)&&s.cm>0))continue;const[a,n]=zn(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],h=n[1]-a[1],l=Math.hypot(r,h);if(!(l>c))continue;const u=r/l,g=h/l,y=A(e.rooms,d,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),$=y.flatMap(t=>{if(t.open||"outer"!==t.kind&&"shared"!==t.kind)return[];const e=Nn(a,n,t.a,t.b,c);return e?[{interval:t,range:e}]:[]});if(!$.length)continue;const w=_.filter(t=>"partition"===t.host?.kind&&t.host.id===s.id).map(t=>({opening:t,resolved:z(t,e.partitions,o.coordScale,o.cellCm,o.gridPitch).resolved}));if(w.some(t=>!t.resolved))continue;const k=[0,l];for(const{range:t}of $)k.push(t.lo,t.hi);const x=k.slice(),M=new Map;for(const{opening:t,resolved:e}of w){const s=An(e.center,a,u,g),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(l,i.hi))}const S=[...new Set(x.filter(t=>Number.isFinite(t)&&t>=-c&&t<=l+c).map(t=>Math.max(0,Math.min(l,t)).toFixed(9)))].map(Number).sort((t,e)=>t-e),C=p.map(t=>Wn(t,o.coordScale)).filter(t=>t.id!==s.id),D=e.room_drafts.filter(t=>!m.has(t.id)),P=[];for(let t=0;t+1c))continue;const r=Fn(a,u,g,i),h=Fn(a,u,g,n),l=$.filter(({range:t})=>t.lo<=i+c&&t.hi>=n-c).map(({interval:t})=>t),d=new Map;for(const t of l)d.set(t.roomId,t);const p=[...d.values()],_=new Set(p.map(t=>t.kind)),m=new Set(p.map(t=>t.cm>0?t.cm:N)),f=p[0]?.kind,b=[...d.keys()].sort(),v=1===_.size&&1===m.size&&("outer"===f&&1===b.length||"shared"===f&&2===b.length),y={id:s.id,a:r,b:h,cm:s.cm},w=C.some(t=>!!Nn(r,h,t.a,t.b,c)),k=D.some(t=>t.points.some((e,s)=>s+10?p[0].cm:N:0,I=v?Math.max(M,s.cm):s.cm;P.push({lo:i,hi:n,a:r,b:h,safe:x,signature:x?`${f}|${b.join(",")}|${I}`:"",roomIds:b,roomCm:M,finalCm:I})}if(!P.some(t=>t.safe))continue;const I=new Map;for(const{opening:t,resolved:e}of w){const i=M.get(t.id),a=k.some(t=>t>i.lo+c&&tHn(t,i,c)),r=new Set(n.filter(t=>t.safe).map(t=>t.signature));if(!a&&n.length>0&&n.every(t=>t.safe)&&1===r.size&&H(e,y,c)){I.set(t.id,{resolved:e,signature:[...r][0]});continue}const h=O(s,o.cellCm,o.gridPitch),l={lo:i.lo-h,hi:i.hi+h};for(const t of P)Hn(t,l,c)&&(t.safe=!1,t.signature="")}let T=!0;for(;T;){T=!1;for(const[t,e]of[...I.entries()]){const i=M.get(t),a=P.filter(t=>Hn(t,i,c));if(a.length>0&&a.every(t=>t.safe)&&a.every(t=>t.signature===e.signature))continue;I.delete(t);const n=O(s,o.cellCm,o.gridPitch),r={lo:i.lo-n,hi:i.hi+n};for(const t of P)Hn(t,r,c)&&(t.safe=!1,t.signature="");T=!0}}const R=jn(P,c),j=R.filter(t=>t.safe),q=R.filter(t=>!t.safe);if(!j.length)continue;if(p.length-1+q.length>2e3)continue;let U=d;for(const t of j){const[e,i]=zn(s.a,s.b)<=0?[t.a,t.b]:[t.b,t.a];U=L(U,e,i,t.finalCm,o.pitch,o.coordScale)}if(U=E(e.rooms,U,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale),U.length>500)continue;const K=new Set(p.map(t=>t.id));K.delete(s.id);const V=q.map((t,e)=>{const i=[t.a[0]/o.coordScale,t.a[1]/o.coordScale],a=[t.b[0]/o.coordScale,t.b[1]/o.coordScale],n=0===e?s.id:Gn(s.id,i,a,K);return K.add(n),{id:n,a:i,b:a,cm:s.cm}}),J=p.findIndex(t=>t.id===s.id),Y=p.slice();Y.splice(J,1,...V);const X=Y.map(t=>Wn(t,o.coordScale)),Z=new Map;let Q=!0;for(const{opening:t,resolved:e}of w){const s=I.get(t.id);if(s){const e=F(t,s.resolved,o.coordScale),{host:i,...a}=e;Z.set(t.id,a);continue}const i=M.get(t.id),a=V[q.findIndex(t=>t.lo<=i.lo+c&&t.hi>=i.hi-c)],n=a&&X.find(t=>t.id===a.id);if(!a||!n){Q=!1;break}const r=n.b[0]-n.a[0],h=n.b[1]-n.a[1],l=Math.hypot(r,h),d=An(e.center,n.a,r/l,h/l),p={...F(t,e,o.coordScale),host:{kind:"partition",id:a.id,t:d/l}};if(!B(p,X,o.coordScale,o.cellCm,o.gridPitch).resolved){Q=!1;break}Z.set(t.id,p)}if(!Q)continue;const tt=_.map(t=>Z.get(t.id)||t),et=[...I.keys()].map(t=>Z.get(t)),st=et.map(t=>En(t,X,o));if(st.some(t=>!t))continue;let it=!1;for(let t=0;tt.id));for(const t of tt){if(ot.has(t.id))continue;const e=En(t,X,o);e&&st.some(t=>Bn(t,e,c))&&(it=!0)}if(it)continue;const at=W(e.rooms,U,i,o.pitch,o.cellCm,o.gridPitch,o.coordScale);[...I.entries()].every(([t,e])=>{const s=Z.get(t),i=G(at,{x:s.x*o.coordScale,y:s.y*o.coordScale,angle:s.angle,length:s.length*o.coordScale},!0),a=[i.negative,i.positive].filter(t=>!!t?.full),n=e.signature.split("|")[1].split(","),r=new Set(a.map(t=>t.roomId));return a.length===n.length&&r.size===n.length&&n.every(t=>r.has(t))})&&(d=U,p=Y,_=tt,f+=j.length,b+=I.size)}return{walls:d,partitions:p,openings:_,roomDrafts:g,partitionsReconciled:f,openingsRehosted:b,removedDrafts:m.size}}const Un=t=>JSON.parse(JSON.stringify(t)),Kn=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),Vn=(t,e)=>e.length>0&&e.length<=35&&("space"===t?/^[a-z0-9_-]+$/.test(e):/^[A-Za-z0-9_-]+$/.test(e));function Jn(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 Yn=(t,e,s)=>{const i=t.get(e)||[];i.push(s),t.set(e,i)};const Xn=1e-9;class Zn extends Error{constructor(t,e=""){super(e?`${t}: ${e}`:t),this.reason=t,this.name="WallSegmentModelError"}}const Qn=t=>JSON.parse(JSON.stringify(t)),tr=t=>Array.isArray(t)&&t.length>=2&&Number.isFinite(Number(t[0]))&&Number.isFinite(Number(t[1])),er=t=>[Number(t[0]),Number(t[1])],sr=t=>`${Number(t[0]).toFixed(12)},${Number(t[1]).toFixed(12)}`,ir=(t,e)=>{const s=sr(t),i=sr(e);return ssr(t)<=sr(e)?[er(t),er(e)]:[er(e),er(t)],ar=(t,e)=>Math.hypot(e[0]-t[0],e[1]-t[1]),nr=t=>{const e=[[Number(t.points[0][0]),Number(t.points[0][1])]],s=[];for(let i=1;i{const s=new Set,i=t=>{const e=Number(t);if(!Number.isFinite(e))return;const i=e/I;Math.abs(i-Math.round(i))>=X&&s.add(e.toFixed(12))};for(const e of Array.isArray(t?.rooms)?t.rooms:[])for(const t of R(e)||[])i(t[0]),i(t[1]);for(const e of[t?.wall_segments,t?.walls])for(const t of Array.isArray(e)?e:[])i(t?.a?.[0]),i(t?.a?.[1]),i(t?.b?.[0]),i(t?.b?.[1]);for(const t of e)i(t?.[0]),i(t?.[1]);return s.size},hr=(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},lr=(t,e,s)=>{const i=Math.max(0,Math.min(1,hr(t,e,s)));return Math.hypot(t[0]-(e[0]+(s[0]-e[0])*i),t[1]-(e[1]+(s[1]-e[1])*i))},cr=(t,e,s,i,o=Xn)=>{const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(r<=o)return 0;const h=e=>Math.abs((e[0]-t[0])*n-(e[1]-t[1])*a)/r;if(h(s)>o||h(i)>o)return 0;const l=hr(s,t,e),c=hr(i,t,e);return Math.max(0,Math.min(1,Math.max(l,c))-Math.max(0,Math.min(l,c)))*r},dr=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]),h=new Uint32Array(64),l=(t,e)=>t>>>e|t<<32-e;for(let t=0;t>>3,o=l(s,17)^l(s,19)^s>>>10;h[t]=h[t-16]+i+h[t-7]+o>>>0}let[e,s,i,o,c,d,p,_]=r;for(let t=0;t<64;t++){const a=_+(l(c,6)^l(c,11)^l(c,25))+(c&d^~c&p)+n[t]+h[t]>>>0,r=e&s^e&i^s&i;_=p,p=d,d=c,c=o+a>>>0,o=i,i=s,s=e,e=a+((l(e,2)^l(e,13)^l(e,22))+r>>>0)>>>0}r[0]=r[0]+e>>>0,r[1]=r[1]+s>>>0,r[2]=r[2]+i>>>0,r[3]=r[3]+o>>>0,r[4]=r[4]+c>>>0,r[5]=r[5]+d>>>0,r[6]=r[6]+p>>>0,r[7]=r[7]+_>>>0}const c=new Uint8Array(32),d=new DataView(c.buffer);for(let t=0;t{const e="abcdefghijklmnopqrstuvwxyz234567";let s=0,i=0,o="";for(const a of t)for(i=i<<8|a,s+=8;s>=5;)o+=e[i>>>s-5&31],s-=5;return s&&(o+=e[i<<5-s&31]),o},_r=(t,e,s,i,o="")=>{const[a,n]=or(e,s),r=`${t}|${sr(a)}|${sr(n)}|${[...i].sort().join(",")}${o}`;return`wall-${pr(dr(r)).slice(0,20)}`};let ur=0;const mr=t=>{for(let e=0;e<1e3;e++){const e=globalThis.crypto?.randomUUID?.(),s=`wall-${e||pr(dr(`${Date.now()}|${ur++}|${Math.random()}`)).slice(0,26)}`;if(!t.has(s))return s}throw new Zn("duplicate-id","id factory exhausted")},gr=t=>{const e=new Map;for(const s of Array.isArray(t?.wall_segments)?t.wall_segments:[])if(s&&"string"==typeof s.id&&tr(s.a)&&tr(s.b)){if(e.has(s.id))throw new Zn("duplicate-id",s.id);e.set(s.id,s)}return e},fr=(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)<=Xn&&Math.abs(e[1]-i[1]-a)<=Xn?[o,a]:null};return i(s.a,s.b)||i(s.b,s.a)},br=(t,e)=>{const s=Array.isArray(t.rooms)?t.rooms:[],i=V(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]),o=i.length?i:J(s,null,1,.04*I,!0),a=[];for(const t of s){const s=R(t),i=Array.isArray(t?.wall_ids)?t.wall_ids:[];if(s&&i.length===s.length)for(let t=0;t"partition"!==t.host?.kind&&[Number(t.x),Number(t.y)].every(Number.isFinite)&&Number.isFinite(Number(t.angle))&&Number(t.length)>0&&o.some(e=>lr([Number(t.x),Number(t.y)],[e[0],e[1]],[e[2],e[3]])<=.04*I)):[],h=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]}}),l=(t,e)=>r.some(s=>{const i=[Number(s.x),Number(s.y)];if(!Z(t,e,Number(s.angle)))return!1;if(lr(i,t,e)>.02*I)return!1;const o=ar(t,e),a=hr(i,t,e)*o,n=Number(s.length)/2;return a+n>=-Xn&&a-n<=o+Xn}),c=new Map,d=[];for(const i of s){const r=String(i?.id||""),p=R(i);if(!r||!p||p.length<3)throw new Zn("invalid-room",r);const _=Y(s,r,n,I,1,[...t.walls||[],...h]);if(!_||_.poly.length<3)throw new Zn("invalid-room",r);const u=Array.isArray(i.wall_ids)?i.wall_ids:[],m=u.length===p.length;let g=null,f=m;if(f)for(let t=0;tXn||Math.abs(i[1]-g[1])>Xn)){f=!1;break}g=i}const b=[];for(let t=0;t<_.poly.length;t++){const s=_.poly[t],i=_.poly[(t+1)%_.poly.length];if(ar(s,i)<=Xn)throw new Zn("zero-length",r);const n=ir(s,i);let h=c.get(n);if(!h){const[t,e]=or(s,i);h={key:n,a:t,b:e,owners:new Set,preferredIds:new Set,positionalIds:new Set,preferredCarriers:new Map,parentKeys:new Set,zeroWall:!1},c.set(n,h)}if(h.owners.add(r),h.owners.size>2)throw new Zn("third-owner",n);const d=m?u[_.parent[t]]:void 0;if("string"==typeof d&&d){const o=e.get(d);f||!o||cr(s,i,o.a,o.b)>Xn?h.preferredIds.add(d):h.positionalIds.add(d),h.preferredCarriers.set(d,{a:er(p[_.parent[t]]),b:er(p[(_.parent[t]+1)%p.length])})}const g=_.parent[t];h.parentKeys.add(K(p[g],p[(g+1)%p.length],I));const v=[(s[0]+i[0])/2,(s[1]+i[1])/2],y=t=>t.some(t=>lr(v,[t[0],t[1]],[t[2],t[3]])<=.04*I);h.zeroWall||=y(a)||y(o)&&!l(s,i),b.push(n)}const v={...i};delete v.wall_ids,d.push({...v,poly:_.poly.map(t=>[t[0],t[1]]),wall_ids:b})}return{atoms:[...c.values()].sort((t,e)=>t.key.localeCompare(e.key)),rooms:d}},vr=(t,e,s,i,o)=>{const a=new Map([...s.values()].map(t=>[ir(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 Zn("duplicate-id",e);r.set(t,i);continue}if(t.preferredIds.size>1)throw new Zn("duplicate-id",[...t.preferredIds].sort().join(","));const i=[...t.preferredIds][0],h=i?s.get(i):void 0;if(h){r.set(t,h);continue}const l=i?t.preferredCarriers.get(i):void 0;if(i&&l){r.set(t,{id:i,a:l.a,b:l.b,cm:0});continue}const c=a.get(t.key);if(c){r.set(t,c);continue}const d=[...s.values()].filter(e=>cr(t.a,t.b,e.a,e.b)>Xn),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)||ar(e.a,e.b)-ar(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 h=new Map;for(const[t,e]of r){const s=h.get(e.id)||[];s.push(t),h.set(e.id,s)}for(const[t,e]of h){const i=s.get(t)||r.get(e[0]);if(!i)throw new Zn("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=lr(o,t.a,t.b)<=Xn?0:1,a=lr(o,e.a,e.b)<=Xn?0:1;if(s!==a)return s-a;return(lr(i.a,t.a,t.b)<=Xn?0:1)-(lr(i.a,e.a,e.b)<=Xn?0:1)||t.key.localeCompare(e.key)}),e[0].id=t}const l=(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(l.has(t.id))throw new Zn("duplicate-id",t.id);l.add(t.id)}const c=e.filter(t=>!t.id);if(i){const e=c.map(e=>{const[s,i]=or(e.a,e.b),o=`${String(t.id||"")}|${sr(s)}|${sr(i)}|${[...e.owners].sort().join(",")}`,a=pr(dr(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 Zn("duplicate-id",t.digest);s.set(t.digest,t.seed);let i=1,o=t.base;for(;l.has(o);)o=`${t.base}-${++i}`;t.atom.id=o,l.add(o)}}else for(const t of c)t.id=mr(l),l.add(t.id)},yr=(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=hr(s,e.a,e.b),o=ar(e.a,e.b),a=Number(t.length)/2;return i>=-Xn&&i<=1+Xn&&lr(s,e.a,e.b)<=.02*I&&Z(e.a,e.b,Number(t.angle))&&Number.isFinite(a)&&a>=0&&i*o-a>=-Xn&&i*o+a<=o+Xn},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,hr(s,n.a,n.b)))}},$r=(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=hr(s,e.a,e.b),a=ar(e.a,e.b);return o>=-Xn&&o<=1+Xn&&lr(s,e.a,e.b)<=.02*I&&Z(e.a,e.b,Number(t.angle))&&Number.isFinite(i)&&i>=0&&o*a-i>=-Xn&&o*a+i<=a+Xn}),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)=>lr(s,t.a,t.b)-lr(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,hr(s,a.a,a.b)))}:null},wr=(t,e,s)=>{const i=gr(t),{atoms:o,rooms:a}=br(t,i);vr(t,o,i,e,s);const n=o.map(e=>{const s=e.id?i.get(e.id):void 0,o=((t,e,s)=>{if(e.zeroWall)return 0;const i=Array.isArray(t.walls)?t.walls:[],o=K(e.a,e.b,I),a=i.filter(t=>Number(t.cm)>0&&(!(t.key!==o&&!e.parentKeys.has(t.key))||!(!tr(t.a)||!tr(t.b))&&cr(e.a,e.b,t.a,t.b)>=ar(e.a,e.b)-Xn)).map(t=>Math.max(1,Math.min(100,Number(t.cm))));if(new Set(a.map(t=>t.toFixed(9))).size>1)throw new Zn("thickness-conflict",e.key);if(a.length)return a[0];const n=Q(i,e.a,e.b,I,1);return n>0?n:Number(s?.cm)>0?Number(s.cm):0})(t,e,s);return{...s||{},id:e.id,a:[...e.a],b:[...e.b],cm:o}}),r=new Map(o.map(t=>[t.key,t.id]));for(const t of a)t.wall_ids=t.wall_ids.map(t=>r.get(t));t.rooms=a,t.wall_segments=n,t.walls=n.filter(t=>t.cm>0).map(t=>({key:K(t.a,t.b,I),cm:t.cm,a:[...t.a],b:[...t.b]})),t.walls.length||delete t.walls,delete t.open_spans;for(const e of t.rooms)delete e.open_to;return((t,e)=>{const s=new Set;for(const e of[t.rooms,t.openings,t.decor,t.room_drafts,t.partitions,t.wall_columns,t.wall_segments])for(const t of Array.isArray(e)?e:[])"string"==typeof t?.id&&t.id&&s.add(t.id);for(const i of Array.isArray(t.room_drafts)?t.room_drafts:[]){const o=Array.isArray(i.segments)?i.segments:[];for(let a=0;a{const i=Array.isArray(t.openings)?t.openings:[];for(const t of i){if("partition"===t.host?.kind)continue;if(!t.host&&!s){const s=yr(t,e);s&&(t.host=s);continue}const i=yr(t,e)??(s?$r(t,e):null);if(i)t.host=i;else{if(!s)throw new Zn("opening-host",t.id);delete t.host}}})(t,n,e),n.reduce((t,e)=>t+(i.has(e.id)?0:1),0)};function kr(t,e={}){const s=JSON.stringify(t),i=Qn(t);U(i);let o=0;const a=Number(i?.model_version||0)<9;for(const t of Array.isArray(i?.spaces)?i.spaces:[]){const s=e.lineageSpaceId===String(t?.id||"")?e.lineageHints:void 0;o+=wr(t,a,s)}return i.model_version=9,U(i),{config:i,changed:s!==JSON.stringify(i),migratedSegments:o}}const xr=t=>!!t&&"object"==typeof t&&!Array.isArray(t);function Mr(t,e){const s=(t,e)=>{if(Array.isArray(t)&&Array.isArray(e)){const i=new Map;for(const e of t)xr(e)&&"string"==typeof e.id&&e.id&&i.set(e.id,e);const o=e.map((e,o)=>{if(xr(e)&&"string"==typeof e.id&&e.id){const t=i.get(e.id);return t?s(t,e):Qn(e)}return o[e,e in t?s(t[e],i):Qn(i)]);for(const e of Object.keys(t))delete t[e];for(const[e,s]of i)t[e]=s;return t}return Qn(e)};return s(t,e)}const Sr=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),Cr=(t,e,s)=>Math.min(s,Math.max(e,t)),Dr=t=>ut({spaces:[t]})[0],Pr=(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,h=Math.max(i*r*.02,1e-9),l=[];for(const e of t||[])for(const t of R(e)||[])l.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*h),p=new Map;for(const n of t||[]){if(!n?.id)continue;const _=mt(t,n.id,e,s,i,o,a,r);if(_)for(let t=0;t<_.orig.length;t++){const e=[];for(let s=0;s<_.parent.length;s++)_.parent[s]===t&&e.push(s);for(let t=1;t+10&&u>0&&n===m&&u!==n))continue;const g=_.poly[i],f=_.poly[(i+1)%_.poly.length],b=Math.hypot(f[0]-g[0],f[1]-g[1]);if(!(b>h&&b<.5*a-1e-9*a))continue;if(d(g,c)||d(f,c))continue;if(d(g,l)&&d(f,l))continue;const v=Pr(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 _=e.slice();const u=(t,e)=>Math.hypot(t[0]-e[0],t[1]-e[1])<=2*h,m=(t,e)=>{if(!Array.isArray(t.a)||!Array.isArray(t.b)||t.a.length<2||t.b.length<2)return!1;const s=[Number(t.a[0])*r,Number(t.a[1])*r],i=[Number(t.b[0])*r,Number(t.b[1])*r];return!![...s,...i].every(Number.isFinite)&&(u(s,e.a)&&u(i,e.b)||u(s,e.b)&&u(i,e.a))};for(const t of[...p.values()].filter(t=>1===t.targets.size).sort((t,e)=>Pr(t.a,t.b,r).localeCompare(Pr(e.a,e.b,r)))){const e=[...t.targets][0],s=_.filter(e=>m(e,t));if(new Set(s.map(t=>t.cm)).size>1)continue;let o=!1;_=_.map(s=>m(s,t)?(o=!0,s.cm===e?s:{...s,cm:e}):s),o||(_=L(_,t.a,t.b,e,i,r))}return _}const Tr=t=>{const e=[];for(const s of t||[]){const t=R(s);if(t?.length)for(let s=0;s"string"==typeof t?.id?t.id:"").filter(Boolean),c=new Set(l),d=new Map;for(const t of l){const e=Jn("space",t);e.layers>0&&Vn("space",e.root)&&Yn(d,e.root,t)}const p=new Map,_=new Map,u=new Map,m=new Map;for(const t of r){const e="string"==typeof t?.id?t.id:"";if(!e)continue;const s=new Map;for(const i of Array.isArray(t.rooms)?t.rooms:[]){const t="string"==typeof i?.id?i.id:"";if(!t)continue;const o=Jn("room",t);o.layers>0&&Vn("room",o.root)&&Yn(s,o.root,t),_.has(t)||_.set(t,e),u.has(t)||u.set(t,String(i.name||""));const a="string"==typeof i.area?i.area:"";if(a){const s=m.get(a)||[];s.push({spaceId:e,roomId:t}),m.set(a,s)}}p.set(e,s)}const g=new Set(_.keys()),f=new Map,b=new Map;for(const t of h)"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,$=t=>c.has(t)?null:(()=>{const e=Jn("space",t).root;if(!Vn("space",e))return null;const s=d.get(e)||[];return 1===s.length?s[0]:null})(),w=(t,e)=>{const s=Jn("room",t).root;if(!Vn("room",s))return null;const i=p.get(e)?.get(s)||[];return 1===i.length?i[0]:null},k=t=>{const e=s.effectiveAreaByMarker?.[t]||"",i=e&&m.get(e)||[];return 1===i.length?i[0]:null},x=(t,e,s)=>{if("string"==typeof t.room_id&&t.room_id&&!g.has(t.room_id)){const i=e?w(t.room_id,e):null;i?(t.room_id=i,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?w(s,e):null;o?(i[t]=o,v.roomRefsRemapped++):v.nestedRefsUnresolved++}};for(const t of h){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),h=!0===t.removed;let l=s&&c.has(s)?s:null,d=null,p=!1;if(i){const i=$(s);i?(t.space=i,l=i,p=!0,v.spaceRefsRemapped++):h||"virtual"===t.binding?h||(delete t.space,l=null,v.markersDetached++):(d=k(e),d?(t.space=d.spaceId,l=d.spaceId,v.spaceRefsRemapped++):(delete t.space,l=null,v.markersDetached++))}h&&!p||x(t,l,d),r&&p&&n===s&&l&&(o[e]={...a,s:l},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=$(s);if(i){if(t.startsWith("rl_")){const s=t.slice(3),a=w(s,i);if(a){const s=`rl_${a}`;Kn(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,S=!0===M?.authoritative,C=new Set(M?.deviceIds||[]),D=new Set(M?.entityIds||[]),P=new Set(Array.isArray(i.settings?.known_devices)?i.settings.known_devices.filter(t=>"string"==typeof t):[]),I=(t,e="")=>{const s=String(M?.names?.[t]||e||"").trim();return s&&s!==t?s:""},T=(t,e,s,i="",o)=>({id:t,spaceId:e,kind:s,name:I(t,i),...o?{reason:o}:{}}),R=t=>{"room_label"===t?v.orphanRoomLabelsRemoved++:"group"===t?v.orphanGroupPositionsRemoved++:v.orphanDevicePositionsRemoved++},z=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),h=b.get(t);if(r)a=T(t,i,"device",String(r.name||"")),n="live";else if(h)a=T(t,i,"device",String(h.name||"")),n="absent";else if(t.startsWith("rl_")){const e=t.slice(3);a=T(t,i,"room_label",u.get(e)||""),n=g.has(e)?"live":"absent"}else if(t.startsWith("lg_")){const e=t.slice(3);a=T(t,i,"group"),n=D.has(e)?"live":S?"absent":"unverified","unverified"===n&&(a.reason="registry_unavailable")}else C.has(t)?(a=T(t,i,"device"),n="live"):P.has(t)?(a=T(t,i,"device"),n=S?"absent":"unverified","unverified"===n&&(a.reason="registry_unavailable")):(a=T(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++,R(a.kind),v.removedPositions.push(a);continue}}else v.unverifiedPositions.push(a);v.positionsUnresolved++,z.add(i)}else delete o[t],R(a.kind),v.removedPositions.push(a)}return v.deadSpaceIds=[...z].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=tt(n,a.layout);U(n),et(a.layout);const h=JSON.stringify(t||{}),l=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&&Sr(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(Sr(o,"segments")&&(delete o.segments,e++),Sr(o,"plan_scale")){const t=Number(o.plan_scale);Number.isFinite(t)&&t>=ht&&t<=lt&&(Sr(o,"plan_scale_x")||(o.plan_scale_x=t),Sr(o,"plan_scale_y")||(o.plan_scale_y=t),delete o.plan_scale,e++)}const a=Number(o.cell_cm);Sr(o,"cell_cm")&&(!Number.isFinite(a)||a<.1||a>1e3)&&(o.cell_cm=Number.isFinite(a)&&a>0?Cr(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)Sr(t,"angle")&&(delete t.angle,e++);else if("square"===t.shape&&Sr(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(Sr(t,"width")){const s=Number(t.width);(Sr(t,"width_cm")||Number.isFinite(s))&&(Sr(t,"width_cm")||(t.width_cm=Number(Cr(s/nt*r,.1,100).toFixed(6))),delete t.width,e++)}if("rect"!==t?.kind&&"ellipse"!==t?.kind||!0!==t.fill||(Sr(t,"fill_color")||(t.fill_color=t.color||"#607d8b",e++),Sr(t,"fill_opacity")||(t.fill_opacity=.25,e++)),"text"!==t?.kind)continue;void 0===t.size_cm?(t.size_cm=Number(Cr(ct*dt(t)/nt*r,.1,2e3).toFixed(6)),delete t.scale,delete t.size,e++):(Sr(t,"scale")||Sr(t,"size"))&&(delete t.scale,delete t.size,e++);let s=String(t.text??"");const i=[...s.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!pt(t[1]));if(!(Sr(t,"entity")||Sr(t,"attr")||Sr(t,"unit")))continue;const o=String(t.unit??"").trim(),a="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,n=i||o?"":_t(t.entity,a);if(i||n){if(n){const e=s.indexOf("{}");s=e>=0?s.slice(0,e)+n+s.slice(e+2):`${s}${s?" ":""}${n}`,t.text=s}delete t.entity,delete t.attr,delete t.unit,e++}}}return{total:e,glowSpaces:s,glowRooms:i}})(n);let p=d.total;const _=(u=n.spaces||[],JSON.parse(JSON.stringify(u)));var u;const m=wn(n.spaces||[],a.layout);let g=0,f=0,b=0,v="";const y=m.spaces.map(t=>{const e=st(t);g+=e.report.wallsStraightened,f+=e.report.wallsStraightenSkipped;const s=Number(t?.cell_cm)>0?Number(t.cell_cm):5,i=e.report.maxStraightenShift/I*s;return i>b&&(b=i,v=String(t?.id||"")),e.space}),$=g?wn(y,m.layout):{...m,spaces:y};n.spaces=$.spaces;const w=g?{...m.report,moved:m.report.moved+$.report.moved,coordsCanonicalized:m.report.coordsCanonicalized+$.report.coordsCanonicalized,maxShift:Math.max(m.report.maxShift,$.report.maxShift),maxShiftCm:Math.max(m.report.maxShiftCm,$.report.maxShiftCm),maxSpace:$.report.maxShiftCm>m.report.maxShiftCm?$.report.maxSpace:m.report.maxSpace,rotated:m.report.rotated+$.report.rotated,removedDrafts:m.report.removedDrafts+$.report.removedDrafts}:{...m.report};let k=0,x=0,M=0,S=0,C=0,D=0,P=0,T=0;for(let t=0;t0===Number(t.cm)),walls:e.walls||[]}),a=Dr(e),r=Dr(s);if(!a||!r)continue;const h=Tr(a.rooms),l=Tr(r.rooms),c=.02*nt,d=(e.wall_segments||[]).filter(t=>0===Number(t.cm)).map(t=>({...t,key:K(t.a,t.b,I),cm:0})),p=new Set(d.map(t=>t.key)),u=it(e,a.rooms,ot,c);x+=u.length;for(const t of u){const e=[t[0]/ot,t[1]/ot],s=[t[2]/ot,t[3]/ot],i=K(e,s,I);p.has(i)||(p.add(i),d.push({key:i,a:e,b:s,cm:0}))}const m=d.length,g=at(d,h,l,I,ot),f=(t,e,s)=>{const i=s[0]-e[0],o=s[1]-e[1],a=i*i+o*o;if(!(a>0))return Math.hypot(t[0]-e[0],t[1]-e[1]);const n=Math.max(0,Math.min(1,((t[0]-e[0])*i+(t[1]-e[1])*o)/a));return Math.hypot(t[0]-(e[0]+i*n),t[1]-(e[1]+o*n))},b=g.filter(t=>{if(!Array.isArray(t.a)||!Array.isArray(t.b))return!1;const e=t.a.map(t=>t*ot),s=t.b.map(t=>t*ot);return l.some(([t,i])=>f(e,t,i)<=4*c&&f(s,t,i)<=4*c)});M+=Math.max(0,m-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]*ot,t.a[1]*ot,t.b[0]*ot,t.b[1]*ot]),$=Array.isArray(e.walls)?e.walls.length:0;let w=at(e.walls,h,l,I,ot);w=Ir(r.rooms,w,y,I,Number(s.cell_cm)>0?Number(s.cell_cm):5,nt,ot),w=E(r.rooms,w,y,I,Number(s.cell_cm)>0?Number(s.cell_cm):5,nt,ot),w=rt(w,s.rooms||[],I,1,y.map(t=>[t[0]/ot,t[1]/ot,t[2]/ot,t[3]/ot])),k+=Math.max(0,$-w.length),w.length?s.walls=w:delete s.walls;const R=Pn(s.partitions||[],{pitch:I,geometry:Tn(s)});R.merged&&(S+=R.merged,s.partitions=R.partitions,In(s.openings,s.partitions,R.openingMoves,{coordScale:ot,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,gridPitch:nt}));const z=Dr(s);if(z){const t=o(s,z,s.walls||[],y,{pitch:I,cellCm:Number(s.cell_cm)>0?Number(s.cell_cm):5,gridPitch:nt,coordScale:ot});t.partitionsReconciled&&(C+=t.partitionsReconciled,D+=t.openingsRehosted,t.partitions.length?s.partitions=t.partitions:delete s.partitions,t.openings.length?s.openings=t.openings:delete s.openings,t.walls.length?s.walls=t.walls:delete s.walls),t.removedDrafts&&(P+=t.removedDrafts,t.roomDrafts.length?s.room_drafts=t.roomDrafts:delete s.room_drafts)}JSON.stringify({zero:(s.wall_segments||[]).filter(t=>0===Number(t.cm)),walls:s.walls||[]})!==i&&T++}let R=0;c<=9&&(R=function(t){const e=kr(t);return Mr(t,e.config),{...e,config:t}}(n).migratedSegments);const z=U(n),F=et($.layout),A=JSON.stringify(z)!==h||JSON.stringify(F)!==l;c<9&&A&&(z.model_version=9);const N=JSON.stringify(z)!==h||JSON.stringify(F)!==l,H=Number.isInteger(Number(z.model_version))?Number(z.model_version):c,O=N?w:{...w,moved:0,coordsCanonicalized:0,maxShift:0,maxShiftCm:0,maxSpace:"",rotated:0,removedDrafts:0},L=N?a.report:{...a.report,spaceRefsRemapped:0,roomRefsRemapped:0,positionsRemapped:0,markersDetached:0,orphanRoomLabelsRemoved:0,orphanDevicePositionsRemoved:0,orphanGroupPositionsRemoved:0,liveMissingPositionsRemoved:0};return{config:z,layout:F,report:{...O,modelFrom:c,modelTo:H,migrated:N?p:0,glowSpacesMigrated:N?d.glowSpaces:0,glowRoomsMigrated:N?d.glowRooms:0,canonicalized:N?T:0,wallSegmentsMigrated:N?R:0,legacyZeroWallsMigrated:N?x:0,wallsMerged:N?k:0,spansMerged:N?M:0,partitionsMerged:N?S:0,partitionsReconciled:N?C:0,openingsRehosted:N?D:0,redundantDraftsRemoved:N?P:0,wallsStraightened:N?g:0,wallsStraightenSkipped:f,maxStraightenShiftCm:N?b:0,maxStraightenSpace:N?v:"",latticeCoordinatesCanonicalized:N?r.canonicalized:0,latticeCoordinatesFar:N?r.far:0,latticeMaxShift:N?r.maxShift:0,latticeMaxShiftCm:N?r.maxShiftCm:0,latticeSpaces:N?r.spaces:[],...L},changed:N}}const zr=(t,e)=>t[0]*e[1]-t[1]*e[0],Fr=(t,e)=>t[0]*e[0]+t[1]*e[1],Ar=(t,e)=>[t[0]-e[0],t[1]-e[1]],Nr=(t,e,s)=>[t[0]+e[0]*s,t[1]+e[1]*s];function Hr(t,e,s){return Math.abs(zr(t,e))<=s}function Or(t,e,s){return Math.abs(zr(Ar(t,e),s))}function Lr(t,e,s,i,o){const a=e[0]-t[0],n=e[1]-t[1],r=Math.hypot(a,n);if(!(r>o&&s>0))return[];const h=[a/r,n/r];return function(t,e,s){const i=e.map(([e,s])=>[Math.max(0,Math.min(e,s)),Math.min(t,Math.max(e,s))]).filter(([t,e])=>e>t+s).sort((t,e)=>t[0]-e[0]||t[1]-e[1]),o=[];for(const t of i){const e=o[o.length-1];!e||t[0]>e[1]+s?o.push([...t]):e[1]=Math.max(e[1],t[1])}const a=[];let n=0;for(const[t,e]of o)t>n+s&&a.push([n,t]),n=Math.max(n,e);return t>n+s&&a.push([n,t]),a}(r,i.flatMap(e=>{const i=e.b[0]-e.a[0],a=e.b[1]-e.a[1],n=Math.hypot(i,a);if(!(n>o&&Hr(h,[i/n,a/n],1e-6)))return[];if(Or(e.a,t,h)>1.1*Math.max(s,o)||Or(e.b,t,h)>1.1*Math.max(s,o))return[];return[[Fr(Ar(e.a,t),h),Fr(Ar(e.b,t),h)]]}),o).flatMap(([e,i])=>{const o=bt({a:Nr(t,h,e),b:Nr(t,h,i),halfDepth:s});return o?[o]:[]})}function Er(t){const e=t.coordScale??1,s=Math.max(t.epsilon??2e-4*t.gridPitch,1e-9),i=[];for(const s of t.rooms||[]){if(!s?.id)continue;const o=mt(t.rooms,s.id,t.walls,t.openCuts,t.pitch,t.cellCm,t.gridPitch,e);if(!o||o.poly.length<3)continue;const a=gt(o.poly,o.offsets);!a||a.length<3||i.push({roomId:s.id,profile:o,inner:a})}i.sort((t,e)=>t.roomId.localeCompare(e.roomId));const o=(t.roomOpenings||[]).map(t=>{const e=t.angle*Math.PI/180,s=[Math.cos(e),Math.sin(e)],i=Math.max(0,t.length)/2;return{a:Nr([t.x,t.y],s,-i),b:Nr([t.x,t.y],s,i)}}),a=[];for(const i of ft(t.rooms,t.walls,t.openCuts,t.pitch,t.cellCm,t.gridPitch,e))for(const t of Lr(i.a,i.b,i.depthUnits/2,o,s))a.push({body:t});const n=new Map;for(const e of t.partitionCuts||[]){const t=n.get(e.hostId)||[];t.push(e),n.set(e.hostId,t)}for(const e of t.partitions||[]){const i=j(e.cm,t.cellCm,t.gridPitch)/2;for(const t of Lr(e.a,e.b,i,n.get(e.id)||[],s))a.push({body:t,partitionId:e.id})}return{rooms:i,boundaries:a,epsilon:s}}function Br(t,e,s,i){const o=t.profile.offsets[e];if(!(o>0))return null;const a=function(t,e){const s=t[e],i=t[(e+1)%t.length],o=i[0]-s[0],a=i[1]-s[1],n=Math.hypot(o,a)||1;return function(t){let e=0;for(let s=0;s=0?[-a/n,o/n]:[a/n,-o/n]}(t.profile.poly,e),n=Nr(s.center,a,o),r=[];for(let e=0;ei&&Hr(s.axis,[h[0]/l,h[1]/l],1e-6)))continue;if(Or(o,n,s.axis)>i||Or(a,n,s.axis)>i)continue;const c=Fr(Ar(o,n),s.axis),d=Fr(Ar(a,n),s.axis);r.push([Math.min(c,d),Math.max(c,d)])}const h=function(t,e){t.sort((t,e)=>t[0]-e[0]||t[1]-e[1]);const s=[];for(const i of t){const t=s[s.length-1];!t||i[0]>t[1]+e?s.push([...i]):t[1]=Math.max(t[1],i[1])}return s}(r,i).find(([t,e])=>t<=i&&e>=-i);if(!h)return null;const[l,c]=h,d=Nr(n,s.axis,-s.half),p=Nr(n,s.axis,s.half),_=Math.max(0,-s.half-l),u=Math.max(0,c-s.half),m=_>0?Nr(n,s.axis,l):d,g=u>0?Nr(n,s.axis,c):p,f=Fr(a,s.normal)>=0?1:-1,b=(e,i,o)=>({from:e,to:i,label:[(e[0]+i[0])/2,(e[1]+i[1])/2],axis:s.axis,labelNormal:a,distance:o,roomId:t.roomId,roomSide:f,source:"room-face"});return{left:b(d,m,_),right:b(p,g,u)}}function Wr(t){const e=Nr(t.center,t.axis,-t.half),s=Nr(t.center,t.axis,t.half),i=Nr(t.center,t.axis,Math.min(-t.half,t.targetLo)),o=Nr(t.center,t.axis,Math.max(t.half,t.targetHi)),a=(e,s)=>({from:e,to:s,label:[(e[0]+s[0])/2,(e[1]+s[1])/2],axis:t.axis,labelNormal:t.normal,distance:Math.hypot(s[0]-e[0],s[1]-e[1]),source:"host-end"});return[a(e,i),a(s,o)]}function Gr(t,e,s,i){const o=Ar(s,e),a=Fr(o,o);if(!(a>i*i))return Math.hypot(...Ar(t,e))<=i;const n=Fr(Ar(t,e),o)/a;if(n<-i||n>1+i)return!1;const r=Nr(e,o,Math.max(0,Math.min(1,n)));return Math.hypot(...Ar(t,r))<=i}function jr(t,e,s){let i=!1;for(let o=0,a=e.length-1;ot[1]!=l>t[1]&&t[0]<(h-n)*(t[1]-r)/(l-r)+n&&(i=!i)}return i}function qr(t,e,s,i,o,a){const n=Ar(i,s),r=zr(e,n);if(Math.abs(r)<=a)return null;const h=Ar(s,t),l=zr(h,n)/r,c=zr(h,e)/r;return l<-a||l>o+a||c<-a||c>1+a?null:Math.max(0,Math.min(o,l))}function Ur(t,e,s){const i=Wr(s),o="partition"===t.host?.kind?t.host.id:void 0;return[{base:i[0],direction:[-s.axis[0],-s.axis[1]]},{base:i[1],direction:s.axis}].map(({base:t,direction:s})=>{const i=t.distance,a=function(t,e,s,i,o,a){let n=null;for(const r of i)if(!o||r.partitionId!==o){if(jr(t,r.body,a))return 0;for(let i=0;iFr(Ar(t,o),s));return{center:o,axis:s,normal:i,half:Math.max(0,t.renderedLength)/2,targetLo:Math.min(...a),targetHi:Math.max(...a)}}(t),i=e.rooms.flatMap(t=>{const i=function(t,e,s){const{profile:i}=t;let o=null;for(let t=0;t0))continue;const a=i.poly[t],n=i.poly[(t+1)%i.poly.length],r=Ar(n,a),h=Math.hypot(r[0],r[1]);if(!(h>s&&Hr(e.axis,[r[0]/h,r[1]/h],1e-6)))continue;if(Or(a,e.center,e.axis)>s||Or(n,e.center,e.axis)>s)continue;const l=Fr(Ar(a,e.center),e.axis),c=Fr(Ar(n,e.center),e.axis),d=Math.min(l,c),p=Math.max(l,c);if(d>-e.half+s||p0?d:p<0?-p:0);(!o||_2)return Wr(s);if(i.length){const t=i.map(({room:t,edge:i})=>Br(t,i,s,e.epsilon));if(t.some(t=>!t))return Wr(s);const o=t;return[...o.map(t=>t.left),...o.map(t=>t.right)]}return Ur(t,e,s)}const Vr="1.69.0-beta.2",Jr={badge:"display.badge",icon_ripple:"display.icon_ripple",value:"display.value",static_icon:"display.static_icon"},Yr={badge:"marker.display_hint_badge",icon_ripple:"marker.display_hint_icon_ripple",value:"marker.display_hint_value",static_icon:"marker.display_hint_static_icon"},Xr=2e3,Zr=1e3,Qr=t=>{const e=String(t??"").trim().replace(",",".");if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(e))return null;const s=Number(e);return Number.isFinite(s)?s:null},th=(t,e,s,i)=>{for(t.delete(e),t.set(e,s);t.size>i;){const e=t.keys().next().value;if(void 0===e)break;t.delete(e)}},eh=1e3,sh=2e3,ih=t=>{try{t.target?.setPointerCapture?.(t.pointerId)}catch{}},oh="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";class ah{constructor(t){this.host=t,this._junctionBaselineCache=new WeakMap,this._undoGeometry=()=>{if(this.host._physicalDrag||this.host._physicalRotate)return void this._cancelPhysicalGesture();if(this.host._decorDraft)return this.host._decorDraft=null,void this.host.requestUpdate();if(this.host._decorMove||this.host._dtDrag||this.host._bdDrag)return void this._cancelDecorGesture();if(this.host._resize.dragging)return void this._rszCancelDrag();const t=this.host._geometryHistory.undo();t&&(this._applyGeometryState(t.before,!0)?this.host._showToast(this.host._t("history.undone",{name:t.name})):this.host._geometryHistory.clear())},this._redoGeometry=()=>{if(this.host._physicalDrag||this.host._physicalRotate)return void this._cancelPhysicalGesture();if(this.host._decorDraft)return this.host._decorDraft=null,void this.host.requestUpdate();if(this.host._decorMove||this.host._dtDrag||this.host._bdDrag)return void this._cancelDecorGesture();if(this.host._resize.dragging)return void this._rszCancelDrag();const t=this.host._geometryHistory.redo();t&&(this._applyGeometryState(t.after,!0)?this.host._showToast(this.host._t("history.redone",{name:t.name})):this.host._geometryHistory.clear())},this._savePhysicalDialog=()=>{const t=this.host._physicalDialog,e=this.host._curSpaceCfg,s=this.host._spaceModel();if(!t||!e||!s)return;const i=Qr(t.cm);if(null==i)return void this._showPhysicalRange("column"===t.kind?vt:100,"column"===t.kind?1:0);const o=this.host._imperial?2.54*i:i,a="column"===t.kind?vt:100,n="column"===t.kind?1:0;if(!Number.isFinite(o)||oa)return void this._showPhysicalRange(a,n);if("column"===t.kind){const e=s.wall_columns.find(e=>e.id===t.id);if(!e)return;const i=Qr(t.angle||"0");if("circle"!==t.shape&&(null==i||i<0||i>=90))return void this.host._showToast(this.host._t("toast.physical_angle"));const a="circle"===t.shape?{id:t.id,shape:"circle",center:e.center,cm:o}:{id:t.id,shape:"square",center:e.center,cm:o,angle:i};if(s.wall_columns.some(e=>e.id!==t.id&&yt(e,a,.02*this.host._gridPitch)))return void this.host._showToast(this.host._t("toast.column_duplicate"))}const r=this._geometrySnapshot();if("partition"===t.kind){const s=(e.partitions||[]).find(e=>e.id===t.id);if(s&&0===o&&$t(e.openings,{kind:"partition",id:t.id}))return void this.host._showToast(this.host._t("toast.zero_wall_opening_conflict"));s&&(s.cm=o)}else if("column"===t.kind){const s=(e.wall_columns||[]).find(e=>e.id===t.id);s&&(s.cm=wt(o),s.shape="circle"===t.shape?"circle":"square","square"===s.shape?s.angle=Qr(t.angle||"0"):delete s.angle)}else{const s=(e.room_drafts||[]).find(e=>e.id===t.id);s?.segments?.[t.segment||0]&&(s.segments[t.segment||0].cm=o)}const h=this._commitPhysicalGeometry(this.host._t("history.physical_edit"),r);this.host._physicalDialog=null,h||this.host.requestUpdate()},this._deletePhysicalSelection=()=>{const t=this.host._physicalSel,e=this.host._curSpaceCfg;if(!t||!e)return;if("draft"===t.kind)return void this._deleteDraftWhole();const s=this._geometrySnapshot();if("partition"===t.kind){const s=(e.openings||[]).filter(e=>"partition"===e.host?.kind&&e.host.id===t.id).sort((t,e)=>(t.host?.t||0)-(e.host?.t||0));if(s.length)return void(this.host._partitionDeleteDialog={id:t.id,openings:s.map(t=>JSON.parse(JSON.stringify(t)))})}const i="partition"===t.kind?"partitions":"column"===t.kind?"wall_columns":"room_drafts";e[i]=(e[i]||[]).filter(e=>e.id!==t.id),e[i].length||delete e[i],this.host._activeDraftId===t.id&&this._cancelPath(),this.host._physicalSel=null,this.host._physicalDialog=null,this._commitPhysicalGeometry(this.host._t("history.physical_delete"),s)},this._confirmPartitionDelete=()=>{const t=this.host._partitionDeleteDialog,e=this.host._curSpaceCfg;if(!t||!e)return;const s=this._geometrySnapshot();e.partitions=(e.partitions||[]).filter(e=>e.id!==t.id),e.partitions.length||delete e.partitions,e.openings=(e.openings||[]).filter(e=>"partition"!==e.host?.kind||e.host.id!==t.id),e.openings.length||delete e.openings,this.host._partitionDeleteDialog=null,this.host._physicalSel=null,this.host._physicalDialog=null,this._commitPhysicalGeometry(this.host._t("history.physical_delete"),s)},this._deleteDraftWhole=()=>{const t="draft"===this.host._physicalDialog?.kind?this.host._physicalDialog.id:"draft"===this.host._physicalSel?.kind?this.host._physicalSel.id:null,e=this.host._curSpaceCfg;if(!t||!e||!confirm(this.host._t("confirm.delete_draft")))return;const s=this._geometrySnapshot();e.room_drafts=(e.room_drafts||[]).filter(e=>e.id!==t),e.room_drafts.length||delete e.room_drafts,this.host._activeDraftId===t&&this._cancelPath(),this.host._physicalSel=null,this.host._physicalDialog=null,this._commitPhysicalGeometry(this.host._t("history.physical_delete"),s)},this._deleteDraftSegment=()=>{const t=this.host._physicalDialog,e=this.host._curSpaceCfg;if(!t||"draft"!==t.kind||!e)return;if(!confirm(this.host._t("confirm.delete_draft_segment")))return;const s=(e.room_drafts||[]).findIndex(e=>e.id===t.id);if(s<0)return;const i=e.room_drafts[s],o=Math.max(0,Math.min(i.segments.length-1,t.segment||0)),a=[],n=i.points.slice(0,o+1),r=i.points.slice(o+1);if(n.length>=2&&a.push({id:i.id,points:n,segments:i.segments.slice(0,o)}),r.length>=2&&a.push({id:a.length?`${i.id}-${Date.now().toString(36)}`:i.id,points:r,segments:i.segments.slice(o+1)}),2===a.length&&e.room_drafts.length>=200)return void this.host._showToast(this.host._t("toast.physical_limit"));const h=this._geometrySnapshot();e.room_drafts.splice(s,1,...a),e.room_drafts.length||delete e.room_drafts,this.host._activeDraftId===i.id&&this._cancelPath(),this.host._physicalDialog=null,this.host._physicalSel=a.length?{kind:"draft",id:a[0].id}:null,this._commitPhysicalGeometry(this.host._t("history.draft_segment_delete"),h)},this._confirmRoomDelete=t=>{const e=this.host._roomDeleteDialog,s=this.host._curSpaceCfg,i=this.host._spaceModel();if(!e||!s||!i)return;const o=i.rooms.find(t=>t.id===e.roomId);if(!o)return void(this.host._roomDeleteDialog=null);const a=this.host._openCuts(),n=sn(A(i.rooms,this.host._spaceWalls,a,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,eh).filter(t=>t.roomId===o.id),i.partitions,this.host._openingsR.map(t=>({...t,x:t.rx,y:t.ry})),.02*this.host._gridPitch),r=new Set(n.materialize.filter(t=>!t.reusePartitionId).map(t=>t.interval.key)).size;if(t&&(s.partitions||[]).length+r>sh)return void this.host._showToast(this.host._t("toast.physical_limit"));const h=this._geometrySnapshot(),l=kt(i.rooms,this.host._spaceWalls,a,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,eh);if(t){s.partitions||=[];const t=new Map,e=new Map,i=t=>{const e=(s.wall_segments||[]).find(e=>{const s=[Number(e.a?.[0])*eh,Number(e.a?.[1])*eh],i=[Number(e.b?.[0])*eh,Number(e.b?.[1])*eh];return this._samePt(t.a,s)&&this._samePt(t.b,i)||this._samePt(t.a,i)&&this._samePt(t.b,s)});return"string"==typeof e?.id&&e.id?e.id:null},o=Date.now().toString(36);for(const a of n.materialize){let n=a.reusePartitionId?s.partitions.find(t=>t.id===a.reusePartitionId):e.get(a.interval.key);n||(n={id:i(a.interval)||`partition-room-${o}-${e.size}`,a:[a.interval.a[0]/eh,a.interval.a[1]/eh],b:[a.interval.b[0]/eh,a.interval.b[1]/eh],cm:a.interval.cm},s.partitions.push(n),e.set(a.interval.key,n)),t.set(a.interval.key,n)}for(const e of s.openings||[]){const s=n.openingIntervals.get(e.id),i=s?t.get(s):null,o=this.host._openingsR.find(t=>t.id===e.id);if(!i||!o)continue;const a={a:[i.a[0]*eh,i.a[1]*eh],b:[i.b[0]*eh,i.b[1]*eh]};e.host={kind:"partition",id:i.id,t:on([o.rx,o.ry],a)}}}else if(n.removeOpeningIds.length){const t=new Set(n.removeOpeningIds);s.openings=(s.openings||[]).filter(e=>!t.has(e.id)),s.openings.length||delete s.openings}s.rooms=s.rooms.filter(t=>t.id!==o.id),this.host._cfgEpoch++;const c=this.host._normalizeWalls(l,this.host._openCuts());c.length?s.walls=c:delete s.walls,this.host._roomDeleteDialog=null,this._commitPhysicalGeometry(this.host._t(t?"history.delete_room_keep_walls":"history.delete_room_with_walls"),h),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host.requestUpdate()},this._rebindPartitionOpening=()=>{const t=this.host._openingDialog;if(!t?.id)return;const e=t.id;this._activateMarkupTool("opening"),"opening"===this.host._tool&&(this.host._openingRebindId=e,this.host._openingPreset={type:t.type,lengthCm:t.lengthCm,flipH:t.flipH,flipV:t.flipV,revision:++this.host._openingPresetRevision},this.host._openingDialog=null,this.host._openingHoverCandidate=null)},this._deviceInboxTabKey=t=>{if("ArrowLeft"!==t.key&&"ArrowRight"!==t.key)return;const e=this.host._deviceInbox;if(!e)return;const s=["on_plan","available","hidden","readd"],i="ArrowRight"===t.key?1:-1,o=(s.indexOf(e.tab)+i+s.length)%s.length;this.host._deviceInbox={...e,tab:s[o],limit:100,onlyNew:!1},t.preventDefault()},this._keepClosedAsPartitions=()=>{if(this.host._wallFaceBatch)return void this._decideWallFace(!1);if(!this.host._contourClosed||this.host._pendingSplit||!this.host._curSpaceCfg)return;const t=this.host._curSpaceCfg,e=this.host._path.slice(0,-1);if((t.partitions||[]).length+e.length>sh)return void this.host._showToast(this.host._t("toast.physical_limit"));const s=this._geometrySnapshot(),i=Pa(e.length,[...this.host._draftSegmentCms,this.host._closingWallCm??void 0],this.host._drawWallCm,N);t.partitions||=[];const o=Date.now().toString(36),a=this.host._activeDraftId?(t.room_drafts||[]).find(t=>t.id===this.host._activeDraftId):null,n=this._draftSegmentsForPath(this.host._path,a,i);for(let s=0;st.id!==this.host._activeDraftId),t.room_drafts.length||delete t.room_drafts),this._commitPhysicalGeometry(this.host._t("history.contour_to_partitions"),s),this.host._roomDialog=!1,this.host._path=[],delete this.host._resumeDraftBySpace[this.host._space],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null},this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),e=this.host._spaceDialog;e&&(this.host._spaceDialog={...e,saved:t?.plans||[],savedBusy:!1})}catch(t){const e=this.host._spaceDialog;e&&(this.host._spaceDialog={...e,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}},this._openSettingsDialog=()=>{if(!this.host._norm)return;const t=this.host._glowRadiusCm,e=this.host._imperial?Math.round(t/30.48*10)/10:Math.round(t)/100;this.host._settingsDialog={colors:JSON.parse(JSON.stringify(this.host._fillColors)),glowRadius:e,bgColor:Ct(this.host._settings,{bgColor:null})||null,northDeg:St(this.host._settings,{}),bgMode:Mt(this.host._settings,{}),sunRays:xt(this.host._settings,{}),busy:!1}},this._openAlignDialog=()=>this._previewAlignDialog(!1),this._toggleOptimizeLivePositions=()=>{const t=this.host._alignDialog;t&&!t.busy&&t.report.liveMissingPositions.length&&this._previewAlignDialog(!t.removeLiveMissingPositions)},this._openBackupExport=()=>{this.host._settingsDialog=null,this.host._backupExportDialog={kind:"full",planOnly:!1,busy:!1,error:""}},this._openRulesDialog=()=>{if(!this.host._norm)return;const t=this.host._settings.icon_rules,e=(t&&t.length?t:Dt).map(t=>({...t}));this.host._rulesDialog={rules:e,test:"",busy:!1}},t._editorSecondary=new _n({root:()=>t.renderRoot,requestUpdate:()=>t.requestUpdate(),updateComplete:()=>t.updateComplete,clearTip:()=>{t._tip=null}}),t._resize=new Lo}_help(t){const e=`${t}.aria`,s=d(this.host.hass,this.host._config?.language);return Pt(s,t)&&Pt(s,e)?o``:a}_setMode(t,e=!0){this.host._endTabDrag(),this.host._pendingNavMode=null;const s=this.host._spaceModel();if(!s)return this.host._cancelModeTransition(!1),void(this.host._mode="view");if(this.host._kiosk&&"view"!==t)return;if(this.host._mode===t){if(!e&&"view"===t&&this.host._modeTransitionBusy){const e=this.host._currentModeVisual(t),s=this.host._modeTransitionTargetZoom,i=this.host._modeTransitionTargetCenterX,o=this.host._modeTransitionTargetCenterY;this.host._cancelModeTransition(!1),this.host._commitViewModeAtomic(e,s,i,o)}return}if(this.host._bootSoftCancel(),("plan"===t||"decor"===t)&&!this.host._norm)return void this.host._showToast(this.host._t("toast.markup_needs_server"));if(this.host._wallFaceBatch&&this._roomDialogCancel(),"plan"===this.host._mode&&"draw"===this.host._tool&&!this._finishWallChain())return;this.host._clearTransientHover(!0),this.host._cancelDevicePressFeedback();const i=this.host._mode,o=this.host._effectiveProjection(),a=this.host._currentModeVisual(i),n=this.host._modeTransitionBusy,r=a&&"view"!==i&&"view"!==t?{...a,toolbarContentOpacity:this.host._reducedMotion?1:.35}:a;this.host._cancelModeTransition(!1),this.host._editorSecondary.closeForNavigation(),(this.host._decorMove||this.host._dtDrag||this.host._bdDrag)&&this._cancelDecorGesture();const h=!s.bg&&"view"===t!=("view"===i),l=n&&"view"===i&&"view"!==t?this.host._modeTransitionEditorCamera:null;let c=l?.zoom??(n?this.host._modeTransitionTargetZoom:this.host._zoom),d=l?l.centerX:n?this.host._modeTransitionTargetCenterX:r?.viewport.centerX,p=l?l.centerY:n?this.host._modeTransitionTargetCenterY:r?.viewport.centerY;if("view"===i&&"view"!==t&&!n){const e=this.host._view;if(this.host._viewModeSnap={space:this.host._space,zoom:this.host._zoom,cx:e?this.host._logicalViewCenter(o)?.x:void 0,cy:e?this.host._logicalViewCenter(o)?.y:void 0},"iso"===o){const e=this.host._logicalViewCenter("iso");d=e?.x,p=e?.y,this.host._view=null,this.host._mode=t,this.host._applyView(this.host._zoom,e?.x,e?.y)}h&&(c=1,d=void 0,p=void 0)}if("plan"===i&&this.host._activeDraftId&&(this.host._resumeDraftBySpace[this.host._space]=this.host._activeDraftId),this.host._mode=t,"devices"===i&&"devices"!==t&&(this.host._showHidden=!1,this.host._deviceInbox=null,this.host._deviceInboxReturn=null,this.host._deviceInboxMemo=null),this.host._editorChromeMode="view"===t?i:t,"view"===t){"view"===i||n||(this.host._modeTransitionEditorCamera={zoom:this.host._zoom,centerX:r?.viewport.centerX,centerY:r?.viewport.centerY});const t=this.host._viewModeSnap;if(t&&t.space===this.host._space){c=t.zoom;const e=this.host._labsIso&&"iso"===this.host._viewPreference[this.host._space]?"iso":"flat",s=null!=t.cx&&null!=t.cy&&"iso"===e?It([t.cx,t.cy],0):null;d=s?.[0]??t.cx,p=s?.[1]??t.cy}else t&&(c=this.host._zoomBySpace[this.host._space]||1,d=void 0,p=void 0)}else this.host._modeTransitionEditorCamera={zoom:c,centerX:d,centerY:p};this.host._modeTransitionTargetZoom=c,this.host._modeTransitionTargetCenterX=d,this.host._modeTransitionTargetCenterY=p,("iso"===o||"view"===t&&this.host._labsIso&&"iso"===this.host._viewPreference[this.host._space])&&(this.host._modeTransitionForceAtomic=!0);const _=++this.host._modeTransitionRequest;e?r?(this.host._modeTransitionPreparing=!0,this.host._modeTransitionVisual=r,this.host._prepareModeTransition(_,r,t,c,d,p)):(this.host._modeTransitionPreparing=!1,this.host._modeTransitionVisual=null,this.host._zoom=c,this.host._view=null,requestAnimationFrame(()=>{this.host.isConnected&&_===this.host._modeTransitionRequest&&this.host._mode===t&&(this.host._applyView(c,d,p),"view"===t&&(this.host._viewModeSnap=null,this.host._modeTransitionEditorCamera=null),this.host.requestUpdate())})):"view"===t&&this.host._commitViewModeAtomic(r,c,d,p),this.host._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!0),this.host._tool="draw",this.host._mergeSel=null,this.host._mergeDialog=null,this.host._splitSel=null,this.host._pendingSplit=null,this.host._selId=null,this.host._physicalSel=null,this.host._physicalDialog=null,this.host._physicalDrag=null,this._rszResetController(),this.host._tip=null,this.host._hoverRoom=null,this.host._decorDraft=null,this.host._decorSel=null,this.host._decorMove=null,this.host._backdropDialog=null,this.host._decorTool="select",this.host._bdDrag=null,this.host._dtDrag=null,this.host._dtBox=null,"plan"===t&&(this._primeDrawWallField(),this._resumeLastDraft()),this.host._saveNav()}_primeDrawWallField(){null===this.host._drawWallField&&(this.host._drawWallField=Tt(N,this.host._imperial))}_showPhysicalRange(t=this.host._drawWallMaxCm,e=0){this.host._showToast(this.host._t("toast.physical_range",{min:Tt(e,this.host._imperial),max:Tt(t,this.host._imperial),unit:this.host._t(this.host._imperial?"wallthick.unit_in":"wallthick.unit_cm")}))}_draftSegmentCount(t=this.host._curSpaceCfg){return(t?.room_drafts||[]).reduce((t,e)=>t+(Array.isArray(e.segments)?e.segments.length:0),0)}_mergeSpacePartitions(t,e){const s=t?.partitions||[];if(s.length<2)return 0;const i=Pn(s,{pitch:I,seedIds:e,geometry:Tn(t,{excludeDraftId:this.host._activeDraftId})});return i.merged?(t.partitions=i.partitions,In(t.openings,t.partitions,i.openingMoves,{coordScale:eh,cellCm:this.host._cellCm,gridPitch:this.host._gridPitch}),i.merged):0}_finishWallChain(){if("draw"!==this.host._tool||this.host._wallFaceBatch||this.host._roomDialog)return!0;const t=this.host._curSpaceCfg;if(!t||this.host._path.length<2)return this.host._path=[],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this._clearPlanSnapHover(),!0;const e=Ia(this.host._path,Pa(this.host._path.length-1,this.host._draftSegmentCms,this.host._drawWallCm,N)),s=e.length;if((t.partitions||[]).length+s>sh)return this.host._showToast(this.host._t("toast.physical_limit")),!1;const i=this._geometrySnapshot();t.partitions||=[];const o=Date.now().toString(36),a=[],n=this.host._activeDraftId?(t.room_drafts||[]).find(t=>t.id===this.host._activeDraftId):null,r=this._draftSegmentsForPath(this.host._path,n,e.map(t=>t.cm));for(let i=0;it.id!==this.host._activeDraftId),t.room_drafts.length||delete t.room_drafts),this._commitPhysicalGeometry(this.host._t("history.wall_chain_finish"),i),delete this.host._resumeDraftBySpace[this.host._space],this.host._path=[],this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this._clearPlanSnapHover(),!0}_activateMarkupTool(t){t!==this.host._tool&&(this.host._wallFaceBatch&&this._roomDialogCancel(),("draw"!==this.host._tool||this._finishWallChain())&&(this._cancelPath(),"resize"===this.host._tool&&(this.host._resize.dragging?this._rszCancelDrag():this.host._resize.reset()),this.host._tool=t,"draw"===t&&this._resumeLastDraft(),"resize"===t&&this.host._resize.selectRoom(null),"wallthick"===t&&(this.host._wallDialog=null)))}_limitReached(t){const e=this.host._curSpaceCfg;if(!e)return!0;const s="draft"===t?(e.room_drafts||[]).length>=200:"partition"===t?(e.partitions||[]).length>=sh:(e.wall_columns||[]).length>=500;return s&&this.host._showToast(this.host._t("toast.physical_limit")),s}_svgPoint(t){const e=this.host.renderRoot.querySelector(".stage").getBoundingClientRect();return this.host._screenToVb(t.clientX-e.left,t.clientY-e.top)}_snap(t){const e=this.host._gridPitch;return[Rt(zt(t[0],e)),Rt(zt(t[1],e))]}_snapDrawPoint(t,e=!1){const s=this.host._path[this.host._path.length-1],i=e&&s?Ft(s,t,this.host._gridPitch,Ci):t;return this._snap(i)}_planSnapOpeningCuts(t,e){if(!this.host._openingsR.length)return[];const s=this.host._openingWallIndexFor(t,e).value,i=[];for(const e of this.host._roomWallOpeningInputs(this.host._openingsR,t)){const t=G(s,e);if(!t.negative&&!t.positive)continue;const o=e.angle*Math.PI/180,a=Math.cos(o)*e.length/2,n=Math.sin(o)*e.length/2;i.push([e.x-a,e.y-n,e.x+a,e.y+n])}return i}_planSnapGeometrySnapshot(){const t=this.host._spaceModel();if(!t)return{key:`${this.host._space}|empty`,value:{segments:[],endpoints:[]}};const e=[this.host._space,this.host._cfgEpoch,this.host._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this.host._planSnapGeometryCache?.key===e)return this.host._planSnapGeometryCache;const s=this.host._openCuts(),i=$a({space:t,activeDraftId:this.host._activeDraftId,roomCuts:this._planSnapOpeningCuts(t,s),partitionCuts:this._partitionOpeningCuts(t),epsilon:2e-4*this.host._gridPitch});return this.host._planSnapGeometryCache={key:e,value:i},this.host._planSnapGeometryCache}_hiddenWallDiagnosticSnapshot(){const t=this.host._spaceModel();if(!t)return{key:`${this.host._space}|hidden-empty`,value:{segments:[],endpoints:[]}};const e=["hidden",this.host._space,this.host._cfgEpoch,this.host._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this.host._hiddenWallDiagnosticCache?.key===e)return this.host._hiddenWallDiagnosticCache;const s=ya({space:t,activeDraftId:this.host._activeDraftId,epsilon:2e-4*this.host._gridPitch});return this.host._hiddenWallDiagnosticCache={key:e,value:s},this.host._hiddenWallDiagnosticCache}_planStructuralGeometrySnapshot(){const t=this.host._spaceModel();if(!t)return{key:`${this.host._space}|structural-empty`,value:{segments:[],endpoints:[]}};const e=["structural",this.host._space,this.host._cfgEpoch,this.host._activeDraftId||"",t.rooms.length,t.room_drafts.length,t.partitions.length].join("|");if(this.host._planStructuralGeometryCache?.key===e)return this.host._planStructuralGeometryCache;const s=$a({space:t,activeDraftId:this.host._activeDraftId,epsilon:2e-4*this.host._gridPitch});return this.host._planStructuralGeometryCache={key:e,value:s},this.host._planStructuralGeometryCache}_planSnapContextKey(t){const e=this.host._path[0],s=this.host._path[this.host._path.length-1];return[t,this.host._tool,this.host._path.length,e?`${e[0]},${e[1]}`:"",s?`${s[0]},${s[1]}`:""].join("|")}_resolvePlanDrawPoint(t,e){const s=this._planSnapGeometrySnapshot(),i=this.host._path[this.host._path.length-1],o="draw"===this.host._tool&&this.host._path.length>=3?[{point:this.host._path[0],key:"closure:first-point"}]:[],a={tolerance:this._cssPxToRender(12),distinguishTolerance:this._cssPxToRender(8),gridStep:this.host._gridPitch,excludePoints:i?[i]:[],extraEndpoints:o,epsilon:2e-4*this.host._gridPitch},n=e&&i?Ca(s.value,t,{...a,anchor:i}):function(t,e,s){if(!(pa(e)&&s.tolerance>=0))return{kind:"none",candidate:null,conflicts:[]};const i=s.epsilon??da,o=s.excludePoints||[],a=Ma(xa(t,e,s),s.distinguishTolerance||0);if(a)return a;let n=null;for(const a of t.segments){const t=[a.a[0],a.a[1],a.b[0],a.b[1]],r=D([e[0],e[1]],t);if(r>s.tolerance)continue;const h=Sa(a,e,s.gridStep);!wa(h,o,i)&&ka(r,a.key,n)&&(n={kind:"line",point:h,key:a.key,distance:r,segment:a})}return n?{kind:"resolved",candidate:n,conflicts:[]}:{kind:"none",candidate:null,conflicts:[]}}(s.value,t,a),r="resolved"===n.kind?n.candidate:null,h=r?[...r.point]:this._snapDrawPoint(t,e),l=i?At(i,h):h;return{point:l,candidate:r&&q(l,r.point)?r:null,conflicts:"ambiguous"===n.kind?n.conflicts:[],ambiguous:"ambiguous"===n.kind,contextKey:this._planSnapContextKey(s.key)}}_clearPlanSnapHover(t=!0){this.host._planSnapHover=null,this._syncPlanSnapActiveMarker(null),this._syncPlanSnapConflictMarkers([]),t&&(this.host._cursorPt=null)}_samePt(t,e){return q(t,e)}_dropLegacySegments(){for(const t of this.host._serverCfg?.markers||[])"ripple"===t.display&&(t.display="icon_ripple");for(const t of this.host._serverCfg?.spaces||[]){delete t.segments;const e=new Set,s=t=>"string"==typeof t&&t.length>=1&&t.length<=64&&!e.has(t),i=t=>(e.add(t),!0),o=t=>Array.isArray(t)&&2===t.length&&t.every(t=>Number.isFinite(Number(t))&&Math.abs(Number(t))<=Xt);if(Array.isArray(t.partitions)&&(t.partitions=t.partitions.filter(t=>t&&s(t.id)&&o(t.a)&&o(t.b)&&Math.hypot(t.a[0]-t.b[0],t.a[1]-t.b[1])>1e-9&&i(t.id)).map(t=>({...t,cm:Number.isFinite(Number(t.cm))?Math.max(0,Math.min(100,Number(t.cm))):15})),t.partitions.length||delete t.partitions),Array.isArray(t.wall_columns)&&(t.wall_columns=t.wall_columns.filter(t=>t&&s(t.id)&&o(t.center)&&i(t.id)).map(t=>({id:t.id,shape:"circle"===t.shape?"circle":"square",center:[Number(t.center[0]),Number(t.center[1])],cm:wt(Number(t.cm)||15),..."circle"===t.shape?{}:{angle:Nt(t.angle)}})),t.wall_columns.length||delete t.wall_columns),Array.isArray(t.room_drafts)&&(t.room_drafts=t.room_drafts.filter(t=>t&&s(t.id)&&Array.isArray(t.points)&&t.points.length>=2&&t.points.every(o)&&i(t.id)).map(t=>{const e=nr(t);return{id:t.id,...e}}).filter(t=>t.points.length>=2),t.room_drafts.length||delete t.room_drafts),Array.isArray(t.walls)){const e=Ht(ut({spaces:[t]}),t.id),s=e?Ot(t,e,eh,.02*nt).contour.map(t=>t.map(t=>t/eh)):V(t.open_spans).map(t=>[t.a[0],t.a[1],t.b[0],t.b[1]]);t.walls=rt(t.walls,t.rooms||[],I,1,s),t.walls.length||delete t.walls}}}_rollbackRejectedPhysicalWrites(t){if(!this.host._serverCfg||!t.length)return!1;let e=!1;for(const[s]of t){const t=this.host._pendingPhysicalWrites.get(s);t&&(e=this._restoreGeometryStateInConfig(this.host._serverCfg,t.before)||e,this.host._pendingPhysicalWrites.delete(s))}return!!e&&(this._clearGeometryGesture(),this.host._geometryHistory.clear(),this.host._cfgEpoch++,this.host._modelCache=null,this.host._wallUnionCache=null,this.host._physicalBodiesCache=null,this.host._frame=null,this.host._regSignature="",this.host._cfgContentFingerprint=Lt(this.host._serverCfg),this.host._maybeRebuildDevices(),this.host.requestUpdate(),!0)}async _reloadRejectedPhysicalWrite(){const t=this.host._writeChain;await t.catch(()=>{}),await this.host._reloadConfigOnly(!0)}_writeConfig(){this.host._writesPending++,this.host._writeChain=Et(this.host._writeChain,async()=>{if(!this.host._serverCfg)return;this._dropLegacySegments();const t=ki(this.host._serverCfg),e=Lt(t),s=[...this.host._pendingPhysicalWrites.entries()];for(const[e,i]of s){const s=t.spaces.find(t=>t.id===e),o=jt(s);if(o===i.fingerprint)continue;let a=!1;try{a=this.host._checkSpacePhysicalGeometry(t,e).ok}catch{a=!1}if(!a)throw this._restoreGeometryStateLocal(i.before),this.host._pendingPhysicalWrites.delete(e),this.host._geometryHistory.clear(),this.host._showToast(this.host._t("toast.geometry_unsafe")),Object.assign(new Error("unsafe wall geometry"),{code:"geometry-unsafe"});i.fingerprint=o}e!==Lt(this.host._serverCfg)&&(this.host._serverCfg=t),this.host._cfgContentFingerprint=e;try{await this.host._sendConfigCandidate(t)}catch(t){if(!this._rollbackRejectedPhysicalWrites(s))throw t;const e=t&&"object"==typeof t?t:Object.assign(new Error(String(t)),{cause:t});throw e.physicalGeometryRolledBack=!0,e}for(const[t,e]of s)this.host._pendingPhysicalWrites.get(t)?.fingerprint===e.fingerprint&&this.host._pendingPhysicalWrites.delete(t)});return this.host._writeChain.finally(()=>{this.host._writesPending--})}_saveConfig(){this.host._cfgEpoch++,this.host._saveConfigDebounced()}_geometrySnapshotFromConfig(t,e){const s=t?.spaces?.find(t=>t.id===e);if(!s)return null;const i=t=>JSON.parse(JSON.stringify(t)),o={};for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])void 0!==s[t]&&(o[t]=s[t]);return{spaceId:e,rooms:i(s.rooms||[]),...Array.isArray(s.openings)?{openings:i(s.openings)}:{},...Array.isArray(s.walls)?{walls:i(s.walls)}:{},...Array.isArray(s.wall_segments)?{wall_segments:i(s.wall_segments)}:{},...Array.isArray(s.open_spans)?{open_spans:i(s.open_spans)}:{},...Array.isArray(s.room_drafts)?{room_drafts:i(s.room_drafts)}:{},...Array.isArray(s.partitions)?{partitions:i(s.partitions)}:{},...Array.isArray(s.wall_columns)?{wall_columns:i(s.wall_columns)}:{},...Array.isArray(s.decor)?{decor:i(s.decor)}:{},plan_transform:o}}_geometrySnapshot(t=this.host._space){return this._geometrySnapshotFromConfig(this.host._serverCfg,t)}_recordGeometry(t,e){if(!e)return;const s=this._geometrySnapshot(e.spaceId);s&&JSON.stringify(e)!==JSON.stringify(s)&&(this.host._geometryHistory.push({name:t,before:e,after:s}),this.host.requestUpdate())}_restoreGeometryStateInConfig(t,e,s=!1){const i=t?.spaces?.find(t=>t.id===e.spaceId);if(!i)return!1;const o=t=>JSON.parse(JSON.stringify(t)),a=new Map((i.rooms||[]).map(t=>[t.id,t]));if(i.rooms=o(e.rooms),s)for(const t of i.rooms){const e=a.get(t.id);!Array.isArray(t.wall_ids)&&Array.isArray(e?.wall_ids)&&e.wall_ids.length===t.poly?.length&&(t.wall_ids=o(e.wall_ids))}const n=(t,e)=>{void 0!==e?i[t]=o(e):s&&"wall_segments"===t||delete i[t]},r=new Map((i.openings||[]).map(t=>[t.id,t])),h=new Map((i.room_drafts||[]).map(t=>[t.id,t]));if(n("openings",e.openings),n("walls",e.walls),n("wall_segments",e.wall_segments),n("open_spans",e.open_spans),n("room_drafts",e.room_drafts),n("partitions",e.partitions),n("wall_columns",e.wall_columns),n("decor",e.decor),s){for(const t of i.openings||[]){const e=r.get(t.id);t.host||"wall"!==e?.host?.kind||(t.host=o(e.host))}for(const t of i.room_drafts||[]){const e=h.get(t.id);for(let s=0;s<(t.segments||[]).length;s++)!t.segments[s]?.id&&e?.segments?.[s]?.id&&(t.segments[s].id=e.segments[s].id)}}for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])delete i[t];return Object.assign(i,o(e.plan_transform||{})),!0}_restoreGeometryStateLocal(t){return!!this._restoreGeometryStateInConfig(this.host._serverCfg,t)&&(this.host._cfgEpoch++,this.host._modelCache=null,this.host._wallUnionCache=null,this.host._physicalBodiesCache=null,this.host._frame=null,this.host.requestUpdate(),!0)}_wallModelBlockerLabel(t){const e=t instanceof Zn?t.reason:"invalid-room";return this.host._t(`wall_model.reason.${e}`)}_hasLegacyZeroWallFields(t=this.host._serverCfg){return(t?.spaces||[]).some(t=>Array.isArray(t?.open_spans)&&t.open_spans.length>0||(t?.rooms||[]).some(t=>Array.isArray(t?.open_to)&&t.open_to.length>0))}_showWallModelMigrationBlocked(t){const e=this._hasLegacyZeroWallFields()?"toast.zero_wall_migration_blocked":"toast.wall_model_migration_blocked";this.host._showToast(this.host._t(e,{reason:this._wallModelBlockerLabel(t)}))}_limitSegmentsOf(t){const e=[];for(const s of t?.wall_segments||[])s?.a&&s?.b&&e.push({id:String(s.id||""),a:s.a,b:s.b,cm:Number(s.cm)});for(const s of t?.partitions||[])s?.a&&s?.b&&e.push({id:String(s.id||""),a:s.a,b:s.b,cm:Number(s.cm)});for(const s of t?.room_drafts||[]){const t=Array.isArray(s?.points)?s.points:[],i=Array.isArray(s?.segments)?s.segments:[];for(let o=0;o+1t?.id===e);if(!i)return[];const o=Number(i.cell_cm)>0?Number(i.cell_cm):5,a=this._limitSegmentsOf(i),n=[...Xo(a),...sa(a,o,I),...oa(a,o,I)];let r=null;try{r=Bt(i.rooms||[],i.walls||[],[],I,o,I,1)}catch{r=null}let h="ok"===s?.status||"degraded-extra"===s?.status?s.roomGeom:null;if(!h&&r&&r.nodes.length)try{const t=Wt(i.rooms||[],i.walls||[],[],[],I,o,I,1);h="ok"===t?.status||"degraded-extra"===t?.status?t.roomGeom:null}catch{h=null}for(const t of i.rooms||[]){const e=String(t?.id||"");if(!e)continue;let s=null;try{s=Gt(i.rooms||[],e,i.walls||[],[],I,o,I,1,h??void 0,r)}catch{s=null}n.push(...aa(e,s,o,I))}return n}_junctionLimitLabel(t){const e=t=>String(Math.round(10*t)/10);return this.host._t(`junction.limit_${t.rule}`,{actual:e(t.actual),limit:e(t.limit)})}_junctionLimitsIntroduced(t,e,s,i){let o;const a=(e?.spaces||[]).find(t=>t?.id===s);let n="";try{n=jt(a)}catch{n=""}const r=e&&"object"==typeof e?this._junctionBaselineCache.get(e):void 0;if(r&&n&&r.fingerprint===n&&r.spaceId===s&&(o=r.violations),!o){try{const t=Number(e?.model_version||0)>=9?e:kr(e).config;o=this.host._junctionLimitViolations(t,s)}catch{return[]}e&&"object"==typeof e&&n&&this._junctionBaselineCache.set(e,{spaceId:s,fingerprint:n,violations:o})}let h=[];try{h=this.host._junctionLimitViolations(t,s,i)}catch{return[{rule:"check_failed",subject:s,actual:0,limit:0}]}return function(t,e){const s=new Map;for(const t of e||[])s.set(t.rule,(s.get(t.rule)||0)+1);const i=new Map;for(const e of t||[])i.set(e.rule,[...i.get(e.rule)||[],e]);const o=[];for(const[t,e]of i){const i=e.length-(s.get(t)||0);i>0&&o.push(...e.slice(0,i))}return o}(h,o)}_commitPhysicalGeometry(t,e,s=[]){if(!e||!this.host._serverCfg)return!1;const i=this.host._serverCfg,o=this._geometrySnapshotFromConfig(i,e.spaceId),a=i.spaces.find(t=>t.id===e.spaceId);if(!a||jt(e)===jt(a))return!1;let n,r=!1;try{r=this.host._checkSpacePhysicalGeometry(i,e.spaceId).ok}catch{r=!1}if(!r)return this._clearGeometryGesture(),this._restoreGeometryStateLocal(e),this.host._showToast(this.host._t("toast.geometry_unsafe")),!1;let h=e;try{if(Number(i.model_version||0)<9){const t=JSON.parse(JSON.stringify(i));if(!this._restoreGeometryStateInConfig(t,e))throw new Zn("invalid-room",e.spaceId);const s=kr(t).config;h=this._geometrySnapshotFromConfig(s,e.spaceId)||e;const a=JSON.parse(JSON.stringify(s));if(!o||!this._restoreGeometryStateInConfig(a,o,!0))throw new Zn("invalid-room",e.spaceId);const r=s.spaces.find(t=>t.id===e.spaceId),l=a.spaces.find(t=>t.id===e.spaceId);if(!Array.isArray(o.wall_segments)&&JSON.stringify(e.rooms)===JSON.stringify(o.rooms))for(const t of l?.wall_segments||[])t.cm=Q(o.walls,t.a,t.b,I,1);const c=((t,e,s)=>{const i=new Map,o=new Map((t?.rooms||[]).map(t=>[t.id,t])),a=new Map((e||[]).map(t=>[t.id,t])),{rooms:n}=br(s,gr(t));for(const t of n){const e=a.get(t.id),n=o.get(t.id),r=R(e),h=(s.rooms||[]).find(e=>e.id===t.id),l=R(h),c=R(n);if(r&&l&&c&&r.length===l.length&&c.length===n?.wall_ids?.length&&t.poly.length===t.wall_ids.length)for(let e=0;e{const o=[];for(let a=0;aXn||lr(r,s,i)>Xn)continue;const h=hr(n,s,i),l=hr(r,s,i);h<-Xn||l>1+Xn||l<=h+Xn||o.push({start:h,id:e[a]})}return o.sort((t,e)=>t.start-e.start)},o=s(c,n.wall_ids,r[e],r[(e+1)%r.length]),a=s(t.poly,t.wall_ids,l[e],l[(e+1)%l.length]);if(o.length&&o.length===a.length)for(let t=0;tt.id===e.spaceId),i=this.host._path.length>=2?this.host._path.map(t=>[t[0]/eh,t[1]/eh]):[];i.push(...s.map(t=>[t[0],t[1]])),l=rr(t)<=rr(h,i)&&this.host._checkSpacePhysicalGeometry(n,e.spaceId).ok}catch{l=!1}if(!l)return this._clearGeometryGesture(),this._restoreGeometryStateLocal(e),this.host._showToast(this.host._t("toast.geometry_unsafe")),!1;const c=JSON.parse(JSON.stringify(i));this._restoreGeometryStateInConfig(c,e);const d=this._junctionLimitsIntroduced(n,c,e.spaceId);if(d.length)return this._clearGeometryGesture(),this._restoreGeometryStateLocal(e),this.host._showToast(this._junctionLimitLabel(d[0])),!1;Mr(i,n),this._recordGeometry(t,h);const p=i.spaces.find(t=>t.id===e.spaceId),_=this.host._pendingPhysicalWrites.get(e.spaceId);return this.host._pendingPhysicalWrites.set(e.spaceId,{before:_?.before||h,fingerprint:jt(p)}),this._saveConfig(),!0}_clearGeometryGesture(){this.host._path=[],this._clearPlanSnapHover(),this._clearOpeningPlacement(!1),this.host._mergeSel=null,this.host._mergeDialog=null,this.host._splitSel=null,this.host._pendingSplit=null,this.host._wallFaceBatch=null,this.host._wallRepairDiagnostic=null,this.host._roomDeleteDialog=null,this.host._wallDialog=null,this.host._physicalDialog=null,this.host._physicalSel=null,this.host._physicalDrag=null,this.host._physicalRotate=null,this.host._activeDraftId=null,this.host._draftSegmentCms=[],this.host._closingWallCm=null,this.host._openingDialog=null,this._rszResetController(),this.host._decorDraft=null,this.host._decorMove=null,this.host._dtDrag=null,this.host._bdDrag=null}_stagePointerCancel(t){if(clearTimeout(this.host._kioskHoldTimer),this.host._swipeStart?.id===t.pointerId&&(this.host._swipeStart=null),this.host._physicalDrag?.pid===t.pointerId||this.host._physicalRotate?.pid===t.pointerId)return void this._cancelPhysicalGesture();if(this.host._decorDraft?.pid===t.pointerId)return this.host._decorDraft=null,void this.host.requestUpdate();if(this.host._decorMove?.pid===t.pointerId||this.host._dtDrag?.pid===t.pointerId||this.host._bdDrag?.pid===t.pointerId)return void this._cancelDecorGesture();"opening"===this.host._tool?(this.host._cursorPt=null,this._clearOpeningPlacement(!1)):"draw"===this.host._tool&&this._clearPlanSnapHover();const e=!!this.host._pinchStart||!!this.host._panStart;this.host._pointers.delete(t.pointerId),this.host._pointers.size<2&&(this.host._pinchStart=null),0===this.host._pointers.size&&(this.host._panStart=null,this.host._panLock=null),e&&0===this.host._pointers.size&&this.host.requestUpdate()}_applyGeometryState(t,e=!1){if(!this.host._canCommitSpace(t.spaceId))return!1;const s=this._geometrySnapshot(t.spaceId);if(!s||!this._restoreGeometryStateLocal(t))return!1;const i=this.host._serverCfg,o=jt(s)!==jt(t);if(o){let o=!1;try{const s=i?this.host._checkSpacePhysicalGeometry(i,t.spaceId):null;o=!!s?.ok||!(!e||"wall-degraded-extra"!==s?.reason)}catch{o=!1}if(!o)return this._restoreGeometryStateLocal(s),this.host._showToast(this.host._t("toast.geometry_unsafe")),!1}let a;try{a=kr(i).config}catch(t){return this._restoreGeometryStateLocal(s),this._showWallModelMigrationBlocked(t),!1}if(o){let o=!1;try{const s=a?this.host._checkSpacePhysicalGeometry(a,t.spaceId):null;o=!!s?.ok||!(!e||"wall-degraded-extra"!==s?.reason)}catch{o=!1}if(!o)return this._restoreGeometryStateLocal(s),this.host._showToast(this.host._t("toast.geometry_unsafe")),!1;Mr(i,a);const n=i?.spaces.find(e=>e.id===t.spaceId),r=this.host._pendingPhysicalWrites.get(t.spaceId);this.host._pendingPhysicalWrites.set(t.spaceId,{before:r?.before||s,fingerprint:jt(n)})}else Mr(i,a);return this._clearGeometryGesture(),this.host._space!==t.spaceId&&(this.host._commitSpace(t.spaceId),this.host._saveNav(),this.host._restoreZoom()),this.host._modelCache=null,this.host._frame=null,this.host._regSignature="",this.host._maybeRebuildDevices(),this._saveConfig(),this.host.requestUpdate(),!0}_roomAt(t){return this.host._spaceModel()?.rooms.find(e=>{const s=R(e);return!!s&&qt(t,s)})}_overlapRoom(t){return this.host._spaceModel()?.rooms.find(e=>{const s=R(e);return!!s&&$(t,s)})}_pointInRoom(t,e){return e.poly?Ut(t,e.poly):null!=e.x&&t[0]>=e.x&&t[0]<=e.x+e.w&&t[1]>=e.y&&t[1]<=e.y+e.h}_contourSelfIntersects(t){if(!po(t))return!0;const e=t.length,s=.001;for(let i=0;i=500)return this.host._showToast(this.host._t("toast.physical_limit")),!1;const t=this.host._curSpaceCfg;return!(!this.host._activeDraftId&&(t?.room_drafts||[]).length>=200||this._draftSegmentCount(t)>=2e3||(t?.partitions||[]).length+this.host._path.length>sh)||(this.host._showToast(this.host._t("toast.physical_limit")),!1)}_markupClick(t){if(this.host._vacFit)return;if(!this.host._markup)return;const e=this.host._spaceModel();if(!e)return void this._clearGeometryGesture();if(this.host._suppressClick)return;if(this.host._drag||this.host._rlResize)return;const s=t.composedPath?.()||[];if(s.some(t=>t?.classList?.contains?.("roomlabel")||t?.classList?.contains?.("rlhandle")))return;if(s.some(t=>t?.classList?.contains?.("physical-hit")))return;const i=this._svgPoint(t);if("select"===this.host._tool)return void(this.host._physicalSel=null);if("resize"===this.host._tool){if(this.host._resize.dragging||s.some(t=>t?.classList?.contains?.("rszhandle")))return;const t=[...e.rooms].reverse().find(t=>this._pointInRoom(i,t));return this.host._resize.selectRoom(t?.id||null),void this.host.requestUpdate()}if("delroom"===this.host._tool)return void this._deleteRoomClick(i);if("opening"===this.host._tool)return void this._openingClick(i);if("merge"===this.host._tool)return void this._mergeClick(i);if("wallthick"===this.host._tool)return void this._wallThickClick(i);if("split"===this.host._tool)return void this._splitClick(i);if("column"===this.host._tool)return void this._columnClick(i);this.host._wallRepairDiagnostic=null;const o=this._resolvePlanDrawPoint(i,t.shiftKey);if(o.ambiguous)return this.host._planSnapHover={contextKey:o.contextKey,candidate:null,conflicts:o.conflicts},this._syncPlanSnapActiveMarker(null),this._syncPlanSnapConflictMarkers(o.conflicts),void this.host._showToast(this.host._t("toast.plan_snap_ambiguous"));let a=o.point;if(t.ctrlKey||t.metaKey){if(t.preventDefault(),this.host._path.length<3)return;a=At(this.host._path[this.host._path.length-1],this.host._path[0])}if(!this.host._path.length){if(!t.shiftKey&&!o.candidate&&this._offerExistingWallFace(i))return;const e=this._draftEndAt(a);return e?(this.host._activeDraftId=e.draft.id,this.host._resumeDraftBySpace[this.host._space]=e.draft.id,this.host._path=e.reverse?[...e.draft.points].reverse().map(t=>[...t]):e.draft.points.map(t=>[...t]),void(this.host._draftSegmentCms=this._adoptDraftCms(this.host._path,e.reverse?[...e.draft.segments].reverse().map(t=>t.cm):e.draft.segments.map(t=>t.cm),e.draft.id))):(this.host._activeDraftId=null,this.host._draftSegmentCms=[],void(this.host._path=[a]))}const n=this.host._path[this.host._path.length-1];if(this._samePt(a,n))return;const r=this._draftEndAt(a,this.host._activeDraftId||void 0);if(r)return void this._mergeDraftEndpoint(r);if(!this._canAppendRoomDraftPoint())return;const h=this.host._drawWallCm;if(null==h)return void this._showPhysicalRange(100);const l=this.host._path.map(t=>[...t]);this.host._path=[...this.host._path,a],this.host._draftSegmentCms=[...this.host._draftSegmentCms,h],this._persistActiveDraftSegment(),this._offerWallFaces(l)}_draftEndAt(t,e){const s=this.host._spaceModel();if(!s)return null;const i=this.host._viewOr(this.host._baseVb()),o=Math.max(.15*this.host._gridPitch,this.host._stageEl?.clientWidth?i.w/this.host._stageEl.clientWidth*12:0);for(const i of s.room_drafts||[]){if(i.id===e)continue;if(i.points.length<2)continue;const s=i.points[0],a=i.points[i.points.length-1];if(Math.hypot(t[0]-a[0],t[1]-a[1])<=o)return{draft:i,reverse:!1};if(Math.hypot(t[0]-s[0],t[1]-s[1])<=o)return{draft:i,reverse:!0}}return null}_mergeDraftEndpoint(t){const e=this.host._curSpaceCfg;if(!e||!this.host._path.length)return;const s=this.host._path.map(t=>[...t]),i=this._wallGraphSources(s),o=Array.isArray(e.room_drafts)?e.room_drafts:[],a=this.host._activeDraftId?o.find(t=>t.id===this.host._activeDraftId):null,n=o.find(e=>e.id===t.draft.id);if(!n)return;const r=t.reverse?t.draft.points.map(t=>[...t]):[...t.draft.points].reverse().map(t=>[...t]),h=t.reverse?(n.segments||[]).map(t=>({...t})):[...n.segments||[]].reverse().map(t=>({...t})),l=this.host._path[this.host._path.length-1],c=this._samePt(l,r[0]),d=c?null:this.host._drawWallCm;if(!c&&null==d)return void this._showPhysicalRange(100);const p=this._draftSegmentsForPath(this.host._path,a,this.host._draftSegmentCms),_=[...this.host._path.map(t=>[...t]),...c?r.slice(1):r],u=[...p,...null==d?[]:[{cm:d}],...h],m=_.length>=4&&this._samePt(_[0],_[_.length-1]),g=_,f=u;if(g.length>500)return void this.host._showToast(this.host._t("toast.physical_limit"));const b=(a?.segments?.length||0)+(n.segments?.length||0);if(this._draftSegmentCount(e)-b+f.length>2e3)return void this.host._showToast(this.host._t("toast.physical_limit"));if(m){const t=g.slice(0,-1);if(this._contourSelfIntersects(t)||k(t)<=1e-6)return void this.host._showToast(this.host._t("toast.contour_cannot_close"));const e=this._overlapRoom(t);if(e)return void this.host._showToast(this.host._t("toast.room_overlap",{name:e.name||""}))}const v=this._geometrySnapshot(),y=this.host._activeDraftId||t.draft.id,$={...a||n,id:y,points:g.map(t=>[t[0]/eh,t[1]/eh]),segments:f};e.room_drafts=o.filter(e=>e.id!==t.draft.id&&(!this.host._activeDraftId||e.id!==this.host._activeDraftId)),e.room_drafts.push($),this.host._activeDraftId=y,this.host._resumeDraftBySpace[this.host._space]=y,this.host._path=g,this.host._draftSegmentCms=this._adoptDraftCms(g,f.map(t=>Number(t.cm)),y),this.host._physicalSel=null,this._commitPhysicalGeometry(this.host._t("history.draft_merge"),v),null!=d&&this._offerWallFaces(s,s.length-1,i)}_adoptDraftCms(t,e,s){const i=Math.max(0,t.length-1),o=Pa(i,e,this.host._drawWallCm,N);return e.length!==i&&console.debug(`[houseplan] draft ${s??"?"}: восстановлено толщин ${i-e.length} (#234)`),o}_draftSegmentsForPath(t,e,s){const i=Array.isArray(e?.points)?e.points.map(t=>[Number(t?.[0])*eh,Number(t?.[1])*eh]):[],o=Array.isArray(e?.segments)?e.segments:[];return Pa(Math.max(0,t.length-1),s,this.host._drawWallCm,N).map((e,s)=>{const a=t[s],n=t[s+1],r=i.findIndex((t,e)=>{if(e+1>=i.length)return!1;const s=i[e+1];return this._samePt(a,t)&&this._samePt(n,s)||this._samePt(a,s)&&this._samePt(n,t)});return{...r>=0?o[r]:{},cm:e}})}_persistActiveDraftSegment(){if(this.host._path.length<2||!this.host._curSpaceCfg)return;const t=this._geometrySnapshot(),e=this.host._curSpaceCfg;e.room_drafts||=[],this.host._activeDraftId||(this.host._activeDraftId="draft-"+Date.now().toString(36)),this.host._resumeDraftBySpace[this.host._space]=this.host._activeDraftId;const s=e.room_drafts.findIndex(t=>t.id===this.host._activeDraftId),i={...s>=0?e.room_drafts[s]:{},id:this.host._activeDraftId,points:this.host._path.map(t=>[t[0]/eh,t[1]/eh]),segments:this._draftSegmentsForPath(this.host._path,s>=0?e.room_drafts[s]:null,this.host._draftSegmentCms)};s>=0?e.room_drafts[s]=i:e.room_drafts.push(i),this._commitPhysicalGeometry(this.host._t("history.draft_segment"),t)}_activeWallSourceKey(t){return`active:${this.host._activeDraftId||"session"}:${t}`}_wallGraphSources(t){const e=this._planStructuralGeometrySnapshot().value.segments.map(t=>({a:t.a,b:t.b,key:`static:${t.key}`}));for(let s=0;s+1t.key===s);if(i>=0){const[t]=this.host._wallFaceGraphCache.splice(i,1);return this.host._wallFaceGraphCache.push(t),t.value}const o=Za(t,e);return this.host._wallFaceGraphCache.push({key:s,value:o}),this.host._wallFaceGraphCache.length>4&&this.host._wallFaceGraphCache.shift(),o}_offerWallFaces(t,e=this.host._path.length-2,s){if(this.host._path.length<2||this.host._wallFaceBatch||this.host._roomDialog)return;const i=this.host._spaceModel();if(!i)return;const o=this._activeWallSourceKey(e),a=2e-4*this.host._gridPitch;let n,r;try{const e=s||this._wallGraphSources(t);r=this._wallGraphSources(this.host._path),n=function(t,e,s){const i=new Set(t.faces.map(t=>t.key));return e.faces.filter(t=>!i.has(t.key)&&t.sourceKeys.includes(s))}(this._wallFaceGraph(e,a),this._wallFaceGraph(r,a),o)}catch{return}if(!n.length){const t=dn(r,{requiredSourceKey:o,maxDistance:j(2,this.host._cellCm,this.host._gridPitch),gridStep:this.host._gridPitch,epsilon:a});return"ambiguous"===t.kind?(this.host._wallRepairDiagnostic=t.proposals[0]||null,void this.host._showToast(this.host._t(0===this.host._drawWallCm?"toast.zero_wall_ambiguous":"toast.wall_repair_ambiguous"))):void("repair"!==t.kind||this._overlapRoom(t.face.ring)||this._beginWallFaceBatch([{...t.face,repair:t.proposal}]))}for(const t of i.rooms){const e=R(t);if(!t.id||!e)continue;const s=Kt(e,this.host._path,.02*this.host._gridPitch);if(!s)continue;const[i,o]=s,a=k(i)>=k(o)?i:o,r=a===i?o:i,h=[...n].sort((t,e)=>Math.abs(t.area-k(r))-Math.abs(e.area-k(r))||t.key.localeCompare(e.key))[0];if(!h)return;return void this._beginWallFaceBatch([{...h,ring:r.map(t=>[t[0],t[1]]),split:{roomId:t.id,mainPoly:a,newPoly:r},consumeAllActive:!0}])}const h=n.filter(t=>!(t.ring.length<3||this._contourSelfIntersects(t.ring))&&!this._overlapRoom(t.ring));h.length&&this._beginWallFaceBatch(h)}_beginWallFaceBatch(t){this.host._wallRepairDiagnostic=null,this.host._wallFaceBatch={candidates:[...t].sort((t,e)=>t.area-e.area||t.key.localeCompare(e.key)),index:0,decisions:[],activePath:this.host._path.map(t=>[...t]),activeCms:[...this.host._draftSegmentCms],activeDraftId:this.host._activeDraftId},this._clearPlanSnapHover(),this.host._nameSel="",this.host._areaSel="",this._resetRoomDialogFields(),this.host._roomDialog=!0}_offerExistingWallFace(t){if(this.host._path.length||this.host._wallFaceBatch||this.host._roomDialog)return!1;const e=2e-4*this.host._gridPitch;try{let s,i=Qa(this._wallFaceGraph(this._wallGraphSources([]),e),t,e);if(!i){const o=dn(this._wallGraphSources([]),{point:t,maxDistance:j(2,this.host._cellCm,this.host._gridPitch),gridStep:this.host._gridPitch,epsilon:e});if("ambiguous"===o.kind)return this.host._wallRepairDiagnostic=o.proposals[0]||null,this.host._showToast(this.host._t(0===this.host._drawWallCm?"toast.zero_wall_ambiguous":"toast.wall_repair_ambiguous")),!0;if("repair"===o.kind)i=o.face,s=o.proposal;else if("none"===o.kind){const s=dn(this._wallGraphSources([]),{point:t,maxDistance:this._cssPxToRender(12),gridStep:this.host._gridPitch,epsilon:e});if("repair"===s.kind)return this.host._wallRepairDiagnostic=s.proposal,this.host._showToast(this.host._t("toast.wall_repair_too_large")),!0}}return!(!i||i.ring.length<3||this._contourSelfIntersects(i.ring)||this._overlapRoom(i.ring))&&(this._beginWallFaceBatch([{...i,existing:!s,repair:s}]),!0)}catch{return!1}}_columnClick(t){const e=this._snap(t),s=this.host._drawWallCm;if(null==s)return void this._showPhysicalRange(vt,1);if(!this.host._curSpaceCfg||this._limitReached("column"))return;const i=this.host._spaceModel();if(!i)return;const o={id:"column-"+Date.now().toString(36),shape:"square",center:e,cm:wt(s),angle:0},a=(i.wall_columns||[]).find(t=>yt(t,o,.02*this.host._gridPitch));if(a)return clearTimeout(this.host._duplicateColumnTimer),this.host._duplicateColumnId=a.id,this.host._duplicateColumnTimer=window.setTimeout(()=>{this.host._duplicateColumnId=null},900),void this.host._showToast(this.host._t("toast.column_duplicate"));const n=this._geometrySnapshot(),r=this.host._curSpaceCfg;r.wall_columns||=[],r.wall_columns.push({...o,center:[e[0]/eh,e[1]/eh]}),this._commitPhysicalGeometry(this.host._t("history.column_add"),n)}_openPhysicalDialog(t,e,s){const i=this.host._spaceModel();if(i)if("partition"===t){const s=i.partitions.find(t=>t.id===e);s&&(this.host._physicalDialog={kind:t,id:e,cm:Tt(s.cm,this.host._imperial),length:this.host._fmtLen(s.a,s.b)})}else if("column"===t){const s=i.wall_columns.find(t=>t.id===e);s&&(this.host._physicalDialog={kind:t,id:e,cm:Tt(s.cm,this.host._imperial),shape:s.shape,angle:this.host._angleField("square"===s.shape?Nt(s.angle):0)})}else{const o=i.room_drafts.find(t=>t.id===e),a=Math.max(0,Math.min(o?.segments.length?o.segments.length-1:0,s||0));o?.segments[a]&&(this.host._physicalDialog={kind:t,id:e,segment:a,cm:Tt(o.segments[a].cm,this.host._imperial),length:this.host._fmtLen(o.points[a],o.points[a+1])})}}_physicalDown(t,e,s){const i=this.host._spaceModel();if(!i)return;t.stopPropagation(),ih(t);const o=this._svgPoint(t),a=[];for(const t of[...i.wall_columns].reverse())Vt(o,Jt(t,this.host._cellCm,this.host._gridPitch))&&a.push({kind:"column",id:t.id});for(const t of[...i.partitions].reverse()){const e=Yt(t.a,t.b,t.cm,this.host._cellCm,this.host._gridPitch);e&&Vt(o,e)&&a.push({kind:"partition",id:t.id})}a.some(t=>t.kind===e&&t.id===s)||a.unshift({kind:e,id:s});const n=a.map(t=>`${t.kind}:${t.id}`).sort().join("|"),r=performance.now(),h=this.host._physicalPickCycle,l=a.length>1&&h?.signature===n&&r-h.at>380&&r-h.at<=1200&&Math.hypot(t.clientX-h.x,t.clientY-h.y)<=10?(h.index+1)%a.length:Math.max(0,a.findIndex(t=>t.kind===e&&t.id===s));this.host._physicalPickCycle={signature:n,index:l,x:t.clientX,y:t.clientY,at:r},e=a[l].kind,s=a[l].id;const c="partition"===e?i.partitions.find(t=>t.id===s):i.wall_columns.find(t=>t.id===s);c&&(this.host._physicalSel={kind:e,id:s},this.host._physicalDrag={pid:t.pointerId,kind:e,id:s,start:this._svgPoint(t),startClient:[t.clientX,t.clientY],before:this._geometrySnapshot(),moved:!1,base:JSON.parse(JSON.stringify(c)),delta:[0,0]})}_clampPhysicalDelta(t,e,s){const i="partition"===t?[e.a,e.b]:[e.center],o=i.map(t=>t[0]),a=i.map(t=>t[1]);return[Math.max(-Xt*eh-Math.min(...o),Math.min(Xt*eh-Math.max(...o),s[0])),Math.max(-Xt*eh-Math.min(...a),Math.min(Xt*eh-Math.max(...a),s[1]))]}_physicalMove(t){const e=this.host._physicalDrag;if(!e||e.pid!==t.pointerId)return;t.stopPropagation();const s=this._svgPoint(t),i="partition"===e.kind?e.base.a:e.base.center,o=this._snap([i[0]+s[0]-e.start[0],i[1]+s[1]-e.start[1]]),a=this._clampPhysicalDelta(e.kind,e.base,[o[0]-i[0],o[1]-i[1]]);this.host._physicalDrag={...e,delta:a,moved:e.moved||Math.hypot(t.clientX-e.startClient[0],t.clientY-e.startClient[1])>=5}}_physicalUp(t){const e=this.host._physicalDrag;if(!e||e.pid!==t.pointerId)return;if(t.stopPropagation(),this.host._physicalDrag=null,!e.moved)return void this._registerPhysicalTap(e.kind,e.id);const s=this.host._spaceModel();if(!this.host._curSpaceCfg||!s)return;const i=this.host._curSpaceCfg;if("partition"===e.kind){const t=(i.partitions||[]).find(t=>t.id===e.id),s=e.base;if(t){const o={...s,a:[s.a[0]+e.delta[0],s.a[1]+e.delta[1]],b:[s.b[0]+e.delta[0],s.b[1]+e.delta[1]]};t.a=[o.a[0]/eh,o.a[1]/eh],t.b=[o.b[0]/eh,o.b[1]/eh];for(const t of i.openings||[]){if("partition"!==t.host?.kind||t.host.id!==e.id)continue;const s=z(t,[o],eh,this.host._cellCm,this.host._gridPitch).resolved;s&&Object.assign(t,F(t,s,eh))}}}else{const t=(i.wall_columns||[]).find(t=>t.id===e.id),o=e.base,a={...o,center:[o.center[0]+e.delta[0],o.center[1]+e.delta[1]]};if(s.wall_columns.some(t=>t.id!==e.id&&yt(t,a,.02*this.host._gridPitch)))return void this.host._showToast(this.host._t("toast.column_duplicate"));t&&(t.center=[(o.center[0]+e.delta[0])/eh,(o.center[1]+e.delta[1])/eh])}this._commitPhysicalGeometry(this.host._t("history.physical_move"),e.before)}_registerPhysicalTap(t,e,s){const i=performance.now(),o=this.host._physicalLastTap?.kind===t&&this.host._physicalLastTap.id===e&&this.host._physicalLastTap.segment===s&&i-this.host._physicalLastTap.at<=360;this.host._physicalLastTap={kind:t,id:e,segment:s,at:i},o&&(this.host._physicalLastTap=null,this._openPhysicalDialog(t,e,s))}_cancelPhysicalGesture(){this.host._physicalDrag=null,this.host._physicalRotate=null,this.host.requestUpdate()}_physicalRotateDown(t,e){if("square"!==e.shape||!this.host._spaceModel())return;t.preventDefault(),t.stopPropagation(),ih(t);const s=this._svgPoint(t);this.host._physicalSel={kind:"column",id:e.id},this.host._physicalRotate={pid:t.pointerId,id:e.id,center:[...e.center],startAngle:180*Math.atan2(s[1]-e.center[1],s[0]-e.center[0])/Math.PI,baseAngle:Nt(e.angle),angle:Nt(e.angle),before:this._geometrySnapshot(),moved:!1}}_physicalRotateMove(t){const e=this.host._physicalRotate;if(!e||e.pid!==t.pointerId)return;t.preventDefault(),t.stopPropagation();const s=this._svgPoint(t),i=180*Math.atan2(s[1]-e.center[1],s[0]-e.center[0])/Math.PI,o=e.baseAngle+i-e.startAngle,a=Nt(t.shiftKey?o:5*Math.round(o/5));this.host._physicalRotate={...e,angle:a,moved:e.moved||Math.abs(o-e.baseAngle)>=.5}}_physicalRotateUp(t){const e=this.host._physicalRotate;if(!e||e.pid!==t.pointerId)return;t.preventDefault(),t.stopPropagation(),this.host._physicalRotate=null;const s=this.host._spaceModel();if(!e.moved||!this.host._curSpaceCfg||!s)return;const i=s.wall_columns.find(t=>t.id===e.id);if(!i||"square"!==i.shape)return;const o={...i,angle:e.angle};if(s.wall_columns.some(t=>t.id!==e.id&&yt(t,o,.02*this.host._gridPitch)))return void this.host._showToast(this.host._t("toast.column_duplicate"));const a=this.host._curSpaceCfg.wall_columns?.find(t=>t.id===e.id);a&&(a.angle=e.angle,this._commitPhysicalGeometry(this.host._t("history.physical_edit"),e.before))}_rszRooms(){const t=[],e=this.host._spaceModel();if(!e)return t;for(const s of e.rooms){const e=s.id?R(s):null;e&&t.push({id:s.id,poly:e,wall_ids:Array.isArray(s.wall_ids)?[...s.wall_ids]:void 0})}return s=t,i=Math.max(1e-12,1e-12*this.host._gridPitch),s.map(t=>{if(!Array.isArray(t.wall_ids)||t.wall_ids.length!==t.poly.length)return{...t,poly:t.poly.map(t=>[...t])};const e=t.poly.map(t=>[...t]);let s=!0;for(;s&&e.length>3;){s=!1;for(let t=0;t0){e.splice(t,1),s=!0;break}}}return{...t,poly:e}});var s,i}_rszOpenings(){return this.host._openingsR.map(t=>({id:t.id,x:t.rx,y:t.ry,length:t.rlen,hosted:!!t.host,angle:t.angle,type:t.type}))}_rszObstacles(){const t=this.host._spaceModel();if(!t)return[];const e=[];for(const s of t.partitions||[])e.push({kind:"segment",a:[...s.a],b:[...s.b],half:j(s.cm,this.host._cellCm,this.host._gridPitch)/2});for(const s of t.room_drafts||[])for(let t=0;t+1Array.isArray(t.a)&&Array.isArray(t.b)&&t.a.length>=2&&t.b.length>=2).map(t=>({wall:t,a:[t.a[0]*eh,t.a[1]*this.host._spaceH],b:[t.b[0]*eh,t.b[1]*this.host._spaceH]})),o=Math.abs(t[0]-e[0])<=.05*this.host._gridPitch?"v":Math.abs(t[1]-e[1])<=.05*this.host._gridPitch?"h":null,a=i.filter(s=>!!o&&("h"===o?!(Math.abs(s.a[1]-t[1])>.05*this.host._gridPitch||Math.abs(s.b[1]-t[1])>.05*this.host._gridPitch)&&Math.min(Math.max(t[0],e[0]),Math.max(s.a[0],s.b[0]))-Math.max(Math.min(t[0],e[0]),Math.min(s.a[0],s.b[0]))>.05*this.host._gridPitch:!(Math.abs(s.a[0]-t[0])>.05*this.host._gridPitch||Math.abs(s.b[0]-t[0])>.05*this.host._gridPitch)&&Math.min(Math.max(t[1],e[1]),Math.max(s.a[1],s.b[1]))-Math.max(Math.min(t[1],e[1]),Math.min(s.a[1],s.b[1]))>.05*this.host._gridPitch)),n=new Set(a.map(t=>Number(t.wall.cm)).filter(t=>t>0));return{minDim:this.host._cmToUnits(30),eps:.05*this.host._gridPitch,step:this.host._gridPitch,movingHalf:s>0?j(s,this.host._cellCm,this.host._gridPitch)/2:0,obstacles:this._rszObstacles(),thicknessConflict:n.size>1}}_rszResolution(t,e,s){const i=this.host._resize.snapshotIdentity||s||this._rszSnapshot(),o=`${this.host._space}|${this.host._cellCm}|${this.host._gridPitch}|${i}`,a=`${t}:${e}`;return this.host._resize.resolve(o,a,()=>{const s=[...this.host._resize.rooms||this._rszRooms()],i=s.find(e=>e.id===t),o=i?.poly?.[e]||[0,0],a=i?.poly?.[(e+1)%(i?.poly?.length||1)]||[0,0];return function(t,e,s,i,o){const{eps:a}=o,n=t.find(t=>t.id===s);if(!n||i<0||i>=(n.poly?.length||0)||n.poly.length<4||!po(n.poly))return{enabled:!1,reason:"invalid-geometry"};const r=n.poly[i],h=n.poly[(i+1)%n.poly.length],l=go(r,h,a);if(!l)return{enabled:!1,reason:"diagonal"};if(!yo(n.poly,i,l,a))return{enabled:!1,reason:"side-angle"};if(o.thicknessConflict)return{enabled:!1,reason:"thickness-conflict"};for(const t of o.obstacles||[])if(ko(t,r,h,o))return{enabled:!1,reason:"duplicate-physical-wall"};const c=ro(oo(h,r)),d=[],p=new Set;let _=!1,u=!1;for(const e of t)if(e.id!==s)for(let t=0;t1||d.length>1)return{enabled:!1,reason:"multiple-rooms"};const m={[s]:i},g=[s];if(1===d.length){const t=d[0];if(!po(t.room.poly))return{enabled:!1,reason:"invalid-geometry"};if(!yo(t.room.poly,t.edge,l,a))return{enabled:!1,reason:"side-angle"};g.push(t.room.id),m[t.room.id]=t.edge}const f=[];for(const t of e)if(!(lo([t.x,t.y],r,h)>2*a)){if(t.hosted||t.length>c+2*a)return{enabled:!1,reason:"opening-conflict"};f.push(t.id)}const b=Object.fromEntries(g.map(e=>[e,t.find(t=>t.id===e).poly.length])),v=[];for(const e of g){const s=t.find(t=>t.id===e),i=m[e],o=(i-1+s.poly.length)%s.poly.length,n=(i+1)%s.poly.length,r=So(t,e,o,1,a),h=So(t,e,n,0,a);if(!r||!h)return{enabled:!1,reason:"partial-shared"};v.push(r,h)}const y={roomId:s,edge:i,a:[...r],b:[...h],n:co(n.poly,i),roomIds:g,edgeByRoom:m,topology:b,movingOpeningIds:f,sideOwnership:v};if(!zo(t,e,y,0,o))return{enabled:!1,reason:"invalid-geometry"};const $=Math.abs(Number(o.step));if(Number.isFinite($)&&$>a){const s=[-$,$];if(!s.some(s=>zo(t,e,y,s,o))){if(!s.some(s=>Po(Io(t,e,y,s),y,a)))return{enabled:!1,reason:"partial-shared"};const i={...o,obstacles:[]};return s.some(s=>zo(t,e,y,s,i))?{enabled:!1,reason:"duplicate-physical-wall"}:e.length&&s.some(e=>zo(t,[],y,e,o))?{enabled:!1,reason:"opening-conflict"}:{enabled:!1,reason:"invalid-geometry"}}}return{enabled:!0,plan:y}}(s,[...this.host._resize.openings||this._rszOpenings()],t,e,this._rszOptsFor(o,a))})}_rszSnapshot(){return JSON.stringify(this._geometrySnapshot()||{spaceId:this.host._space,rooms:[],openings:[],walls:[],open_spans:[]})}_rszResetController(){const t=null!==this.host._resize.preview;this.host._resize.reset(),t&&this.host._cfgEpoch++}_rszProjectPreview(t,e,s,i,o){this.host._rszLimitViolation=null;const a=this.host._serverCfg?.spaces.find(t=>t.id===this.host._space);if(!a||!this.host._serverCfg)return{ok:!1,reason:"missing-context"};const n=JSON.parse(t),r={...a,rooms:n.rooms,openings:n.openings||[]};for(const t of["walls","wall_segments","open_spans","room_drafts","partitions","wall_columns","decor"])void 0!==n[t]?r[t]=n[t]:delete r[t];for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])void 0!==n.plan_transform?.[t]?r[t]=n.plan_transform[t]:delete r[t];const h=this.host._spaceH;for(const[t,s]of Object.entries(e)){const e=r.rooms.find(e=>e.id===t);e&&(e.poly=s.map(t=>[t[0]/eh,t[1]/h]),delete e.x,delete e.y,delete e.w,delete e.h)}for(const[t,e]of Object.entries(s)){const s=(r.openings||[]).find(e=>e.id===t);s&&(s.x=e[0]/eh,s.y=e[1]/h)}const l=[],c=[];for(const t of i){const e=o.find(e=>e.id===t),s=r.rooms.find(e=>e.id===t);if(!e||!s?.poly)continue;const i=s.poly.map(t=>[t[0]*eh,t[1]*h]);if(e.poly.length!==i.length)continue;const a=Array.isArray(e.wall_ids)?e.wall_ids:[];for(let t=0;tt.id===s):null;o&&(o.a=[i[t][0]/eh,i[t][1]/eh],o.b=[i[(t+1)%i.length][0]/eh,i[(t+1)%i.length][1]/eh])}}if(l.length&&Array.isArray(r.walls)&&r.walls.length){const t=Zt(r.walls,l,c,this.host._wallKeyPitch,eh,"fixed-topology");if(t.rejected)return{ok:!1,reason:"wall-metadata"};r.walls=t.walls}const d=[];for(const t of r.rooms||[]){const e=R(t);if(e&&!(e.length<2))for(let t=0;tJSON.stringify([t?.key,t?.cm,t?.a,t?.b]),_=new Map;for(const t of n.walls||[]){const e=p(t);_.set(e,(_.get(e)||0)+1)}const u=[];for(const t of r.walls||[]){const e=p(t),s=_.get(e)||0;s?_.set(e,s-1):u.push(t)}if(Qt(u,d,this.host._wallKeyPitch,eh,n.walls||[]).length)return{ok:!1,reason:"wall-metadata"};const m=this._rszSpaceCandidateGeometry(this.host._space,r);if(!m.ok)return{ok:!1,reason:"physical-geometry"};const g={...this.host._serverCfg,spaces:(this.host._serverCfg?.spaces||[]).map(t=>t?.id===this.host._space?r:t)},f=this._junctionLimitsIntroduced(g,this.host._serverCfg,this.host._space,m.wallGeometry);return f.length?(this.host._rszLimitViolation=f[0],{ok:!1,reason:"junction-limit"}):{ok:!0,value:{preview:{space:this.host._space,sp:r},beforeWalls:n.walls||[],afterWalls:r.walls||[],artifact:m.wallGeometry}}}_rszAcceptPreview(t,e){if(this.host._cfgEpoch++,!t||!e)return;const s=te(e);if(!s)return;const i=`${this.host._space}|${this.host._cfgEpoch}|${t.sp.rooms.length}`;Object.defineProperty(s,"sourceFingerprint",{value:Lt([t.sp,this.host._cellCm,this.host._gridPitch]),enumerable:!1});const o={key:i,value:s};th(this.host._wallUnionPool,i,o,8),this.host._wallUnionCache=o}_rszSpaceCandidateGeometry(t,e){if(!this.host._serverCfg)return{ok:!1,wallGeometry:null};const s={...this.host._serverCfg,spaces:this.host._serverCfg.spaces.map(s=>s.id===t?e:s)};let i=null;try{return{ok:this.host._checkSpacePhysicalGeometry(s,t,t=>{i=t}).ok,wallGeometry:i}}catch{return{ok:!1,wallGeometry:null}}}_rszSpaceCandidateRenderable(t,e){if(!this.host._serverCfg)return!1;try{const s={...this.host._serverCfg,spaces:this.host._serverCfg.spaces.map(s=>s.id===t?e:s)};return this.host._checkSpacePhysicalGeometry(s,t).ok}catch{return!1}}_rszCandidateRenderable(t){return!!t&&t.space===this.host._space&&this._rszSpaceCandidateRenderable(t.space,t.sp)}_rszEdgeDown(t,e,s){if("resize"!==this.host._tool||this.host._resize.dragging)return;t.stopPropagation(),t.preventDefault();const i=this._rszRooms(),o=this._rszResolution(e,s);if(!o.enabled)return void this.host._showToast(this._rszReasonText(o.reason));ih(t);const a=o.plan,n=this._svgPoint(t),r=`${this.host._space}|${this.host._cfgEpoch}|${i.length}`,h=this.host._wallUnionCache?.key===r?this.host._wallUnionCache.value:null,l=this._rszSnapshot();this.host._resize.begin({pointerId:t.pointerId,start:[n[0],n[1]],roomId:e,plan:a,options:this._rszOptsFor(a.a,a.b),rooms:i,openings:this._rszOpenings(),snapshotIdentity:l,before:JSON.parse(l),wallUnionBefore:h})}_rszReasonText(t){return this.host._t(`resize.disabled.${t}`)}_rszDisabledActivate(t,e){t.stopPropagation(),t.preventDefault(),this.host._showToast(this._rszReasonText(e))}_rszDisabledKey(t,e){"Enter"!==t.key&&" "!==t.key||this._rszDisabledActivate(t,e)}_rszMove(t){if(!this.host._resize.ownsPointer(t.pointerId))return;t.stopPropagation();const e=this._svgPoint(t),s=this.host._resize.move({pointerId:t.pointerId,point:[e[0],e[1]],step:this.host._gridPitch,snap:t=>{const e=this._snap(t);return[e[0],e[1]]},project:(t,e,s,i,o)=>this._rszProjectPreview(t,e,s,i,o),publish:(t,e)=>this._rszAcceptPreview(t,e),measure:(t,e)=>this._rszEdgeLabels(t,e)});if("rejected"===s.kind)return s.notify&&this.host._showToast(this.host._rszLimitViolation?`${this.host._t("resize.limit_stopped")} — `+this._junctionLimitLabel(this.host._rszLimitViolation):this.host._t("resize.preview_failed")),void this.host.requestUpdate();"accepted"===s.kind&&this.host.requestUpdate()}_rszUp(t){if(!this.host._resize.ownsPointer(t.pointerId))return;t.stopPropagation();const e=this.host._resize.finish({pointerId:t.pointerId,currentSnapshotIdentity:this._rszSnapshot(),validatePreview:t=>this._rszCandidateRenderable(t)});if("no-op"===e.kind)return this.host._cfgEpoch++,void this.host.requestUpdate();if("rejected"===e.kind)return this.host._cfgEpoch++,this.host._showToast(this.host._t("resize.commit_failed")),void this.host.requestUpdate();const s=e.preview,i=this.host._serverCfg?.spaces.find(t=>t.id===s.space);i&&(i.rooms=s.sp.rooms,i.openings=s.sp.openings,Array.isArray(s.sp.walls)&&(s.sp.walls.length?i.walls=s.sp.walls:delete i.walls),Array.isArray(s.sp.wall_segments)&&(i.wall_segments=s.sp.wall_segments)),this.host._suppressClick=!0,setTimeout(()=>this.host._suppressClick=!1,0),this._commitPhysicalGeometry(this.host._t("history.resize_room"),e.before),this.host.requestUpdate()}_rszCancelDrag(t){const e=this.host._resize.cancel(this._rszSnapshot(),t);if("no-op"!==e.kind){if(this.host._cfgEpoch++,e.restoreWallUnion){const t=this.host._spaceModel();if(t){const s=`${this.host._space}|${this.host._cfgEpoch}|${t.rooms.length}`,i={key:s,value:e.restoreWallUnion};th(this.host._wallUnionPool,s,i,8),this.host._wallUnionCache=i}}this.host.requestUpdate()}}_rszPointerCancel(t){this.host._resize.ownsPointer(t.pointerId)&&(t.stopPropagation(),this._rszCancelDrag(t.pointerId))}_rszEdgeLabels(t,e,s=this.host._resize.rooms){const i=s,o=[],a=t.polys[e.roomId]||i?.find(t=>t.id===e.roomId).poly;if(!a||!i)return o;const n=a.length,r=this._rszInnerSpanCms(e.roomId,a,t.polys);for(const t of function(t,e){const s=t.length;return[(e-1+s)%s,(e+1)%s]}(a,e.edge)){const e=a[t],s=a[(t+1)%n],i=r?.[t];o.push({kind:"length",x:(e[0]+s[0])/2,y:(e[1]+s[1])/2,text:null==i?this.host._fmtLen(e,s):ee(i,"mi"===this.host.hass?.config?.unit_system?.length),edge:{a:[e[0],e[1]],b:[s[0],s[1]]}})}const h="mi"===this.host.hass?.config?.unit_system?.length,l=e.roomIds,c=this.host._spaceWalls,d=this.host._physicalBodiesR(),p=this.host._baseVb(),_=this.host._view&&this.host._view.w>0&&this.host._view.h>0?this.host._view:{x:p[0],y:p[1],w:p[2],h:p[3]},[u,m]=this.host._lastValidStageSize||[_.w,_.h],g={..._,stageWidth:Math.max(1,u),stageHeight:Math.max(1,m)},f=this.host._spaceModel(),b=this.host._config?.icon_size??2.5,v=f?se(b>8?2.5:b,f,_.w,this.host._kiosk?this.host._kioskScale.icon:1)*g.stageWidth/100:24,y=Math.max(10,.77*v),$=this.host._t("room.settings_short"),w=y*(1.457+.66*Math.max(1,$.length)*.42);for(const s of l){const a=t.polys[s]||i.find(t=>t.id===s).poly,n=c.length&&f&&this.host._innerRoomContour(f,s)||a,r=d.length?ie(oe(n,d))*Math.pow(this.host._cellCm/this.host._gridPitch,2)/1e4:ae(n,this.host._gridPitch,this.host._cellCm),l=ne(r,h),p=Bo({poly:a,edge:e.edgeByRoom[s],text:l,view:g,gearCenter:re(a),gearWidthPx:w,gearHeightPx:y});o.push({kind:"area",roomId:s,x:p.anchor[0],y:p.anchor[1],text:l,placement:p})}return o}_rszInnerSpanCms(t,e,s){const i=Object.keys(s).length?Object.entries(s).map(([t,e])=>({id:t,poly:e})):this.host._spaceModel()?.rooms;if(!i?.length)return null;const o=this.host._spaceWalls;if(!o.length)return null;const a=this.host._openCuts(),n=he(i,t,o,a,this.host._wallKeyPitch,this.host._cellCm,this.host._gridPitch,eh);if(!n||n.length!==e.length)return null;const r=this.host._cellCm/this.host._gridPitch;return e.map((t,s)=>le(e,s,n)*r)}_renderResizeMeasurements(){const t=this.host._resize.liveLabels;if(!t?.length)return a;const e=t.filter(t=>"length"===t.kind),s=t.filter(t=>"area"===t.kind);return ce``}_renderResizeLayer(t){const e=Math.max(.013*t.w,5),s=e/2,i=t=>t.toFixed(1),o=`M ${i(-.7*s)} 0 H ${i(.7*s)} M 0 ${i(-.22*s)} V ${i(-s)} M ${i(-.32*s)} ${i(-.6*s)} L 0 ${i(-s)} L ${i(.32*s)} ${i(-.6*s)} M 0 ${i(.22*s)} V ${i(s)} M ${i(-.32*s)} ${i(.6*s)} L 0 ${i(s)} L ${i(.32*s)} ${i(.6*s)}`,a=[],n=this._rszRooms(),r=this.host._resize.snapshotIdentity||this._rszSnapshot();for(const t of n)for(let s=0;sthis._rszEdgeDown(e,t.id,s)} + @pointermove=${t=>this._rszMove(t)} + @pointerup=${t=>this._rszUp(t)} + @pointercancel=${t=>this._rszPointerCancel(t)} + @lostpointercapture=${t=>this._rszPointerCancel(t)} + @click=${_?t=>this._rszDisabledActivate(t,p.reason):null} + @keydown=${_?t=>this._rszDisabledKey(t,p.reason):null}> + ${u} + `),a.push(ce``)}return ce`${a}`}_partitionOpeningCuts(t=this.host._spaceModel(),e=()=>!0){if(!t)return[];const s=this.host._curSpaceCfg?.id===t.id?this.host._curSpaceCfg:null,i=de(s,t,this.host._cellCm,this.host._gridPitch,eh);return pe(i,e)}_decorSnapGeometry(t){const e=this.host._spaceModel();if(!e)return{points:[],segments:[]};const s=t||"",i=this.host._decorSnapCache;if(i&&i.epoch===this.host._cfgEpoch&&i.space===this.host._space&&i.height===this.host._decorH&&i.exclude===s)return i.geometry;const o=[];for(const e of this.host._decorList)if(e.id!==t)if("line"===e.kind){const t=[e.x1*eh,e.y1*this.host._decorH],s=[e.x2*eh,e.y2*this.host._decorH];o.push({points:[t,s,[(t[0]+s[0])/2,(t[1]+s[1])/2]],segments:[{a:t,b:s}]})}else if("text"===e.kind)o.push({points:[[e.x*eh,e.y*this.host._decorH]],segments:[]});else{const t=this.host._decorBoxOf(e);t&&o.push(_e(t))}for(const t of e.rooms){const e=R(t);e?.length&&o.push({points:e.flatMap((t,s)=>{const i=e[(s+1)%e.length];return[t,[(t[0]+i[0])/2,(t[1]+i[1])/2]]}),segments:e.map((t,s)=>({a:t,b:e[(s+1)%e.length]}))})}const a=ue(o);return this.host._decorSnapCache={epoch:this.host._cfgEpoch,space:this.host._space,height:this.host._decorH,exclude:s,geometry:a},a}_decorSnap(t,e="mouse",s){const i=this.host._stageEl,o=this.host._viewOr(this.host._baseVb()),a="touch"===e||"pen"===e?14:8,n=i?o.w/Math.max(1,i.clientWidth)*a:this.host._gridPitch;return me(t,this._decorSnapGeometry(s),n,t=>this._snap(t)).point}_replaceDecor(t,e){const s=this.host._curSpaceCfg;s&&(s.decor=this.host._decorList.map(s=>s.id===t?{...s,...e}:s),this.host.requestUpdate())}_cancelDecorGesture(){const t=this.host._decorMove?.before||this.host._dtDrag?.before||this.host._bdDrag?.before,e=t&&this.host._serverCfg?.spaces.find(e=>e.id===t.spaceId);if(t&&e){const s=t=>JSON.parse(JSON.stringify(t));void 0!==t.decor?e.decor=s(t.decor):delete e.decor;for(const t of["plan_x","plan_y","plan_scale","plan_scale_x","plan_scale_y","plan_angle"])delete e[t];Object.assign(e,s(t.plan_transform||{})),this.host._cfgEpoch++}this.host._decorMove=null,this.host._dtDrag=null,this.host._bdDrag=null,this.host.requestUpdate()}_decorPointerDown(t){const e=this.host._decorTool;if("select"===e||"erase"===e?t.target.closest?.(".dshape"):null)return!0;if("line"===e||"rect"===e||"ellipse"===e){t.preventDefault();const s=this._decorSnap(this._svgPoint(t),t.pointerType);return this.host._decorDraft={kind:e,a:s,b:s,pid:t.pointerId},ih(t),!0}if("text"===e){const e=this._decorSnap(this._svgPoint(t),t.pointerType);return this.host._decorTextDialog={x:fe(e[0]/eh),y:fe(e[1]/this.host._decorH),text:"",color:this.host._decorStyle.color,opacity:this.host._decorStyle.opacity,angle:"0",sizeCm:ge(ct,this.host._cellCm,this.host._gridPitch)},this.host._decorTextSelection={start:0,end:0},!0}if("furniture"===e)return!!this.host._furnPalette&&(t.preventDefault(),this._furnPlace(this._svgPoint(t),t.shiftKey),!0);if("select"===e&&(this.host._decorSel=null),this.host._bdMovable){const e=this.host._bdRect,s=this._svgPoint(t),i=e.x+e.w/2,o=e.y+e.h/2,a=-be(e.angle)*Math.PI/180,n=s[0]-i,r=s[1]-o,h=[i+n*Math.cos(a)-r*Math.sin(a),o+n*Math.sin(a)+r*Math.cos(a)];if(h[0]>=e.x&&h[0]<=e.x+e.w&&h[1]>=e.y&&h[1]<=e.y+e.h)return t.preventDefault(),this._bdStart(t)}return!1}_decorCommitDraft(){const t=this.host._decorDraft;if(this.host._decorDraft=null,!t)return;const e=.5*this.host._gridPitch;if(!ve(t.kind,t.a,t.b,e))return;const s=eh,i=this.host._decorH,o=this.host._decorStyle,a=this._geometrySnapshot(),n="dc"+Date.now().toString(36)+Math.random().toString(36).slice(2,5),r=fe;let h;if("line"===t.kind)h={id:n,kind:"line",x1:r(t.a[0]/s),y1:r(t.a[1]/i),x2:r(t.b[0]/s),y2:r(t.b[1]/i),...ye(o,!1)};else{const e=r(Math.min(t.a[0],t.b[0])/s),a=r(Math.min(t.a[1],t.b[1])/i),l=Math.abs(t.b[0]-t.a[0])/s,c=Math.abs(t.b[1]-t.a[1])/i;h={id:n,kind:t.kind,x:e,y:a,w:l,h:c,...ye(o,!0)}}this.host._curSpaceCfg.decor=[...this.host._decorList,h],this.host._decorSel=n,this._recordGeometry(this.host._t("history.decor_add"),a),this._saveConfig(),this.host.requestUpdate()}_decorShapeDown(t,e){if("decor"!==this.host._mode)return;const s=this.host._decorTool;if("text"===s){if("text"!==e.kind)return;return t.stopPropagation(),t.preventDefault(),void this._decorOpenText(e)}"select"!==s&&"erase"!==s||(t.stopPropagation(),t.preventDefault(),"erase"!==s?(this.host._decorSel=e.id,this.host._decorMove={id:e.id,start:this._svgPoint(t),orig:JSON.parse(JSON.stringify(e)),pid:t.pointerId,moved:!1,before:this._geometrySnapshot()},ih(t)):this.host._decorEraseConfirm={id:e.id,kind:e.kind})}_decorMoveUpdate(t){const e=this.host._decorMove;if("furniture"===e.orig?.kind)return void this._furnMoveUpdate(t);const s=this._svgPoint(t),i=e.orig,o=("line"===i.kind?i.x1:i.x)*eh,a=("line"===i.kind?i.y1:i.y)*this.host._decorH,n=this._decorSnap([o+(s[0]-e.start[0]),a+(s[1]-e.start[1])],t.pointerType,e.id);let r=(n[0]-o)/eh,h=(n[1]-a)/this.host._decorH;const l=e.orig,c="line"===l.kind?Math.min(l.x1,l.x2):l.x,d="line"===l.kind?Math.min(l.y1,l.y2):l.y,p="line"===l.kind?Math.abs(l.x2-l.x1):l.w||0,_="line"===l.kind?Math.abs(l.y2-l.y1):l.h||0,u=Xt;r=Math.max(-u-c,Math.min(u-c-p,r)),h=Math.max(-u-d,Math.min(u-d-_,h)),(r||h)&&(e.moved=!0);this.host._curSpaceCfg.decor=this.host._decorList.map(t=>{if(t.id!==e.id)return t;const s=e.orig;return"line"===t.kind?{...t,x1:s.x1+r,y1:s.y1+h,x2:s.x2+r,y2:s.y2+h}:{...t,x:s.x+r,y:s.y+h}}),this.host.requestUpdate()}_decorShapeDbl(t,e){"decor"===this.host._mode&&"select"===this.host._decorTool&&(t.preventDefault(),t.stopPropagation(),this.host._decorMove=null,this.host._decorSel=e.id,this._openDecorProperties(e))}_openDecorProperties(t){if("decor"!==this.host._mode||"select"!==this.host._decorTool)return;if("text"===t.kind)return void this._decorOpenText(t);if(!["line","rect","ellipse","furniture"].includes(t.kind))return;const e=this.host._decorResolvedStyle(t),s="line"===t.kind?t:null,i=this.host._decorBoxOf(t);this.host._decorShapeDialog={id:t.id,kind:t.kind,color:e.color,opacity:e.opacity,widthCm:e.widthCm,angle:this.host._angleField(be(s?$e([s.x1*eh,s.y1*this.host._decorH],[s.x2*eh,s.y2*this.host._decorH]):t.angle)),...s?{lengthCm:ge(Math.hypot((s.x2-s.x1)*eh,(s.y2-s.y1)*this.host._decorH),this.host._cellCm,this.host._gridPitch),lineStyle:"dashed"===s.line_style?"dashed":"solid"}:{},...i?{sizeWCm:ge(i.w,this.host._cellCm,this.host._gridPitch),sizeHCm:ge(i.h,this.host._cellCm,this.host._gridPitch)}:{},..."furniture"===t.kind?{symbol:t.symbol}:{},..."rect"===t.kind||"ellipse"===t.kind?{fill:e.fill,fillColor:e.fillColor,fillOpacity:e.fillOpacity}:{}}}_decorOpenText(t){if("text"!==t.kind)return;let e=String(t.text??"");const s=[...e.matchAll(/\{([^{}\r\n]+)\}/g)].some(t=>!!pt(t[1])),i=String(t.unit??"").trim(),o="state"===String(t.attr??"").trim().toLowerCase()?null:t.attr,a=s||i?"":_t(t.entity,o),n=!(!String(t.entity??"").trim()||s||a&&!i);if(a&&!n){const t=e.indexOf("{}");e=t>=0?e.slice(0,t)+a+e.slice(t+2):`${e}${e?" ":""}${a}`}this.host._decorTextDialog={id:t.id,x:t.x,y:t.y,text:e,color:h(t.color,this.host._decorStyle.color),opacity:we(t.opacity,this.host._decorStyle.opacity),angle:this.host._angleField(t.angle),sizeCm:this.host._decorTextSizeCm(t),pickerEntity:t.entity||"",preserveLegacy:n||void 0},this.host._decorTextSelection={start:e.length,end:e.length}}_decorRememberTextSelection(t){this.host._decorTextSelection={start:t.selectionStart??t.value.length,end:t.selectionEnd??t.value.length}}_decorInsertLiveVariable(t){const e=this.host._decorTextDialog;if(!e)return;const s=_t(e.pickerEntity,t);if(!s)return;const i=e.text,o=Math.max(0,Math.min(i.length,this.host._decorTextSelection.start)),a=Math.max(o,Math.min(i.length,this.host._decorTextSelection.end));if(i.length-(a-o)+s.length>200)return;const n=i.slice(0,o)+s+i.slice(a),r=o+s.length;this.host._decorTextSelection={start:r,end:r},this.host._decorTextDialog={...e,text:n,preserveLegacy:void 0},this.host.updateComplete.then(()=>{const t=this.host.renderRoot.querySelector("textarea.dtarea");t&&(t.focus(),t.setSelectionRange(r,r))})}_decorSaveText(){const t=this.host._decorTextDialog,e=String(t?.text??"").replace(/\r\n?/g,"\n").trim();if(!t||!e)return void(this.host._decorTextDialog=null);const s=this._geometrySnapshot(),i=this.host._curSpaceCfg,o={color:t.color,opacity:we(t.opacity),size_cm:Number(Math.max(.1,Math.min(Xr,t.sizeCm)).toFixed(4)),...be(t.angle)?{angle:be(t.angle)}:{}};if(t.id)i.decor=this.host._decorList.map(s=>{if(s.id!==t.id)return s;if("text"!==s.kind)return s;if(t.preserveLegacy){const{angle:t,size:i,scale:a,...n}=s;return{...n,text:e,...o}}const{entity:i,attr:a,unit:n,...r}=s,{angle:h,size:l,scale:c,...d}=r;return{...d,text:e,...o}});else{const s="dc"+Date.now().toString(36)+Math.random().toString(36).slice(2,5);i.decor=[...this.host._decorList,{id:s,kind:"text",x:t.x,y:t.y,text:e,...o}],this.host._decorSel=s}this.host._decorTextDialog=null,this._recordGeometry(this.host._t(t.id?"history.decor_edit":"history.decor_add"),s),this._saveConfig(),this.host.requestUpdate()}_decorSaveShape(){const t=this.host._decorShapeDialog;if(!t)return;const e=this._geometrySnapshot(),s={color:t.color,opacity:we(t.opacity),widthCm:Math.max(.1,Math.min(100,Number(t.widthCm)||.1)),fill:!!t.fill,fillColor:t.fillColor||t.color,fillOpacity:we(t.fillOpacity,.25)};this.host._curSpaceCfg.decor=this.host._decorList.map(e=>{if(e.id!==t.id)return e;const i="rect"===t.kind||"ellipse"===t.kind,o=ye(s,i);if("line"===e.kind){const s=(e.x1+e.x2)/2*eh,i=(e.y1+e.y2)/2*this.host._decorH,a=ke(Math.max(.1,Number(t.lengthCm)||.1),this.host._cellCm,this.host._gridPitch),n=be(t.angle)*Math.PI/180,r=Math.cos(n)*a/2,h=Math.sin(n)*a/2,l=this._snap([s-r,i-h]),c=this._snap([s+r,i+h]),{width:d,line_style:p,..._}=e;return{..._,...o,x1:fe(l[0]/eh),y1:fe(l[1]/this.host._decorH),x2:fe(c[0]/eh),y2:fe(c[1]/this.host._decorH),..."dashed"===t.lineStyle?{line_style:"dashed"}:{}}}if("rect"===e.kind||"ellipse"===e.kind||"furniture"===e.kind){const s=e.w*eh,i=e.h*this.host._decorH,a=Math.max(this.host._gridPitch,zt(ke(Number(t.sizeWCm),this.host._cellCm,this.host._gridPitch),this.host._gridPitch)),n=Math.max(this.host._gridPitch,zt(ke(Number(t.sizeHCm),this.host._cellCm,this.host._gridPitch),this.host._gridPitch)),r=e.x*eh+s/2,h=e.y*this.host._decorH+i/2,l=be(t.angle),c=xe({x:r-a/2,y:h-n/2},l,t=>this._snap(t)),{width:d,angle:p,..._}=e;return{..._,...o,x:fe(c[0]/eh),y:fe(c[1]/this.host._decorH),w:a/eh,h:n/this.host._decorH,..."furniture"===e.kind&&t.symbol?{symbol:t.symbol}:{},...l?{angle:l}:{}}}return e}),this.host._decorStyle={...s,fill:"rect"===t.kind||"ellipse"===t.kind?s.fill:this.host._decorStyle.fill,fillColor:"rect"===t.kind||"ellipse"===t.kind?s.fillColor:this.host._decorStyle.fillColor,fillOpacity:"rect"===t.kind||"ellipse"===t.kind?s.fillOpacity:this.host._decorStyle.fillOpacity},this.host._decorShapeDialog=null,this._recordGeometry(this.host._t("history.decor_edit"),e),this._saveConfig(),this.host.requestUpdate()}_dtPivot(t){return"line"===t.kind?[(t.x1+t.x2)/2*eh,(t.y1+t.y2)/2*this.host._decorH]:"furniture"===t.kind||"rect"===t.kind||"ellipse"===t.kind?[(t.x+t.w/2)*eh,(t.y+t.h/2)*this.host._decorH]:[t.x*eh,t.y*this.host._decorH]}_dtApply(t,e){const s=this.host._curSpaceCfg;s&&(s.decor=this.host._decorList.map(s=>{if(s.id!==t)return s;const i={...s};"text"===s.kind&&void 0!==e.textSizeCm&&(delete i.size,delete i.scale);const o={...i};return void 0!==e.textSizeCm&&(o.size_cm=Number(Math.max(.1,Math.min(Xr,e.textSizeCm)).toFixed(4))),void 0!==e.angle&&(e.angle?o.angle=Number(e.angle.toFixed(2)):delete o.angle),o}),this.host._cfgEpoch++,this.host.requestUpdate())}_dtStart(t,e,s,i){const o=this.host._dtSel;if(!o)return;t.stopPropagation(),t.preventDefault();const[a,n]=this._dtPivot(o),r=this._svgPoint(t),h=this.host._decorBoxOf(o);this.host._dtDrag={id:o.id,kind:e,pid:t.pointerId,ax:a,ay:n,r0:Math.hypot(r[0]-a,r[1]-n),a0:180*Math.atan2(r[1]-n,r[0]-a)/Math.PI,textSizeCm0:"text"===o.kind?this.host._decorTextSizeCm(o):1,angle0:"line"===o.kind?0:Number(o.angle)||0,sgx:s?.[0],sgy:s?.[1],orig:h||void 0,origShape:JSON.parse(JSON.stringify(o)),before:this._geometrySnapshot(),lineEnd:i,moved:!1},ih(t)}_dtMove(t){const e=this.host._dtDrag;if(!e)return;const s=this._svgPoint(t);if(void 0!==e.lineEnd&&"line"===e.origShape.kind){const i=this._decorSnap(s,t.pointerType,e.id),o=fe(i[0]/eh),a=fe(i[1]/this.host._decorH),n=e.origShape,r=0===e.lineEnd?n.x1:n.x2,h=0===e.lineEnd?n.y1:n.y2;return(Math.abs(o-r)>1e-9||Math.abs(a-h)>1e-9)&&(e.moved=!0),void this._replaceDecor(e.id,0===e.lineEnd?{x1:o,y1:a}:{x2:o,y2:a})}if("scale"===e.kind&&e.orig){const i=Me(e.orig,e.sgx??1,e.sgy??1,s[0],s[1],!t.shiftKey,this.host._gridPitch,this.host._gridPitch),o=Math.abs(i.x-e.orig.x)>1e-6||Math.abs(i.y-e.orig.y)>1e-6||Math.abs(i.w-e.orig.w)>1e-6||Math.abs(i.h-e.orig.h)>1e-6;if(!o&&!e.moved)return;return e.moved||=o,void this._decorApplyBox(e.id,i)}if("scale"===e.kind){const t=Math.hypot(s[0]-e.ax,s[1]-e.ay);if(e.r0<1e-6)return;const i=Math.max(.1,Math.min(Xr,e.textSizeCm0*(t/e.r0))),o=Math.abs(i-e.textSizeCm0)>1e-6;if(!o&&!e.moved)return;return e.moved||=o,void this._dtApply(e.id,{textSizeCm:i})}const i=180*Math.atan2(s[1]-e.ay,s[0]-e.ax)/Math.PI;let o=e.angle0+(i-e.a0);t.shiftKey||(o=5*Math.round(o/5)),o=(o%360+360)%360,o>180&&(o-=360);const a=Math.abs(o-e.angle0)>1e-6;(a||e.moved)&&(e.moved||=a,this._dtApply(e.id,{angle:o}))}_dtUp(){const t=this.host._dtDrag;this.host._dtDrag=null,t?.moved&&(this._recordGeometry(this.host._t("history.decor_transform"),t.before),this._saveConfig()),this.host.requestUpdate()}_dtMeasure(){const t=this.host._dtSel;if(!t)return void(this.host._dtBox&&(this.host._dtBox=null,this.host.requestUpdate()));let e;if("line"===t.kind){const s=t.x1*eh,i=t.y1*this.host._decorH,o=t.x2*eh,a=t.y2*this.host._decorH;e={id:t.id,x:Math.min(s,o),y:Math.min(i,a),w:Math.abs(o-s),h:Math.abs(a-i)}}else if("furniture"===t.kind||"rect"===t.kind||"ellipse"===t.kind)e={id:t.id,x:t.x*eh,y:t.y*this.host._decorH,w:t.w*eh,h:t.h*this.host._decorH};else{const s=this.host.renderRoot.querySelector(`text.dtext[data-id="${t.id}"]`);if(!s||"function"!=typeof s.getBBox)return;let i;try{i=s.getBBox()}catch{return}if(!i||!i.width&&!i.height)return;e={id:t.id,x:i.x,y:i.y,w:i.width,h:i.height}}const s=this.host._dtBox;s&&s.id===e.id&&Math.abs(s.x-e.x)<.01&&Math.abs(s.y-e.y)<.01&&Math.abs(s.w-e.w)<.01&&Math.abs(s.h-e.h)<.01||(this.host._dtBox=e,this.host.requestUpdate())}_deleteDecor(t){if(!this.host._decorList.some(e=>e.id===t))return;const e=this._geometrySnapshot();this.host._curSpaceCfg.decor=this.host._decorList.filter(e=>e.id!==t),this.host._decorSel===t&&(this.host._decorSel=null),this._recordGeometry(this.host._t("history.decor_delete"),e),this._saveConfig(),this.host.requestUpdate()}_decorDeleteSel(){this.host._decorSel&&this._deleteDecor(this.host._decorSel)}_confirmDecorErase(){const t=this.host._decorEraseConfirm;this.host._decorEraseConfirm=null,t&&this._deleteDecor(t.id)}_furnFieldValue(t){return Math.round(100*(this.host._imperial?t/30.48:t/100))/100}_furnFieldToCm(t){return Se(this.host._imperial?30.48*t:100*t)}_furnPick(t){const e=Ce(t);this.host._furnPalette={symbol:t,w:e.w,h:e.h}}_furnPlace(t,e=!1){const s=this.host._furnPalette,i=this.host._curSpaceCfg;if(!s||!i)return;const o=eh,a=this.host._decorH,n=De(Pe(s.w,this.host._cellCm,this.host._gridPitch,o)),r=De(Pe(s.h,this.host._cellCm,this.host._gridPitch,o)),h=this._geometrySnapshot(),l=this._decorSnap(t);let c=l[0],d=l[1],p=0;const _=e?null:Ie(c,d,r*a,this.host._furnWalls,this.host._furnWallReach,this.host._gridPitch);_&&(c=_.cx,d=_.cy,p=_.angle);const u="df"+Date.now().toString(36)+Math.random().toString(36).slice(2,5),m={id:u,kind:"furniture",symbol:s.symbol,x:fe(c/o-n/2),y:fe(d/a-r/2),w:n,h:r,...ye(this.host._decorStyle,!1)};p&&(m.angle=Number(p.toFixed(2))),i.decor=[...this.host._decorList,m],this.host._decorSel=u,this.host._decorTool="select",this.host._furnPalette=null,this.host._furnCategory=null,this._recordGeometry(this.host._t("history.decor_add"),h),this._saveConfig(),this.host.requestUpdate()}_furnMoveUpdate(t){const e=this.host._decorMove;if("furniture"!==e.orig.kind)return;const s=e.orig,i=this.host._curSpaceCfg;if(!i)return;const o=eh,a=this.host._decorH,n=this._svgPoint(t),r=(s.x+s.w/2)*o+(n[0]-e.start[0]),h=(s.y+s.h/2)*a+(n[1]-e.start[1]);let l,c,d=Number(s.angle)||0;const p=t.shiftKey?null:Ie(r,h,s.h*a,this.host._furnWalls,this.host._furnWallReach,this.host._gridPitch);if(p)l=p.cx/o-s.w/2,c=p.cy/a-s.h/2,d=p.angle;else{const i=this._decorSnap([r-s.w/2*o,h-s.h/2*a],t.pointerType,e.id);l=i[0]/o,c=i[1]/a}l=fe(l),c=fe(c),(Math.abs(l-s.x)>1e-9||Math.abs(c-s.y)>1e-9||Math.abs(d-(Number(s.angle)||0))>1e-9)&&(e.moved=!0),i.decor=this.host._decorList.map(t=>{if(t.id!==e.id)return t;const s={...t,x:l,y:c};return d?s.angle=Number(d.toFixed(2)):delete s.angle,s}),this.host.requestUpdate()}_decorApplyBox(t,e){const s=this.host._curSpaceCfg;if(!s)return;const i=eh,o=this.host._decorH;s.decor=this.host._decorList.map(s=>{if(s.id!==t)return s;const a=xe(e,s.angle,t=>this._snap(t));return{...s,x:fe(a[0]/i),y:fe(a[1]/o),w:Math.max(this.host._gridPitch/i,Math.min(2*Xt,e.w/i)),h:Math.max(this.host._gridPitch/o,Math.min(2*Xt,e.h/o))}}),this.host._cfgEpoch++,this.host.requestUpdate()}_renderFurnPalette(){const t=this.host._furnPalette,e=this.host._furnCategory,s=Te.flatMap(t=>Re(t)),i=Wo.filter(t=>s.some(e=>e.category===t.id)),a=i.find(t=>t.id===e)||null,n=a?s.filter(t=>t.category===a.id):[],r=this.host._t(this.host._imperial?"gs.unit_ft":"gs.unit_m");return o`
t.stopPropagation()}> +
+ ${this.host._t("furn.title")} + + +
+
+ ${a?o` + +
+ ${this.host._t(`furn.cat_${a.id}`)} +
+
+ ${n.map(e=>o``)} +
+ `:Te.map(t=>o` +
${this.host._t(`furn.group_${t}`)}
+
+ ${i.filter(e=>e.group===t).map(t=>o``)} +
`)} +
+ ${t?o`
+ + this.host._furnPalette={...t,w:this._furnFieldToCm(Number(e.target.value))}} /> + + this.host._furnPalette={...t,h:this._furnFieldToCm(Number(e.target.value))}} /> + ${this.host._t("furn.place_hint")} +
`:o`
${this.host._t("furn.pick_hint")}
`} +
`}_openBackdropDialog(t){if(!this.host._bdMovable||!this.host._bdRect)return;t?.preventDefault(),t?.stopPropagation(),this.host._bdDrag=null;const e=this.host._bdRect;this.host._backdropDialog={widthCm:ge(e.w,this.host._cellCm,this.host._gridPitch),heightCm:ge(e.h,this.host._cellCm,this.host._gridPitch),angle:this.host._angleField(e.angle)}}_saveBackdropDialog(){const t=this.host._backdropDialog,e=this.host._bdBase,s=this.host._bdRect;if(!t||!e||!s)return;const i=be(t.angle),o=this._geometrySnapshot(),a=Math.min(e.w*lt,Math.max(e.w*ht,zt(ke(t.widthCm,this.host._cellCm,this.host._gridPitch),this.host._gridPitch))),n=Math.min(e.h*lt,Math.max(e.h*ht,zt(ke(t.heightCm,this.host._cellCm,this.host._gridPitch),this.host._gridPitch))),r=s.x+s.w/2,h=s.y+s.h/2,l=xe({x:r-a/2,y:h-n/2},i,t=>this._snap(t));this._bdApply((l[0]-e.x)/eh,(l[1]-e.y)/eh,a/e.w,n/e.h,i),this.host._backdropDialog=null,this._recordGeometry(this.host._t("history.backdrop_transform"),o),this._saveConfig()}_bdApply(t,e,s,i,o){const a=this.host._curSpaceCfg;if(!a)return;a.plan_x=Number(fe(t).toFixed(6)),a.plan_y=Number(fe(e).toFixed(6)),delete a.plan_scale,a.plan_scale_x=Number(Math.min(lt,Math.max(ht,s)).toFixed(6)),a.plan_scale_y=Number(Math.min(lt,Math.max(ht,i)).toFixed(6));const n=be(o);n?a.plan_angle=Number(n.toFixed(2)):delete a.plan_angle,this.host._cfgEpoch++,this.host.requestUpdate()}_bdStart(t,e,s=!1){const i=this.host._bdBase,o=this.host._bdRect;if(!i||!o)return!1;const a=this._svgPoint(t),n=e?e[0]:0,r=e?e[1]:0,h=n>0?o.x:o.x+o.w,l=r>0?o.y:o.y+o.h;return this.host._bdDrag={kind:s?"rotate":e?"scale":"move",pid:t.pointerId,sx:a[0],sy:a[1],base:i,p0:this.host._bdParams,fx:h,fy:l,sgx:n,sgy:r,rect0:{x:o.x,y:o.y,w:o.w,h:o.h,angle:o.angle},before:this._geometrySnapshot(),moved:!1},ih(t),!0}_bdMove(t){const e=this.host._bdDrag;if(!e)return;const s=this._svgPoint(t),i=e.base;if("move"===e.kind){const t=e.rect0.x,o=e.rect0.y,a=this._snap([t+(s[0]-e.sx),o+(s[1]-e.sy)]),n=Math.abs(a[0]-t)>1e-9||Math.abs(a[1]-o)>1e-9;if(!n&&!e.moved)return;return e.moved||=n,void this._bdApply((a[0]-i.x)/eh,(a[1]-i.y)/eh,e.p0.sx,e.p0.sy,e.p0.angle)}if("rotate"===e.kind){const i=e.rect0.x+e.rect0.w/2,o=e.rect0.y+e.rect0.h/2,a=180*Math.atan2(e.sy-o,e.sx-i)/Math.PI;let n=e.p0.angle+(180*Math.atan2(s[1]-o,s[0]-i)/Math.PI-a);t.shiftKey||(n=5*Math.round(n/5)),n=be(n);const r=Math.abs(n-e.p0.angle)>1e-9;if(!r&&!e.moved)return;return e.moved||=r,void this._bdApply(e.p0.dx,e.p0.dy,e.p0.sx,e.p0.sy,n)}const o=Me(e.rect0,e.sgx,e.sgy,s[0],s[1],!t.shiftKey,this.host._gridPitch,Math.min(i.w,i.h)*ht),a=o.w/Math.max(1e-9,i.w),n=o.h/Math.max(1e-9,i.h),r=Math.abs(a-e.p0.sx)>1e-9||Math.abs(n-e.p0.sy)>1e-9||Math.abs(o.x-e.rect0.x)>1e-9||Math.abs(o.y-e.rect0.y)>1e-9;if(!r&&!e.moved)return;e.moved||=r;const h=xe(o,e.p0.angle,t=>this._snap(t));this._bdApply((h[0]-i.x)/eh,(h[1]-i.y)/eh,a,n,e.p0.angle)}_bdReset(){const t=this.host._curSpaceCfg;if(!t)return;const e=this._geometrySnapshot();delete t.plan_x,delete t.plan_y,delete t.plan_scale,delete t.plan_scale_x,delete t.plan_scale_y,delete t.plan_angle,this.host._bdDrag=null,this._recordGeometry(this.host._t("history.backdrop_transform"),e),this._saveConfig(),this.host._showToast(this.host._t("decor.backdrop_reset_done")),this.host.requestUpdate()}_bdUp(){const t=this.host._bdDrag;this.host._bdDrag=null,t?.moved&&(this._recordGeometry(this.host._t("history.backdrop_transform"),t.before),this._saveConfig()),this.host.requestUpdate()}_renderBackdropFrame(t){const e=this.host._bdRect;if(!this.host._bdActive||!e)return a;const s=.02*Math.max(t.w,t.h),i=s/4,o=e.x+e.w/2,n=e.y+e.h/2,r=be(e.angle),h=2.2*s;return ce` + + + {t.stopPropagation(),t.preventDefault(),this._bdStart(t,void 0,!0)}}> + + ${[[-1,-1,"nwse"],[1,-1,"nesw"],[1,1,"nwse"],[-1,1,"nesw"]].map(([t,o,a])=>{const n=t<0?e.x:e.x+e.w,r=o<0?e.y:e.y+e.h;return ce`{e.stopPropagation(),e.preventDefault(),this._bdStart(e,[t,o])}}>`})} + `}_renderEditorGroupLauncher(t){return this.host._editorSecondary.renderGroupLauncher(t,this.host._editorToolbarGroups,this.host._editorSecondaryCopy)}_runEditorContext(t,e){this.host._editorSecondary.runContext(t,this.host._editorSecondaryContextId,e)}_renderEditorGroupModel(t){return this.host._editorSecondary.renderGroupModel(t,this.host._editorSecondaryContextId,this.host._editorSecondaryCopy)}_renderDrawWallControl(){const t="column"===this.host._tool?1:0;return o``}_renderPlanSecondary(){const t=this.host._editorSecondaryContextId,e=this.host._physicalSel;if(e){if(!("partition"===e.kind?!!this.host._curSpaceCfg.partitions?.some(t=>t.id===e.id):"column"===e.kind?!!this.host._curSpaceCfg.wall_columns?.some(t=>t.id===e.id):!!this.host._curSpaceCfg.room_drafts?.some(t=>t.id===e.id)))return null;const s="partition"===e.kind?this.host._t("markup.partition"):"column"===e.kind?this.host._t("markup.column"):this.host._t("markup.add");return{contextId:t,kind:"selection",ariaLabel:this.host._t("editor.context_actions",{object:s}),visibleLabel:s,content:o` + + `}}const s="draw"===this.host._tool||"column"===this.host._tool,i="column"===this.host._tool?"markup.hint_column":"resize"===this.host._tool?"markup.hint_resize":"wallthick"===this.host._tool?"markup.hint_wallthick":null,n="draw"===this.host._tool?this.host._t(this.host._path.length?"markup.hint_points":"markup.hint_start",this.host._path.length?{n:this.host._path.length}:void 0):"";if(!s&&!i&&!n)return null;const r="draw"===this.host._tool&&this.host._path.length>0;return{contextId:t,kind:r?"operation":"tool",ariaLabel:this.host._t("editor.tool_options",{tool:this.host._t("draw"===this.host._tool?"markup.add":"column"===this.host._tool?"markup.column":"resize"===this.host._tool?"markup.resize":"markup.wallthick")}),content:o` + ${s?this._renderDrawWallControl():a} + ${n?o`${n}`:a} + ${i?o`${this.host._t(i)}`:a} + ${"draw"===this.host._tool&&this.host._path.length?o``:a}`}}_renderDecorSecondary(){const t=this.host._editorSecondaryContextId;if("furniture"===this.host._decorTool)return{contextId:t,kind:"palette",ariaLabel:this.host._t("editor.palette",{tool:this.host._t("decor.furniture")}),launcherId:"furniture",dismissPolicy:this.host._furnPalette?"stay-open-on-canvas":"outside",dismiss:()=>{"furniture"===this.host._decorTool&&(this.host._furnPalette=null,this.host._furnCategory=null,this.host._decorTool="select",this.host.requestUpdate())},content:this._renderFurnPalette()};const e=this.host._dtSel;if(e){const s=this.host._t(`decor.${e.kind}`);return{contextId:t,kind:"selection",ariaLabel:this.host._t("editor.context_actions",{object:s}),visibleLabel:s,content:o` + + `}}const s="line"===this.host._decorTool||"rect"===this.host._decorTool||"ellipse"===this.host._decorTool,i="rect"===this.host._decorTool||"ellipse"===this.host._decorTool,n="backdrop"===this.host._decorTool&&!!this.host._bdRect;return s||n?{contextId:t,kind:"tool",ariaLabel:this.host._t("editor.tool_options",{tool:this.host._t(s?`decor.${this.host._decorTool}`:"decor.backdrop")}),content:o` + ${s?o` + this.host._decorStyle={...this.host._decorStyle,...t.detail}}> + + ${i?o` + this.host._decorStyle={...this.host._decorStyle,fillColor:t.detail.color,fillOpacity:t.detail.opacity}}>`:a} + `:a} + ${n?o`${this.host._t("decor.backdrop_hint")}`:a}`}:null}_withBackdropReset(t){if(!this.host._bdMoved||this.host._bdDrag||"palette"===t?.kind)return t;const e=this.host._editorSecondaryContextId,s=o``;return t?{...t,kind:"selection"===t.kind?"mixed":t.kind,content:o`${t.content}${s}`}:{contextId:e,kind:"tool",ariaLabel:this.host._t("editor.tool_options",{tool:this.host._t("decor.backdrop")}),content:s}}_renderEditorSecondary(){if(!this.host._editing)return a;const t=this.host._editorSecondary.activeGroup(this.host._editorToolbarGroups),e=t?this._renderEditorGroupModel(t):"plan"===this.host._mode?this._renderPlanSecondary():"decor"===this.host._mode?this._withBackdropReset(this._renderDecorSecondary()):null;return this.host._editorSecondary.render(e,this.host._editorSecondaryDialogBlocked)}_renderDecorBar(){const t=[["select","mdi:cursor-default-outline","decor.select"],...this.host._bdRect?[["backdrop","mdi:image-move","decor.backdrop"]]:[],["line","mdi:vector-line","decor.line"],["rect","mdi:rectangle-outline","decor.rect"],["ellipse","mdi:ellipse-outline","decor.ellipse"],["text","mdi:format-text","decor.text"],["furniture","mdi:sofa-outline","decor.furniture"],["erase","mdi:eraser","decor.erase"]],e=this.host._geometryHistory.undoName,s=this.host._geometryHistory.redoName;return o`
+
+ ${t.map(([t,e,s])=>o``)} + ${this.host._editorToolbarGroups.map(t=>this._renderEditorGroupLauncher(t))} + + +
+
+ +
+
`}_renderDecorEraseConfirm(){const t=this.host._decorEraseConfirm,e=this.host._t(`decor.${t.kind}`);return o`this.host._decorEraseConfirm=null}> +

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

`:a} + ${d?o`

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

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

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

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

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

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

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

`:a} + ${m?o`

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

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

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

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

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

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

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

`:a} + ${c?o`

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

`:a} + ${g?o`

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

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

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

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

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

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

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

+
+
+ + + + +
+
`}_renderPhysicalDialog(){const t=this.host._physicalDialog,e="column"===t.kind;return o`this.host._physicalDialog=null}> +
+ ${e?o` + `:a} + +
this.host._physicalDialog={...t,cm:e.target.value}} /> + ${this.host._t(this.host._imperial?"wallthick.unit_in":"wallthick.unit_cm")}
+ ${e&&"square"===t.shape?o` + + this.host._physicalDialog={...t,angle:e.target.value}} />`:a} + ${t.length?o`
${this.host._t("physical.length")}: ${t.length}
`:a} +
+ +
`}_renderMarkupBar(){const t=this.host._geometryHistory.undoName,e=this.host._geometryHistory.redoName,s=t?this.host._t("history.undo_named",{name:t}):this.host._t("history.undo_empty"),i=e?this.host._t("history.redo_named",{name:e}):this.host._t("history.redo_empty");return o`
+
+ + + + + + + + + + ${this.host._editorToolbarGroups.map(t=>this._renderEditorGroupLauncher(t))} + + + + +
+
+ +
+
`}_renderDevicesBar(){return o`
+
+ + + + ${this.host._editorToolbarGroups.map(t=>this._renderEditorGroupLauncher(t))} +
+
+ +
+
`}_renderDeviceInbox(){const t=this.host._deviceInbox,e=this._deviceInboxRows(),s=Object.fromEntries(["on_plan","available","hidden","readd"].map(t=>[t,e.filter(e=>e.category===t).length])),i=function(t,e,s,i=!1){const o=s.trim().toLocaleLowerCase();return t.filter(t=>t.category===e&&(!i||t.isNew)&&(!o||t.searchText.includes(o)))}(e,t.tab,t.search,"on_plan"===t.tab&&t.onlyNew),n=i.slice(0,t.limit),r=t=>this.host._t(`device_inbox.tab_${t}`),h=`device_inbox.empty_${t.tab}`;return o`this.host._deviceInbox=null}> +
+
+ this.host._deviceInbox={...t,search:e.target.value,limit:100}} /> + +
+
this._deviceInboxTabKey(t)}> + ${["on_plan","available","hidden","readd"].map(e=>o` + `)} +
+
+ ${"on_plan"===t.tab?o``:a} + ${"available"===t.tab?o``:a} + +
+
+ ${n.length?n.map(t=>{const e="on_plan"===t.category?t.canFind?o``:o``:"hidden"===t.category?o``:o``,s="active"===t.status.kind?"":this.host._t(`device_inbox.status_${t.status.kind}`);return o`
+ +
+
${t.name} + ${t.isNew?o`${this.host._t("device_inbox.new")}`:a} +
+
+ ${[t.model,t.integration,t.spaceName,t.areaName].filter(Boolean).join(" · ")} +
+
+ ${this.host._t(`device_inbox.reason_${t.reason}`)} + ${s?o`${s}`:a} +
+ ${t.binding} +
+
+ ${e} + ${t.canEdit||t.canHide||"available"===t.category||"hidden"===t.category||this.host._bindingHasHaPage(t.binding)?o` +
+ + + +
+ ${t.canEdit&&("on_plan"!==t.category||t.canFind)?o``:a} + ${t.canHide?o``:a} + ${"available"===t.category?o``:a} + ${"hidden"===t.category?o``:a} + ${this.host._bindingHasHaPage(t.binding)?o``:a} +
+
`:a} +
+
`}):o`
${this.host._t(h)}
`} +
+ ${i.length>n.length?o``:a} +
+
+ +
+
`}_markerValueBadgeFields(t){return Qs({touched:t.valueBadgeTouched,originalHas:t.originalHasValueBadge,original:t.originalValueBadge,enabled:t.valueBadgeEnabled,source:t.valueBadgeSource,position:t.valueBadgePosition})}_markerDraft(t){if("ha"===t.bindingMode&&(!t.binding||"virtual"===t.binding))return null;const e=ns(t.room),s=Ze(t.binding,t.devId,()=>"__hp_device_preview__"),i=this.host._markers.find(e=>e.id===s||e.id===t.devId),o=ss(t.binding,t.controls,this.host._bindingEntities(t.binding)),a=this._effectiveStoredTapAction(t),n={id:s,binding:t.binding,name:t.name.trim()||null,icon:t.icon||null,display:"badge"!==t.display?t.display:null,ripple_color:"icon_ripple"===t.display&&t.rippleColor?t.rippleColor:null,ripple_size:"icon_ripple"===t.display&&1.5!==t.rippleSize?t.rippleSize:null,size:1!==t.size?t.size:null,angle:t.angle||null,...this._markerTapActionFields(t),...this._markerToggleEntityFields(t),tap_target:"run"===a&&t.tapTarget||null,tap_confirm:!!t.tapConfirm||null,controls:o.length?o:null,...this._markerLightFields(t),...this._markerValueBadgeFields(t),use_climate_temp:!!t.useClimateTemp||null,glow_radius_cm:(()=>{const e=Qr(t.glowRadius);return null==e||e<=0?null:Math.round(this.host._imperial?30.48*e:100*e)})(),model:t.model.trim()||null,link:t.link.trim()||null,description:t.description.trim()||null,pdfs:t.pdfs,hidden:t.hideFromPlan,vacuum:i?.vacuum||null};return("virtual"===t.binding||t.room)&&(n.space=e?.space||("virtual"===t.binding?this.host._space:null),n.area=e?.area||null,n.room_id=e?.roomId||null),n}_markerPreviewDevice(t){const e=this._markerDraft(t);if(!e)return null;const s=`${this.host._haRegistry.revision}\n${Lt(this.host._markers)}\n${JSON.stringify(e)}`;if(this.host._markerPreviewMemo?.key===s)return this.host._markerPreviewMemo.device;const i=ti({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 ei(t,{single:t=>{if("via"in t&&"virtual-light"===t.via)return this.host._t("marker.virtual_light_target",{name:t.name});const e=t.entityId||("ref"in t?t.ref:""),s=t.name||e;return this.host._t("marker.toggle_hint_single",{name:s,id:e})},group:t=>this.host._t("marker.toggle_hint_group",{count:t.length,names:t.map(t=>`${t.name} (${t.entityId})`).join(", ")}),currentNext:(t,s)=>"virtual-light"===t.via?this.host._t("marker.virtual_light_current",{state:this.host._t("on"===t.state?"marker.virtual_light_state_on":"marker.virtual_light_state_off"),effect:e(s)}):this.host._t("marker.toggle_hint_current",{state:this._toggleStateText(t.entityId,t.state),effect:e(s)}),groupCurrentNext:(t,s)=>this.host._t("marker.toggle_hint_group_current",{on:t.filter(t=>"on"===t.state).length,count:t.length,effect:e(s)}),skipped:t=>this.host._t("marker.toggle_hint_skipped",{count:t.length,targets:t.map(t=>{const e=t.entityId||t.ref;return`${t.name||e} (${e}: ${s(t.reason)})`}).join(", ")}),none:t=>this.host._t(`marker.toggle_none_${t.replaceAll("-","_")}`)})}_effectiveStoredTapAction(t,e){return t.tapActionTouched?t.tapAction:is(t.originalHasTapAction?t.originalTapAction:null,e)}_effectiveMarkerTapAction(t,e=this._markerPreviewDevice(t)){return this._effectiveStoredTapAction(t,e?.primary?.split(".")[0])}_announceToggleDraft(t){const e=this._markerPreviewDevice(t),s=t.tapActionTouched?t:{...t,tapAction:this._effectiveMarkerTapAction(t,e)},i="toggle"===s.tapAction?this._toggleHintLines(this._toggleIntentForDialog(s)).join(" "):"";return{...s,tapHintAnnouncement:i}}_valueBadgeForBinding(t,e){const s={...t,binding:e,valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0},i=this._markerPreviewDevice(s);if(!i)return{valueBadgeEnabled:!1,valueBadgeSource:null,valueBadgeTouched:!0};const o=[...this.host._devices.filter(t=>t.id!==i.id),i],a=ts(this.host._planHass,i,o),n=es(this.host._planHass,i,a);return{valueBadgeEnabled:t.valueBadgeEnabled&&!!n,valueBadgeSource:n,valueBadgeTouched:!0}}_markerSpatialSource(t){const e=this._markerPreviewDevice(t);if(!e)return null;const s={...e,hidden:!1};return si(ii(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&&oi(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&&ai(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 ai(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} ${ai(o).join(" ")}`.toLowerCase()})}const o=Object.keys(this.host.hass.states||{}).filter(e=>ni(e)&&!i.has(e)&&ri(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(hi(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=li(s?this.host._planHass.states[s.eid]:void 0,null,this.host._fillColors.glow_light.c),o=!e.glowColorDrafted,a="fixed"===t&&!e.glowBrightnessDrafted;this.host._markerDialog={...e,glowMode:t,glowColor:o?i.c:e.glowColor,glowBrightness:a?Math.max(1,Math.round(100*i.bri)):e.glowBrightness,glowColorDrafted:!0,glowBrightnessDrafted:e.glowBrightnessDrafted||"fixed"===t,glowTouched:!0}}_renderMarkerDialog(){const t=this.host._markerDialog,e="virtual"===t.bindingMode,s=this._bindingCandidates();this.host._bindingEntities(t.binding);const i=e?null:this.host._bindingStatus(t.binding),n=!e&&this.host._bindingHasHaPage(t.binding),r=this._markerPreviewDevice(t),h=this._effectiveMarkerTapAction(t,r),l=r?ps(this.host._serverCfg?.spaces.find(t=>t.id===r.space)):null,c=r?this._markerPreviewDevices(r):this.host._devices,d="toggle"===h&&r?this._toggleIntent(r,c):null,p=this._toggleHintLines(d),_=r?ci(this.host._planHass,r,{liveStates:!1!==this.host._config?.live_states,showTemperature:!1!==this.host._config?.show_temperature,showSignal:l?.showLqi??!1!==this.host._config?.show_signal,designPreview:!0,activityRuntime:this.host._activityRt.get(r.id),lightDevices:c,registryHass:this.host._fullRegistryHass,reducedMotion:this.host._reducedMotion}):null,u=r?ts(this.host._planHass,r,c):[],m=r?es(this.host._planHass,r,u):null,g=t.valueBadgeTouched?t.valueBadgeEnabled:!!_?.valueBadge,f=t.valueBadgeTouched?t.valueBadgeSource:_?.valueBadge?.source||t.valueBadgeSource,b=t.valueBadgeTouched?t.valueBadgePosition:_?.valueBadge?.position||t.valueBadgePosition,v=di(f),y=!!f&&!u.some(t=>t.key===v),$=u.find(t=>t.key===v),w=_?.valueSource?_.valueSource.attribute?`attr:${_.valueSource.eid}:${_.valueSource.attribute}`:`state:${_.valueSource.eid}`:"",k=this._markerAutoHasSpatialSource(t),x=!!r&&pi(this.host._planHass,{...r}),M=_i(t.lightRole,k,x,t.glowMode),S=!M.sourceExists,C=!M.fromSourceEnabled,D=M.passive,P=M.effectiveMode,I="never"===t.lightRole?this.host._t("marker.glow_disabled_never"):"auto"!==t.lightRole||k?D?this.host._t("marker.glow_passive_hint"):this.host._t("marker.glow_disabled_no_entity"):this.host._t("marker.glow_disabled_auto"),T=r?ai(r):[],R=r&&ui(r)||"",z=!!t.lightEntity&&!T.includes(t.lightEntity),F=r?mi(r):[],A=!!t.toggleEntity&&!F.includes(t.toggleEntity),N="toggle"===h?this._toggleIntentForDialog({...t,toggleEntity:"",toggleEntityTouched:!0}):null,H=N?[...N.targets,...N.skippedTargets].map(t=>t.entityId||("ref"in t?t.ref:"")).filter(Boolean).join(", "):"",O=(()=>{if(e)return null;const i=s.find(e=>e.value===t.binding);if(i)return i.label;const[o,a]=t.binding.split(":");return"device"===o?this.host._fullRegistryHass.devices[a]?.name_by_user||this.host._fullRegistryHass.devices[a]?.name||a:this.host._fullRegistryHass.entities[a]?.name||this.host.hass.states[a]?.attributes?.friendly_name||a})();return o`this._closeMarkerDialog()}> +
+ ${"ha_disabled"===i?.kind?o`
+ + ${this.host._t(`marker.ha_disabled_${i.reason}`)} + ${n?o``:a} +
`:"unverified"===i?.kind&&t.binding?o`
+ + ${this.host._t("marker.ha_registry_limited")} +
`:a} + + this.host._markerDialog={...t,name:e.target.value}} /> + + +
+ +
+ + +
+ ${"ha"===t.bindingMode?o` + ${t.bindingOpen?o`
+ this.host._markerDialog={...t,bindingFilter:e.target.value}} /> +
+ ${s.map(e=>o`
{const s={...t,binding:e.value,bindingOpen:!1,controls:ss(e.value,t.controls,this.host._bindingEntities(e.value)),autoIcon:this.host._autoIconForBinding(e.value)};this.host._markerDialog=this._announceToggleDraft({...s,...this._valueBadgeForBinding(s,e.value)})}}> + ${e.label}${e.sub} +
`)} + ${s.length?a:o`
${this.host._t("marker.nothing_found")}
`} +
+
`:a}`:a} +
+ + + + + ${this._renderVacSection(t)} + + + + ${"toggle"===h&&(F.length>1||A)?o`
+
+ + ${this._help("marker.toggle_entity.help")} +
+ + ${A?o`

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

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

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

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

+ ${I} +

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

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

`:a} + + + +

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

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

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

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

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

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

${$.technical}

`:a} + ${y?o`

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

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

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

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

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

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

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

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

+ ${s} +

`:a} + + this.host._nameSel=t.target.value} /> + + + + + + ${[["","fill.inherit"],...wi.map(t=>[t,"fill."+t])].map(([t,e])=>o``)} + ${"custom"===r?o`
+ ${this.host._roomCustomFill?this.host._t("room.custom_fill_own"):this.host._t("room.custom_fill_space")} + {this.host._roomCustomFill={c:t.detail.color,a:t.detail.opacity}}}> + ${this.host._roomCustomFill?o``:a} +
`:a} + ${this._renderRoomSource("temp")} + ${this._renderRoomSource("hum")} + + + +
+ ${this._rangeInput(50,300,5,Math.round(100*this.host._roomNameScale),t=>{this.host._roomNameScale=t/100,this.host.requestUpdate()})} + ${Math.round(100*this.host._roomNameScale)}% +
+ +
+ ${this._rangeInput(50,300,5,Math.round(100*this.host._roomLabelScale),t=>{this.host._roomLabelScale=t/100,this.host.requestUpdate()})} + ${Math.round(100*this.host._roomLabelScale)}% +
+ ${this.host._renderCardPreview(ps(this.host._curSpaceCfg).cardFontScale,this.host._roomNameScale,this.host._roomLabelScale)} +
+
+ + + ${t?o``:o`${this.host._pendingSplit?a:o``} + `} +
+
`}}export{oh as EDITOR_RUNTIME_FINGERPRINT,ah as HouseplanEditorRuntime}; diff --git a/dist/houseplan-assets/houseplan-onboarding-runtime-BkWWzfSR.js b/dist/houseplan-assets/houseplan-onboarding-runtime-BkWWzfSR.js new file mode 100644 index 00000000..a4cff7d0 --- /dev/null +++ b/dist/houseplan-assets/houseplan-onboarding-runtime-BkWWzfSR.js @@ -0,0 +1,217 @@ +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";import{bU as t,bV as s,bW as e,bX as o,aq as a,bY as l,c1 as i,bZ as h,b_ as n,b$ as c,c0 as r,b as p,A as _,cS as d,ap as u,ar as g,cT as m}from"./houseplan-card-BrUCyMoE.js";import{i as b,c as $,a as v,s as f,t as y}from"./space-deletion-CLA5ezlL.js";const w=1e3,D=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},S="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";class C{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_openSpaceDialog(p,_){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===p){const i=this.host._serverCfg.spaces.find(t=>t.id===_);if(!i)return;const h=t(i),n=i.settings?.custom_fill&&"object"==typeof i.settings.custom_fill?s(i.settings.custom_fill):null,c="none"===h.fill?{...n||e,a:0}:n;return void(this.host._spaceDialog={mode:p,spaceId:_,title:i.title,planUrl:i.plan_url||null,planFile:null,source:i.plan_url?"file":"draw",showBorders:h.showBorders,showNames:h.showNames,zeroWallStyle:l(i),displayTouched:!0,hideDecor:h.hideDecor,hideOpenings:h.hideOpenings,roomColor:h.color,roomOpacity:h.opacity,fillMode:"none"===h.fill?"custom":h.fill,customFill:c,glowEnabled:h.glow,bgColor:h.bgColor,bgMode:"static"===i.settings?.bg_mode||"daynight"===i.settings?.bg_mode?i.settings.bg_mode:null,northDeg:a({},i.settings),sunRays:"boolean"==typeof i.settings?.sun_rays?i.settings.sun_rays:null,tempMin:h.tempMin,tempMax:h.tempMax,showLqi:h.showLqi??this.host._config?.show_signal??!0,cardFontScale:h.cardFontScale,labelTemp:h.labelTemp,labelHum:h.labelHum,labelLqi:h.labelLqi,labelLight:h.labelLight,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,cellCmInput:o(Number(i.cell_cm)>0?Number(i.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const d=i(this.host._imperial);this.host._spaceDialog={mode:p,title:"",planUrl:null,planFile:null,...b(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:r,roomOpacity:c,fillMode:"custom",customFill:{...e,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:n,tempMax:h,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:d,cellCmInput:o(d,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;const o={"image/svg+xml":"svg","image/png":"png","image/jpeg":"jpg","image/webp":"webp"}[e.type]||(e.name.toLowerCase().endsWith(".svg")?"svg":"");if(!o)return void this.host._showToast(this.host._t("toast.plan_formats"));const a=new Uint8Array(await e.arrayBuffer());let l="";for(let t=0;t{const s=new Image;s.onload=()=>t(s.naturalWidth&&s.naturalHeight?s.naturalWidth/s.naturalHeight:1.414),s.onerror=()=>t(1.414),s.src=h});URL.revokeObjectURL(h),this.host._spaceDialog={...this.host._spaceDialog,planFile:{ext:o,b64:i,aspect:n,name:e.name}}}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),o=this.host._spaceDialog;return o&&o.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...o,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){if(confirm(this.host._t("confirm.delete_plan",{name:t})))try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return p`
${this.host._t("space.loading")}
`;const s=t.saved||[];if(!s.length)return p`
${this.host._t("space.no_saved")}
`;return p`
+ ${s.map(s=>{return p` +
+ +
+ ${s.name} + ${e=s.size,e>=1048576?`${(e/1048576).toFixed(1)} MB`:`${Math.round(e/1024)} KB`}${s.used_by.length?` · ${this.host._t("space.used_by",{list:s.used_by.join(", ")})}`:""} +
+ + +
`;var e})} +
`}async _saveConfigNow(){this.host._cfgEpoch++;try{await this.host._writeConfig()}catch(t){const s=t;throw s?.physicalGeometryRolledBack?await this.host._reloadRejectedPhysicalWrite():"conflict"===s?.code&&await this.host._reloadConfigOnly(),t}}async _saveSpaceDialog(){const t=this.host._spaceDialog;if(!t||t.busy||!t.title.trim())return;if("file"===t.source&&!t.planFile&&!t.planUrl)return void this.host._showToast(this.host._t("toast.plan_required"));const s="create"===t.mode&&0===(this.host._serverCfg?.spaces.length||0);this.host._spaceDialog={...t,busy:!0};try{const e="create"===t.mode?`s${Date.now().toString(36)}`:t.spaceId;let o=null;if("file"===t.source&&t.planFile){o={url:(await this.host.hass.callWS({type:"houseplan/plan/set",space_id:e,ext:t.planFile.ext,data:t.planFile.b64})).url,aspect:t.planFile.aspect}}let a=t.savedAspect||null;!o&&"file"===t.source&&t.planUrl&&!a&&this.host._aspectJob&&(a=await this.host._aspectJob||null);const l=this.host._serverCfg;let i=l.spaces.find(t=>t.id===e);if("create"===t.mode)i=$(e,t.title.trim()),l.spaces.push(i);else{if(!i)throw new Error(`space ${e} is gone from the config`);i.title=t.title.trim()}if(!i)throw new Error(`space ${e} is unavailable`);if(o?(i.plan_url=o.url,i.plan_aspect=o.aspect):"file"===t.source&&t.planUrl&&t.planUrl!==i.plan_url&&(i.plan_url=t.planUrl,i.plan_aspect=a),"draw"===t.source&&(i.plan_url=null,i.plan_aspect=null,delete i.plan_x,delete i.plan_y,delete i.plan_scale,delete i.plan_scale_x,delete i.plan_scale_y,delete i.plan_angle),i.settings={...i.settings||{},show_borders:t.showBorders,show_names:t.showNames,hide_decor:t.hideDecor||void 0,hide_openings:t.hideOpenings||void 0,room_color:t.roomColor,room_opacity:t.roomOpacity,bg_color:t.bgColor||void 0,bg_mode:t.bgMode||void 0,north_deg:t.northDeg??void 0,sun_rays:t.sunRays??void 0,fill_mode:t.fillMode,custom_fill:t.customFill||void 0,glow_enabled:t.glowEnabled,temp_min:Number.isFinite(t.tempMin)?Math.min(t.tempMin,t.tempMax):n,temp_max:Number.isFinite(t.tempMax)?Math.max(t.tempMin,t.tempMax):h,show_lqi:t.showLqi,card_font_scale:1!==t.cardFontScale?t.cardFontScale:void 0,label_temp:t.labelTemp,label_hum:t.labelHum,label_lqi:t.labelLqi,label_light:t.labelLight},i.zero_wall_style=t.zeroWallStyle,i.cell_cm=Number.isFinite(t.cellCm)&&t.cellCm>0?Math.max(.1,Math.min(w,t.cellCm)):5,await this._saveConfigNow(),this.host._spaceDialog=null,"create"===t.mode&&this.host._commitSpace(i.id),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._importQueue.length)this._openNextImport();else if(s||this.host._importTotal>0){const t=this.host._importTotal>0;this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),await this.host._requestMode("plan"),this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this.host._primeDrawWallField(),this.host._showToast(this.host._t(s&&!t?"toast.space_added_onboard":"import.done"))}else this.host._showToast(this.host._t("create"===t.mode?"toast.space_added":"toast.space_saved")),"create"===t.mode&&("plan"!==this.host._mode?await this.host._requestMode("plan"):(this.host._tool="draw",this.host._path=[],this.host._cursorPt=null,this.host._primeDrawWallField(),this.host._saveNav()))}catch(t){const s=t;"conflict"!==s?.code&&await this.host._reloadConfigOnly(!0),this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,busy:!1}),this.host._showToast(this.host._t("toast.error",{err:this.host._errText(t)}))}}async _deleteSpace(){const t=this.host._spaceDialog;if(!t||"edit"!==t.mode)return;const s=this.host._serverCfg;if(!s)return;const e=s.spaces.find(s=>s.id===t.spaceId);if(!e)return;const o=v(s,this.host._layout||{},t.spaceId||""),a=1===s.spaces.length&&s.spaces[0]?.id===t.spaceId;if(!o.count||a){if(confirm(this.host._t("confirm.delete_space",{title:e.title}))){this.host._spaceDialog={...t,deleteBlockers:0,busy:!0};try{this.host._saveConfigDebounced.pending()&&this.host._saveConfigDebounced.flush(),this.host._persistLayout.pending()&&this.host._persistLayout.flush(),await this.host._writeChain;const s=await this.host.hass.callWS({type:"houseplan/space/delete",space_id:t.spaceId,expected_config_rev:this.host._cfgRev,expected_layout_rev:this.host._layoutRev}),[e,o]=await Promise.all([this.host.hass.callWS({type:"houseplan/config/get"}),this.host.hass.callWS({type:"houseplan/layout/get"})]);this.host._adoptStructuralResponses(e,o),this.host._cfgRev=s?.config_rev??this.host._cfgRev,this.host._layoutRev=s?.layout_rev??this.host._layoutRev,this.host._spaceDialog=null,this.host._space===t.spaceId&&this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||""),this.host._regSignature="",this.host._maybeRebuildDevices(),this.host._showToast(this.host._t("toast.space_deleted"))}catch(s){const e=s;"conflict"!==e?.code&&"space_in_use"!==e?.code||await Promise.all([this.host._reloadConfigOnly(!0),this.host._reloadLayoutOnly()]);const o=this.host._serverCfg;if(this.host._spaceDialog&&o){const s=v(o,this.host._layout||{},t.spaceId||""),e=1===o.spaces.length&&o.spaces[0]?.id===t.spaceId;this.host._spaceDialog={...this.host._spaceDialog,busy:!1,deleteBlockers:e?0:s.count}}this.host._showToast(this.host._t("toast.delete_failed",{err:this.host._errText(s)}))}}}else this.host._spaceDialog={...t,deleteBlockers:o.count}}_startImport(){const t=this.host._importDialog;if(!t)return;const s=t.floors.filter(t=>t.checked).map(t=>t.name);this.host._importDialog=null,s.length?(this.host._importQueue=s,this.host._importTotal=s.length,this._openNextImport()):this._openSpaceDialog("create")}_openNextImport(){const t=this.host._importQueue.shift();if(void 0===t)return;const s=i(this.host._imperial);this.host._spaceDialog={mode:"create",title:t,planUrl:null,planFile:null,...b(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:r,roomOpacity:c,fillMode:"custom",customFill:null,glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:n,tempMax:h,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:s,cellCmInput:o(s,this.host._imperial),cellCmTouched:!1,busy:!1}}_skipImport(){this.host._spaceDialog=null,this.host._importQueue.length?this._openNextImport():this.host._importTotal>0&&this.host._model.length&&(this.host._importTotal=0,this.host._commitSpace(this.host._serverCfg.spaces[0]?.id||this.host._space),this.host._requestMode("plan").then(()=>{this.host._showToast(this.host._t("import.done"))}))}_renderImportDialog(){const t=this.host._importDialog,s=t.floors.filter(t=>t.checked).length;return p`this.host._importDialog=null}> +
+
${this.host._t("import.hint")}
+ ${t.floors.map((s,e)=>p``)} +
+
+ + + +
+
`}_boolInput(t,s){return p`s(t.target.checked)} />`}_rangeInput(t,s,e,o,a){return p`a(Number(t.target.value))} />`}_renderSpaceDialog(){return this._renderSpaceDialogBody(this.host._spaceDialog)}_renderSpaceDialogBody(t){const s=this.host._importTotal>0&&"create"===t.mode?this.host._t("import.progress",{i:this.host._importTotal-this.host._importQueue.length,n:this.host._importTotal}):"",l=()=>{this.host._spaceDialog=null,this.host._importQueue=[],this.host._importTotal=0};return p` +
+ + this.host._spaceDialog={...t,title:s.target.value}} /> + + + ${"file"===t.source?p`
+ ${t.planFile?p`${t.planFile.name}`:t.planUrl?p`${this.host._t("space.plan_alt")}`:p`${this.host._t("space.no_plan")}`} + + + this._pickPlanFile(t)} /> + + +
+ ${t.pickSaved?this._renderServerPlans(t):_}`:_} + + + +
+ {const e=s.target.value,o=D(e),a=null==o?null:d(o,this.host._imperial);this.host._spaceDialog={...t,cellCmInput:e,cellCmTouched:!0,cellCm:null!=a&&a>0?Math.max(.1,Math.min(w,a)):t.cellCm}}} /> + ${this.host._t(this.host._imperial?"space.scale_unit_imperial":"space.scale_unit")} +
+ + + + + +
${this.host._t("space.zero_wall_help")}
+ + + +
${this.host._t("space.hide_decor_tip")}
+ +
${this.host._t("space.hide_openings_tip")}
+ + ${[["labelTemp","space.label_temp"],["labelHum","space.label_hum"],["labelLqi","space.label_lqi"],["labelLight","space.label_light"]].map(([s,e])=>p``)} + +
+ ${this._rangeInput(50,300,5,Math.round(100*t.cardFontScale),s=>{this.host._spaceDialog={...t,cardFontScale:s/100}})} + ${Math.round(100*t.cardFontScale)}% +
+ ${this.host._renderCardPreview(t.cardFontScale,1,1)} +
+ {this.host._spaceDialog={...t,roomColor:s.detail.color,roomOpacity:s.detail.opacity}}}> +
+ + + ${"static"===(t.bgMode??u(this.host._settings,{}))?p` +
+ {this.host._spaceDialog={...t,bgColor:s.detail.color}}}> + ${t.bgColor?p``:p`${this.host._t("space.bg_inherited")}`} +
`:_} + +
+ {const e=s.target.value.trim(),o=""===e?null:Math.round(Number(e));this.host._spaceDialog={...t,northDeg:null!==o&&Number.isFinite(o)?Math.min(359,Math.max(0,o)):null}}} /> + ${null===t.northDeg?this.host._t("space.north_inherited",{v:null===a(this.host._settings,{})?"—":`${a(this.host._settings,{})}°`}):"°"} +
+ + + + ${m.map(t=>[t,`fill.${t}`]).map(([s,o])=>p` + ${"custom"===s&&"custom"===t.fillMode?p` +
+ ${this.host._t("space.custom_fill")} + {this.host._spaceDialog={...t,customFill:{c:s.detail.color,a:s.detail.opacity}}}}> + ${t.customFill?p``:_} +
`:_}`)} + + ${t.deleteBlockers?p``:_} +
+ +
`}}export{C as HouseplanOnboardingRuntime,S as ONBOARDING_RUNTIME_FINGERPRINT}; diff --git a/dist/houseplan-assets/space-deletion-CLA5ezlL.js b/dist/houseplan-assets/space-deletion-CLA5ezlL.js new file mode 100644 index 00000000..822c577d --- /dev/null +++ b/dist/houseplan-assets/space-deletion-CLA5ezlL.js @@ -0,0 +1 @@ +function e(e,o){return{id:e,title:o,plan_url:null,view_box:[0,0,1,1],rooms:[],wall_segments:[]}}function o(e="file"){const o="draw"===e;return{source:e,showBorders:o,showNames:o,displayTouched:!1}}function r(e,o){if(e.displayTouched)return{...e,source:o};const r="draw"===o;return{...e,source:o,showBorders:r,showNames:r}}function s(e,o,r){return{...e,[o]:r,displayTouched:!0}}function a(e,o,r){const s=(e?.spaces||[]).find(e=>e?.id===r),a=new Set((s?.rooms||[]).map(e=>String(e?.id||"")).filter(Boolean)),t=[...new Set((e?.markers||[]).filter(e=>!0!==e?.removed&&"string"==typeof e?.id).filter(e=>e.space===r||"string"==typeof e.room_id&&a.has(e.room_id)||o?.[e.id]?.s===r).map(e=>e.id))].sort((e,o)=>e.localeCompare(o));return{markerIds:t,count:t.length}}globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";export{a,e as c,o as i,r as s,s as t}; diff --git a/dist/houseplan-card.js b/dist/houseplan-card.js index a9cc9074..89defeea 100644 --- a/dist/houseplan-card.js +++ b/dist/houseplan-card.js @@ -1 +1 @@ -globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="e6c51f2467ae4e22a792e536ae954291ab5a46915e728b216c8c45bc6816b209";try{await import("./houseplan-assets/houseplan-card-DI__VUPO.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).":"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 entry: the main chunk is unavailable",e)} +globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="817110bad40d29ee0aa8e4ef2dadfda9e310dfa6346ddb5d2725ecafb359f073";try{await import("./houseplan-assets/houseplan-card-BrUCyMoE.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).":"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 entry: the main chunk is unavailable",e)} diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index c2ba3ac7..9a4838af 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,12 +2,6 @@ ## Unreleased -- Furniture placement in the Background editor now shows a translucent mouse - preview with the exact future size, rotation and wall snap. It follows live - size edits and disappears without a config change on cancel; on touch, - movement, cancellation or a second contact cannot create an accidental item - ([#359](https://github.com/Matysh/houseplan-card/issues/359)). - - Robot-vacuum trails now follow the same recorded points with softly rounded corners instead of a visibly segmented polyline. Current and previous runs use the same bounded curve, preserve telemetry gaps and never deviate by more diff --git a/docs/CHANGELOG.ru.md b/docs/CHANGELOG.ru.md index d09db577..65106883 100755 --- a/docs/CHANGELOG.ru.md +++ b/docs/CHANGELOG.ru.md @@ -8,12 +8,6 @@ ## Не выпущено -- При размещении мебели в редакторе подложки мышь теперь показывает на плане - полупрозрачный символ с точным будущим размером, поворотом и привязкой к - стене. Предпросмотр обновляется вместе с полями размера и исчезает без - изменений при отмене; на touch движение, отмена или второй палец не создают - случайный предмет ([#359](https://github.com/Matysh/houseplan-card/issues/359)). - - След пылесоса теперь повторяет те же записанные точки с мягко скруглёнными поворотами вместо заметной ломаной. Текущая и предыдущая уборки используют одну ограниченную кривую, сохраняют разрывы телеметрии и не отклоняются от diff --git a/docs/FURNITURE.md b/docs/FURNITURE.md index e44b4e05..a3fd353b 100644 --- a/docs/FURNITURE.md +++ b/docs/FURNITURE.md @@ -53,21 +53,9 @@ Furniture is a two-level non-modal palette in the editor context tray: 3. The second level shows the real top-view drawings. Back returns to the category list and clears any armed symbol. 4. Picking a variant arms one placement and reveals editable Width and Depth - in the Home Assistant length unit. With a mouse, moving over the plan shows - the real top-view symbol at its exact future size, wall magnet, rotation and - canvas clamp. Editing Width or Depth updates that ghost immediately without - requiring another pointer move. -5. Clicking the plan places exactly the previewed object and returns to Select. - Shift keeps the established free-placement behaviour. The ghost is a - transient, 55%-opaque rendering aid: it is never saved and never enters - Undo history. -6. Pointer leave, Escape, palette/tool/editor/space changes and remount clear - the ghost. Unknown or stale symbol ids show and save nothing. - -Touch and pen do not emulate hover or show a placement ghost. Their best-effort -editor path saves one object only after a clean tap; movement, pointer cancel -or a second contact cancels that pending stamp so pinch/cancel cannot create -furniture accidentally. View and kiosk touch guarantees remain unchanged. + in the Home Assistant length unit. +5. Clicking the plan places the object and returns to Select. Shift keeps the + established free-placement behaviour. The properties dialog remains a flat native select, grouped by category. Its optgroup label includes both the parent group and category because HTML selects diff --git a/docs/USER-GUIDE.ru.md b/docs/USER-GUIDE.ru.md index 47732c0c..23d1a303 100644 --- a/docs/USER-GUIDE.ru.md +++ b/docs/USER-GUIDE.ru.md @@ -1302,11 +1302,7 @@ Power=`off`/`unavailable` подавляет даже устаревший ак ### Мебель -Библиотека содержит группы мебели, бытовой техники, сантехники и прочих символов. Размер можно задать в метрах или десятичных футах. После выбора символа наведите мышь на план: полупрозрачное изображение заранее показывает точное будущее положение, размер и поворот предмета. Изменение ширины или глубины сразу обновляет предпросмотр. Клик размещает предмет именно в показанной позиции; выход курсора с плана, `Esc`, смена инструмента, пространства или редактора убирают предпросмотр без изменения плана. - -На сенсорных экранах предпросмотр не показывается: чистый тап размещает предмет, а движение, отмена касания или второй палец отменяют ожидающее размещение. Редактирование на touch-устройствах по-прежнему поддерживается по остаточному принципу; для полноценной работы используйте desktop. - -При размещении рядом со стеной предмет: +Библиотека содержит группы мебели, бытовой техники, сантехники и прочих символов. Размер можно задать в метрах или десятичных футах. При размещении рядом со стеной предмет: - прижимается к ней и поворачивается параллельно; - всегда прижимается к ближайшей стене в радиусе магнита, иначе размещается по сетке; diff --git a/docs/reviews/CODE-REVIEW-359-r1.md b/docs/reviews/CODE-REVIEW-359-r1.md new file mode 100644 index 00000000..a79a3301 --- /dev/null +++ b/docs/reviews/CODE-REVIEW-359-r1.md @@ -0,0 +1,206 @@ +# CODE-REVIEW-359-r1 + +Issue: [#359](https://github.com/Matysh/houseplan-card/issues/359) — Предпросмотр мебели на плане перед размещением +SHA: `8b66d67d` (`issue/359-furniture-placement-preview`) +ТЗ: `docs/specs/359-furniture-placement-preview.md`, spec review r2 — зелёный +Заход: r1 · блокирующих циклов израсходовано 0 из 4 (r1 — первый заход code review, разбор полный) + +## Скоуп проверки + +Диапазон `origin/dev..HEAD` — 5 коммитов, из них один продуктовый: +`8b66d67d feat: preview furniture placement` (Issue: #359, User-Visible: yes). +Остальные четыре — спек и спек-ревью документы (r1/r2), уже принятые до этого +этапа. + +Диф продуктового кода: `src/furniture.ts`, `src/houseplan-card.ts`, +`src/houseplan-editor-runtime.ts`, `src/styles/plan.styles.ts`. Плюс тесты +(`test/furniture.test.mjs`, `test/golden-matrix.test.mjs`, +`demo/smoke_furniture.mjs`, `demo/golden/harness.mjs`, `demo/golden/matrix.mjs`), +документация (`docs/FURNITURE.md`, `docs/USER-GUIDE.ru.md`, оба CHANGELOG) и +бандл/дистрибутив (класс D, обновлён `bundle:sync`). + +Диф не трогает геометрию комнат/толщину/`layout`/`marker.space`/`open_spans`: +`_furnWalls` используется только на чтение для магнита мебели, схема decor не +меняется. `npm run invariants` не требуется — подтверждено чтением диффа +(нет изменений в space-geometry/wall-degrade/rekey путях кроме одного нового +импорта `clampCanvasN`, который уже существует и не меняет поведение). + +## Как проверялось + +Дешёвые гейты прогнаны лично на этом SHA (зелёного Validate на нём нет): + +| Гейт | Команда | Результат | +|---|---|---| +| typecheck | `npx tsc --noEmit` | чисто, без вывода | +| unit | `npm test` | `tests 1511 · pass 1510 · fail 0 · skipped 1` | +| build | `npm run build` | `created dist in 15.3s` | +| bundle sync | `npm run bundle:sync` | три копии синхронны (`custom_components`, `demo/srv/assets`) | +| bundle budget | `npm run bundle:budget` | View 272469 B / 282000 B (headroom 9531 B), editor 137196 B | +| furniture pack | `npm run furniture:check` | `Furniture pack OK: 44 plan symbols, 33 menu icons` | +| **docs fingerprint** | `node scripts/check-docs.mjs` | **`ERROR screenshot source fingerprint is stale`** — см. находку ниже | +| docs пересборка (диагностика находки) | `node demo/docs/capture.mjs` | пересобрал скриншоты/фингерпринт локально, подтвердил причину; изменения отменены (`git checkout -- docs/images/`), не коммитил | +| browser smoke | `node demo/smoke_furniture.mjs` | `OK`, все 60+ именованных ассертов true | +| golden (новый сценарий) | `node demo/golden/run.mjs --mode=capture --scenario=furniture-placement-preview-light` | `missing-baseline` — ожидаемо, приёмка эталона требует полного Linux CI (AC10, `demo/golden/README.md`) | +| golden (регрессия) | `npm run golden:verify` | все существующие сценарии `passed`, кроме нового (`missing-baseline`, ожидаемо) — новая композиция decor-слоя не сдвинула ни один принятый эталон | +| smoke-select (широкий охват) | `node scripts/smoke-select.mjs --base origin/dev --head HEAD` | 4 файла `src/**`, 44 изменённых символа-проекта; 31 «прямое совпадение», включая `demo/smoke_furniture.mjs` (уже прогнан). Остальные «прямые» — общие декор-символы (`_curSpaceCfg`, `_decorTool`, `_svgPoint`, `NORM_W`, `_editorRuntime`, `_pointers`) на диффах в `_stagePointerMove/_stagePointerLeave/_stagePointerUp`, которые новый код только оборачивает веткой `_decorTool === 'furniture'`, не меняя остальные ветки — прочитаны построчно (см. ниже), не прогонялись целиком: точечный per-tool guard, не общая decor-логика | + +Инвариант «один источник числа»: preview и commit используют один и тот же +чистый `resolveFurniturePlacement` (`src/furniture.ts:418`) — подтверждено +и unit-тестом (`preview и commit равны для одного input`), и smoke +(`previewAndCommitAreIdentical`), и чтением кода (`_furnPlace` больше не +пересчитывает привязку отдельно, а берёт результат `_resolveFurniturePlacement` +целиком). Второй показываемый параметр — ширина/глубина в полях палитры — тот +же `pal.w/pal.h`, что уходит в резолвер; отдельного пути нет. + +## Находки + +### High — 1 + +**docs-гейт на этом SHA красный: скриншот-фингерпринт устарел, а PNG не +пересобраны.** + +- Файл: `docs/images/screenshots.json` +- Воспроизведение: `node scripts/check-docs.mjs` → + `ERROR screenshot source fingerprint is stale; run npm run build && node demo/docs/capture.mjs`. + Причина — числами: записанный в коммите `sourceFingerprint` — + `c94b78394be8a5a7dc2973652aa9aba4b6896cfd4c7f44c0038fadf911e62eb4` (тот же, + что и на `origin/dev`, `git show origin/dev:docs/images/screenshots.json` + и `git show HEAD^:docs/images/screenshots.json` совпадают — на `dev` гейт + был зелёным). Диф трогает `src/furniture.ts`, `src/houseplan-card.ts`, + `src/houseplan-editor-runtime.ts`, `src/styles/plan.styles.ts` — фингерпринт + считается по всему `src/**`, значит любая правка делает его устаревшим. + Пересчитанный локально фингерпринт — `5e7ddb2ac8885e8e6edf2113a1f35551ce3338234da9324d0874e3f861205502`; + `docs/images/*.png` и `docs/images/screenshots.json` в коммите + `8b66d67d` не обновлены. +- Последствие: это ровно `docs` job из `validate.yml` — «реальный блокер» + (AGENTS.md). На этом SHA он красный детерминированно, не по вкусу CI-раннера. + Слияние в `dev` без починки повторит #230/#234: `dev` останется с красным + `docs` до следующей задачи (#237). +- Это не про содержание документации — `docs/FURNITURE.md` и + `docs/USER-GUIDE.ru.md` обновлены корректно и по делу (см. «Проверено и + корректно»). Дело исключительно в шаге релиз-артефактов «пересобрать + скриншоты», который ТЗ не назвало явно (в разделе «Release-артефакты» ТЗ + вообще не упомянут скриншотный гейт), но `AGENTS.md`/`PROCESS.md` требуют + его для любой правки `src/**`, а хендофф автора его не называет и не + прогонял. +- Почин: `npm run build && node demo/docs/capture.mjs`, затем + `node scripts/check-docs.mjs` до зелёного, закоммитить обновлённые + `docs/images/*.png` и `docs/images/screenshots.json` вместе с остальным + диффом (или отдельным коммитом класса C/D с тем же issue-трейлером). + +Находка в скоупе задачи (сама задача внесла правку в `src/**`, из-за которой +гейт стал красным) — чинится в этом же issue, отдельный issue не заводится. + +## Проверено и корректно + +- **AC1 (появление)** — `mouseHoverShowsRealSymbol` в smoke: реальный path, + `data-symbol` совпадает с выбранным символом. +- **AC2 (геометрический паритет)** — `resolveFurniturePlacement` + (`src/furniture.ts:418`) — чистая функция, вызывается один раз и для превью + (`_resolveFurniturePlacement` → `_furniturePreviewPlacement`), и для коммита + (`_furnPlace`). Unit-тест сравнивает результат `deepEqual` для одинакового + входа; отдельный тест покрывает `free`/`Shift` и canvas-guard + (`clampCanvasN`, лимит 5000) и `null` для неизвестного символа. Smoke + `previewAndCommitAreIdentical` сравнивает реально размещённый `sofa` с + зафиксированным значением превью перед кликом — `x/y/w/h` с точностью + `1e-12`, `angle` точно. +- **AC3 (живые размеры)** — `sizeUpdatesPreviewWithoutPointerMove`: изменение + поля Width без нового движения мыши меняет `w` превью и `transform`. + Работает потому, что рендер геометрии превью читает текущий `_furnPalette` + на каждый рендер (`_furniturePreviewPlacement` — геттер, не кэш). +- **AC4 (чистота)** — `previewDoesNotMutateConfigOrHistory`: `_decorList.length`, + `_cfgEpoch`, undo/redo-имена не меняются на `pointermove`. Прочитано в коде: + `_furnPointerMove` пишет только `_furnPreviewInput` (`@state`, не часть + конфига) и ничего не передаёт в `_saveConfig`/`_recordGeometry`. +- **AC5 (очистка)** — `pointerLeaveClearsPreview`, + `previewClearsAfterCommit` в smoke; остальные точки очистки (Escape, + кнопки «закрыть»/«назад»/категория палитры, переключение инструмента, + `_setMode`, смена `_space`, `_stagePointerCancel`, + `_clearGeometryGesture`) не покрыты ни отдельным smoke-шагом, ни + source-contract тестом (ТЗ допускал последний опционально, «если нельзя + надёжно доказать одним smoke» — план его не потребовал письменно, но и не + реализовал). **Проверено чтением, не исполнением**: все девять точек вызова + `_clearFurniturePreview()` (`src/houseplan-editor-runtime.ts:1178, 2207, + 2238, 4722, 4746, 4867, 4878, 4902, 5222, 5345, 5357, 5361` и + `src/houseplan-card.ts:1450, 2691, 2797`) расположены до любого early-return, + который мог бы их обойти — прослежено построчно для `_setMode` (в самом + начале функции, до проверки «тот же режим»), для Escape-ветки (до сброса + `_furnPalette`), для кнопок палитры и переключателя инструментов в + `_renderDecorBar`/`_renderFurnPalette`/`_renderDecorSecondary`. Пропусков не + нашёл. +- **AC6 (ввод)** — `shiftBypassesTheWallMagnet` (было + `shiftKeepsTheMagnet` — переименовано согласно новому контракту `Shift`, + смок обновлён консистентно с CANVAS.md §9.4 и ТЗ п.3); + `touchCancelMoveAndSecondContactDoNotSave` — четыре синтетических + touch-сценария (move>8px, cancel, второй contact, `isPrimary:false`) не + создают запись. Прочитано: `_furnPointerMove` помечает `pending.cancelled` + при движении больше 8px (тот же порог, что уже использует `_stagePointerMove` + для pan-lock, `src/houseplan-card.ts:6220` — не новое магическое число), а + `_decorPointerDown` игнорирует второй контакт, не создавая для него + собственный `pending`. +- **AC7 (визуальный контракт)** — `previewIsTransientAndInert`: `aria-hidden`, + `pointer-events: none` (вычисленный computed style), `opacity: 0.55` с + допуском `1e-6`. CSS-правило `.decorlayer .furniture-placement-preview` + (`src/styles/plan.styles.ts`) не задевает никакой другой класс. +- **AC8 (совместимость)** — весь остальной furniture-flow (drag/resize/rotate, + erase, View-рендер) прогнан тем же расширенным smoke и остаётся зелёным; + `npm test` без регрессий (1510 pass, 0 fail); `npm run golden:verify` — + все ранее принятые сценарии `passed`, ни один не сдвинут новым кодом + decor-слоя. +- **AC9 (неизвестный символ)** — unit-тест + `resolveFurniturePlacement({..., symbol: 'future_unknown_symbol'})` → `null`; + smoke `unknownSymbolFailsDark` форсирует невалидный `_furnPalette`, проверяет + отсутствие ghost и записи, и что инструмент остаётся вооружён для восстановления + валидного выбора. +- **AC10 (композиция)** — golden-сценарий `furniture-placement-preview-light` + зарегистрирован в `matrix.mjs` и `test/golden-matrix.test.mjs`; harness + (`demo/golden/harness.mjs`) программно вооружает предмет, ставит курсор и + проверяет DOM-контракт (символ, `aria-hidden`, `pointer-events`, opacity, + порядок относительно `[data-hp="wall"]`) до самого растрового захвата — + капчур прошёл (`missing-baseline`, эталон не принят локально — верно по + правилам `demo/golden/README.md` и по `npm run golden:verify`, который не + нашёл ни одной существующей регрессии). +- Трейлеры: `Issue: #359`, `User-Visible: yes` на продуктовом коммите; оба + CHANGELOG (`docs/CHANGELOG.md`, `docs/CHANGELOG.ru.md`) правлены в том же + коммите `8b66d67d`. Формулировки соответствуют реальному поведению (сверено + построчно с кодом), терминология `docs/USER-GUIDE.ru.md` и `docs/FURNITURE.md` + не придумана заново, согласована с существующим разделом «Мебель». +- Ветка/процесс: один продуктовый коммит на весь диф, класс A корректно + отделён от класса D (бандл) — все три копии бандла синхронны + (`bundle:sync`), бюджет в пределах (`bundle:budget`). + +## Чего не проверял + +- **`python -m pytest tests_backend`** — не прогонялся: диф не касается + `custom_components/**/*.py`. +- **Performance-профили** — не прогонялись: не названы в AC, диф не трогает + чувствительные к перфу пути (рендер одного дополнительного SVG-path на + pointermove — цена признана в ТЗ и не требует профиля). +- **`npm run invariants`** — не прогонялся: диф не меняет рёбра комнат, записи + толщины, `layout`, `marker.space`, `open_spans`; `_furnWalls` используется + только на чтение существующим (не новым) резолвером стен. +- **Полный `demo/smoke_*.mjs` набор** — не прогонялся целиком; выбор сужен + инструментом `smoke-select.mjs` (см. таблицу выше) до + `smoke_furniture.mjs`, который прогнан. Остальные «прямые совпадения» разобраны + чтением как точечные ветки существующей decor pointer-логики, не общие пути. +- **`docs/images/*.png` визуально** — не сверял пиксель-в-пиксель новые + скриншоты с прежними (не требуется: находка в том, что фингерпринт вообще + не пересобран в коммите, а не в содержимом самих кадров). + +## Вердикт + +Функционально фича сделана верно и полно: единый resolver, паритет +preview/commit, полная очистка по всем перечисленным в контракте границам +(включая девять точек, проверенных чтением), touch/pen fail-safe, unknown-symbol +fail-dark, новый golden-сценарий и расширенный smoke — всё воспроизводимо и +падение тестов проверяемо (пробовал ломать резолвер мысленно на canvas-guard — +тест зафиксировал бы `-5000`, а не что-то другое; unknown-symbol тест ловит +регрессию `furnitureGraphic` напрямую). + +Единственная находка — не в продуктовой логике, а в release-артефакте: +скриншотный гейт документации остался красным на этом SHA. Это High по +формальному эффекту (гарантированно красный обязательный job `docs` в +`validate.yml` при слиянии) и по прецеденту (#230/#234/#237), поэтому +вердикт — красный, а не жёлтый с отложенным High. + +Вердикт: красный · заход r1 · блокирующих циклов 0/4 · High: 1 · Medium: 0 → в задаче diff --git a/src/furniture.ts b/src/furniture.ts index 417d2fa7..66a4b794 100644 --- a/src/furniture.ts +++ b/src/furniture.ts @@ -28,7 +28,7 @@ * colour, so a plan stays a drawing (owner: «символы рисуются линейно»). */ -import { NORM_W, GRID_PITCH, CANVAS_LIMIT, clampCanvasN } from './space-geometry'; +import { NORM_W, GRID_PITCH, CANVAS_LIMIT } from './space-geometry'; import { GENERATED_FURNITURE_PLAN } from './furniture-plan-art.generated'; /** Groups the palette shows, in the order it shows them. */ @@ -395,33 +395,6 @@ export interface FurnitureSnap { /** Wall segments (`[x1,y1,x2,y2]`) in whatever units the caller works in. */ export type WallSeg = number[]; -/** Final normalised box shared by the placement ghost and the saved decor - * record. Keeping this result pure prevents a preview/commit jump when wall - * magnetism or the canvas guard participates (#359). */ -export interface FurniturePlacement { - symbol: string; - x: number; - y: number; - w: number; - h: number; - angle: number; -} - -export interface FurniturePlacementInput { - symbol: string; - widthCm: number; - depthCm: number; - /** Already resolved decor/grid snap point, in render units. */ - point: readonly [number, number]; - canvasW: number; - canvasH: number; - cellCm: number; - gridPitch: number; - walls: WallSeg[]; - wallReach: number; - free?: boolean; -} - const norm180 = (a: number): number => { let x = ((a % 360) + 360) % 360; if (x > 180) x -= 360; @@ -485,43 +458,6 @@ export function snapFurnitureToWall( return best; } -/** - * Resolve the exact geometry one furniture stamp will own. - * - * The caller owns the higher-level decor/room/grid snap because that geometry - * is editor state. Everything after that point is pure and therefore shared - * byte-for-byte by hover preview and commit. Unknown symbols fail dark: a - * newer config or a stale palette cannot create invisible furniture. - */ -export function resolveFurniturePlacement(input: FurniturePlacementInput): FurniturePlacement | null { - const { - symbol, widthCm, depthCm, point, canvasW, canvasH, cellCm, gridPitch, - walls, wallReach, free = false, - } = input; - if (!furnitureGraphic(symbol) || !(canvasW > 0) || !(canvasH > 0) - || !Number.isFinite(point[0]) || !Number.isFinite(point[1])) return null; - const w = clampFurnSize(cmToNorm(widthCm, cellCm, gridPitch, canvasW)); - const h = clampFurnSize(cmToNorm(depthCm, cellCm, gridPitch, canvasW)); - let cx = point[0], cy = point[1]; - let angle = 0; - const snap = free ? null : snapFurnitureToWall( - cx, cy, h * canvasH, walls, wallReach, gridPitch, - ); - if (snap) { - cx = snap.cx; - cy = snap.cy; - angle = snap.angle; - } - return { - symbol, - x: clampCanvasN(cx / canvasW - w / 2), - y: clampCanvasN(cy / canvasH - h / 2), - w, - h, - angle: Number(angle.toFixed(2)), - }; -} - /** * The four corners of a rotated box, world units, in the order the frame * draws them: NW, NE, SE, SW. Pure, so the frame, the gestures and the tests diff --git a/src/houseplan-card.ts b/src/houseplan-card.ts index 90ac48b9..f63762fc 100755 --- a/src/houseplan-card.ts +++ b/src/houseplan-card.ts @@ -63,8 +63,7 @@ import { dayCycleStageVars, renderDayCycleEnvironment } from './day-cycle-render import { FURNITURE_GROUPS, furnitureOfGroup, furnitureSymbol, furnitureDefaultCm, furnitureGraphic, furnitureCorners, snapFurnitureToWall, - cmToNorm, clampFurnSize, clampFurnCm, FURN_WALL_CELLS, - type FurnitureGroup, type FurniturePlacement, + cmToNorm, clampFurnSize, clampFurnCm, FURN_WALL_CELLS, type FurnitureGroup, } from './furniture'; import { degradeWalls, rekeyWallsAfterMoveChecked, wallRecordCarrierViolations, @@ -1038,15 +1037,6 @@ export class HouseplanCard extends LitElement { private _furnPalette: { symbol: string; w: number; h: number } | null = null; /** Category currently open in the two-level furniture palette. */ private _furnCategory: string | null = null; - /** Last fine-pointer location while one furniture stamp is armed. The final - * geometry is deliberately resolved on render from the live palette so a - * Width/Depth edit updates the ghost without another mouse move (#359). */ - private _furnPreviewInput: { raw: [number, number]; free: boolean } | null = null; - /** Touch/pen has no hover. Delay its one-shot stamp until a clean pointerup - * so pointercancel or a second contact cannot save accidental geometry. */ - private _furnTouchPending: { - pid: number; sx: number; sy: number; pointerType: string; cancelled: boolean; - } | null = null; /** The selected shape's own unrotated frame (text is measured from SVG). */ private _dtBox: { id: string; x: number; y: number; w: number; h: number } | null = null; /** @@ -1447,7 +1437,6 @@ export class HouseplanCard extends LitElement { if (id !== this._space) { this._clearTransientHover(true); this._cancelDevicePressFeedback(); - this._editorRuntime?._clearFurniturePreview(); } this._space = id; return true; @@ -2442,7 +2431,6 @@ export class HouseplanCard extends LitElement { _backdropDialog: { state: true }, _furnPalette: { state: true }, _furnCategory: { state: true }, - _furnPreviewInput: { state: true }, _bdDrag: { state: true }, _dtBox: { state: true }, _dtDrag: { state: true }, @@ -2688,7 +2676,6 @@ export class HouseplanCard extends LitElement { this._warmRelease(); this._clearPlanSnapHover(); this._clearOpeningPlacement(true); - this._editorRuntime?._clearFurniturePreview(); this._touchContacts.clear(); this._touchSequenceMultitouch = false; this._touchClickBlockUntil = 0; @@ -2794,7 +2781,6 @@ export class HouseplanCard extends LitElement { // The palette is one explicit surface: Escape closes it and returns // to Select in one step, regardless of whether a symbol was armed. else if (this._decorTool === 'furniture') { - this._editorRuntime?._clearFurniturePreview(); this._furnPalette = null; this._furnCategory = null; this._decorTool = 'select'; @@ -6170,10 +6156,6 @@ export class HouseplanCard extends LitElement { this._decorMoveUpdate(ev); return; } - if (this._mode === 'decor' && this._decorTool === 'furniture' && this._editorRuntime) { - this._notePointer(ev); - if (this._editorRuntime._furnPointerMove(ev, this._pointerModality.hoverEnabled)) return; - } if (!this._pointers.has(ev.pointerId)) { this._markupMove(ev); return; @@ -6238,8 +6220,7 @@ export class HouseplanCard extends LitElement { } } - private _stagePointerLeave(ev: PointerEvent): void { - if (this._mode === 'decor') this._editorRuntime?._furnPointerLeave(ev); + private _stagePointerLeave(_ev: PointerEvent): void { if (!this._markup) return; if (this._tool === 'opening') { this._cursorPt = null; @@ -6316,7 +6297,6 @@ export class HouseplanCard extends LitElement { this._decorMove = null; return; } - if (this._editorRuntime?._furnPointerUp(ev)) return; const viewportGestureEnded = !!this._pinchStart || !!this._panStart; this._pointers.delete(ev.pointerId); if (this._pointers.size < 2) this._pinchStart = null; @@ -8038,36 +8018,6 @@ export class HouseplanCard extends LitElement { ` as unknown as TemplateResult; } - private get _furniturePreviewPlacement(): FurniturePlacement | null { - const input = this._furnPreviewInput; - if (!input || !this._editorRuntime || this._mode !== 'decor' - || this._decorTool !== 'furniture' || !this._furnPalette - || !this._pointerModality.hoverEnabled) return null; - return this._editorRuntime._resolveFurniturePlacement(input.raw, input.free, 'mouse'); - } - - /** One real furniture path, in the same decor composition group as saved - * shapes. It paints after them (so it is visible) and the whole decor layer - * still paints below physical walls (#359). */ - private _renderFurniturePlacementPreview(): TemplateResult | typeof nothing { - const placement = this._furniturePreviewPlacement; - if (!placement) return nothing; - const art = furnitureGraphic(placement.symbol); - if (!art) return nothing; - const W = NORM_W, H = this._decorH; - const W2 = placement.w * W, H2 = placement.h * H; - const cx = placement.x * W + W2 / 2, cy = placement.y * H + H2 / 2; - const transform = `${placement.angle ? `rotate(${placement.angle} ${cx} ${cy}) ` : ''}` - + `translate(${placement.x * W} ${placement.y * H}) scale(${W2 / art.viewW} ${H2 / art.viewH})`; - const style = this._decorStyle; - return svg``; - } - private _renderDecorLayer(): TemplateResult { const W = NORM_W, H = this._decorH; const editing = this._mode === 'decor'; @@ -8187,7 +8137,7 @@ export class HouseplanCard extends LitElement { stroke="${st.color}" stroke-opacity="${st.opacity}" stroke-width="${sw}" fill="${st.fill ? st.fillColor : 'none'}" fill-opacity="${st.fill ? st.fillOpacity : 0}">`; } } - return svg`${shapes}${draft}${this._renderFurniturePlacementPreview()}` as unknown as TemplateResult; + return svg`${shapes}${draft}` as unknown as TemplateResult; } // ================= shared editor secondary surface ================= diff --git a/src/houseplan-editor-runtime.ts b/src/houseplan-editor-runtime.ts index cd3f39d0..b823afc0 100644 --- a/src/houseplan-editor-runtime.ts +++ b/src/houseplan-editor-runtime.ts @@ -65,9 +65,7 @@ import { dayCycleStageVars, renderDayCycleEnvironment } from './day-cycle-render import { FURNITURE_GROUPS, furnitureOfGroup, furnitureDefaultCm, furnitureGraphic, furnitureCorners, snapFurnitureToWall, - resolveFurniturePlacement, - clampFurnCm, FURN_WALL_CELLS, - type FurnitureGroup, type FurniturePlacement, + cmToNorm, clampFurnSize, clampFurnCm, FURN_WALL_CELLS, type FurnitureGroup, } from './furniture'; import { GENERATED_FURNITURE_MENU } from './furniture-menu-art.generated'; import { @@ -919,10 +917,6 @@ export interface HouseplanEditorHostPort { _fullRegistryHass: any; _furnPalette: { symbol: string; w: number; h: number; } | null; _furnCategory: string | null; - _furnPreviewInput: { raw: [number, number]; free: boolean; } | null; - _furnTouchPending: { - pid: number; sx: number; sy: number; pointerType: string; cancelled: boolean; - } | null; _furnWallReach: number; _furnWalls: number[][]; _gearPtCache: WeakMap; @@ -1175,7 +1169,6 @@ public _help(key: Extract): TemplateResult | typeof n public _setMode(mode: 'view' | 'plan' | 'devices' | 'decor', animate = true): void { this.host._endTabDrag(); - this._clearFurniturePreview(); // A mode command is newer than the editor remembered by a same-route warm // remount. Clear it before the same-mode early return: while can_write is // pending, Lit may still be presenting the previous editor DOM even though @@ -2204,7 +2197,6 @@ public _commitPhysicalGeometry( } public _clearGeometryGesture(): void { - this._clearFurniturePreview(); this.host._path = []; this._clearPlanSnapHover(); this._clearOpeningPlacement(false); @@ -2234,12 +2226,6 @@ public _clearGeometryGesture(): void { public _stagePointerCancel(ev: PointerEvent): void { clearTimeout(this.host._kioskHoldTimer); if (this.host._swipeStart?.id === ev.pointerId) this.host._swipeStart = null; - if (this.host._furnTouchPending?.pid === ev.pointerId) { - this._clearFurniturePreview(); - this.host._pointers.delete(ev.pointerId); - this.host.requestUpdate(); - return; - } if (this.host._physicalDrag?.pid === ev.pointerId || this.host._physicalRotate?.pid === ev.pointerId) { this._cancelPhysicalGesture(); return; @@ -4109,29 +4095,7 @@ public _decorPointerDown(ev: PointerEvent): boolean { // must not silently place whatever was chosen last week. if (!this.host._furnPalette) return false; ev.preventDefault(); - // A mouse has already shown the exact result and keeps the traditional - // one-press stamp. Touch/pen has no hover, so commit only after a clean - // pointerup; pointercancel, movement and a second contact stay fail-dark. - const pointerType = ev.pointerType || 'mouse'; - if (pointerType === 'mouse') { - this._furnPlace(this._svgPoint(ev), ev.shiftKey, pointerType); - return true; - } - const pending = this.host._furnTouchPending; - if (pending && pending.pid !== ev.pointerId) { - pending.cancelled = true; - this.host._furnPreviewInput = null; - return true; - } - this.host._furnTouchPending = { - pid: ev.pointerId, - sx: ev.clientX, - sy: ev.clientY, - pointerType, - cancelled: false, - }; - this.host._furnPreviewInput = null; - capturePointer(ev); + this._furnPlace(this._svgPoint(ev), ev.shiftKey); return true; } // Empty-space selection belongs only to Select. Erase is an object @@ -4675,104 +4639,41 @@ public _furnPick(symbol: string): void { this.host._furnPalette = { symbol, w: d.w, h: d.h }; } -public _resolveFurniturePlacement( - raw: number[], free = false, pointerType = 'mouse', - ): FurniturePlacement | null { +public _furnPlace(raw: number[], free = false): void { const pal = this.host._furnPalette; const sp = this.host._curSpaceCfg; - if (!pal || !sp) return null; + if (!pal || !sp) return; const W = NORM_W, H = this.host._decorH; - const snapped = this._decorSnap(raw, pointerType); - return resolveFurniturePlacement({ - symbol: pal.symbol, - widthCm: pal.w, - depthCm: pal.h, - point: [snapped[0], snapped[1]], - canvasW: W, - canvasH: H, - cellCm: this.host._cellCm, - gridPitch: this.host._gridPitch, - walls: this.host._furnWalls, - wallReach: this.host._furnWallReach, - free, - }); - } - -public _furnPlace(raw: number[], free = false, pointerType = 'mouse'): void { - const placement = this._resolveFurniturePlacement(raw, free, pointerType); - if (!placement) return; - const sp = this.host._curSpaceCfg; - if (!sp) return; + const wN = clampFurnSize(cmToNorm(pal.w, this.host._cellCm, this.host._gridPitch, W)); + const hN = clampFurnSize(cmToNorm(pal.h, this.host._cellCm, this.host._gridPitch, W)); const before = this._geometrySnapshot(); + const c = this._decorSnap(raw); + let cx = c[0], cy = c[1]; + let angle = 0; + const snap = free ? null : snapFurnitureToWall(cx, cy, hN * H, this.host._furnWalls, + this.host._furnWallReach, this.host._gridPitch); + if (snap) { cx = snap.cx; cy = snap.cy; angle = snap.angle; } const id = 'df' + Date.now().toString(36) + Math.random().toString(36).slice(2, 5); const shape: any = { - id, kind: 'furniture', symbol: placement.symbol, - x: placement.x, y: placement.y, w: placement.w, h: placement.h, + id, kind: 'furniture', symbol: pal.symbol, + x: clampCanvasN(cx / W - wN / 2), y: clampCanvasN(cy / H - hN / 2), + w: wN, h: hN, ...decorStylePatch(this.host._decorStyle, false), }; // a straight piece stores no angle at all, exactly as a straight label // stores none (docs/LIVE-TEXT.md §3) - if (placement.angle) shape.angle = placement.angle; + if (angle) shape.angle = Number(angle.toFixed(2)); sp.decor = [...this.host._decorList, shape]; this.host._decorSel = id; // …and the editor goes back to the tool that can move what was just placed this.host._decorTool = 'select'; this.host._furnPalette = null; this.host._furnCategory = null; - this._clearFurniturePreview(); this._recordGeometry(this.host._t('history.decor_add'), before); this._saveConfig(); this.host.requestUpdate(); } -public _clearFurniturePreview(): void { - this.host._furnPreviewInput = null; - this.host._furnTouchPending = null; - } - -/** Track only real fine-pointer hover. Touch/pen own a delayed one-tap - * transaction below and must never resurrect a compatibility mouse ghost. */ -public _furnPointerMove(ev: PointerEvent, hoverAllowed: boolean): boolean { - const pending = this.host._furnTouchPending; - if (pending?.pid === ev.pointerId) { - if (Math.abs(ev.clientX - pending.sx) + Math.abs(ev.clientY - pending.sy) > 8) { - pending.cancelled = true; - } - this.host._furnPreviewInput = null; - return true; - } - if (this.host._mode !== 'decor' || this.host._decorTool !== 'furniture' - || !this.host._furnPalette) { - this._clearFurniturePreview(); - return false; - } - if (ev.pointerType !== 'mouse' || !hoverAllowed) { - this.host._furnPreviewInput = null; - return false; - } - const raw = this._svgPoint(ev); - this.host._furnPreviewInput = { raw: [raw[0], raw[1]], free: ev.shiftKey }; - return true; - } - -public _furnPointerLeave(ev: PointerEvent): void { - if (this.host._furnTouchPending?.pid === ev.pointerId) { - this.host._furnTouchPending.cancelled = true; - } - this.host._furnPreviewInput = null; - } - -public _furnPointerUp(ev: PointerEvent): boolean { - const pending = this.host._furnTouchPending; - if (!pending || pending.pid !== ev.pointerId) return false; - this.host._furnTouchPending = null; - if (!pending.cancelled && this.host._mode === 'decor' - && this.host._decorTool === 'furniture' && this.host._furnPalette) { - this._furnPlace(this._svgPoint(ev), ev.shiftKey, pending.pointerType); - } - return true; - } - public _furnMoveUpdate(ev: PointerEvent): void { const m = this.host._decorMove!; if (m.orig.kind !== 'furniture') return; @@ -4864,7 +4765,6 @@ public _renderFurnPalette(): TemplateResult {