@jimka/typescript-ui 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/AbstractInput-Dt9ooHjo.js +2 -0
- package/dist/lib/AbstractInput-Dt9ooHjo.js.map +1 -0
- package/dist/lib/AccordionConstraints-DahZEfEp.js +2 -0
- package/dist/lib/AccordionConstraints-DahZEfEp.js.map +1 -0
- package/dist/lib/{Anchor-iZhsvMlT.js → Anchor-DdYgyn2V.js} +2 -2
- package/dist/lib/{Anchor-iZhsvMlT.js.map → Anchor-DdYgyn2V.js.map} +1 -1
- package/dist/lib/{AnimatedDropdown-D0RhVgv3.js → AnimatedDropdown-_KhHzX5D.js} +2 -2
- package/dist/lib/AnimatedDropdown-_KhHzX5D.js.map +1 -0
- package/dist/lib/Border-BELbqMDJ.js +2 -0
- package/dist/lib/Border-BELbqMDJ.js.map +1 -0
- package/dist/lib/Button-CKzjQyqA.js +2 -0
- package/dist/lib/Button-CKzjQyqA.js.map +1 -0
- package/dist/lib/{Card-C20k2YHU.js → Card-CAp7LcB5.js} +2 -2
- package/dist/lib/{Card-C20k2YHU.js.map → Card-CAp7LcB5.js.map} +1 -1
- package/dist/lib/Checkbox-CvAZJ4_T.js +2 -0
- package/dist/lib/Checkbox-CvAZJ4_T.js.map +1 -0
- package/dist/lib/CodeEditor-DoGGdL1Y.js +2 -0
- package/dist/lib/CodeEditor-DoGGdL1Y.js.map +1 -0
- package/dist/lib/ComboBox-DgjMnpdh.js +2 -0
- package/dist/lib/ComboBox-DgjMnpdh.js.map +1 -0
- package/dist/lib/Component-YrLXKJZS.js +2 -0
- package/dist/lib/Component-YrLXKJZS.js.map +1 -0
- package/dist/lib/Container-C5cxnioS.js +2 -0
- package/dist/lib/{Container-FWRjgF6T.js.map → Container-C5cxnioS.js.map} +1 -1
- package/dist/lib/DOM-DDhDN8lQ.js +2 -0
- package/dist/lib/DOM-DDhDN8lQ.js.map +1 -0
- package/dist/lib/Diagnostics-MI6Yw-3E.js +2 -0
- package/dist/lib/Diagnostics-MI6Yw-3E.js.map +1 -0
- package/dist/lib/Dialog-CXQXRQQK.js +2 -0
- package/dist/lib/Dialog-CXQXRQQK.js.map +1 -0
- package/dist/lib/DragManager-D5pBaPPg.js +2 -0
- package/dist/lib/DragManager-D5pBaPPg.js.map +1 -0
- package/dist/lib/{FieldDecorator-DyPX8CFh.js → FieldDecorator-37IgKHHm.js} +2 -2
- package/dist/lib/{FieldDecorator-DyPX8CFh.js.map → FieldDecorator-37IgKHHm.js.map} +1 -1
- package/dist/lib/{Fit-CaPMj7Up.js → Fit-amTWlJM2.js} +2 -2
- package/dist/lib/{Fit-CaPMj7Up.js.map → Fit-amTWlJM2.js.map} +1 -1
- package/dist/lib/{FloatingPanel-Dsy_vJxi.js → FloatingPanel-CwsFPYbc.js} +2 -2
- package/dist/lib/{FloatingPanel-Dsy_vJxi.js.map → FloatingPanel-CwsFPYbc.js.map} +1 -1
- package/dist/lib/Glyph-Cof7BxfJ.js +2 -0
- package/dist/lib/Glyph-Cof7BxfJ.js.map +1 -0
- package/dist/lib/{Grid-ft_UUpj8.js → Grid-BQZ4UIUH.js} +2 -2
- package/dist/lib/{Grid-ft_UUpj8.js.map → Grid-BQZ4UIUH.js.map} +1 -1
- package/dist/lib/GridConstraints-BkXa62z0.js +2 -0
- package/dist/lib/GridConstraints-BkXa62z0.js.map +1 -0
- package/dist/lib/{Header-Osm3IjDw.js → Header-Cj33ABP1.js} +2 -2
- package/dist/lib/{Header-Osm3IjDw.js.map → Header-Cj33ABP1.js.map} +1 -1
- package/dist/lib/{IconText-BBaYJ2Fx.js → IconText-Dp64iq_q.js} +2 -2
- package/dist/lib/{IconText-BBaYJ2Fx.js.map → IconText-Dp64iq_q.js.map} +1 -1
- package/dist/lib/LabeledGrid-Dpelrc1k.js +2 -0
- package/dist/lib/LabeledGrid-Dpelrc1k.js.map +1 -0
- package/dist/lib/LayoutSerialization-DgLJSuew.js +2 -0
- package/dist/lib/LayoutSerialization-DgLJSuew.js.map +1 -0
- package/dist/lib/Link-DE8tE3u3.js +2 -0
- package/dist/lib/Link-DE8tE3u3.js.map +1 -0
- package/dist/lib/List-TfgHScl3.js +2 -0
- package/dist/lib/List-TfgHScl3.js.map +1 -0
- package/dist/lib/ListenerBag-DYRl4TSb.js +2 -0
- package/dist/lib/ListenerBag-DYRl4TSb.js.map +1 -0
- package/dist/lib/{MemoryStore-DhPoU-7X.js → MemoryStore-ByGDEKYI.js} +2 -2
- package/dist/lib/{MemoryStore-DhPoU-7X.js.map → MemoryStore-ByGDEKYI.js.map} +1 -1
- package/dist/lib/Menu-BCQISKiQ.js +2 -0
- package/dist/lib/Menu-BCQISKiQ.js.map +1 -0
- package/dist/lib/{MenuButton-BqCT-1yv.js → MenuButton-BO4y3jf2.js} +2 -2
- package/dist/lib/{MenuButton-BqCT-1yv.js.map → MenuButton-BO4y3jf2.js.map} +1 -1
- package/dist/lib/{OverlayFade-CuEXgimf.js → OverlayFade-C1yQKffL.js} +2 -2
- package/dist/lib/{OverlayFade-CuEXgimf.js.map → OverlayFade-C1yQKffL.js.map} +1 -1
- package/dist/lib/{Panel-CtViePqY.js → Panel-DlsVVuvn.js} +2 -2
- package/dist/lib/{Panel-CtViePqY.js.map → Panel-DlsVVuvn.js.map} +1 -1
- package/dist/lib/{Position-BIEU1Eze.js → Position-DWR1nIpA.js} +2 -2
- package/dist/lib/{Position-BIEU1Eze.js.map → Position-DWR1nIpA.js.map} +1 -1
- package/dist/lib/ProgressSpinner-BI9tFIVm.js +2 -0
- package/dist/lib/ProgressSpinner-BI9tFIVm.js.map +1 -0
- package/dist/lib/RadioButton-BxcuFChp.js +2 -0
- package/dist/lib/RadioButton-BxcuFChp.js.map +1 -0
- package/dist/lib/RadioMenuRow-B2bthoxj.js +2 -0
- package/dist/lib/RadioMenuRow-B2bthoxj.js.map +1 -0
- package/dist/lib/{RovingTabIndex--w28AnXc.js → RovingTabIndex-BttlsARv.js} +2 -2
- package/dist/lib/{RovingTabIndex--w28AnXc.js.map → RovingTabIndex-BttlsARv.js.map} +1 -1
- package/dist/lib/Scrollbar-orAWHWap.js +2 -0
- package/dist/lib/Scrollbar-orAWHWap.js.map +1 -0
- package/dist/lib/SelectableText-BbS_lRzY.js +2 -0
- package/dist/lib/SelectableText-BbS_lRzY.js.map +1 -0
- package/dist/lib/Slider-BvXc-cx5.js +2 -0
- package/dist/lib/Slider-BvXc-cx5.js.map +1 -0
- package/dist/lib/Spacer-C6faKe1V.js +2 -0
- package/dist/lib/Spacer-C6faKe1V.js.map +1 -0
- package/dist/lib/StyleTraits-CAtzeyRR.js +2 -0
- package/dist/lib/StyleTraits-CAtzeyRR.js.map +1 -0
- package/dist/lib/TabButton-BQDaBszs.js +2 -0
- package/dist/lib/TabButton-BQDaBszs.js.map +1 -0
- package/dist/lib/TabCloseButton-B-iLVPGZ.js +2 -0
- package/dist/lib/TabCloseButton-B-iLVPGZ.js.map +1 -0
- package/dist/lib/Table-3McEw5gr.js +7 -0
- package/dist/lib/Table-3McEw5gr.js.map +1 -0
- package/dist/lib/Text-CGFXPhHD.js +2 -0
- package/dist/lib/Text-CGFXPhHD.js.map +1 -0
- package/dist/lib/Tooltip-DgRHQZhL.js +3 -0
- package/dist/lib/Tooltip-DgRHQZhL.js.map +1 -0
- package/dist/lib/Tree-Bq2pjjAz.js +2 -0
- package/dist/lib/Tree-Bq2pjjAz.js.map +1 -0
- package/dist/lib/{VBox-DVe4UXwX.js → VBox-hFIZAEpT.js} +2 -2
- package/dist/lib/{VBox-DVe4UXwX.js.map → VBox-hFIZAEpT.js.map} +1 -1
- package/dist/lib/{VirtualScroller-ggPTCQb0.js → VirtualScroller-Csa3GBSM.js} +2 -2
- package/dist/lib/{VirtualScroller-ggPTCQb0.js.map → VirtualScroller-Csa3GBSM.js.map} +1 -1
- package/dist/lib/Window-CQ14_65z.js +2 -0
- package/dist/lib/Window-CQ14_65z.js.map +1 -0
- package/dist/lib/component/button.es.js +1 -1
- package/dist/lib/component/button.es.js.map +1 -1
- package/dist/lib/component/chart.es.js +1 -1
- package/dist/lib/component/chart.es.js.map +1 -1
- package/dist/lib/component/container.es.js +1 -1
- package/dist/lib/component/container.es.js.map +1 -1
- package/dist/lib/component/diagram.es.js +1 -1
- package/dist/lib/component/diagram.es.js.map +1 -1
- package/dist/lib/component/display.es.js +1 -1
- package/dist/lib/component/display.es.js.map +1 -1
- package/dist/lib/component/editor.es.js +2 -2
- package/dist/lib/component/editor.es.js.map +1 -1
- package/dist/lib/component/input.es.js +1 -1
- package/dist/lib/component/input.es.js.map +1 -1
- package/dist/lib/component/list.es.js +1 -1
- package/dist/lib/component/list.es.js.map +1 -1
- package/dist/lib/component/menubar.es.js +1 -1
- package/dist/lib/component/menubar.es.js.map +1 -1
- package/dist/lib/component/table.es.js +1 -6
- package/dist/lib/component/table.es.js.map +1 -1
- package/dist/lib/component/tree.es.js +1 -1
- package/dist/lib/component/tree.es.js.map +1 -1
- package/dist/lib/core-DpzpKLWE.js +2 -0
- package/dist/lib/core-DpzpKLWE.js.map +1 -0
- package/dist/lib/core.es.js +1 -2
- package/dist/lib/data.es.js +1 -1
- package/dist/lib/diagnostics.es.js +24 -0
- package/dist/lib/diagnostics.es.js.map +1 -0
- package/dist/lib/glyphs/solid/index.es.js +1 -1
- package/dist/lib/layout.es.js +1 -1
- package/dist/lib/layout.es.js.map +1 -1
- package/dist/lib/overlay.es.js +1 -1
- package/dist/lib/overlay.es.js.map +1 -1
- package/dist/lib/primitive-8YvORgGS.js +2 -0
- package/dist/lib/primitive-8YvORgGS.js.map +1 -0
- package/dist/lib/primitive.es.js +1 -2
- package/dist/lib/router.es.js +1 -1
- package/dist/lib/selectionsEqual-DWdW5pxP.js +2 -0
- package/dist/lib/{selectionsEqual-C7MrKMQr.js.map → selectionsEqual-DWdW5pxP.js.map} +1 -1
- package/dist/lib/types/component/button/Button.d.ts +6 -14
- package/dist/lib/types/component/button/TabButton.d.ts +3 -5
- package/dist/lib/types/component/button/TabCloseButton.d.ts +3 -0
- package/dist/lib/types/component/button/ToggleButton.d.ts +2 -5
- package/dist/lib/types/component/chart/AbstractChart.d.ts +2 -2
- package/dist/lib/types/component/container/AccordionHeader.d.ts +6 -1
- package/dist/lib/types/component/container/AccordionIndicator.d.ts +2 -0
- package/dist/lib/types/component/container/FieldSet.d.ts +2 -0
- package/dist/lib/types/component/container/LabeledFieldSet.d.ts +1 -1
- package/dist/lib/types/component/container/LabeledGrid.d.ts +4 -1
- package/dist/lib/types/component/container/Legend.d.ts +2 -2
- package/dist/lib/types/component/container/MenuItem.d.ts +1 -0
- package/dist/lib/types/component/container/WindowBorder.d.ts +2 -2
- package/dist/lib/types/component/container/WindowHeader.d.ts +6 -0
- package/dist/lib/types/component/diagram/DiagramEdgeLayer.d.ts +10 -0
- package/dist/lib/types/component/diagram/DiagramGroupNode.d.ts +2 -0
- package/dist/lib/types/component/diagram/DiagramNode.d.ts +6 -2
- package/dist/lib/types/component/diagram/DiagramNodeLayer.d.ts +25 -0
- package/dist/lib/types/component/diagram/DiagramResidency.d.ts +11 -0
- package/dist/lib/types/component/diagram/DiagramView.d.ts +22 -0
- package/dist/lib/types/component/input/AbstractCalendarDropdown.d.ts +4 -4
- package/dist/lib/types/component/input/AbstractInput.d.ts +1 -0
- package/dist/lib/types/component/input/AbstractPickerField.d.ts +4 -2
- package/dist/lib/types/component/input/AutoCompleteDropdown.d.ts +2 -2
- package/dist/lib/types/component/input/AutoCompleteField.d.ts +1 -0
- package/dist/lib/types/component/input/ComboBox.d.ts +5 -2
- package/dist/lib/types/component/input/Link.d.ts +2 -2
- package/dist/lib/types/component/input/PasswordField.d.ts +2 -2
- package/dist/lib/types/component/input/PickerButton.d.ts +5 -2
- package/dist/lib/types/component/input/PickerInput.d.ts +2 -2
- package/dist/lib/types/component/input/SelectableText.d.ts +2 -2
- package/dist/lib/types/component/input/SpinButton.d.ts +3 -2
- package/dist/lib/types/component/input/Text.d.ts +3 -7
- package/dist/lib/types/component/input/TextArea.d.ts +2 -2
- package/dist/lib/types/component/input/TextField.d.ts +2 -2
- package/dist/lib/types/component/input/TextInput.d.ts +4 -2
- package/dist/lib/types/component/input/TimePickerDropdown.d.ts +2 -2
- package/dist/lib/types/component/input/UsernameField.d.ts +2 -2
- package/dist/lib/types/component/list/AbstractMarkerList.d.ts +2 -0
- package/dist/lib/types/component/list/AbstractSelectableList.d.ts +4 -2
- package/dist/lib/types/component/list/ListItem.d.ts +2 -1
- package/dist/lib/types/component/menubar/MenuBarButton.d.ts +3 -0
- package/dist/lib/types/component/menubar/ToolBar.d.ts +2 -0
- package/dist/lib/types/component/table/Body.d.ts +14 -6
- package/dist/lib/types/component/table/Column.d.ts +2 -0
- package/dist/lib/types/component/table/ColumnConfig.d.ts +1 -0
- package/dist/lib/types/component/table/Footer.d.ts +2 -0
- package/dist/lib/types/component/table/Header.d.ts +7 -0
- package/dist/lib/types/component/table/Row.d.ts +2 -0
- package/dist/lib/types/component/table/Table.d.ts +4 -1
- package/dist/lib/types/component/table/TablePanel.d.ts +5 -0
- package/dist/lib/types/component/table/TreeTablePanel.d.ts +5 -0
- package/dist/lib/types/component/table/cell/Cell.d.ts +3 -2
- package/dist/lib/types/component/table/cell/Header.d.ts +4 -3
- package/dist/lib/types/component/table/cell/ParentHeader.d.ts +4 -0
- package/dist/lib/types/component/tree/TreeRow.d.ts +2 -0
- package/dist/lib/types/core/AnimatedDropdown.d.ts +2 -2
- package/dist/lib/types/core/Binding.d.ts +1 -0
- package/dist/lib/types/core/ClassStyleRules.d.ts +44 -22
- package/dist/lib/types/core/Component.d.ts +55 -28
- package/dist/lib/types/core/DOM.d.ts +6 -0
- package/dist/lib/types/core/Diagnostics.d.ts +22 -0
- package/dist/lib/types/core/Event.d.ts +7 -0
- package/dist/lib/types/core/LayerManager.d.ts +2 -0
- package/dist/lib/types/core/ListenerBag.d.ts +1 -0
- package/dist/lib/types/core/StyleTarget.d.ts +12 -0
- package/dist/lib/types/core/StyleTraits.d.ts +4 -0
- package/dist/lib/types/core/Theme.d.ts +5 -2
- package/dist/lib/types/core/index.d.ts +5 -2
- package/dist/lib/types/diagnostics/DiagnosticsOverlay.d.ts +29 -0
- package/dist/lib/types/diagnostics/DiagnosticsSampler.d.ts +61 -0
- package/dist/lib/types/diagnostics/StyleAudit.d.ts +19 -0
- package/dist/lib/types/diagnostics/StyleAuditOverlay.d.ts +12 -0
- package/dist/lib/types/diagnostics/StyleAuditView.d.ts +13 -0
- package/dist/lib/types/diagnostics/index.d.ts +7 -0
- package/dist/lib/types/layout/LayoutManager.d.ts +3 -0
- package/dist/lib/types/layout/Table.d.ts +1 -0
- package/dist/lib/types/overlay/AbstractWindow.d.ts +35 -2
- package/dist/lib/types/overlay/ButtonGroup.d.ts +1 -0
- package/dist/lib/types/overlay/Dialog.d.ts +1 -0
- package/dist/lib/types/overlay/Menu.d.ts +2 -0
- package/dist/lib/types/overlay/Notification.d.ts +0 -1
- package/dist/lib/types/overlay/PopupPanel.d.ts +2 -2
- package/dist/lib/types/overlay/RailHandle.d.ts +4 -5
- package/dist/lib/types/overlay/TabWindow.d.ts +3 -0
- package/dist/lib/types/overlay/Tooltip.d.ts +1 -0
- package/dist/lib/types/overlay/Window.d.ts +4 -1
- package/dist/lib/validation.es.js +1 -1
- package/llms.txt +2 -0
- package/package.json +5 -1
- package/dist/lib/AbstractInput-W2PLJV5_.js +0 -2
- package/dist/lib/AbstractInput-W2PLJV5_.js.map +0 -1
- package/dist/lib/AnimatedDropdown-D0RhVgv3.js.map +0 -1
- package/dist/lib/Border-6GsTNV-2.js +0 -2
- package/dist/lib/Border-6GsTNV-2.js.map +0 -1
- package/dist/lib/Button-CnFAiQuV.js +0 -2
- package/dist/lib/Button-CnFAiQuV.js.map +0 -1
- package/dist/lib/Checkbox-CM1z8keM.js +0 -2
- package/dist/lib/Checkbox-CM1z8keM.js.map +0 -1
- package/dist/lib/CheckboxMenuRow-C1h4LPHR.js +0 -2
- package/dist/lib/CheckboxMenuRow-C1h4LPHR.js.map +0 -1
- package/dist/lib/CodeEditor-CTL2WjF8.js +0 -2
- package/dist/lib/CodeEditor-CTL2WjF8.js.map +0 -1
- package/dist/lib/ComboBox-PZ5YPL0X.js +0 -2
- package/dist/lib/ComboBox-PZ5YPL0X.js.map +0 -1
- package/dist/lib/Component-D99-15Zt.js +0 -2
- package/dist/lib/Component-D99-15Zt.js.map +0 -1
- package/dist/lib/Container-FWRjgF6T.js +0 -2
- package/dist/lib/DOM-Cjh7_7TF.js +0 -2
- package/dist/lib/DOM-Cjh7_7TF.js.map +0 -1
- package/dist/lib/Dialog-DN78RaVH.js +0 -2
- package/dist/lib/Dialog-DN78RaVH.js.map +0 -1
- package/dist/lib/Glyph-DiEpD3gy.js +0 -2
- package/dist/lib/Glyph-DiEpD3gy.js.map +0 -1
- package/dist/lib/GridConstraints-CvZ0Nzaw.js +0 -2
- package/dist/lib/GridConstraints-CvZ0Nzaw.js.map +0 -1
- package/dist/lib/LayoutSerialization-BC64__O7.js +0 -2
- package/dist/lib/LayoutSerialization-BC64__O7.js.map +0 -1
- package/dist/lib/List-CQbZK_pT.js +0 -2
- package/dist/lib/List-CQbZK_pT.js.map +0 -1
- package/dist/lib/ListenerBag-WPdKuuds.js +0 -2
- package/dist/lib/ListenerBag-WPdKuuds.js.map +0 -1
- package/dist/lib/Menu-CwHluLGT.js +0 -2
- package/dist/lib/Menu-CwHluLGT.js.map +0 -1
- package/dist/lib/ProgressSpinner-BuBvC1FY.js +0 -2
- package/dist/lib/ProgressSpinner-BuBvC1FY.js.map +0 -1
- package/dist/lib/RadioButton-Df5J-H6m.js +0 -2
- package/dist/lib/RadioButton-Df5J-H6m.js.map +0 -1
- package/dist/lib/RadioMenuRow-Cfv0x6Qj.js +0 -2
- package/dist/lib/RadioMenuRow-Cfv0x6Qj.js.map +0 -1
- package/dist/lib/Scrollbar-DcnueNJd.js +0 -2
- package/dist/lib/Scrollbar-DcnueNJd.js.map +0 -1
- package/dist/lib/SelectableText-DZNxjKXR.js +0 -2
- package/dist/lib/SelectableText-DZNxjKXR.js.map +0 -1
- package/dist/lib/Slider-DNfd8Lxz.js +0 -2
- package/dist/lib/Slider-DNfd8Lxz.js.map +0 -1
- package/dist/lib/Spacer-BznfGbwG.js +0 -2
- package/dist/lib/Spacer-BznfGbwG.js.map +0 -1
- package/dist/lib/TabButton-CAACsMov.js +0 -2
- package/dist/lib/TabButton-CAACsMov.js.map +0 -1
- package/dist/lib/TabCloseButton-CCiqsX3y.js +0 -2
- package/dist/lib/TabCloseButton-CCiqsX3y.js.map +0 -1
- package/dist/lib/Text-O-FWa5Cy.js +0 -2
- package/dist/lib/Text-O-FWa5Cy.js.map +0 -1
- package/dist/lib/Tooltip-CyICVu15.js +0 -3
- package/dist/lib/Tooltip-CyICVu15.js.map +0 -1
- package/dist/lib/Tree-CSEguhlk.js +0 -2
- package/dist/lib/Tree-CSEguhlk.js.map +0 -1
- package/dist/lib/core.es.js.map +0 -1
- package/dist/lib/primitive.es.js.map +0 -1
- package/dist/lib/selectionsEqual-C7MrKMQr.js +0 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Window-CQ14_65z.js","names":[],"sources":["../../src/typescript/lib/component/container/WindowBorder.ts","../../src/typescript/lib/component/display/SpinnerWrap.ts","../../src/typescript/lib/overlay/AbstractWindow.ts","../../src/typescript/lib/overlay/windowControls.ts","../../src/typescript/lib/component/container/WindowHeader.ts","../../src/typescript/lib/overlay/Window.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { StyleBag, StyleStateSpec } from \"~/core/ClassStyleRules.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { beginPointerDrag, endPointerDrag } from \"~/core/PointerDrag.js\";\nimport { ListenerBag } from \"~/core/ListenerBag.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * String-literal union of the events emitted by {@link WindowBorder}.\n *\n * @category Components\n */\nexport type WindowBorderEvent = \"drag\";\n\n/**\n * The eight edge / corner positions used by {@link WindowBorder} to identify\n * which border strip the user is dragging.\n *\n * @category Components\n */\nexport enum Direction {\n NORTH,\n SOUTH,\n WEST,\n EAST,\n NORTHWEST,\n SOUTHEAST,\n SOUTHWEST,\n NORTHEAST\n}\n\n/**\n * Construction-time options for {@link WindowBorder}.\n *\n * @category Components\n */\nexport interface WindowBorderOptions extends ComponentOptions {\n /**\n * Multi-event listener bag dispatched to {@link WindowBorder.on} at\n * construction time.\n */\n listeners?: {\n drag?: (border: WindowBorder, e: MouseEvent) => void;\n };\n}\n\n/**\n * CSS class added to the DOM element of the currently snap-targeted strip.\n * Kept package-private (`@internal`) — the owning [`Window`](/api/overlay/classes/Window)\n * toggles it through {@link WindowBorder.setSnapTarget}.\n *\n * @internal\n */\nconst SNAP_TARGET_CLASS = \"snap-target\";\n\n/**\n * Class-level defaults forwarded to `super` so the cascade hits Component's\n * applyOptions with `{ tag: \"div\" }` already merged into `_defaultOptions`.\n */\nconst _defaultWindowBorderOptions: Partial<WindowBorderOptions> = {\n tag: \"div\",\n};\n\n/** `.snap-target`'s box-shadow declaration, read by `ownStyleStates`' entry below. */\nconst WINDOW_BORDER_SNAP_TARGET_DECLARATIONS: Readonly<Record<string, string>> = Object.freeze({\n boxShadow: \"var(--ts-ui-window-snap-glow, 0 0 0 2px rgba(30, 100, 200, 0.7))\",\n});\n\n/**\n * A resizable window border strip component.\n *\n * Each instance represents one edge or corner of a resizable window. It listens for\n * mouse/touch drag events and notifies registered listeners with the mouse event so\n * the parent window can compute and apply the new size.\n *\n * @category Components\n */\nclass WindowBorder extends Component<WindowBorderOptions> {\n\n // Declares `.snap-target` so `styleLayers()`/`restingGuardSuffix` know\n // about it — see `Button`'s `ownStyleStates` for the full mechanism.\n protected static readonly ownStyleStates: readonly StyleStateSpec[] = [\n {\n selector: \".\" + SNAP_TARGET_CLASS,\n extract: (): StyleBag => ({ shadow: WINDOW_BORDER_SNAP_TARGET_DECLARATIONS.boxShadow }),\n },\n ];\n\n private _direction: Direction = Direction.NORTH;\n private _listeners: ListenerBag<WindowBorderEvent> = this.registerListenerBag(new ListenerBag<WindowBorderEvent>());\n private _dragStartListener: Event.Listener;\n private _dragStopListener: Event.Listener;\n private _fireDragListener: Event.Listener;\n private _snapTarget: boolean = false;\n\n /**\n * @param direction - Which window edge (or corner) this border drives.\n * @param options - Optional construction options.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; subclasses forward their `_defaultXxxOptions`\n * constant here.\n */\n constructor(\n direction: Direction,\n options?: WindowBorderOptions,\n subclassDefaults?: Partial<WindowBorderOptions>,\n ) {\n super(options, { ..._defaultWindowBorderOptions, ...(subclassDefaults ?? {}) });\n\n if (direction) {\n this._direction = direction;\n }\n\n // Set here, not in `render()`: a construction-time `writeStyle` (which\n // `setCursor` funnels through) only caches into the instance style\n // layer and defers its CSS write to the render pass's own\n // `applyStyle` sweep. Calling it *after* `super.render()` instead —\n // as this used to — writes through `getElement()`, which is not yet\n // resolvable at that point (the element has no live-DOM id match and\n // isn't cached as `_element` until `render()` returns to its caller),\n // so the write silently deferred and, with no second `applyStyle()`\n // pass ever running for a border strip, was dropped for good.\n const cursor = this.dragCursor();\n if (cursor) {\n this.setCursor(cursor);\n }\n\n this._dragStartListener = this.onDragStart.bind(this);\n this._dragStopListener = this.onDragStop.bind(this);\n this._fireDragListener = this._dispatchDrag.bind(this);\n\n Event.addListener(this, 'mousedown', this._dragStartListener);\n\n this.applyListeners(options?.listeners);\n }\n\n /**\n * Returns the resize direction of this border strip.\n *\n * @returns The Direction enum value for this border.\n */\n getDirection() {\n return this._direction;\n }\n\n /**\n * Sets the resize direction, defaulting to NORTH if not provided.\n *\n * @param direction - The Direction enum value. Defaults to NORTH if falsy.\n */\n setDirection(direction: Direction) : this {\n if (!direction) {\n direction = Direction.NORTH;\n }\n\n this._direction = direction;\n\n return this;\n }\n\n /**\n * Registers a listener for one of this border's events.\n *\n * @param event - `\"drag\"` fires on each mousemove/touchmove during a\n * drag, receiving this border and the originating event.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This border, for method chaining.\n */\n on(event: \"drag\", listener: (border: WindowBorder, e: MouseEvent) => void): this;\n on(event: WindowBorderEvent, listener: Function): this {\n this._listeners.add(event, listener);\n\n return this;\n }\n\n /**\n * Removes a previously registered listener. The exact callback reference\n * must match.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This border, for method chaining.\n */\n off(event: WindowBorderEvent, listener: Function): this {\n this._listeners.remove(event, listener);\n\n return this;\n }\n\n /**\n * Fires every listener registered for `event` with `payload`, in\n * registration order.\n *\n * @param event - The event to emit.\n * @param payload - Forwarded to each listener.\n */\n protected emit(event: \"drag\", border: WindowBorder, e: MouseEvent): void;\n protected emit(event: WindowBorderEvent, ...payload: unknown[]): void {\n this._listeners.fire(event, ...payload);\n }\n\n /**\n * Internal mousemove dispatch — fires the `drag` event with this border\n * and the originating mouse event.\n *\n * @param e - The MouseEvent observed by the viewport-mousemove listener.\n * @returns `true`, consuming the move so nothing else tracks the pointer mid-resize.\n */\n private _dispatchDrag(e: MouseEvent): Event.ListenerResult {\n this.emit(\"drag\", this, e);\n\n return true;\n }\n\n /**\n * Returns whether this border strip is currently flagged as the snap target.\n *\n * @returns True when the snap-target CSS class is applied.\n */\n isSnapTarget(): boolean {\n return this._snapTarget;\n }\n\n /**\n * Toggles the snap-target CSS class on this strip's DOM element. Called by\n * the owning [`Window`](/api/overlay/classes/Window) while the snap modifier\n * is held and the cursor is within the configured threshold.\n *\n * @param value - True to highlight this strip as the snap target.\n *\n * @returns This component, for method chaining.\n */\n setSnapTarget(value: boolean): this {\n if (this._snapTarget === value) {\n return this;\n }\n\n this._snapTarget = value;\n\n // Unconditional, not gated on `this.getElement()`: `setStyleState`\n // updates `_activeStates` regardless of whether an element exists\n // yet (only its own DOM write is internally element-gated) — see\n // `ToggleButton.setSelected`'s own comment for the full reasoning.\n this.setStyleState(\".\" + SNAP_TARGET_CLASS, value);\n\n return this;\n }\n\n /**\n * Attaches viewport mouse/touch move and stop listeners and disables body pointer events.\n *\n * @param e - The originating mousedown event. Optional so a caller can\n * trigger a drag with no real event; when supplied — both the strip's\n * own `mousedown` wiring and `AbstractWindow`'s snap-resize forwarding\n * (`onSnapMouseDown`, reached through an unfiltered viewport listener)\n * always do — a non-primary button is rejected.\n */\n onDragStart(e?: MouseEvent) {\n if (e && !Event.isPrimaryButton(e)) {\n return;\n }\n\n Event.addViewportListener(this, 'mouseup', this._dragStopListener);\n Event.addViewportListener(this, 'touchend', this._dragStopListener);\n Event.addViewportListener(this, 'touchcancel', this._dragStopListener);\n Event.addViewportListener(this, 'mousemove', this._fireDragListener);\n Event.addViewportListener(this, 'touchmove', this._fireDragListener);\n\n // A direction with no resize cursor of its own still suppresses body\n // pointer events; it just has nothing to hold, so it keeps the default.\n beginPointerDrag(this.dragCursor() ?? \"default\");\n }\n\n /**\n * Removes viewport listeners and restores body pointer events when drag ends.\n *\n * @returns `true`, consuming the release that ends the border resize.\n */\n onDragStop(): Event.ListenerResult {\n Event.removeViewportListener(this, 'mouseup', this._dragStopListener);\n Event.removeViewportListener(this, 'touchend', this._dragStopListener);\n Event.removeViewportListener(this, 'touchcancel', this._dragStopListener);\n Event.removeViewportListener(this, 'mousemove', this._fireDragListener);\n Event.removeViewportListener(this, 'touchmove', this._fireDragListener);\n\n endPointerDrag();\n\n // Drop the snap-target highlight (if any) once the drag commits, so a\n // subsequent Ctrl-release on the same hover doesn't leave the strip glowing.\n this.setSnapTarget(false);\n\n return true;\n }\n\n /**\n * The resize cursor for the edge or corner this strip sits on, shared by the\n * hover state and the drag itself so the two can never disagree.\n *\n * @returns The CSS cursor naming the resize axis, or `undefined` for a\n * direction that does not resize.\n */\n private dragCursor(): string | undefined {\n switch (this._direction) {\n case Direction.NORTH:\n case Direction.SOUTH:\n return \"ns-resize\";\n case Direction.WEST:\n case Direction.EAST:\n return \"ew-resize\";\n case Direction.NORTHWEST:\n case Direction.SOUTHEAST:\n return \"nwse-resize\";\n case Direction.SOUTHWEST:\n case Direction.NORTHEAST:\n return \"nesw-resize\";\n }\n\n return undefined;\n }\n\n /**\n * Renders the border element. The resize cursor is set at construction\n * time (see the constructor) rather than here.\n *\n * @returns The created element.\n */\n render() {\n let element = super.render();\n\n if (this._snapTarget) {\n DOM.sink.apply(element, { addClass: [SNAP_TARGET_CLASS] });\n }\n\n return element;\n }\n\n}\n\nconst WindowBorderCallable = callable(WindowBorder);\ntype WindowBorderCallable = WindowBorder;\nexport {\n WindowBorder as _WindowBorder,\n WindowBorderCallable as WindowBorder\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { Fit } from \"~/layout/Fit.js\";\nimport { FillType } from \"~/layout/FillType.js\";\nimport { ProgressSpinner } from \"~/component/display/ProgressSpinner.js\";\n\n/**\n * Shared visual recipe for the placeholder [`Animation.materialize`](/api/core/namespaces/Animation/functions/materialize)\n * mounts while it waits on a deferred build: {@link Tab}'s lazy-tab\n * activation and {@link AbstractWindow}'s `setContentFactory` both need the\n * same centred spinner, so the construction lives here as the single source\n * of truth rather than duplicated at each call site.\n *\n * @category Core\n */\n\n/**\n * Builds the spinner placeholder `Animation.materialize` mounts into its host:\n * a fixed-size `ProgressSpinner` wrapped in a [`Fit`](/api/layout/classes/Fit)\n * layout configured with `FillType.NONE` so the spinner sits at its preferred\n * size in the geometric centre of the host's content area. The diameter\n * (24 px) matches `TablePanel`'s store-loading spinner so a slow deferred\n * build and a slow data load look identical to the user.\n *\n * @returns A Component owning a single `ProgressSpinner` child.\n */\nexport function createSpinnerWrap(): Component {\n const wrap = new Component();\n wrap.setLayoutManager(new Fit({ fill: FillType.NONE }));\n wrap.addComponent(new ProgressSpinner(24));\n\n return wrap;\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { Util } from \"~/core/Util.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { WindowBorder, Direction } from \"~/component/container/WindowBorder.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { Animation } from \"~/core/Animation.js\";\nimport { LayerManager, DismissableLayer, LayerDismissMode } from \"~/core/LayerManager.js\";\nimport { trapWheel, untrapWheel } from \"~/core/WheelTrap.js\";\nimport { createSpinnerWrap } from \"~/component/display/SpinnerWrap.js\";\nimport { Container, ContainerOptions } from \"~/core/Container.js\";\nimport type { StyleBag } from \"~/core/ClassStyleRules.js\";\nimport { ListenerBag } from \"~/core/ListenerBag.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { Size } from \"~/primitive/Size.js\";\nimport { Placement } from \"~/primitive/Placement.js\";\nimport type { Rail } from \"~/overlay/Rail.js\";\nimport { Menu } from \"~/overlay/Menu.js\";\nimport { MenuItemConfig } from \"~/component/container/MenuItem.js\";\nimport { CheckboxMenuRow } from \"~/component/container/CheckboxMenuRow.js\";\n\n// Window body inset in pixels, set explicitly now that the base is Container\n// (zero default insets) rather than Panel (which supplied this 4px implicitly).\n// `doLayout` folds this inset into the resize-border thickness, so it both pads\n// the body content and reserves the grab band the WindowBorder handles sit in;\n// 4px preserves the exact resting geometry windows inherited from Panel before\n// the reparent.\nconst WINDOW_BODY_INSET_PX: number = 4;\nconst WINDOW_ANIM_DURATION_MS: number = 150;\n// Size delta, in pixels on the larger-changing axis, above which a window-state\n// transition swaps its plain rect tween for the fade path below. Below the\n// threshold every tween frame relays out the body's real content, which is\n// cheap for an ordinary window; above it, a virtualized body (a wide table)\n// would have to build a burst of newly-revealed cells on every frame, which\n// reads as a stutter, so the fade path instead pauses the body's own layout\n// for the glide and pays for that relayout once, when it lands. 960 px is\n// half a 1920-wide screen: a sweep that reveals more than that much new\n// content in 150 ms is where that per-frame cost would start to show.\nconst WINDOW_FADE_THRESHOLD_PX: number = 960;\n// Duration of each leg of that fade. 100 ms (this constant's original value)\n// armed and completed correctly but read as an instant cut rather than a\n// fade: a handful of frames isn't enough for a human eye to register motion\n// rather than a flicker. 200 ms per leg is long enough to read as a\n// deliberate fade.\nconst WINDOW_FADE_DURATION_MS: number = 200;\n// Animation.play's fallback-timer grace period for the fade-in leg only (see\n// fadeRectSwap), applied on top of WINDOW_FADE_DURATION_MS. resumeLayout's\n// relayout runs synchronously just before this leg is armed, and for\n// expensive content (a wide virtualized table can take several hundred\n// milliseconds to lay out its cells) that leaves the main thread too busy to\n// reach the style recalculation that starts the transition before\n// Animation.play's own default 40 ms buffer already expires — its pre-rearm\n// fallback then fires first, clearing the fade before the browser ever\n// paints a frame of it, so the \"fade\" reads as an instant pop. A late\n// transitionstart already re-arms the deadline from its own real start, so\n// this only pads how long the pre-rearm timer waits for that first signal\n// before giving up; it never delays a transition that starts and completes\n// on time.\nconst WINDOW_FADE_IN_FALLBACK_BUFFER_MS: number = 1000;\nconst SNAP_DOCK_GAP_PX: number = 4;\nconst DEFAULT_MIN_DOCK_WIDTH_PX: number = 200;\n// Must-stay-visible slab of a window edge, used only when constrainToViewport is\n// disabled: in that fallback the drag keeps at least this many pixels of the\n// window inside the viewport so its header bar can never be dropped fully\n// off-screen and become ungrabbable. The default, full-window containment never\n// consults this. 24 px is wide enough to grab with a cursor yet narrow enough\n// not to feel restrictive.\nconst EDGE_MARGIN_PX: number = 24;\n// Fallback chrome-band height used before the window has laid out, when the\n// title chrome's measured height (`chromeHeight()`) still reads 0. 26 px is the\n// default chrome height a `Window` header renders at, so a pre-layout geometry\n// calculation lands on the same footprint the laid-out window will have.\nconst CHROME_HEIGHT_FLOOR_PX: number = 26;\n// Clearance a normal-state window is refit inside of after a viewport resize\n// (see `fitNormalWindowToViewport`) — deliberately wider than `EDGE_MARGIN_PX`\n// since this refit can also shrink the window, so the margin doubles as\n// breathing room around the resized box rather than just a grab strip.\nconst VIEWPORT_RESIZE_MARGIN_PX: number = 50;\n\n/**\n * Lifecycle state for an {@link AbstractWindow}. The three values are mutually\n * exclusive — a window is always exactly one of:\n *\n * - `\"normal\"` — free-floating; user can drag and resize it.\n * - `\"minimized\"` — docked along the bottom of the viewport at header height.\n * - `\"maximized\"` — filling the viewport (or its parent, per `maximizeBounds`).\n *\n * The state field carries no presentation state; the corresponding rect and\n * body-visibility are computed by the window's state-transition switch.\n *\n * @category Core\n */\nexport type WindowState = \"normal\" | \"minimized\" | \"maximized\";\n\n/**\n * Typed events an {@link AbstractWindow} emits. `\"minimize\"` fires when the\n * window enters `\"minimized\"`, `\"restore\"` when it leaves it, `\"close\"` when\n * the window is closed, and `\"activate\"` when the window becomes the active\n * layer (a raise / focus). A [`Rail`](/api/overlay/classes/Rail) subscribes to\n * the first three to mirror a window minimized into it as a launcher handle; a\n * [`Dock`](/api/overlay/classes/Dock) subscribes to `\"activate\"` to track which\n * floated panel is focused.\n *\n * @category Core\n */\nexport type WindowEvent = \"minimize\" | \"restore\" | \"close\" | \"activate\";\n\n/**\n * Snap-resize modifier key. Matches the matching property names exposed by\n * `KeyboardEvent`.\n *\n * @category Core\n */\nexport type WindowSnapModifier = \"ctrl\" | \"meta\" | \"alt\" | \"shift\";\n\n/**\n * Where to fill when entering the `\"maximized\"` state.\n *\n * - `\"viewport\"` — fill `window.innerWidth` / `window.innerHeight` (default;\n * matches the natural mount point since the window appends itself directly to\n * `document.documentElement`).\n * - `\"parent\"` — fill the window element's `parentElement` rect. Use when\n * the window has been re-parented into a regular Panel.\n *\n * @category Core\n */\nexport type WindowMaximizeBounds = \"viewport\" | \"parent\";\n\n/**\n * A window's rectangle in viewport pixels.\n *\n * @category Core\n */\nexport interface WindowRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * Construction-time options for {@link AbstractWindow} and its subclasses.\n *\n * @category Core\n */\nexport interface WindowOptions extends ContainerOptions {\n headerText?: string;\n glyph?: string;\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n contentFactory?: () => Component;\n onReady?: (component: Component) => void;\n closeable?: boolean;\n minimizable?: boolean;\n maximizable?: boolean;\n /** Enables the drag-to-resize border strips. Defaults to `true`. */\n resizable?: boolean;\n /** Keeps the window above every unpinned window. Defaults to `false`. */\n alwaysOnTop?: boolean;\n /** Freezes the window: no drag-to-move and no drag-to-resize. Defaults to `false`. */\n locked?: boolean;\n maximizeBounds?: WindowMaximizeBounds;\n windowState?: WindowState;\n snapResizeEnabled?: boolean;\n snapThreshold?: number;\n snapModifier?: WindowSnapModifier;\n constrainToViewport?: boolean;\n}\n\n/**\n * User-overridable visual defaults forwarded to `super` via the options bag.\n * The cascade in `Component`'s constructor dispatches each setter once with\n * the final value, so any field the caller supplied wins. `headerText`,\n * `glyph`, `contentFactory`, and `onReady` touch subclass chrome or the\n * `contentFactory` field (both initialised after `super`), so `applyOptions`\n * writes them pure into `_options` and the constructor body dispatches them\n * once the children/fields exist.\n */\nconst _defaultWindowOptions: Partial<WindowOptions> = {\n x: 50,\n y: 50,\n width: 400,\n height: 300,\n insets: new Insets(WINDOW_BODY_INSET_PX, WINDOW_BODY_INSET_PX, WINDOW_BODY_INSET_PX, WINDOW_BODY_INSET_PX),\n border: \"1px solid var(--ts-ui-border-color, black)\",\n borderRadius: \"var(--ts-ui-border-radius, 4px)\",\n shadow: \"var(--ts-ui-window-shadow, 3px 3px 2px rgba(0, 0, 0, 0.4))\",\n backgroundColor: \"var(--ts-ui-body-bg, rgb(241, 241, 241))\",\n closeable: true,\n minimizable: true,\n maximizable: true,\n resizable: true,\n alwaysOnTop: false,\n locked: false,\n maximizeBounds: \"viewport\",\n windowState: \"normal\",\n snapResizeEnabled: true,\n snapThreshold: 12,\n snapModifier: \"ctrl\",\n constrainToViewport: true,\n};\n\n// z-index for the eight resize handles, lifting them above the window's content\n// layers so the edges and corners stay grabbable even when content paints over\n// the gutter — a TabWindow bar (`barIgnoreParentInsets`) or a Window header\n// (`ignoreParentInsets`) reaches the outer edge, and the layout-manager bar is\n// appended *after* the handles in DOM, so without an explicit z-index it would\n// win hit-testing. 10 sits comfortably above the tab bar's internal chrome\n// (tool group, indicator, scroll-arrow buttons top out at z-index 3).\nconst RESIZE_BORDER_Z_INDEX: number = 10;\n\n/**\n * Header-agnostic base for floating, resizable, draggable windows.\n *\n * Owns everything that does not name a title-bar header: the eight resize-handle\n * border strips, the move drag flow, the three-state lifecycle (`\"normal\"` /\n * `\"minimized\"` / `\"maximized\"`), the closeable / minimizable / maximizable\n * *state*, active-focus *state*, z-order, show/hide, the min-size seed\n * *mechanism*, and the open-windows registry. Everything that differs per\n * subclass — how the move gesture is wired, how state reflects into UI, how the\n * title reads, how content is added, how tall the chrome is, and which child is\n * chrome — is delegated to `protected`/`abstract` hooks.\n *\n * Two concrete subclasses extend it: {@link Window} (a `Border` layout with a\n * `WindowHeader`) and `TabWindow` (a headerless `Tab` layout).\n *\n * @category Core\n */\nexport abstract class AbstractWindow extends Container<WindowOptions> implements DismissableLayer {\n\n // Own contribution to the hierarchy-aware class tier — see\n // plans/implemented/class-hierarchy-cascade.md.\n protected static readonly ownClassStyleDefaults: StyleBag = _defaultWindowOptions;\n\n private static openWindows: Set<AbstractWindow> = new Set<AbstractWindow>();\n\n private _borderComponents: {\n west: WindowBorder,\n northwest: WindowBorder,\n north: WindowBorder,\n northeast: WindowBorder,\n east: WindowBorder,\n southeast: WindowBorder,\n south: WindowBorder,\n southwest: WindowBorder,\n };\n\n private _animationFrameId: number | null = null;\n private _pendingClientX: number = 0;\n private _pendingClientY: number = 0;\n private _pendingBorder: WindowBorder | null = null;\n private _resizeSessionActive: boolean = false;\n private _resizeOriginClientX: number = 0;\n private _resizeOriginClientY: number = 0;\n private _resizeOriginX: number = 0;\n private _resizeOriginY: number = 0;\n private _resizeOriginW: number = 0;\n private _resizeOriginH: number = 0;\n private _resizeFps: number = 60;\n private _lastFlushTime: number = 0;\n private _dragStartLeft: number = 0;\n private _dragStartTop: number = 0;\n private _dragOriginClientX: number = 0;\n private _dragOriginClientY: number = 0;\n private _dragDX: number = 0;\n private _dragDY: number = 0;\n // Lowest / highest top-left coordinate the window has reached during the\n // in-progress move drag, per axis. Seeded to the drag origin in\n // startMoveFrom and ratcheted in clampDragDelta so an off-screen edge can\n // only ever travel back toward the viewport, never further out — even\n // mid-drag after reversing direction.\n private _dragReachMinX: number = 0;\n private _dragReachMaxX: number = 0;\n private _dragReachMinY: number = 0;\n private _dragReachMaxY: number = 0;\n private _contentFactory: (() => Component) | null = null;\n private _contentReadyCallback: ((component: Component) => void) | null = null;\n\n protected _preMinimizeState: \"normal\" | \"maximized\" = \"normal\";\n private _restoreRect: WindowRect | null = null;\n private _normalMinSize: Size | null = null;\n private _bodyHost: Component | null = null;\n /** True while a fade owns the body host's inline opacity. See `endBodyFade`. */\n private _bodyFadeActive: boolean = false;\n\n /** Rail this window minimizes into, or null for the built-in bottom strip. */\n private _rail: Rail | null = null;\n /** Lazily-created rebuild-mode window menu — see `openWindowMenu`. */\n private _windowMenu: Menu | null = null;\n /** Typed-event fan-out for `\"minimize\"` / `\"restore\"` / `\"close\"`. */\n private _windowListeners: ListenerBag<WindowEvent> = this.registerListenerBag(new ListenerBag<WindowEvent>());\n private _stateAnimHandle: Animation.CancelHandle | null = null;\n\n // In-flight animations, cancelled on teardown so their fallback timers\n // cannot fire against this window's released element handle.\n private _showAnimation: Animation.CancelHandle | null = null;\n private _materializeAnimation: Animation.CancelHandle | null = null;\n private _closeAnimation: Animation.CancelHandle | null = null;\n private _railCollapseAnimation: Animation.CancelHandle | null = null;\n private _railExpandAnimation: Animation.CancelHandle | null = null;\n private _viewportResizeBound: boolean = false;\n\n private _snapEnabled: boolean = false;\n private _snapKeysAttached: boolean = false;\n private _snapMoveAttached: boolean = false;\n private _snapTargetBorder: WindowBorder | null = null;\n\n private readonly _boundOnDrag: (e: MouseEvent) => Event.ListenerResult = (e: MouseEvent) => this.onDrag(e);\n private readonly _boundOnMouseUp: () => Event.ListenerResult = () => this.onMouseUp();\n private readonly _boundOnResizeEnd: () => Event.ListenerResult = () => this.onResizeEnd();\n private readonly _boundOnSnapKeyDown: (e: KeyboardEvent) => void = (e) => this.onSnapKeyDown(e);\n private readonly _boundOnSnapKeyUp: (e: KeyboardEvent) => void = (e) => this.onSnapKeyUp(e);\n private readonly _boundOnSnapMouseMove: (e: MouseEvent) => void = (e) => this.onSnapMouseMove(e);\n private readonly _boundOnSnapMouseDown: (e: MouseEvent) => Event.ListenerResult = (e) => this.onSnapMouseDown(e);\n private readonly _boundOnViewportResize: () => void = () => this.onViewportResize();\n private readonly _boundOnSnapBlur: () => void = () => this.clearSnapState();\n private readonly _boundOnBorderResize: (border: WindowBorder, e: MouseEvent) => void = (border, e) => this.onResize(border, e);\n private readonly _boundOnBringToFront: () => void = () => this.bringToFront();\n // Bound `action` handlers for the window menu's Minimize/Maximize/Close\n // rows — a lazily-created, rebuild-mode Menu (see `openWindowMenu`).\n private readonly _boundToggleMinimize: () => void = () => this.toggleMinimize();\n private readonly _boundToggleMaximize: () => void = () => this.toggleMaximize();\n private readonly _boundRequestClose: () => void = () => this.requestClose();\n // Schedules a layout pass on theme change, so every `Text` under this\n // window re-measures lazily against the new theme's metrics — windows\n // are appended to `document.documentElement`, not to `Body`, so they need\n // their own root reflow subscription rather than sharing Body's.\n private readonly _boundOnThemeReflow: () => void = () => this.scheduleLayout();\n\n /**\n * Builds the chrome-agnostic, dereference-free part of a window: the eight\n * resize-border overlays, the hidden-until-shown / layout-containment flags,\n * and the bring-to-front subtree listener. The late state dispatch, the\n * `wireMoveTrigger()` call, and the min-size seed are deferred to\n * `initChrome`, which a subclass calls *after* it has\n * built its chrome — never here, where subclass chrome does not yet exist.\n *\n * @param options - The options bag carrying the window's configuration.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; subclasses forward their `_defaultXxxOptions`\n * constant here.\n */\n constructor(options?: WindowOptions, subclassDefaults?: Partial<WindowOptions>) {\n super(options, { ..._defaultWindowOptions, ...(subclassDefaults ?? {}) });\n\n this.subscribeTheme(this._boundOnThemeReflow);\n\n this._borderComponents = {\n west: new WindowBorder(Direction.WEST),\n northwest: new WindowBorder(Direction.NORTHWEST),\n north: new WindowBorder(Direction.NORTH),\n northeast: new WindowBorder(Direction.NORTHEAST),\n east: new WindowBorder(Direction.EAST),\n southeast: new WindowBorder(Direction.SOUTHEAST),\n south: new WindowBorder(Direction.SOUTH),\n southwest: new WindowBorder(Direction.SOUTHWEST),\n };\n\n this._borderComponents.west.on(\"drag\", this._boundOnBorderResize);\n this._borderComponents.northwest.on(\"drag\", this._boundOnBorderResize);\n this._borderComponents.north.on(\"drag\", this._boundOnBorderResize);\n this._borderComponents.northeast.on(\"drag\", this._boundOnBorderResize);\n this._borderComponents.east.on(\"drag\", this._boundOnBorderResize);\n this._borderComponents.southeast.on(\"drag\", this._boundOnBorderResize);\n this._borderComponents.south.on(\"drag\", this._boundOnBorderResize);\n this._borderComponents.southwest.on(\"drag\", this._boundOnBorderResize);\n\n // Keep the resize handles on top of the window's content (see\n // RESIZE_BORDER_Z_INDEX) so a bar/header that paints over the gutter does\n // not steal their edge/corner hit area.\n for (const border of Object.values(this._borderComponents)) {\n border.setZIndex(RESIZE_BORDER_Z_INDEX);\n }\n\n this.setVisible(false);\n // Resizable — size containment unsafe; layout containment scopes reflow to the window subtree.\n this.setContain(\"layout\");\n\n // Focusable as a unit so activation can move keyboard focus to the\n // window (see onActivate / focusSelf). -1 keeps it out of the Tab order\n // — focus is driven programmatically on activation, not by tabbing.\n this.getAria().setTabIndex(-1);\n\n // Any button brings the window to front — a right-click should raise\n // it before its context menu opens too, not just a left-click.\n Event.addSubtreeListener(this, \"mousedown\", { button: \"any\", handler: this._boundOnBringToFront });\n }\n\n /**\n * Runs the chrome-dependent late setup a subclass cannot do during\n * `super()`: dispatches the state-affecting option flags through the\n * `reflect*` hooks, registers the deferred content factory, installs the\n * move gesture via `wireMoveTrigger`, and seeds the\n * default min size from {@link AbstractWindow.minContentWidthSeed}. The\n * subclass constructor calls this *after* it has built its chrome (so the\n * hooks have something to reflect into), avoiding the class-field\n * super-cascade trap.\n *\n * @param options - The constructor's original options bag, consulted only\n * to skip the min-size seed when the caller supplied an explicit\n * `minSize`.\n */\n protected initChrome(options?: WindowOptions): void {\n if (this._options.contentFactory !== undefined) {\n this.setContentFactory(this._options.contentFactory, this._options.onReady);\n }\n\n // Late-built dispatch for state-affecting flags: these reflect into the\n // subclass chrome (minimizable / maximizable buttons or tools) or\n // trigger a tween (windowState), so they must run after the chrome is\n // built and the geometry fields are initialised.\n // All carry a class default, so dispatch the caller value (stashed in\n // `_options` by `applyOptions`) or the class default — never leave the\n // chrome unbuilt. Minimizable/maximizable reflect rather than re-set:\n // `resizable` can veto the effective value, and routing through\n // setMinimizable/setMaximizable would write that gated value back\n // into `_options`, overwriting the caller's own setting.\n this.setCloseable(this.isCloseable());\n this.reflectMinimizable(this.isMinimizable());\n this.reflectMaximizable(this.isMaximizable());\n this.setResizable(this.isResizable());\n this.setLocked(this.isLocked());\n this.setMaximizeBounds(this.getMaximizeBounds());\n this.setWindowState(this.getWindowState());\n\n this.wireMoveTrigger();\n\n // Default minSize: enough chrome room for the title content and trailing\n // controls plus a 200 px body floor. Skipped when the caller supplied an\n // explicit `minSize` in the options bag.\n if (options?.minSize === undefined) {\n this.setMinSize({ width: this.minContentWidthSeed(), height: 200 });\n }\n }\n\n /**\n * Applies a {@link WindowOptions} bag. Inherited Container/Component fields\n * cascade through `super.applyOptions`; `headerText` / `glyph` /\n * `contentFactory` / `onReady` are written pure into `_options` here and\n * dispatched later (from `initChrome`, or — for `glyph` — the subclass\n * constructor) once the chrome and the `contentFactory` field exist. `x`,\n * `y`, `width`, `height` cascade directly through their setters — they write\n * to local fields and skip the DOM until an element exists.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: WindowOptions): this {\n super.applyOptions(options);\n\n if (options.headerText !== undefined) this._options.headerText = options.headerText;\n if (options.glyph !== undefined) this._options.glyph = options.glyph;\n if (options.contentFactory !== undefined) this._options.contentFactory = options.contentFactory;\n if (options.onReady !== undefined) this._options.onReady = options.onReady;\n\n // Geometry carries a class default and seeds the window's first render,\n // so always dispatch the caller value or the class default. Resolved\n // inline (not via getX/getWidth) because those getters return the live,\n // post-drag geometry — not the construction-time option default.\n this.setX(options.x ?? this._defaultOptions.x!);\n this.setY(options.y ?? this._defaultOptions.y!);\n this.setWidth(options.width ?? this._defaultOptions.width!);\n this.setHeight(options.height ?? this._defaultOptions.height!);\n\n // State-affecting flags are written pure into `_options` here (caller\n // value only) and dispatched late from `initChrome`, which folds the\n // class default — the setters need subclass chrome (minimizable /\n // maximizable) or geometry (windowState) which only exist after super.\n if (options.closeable !== undefined) this._options.closeable = options.closeable;\n if (options.minimizable !== undefined) this._options.minimizable = options.minimizable;\n if (options.maximizable !== undefined) this._options.maximizable = options.maximizable;\n if (options.resizable !== undefined) this._options.resizable = options.resizable;\n if (options.alwaysOnTop !== undefined) this._options.alwaysOnTop = options.alwaysOnTop;\n if (options.locked !== undefined) this._options.locked = options.locked;\n if (options.maximizeBounds !== undefined) this._options.maximizeBounds = options.maximizeBounds;\n if (options.windowState !== undefined) this._options.windowState = options.windowState;\n\n this.setSnapResizeEnabled(options.snapResizeEnabled ?? this.isSnapResizeEnabled());\n this.setSnapThreshold(options.snapThreshold ?? this.getSnapThreshold());\n this.setSnapModifier(options.snapModifier ?? this.getSnapModifier());\n\n this.setConstrainToViewport(options.constrainToViewport ?? this.isConstrainToViewport());\n\n return this;\n }\n\n // ----- subclass hooks (what differs per subclass) -----\n\n /**\n * Installs the move gesture that lets the user drag the window. The\n * subclass wires the press source (a header's `mousedown`, an empty\n * tab-bar press, …) to {@link AbstractWindow.startMoveFrom}. Called once\n * from `initChrome`.\n */\n protected abstract wireMoveTrigger(): void;\n\n /**\n * Pushes the closeable state into the subclass UI (a header close button,\n * a control tool, …). Called by the non-virtual {@link AbstractWindow.setCloseable}\n * after the `_options.closeable` write.\n *\n * @param value - True when the window can be closed by the user.\n */\n protected abstract reflectCloseable(value: boolean): void;\n\n /**\n * Pushes the minimizable state into the subclass UI. Called by the\n * non-virtual {@link AbstractWindow.setMinimizable} after the\n * `_options.minimizable` write.\n *\n * @param value - True when the minimize affordance is shown.\n */\n protected abstract reflectMinimizable(value: boolean): void;\n\n /**\n * Pushes the maximizable state into the subclass UI. Called by the\n * non-virtual {@link AbstractWindow.setMaximizable} after the\n * `_options.maximizable` write.\n *\n * @param value - True when the maximize affordance is shown.\n */\n protected abstract reflectMaximizable(value: boolean): void;\n\n /**\n * Pushes the maximize *availability* into the subclass UI — disables\n * (never hides) the maximize control while it is unusable, mirroring\n * `reflectCloseable`'s disable-not-hide convention. Distinct from\n * {@link reflectMaximizable}, which hides the control entirely when the\n * window isn't maximizable at all: `locked` is a runtime-togglable state,\n * not a construction-time capability, so it disables the still-visible\n * control instead. Called by the non-virtual\n * {@link AbstractWindow.applyMaximizeAvailability}.\n *\n * @param value - True when the maximize control should be enabled.\n */\n protected abstract reflectMaximizeAvailability(value: boolean): void;\n\n /**\n * Reflects a window-state transition into the subclass UI — typically the\n * maximize/restore glyph swap. Called from {@link AbstractWindow.setWindowState}\n * as the state changes.\n *\n * @param state - The state being entered.\n */\n protected abstract reflectMaximizeState(state: WindowState): void;\n\n /**\n * Paints the active/inactive appearance (e.g. a header gradient). Called\n * from {@link AbstractWindow.onActivate}; the active *state* itself is\n * generic and lives on the base.\n *\n * @param active - True when this window is the active layer.\n */\n protected abstract paintActive(active: boolean): void;\n\n /**\n * Reads the window's title for serialization and any future title reader.\n * Read-only by design — there is no title *writer* on the base (a derived\n * title, e.g. a tab label, cannot be set).\n *\n * @returns The current title text.\n */\n abstract getTitle(): string;\n\n /**\n * Returns the min-content-width value seeded into the default min size by\n * `initChrome` (a header's required width, a tab bar's\n * min width, …).\n *\n * @returns The seed width in pixels.\n */\n protected abstract minContentWidthSeed(): number;\n\n /**\n * Returns the height of the window's title chrome, consulted by the generic\n * viewport-clamp / dock-rect / minimized-stack geometry. Defaulted to `0`;\n * the {@link CHROME_HEIGHT_FLOOR_PX} \"before the chrome laid out\" floor is\n * applied at each call site, not here. Subclasses override to return their\n * real chrome height.\n *\n * @returns The chrome height in pixels.\n */\n protected chromeHeight(): number {\n return 0;\n }\n\n /**\n * Returns the window's intrinsic chrome minimum — the smallest outer size\n * that still shows the title chrome (header / control tools / tab strip)\n * without crushing it. Consulted by {@link setWidth} / {@link setHeight} as\n * the resize floor instead of {@link Component.getMinSize}, which folds in\n * the body content's layout-manager minimum. A window is a `Container`\n * ({@link Container.clampsToContentSize} is `false`), so oversized body\n * content overflows rather than inflating the window past this chrome floor.\n *\n * Built from the two chrome seeds the subclasses already expose —\n * {@link minContentWidthSeed} and {@link chromeHeight} — converted from a\n * content-min to an outer-window min by adding the perimeter the body inset\n * folds into the resize-border band (mirroring {@link doLayout}'s\n * outer→inner arithmetic, which adds a single inset side per axis).\n *\n * @returns The chrome-only minimum outer size in pixels.\n */\n protected chromeMinSize(): Size {\n const border = this.getBorderSize();\n const insets = this.getInsets();\n\n const horizontalChrome = (Number(border.left) || 0) + (Number(border.right) || 0) + insets.getLeft();\n const verticalChrome = (Number(border.top) || 0) + (Number(border.bottom) || 0) + insets.getTop();\n\n return {\n width: this.minContentWidthSeed() + horizontalChrome,\n height: (this.chromeHeight() || CHROME_HEIGHT_FLOOR_PX) + verticalChrome,\n };\n }\n\n /**\n * Adds a content component to the window. The subclass decides how (a\n * `Border` CENTER region, a `Tab` entry, …).\n *\n * @param content - The content component to add.\n */\n protected abstract addContent(content: Component): void;\n\n /**\n * Reports whether `child` is the window's chrome rather than its content.\n * Used by the generic body-host discovery to skip the chrome. Defaulted to\n * `false` (every child is content); subclasses with a chrome child override.\n *\n * @param _child - The child component to classify.\n * @returns True when `child` is chrome.\n */\n isChromeComponent(_child: Component): boolean {\n return false;\n }\n\n /**\n * Sets the window width, clamping to the `chromeMinSize` floor so border\n * drags can't shrink the window below the chrome's required width (icon,\n * title budget, control tools). Oversized body content overflows per the\n * `Container` policy rather than holding the window open.\n *\n * @param width - Requested width in pixels.\n *\n * @returns This component, for method chaining.\n *\n * @remarks Clamps to the chrome minimum, NOT `getMinSize` — the latter\n * folds in the layout manager's (body content's) min, which would let a\n * tall/wide child hold the window open and contradicts\n * `Container.clampsToContentSize` being `false`. An explicit consumer\n * `minSize` is still enforced separately by `Component.setWidth`'s private\n * `clampWidth`, so a caller-set floor remains honoured. The clamp is\n * skipped until the window is rendered: `chromeMinSize` consults subclass\n * chrome (the header / strip) that does not exist yet while `applyOptions`\n * cascades `width` during `super()` — the same pre-render window in which\n * the setter already defers its DOM write.\n */\n setWidth(width: number): this {\n if (this.getElement()) {\n const min = this.chromeMinSize();\n\n if (width < min.width) {\n width = min.width;\n }\n }\n\n return super.setWidth(width);\n }\n\n /**\n * Sets the window height, clamping to the `chromeMinSize` floor for the\n * same reason described on {@link setWidth}.\n *\n * @param height - Requested height in pixels.\n *\n * @returns This component, for method chaining.\n */\n setHeight(height: number): this {\n if (this.getElement()) {\n const min = this.chromeMinSize();\n\n if (height < min.height) {\n height = min.height;\n }\n }\n\n return super.setHeight(height);\n }\n\n /**\n * Appends the window element to the document root, triggers layout, and makes it visible.\n *\n * @remarks When a content factory has been registered via\n * {@link AbstractWindow.setContentFactory}, the window opens with a centred\n * `ProgressSpinner` in its content area and the factory is invoked behind\n * a two-rAF yield via [`Animation.materialize`](/api/core/namespaces/Animation/functions/materialize).\n * The entrance scale-in and the spinner pause run concurrently, so by the\n * time the window finishes scaling in the spinner is already on screen.\n */\n show(): this {\n const el = this.getElement(true)!;\n\n // Join the central layer tree before bringToFront so the manager has\n // a node to re-stamp. A dropdown opened inside the window then\n // registers as the window's child and stacks above it.\n LayerManager.register(this);\n\n // Trap wheels no inner scroller claimed so they cannot fall through to\n // scrollable content behind the floating window.\n trapWheel(this);\n\n this.doLayout();\n this.bringToFront();\n\n AbstractWindow.openWindows.add(this);\n this.attachViewportResizeListener();\n\n LayerManager.mount(el);\n\n this.setVisible(true);\n\n this._showAnimation?.cancel();\n this._showAnimation = Animation.play(el, {\n from: { opacity: \"0\", transform: \"scale(0.97)\" },\n to: { opacity: \"1\", transform: \"scale(1)\" },\n durationMs: WINDOW_ANIM_DURATION_MS,\n properties: [\"opacity\", \"transform\"],\n });\n\n if (this._contentFactory) {\n const factory = this._contentFactory;\n const onReady = this._contentReadyCallback;\n this._contentFactory = null;\n this._contentReadyCallback = null;\n\n const spinner = createSpinnerWrap();\n\n this._materializeAnimation?.cancel();\n this._materializeAnimation = Animation.materialize({\n host: this,\n factory: factory,\n spinnerComponent: spinner,\n onReady: (component: Component) => {\n this._bodyHost = component;\n if (onReady) {\n onReady(component);\n }\n }\n });\n } else {\n this._bodyHost = this.findBodyHost();\n }\n\n if (this.isSnapResizeEnabled()) {\n this.attachSnapKeyboardListeners();\n }\n\n return this;\n }\n\n /**\n * Registers a factory that produces the window's content on first paint\n * instead of at construction time, and optionally a callback to run once\n * the produced component is attached, laid out, and faded in.\n *\n * @param factory - Zero-argument function returning the content component.\n * @param onReady - Optional callback fired after the content fade-in\n * completes (or immediately, under `prefers-reduced-motion: reduce`).\n * Receives the component the factory returned, fully attached and sized.\n *\n * @returns This window, for method chaining.\n *\n * @remarks Use when the content tree is expensive to build. `show()`\n * opens the window immediately with a spinner in the content area and\n * invokes the factory after a two-rAF yield via\n * [`Animation.materialize`](/api/core/namespaces/Animation/functions/materialize),\n * so the open-animation reaches the screen before the main-thread build\n * cost is incurred. Calling `show()` without a factory keeps the eager\n * `addComponent` lifecycle unchanged.\n *\n * Use the `onReady` callback for work that must happen after the content\n * is on screen and sized — for example kicking off an async data load\n * whose loading spinner is rendered by the content tree itself. Running\n * such work before `onReady` would emit `loadingchange: true` before\n * the panel had subscribed (or before the target had a size).\n *\n * @example\n * ```typescript\n * const win = new Window(\"Heavy\");\n * win.setSize({ width: 800, height: 600 });\n * win.setContentFactory(\n * () => new TablePanel(store),\n * () => void store.load()\n * );\n * win.show();\n * ```\n */\n setContentFactory(\n factory: () => Component,\n onReady?: (component: Component) => void\n ): this {\n this._contentFactory = factory;\n this._contentReadyCallback = onReady ?? null;\n\n return this;\n }\n\n /**\n * Raises this window above all other windows by assigning it the highest z-index,\n * and marks it as the active window, updating the title bar appearance on both\n * the previously active window and this one.\n */\n bringToFront(): void {\n // Route the raise through the manager: it re-allocates the z-stamp\n // (mirrored back via onZIndexChanged) and marks this window active,\n // which deactivates the previously-active window's title bar through\n // onActivate. No local activeWindow / setActive bookkeeping is needed.\n LayerManager.bringToFront(this);\n }\n\n // ----- DismissableLayer -----\n\n /**\n * Returns the window's root element for the central layer tree.\n *\n * @returns The window's element, or null when not yet rendered.\n */\n getLayerElement(): Handle | null {\n return this.getElement() ?? null;\n }\n\n /**\n * Returns the dismiss mode the document-level handlers consult. A window\n * is never dismissed by an outside interaction, so it stays `\"manual\"`.\n * Activation (the title-bar highlight) is orthogonal to dismissal — the\n * manager drives it through {@link AbstractWindow.onActivate} for any mode.\n *\n * @returns The layer dismiss mode.\n */\n getDismissMode(): LayerDismissMode {\n return \"manual\";\n }\n\n /**\n * Reflects the active state onto the window chrome. The manager calls this\n * with `true` when a pointer / focus interaction lands inside the window\n * (or a layer opened inside it) and `false` when another layer takes over\n * or an empty-viewport click deactivates everything. The active *state* is\n * generic; the paint is delegated to `paintActive`.\n *\n * @param active - True when this window is the active layer.\n */\n onActivate(active: boolean): void {\n this.paintActive(active);\n\n if (active) {\n this.focusSelf();\n this.emit(\"activate\");\n }\n }\n\n /**\n * Moves keyboard focus to the window when it is activated, unless focus is\n * already inside it (so a click that lands on a child input keeps that\n * input focused rather than yanking focus up to the window root). Uses\n * `preventScroll` because the window is an absolutely-positioned overlay —\n * a native focus scroll would jolt any `overflow: hidden` ancestor.\n */\n private focusSelf(): void {\n const element = this.getElement();\n if (!element || DOM.source.contains(element, DOM.source.getActiveElement())) {\n return;\n }\n\n this.focus(true);\n }\n\n /**\n * Advisory close request from the manager. A window owns its own close\n * affordance, so this routes to the same teardown.\n */\n requestClose(): void {\n this.onExitAction();\n }\n\n /**\n * Returns the window's z-index band so unrelated windows stack beneath\n * popovers, dropdowns, and dialogs — the pinned band while\n * {@link isAlwaysOnTop} is true, keeping the window above unpinned peers.\n *\n * @returns The window band base.\n */\n getBand(): number {\n return this.isAlwaysOnTop() ? LayerManager.Band.PinnedWindow : LayerManager.Band.Window;\n }\n\n /**\n * Windows are independent top-level peers, not layers opened from one\n * another, so each registers as a tree root. This keeps raising one window\n * from dragging another up with it: {@link LayerManager.bringToFront}\n * re-stamps a node together with its descendants, which is correct for a\n * dropdown nested inside a window but wrong for two sibling windows.\n *\n * @returns Always `true`.\n */\n isLayerRoot(): boolean {\n return true;\n }\n\n /**\n * Mirrors a manager-allocated z-index onto the element when the window\n * (or a layer opened inside it) is raised via\n * {@link LayerManager.bringToFront}.\n *\n * @param zIndex - The fresh z-index assigned by the manager.\n */\n onZIndexChanged(zIndex: number): void {\n this.setZIndex(zIndex);\n }\n\n /**\n * Hides the window and destroys its DOM element when the close button is clicked.\n */\n onExitAction(): void {\n // Notify subscribers (e.g. a Rail) before teardown, so a rail handle\n // representing this window is removed as the window closes.\n this.emit(\"close\");\n\n if (this._animationFrameId !== null) {\n DOM.sink.cancelAnimationFrame(this._animationFrameId);\n this._animationFrameId = null;\n }\n\n this._stateAnimHandle?.cancel();\n this._stateAnimHandle = null;\n\n // Drop any pending factory / onReady closure so its captured\n // references are free for GC if the window is closed before show()\n // ran the factory.\n this._contentFactory = null;\n this._contentReadyCallback = null;\n\n this.detachSnapKeyboardListeners();\n this.detachSnapMouseListeners();\n this.detachViewportResizeListener();\n this.clearSnapTargetBorder();\n\n LayerManager.unregister(this);\n untrapWheel(this);\n\n AbstractWindow.openWindows.delete(this);\n\n // Re-layout the dock so any sibling minimized windows close any gap\n // this one's removal left behind.\n AbstractWindow.relayoutMinimizedStack();\n\n const el = this.getElement();\n const finalize = (): void => {\n this.setVisible(false);\n this.destructor();\n };\n\n if (!el) {\n finalize();\n return;\n }\n\n this._closeAnimation?.cancel();\n this._closeAnimation = Animation.play(el, {\n to: { opacity: \"0\", transform: \"scale(0.97)\" },\n durationMs: WINDOW_ANIM_DURATION_MS,\n properties: [\"opacity\", \"transform\"],\n onComplete: finalize,\n });\n }\n\n /**\n * Tears the eight resize-border strips down before the inherited destructor\n * runs. They are appended straight to the window element by `renderContent`\n * rather than registered as child components, so the base destructor's\n * recursion over the child list never reaches them — leaving each strip's\n * per-instance stylesheet rules on the shared sheet for the life of the\n * page, and the sheet growing with every open/close cycle.\n */\n protected destructor(): void {\n // Before `super.destructor()` releases this window's element handle,\n // which every one of these animations' fallback timers would write to.\n this._stateAnimHandle?.cancel();\n this._stateAnimHandle = null;\n this._showAnimation?.cancel();\n this._showAnimation = null;\n this._materializeAnimation?.cancel();\n this._materializeAnimation = null;\n this._closeAnimation?.cancel();\n this._closeAnimation = null;\n this._railCollapseAnimation?.cancel();\n this._railCollapseAnimation = null;\n this._railExpandAnimation?.cancel();\n this._railExpandAnimation = null;\n\n for (const border of Object.values(this._borderComponents)) {\n border.dispose();\n }\n\n // `_windowMenu` is a LayerManager-mounted panel, never a registered\n // child (see Menu.ts's class comment), so `super.destructor()`'s\n // child recursion cannot reach it.\n this._windowMenu?.dispose();\n this._windowMenu = null;\n\n super.destructor();\n }\n\n /**\n * Returns the current lifecycle state (`\"normal\"`, `\"minimized\"`, or\n * `\"maximized\"`).\n *\n * @returns The current {@link WindowState}.\n */\n getWindowState(): WindowState {\n return this._options.windowState ?? this._defaultOptions.windowState!;\n }\n\n /**\n * Returns a snapshot array of every currently-open window. Used by layout\n * serialization to capture the floating-window plane, which is mounted on\n * `document.documentElement` rather than inside any container tree.\n *\n * @returns The open windows, in insertion order.\n */\n static getOpenWindows(): AbstractWindow[] {\n return Array.from(AbstractWindow.openWindows);\n }\n\n /**\n * Returns the window's current rectangle in viewport pixels. The public form\n * of the internal current-rect read, for layout serialization.\n *\n * @returns The `{ x, y, width, height }` the window currently occupies.\n */\n getRect(): WindowRect {\n return this.currentRect();\n }\n\n /**\n * Applies a rectangle captured by {@link getRect}, in viewport pixels.\n * `setWidth`/`setHeight` clamp against the window's minimum size and the\n * position is constrained to the viewport on the next layout, so a saved\n * rect from a larger or differently-shaped screen is pulled back into view.\n *\n * @param rect - The `{ x, y, width, height }` to apply.\n * @returns This window, for method chaining.\n */\n applyRect(rect: WindowRect): this {\n this.setX(rect.x);\n this.setY(rect.y);\n this.setWidth(rect.width);\n this.setHeight(rect.height);\n\n return this;\n }\n\n /**\n * Returns the cached normal-state rectangle a minimized or maximized window\n * un-collapses to, or `null` when the window is in its normal state.\n * Captured by serialization so a window serialized while minimized or\n * maximized round-trips back to the right normal geometry — on restore the\n * normal rect is applied first and `setWindowState` re-caches it.\n *\n * @returns The restore rect, or `null`.\n */\n getRestoreRect(): WindowRect | null {\n return this._restoreRect;\n }\n\n /**\n * Sets the lifecycle state. Tweens geometry between the current rect and\n * the rect implied by the target state over `WINDOW_ANIM_DURATION_MS`,\n * unless that rect changes the window's width or height by more than a\n * fixed pixel threshold — a maximize/minimize/restore that reveals a lot\n * of new content at once instead fades the window's body out, glides to\n * the target rect over the same duration with the body's own layout\n * paused, and fades the body back in, so a wide or tall body is only\n * laid out once — when the glide lands — rather than on every glide\n * frame. Under `prefers-reduced-motion: reduce` either path collapses to\n * a single synchronous commit.\n *\n * @param state - One of `\"normal\"`, `\"minimized\"`, or `\"maximized\"`.\n *\n * @returns This window, for method chaining.\n *\n * @remarks Round-trips through `_restoreRect`: leaving `\"normal\"` caches\n * the current rect; returning to `\"normal\"` reads it back and clears the\n * cache. While minimized or maximized, drag and resize are suppressed\n * (see `startMoveFrom` and `onResize` early-returns).\n */\n setWindowState(state: WindowState): this {\n const from = this.getWindowState();\n if (from === state) {\n return this;\n }\n\n // If a drag is in flight, commit it first so `_restoreRect` captures\n // the post-drag position instead of the stale start position.\n if (this._animationFrameId !== null) {\n DOM.sink.cancelAnimationFrame(this._animationFrameId);\n this._animationFrameId = null;\n }\n\n this._options.windowState = state;\n\n // A rail-minimized window is hidden outright (the rail handle is its\n // minimized representation), so re-show it and play the reverse genie —\n // scaling/fading back up out of the rail — before the state branch runs.\n if (from === \"minimized\" && this._rail !== null) {\n this.setDisplayed(true);\n this.animateRailExpand();\n }\n\n if (state === \"normal\") {\n // Restore body visibility BEFORE the tween starts so the\n // animation plays against the body content, not against an\n // empty rect.\n this.setBodyHostDisplayed(true);\n this.reflectMaximizeState(\"normal\");\n\n // The stored rect was captured against whatever viewport size was\n // current before this window left \"normal\" — clamp it back\n // on-screen in case the viewport has shrunk since, mirroring the\n // clamp a \"normal\" window would itself have received via\n // fitNormalWindowToViewport over the same span.\n const target = this._restoreRect ? this.clampRectToViewport(this._restoreRect) : this.currentRect();\n this._restoreRect = null;\n\n // Idempotent: already bound for a window restoring from a docked\n // minimize, but a rail-minimized window never attached it (hidden\n // while docked, so nothing to clamp) — re-attach here so the\n // restored window resumes tracking viewport resizes.\n this.attachViewportResizeListener();\n this.animateRect(target, () => {\n this.restoreNormalMinSize();\n AbstractWindow.relayoutMinimizedStack();\n });\n } else if (state === \"minimized\") {\n if (from === \"normal\") {\n this._restoreRect = this.currentRect();\n }\n this._preMinimizeState = from === \"maximized\" ? \"maximized\" : \"normal\";\n this.reflectMaximizeState(\"minimized\");\n this.detachViewportResizeListener();\n\n if (this._rail !== null) {\n // Rail-docked: skip the built-in bottom strip. Genie the window\n // — scaling and fading it into the rail's handle corner — then\n // hide it outright and let the rail show its handle (via the\n // deferred \"minimize\" event). The geometry is left untouched, so\n // the reverse genie on restore replays from the same rect.\n this.animateRailCollapse(() => {\n this.setDisplayed(false);\n this.emit(\"minimize\");\n });\n } else {\n // The window's normal-resize min size (e.g. the 200px body floor\n // `initChrome` seeds) is enforced independently of `chromeMinSize`\n // (see `setWidth`/`setHeight`), so it would otherwise stop the dock\n // animation from ever reaching the strip's compact height. Relax it\n // for as long as the window stays docked; `restoreNormalMinSize`\n // reinstates it once a later growth tween actually reaches it — not\n // up front, which would clamp the still-shrunk box back up to the\n // floor via CSS for a visible flicker before the growth catches up.\n // Guarded so an interrupted restore (grow tween cancelled before its\n // own restore ran) doesn't clobber the real floor with the\n // still-relaxed 0x0 it left behind.\n if (this._normalMinSize === null) {\n this._normalMinSize = this.getMinSizeConstraint();\n }\n this.setMinSize({ width: 0, height: 0 });\n\n const target = this.computeDockRect();\n this.animateRect(target, () => {\n this.setBodyHostDisplayed(false);\n this.attachViewportResizeListener();\n AbstractWindow.relayoutMinimizedStack();\n });\n\n this.emit(\"minimize\");\n }\n } else {\n // maximized\n if (from === \"normal\") {\n this._restoreRect = this.currentRect();\n }\n this.setBodyHostDisplayed(true);\n this.reflectMaximizeState(\"maximized\");\n\n const target = this.computeMaximizeRect();\n this.animateRect(target, () => {\n this.restoreNormalMinSize();\n this.attachViewportResizeListener();\n AbstractWindow.relayoutMinimizedStack();\n });\n }\n\n // Notify subscribers (e.g. a Rail) when the window leaves the minimized\n // state. The \"minimize\" counterpart is emitted from the branch above —\n // deferred to the rail fly-in's completion on the rail path.\n if (from === \"minimized\" && state !== \"minimized\") {\n this.emit(\"restore\");\n }\n\n return this;\n }\n\n /**\n * Reinstates the normal-resize min size relaxed while docked (see\n * {@link AbstractWindow.setWindowState}'s `\"minimized\"` branch), once a\n * growth tween away from `\"minimized\"` has actually reached its target —\n * so the floor is only ever applied when the window's live size is\n * already at or above it. No-ops when nothing is relaxed, which covers\n * both a rail-docked window (geometry, and so this floor, is never\n * touched) and a growth tween that already restored it.\n */\n private restoreNormalMinSize(): void {\n if (this._normalMinSize === null) {\n return;\n }\n\n this.setMinSize(this._normalMinSize);\n this._normalMinSize = null;\n }\n\n /**\n * Returns whether the window is currently in the `\"maximized\"` state.\n *\n * @returns True when the current state is `\"maximized\"`.\n */\n isMaximized(): boolean {\n return this.getWindowState() === \"maximized\";\n }\n\n /**\n * Returns whether the window is currently in the `\"minimized\"` state.\n *\n * @returns True when the current state is `\"minimized\"`.\n */\n isMinimized(): boolean {\n return this.getWindowState() === \"minimized\";\n }\n\n /**\n * Toggles between `\"normal\"` and `\"minimized\"`. No-ops when the window is\n * not minimizable, or when transitioning from `\"maximized\"` (use\n * `setWindowState(\"minimized\")` directly for that path).\n */\n toggleMinimize(): void {\n if (!this.isMinimizable()) {\n return;\n }\n\n if (this.getWindowState() === \"minimized\") {\n this.setWindowState(\"normal\");\n } else {\n this.setWindowState(\"minimized\");\n }\n }\n\n /**\n * Minimizes the window. Sugar over `setWindowState(\"minimized\")`.\n *\n * @returns This window, for method chaining.\n */\n minimize(): this {\n return this.setWindowState(\"minimized\");\n }\n\n /**\n * Restores the window from a minimized state to whatever it was before\n * (`\"normal\"` or `\"maximized\"`) and brings it to the front so it becomes\n * the active, focused window. No-op when the window is not minimized.\n *\n * @remarks Restoring is typically driven from a rail handle — a click\n * outside the window, which never activates it on its own. The window also\n * usually stays the layer manager's active layer while minimized (nothing\n * else took over), so `bringToFront` is an activation no-op and `onActivate`\n * never re-fires. Both the raise and the keyboard focus are therefore made\n * explicit here.\n *\n * @returns This window, for method chaining.\n */\n restore(): this {\n if (!this.isMinimized()) {\n return this;\n }\n\n this.setWindowState(this._preMinimizeState);\n this.bringToFront();\n this.focus(true);\n\n return this;\n }\n\n /**\n * Attaches a {@link Rail} this window minimizes into, replacing the built-in\n * bottom-of-viewport dock strip: while minimized the window is hidden and\n * represented by a handle on the rail that restores it on click. Pass `null`\n * to detach and fall back to the built-in strip. The rail subscribes to the\n * window's minimize / restore / close events.\n *\n * @param rail - The rail to minimize into, or `null` to detach.\n *\n * @returns This window, for method chaining.\n */\n setRail(rail: Rail | null): this {\n if (this._rail === rail) {\n return this;\n }\n\n if (this._rail !== null) {\n this._rail.unregisterWindow(this);\n }\n\n this._rail = rail;\n\n if (rail !== null) {\n rail.registerWindow(this);\n }\n\n return this;\n }\n\n /**\n * Returns the rail this window minimizes into, or `null` when it uses the\n * built-in bottom dock strip.\n *\n * @returns The attached rail, or `null`.\n */\n getRail(): Rail | null {\n return this._rail;\n }\n\n /**\n * Returns the window's leading glyph, or `undefined` when none was set. Read\n * by a {@link Rail} to label the handle for a window minimized into it.\n *\n * @returns The glyph name, or `undefined`.\n */\n getGlyph(): string | undefined {\n return this._options.glyph;\n }\n\n /**\n * Registers a listener for one of the window's lifecycle events.\n *\n * @param event - `\"minimize\"` / `\"restore\"` / `\"close\"` / `\"activate\"`.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This window, for method chaining.\n */\n on(event: WindowEvent, listener: () => void): this {\n this._windowListeners.add(event, listener);\n\n return this;\n }\n\n /**\n * Removes a previously registered listener. The exact callback reference\n * must match.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This window, for method chaining.\n */\n off(event: WindowEvent, listener: () => void): this {\n this._windowListeners.remove(event, listener);\n\n return this;\n }\n\n /**\n * Fires every listener registered for `event`, in registration order.\n *\n * @param event - The event to emit.\n */\n protected emit(event: WindowEvent): void {\n this._windowListeners.fire(event);\n }\n\n /**\n * Toggles between `\"normal\"` and `\"maximized\"`. No-ops when the window is\n * not maximizable.\n */\n toggleMaximize(): void {\n if (!this.isMaximizable()) {\n return;\n }\n\n if (this.getWindowState() === \"maximized\") {\n this.setWindowState(\"normal\");\n } else {\n this.setWindowState(\"maximized\");\n }\n }\n\n /**\n * Enables or disables the close affordance. When disabled the window can no\n * longer be torn down by the user — only programmatically via\n * {@link requestClose} — so its content cannot be destroyed by a stray\n * click. Minimize / maximize are unaffected. Stores the state and reflects\n * it into the subclass UI via `reflectCloseable`.\n *\n * @param value - True to enable the close affordance.\n *\n * @returns This window, for method chaining.\n */\n setCloseable(value: boolean): this {\n this._options.closeable = value;\n this.reflectCloseable(value);\n\n return this;\n }\n\n /**\n * Returns whether the close affordance is enabled.\n *\n * @returns True when the close affordance is enabled.\n */\n isCloseable(): boolean {\n return this._options.closeable ?? this._defaultOptions.closeable!;\n }\n\n /**\n * Toggles whether the minimize affordance is shown. Stores the caller's\n * own value and reflects the *effective* value via `reflectMinimizable`:\n * when the window is not resizable the affordance stays hidden regardless\n * of `value`, but `value` is remembered and takes effect again once\n * `resizable` is re-enabled.\n *\n * @param value - True to show the minimize affordance.\n *\n * @returns This window, for method chaining.\n */\n setMinimizable(value: boolean): this {\n this._options.minimizable = value;\n this.reflectMinimizable(this.isMinimizable());\n\n return this;\n }\n\n /**\n * Returns whether the minimize affordance is shown. `false` whenever the\n * window is not resizable, regardless of the `minimizable` option.\n *\n * @returns True when the minimize affordance is shown.\n */\n isMinimizable(): boolean {\n return this.isResizable() && (this._options.minimizable ?? this._defaultOptions.minimizable!);\n }\n\n /**\n * Toggles whether the maximize affordance is shown. Stores the caller's\n * own value and reflects the *effective* value via `reflectMaximizable`:\n * when the window is not resizable the affordance stays hidden regardless\n * of `value`, but `value` is remembered and takes effect again once\n * `resizable` is re-enabled.\n *\n * @param value - True to show the maximize affordance.\n *\n * @returns This window, for method chaining.\n */\n setMaximizable(value: boolean): this {\n this._options.maximizable = value;\n this.reflectMaximizable(this.isMaximizable());\n this.applyMaximizeAvailability();\n\n return this;\n }\n\n /**\n * Returns whether the maximize affordance is shown. `false` whenever the\n * window is not resizable, regardless of the `maximizable` option.\n *\n * @returns True when the maximize affordance is shown.\n */\n isMaximizable(): boolean {\n return this.isResizable() && (this._options.maximizable ?? this._defaultOptions.maximizable!);\n }\n\n /**\n * True when a border drag may run: resizable and not frozen by the lock.\n *\n * @returns True when resize dragging is currently permitted.\n */\n private canResize(): boolean {\n return this.isResizable() && !this.isLocked();\n }\n\n /**\n * Shows or hides the eight resize-border strips from the effective\n * resize gate ({@link canResize}), disarming a live snap session when\n * they become hidden. The single place that writes the strips'\n * visibility, shared by {@link setResizable} and {@link setLocked}.\n */\n private applyResizeBorderVisibility(): void {\n const enabled = this.canResize();\n\n // Hidden strips take no cursor and no hit test, so a frozen or\n // non-resizable edge shows the ordinary pointer instead of a resize\n // cursor that silently does nothing. `null` (inherit), not `true`, on\n // the restore branch — an explicit `visible: true` would override the\n // window's own hidden state while it is still being constructed\n // (`setVisible` is called with `false` before `show()` reveals it).\n for (const border of Object.values(this._borderComponents)) {\n border.setVisible(enabled ? null : false);\n }\n\n if (!enabled) {\n this.clearSnapState();\n }\n }\n\n /**\n * True when the maximize/restore affordance may be *used*: maximizable\n * and not frozen by the lock. Unlike {@link canResize}, this does not\n * gate {@link toggleMaximize} itself — a locked window's maximize state\n * still changes programmatically (e.g. layout restore), matching the\n * plan's Non-Goal that `locked` gates user drag gestures, not the API.\n * It gates every *user-facing* maximize control instead: the header\n * button, a `TabWindow`'s tool, the header/bar double-click gesture, and\n * the window menu's Maximize/Restore row.\n *\n * @returns True when the maximize affordance is currently usable.\n */\n protected canMaximize(): boolean {\n return this.isMaximizable() && !this.isLocked();\n }\n\n /**\n * Pushes the effective maximize-availability gate ({@link canMaximize})\n * into the subclass UI via {@link reflectMaximizeAvailability}, and\n * refreshes the Maximize row of an already-open window menu (see\n * {@link refreshWindowMenuMaximizeAvailability}). The single place that\n * recomputes the gate, called whenever any of its inputs — resizable,\n * maximizable, or locked — changes.\n */\n private applyMaximizeAvailability(): void {\n this.reflectMaximizeAvailability(this.canMaximize());\n this.refreshWindowMenuMaximizeAvailability();\n }\n\n /**\n * Live-refreshes the Maximize/Restore row's `enabled` state in an\n * already-open window menu, without closing, rebuilding, or\n * re-animating the panel — so toggling \"Lock position\" from inside the\n * still-open menu (that row's own action deliberately leaves the panel\n * open, so both switches can be flipped in one visit) immediately greys\n * out Maximize instead of leaving it clickable until the menu is next\n * reopened. A no-op when no menu has ever been built, or when the\n * window isn't maximizable at all (no Maximize row was ever built to\n * refresh). The row's index mirrors {@link buildWindowMenuItems}'s own\n * ordering — Minimize (when minimizable) precedes Maximize — which this\n * assumes is unchanged since the menu was last (re)built; a capability\n * change (`resizable` / `maximizable`) while the menu stays open would\n * add or remove rows outright, which needs a full rebuild and is out of\n * scope for this same-row nudge.\n */\n private refreshWindowMenuMaximizeAvailability(): void {\n if (!this._windowMenu || !this.isMaximizable()) {\n return;\n }\n\n const maximizeIndex = this.isMinimizable() ? 1 : 0;\n\n this._windowMenu.setItemEnabled(maximizeIndex, this.canMaximize());\n }\n\n /**\n * Toggles the drag-to-resize border strips. Disabling hides all eight\n * strips (no cursor, no hit test) and disarms any in-progress snap-resize\n * session; moving is unaffected, but disabling also hides the minimize\n * and maximize affordances and blocks `toggleMinimize` / `toggleMaximize`\n * — `resizable` is the master switch for both, see `isMinimizable` /\n * `isMaximizable`.\n *\n * @param value - True to show and arm the resize border strips, false to\n * hide and disarm them.\n *\n * @returns This window, for method chaining.\n */\n setResizable(value: boolean): this {\n this._options.resizable = value;\n\n this.applyResizeBorderVisibility();\n\n // `resizable` supersedes minimizable/maximizable, so both affordances\n // re-reflect against their effective value. Straight to the reflect\n // hooks: setMinimizable/setMaximizable would write the gated value\n // into `_options` and destroy the caller's own setting.\n this.reflectMinimizable(this.isMinimizable());\n this.reflectMaximizable(this.isMaximizable());\n this.applyMaximizeAvailability();\n\n return this;\n }\n\n /**\n * Returns whether the drag-to-resize border strips are enabled.\n *\n * @returns True when the resize border strips are shown and active.\n */\n isResizable(): boolean {\n return this._options.resizable ?? this._defaultOptions.resizable!;\n }\n\n /**\n * Freezes or unfreezes the window: while locked, drag-to-move and\n * drag-to-resize are both vetoed and the eight resize-border strips are\n * hidden. Maximize (and un-maximizing) is itself a resize, so every\n * user-facing maximize control is disabled too — see `canMaximize`\n * — but minimize and close are left alone, since neither one resizes the\n * window: `resizable` — not `locked` — stays their master switch (see\n * `isMinimizable` / `isCloseable`).\n *\n * @param value - True to freeze the window; false to restore whatever\n * `resizable` allows.\n *\n * @returns This window, for method chaining.\n */\n setLocked(value: boolean): this {\n this._options.locked = value;\n this.applyResizeBorderVisibility();\n this.applyMaximizeAvailability();\n\n return this;\n }\n\n /**\n * Returns whether the window is currently locked (frozen).\n *\n * @returns True when the window is locked.\n */\n isLocked(): boolean {\n return this._options.locked ?? this._defaultOptions.locked!;\n }\n\n /**\n * Toggles whether the window is kept above every unpinned window, by\n * moving its registered layer between {@link LayerManager.Band.Window}\n * and {@link LayerManager.Band.PinnedWindow}.\n *\n * @param value - True to pin the window above unpinned peers.\n *\n * @returns This window, for method chaining.\n */\n setAlwaysOnTop(value: boolean): this {\n this._options.alwaysOnTop = value;\n LayerManager.setBand(this, this.getBand());\n\n return this;\n }\n\n /**\n * Returns whether the window is pinned above unpinned peers.\n *\n * @returns True when the window is always-on-top.\n */\n isAlwaysOnTop(): boolean {\n return this._options.alwaysOnTop ?? this._defaultOptions.alwaysOnTop!;\n }\n\n /**\n * Builds the window menu's item list from the window's current state:\n * Minimize / Maximize (omitted when not minimizable / maximizable, per\n * `resizable`'s master-switch gating; Maximize additionally disabled —\n * never omitted — while {@link canMaximize} is false, i.e. while locked),\n * a separator, the \"Always on top\" and \"Lock position\" checkable rows,\n * another separator, and Close (always present, disabled when not\n * closeable). Minimize/Maximize/Close each carry a glyph that swaps to\n * match the window state; on `Window` this always matches the header\n * button's own glyph in the same state, but on `TabWindow` the trailing\n * tool buttons never swap (`reflectMaximizeState` is a no-op there — see\n * its own doc), so the menu row and the tool button can show different\n * icons while minimized or maximized. The two checkable rows\n * deliberately carry none — they stay plain `CheckboxMenuRow` factories,\n * not icon-capable `MenuItem`s. Rebuilt on every open — see the plan's\n * Architecture Decisions — so the checkable rows' `checked`, the\n * Minimize/Maximize labels and glyphs, and the Maximize row's `enabled`\n * always reflect live state.\n *\n * @returns The menu's item configs, in display order.\n */\n private buildWindowMenuItems(): MenuItemConfig[] {\n const items: MenuItemConfig[] = [];\n const state = this.getWindowState();\n\n if (this.isMinimizable()) {\n items.push({\n text: state === \"minimized\" ? \"Restore\" : \"Minimize\",\n glyph: state === \"minimized\" ? \"window-restore\" : \"window-minimize\",\n action: this._boundToggleMinimize,\n });\n }\n\n if (this.isMaximizable()) {\n items.push({\n text: state === \"maximized\" ? \"Restore\" : \"Maximize\",\n glyph: state === \"maximized\" ? \"window-restore\" : \"window-maximize\",\n enabled: this.canMaximize(),\n action: this._boundToggleMaximize,\n });\n }\n\n if (items.length > 0) {\n items.push({ separator: true });\n }\n\n items.push(\n {\n row: () => {\n const row = new CheckboxMenuRow({ text: \"Always on top\", checked: this.isAlwaysOnTop() });\n\n row.on(\"action\", () => { this.setAlwaysOnTop(row.isChecked()); });\n\n return row;\n },\n },\n {\n row: () => {\n const row = new CheckboxMenuRow({ text: \"Lock position\", checked: this.isLocked() });\n\n row.on(\"action\", () => { this.setLocked(row.isChecked()); });\n\n return row;\n },\n },\n { separator: true },\n { text: \"Close\", glyph: \"xmark\", enabled: this.isCloseable(), action: this._boundRequestClose },\n );\n\n return items;\n }\n\n /**\n * Opens (or toggle-shuts) the window's system menu anchored under\n * `opener` — the title icon in both concrete subclasses. No-ops when\n * `opener` has no rendered element (e.g. a `Window` whose icon was\n * removed via `clearGlyph`), so there is no anchor rect to open against.\n *\n * @param opener - The component the menu is anchored under and excluded\n * from outside-click dismissal (see `Menu.toggleFor`).\n */\n protected openWindowMenu(opener: Component): void {\n const openerEl = opener.getElement();\n\n if (!openerEl) {\n return;\n }\n\n this._windowMenu ??= new Menu();\n this._windowMenu.toggleFor(openerEl, DOM.source.getViewportRect(opener), this.buildWindowMenuItems());\n }\n\n /**\n * Sets the rect the window fills when entering the `\"maximized\"` state.\n *\n * @param value - `\"viewport\"` to fill the browser viewport,\n * `\"parent\"` to fill the window element's parent rect.\n *\n * @returns This window, for method chaining.\n */\n setMaximizeBounds(value: WindowMaximizeBounds): this {\n this._options.maximizeBounds = value;\n\n return this;\n }\n\n /**\n * Returns the current maximize-bounds policy.\n *\n * @returns Either `\"viewport\"` or `\"parent\"`.\n */\n getMaximizeBounds(): WindowMaximizeBounds {\n return this._options.maximizeBounds ?? this._defaultOptions.maximizeBounds!;\n }\n\n /**\n * Enables or disables the Ctrl-snap resize affordance. When disabled, the\n * keyboard listeners are detached and the snap-target border (if any) is\n * cleared.\n *\n * @param value - True to enable snap-to-edge detection.\n *\n * @returns This window, for method chaining.\n */\n setSnapResizeEnabled(value: boolean): this {\n if (this._options.snapResizeEnabled === value) {\n return this;\n }\n\n this._options.snapResizeEnabled = value;\n\n if (!value) {\n this.clearSnapState();\n this.detachSnapKeyboardListeners();\n } else if (this.getElement()) {\n this.attachSnapKeyboardListeners();\n }\n\n return this;\n }\n\n /**\n * Returns whether the snap-resize affordance is enabled.\n *\n * @returns True when snap-resize is enabled.\n */\n isSnapResizeEnabled(): boolean {\n return this._options.snapResizeEnabled ?? this._defaultOptions.snapResizeEnabled!;\n }\n\n /**\n * Controls how far a window may be dragged. When enabled (the default) the\n * whole window is kept inside the viewport — every border stops at the\n * viewport edge. When disabled the window may travel off-screen but its\n * header stays grabbable, so it can never be dropped fully out of reach.\n *\n * @param value - True to keep the entire window inside the viewport.\n *\n * @returns This window, for method chaining.\n */\n setConstrainToViewport(value: boolean): this {\n this._options.constrainToViewport = value;\n\n return this;\n }\n\n /**\n * Returns whether the whole window is constrained to the viewport while dragging.\n *\n * @returns True when the entire window is kept inside the viewport.\n */\n isConstrainToViewport(): boolean {\n return this._options.constrainToViewport ?? this._defaultOptions.constrainToViewport!;\n }\n\n /**\n * Sets the cursor-to-edge distance (in pixels) under which a border strip\n * is treated as the snap target while the modifier key is held.\n *\n * @param px - Threshold distance in pixels.\n *\n * @returns This window, for method chaining.\n */\n setSnapThreshold(px: number): this {\n this._options.snapThreshold = px;\n\n return this;\n }\n\n /**\n * Returns the current snap-detection threshold in pixels.\n *\n * @returns The threshold in pixels.\n */\n getSnapThreshold(): number {\n return this._options.snapThreshold ?? this._defaultOptions.snapThreshold!;\n }\n\n /**\n * Sets the modifier key that activates snap-resize detection.\n *\n * @param key - `\"ctrl\"`, `\"meta\"`, `\"alt\"`, or `\"shift\"`.\n *\n * @returns This window, for method chaining.\n */\n setSnapModifier(key: WindowSnapModifier): this {\n this._options.snapModifier = key;\n\n return this;\n }\n\n /**\n * Returns the modifier key currently activating snap-resize detection.\n *\n * @returns One of `\"ctrl\"`, `\"meta\"`, `\"alt\"`, `\"shift\"`.\n */\n getSnapModifier(): WindowSnapModifier {\n return this._options.snapModifier ?? this._defaultOptions.snapModifier!;\n }\n\n /**\n * Handles a window-move press by delegating to {@link AbstractWindow.startMoveFrom}.\n * Wired by each subclass's `wireMoveTrigger` to the\n * appropriate press source.\n *\n * @param e - The mousedown event whose pointer coordinate anchors the drag.\n */\n onMouseDown(e: MouseEvent): void {\n this.startMoveFrom(e);\n }\n\n /**\n * Begins a window move from a press anywhere a subclass routes here.\n * Snapshots the start position and pointer origin, and registers the\n * viewport move/up listeners. No-ops for a Shift-modified press (reserved\n * for re-dock gestures) or when the window is not in the `\"normal\"` state.\n *\n * @param e - The mousedown event whose pointer coordinate anchors the drag.\n *\n * @remarks The event argument is required — `e.clientX`/`e.clientY` seed the\n * absolute-pointer drag origin read by `onDrag`.\n */\n startMoveFrom(e: MouseEvent): void {\n // Primary button only — a right- or middle-click mousedown on the\n // header must not start a window move, mirroring DragManager's own\n // button gate on every other drag source.\n if (!Event.isPrimaryButton(e)) {\n return;\n }\n\n // Shift+drag is a re-dock gesture (handled by a subclass drag source),\n // not a window move — don't start the move. (Ctrl is left free for the\n // snap-resize affordance.)\n if (e.shiftKey) {\n return;\n }\n\n if (this.getWindowState() !== \"normal\") {\n return;\n }\n\n if (this.isLocked()) {\n return;\n }\n\n // Snapshot the start position and pointer origin so onDrag derives the move from\n // (current pointer - origin) absolutely rather than accumulating per-move deltas,\n // and onMouseUp can commit (start + delta) back to left/top.\n this._dragStartLeft = this.getX();\n this._dragStartTop = this.getY();\n this._dragOriginClientX = e.clientX;\n this._dragOriginClientY = e.clientY;\n this._dragDX = 0;\n this._dragDY = 0;\n\n // Seed the per-axis reach ratchet at the start position so the first\n // frame's allowed range spans the origin (no snap on grab) and tightens\n // from there.\n this._dragReachMinX = this._dragStartLeft;\n this._dragReachMaxX = this._dragStartLeft;\n this._dragReachMinY = this._dragStartTop;\n this._dragReachMaxY = this._dragStartTop;\n\n // Viewport listeners are required (rather than direct document listeners) because\n // Event.baseViewportListener stops mouseup propagation at window capture phase\n // whenever any viewport listener for the type exists (e.g. SpinButton registers\n // one at construction), which would prevent document-level handlers from firing.\n Event.addViewportListener(this, 'mouseup', this._boundOnMouseUp);\n Event.addViewportListener(this, 'mousemove', this._boundOnDrag);\n }\n\n /**\n * Adjusts the window's position and size based on the dragged border direction.\n *\n * @param border - The border handle that triggered the resize.\n * @param e - The mouse event carrying the absolute pointer coordinate.\n *\n * @remarks On the first move of a drag session the window's origin geometry\n * (pointer `clientX`/`clientY`, position, and size) is captured so that\n * `flushResize` can derive the new size from `origin + offset` rather\n * than accumulating per-move deltas. `WindowBorder` exposes no mousedown\n * hook to the window, so the capture is lazy and a viewport `mouseup`\n * listener clears the session flag when the drag ends.\n */\n onResize(border: WindowBorder, e: MouseEvent): void {\n if (!this.canResize()) {\n return;\n }\n\n if (this.getWindowState() !== \"normal\") {\n return;\n }\n\n e.preventDefault();\n\n if (!this._resizeSessionActive) {\n this._resizeSessionActive = true;\n this._resizeOriginClientX = e.clientX;\n this._resizeOriginClientY = e.clientY;\n this._resizeOriginX = this.getX();\n this._resizeOriginY = this.getY();\n this._resizeOriginW = this.getWidth();\n this._resizeOriginH = this.getHeight();\n\n Event.addViewportListener(this, 'mouseup', this._boundOnResizeEnd);\n Event.addViewportListener(this, 'touchend', this._boundOnResizeEnd);\n Event.addViewportListener(this, 'touchcancel', this._boundOnResizeEnd);\n }\n\n this._pendingClientX = e.clientX;\n this._pendingClientY = e.clientY;\n this._pendingBorder = border;\n\n if (this._animationFrameId === null) {\n this._animationFrameId = DOM.sink.requestAnimationFrame((ts) => this.flushResize(ts));\n }\n }\n\n /**\n * Clears the resize-session origin capture when a border drag ends, so the\n * next drag re-captures a fresh origin. Detaches the viewport listeners it\n * was registered with.\n *\n * @returns `true`, consuming the release that ends the border resize.\n */\n private onResizeEnd(): Event.ListenerResult {\n this._resizeSessionActive = false;\n\n Event.removeViewportListener(this, 'mouseup', this._boundOnResizeEnd);\n Event.removeViewportListener(this, 'touchend', this._boundOnResizeEnd);\n Event.removeViewportListener(this, 'touchcancel', this._boundOnResizeEnd);\n\n return true;\n }\n\n /**\n * Returns the maximum number of layout passes per second during a resize drag.\n *\n * @returns The current frames-per-second cap.\n */\n getResizeFps(): number {\n return this._resizeFps;\n }\n\n /**\n * Sets the maximum number of layout passes per second during a resize drag.\n *\n * @param fps - Frames per second cap (e.g. 30 or 20). Defaults to 60.\n *\n * @returns This window, for method chaining.\n */\n setResizeFps(fps: number): this {\n this._resizeFps = fps;\n\n return this;\n }\n\n /**\n * Commits a throttled resize frame: derives the new geometry from the\n * captured origin and pointer offset, clamps it to the viewport edge, and\n * lays out. Re-schedules itself when called inside the per-frame interval.\n *\n * @param timestamp - The rAF timestamp for this frame.\n */\n private flushResize(timestamp: number): void {\n if (timestamp - this._lastFlushTime < 1000 / this._resizeFps) {\n this._animationFrameId = DOM.sink.requestAnimationFrame((ts) => this.flushResize(ts));\n return;\n }\n\n this._lastFlushTime = timestamp;\n this._animationFrameId = null;\n\n const border = this._pendingBorder;\n\n this._pendingBorder = null;\n\n if (!border) {\n return;\n }\n\n // Offset of the pointer from where the drag began. The new size is\n // `origin ± offset` clamped by setWidth/setHeight; WEST/NORTH edges\n // additionally re-derive position from the *clamped* size so the\n // opposite (fixed) edge stays put and over-travel past the minimum is\n // absorbed instead of decoupling the dragged edge from the cursor.\n const offsetX = this._pendingClientX - this._resizeOriginClientX;\n const offsetY = this._pendingClientY - this._resizeOriginClientY;\n\n const originRight = this._resizeOriginX + this._resizeOriginW;\n const originBottom = this._resizeOriginY + this._resizeOriginH;\n\n // Viewport size caps so a dragged edge can't leave the screen. Each is the\n // largest size that keeps the moving edge inside the viewport given the fixed\n // opposite edge: east/south grow toward the far viewport edge, west/north grow\n // toward 0. Applied as an extra Math.min before setWidth/setHeight clamp to\n // their own min/max, so the WEST/NORTH position re-derivation below stays\n // consistent with the clamped size.\n const vp = DOM.source.getViewportSize();\n const eastWidthCap = vp.width - this._resizeOriginX;\n const westWidthCap = originRight;\n const southHeightCap = vp.height - this._resizeOriginY;\n const northHeightCap = originBottom;\n\n this.setAutoCommitStyle(false);\n switch (border.getDirection()) {\n case Direction.NORTHWEST:\n this.setWidth(Math.min(this._resizeOriginW - offsetX, westWidthCap));\n this.setHeight(Math.min(this._resizeOriginH - offsetY, northHeightCap));\n this.setX(originRight - this.getWidth());\n this.setY(originBottom - this.getHeight());\n\n break;\n case Direction.NORTH:\n this.setHeight(Math.min(this._resizeOriginH - offsetY, northHeightCap));\n this.setY(originBottom - this.getHeight());\n\n break;\n case Direction.NORTHEAST:\n this.setWidth(Math.min(this._resizeOriginW + offsetX, eastWidthCap));\n this.setHeight(Math.min(this._resizeOriginH - offsetY, northHeightCap));\n this.setY(originBottom - this.getHeight());\n\n break;\n case Direction.EAST:\n this.setWidth(Math.min(this._resizeOriginW + offsetX, eastWidthCap));\n\n break;\n case Direction.SOUTHEAST:\n this.setWidth(Math.min(this._resizeOriginW + offsetX, eastWidthCap));\n this.setHeight(Math.min(this._resizeOriginH + offsetY, southHeightCap));\n\n break;\n case Direction.SOUTH:\n this.setHeight(Math.min(this._resizeOriginH + offsetY, southHeightCap));\n\n break;\n case Direction.SOUTHWEST:\n this.setWidth(Math.min(this._resizeOriginW - offsetX, westWidthCap));\n this.setHeight(Math.min(this._resizeOriginH + offsetY, southHeightCap));\n this.setX(originRight - this.getWidth());\n\n break;\n case Direction.WEST:\n this.setWidth(Math.min(this._resizeOriginW - offsetX, westWidthCap));\n this.setX(originRight - this.getWidth());\n\n break;\n }\n\n this.doLayout();\n this.setAutoCommitStyle(true);\n }\n\n /**\n * The min/max top-left position that keeps the window inside the viewport,\n * honouring {@link isConstrainToViewport} (whole window in view) or the\n * header-reachable fallback (at least an `EDGE_MARGIN_PX` strip and the full\n * chrome band visible). Shared by drag clamping and {@link clampPositionToViewport}.\n *\n * @returns The position bounds in viewport pixels.\n */\n private viewportPositionBounds(): { minX: number; maxX: number; minY: number; maxY: number } {\n const w = this.getWidth();\n const vp = DOM.source.getViewportSize();\n const vw = vp.width;\n const vh = vp.height;\n\n if (this.isConstrainToViewport()) {\n // Whole window inside the viewport: every border stops at the edge.\n return { minX: 0, maxX: vw - w, minY: 0, maxY: vh - this.getHeight() };\n }\n\n // Header-reachable fallback: keep at least an EDGE_MARGIN_PX strip visible\n // horizontally and the whole chrome band visible vertically. The\n // CHROME_HEIGHT_FLOOR_PX floor covers the pre-layout window before the\n // chrome has measured a real height.\n const headerH = this.chromeHeight() || CHROME_HEIGHT_FLOOR_PX;\n\n return { minX: EDGE_MARGIN_PX - w, maxX: vw - EDGE_MARGIN_PX, minY: 0, maxY: vh - headerH };\n }\n\n /**\n * Clamps the pending drag delta so the window's top-left stays within\n * {@link viewportPositionBounds}. Mutates `_dragDX`/`_dragDY` in place so\n * both the live translate and the `onMouseUp` commit read the clamped\n * values from one chokepoint.\n */\n private clampDragDelta(): void {\n const { minX, maxX, minY, maxY } = this.viewportPositionBounds();\n\n // A window can start beyond a bound — larger than the viewport, or\n // opened with an edge off-screen. A plain [min, max] clamp would snap it\n // back to the bound on grab, jerking it from under the cursor. Instead\n // ratchet the allowed range from the reach extremes: the far end follows\n // the window as it travels toward the viewport (`max(maxBound, reachMin)`\n // floored at the real bound) so an off-screen edge can move in but never\n // back out — disallowing southward/eastward travel for as long as that\n // edge stays outside, even after reversing mid-drag. Symmetric on the\n // near end. For a window that started in-bounds the reach extremes sit\n // within [min, max], so this collapses to the plain clamp.\n const hiX = Math.max(maxX, this._dragReachMinX);\n const loX = Math.min(minX, this._dragReachMaxX);\n const hiY = Math.max(maxY, this._dragReachMinY);\n const loY = Math.min(minY, this._dragReachMaxY);\n\n const targetX = this._dragStartLeft + this._dragDX;\n const targetY = this._dragStartTop + this._dragDY;\n\n const clampedX = Util.clamp(targetX, loX, hiX);\n const clampedY = Util.clamp(targetY, loY, hiY);\n\n // Record the new reach so the next frame's range can only tighten.\n this._dragReachMinX = Math.min(this._dragReachMinX, clampedX);\n this._dragReachMaxX = Math.max(this._dragReachMaxX, clampedX);\n this._dragReachMinY = Math.min(this._dragReachMinY, clampedY);\n this._dragReachMaxY = Math.max(this._dragReachMaxY, clampedY);\n\n this._dragDX = clampedX - this._dragStartLeft;\n this._dragDY = clampedY - this._dragStartTop;\n }\n\n /**\n * Clamps the window's current position so the window sits inside the\n * viewport, by the same rule the move-drag uses. Call after positioning a\n * window programmatically — e.g. opening one at a tear-off release point that\n * may lie past the viewport edge — so it can never land off-screen. Set the\n * window's size first, since the bounds depend on it.\n *\n * @returns This window, for method chaining.\n */\n clampPositionToViewport(): this {\n const { minX, maxX, minY, maxY } = this.viewportPositionBounds();\n\n // High-first clamp (not Util.clamp): when the window is larger than the\n // viewport, maxX < minX, and this must pin the leading edge on-screen\n // (yield minX) rather than the low-first form's trailing edge (maxX).\n this.setX(Math.max(Math.min(this.getX(), maxX), minX));\n this.setY(Math.max(Math.min(this.getY(), maxY), minY));\n\n return this;\n }\n\n /**\n * Moves the window to follow the pointer while dragging.\n *\n * @param e - The mouse event carrying the absolute pointer coordinate.\n * @returns `{ stop: true, prevent: true }`, consuming the move and suppressing the browser's default text selection while dragging.\n */\n onDrag(e: MouseEvent): Event.ListenerResult {\n // Promoted here rather than in startMoveFrom: a plain click (mousedown +\n // mouseup with no intervening move) never reaches this method, so it never\n // pays for a compositor layer it doesn't need. Promoting on a bare click\n // was visible as a ~1px flash across the window's content — many descendant\n // glyph icons sit at sub-pixel CSS positions, and Chromium rasterizes a\n // promoted layer against its own snapped origin, nudging them briefly.\n // setWillChange no-ops once the value is already \"transform\", so this is\n // free on every subsequent move of the same drag. Released in onMouseUp.\n this.setWillChange(\"transform\");\n\n // Derive the delta from the absolute pointer offset (not accumulated movementX)\n // so clampDragDelta's writeback can't drift: when the window is pinned at an edge\n // the over-travel is absorbed and the window re-attaches to the cursor on reverse.\n this._dragDX = e.clientX - this._dragOriginClientX;\n this._dragDY = e.clientY - this._dragOriginClientY;\n\n this.clampDragDelta();\n\n // Compositor-only translate during drag; the cached left/top stay at the start\n // position so the field-DOM invariant holds (left === style.left throughout).\n this.setTranslate(this._dragDX, this._dragDY);\n\n return { stop: true, prevent: true };\n }\n\n /**\n * Detaches the document-level drag listeners when the mouse button is released.\n *\n * @returns `true`, consuming the release that ends the window drag.\n */\n onMouseUp(): Event.ListenerResult {\n // Commit the in-progress translate back to left/top so subsequent layout passes\n // operate from the new position. setTranslate(0, 0) frees the compositor layer.\n this.setX(this._dragStartLeft + this._dragDX);\n this.setY(this._dragStartTop + this._dragDY);\n this.setTranslate(0, 0);\n this.setWillChange(null);\n\n Event.removeViewportListener(this, 'mouseup', this._boundOnMouseUp);\n Event.removeViewportListener(this, 'mousemove', this._boundOnDrag);\n\n return true;\n }\n\n /**\n * Runs the border layout and positions all eight resize-handle strips around the window.\n *\n * @returns This component, for method chaining.\n */\n doLayout(): this {\n super.doLayout();\n\n let borderSize = this.getBorderSize();\n let insets = this.getInsets();\n let horisontallBorderWidth = (Number(borderSize.left) || 0) + (Number(borderSize.right) || 0) + insets.getLeft();\n let verticalBorderWidth = (Number(borderSize.top) || 0) + (Number(borderSize.bottom) || 0) + insets.getTop();\n let size = this.getSize();\n if (!size) {\n throw new Error(\"Component doesn't seem to be rendered.\");\n }\n\n let innerSize = this.getInnerSize();\n if (!innerSize) {\n throw new Error(\"Component doesn't seem to be rendered.\");\n }\n\n this._borderComponents.west.setAutoCommitStyle(false);\n this._borderComponents.northwest.setAutoCommitStyle(false);\n this._borderComponents.north.setAutoCommitStyle(false);\n this._borderComponents.northeast.setAutoCommitStyle(false);\n this._borderComponents.east.setAutoCommitStyle(false);\n this._borderComponents.southeast.setAutoCommitStyle(false);\n this._borderComponents.south.setAutoCommitStyle(false);\n this._borderComponents.southwest.setAutoCommitStyle(false);\n\n this._borderComponents.west.setX(0);\n this._borderComponents.west.setY(insets.getTop());\n this._borderComponents.west.setWidth(insets.getLeft());\n this._borderComponents.west.setHeight(innerSize.height);\n\n this._borderComponents.northwest.setX(0);\n this._borderComponents.northwest.setY(0);\n this._borderComponents.northwest.setWidth(insets.getLeft());\n this._borderComponents.northwest.setHeight(insets.getTop());\n\n this._borderComponents.north.setX(insets.getLeft());\n this._borderComponents.north.setY(0);\n this._borderComponents.north.setWidth(innerSize.width);\n this._borderComponents.north.setHeight(insets.getTop());\n\n this._borderComponents.northeast.setX(size.width - horisontallBorderWidth);\n this._borderComponents.northeast.setY(0);\n this._borderComponents.northeast.setWidth(insets.getRight());\n this._borderComponents.northeast.setHeight(insets.getTop());\n\n this._borderComponents.east.setX(size.width - horisontallBorderWidth);\n this._borderComponents.east.setY(insets.getTop());\n this._borderComponents.east.setWidth(insets.getRight());\n this._borderComponents.east.setHeight(innerSize.height);\n\n this._borderComponents.southeast.setX(size.width - horisontallBorderWidth);\n this._borderComponents.southeast.setY(size.height - verticalBorderWidth);\n this._borderComponents.southeast.setWidth(insets.getRight());\n this._borderComponents.southeast.setHeight(insets.getBottom());\n\n this._borderComponents.south.setX(insets.getLeft());\n this._borderComponents.south.setY(size.height - verticalBorderWidth);\n this._borderComponents.south.setWidth(innerSize.width);\n this._borderComponents.south.setHeight(insets.getRight());\n\n this._borderComponents.southwest.setX(0);\n this._borderComponents.southwest.setY(size.height - verticalBorderWidth);\n this._borderComponents.southwest.setWidth(insets.getLeft());\n this._borderComponents.southwest.setHeight(insets.getBottom());\n\n this._borderComponents.west.setAutoCommitStyle(true);\n this._borderComponents.northwest.setAutoCommitStyle(true);\n this._borderComponents.north.setAutoCommitStyle(true);\n this._borderComponents.northeast.setAutoCommitStyle(true);\n this._borderComponents.east.setAutoCommitStyle(true);\n this._borderComponents.southeast.setAutoCommitStyle(true);\n this._borderComponents.south.setAutoCommitStyle(true);\n this._borderComponents.southwest.setAutoCommitStyle(true);\n\n return this;\n }\n\n /**\n * Creates the window element and appends all eight resize-handle border elements.\n *\n * @returns The root HTMLElement for this window.\n */\n render(): Handle {\n let element = super.render();\n\n DOM.sink.appendChild(element, this._borderComponents.west.getElement(true)!);\n DOM.sink.appendChild(element, this._borderComponents.northwest.getElement(true)!);\n DOM.sink.appendChild(element, this._borderComponents.north.getElement(true)!);\n DOM.sink.appendChild(element, this._borderComponents.northeast.getElement(true)!);\n DOM.sink.appendChild(element, this._borderComponents.east.getElement(true)!);\n DOM.sink.appendChild(element, this._borderComponents.southeast.getElement(true)!);\n DOM.sink.appendChild(element, this._borderComponents.south.getElement(true)!);\n DOM.sink.appendChild(element, this._borderComponents.southwest.getElement(true)!);\n\n return element;\n }\n\n // ----- state-transition helpers -----\n\n /**\n * Returns the window's current rect from its live geometry fields.\n *\n * @returns The current `{ x, y, width, height }`.\n */\n private currentRect(): WindowRect {\n return {\n x: this.getX(),\n y: this.getY(),\n width: this.getWidth(),\n height: this.getHeight(),\n };\n }\n\n /**\n * Returns the first non-chrome child component, if any. Used to hide the\n * body while minimized so the docked strip shows only the title bar.\n *\n * @returns The body host component, or `null`.\n */\n protected findBodyHost(): Component | null {\n const children = this.getComponents();\n for (const child of children) {\n if (!this.isChromeComponent(child)) {\n return child;\n }\n }\n return null;\n }\n\n /**\n * Returns the window's body host, finding it lazily on first use and\n * caching the result in `_bodyHost`.\n *\n * @returns The body host component, or `null`.\n */\n private resolveBodyHost(): Component | null {\n if (!this._bodyHost) {\n this._bodyHost = this.findBodyHost();\n }\n\n return this._bodyHost;\n }\n\n /**\n * Shows or hides the window's body host, finding it lazily on first use.\n *\n * @param displayed - True to show the body, false to hide it.\n */\n private setBodyHostDisplayed(displayed: boolean): void {\n this.resolveBodyHost()?.setDisplayed(displayed);\n }\n\n /**\n * Computes the rect the window fills when maximized — the parent rect for\n * `\"parent\"` bounds, otherwise the full viewport.\n *\n * @returns The maximize target rect.\n */\n private computeMaximizeRect(): WindowRect {\n if (this.getMaximizeBounds() === \"parent\") {\n const el = this.getElement();\n const parent = el ? DOM.source.getParentElement(el) : null;\n if (parent && parent !== DOM.source.getDocumentElement()) {\n const r = DOM.source.getElementRect(parent);\n return { x: 0, y: 0, width: r.width, height: r.height };\n }\n }\n\n const vp = DOM.source.getViewportSize();\n\n return {\n x: 0,\n y: 0,\n width: vp.width,\n height: vp.height,\n };\n }\n\n /**\n * Computes the docked rect for a minimized window — a chrome-height slab\n * along the bottom of the viewport, in the window's dock slot.\n *\n * @returns The minimized dock rect.\n */\n private computeDockRect(): WindowRect {\n const dockWidth = this.getMinDockWidth();\n const slotIndex = this.computeDockSlotIndex();\n const headerHeight = this.chromeHeight() || CHROME_HEIGHT_FLOOR_PX;\n const x = slotIndex * (dockWidth + SNAP_DOCK_GAP_PX);\n const y = DOM.source.getViewportSize().height - headerHeight;\n\n return { x, y, width: dockWidth, height: headerHeight };\n }\n\n /**\n * Builds the genie `transform` that collapses the window into its own rail\n * handle: it translates the window onto the rail edge (cross-axis) centred\n * along the handle's length (main-axis, from `Rail.handleMainAxisOffset` and\n * `Rail.handleMainAxisExtent`) and scales it down to roughly the rail\n * thickness, so the window appears to shrink into its own spot in the handle\n * stack. Paired with `transform-origin: 0 0` and an opacity fade by the\n * collapse/expand animations. Assumes a rail is attached.\n *\n * @returns A `translate(...) scale(...)` CSS transform value.\n */\n private railGenieTransform(): string {\n const rail = this._rail as Rail;\n const thickness = rail.getThickness();\n const cur = this.currentRect();\n // Shrink to roughly the rail's thickness — clamped so an already-narrow\n // window still visibly collapses rather than scaling up.\n const scale = Math.min(0.5, thickness / Math.max(cur.width, 1));\n\n // Centre the shrunken window along its handle's length rather than\n // pinning its leading corner to the slot: aim the window's own centre at\n // the handle's centre (offset + half the handle) by pulling the corner\n // back half the scaled window. When no handle can be measured or\n // predicted (the first minimise into an empty rail) the length is 0 and\n // the window stays at the slot's leading edge. The cross axis is left\n // alone — the scaled window already fits the thickness.\n const edge = rail.getEdge();\n const vertical = edge === Placement.EAST || edge === Placement.WEST;\n const mainOffset = rail.handleMainAxisOffset(this);\n const handleExtent = rail.handleMainAxisExtent(this);\n const scaledMain = (vertical ? cur.height : cur.width) * scale;\n const mainTarget = handleExtent > 0\n ? mainOffset + (handleExtent - scaledMain) / 2\n : mainOffset;\n\n // Each edge sets its main axis to the centred target and its cross axis to\n // the rail edge; the two initialise to 0 so the axis an edge leaves\n // untouched keeps the correct cross value (0 is the top/left edge for\n // WEST/NORTH).\n let targetX = 0;\n let targetY = 0;\n\n switch (edge) {\n case Placement.EAST:\n targetX = DOM.source.getViewportSize().width - thickness;\n targetY = mainTarget;\n\n break;\n\n case Placement.WEST:\n targetY = mainTarget;\n\n break;\n\n case Placement.SOUTH:\n targetX = mainTarget;\n targetY = DOM.source.getViewportSize().height - thickness;\n\n break;\n\n case Placement.NORTH:\n targetX = mainTarget;\n\n break;\n\n default:\n targetY = mainTarget;\n\n break;\n }\n\n const tx = targetX - cur.x;\n const ty = targetY - cur.y;\n\n return `translate(${tx}px, ${ty}px) scale(${scale})`;\n }\n\n /**\n * Plays the minimize genie: scales and fades the window into its rail's\n * handle corner over `WINDOW_ANIM_DURATION_MS`, then runs `onDone` (which\n * hides the window and lets the rail show its handle). Honours\n * `prefers-reduced-motion` via {@link Animation.play}.\n *\n * @param onDone - Callback fired once the collapse completes.\n */\n private animateRailCollapse(onDone: () => void): void {\n const element = this.getElement();\n\n if (!element) {\n onDone();\n\n return;\n }\n\n this._railCollapseAnimation?.cancel();\n this._railCollapseAnimation = Animation.play(element, {\n from: { transformOrigin: \"0 0\", transform: \"translate(0, 0) scale(1)\", opacity: \"1\" },\n to: { transform: this.railGenieTransform(), opacity: \"0\" },\n durationMs: WINDOW_ANIM_DURATION_MS,\n properties: [\"transform\", \"opacity\"],\n onComplete: onDone,\n });\n }\n\n /**\n * Plays the reverse genie on restore: scales and fades the window back up\n * out of its rail's handle corner to its resting rect. The geometry never\n * moved while minimized, so this replays from the same collapsed transform.\n */\n private animateRailExpand(): void {\n const element = this.getElement();\n\n if (!element) {\n return;\n }\n\n this._railExpandAnimation?.cancel();\n this._railExpandAnimation = Animation.play(element, {\n from: { transformOrigin: \"0 0\", transform: this.railGenieTransform(), opacity: \"0\" },\n to: { transform: \"translate(0, 0) scale(1)\", opacity: \"1\" },\n durationMs: WINDOW_ANIM_DURATION_MS,\n properties: [\"transform\", \"opacity\"],\n });\n }\n\n /**\n * Returns the per-slot width of the minimized dock, read from the\n * `--ts-ui-window-min-dock-width` CSS variable with a built-in fallback.\n *\n * @returns The dock slot width in pixels.\n */\n private getMinDockWidth(): number {\n const cssVar = DOM.source.getThemeVar(\"--ts-ui-window-min-dock-width\");\n if (cssVar) {\n const parsed = parseFloat(cssVar);\n if (!isNaN(parsed) && parsed > 0) {\n return parsed;\n }\n }\n\n return DEFAULT_MIN_DOCK_WIDTH_PX;\n }\n\n /**\n * Returns this window's slot index in the minimized dock — the count of\n * minimized windows ahead of it in the open-windows order.\n *\n * @returns The zero-based dock slot index.\n */\n private computeDockSlotIndex(): number {\n let index = 0;\n for (const win of AbstractWindow.openWindows) {\n if (win === this) {\n return index;\n }\n if (win.getWindowState() === \"minimized\") {\n index++;\n }\n }\n return index;\n }\n\n /**\n * Re-positions every minimized window into a gap-free row along the bottom\n * of the viewport. Run after any change to the open/minimized set.\n */\n private static relayoutMinimizedStack(): void {\n let index = 0;\n for (const win of AbstractWindow.openWindows) {\n if (win.getWindowState() !== \"minimized\") {\n continue;\n }\n const dockWidth = win.getMinDockWidth();\n const headerHeight = win.chromeHeight() || CHROME_HEIGHT_FLOOR_PX;\n const x = index * (dockWidth + SNAP_DOCK_GAP_PX);\n const y = DOM.source.getViewportSize().height - headerHeight;\n\n win.setAutoCommitStyle(false);\n win.setX(x);\n win.setY(y);\n win.setWidth(dockWidth);\n win.setHeight(headerHeight);\n win.doLayout();\n win.setAutoCommitStyle(true);\n\n index++;\n }\n }\n\n /**\n * Animates the window to `target`, choosing between two strategies\n * depending on how large the size change is. A transition whose width or\n * height changes by more than `WINDOW_FADE_THRESHOLD_PX` fades the body\n * host out, glides to `target` with the body host's own layout paused,\n * runs the one relayout that deferred, then fades the body host back in;\n * a smaller transition tweens the rect over `WINDOW_ANIM_DURATION_MS`\n * without pausing anything, as before — its body is cheap enough to\n * relayout every frame. `prefers-reduced-motion` collapses either path to\n * one synchronous commit at `target`.\n *\n * @param target - The rect to animate to.\n * @param onDone - Optional callback fired once the animation completes.\n */\n private animateRect(target: WindowRect, onDone?: () => void): void {\n this.beginStateAnimation();\n\n if (this.isLargeRectChange(target)) {\n this.fadeRectSwap(target, onDone);\n } else {\n this.tweenRect(target, onDone);\n }\n }\n\n /**\n * Whether `target` changes the window's width or height, relative to its\n * current rect, by more than `WINDOW_FADE_THRESHOLD_PX`. Position deltas\n * are ignored.\n *\n * @param target - The candidate target rect.\n * @returns True when the larger of the two size deltas exceeds the fade\n * threshold.\n */\n private isLargeRectChange(target: WindowRect): boolean {\n const current = this.currentRect();\n\n return Math.max(\n Math.abs(target.width - current.width),\n Math.abs(target.height - current.height),\n ) > WINDOW_FADE_THRESHOLD_PX;\n }\n\n /**\n * Fades the body host out, glides the window to `target` over\n * `WINDOW_ANIM_DURATION_MS` with the body host's own layout paused, runs\n * the one relayout that glide deferred, then fades the body host back\n * in. Used by `animateRect` for a large size change: pausing the body\n * host means every glide frame's `commitRect` → `doLayout` still\n * repositions the chrome (the header and the eight resize strips) and\n * the body's own box — both cheap — without recursing into the body's\n * own potentially expensive relayout (e.g. a wide table rebuilding its\n * column window, measured at several hundred ms), so the chrome tracks\n * the glide in real time while that cost is paid once, when it lands,\n * instead of once per frame.\n *\n * @param target - The rect to glide to.\n * @param onDone - Optional callback fired once the glide lands and its\n * deferred relayout runs, before the fade-in starts.\n */\n private fadeRectSwap(target: WindowRect, onDone?: () => void): void {\n const host = this.resolveBodyHost();\n const element = host?.getElement();\n\n // No body to fade (a chrome-only window, or one not rendered yet): the\n // swap is just the jump.\n if (!host || !element) {\n this.commitRect(target);\n onDone?.();\n\n return;\n }\n\n this._bodyFadeActive = true;\n this._stateAnimHandle = Animation.play(element, {\n to: { opacity: \"0\" },\n durationMs: WINDOW_FADE_DURATION_MS,\n properties: [\"opacity\"],\n onComplete: (): void => {\n // Paused for the whole glide below, not just its landing\n // commit — see this method's own doc comment.\n // beginStateAnimation resumes this if a later transition\n // supersedes it first.\n host.pauseLayout();\n\n this._stateAnimHandle = Animation.tween<WindowRect>({\n from: this.currentRect(),\n to: target,\n durationMs: WINDOW_ANIM_DURATION_MS,\n onStep: (rect: WindowRect): void => this.commitRect(rect),\n onComplete: (): void => {\n // The one relayout the glide above deferred, paid now\n // that the window is sitting at its final rect.\n host.resumeLayout();\n onDone?.();\n\n // `onDone` may have hidden the body outright (the\n // minimized branch does). Leave it faded rather than\n // pay for a fade-in nobody will see — the next\n // transition that shows it again fades it in as part\n // of its own sequence.\n if (!host.isDisplayed()) {\n this._stateAnimHandle = null;\n this.endBodyFade();\n\n return;\n }\n\n this.startFadeIn(element);\n },\n });\n },\n });\n }\n\n /**\n * Fades `element` — the body host's element, left invisible by\n * `fadeRectSwap`'s fade-out — back in.\n *\n * @param element - The body host's element handle.\n */\n private startFadeIn(element: Handle): void {\n // No `from` here: the fade-out above already committed opacity \"0\"\n // onto `element` before calling this method (via its own\n // applyTransitionAndTo, whether it finished through transitionend or\n // the fallback timer), and nothing between there and here touches\n // opacity. Restating a `from` that already holds would be a no-op\n // write, but Animation.play still burns two `requestAnimationFrame`\n // turns proving it painted — turns that can run far longer than\n // their nominal ~33ms right after a relayout, which measured as a\n // 140+ms dead stall with the body pinned at invisible for no visible\n // reason.\n this._stateAnimHandle = Animation.play(element, {\n to: { opacity: \"1\" },\n durationMs: WINDOW_FADE_DURATION_MS,\n properties: [\"opacity\"],\n // See WINDOW_FADE_IN_FALLBACK_BUFFER_MS: the relayout just\n // before this call can leave the main thread too busy to start\n // this transition within Animation.play's default 40 ms buffer,\n // so the fallback needs more patience here than the fade-out leg\n // (which isn't preceded by a relayout).\n fallbackBufferMs: WINDOW_FADE_IN_FALLBACK_BUFFER_MS,\n onComplete: (): void => {\n this._stateAnimHandle = null;\n this.endBodyFade();\n },\n });\n }\n\n /**\n * Cancels whatever window-state animation is currently in flight and, if\n * it was a fade, restores the body host's opacity. Run at the start of\n * every `animateRect` call so a fade abandoned mid-flight never leaves\n * the body host stranded at a partial opacity — or, if it was cancelled\n * mid-glide before its landing resumed the body host's layout (see\n * `fadeRectSwap`), stranded with that layout still paused.\n */\n private beginStateAnimation(): void {\n this._stateAnimHandle?.cancel();\n this._stateAnimHandle = null;\n this.endBodyFade();\n\n const host = this.resolveBodyHost();\n if (host?.isLayoutPaused()) {\n host.resumeLayout();\n }\n }\n\n /**\n * Clears the body host's inline opacity if a fade currently owns it.\n * A no-op when no fade is active.\n */\n private endBodyFade(): void {\n if (!this._bodyFadeActive) {\n return;\n }\n\n this._bodyFadeActive = false;\n this.resolveBodyHost()?.clearOpacity();\n }\n\n /**\n * Writes `rect`'s `x`, `y`, `width`, `height` onto the window and lays it\n * out in a single synchronous pass.\n *\n * @param rect - The rect to commit.\n */\n private commitRect(rect: WindowRect): void {\n this.setAutoCommitStyle(false);\n this.setX(rect.x);\n this.setY(rect.y);\n this.setWidth(rect.width);\n this.setHeight(rect.height);\n this.doLayout();\n this.setAutoCommitStyle(true);\n }\n\n /**\n * Tweens the window's `x`, `y`, `width`, `height` from the current rect to\n * `target` over `WINDOW_ANIM_DURATION_MS`. Honours `prefers-reduced-motion`\n * by skipping straight to the final rect in one frame.\n *\n * @param target - The rect to tween to.\n * @param onDone - Optional callback fired once the tween completes.\n */\n private tweenRect(target: WindowRect, onDone?: () => void): void {\n this._stateAnimHandle = Animation.tween<WindowRect>({\n from: this.currentRect(),\n to: target,\n durationMs: WINDOW_ANIM_DURATION_MS,\n onStep: (rect: WindowRect): void => this.commitRect(rect),\n onComplete: (): void => {\n this._stateAnimHandle = null;\n onDone?.();\n },\n });\n }\n\n // ----- viewport-resize handling -----\n\n /**\n * Attaches the viewport-resize listener that keeps a maximized window\n * filling the viewport, re-anchors a docked-minimized window's stack to\n * the bottom-left corner, or refits a normal window back on-screen.\n * Bound for the life of the window from {@link show}; idempotent.\n */\n private attachViewportResizeListener(): void {\n if (this._viewportResizeBound) {\n return;\n }\n\n Event.addViewportListener(this, \"resize\", this._boundOnViewportResize);\n this._viewportResizeBound = true;\n }\n\n /**\n * Detaches the viewport-resize listener. Idempotent.\n */\n private detachViewportResizeListener(): void {\n if (!this._viewportResizeBound) {\n return;\n }\n\n Event.removeViewportListener(this, \"resize\", this._boundOnViewportResize);\n this._viewportResizeBound = false;\n }\n\n /**\n * Re-fills the viewport when the browser window resizes while this window\n * is maximized, re-anchors the whole minimized stack to the viewport's\n * new bottom-left corner when this window is docked-minimized, or refits\n * the window inside the viewport (see {@link fitNormalWindowToViewport})\n * when it is in the normal state — so shrinking the viewport can never\n * strand a window's header out of reach.\n */\n private onViewportResize(): void {\n const state = this.getWindowState();\n\n if (state === \"minimized\") {\n AbstractWindow.relayoutMinimizedStack();\n\n return;\n }\n\n if (state === \"normal\") {\n this.fitNormalWindowToViewport();\n\n return;\n }\n\n const rect = this.computeMaximizeRect();\n this.setAutoCommitStyle(false);\n this.setX(rect.x);\n this.setY(rect.y);\n this.setWidth(rect.width);\n this.setHeight(rect.height);\n this.doLayout();\n this.setAutoCommitStyle(true);\n\n AbstractWindow.relayoutMinimizedStack();\n }\n\n /**\n * Refits a normal-state window inside the viewport shrunk by\n * {@link VIEWPORT_RESIZE_MARGIN_PX} on every side, after a viewport resize.\n * Shrinks the window down to that margin — never below its own min-size —\n * when it no longer fits, then repositions it so every edge keeps the\n * margin's clearance. When the window's min-size itself exceeds the\n * margin-shrunk viewport, it is pinned {@link VIEWPORT_RESIZE_MARGIN_PX}\n * from the top-left corner and left to spill past the bottom/right edge\n * rather than forced below its floor.\n */\n private fitNormalWindowToViewport(): void {\n const clamped = this.clampRectToViewport(this.currentRect());\n\n this.setAutoCommitStyle(false);\n this.setWidth(clamped.width);\n this.setHeight(clamped.height);\n this.setX(clamped.x);\n this.setY(clamped.y);\n this.doLayout();\n this.setAutoCommitStyle(true);\n }\n\n /**\n * Clamps an arbitrary rect into the viewport shrunk by\n * {@link VIEWPORT_RESIZE_MARGIN_PX} on every side — the shared arithmetic\n * behind {@link fitNormalWindowToViewport} (which clamps the window's own\n * live geometry after a resize) and restoring from `\"maximized\"` /\n * `\"minimized\"` (which must clamp the *stored* pre-maximize rect before\n * animating to it, without first mutating the window's still-maximized\n * live geometry). Only ever shrinks — a rect already inside the margin\n * keeps its size — and never below the window's own min-size, mirroring\n * `setWidth`/`setHeight`'s own clamp. When the min-size itself exceeds the\n * margin-shrunk viewport, the rect is pinned {@link VIEWPORT_RESIZE_MARGIN_PX}\n * from the top-left corner and left to spill past the bottom/right edge\n * rather than forced below its floor.\n *\n * @param rect - The candidate rect to clamp.\n * @returns The clamped rect.\n */\n private clampRectToViewport(rect: WindowRect): WindowRect {\n const vp = DOM.source.getViewportSize();\n const availWidth = Math.max(0, vp.width - 2 * VIEWPORT_RESIZE_MARGIN_PX);\n const availHeight = Math.max(0, vp.height - 2 * VIEWPORT_RESIZE_MARGIN_PX);\n const minSize = this.getMinSize();\n\n const width = Math.max(Math.min(rect.width, availWidth), minSize?.width ?? 0);\n const height = Math.max(Math.min(rect.height, availHeight), minSize?.height ?? 0);\n\n const maxX = vp.width - VIEWPORT_RESIZE_MARGIN_PX - width;\n const maxY = vp.height - VIEWPORT_RESIZE_MARGIN_PX - height;\n\n // High-first clamp (not Util.clamp): when the min-size exceeds the\n // margin-shrunk viewport, maxX/maxY fall below the margin, and this\n // must pin the rect to the margin (spilling past the far edge) rather\n // than the low-first form's off-screen trailing edge.\n const x = Math.max(Math.min(rect.x, maxX), VIEWPORT_RESIZE_MARGIN_PX);\n const y = Math.max(Math.min(rect.y, maxY), VIEWPORT_RESIZE_MARGIN_PX);\n\n return { x, y, width, height };\n }\n\n // ----- snap-resize listeners -----\n\n /**\n * Attaches the keyboard listeners that arm the snap-resize affordance.\n * Idempotent.\n */\n private attachSnapKeyboardListeners(): void {\n if (this._snapKeysAttached) {\n return;\n }\n\n Event.addViewportListener(this, \"keydown\", this._boundOnSnapKeyDown);\n Event.addViewportListener(this, \"keyup\", this._boundOnSnapKeyUp);\n Event.addViewportListener(this, \"blur\", this._boundOnSnapBlur);\n this._snapKeysAttached = true;\n }\n\n /**\n * Detaches the snap-resize keyboard listeners. Idempotent.\n */\n private detachSnapKeyboardListeners(): void {\n if (!this._snapKeysAttached) {\n return;\n }\n\n Event.removeViewportListener(this, \"keydown\", this._boundOnSnapKeyDown);\n Event.removeViewportListener(this, \"keyup\", this._boundOnSnapKeyUp);\n Event.removeViewportListener(this, \"blur\", this._boundOnSnapBlur);\n this._snapKeysAttached = false;\n }\n\n /**\n * Attaches the mouse listeners that track the snap-target border while the\n * modifier is held. Idempotent.\n */\n private attachSnapMouseListeners(): void {\n if (this._snapMoveAttached) {\n return;\n }\n\n Event.addViewportListener(this, \"mousemove\", this._boundOnSnapMouseMove);\n Event.addViewportListener(this, \"mousedown\", this._boundOnSnapMouseDown);\n this._snapMoveAttached = true;\n }\n\n /**\n * Detaches the snap-resize mouse listeners. Idempotent.\n */\n private detachSnapMouseListeners(): void {\n if (!this._snapMoveAttached) {\n return;\n }\n\n Event.removeViewportListener(this, \"mousemove\", this._boundOnSnapMouseMove);\n Event.removeViewportListener(this, \"mousedown\", this._boundOnSnapMouseDown);\n this._snapMoveAttached = false;\n }\n\n /**\n * Clears any highlighted snap-target border.\n */\n private clearSnapTargetBorder(): void {\n if (this._snapTargetBorder) {\n this._snapTargetBorder.setSnapTarget(false);\n this._snapTargetBorder = null;\n }\n }\n\n /**\n * Tears down the whole snap-resize session — disarms it, detaches the mouse\n * listeners, and clears the target border.\n */\n private clearSnapState(): void {\n this._snapEnabled = false;\n this.detachSnapMouseListeners();\n this.clearSnapTargetBorder();\n }\n\n /**\n * Arms snap detection when the watched modifier goes down while the window\n * is resizable, normal, and snap-resize is enabled.\n *\n * @param e - The keydown event.\n */\n private onSnapKeyDown(e: KeyboardEvent): void {\n if (!this.canResize()) {\n return;\n }\n\n if (!this.isSnapResizeEnabled()) {\n return;\n }\n if (this.getWindowState() !== \"normal\") {\n return;\n }\n if (!this.modifierMatches(e)) {\n return;\n }\n if (this._snapEnabled) {\n return;\n }\n\n this._snapEnabled = true;\n this.attachSnapMouseListeners();\n }\n\n /**\n * Disarms snap detection when the watched modifier is released.\n *\n * @param e - The keyup event.\n */\n private onSnapKeyUp(e: KeyboardEvent): void {\n if (!this._snapEnabled) {\n return;\n }\n // Some browsers fire keyup with a different key field when modifiers\n // chord; only release when the watched modifier is no longer active.\n if (this.modifierStillHeld(e)) {\n return;\n }\n\n this.clearSnapState();\n }\n\n /**\n * Returns whether the configured snap modifier is active in `e`.\n *\n * @param e - The keyboard event to inspect.\n * @returns True when the watched modifier is held.\n */\n private modifierMatches(e: KeyboardEvent): boolean {\n switch (this.getSnapModifier()) {\n case \"ctrl\": return e.ctrlKey;\n case \"meta\": return e.metaKey;\n case \"alt\": return e.altKey;\n case \"shift\": return e.shiftKey;\n }\n }\n\n /**\n * Returns whether the watched snap modifier is still held in `e`.\n *\n * @param e - The keyboard event to inspect.\n * @returns True when the watched modifier remains active.\n */\n private modifierStillHeld(e: KeyboardEvent): boolean {\n return this.modifierMatches(e);\n }\n\n /**\n * Tracks the nearest border under the cursor while snap is armed, updating\n * the highlighted snap-target border.\n *\n * @param e - The mousemove event.\n */\n private onSnapMouseMove(e: MouseEvent): void {\n if (!this._snapEnabled) {\n return;\n }\n\n const winner = this.pickSnapBorder(e.clientX, e.clientY);\n if (winner === this._snapTargetBorder) {\n return;\n }\n\n if (this._snapTargetBorder) {\n this._snapTargetBorder.setSnapTarget(false);\n }\n this._snapTargetBorder = winner;\n if (winner) {\n winner.setSnapTarget(true);\n }\n }\n\n /**\n * Picks the closest border strip to a cursor point within the snap\n * threshold, preferring corners over edges on ties.\n *\n * @param cx - Cursor x in viewport pixels.\n * @param cy - Cursor y in viewport pixels.\n * @returns The nearest border within threshold, or `null`.\n */\n private pickSnapBorder(cx: number, cy: number): WindowBorder | null {\n const candidates: WindowBorder[] = [\n // Corners first so ties go to corners over edges.\n this._borderComponents.northwest,\n this._borderComponents.northeast,\n this._borderComponents.southeast,\n this._borderComponents.southwest,\n this._borderComponents.north,\n this._borderComponents.east,\n this._borderComponents.south,\n this._borderComponents.west,\n ];\n\n let best: WindowBorder | null = null;\n let bestDist = this.getSnapThreshold();\n\n for (const border of candidates) {\n const el = border.getElement();\n if (!el) {\n continue;\n }\n const rect = DOM.source.getElementRect(el);\n const dx = Math.max(rect.left - cx, 0, cx - rect.right);\n const dy = Math.max(rect.top - cy, 0, cy - rect.bottom);\n const dist = Math.hypot(dx, dy);\n\n if (dist <= bestDist) {\n best = border;\n bestDist = dist;\n }\n }\n\n return best;\n }\n\n /**\n * Forwards a press near (but outside) the highlighted snap-target border\n * into that border's own drag flow.\n *\n * @param e - The mousedown event.\n * @returns `true` when the press starts a snap drag; nothing when it does not, so the event keeps propagating.\n */\n private onSnapMouseDown(e: MouseEvent): Event.ListenerResult {\n const target = this._snapTargetBorder;\n if (!target) {\n return;\n }\n\n // If the mousedown landed directly on the highlighted border, the\n // strip's own `mousedown` listener (registered in WindowBorder's\n // constructor) will already fire onDragStart — forwarding here would\n // double-register the viewport listeners. The snap forwarding is only\n // useful when the cursor sits *outside* the 4 px strip.\n const targetEl = target.getElement();\n if (targetEl && DOM.source.isNode(e.target) && DOM.source.contains(targetEl, DOM.source.intern(e.target))) {\n this._snapTargetBorder = null;\n return;\n }\n\n // Forward into the border's own drag flow. The snap-target highlight\n // is cleared in the matching onDragStop hook the border owns.\n target.onDragStart(e);\n this._snapTargetBorder = null;\n\n return true;\n }\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Button, ButtonOptions } from \"~/component/button/Button.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport type { StyleBag, StyleStateSpec } from \"~/core/ClassStyleRules.js\";\n\n/**\n * Resting + pressed/hover defaults for a window control button (minimize /\n * maximize / close), painted from the theme's `window.control` tokens.\n * `backgroundColor` and `backgroundImage` both carry the same token —\n * flat-colour themes (modern/dark) resolve it as a colour, the classic\n * theme's gradient resolves it as an image; CSS silently drops whichever\n * channel doesn't parse, the same two-channel pattern Button's own resting\n * fill uses (see Button.ts's chromeful `applyChromeOptions` branch).\n * `pressedForegroundColor`/`pressedShadow`/`hoverShadow` are pinned to the\n * same value as the resting tier — window-control buttons never change\n * colour or shadow on press/hover, only background — so the `ownStyleStates`\n * merge below doesn't leak Button's generic raised pressed/hover chrome onto\n * these two properties. `borderRadius: undefined` is an explicit key (not an\n * omission) so it wins over Button's own non-empty default in the\n * subclassDefaults spread merge, mirroring TabButton's identical trick.\n */\nconst _defaultWindowControlOptions: Partial<ButtonOptions> = {\n backgroundColor: \"var(--ts-ui-window-control-bg)\",\n backgroundImage: \"var(--ts-ui-window-control-bg)\",\n border: \"var(--ts-ui-window-control-border)\",\n borderRadius: undefined,\n shadow: \"var(--ts-ui-window-control-shadow)\",\n pressedForegroundColor: \"var(--ts-ui-text-color, black)\",\n pressedBackgroundColor: \"var(--ts-ui-window-control-active-bg)\",\n pressedBackgroundImage: \"var(--ts-ui-window-control-active-bg)\",\n pressedShadow: \"var(--ts-ui-window-control-shadow)\",\n hoverBackgroundColor: \"var(--ts-ui-window-control-hover-bg)\",\n hoverBackgroundImage: \"var(--ts-ui-window-control-hover-bg)\",\n hoverShadow: \"var(--ts-ui-window-control-shadow)\",\n};\n\n/**\n * A single window control button (minimize / maximize / close), shared by\n * `TabWindow`'s trailing tools and `WindowHeader`'s trailing buttons. Real,\n * declared chrome instead of `chromeless: true` — see\n * plans/implemented/button-variant-chrome-dedup.md's Architecture Decisions\n * for why chromeless's bare-`#id` resting write can never lose to a shared\n * class rule. Module-private: not exported, not wrapped in `callable()`\n * (same treatment as `CheckboxBox` in `Checkbox.ts`).\n */\nclass WindowControlButton extends Button {\n protected static readonly ownClassStyleDefaults: StyleBag = _defaultWindowControlOptions;\n\n protected static readonly ownStyleStates: readonly StyleStateSpec[] = [\n {\n selector: \".pressed\",\n extract: (): StyleBag => ({\n foregroundColor: _defaultWindowControlOptions.pressedForegroundColor,\n backgroundColor: _defaultWindowControlOptions.pressedBackgroundColor,\n backgroundImage: _defaultWindowControlOptions.pressedBackgroundImage,\n shadow: _defaultWindowControlOptions.pressedShadow,\n }),\n },\n {\n selector: \":hover\",\n extract: (): StyleBag => ({\n backgroundColor: _defaultWindowControlOptions.hoverBackgroundColor,\n backgroundImage: _defaultWindowControlOptions.hoverBackgroundImage,\n shadow: _defaultWindowControlOptions.hoverShadow,\n }),\n },\n ];\n\n constructor(glyph: string, subclassDefaults?: Partial<ButtonOptions>) {\n super(undefined, { glyph, insets: new Insets(2, 2, 2, 2) }, { ..._defaultWindowControlOptions, ...(subclassDefaults ?? {}) });\n }\n}\n\n/**\n * Resting + pressed/hover defaults for the window-menu-trigger leading glyph\n * (title icon) — transparent at rest, so the bar/header surface shows\n * through, with a `1px solid transparent` border reserving the same border\n * box the real controls' themed border occupies (keeps it a size/inset\n * peer). `pressedShadow` / `hoverShadow` are pinned to `\"none\"` (this\n * button's own resting shadow), mirroring how `_defaultWindowControlOptions`\n * pins its own pressed/hover shadow to its resting value — the icon now\n * opens the window menu, so it needs the same active/hover background swap\n * `WindowControlButton` declares, just never a shadow or foreground change.\n */\nconst _defaultWindowLeadGlyphOptions: Partial<ButtonOptions> = {\n backgroundColor: \"transparent\",\n backgroundImage: \"none\",\n border: \"1px solid transparent\",\n borderRadius: undefined,\n shadow: \"none\",\n pressedForegroundColor: \"var(--ts-ui-text-color, black)\",\n pressedBackgroundColor: \"var(--ts-ui-window-control-active-bg)\",\n pressedBackgroundImage: \"var(--ts-ui-window-control-active-bg)\",\n pressedShadow: \"none\",\n hoverBackgroundColor: \"var(--ts-ui-window-control-hover-bg)\",\n hoverBackgroundImage: \"var(--ts-ui-window-control-hover-bg)\",\n hoverShadow: \"none\",\n};\n\n/**\n * The window's leading glyph (title icon) and system-menu trigger. Real,\n * declared chrome — the same `ownStyleStates` shape `WindowControlButton`\n * declares — since a press now opens the window menu instead of falling\n * through to the window-move gesture.\n */\nclass WindowLeadGlyphButton extends Button {\n protected static readonly ownClassStyleDefaults: StyleBag = _defaultWindowLeadGlyphOptions;\n\n protected static readonly ownStyleStates: readonly StyleStateSpec[] = [\n {\n selector: \".pressed\",\n extract: (): StyleBag => ({\n foregroundColor: _defaultWindowLeadGlyphOptions.pressedForegroundColor,\n backgroundColor: _defaultWindowLeadGlyphOptions.pressedBackgroundColor,\n backgroundImage: _defaultWindowLeadGlyphOptions.pressedBackgroundImage,\n shadow: _defaultWindowLeadGlyphOptions.pressedShadow,\n }),\n },\n {\n selector: \":hover\",\n extract: (): StyleBag => ({\n backgroundColor: _defaultWindowLeadGlyphOptions.hoverBackgroundColor,\n backgroundImage: _defaultWindowLeadGlyphOptions.hoverBackgroundImage,\n shadow: _defaultWindowLeadGlyphOptions.hoverShadow,\n }),\n },\n ];\n\n constructor(glyph: string, subclassDefaults?: Partial<ButtonOptions>) {\n super(undefined, { glyph, insets: new Insets(2, 2, 2, 2) }, { ..._defaultWindowLeadGlyphOptions, ...(subclassDefaults ?? {}) });\n }\n}\n\n/**\n * Builds a window control button (minimize / maximize / close) shared by\n * `TabWindow` and `WindowHeader`. Callers wire the `\"action\"` listener and\n * may override the insets to match their container's box (a `TabWindow`'s\n * bar re-sets them to the compact tool inset).\n *\n * @param glyph - The registry glyph name to show.\n *\n * @returns The configured control button.\n */\nexport function createWindowControlButton(glyph: string): Button {\n return new WindowControlButton(glyph);\n}\n\n/**\n * Builds the window's leading glyph (title icon) shared by `TabWindow` and\n * `WindowHeader` — the window's system-menu trigger, not a decorative\n * pass-through. Same size/inset box as {@link createWindowControlButton} so\n * it is a peer of the trailing controls.\n *\n * @param glyph - The registry glyph name to show.\n *\n * @returns The configured leading glyph button.\n */\nexport function createWindowLeadGlyphButton(glyph: string): Button {\n const button = new WindowLeadGlyphButton(glyph);\n // Button sets its whole `_content` row to `pointer-events: none` so face\n // clicks fall through to the `<button>`; this button then sits inside\n // `TabBar._leadGroup`'s own `pointer-events: none`, so with no declaration\n // of its own it would stay un-hit-testable — see SplitButton's chevron\n // for the identical inherited-none reason.\n button.setPointerEvents(\"auto\");\n\n return button;\n}\n\n/**\n * Toggles a set of window control buttons between their opaque themed fill\n * (focused) and `\"transparent\"` (blurred). Two channels (`backgroundColor` +\n * `backgroundImage`), not the `background` shorthand — see this file's\n * `_defaultWindowControlOptions` comment for why. Shared by `TabWindow`'s\n * and `WindowHeader`'s focus hooks.\n *\n * @param buttons - The control buttons to flatten or restore.\n * @param active - True to restore the control fill, false to flatten it.\n */\nexport function setWindowControlsActive(buttons: Button[], active: boolean): void {\n const backgroundColor = active ? \"var(--ts-ui-window-control-bg)\" : \"transparent\";\n const backgroundImage = active ? \"var(--ts-ui-window-control-bg)\" : \"none\";\n\n for (const button of buttons) {\n button.setBackgroundColor(backgroundColor);\n button.setBackgroundImage(backgroundImage);\n }\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Header, HeaderOptions } from \"~/component/display/Header.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { Button, ClickListener } from \"~/component/button/Button.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { ThemeManager } from \"~/core/Theme.js\";\nimport { Glyph, GlyphOptions } from \"~/component/display/Glyph.js\";\nimport type { StyleTrait } from \"~/core/ClassStyleRules.js\";\nimport { GLYPH_MD_INK_TRAIT } from \"~/core/StyleTraits.js\";\nimport { UNBOUNDED } from \"~/primitive/Size.js\";\nimport { HBox } from \"~/layout/HBox.js\";\nimport { Fit } from \"~/layout/Fit.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { FillType } from \"~/layout/FillType.js\";\nimport { AnchorType } from \"~/layout/AnchorType.js\";\nimport { Placement } from \"~/primitive/Placement.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport {\n createWindowControlButton,\n setWindowControlsActive,\n} from \"~/overlay/windowControls.js\";\nimport { xmark } from \"~/glyphs/solid/xmark.js\";\nimport { window_maximize } from \"~/glyphs/solid/window_maximize.js\";\nimport { window_minimize } from \"~/glyphs/solid/window_minimize.js\";\nimport { window_restore } from \"~/glyphs/solid/window_restore.js\";\n\nGlyph.register(xmark, window_maximize, window_minimize, window_restore);\n\n// Equal top/bottom gap (px) around the title line inside the header band. The\n// header thickness is `textHeight + 2 * CHROME_MARGIN`; the stretched controls\n// fill that full-height band edge-to-edge (no overflow, so the region clip frame\n// contains them), and the Fit-centred title sits with this margin above and\n// below. Tuned so the thickness matches the established ~26px window-chrome height\n// (title line ≈ 18px + 2×4), keeping the redesign visually surgical.\nconst CHROME_MARGIN: number = 4;\n\n/**\n * Construction-time options for {@link WindowHeader}.\n *\n * @category Components\n */\nexport interface WindowHeaderOptions extends HeaderOptions {\n closeable?: boolean;\n minimizable?: boolean;\n maximizable?: boolean;\n glyph?: string;\n}\n\n// Cancels `Glyph`'s own glyphLg-sized minSize/maxSize default (see\n// `glyphDefaultSize()` in Glyph.ts), which would otherwise still deviate from\n// the framework baseline and reinstate a `.WindowHeaderTitleGlyph` class rule\n// carrying the wrong (glyphLg, not glyphMd) size. These values resolve to\n// exactly the framework's own minWidth/minHeight (\"0px\") and maxWidth/\n// maxHeight (\"none\"), so this class contributes no CSS deviation of its own —\n// GLYPH_MD_INK_TRAIT alone supplies the shared size, and `updatePreferredSize`\n// still pins the real per-instance value on top of it every render.\nconst NO_OWN_SIZE_DEFAULT: Partial<GlyphOptions> = {\n minSize: { width: 0, height: 0 },\n maxSize: { width: UNBOUNDED, height: UNBOUNDED },\n};\n\n/**\n * The leading icon inside a {@link WindowHeader}'s title row. Opts into\n * `GLYPH_MD_INK_TRAIT`, so every window's title icon shares one CSS rule\n * with `ComboBoxCaretGlyph`'s chevron instead of each repeating the same\n * theme-matched size on its own class rule.\n */\nclass WindowHeaderTitleGlyph extends Glyph {\n protected static readonly ownStyleTraits: readonly StyleTrait[] = [GLYPH_MD_INK_TRAIT];\n\n /**\n * @param name - The glyph to render.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; forwarded so a subclass can seed a default without\n * editing this constant.\n */\n constructor(name: string, subclassDefaults?: Partial<GlyphOptions>) {\n super(name, undefined, { ...NO_OWN_SIZE_DEFAULT, ...(subclassDefaults ?? {}) });\n }\n}\n\n/**\n * A window title bar component with an embedded `xmark` glyph close button\n * and an optional title icon shown to the west of the title text.\n *\n * Extends [`Header`](/api/component/display/classes/Header) by anchoring a\n * trailing row of minimize / maximize / close buttons to the east side and\n * exposing an optional title-icon slot on the west.\n *\n * @category Components\n */\nclass WindowHeader extends Header {\n\n private _exitButton: Button;\n private _minimizeButton: Button;\n private _maximizeButton: Button;\n private _trailingRow: Component;\n private _activeBackground: string;\n private _titleGlyph: Glyph | null = null;\n private _titleRow: Component;\n private _closeable: boolean = true;\n private _minimizable: boolean = true;\n private _maximizable: boolean = true;\n private _titleGlyphClickListener: (() => void) | null = null;\n private readonly _boundOnHeaderClick: (e: MouseEvent) => void = (e) => this.onHeaderClick(e);\n\n constructor(text: string, options?: WindowHeaderOptions) {\n super(text);\n\n // Focused fill: the dedicated window-header surface, valued equal to the\n // tab-toolbar fill a TabWindow's bar uses so a header Window and a headerless\n // TabWindow share one window-chrome colour (both also share the gutter fill\n // when blurred), while staying independently themeable. A solid colour, not\n // the button gradient that used to sit here.\n this._activeBackground = \"var(--ts-ui-window-header-bg, #eee)\";\n this.setBackgroundColor(this._activeBackground);\n\n // Horizontal-only padding: the header is a strip whose vertical extent is\n // the chrome thickness (see updatePreferredSize), so the internal Border\n // band spans the full height and the stretched trailing controls reach the\n // bottom edge where the content panel begins. A vertical inset would shrink\n // the band away from that edge and re-open the gap the redesign closes.\n this.setInsets(new Insets(0, 4, 0, 4));\n\n // Reparent the inherited title text into a permanent HBox row that\n // owns the Border WEST slot. setGlyph then only has to swap the\n // optional leading glyph child in or out of this row.\n const title = this.getText();\n this.removeComponent(title);\n\n this._titleRow = new Component();\n this._titleRow.setLayoutManager(new HBox({ spacing: 8 }));\n // Leading inset so the title icon sits the same distance from the left edge\n // as the trailing controls sit from the right (and as a TabWindow's leading\n // glyph) — without it the icon hugs the corner, closer in than the controls.\n this._titleRow.setInsets(new Insets(0, 0, 0, 5));\n this._titleRow.setPointerEvents(\"none\");\n this._titleRow.addComponent(title);\n\n // Centre the title line vertically in the full-height band: a Fit cell\n // fills the WEST region's width and centres its single child (the title\n // row) on the cross axis. A WEST `AnchorType.CENTER` would not work — the\n // non-collapsible Border region commits via the clip-frame path, which\n // bypasses anchor resolution — so the centring lives in this layout, not\n // the placement anchor.\n const titleCell = new Component();\n titleCell.setLayoutManager(new Fit({ fill: FillType.HORIZONTAL }));\n titleCell.setPointerEvents(\"none\");\n titleCell.addComponent(this._titleRow);\n\n this.addComponent(titleCell, {\n placement: Placement.WEST,\n anchor: AnchorType.WEST,\n fill: FillType.HORIZONTAL\n });\n\n // Control buttons built from the shared window-control factory so the\n // header's trailing controls match a TabWindow's exactly: the themed\n // `window.control` fill (white in modern, raised in classic). Like a\n // TabWindow's controls — stretched to the strip thickness — these are\n // stretched to the full header band (see the trailing row below), so their\n // `Insets(0,4,0,4)` only sets the within-box horizontal padding; the stretch\n // supplies the height. They fill the band edge-to-edge (no overflow, so the\n // clip frame contains them) and meet the content panel at the bottom edge.\n this._minimizeButton = createWindowControlButton(\"window-minimize\");\n this._maximizeButton = createWindowControlButton(\"window-maximize\");\n this._exitButton = createWindowControlButton(\"xmark\");\n\n for (const control of [this._minimizeButton, this._maximizeButton, this._exitButton]) {\n control.setInsets(new Insets(0, 4, 0, 4));\n }\n\n this._trailingRow = new Component();\n this._trailingRow.setLayoutManager(new HBox({ spacing: 0, stretching: true }));\n this._trailingRow.setInsets(new Insets(0, 0, 0, 0));\n this._trailingRow.addComponent(this._minimizeButton);\n this._trailingRow.addComponent(this._maximizeButton);\n this._trailingRow.addComponent(this._exitButton);\n\n this.addComponent(this._trailingRow, { placement: Placement.EAST });\n\n // Default title icon: applied unless an explicit glyph name was passed.\n // Call clearGlyph() on the resulting WindowHeader to opt out entirely.\n if (options?.glyph === undefined) {\n this.setGlyph(\"window-maximize\");\n }\n\n if (options) {\n this.applyOptions(options);\n }\n }\n\n /**\n * Derives the header's preferred height as a chrome-band thickness —\n * `textHeight + 2 * CHROME_MARGIN` — rather than the base `textHeight +\n * vertical insets`. With the vertical insets zeroed (so the band reaches the\n * content edge for the stretched controls), the base derivation would collapse\n * the header to the bare text height; this override supplies the breathing band\n * that seats the control box and centres the title line. Runs at construction\n * and on every theme change (the base wires both to this method), so the\n * thickness survives a theme toggle.\n *\n * @remarks Touches the `_titleGlyph` subclass field only behind an\n * `if (this._titleGlyph)` guard, so it stays safe when called via `super()`\n * before subclass fields init: during the super-cascade the field is\n * `undefined`, the guard skips the re-pin, and the rest reads only the\n * inherited text and the module constant.\n */\n protected updatePreferredSize(): void {\n // 20px mirrors the base Header's pre-measurement fallback (a sane default\n // line height before the text element has measured); the real height takes\n // over on the first measured pass.\n const textSize = this.getText().getPreferredSize();\n const textHeight = textSize ? textSize.height : 20;\n\n this.setPreferredSize({ width: 100, height: textHeight + 2 * CHROME_MARGIN });\n\n // Re-pin the title glyph's ink whenever the header re-measures — the\n // inherited Header theme listener drives this method on construction and\n // every theme change, so an SVG title glyph follows a base-size change\n // with no listener of our own. Guarded because the field is undefined\n // during the super() cascade that first runs this method.\n if (this._titleGlyph) {\n const ink = this.resolveTitleGlyphInk();\n this._titleGlyph.setPreferredSize({ width: ink, height: ink });\n }\n }\n\n /**\n * Reads the title-glyph ink size in px from the active theme's resolved\n * scale snapshot. Read at render time (the `updatePreferredSize` re-pin and\n * `setGlyph`); a base- or theme-change re-resolves the snapshot in `setTheme`\n * and the next layout pass picks it up.\n *\n * @returns The title-glyph ink size in pixels.\n */\n private resolveTitleGlyphInk(): number {\n return ThemeManager.getResolvedScale().glyphMd;\n }\n\n /**\n * Applies a {@link WindowHeaderOptions} bag, dispatching the closeable,\n * minimizable, and maximizable flags and the optional title-glyph name\n * after inherited Header fields.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: WindowHeaderOptions): this {\n super.applyOptions(options);\n\n if (options.closeable !== undefined) {\n this.setCloseable(options.closeable);\n }\n\n if (options.minimizable !== undefined) {\n this.setMinimizable(options.minimizable);\n }\n\n if (options.maximizable !== undefined) {\n this.setMaximizable(options.maximizable);\n }\n\n if (options.glyph !== undefined) {\n this.setGlyph(options.glyph);\n }\n\n return this;\n }\n\n /**\n * Sets or clears the title icon shown to the west of the header text.\n *\n * @param name - Registry glyph name to display, or `null` to remove the icon.\n *\n * @returns This component, for method chaining.\n *\n * @remarks\n * Swaps the optional leading glyph child of the permanent title row built\n * by the constructor. The inherited title text always lives inside that\n * row, so the two never overlap and Border's WEST slot only ever tracks\n * one component.\n */\n setGlyph(name: string): this {\n if (this._titleGlyph) {\n this._titleRow.removeComponent(this._titleGlyph);\n this._titleGlyph = null;\n }\n\n // The window's system-menu trigger, sized to the same ink the\n // TabWindow's leading glyph renders, so the title icon matches it. Kept a\n // plain Glyph rather than a control-peer button so it baseline-aligns with\n // the title text in this shared row (a taller control box would desync the\n // text's vertical centring); the leading inset on the title row supplies the\n // corner offset that mirrors the TabWindow's. Pointer events are re-enabled\n // (its `pointer-events: none` ancestors leave the rest of the title row a\n // drag handle) and the cursor reads clickable.\n const glyph = new WindowHeaderTitleGlyph(name);\n const ink = this.resolveTitleGlyphInk();\n glyph.setPreferredSize({ width: ink, height: ink });\n glyph.setPointerEvents(\"auto\");\n glyph.setCursor(\"pointer\");\n this._titleGlyph = glyph;\n\n this._titleRow.insertComponent(glyph, 0);\n\n return this;\n }\n\n /**\n * Removes the title icon from the header, if one is present.\n *\n * @returns This component, for method chaining.\n */\n clearGlyph(): this {\n if (this._titleGlyph) {\n this._titleRow.removeComponent(this._titleGlyph);\n this._titleGlyph = null;\n }\n\n return this;\n }\n\n /**\n * Returns the current title-glyph component, or null if none is set.\n *\n * @returns The title [`Glyph`](/api/component/display/classes/Glyph), or null.\n */\n getGlyph(): Glyph | null {\n return this._titleGlyph;\n }\n\n /**\n * Toggles the title bar appearance between the focused and unfocused states.\n *\n * @param active - True to show the focused tab-toolbar background; false for the unfocused gutter background.\n */\n setActive(active: boolean): this {\n this.setBackgroundColor(active\n ? this._activeBackground\n : \"var(--ts-ui-gutter-bg, rgb(200, 200, 200))\");\n\n // Flatten the controls to transparent on blur (and restore the themed fill\n // on focus) exactly like a TabWindow's bar, via the shared helper.\n setWindowControlsActive([this._minimizeButton, this._maximizeButton, this._exitButton], active);\n\n return this;\n }\n\n /**\n * Enables or disables the close (exit) button. Disabling greys it out and\n * stops it firing, rather than hiding it — so a non-closeable window keeps a\n * full, evenly-spaced button row instead of a gap where the close button was.\n *\n * @param value - True to enable the close button, false to disable it.\n *\n * @returns This component, for method chaining.\n */\n setCloseable(value: boolean): this {\n this._closeable = value;\n this._exitButton.setEnabled(value);\n\n return this;\n }\n\n /**\n * Returns whether the close button is enabled.\n *\n * @returns True when the close button is enabled.\n */\n isCloseable(): boolean {\n return this._closeable;\n }\n\n /**\n * Toggles the visibility of the minimize button.\n *\n * @param value - True to show the minimize button, false to hide it.\n *\n * @returns This component, for method chaining.\n */\n setMinimizable(value: boolean): this {\n this._minimizable = value;\n this._minimizeButton.setVisible(value);\n\n return this;\n }\n\n /**\n * Returns whether the minimize button is visible.\n *\n * @returns True when the minimize button is shown.\n */\n isMinimizable(): boolean {\n return this._minimizable;\n }\n\n /**\n * Toggles the visibility of the maximize button.\n *\n * @param value - True to show the maximize button, false to hide it.\n *\n * @returns This component, for method chaining.\n */\n setMaximizable(value: boolean): this {\n this._maximizable = value;\n this._maximizeButton.setVisible(value);\n\n return this;\n }\n\n /**\n * Returns whether the maximize button is visible.\n *\n * @returns True when the maximize button is shown.\n */\n isMaximizable(): boolean {\n return this._maximizable;\n }\n\n /**\n * Enables or disables the maximize button without hiding it — used while\n * the owning window is locked, since maximizing (and un-maximizing) is\n * itself a resize. Distinct from {@link setMaximizable}, which hides the\n * button entirely: `locked` is a runtime-togglable state, not a\n * construction-time capability, so it disables the still-visible button\n * instead, mirroring {@link setCloseable}'s disable-not-hide convention.\n *\n * @param value - True to enable the maximize button, false to disable it.\n *\n * @returns This component, for method chaining.\n */\n setMaximizeButtonEnabled(value: boolean): this {\n this._maximizeButton.setEnabled(value);\n\n return this;\n }\n\n /**\n * Returns whether the maximize button is currently enabled.\n *\n * @returns True when the maximize button is enabled.\n */\n isMaximizeButtonEnabled(): boolean {\n return this._maximizeButton.isEnabled();\n }\n\n /**\n * Swaps the maximize button's glyph between the \"maximize\" and \"restore\"\n * icons. Called by the owning [`Window`](/api/overlay/classes/Window) when\n * transitioning between the `\"normal\"` and `\"maximized\"` states.\n *\n * @param name - Either `\"window-maximize\"` or `\"window-restore\"`.\n *\n * @returns This component, for method chaining.\n */\n setMaximizeButtonGlyph(name: \"window-maximize\" | \"window-restore\"): this {\n this._maximizeButton.setGlyph(name);\n\n return this;\n }\n\n /**\n * Swaps the minimize button's glyph between the \"minimize\" and \"restore\"\n * icons. Called by the owning [`Window`](/api/overlay/classes/Window) when\n * transitioning into and out of the `\"minimized\"` state — while minimized the\n * window stays docked at header height with the button visible, so a restore\n * glyph signals that pressing it un-minimizes (mirroring the maximize button's\n * restore swap).\n *\n * @param name - Either `\"window-minimize\"` or `\"window-restore\"`.\n *\n * @returns This component, for method chaining.\n */\n setMinimizeButtonGlyph(name: \"window-minimize\" | \"window-restore\"): this {\n this._minimizeButton.setGlyph(name);\n\n return this;\n }\n\n /**\n * Registers a click listener on the window close button.\n *\n * @param listener - The callback to invoke when the close button is clicked.\n */\n addExitButtonListener(listener: Function) : this {\n this._exitButton.on(\"action\", listener as ClickListener);\n\n return this;\n }\n\n /**\n * Registers a click listener on the window minimize button.\n *\n * @param listener - The callback to invoke when the minimize button is clicked.\n */\n addMinimizeButtonListener(listener: Function): this {\n this._minimizeButton.on(\"action\", listener as ClickListener);\n\n return this;\n }\n\n /**\n * Registers a click listener on the window maximize button.\n *\n * @param listener - The callback to invoke when the maximize button is clicked.\n */\n addMaximizeButtonListener(listener: Function): this {\n this._maximizeButton.on(\"action\", listener as ClickListener);\n\n return this;\n }\n\n /**\n * Registers a `dblclick` listener on the header bar itself, used by the\n * owning [`Window`](/api/overlay/classes/Window) to toggle the maximize state\n * when the user double-clicks the title (but not the trailing buttons).\n *\n * @param listener - The callback to invoke on `dblclick`.\n */\n addHeaderDoubleClickListener(listener: Event.Listener): this {\n // Subtree, not exact-target: the title row sits inside a Border clip-frame\n // wrapper, so a double-click on the title text/glyph targets that wrapper\n // rather than the bare header element. The owning Window's handler already\n // filters out the trailing buttons via targetIsInHeaderControl.\n Event.addSubtreeListener(this, \"dblclick\", listener);\n\n return this;\n }\n\n /**\n * Registers a listener for a click on the title icon. A second call\n * replaces the listener; the underlying subtree click listener is wired\n * only once, on the first call.\n *\n * @param listener - The callback to invoke when the title icon is clicked.\n *\n * @returns This component, for method chaining.\n */\n addTitleGlyphClickListener(listener: () => void): this {\n if (this._titleGlyphClickListener === null) {\n // Subtree, not exact-target: the icon sits inside the title row's\n // own clip-frame wrapper (see addHeaderDoubleClickListener), so a\n // click on it targets that wrapper rather than the bare header.\n Event.addSubtreeListener(this, \"click\", this._boundOnHeaderClick);\n }\n\n this._titleGlyphClickListener = listener;\n\n return this;\n }\n\n /**\n * Subtree `click` handler backing {@link addTitleGlyphClickListener}:\n * invokes the registered listener only when the click landed inside the\n * title icon.\n *\n * @param e - The header subtree's `click` event.\n */\n private onHeaderClick(e: MouseEvent): void {\n const target = e.target === null ? null : DOM.source.intern(e.target);\n const glyphEl = this._titleGlyph?.getElement();\n\n if (!target || !glyphEl || !DOM.source.contains(glyphEl, target)) {\n return;\n }\n\n this._titleGlyphClickListener?.();\n }\n\n /**\n * Computes the natural required width of the header: title glyph width\n * (or 0 when no glyph is set) plus the supplied text budget plus the\n * three trailing buttons' row width. Used by the owning\n * [`Window`](/api/overlay/classes/Window) to derive a minSize that keeps\n * the title icon, some text space, and the trailing buttons all visible\n * when the window is shrunk.\n *\n * @param textBudget - Pixels to reserve for the title text label.\n *\n * @returns The natural required header width in pixels.\n */\n getMinContentWidth(textBudget: number = 100): number {\n const glyphW = this._titleGlyph?.getPreferredSize()?.width ?? 0;\n const trailingW = this._trailingRow.getPreferredSize()?.width ?? 0;\n\n return glyphW + textBudget + trailingW;\n }\n\n /**\n * Returns the minimize button DOM element, if the header has been rendered.\n *\n * @returns The minimize button's HTMLElement, or undefined when the header\n * has not yet been rendered.\n *\n * @remarks Used by the owning [`Window`](/api/overlay/classes/Window) to\n * short-circuit `dblclick`-on-header maximize toggling when the click\n * target sits inside one of the trailing buttons.\n */\n getMinimizeButtonElement(): Handle | undefined {\n return this._minimizeButton.getElement();\n }\n\n /**\n * Returns the maximize button DOM element, if the header has been rendered.\n *\n * @returns The maximize button's HTMLElement, or undefined when the header\n * has not yet been rendered.\n */\n getMaximizeButtonElement(): Handle | undefined {\n return this._maximizeButton.getElement();\n }\n\n /**\n * Returns the close (exit) button DOM element, if the header has been rendered.\n *\n * @returns The exit button's HTMLElement, or undefined when the header\n * has not yet been rendered.\n */\n getExitButtonElement(): Handle | undefined {\n return this._exitButton.getElement();\n }\n}\n\nconst WindowHeaderCallable = callable(WindowHeader);\ntype WindowHeaderCallable = WindowHeader;\nexport {\n WindowHeader as _WindowHeader,\n WindowHeaderCallable as WindowHeader\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Border } from \"~/layout/Border.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { DOM, type Handle } from \"~/core/DOM.js\";\nimport { WindowHeader } from \"~/component/container/WindowHeader.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { Placement } from \"~/primitive/Placement.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport { DragManager, DragData, DragEventDetail, TabDragData, tabDragRegistry } from \"~/overlay/DragManager.js\";\nimport {\n AbstractWindow,\n WindowOptions,\n WindowState,\n} from \"~/overlay/AbstractWindow.js\";\n\nexport type {\n WindowOptions,\n WindowState,\n WindowMaximizeBounds,\n WindowSnapModifier,\n WindowRect,\n} from \"~/overlay/AbstractWindow.js\";\n\n/**\n * A floating, resizable, and draggable window component.\n *\n * Renders a titled panel with eight border-handle strips that the user can\n * drag to resize the window from any edge or corner. Supports a three-state\n * lifecycle (`\"normal\"` / `\"minimized\"` / `\"maximized\"`) accessed through\n * {@link Window.setWindowState}, plus an opt-in Ctrl-snap resize affordance\n * that highlights the nearest border within a 12-pixel threshold so the\n * 4-pixel-wide grab strips are easier to land on.\n *\n * Extends {@link AbstractWindow}, which owns the header-agnostic window\n * machinery; `Window` adds the `Border` layout, a non-null\n * {@link WindowHeader} in NORTH, content in CENTER, and the Shift-drag re-dock\n * source. It implements the base's hooks via its header.\n *\n * @category Core\n */\nclass Window extends AbstractWindow {\n\n private _header: WindowHeader;\n\n // Shift-drag re-dock: a header press with Shift held starts a tab-dock drag\n // instead of a window move. Shift (not Ctrl) so it never collides with the\n // Ctrl snap-resize affordance. `_headerDragShift` captures the modifier at\n // press (the drag-source callbacks get no key state); `_headerDragComponentId`\n // stashes the registered content id so onDragEnd can clean the registry after\n // the dock already moved the content out.\n private _headerDragShift: boolean = false;\n private _headerDragComponentId: string = \"\";\n private readonly _boundCaptureHeaderShift: (e: MouseEvent) => void = (e: MouseEvent) => this.captureHeaderShift(e);\n private readonly _boundOnHeaderMouseDown: (e: MouseEvent) => void = (e: MouseEvent) => this.onHeaderMouseDown(e);\n private readonly _boundOnTitleGlyphClick: () => void = () => this.onTitleGlyphClick();\n\n /**\n * Builds a header window: a `Border` layout with a {@link WindowHeader} in\n * NORTH, wires the header buttons and the Shift-drag re-dock source, then\n * runs the base's late chrome setup via `initChrome`.\n *\n * @param headerText - The initial title-bar text (overridden by\n * `options.headerText` when both are supplied).\n * @param options - Optional window configuration.\n */\n constructor(headerText: string, options?: WindowOptions) {\n super(options);\n\n this.setLayoutManager(new Border());\n\n // Build the header with the effective text up front (consumer's\n // `options.headerText` from the cascade-written `_options`, falling\n // back to the positional argument, falling back to \"Window\"). The\n // late-built dispatch below skips `setHeaderText` because the header\n // already carries the right text — re-setting it would write the\n // same value twice.\n const effectiveHeaderText = this._options.headerText ?? headerText ?? \"Window\";\n this._header = new WindowHeader(effectiveHeaderText);\n this.addComponent(this._header, {\n placement: Placement.NORTH,\n ignoreParentInsets: true\n });\n this._header.addExitButtonListener(() => this.onExitAction());\n this._header.addMinimizeButtonListener(() => this.toggleMinimize());\n this._header.addMaximizeButtonListener(() => this.toggleMaximize());\n this._header.addHeaderDoubleClickListener((e: MouseEvent) => this.onHeaderDoubleClick(e));\n this._header.addTitleGlyphClickListener(this._boundOnTitleGlyphClick);\n\n // Late-built state: the glyph field was written pure to `_options` by\n // the super-time cascade. Dispatch it now that `this._header` exists.\n // (The generic contentFactory / state dispatch runs in initChrome.)\n if (this._options.glyph !== undefined) {\n this._header.setGlyph(this._options.glyph);\n }\n\n this.initChrome(options);\n }\n\n /**\n * Returns the window's title-bar component.\n *\n * @returns The internal {@link WindowHeader} instance, exposing the close\n * button, title text, and optional title-icon slot.\n */\n getHeader(): WindowHeader {\n return this._header;\n }\n\n /**\n * Updates the text shown in the window's title bar.\n *\n * @param text - The new header label text.\n *\n * @returns This window, for method chaining.\n */\n setHeaderText(text: string): this {\n if (!this._header) {\n throw new Error(\"Window does not have a header.\");\n }\n\n this._header.getText().setText(text);\n\n return this;\n }\n\n /**\n * Sets the title-bar glyph (leading icon). Also caches it on the options bag\n * so {@link AbstractWindow.getGlyph} (read by a rail to label a minimized\n * window's handle) stays in sync with runtime changes.\n *\n * @param glyph - The glyph name to show before the title text.\n *\n * @returns This window, for method chaining.\n */\n setGlyph(glyph: string): this {\n this._options.glyph = glyph;\n this._header.setGlyph(glyph);\n\n return this;\n }\n\n // ----- AbstractWindow hook implementations -----\n\n /**\n * Wires the window-move gesture: a plain header `mousedown` starts a window\n * move, a Shift-held press is captured for the re-dock drag source, and the\n * header is registered as a tab-dock drag source.\n */\n protected wireMoveTrigger(): void {\n // Subtree listeners (not exact-target) because the header's title row sits\n // inside a Border clip-frame wrapper: a press on the title text or glyph\n // targets that wrapper, not the bare header element, so an exact-target\n // listener would miss it. Matches the drag source below, which already\n // observes the whole header subtree via addMouseDownSubtreeListener.\n // Vetoes a press on the trailing minimize/maximize/close buttons — those\n // own their own click handlers and must not also start a window move.\n Event.addSubtreeListener(this._header, \"mousedown\", this._boundOnHeaderMouseDown);\n\n // Shift-drag the header to re-dock the window's body content onto a Tab\n // strip. The capture listener records the modifier (registered before the\n // drag source so it runs first); the drag source vetoes a plain (no-Shift)\n // press so the normal window move runs.\n Event.addSubtreeListener(this._header, \"mousedown\", this._boundCaptureHeaderShift);\n DragManager.makeDragSource(this._header, {\n dragData: (): DragData => this.buildHeaderDragData(),\n onDragStart: (): boolean | void => this.onHeaderDragStart(),\n onDragEnd: (_detail: DragEventDetail, dropped: boolean): void => this.onHeaderDragEnd(dropped),\n });\n }\n\n /**\n * Reflects the closeable state onto the header close button.\n *\n * @param value - True to enable the close button.\n */\n protected reflectCloseable(value: boolean): void {\n this._header.setCloseable(value);\n }\n\n /**\n * Reflects the minimizable state onto the header minimize button.\n *\n * @param value - True to show the minimize button.\n */\n protected reflectMinimizable(value: boolean): void {\n this._header.setMinimizable(value);\n }\n\n /**\n * Reflects the maximizable state onto the header maximize button.\n *\n * @param value - True to show the maximize button.\n */\n protected reflectMaximizable(value: boolean): void {\n this._header.setMaximizable(value);\n }\n\n /**\n * Reflects the maximize-availability gate onto the header maximize\n * button's enabled state, without touching its visibility.\n *\n * @param value - True to enable the maximize button.\n */\n protected reflectMaximizeAvailability(value: boolean): void {\n this._header.setMaximizeButtonEnabled(value);\n }\n\n /**\n * Swaps the header control glyphs to match the window state: the maximize\n * button shows `window-restore` when maximized (else `window-maximize`), and\n * the minimize button shows `window-restore` when minimized (else\n * `window-minimize`). A minimized window stays docked at header height with\n * both buttons visible, so reflecting the minimized state onto the minimize\n * button keeps it symmetric with the maximize/restore swap.\n *\n * @param state - The window state being entered.\n */\n protected reflectMaximizeState(state: WindowState): void {\n this._header.setMaximizeButtonGlyph(state === \"maximized\" ? \"window-restore\" : \"window-maximize\");\n this._header.setMinimizeButtonGlyph(state === \"minimized\" ? \"window-restore\" : \"window-minimize\");\n }\n\n /**\n * Paints the active/inactive state onto the title bar.\n *\n * @param active - True when this window is the active layer.\n */\n protected paintActive(active: boolean): void {\n this._header.setActive(active);\n }\n\n /**\n * Returns the title-bar text for serialization.\n *\n * @returns The current header text.\n */\n getTitle(): string {\n return String(this._header.getText().getText());\n }\n\n /**\n * Returns the header's required width, seeded into the default min size.\n *\n * @returns The header min-content width in pixels.\n */\n protected minContentWidthSeed(): number {\n return this._header.getMinContentWidth();\n }\n\n /**\n * Returns the header's laid-out height — the window's title chrome height.\n *\n * @returns The header height in pixels.\n */\n protected chromeHeight(): number {\n return this._header.getHeight();\n }\n\n /**\n * Adds content to the window's CENTER region.\n *\n * @param content - The content component to add.\n */\n protected addContent(content: Component): void {\n this.addComponent(content, { placement: Placement.CENTER });\n }\n\n /**\n * Reports whether `child` is the window's chrome — true only for the header.\n *\n * @param child - The child component to classify.\n * @returns True when `child` is the header.\n */\n isChromeComponent(child: Component): boolean {\n return child === this._header;\n }\n\n // ----- header-specific gestures -----\n\n /**\n * Starts a window move from a header press, unless the press lands on one\n * of the trailing minimize/maximize/close buttons — those own their own\n * click handlers and must not also drag the window.\n *\n * @param e - The header `mousedown` event.\n */\n private onHeaderMouseDown(e: MouseEvent): void {\n const target = e.target === null ? null : DOM.source.intern(e.target);\n if (target && this.targetIsInHeaderControl(target)) {\n return;\n }\n\n this.onMouseDown(e);\n }\n\n /**\n * Handles `dblclick` on the header bar. When minimized, restores to the\n * pre-minimize state (`\"normal\"` or `\"maximized\"`); otherwise toggles\n * maximize. Clicks on the trailing buttons are ignored — they own their\n * own handlers.\n *\n * @param e - The header `dblclick` event.\n */\n private onHeaderDoubleClick(e: MouseEvent): void {\n const target = e.target === null ? null : DOM.source.intern(e.target);\n if (target && this.targetIsInHeaderControl(target)) {\n return;\n }\n\n if (this.getWindowState() === \"minimized\") {\n this.setWindowState(this._preMinimizeState);\n return;\n }\n\n if (!this.canMaximize()) {\n return;\n }\n this.toggleMaximize();\n }\n\n /**\n * Returns whether `target` lies inside one of the header's own controls —\n * the trailing minimize / maximize / exit buttons, or the leading title\n * icon — each of which owns its own click handler and must not also\n * start a window move or trigger the header's double-click maximize.\n *\n * @param target - The event target handle to test.\n * @returns True when the target is inside a header control.\n */\n private targetIsInHeaderControl(target: Handle): boolean {\n const controls: Array<Handle | undefined> = [\n this._header.getMinimizeButtonElement(),\n this._header.getMaximizeButtonElement(),\n this._header.getExitButtonElement(),\n this._header.getGlyph()?.getElement(),\n ];\n for (const control of controls) {\n if (control && DOM.source.contains(control, target)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Opens the window menu anchored under the header's title icon, in\n * response to a click on it.\n */\n private onTitleGlyphClick(): void {\n const glyph = this._header.getGlyph();\n\n if (glyph) {\n this.openWindowMenu(glyph);\n }\n }\n\n /**\n * Records whether Shift was held at the header press, so the header drag\n * source — whose callbacks receive no key state — can tell a re-dock gesture\n * from a plain window move.\n *\n * @param e - The header `mousedown` event.\n */\n private captureHeaderShift(e: MouseEvent): void {\n this._headerDragShift = e.shiftKey;\n }\n\n /**\n * Builds the tab-dock payload for a Shift-drag of the header. `sourceTabId` is\n * the window's own id — never a strip's, so a drop target treats it as a\n * foreign dock rather than a same-strip reorder.\n *\n * @returns The {@link TabDragData} payload for the window's body content.\n */\n private buildHeaderDragData(): DragData {\n const content = this.findBodyHost();\n\n const data: TabDragData = {\n tabDrag: true,\n sourceTabId: this.getId(),\n componentId: content ? content.getId() : \"\",\n label: String(this._header.getText().getText()),\n };\n\n return { ...data };\n }\n\n /**\n * Vetoes the header drag unless Shift was held and the window has body\n * content. When it proceeds, it registers the live content so the\n * destination strip can resolve it from the id-only drag data.\n *\n * @returns `false` to veto (plain move / nothing to dock); otherwise `void`.\n */\n private onHeaderDragStart(): boolean | void {\n const shift = this._headerDragShift;\n this._headerDragShift = false;\n\n const content = this.findBodyHost();\n\n if (!shift || !content) {\n return false;\n }\n\n this._headerDragComponentId = content.getId();\n tabDragRegistry.set(content.getId(), content);\n }\n\n /**\n * Cleans up the registry entry once the gesture ends and, when the drop\n * docked the content elsewhere (so the window has emptied), closes the window.\n *\n * @param dropped - `true` when the release landed on a registered drop\n * target (whether it accepted or refused the drop); `false` on a release\n * over empty space. The window only closes when the content actually left.\n */\n private onHeaderDragEnd(dropped: boolean): void {\n tabDragRegistry.delete(this._headerDragComponentId);\n this._headerDragComponentId = \"\";\n\n if (dropped && this.findBodyHost() === null) {\n this.requestClose();\n }\n }\n}\n\nconst WindowCallable = callable(Window);\ntype WindowCallable = Window;\nexport {\n Window as _Window,\n WindowCallable as Window\n};\n"],"mappings":"imCAuBA,IAAY,EAAL,SAAA,EAAA,OACH,GAAA,EAAA,MAAA,GAAA,QACA,EAAA,EAAA,MAAA,GAAA,QACA,EAAA,EAAA,KAAA,GAAA,OACA,EAAA,EAAA,KAAA,GAAA,OACA,EAAA,EAAA,UAAA,GAAA,YACA,EAAA,EAAA,UAAA,GAAA,YACA,EAAA,EAAA,UAAA,GAAA,YACA,EAAA,EAAA,UAAA,GAAA,aACJ,EAAA,CAAA,CAAA,EAwBM,EAAoB,cAMpB,EAA4D,CAC9D,IAAK,KACT,EAGM,EAA2E,OAAO,OAAO,CAC3F,UAAW,kEACf,CAAC,EAWK,aAAN,cAA2B,CAA+B,CAItD,OAA0B,eAA4C,CAClE,CACI,SAAU,eACV,aAA2B,CAAE,OAAQ,EAAuC,SAAU,EAC1F,CACJ,EAEA,WAAQ,EACR,WAAqD,KAAK,oBAAoB,IAAI,CAAgC,EAClH,mBACA,kBACA,kBACA,YAA+B,GAS/B,YACI,EACA,EACA,EACF,CACE,MAAM,EAAS,CAAE,GAAG,EAA6B,GAAI,GAAoB,CAAC,CAAG,CAAC,EAE1E,IACA,KAAK,WAAa,GAYtB,IAAM,EAAS,KAAK,WAAW,EAC3B,GACA,KAAK,UAAU,CAAM,EAGzB,KAAK,mBAAqB,KAAK,YAAY,KAAK,IAAI,EACpD,KAAK,kBAAoB,KAAK,WAAW,KAAK,IAAI,EAClD,KAAK,kBAAoB,KAAK,cAAc,KAAK,IAAI,EAErD,EAAM,YAAY,KAAM,YAAa,KAAK,kBAAkB,EAE5D,KAAK,eAAe,GAAS,SAAS,CAC1C,CAOA,cAAe,CACX,OAAO,KAAK,UAChB,CAOA,aAAa,EAA6B,CAOtC,MANA,CACI,IAAA,EAGJ,KAAK,WAAa,EAEX,IACX,CAYA,GAAG,EAA2B,EAA0B,CAGpD,OAFA,KAAK,WAAW,IAAI,EAAO,CAAQ,EAE5B,IACX,CAWA,IAAI,EAA0B,EAA0B,CAGpD,OAFA,KAAK,WAAW,OAAO,EAAO,CAAQ,EAE/B,IACX,CAUA,KAAe,EAA0B,GAAG,EAA0B,CAClE,KAAK,WAAW,KAAK,EAAO,GAAG,CAAO,CAC1C,CASA,cAAsB,EAAqC,CAGvD,OAFA,KAAK,KAAK,OAAQ,KAAM,CAAC,EAElB,EACX,CAOA,cAAwB,CACpB,OAAO,KAAK,WAChB,CAWA,cAAc,EAAsB,CAahC,OAZI,KAAK,cAAgB,EACd,MAGX,KAAK,YAAc,EAMnB,KAAK,cAAc,eAAyB,CAAK,EAE1C,KACX,CAWA,YAAY,EAAgB,CACpB,GAAK,CAAC,EAAM,gBAAgB,CAAC,IAIjC,EAAM,oBAAoB,KAAM,UAAW,KAAK,iBAAiB,EACjE,EAAM,oBAAoB,KAAM,WAAY,KAAK,iBAAiB,EAClE,EAAM,oBAAoB,KAAM,cAAe,KAAK,iBAAiB,EACrE,EAAM,oBAAoB,KAAM,YAAa,KAAK,iBAAiB,EACnE,EAAM,oBAAoB,KAAM,YAAa,KAAK,iBAAiB,EAInE,EAAiB,KAAK,WAAW,GAAK,SAAS,EACnD,CAOA,YAAmC,CAa/B,OAZA,EAAM,uBAAuB,KAAM,UAAW,KAAK,iBAAiB,EACpE,EAAM,uBAAuB,KAAM,WAAY,KAAK,iBAAiB,EACrE,EAAM,uBAAuB,KAAM,cAAe,KAAK,iBAAiB,EACxE,EAAM,uBAAuB,KAAM,YAAa,KAAK,iBAAiB,EACtE,EAAM,uBAAuB,KAAM,YAAa,KAAK,iBAAiB,EAEtE,EAAe,EAIf,KAAK,cAAc,EAAK,EAEjB,EACX,CASA,YAAyC,CACrC,OAAQ,KAAK,WAAb,CACI,IAAA,GACA,IAAA,GACI,MAAO,YACX,IAAA,GACA,IAAA,GACI,MAAO,YACX,IAAA,GACA,IAAA,GACI,MAAO,cACX,IAAA,GACA,IAAA,GACI,MAAO,aACf,CAGJ,CAQA,QAAS,CACL,IAAI,EAAU,MAAM,OAAO,EAM3B,OAJI,KAAK,aACL,EAAI,KAAK,MAAM,EAAS,CAAE,SAAU,CAAC,CAAiB,CAAE,CAAC,EAGtD,CACX,CAEJ,EAEM,EAAuB,EAAS,YAAY,EC5TlD,SAAgB,mBAA+B,CAC3C,IAAM,EAAO,IAAI,EAIjB,OAHA,EAAK,iBAAiB,IAAI,EAAI,CAAE,KAAM,EAAS,IAAK,CAAC,CAAC,EACtD,EAAK,aAAa,IAAI,EAAgB,EAAE,CAAC,EAElC,CACX,CCJA,IAAM,EAAmC,EACnC,EAAkC,IAUlC,EAAmC,IAMnC,EAAkC,IAclC,EAA4C,IAC5C,EAAmC,EACnC,EAAoC,IAOpC,EAAoC,GAKpC,EAAmC,GAKnC,EAAoC,GAuGpC,EAAgD,CAClD,EAAmB,GACnB,EAAmB,GACnB,MAAmB,IACnB,OAAmB,IACnB,OAAmB,IAAI,EAAO,EAAsB,EAAsB,EAAsB,CAAoB,EACpH,OAAmB,6CACnB,aAAmB,kCACnB,OAAmB,6DACnB,gBAAmB,2CACnB,UAAmB,GACnB,YAAmB,GACnB,YAAmB,GACnB,UAAmB,GACnB,YAAmB,GACnB,OAAmB,GACnB,eAAmB,WACnB,YAAmB,SACnB,kBAAmB,GACnB,cAAmB,GACnB,aAAmB,OACnB,oBAAqB,EACzB,EASM,EAAgC,GAmBhB,EAAtB,MAAsB,uBAAuB,CAAqD,CAI9F,OAA0B,sBAAkC,EAE5D,OAAe,YAAmC,IAAI,IAEtD,kBAWA,kBAA2C,KAC3C,gBAAkC,EAClC,gBAAkC,EAClC,eAA8C,KAC9C,qBAAwC,GACxC,qBAAuC,EACvC,qBAAuC,EACvC,eAAiC,EACjC,eAAiC,EACjC,eAAiC,EACjC,eAAiC,EACjC,WAA6B,GAC7B,eAAiC,EACjC,eAAiC,EACjC,cAAgC,EAChC,mBAAqC,EACrC,mBAAqC,EACrC,QAA0B,EAC1B,QAA0B,EAM1B,eAAiC,EACjC,eAAiC,EACjC,eAAiC,EACjC,eAAiC,EACjC,gBAAoD,KACpD,sBAAyE,KAEzE,kBAAuD,SACvD,aAAgD,KAChD,eAA0C,KAC1C,UAA+C,KAE/C,gBAAmC,GAGnC,MAA0C,KAE1C,YAA0C,KAE1C,iBAAuD,KAAK,oBAAoB,IAAI,CAA0B,EAC9G,iBAA4D,KAI5D,eAAgE,KAChE,sBAAgE,KAChE,gBAAgE,KAChE,uBAAgE,KAChE,qBAAgE,KAChE,qBAAwC,GAExC,aAAsC,GACtC,kBAAsC,GACtC,kBAAsC,GACtC,kBAAkD,KAElD,aAA0E,GAAkB,KAAK,OAAO,CAAC,EACzG,oBAAqE,KAAK,UAAU,EACpF,sBAAuE,KAAK,YAAY,EACxF,oBAAsE,GAAM,KAAK,cAAc,CAAC,EAChG,kBAAsE,GAAM,KAAK,YAAY,CAAC,EAC9F,sBAAsE,GAAM,KAAK,gBAAgB,CAAC,EAClG,sBAAsF,GAAM,KAAK,gBAAgB,CAAC,EAClH,2BAA2E,KAAK,iBAAiB,EACjG,qBAA2E,KAAK,eAAe,EAC/F,sBAA0F,EAAQ,IAAM,KAAK,SAAS,EAAQ,CAAC,EAC/H,yBAA2E,KAAK,aAAa,EAG7F,yBAA0D,KAAK,eAAe,EAC9E,yBAA0D,KAAK,eAAe,EAC9E,uBAA0D,KAAK,aAAa,EAK5E,wBAA2E,KAAK,eAAe,EAe/F,YAAY,EAAyB,EAA2C,CAC5E,MAAM,EAAS,CAAE,GAAG,EAAuB,GAAI,GAAoB,CAAC,CAAG,CAAC,EAExE,KAAK,eAAe,KAAK,mBAAmB,EAE5C,KAAK,kBAAoB,CACrB,KAAM,IAAI,EAAa,EAAU,IAAI,EACrC,UAAW,IAAI,EAAa,EAAU,SAAS,EAC/C,MAAO,IAAI,EAAa,EAAU,KAAK,EACvC,UAAW,IAAI,EAAa,EAAU,SAAS,EAC/C,KAAM,IAAI,EAAa,EAAU,IAAI,EACrC,UAAW,IAAI,EAAa,EAAU,SAAS,EAC/C,MAAO,IAAI,EAAa,EAAU,KAAK,EACvC,UAAW,IAAI,EAAa,EAAU,SAAS,CACnD,EAEA,KAAK,kBAAkB,KAAK,GAAG,OAAQ,KAAK,oBAAoB,EAChE,KAAK,kBAAkB,UAAU,GAAG,OAAQ,KAAK,oBAAoB,EACrE,KAAK,kBAAkB,MAAM,GAAG,OAAQ,KAAK,oBAAoB,EACjE,KAAK,kBAAkB,UAAU,GAAG,OAAQ,KAAK,oBAAoB,EACrE,KAAK,kBAAkB,KAAK,GAAG,OAAQ,KAAK,oBAAoB,EAChE,KAAK,kBAAkB,UAAU,GAAG,OAAQ,KAAK,oBAAoB,EACrE,KAAK,kBAAkB,MAAM,GAAG,OAAQ,KAAK,oBAAoB,EACjE,KAAK,kBAAkB,UAAU,GAAG,OAAQ,KAAK,oBAAoB,EAKrE,IAAK,IAAM,KAAU,OAAO,OAAO,KAAK,iBAAiB,EACrD,EAAO,UAAU,CAAqB,EAG1C,KAAK,WAAW,EAAK,EAErB,KAAK,WAAW,QAAQ,EAKxB,KAAK,QAAQ,CAAC,CAAC,YAAY,EAAE,EAI7B,EAAM,mBAAmB,KAAM,YAAa,CAAE,OAAQ,MAAO,QAAS,KAAK,oBAAqB,CAAC,CACrG,CAgBA,WAAqB,EAA+B,CAC5C,KAAK,SAAS,iBAAmB,IAAA,IACjC,KAAK,kBAAkB,KAAK,SAAS,eAAgB,KAAK,SAAS,OAAO,EAa9E,KAAK,aAAa,KAAK,YAAY,CAAC,EACpC,KAAK,mBAAmB,KAAK,cAAc,CAAC,EAC5C,KAAK,mBAAmB,KAAK,cAAc,CAAC,EAC5C,KAAK,aAAa,KAAK,YAAY,CAAC,EACpC,KAAK,UAAU,KAAK,SAAS,CAAC,EAC9B,KAAK,kBAAkB,KAAK,kBAAkB,CAAC,EAC/C,KAAK,eAAe,KAAK,eAAe,CAAC,EAEzC,KAAK,gBAAgB,EAKjB,GAAS,UAAY,IAAA,IACrB,KAAK,WAAW,CAAE,MAAO,KAAK,oBAAoB,EAAG,OAAQ,GAAI,CAAC,CAE1E,CAaA,aAAuB,EAA8B,CAoCjD,OAnCA,MAAM,aAAa,CAAO,EAEtB,EAAQ,aAAmB,IAAA,KAAW,KAAK,SAAS,WAAiB,EAAQ,YAC7E,EAAQ,QAAmB,IAAA,KAAW,KAAK,SAAS,MAAiB,EAAQ,OAC7E,EAAQ,iBAAmB,IAAA,KAAW,KAAK,SAAS,eAAiB,EAAQ,gBAC7E,EAAQ,UAAmB,IAAA,KAAW,KAAK,SAAS,QAAiB,EAAQ,SAMjF,KAAK,KAAK,EAAQ,GAAK,KAAK,gBAAgB,CAAE,EAC9C,KAAK,KAAK,EAAQ,GAAK,KAAK,gBAAgB,CAAE,EAC9C,KAAK,SAAS,EAAQ,OAAS,KAAK,gBAAgB,KAAM,EAC1D,KAAK,UAAU,EAAQ,QAAU,KAAK,gBAAgB,MAAO,EAMzD,EAAQ,YAAmB,IAAA,KAAW,KAAK,SAAS,UAAiB,EAAQ,WAC7E,EAAQ,cAAmB,IAAA,KAAW,KAAK,SAAS,YAAiB,EAAQ,aAC7E,EAAQ,cAAmB,IAAA,KAAW,KAAK,SAAS,YAAiB,EAAQ,aAC7E,EAAQ,YAAmB,IAAA,KAAW,KAAK,SAAS,UAAiB,EAAQ,WAC7E,EAAQ,cAAmB,IAAA,KAAW,KAAK,SAAS,YAAiB,EAAQ,aAC7E,EAAQ,SAAmB,IAAA,KAAW,KAAK,SAAS,OAAiB,EAAQ,QAC7E,EAAQ,iBAAmB,IAAA,KAAW,KAAK,SAAS,eAAiB,EAAQ,gBAC7E,EAAQ,cAAmB,IAAA,KAAW,KAAK,SAAS,YAAiB,EAAQ,aAEjF,KAAK,qBAAqB,EAAQ,mBAAqB,KAAK,oBAAoB,CAAC,EACjF,KAAK,iBAAiB,EAAQ,eAAiB,KAAK,iBAAiB,CAAC,EACtE,KAAK,gBAAgB,EAAQ,cAAgB,KAAK,gBAAgB,CAAC,EAEnE,KAAK,uBAAuB,EAAQ,qBAAuB,KAAK,sBAAsB,CAAC,EAEhF,IACX,CAkGA,cAAiC,CAC7B,MAAO,EACX,CAmBA,eAAgC,CAC5B,IAAM,EAAS,KAAK,cAAc,EAC5B,EAAS,KAAK,UAAU,EAExB,GAAoB,OAAO,EAAO,IAAI,GAAK,IAAM,OAAO,EAAO,KAAK,GAAM,GAAK,EAAO,QAAQ,EAC9F,GAAoB,OAAO,EAAO,GAAG,GAAM,IAAM,OAAO,EAAO,MAAM,GAAK,GAAK,EAAO,OAAO,EAEnG,MAAO,CACH,MAAQ,KAAK,oBAAoB,EAAI,EACrC,QAAS,KAAK,aAAa,GAAK,GAA0B,CAC9D,CACJ,CAkBA,kBAAkB,EAA4B,CAC1C,MAAO,EACX,CAuBA,SAAS,EAAqB,CAC1B,GAAI,KAAK,WAAW,EAAG,CACnB,IAAM,EAAM,KAAK,cAAc,EAE3B,EAAQ,EAAI,QACZ,EAAQ,EAAI,MAEpB,CAEA,OAAO,MAAM,SAAS,CAAK,CAC/B,CAUA,UAAU,EAAsB,CAC5B,GAAI,KAAK,WAAW,EAAG,CACnB,IAAM,EAAM,KAAK,cAAc,EAE3B,EAAS,EAAI,SACb,EAAS,EAAI,OAErB,CAEA,OAAO,MAAM,UAAU,CAAM,CACjC,CAYA,MAAa,CACT,IAAM,EAAK,KAAK,WAAW,EAAI,EA6B/B,GAxBA,EAAa,SAAS,IAAI,EAI1B,EAAU,IAAI,EAEd,KAAK,SAAS,EACd,KAAK,aAAa,EAElB,eAAe,YAAY,IAAI,IAAI,EACnC,KAAK,6BAA6B,EAElC,EAAa,MAAM,CAAE,EAErB,KAAK,WAAW,EAAI,EAEpB,KAAK,gBAAgB,OAAO,EAC5B,KAAK,eAAiB,EAAU,KAAK,EAAI,CACrC,KAAY,CAAE,QAAS,IAAK,UAAW,aAAc,EACrD,GAAY,CAAE,QAAS,IAAK,UAAW,UAAc,EACrD,WAAY,EACZ,WAAY,CAAC,UAAW,WAAW,CACvC,CAAC,EAEG,KAAK,gBAAiB,CACtB,IAAM,EAAW,KAAK,gBAChB,EAAW,KAAK,sBACtB,KAAK,gBAAwB,KAC7B,KAAK,sBAAwB,KAE7B,IAAM,EAAU,kBAAkB,EAElC,KAAK,uBAAuB,OAAO,EACnC,KAAK,sBAAwB,EAAU,YAAY,CAC/C,KAAkB,KACA,UAClB,iBAAkB,EAClB,QAAmB,GAAyB,CACxC,KAAK,UAAY,EACb,GACA,EAAQ,CAAS,CAEzB,CACJ,CAAC,CACL,KACI,MAAK,UAAY,KAAK,aAAa,EAOvC,OAJI,KAAK,oBAAoB,GACzB,KAAK,4BAA4B,EAG9B,IACX,CAuCA,kBACI,EACA,EACI,CAIJ,MAHA,MAAK,gBAAwB,EAC7B,KAAK,sBAAwB,GAAW,KAEjC,IACX,CAOA,cAAqB,CAKjB,EAAa,aAAa,IAAI,CAClC,CASA,iBAAiC,CAC7B,OAAO,KAAK,WAAW,GAAK,IAChC,CAUA,gBAAmC,CAC/B,MAAO,QACX,CAWA,WAAW,EAAuB,CAC9B,KAAK,YAAY,CAAM,EAEnB,IACA,KAAK,UAAU,EACf,KAAK,KAAK,UAAU,EAE5B,CASA,WAA0B,CACtB,IAAM,EAAU,KAAK,WAAW,EAC5B,CAAC,GAAW,EAAI,OAAO,SAAS,EAAS,EAAI,OAAO,iBAAiB,CAAC,GAI1E,KAAK,MAAM,EAAI,CACnB,CAMA,cAAqB,CACjB,KAAK,aAAa,CACtB,CASA,SAAkB,CACd,OAAO,KAAK,cAAc,EAAI,EAAa,KAAK,aAAe,EAAa,KAAK,MACrF,CAWA,aAAuB,CACnB,MAAO,EACX,CASA,gBAAgB,EAAsB,CAClC,KAAK,UAAU,CAAM,CACzB,CAKA,cAAqB,CAGjB,KAAK,KAAK,OAAO,EAEb,KAAK,oBAAsB,OAC3B,EAAI,KAAK,qBAAqB,KAAK,iBAAiB,EACpD,KAAK,kBAAoB,MAG7B,KAAK,kBAAkB,OAAO,EAC9B,KAAK,iBAAmB,KAKxB,KAAK,gBAAwB,KAC7B,KAAK,sBAAwB,KAE7B,KAAK,4BAA4B,EACjC,KAAK,yBAAyB,EAC9B,KAAK,6BAA6B,EAClC,KAAK,sBAAsB,EAE3B,EAAa,WAAW,IAAI,EAC5B,GAAY,IAAI,EAEhB,eAAe,YAAY,OAAO,IAAI,EAItC,eAAe,uBAAuB,EAEtC,IAAM,EAAK,KAAK,WAAW,EACrB,aAAuB,CACzB,KAAK,WAAW,EAAK,EACrB,KAAK,WAAW,CACpB,EAEA,GAAI,CAAC,EAAI,CACL,SAAS,EACT,MACJ,CAEA,KAAK,iBAAiB,OAAO,EAC7B,KAAK,gBAAkB,EAAU,KAAK,EAAI,CACtC,GAAY,CAAE,QAAS,IAAK,UAAW,aAAc,EACrD,WAAY,EACZ,WAAY,CAAC,UAAW,WAAW,EACnC,WAAY,QAChB,CAAC,CACL,CAUA,YAA6B,CAGzB,KAAK,kBAAkB,OAAO,EAC9B,KAAK,iBAAmB,KACxB,KAAK,gBAAgB,OAAO,EAC5B,KAAK,eAAiB,KACtB,KAAK,uBAAuB,OAAO,EACnC,KAAK,sBAAwB,KAC7B,KAAK,iBAAiB,OAAO,EAC7B,KAAK,gBAAkB,KACvB,KAAK,wBAAwB,OAAO,EACpC,KAAK,uBAAyB,KAC9B,KAAK,sBAAsB,OAAO,EAClC,KAAK,qBAAuB,KAE5B,IAAK,IAAM,KAAU,OAAO,OAAO,KAAK,iBAAiB,EACrD,EAAO,QAAQ,EAMnB,KAAK,aAAa,QAAQ,EAC1B,KAAK,YAAc,KAEnB,MAAM,WAAW,CACrB,CAQA,gBAA8B,CAC1B,OAAO,KAAK,SAAS,aAAe,KAAK,gBAAgB,WAC7D,CASA,OAAO,gBAAmC,CACtC,OAAO,MAAM,KAAK,eAAe,WAAW,CAChD,CAQA,SAAsB,CAClB,OAAO,KAAK,YAAY,CAC5B,CAWA,UAAU,EAAwB,CAM9B,OALA,KAAK,KAAK,EAAK,CAAC,EAChB,KAAK,KAAK,EAAK,CAAC,EAChB,KAAK,SAAS,EAAK,KAAK,EACxB,KAAK,UAAU,EAAK,MAAM,EAEnB,IACX,CAWA,gBAAoC,CAChC,OAAO,KAAK,YAChB,CAuBA,eAAe,EAA0B,CACrC,IAAM,EAAO,KAAK,eAAe,EACjC,GAAI,IAAS,EACT,OAAO,KAoBX,GAfI,KAAK,oBAAsB,OAC3B,EAAI,KAAK,qBAAqB,KAAK,iBAAiB,EACpD,KAAK,kBAAoB,MAG7B,KAAK,SAAS,YAAc,EAKxB,IAAS,aAAe,KAAK,QAAU,OACvC,KAAK,aAAa,EAAI,EACtB,KAAK,kBAAkB,GAGvB,IAAU,SAAU,CAIpB,KAAK,qBAAqB,EAAI,EAC9B,KAAK,qBAAqB,QAAQ,EAOlC,IAAM,EAAS,KAAK,aAAe,KAAK,oBAAoB,KAAK,YAAY,EAAI,KAAK,YAAY,EAClG,KAAK,aAAe,KAMpB,KAAK,6BAA6B,EAClC,KAAK,YAAY,MAAc,CAC3B,KAAK,qBAAqB,EAC1B,eAAe,uBAAuB,CAC1C,CAAC,CACL,MAAO,GAAI,IAAU,YAAa,CAQ9B,GAPI,IAAS,WACT,KAAK,aAAe,KAAK,YAAY,GAEzC,KAAK,kBAAoB,IAAS,YAAc,YAAc,SAC9D,KAAK,qBAAqB,WAAW,EACrC,KAAK,6BAA6B,EAE9B,KAAK,QAAU,KAMf,KAAK,wBAA0B,CAC3B,KAAK,aAAa,EAAK,EACvB,KAAK,KAAK,UAAU,CACxB,CAAC,MACE,CAYC,KAAK,iBAAmB,OACxB,KAAK,eAAiB,KAAK,qBAAqB,GAEpD,KAAK,WAAW,CAAE,MAAO,EAAG,OAAQ,CAAE,CAAC,EAEvC,IAAM,EAAS,KAAK,gBAAgB,EACpC,KAAK,YAAY,MAAc,CAC3B,KAAK,qBAAqB,EAAK,EAC/B,KAAK,6BAA6B,EAClC,eAAe,uBAAuB,CAC1C,CAAC,EAED,KAAK,KAAK,UAAU,CACxB,CACJ,KAAO,CAEC,IAAS,WACT,KAAK,aAAe,KAAK,YAAY,GAEzC,KAAK,qBAAqB,EAAI,EAC9B,KAAK,qBAAqB,WAAW,EAErC,IAAM,EAAS,KAAK,oBAAoB,EACxC,KAAK,YAAY,MAAc,CAC3B,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,EAClC,eAAe,uBAAuB,CAC1C,CAAC,CACL,CASA,OAJI,IAAS,aAAe,IAAU,aAClC,KAAK,KAAK,SAAS,EAGhB,IACX,CAWA,sBAAqC,CAC7B,KAAK,iBAAmB,OAI5B,KAAK,WAAW,KAAK,cAAc,EACnC,KAAK,eAAiB,KAC1B,CAOA,aAAuB,CACnB,OAAO,KAAK,eAAe,IAAM,WACrC,CAOA,aAAuB,CACnB,OAAO,KAAK,eAAe,IAAM,WACrC,CAOA,gBAAuB,CACd,KAAK,cAAc,IAIpB,KAAK,eAAe,IAAM,YAC1B,KAAK,eAAe,QAAQ,EAE5B,KAAK,eAAe,WAAW,EAEvC,CAOA,UAAiB,CACb,OAAO,KAAK,eAAe,WAAW,CAC1C,CAgBA,SAAgB,CASZ,OARK,KAAK,YAAY,GAItB,KAAK,eAAe,KAAK,iBAAiB,EAC1C,KAAK,aAAa,EAClB,KAAK,MAAM,EAAI,EAER,MAPI,IAQf,CAaA,QAAQ,EAAyB,CAe7B,OAdI,KAAK,QAAU,EACR,MAGP,KAAK,QAAU,MACf,KAAK,MAAM,iBAAiB,IAAI,EAGpC,KAAK,MAAQ,EAET,IAAS,MACT,EAAK,eAAe,IAAI,EAGrB,KACX,CAQA,SAAuB,CACnB,OAAO,KAAK,KAChB,CAQA,UAA+B,CAC3B,OAAO,KAAK,SAAS,KACzB,CAUA,GAAG,EAAoB,EAA4B,CAG/C,OAFA,KAAK,iBAAiB,IAAI,EAAO,CAAQ,EAElC,IACX,CAWA,IAAI,EAAoB,EAA4B,CAGhD,OAFA,KAAK,iBAAiB,OAAO,EAAO,CAAQ,EAErC,IACX,CAOA,KAAe,EAA0B,CACrC,KAAK,iBAAiB,KAAK,CAAK,CACpC,CAMA,gBAAuB,CACd,KAAK,cAAc,IAIpB,KAAK,eAAe,IAAM,YAC1B,KAAK,eAAe,QAAQ,EAE5B,KAAK,eAAe,WAAW,EAEvC,CAaA,aAAa,EAAsB,CAI/B,MAHA,MAAK,SAAS,UAAY,EAC1B,KAAK,iBAAiB,CAAK,EAEpB,IACX,CAOA,aAAuB,CACnB,OAAO,KAAK,SAAS,WAAa,KAAK,gBAAgB,SAC3D,CAaA,eAAe,EAAsB,CAIjC,MAHA,MAAK,SAAS,YAAc,EAC5B,KAAK,mBAAmB,KAAK,cAAc,CAAC,EAErC,IACX,CAQA,eAAyB,CACrB,OAAO,KAAK,YAAY,IAAM,KAAK,SAAS,aAAe,KAAK,gBAAgB,YACpF,CAaA,eAAe,EAAsB,CAKjC,MAJA,MAAK,SAAS,YAAc,EAC5B,KAAK,mBAAmB,KAAK,cAAc,CAAC,EAC5C,KAAK,0BAA0B,EAExB,IACX,CAQA,eAAyB,CACrB,OAAO,KAAK,YAAY,IAAM,KAAK,SAAS,aAAe,KAAK,gBAAgB,YACpF,CAOA,WAA6B,CACzB,OAAO,KAAK,YAAY,GAAK,CAAC,KAAK,SAAS,CAChD,CAQA,6BAA4C,CACxC,IAAM,EAAU,KAAK,UAAU,EAQ/B,IAAK,IAAM,KAAU,OAAO,OAAO,KAAK,iBAAiB,EACrD,EAAO,WAAW,EAAU,KAAO,EAAK,EAGvC,GACD,KAAK,eAAe,CAE5B,CAcA,aAAiC,CAC7B,OAAO,KAAK,cAAc,GAAK,CAAC,KAAK,SAAS,CAClD,CAUA,2BAA0C,CACtC,KAAK,4BAA4B,KAAK,YAAY,CAAC,EACnD,KAAK,sCAAsC,CAC/C,CAkBA,uCAAsD,CAClD,GAAI,CAAC,KAAK,aAAe,CAAC,KAAK,cAAc,EACzC,OAGJ,IAAM,EAAgB,QAAK,cAAc,EAEzC,KAAK,YAAY,eAAe,EAAe,KAAK,YAAY,CAAC,CACrE,CAeA,aAAa,EAAsB,CAa/B,MAZA,MAAK,SAAS,UAAY,EAE1B,KAAK,4BAA4B,EAMjC,KAAK,mBAAmB,KAAK,cAAc,CAAC,EAC5C,KAAK,mBAAmB,KAAK,cAAc,CAAC,EAC5C,KAAK,0BAA0B,EAExB,IACX,CAOA,aAAuB,CACnB,OAAO,KAAK,SAAS,WAAa,KAAK,gBAAgB,SAC3D,CAgBA,UAAU,EAAsB,CAK5B,MAJA,MAAK,SAAS,OAAS,EACvB,KAAK,4BAA4B,EACjC,KAAK,0BAA0B,EAExB,IACX,CAOA,UAAoB,CAChB,OAAO,KAAK,SAAS,QAAU,KAAK,gBAAgB,MACxD,CAWA,eAAe,EAAsB,CAIjC,MAHA,MAAK,SAAS,YAAc,EAC5B,EAAa,QAAQ,KAAM,KAAK,QAAQ,CAAC,EAElC,IACX,CAOA,eAAyB,CACrB,OAAO,KAAK,SAAS,aAAe,KAAK,gBAAgB,WAC7D,CAuBA,sBAAiD,CAC7C,IAAM,EAA0B,CAAC,EAC3B,EAAQ,KAAK,eAAe,EA8ClC,OA5CI,KAAK,cAAc,GACnB,EAAM,KAAK,CACP,KAAQ,IAAU,YAAc,UAAY,WAC5C,MAAQ,IAAU,YAAc,iBAAmB,kBACnD,OAAQ,KAAK,oBACjB,CAAC,EAGD,KAAK,cAAc,GACnB,EAAM,KAAK,CACP,KAAS,IAAU,YAAc,UAAY,WAC7C,MAAS,IAAU,YAAc,iBAAmB,kBACpD,QAAS,KAAK,YAAY,EAC1B,OAAS,KAAK,oBAClB,CAAC,EAGD,EAAM,OAAS,GACf,EAAM,KAAK,CAAE,UAAW,EAAK,CAAC,EAGlC,EAAM,KACF,CACI,QAAW,CACP,IAAM,EAAM,IAAI,EAAgB,CAAE,KAAM,gBAAiB,QAAS,KAAK,cAAc,CAAE,CAAC,EAIxF,OAFA,EAAI,GAAG,aAAgB,CAAE,KAAK,eAAe,EAAI,UAAU,CAAC,CAAG,CAAC,EAEzD,CACX,CACJ,EACA,CACI,QAAW,CACP,IAAM,EAAM,IAAI,EAAgB,CAAE,KAAM,gBAAiB,QAAS,KAAK,SAAS,CAAE,CAAC,EAInF,OAFA,EAAI,GAAG,aAAgB,CAAE,KAAK,UAAU,EAAI,UAAU,CAAC,CAAG,CAAC,EAEpD,CACX,CACJ,EACA,CAAE,UAAW,EAAK,EAClB,CAAE,KAAM,QAAS,MAAO,QAAS,QAAS,KAAK,YAAY,EAAG,OAAQ,KAAK,kBAAmB,CAClG,EAEO,CACX,CAWA,eAAyB,EAAyB,CAC9C,IAAM,EAAW,EAAO,WAAW,EAE9B,IAIL,KAAK,cAAgB,IAAI,EACzB,KAAK,YAAY,UAAU,EAAU,EAAI,OAAO,gBAAgB,CAAM,EAAG,KAAK,qBAAqB,CAAC,EACxG,CAUA,kBAAkB,EAAmC,CAGjD,MAFA,MAAK,SAAS,eAAiB,EAExB,IACX,CAOA,mBAA0C,CACtC,OAAO,KAAK,SAAS,gBAAkB,KAAK,gBAAgB,cAChE,CAWA,qBAAqB,EAAsB,CAcvC,OAbI,KAAK,SAAS,oBAAsB,EAC7B,MAGX,KAAK,SAAS,kBAAoB,EAE7B,EAGM,KAAK,WAAW,GACvB,KAAK,4BAA4B,GAHjC,KAAK,eAAe,EACpB,KAAK,4BAA4B,GAK9B,KACX,CAOA,qBAA+B,CAC3B,OAAO,KAAK,SAAS,mBAAqB,KAAK,gBAAgB,iBACnE,CAYA,uBAAuB,EAAsB,CAGzC,MAFA,MAAK,SAAS,oBAAsB,EAE7B,IACX,CAOA,uBAAiC,CAC7B,OAAO,KAAK,SAAS,qBAAuB,KAAK,gBAAgB,mBACrE,CAUA,iBAAiB,EAAkB,CAG/B,MAFA,MAAK,SAAS,cAAgB,EAEvB,IACX,CAOA,kBAA2B,CACvB,OAAO,KAAK,SAAS,eAAiB,KAAK,gBAAgB,aAC/D,CASA,gBAAgB,EAA+B,CAG3C,MAFA,MAAK,SAAS,aAAe,EAEtB,IACX,CAOA,iBAAsC,CAClC,OAAO,KAAK,SAAS,cAAgB,KAAK,gBAAgB,YAC9D,CASA,YAAY,EAAqB,CAC7B,KAAK,cAAc,CAAC,CACxB,CAaA,cAAc,EAAqB,CAI1B,EAAM,gBAAgB,CAAC,IAOxB,EAAE,UAIF,KAAK,eAAe,IAAM,WAI1B,KAAK,SAAS,IAOlB,KAAK,eAAiB,KAAK,KAAK,EAChC,KAAK,cAAiB,KAAK,KAAK,EAChC,KAAK,mBAAqB,EAAE,QAC5B,KAAK,mBAAqB,EAAE,QAC5B,KAAK,QAAU,EACf,KAAK,QAAU,EAKf,KAAK,eAAiB,KAAK,eAC3B,KAAK,eAAiB,KAAK,eAC3B,KAAK,eAAiB,KAAK,cAC3B,KAAK,eAAiB,KAAK,cAM3B,EAAM,oBAAoB,KAAM,UAAW,KAAK,eAAe,EAC/D,EAAM,oBAAoB,KAAM,YAAa,KAAK,YAAY,IAClE,CAeA,SAAS,EAAsB,EAAqB,CAC3C,KAAK,UAAU,GAIhB,KAAK,eAAe,IAAM,WAI9B,EAAE,eAAe,EAEZ,KAAK,uBACN,KAAK,qBAAuB,GAC5B,KAAK,qBAAuB,EAAE,QAC9B,KAAK,qBAAuB,EAAE,QAC9B,KAAK,eAAuB,KAAK,KAAK,EACtC,KAAK,eAAuB,KAAK,KAAK,EACtC,KAAK,eAAuB,KAAK,SAAS,EAC1C,KAAK,eAAuB,KAAK,UAAU,EAE3C,EAAM,oBAAoB,KAAM,UAAe,KAAK,iBAAiB,EACrE,EAAM,oBAAoB,KAAM,WAAe,KAAK,iBAAiB,EACrE,EAAM,oBAAoB,KAAM,cAAe,KAAK,iBAAiB,GAGzE,KAAK,gBAAkB,EAAE,QACzB,KAAK,gBAAkB,EAAE,QACzB,KAAK,eAAiB,EAElB,KAAK,oBAAsB,OAC3B,KAAK,kBAAoB,EAAI,KAAK,sBAAuB,GAAO,KAAK,YAAY,CAAE,CAAC,GAE5F,CASA,aAA4C,CAOxC,MANA,MAAK,qBAAuB,GAE5B,EAAM,uBAAuB,KAAM,UAAe,KAAK,iBAAiB,EACxE,EAAM,uBAAuB,KAAM,WAAe,KAAK,iBAAiB,EACxE,EAAM,uBAAuB,KAAM,cAAe,KAAK,iBAAiB,EAEjE,EACX,CAOA,cAAuB,CACnB,OAAO,KAAK,UAChB,CASA,aAAa,EAAmB,CAG5B,MAFA,MAAK,WAAa,EAEX,IACX,CASA,YAAoB,EAAyB,CACzC,GAAI,EAAY,KAAK,eAAiB,IAAO,KAAK,WAAY,CAC1D,KAAK,kBAAoB,EAAI,KAAK,sBAAuB,GAAO,KAAK,YAAY,CAAE,CAAC,EACpF,MACJ,CAEA,KAAK,eAAiB,EACtB,KAAK,kBAAoB,KAEzB,IAAM,EAAS,KAAK,eAIpB,GAFA,KAAK,eAAiB,KAElB,CAAC,EACD,OAQJ,IAAM,EAAU,KAAK,gBAAkB,KAAK,qBACtC,EAAU,KAAK,gBAAkB,KAAK,qBAEtC,EAAe,KAAK,eAAiB,KAAK,eAC1C,EAAe,KAAK,eAAiB,KAAK,eAQ1C,EAAiB,EAAI,OAAO,gBAAgB,EAC5C,EAAiB,EAAG,MAAS,KAAK,eAClC,EAAiB,EACjB,EAAiB,EAAG,OAAS,KAAK,eAClC,EAAiB,EAGvB,OADA,KAAK,mBAAmB,EAAK,EACrB,EAAO,aAAa,EAA5B,CACI,KAAK,EAAU,UACX,KAAK,SAAS,KAAK,IAAI,KAAK,eAAiB,EAAS,CAAY,CAAC,EACnE,KAAK,UAAU,KAAK,IAAI,KAAK,eAAiB,EAAS,CAAc,CAAC,EACtE,KAAK,KAAK,EAAc,KAAK,SAAS,CAAC,EACvC,KAAK,KAAK,EAAe,KAAK,UAAU,CAAC,EAEzC,MACJ,KAAK,EAAU,MACX,KAAK,UAAU,KAAK,IAAI,KAAK,eAAiB,EAAS,CAAc,CAAC,EACtE,KAAK,KAAK,EAAe,KAAK,UAAU,CAAC,EAEzC,MACJ,KAAK,EAAU,UACX,KAAK,SAAS,KAAK,IAAI,KAAK,eAAiB,EAAS,CAAY,CAAC,EACnE,KAAK,UAAU,KAAK,IAAI,KAAK,eAAiB,EAAS,CAAc,CAAC,EACtE,KAAK,KAAK,EAAe,KAAK,UAAU,CAAC,EAEzC,MACJ,KAAK,EAAU,KACX,KAAK,SAAS,KAAK,IAAI,KAAK,eAAiB,EAAS,CAAY,CAAC,EAEnE,MACJ,KAAK,EAAU,UACX,KAAK,SAAS,KAAK,IAAI,KAAK,eAAiB,EAAS,CAAY,CAAC,EACnE,KAAK,UAAU,KAAK,IAAI,KAAK,eAAiB,EAAS,CAAc,CAAC,EAEtE,MACJ,KAAK,EAAU,MACX,KAAK,UAAU,KAAK,IAAI,KAAK,eAAiB,EAAS,CAAc,CAAC,EAEtE,MACJ,KAAK,EAAU,UACX,KAAK,SAAS,KAAK,IAAI,KAAK,eAAiB,EAAS,CAAY,CAAC,EACnE,KAAK,UAAU,KAAK,IAAI,KAAK,eAAiB,EAAS,CAAc,CAAC,EACtE,KAAK,KAAK,EAAc,KAAK,SAAS,CAAC,EAEvC,MACJ,KAAK,EAAU,KACX,KAAK,SAAS,KAAK,IAAI,KAAK,eAAiB,EAAS,CAAY,CAAC,EACnE,KAAK,KAAK,EAAc,KAAK,SAAS,CAAC,CAG/C,CAEA,KAAK,SAAS,EACd,KAAK,mBAAmB,EAAI,CAChC,CAUA,wBAA6F,CACzF,IAAM,EAAK,KAAK,SAAS,EACnB,EAAK,EAAI,OAAO,gBAAgB,EAChC,EAAK,EAAG,MACR,EAAK,EAAG,OAEd,GAAI,KAAK,sBAAsB,EAE3B,MAAO,CAAE,KAAM,EAAG,KAAM,EAAK,EAAG,KAAM,EAAG,KAAM,EAAK,KAAK,UAAU,CAAE,EAOzE,IAAM,EAAU,KAAK,aAAa,GAAK,EAEvC,MAAO,CAAE,KAAM,EAAiB,EAAG,KAAM,EAAK,EAAgB,KAAM,EAAG,KAAM,EAAK,CAAQ,CAC9F,CAQA,gBAA+B,CAC3B,GAAM,CAAE,OAAM,OAAM,OAAM,QAAS,KAAK,uBAAuB,EAYzD,EAAM,KAAK,IAAI,EAAM,KAAK,cAAc,EACxC,EAAM,KAAK,IAAI,EAAM,KAAK,cAAc,EACxC,EAAM,KAAK,IAAI,EAAM,KAAK,cAAc,EACxC,EAAM,KAAK,IAAI,EAAM,KAAK,cAAc,EAExC,EAAU,KAAK,eAAiB,KAAK,QACrC,EAAU,KAAK,cAAiB,KAAK,QAErC,EAAW,EAAK,MAAM,EAAS,EAAK,CAAG,EACvC,EAAW,EAAK,MAAM,EAAS,EAAK,CAAG,EAG7C,KAAK,eAAiB,KAAK,IAAI,KAAK,eAAgB,CAAQ,EAC5D,KAAK,eAAiB,KAAK,IAAI,KAAK,eAAgB,CAAQ,EAC5D,KAAK,eAAiB,KAAK,IAAI,KAAK,eAAgB,CAAQ,EAC5D,KAAK,eAAiB,KAAK,IAAI,KAAK,eAAgB,CAAQ,EAE5D,KAAK,QAAU,EAAW,KAAK,eAC/B,KAAK,QAAU,EAAW,KAAK,aACnC,CAWA,yBAAgC,CAC5B,GAAM,CAAE,OAAM,OAAM,OAAM,QAAS,KAAK,uBAAuB,EAQ/D,OAHA,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,KAAK,EAAG,CAAI,EAAG,CAAI,CAAC,EACrD,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,KAAK,EAAG,CAAI,EAAG,CAAI,CAAC,EAE9C,IACX,CAQA,OAAO,EAAqC,CAuBxC,OAdA,KAAK,cAAc,WAAW,EAK9B,KAAK,QAAU,EAAE,QAAU,KAAK,mBAChC,KAAK,QAAU,EAAE,QAAU,KAAK,mBAEhC,KAAK,eAAe,EAIpB,KAAK,aAAa,KAAK,QAAS,KAAK,OAAO,EAErC,CAAE,KAAM,GAAM,QAAS,EAAK,CACvC,CAOA,WAAkC,CAW9B,OARA,KAAK,KAAK,KAAK,eAAiB,KAAK,OAAO,EAC5C,KAAK,KAAK,KAAK,cAAiB,KAAK,OAAO,EAC5C,KAAK,aAAa,EAAG,CAAC,EACtB,KAAK,cAAc,IAAI,EAEvB,EAAM,uBAAuB,KAAM,UAAW,KAAK,eAAe,EAClE,EAAM,uBAAuB,KAAM,YAAa,KAAK,YAAY,EAE1D,EACX,CAOA,UAAiB,CACb,MAAM,SAAS,EAEf,IAAI,EAAa,KAAK,cAAc,EAChC,EAAS,KAAK,UAAU,EACxB,GAA0B,OAAO,EAAW,IAAI,GAAK,IAAM,OAAO,EAAW,KAAK,GAAK,GAAK,EAAO,QAAQ,EAC3G,GAAuB,OAAO,EAAW,GAAG,GAAK,IAAM,OAAO,EAAW,MAAM,GAAK,GAAK,EAAO,OAAO,EACvG,EAAO,KAAK,QAAQ,EACxB,GAAI,CAAC,EACD,MAAU,MAAM,wCAAwC,EAG5D,IAAI,EAAY,KAAK,aAAa,EAClC,GAAI,CAAC,EACD,MAAU,MAAM,wCAAwC,EA6D5D,OA1DA,KAAK,kBAAkB,KAAK,mBAAmB,EAAK,EACpD,KAAK,kBAAkB,UAAU,mBAAmB,EAAK,EACzD,KAAK,kBAAkB,MAAM,mBAAmB,EAAK,EACrD,KAAK,kBAAkB,UAAU,mBAAmB,EAAK,EACzD,KAAK,kBAAkB,KAAK,mBAAmB,EAAK,EACpD,KAAK,kBAAkB,UAAU,mBAAmB,EAAK,EACzD,KAAK,kBAAkB,MAAM,mBAAmB,EAAK,EACrD,KAAK,kBAAkB,UAAU,mBAAmB,EAAK,EAEzD,KAAK,kBAAkB,KAAK,KAAK,CAAC,EAClC,KAAK,kBAAkB,KAAK,KAAK,EAAO,OAAO,CAAC,EAChD,KAAK,kBAAkB,KAAK,SAAS,EAAO,QAAQ,CAAC,EACrD,KAAK,kBAAkB,KAAK,UAAU,EAAU,MAAM,EAEtD,KAAK,kBAAkB,UAAU,KAAK,CAAC,EACvC,KAAK,kBAAkB,UAAU,KAAK,CAAC,EACvC,KAAK,kBAAkB,UAAU,SAAS,EAAO,QAAQ,CAAC,EAC1D,KAAK,kBAAkB,UAAU,UAAU,EAAO,OAAO,CAAC,EAE1D,KAAK,kBAAkB,MAAM,KAAK,EAAO,QAAQ,CAAC,EAClD,KAAK,kBAAkB,MAAM,KAAK,CAAC,EACnC,KAAK,kBAAkB,MAAM,SAAS,EAAU,KAAK,EACrD,KAAK,kBAAkB,MAAM,UAAU,EAAO,OAAO,CAAC,EAEtD,KAAK,kBAAkB,UAAU,KAAK,EAAK,MAAQ,CAAsB,EACzE,KAAK,kBAAkB,UAAU,KAAK,CAAC,EACvC,KAAK,kBAAkB,UAAU,SAAS,EAAO,SAAS,CAAC,EAC3D,KAAK,kBAAkB,UAAU,UAAU,EAAO,OAAO,CAAC,EAE1D,KAAK,kBAAkB,KAAK,KAAK,EAAK,MAAQ,CAAsB,EACpE,KAAK,kBAAkB,KAAK,KAAK,EAAO,OAAO,CAAC,EAChD,KAAK,kBAAkB,KAAK,SAAS,EAAO,SAAS,CAAC,EACtD,KAAK,kBAAkB,KAAK,UAAU,EAAU,MAAM,EAEtD,KAAK,kBAAkB,UAAU,KAAK,EAAK,MAAQ,CAAsB,EACzE,KAAK,kBAAkB,UAAU,KAAK,EAAK,OAAS,CAAmB,EACvE,KAAK,kBAAkB,UAAU,SAAS,EAAO,SAAS,CAAC,EAC3D,KAAK,kBAAkB,UAAU,UAAU,EAAO,UAAU,CAAC,EAE7D,KAAK,kBAAkB,MAAM,KAAK,EAAO,QAAQ,CAAC,EAClD,KAAK,kBAAkB,MAAM,KAAK,EAAK,OAAS,CAAmB,EACnE,KAAK,kBAAkB,MAAM,SAAS,EAAU,KAAK,EACrD,KAAK,kBAAkB,MAAM,UAAU,EAAO,SAAS,CAAC,EAExD,KAAK,kBAAkB,UAAU,KAAK,CAAC,EACvC,KAAK,kBAAkB,UAAU,KAAK,EAAK,OAAS,CAAmB,EACvE,KAAK,kBAAkB,UAAU,SAAS,EAAO,QAAQ,CAAC,EAC1D,KAAK,kBAAkB,UAAU,UAAU,EAAO,UAAU,CAAC,EAE7D,KAAK,kBAAkB,KAAK,mBAAmB,EAAI,EACnD,KAAK,kBAAkB,UAAU,mBAAmB,EAAI,EACxD,KAAK,kBAAkB,MAAM,mBAAmB,EAAI,EACpD,KAAK,kBAAkB,UAAU,mBAAmB,EAAI,EACxD,KAAK,kBAAkB,KAAK,mBAAmB,EAAI,EACnD,KAAK,kBAAkB,UAAU,mBAAmB,EAAI,EACxD,KAAK,kBAAkB,MAAM,mBAAmB,EAAI,EACpD,KAAK,kBAAkB,UAAU,mBAAmB,EAAI,EAEjD,IACX,CAOA,QAAiB,CACb,IAAI,EAAU,MAAM,OAAO,EAW3B,OATA,EAAI,KAAK,YAAY,EAAS,KAAK,kBAAkB,KAAK,WAAW,EAAI,CAAE,EAC3E,EAAI,KAAK,YAAY,EAAS,KAAK,kBAAkB,UAAU,WAAW,EAAI,CAAE,EAChF,EAAI,KAAK,YAAY,EAAS,KAAK,kBAAkB,MAAM,WAAW,EAAI,CAAE,EAC5E,EAAI,KAAK,YAAY,EAAS,KAAK,kBAAkB,UAAU,WAAW,EAAI,CAAE,EAChF,EAAI,KAAK,YAAY,EAAS,KAAK,kBAAkB,KAAK,WAAW,EAAI,CAAE,EAC3E,EAAI,KAAK,YAAY,EAAS,KAAK,kBAAkB,UAAU,WAAW,EAAI,CAAE,EAChF,EAAI,KAAK,YAAY,EAAS,KAAK,kBAAkB,MAAM,WAAW,EAAI,CAAE,EAC5E,EAAI,KAAK,YAAY,EAAS,KAAK,kBAAkB,UAAU,WAAW,EAAI,CAAE,EAEzE,CACX,CASA,aAAkC,CAC9B,MAAO,CACH,EAAQ,KAAK,KAAK,EAClB,EAAQ,KAAK,KAAK,EAClB,MAAQ,KAAK,SAAS,EACtB,OAAQ,KAAK,UAAU,CAC3B,CACJ,CAQA,cAA2C,CACvC,IAAM,EAAW,KAAK,cAAc,EACpC,IAAK,IAAM,KAAS,EAChB,GAAI,CAAC,KAAK,kBAAkB,CAAK,EAC7B,OAAO,EAGf,OAAO,IACX,CAQA,iBAA4C,CAKxC,MAJA,CACI,KAAK,YAAY,KAAK,aAAa,EAGhC,KAAK,SAChB,CAOA,qBAA6B,EAA0B,CACnD,KAAK,gBAAgB,CAAC,EAAE,aAAa,CAAS,CAClD,CAQA,qBAA0C,CACtC,GAAI,KAAK,kBAAkB,IAAM,SAAU,CACvC,IAAM,EAAK,KAAK,WAAW,EACrB,EAAS,EAAK,EAAI,OAAO,iBAAiB,CAAE,EAAI,KACtD,GAAI,GAAU,IAAW,EAAI,OAAO,mBAAmB,EAAG,CACtD,IAAM,EAAI,EAAI,OAAO,eAAe,CAAM,EAC1C,MAAO,CAAE,EAAG,EAAG,EAAG,EAAG,MAAO,EAAE,MAAO,OAAQ,EAAE,MAAO,CAC1D,CACJ,CAEA,IAAM,EAAK,EAAI,OAAO,gBAAgB,EAEtC,MAAO,CACH,EAAQ,EACR,EAAQ,EACR,MAAQ,EAAG,MACX,OAAQ,EAAG,MACf,CACJ,CAQA,iBAAsC,CAClC,IAAM,EAAY,KAAK,gBAAgB,EACjC,EAAY,KAAK,qBAAqB,EACtC,EAAe,KAAK,aAAa,GAAK,EAI5C,MAAO,CAAE,EAHC,GAAa,EAAY,GAGvB,EAFF,EAAI,OAAO,gBAAgB,CAAC,CAAC,OAAS,EAEjC,MAAO,EAAW,OAAQ,CAAa,CAC1D,CAaA,oBAAqC,CACjC,IAAM,EAAa,KAAK,MAClB,EAAa,EAAK,aAAa,EAC/B,EAAa,KAAK,YAAY,EAG9B,EAAa,KAAK,IAAI,GAAK,EAAY,KAAK,IAAI,EAAI,MAAO,CAAC,CAAC,EAS7D,EAAe,EAAK,QAAQ,EAC5B,EAAe,IAAS,EAAU,MAAQ,IAAS,EAAU,KAC7D,EAAe,EAAK,qBAAqB,IAAI,EAC7C,EAAe,EAAK,qBAAqB,IAAI,EAC7C,GAAgB,EAAW,EAAI,OAAS,EAAI,OAAS,EACrD,EAAe,EAAe,EAC9B,GAAc,EAAe,GAAc,EAC3C,EAMF,EAAU,EACV,EAAU,EAEd,OAAQ,EAAR,CACI,KAAK,EAAU,KACX,EAAU,EAAI,OAAO,gBAAgB,CAAC,CAAC,MAAQ,EAC/C,EAAU,EAEV,MAEJ,KAAK,EAAU,KACX,EAAU,EAEV,MAEJ,KAAK,EAAU,MACX,EAAU,EACV,EAAU,EAAI,OAAO,gBAAgB,CAAC,CAAC,OAAS,EAEhD,MAEJ,KAAK,EAAU,MACX,EAAU,EAEV,MAEJ,QACI,EAAU,CAGlB,CAKA,MAAO,aAHI,EAAU,EAAI,EAGF,MAFZ,EAAU,EAAI,EAEO,YAAY,EAAM,EACtD,CAUA,oBAA4B,EAA0B,CAClD,IAAM,EAAU,KAAK,WAAW,EAEhC,GAAI,CAAC,EAAS,CACV,EAAO,EAEP,MACJ,CAEA,KAAK,wBAAwB,OAAO,EACpC,KAAK,uBAAyB,EAAU,KAAK,EAAS,CAClD,KAAY,CAAE,gBAAiB,MAAO,UAAW,2BAA4B,QAAS,GAAI,EAC1F,GAAY,CAAE,UAAW,KAAK,mBAAmB,EAAG,QAAS,GAAI,EACjE,WAAY,EACZ,WAAY,CAAC,YAAa,SAAS,EACnC,WAAY,CAChB,CAAC,CACL,CAOA,mBAAkC,CAC9B,IAAM,EAAU,KAAK,WAAW,EAE3B,IAIL,KAAK,sBAAsB,OAAO,EAClC,KAAK,qBAAuB,EAAU,KAAK,EAAS,CAChD,KAAY,CAAE,gBAAiB,MAAO,UAAW,KAAK,mBAAmB,EAAG,QAAS,GAAI,EACzF,GAAY,CAAE,UAAW,2BAA4B,QAAS,GAAI,EAClE,WAAY,EACZ,WAAY,CAAC,YAAa,SAAS,CACvC,CAAC,EACL,CAQA,iBAAkC,CAC9B,IAAM,EAAS,EAAI,OAAO,YAAY,+BAA+B,EACrE,GAAI,EAAQ,CACR,IAAM,EAAS,WAAW,CAAM,EAChC,GAAI,CAAC,MAAM,CAAM,GAAK,EAAS,EAC3B,OAAO,CAEf,CAEA,OAAO,CACX,CAQA,sBAAuC,CACnC,IAAI,EAAQ,EACZ,IAAK,IAAM,KAAO,eAAe,YAAa,CAC1C,GAAI,IAAQ,KACR,OAAO,EAEP,EAAI,eAAe,IAAM,aACzB,GAER,CACA,OAAO,CACX,CAMA,OAAe,wBAA+B,CAC1C,IAAI,EAAQ,EACZ,IAAK,IAAM,KAAO,eAAe,YAAa,CAC1C,GAAI,EAAI,eAAe,IAAM,YACzB,SAEJ,IAAM,EAAc,EAAI,gBAAgB,EAClC,EAAe,EAAI,aAAa,GAAK,EACrC,EAAI,GAAS,EAAY,GACzB,EAAI,EAAI,OAAO,gBAAgB,CAAC,CAAC,OAAS,EAEhD,EAAI,mBAAmB,EAAK,EAC5B,EAAI,KAAK,CAAC,EACV,EAAI,KAAK,CAAC,EACV,EAAI,SAAS,CAAS,EACtB,EAAI,UAAU,CAAY,EAC1B,EAAI,SAAS,EACb,EAAI,mBAAmB,EAAI,EAE3B,GACJ,CACJ,CAgBA,YAAoB,EAAoB,EAA2B,CAC/D,KAAK,oBAAoB,EAErB,KAAK,kBAAkB,CAAM,EAC7B,KAAK,aAAa,EAAQ,CAAM,EAEhC,KAAK,UAAU,EAAQ,CAAM,CAErC,CAWA,kBAA0B,EAA6B,CACnD,IAAM,EAAU,KAAK,YAAY,EAEjC,OAAO,KAAK,IACR,KAAK,IAAI,EAAO,MAAS,EAAQ,KAAK,EACtC,KAAK,IAAI,EAAO,OAAS,EAAQ,MAAM,CAC3C,EAAI,CACR,CAmBA,aAAqB,EAAoB,EAA2B,CAChE,IAAM,EAAU,KAAK,gBAAgB,EAC/B,EAAU,GAAM,WAAW,EAIjC,GAAI,CAAC,GAAQ,CAAC,EAAS,CACnB,KAAK,WAAW,CAAM,EACtB,IAAS,EAET,MACJ,CAEA,KAAK,gBAAkB,GACvB,KAAK,iBAAmB,EAAU,KAAK,EAAS,CAC5C,GAAY,CAAE,QAAS,GAAI,EAC3B,WAAY,EACZ,WAAY,CAAC,SAAS,EACtB,eAAwB,CAKpB,EAAK,YAAY,EAEjB,KAAK,iBAAmB,EAAU,MAAkB,CAChD,KAAY,KAAK,YAAY,EAC7B,GAAY,EACZ,WAAY,EACZ,OAAa,GAA2B,KAAK,WAAW,CAAI,EAC5D,eAAwB,CAWpB,GARA,EAAK,aAAa,EAClB,IAAS,EAOL,CAAC,EAAK,YAAY,EAAG,CACrB,KAAK,iBAAmB,KACxB,KAAK,YAAY,EAEjB,MACJ,CAEA,KAAK,YAAY,CAAO,CAC5B,CACJ,CAAC,CACL,CACJ,CAAC,CACL,CAQA,YAAoB,EAAuB,CAWvC,KAAK,iBAAmB,EAAU,KAAK,EAAS,CAC5C,GAAY,CAAE,QAAS,GAAI,EAC3B,WAAY,EACZ,WAAY,CAAC,SAAS,EAMtB,iBAAkB,EAClB,eAAwB,CACpB,KAAK,iBAAmB,KACxB,KAAK,YAAY,CACrB,CACJ,CAAC,CACL,CAUA,qBAAoC,CAChC,KAAK,kBAAkB,OAAO,EAC9B,KAAK,iBAAmB,KACxB,KAAK,YAAY,EAEjB,IAAM,EAAO,KAAK,gBAAgB,EAC9B,GAAM,eAAe,GACrB,EAAK,aAAa,CAE1B,CAMA,aAA4B,CACnB,KAAK,kBAIV,KAAK,gBAAkB,GACvB,KAAK,gBAAgB,CAAC,EAAE,aAAa,EACzC,CAQA,WAAmB,EAAwB,CACvC,KAAK,mBAAmB,EAAK,EAC7B,KAAK,KAAK,EAAK,CAAC,EAChB,KAAK,KAAK,EAAK,CAAC,EAChB,KAAK,SAAS,EAAK,KAAK,EACxB,KAAK,UAAU,EAAK,MAAM,EAC1B,KAAK,SAAS,EACd,KAAK,mBAAmB,EAAI,CAChC,CAUA,UAAkB,EAAoB,EAA2B,CAC7D,KAAK,iBAAmB,EAAU,MAAkB,CAChD,KAAY,KAAK,YAAY,EAC7B,GAAY,EACZ,WAAY,EACZ,OAAa,GAA2B,KAAK,WAAW,CAAI,EAC5D,eAAwB,CACpB,KAAK,iBAAmB,KACxB,IAAS,CACb,CACJ,CAAC,CACL,CAUA,8BAA6C,CACrC,AAKJ,KAAK,wBADL,EAAM,oBAAoB,KAAM,SAAU,KAAK,sBAAsB,EACzC,GAChC,CAKA,8BAA6C,CACpC,AAKL,KAAK,wBADL,EAAM,uBAAuB,KAAM,SAAU,KAAK,sBAAsB,EAC5C,GAChC,CAUA,kBAAiC,CAC7B,IAAM,EAAQ,KAAK,eAAe,EAElC,GAAI,IAAU,YAAa,CACvB,eAAe,uBAAuB,EAEtC,MACJ,CAEA,GAAI,IAAU,SAAU,CACpB,KAAK,0BAA0B,EAE/B,MACJ,CAEA,IAAM,EAAO,KAAK,oBAAoB,EACtC,KAAK,mBAAmB,EAAK,EAC7B,KAAK,KAAK,EAAK,CAAC,EAChB,KAAK,KAAK,EAAK,CAAC,EAChB,KAAK,SAAS,EAAK,KAAK,EACxB,KAAK,UAAU,EAAK,MAAM,EAC1B,KAAK,SAAS,EACd,KAAK,mBAAmB,EAAI,EAE5B,eAAe,uBAAuB,CAC1C,CAYA,2BAA0C,CACtC,IAAM,EAAU,KAAK,oBAAoB,KAAK,YAAY,CAAC,EAE3D,KAAK,mBAAmB,EAAK,EAC7B,KAAK,SAAS,EAAQ,KAAK,EAC3B,KAAK,UAAU,EAAQ,MAAM,EAC7B,KAAK,KAAK,EAAQ,CAAC,EACnB,KAAK,KAAK,EAAQ,CAAC,EACnB,KAAK,SAAS,EACd,KAAK,mBAAmB,EAAI,CAChC,CAmBA,oBAA4B,EAA8B,CACtD,IAAM,EAAc,EAAI,OAAO,gBAAgB,EACzC,EAAc,KAAK,IAAI,EAAG,EAAG,MAAS,GAA6B,EACnE,EAAc,KAAK,IAAI,EAAG,EAAG,OAAS,GAA6B,EACnE,EAAc,KAAK,WAAW,EAE9B,EAAS,KAAK,IAAI,KAAK,IAAI,EAAK,MAAQ,CAAU,EAAI,GAAS,OAAU,CAAC,EAC1E,EAAS,KAAK,IAAI,KAAK,IAAI,EAAK,OAAQ,CAAW,EAAG,GAAS,QAAU,CAAC,EAE1E,EAAO,EAAG,MAAS,EAA4B,EAC/C,EAAO,EAAG,OAAS,EAA4B,EASrD,MAAO,CAAE,EAHC,KAAK,IAAI,KAAK,IAAI,EAAK,EAAG,CAAI,EAAG,CAGlC,EAAG,EAFF,KAAK,IAAI,KAAK,IAAI,EAAK,EAAG,CAAI,EAAG,CAE/B,EAAG,QAAO,QAAO,CACjC,CAQA,6BAA4C,CACpC,AAOJ,KAAK,qBAHL,EAAM,oBAAoB,KAAM,UAAW,KAAK,mBAAmB,EACnE,EAAM,oBAAoB,KAAM,QAAW,KAAK,iBAAiB,EACjE,EAAM,oBAAoB,KAAM,OAAW,KAAK,gBAAgB,EACvC,GAC7B,CAKA,6BAA4C,CACnC,AAOL,KAAK,qBAHL,EAAM,uBAAuB,KAAM,UAAW,KAAK,mBAAmB,EACtE,EAAM,uBAAuB,KAAM,QAAW,KAAK,iBAAiB,EACpE,EAAM,uBAAuB,KAAM,OAAW,KAAK,gBAAgB,EAC1C,GAC7B,CAMA,0BAAyC,CACjC,AAMJ,KAAK,qBAFL,EAAM,oBAAoB,KAAM,YAAa,KAAK,qBAAqB,EACvE,EAAM,oBAAoB,KAAM,YAAa,KAAK,qBAAqB,EAC9C,GAC7B,CAKA,0BAAyC,CAChC,AAML,KAAK,qBAFL,EAAM,uBAAuB,KAAM,YAAa,KAAK,qBAAqB,EAC1E,EAAM,uBAAuB,KAAM,YAAa,KAAK,qBAAqB,EACjD,GAC7B,CAKA,uBAAsC,CAClC,AAEI,KAAK,qBADL,KAAK,kBAAkB,cAAc,EAAK,EACjB,KAEjC,CAMA,gBAA+B,CAC3B,KAAK,aAAe,GACpB,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,CAC/B,CAQA,cAAsB,EAAwB,CACrC,KAAK,UAAU,GAIf,KAAK,oBAAoB,GAG1B,KAAK,eAAe,IAAM,UAGzB,KAAK,gBAAgB,CAAC,IAGvB,KAAK,eAIT,KAAK,aAAe,GACpB,KAAK,yBAAyB,GAClC,CAOA,YAAoB,EAAwB,CACnC,KAAK,eAKN,KAAK,kBAAkB,CAAC,GAI5B,KAAK,eAAe,EACxB,CAQA,gBAAwB,EAA2B,CAC/C,OAAQ,KAAK,gBAAgB,EAA7B,CACI,IAAK,OAAS,OAAO,EAAE,QACvB,IAAK,OAAS,OAAO,EAAE,QACvB,IAAK,MAAS,OAAO,EAAE,OACvB,IAAK,QAAS,OAAO,EAAE,QAC3B,CACJ,CAQA,kBAA0B,EAA2B,CACjD,OAAO,KAAK,gBAAgB,CAAC,CACjC,CAQA,gBAAwB,EAAqB,CACzC,GAAI,CAAC,KAAK,aACN,OAGJ,IAAM,EAAS,KAAK,eAAe,EAAE,QAAS,EAAE,OAAO,EACnD,IAAW,KAAK,oBAIhB,KAAK,mBACL,KAAK,kBAAkB,cAAc,EAAK,EAE9C,KAAK,kBAAoB,EACrB,GACA,EAAO,cAAc,EAAI,EAEjC,CAUA,eAAuB,EAAY,EAAiC,CAChE,IAAM,EAA6B,CAE/B,KAAK,kBAAkB,UACvB,KAAK,kBAAkB,UACvB,KAAK,kBAAkB,UACvB,KAAK,kBAAkB,UACvB,KAAK,kBAAkB,MACvB,KAAK,kBAAkB,KACvB,KAAK,kBAAkB,MACvB,KAAK,kBAAkB,IAC3B,EAEI,EAA4B,KAC5B,EAAW,KAAK,iBAAiB,EAErC,IAAK,IAAM,KAAU,EAAY,CAC7B,IAAM,EAAK,EAAO,WAAW,EAC7B,GAAI,CAAC,EACD,SAEJ,IAAM,EAAO,EAAI,OAAO,eAAe,CAAE,EACnC,EAAK,KAAK,IAAI,EAAK,KAAO,EAAI,EAAG,EAAK,EAAK,KAAK,EAChD,EAAK,KAAK,IAAI,EAAK,IAAO,EAAI,EAAG,EAAK,EAAK,MAAM,EACjD,EAAO,KAAK,MAAM,EAAI,CAAE,EAE1B,GAAQ,IACR,EAAW,EACX,EAAW,EAEnB,CAEA,OAAO,CACX,CASA,gBAAwB,EAAqC,CACzD,IAAM,EAAS,KAAK,kBACpB,GAAI,CAAC,EACD,OAQJ,IAAM,EAAW,EAAO,WAAW,EACnC,GAAI,GAAY,EAAI,OAAO,OAAO,EAAE,MAAM,GAAK,EAAI,OAAO,SAAS,EAAU,EAAI,OAAO,OAAO,EAAE,MAAM,CAAC,EAAG,CACvG,KAAK,kBAAoB,KACzB,MACJ,CAOA,OAHA,EAAO,YAAY,CAAC,EACpB,KAAK,kBAAoB,KAElB,EACX,CACJ,EC5qGM,EAAuD,CACzD,gBAAwB,iCACxB,gBAAwB,iCACxB,OAAwB,qCACxB,aAAwB,IAAA,GACxB,OAAwB,qCACxB,uBAAwB,iCACxB,uBAAwB,wCACxB,uBAAwB,wCACxB,cAAwB,qCACxB,qBAAwB,uCACxB,qBAAwB,uCACxB,YAAwB,oCAC5B,EAWM,oBAAN,cAAkC,CAAO,CACrC,OAA0B,sBAAkC,EAE5D,OAA0B,eAA4C,CAClE,CACI,SAAU,WACV,aAA0B,CACtB,gBAAiB,EAA6B,uBAC9C,gBAAiB,EAA6B,uBAC9C,gBAAiB,EAA6B,uBAC9C,OAAiB,EAA6B,aAClD,EACJ,EACA,CACI,SAAU,SACV,aAA0B,CACtB,gBAAiB,EAA6B,qBAC9C,gBAAiB,EAA6B,qBAC9C,OAAiB,EAA6B,WAClD,EACJ,CACJ,EAEA,YAAY,EAAe,EAA2C,CAClE,MAAM,IAAA,GAAW,CAAE,QAAO,OAAQ,IAAI,EAAO,EAAG,EAAG,EAAG,CAAC,CAAE,EAAG,CAAE,GAAG,EAA8B,GAAI,GAAoB,CAAC,CAAG,CAAC,CAChI,CACJ,EAaM,EAAyD,CAC3D,gBAAwB,cACxB,gBAAwB,OACxB,OAAwB,wBACxB,aAAwB,IAAA,GACxB,OAAwB,OACxB,uBAAwB,iCACxB,uBAAwB,wCACxB,uBAAwB,wCACxB,cAAwB,OACxB,qBAAwB,uCACxB,qBAAwB,uCACxB,YAAwB,MAC5B,EAQM,sBAAN,cAAoC,CAAO,CACvC,OAA0B,sBAAkC,EAE5D,OAA0B,eAA4C,CAClE,CACI,SAAU,WACV,aAA0B,CACtB,gBAAiB,EAA+B,uBAChD,gBAAiB,EAA+B,uBAChD,gBAAiB,EAA+B,uBAChD,OAAiB,EAA+B,aACpD,EACJ,EACA,CACI,SAAU,SACV,aAA0B,CACtB,gBAAiB,EAA+B,qBAChD,gBAAiB,EAA+B,qBAChD,OAAiB,EAA+B,WACpD,EACJ,CACJ,EAEA,YAAY,EAAe,EAA2C,CAClE,MAAM,IAAA,GAAW,CAAE,QAAO,OAAQ,IAAI,EAAO,EAAG,EAAG,EAAG,CAAC,CAAE,EAAG,CAAE,GAAG,EAAgC,GAAI,GAAoB,CAAC,CAAG,CAAC,CAClI,CACJ,EAYA,SAAgB,0BAA0B,EAAuB,CAC7D,OAAO,IAAI,oBAAoB,CAAK,CACxC,CAYA,SAAgB,4BAA4B,EAAuB,CAC/D,IAAM,EAAS,IAAI,sBAAsB,CAAK,EAQ9C,OAFA,EAAO,iBAAiB,MAAM,EAEvB,CACX,CAYA,SAAgB,wBAAwB,EAAmB,EAAuB,CAC9E,IAAM,EAAkB,EAAS,iCAAmC,cAC9D,EAAkB,EAAS,iCAAmC,OAEpE,IAAK,IAAM,KAAU,EACjB,EAAO,mBAAmB,CAAe,EACzC,EAAO,mBAAmB,CAAe,CAEjD,CC/JA,EAAM,SAAS,EAAO,EAAiB,EAAiB,CAAc,EA8BtE,IAAM,GAA6C,CAC/C,QAAS,CAAE,MAAO,EAAG,OAAQ,CAAE,EAC/B,QAAS,CAAE,MAAO,EAAW,OAAQ,CAAU,CACnD,EAQM,uBAAN,cAAqC,CAAM,CACvC,OAA0B,eAAwC,CAAC,CAAkB,EAQrF,YAAY,EAAc,EAA0C,CAChE,MAAM,EAAM,IAAA,GAAW,CAAE,GAAG,GAAqB,GAAI,GAAoB,CAAC,CAAG,CAAC,CAClF,CACJ,EAYM,aAAN,cAA2B,CAAO,CAE9B,YACA,gBACA,gBACA,aACA,kBACA,YAAyC,KACzC,UACA,WAAoC,GACpC,aAAoC,GACpC,aAAoC,GACpC,yBAAwD,KACxD,oBAAiE,GAAM,KAAK,cAAc,CAAC,EAE3F,YAAY,EAAc,EAA+B,CACrD,MAAM,CAAI,EAOV,KAAK,kBAAoB,sCACzB,KAAK,mBAAmB,KAAK,iBAAiB,EAO9C,KAAK,UAAU,IAAI,EAAO,EAAG,EAAG,EAAG,CAAC,CAAC,EAKrC,IAAM,EAAQ,KAAK,QAAQ,EAC3B,KAAK,gBAAgB,CAAK,EAE1B,KAAK,UAAY,IAAI,EACrB,KAAK,UAAU,iBAAiB,IAAI,EAAK,CAAE,QAAS,CAAE,CAAC,CAAC,EAIxD,KAAK,UAAU,UAAU,IAAI,EAAO,EAAG,EAAG,EAAG,CAAC,CAAC,EAC/C,KAAK,UAAU,iBAAiB,MAAM,EACtC,KAAK,UAAU,aAAa,CAAK,EAQjC,IAAM,EAAY,IAAI,EACtB,EAAU,iBAAiB,IAAI,EAAI,CAAE,KAAM,EAAS,UAAW,CAAC,CAAC,EACjE,EAAU,iBAAiB,MAAM,EACjC,EAAU,aAAa,KAAK,SAAS,EAErC,KAAK,aAAa,EAAW,CACzB,UAAW,EAAU,KACrB,OAAW,EAAW,KACtB,KAAW,EAAS,UACxB,CAAC,EAUD,KAAK,gBAAkB,0BAA0B,iBAAiB,EAClE,KAAK,gBAAkB,0BAA0B,iBAAiB,EAClE,KAAK,YAAkB,0BAA0B,OAAO,EAExD,IAAK,IAAM,IAAW,CAAC,KAAK,gBAAiB,KAAK,gBAAiB,KAAK,WAAW,EAC/E,EAAQ,UAAU,IAAI,EAAO,EAAG,EAAG,EAAG,CAAC,CAAC,EAG5C,KAAK,aAAe,IAAI,EACxB,KAAK,aAAa,iBAAiB,IAAI,EAAK,CAAE,QAAS,EAAG,WAAY,EAAK,CAAC,CAAC,EAC7E,KAAK,aAAa,UAAU,IAAI,EAAO,EAAG,EAAG,EAAG,CAAC,CAAC,EAClD,KAAK,aAAa,aAAa,KAAK,eAAe,EACnD,KAAK,aAAa,aAAa,KAAK,eAAe,EACnD,KAAK,aAAa,aAAa,KAAK,WAAW,EAE/C,KAAK,aAAa,KAAK,aAAc,CAAE,UAAW,EAAU,IAAK,CAAC,EAI9D,GAAS,QAAU,IAAA,IACnB,KAAK,SAAS,iBAAiB,EAG/B,GACA,KAAK,aAAa,CAAO,CAEjC,CAkBA,qBAAsC,CAIlC,IAAM,EAAW,KAAK,QAAQ,CAAC,CAAC,iBAAiB,EAC3C,EAAa,EAAW,EAAS,OAAS,GAShD,GAPA,KAAK,iBAAiB,CAAE,MAAO,IAAK,OAAQ,EAAa,CAAkB,CAAC,EAOxE,KAAK,YAAa,CAClB,IAAM,EAAM,KAAK,qBAAqB,EACtC,KAAK,YAAY,iBAAiB,CAAE,MAAO,EAAK,OAAQ,CAAI,CAAC,CACjE,CACJ,CAUA,sBAAuC,CACnC,OAAO,EAAa,iBAAiB,CAAC,CAAC,OAC3C,CASA,aAAuB,EAAoC,CAmBvD,OAlBA,MAAM,aAAa,CAAO,EAEtB,EAAQ,YAAc,IAAA,IACtB,KAAK,aAAa,EAAQ,SAAS,EAGnC,EAAQ,cAAgB,IAAA,IACxB,KAAK,eAAe,EAAQ,WAAW,EAGvC,EAAQ,cAAgB,IAAA,IACxB,KAAK,eAAe,EAAQ,WAAW,EAGvC,EAAQ,QAAU,IAAA,IAClB,KAAK,SAAS,EAAQ,KAAK,EAGxB,IACX,CAeA,SAAS,EAAoB,CACzB,AAEI,KAAK,eADL,KAAK,UAAU,gBAAgB,KAAK,WAAW,EAC5B,MAWvB,IAAM,EAAQ,IAAI,uBAAuB,CAAI,EACvC,EAAM,KAAK,qBAAqB,EAQtC,OAPA,EAAM,iBAAiB,CAAE,MAAO,EAAK,OAAQ,CAAI,CAAC,EAClD,EAAM,iBAAiB,MAAM,EAC7B,EAAM,UAAU,SAAS,EACzB,KAAK,YAAc,EAEnB,KAAK,UAAU,gBAAgB,EAAO,CAAC,EAEhC,IACX,CAOA,YAAmB,CAMf,MALA,CAEI,KAAK,eADL,KAAK,UAAU,gBAAgB,KAAK,WAAW,EAC5B,MAGhB,IACX,CAOA,UAAyB,CACrB,OAAO,KAAK,WAChB,CAOA,UAAU,EAAuB,CAS7B,OARA,KAAK,mBAAmB,EAClB,KAAK,kBACL,4CAA4C,EAIlD,wBAAwB,CAAC,KAAK,gBAAiB,KAAK,gBAAiB,KAAK,WAAW,EAAG,CAAM,EAEvF,IACX,CAWA,aAAa,EAAsB,CAI/B,MAHA,MAAK,WAAa,EAClB,KAAK,YAAY,WAAW,CAAK,EAE1B,IACX,CAOA,aAAuB,CACnB,OAAO,KAAK,UAChB,CASA,eAAe,EAAsB,CAIjC,MAHA,MAAK,aAAe,EACpB,KAAK,gBAAgB,WAAW,CAAK,EAE9B,IACX,CAOA,eAAyB,CACrB,OAAO,KAAK,YAChB,CASA,eAAe,EAAsB,CAIjC,MAHA,MAAK,aAAe,EACpB,KAAK,gBAAgB,WAAW,CAAK,EAE9B,IACX,CAOA,eAAyB,CACrB,OAAO,KAAK,YAChB,CAcA,yBAAyB,EAAsB,CAG3C,OAFA,KAAK,gBAAgB,WAAW,CAAK,EAE9B,IACX,CAOA,yBAAmC,CAC/B,OAAO,KAAK,gBAAgB,UAAU,CAC1C,CAWA,uBAAuB,EAAkD,CAGrE,OAFA,KAAK,gBAAgB,SAAS,CAAI,EAE3B,IACX,CAcA,uBAAuB,EAAkD,CAGrE,OAFA,KAAK,gBAAgB,SAAS,CAAI,EAE3B,IACX,CAOA,sBAAsB,EAA2B,CAG7C,OAFA,KAAK,YAAY,GAAG,SAAU,CAAyB,EAEhD,IACX,CAOA,0BAA0B,EAA0B,CAGhD,OAFA,KAAK,gBAAgB,GAAG,SAAU,CAAyB,EAEpD,IACX,CAOA,0BAA0B,EAA0B,CAGhD,OAFA,KAAK,gBAAgB,GAAG,SAAU,CAAyB,EAEpD,IACX,CASA,6BAA6B,EAAgC,CAOzD,OAFA,EAAM,mBAAmB,KAAM,WAAY,CAAQ,EAE5C,IACX,CAWA,2BAA2B,EAA4B,CAUnD,OATI,KAAK,2BAA6B,MAIlC,EAAM,mBAAmB,KAAM,QAAS,KAAK,mBAAmB,EAGpE,KAAK,yBAA2B,EAEzB,IACX,CASA,cAAsB,EAAqB,CACvC,IAAM,EAAS,EAAE,SAAW,KAAO,KAAO,EAAI,OAAO,OAAO,EAAE,MAAM,EAC9D,EAAU,KAAK,aAAa,WAAW,EAEzC,CAAC,GAAU,CAAC,GAAW,CAAC,EAAI,OAAO,SAAS,EAAS,CAAM,GAI/D,KAAK,2BAA2B,CACpC,CAcA,mBAAmB,EAAqB,IAAa,CACjD,IAAM,EAAY,KAAK,aAAa,iBAAiB,CAAC,EAAE,OAAS,EAC3D,EAAY,KAAK,aAAa,iBAAiB,CAAC,EAAE,OAAU,EAElE,OAAO,EAAS,EAAa,CACjC,CAYA,0BAA+C,CAC3C,OAAO,KAAK,gBAAgB,WAAW,CAC3C,CAQA,0BAA+C,CAC3C,OAAO,KAAK,gBAAgB,WAAW,CAC3C,CAQA,sBAA2C,CACvC,OAAO,KAAK,YAAY,WAAW,CACvC,CACJ,EAEM,EAAuB,EAAS,YAAY,ECzkB5C,OAAN,cAAqB,CAAe,CAEhC,QAQA,iBAAoC,GACpC,uBAAyC,GACzC,yBAAsE,GAAkB,KAAK,mBAAmB,CAAC,EACjH,wBAAqE,GAAkB,KAAK,kBAAkB,CAAC,EAC/G,4BAA6D,KAAK,kBAAkB,EAWpF,YAAY,EAAoB,EAAyB,CACrD,MAAM,CAAO,EAEb,KAAK,iBAAiB,IAAI,EAAQ,EAQlC,IAAM,EAAsB,KAAK,SAAS,YAAc,GAAc,SACtE,KAAK,QAAU,IAAI,EAAa,CAAmB,EACnD,KAAK,aAAa,KAAK,QAAS,CAC5B,UAAW,EAAU,MACrB,mBAAoB,EACxB,CAAC,EACD,KAAK,QAAQ,0BAA4B,KAAK,aAAa,CAAC,EAC5D,KAAK,QAAQ,8BAAgC,KAAK,eAAe,CAAC,EAClE,KAAK,QAAQ,8BAAgC,KAAK,eAAe,CAAC,EAClE,KAAK,QAAQ,6BAA8B,GAAkB,KAAK,oBAAoB,CAAC,CAAC,EACxF,KAAK,QAAQ,2BAA2B,KAAK,uBAAuB,EAKhE,KAAK,SAAS,QAAU,IAAA,IACxB,KAAK,QAAQ,SAAS,KAAK,SAAS,KAAK,EAG7C,KAAK,WAAW,CAAO,CAC3B,CAQA,WAA0B,CACtB,OAAO,KAAK,OAChB,CASA,cAAc,EAAoB,CAC9B,GAAI,CAAC,KAAK,QACN,MAAU,MAAM,gCAAgC,EAKpD,OAFA,KAAK,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAI,EAE5B,IACX,CAWA,SAAS,EAAqB,CAI1B,MAHA,MAAK,SAAS,MAAQ,EACtB,KAAK,QAAQ,SAAS,CAAK,EAEpB,IACX,CASA,iBAAkC,CAQ9B,EAAM,mBAAmB,KAAK,QAAS,YAAa,KAAK,uBAAuB,EAMhF,EAAM,mBAAmB,KAAK,QAAS,YAAa,KAAK,wBAAwB,EACjF,EAAY,eAAe,KAAK,QAAS,CACrC,aAA0B,KAAK,oBAAoB,EACnD,gBAAmC,KAAK,kBAAkB,EAC1D,WAAY,EAA0B,IAA2B,KAAK,gBAAgB,CAAO,CACjG,CAAC,CACL,CAOA,iBAA2B,EAAsB,CAC7C,KAAK,QAAQ,aAAa,CAAK,CACnC,CAOA,mBAA6B,EAAsB,CAC/C,KAAK,QAAQ,eAAe,CAAK,CACrC,CAOA,mBAA6B,EAAsB,CAC/C,KAAK,QAAQ,eAAe,CAAK,CACrC,CAQA,4BAAsC,EAAsB,CACxD,KAAK,QAAQ,yBAAyB,CAAK,CAC/C,CAYA,qBAA+B,EAA0B,CACrD,KAAK,QAAQ,uBAAuB,IAAU,YAAc,iBAAmB,iBAAiB,EAChG,KAAK,QAAQ,uBAAuB,IAAU,YAAc,iBAAmB,iBAAiB,CACpG,CAOA,YAAsB,EAAuB,CACzC,KAAK,QAAQ,UAAU,CAAM,CACjC,CAOA,UAAmB,CACf,OAAO,OAAO,KAAK,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAClD,CAOA,qBAAwC,CACpC,OAAO,KAAK,QAAQ,mBAAmB,CAC3C,CAOA,cAAiC,CAC7B,OAAO,KAAK,QAAQ,UAAU,CAClC,CAOA,WAAqB,EAA0B,CAC3C,KAAK,aAAa,EAAS,CAAE,UAAW,EAAU,MAAO,CAAC,CAC9D,CAQA,kBAAkB,EAA2B,CACzC,OAAO,IAAU,KAAK,OAC1B,CAWA,kBAA0B,EAAqB,CAC3C,IAAM,EAAS,EAAE,SAAW,KAAO,KAAO,EAAI,OAAO,OAAO,EAAE,MAAM,EAChE,GAAU,KAAK,wBAAwB,CAAM,GAIjD,KAAK,YAAY,CAAC,CACtB,CAUA,oBAA4B,EAAqB,CAC7C,IAAM,EAAS,EAAE,SAAW,KAAO,KAAO,EAAI,OAAO,OAAO,EAAE,MAAM,EAChE,QAAU,KAAK,wBAAwB,CAAM,GAIjD,IAAI,KAAK,eAAe,IAAM,YAAa,CACvC,KAAK,eAAe,KAAK,iBAAiB,EAC1C,MACJ,CAEK,KAAK,YAAY,GAGtB,KAAK,eAAe,CALpB,CAMJ,CAWA,wBAAgC,EAAyB,CACrD,IAAM,EAAsC,CACxC,KAAK,QAAQ,yBAAyB,EACtC,KAAK,QAAQ,yBAAyB,EACtC,KAAK,QAAQ,qBAAqB,EAClC,KAAK,QAAQ,SAAS,CAAC,EAAE,WAAW,CACxC,EACA,IAAK,IAAM,KAAW,EAClB,GAAI,GAAW,EAAI,OAAO,SAAS,EAAS,CAAM,EAC9C,MAAO,GAGf,MAAO,EACX,CAMA,mBAAkC,CAC9B,IAAM,EAAQ,KAAK,QAAQ,SAAS,EAEhC,GACA,KAAK,eAAe,CAAK,CAEjC,CASA,mBAA2B,EAAqB,CAC5C,KAAK,iBAAmB,EAAE,QAC9B,CASA,qBAAwC,CACpC,IAAM,EAAU,KAAK,aAAa,EASlC,MAAO,CANH,QAAa,GACb,YAAa,KAAK,MAAM,EACxB,YAAa,EAAU,EAAQ,MAAM,EAAI,GACzC,MAAa,OAAO,KAAK,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAGvC,CACrB,CASA,mBAA4C,CACxC,IAAM,EAAQ,KAAK,iBACnB,KAAK,iBAAmB,GAExB,IAAM,EAAU,KAAK,aAAa,EAElC,GAAI,CAAC,GAAS,CAAC,EACX,MAAO,GAGX,KAAK,uBAAyB,EAAQ,MAAM,EAC5C,EAAgB,IAAI,EAAQ,MAAM,EAAG,CAAO,CAChD,CAUA,gBAAwB,EAAwB,CAC5C,EAAgB,OAAO,KAAK,sBAAsB,EAClD,KAAK,uBAAyB,GAE1B,GAAW,KAAK,aAAa,IAAM,MACnC,KAAK,aAAa,CAE1B,CACJ,EAEM,GAAiB,EAAS,MAAM"}
|