@alfadocs/ui-kit-debug 1.67.0 → 1.68.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/_chunks/{address-fields-CJtu7LQU.js → address-fields-BUPRs3n-.js} +3 -3
- package/dist/_chunks/{address-fields-CJtu7LQU.js.map → address-fields-BUPRs3n-.js.map} +1 -1
- package/dist/_chunks/{agenda-card-DR9gDdKp.js → agenda-card-BDuvreCe.js} +2 -2
- package/dist/_chunks/{agenda-card-DR9gDdKp.js.map → agenda-card-BDuvreCe.js.map} +1 -1
- package/dist/_chunks/{agenda-tray-DGB1Zup-.js → agenda-tray-CfwylhWf.js} +3 -3
- package/dist/_chunks/{agenda-tray-DGB1Zup-.js.map → agenda-tray-CfwylhWf.js.map} +1 -1
- package/dist/_chunks/{ai-credits-exhausted-notice-DfAgfZDF.js → ai-credits-exhausted-notice-Bg8NpW2K.js} +2 -2
- package/dist/_chunks/{ai-credits-exhausted-notice-DfAgfZDF.js.map → ai-credits-exhausted-notice-Bg8NpW2K.js.map} +1 -1
- package/dist/_chunks/{ai-permission-notice-qsdm4Sx4.js → ai-permission-notice-C00i6VhY.js} +2 -2
- package/dist/_chunks/{ai-permission-notice-qsdm4Sx4.js.map → ai-permission-notice-C00i6VhY.js.map} +1 -1
- package/dist/_chunks/{ai-prompt-input-DSGSe4LH.js → ai-prompt-input-DzgyoKyk.js} +141 -139
- package/dist/_chunks/ai-prompt-input-DzgyoKyk.js.map +1 -0
- package/dist/_chunks/{alert-DjsJMGRE.js → alert-9kEwDza3.js} +122 -112
- package/dist/_chunks/alert-9kEwDza3.js.map +1 -0
- package/dist/_chunks/{alia-sidebar-qe0quZkB.js → alia-sidebar-B06ZSOaF.js} +3 -3
- package/dist/_chunks/{alia-sidebar-qe0quZkB.js.map → alia-sidebar-B06ZSOaF.js.map} +1 -1
- package/dist/_chunks/{anamnesis-summary-card-CMzBLTiN.js → anamnesis-summary-card-DQ3iE1gD.js} +2 -2
- package/dist/_chunks/{anamnesis-summary-card-CMzBLTiN.js.map → anamnesis-summary-card-DQ3iE1gD.js.map} +1 -1
- package/dist/_chunks/{anamnesis-summary-rows-BQ_EokKz.js → anamnesis-summary-rows-CNK0fIJk.js} +392 -388
- package/dist/_chunks/anamnesis-summary-rows-CNK0fIJk.js.map +1 -0
- package/dist/_chunks/{appointment-card-CL32sux-.js → appointment-card-5JMWi9_f.js} +2 -2
- package/dist/_chunks/{appointment-card-CL32sux-.js.map → appointment-card-5JMWi9_f.js.map} +1 -1
- package/dist/_chunks/{appointment-peek-B5mcDcXt.js → appointment-peek-D5XCfYKu.js} +2 -2
- package/dist/_chunks/{appointment-peek-B5mcDcXt.js.map → appointment-peek-D5XCfYKu.js.map} +1 -1
- package/dist/_chunks/{appointment-timeline-CCqjORFb.js → appointment-timeline-VFP6HoXT.js} +4 -4
- package/dist/_chunks/{appointment-timeline-CCqjORFb.js.map → appointment-timeline-VFP6HoXT.js.map} +1 -1
- package/dist/_chunks/{appointment-tray-qtpJt8e0.js → appointment-tray-B3PDER3I.js} +3 -3
- package/dist/_chunks/{appointment-tray-qtpJt8e0.js.map → appointment-tray-B3PDER3I.js.map} +1 -1
- package/dist/_chunks/{audio-recorder-B11RR-rC.js → audio-recorder-4Ll0pwYK.js} +3 -3
- package/dist/_chunks/{audio-recorder-B11RR-rC.js.map → audio-recorder-4Ll0pwYK.js.map} +1 -1
- package/dist/_chunks/{auth-form-parts-DwUTH6YN.js → auth-form-parts-B40zvD-a.js} +2 -2
- package/dist/_chunks/{auth-form-parts-DwUTH6YN.js.map → auth-form-parts-B40zvD-a.js.map} +1 -1
- package/dist/_chunks/avatar-BPiPL7ND.js +199 -0
- package/dist/_chunks/avatar-BPiPL7ND.js.map +1 -0
- package/dist/_chunks/{balance-badge-cell-DZNthHO1.js → balance-badge-cell-BG3DMly4.js} +4 -4
- package/dist/_chunks/{balance-badge-cell-DZNthHO1.js.map → balance-badge-cell-BG3DMly4.js.map} +1 -1
- package/dist/_chunks/{bishop-score-CaNTrikJ.js → bishop-score-Df8nF1qg.js} +2 -2
- package/dist/_chunks/{bishop-score-CaNTrikJ.js.map → bishop-score-Df8nF1qg.js.map} +1 -1
- package/dist/_chunks/{booking-tTVxKPQY.js → booking-B1pDbERi.js} +377 -335
- package/dist/_chunks/booking-B1pDbERi.js.map +1 -0
- package/dist/_chunks/{calendar-BhN-jisv.js → calendar-BvOM8rG3.js} +2 -2
- package/dist/_chunks/{calendar-BhN-jisv.js.map → calendar-BvOM8rG3.js.map} +1 -1
- package/dist/_chunks/{calendar-workspace-MRrzcxAy.js → calendar-workspace-CYK1M83j.js} +18 -18
- package/dist/_chunks/{calendar-workspace-MRrzcxAy.js.map → calendar-workspace-CYK1M83j.js.map} +1 -1
- package/dist/_chunks/{chat-message-fRLZ95O5.js → chat-message-Be-9vIIQ.js} +2 -2
- package/dist/_chunks/{chat-message-fRLZ95O5.js.map → chat-message-Be-9vIIQ.js.map} +1 -1
- package/dist/_chunks/{clinical-note-card-BnFTIs6x.js → clinical-note-card-Caidqcwa.js} +2 -2
- package/dist/_chunks/{clinical-note-card-BnFTIs6x.js.map → clinical-note-card-Caidqcwa.js.map} +1 -1
- package/dist/_chunks/{color-picker-BsggJovx.js → color-picker-AcaWuKah.js} +99 -95
- package/dist/_chunks/color-picker-AcaWuKah.js.map +1 -0
- package/dist/_chunks/{combobox-U5yfO6o0.js → combobox-vF9O-QoG.js} +92 -83
- package/dist/_chunks/combobox-vF9O-QoG.js.map +1 -0
- package/dist/_chunks/{contact-profile-card-C4-OCshj.js → contact-profile-card-CAwwOqHl.js} +40 -40
- package/dist/_chunks/contact-profile-card-CAwwOqHl.js.map +1 -0
- package/dist/_chunks/{control-room-rail-DUerqHeo.js → control-room-rail-BB6rCDWI.js} +3 -3
- package/dist/_chunks/{control-room-rail-DUerqHeo.js.map → control-room-rail-BB6rCDWI.js.map} +1 -1
- package/dist/_chunks/{country-select-DF5Bd_mn.js → country-select-CSE2Zm_s.js} +2 -2
- package/dist/_chunks/{country-select-DF5Bd_mn.js.map → country-select-CSE2Zm_s.js.map} +1 -1
- package/dist/_chunks/dashboard-grid-7JzaiKnk.js +1487 -0
- package/dist/_chunks/dashboard-grid-7JzaiKnk.js.map +1 -0
- package/dist/_chunks/{data-table-COoCQ4n_.js → data-table-Cty4-Jht.js} +3 -3
- package/dist/_chunks/{data-table-COoCQ4n_.js.map → data-table-Cty4-Jht.js.map} +1 -1
- package/dist/_chunks/{dependent-selector-DBr1AhLg.js → dependent-selector-C4kOgO8b.js} +2 -2
- package/dist/_chunks/{dependent-selector-DBr1AhLg.js.map → dependent-selector-C4kOgO8b.js.map} +1 -1
- package/dist/_chunks/{document-preview-VyQOjFVL.js → document-preview-513f3iPn.js} +4 -4
- package/dist/_chunks/{document-preview-VyQOjFVL.js.map → document-preview-513f3iPn.js.map} +1 -1
- package/dist/_chunks/{document-scanner-CXH_GYh4.js → document-scanner-Bd3wbzpI.js} +2 -2
- package/dist/_chunks/{document-scanner-CXH_GYh4.js.map → document-scanner-Bd3wbzpI.js.map} +1 -1
- package/dist/_chunks/{editable-description-ChGNdYY8.js → editable-description-DnAFi360.js} +2 -2
- package/dist/_chunks/{editable-description-ChGNdYY8.js.map → editable-description-DnAFi360.js.map} +1 -1
- package/dist/_chunks/{entity-summary-Bj-Wxq7Y.js → entity-summary-C2B8yNmc.js} +4 -4
- package/dist/_chunks/{entity-summary-Bj-Wxq7Y.js.map → entity-summary-C2B8yNmc.js.map} +1 -1
- package/dist/_chunks/{error-summary-PUE5Zxp9.js → error-summary-mGxIyDAY.js} +2 -2
- package/dist/_chunks/{error-summary-PUE5Zxp9.js.map → error-summary-mGxIyDAY.js.map} +1 -1
- package/dist/_chunks/{face-scheme-DAD-mXzM.js → face-scheme-CSJdRNad.js} +248 -244
- package/dist/_chunks/{face-scheme-DAD-mXzM.js.map → face-scheme-CSJdRNad.js.map} +1 -1
- package/dist/_chunks/{file-manager-RiV7-OEE.js → file-manager-D4cPnRhL.js} +3 -3
- package/dist/_chunks/{file-manager-RiV7-OEE.js.map → file-manager-D4cPnRhL.js.map} +1 -1
- package/dist/_chunks/{forgot-password-form-CPOfRE0C.js → forgot-password-form-Dqi7R-NL.js} +4 -4
- package/dist/_chunks/{forgot-password-form-CPOfRE0C.js.map → forgot-password-form-Dqi7R-NL.js.map} +1 -1
- package/dist/_chunks/format-number-DdzqwMs1.js +13 -0
- package/dist/_chunks/format-number-DdzqwMs1.js.map +1 -0
- package/dist/_chunks/{freemium-paywall-6DO7noHX.js → freemium-paywall-C73C8Rgd.js} +2 -2
- package/dist/_chunks/{freemium-paywall-6DO7noHX.js.map → freemium-paywall-C73C8Rgd.js.map} +1 -1
- package/dist/_chunks/{gestational-age-calculator-CZYa2D6m.js → gestational-age-calculator-Du53p8MH.js} +2 -2
- package/dist/_chunks/{gestational-age-calculator-CZYa2D6m.js.map → gestational-age-calculator-Du53p8MH.js.map} +1 -1
- package/dist/_chunks/{header-settings-BSH9Gk0J.js → header-settings-DlUbvAUx.js} +37 -36
- package/dist/_chunks/header-settings-DlUbvAUx.js.map +1 -0
- package/dist/_chunks/{heatmap-C1TeC7wT.js → heatmap-DbZIQg14.js} +4 -4
- package/dist/_chunks/{heatmap-C1TeC7wT.js.map → heatmap-DbZIQg14.js.map} +1 -1
- package/dist/_chunks/{help-me-write-templates-Bw3Q58x-.js → help-me-write-templates-5WkUfvc_.js} +3 -3
- package/dist/_chunks/{help-me-write-templates-Bw3Q58x-.js.map → help-me-write-templates-5WkUfvc_.js.map} +1 -1
- package/dist/_chunks/{kit-extensions-DWs1UEXb.js → kit-extensions-CYvLL4ee.js} +3 -3
- package/dist/_chunks/{kit-extensions-DWs1UEXb.js.map → kit-extensions-CYvLL4ee.js.map} +1 -1
- package/dist/_chunks/length-token-DwMnGEYT.js +24 -0
- package/dist/_chunks/length-token-DwMnGEYT.js.map +1 -0
- package/dist/_chunks/{link-cell-renderer-CtTsvfPY.js → link-cell-renderer-DtIsQWDO.js} +4 -4
- package/dist/_chunks/{link-cell-renderer-CtTsvfPY.js.map → link-cell-renderer-DtIsQWDO.js.map} +1 -1
- package/dist/_chunks/{login-dev-card-A-CL3mjt.js → login-dev-card-vEL-o5wq.js} +3 -3
- package/dist/_chunks/{login-dev-card-A-CL3mjt.js.map → login-dev-card-vEL-o5wq.js.map} +1 -1
- package/dist/_chunks/{map-view-BuVfJMEa.js → map-view-CtohteZD.js} +300 -191
- package/dist/_chunks/map-view-CtohteZD.js.map +1 -0
- package/dist/_chunks/{marketplace-app-shell-DtSX8sYb.js → marketplace-app-shell-CcLQ0Dn-.js} +4 -4
- package/dist/_chunks/{marketplace-app-shell-DtSX8sYb.js.map → marketplace-app-shell-CcLQ0Dn-.js.map} +1 -1
- package/dist/_chunks/{message-card-A3mJNqfy.js → message-card-C_ksqIYM.js} +2 -2
- package/dist/_chunks/{message-card-A3mJNqfy.js.map → message-card-C_ksqIYM.js.map} +1 -1
- package/dist/_chunks/{message-tray-Ft6vSr71.js → message-tray-DCoQ4GQb.js} +3 -3
- package/dist/_chunks/{message-tray-Ft6vSr71.js.map → message-tray-DCoQ4GQb.js.map} +1 -1
- package/dist/_chunks/{multi-select-CMaAQQgb.js → multi-select-BOad3za9.js} +110 -98
- package/dist/_chunks/multi-select-BOad3za9.js.map +1 -0
- package/dist/_chunks/{muscle-scheme-YoN3rYXV.js → muscle-scheme-C66WlCxG.js} +2 -2
- package/dist/_chunks/{muscle-scheme-YoN3rYXV.js.map → muscle-scheme-C66WlCxG.js.map} +1 -1
- package/dist/_chunks/{note-timeline-DDqNU46n.js → note-timeline-KzL52MmB.js} +2 -2
- package/dist/_chunks/{note-timeline-DDqNU46n.js.map → note-timeline-KzL52MmB.js.map} +1 -1
- package/dist/_chunks/{notes-panel-IdsmqRFC.js → notes-panel-BXN46XkF.js} +6 -6
- package/dist/_chunks/{notes-panel-IdsmqRFC.js.map → notes-panel-BXN46XkF.js.map} +1 -1
- package/dist/_chunks/notice-group-DkYzKyAZ.js +291 -0
- package/dist/_chunks/notice-group-DkYzKyAZ.js.map +1 -0
- package/dist/_chunks/{notification-tray-BR3seWA7.js → notification-tray-Cp18MW5b.js} +2 -2
- package/dist/_chunks/{notification-tray-BR3seWA7.js.map → notification-tray-Cp18MW5b.js.map} +1 -1
- package/dist/_chunks/{operator-hero-3_RG4Dkj.js → operator-hero-6aAIQaFZ.js} +83 -66
- package/dist/_chunks/operator-hero-6aAIQaFZ.js.map +1 -0
- package/dist/_chunks/{optical-prescription-CxfMsbxi.js → optical-prescription-ulXnDbBe.js} +525 -509
- package/dist/_chunks/optical-prescription-ulXnDbBe.js.map +1 -0
- package/dist/_chunks/panel-header-CbtlTe85.js +190 -0
- package/dist/_chunks/panel-header-CbtlTe85.js.map +1 -0
- package/dist/_chunks/{panel-subview-yP4qIbKS.js → panel-subview-BPU7220K.js} +2 -2
- package/dist/_chunks/{panel-subview-yP4qIbKS.js.map → panel-subview-BPU7220K.js.map} +1 -1
- package/dist/_chunks/{patient-details-C-EWQTms.js → patient-details-C4Dyo7Ck.js} +4 -4
- package/dist/_chunks/{patient-details-C-EWQTms.js.map → patient-details-C4Dyo7Ck.js.map} +1 -1
- package/dist/_chunks/{patient-field-row-lY-Tb5Mo.js → patient-field-row-DROvUkFu.js} +4 -4
- package/dist/_chunks/{patient-field-row-lY-Tb5Mo.js.map → patient-field-row-DROvUkFu.js.map} +1 -1
- package/dist/_chunks/{patient-search-DpAKidZ5.js → patient-search-BADdx3M1.js} +2 -2
- package/dist/_chunks/{patient-search-DpAKidZ5.js.map → patient-search-BADdx3M1.js.map} +1 -1
- package/dist/_chunks/{patient-summary-card-Bpto_VCD.js → patient-summary-card-CAimxbuI.js} +4 -4
- package/dist/_chunks/{patient-summary-card-Bpto_VCD.js.map → patient-summary-card-CAimxbuI.js.map} +1 -1
- package/dist/_chunks/{payment-automation-upsell-BQ307qEX.js → payment-automation-upsell-CiwF5UrC.js} +2 -2
- package/dist/_chunks/{payment-automation-upsell-BQ307qEX.js.map → payment-automation-upsell-CiwF5UrC.js.map} +1 -1
- package/dist/_chunks/{payment-form-XKtinW8r.js → payment-form-PBuh8PIa.js} +2 -2
- package/dist/_chunks/{payment-form-XKtinW8r.js.map → payment-form-PBuh8PIa.js.map} +1 -1
- package/dist/_chunks/{pdf-viewer-BvoVMjH4.js → pdf-viewer-gAsNUsA8.js} +2 -2
- package/dist/_chunks/{pdf-viewer-BvoVMjH4.js.map → pdf-viewer-gAsNUsA8.js.map} +1 -1
- package/dist/_chunks/{periodontal-risk-chart-CPy7CNFe.js → periodontal-risk-chart-B7S9OmPC.js} +97 -89
- package/dist/_chunks/periodontal-risk-chart-B7S9OmPC.js.map +1 -0
- package/dist/_chunks/practice-profile-hero-qfrsFQI_.js +236 -0
- package/dist/_chunks/practice-profile-hero-qfrsFQI_.js.map +1 -0
- package/dist/_chunks/{practice-results-BrUDDMXC.js → practice-results-BzThnpnm.js} +328 -298
- package/dist/_chunks/practice-results-BzThnpnm.js.map +1 -0
- package/dist/_chunks/{pregnancy-dating-B8wo4l_r.js → pregnancy-dating-EFcFUJkQ.js} +2 -2
- package/dist/_chunks/{pregnancy-dating-B8wo4l_r.js.map → pregnancy-dating-EFcFUJkQ.js.map} +1 -1
- package/dist/_chunks/{privacy-mask-Ch7743uk.js → privacy-mask-CCz9zuIh.js} +2 -2
- package/dist/_chunks/{privacy-mask-Ch7743uk.js.map → privacy-mask-CCz9zuIh.js.map} +1 -1
- package/dist/_chunks/{product-hub-panel-C_ZosrBt.js → product-hub-panel-YuFbNPlT.js} +2 -2
- package/dist/_chunks/{product-hub-panel-C_ZosrBt.js.map → product-hub-panel-YuFbNPlT.js.map} +1 -1
- package/dist/_chunks/progress-notice-DiHWZ8Ms.js +279 -0
- package/dist/_chunks/progress-notice-DiHWZ8Ms.js.map +1 -0
- package/dist/_chunks/{province-select-Bd20Z9Br.js → province-select-CDjs5obD.js} +2 -2
- package/dist/_chunks/{province-select-Bd20Z9Br.js.map → province-select-CDjs5obD.js.map} +1 -1
- package/dist/_chunks/{radiograph-panel.agent-8Ewv8-d7.js → radiograph-panel.agent-4UllIoTQ.js} +2 -2
- package/dist/_chunks/{radiograph-panel.agent-8Ewv8-d7.js.map → radiograph-panel.agent-4UllIoTQ.js.map} +1 -1
- package/dist/_chunks/{rating-C1Vrmpsi.js → rating-CGYpg5dj.js} +43 -44
- package/dist/_chunks/rating-CGYpg5dj.js.map +1 -0
- package/dist/_chunks/{registration-form-BxwqUZzk.js → registration-form-1B0PTDal.js} +4 -4
- package/dist/_chunks/{registration-form-BxwqUZzk.js.map → registration-form-1B0PTDal.js.map} +1 -1
- package/dist/_chunks/{reviews-panel-AvsVgtJu.js → reviews-panel-CosDZyow.js} +29 -7
- package/dist/_chunks/reviews-panel-CosDZyow.js.map +1 -0
- package/dist/_chunks/{rich-text-editor-aCIoptbg.js → rich-text-editor-56dSsyZI.js} +3 -3
- package/dist/_chunks/{rich-text-editor-aCIoptbg.js.map → rich-text-editor-56dSsyZI.js.map} +1 -1
- package/dist/_chunks/{select-k4gBdS8N.js → select-4S-eYZUf.js} +244 -214
- package/dist/_chunks/select-4S-eYZUf.js.map +1 -0
- package/dist/_chunks/{sign-document-D1P1nUQA.js → sign-document-BiOTs1P4.js} +2 -2
- package/dist/_chunks/{sign-document-D1P1nUQA.js.map → sign-document-BiOTs1P4.js.map} +1 -1
- package/dist/_chunks/{signature-request-3u6TvRt2.js → signature-request-DAmNj_uq.js} +5 -5
- package/dist/_chunks/{signature-request-3u6TvRt2.js.map → signature-request-DAmNj_uq.js.map} +1 -1
- package/dist/_chunks/skeleton-tTWJpvAq.js +415 -0
- package/dist/_chunks/skeleton-tTWJpvAq.js.map +1 -0
- package/dist/_chunks/{slot-grid-dj5f6R2w.js → slot-grid-D_gix9mJ.js} +2 -2
- package/dist/_chunks/{slot-grid-dj5f6R2w.js.map → slot-grid-D_gix9mJ.js.map} +1 -1
- package/dist/_chunks/{tabs-2x3L13jn.js → tabs-BTj-2qMZ.js} +2 -2
- package/dist/_chunks/{tabs-2x3L13jn.js.map → tabs-BTj-2qMZ.js.map} +1 -1
- package/dist/_chunks/{task-card-BS7Uqevr.js → task-card-Ci2XbLmq.js} +2 -2
- package/dist/_chunks/{task-card-BS7Uqevr.js.map → task-card-Ci2XbLmq.js.map} +1 -1
- package/dist/_chunks/{task-editor-Bb5MMcid.js → task-editor-BomyxGoZ.js} +8 -8
- package/dist/_chunks/{task-editor-Bb5MMcid.js.map → task-editor-BomyxGoZ.js.map} +1 -1
- package/dist/_chunks/{task-tray-eQU4KJcA.js → task-tray-Dnc72nl-.js} +3 -3
- package/dist/_chunks/{task-tray-eQU4KJcA.js.map → task-tray-Dnc72nl-.js.map} +1 -1
- package/dist/_chunks/{tasks-panel-BOb57Ysw.js → tasks-panel-ATz9JDy8.js} +6 -6
- package/dist/_chunks/{tasks-panel-BOb57Ysw.js.map → tasks-panel-ATz9JDy8.js.map} +1 -1
- package/dist/_chunks/{theme-toggle-Ctb77x6O.js → theme-toggle-DT_Jn4DC.js} +147 -138
- package/dist/_chunks/theme-toggle-DT_Jn4DC.js.map +1 -0
- package/dist/_chunks/{timeline-DEIuHrWz.js → timeline-wUuTDFY_.js} +2 -2
- package/dist/_chunks/{timeline-DEIuHrWz.js.map → timeline-wUuTDFY_.js.map} +1 -1
- package/dist/_chunks/{tool-rail-C-03rH2I.js → tool-rail-C-M3eVdY.js} +2 -2
- package/dist/_chunks/{tool-rail-C-03rH2I.js.map → tool-rail-C-M3eVdY.js.map} +1 -1
- package/dist/_chunks/{transcript-panel-XudW5l6l.js → transcript-panel-CoHHpcFg.js} +2 -2
- package/dist/_chunks/{transcript-panel-XudW5l6l.js.map → transcript-panel-CoHHpcFg.js.map} +1 -1
- package/dist/_chunks/{treatment-receipt-Cpm8tqQN.js → treatment-receipt-pFqWFyD_.js} +2 -2
- package/dist/_chunks/{treatment-receipt-Cpm8tqQN.js.map → treatment-receipt-pFqWFyD_.js.map} +1 -1
- package/dist/_chunks/{unit-converter-BPZ0Ldkb.js → unit-converter-CIoTmCmP.js} +2 -2
- package/dist/_chunks/{unit-converter-BPZ0Ldkb.js.map → unit-converter-CIoTmCmP.js.map} +1 -1
- package/dist/_chunks/{use-appointment-details-read-CVSPoP5j.js → use-appointment-details-read-CUGfE0hV.js} +12 -12
- package/dist/_chunks/{use-appointment-details-read-CVSPoP5j.js.map → use-appointment-details-read-CUGfE0hV.js.map} +1 -1
- package/dist/_chunks/use-dismissed-CTOWqA0e.js +177 -0
- package/dist/_chunks/use-dismissed-CTOWqA0e.js.map +1 -0
- package/dist/_chunks/{voice-control-panel-BJIEbDq6.js → voice-control-panel-B8Lrk0C4.js} +4 -4
- package/dist/_chunks/{voice-control-panel-BJIEbDq6.js.map → voice-control-panel-B8Lrk0C4.js.map} +1 -1
- package/dist/_chunks/{warning-stack-BdY-0bd3.js → warning-stack-BhHUmRiD.js} +2 -2
- package/dist/_chunks/{warning-stack-BdY-0bd3.js.map → warning-stack-BhHUmRiD.js.map} +1 -1
- package/dist/_chunks/{workflow-map-CYbRD9ek.js → workflow-map-ln4_OG8A.js} +2 -2
- package/dist/_chunks/{workflow-map-CYbRD9ek.js.map → workflow-map-ln4_OG8A.js.map} +1 -1
- package/dist/agent-catalog.json +172 -4
- package/dist/agent-i18n/en.json +25 -1
- package/dist/components/_shared/format-number.d.ts +20 -0
- package/dist/components/_shared/format-number.d.ts.map +1 -0
- package/dist/components/_shared/length-token.d.ts +12 -0
- package/dist/components/_shared/length-token.d.ts.map +1 -0
- package/dist/components/_shared/option.d.ts +1 -0
- package/dist/components/_shared/option.d.ts.map +1 -1
- package/dist/components/address-fields/index.js +1 -1
- package/dist/components/agenda-card/index.js +1 -1
- package/dist/components/agenda-tray/index.js +1 -1
- package/dist/components/ai-credits-notice/index.js +1 -1
- package/dist/components/ai-permission-notice/index.js +1 -1
- package/dist/components/ai-prompt-input/ai-prompt-input.d.ts.map +1 -1
- package/dist/components/ai-prompt-input/index.js +1 -1
- package/dist/components/alert/alert.d.ts +26 -0
- package/dist/components/alert/alert.d.ts.map +1 -1
- package/dist/components/alert/index.js +1 -1
- package/dist/components/anamnesis-summary-card/index.js +1 -1
- package/dist/components/appointment-card/index.js +2 -2
- package/dist/components/appointment-details-panel/index.js +1 -1
- package/dist/components/appointment-peek/index.js +1 -1
- package/dist/components/appointment-timeline/index.js +1 -1
- package/dist/components/audio-recorder/index.js +1 -1
- package/dist/components/avatar/avatar.d.ts +2 -0
- package/dist/components/avatar/avatar.d.ts.map +1 -1
- package/dist/components/avatar/index.js +1 -1
- package/dist/components/bishop-score/index.js +1 -1
- package/dist/components/booking/booking.d.ts.map +1 -1
- package/dist/components/booking/details-form.d.ts.map +1 -1
- package/dist/components/booking/index.js +1 -1
- package/dist/components/calendar/index.js +1 -1
- package/dist/components/chat-message/index.js +1 -1
- package/dist/components/clinical-note-card/index.js +1 -1
- package/dist/components/color-picker/color-picker.d.ts.map +1 -1
- package/dist/components/color-picker/index.js +1 -1
- package/dist/components/combobox/combobox.d.ts.map +1 -1
- package/dist/components/combobox/index.js +1 -1
- package/dist/components/contact-profile-card/index.js +1 -1
- package/dist/components/control-room-rail/index.js +1 -1
- package/dist/components/country-select/index.js +1 -1
- package/dist/components/dashboard-grid/dashboard-grid.agent.d.ts.map +1 -1
- package/dist/components/dashboard-grid/dashboard-grid.d.ts +20 -1
- package/dist/components/dashboard-grid/dashboard-grid.d.ts.map +1 -1
- package/dist/components/dashboard-grid/index.js +1 -1
- package/dist/components/data-table/index.js +2 -2
- package/dist/components/dependent-selector/index.js +1 -1
- package/dist/components/document-preview/index.js +1 -1
- package/dist/components/document-scanner/index.js +1 -1
- package/dist/components/editable-description/index.js +1 -1
- package/dist/components/entity-summary/index.js +1 -1
- package/dist/components/error-summary/index.js +1 -1
- package/dist/components/face-scheme/face-scheme.d.ts.map +1 -1
- package/dist/components/face-scheme/index.js +1 -1
- package/dist/components/file-manager/index.js +1 -1
- package/dist/components/freemium-paywall/index.js +1 -1
- package/dist/components/gestational-age-calculator/index.js +1 -1
- package/dist/components/header-settings/header-settings.d.ts.map +1 -1
- package/dist/components/header-settings/index.js +1 -1
- package/dist/components/heatmap/index.js +1 -1
- package/dist/components/index.d.ts +4 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/map-view/index.d.ts +1 -1
- package/dist/components/map-view/index.d.ts.map +1 -1
- package/dist/components/map-view/index.js +1 -1
- package/dist/components/map-view/map-view.d.ts +51 -0
- package/dist/components/map-view/map-view.d.ts.map +1 -1
- package/dist/components/message-card/index.js +1 -1
- package/dist/components/message-tray/index.js +1 -1
- package/dist/components/multi-select/index.js +1 -1
- package/dist/components/multi-select/multi-select.d.ts.map +1 -1
- package/dist/components/muscle-scheme/index.js +1 -1
- package/dist/components/note-timeline/index.js +1 -1
- package/dist/components/notes-panel/index.js +1 -1
- package/dist/components/notice-group/index.d.ts +3 -0
- package/dist/components/notice-group/index.d.ts.map +1 -0
- package/dist/components/notice-group/index.js +6 -0
- package/dist/components/notice-group/index.js.map +1 -0
- package/dist/components/notice-group/notice-group.agent.d.ts +4 -0
- package/dist/components/notice-group/notice-group.agent.d.ts.map +1 -0
- package/dist/components/notice-group/notice-group.d.ts +43 -0
- package/dist/components/notice-group/notice-group.d.ts.map +1 -0
- package/dist/components/notification-tray/index.js +1 -1
- package/dist/components/operator-hero/index.js +1 -1
- package/dist/components/operator-hero/operator-hero.d.ts.map +1 -1
- package/dist/components/optical-prescription/index.js +1 -1
- package/dist/components/optical-prescription/optical-prescription-data.d.ts +8 -8
- package/dist/components/optical-prescription/optical-prescription-data.d.ts.map +1 -1
- package/dist/components/optical-prescription/optical-prescription.d.ts.map +1 -1
- package/dist/components/panel-header/index.js +1 -1
- package/dist/components/panel-header/panel-header.d.ts +10 -0
- package/dist/components/panel-header/panel-header.d.ts.map +1 -1
- package/dist/components/panel-subview/index.js +1 -1
- package/dist/components/patient-details/index.js +1 -1
- package/dist/components/patient-search/index.js +1 -1
- package/dist/components/patient-summary-card/index.js +1 -1
- package/dist/components/patient-table/index.js +1 -1
- package/dist/components/payment-form/index.js +1 -1
- package/dist/components/pdf-viewer/index.js +1 -1
- package/dist/components/periodontal-risk-chart/index.js +1 -1
- package/dist/components/periodontal-risk-chart/periodontal-risk-chart.d.ts.map +1 -1
- package/dist/components/practice-profile-hero/index.js +1 -1
- package/dist/components/practice-profile-hero/practice-profile-hero.d.ts +4 -1
- package/dist/components/practice-profile-hero/practice-profile-hero.d.ts.map +1 -1
- package/dist/components/practice-results/index.js +1 -1
- package/dist/components/practice-results/practice-results.d.ts +10 -2
- package/dist/components/practice-results/practice-results.d.ts.map +1 -1
- package/dist/components/pregnancy-dating/index.js +1 -1
- package/dist/components/product-hub-tray/index.js +1 -1
- package/dist/components/progress-notice/index.d.ts +3 -0
- package/dist/components/progress-notice/index.d.ts.map +1 -0
- package/dist/components/progress-notice/index.js +6 -0
- package/dist/components/progress-notice/index.js.map +1 -0
- package/dist/components/progress-notice/progress-notice.agent.d.ts +4 -0
- package/dist/components/progress-notice/progress-notice.agent.d.ts.map +1 -0
- package/dist/components/progress-notice/progress-notice.d.ts +81 -0
- package/dist/components/progress-notice/progress-notice.d.ts.map +1 -0
- package/dist/components/province-select/index.js +1 -1
- package/dist/components/radiograph-panel/index.js +1 -1
- package/dist/components/rating/index.js +1 -1
- package/dist/components/rating/rating.d.ts.map +1 -1
- package/dist/components/reviews-panel/index.js +1 -1
- package/dist/components/reviews-panel/reviews-panel.d.ts.map +1 -1
- package/dist/components/rich-text-editor/index.js +2 -2
- package/dist/components/select/index.js +1 -1
- package/dist/components/select/select.d.ts +6 -0
- package/dist/components/select/select.d.ts.map +1 -1
- package/dist/components/sign-document/index.js +1 -1
- package/dist/components/skeleton/index.d.ts +1 -1
- package/dist/components/skeleton/index.d.ts.map +1 -1
- package/dist/components/skeleton/index.js +1 -1
- package/dist/components/skeleton/skeleton.d.ts +41 -1
- package/dist/components/skeleton/skeleton.d.ts.map +1 -1
- package/dist/components/skeleton-scheme/index.js +1 -1
- package/dist/components/slot-grid/index.js +1 -1
- package/dist/components/tabs/index.js +1 -1
- package/dist/components/task-card/index.js +1 -1
- package/dist/components/task-editor/index.js +1 -1
- package/dist/components/task-tray/index.js +1 -1
- package/dist/components/tasks-panel/index.js +1 -1
- package/dist/components/theme-toggle/index.js +1 -1
- package/dist/components/theme-toggle/theme-toggle.d.ts.map +1 -1
- package/dist/components/timeline/index.js +1 -1
- package/dist/components/tool-rail/index.js +1 -1
- package/dist/components/transcript-panel/index.js +1 -1
- package/dist/components/treatment-receipt/index.js +1 -1
- package/dist/components/unit-converter/index.js +1 -1
- package/dist/components/voice-control-panel/index.js +1 -1
- package/dist/components/warning-stack/index.js +1 -1
- package/dist/components/workflow/index.js +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +81 -76
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/use-dismissed.d.ts +58 -0
- package/dist/hooks/use-dismissed.d.ts.map +1 -0
- package/dist/i18n/locales/ar.d.ts +22 -0
- package/dist/i18n/locales/ar.d.ts.map +1 -1
- package/dist/i18n/locales/ar.js +22 -0
- package/dist/i18n/locales/ar.js.map +1 -1
- package/dist/i18n/locales/de.d.ts +22 -0
- package/dist/i18n/locales/de.d.ts.map +1 -1
- package/dist/i18n/locales/de.js +22 -0
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/el.d.ts +22 -0
- package/dist/i18n/locales/el.d.ts.map +1 -1
- package/dist/i18n/locales/el.js +22 -0
- package/dist/i18n/locales/el.js.map +1 -1
- package/dist/i18n/locales/en.d.ts +22 -0
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/en.js +22 -0
- package/dist/i18n/locales/en.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +22 -0
- package/dist/i18n/locales/es.d.ts.map +1 -1
- package/dist/i18n/locales/es.js +22 -0
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +22 -0
- package/dist/i18n/locales/fr.d.ts.map +1 -1
- package/dist/i18n/locales/fr.js +22 -0
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hi.d.ts +22 -0
- package/dist/i18n/locales/hi.d.ts.map +1 -1
- package/dist/i18n/locales/hi.js +22 -0
- package/dist/i18n/locales/hi.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +22 -0
- package/dist/i18n/locales/it.d.ts.map +1 -1
- package/dist/i18n/locales/it.js +22 -0
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/ja.d.ts +22 -0
- package/dist/i18n/locales/ja.d.ts.map +1 -1
- package/dist/i18n/locales/ja.js +22 -0
- package/dist/i18n/locales/ja.js.map +1 -1
- package/dist/i18n/locales/nl.d.ts +22 -0
- package/dist/i18n/locales/nl.d.ts.map +1 -1
- package/dist/i18n/locales/nl.js +22 -0
- package/dist/i18n/locales/nl.js.map +1 -1
- package/dist/i18n/locales/pl.d.ts +22 -0
- package/dist/i18n/locales/pl.d.ts.map +1 -1
- package/dist/i18n/locales/pl.js +22 -0
- package/dist/i18n/locales/pl.js.map +1 -1
- package/dist/i18n/locales/pt.d.ts +22 -0
- package/dist/i18n/locales/pt.d.ts.map +1 -1
- package/dist/i18n/locales/pt.js +22 -0
- package/dist/i18n/locales/pt.js.map +1 -1
- package/dist/i18n/locales/ro.d.ts +22 -0
- package/dist/i18n/locales/ro.d.ts.map +1 -1
- package/dist/i18n/locales/ro.js +22 -0
- package/dist/i18n/locales/ro.js.map +1 -1
- package/dist/i18n/locales/ru.d.ts +22 -0
- package/dist/i18n/locales/ru.d.ts.map +1 -1
- package/dist/i18n/locales/ru.js +22 -0
- package/dist/i18n/locales/ru.js.map +1 -1
- package/dist/i18n/locales/sq.d.ts +22 -0
- package/dist/i18n/locales/sq.d.ts.map +1 -1
- package/dist/i18n/locales/sq.js +22 -0
- package/dist/i18n/locales/sq.js.map +1 -1
- package/dist/i18n/locales/sv.d.ts +22 -0
- package/dist/i18n/locales/sv.d.ts.map +1 -1
- package/dist/i18n/locales/sv.js +22 -0
- package/dist/i18n/locales/sv.js.map +1 -1
- package/dist/i18n/locales/tr.d.ts +22 -0
- package/dist/i18n/locales/tr.d.ts.map +1 -1
- package/dist/i18n/locales/tr.js +22 -0
- package/dist/i18n/locales/tr.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +22 -0
- package/dist/i18n/locales/zh.d.ts.map +1 -1
- package/dist/i18n/locales/zh.js +22 -0
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.js +1194 -1183
- package/dist/index.js.map +1 -1
- package/dist/locales/ar.json +22 -0
- package/dist/locales/de.json +22 -0
- package/dist/locales/el.json +22 -0
- package/dist/locales/en.json +22 -0
- package/dist/locales/es.json +22 -0
- package/dist/locales/fr.json +22 -0
- package/dist/locales/hi.json +22 -0
- package/dist/locales/it.json +22 -0
- package/dist/locales/ja.json +22 -0
- package/dist/locales/nl.json +22 -0
- package/dist/locales/pl.json +22 -0
- package/dist/locales/pt.json +22 -0
- package/dist/locales/ro.json +22 -0
- package/dist/locales/ru.json +22 -0
- package/dist/locales/sq.json +22 -0
- package/dist/locales/sv.json +22 -0
- package/dist/locales/tr.json +22 -0
- package/dist/locales/zh.json +22 -0
- package/dist/patterns/alia-assistant/index.js +1 -1
- package/dist/patterns/anamnesis/anamnesis-export-pdf.d.ts.map +1 -1
- package/dist/patterns/anamnesis/index.js +1 -1
- package/dist/patterns/calendar/index.js +1 -1
- package/dist/patterns/forgot-password-form/index.js +1 -1
- package/dist/patterns/help-me-write-templates/index.js +2 -2
- package/dist/patterns/login-form/index.js +1 -1
- package/dist/patterns/marketplace-app-shell/index.js +1 -1
- package/dist/patterns/payment-automation-upsell/index.js +1 -1
- package/dist/patterns/registration-form/index.js +1 -1
- package/dist/patterns/signature-request/index.js +1 -1
- package/dist/tokens.css +1 -1
- package/package.json +9 -1
- package/dist/_chunks/ai-prompt-input-DSGSe4LH.js.map +0 -1
- package/dist/_chunks/alert-DjsJMGRE.js.map +0 -1
- package/dist/_chunks/anamnesis-summary-rows-BQ_EokKz.js.map +0 -1
- package/dist/_chunks/avatar-WZY3eGE7.js +0 -123
- package/dist/_chunks/avatar-WZY3eGE7.js.map +0 -1
- package/dist/_chunks/booking-tTVxKPQY.js.map +0 -1
- package/dist/_chunks/color-picker-BsggJovx.js.map +0 -1
- package/dist/_chunks/combobox-U5yfO6o0.js.map +0 -1
- package/dist/_chunks/contact-profile-card-C4-OCshj.js.map +0 -1
- package/dist/_chunks/dashboard-grid-B2MB7SRS.js +0 -1428
- package/dist/_chunks/dashboard-grid-B2MB7SRS.js.map +0 -1
- package/dist/_chunks/header-settings-BSH9Gk0J.js.map +0 -1
- package/dist/_chunks/map-view-BuVfJMEa.js.map +0 -1
- package/dist/_chunks/multi-select-CMaAQQgb.js.map +0 -1
- package/dist/_chunks/operator-hero-3_RG4Dkj.js.map +0 -1
- package/dist/_chunks/optical-prescription-CxfMsbxi.js.map +0 -1
- package/dist/_chunks/panel-header-BJkaUwnl.js +0 -128
- package/dist/_chunks/panel-header-BJkaUwnl.js.map +0 -1
- package/dist/_chunks/periodontal-risk-chart-CPy7CNFe.js.map +0 -1
- package/dist/_chunks/practice-profile-hero-Dfc0F60y.js +0 -193
- package/dist/_chunks/practice-profile-hero-Dfc0F60y.js.map +0 -1
- package/dist/_chunks/practice-results-BrUDDMXC.js.map +0 -1
- package/dist/_chunks/rating-C1Vrmpsi.js.map +0 -1
- package/dist/_chunks/reviews-panel-AvsVgtJu.js.map +0 -1
- package/dist/_chunks/select-k4gBdS8N.js.map +0 -1
- package/dist/_chunks/skeleton-B1KTdJ4N.js +0 -116
- package/dist/_chunks/skeleton-B1KTdJ4N.js.map +0 -1
- package/dist/_chunks/theme-toggle-Ctb77x6O.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard-grid-B2MB7SRS.js","sources":["../../node_modules/lucide-react/dist/esm/icons/move-diagonal-2.mjs","../../src/components/dashboard-grid/dashboard-grid.agent.ts","../../src/components/dashboard-grid/dashboard-grid-engine.ts","../../src/components/dashboard-grid/dashboard-grid.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M19 13v6h-6\", key: \"1hxl6d\" }],\n [\"path\", { d: \"M5 11V5h6\", key: \"12e2xe\" }],\n [\"path\", { d: \"m5 5 14 14\", key: \"11anup\" }]\n];\nconst MoveDiagonal2 = createLucideIcon(\"move-diagonal-2\", __iconNode);\n\nexport { __iconNode, MoveDiagonal2 as default };\n//# sourceMappingURL=move-diagonal-2.mjs.map\n","import type { AgentAdapter } from '../../agent/types';\nimport type { DashboardGridHandle } from './dashboard-grid';\n\nexport const dashboardGridAgent: AgentAdapter<DashboardGridHandle> = {\n id: 'dashboard-grid',\n // The board's whole purpose is in-place rearrangement of its widgets.\n // `scroll` is backed by reveal_widget (the catalogue's name heuristic\n // cannot see that and warns).\n capabilities: ['edit_inline', 'scroll'],\n state: {\n layout: {\n type: '{ id: string, x: number, y: number, w: number, h: number }[]',\n descriptionKey: 'ui.agent.dashboardGrid.state.layout',\n description:\n 'Current widget geometry in cell units — ids and rectangles only, no widget content.',\n read: (handle) => handle.getGridState().layout,\n },\n cols: {\n type: 'number',\n descriptionKey: 'ui.agent.dashboardGrid.state.cols',\n description: 'Logical column count of the board.',\n read: (handle) => handle.getGridState().cols,\n },\n editing: {\n type: 'boolean',\n descriptionKey: 'ui.agent.dashboardGrid.state.editing',\n description:\n 'Whether edit mode is on. Move/resize actions are refused while it is off — the host app owns the toggle.',\n read: (handle) => handle.getGridState().editing,\n },\n stacked: {\n type: 'boolean',\n descriptionKey: 'ui.agent.dashboardGrid.state.stacked',\n description:\n 'Whether the board is narrower than its stackBelow width and shows its widgets as one read-only column. Move/resize actions are unavailable while it is true, even in edit mode; the saved layout is unchanged.',\n read: (handle) => handle.getGridState().stacked,\n },\n selectedId: {\n type: 'string | null',\n descriptionKey: 'ui.agent.dashboardGrid.state.selectedId',\n description:\n 'The widget the host has marked (for example while its settings are open), or null. Set by the host, not by agents.',\n read: (handle) => handle.getGridState().selectedId,\n },\n },\n actions: {\n reveal_widget: {\n // Scrolls the view and rings a widget for a moment; changes nothing.\n safety: 'read',\n argsType: 'id',\n argsSchema: {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Widget id (see layout state).' },\n },\n required: ['id'],\n },\n returns: 'Promise<boolean> (revealed)',\n returnsSchema: {\n type: 'boolean',\n description:\n 'True once the widget is in view; false if it has not appeared within a second.',\n },\n idempotent: true,\n errors: [\n 'Unknown or not yet rendered widget id: waits up to a second, then resolves false.',\n ],\n descriptionKey: 'ui.agent.dashboardGrid.actions.revealWidget',\n description:\n 'Scroll a widget into view (its scrolling ancestor and the window) and highlight it briefly. Works in view and edit mode, and for a widget added a moment ago. Does not move focus.',\n invoke: (handle, args: { id: string }) => handle.revealWidget(args.id),\n },\n move_widget: {\n // Rearranging the board mutates user configuration — a write,\n // reversible by moving back.\n safety: 'write',\n argsType: 'id, x, y',\n argsSchema: {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Widget id (see layout state).' },\n x: {\n type: 'integer',\n minimum: 0,\n description: '0-based logical column.',\n },\n y: { type: 'integer', minimum: 0, description: '0-based row.' },\n },\n required: ['id', 'x', 'y'],\n },\n returns: 'boolean (accepted)',\n returnsSchema: {\n type: 'boolean',\n description:\n 'True when applied; false when edit mode is off, the board is stacked, or the id is unknown.',\n },\n idempotent: true,\n errors: [\n 'Unavailable while the board is stacked (state stacked is true): returns false and changes nothing.',\n 'Unavailable while edit mode is off: returns false.',\n 'Unknown widget id: returns false.',\n ],\n descriptionKey: 'ui.agent.dashboardGrid.actions.moveWidget',\n description:\n 'Move a widget to a cell. Out-of-bounds targets are clamped; colliding widgets are pushed down and the layout re-compacts. Refused while edit mode is off or the board is stacked.',\n invoke: (handle, args: { id: string; x: number; y: number }) =>\n handle.moveWidgetTo(args.id, args.x, args.y),\n },\n resize_widget: {\n safety: 'write',\n argsType: 'id, w, h',\n argsSchema: {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Widget id (see layout state).' },\n w: {\n type: 'integer',\n minimum: 1,\n description: 'Column span (≥ 1).',\n },\n h: { type: 'integer', minimum: 1, description: 'Row span (≥ 1).' },\n },\n required: ['id', 'w', 'h'],\n },\n returns: 'boolean (accepted)',\n returnsSchema: {\n type: 'boolean',\n description:\n 'True when applied; false when edit mode is off, the board is stacked, or the id is unknown.',\n },\n idempotent: true,\n errors: [\n 'Unavailable while the board is stacked (state stacked is true): returns false and changes nothing.',\n 'Unavailable while edit mode is off: returns false.',\n 'Unknown widget id: returns false.',\n ],\n descriptionKey: 'ui.agent.dashboardGrid.actions.resizeWidget',\n description:\n 'Resize a widget to a span. Clamped to the grid and the widget’s min/max; colliding widgets are pushed down. Refused while edit mode is off or the board is stacked.',\n invoke: (handle, args: { id: string; w: number; h: number }) =>\n handle.resizeWidgetTo(args.id, args.w, args.h),\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'dashboard-grid',\n description:\n 'Also carries data-stacked=\"true\" while the board shows one read-only column.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n item: {\n attr: 'data-widget-id',\n description: 'Each widget wrapper carries its layout id.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* DashboardGrid engine — pure layout math, no DOM. */\n/* */\n/* The grid is a column-count × unbounded-rows plane. Every widget is */\n/* an axis-aligned rectangle in cell units: `x` is the 0-based LOGICAL */\n/* column (inline-start based — CSS Grid flips it visually in RTL), */\n/* `y` the 0-based row, `w`/`h` the spans. All functions are pure and */\n/* return new arrays; the component layer owns state and DOM. */\n/* ------------------------------------------------------------------ */\n\nexport interface DashboardWidgetLayout {\n id: string;\n /** 0-based logical column of the inline-start edge. */\n x: number;\n /** 0-based row of the block-start edge. */\n y: number;\n /** Column span (≥ 1). */\n w: number;\n /** Row span (≥ 1). */\n h: number;\n minW?: number;\n minH?: number;\n maxW?: number;\n maxH?: number;\n}\n\nexport function collides(\n a: DashboardWidgetLayout,\n b: DashboardWidgetLayout,\n): boolean {\n return (\n a.x < b.x + b.w && b.x < a.x + a.w && a.y < b.y + b.h && b.y < a.y + a.h\n );\n}\n\n/** Clamp a rect to the grid bounds and its own min/max constraints. */\nexport function clampRect(\n item: DashboardWidgetLayout,\n cols: number,\n): DashboardWidgetLayout {\n const minW = Math.max(1, item.minW ?? 1);\n const minH = Math.max(1, item.minH ?? 1);\n const maxW = Math.min(cols, item.maxW ?? cols);\n const maxH = item.maxH ?? Number.POSITIVE_INFINITY;\n const w = Math.min(Math.max(item.w, minW), maxW);\n const h = Math.min(Math.max(item.h, minH), maxH);\n const x = Math.min(Math.max(0, item.x), cols - w);\n const y = Math.max(0, item.y);\n return { ...item, x, y, w, h };\n}\n\n/**\n * Whether `slot` is a hole: free of every other widget, and on each of its\n * rows some widget sits after it (towards inline-end). Free space at the end\n * of a row is not a hole; a blank gap before a widget is.\n */\nfunction isHole(\n slot: DashboardWidgetLayout,\n others: DashboardWidgetLayout[],\n): boolean {\n if (others.some((other) => collides(other, slot))) return false;\n for (let row = slot.y; row < slot.y + slot.h; row += 1) {\n const bounded = others.some(\n (other) =>\n other.x >= slot.x + slot.w && row >= other.y && row < other.y + other.h,\n );\n if (!bounded) return false;\n }\n return true;\n}\n\n/** Reading-order distance between two cells (row-major, `cols` per row). */\nfunction readingDistance(\n a: { x: number; y: number },\n b: { x: number; y: number },\n cols: number,\n): number {\n return Math.abs(a.y * cols + a.x - (b.y * cols + b.x));\n}\n\n/**\n * Resolve overlaps and apply upward gravity. The `activeId` rect (the one\n * being dragged/resized) keeps its exact position; every other widget makes\n * room for it, then rises as far as gravity allows. Deterministic: widgets\n * settle in reading order (y, then x).\n *\n * Reflow rules, so a board never keeps holes that only show once saved:\n * - A widget the active rect lands on first takes the nearest hole that fits\n * (reading order), or free space the moved rect left (`vacated`), between\n * its own height above and where a plain push down would put it.\n * - Otherwise it is pushed down. If it was pushed from its inline-start side,\n * it lines up under the start of the active rect through free cells, so it\n * does not leave a gap before itself. Pushed from above, it keeps its x.\n * - Last, during a gesture only, a widget may rise into a hole above it by\n * up to its own width sideways (never the active rect). Without an active\n * rect (a drop, a remove) only gravity runs, so a saved board is final:\n * compacting it again changes nothing.\n */\nexport function normalise(\n layout: DashboardWidgetLayout[],\n cols: number,\n activeId?: string,\n vacated?: DashboardWidgetLayout,\n): DashboardWidgetLayout[] {\n const items = layout.map((item) => clampRect(item, cols));\n const order = [...items].sort((a, b) => {\n if (a.id === activeId) return -1;\n if (b.id === activeId) return 1;\n return a.y - b.y || a.x - b.x;\n });\n const placed: DashboardWidgetLayout[] = [];\n const active = activeId\n ? items.find((item) => item.id === activeId)\n : undefined;\n const displaced = new Set<string>();\n for (const item of order) {\n if (item.id !== activeId) {\n // Swap-up: when the ACTIVE rect has moved onto this item, prefer\n // lifting the displaced item ABOVE the active rect (into the space\n // the active vacated) over pushing it down. Without this, moving a\n // widget downward past a same-column neighbour is impossible — the\n // neighbour keeps fleeing ahead and the drop compaction reverts the\n // whole gesture.\n if (active && collides(active, item)) {\n const above = { ...item, y: Math.max(0, active.y - item.h) };\n if (\n !collides(active, above) &&\n !placed.some((p) => p.id !== activeId && collides(p, above))\n ) {\n item.y = above.y;\n }\n }\n if (placed.some((p) => collides(p, item))) {\n displaced.add(item.id);\n // Everything else where it stands now: placed rects, and the ones\n // still to come at their current positions.\n const others = items.filter((other) => other.id !== item.id);\n let pushY = item.y;\n while (placed.some((p) => collides(p, { ...item, y: pushY }))) {\n pushY += 1;\n }\n let best: { x: number; y: number } | null = null;\n for (let y = Math.max(0, item.y - item.h); y <= pushY; y += 1) {\n for (let x = 0; x <= cols - item.w; x += 1) {\n const slot = { ...item, x, y };\n const free =\n isHole(slot, others) ||\n (vacated !== undefined &&\n collides(vacated, slot) &&\n !others.some((other) => collides(other, slot)));\n if (!free) continue;\n if (\n !best ||\n readingDistance({ x, y }, item, cols) <\n readingDistance(best, item, cols)\n ) {\n best = { x, y };\n }\n }\n }\n if (best) {\n item.x = best.x;\n item.y = best.y;\n } else {\n item.y = pushY;\n // Pushed from the inline-start side (a neighbour widened or moved\n // into it): line up under the start of that neighbour, through\n // free cells only, so the push leaves no gap before it.\n const fromStart =\n active !== undefined &&\n active.x < item.x &&\n item.x < active.x + active.w;\n const floor = active ? active.x : item.x;\n while (\n fromStart &&\n item.x > floor &&\n !others.some((other) => collides(other, { ...item, x: item.x - 1 }))\n ) {\n item.x -= 1;\n }\n }\n }\n while (placed.some((p) => collides(p, item))) {\n item.y += 1;\n }\n while (item.y > 0) {\n const test = { ...item, y: item.y - 1 };\n if (placed.some((p) => collides(p, test))) break;\n item.y -= 1;\n }\n }\n placed.push(item);\n }\n // Second pass, during a gesture: a widget rises into a hole above it, at\n // most its own width sideways, nearest first. Fills the gap a narrowed\n // widget leaves.\n const settled = active\n ? [...placed].sort((a, b) => a.y - b.y || a.x - b.x)\n : [];\n for (const item of settled) {\n if (item.id === activeId || displaced.has(item.id)) continue;\n const others = placed.filter((other) => other.id !== item.id);\n let target: { x: number; y: number } | null = null;\n for (let y = 0; y < item.y && !target; y += 1) {\n const xs = Array.from(\n { length: 2 * item.w + 1 },\n (_, i) => item.x - item.w + i,\n )\n .filter((x) => x >= 0 && x <= cols - item.w)\n .sort((a, b) => Math.abs(a - item.x) - Math.abs(b - item.x) || a - b);\n for (const x of xs) {\n if (isHole({ ...item, x, y }, others)) {\n target = { x, y };\n break;\n }\n }\n }\n if (target) {\n item.x = target.x;\n item.y = target.y;\n while (item.y > 0) {\n const test = { ...item, y: item.y - 1 };\n if (others.some((other) => collides(other, test))) break;\n item.y -= 1;\n }\n }\n }\n // Preserve the caller's array order (children order), only geometry moved.\n const byId = new Map(placed.map((p) => [p.id, p]));\n return layout.map((item) => byId.get(item.id) as DashboardWidgetLayout);\n}\n\n/** Move a widget to a target cell, resolving collisions around it. */\nexport function moveItem(\n layout: DashboardWidgetLayout[],\n id: string,\n x: number,\n y: number,\n cols: number,\n): DashboardWidgetLayout[] {\n const next = layout.map((item) =>\n item.id === id ? clampRect({ ...item, x, y }, cols) : item,\n );\n return normalise(\n next,\n cols,\n id,\n layout.find((item) => item.id === id),\n );\n}\n\n/** Resize a widget to a target span, resolving collisions around it. */\nexport function resizeItem(\n layout: DashboardWidgetLayout[],\n id: string,\n w: number,\n h: number,\n cols: number,\n): DashboardWidgetLayout[] {\n const next = layout.map((item) =>\n item.id === id\n ? // Resizing never moves the widget: the width clamps to the space\n // between its position and the grid edge (clampRect would slide it).\n // minW wins over the edge clamp so clampRect cannot re-raise w and\n // slide x as a side effect.\n clampRect(\n {\n ...item,\n w: Math.max(item.minW ?? 1, Math.min(w, cols - item.x)),\n h,\n },\n cols,\n )\n : item,\n );\n return normalise(next, cols, id);\n}\n\n/** First free slot (reading order) that fits a `w`×`h` rect. */\nexport function firstFit(\n layout: DashboardWidgetLayout[],\n cols: number,\n w: number,\n h: number,\n): { x: number; y: number } {\n const width = Math.min(Math.max(1, w), cols);\n const maxY = layout.reduce((m, item) => Math.max(m, item.y + item.h), 0);\n for (let y = 0; y <= maxY; y += 1) {\n for (let x = 0; x <= cols - width; x += 1) {\n const candidate: DashboardWidgetLayout = {\n id: '__candidate__',\n x,\n y,\n w: width,\n h,\n };\n if (!layout.some((item) => collides(item, candidate))) {\n return { x, y };\n }\n }\n }\n return { x: 0, y: maxY };\n}\n\n/** Total rows the layout occupies (for sizing the add tile / container). */\nexport function rowCount(layout: DashboardWidgetLayout[]): number {\n return layout.reduce((m, item) => Math.max(m, item.y + item.h), 0);\n}\n\n/* ------------------------------------------------------------------ */\n/* Stacked (narrow board) mode */\n/* ------------------------------------------------------------------ */\n\n/**\n * Extra inline size (px) a stacked board must reach, above `stackBelow`,\n * before it returns to the grid. Without the band a width hovering on the\n * threshold could flip the board back and forth: sub-pixel rounding, or a\n * page scrollbar (classic scrollbars are up to about 20 px) that appears\n * in one mode and disappears in the other because the two modes differ\n * in height.\n */\nexport const STACK_HYSTERESIS_PX = 24;\n\n/**\n * Whether the board shows one stacked column for a measured inline size.\n * Stacks below `stackBelow`; unstacks at `stackBelow + STACK_HYSTERESIS_PX`\n * or wider. An unusable threshold never stacks. A board with no measurable\n * box (`display: none`, a hidden tab) keeps its current mode.\n */\nexport function shouldStack(\n inlineSize: number,\n stackBelow: number | undefined,\n wasStacked: boolean,\n): boolean {\n if (\n stackBelow === undefined ||\n !Number.isFinite(stackBelow) ||\n stackBelow <= 0\n ) {\n return false;\n }\n if (!Number.isFinite(inlineSize) || inlineSize <= 0) return wasStacked;\n return wasStacked\n ? inlineSize < stackBelow + STACK_HYSTERESIS_PX\n : inlineSize < stackBelow;\n}\n\n/**\n * Reading order of the stacked column: row (`y`), then LOGICAL column\n * (`x`, so RTL keeps the same order), then the caller's `ids` order on a\n * tie. Ids without a layout entry keep their relative order at the end.\n */\nexport function stackOrder(\n ids: string[],\n layout: DashboardWidgetLayout[],\n): string[] {\n const byId = new Map(layout.map((item) => [item.id, item]));\n return ids\n .map((id, index) => ({ id, index, entry: byId.get(id) }))\n .sort((a, b) => {\n if (!a.entry || !b.entry) {\n if (a.entry) return -1;\n if (b.entry) return 1;\n return a.index - b.index;\n }\n return (\n a.entry.y - b.entry.y || a.entry.x - b.entry.x || a.index - b.index\n );\n })\n .map(({ id }) => id);\n}\n","/* ------------------------------------------------------------------ */\n/* DashboardGrid — user-configurable widget board. */\n/* */\n/* A CSS-Grid plane (N logical columns × unbounded rows) whose child */\n/* `DashboardGrid.Widget`s can be moved, resized, removed, and added */\n/* while `editing` is on. Layout state is `{id,x,y,w,h}[]` in cell */\n/* units — controlled via `layout`/`onLayoutChange` or uncontrolled */\n/* via `defaultLayout`. The collision/gravity engine lives in */\n/* `dashboard-grid-engine.ts` (pure, unit-tested). */\n/* */\n/* - Coordinates reach CSS through custom properties set with */\n/* `style.setProperty` — the sanctioned escape hatch for runtime */\n/* values (23-constraints §4; same pattern as `progress`). */\n/* - RTL is free: CSS Grid columns are logical, so column 1 sits at */\n/* the inline-start in both directions. Arrow keys are dir-aware. */\n/* - Move/resize are keyboard-first: each handle is a button — Enter/ */\n/* Space grabs, arrows step one cell, Enter drops, Escape cancels — */\n/* with a polite live region announcing every step. */\n/* - Opt-in `stackBelow`: when the board's own inline size (measured */\n/* with a ResizeObserver) is below it, widgets render as one */\n/* read-only column in reading order. The saved layout is untouched. */\n/* ------------------------------------------------------------------ */\n\nimport {\n Children,\n Fragment,\n cloneElement,\n createContext,\n forwardRef,\n isValidElement,\n useCallback,\n useContext,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent as ReactKeyboardEvent,\n type PointerEvent as ReactPointerEvent,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Ellipsis, GripVertical, MoveDiagonal2, Plus, X } from 'lucide-react';\nimport { IconButton } from '../button/icon-button';\nimport { DropdownMenu } from '../dropdown-menu';\nimport { Tooltip } from '../tooltip';\nimport { useIsomorphicLayoutEffect } from '../../hooks/use-isomorphic-layout-effect';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { dashboardGridAgent } from './dashboard-grid.agent';\nimport {\n clampRect,\n collides,\n firstFit,\n moveItem,\n normalise,\n resizeItem,\n rowCount,\n shouldStack,\n stackOrder,\n type DashboardWidgetLayout,\n} from './dashboard-grid-engine';\n\nexport type { DashboardWidgetLayout } from './dashboard-grid-engine';\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst dashboardGridVariants = cva(\n [\n 'ds:grid ds:w-full',\n // A stacking context: a grabbed widget's lift stays inside the board.\n 'ds:isolate',\n 'ds:gap-[var(--spacing-md)]',\n // Edit-mode surface: tint the whole plane, draw faint cell lines, and\n // reserve spare rows (--dg-min-block) so the AVAILABLE space reads at\n // a glance instead of the board ending at the last occupied row.\n 'ds:data-[editing=true]:rounded-[var(--radius-lg)] ds:data-[editing=true]:bg-muted/10',\n 'ds:data-[editing=true]:[background-image:var(--dg-grid-lines)]',\n 'ds:data-[editing=true]:min-h-[var(--dg-min-block)]',\n ].join(' '),\n {\n variants: {\n // Stacked: one full-width column; each row takes its widget's block\n // size. Focus can fall back to the board here (see the focus effect),\n // so it gets the kit's focus ring.\n stacked: {\n false: [\n 'ds:[grid-template-columns:repeat(var(--dg-cols),minmax(0,1fr))]',\n 'ds:[grid-auto-rows:var(--dg-row)]',\n ].join(' '),\n true: [\n 'ds:grid-cols-1 ds:auto-rows-auto',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-ring ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n ].join(' '),\n },\n },\n defaultVariants: { stacked: false },\n },\n);\n\nconst widgetVariants = cva(\n [\n 'ds:relative ds:min-h-0 ds:min-w-0 ds:overflow-hidden',\n // Its own stacking context: a sticky or raised layer inside a widget\n // can never paint over the page's chrome (a sticky toolbar, say).\n 'ds:isolate',\n // Header actions fold into one menu below a set widget width.\n 'ds:@container/widget',\n // Mirror of Card variant=\"elevated\" so widgets read as kit cards.\n 'ds:rounded-[var(--radius-lg)] ds:bg-[var(--card)] ds:text-[var(--card-foreground)]',\n 'ds:[:where(&)]:border-[length:var(--surface-border-width,var(--border-width-sm))] ds:border-[color:var(--card-border)] ds:shadow-[var(--shadow-card)]',\n // Grabbed feedback (keyboard or pointer drag in flight).\n 'ds:data-[grabbed=true]:ring-[length:var(--focus-ring-width)] ds:data-[grabbed=true]:ring-ring ds:data-[grabbed=true]:z-10',\n // Selected (and briefly revealed): an inset edge in --primary, the\n // kit's selected colour, so it reads apart from focus and from a grab.\n 'ds:data-[selected=true]:ring-[length:var(--border-width-md)] ds:data-[selected=true]:ring-inset ds:data-[selected=true]:ring-[color:var(--primary)]',\n 'ds:data-[revealed=true]:ring-[length:var(--border-width-md)] ds:data-[revealed=true]:ring-inset ds:data-[revealed=true]:ring-[color:var(--primary)]',\n 'ds:forced-colors:data-[selected=true]:outline-[length:var(--border-width-md)] ds:forced-colors:data-[selected=true]:outline-solid ds:forced-colors:data-[selected=true]:outline-[Highlight]',\n // Only reachable when stacking removes the focused edit control: the\n // widget then takes focus itself (tabindex -1, set at that moment).\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-ring ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n ].join(' '),\n {\n variants: {\n stacked: {\n false: [\n 'ds:[grid-column-start:var(--dg-x)] ds:[grid-column-end:span_var(--dg-w)]',\n 'ds:[grid-row-start:var(--dg-y)] ds:[grid-row-end:span_var(--dg-h)]',\n ].join(' '),\n true: 'ds:col-span-full ds:row-auto',\n },\n stackedHeight: { grid: '', content: '' },\n },\n compoundVariants: [\n { stacked: false, class: 'ds:flex ds:flex-col' },\n // At least the block size the widget has in the grid (h rows plus the\n // h - 1 gaps). A minimum, not a fixed size: at 200% zoom the widget\n // grows instead of clipping its content (WCAG 1.4.4, 1.4.10).\n {\n stacked: true,\n stackedHeight: 'grid',\n class: [\n 'ds:flex ds:flex-col',\n 'ds:[min-block-size:calc(var(--dg-h)*var(--dg-row)_+_(var(--dg-h)_-_1)*var(--spacing-md))]',\n ].join(' '),\n },\n // As tall as the content, or minStackedHeight. A grid, not a flex\n // column, so the body row is a definite box a 100% chart can fill.\n {\n stacked: true,\n stackedHeight: 'content',\n class: [\n 'ds:grid ds:grid-cols-[minmax(0,1fr)] ds:grid-rows-[auto_1fr]',\n 'ds:[min-block-size:var(--dg-min-stacked)]',\n ].join(' '),\n },\n ],\n defaultVariants: { stacked: false, stackedHeight: 'grid' },\n },\n);\n\nconst widgetBodyVariants = cva(\n 'ds:ps-[var(--spacing-md)] ds:pt-[var(--spacing-xs)]',\n {\n variants: {\n // `box`: fill the widget's block size and clip to it. `content`: take\n // the content's own height (the content-height stack), never a box.\n fit: {\n box: 'ds:min-h-0 ds:flex-1 ds:overflow-hidden',\n content: 'ds:min-w-0',\n },\n // Editing: clear of the resize grip's whole hit area, a\n // --min-target-size square in the corner. Block-end takes the full\n // size, keeping the width narrow widgets need; inline-end the glyph.\n editing: {\n false: 'ds:pe-[var(--spacing-md)] ds:pb-[var(--spacing-md)]',\n true: [\n 'ds:pe-[calc(var(--spacing-lg)_+_var(--spacing-2xs))]',\n 'ds:pb-[var(--min-target-size)]',\n ].join(' '),\n },\n },\n defaultVariants: { fit: 'box', editing: false },\n },\n);\n\n// The resize grip: a small corner glyph, not a button sitting on the\n// content. Its ::before is the hit area, --min-target-size square, anchored\n// at the widget's corner and reaching inward, so the card never clips it.\nconst resizeGripVariants = cva(\n [\n 'ds:absolute ds:bottom-[var(--spacing-2xs)] ds:end-[var(--spacing-2xs)]',\n 'ds:inline-flex ds:size-[var(--spacing-lg)] ds:items-center ds:justify-center',\n 'ds:rounded-[var(--radius-sm)] ds:text-[var(--muted-foreground)] ds:touch-none',\n 'ds:cursor-nwse-resize ds:rtl:cursor-nesw-resize',\n 'ds:hover:bg-muted/20 ds:hover:text-[var(--foreground)]',\n 'ds:aria-pressed:bg-muted/20 ds:aria-pressed:text-[var(--foreground)]',\n 'ds:[&_svg]:size-3.5 ds:rtl:[&_svg]:-scale-x-100',\n \"ds:before:absolute ds:before:content-['']\",\n 'ds:before:bottom-[calc(-1*var(--spacing-2xs))] ds:before:end-[calc(-1*var(--spacing-2xs))]',\n 'ds:before:size-[var(--min-target-size)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-ring ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n ].join(' '),\n);\n\n// Below this widget inline size the header's actions and remove button\n// fold into one \"More actions\" menu (a 3-column widget on a 1440 px window).\n// The gap is the target size less the 32 px button, so neighbouring hit\n// areas meet but never overlap (Settings never covers Remove).\nconst headerFoldVariants = cva(\n 'ds:items-center ds:gap-[calc(var(--min-target-size)_-_var(--spacing-xl))]',\n {\n variants: {\n when: {\n always: 'ds:flex',\n wide: 'ds:flex ds:@max-[300px]/widget:hidden',\n narrow: 'ds:hidden ds:@max-[300px]/widget:flex',\n },\n },\n defaultVariants: { when: 'always' },\n },\n);\n\n// Header icon buttons keep their full --min-target-size hit area on every\n// screen (IconButton drops it from `sm:` up). Keyed on the button's own\n// marker, so it outranks that rule whatever order the CSS is emitted in.\nconst HEADER_BUTTON_CLASSES =\n 'ds:bg-[var(--card)] ds:data-[component=icon-button]:sm:before:block';\n\n// The header row. In edit mode the whole row (outside its buttons) is a\n// drag surface, so it never starts a text selection or a touch callout.\nconst widgetHeaderVariants = cva(\n 'ds:flex ds:items-center ds:gap-[var(--spacing-xs)] ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:pt-[var(--spacing-sm)]',\n {\n variants: {\n editing: {\n false: '',\n true: 'ds:cursor-grab ds:select-none ds:[-webkit-touch-callout:none]',\n },\n },\n defaultVariants: { editing: false },\n },\n);\n\n// One line, cut with an ellipsis. Focusable only while cut (see the widget),\n// so it carries the kit's focus ring for that case.\nconst widgetTitleVariants = cva(\n [\n 'ds:m-0 ds:min-w-0 ds:flex-1 ds:truncate ds:text-sm ds:font-medium',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-ring ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n ].join(' '),\n);\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\n// `stacked` is measured, never a prop: keep it out of the public props.\nexport interface DashboardGridProps extends Omit<\n VariantProps<typeof dashboardGridVariants>,\n 'stacked'\n> {\n /** Accessible name for the board region. Required. */\n 'aria-label': string;\n /** Opaque instance id — emitted as `data-component-id` for the agent registry. */\n id?: string;\n /** Logical column count. Defaults to 12. */\n cols?: number;\n /** Row height in px (one `h` unit). Defaults to 96. */\n rowHeight?: number;\n /** Controlled layout. Entries are matched to widgets by `id`. */\n layout?: DashboardWidgetLayout[];\n /** Uncontrolled initial layout. */\n defaultLayout?: DashboardWidgetLayout[];\n /**\n * Fired after every committed change — move, resize, remove pruning, and\n * the auto-placement of widgets that had no layout entry. Persist this.\n */\n onLayoutChange?: (next: DashboardWidgetLayout[]) => void;\n /** Edit mode: shows move/resize/remove chrome and the add tile. */\n editing?: boolean;\n /**\n * Called when the user activates a widget's remove button. The kit\n * commits the entry removal (one `onLayoutChange`) and manages focus;\n * the consumer unmounts the child. Omit to hide the remove button.\n */\n onRemoveWidget?: (id: string) => void;\n /**\n * Called when the user activates the add tile (rendered in edit mode\n * only when this is provided). The consumer appends a new\n * `DashboardGrid.Widget`; it is auto-placed first-fit and reported via\n * `onLayoutChange`.\n */\n onRequestAdd?: () => void;\n /**\n * Opt-in narrow mode. When the board's OWN inline size (px, measured with\n * a ResizeObserver, not the viewport) is below this value, the widgets\n * render as one full-width, read-only column in reading order (`y`, then\n * logical `x`), each at least its grid height (see `stackedHeight`). No\n * move/resize/remove chrome or add tile shows, even while `editing` is\n * on, and `onLayoutChange` never fires because of stacking: the saved\n * layout is untouched and the grid returns exactly once the board is at\n * least `stackBelow + 24` px wide (the 24 px band stops a width hovering\n * on the threshold, or a page scrollbar, from flipping the board). Unset:\n * the board never stacks.\n *\n * Give the board a container whose width does not depend on its content\n * (normal block flow, or a stretched flex/grid item). In a shrink-to-fit\n * host the narrower stacked column can keep the board stacked.\n * Switching between unset and set at runtime remounts the widgets.\n *\n * SSR: the server render and the first client render show the grid; the\n * board measures itself in a layout effect, before the first client\n * paint. A server-rendered page shows the grid until hydration.\n */\n stackBelow?: number;\n /**\n * Fired when the board enters (`true`) or leaves (`false`) the stacked\n * column, before that mode is painted, so the host can hide its own\n * customise control. Not fired for the initial unstacked state, nor on\n * unmount.\n */\n onStackedChange?: (stacked: boolean) => void;\n /**\n * Marks one widget, for example while its settings are open: it gets the\n * inset --primary edge and `aria-current=\"true\"`. Unset, none is marked.\n */\n selectedId?: string;\n /**\n * Block size of each widget while the board is stacked (`stackBelow`).\n * `'grid'` (the default, unchanged) keeps at least the widget's grid\n * height, so a widget showing one figure leaves empty space below it on a\n * phone. `'content'` makes each stacked widget as tall as its content.\n * A chart that fills its container has no height of its own and would\n * collapse: give its widget a `minStackedHeight`. The grid itself is\n * unchanged either way.\n */\n stackedHeight?: 'grid' | 'content';\n /**\n * Opt-in heading level for every widget title. Unset (the default), a\n * title is plain text, as before. Set it to one level below the heading\n * that introduces the board, so screen-reader users can jump between\n * widgets by heading. A title cut short by the widget's width is\n * focusable and shows the full title in a Tooltip either way.\n */\n widgetHeadingLevel?: 2 | 3 | 4 | 5 | 6;\n /** `DashboardGrid.Widget` children. */\n children: ReactNode;\n className?: string;\n}\n\nexport interface DashboardGridHandle {\n /**\n * Move a widget to a cell. False when not editing, while stacked, or\n * when the id is unknown.\n */\n moveWidgetTo: (id: string, x: number, y: number) => boolean;\n /**\n * Resize a widget to a span. False when not editing, while stacked, or\n * when the id is unknown.\n */\n resizeWidgetTo: (id: string, w: number, h: number) => boolean;\n /**\n * Scroll a widget into view (its nearest scrolling ancestor and the\n * window) and highlight it briefly. Safe to call in the same tick that\n * adds the widget: it waits until the widget is laid out. Resolves true\n * once revealed, false if the widget has not appeared within a second.\n */\n revealWidget: (id: string) => Promise<boolean>;\n /** Current geometry + mode. */\n getGridState: () => {\n cols: number;\n /** The `editing` prop as the host set it. */\n editing: boolean;\n /**\n * True while the board is narrower than `stackBelow` and shows one\n * read-only column. Editing is unavailable until it is false again.\n */\n stacked: boolean;\n /** The saved grid layout; stacking never changes it. */\n layout: DashboardWidgetLayout[];\n /** The `selectedId` prop, or null. */\n selectedId: string | null;\n };\n}\n\n/** A header action that folds into the \"More actions\" menu when narrow. */\nexport interface DashboardWidgetAction {\n /** Stable key. */\n id: string;\n /** Accessible name of the button, and the menu item's text. Translated. */\n label: string;\n /** Glyph for the icon button shown on wide widgets. */\n icon: ReactNode;\n onSelect: () => void;\n}\n\nexport interface DashboardGridWidgetProps {\n /** Stable widget id — matches a `layout` entry. */\n id: string;\n /** Visible widget title (consumer-translated). */\n title: string;\n /** Cell span used when the widget has no layout entry yet. */\n defaultW?: number;\n defaultH?: number;\n /**\n * Smallest span (columns, rows) the widget can be resized to. Applied on\n * render only: the board never writes `minW` / `minH` into the layout it\n * reports through `onLayoutChange`, so a saved layout stays constraint\n * free. A saved entry narrower than this renders at the minimum and is\n * reported at that size on the next change.\n */\n minW?: number;\n minH?: number;\n /**\n * Minimum block size in px while the board is stacked with\n * `stackedHeight=\"content\"`; ignored otherwise. A chart that fills its\n * container needs it, or it collapses to nothing: the body fills this\n * height, less the title row. Content taller than it still grows.\n */\n minStackedHeight?: number;\n /**\n * Header actions such as a widget's settings, in view and edit mode. Each\n * is an icon button; on a narrow widget (under 300 px) they fold, with\n * the remove button, into one \"More actions\" menu so the title keeps its\n * room. Prefer this over `actionsSlot`.\n */\n actions?: DashboardWidgetAction[];\n /** Extra header content, always shown as given (never folded). */\n actionsSlot?: ReactNode;\n children?: ReactNode;\n}\n\n/* ------------------------------------------------------------------ */\n/* Context */\n/* ------------------------------------------------------------------ */\n\ninterface GrabState {\n kind: 'move' | 'resize';\n id: string;\n via: 'pointer' | 'keyboard';\n}\n\ninterface DashboardGridContextValue {\n /** Edit chrome is live: `editing` is on and the board is not stacked. */\n editing: boolean;\n stacked: boolean;\n stackedHeight: 'grid' | 'content';\n selectedId?: string;\n revealedId: string | null;\n headingLevel?: 2 | 3 | 4 | 5 | 6;\n layoutById: Map<string, DashboardWidgetLayout>;\n grab: GrabState | null;\n canRemove: boolean;\n requestRemove: (id: string) => void;\n startKeyboardGrab: (kind: 'move' | 'resize', id: string) => void;\n keyboardStep: (\n event: ReactKeyboardEvent<HTMLButtonElement>,\n id: string,\n ) => void;\n startPointerGrab: (\n kind: 'move' | 'resize',\n id: string,\n event: ReactPointerEvent<HTMLButtonElement>,\n ) => void;\n startHeaderPress: (id: string, event: ReactPointerEvent<HTMLElement>) => void;\n}\n\nconst DashboardGridContext = createContext<DashboardGridContextValue | null>(\n null,\n);\n\ninterface WidgetMeta {\n defaultW: number;\n defaultH: number;\n minW?: number;\n minH?: number;\n}\n\n/** A usable span (a whole number of cells, at least 1), else undefined. */\nfunction positiveSpan(value: number | undefined): number | undefined {\n return value !== undefined && Number.isFinite(value) && value >= 1\n ? Math.floor(value)\n : undefined;\n}\n\n/** Walk widget children, descending into fragments (a common JSX shape). */\nfunction forEachWidgetChild(\n children: ReactNode,\n fn: (child: ReactElement<DashboardGridWidgetProps>) => void,\n): void {\n Children.forEach(children, (child) => {\n if (!isValidElement(child)) return;\n if (child.type === Fragment) {\n forEachWidgetChild(\n (child.props as { children?: ReactNode }).children,\n fn,\n );\n return;\n }\n fn(child as ReactElement<DashboardGridWidgetProps>);\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Widget */\n/* ------------------------------------------------------------------ */\n\nfunction DashboardGridWidget({\n id,\n title,\n minStackedHeight,\n actions,\n actionsSlot,\n children,\n}: DashboardGridWidgetProps) {\n const { t } = useTranslation('ui');\n const ctx = useContext(DashboardGridContext);\n const wrapperRef = useRef<HTMLDivElement>(null);\n // The More actions item picked, run when the menu has closed.\n const pickedRef = useRef<DashboardWidgetAction | null>(null);\n\n if (import.meta.env.DEV && !ctx) {\n console.warn(\n 'DashboardGrid.Widget: must be rendered inside a <DashboardGrid>.',\n );\n }\n\n const entry = ctx?.layoutById.get(id);\n\n // The title is one line. When the widget cuts it short, it becomes a tab\n // stop with a Tooltip carrying the full title. The Tooltip always wraps it,\n // so the node never remounts (and never drops focus) as the width changes.\n const [titleNode, setTitleNode] = useState<HTMLElement | null>(null);\n const [titleCut, setTitleCut] = useState(false);\n const [titleFocused, setTitleFocused] = useState(false);\n const [tipOpen, setTipOpen] = useState(false);\n useEffect(() => {\n if (!titleNode) return undefined;\n const measure = () =>\n setTitleCut(titleNode.scrollWidth > titleNode.clientWidth);\n measure();\n // A web font that loads late changes the text width, not the box.\n const fonts = typeof document !== 'undefined' ? document.fonts : undefined;\n fonts?.addEventListener('loadingdone', measure);\n const observer =\n typeof ResizeObserver === 'undefined'\n ? undefined\n : new ResizeObserver(measure);\n observer?.observe(titleNode);\n return () => {\n fonts?.removeEventListener('loadingdone', measure);\n observer?.disconnect();\n };\n }, [titleNode, title]);\n // A Tooltip asked to open while the title fits stays shut: Radix would\n // not report the close, so a later cut would open it unprompted.\n useEffect(() => {\n if (!titleCut) setTipOpen(false);\n }, [titleCut]);\n\n // Sanctioned escape hatch for runtime-computed values (23-constraints §4):\n // cell coordinates land on CSS custom properties via style.setProperty.\n useIsomorphicLayoutEffect(() => {\n const node = wrapperRef.current;\n if (!node || !entry) return;\n node.style.setProperty('--dg-x', String(entry.x + 1));\n node.style.setProperty('--dg-y', String(entry.y + 1));\n node.style.setProperty('--dg-w', String(entry.w));\n node.style.setProperty('--dg-h', String(entry.h));\n // Set on every widget, `auto` when unset, so it is never inherited.\n node.style.setProperty(\n '--dg-min-stacked',\n minStackedHeight !== undefined &&\n Number.isFinite(minStackedHeight) &&\n minStackedHeight > 0\n ? `${minStackedHeight}px`\n : 'auto',\n );\n }, [entry?.x, entry?.y, entry?.w, entry?.h, entry, minStackedHeight]);\n\n if (!ctx || !entry) return null;\n\n const grabbed = ctx.grab?.id === id;\n const editing = ctx.editing;\n // The consumer's actions, then remove (edit mode). Two or more fold into\n // one menu on a narrow widget; a single one stays a button.\n const headerButtons: DashboardWidgetAction[] = [\n ...(actions ?? []),\n ...(editing && ctx.canRemove\n ? [\n {\n id: REMOVE_ACTION_ID,\n label: t('dashboardGrid.remove', { title }),\n icon: <X />,\n onSelect: () => ctx.requestRemove(id),\n },\n ]\n : []),\n ];\n const foldable = headerButtons.length > 1;\n const TitleTag = ctx.headingLevel\n ? (`h${ctx.headingLevel}` as const)\n : 'span';\n\n return (\n <div\n ref={wrapperRef}\n role=\"listitem\"\n aria-label={title}\n data-component=\"dashboard-grid-widget\"\n data-widget-id={id}\n data-grabbed={grabbed || undefined}\n data-selected={ctx.selectedId === id || undefined}\n data-revealed={ctx.revealedId === id || undefined}\n aria-current={ctx.selectedId === id ? 'true' : undefined}\n className={widgetVariants({\n stacked: ctx.stacked,\n stackedHeight: ctx.stackedHeight,\n })}\n >\n <div\n className={widgetHeaderVariants({ editing })}\n onPointerDown={\n editing ? (event) => ctx.startHeaderPress(id, event) : undefined\n }\n >\n {editing ? (\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n type=\"button\"\n icon={<GripVertical />}\n aria-label={t('dashboardGrid.move', { title })}\n aria-pressed={grabbed && ctx.grab?.kind === 'move'}\n className={`ds:cursor-grab ds:touch-none ${HEADER_BUTTON_CLASSES}`}\n onPointerDown={(event) => ctx.startPointerGrab('move', id, event)}\n onKeyDown={(event) => ctx.keyboardStep(event, id)}\n onClick={() => ctx.startKeyboardGrab('move', id)}\n />\n ) : null}\n <Tooltip\n label={title}\n open={titleCut && tipOpen}\n onOpenChange={(next) => setTipOpen(next && titleCut)}\n >\n <TitleTag\n ref={setTitleNode}\n // A tab stop while cut short, so keyboard users reach the full\n // title, and while focused, so focus never drops to <body>.\n tabIndex={titleCut || titleFocused ? 0 : undefined}\n data-dashboard-grid-title=\"\"\n onFocus={() => setTitleFocused(true)}\n onBlur={() => setTitleFocused(false)}\n className={widgetTitleVariants()}\n >\n {title}\n </TitleTag>\n </Tooltip>\n {actionsSlot}\n {headerButtons.length > 0 ? (\n <div\n className={headerFoldVariants({\n when: foldable ? 'wide' : 'always',\n })}\n >\n {headerButtons.map((action) => (\n <IconButton\n key={action.id}\n size=\"sm\"\n intent=\"outline\"\n type=\"button\"\n icon={action.icon}\n className={HEADER_BUTTON_CLASSES}\n aria-label={action.label}\n onClick={action.onSelect}\n />\n ))}\n </div>\n ) : null}\n {foldable ? (\n <div className={headerFoldVariants({ when: 'narrow' })}>\n <DropdownMenu.Root modal={false}>\n <DropdownMenu.Trigger asChild>\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n type=\"button\"\n icon={<Ellipsis />}\n className={HEADER_BUTTON_CLASSES}\n aria-label={t('dashboardGrid.moreActions', { title })}\n />\n </DropdownMenu.Trigger>\n <DropdownMenu.Content\n align=\"end\"\n // The pick runs once the menu has closed, so focus it moves\n // stays put. Focus still in place: back to the trigger.\n onCloseAutoFocus={(event) => {\n const action = pickedRef.current;\n pickedRef.current = null;\n if (!action) return;\n const before = document.activeElement;\n action.onSelect();\n if (\n action.id === REMOVE_ACTION_ID ||\n document.activeElement !== before\n ) {\n event.preventDefault();\n }\n }}\n >\n {headerButtons.map((action) => (\n <DropdownMenu.Item\n key={action.id}\n startIcon={action.icon}\n onSelect={() => {\n pickedRef.current = action;\n }}\n >\n {action.label}\n </DropdownMenu.Item>\n ))}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n </div>\n ) : null}\n </div>\n <div\n className={widgetBodyVariants({\n fit:\n ctx.stacked && ctx.stackedHeight === 'content' ? 'content' : 'box',\n editing,\n })}\n >\n {children}\n </div>\n {editing ? (\n <button\n type=\"button\"\n aria-label={t('dashboardGrid.resize', { title })}\n aria-pressed={grabbed && ctx.grab?.kind === 'resize'}\n className={resizeGripVariants()}\n onPointerDown={(event) => ctx.startPointerGrab('resize', id, event)}\n onKeyDown={(event) => ctx.keyboardStep(event, id)}\n onClick={() => ctx.startKeyboardGrab('resize', id)}\n >\n <MoveDiagonal2 aria-hidden=\"true\" />\n </button>\n ) : null}\n </div>\n );\n}\nDashboardGridWidget.displayName = 'DashboardGrid.Widget';\n\n/* ------------------------------------------------------------------ */\n/* DashboardGrid */\n/* ------------------------------------------------------------------ */\n\ninterface PointerDragState {\n kind: 'move' | 'resize';\n id: string;\n pointerId: number;\n /** Pointer position relative to the grid's box at the start. Measuring\n against the box (not the viewport) makes any scroll since then count. */\n startGridX: number;\n startGridY: number;\n lastClientX: number;\n lastClientY: number;\n origin: DashboardWidgetLayout;\n colStride: number;\n rowStride: number;\n isRtl: boolean;\n /** Started on a grip button, whose trailing click must be swallowed. */\n fromHandle: boolean;\n /** Where the press began, and whether it has since travelled far enough\n to count as a drag. Auto-scroll waits for that. */\n pressX: number;\n pressY: number;\n travelled: boolean;\n}\n\n/** A press on a widget header that becomes a move once it really drags. */\ninterface HeaderPress {\n id: string;\n pointerId: number;\n pointerType: string;\n startClientX: number;\n startClientY: number;\n surface: HTMLElement;\n holdTimer: ReturnType<typeof setTimeout> | null;\n cleanup: () => void;\n}\n\n/** A reveal waits this long (ms) for its widget, then highlights it this long. */\nconst REVEAL_WAIT_MS = 1000;\nconst REVEAL_HIGHLIGHT_MS = 1600;\n\n/** Header content a press on which never starts a drag. */\nconst HEADER_PRESS_IGNORES = [\n 'button',\n 'a',\n 'input',\n 'select',\n 'textarea',\n 'label',\n 'summary',\n '[contenteditable]:not([contenteditable=\"false\"])',\n '[role=\"button\"]',\n '[role=\"menuitem\"]',\n '[tabindex]:not([data-dashboard-grid-title])',\n].join(', ');\n\n/** The remove entry's id among a widget's header actions. */\nconst REMOVE_ACTION_ID = '__remove__';\n\n/** px a mouse or pen must travel before a header press becomes a drag. */\nconst DRAG_THRESHOLD_PX = 4;\n/** Touch: hold still this long (ms) to pick a widget up by its header. */\nconst TOUCH_HOLD_MS = 400;\n/** Touch: moving further than this (px) before the hold ends is a scroll. */\nconst TOUCH_SLOP_PX = 8;\n/** Auto-scroll: the edge band (px) and the top speed (px per frame). */\nconst AUTO_SCROLL_EDGE_PX = 48;\nconst AUTO_SCROLL_MAX_PX = 18;\n\n/** The nearest ancestor that scrolls on each axis; null means the window. */\nfunction scrollingAncestors(node: HTMLElement): {\n x: HTMLElement | null;\n y: HTMLElement | null;\n} {\n const found: { x: HTMLElement | null; y: HTMLElement | null } = {\n x: null,\n y: null,\n };\n const scrolls = (value: string) =>\n value === 'auto' || value === 'scroll' || value === 'overlay';\n for (\n let current = node.parentElement;\n current &&\n current !== document.body &&\n current !== document.documentElement &&\n !(found.x && found.y);\n current = current.parentElement\n ) {\n const styles = window.getComputedStyle(current);\n if (\n !found.y &&\n scrolls(styles.overflowY) &&\n current.scrollHeight > current.clientHeight\n ) {\n found.y = current;\n }\n if (\n !found.x &&\n scrolls(styles.overflowX) &&\n current.scrollWidth > current.clientWidth\n ) {\n found.x = current;\n }\n }\n return found;\n}\n\n/**\n * The draft for a move or resize target, measured from the grab-time base.\n * A target that is the widget's own place (a press, jitter under half a\n * cell) yields the base itself, so a release with no change rewrites\n * nothing. A widget goes at most two rows past the board's last row.\n */\nfunction gestureDraft(\n base: DashboardWidgetLayout[],\n kind: 'move' | 'resize',\n id: string,\n inline: number,\n block: number,\n cols: number,\n capped = true,\n): DashboardWidgetLayout[] {\n const start = base.find((item) => item.id === id);\n if (!start) return base;\n const bottom = capped ? rowCount(base) + 2 : Number.POSITIVE_INFINITY;\n const next =\n kind === 'move'\n ? moveItem(base, id, inline, Math.min(block, bottom - start.h), cols)\n : resizeItem(base, id, inline, Math.min(block, bottom - start.y), cols);\n const moved = next.find((item) => item.id === id);\n const unchanged =\n moved !== undefined &&\n moved.x === start.x &&\n moved.y === start.y &&\n moved.w === start.w &&\n moved.h === start.h;\n return unchanged ? base : next;\n}\n\n/** Signed speed (px per frame) for a pointer `distance` px inside an edge. */\nfunction edgeSpeed(distance: number): number {\n if (distance >= AUTO_SCROLL_EDGE_PX) return 0;\n const depth =\n (AUTO_SCROLL_EDGE_PX - Math.max(0, distance)) / AUTO_SCROLL_EDGE_PX;\n return Math.ceil(depth * AUTO_SCROLL_MAX_PX);\n}\n\nconst DashboardGridRoot = forwardRef<DashboardGridHandle, DashboardGridProps>(\n (\n {\n 'aria-label': ariaLabel,\n id,\n cols = 12,\n rowHeight = 96,\n layout: layoutProp,\n defaultLayout,\n onLayoutChange,\n editing = false,\n onRemoveWidget,\n onRequestAdd,\n stackBelow,\n onStackedChange,\n stackedHeight = 'grid',\n selectedId,\n widgetHeadingLevel,\n children,\n className,\n },\n ref,\n ) => {\n const { t } = useTranslation('ui');\n const rootRef = useRef<HTMLDivElement>(null);\n const gridRef = useRef<HTMLDivElement>(null);\n\n /* ---- stacked (narrow board) mode -------------------------------- */\n /* Starts unstacked so the server and first client render agree; the */\n /* layout effect below measures before the first client paint. The */\n /* measured box is the board root: in normal flow a block box takes */\n /* its inline size from its container, not from the widgets, so */\n /* stacking does not feed back into the measurement. The hysteresis */\n /* band in `shouldStack` absorbs rounding and a page scrollbar; a */\n /* shrink-to-fit host is documented as unsupported on the prop. */\n const [stacked, setStacked] = useState(false);\n const stackedRef = useRef(false);\n stackedRef.current = stacked;\n // The focused element at the moment the mode flips, so focus can stay\n // in its widget if stacking unmounts it (edit chrome).\n const pendingFocusRef = useRef<{\n element: HTMLElement;\n widgetId: string | null;\n } | null>(null);\n\n const switchStacked = useCallback((next: boolean) => {\n if (next === stackedRef.current) return;\n const root = rootRef.current;\n const focused =\n typeof document !== 'undefined' ? document.activeElement : null;\n pendingFocusRef.current =\n root && focused instanceof HTMLElement && root.contains(focused)\n ? {\n element: focused,\n widgetId:\n focused\n .closest<HTMLElement>('[data-widget-id]')\n ?.getAttribute('data-widget-id') ?? null,\n }\n : null;\n stackedRef.current = next;\n setStacked(next);\n }, []);\n\n useIsomorphicLayoutEffect(() => {\n const node = rootRef.current;\n if (!node) return undefined;\n if (stackBelow === undefined) {\n switchStacked(false);\n return undefined;\n }\n switchStacked(\n shouldStack(node.offsetWidth, stackBelow, stackedRef.current),\n );\n if (typeof ResizeObserver === 'undefined') return undefined;\n const observer = new ResizeObserver((entries) => {\n const entry = entries[entries.length - 1];\n if (!entry) return;\n const inlineSize =\n entry.borderBoxSize?.[0]?.inlineSize ?? entry.contentRect.width;\n switchStacked(shouldStack(inlineSize, stackBelow, stackedRef.current));\n });\n observer.observe(node);\n return () => observer.disconnect();\n }, [stackBelow, switchStacked]);\n\n // Edit chrome is live only while editing AND not stacked.\n const editable = editing && !stacked;\n\n if (import.meta.env.DEV && !ariaLabel) {\n console.warn(\n 'DashboardGrid: `aria-label` is required for accessibility.',\n );\n }\n\n /* ---- child ids in render order --------------------------------- */\n /* Fragments are flattened: `<>{widgets}</>` is a normal consumer */\n /* shape and must contribute its widgets, not an id-less wrapper. */\n const childIds = useMemo(() => {\n const ids: string[] = [];\n forEachWidgetChild(children, (child) => {\n if (child.props.id) ids.push(child.props.id);\n });\n return ids;\n }, [children]);\n const childMeta = useMemo(() => {\n const meta = new Map<string, WidgetMeta>();\n forEachWidgetChild(children, (child) => {\n if (child.props.id) {\n meta.set(child.props.id, {\n defaultW: child.props.defaultW ?? 4,\n defaultH: child.props.defaultH ?? 2,\n minW: positiveSpan(child.props.minW),\n minH: positiveSpan(child.props.minH),\n });\n }\n });\n return meta;\n }, [children]);\n\n /* ---- controlled / uncontrolled layout -------------------------- */\n const [internalLayout, setInternalLayout] = useState<\n DashboardWidgetLayout[]\n >(() => defaultLayout ?? []);\n const committed = layoutProp ?? internalLayout;\n const committedRef = useRef(committed);\n committedRef.current = committed;\n\n // Widget minW / minH reach the engine on render only. What is reported\n // keeps exactly the constraints the consumer's own entries carried.\n const stripInjected = useCallback(\n (layout: DashboardWidgetLayout[]): DashboardWidgetLayout[] =>\n layout.map((item) => {\n const own = committedRef.current.find((e) => e.id === item.id);\n const { minW: _minW, minH: _minH, ...rest } = item;\n return {\n ...rest,\n ...(own?.minW !== undefined ? { minW: own.minW } : {}),\n ...(own?.minH !== undefined ? { minH: own.minH } : {}),\n };\n }),\n [],\n );\n\n const commit = useCallback(\n (next: DashboardWidgetLayout[]) => {\n const reported = stripInjected(next);\n if (layoutProp === undefined) setInternalLayout(reported);\n onLayoutChange?.(reported);\n },\n [layoutProp, onLayoutChange, stripInjected],\n );\n\n /* ---- resolve: bounds-clamp + auto-place missing children -------- */\n /* Entries whose widget is absent are KEPT, not pruned: widgets may */\n /* mount late (lazy chunks, permission gates) and pruning would */\n /* destroy their saved geometry — they simply don't render until the */\n /* child appears. Removal goes through the remove flow, which commits */\n /* the entry removal explicitly. */\n const { resolved, autoPlaced } = useMemo(() => {\n const constrained = (entry: DashboardWidgetLayout) => {\n const meta = childMeta.get(entry.id);\n return clampRect(\n {\n ...entry,\n ...(meta?.minW !== undefined\n ? { minW: Math.max(entry.minW ?? 1, meta.minW) }\n : {}),\n ...(meta?.minH !== undefined\n ? { minH: Math.max(entry.minH ?? 1, meta.minH) }\n : {}),\n },\n cols,\n );\n };\n const clamped = committed.map(constrained);\n const missing = childIds.filter(\n (cid) => !clamped.some((entry) => entry.id === cid),\n );\n if (missing.length === 0) {\n // A minimum (or the bounds clamp) can grow an entry over its\n // neighbour: re-flow, on render only. Nothing is reported.\n const overlapping = clamped.some((entry, i) =>\n clamped.some((other, j) => j > i && collides(entry, other)),\n );\n return {\n resolved: overlapping ? normalise(clamped, cols) : clamped,\n autoPlaced: false,\n };\n }\n const placed = [...clamped];\n for (const cid of missing) {\n const meta = childMeta.get(cid) ?? { defaultW: 4, defaultH: 2 };\n const w = Math.min(Math.max(meta.defaultW, meta.minW ?? 1), cols);\n const h = Math.max(meta.defaultH, meta.minH ?? 1);\n const spot = firstFit(placed, cols, w, h);\n placed.push(constrained({ id: cid, x: spot.x, y: spot.y, w, h }));\n }\n return { resolved: normalise(placed, cols), autoPlaced: true };\n }, [committed, childIds, childMeta, cols]);\n\n // Report auto-placement exactly once per divergence so the consumer can\n // persist the new entries. Bounds-clamping is render-only and never\n // reported — a controlled layout is not rewritten uninvited.\n const reportedRef = useRef('');\n useEffect(() => {\n if (!autoPlaced) return;\n const signature = resolved\n .map(\n (entry) => `${entry.id}:${entry.x},${entry.y},${entry.w},${entry.h}`,\n )\n .join('|');\n if (reportedRef.current !== signature) {\n reportedRef.current = signature;\n commit(resolved);\n }\n }, [autoPlaced, resolved, commit]);\n\n /* ---- drag / grab state ----------------------------------------- */\n /* Live values mirror into refs so event handlers stay PURE: no state */\n /* updater performs side effects (StrictMode double-invokes them and */\n /* render-phase commits would set consumer state during render), and */\n /* the stable callbacks read current values without dependency churn. */\n const [draft, setDraft] = useState<DashboardWidgetLayout[] | null>(null);\n const [grab, setGrab] = useState<GrabState | null>(null);\n const [announcement, setAnnouncement] = useState('');\n const draftRef = useRef<DashboardWidgetLayout[] | null>(null);\n const grabRef = useRef<\n (GrabState & { baseLayout: DashboardWidgetLayout[] }) | null\n >(null);\n const pointerDragRef = useRef<PointerDragState | null>(null);\n // A pointer interaction always ends with a trailing `click` on the\n // handle — preventDefault on pointerdown does NOT suppress it, and\n // pointer capture retargets it to the handle. This flag turns that\n // click into a no-op instead of a phantom keyboard grab.\n const suppressClickRef = useRef(false);\n const colsRef = useRef(cols);\n colsRef.current = cols;\n const resolvedRef = useRef(resolved);\n resolvedRef.current = resolved;\n\n const applyDraft = useCallback((next: DashboardWidgetLayout[] | null) => {\n draftRef.current = next;\n setDraft(next);\n }, []);\n\n const beginGrab = useCallback(\n (\n kind: 'move' | 'resize',\n widgetId: string,\n via: 'pointer' | 'keyboard',\n ) => {\n const state: GrabState = { kind, id: widgetId, via };\n // The grab-time layout is the collision base for EVERY step of this\n // grab: resolving against the mutating draft makes displaced\n // neighbours flee ahead of repeated steps (down-reorder becomes\n // unreachable); resolving against the frozen base keeps targeting\n // stateless and lets the engine's swap-up work.\n grabRef.current = { ...state, baseLayout: resolvedRef.current };\n setGrab(state);\n applyDraft(resolvedRef.current);\n },\n [applyDraft],\n );\n\n const active = draft ?? resolved;\n const layoutById = useMemo(\n () => new Map(active.map((entry) => [entry.id, entry])),\n [active],\n );\n\n const announceEntry = useCallback(\n (kind: 'move' | 'resize', entry: DashboardWidgetLayout) => {\n setAnnouncement(\n kind === 'move'\n ? t('dashboardGrid.movedTo', { col: entry.x + 1, row: entry.y + 1 })\n : t('dashboardGrid.resizedTo', { cols: entry.w, rows: entry.h }),\n );\n },\n [t],\n );\n\n // Removes the window listeners and the auto-scroll loop of a pointer\n // grab. Set when a pointer grab starts, so no event is missed while\n // React has yet to commit the grab.\n const stopPointerRef = useRef<(() => void) | null>(null);\n\n const endGrab = useCallback(\n (commitDraft: boolean) => {\n stopPointerRef.current?.();\n stopPointerRef.current = null;\n const current = draftRef.current;\n const grabbed = grabRef.current;\n grabRef.current = null;\n pointerDragRef.current = null;\n setGrab(null);\n applyDraft(null);\n if (!commitDraft || !current || !grabbed) {\n setAnnouncement(t('dashboardGrid.cancelled'));\n return;\n }\n // Committing compacts the WHOLE board — the dropped widget joins\n // the gravity pass, so a saved dashboard never keeps stray gaps.\n // A release that changed nothing commits nothing: a plain press on\n // a handle must never rewrite the persisted layout.\n const final = normalise(current, colsRef.current);\n const signatureOf = (layout: DashboardWidgetLayout[]): string =>\n layout.map((e) => `${e.id}:${e.x},${e.y},${e.w},${e.h}`).join('|');\n if (signatureOf(final) === signatureOf(resolvedRef.current)) {\n setAnnouncement(t('dashboardGrid.cancelled'));\n return;\n }\n commit(final);\n // Announce where the widget actually SETTLED — compaction can move\n // it past the last previewed cell, and a screen-reader user must\n // not be left with a stale mental model.\n const landed = final.find((entry) => entry.id === grabbed.id);\n setAnnouncement(\n landed\n ? t('dashboardGrid.droppedAt', {\n col: landed.x + 1,\n row: landed.y + 1,\n })\n : t('dashboardGrid.cancelled'),\n );\n },\n [applyDraft, commit, t],\n );\n const endGrabRef = useRef(endGrab);\n endGrabRef.current = endGrab;\n\n /* ---- keyboard grab --------------------------------------------- */\n const startKeyboardGrab = useCallback(\n (kind: 'move' | 'resize', widgetId: string) => {\n if (!editable) return;\n // The click that terminates a pointer interaction is not a request\n // for a keyboard grab.\n if (suppressClickRef.current) {\n suppressClickRef.current = false;\n return;\n }\n const current = grabRef.current;\n if (current?.via === 'pointer') return;\n if (current && current.id === widgetId && current.kind === kind) {\n // Second Enter/Space (button click) drops.\n endGrab(true);\n return;\n }\n beginGrab(kind, widgetId, 'keyboard');\n setAnnouncement(\n kind === 'move'\n ? t('dashboardGrid.grabbed')\n : t('dashboardGrid.resizeGrabbed'),\n );\n },\n [editable, beginGrab, endGrab, t],\n );\n\n const keyboardStep = useCallback(\n (event: ReactKeyboardEvent<HTMLButtonElement>, widgetId: string) => {\n const grabbed = grabRef.current;\n if (!grabbed || grabbed.id !== widgetId || grabbed.via !== 'keyboard') {\n return;\n }\n if (event.key === 'Escape') {\n event.preventDefault();\n endGrab(false);\n return;\n }\n const arrows = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];\n if (!arrows.includes(event.key)) return;\n event.preventDefault();\n const isRtl =\n typeof window !== 'undefined' && gridRef.current\n ? window.getComputedStyle(gridRef.current).direction === 'rtl'\n : false;\n // Visual left/right → logical inline delta (flips in RTL).\n const inlineDelta =\n event.key === 'ArrowRight'\n ? isRtl\n ? -1\n : 1\n : event.key === 'ArrowLeft'\n ? isRtl\n ? 1\n : -1\n : 0;\n const blockDelta =\n event.key === 'ArrowDown' ? 1 : event.key === 'ArrowUp' ? -1 : 0;\n // Target accumulates through the draft; collisions resolve against\n // the frozen grab-time base (see beginGrab).\n const currentDraft = draftRef.current ?? grabbed.baseLayout;\n const entry = currentDraft.find((item) => item.id === widgetId);\n if (!entry) return;\n const next =\n grabbed.kind === 'move'\n ? gestureDraft(\n grabbed.baseLayout,\n 'move',\n widgetId,\n entry.x + inlineDelta,\n entry.y + blockDelta,\n cols,\n )\n : gestureDraft(\n grabbed.baseLayout,\n 'resize',\n widgetId,\n entry.w + inlineDelta,\n entry.h + blockDelta,\n cols,\n );\n applyDraft(next);\n const moved = next.find((item) => item.id === widgetId);\n if (moved) announceEntry(grabbed.kind, moved);\n },\n [cols, endGrab, applyDraft, announceEntry],\n );\n\n /* ---- pointer drag ---------------------------------------------- */\n /* Cells come from the pointer's position against the GRID's box, not */\n /* from clientX/Y since pointerdown: a scroll of any ancestor (auto or */\n /* wheel) moves the box, so the widget follows the content. */\n const applyPointer = useCallback(() => {\n const dragState = pointerDragRef.current;\n const grabbed = grabRef.current;\n const gridNode = gridRef.current;\n if (!dragState || !grabbed || !gridNode) return;\n const rect = gridNode.getBoundingClientRect();\n const dxPx = dragState.lastClientX - rect.left - dragState.startGridX;\n const dyPx = dragState.lastClientY - rect.top - dragState.startGridY;\n // Visual px → logical cells: a rightward drag decreases the logical\n // column in RTL.\n const inlineCells =\n Math.round(dxPx / dragState.colStride) * (dragState.isRtl ? -1 : 1);\n const blockCells = Math.round(dyPx / dragState.rowStride);\n const { origin } = dragState;\n // Origin-absolute targeting against the frozen grab base — every\n // event re-derives the whole draft, nothing accumulates.\n applyDraft(\n dragState.kind === 'move'\n ? gestureDraft(\n grabbed.baseLayout,\n 'move',\n dragState.id,\n origin.x + inlineCells,\n origin.y + blockCells,\n colsRef.current,\n )\n : gestureDraft(\n grabbed.baseLayout,\n 'resize',\n dragState.id,\n origin.w + inlineCells,\n origin.h + blockCells,\n colsRef.current,\n ),\n );\n }, [applyDraft]);\n\n // A touch hold has picked a widget up: the finger must not scroll.\n const holdActiveRef = useRef(false);\n\n // Pointer move/up/cancel are window-level while a drag is in flight so\n // the drag survives the pointer leaving the handle's hit area. Scrolls\n // of any ancestor re-place the widget, and near an edge of the nearest\n // scrolling ancestor (or the window) the view scrolls by itself.\n const trackPointer = useCallback(() => {\n stopPointerRef.current?.();\n const onMove = (event: PointerEvent) => {\n const dragState = pointerDragRef.current;\n if (!dragState || event.pointerId !== dragState.pointerId) return;\n dragState.lastClientX = event.clientX;\n dragState.lastClientY = event.clientY;\n dragState.travelled ||=\n Math.hypot(\n event.clientX - dragState.pressX,\n event.clientY - dragState.pressY,\n ) > DRAG_THRESHOLD_PX;\n applyPointer();\n };\n const finish = (commitDraft: boolean) => (event: PointerEvent) => {\n const dragState = pointerDragRef.current;\n if (!dragState || event.pointerId !== dragState.pointerId) return;\n // Only a grip gets the click that ends a press on it.\n suppressClickRef.current = dragState.fromHandle;\n // Through the ref: the host's onLayoutChange may change mid-drag.\n endGrabRef.current(commitDraft);\n };\n const onUp = finish(true);\n const onCancel = finish(false);\n const onScroll = () => applyPointer();\n let frame = 0;\n const autoScroll = () => {\n frame = requestAnimationFrame(autoScroll);\n const dragState = pointerDragRef.current;\n // A press held still (or a touch hold not yet moved) never scrolls.\n if (!dragState?.travelled) return;\n const gridNode = gridRef.current;\n if (!gridNode) return;\n const { lastClientX: x, lastClientY: y } = dragState;\n // Each axis scrolls its own nearest scroller (a horizontal scroller\n // inside the app's vertical one), or the window. Looked up every\n // frame: a resize can make a wrapper start to overflow mid-grab.\n const scrollers = scrollingAncestors(gridNode);\n const axis = (\n scroller: HTMLElement | null,\n pointer: number,\n vertical: boolean,\n ) => {\n const view = vertical ? window.innerHeight : window.innerWidth;\n const box = scroller?.getBoundingClientRect();\n const start = Math.max(\n vertical ? (box?.top ?? 0) : (box?.left ?? 0),\n 0,\n );\n const end = Math.min(\n vertical ? (box?.bottom ?? view) : (box?.right ?? view),\n view,\n );\n const delta = edgeSpeed(end - pointer) - edgeSpeed(pointer - start);\n if (delta === 0) return;\n const read = () =>\n scroller\n ? vertical\n ? scroller.scrollTop\n : scroller.scrollLeft\n : vertical\n ? window.scrollY\n : window.scrollX;\n const before = read();\n scroller?.scrollBy(vertical ? 0 : delta, vertical ? delta : 0);\n // That scroller is at its end on this axis: the page scrolls.\n if (!scroller || read() === before) {\n window.scrollBy(vertical ? 0 : delta, vertical ? delta : 0);\n }\n };\n axis(scrollers.y, y, true);\n axis(scrollers.x, x, false);\n };\n frame = requestAnimationFrame(autoScroll);\n window.addEventListener('pointermove', onMove);\n window.addEventListener('pointerup', onUp);\n window.addEventListener('pointercancel', onCancel);\n window.addEventListener('scroll', onScroll, {\n capture: true,\n passive: true,\n });\n stopPointerRef.current = () => {\n cancelAnimationFrame(frame);\n holdActiveRef.current = false;\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onUp);\n window.removeEventListener('pointercancel', onCancel);\n window.removeEventListener('scroll', onScroll, { capture: true });\n };\n }, [applyPointer]);\n\n useEffect(\n () => () => {\n stopPointerRef.current?.();\n stopPointerRef.current = null;\n },\n [],\n );\n\n const beginPointerGrab = useCallback(\n (\n kind: 'move' | 'resize',\n widgetId: string,\n pointer: { pointerId: number; clientX: number; clientY: number },\n captureTarget: Element,\n fromHandle: boolean,\n ): boolean => {\n const gridNode = gridRef.current;\n const entry = resolvedRef.current.find((item) => item.id === widgetId);\n if (!gridNode || !entry) return false;\n const rect = gridNode.getBoundingClientRect();\n // A 0-width container (hidden tab, jsdom) has no usable cell metric —\n // pointer dragging is meaningless there; keyboard still works.\n if (rect.width <= 0) return false;\n const styles = window.getComputedStyle(gridNode);\n const gap = Number.parseFloat(styles.columnGap) || 0;\n const rowGap = Number.parseFloat(styles.rowGap) || 0;\n const colWidth = (rect.width - gap * (cols - 1)) / cols;\n pointerDragRef.current = {\n kind,\n id: widgetId,\n pointerId: pointer.pointerId,\n startGridX: pointer.clientX - rect.left,\n startGridY: pointer.clientY - rect.top,\n lastClientX: pointer.clientX,\n lastClientY: pointer.clientY,\n origin: entry,\n colStride: colWidth + gap,\n rowStride: rowHeight + rowGap,\n isRtl: styles.direction === 'rtl',\n fromHandle,\n pressX: pointer.clientX,\n pressY: pointer.clientY,\n travelled: false,\n };\n try {\n captureTarget.setPointerCapture?.(pointer.pointerId);\n } catch {\n // Synthetic pointer events (tests) have no active pointer to\n // capture; the window-level listeners track the drag regardless.\n }\n beginGrab(kind, widgetId, 'pointer');\n trackPointer();\n return true;\n },\n [cols, rowHeight, beginGrab, trackPointer],\n );\n\n const startPointerGrab = useCallback(\n (\n kind: 'move' | 'resize',\n widgetId: string,\n event: ReactPointerEvent<HTMLButtonElement>,\n ) => {\n if (!editable) return;\n // Any grab in flight wins: a keyboard grab must not be hijacked,\n // and a second concurrent pointer (multi-touch) must not reset an\n // active drag.\n if (grabRef.current) return;\n event.preventDefault();\n // preventDefault suppressed the browser's mousedown-focus — restore\n // it explicitly so the focusout/Escape cancel paths stay reachable\n // and the handle shows its focus ring during the drag.\n event.currentTarget.focus?.();\n beginPointerGrab(kind, widgetId, event, event.currentTarget, true);\n },\n [editable, beginPointerGrab],\n );\n\n /* ---- drag from the header -------------------------------------- */\n /* Mouse and pen: a press anywhere on the header (outside its buttons) */\n /* becomes a move once it travels DRAG_THRESHOLD_PX, so a plain click */\n /* still behaves as one. Touch: press and hold still for TOUCH_HOLD_MS */\n /* (moving earlier is a scroll and is left to the browser). */\n const headerPressRef = useRef<HeaderPress | null>(null);\n\n const clearHeaderPress = useCallback(() => {\n const press = headerPressRef.current;\n headerPressRef.current = null;\n if (!press) return;\n if (press.holdTimer) clearTimeout(press.holdTimer);\n press.cleanup();\n }, []);\n\n const startHeaderPress = useCallback(\n (widgetId: string, event: ReactPointerEvent<HTMLElement>) => {\n if (!editable || grabRef.current || headerPressRef.current) return;\n if (event.button !== 0 || !event.isPrimary) return;\n const target = event.target as Element;\n // Only the header's own DOM: React bubbles events from portals (a\n // pop-up opened from the header) through it too.\n if (!event.currentTarget.contains(target)) return;\n // Its controls keep their own behaviour; the title, a tab stop only\n // while cut short, stays a drag surface.\n const control = target.closest(HEADER_PRESS_IGNORES);\n if (control && event.currentTarget.contains(control)) return;\n const surface = event.currentTarget;\n const touch = event.pointerType === 'touch';\n // Mouse and pen: no text selection, no focus jump from the press.\n if (!touch) event.preventDefault();\n const activate = (clientX: number, clientY: number) => {\n const press = headerPressRef.current;\n clearHeaderPress();\n // Another pointer (a second finger on a grip) may have won.\n if (!press || grabRef.current) return;\n if (\n beginPointerGrab(\n 'move',\n press.id,\n {\n pointerId: press.pointerId,\n clientX: press.startClientX,\n clientY: press.startClientY,\n },\n press.surface,\n false,\n )\n ) {\n holdActiveRef.current = touch;\n const dragState = pointerDragRef.current;\n if (dragState) {\n dragState.lastClientX = clientX;\n dragState.lastClientY = clientY;\n // A mouse or pen press only got here by crossing the threshold.\n dragState.travelled = !touch;\n }\n applyPointer();\n }\n };\n const onMove = (move: PointerEvent) => {\n const press = headerPressRef.current;\n if (!press || move.pointerId !== press.pointerId) return;\n const travelled = Math.hypot(\n move.clientX - press.startClientX,\n move.clientY - press.startClientY,\n );\n if (touch) {\n if (travelled > TOUCH_SLOP_PX) clearHeaderPress();\n } else if (travelled > DRAG_THRESHOLD_PX) {\n activate(move.clientX, move.clientY);\n }\n };\n const onEnd = (end: PointerEvent) => {\n if (end.pointerId === headerPressRef.current?.pointerId) {\n clearHeaderPress();\n }\n };\n window.addEventListener('pointermove', onMove);\n window.addEventListener('pointerup', onEnd);\n window.addEventListener('pointercancel', onEnd);\n headerPressRef.current = {\n id: widgetId,\n pointerId: event.pointerId,\n pointerType: event.pointerType,\n startClientX: event.clientX,\n startClientY: event.clientY,\n surface,\n holdTimer: touch\n ? setTimeout(() => {\n const press = headerPressRef.current;\n if (press) activate(press.startClientX, press.startClientY);\n }, TOUCH_HOLD_MS)\n : null,\n cleanup: () => {\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onEnd);\n window.removeEventListener('pointercancel', onEnd);\n },\n };\n },\n [editable, beginPointerGrab, applyPointer, clearHeaderPress],\n );\n\n // When editing ends, a press in progress is dropped and a grab in flight\n // is cancelled, never committed.\n useEffect(() => {\n if (!editable) {\n clearHeaderPress();\n if (grabRef.current) endGrabRef.current(false);\n }\n }, [editable, clearHeaderPress]);\n\n // On unmount: a press's listeners and hold timer go with the board.\n useEffect(() => clearHeaderPress, [clearHeaderPress]);\n\n // Touch: once a hold has picked a widget up, the finger drags it and\n // must not scroll the page. The listener is registered for the whole\n // edit session (non-passive), because the browser only lets a handler\n // that existed at touchstart cancel the scroll.\n useEffect(() => {\n const node = gridRef.current;\n if (!editable || !node) return undefined;\n const onTouchMove = (event: TouchEvent) => {\n if (holdActiveRef.current && event.cancelable) event.preventDefault();\n };\n const onContextMenu = (event: Event) => {\n if (headerPressRef.current || holdActiveRef.current) {\n event.preventDefault();\n }\n };\n node.addEventListener('touchmove', onTouchMove, { passive: false });\n node.addEventListener('contextmenu', onContextMenu);\n return () => {\n node.removeEventListener('touchmove', onTouchMove);\n node.removeEventListener('contextmenu', onContextMenu);\n };\n }, [editable]);\n\n // Escape cancels ANY in-flight grab wherever focus currently is (APG:\n // the cancel key must work for the whole operation, not only while the\n // grabbed handle keeps focus).\n useEffect(() => {\n if (!grab) return undefined;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') endGrab(false);\n };\n window.addEventListener('keydown', onKeyDown);\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [grab, endGrab]);\n\n // A keyboard grab that loses focus is cancelled (never leave the board\n // in a half-grabbed state).\n useEffect(() => {\n if (!grab || grab.via !== 'keyboard') return undefined;\n const onFocusOut = (event: FocusEvent) => {\n const next = event.relatedTarget as Node | null;\n if (!next || !gridRef.current?.contains(next)) endGrab(false);\n };\n const node = gridRef.current;\n node?.addEventListener('focusout', onFocusOut);\n return () => node?.removeEventListener('focusout', onFocusOut);\n }, [grab, endGrab]);\n\n // Stacking removes the chrome a grab is driven by: cancel it, never\n // commit it (stacking must not reach onLayoutChange). While editing,\n // say why the edit controls went away; the message replaces the\n // grab's \"Change cancelled.\".\n useIsomorphicLayoutEffect(() => {\n if (!stacked) return;\n if (grabRef.current) endGrab(false);\n if (editing) setAnnouncement(t('dashboardGrid.stackedReadOnly'));\n }, [stacked, editing, endGrab, t]);\n\n // Keep focus across the mode switch. Being in the DOM is not proof that\n // focus survived: the reorder MOVES keyed nodes, and a browser can drop\n // focus to <body> on a move. So check where focus is now. Lost and the\n // node still here (moved): focus it again. Lost and the node gone (edit\n // chrome unmounted): its widget takes focus, else the board does. Focus\n // that went somewhere else on purpose is left alone.\n useIsomorphicLayoutEffect(() => {\n const pending = pendingFocusRef.current;\n pendingFocusRef.current = null;\n const root = rootRef.current;\n if (!pending || !root) return;\n const active = document.activeElement;\n if (active === pending.element) return;\n if (active !== null && active !== document.body) return;\n if (root.contains(pending.element)) {\n pending.element.focus();\n return;\n }\n const widget = pending.widgetId\n ? Array.from(\n root.querySelectorAll<HTMLElement>('[data-widget-id]'),\n ).find(\n (node) => node.getAttribute('data-widget-id') === pending.widgetId,\n )\n : undefined;\n if (widget) {\n // Focusable by script only, so it never joins the tab order.\n widget.setAttribute('tabindex', '-1');\n widget.focus();\n return;\n }\n gridRef.current?.focus();\n }, [stacked]);\n\n const onStackedChangeRef = useRef(onStackedChange);\n onStackedChangeRef.current = onStackedChange;\n const reportedStackedRef = useRef(false);\n // A layout effect, so a host that hides its own controls on `true`\n // re-renders before the stacked board is first painted.\n useIsomorphicLayoutEffect(() => {\n if (reportedStackedRef.current === stacked) return;\n reportedStackedRef.current = stacked;\n onStackedChangeRef.current?.(stacked);\n }, [stacked]);\n\n /* ---- container CSS vars ---------------------------------------- */\n useIsomorphicLayoutEffect(() => {\n const node = gridRef.current;\n if (!node) return;\n node.style.setProperty('--dg-cols', String(cols));\n node.style.setProperty('--dg-row', `${rowHeight}px`);\n }, [cols, rowHeight]);\n\n // Edit-mode surface metrics. The cell-line gradients and the spare-row\n // min height depend on runtime values (cols, rowHeight, occupied rows),\n // so they flow through custom properties like the coordinates do.\n const visibleRows = rowCount(active);\n useIsomorphicLayoutEffect(() => {\n const node = gridRef.current;\n if (!node) return;\n node.style.setProperty(\n '--dg-grid-lines',\n `repeating-linear-gradient(to right, color-mix(in srgb, var(--border) 50%, transparent) 0 1px, transparent 1px calc((100% + var(--spacing-md)) / ${cols})), ` +\n `repeating-linear-gradient(to bottom, color-mix(in srgb, var(--border) 50%, transparent) 0 1px, transparent 1px calc(${rowHeight}px + var(--spacing-md)))`,\n );\n node.style.setProperty(\n '--dg-min-block',\n `calc(${visibleRows + 2} * (${rowHeight}px + var(--spacing-md)) - var(--spacing-md))`,\n );\n }, [cols, rowHeight, visibleRows]);\n\n /* ---- add tile placement ---------------------------------------- */\n const addTileRef = useRef<HTMLDivElement>(null);\n const showAddTile = editable && Boolean(onRequestAdd);\n const addSpot = useMemo(\n () => (showAddTile ? firstFit(active, cols, 2, 2) : null),\n [showAddTile, active, cols],\n );\n useIsomorphicLayoutEffect(() => {\n const node = addTileRef.current;\n if (!node || !addSpot) return;\n node.style.setProperty('--dg-x', String(addSpot.x + 1));\n node.style.setProperty('--dg-y', String(addSpot.y + 1));\n node.style.setProperty('--dg-w', '2');\n node.style.setProperty('--dg-h', '2');\n }, [addSpot]);\n\n /* ---- remove flow ------------------------------------------------ */\n const requestRemove = useCallback(\n (widgetId: string) => {\n // The kit owns the entry removal (single commit) and the focus\n // recovery — the consumer only unmounts the child. Without this a\n // keyboard user's focus falls to <body> when the button unmounts.\n // Focus goes to the next widget in Tab order (else the one before):\n // its first control, the move grip while editing; else the board.\n const widgets = Array.from(\n gridRef.current?.querySelectorAll<HTMLElement>('[data-widget-id]') ??\n [],\n );\n const at = widgets.findIndex(\n (node) => node.getAttribute('data-widget-id') === widgetId,\n );\n const neighbour = (widgets[at + 1] ?? widgets[at - 1])?.getAttribute(\n 'data-widget-id',\n );\n commit(\n normalise(\n resolvedRef.current.filter((entry) => entry.id !== widgetId),\n colsRef.current,\n ),\n );\n setAnnouncement(t('dashboardGrid.removed'));\n onRemoveWidget?.(widgetId);\n requestAnimationFrame(() => {\n const root = gridRef.current;\n if (!root) return;\n const next = Array.from(\n root.querySelectorAll<HTMLElement>('[data-widget-id]'),\n ).find((node) => node.getAttribute('data-widget-id') === neighbour);\n const target =\n next?.querySelector<HTMLButtonElement>('button') ??\n root.querySelector<HTMLButtonElement>('button');\n if (target) target.focus();\n else root.focus();\n });\n },\n [commit, onRemoveWidget, t],\n );\n\n /* ---- reveal ------------------------------------------------------ */\n /* A reveal waits for its widget: a host adds a widget and reveals it */\n /* in one tick, before React has rendered it. Each commit and each */\n /* frame tries again, until the widget has a box or a second passes. */\n const [revealedId, setRevealedId] = useState<string | null>(null);\n const pendingRevealRef = useRef<{\n id: string;\n deadline: number;\n resolve: (revealed: boolean) => void;\n } | null>(null);\n const revealTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const revealFrameRef = useRef(0);\n\n const tryReveal = useCallback((): boolean => {\n const pending = pendingRevealRef.current;\n const root = gridRef.current;\n if (!pending || !root) return false;\n const node = Array.from(\n root.querySelectorAll<HTMLElement>('[data-widget-id]'),\n ).find((item) => item.getAttribute('data-widget-id') === pending.id);\n const box = node?.getBoundingClientRect();\n if (!node || !box || box.height <= 0) {\n if (performance.now() > pending.deadline) {\n pendingRevealRef.current = null;\n pending.resolve(false);\n }\n return false;\n }\n pendingRevealRef.current = null;\n const reduceMotion =\n window.matchMedia?.('(prefers-reduced-motion: reduce)').matches ||\n window\n .getComputedStyle(root)\n .getPropertyValue('--animation-duration')\n .trim() === '0ms';\n node.scrollIntoView({\n block: 'nearest',\n inline: 'nearest',\n behavior: reduceMotion ? 'auto' : 'smooth',\n });\n setRevealedId(pending.id);\n if (revealTimerRef.current) clearTimeout(revealTimerRef.current);\n revealTimerRef.current = setTimeout(\n () => setRevealedId(null),\n REVEAL_HIGHLIGHT_MS,\n );\n pending.resolve(true);\n return true;\n }, []);\n\n const revealWidget = useCallback(\n (widgetId: string) =>\n new Promise<boolean>((resolve) => {\n pendingRevealRef.current?.resolve(false);\n cancelAnimationFrame(revealFrameRef.current);\n // A real timer as well as the frames: requestAnimationFrame stops\n // in a background tab, and the deadline must still hold there.\n const deadline = setTimeout(() => {\n const pending = pendingRevealRef.current;\n if (pending?.resolve !== settle) return;\n if (!tryReveal() && pendingRevealRef.current === pending) {\n pendingRevealRef.current = null;\n settle(false);\n }\n }, REVEAL_WAIT_MS);\n const settle = (revealed: boolean) => {\n clearTimeout(deadline);\n resolve(revealed);\n };\n pendingRevealRef.current = {\n id: widgetId,\n deadline: performance.now() + REVEAL_WAIT_MS,\n resolve: settle,\n };\n const poll = () => {\n if (!pendingRevealRef.current) return;\n if (!tryReveal() && pendingRevealRef.current) {\n revealFrameRef.current = requestAnimationFrame(poll);\n }\n };\n revealFrameRef.current = requestAnimationFrame(poll);\n }),\n [tryReveal],\n );\n\n // After every commit: the widget a pending reveal waits for may be here.\n useIsomorphicLayoutEffect(() => {\n if (pendingRevealRef.current) tryReveal();\n });\n\n useEffect(\n () => () => {\n cancelAnimationFrame(revealFrameRef.current);\n if (revealTimerRef.current) clearTimeout(revealTimerRef.current);\n pendingRevealRef.current?.resolve(false);\n pendingRevealRef.current = null;\n },\n [],\n );\n\n /* ---- imperative handle / agent --------------------------------- */\n const agentHandle = useMemo<DashboardGridHandle>(\n () => ({\n moveWidgetTo(widgetId, x, y) {\n // The ref also catches a stack decided but not yet rendered.\n if (!editable || stackedRef.current) return false;\n if (!Number.isFinite(x) || !Number.isFinite(y)) return false;\n if (!resolved.some((item) => item.id === widgetId)) return false;\n // Round: fractional cells produce invalid grid-column values. A\n // move to its own cell keeps the board as it is and saves nothing.\n const draft = gestureDraft(\n resolved,\n 'move',\n widgetId,\n Math.round(x),\n Math.round(y),\n cols,\n false,\n );\n if (draft !== resolved) commit(normalise(draft, cols));\n return true;\n },\n resizeWidgetTo(widgetId, w, h) {\n if (!editable || stackedRef.current) return false;\n if (!Number.isFinite(w) || !Number.isFinite(h)) return false;\n if (!resolved.some((item) => item.id === widgetId)) return false;\n const draft = gestureDraft(\n resolved,\n 'resize',\n widgetId,\n Math.round(w),\n Math.round(h),\n cols,\n false,\n );\n if (draft !== resolved) commit(normalise(draft, cols));\n return true;\n },\n revealWidget,\n getGridState() {\n return {\n cols,\n editing,\n stacked,\n layout: stripInjected(resolved),\n selectedId: selectedId ?? null,\n };\n },\n }),\n [\n editable,\n editing,\n stacked,\n resolved,\n cols,\n commit,\n stripInjected,\n revealWidget,\n selectedId,\n ],\n );\n useImperativeHandle(ref, () => agentHandle, [agentHandle]);\n useAgentRegistration(dashboardGridAgent, agentHandle, id);\n\n const contextValue = useMemo<DashboardGridContextValue>(\n () => ({\n editing: editable,\n stacked,\n stackedHeight,\n selectedId,\n revealedId,\n headingLevel: widgetHeadingLevel,\n layoutById,\n grab,\n canRemove: Boolean(onRemoveWidget),\n requestRemove,\n startKeyboardGrab,\n keyboardStep,\n startPointerGrab,\n startHeaderPress,\n }),\n [\n editable,\n stacked,\n stackedHeight,\n selectedId,\n revealedId,\n widgetHeadingLevel,\n layoutById,\n grab,\n onRemoveWidget,\n requestRemove,\n startKeyboardGrab,\n keyboardStep,\n startPointerGrab,\n startHeaderPress,\n ],\n );\n\n /* ---- children in DOM order -------------------------------------- */\n /* With `stackBelow` set, widgets render as ONE keyed array in both */\n /* modes, so a mode switch only reorders them: React moves the nodes, */\n /* nothing remounts or loses state. Stacked, the DOM order IS the */\n /* reading order, so keyboard and screen-reader order match the */\n /* column. Without `stackBelow`, children render exactly as passed. */\n const renderedChildren = useMemo<ReactNode>(() => {\n if (stackBelow === undefined) return children;\n const all: ReactElement[] = [];\n const byId = new Map<string, ReactElement>();\n const unkeyed: ReactElement[] = [];\n // Keys keep the consumer's own key (so changing it still remounts)\n // and add the widget id, unique once fragments are flattened.\n forEachWidgetChild(children, (child) => {\n const widgetId = child.props.id;\n if (widgetId && !byId.has(widgetId)) {\n const element = cloneElement(child, {\n key: `widget:${widgetId}:${child.key ?? ''}`,\n });\n byId.set(widgetId, element);\n all.push(element);\n } else {\n const element = cloneElement(child, {\n key:\n child.key === null\n ? `child:at:${unkeyed.length}`\n : `child:key:${child.key}`,\n });\n unkeyed.push(element);\n all.push(element);\n }\n });\n if (!stacked) return all;\n return [\n ...stackOrder([...byId.keys()], resolved).map(\n (widgetId) => byId.get(widgetId) as ReactElement,\n ),\n ...unkeyed,\n ];\n }, [stackBelow, children, stacked, resolved]);\n\n return (\n <div\n ref={rootRef}\n data-component=\"dashboard-grid\"\n data-component-id={id}\n data-editing={editable || undefined}\n data-stacked={stacked || undefined}\n className={`ds:block ds:w-full ${className ?? ''}`.trim()}\n >\n <div role=\"status\" aria-live=\"polite\" className=\"ds:sr-only\">\n {announcement}\n </div>\n <div\n ref={gridRef}\n role=\"list\"\n aria-label={ariaLabel}\n tabIndex={-1}\n data-editing={editable || undefined}\n data-stacked={stacked || undefined}\n className={dashboardGridVariants({ stacked })}\n >\n <DashboardGridContext.Provider value={contextValue}>\n {renderedChildren}\n </DashboardGridContext.Provider>\n {showAddTile ? (\n // role=\"list\" allows only listitem children — the tile wrapper\n // carries the grid placement, the button fills it.\n <div\n ref={addTileRef}\n role=\"listitem\"\n className={[\n 'ds:flex',\n 'ds:[grid-column-start:var(--dg-x)] ds:[grid-column-end:span_var(--dg-w)]',\n 'ds:[grid-row-start:var(--dg-y)] ds:[grid-row-end:span_var(--dg-h)]',\n ].join(' ')}\n >\n <button\n type=\"button\"\n onClick={onRequestAdd}\n className={[\n 'ds:flex ds:flex-1 ds:items-center ds:justify-center ds:gap-[var(--spacing-xs)]',\n 'ds:rounded-[var(--radius-lg)] ds:border ds:border-dashed ds:border-border',\n 'ds:text-sm ds:text-muted-foreground ds:transition-colors',\n 'ds:hover:bg-muted/10 ds:hover:text-foreground',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-ring',\n ].join(' ')}\n >\n <Plus aria-hidden=\"true\" className=\"ds:size-4\" />\n {t('dashboardGrid.add')}\n </button>\n </div>\n ) : null}\n </div>\n </div>\n );\n },\n);\nDashboardGridRoot.displayName = 'DashboardGrid';\n\nexport const DashboardGrid = Object.assign(DashboardGridRoot, {\n Widget: DashboardGridWidget,\n});\n"],"names":["__iconNode","MoveDiagonal2","createLucideIcon","dashboardGridAgent","handle","args","collides","a","b","clampRect","item","cols","minW","minH","maxW","maxH","w","h","x","y","isHole","slot","others","other","row","readingDistance","normalise","layout","activeId","vacated","items","order","placed","active","displaced","above","p","pushY","best","fromStart","floor","test","settled","target","xs","_","i","byId","moveItem","id","next","resizeItem","firstFit","width","maxY","m","candidate","rowCount","STACK_HYSTERESIS_PX","shouldStack","inlineSize","stackBelow","wasStacked","stackOrder","ids","index","dashboardGridVariants","cva","widgetVariants","widgetBodyVariants","resizeGripVariants","headerFoldVariants","HEADER_BUTTON_CLASSES","widgetHeaderVariants","widgetTitleVariants","DashboardGridContext","createContext","positiveSpan","value","forEachWidgetChild","children","fn","Children","child","isValidElement","Fragment","DashboardGridWidget","title","minStackedHeight","actions","actionsSlot","t","useTranslation","ctx","useContext","wrapperRef","useRef","pickedRef","entry","titleNode","setTitleNode","useState","titleCut","setTitleCut","titleFocused","setTitleFocused","tipOpen","setTipOpen","useEffect","measure","fonts","observer","useIsomorphicLayoutEffect","node","grabbed","_a","editing","headerButtons","REMOVE_ACTION_ID","X","foldable","TitleTag","jsxs","event","jsx","IconButton","GripVertical","_b","Tooltip","action","DropdownMenu","Ellipsis","before","_c","REVEAL_WAIT_MS","REVEAL_HIGHLIGHT_MS","HEADER_PRESS_IGNORES","DRAG_THRESHOLD_PX","TOUCH_HOLD_MS","TOUCH_SLOP_PX","AUTO_SCROLL_EDGE_PX","AUTO_SCROLL_MAX_PX","scrollingAncestors","found","scrolls","current","styles","gestureDraft","base","kind","inline","block","capped","start","bottom","moved","edgeSpeed","distance","depth","DashboardGridRoot","forwardRef","ariaLabel","rowHeight","layoutProp","defaultLayout","onLayoutChange","onRemoveWidget","onRequestAdd","onStackedChange","stackedHeight","selectedId","widgetHeadingLevel","className","ref","rootRef","gridRef","stacked","setStacked","stackedRef","pendingFocusRef","switchStacked","useCallback","root","focused","entries","editable","childIds","useMemo","childMeta","meta","internalLayout","setInternalLayout","committed","committedRef","stripInjected","own","e","_minW","_minH","rest","commit","reported","resolved","autoPlaced","constrained","clamped","missing","cid","j","spot","reportedRef","signature","draft","setDraft","grab","setGrab","announcement","setAnnouncement","draftRef","grabRef","pointerDragRef","suppressClickRef","colsRef","resolvedRef","applyDraft","beginGrab","widgetId","via","state","layoutById","announceEntry","stopPointerRef","endGrab","commitDraft","final","signatureOf","landed","endGrabRef","startKeyboardGrab","keyboardStep","isRtl","inlineDelta","blockDelta","applyPointer","dragState","gridNode","rect","dxPx","dyPx","inlineCells","blockCells","origin","holdActiveRef","trackPointer","onMove","finish","onUp","onCancel","onScroll","frame","autoScroll","scrollers","axis","scroller","pointer","vertical","view","box","end","delta","read","beginPointerGrab","captureTarget","fromHandle","gap","rowGap","colWidth","startPointerGrab","headerPressRef","clearHeaderPress","press","startHeaderPress","control","surface","touch","activate","clientX","clientY","move","travelled","onEnd","onTouchMove","onContextMenu","onKeyDown","onFocusOut","pending","widget","onStackedChangeRef","reportedStackedRef","visibleRows","addTileRef","showAddTile","addSpot","requestRemove","widgets","at","neighbour","revealedId","setRevealedId","pendingRevealRef","revealTimerRef","revealFrameRef","tryReveal","reduceMotion","revealWidget","resolve","deadline","settle","revealed","poll","agentHandle","useImperativeHandle","useAgentRegistration","contextValue","renderedChildren","all","unkeyed","element","cloneElement","Plus","DashboardGrid"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,MAAMA,KAAa;AAAA,EACjB,CAAC,QAAQ,EAAE,GAAG,eAAe,KAAK,SAAQ,CAAE;AAAA,EAC5C,CAAC,QAAQ,EAAE,GAAG,aAAa,KAAK,SAAQ,CAAE;AAAA,EAC1C,CAAC,QAAQ,EAAE,GAAG,cAAc,KAAK,SAAQ,CAAE;AAC7C,GACMC,KAAgBC,GAAiB,mBAAmBF,EAAU,GCXvDG,KAAwD;AAAA,EACnE,IAAI;AAAA;AAAA;AAAA;AAAA,EAIJ,cAAc,CAAC,eAAe,QAAQ;AAAA,EACtC,OAAO;AAAA,IACL,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,aACE;AAAA,MACF,MAAM,CAACC,MAAWA,EAAO,eAAe;AAAA,IAAA;AAAA,IAE1C,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,aAAa;AAAA,MACb,MAAM,CAACA,MAAWA,EAAO,eAAe;AAAA,IAAA;AAAA,IAE1C,SAAS;AAAA,MACP,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,aACE;AAAA,MACF,MAAM,CAACA,MAAWA,EAAO,eAAe;AAAA,IAAA;AAAA,IAE1C,SAAS;AAAA,MACP,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,aACE;AAAA,MACF,MAAM,CAACA,MAAWA,EAAO,eAAe;AAAA,IAAA;AAAA,IAE1C,YAAY;AAAA,MACV,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,aACE;AAAA,MACF,MAAM,CAACA,MAAWA,EAAO,eAAe;AAAA,IAAA;AAAA,EAC1C;AAAA,EAEF,SAAS;AAAA,IACP,eAAe;AAAA;AAAA,MAEb,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY;AAAA,UACV,IAAI,EAAE,MAAM,UAAU,aAAa,gCAAA;AAAA,QAAgC;AAAA,QAErE,UAAU,CAAC,IAAI;AAAA,MAAA;AAAA,MAEjB,SAAS;AAAA,MACT,eAAe;AAAA,QACb,MAAM;AAAA,QACN,aACE;AAAA,MAAA;AAAA,MAEJ,YAAY;AAAA,MACZ,QAAQ;AAAA,QACN;AAAA,MAAA;AAAA,MAEF,gBAAgB;AAAA,MAChB,aACE;AAAA,MACF,QAAQ,CAACA,GAAQC,MAAyBD,EAAO,aAAaC,EAAK,EAAE;AAAA,IAAA;AAAA,IAEvE,aAAa;AAAA;AAAA;AAAA,MAGX,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY;AAAA,UACV,IAAI,EAAE,MAAM,UAAU,aAAa,gCAAA;AAAA,UACnC,GAAG;AAAA,YACD,MAAM;AAAA,YACN,SAAS;AAAA,YACT,aAAa;AAAA,UAAA;AAAA,UAEf,GAAG,EAAE,MAAM,WAAW,SAAS,GAAG,aAAa,eAAA;AAAA,QAAe;AAAA,QAEhE,UAAU,CAAC,MAAM,KAAK,GAAG;AAAA,MAAA;AAAA,MAE3B,SAAS;AAAA,MACT,eAAe;AAAA,QACb,MAAM;AAAA,QACN,aACE;AAAA,MAAA;AAAA,MAEJ,YAAY;AAAA,MACZ,QAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MAEF,gBAAgB;AAAA,MAChB,aACE;AAAA,MACF,QAAQ,CAACD,GAAQC,MACfD,EAAO,aAAaC,EAAK,IAAIA,EAAK,GAAGA,EAAK,CAAC;AAAA,IAAA;AAAA,IAE/C,eAAe;AAAA,MACb,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,YAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY;AAAA,UACV,IAAI,EAAE,MAAM,UAAU,aAAa,gCAAA;AAAA,UACnC,GAAG;AAAA,YACD,MAAM;AAAA,YACN,SAAS;AAAA,YACT,aAAa;AAAA,UAAA;AAAA,UAEf,GAAG,EAAE,MAAM,WAAW,SAAS,GAAG,aAAa,kBAAA;AAAA,QAAkB;AAAA,QAEnE,UAAU,CAAC,MAAM,KAAK,GAAG;AAAA,MAAA;AAAA,MAE3B,SAAS;AAAA,MACT,eAAe;AAAA,QACb,MAAM;AAAA,QACN,aACE;AAAA,MAAA;AAAA,MAEJ,YAAY;AAAA,MACZ,QAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MAEF,gBAAgB;AAAA,MAChB,aACE;AAAA,MACF,QAAQ,CAACD,GAAQC,MACfD,EAAO,eAAeC,EAAK,IAAIA,EAAK,GAAGA,EAAK,CAAC;AAAA,IAAA;AAAA,EACjD;AAAA,EAEF,UAAU;AAAA,IACR,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aACE;AAAA,IAAA;AAAA,IAEJ,YAAY;AAAA,MACV,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,aAAa;AAAA,IAAA;AAAA,IAEf,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,IAAA;AAAA,EACf;AAEJ;ACtIO,SAASC,EACdC,GACAC,GACS;AACT,SACED,EAAE,IAAIC,EAAE,IAAIA,EAAE,KAAKA,EAAE,IAAID,EAAE,IAAIA,EAAE,KAAKA,EAAE,IAAIC,EAAE,IAAIA,EAAE,KAAKA,EAAE,IAAID,EAAE,IAAIA,EAAE;AAE3E;AAGO,SAASE,GACdC,GACAC,GACuB;AACvB,QAAMC,IAAO,KAAK,IAAI,GAAGF,EAAK,QAAQ,CAAC,GACjCG,IAAO,KAAK,IAAI,GAAGH,EAAK,QAAQ,CAAC,GACjCI,IAAO,KAAK,IAAIH,GAAMD,EAAK,QAAQC,CAAI,GACvCI,IAAOL,EAAK,QAAQ,OAAO,mBAC3BM,IAAI,KAAK,IAAI,KAAK,IAAIN,EAAK,GAAGE,CAAI,GAAGE,CAAI,GACzCG,IAAI,KAAK,IAAI,KAAK,IAAIP,EAAK,GAAGG,CAAI,GAAGE,CAAI,GACzCG,IAAI,KAAK,IAAI,KAAK,IAAI,GAAGR,EAAK,CAAC,GAAGC,IAAOK,CAAC,GAC1CG,IAAI,KAAK,IAAI,GAAGT,EAAK,CAAC;AAC5B,SAAO,EAAE,GAAGA,GAAM,GAAAQ,GAAG,GAAAC,GAAG,GAAAH,GAAG,GAAAC,EAAA;AAC7B;AAOA,SAASG,GACPC,GACAC,GACS;AACT,MAAIA,EAAO,KAAK,CAACC,MAAUjB,EAASiB,GAAOF,CAAI,CAAC,EAAG,QAAO;AAC1D,WAASG,IAAMH,EAAK,GAAGG,IAAMH,EAAK,IAAIA,EAAK,GAAGG,KAAO;AAKnD,QAAI,CAJYF,EAAO;AAAA,MACrB,CAACC,MACCA,EAAM,KAAKF,EAAK,IAAIA,EAAK,KAAKG,KAAOD,EAAM,KAAKC,IAAMD,EAAM,IAAIA,EAAM;AAAA,IAAA,EAE5D,QAAO;AAEvB,SAAO;AACT;AAGA,SAASE,GACPlB,GACAC,GACAG,GACQ;AACR,SAAO,KAAK,IAAIJ,EAAE,IAAII,IAAOJ,EAAE,KAAKC,EAAE,IAAIG,IAAOH,EAAE,EAAE;AACvD;AAoBO,SAASkB,GACdC,GACAhB,GACAiB,GACAC,GACyB;AACzB,QAAMC,IAAQH,EAAO,IAAI,CAACjB,MAASD,GAAUC,GAAMC,CAAI,CAAC,GAClDoB,IAAQ,CAAC,GAAGD,CAAK,EAAE,KAAK,CAACvB,GAAGC,MAC5BD,EAAE,OAAOqB,IAAiB,KAC1BpB,EAAE,OAAOoB,IAAiB,IACvBrB,EAAE,IAAIC,EAAE,KAAKD,EAAE,IAAIC,EAAE,CAC7B,GACKwB,IAAkC,CAAA,GAClCC,IAASL,IACXE,EAAM,KAAK,CAACpB,MAASA,EAAK,OAAOkB,CAAQ,IACzC,QACEM,wBAAgB,IAAA;AACtB,aAAWxB,KAAQqB,GAAO;AACxB,QAAIrB,EAAK,OAAOkB,GAAU;AAOxB,UAAIK,KAAU3B,EAAS2B,GAAQvB,CAAI,GAAG;AACpC,cAAMyB,IAAQ,EAAE,GAAGzB,GAAM,GAAG,KAAK,IAAI,GAAGuB,EAAO,IAAIvB,EAAK,CAAC,EAAA;AACzD,QACE,CAACJ,EAAS2B,GAAQE,CAAK,KACvB,CAACH,EAAO,KAAK,CAACI,MAAMA,EAAE,OAAOR,KAAYtB,EAAS8B,GAAGD,CAAK,CAAC,MAE3DzB,EAAK,IAAIyB,EAAM;AAAA,MAEnB;AACA,UAAIH,EAAO,KAAK,CAACI,MAAM9B,EAAS8B,GAAG1B,CAAI,CAAC,GAAG;AACzC,QAAAwB,EAAU,IAAIxB,EAAK,EAAE;AAGrB,cAAMY,IAASQ,EAAM,OAAO,CAACP,MAAUA,EAAM,OAAOb,EAAK,EAAE;AAC3D,YAAI2B,IAAQ3B,EAAK;AACjB,eAAOsB,EAAO,KAAK,CAACI,MAAM9B,EAAS8B,GAAG,EAAE,GAAG1B,GAAM,GAAG2B,EAAA,CAAO,CAAC;AAC1D,UAAAA,KAAS;AAEX,YAAIC,IAAwC;AAC5C,iBAASnB,IAAI,KAAK,IAAI,GAAGT,EAAK,IAAIA,EAAK,CAAC,GAAGS,KAAKkB,GAAOlB,KAAK;AAC1D,mBAASD,IAAI,GAAGA,KAAKP,IAAOD,EAAK,GAAGQ,KAAK,GAAG;AAC1C,kBAAMG,IAAO,EAAE,GAAGX,GAAM,GAAAQ,GAAG,GAAAC,EAAA;AAM3B,aAJEC,GAAOC,GAAMC,CAAM,KAClBO,MAAY,UACXvB,EAASuB,GAASR,CAAI,KACtB,CAACC,EAAO,KAAK,CAACC,MAAUjB,EAASiB,GAAOF,CAAI,CAAC,OAG/C,CAACiB,KACDb,GAAgB,EAAE,GAAAP,GAAG,GAAAC,EAAA,GAAKT,GAAMC,CAAI,IAClCc,GAAgBa,GAAM5B,GAAMC,CAAI,OAElC2B,IAAO,EAAE,GAAApB,GAAG,GAAAC,EAAA;AAAA,UAEhB;AAEF,YAAImB;AACF,UAAA5B,EAAK,IAAI4B,EAAK,GACd5B,EAAK,IAAI4B,EAAK;AAAA,aACT;AACL,UAAA5B,EAAK,IAAI2B;AAIT,gBAAME,IACJN,MAAW,UACXA,EAAO,IAAIvB,EAAK,KAChBA,EAAK,IAAIuB,EAAO,IAAIA,EAAO,GACvBO,IAAQP,IAASA,EAAO,IAAIvB,EAAK;AACvC,iBACE6B,KACA7B,EAAK,IAAI8B,KACT,CAAClB,EAAO,KAAK,CAACC,MAAUjB,EAASiB,GAAO,EAAE,GAAGb,GAAM,GAAGA,EAAK,IAAI,EAAA,CAAG,CAAC;AAEnE,YAAAA,EAAK,KAAK;AAAA,QAEd;AAAA,MACF;AACA,aAAOsB,EAAO,KAAK,CAACI,MAAM9B,EAAS8B,GAAG1B,CAAI,CAAC;AACzC,QAAAA,EAAK,KAAK;AAEZ,aAAOA,EAAK,IAAI,KAAG;AACjB,cAAM+B,IAAO,EAAE,GAAG/B,GAAM,GAAGA,EAAK,IAAI,EAAA;AACpC,YAAIsB,EAAO,KAAK,CAACI,MAAM9B,EAAS8B,GAAGK,CAAI,CAAC,EAAG;AAC3C,QAAA/B,EAAK,KAAK;AAAA,MACZ;AAAA,IACF;AACA,IAAAsB,EAAO,KAAKtB,CAAI;AAAA,EAClB;AAIA,QAAMgC,IAAUT,IACZ,CAAC,GAAGD,CAAM,EAAE,KAAK,CAACzB,GAAGC,MAAMD,EAAE,IAAIC,EAAE,KAAKD,EAAE,IAAIC,EAAE,CAAC,IACjD,CAAA;AACJ,aAAWE,KAAQgC,GAAS;AAC1B,QAAIhC,EAAK,OAAOkB,KAAYM,EAAU,IAAIxB,EAAK,EAAE,EAAG;AACpD,UAAMY,IAASU,EAAO,OAAO,CAACT,MAAUA,EAAM,OAAOb,EAAK,EAAE;AAC5D,QAAIiC,IAA0C;AAC9C,aAASxB,IAAI,GAAGA,IAAIT,EAAK,KAAK,CAACiC,GAAQxB,KAAK,GAAG;AAC7C,YAAMyB,IAAK,MAAM;AAAA,QACf,EAAE,QAAQ,IAAIlC,EAAK,IAAI,EAAA;AAAA,QACvB,CAACmC,GAAGC,MAAMpC,EAAK,IAAIA,EAAK,IAAIoC;AAAA,MAAA,EAE3B,OAAO,CAAC5B,MAAMA,KAAK,KAAKA,KAAKP,IAAOD,EAAK,CAAC,EAC1C,KAAK,CAACH,GAAGC,MAAM,KAAK,IAAID,IAAIG,EAAK,CAAC,IAAI,KAAK,IAAIF,IAAIE,EAAK,CAAC,KAAKH,IAAIC,CAAC;AACtE,iBAAWU,KAAK0B;AACd,YAAIxB,GAAO,EAAE,GAAGV,GAAM,GAAAQ,GAAG,GAAAC,EAAA,GAAKG,CAAM,GAAG;AACrC,UAAAqB,IAAS,EAAE,GAAAzB,GAAG,GAAAC,EAAA;AACd;AAAA,QACF;AAAA,IAEJ;AACA,QAAIwB;AAGF,WAFAjC,EAAK,IAAIiC,EAAO,GAChBjC,EAAK,IAAIiC,EAAO,GACTjC,EAAK,IAAI,KAAG;AACjB,cAAM+B,IAAO,EAAE,GAAG/B,GAAM,GAAGA,EAAK,IAAI,EAAA;AACpC,YAAIY,EAAO,KAAK,CAACC,MAAUjB,EAASiB,GAAOkB,CAAI,CAAC,EAAG;AACnD,QAAA/B,EAAK,KAAK;AAAA,MACZ;AAAA,EAEJ;AAEA,QAAMqC,IAAO,IAAI,IAAIf,EAAO,IAAI,CAACI,MAAM,CAACA,EAAE,IAAIA,CAAC,CAAC,CAAC;AACjD,SAAOT,EAAO,IAAI,CAACjB,MAASqC,EAAK,IAAIrC,EAAK,EAAE,CAA0B;AACxE;AAGO,SAASsC,GACdrB,GACAsB,GACA/B,GACAC,GACAR,GACyB;AACzB,QAAMuC,IAAOvB,EAAO;AAAA,IAAI,CAACjB,MACvBA,EAAK,OAAOuC,IAAKxC,GAAU,EAAE,GAAGC,GAAM,GAAAQ,GAAG,GAAAC,EAAA,GAAKR,CAAI,IAAID;AAAA,EAAA;AAExD,SAAOgB;AAAA,IACLwB;AAAA,IACAvC;AAAA,IACAsC;AAAA,IACAtB,EAAO,KAAK,CAACjB,MAASA,EAAK,OAAOuC,CAAE;AAAA,EAAA;AAExC;AAGO,SAASE,GACdxB,GACAsB,GACAjC,GACAC,GACAN,GACyB;AACzB,QAAMuC,IAAOvB,EAAO;AAAA,IAAI,CAACjB,MACvBA,EAAK,OAAOuC;AAAA;AAAA;AAAA;AAAA;AAAA,MAKRxC;AAAA,QACE;AAAA,UACE,GAAGC;AAAA,UACH,GAAG,KAAK,IAAIA,EAAK,QAAQ,GAAG,KAAK,IAAIM,GAAGL,IAAOD,EAAK,CAAC,CAAC;AAAA,UACtD,GAAAO;AAAA,QAAA;AAAA,QAEFN;AAAA,MAAA;AAAA,QAEFD;AAAA,EAAA;AAEN,SAAOgB,GAAUwB,GAAMvC,GAAMsC,CAAE;AACjC;AAGO,SAASG,GACdzB,GACAhB,GACAK,GACAC,GAC0B;AAC1B,QAAMoC,IAAQ,KAAK,IAAI,KAAK,IAAI,GAAGrC,CAAC,GAAGL,CAAI,GACrC2C,IAAO3B,EAAO,OAAO,CAAC4B,GAAG7C,MAAS,KAAK,IAAI6C,GAAG7C,EAAK,IAAIA,EAAK,CAAC,GAAG,CAAC;AACvE,WAASS,IAAI,GAAGA,KAAKmC,GAAMnC,KAAK;AAC9B,aAASD,IAAI,GAAGA,KAAKP,IAAO0C,GAAOnC,KAAK,GAAG;AACzC,YAAMsC,IAAmC;AAAA,QAEvC,GAAAtC;AAAA,QACA,GAAAC;AAAA,QACA,GAAGkC;AAAA,QACH,GAAApC;AAAA,MAAA;AAEF,UAAI,CAACU,EAAO,KAAK,CAACjB,MAASJ,EAASI,GAAM8C,CAAS,CAAC;AAClD,eAAO,EAAE,GAAAtC,GAAG,GAAAC,EAAA;AAAA,IAEhB;AAEF,SAAO,EAAE,GAAG,GAAG,GAAGmC,EAAA;AACpB;AAGO,SAASG,GAAS9B,GAAyC;AAChE,SAAOA,EAAO,OAAO,CAAC4B,GAAG7C,MAAS,KAAK,IAAI6C,GAAG7C,EAAK,IAAIA,EAAK,CAAC,GAAG,CAAC;AACnE;AAcO,MAAMgD,KAAsB;AAQ5B,SAASC,GACdC,GACAC,GACAC,GACS;AACT,SACED,MAAe,UACf,CAAC,OAAO,SAASA,CAAU,KAC3BA,KAAc,IAEP,KAEL,CAAC,OAAO,SAASD,CAAU,KAAKA,KAAc,IAAUE,IACrDA,IACHF,IAAaC,IAAaH,KAC1BE,IAAaC;AACnB;AAOO,SAASE,GACdC,GACArC,GACU;AACV,QAAMoB,IAAO,IAAI,IAAIpB,EAAO,IAAI,CAACjB,MAAS,CAACA,EAAK,IAAIA,CAAI,CAAC,CAAC;AAC1D,SAAOsD,EACJ,IAAI,CAACf,GAAIgB,OAAW,EAAE,IAAAhB,GAAI,OAAAgB,GAAO,OAAOlB,EAAK,IAAIE,CAAE,EAAA,EAAI,EACvD,KAAK,CAAC1C,GAAGC,MACJ,CAACD,EAAE,SAAS,CAACC,EAAE,QACbD,EAAE,QAAc,KAChBC,EAAE,QAAc,IACbD,EAAE,QAAQC,EAAE,QAGnBD,EAAE,MAAM,IAAIC,EAAE,MAAM,KAAKD,EAAE,MAAM,IAAIC,EAAE,MAAM,KAAKD,EAAE,QAAQC,EAAE,KAEjE,EACA,IAAI,CAAC,EAAE,IAAAyC,EAAA,MAASA,CAAE;AACvB;AC5SA,MAAMiB,KAAwBC;AAAA,EAC5B;AAAA,IACE;AAAA;AAAA,IAEA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA,IAIA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AAAA,EACV;AAAA,IACE,UAAU;AAAA;AAAA;AAAA;AAAA,MAIR,SAAS;AAAA,QACP,OAAO;AAAA,UACL;AAAA,UACA;AAAA,QAAA,EACA,KAAK,GAAG;AAAA,QACV,MAAM;AAAA,UACJ;AAAA,UACA;AAAA,QAAA,EACA,KAAK,GAAG;AAAA,MAAA;AAAA,IACZ;AAAA,IAEF,iBAAiB,EAAE,SAAS,GAAA;AAAA,EAAM;AAEtC,GAEMC,KAAiBD;AAAA,EACrB;AAAA,IACE;AAAA;AAAA;AAAA,IAGA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA,IACA;AAAA;AAAA,IAEA;AAAA;AAAA;AAAA,IAGA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA,IAGA;AAAA,EAAA,EACA,KAAK,GAAG;AAAA,EACV;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,OAAO;AAAA,UACL;AAAA,UACA;AAAA,QAAA,EACA,KAAK,GAAG;AAAA,QACV,MAAM;AAAA,MAAA;AAAA,MAER,eAAe,EAAE,MAAM,IAAI,SAAS,GAAA;AAAA,IAAG;AAAA,IAEzC,kBAAkB;AAAA,MAChB,EAAE,SAAS,IAAO,OAAO,sBAAA;AAAA;AAAA;AAAA;AAAA,MAIzB;AAAA,QACE,SAAS;AAAA,QACT,eAAe;AAAA,QACf,OAAO;AAAA,UACL;AAAA,UACA;AAAA,QAAA,EACA,KAAK,GAAG;AAAA,MAAA;AAAA;AAAA;AAAA,MAIZ;AAAA,QACE,SAAS;AAAA,QACT,eAAe;AAAA,QACf,OAAO;AAAA,UACL;AAAA,UACA;AAAA,QAAA,EACA,KAAK,GAAG;AAAA,MAAA;AAAA,IACZ;AAAA,IAEF,iBAAiB,EAAE,SAAS,IAAO,eAAe,OAAA;AAAA,EAAO;AAE7D,GAEME,KAAqBF;AAAA,EACzB;AAAA,EACA;AAAA,IACE,UAAU;AAAA;AAAA;AAAA,MAGR,KAAK;AAAA,QACH,KAAK;AAAA,QACL,SAAS;AAAA,MAAA;AAAA;AAAA;AAAA;AAAA,MAKX,SAAS;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,UACJ;AAAA,UACA;AAAA,QAAA,EACA,KAAK,GAAG;AAAA,MAAA;AAAA,IACZ;AAAA,IAEF,iBAAiB,EAAE,KAAK,OAAO,SAAS,GAAA;AAAA,EAAM;AAElD,GAKMG,KAAqBH;AAAA,EACzB;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AACZ,GAMMI,KAAqBJ;AAAA,EACzB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,MAAM;AAAA,QACJ,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,QAAQ;AAAA,MAAA;AAAA,IACV;AAAA,IAEF,iBAAiB,EAAE,MAAM,SAAA;AAAA,EAAS;AAEtC,GAKMK,KACJ,uEAIIC,KAAuBN;AAAA,EAC3B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MAAA;AAAA,IACR;AAAA,IAEF,iBAAiB,EAAE,SAAS,GAAA;AAAA,EAAM;AAEtC,GAIMO,KAAsBP;AAAA,EAC1B;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AACZ,GAyNMQ,KAAuBC;AAAA,EAC3B;AACF;AAUA,SAASC,GAAaC,GAA+C;AACnE,SAAOA,MAAU,UAAa,OAAO,SAASA,CAAK,KAAKA,KAAS,IAC7D,KAAK,MAAMA,CAAK,IAChB;AACN;AAGA,SAASC,GACPC,GACAC,GACM;AACN,EAAAC,GAAS,QAAQF,GAAU,CAACG,MAAU;AACpC,QAAKC,GAAeD,CAAK,GACzB;AAAA,UAAIA,EAAM,SAASE,IAAU;AAC3B,QAAAN;AAAA,UACGI,EAAM,MAAmC;AAAA,UAC1CF;AAAA,QAAA;AAEF;AAAA,MACF;AACA,MAAAA,EAAGE,CAA+C;AAAA;AAAA,EACpD,CAAC;AACH;AAMA,SAASG,GAAoB;AAAA,EAC3B,IAAArC;AAAA,EACA,OAAAsC;AAAA,EACA,kBAAAC;AAAA,EACA,SAAAC;AAAA,EACA,aAAAC;AAAA,EACA,UAAAV;AACF,GAA6B;;AAC3B,QAAM,EAAE,GAAAW,EAAA,IAAMC,GAAe,IAAI,GAC3BC,IAAMC,GAAWnB,EAAoB,GACrCoB,IAAaC,EAAuB,IAAI,GAExCC,IAAYD,EAAqC,IAAI,GAQrDE,IAAQL,KAAA,gBAAAA,EAAK,WAAW,IAAI5C,IAK5B,CAACkD,GAAWC,CAAY,IAAIC,EAA6B,IAAI,GAC7D,CAACC,GAAUC,CAAW,IAAIF,EAAS,EAAK,GACxC,CAACG,GAAcC,CAAe,IAAIJ,EAAS,EAAK,GAChD,CAACK,GAASC,CAAU,IAAIN,EAAS,EAAK;AA6C5C,MA5CAO,EAAU,MAAM;AACd,QAAI,CAACT,EAAW;AAChB,UAAMU,IAAU,MACdN,EAAYJ,EAAU,cAAcA,EAAU,WAAW;AAC3D,IAAAU,EAAA;AAEA,UAAMC,IAAQ,OAAO,WAAa,MAAc,SAAS,QAAQ;AACjE,IAAAA,KAAA,QAAAA,EAAO,iBAAiB,eAAeD;AACvC,UAAME,IACJ,OAAO,iBAAmB,MACtB,SACA,IAAI,eAAeF,CAAO;AAChC,WAAAE,KAAA,QAAAA,EAAU,QAAQZ,IACX,MAAM;AACX,MAAAW,KAAA,QAAAA,EAAO,oBAAoB,eAAeD,IAC1CE,KAAA,QAAAA,EAAU;AAAA,IACZ;AAAA,EACF,GAAG,CAACZ,GAAWZ,CAAK,CAAC,GAGrBqB,EAAU,MAAM;AACd,IAAKN,KAAUK,EAAW,EAAK;AAAA,EACjC,GAAG,CAACL,CAAQ,CAAC,GAIbU,GAA0B,MAAM;AAC9B,UAAMC,IAAOlB,EAAW;AACxB,IAAI,CAACkB,KAAQ,CAACf,MACde,EAAK,MAAM,YAAY,UAAU,OAAOf,EAAM,IAAI,CAAC,CAAC,GACpDe,EAAK,MAAM,YAAY,UAAU,OAAOf,EAAM,IAAI,CAAC,CAAC,GACpDe,EAAK,MAAM,YAAY,UAAU,OAAOf,EAAM,CAAC,CAAC,GAChDe,EAAK,MAAM,YAAY,UAAU,OAAOf,EAAM,CAAC,CAAC,GAEhDe,EAAK,MAAM;AAAA,MACT;AAAA,MACAzB,MAAqB,UACnB,OAAO,SAASA,CAAgB,KAChCA,IAAmB,IACjB,GAAGA,CAAgB,OACnB;AAAA,IAAA;AAAA,EAER,GAAG,CAACU,KAAA,gBAAAA,EAAO,GAAGA,KAAA,gBAAAA,EAAO,GAAGA,KAAA,gBAAAA,EAAO,GAAGA,KAAA,gBAAAA,EAAO,GAAGA,GAAOV,CAAgB,CAAC,GAEhE,CAACK,KAAO,CAACK,EAAO,QAAO;AAE3B,QAAMgB,MAAUC,KAAAtB,EAAI,SAAJ,gBAAAsB,GAAU,QAAOlE,GAC3BmE,IAAUvB,EAAI,SAGdwB,IAAyC;AAAA,IAC7C,GAAI5B,KAAW,CAAA;AAAA,IACf,GAAI2B,KAAWvB,EAAI,YACf;AAAA,MACE;AAAA,QACE,IAAIyB;AAAA,QACJ,OAAO3B,EAAE,wBAAwB,EAAE,OAAAJ,GAAO;AAAA,QAC1C,wBAAOgC,IAAA,EAAE;AAAA,QACT,UAAU,MAAM1B,EAAI,cAAc5C,CAAE;AAAA,MAAA;AAAA,IACtC,IAEF,CAAA;AAAA,EAAC,GAEDuE,KAAWH,EAAc,SAAS,GAClCI,IAAW5B,EAAI,eAChB,IAAIA,EAAI,YAAY,KACrB;AAEJ,SACE,gBAAA6B;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAK3B;AAAA,MACL,MAAK;AAAA,MACL,cAAYR;AAAA,MACZ,kBAAe;AAAA,MACf,kBAAgBtC;AAAA,MAChB,gBAAciE,KAAW;AAAA,MACzB,iBAAerB,EAAI,eAAe5C,KAAM;AAAA,MACxC,iBAAe4C,EAAI,eAAe5C,KAAM;AAAA,MACxC,gBAAc4C,EAAI,eAAe5C,IAAK,SAAS;AAAA,MAC/C,WAAWmB,GAAe;AAAA,QACxB,SAASyB,EAAI;AAAA,QACb,eAAeA,EAAI;AAAA,MAAA,CACpB;AAAA,MAED,UAAA;AAAA,QAAA,gBAAA6B;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAWjD,GAAqB,EAAE,SAAA2C,GAAS;AAAA,YAC3C,eACEA,IAAU,CAACO,MAAU9B,EAAI,iBAAiB5C,GAAI0E,CAAK,IAAI;AAAA,YAGxD,UAAA;AAAA,cAAAP,IACC,gBAAAQ;AAAA,gBAACC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,QAAO;AAAA,kBACP,MAAK;AAAA,kBACL,wBAAOC,IAAA,EAAa;AAAA,kBACpB,cAAYnC,EAAE,sBAAsB,EAAE,OAAAJ,GAAO;AAAA,kBAC7C,gBAAc2B,OAAWa,KAAAlC,EAAI,SAAJ,gBAAAkC,GAAU,UAAS;AAAA,kBAC5C,WAAW,gCAAgCvD,EAAqB;AAAA,kBAChE,eAAe,CAACmD,MAAU9B,EAAI,iBAAiB,QAAQ5C,GAAI0E,CAAK;AAAA,kBAChE,WAAW,CAACA,MAAU9B,EAAI,aAAa8B,GAAO1E,CAAE;AAAA,kBAChD,SAAS,MAAM4C,EAAI,kBAAkB,QAAQ5C,CAAE;AAAA,gBAAA;AAAA,cAAA,IAE/C;AAAA,cACJ,gBAAA2E;AAAA,gBAACI;AAAA,gBAAA;AAAA,kBACC,OAAOzC;AAAA,kBACP,MAAMe,KAAYI;AAAA,kBAClB,cAAc,CAACxD,MAASyD,EAAWzD,KAAQoD,CAAQ;AAAA,kBAEnD,UAAA,gBAAAsB;AAAA,oBAACH;AAAA,oBAAA;AAAA,sBACC,KAAKrB;AAAA,sBAGL,UAAUE,KAAYE,IAAe,IAAI;AAAA,sBACzC,6BAA0B;AAAA,sBAC1B,SAAS,MAAMC,EAAgB,EAAI;AAAA,sBACnC,QAAQ,MAAMA,EAAgB,EAAK;AAAA,sBACnC,WAAW/B,GAAA;AAAA,sBAEV,UAAAa;AAAA,oBAAA;AAAA,kBAAA;AAAA,gBACH;AAAA,cAAA;AAAA,cAEDG;AAAA,cACA2B,EAAc,SAAS,IACtB,gBAAAO;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,WAAWrD,GAAmB;AAAA,oBAC5B,MAAMiD,KAAW,SAAS;AAAA,kBAAA,CAC3B;AAAA,kBAEA,UAAAH,EAAc,IAAI,CAACY,MAClB,gBAAAL;AAAA,oBAACC;AAAA,oBAAA;AAAA,sBAEC,MAAK;AAAA,sBACL,QAAO;AAAA,sBACP,MAAK;AAAA,sBACL,MAAMI,EAAO;AAAA,sBACb,WAAWzD;AAAA,sBACX,cAAYyD,EAAO;AAAA,sBACnB,SAASA,EAAO;AAAA,oBAAA;AAAA,oBAPXA,EAAO;AAAA,kBAAA,CASf;AAAA,gBAAA;AAAA,cAAA,IAED;AAAA,cACHT,KACC,gBAAAI,EAAC,OAAA,EAAI,WAAWrD,GAAmB,EAAE,MAAM,SAAA,CAAU,GACnD,UAAA,gBAAAmD,GAACQ,GAAa,MAAb,EAAkB,OAAO,IACxB,UAAA;AAAA,kCAACA,GAAa,SAAb,EAAqB,SAAO,IAC3B,UAAA,gBAAAN;AAAA,kBAACC;AAAA,kBAAA;AAAA,oBACC,MAAK;AAAA,oBACL,QAAO;AAAA,oBACP,MAAK;AAAA,oBACL,wBAAOM,IAAA,EAAS;AAAA,oBAChB,WAAW3D;AAAA,oBACX,cAAYmB,EAAE,6BAA6B,EAAE,OAAAJ,GAAO;AAAA,kBAAA;AAAA,gBAAA,GAExD;AAAA,gBACA,gBAAAqC;AAAA,kBAACM,GAAa;AAAA,kBAAb;AAAA,oBACC,OAAM;AAAA,oBAGN,kBAAkB,CAACP,MAAU;AAC3B,4BAAMM,IAAShC,EAAU;AAEzB,0BADAA,EAAU,UAAU,MAChB,CAACgC,EAAQ;AACb,4BAAMG,IAAS,SAAS;AACxB,sBAAAH,EAAO,SAAA,IAELA,EAAO,OAAOX,MACd,SAAS,kBAAkBc,MAE3BT,EAAM,eAAA;AAAA,oBAEV;AAAA,oBAEC,UAAAN,EAAc,IAAI,CAACY,MAClB,gBAAAL;AAAA,sBAACM,GAAa;AAAA,sBAAb;AAAA,wBAEC,WAAWD,EAAO;AAAA,wBAClB,UAAU,MAAM;AACd,0BAAAhC,EAAU,UAAUgC;AAAA,wBACtB;AAAA,wBAEC,UAAAA,EAAO;AAAA,sBAAA;AAAA,sBANHA,EAAO;AAAA,oBAAA,CAQf;AAAA,kBAAA;AAAA,gBAAA;AAAA,cACH,EAAA,CACF,EAAA,CACF,IACE;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAEN,gBAAAL;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAWvD,GAAmB;AAAA,cAC5B,KACEwB,EAAI,WAAWA,EAAI,kBAAkB,YAAY,YAAY;AAAA,cAC/D,SAAAuB;AAAA,YAAA,CACD;AAAA,YAEA,UAAApC;AAAA,UAAA;AAAA,QAAA;AAAA,QAEFoC,IACC,gBAAAQ;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,cAAYjC,EAAE,wBAAwB,EAAE,OAAAJ,GAAO;AAAA,YAC/C,gBAAc2B,OAAWmB,IAAAxC,EAAI,SAAJ,gBAAAwC,EAAU,UAAS;AAAA,YAC5C,WAAW/D,GAAA;AAAA,YACX,eAAe,CAACqD,MAAU9B,EAAI,iBAAiB,UAAU5C,GAAI0E,CAAK;AAAA,YAClE,WAAW,CAACA,MAAU9B,EAAI,aAAa8B,GAAO1E,CAAE;AAAA,YAChD,SAAS,MAAM4C,EAAI,kBAAkB,UAAU5C,CAAE;AAAA,YAEjD,UAAA,gBAAA2E,EAAC3H,IAAA,EAAc,eAAY,QAAO;AAAA,UAAA;AAAA,QAAA,IAElC;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGV;AACAqF,GAAoB,cAAc;AA0ClC,MAAMgD,KAAiB,KACjBC,KAAsB,MAGtBC,KAAuB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,IAAI,GAGLlB,KAAmB,cAGnBmB,KAAoB,GAEpBC,KAAgB,KAEhBC,KAAgB,GAEhBC,KAAsB,IACtBC,KAAqB;AAG3B,SAASC,GAAmB7B,GAG1B;AACA,QAAM8B,IAA0D;AAAA,IAC9D,GAAG;AAAA,IACH,GAAG;AAAA,EAAA,GAECC,IAAU,CAAClE,MACfA,MAAU,UAAUA,MAAU,YAAYA,MAAU;AACtD,WACMmE,IAAUhC,EAAK,eACnBgC,KACAA,MAAY,SAAS,QACrBA,MAAY,SAAS,mBACrB,EAAEF,EAAM,KAAKA,EAAM,IACnBE,IAAUA,EAAQ,eAClB;AACA,UAAMC,IAAS,OAAO,iBAAiBD,CAAO;AAC9C,IACE,CAACF,EAAM,KACPC,EAAQE,EAAO,SAAS,KACxBD,EAAQ,eAAeA,EAAQ,iBAE/BF,EAAM,IAAIE,IAGV,CAACF,EAAM,KACPC,EAAQE,EAAO,SAAS,KACxBD,EAAQ,cAAcA,EAAQ,gBAE9BF,EAAM,IAAIE;AAAA,EAEd;AACA,SAAOF;AACT;AAQA,SAASI,GACPC,GACAC,GACApG,GACAqG,GACAC,GACA5I,GACA6I,IAAS,IACgB;AACzB,QAAMC,IAAQL,EAAK,KAAK,CAAC1I,MAASA,EAAK,OAAOuC,CAAE;AAChD,MAAI,CAACwG,EAAO,QAAOL;AACnB,QAAMM,IAASF,IAAS/F,GAAS2F,CAAI,IAAI,IAAI,OAAO,mBAC9ClG,IACJmG,MAAS,SACLrG,GAASoG,GAAMnG,GAAIqG,GAAQ,KAAK,IAAIC,GAAOG,IAASD,EAAM,CAAC,GAAG9I,CAAI,IAClEwC,GAAWiG,GAAMnG,GAAIqG,GAAQ,KAAK,IAAIC,GAAOG,IAASD,EAAM,CAAC,GAAG9I,CAAI,GACpEgJ,IAAQzG,EAAK,KAAK,CAACxC,MAASA,EAAK,OAAOuC,CAAE;AAOhD,SALE0G,MAAU,UACVA,EAAM,MAAMF,EAAM,KAClBE,EAAM,MAAMF,EAAM,KAClBE,EAAM,MAAMF,EAAM,KAClBE,EAAM,MAAMF,EAAM,IACDL,IAAOlG;AAC5B;AAGA,SAAS0G,GAAUC,GAA0B;AAC3C,MAAIA,KAAYjB,GAAqB,QAAO;AAC5C,QAAMkB,KACHlB,KAAsB,KAAK,IAAI,GAAGiB,CAAQ,KAAKjB;AAClD,SAAO,KAAK,KAAKkB,IAAQjB,EAAkB;AAC7C;AAEA,MAAMkB,KAAoBC;AAAA,EACxB,CACE;AAAA,IACE,cAAcC;AAAA,IACd,IAAAhH;AAAA,IACA,MAAAtC,IAAO;AAAA,IACP,WAAAuJ,IAAY;AAAA,IACZ,QAAQC;AAAA,IACR,eAAAC;AAAA,IACA,gBAAAC;AAAA,IACA,SAAAjD,IAAU;AAAA,IACV,gBAAAkD;AAAA,IACA,cAAAC;AAAA,IACA,YAAA1G;AAAA,IACA,iBAAA2G;AAAA,IACA,eAAAC,IAAgB;AAAA,IAChB,YAAAC;AAAA,IACA,oBAAAC;AAAA,IACA,UAAA3F;AAAA,IACA,WAAA4F;AAAA,EAAA,GAEFC,MACG;AACH,UAAM,EAAE,GAAAlF,EAAA,IAAMC,GAAe,IAAI,GAC3BkF,IAAU9E,EAAuB,IAAI,GACrC+E,IAAU/E,EAAuB,IAAI,GAUrC,CAACgF,GAASC,EAAU,IAAI5E,EAAS,EAAK,GACtC6E,IAAalF,EAAO,EAAK;AAC/B,IAAAkF,EAAW,UAAUF;AAGrB,UAAMG,KAAkBnF,EAGd,IAAI,GAERoF,KAAgBC,EAAY,CAACnI,MAAkB;;AACnD,UAAIA,MAASgI,EAAW,QAAS;AACjC,YAAMI,IAAOR,EAAQ,SACfS,IACJ,OAAO,WAAa,MAAc,SAAS,gBAAgB;AAC7D,MAAAJ,GAAgB,UACdG,KAAQC,aAAmB,eAAeD,EAAK,SAASC,CAAO,IAC3D;AAAA,QACE,SAASA;AAAA,QACT,YACEpE,IAAAoE,EACG,QAAqB,kBAAkB,MAD1C,gBAAApE,EAEI,aAAa,sBAAqB;AAAA,MAAA,IAE1C,MACN+D,EAAW,UAAUhI,GACrB+H,GAAW/H,CAAI;AAAA,IACjB,GAAG,CAAA,CAAE;AAEL,IAAA8D,GAA0B,MAAM;AAC9B,YAAMC,IAAO6D,EAAQ;AACrB,UAAI,CAAC7D,EAAM;AACX,UAAIpD,MAAe,QAAW;AAC5B,QAAAuH,GAAc,EAAK;AACnB;AAAA,MACF;AAIA,UAHAA;AAAA,QACEzH,GAAYsD,EAAK,aAAapD,GAAYqH,EAAW,OAAO;AAAA,MAAA,GAE1D,OAAO,iBAAmB,IAAa;AAC3C,YAAMnE,IAAW,IAAI,eAAe,CAACyE,MAAY;;AAC/C,cAAMtF,IAAQsF,EAAQA,EAAQ,SAAS,CAAC;AACxC,YAAI,CAACtF,EAAO;AACZ,cAAMtC,MACJmE,KAAAZ,IAAAjB,EAAM,kBAAN,gBAAAiB,EAAsB,OAAtB,gBAAAY,EAA0B,eAAc7B,EAAM,YAAY;AAC5D,QAAAkF,GAAczH,GAAYC,GAAYC,GAAYqH,EAAW,OAAO,CAAC;AAAA,MACvE,CAAC;AACD,aAAAnE,EAAS,QAAQE,CAAI,GACd,MAAMF,EAAS,WAAA;AAAA,IACxB,GAAG,CAAClD,GAAYuH,EAAa,CAAC;AAG9B,UAAMK,IAAWrE,KAAW,CAAC4D,GAWvBU,IAAWC,GAAQ,MAAM;AAC7B,YAAM3H,IAAgB,CAAA;AACtB,aAAAe,GAAmBC,GAAU,CAACG,MAAU;AACtC,QAAIA,EAAM,MAAM,QAAQ,KAAKA,EAAM,MAAM,EAAE;AAAA,MAC7C,CAAC,GACMnB;AAAA,IACT,GAAG,CAACgB,CAAQ,CAAC,GACP4G,IAAYD,GAAQ,MAAM;AAC9B,YAAME,wBAAW,IAAA;AACjB,aAAA9G,GAAmBC,GAAU,CAACG,MAAU;AACtC,QAAIA,EAAM,MAAM,MACd0G,EAAK,IAAI1G,EAAM,MAAM,IAAI;AAAA,UACvB,UAAUA,EAAM,MAAM,YAAY;AAAA,UAClC,UAAUA,EAAM,MAAM,YAAY;AAAA,UAClC,MAAMN,GAAaM,EAAM,MAAM,IAAI;AAAA,UACnC,MAAMN,GAAaM,EAAM,MAAM,IAAI;AAAA,QAAA,CACpC;AAAA,MAEL,CAAC,GACM0G;AAAA,IACT,GAAG,CAAC7G,CAAQ,CAAC,GAGP,CAAC8G,GAAgBC,EAAiB,IAAI1F,EAE1C,MAAM+D,KAAiB,EAAE,GACrB4B,KAAY7B,KAAc2B,GAC1BG,KAAejG,EAAOgG,EAAS;AACrC,IAAAC,GAAa,UAAUD;AAIvB,UAAME,KAAgBb;AAAA,MACpB,CAAC1J,MACCA,EAAO,IAAI,CAACjB,MAAS;AACnB,cAAMyL,IAAMF,GAAa,QAAQ,KAAK,CAACG,MAAMA,EAAE,OAAO1L,EAAK,EAAE,GACvD,EAAE,MAAM2L,GAAO,MAAMC,GAAO,GAAGC,MAAS7L;AAC9C,eAAO;AAAA,UACL,GAAG6L;AAAA,UACH,IAAIJ,KAAA,gBAAAA,EAAK,UAAS,SAAY,EAAE,MAAMA,EAAI,KAAA,IAAS,CAAA;AAAA,UACnD,IAAIA,KAAA,gBAAAA,EAAK,UAAS,SAAY,EAAE,MAAMA,EAAI,SAAS,CAAA;AAAA,QAAC;AAAA,MAExD,CAAC;AAAA,MACH,CAAA;AAAA,IAAC,GAGGK,IAASnB;AAAA,MACb,CAACnI,MAAkC;AACjC,cAAMuJ,IAAWP,GAAchJ,CAAI;AACnC,QAAIiH,MAAe,UAAW4B,GAAkBU,CAAQ,GACxDpC,KAAA,QAAAA,EAAiBoC;AAAA,MACnB;AAAA,MACA,CAACtC,GAAYE,GAAgB6B,EAAa;AAAA,IAAA,GAStC,EAAE,UAAAQ,GAAU,YAAAC,GAAA,IAAehB,GAAQ,MAAM;AAC7C,YAAMiB,IAAc,CAAC1G,MAAiC;AACpD,cAAM2F,IAAOD,EAAU,IAAI1F,EAAM,EAAE;AACnC,eAAOzF;AAAA,UACL;AAAA,YACE,GAAGyF;AAAA,YACH,IAAI2F,KAAA,gBAAAA,EAAM,UAAS,SACf,EAAE,MAAM,KAAK,IAAI3F,EAAM,QAAQ,GAAG2F,EAAK,IAAI,EAAA,IAC3C,CAAA;AAAA,YACJ,IAAIA,KAAA,gBAAAA,EAAM,UAAS,SACf,EAAE,MAAM,KAAK,IAAI3F,EAAM,QAAQ,GAAG2F,EAAK,IAAI,EAAA,IAC3C,CAAA;AAAA,UAAC;AAAA,UAEPlL;AAAA,QAAA;AAAA,MAEJ,GACMkM,IAAUb,GAAU,IAAIY,CAAW,GACnCE,IAAUpB,EAAS;AAAA,QACvB,CAACqB,MAAQ,CAACF,EAAQ,KAAK,CAAC3G,MAAUA,EAAM,OAAO6G,CAAG;AAAA,MAAA;AAEpD,UAAID,EAAQ,WAAW;AAMrB,eAAO;AAAA,UACL,UAJkBD,EAAQ;AAAA,YAAK,CAAC3G,GAAOpD,MACvC+J,EAAQ,KAAK,CAACtL,GAAOyL,MAAMA,IAAIlK,KAAKxC,EAAS4F,GAAO3E,CAAK,CAAC;AAAA,UAAA,IAGlCG,GAAUmL,GAASlM,CAAI,IAAIkM;AAAA,UACnD,YAAY;AAAA,QAAA;AAGhB,YAAM7K,IAAS,CAAC,GAAG6K,CAAO;AAC1B,iBAAWE,KAAOD,GAAS;AACzB,cAAMjB,IAAOD,EAAU,IAAImB,CAAG,KAAK,EAAE,UAAU,GAAG,UAAU,EAAA,GACtD/L,IAAI,KAAK,IAAI,KAAK,IAAI6K,EAAK,UAAUA,EAAK,QAAQ,CAAC,GAAGlL,CAAI,GAC1DM,IAAI,KAAK,IAAI4K,EAAK,UAAUA,EAAK,QAAQ,CAAC,GAC1CoB,IAAO7J,GAASpB,GAAQrB,GAAMK,GAAGC,CAAC;AACxC,QAAAe,EAAO,KAAK4K,EAAY,EAAE,IAAIG,GAAK,GAAGE,EAAK,GAAG,GAAGA,EAAK,GAAG,GAAAjM,GAAG,GAAAC,EAAA,CAAG,CAAC;AAAA,MAClE;AACA,aAAO,EAAE,UAAUS,GAAUM,GAAQrB,CAAI,GAAG,YAAY,GAAA;AAAA,IAC1D,GAAG,CAACqL,IAAWN,GAAUE,GAAWjL,CAAI,CAAC,GAKnCuM,KAAclH,EAAO,EAAE;AAC7B,IAAAY,EAAU,MAAM;AACd,UAAI,CAAC+F,GAAY;AACjB,YAAMQ,IAAYT,EACf;AAAA,QACC,CAACxG,MAAU,GAAGA,EAAM,EAAE,IAAIA,EAAM,CAAC,IAAIA,EAAM,CAAC,IAAIA,EAAM,CAAC,IAAIA,EAAM,CAAC;AAAA,MAAA,EAEnE,KAAK,GAAG;AACX,MAAIgH,GAAY,YAAYC,MAC1BD,GAAY,UAAUC,GACtBX,EAAOE,CAAQ;AAAA,IAEnB,GAAG,CAACC,IAAYD,GAAUF,CAAM,CAAC;AAOjC,UAAM,CAACY,IAAOC,EAAQ,IAAIhH,EAAyC,IAAI,GACjE,CAACiH,IAAMC,EAAO,IAAIlH,EAA2B,IAAI,GACjD,CAACmH,IAAcC,EAAe,IAAIpH,EAAS,EAAE,GAC7CqH,KAAW1H,EAAuC,IAAI,GACtD2H,IAAU3H,EAEd,IAAI,GACA4H,KAAiB5H,EAAgC,IAAI,GAKrD6H,KAAmB7H,EAAO,EAAK,GAC/B8H,KAAU9H,EAAOrF,CAAI;AAC3B,IAAAmN,GAAQ,UAAUnN;AAClB,UAAMoN,KAAc/H,EAAO0G,CAAQ;AACnC,IAAAqB,GAAY,UAAUrB;AAEtB,UAAMsB,KAAa3C,EAAY,CAACnI,MAAyC;AACvE,MAAAwK,GAAS,UAAUxK,GACnBmK,GAASnK,CAAI;AAAA,IACf,GAAG,CAAA,CAAE,GAEC+K,KAAY5C;AAAA,MAChB,CACEhC,GACA6E,GACAC,MACG;AACH,cAAMC,IAAmB,EAAE,MAAA/E,GAAM,IAAI6E,GAAU,KAAAC,EAAA;AAM/C,QAAAR,EAAQ,UAAU,EAAE,GAAGS,GAAO,YAAYL,GAAY,QAAA,GACtDR,GAAQa,CAAK,GACbJ,GAAWD,GAAY,OAAO;AAAA,MAChC;AAAA,MACA,CAACC,EAAU;AAAA,IAAA,GAGP/L,KAASmL,MAASV,GAClB2B,KAAa1C;AAAA,MACjB,MAAM,IAAI,IAAI1J,GAAO,IAAI,CAACiE,MAAU,CAACA,EAAM,IAAIA,CAAK,CAAC,CAAC;AAAA,MACtD,CAACjE,EAAM;AAAA,IAAA,GAGHqM,KAAgBjD;AAAA,MACpB,CAAChC,GAAyBnD,MAAiC;AACzD,QAAAuH;AAAA,UACEpE,MAAS,SACL1D,EAAE,yBAAyB,EAAE,KAAKO,EAAM,IAAI,GAAG,KAAKA,EAAM,IAAI,GAAG,IACjEP,EAAE,2BAA2B,EAAE,MAAMO,EAAM,GAAG,MAAMA,EAAM,EAAA,CAAG;AAAA,QAAA;AAAA,MAErE;AAAA,MACA,CAACP,CAAC;AAAA,IAAA,GAME4I,IAAiBvI,EAA4B,IAAI,GAEjDwI,IAAUnD;AAAA,MACd,CAACoD,MAAyB;;AACxB,SAAAtH,IAAAoH,EAAe,YAAf,QAAApH,EAAA,KAAAoH,IACAA,EAAe,UAAU;AACzB,cAAMtF,IAAUyE,GAAS,SACnBxG,IAAUyG,EAAQ;AAKxB,YAJAA,EAAQ,UAAU,MAClBC,GAAe,UAAU,MACzBL,GAAQ,IAAI,GACZS,GAAW,IAAI,GACX,CAACS,KAAe,CAACxF,KAAW,CAAC/B,GAAS;AACxC,UAAAuG,GAAgB9H,EAAE,yBAAyB,CAAC;AAC5C;AAAA,QACF;AAKA,cAAM+I,IAAQhN,GAAUuH,GAAS6E,GAAQ,OAAO,GAC1Ca,IAAc,CAAChN,MACnBA,EAAO,IAAI,CAACyK,MAAM,GAAGA,EAAE,EAAE,IAAIA,EAAE,CAAC,IAAIA,EAAE,CAAC,IAAIA,EAAE,CAAC,IAAIA,EAAE,CAAC,EAAE,EAAE,KAAK,GAAG;AACnE,YAAIuC,EAAYD,CAAK,MAAMC,EAAYZ,GAAY,OAAO,GAAG;AAC3D,UAAAN,GAAgB9H,EAAE,yBAAyB,CAAC;AAC5C;AAAA,QACF;AACA,QAAA6G,EAAOkC,CAAK;AAIZ,cAAME,IAASF,EAAM,KAAK,CAACxI,MAAUA,EAAM,OAAOgB,EAAQ,EAAE;AAC5D,QAAAuG;AAAA,UACEmB,IACIjJ,EAAE,2BAA2B;AAAA,YAC3B,KAAKiJ,EAAO,IAAI;AAAA,YAChB,KAAKA,EAAO,IAAI;AAAA,UAAA,CACjB,IACDjJ,EAAE,yBAAyB;AAAA,QAAA;AAAA,MAEnC;AAAA,MACA,CAACqI,IAAYxB,GAAQ7G,CAAC;AAAA,IAAA,GAElBkJ,KAAa7I,EAAOwI,CAAO;AACjC,IAAAK,GAAW,UAAUL;AAGrB,UAAMM,KAAoBzD;AAAA,MACxB,CAAChC,GAAyB6E,MAAqB;AAC7C,YAAI,CAACzC,EAAU;AAGf,YAAIoC,GAAiB,SAAS;AAC5B,UAAAA,GAAiB,UAAU;AAC3B;AAAA,QACF;AACA,cAAM5E,IAAU0E,EAAQ;AACxB,aAAI1E,KAAA,gBAAAA,EAAS,SAAQ,WACrB;AAAA,cAAIA,KAAWA,EAAQ,OAAOiF,KAAYjF,EAAQ,SAASI,GAAM;AAE/D,YAAAmF,EAAQ,EAAI;AACZ;AAAA,UACF;AACA,UAAAP,GAAU5E,GAAM6E,GAAU,UAAU,GACpCT;AAAA,YAEM9H,EADJ0D,MAAS,SACH,0BACA,6BADuB;AAAA,UACM;AAAA;AAAA,MAEvC;AAAA,MACA,CAACoC,GAAUwC,IAAWO,GAAS7I,CAAC;AAAA,IAAA,GAG5BoJ,KAAe1D;AAAA,MACnB,CAAC1D,GAA8CuG,MAAqB;AAClE,cAAMhH,IAAUyG,EAAQ;AACxB,YAAI,CAACzG,KAAWA,EAAQ,OAAOgH,KAAYhH,EAAQ,QAAQ;AACzD;AAEF,YAAIS,EAAM,QAAQ,UAAU;AAC1B,UAAAA,EAAM,eAAA,GACN6G,EAAQ,EAAK;AACb;AAAA,QACF;AAEA,YAAI,CADW,CAAC,aAAa,cAAc,WAAW,WAAW,EACrD,SAAS7G,EAAM,GAAG,EAAG;AACjC,QAAAA,EAAM,eAAA;AACN,cAAMqH,IACJ,OAAO,SAAW,OAAejE,EAAQ,UACrC,OAAO,iBAAiBA,EAAQ,OAAO,EAAE,cAAc,QACvD,IAEAkE,IACJtH,EAAM,QAAQ,eACVqH,IACE,KACA,IACFrH,EAAM,QAAQ,cACZqH,IACE,IACA,KACF,GACFE,IACJvH,EAAM,QAAQ,cAAc,IAAIA,EAAM,QAAQ,YAAY,KAAK,GAI3DzB,KADewH,GAAS,WAAWxG,EAAQ,YACtB,KAAK,CAACxG,MAASA,EAAK,OAAOwN,CAAQ;AAC9D,YAAI,CAAChI,EAAO;AACZ,cAAMhD,IACJgE,EAAQ,SAAS,SACbiC;AAAA,UACEjC,EAAQ;AAAA,UACR;AAAA,UACAgH;AAAA,UACAhI,EAAM,IAAI+I;AAAA,UACV/I,EAAM,IAAIgJ;AAAA,UACVvO;AAAA,QAAA,IAEFwI;AAAA,UACEjC,EAAQ;AAAA,UACR;AAAA,UACAgH;AAAA,UACAhI,EAAM,IAAI+I;AAAA,UACV/I,EAAM,IAAIgJ;AAAA,UACVvO;AAAA,QAAA;AAER,QAAAqN,GAAW9K,CAAI;AACf,cAAMyG,IAAQzG,EAAK,KAAK,CAACxC,MAASA,EAAK,OAAOwN,CAAQ;AACtD,QAAIvE,KAAO2E,GAAcpH,EAAQ,MAAMyC,CAAK;AAAA,MAC9C;AAAA,MACA,CAAChJ,GAAM6N,GAASR,IAAYM,EAAa;AAAA,IAAA,GAOrCa,KAAe9D,EAAY,MAAM;AACrC,YAAM+D,IAAYxB,GAAe,SAC3B1G,IAAUyG,EAAQ,SAClB0B,IAAWtE,EAAQ;AACzB,UAAI,CAACqE,KAAa,CAAClI,KAAW,CAACmI,EAAU;AACzC,YAAMC,IAAOD,EAAS,sBAAA,GAChBE,IAAOH,EAAU,cAAcE,EAAK,OAAOF,EAAU,YACrDI,IAAOJ,EAAU,cAAcE,EAAK,MAAMF,EAAU,YAGpDK,IACJ,KAAK,MAAMF,IAAOH,EAAU,SAAS,KAAKA,EAAU,QAAQ,KAAK,IAC7DM,IAAa,KAAK,MAAMF,IAAOJ,EAAU,SAAS,GAClD,EAAE,QAAAO,MAAWP;AAGnB,MAAApB;AAAA,QACEoB,EAAU,SAAS,SACfjG;AAAA,UACEjC,EAAQ;AAAA,UACR;AAAA,UACAkI,EAAU;AAAA,UACVO,EAAO,IAAIF;AAAA,UACXE,EAAO,IAAID;AAAA,UACX5B,GAAQ;AAAA,QAAA,IAEV3E;AAAA,UACEjC,EAAQ;AAAA,UACR;AAAA,UACAkI,EAAU;AAAA,UACVO,EAAO,IAAIF;AAAA,UACXE,EAAO,IAAID;AAAA,UACX5B,GAAQ;AAAA,QAAA;AAAA,MACV;AAAA,IAER,GAAG,CAACE,EAAU,CAAC,GAGT4B,KAAgB5J,EAAO,EAAK,GAM5B6J,KAAexE,EAAY,MAAM;;AACrC,OAAAlE,IAAAoH,EAAe,YAAf,QAAApH,EAAA,KAAAoH;AACA,YAAMuB,IAAS,CAACnI,MAAwB;AACtC,cAAMyH,IAAYxB,GAAe;AACjC,QAAI,CAACwB,KAAazH,EAAM,cAAcyH,EAAU,cAChDA,EAAU,cAAczH,EAAM,SAC9ByH,EAAU,cAAczH,EAAM,SAC9ByH,EAAU,cAAVA,EAAU,YACR,KAAK;AAAA,UACHzH,EAAM,UAAUyH,EAAU;AAAA,UAC1BzH,EAAM,UAAUyH,EAAU;AAAA,QAAA,IACxB3G,KACN0G,GAAA;AAAA,MACF,GACMY,IAAS,CAACtB,MAAyB,CAAC9G,MAAwB;AAChE,cAAMyH,IAAYxB,GAAe;AACjC,QAAI,CAACwB,KAAazH,EAAM,cAAcyH,EAAU,cAEhDvB,GAAiB,UAAUuB,EAAU,YAErCP,GAAW,QAAQJ,CAAW;AAAA,MAChC,GACMuB,IAAOD,EAAO,EAAI,GAClBE,IAAWF,EAAO,EAAK,GACvBG,IAAW,MAAMf,GAAA;AACvB,UAAIgB,IAAQ;AACZ,YAAMC,IAAa,MAAM;AACvB,QAAAD,IAAQ,sBAAsBC,CAAU;AACxC,cAAMhB,IAAYxB,GAAe;AAEjC,YAAI,EAACwB,KAAA,QAAAA,EAAW,WAAW;AAC3B,cAAMC,IAAWtE,EAAQ;AACzB,YAAI,CAACsE,EAAU;AACf,cAAM,EAAE,aAAanO,GAAG,aAAaC,MAAMiO,GAIrCiB,IAAYvH,GAAmBuG,CAAQ,GACvCiB,KAAO,CACXC,GACAC,IACAC,OACG;AACH,gBAAMC,KAAOD,KAAW,OAAO,cAAc,OAAO,YAC9CE,IAAMJ,KAAA,gBAAAA,EAAU,yBAChB9G,KAAQ,KAAK;AAAA,YACjBgH,MAAYE,KAAA,gBAAAA,EAAK,QAAO,KAAMA,KAAA,gBAAAA,EAAK,SAAQ;AAAA,YAC3C;AAAA,UAAA,GAEIC,KAAM,KAAK;AAAA,YACfH,MAAYE,KAAA,gBAAAA,EAAK,WAAUD,MAASC,KAAA,gBAAAA,EAAK,UAASD;AAAA,YAClDA;AAAA,UAAA,GAEIG,KAAQjH,GAAUgH,KAAMJ,EAAO,IAAI5G,GAAU4G,KAAU/G,EAAK;AAClE,cAAIoH,OAAU,EAAG;AACjB,gBAAMC,KAAO,MACXP,IACIE,KACEF,EAAS,YACTA,EAAS,aACXE,KACE,OAAO,UACP,OAAO,SACTrI,KAAS0I,GAAA;AACf,UAAAP,KAAA,QAAAA,EAAU,SAASE,KAAW,IAAII,IAAOJ,KAAWI,KAAQ,KAExD,CAACN,KAAYO,GAAA,MAAW1I,OAC1B,OAAO,SAASqI,KAAW,IAAII,IAAOJ,KAAWI,KAAQ,CAAC;AAAA,QAE9D;AACA,QAAAP,GAAKD,EAAU,GAAGlP,GAAG,EAAI,GACzBmP,GAAKD,EAAU,GAAGnP,GAAG,EAAK;AAAA,MAC5B;AACA,MAAAiP,IAAQ,sBAAsBC,CAAU,GACxC,OAAO,iBAAiB,eAAeN,CAAM,GAC7C,OAAO,iBAAiB,aAAaE,CAAI,GACzC,OAAO,iBAAiB,iBAAiBC,CAAQ,GACjD,OAAO,iBAAiB,UAAUC,GAAU;AAAA,QAC1C,SAAS;AAAA,QACT,SAAS;AAAA,MAAA,CACV,GACD3B,EAAe,UAAU,MAAM;AAC7B,6BAAqB4B,CAAK,GAC1BP,GAAc,UAAU,IACxB,OAAO,oBAAoB,eAAeE,CAAM,GAChD,OAAO,oBAAoB,aAAaE,CAAI,GAC5C,OAAO,oBAAoB,iBAAiBC,CAAQ,GACpD,OAAO,oBAAoB,UAAUC,GAAU,EAAE,SAAS,IAAM;AAAA,MAClE;AAAA,IACF,GAAG,CAACf,EAAY,CAAC;AAEjB,IAAAvI;AAAA,MACE,MAAM,MAAM;;AACV,SAAAO,IAAAoH,EAAe,YAAf,QAAApH,EAAA,KAAAoH,IACAA,EAAe,UAAU;AAAA,MAC3B;AAAA,MACA,CAAA;AAAA,IAAC;AAGH,UAAMwC,KAAmB1F;AAAA,MACvB,CACEhC,GACA6E,GACAsC,GACAQ,GACAC,MACY;;AACZ,cAAM5B,IAAWtE,EAAQ,SACnB7E,IAAQ6H,GAAY,QAAQ,KAAK,CAACrN,OAASA,GAAK,OAAOwN,CAAQ;AACrE,YAAI,CAACmB,KAAY,CAACnJ,EAAO,QAAO;AAChC,cAAMoJ,IAAOD,EAAS,sBAAA;AAGtB,YAAIC,EAAK,SAAS,EAAG,QAAO;AAC5B,cAAMpG,IAAS,OAAO,iBAAiBmG,CAAQ,GACzC6B,IAAM,OAAO,WAAWhI,EAAO,SAAS,KAAK,GAC7CiI,IAAS,OAAO,WAAWjI,EAAO,MAAM,KAAK,GAC7CkI,KAAY9B,EAAK,QAAQ4B,KAAOvQ,IAAO,MAAMA;AACnD,QAAAiN,GAAe,UAAU;AAAA,UACvB,MAAAvE;AAAA,UACA,IAAI6E;AAAA,UACJ,WAAWsC,EAAQ;AAAA,UACnB,YAAYA,EAAQ,UAAUlB,EAAK;AAAA,UACnC,YAAYkB,EAAQ,UAAUlB,EAAK;AAAA,UACnC,aAAakB,EAAQ;AAAA,UACrB,aAAaA,EAAQ;AAAA,UACrB,QAAQtK;AAAA,UACR,WAAWkL,IAAWF;AAAA,UACtB,WAAWhH,IAAYiH;AAAA,UACvB,OAAOjI,EAAO,cAAc;AAAA,UAC5B,YAAA+H;AAAA,UACA,QAAQT,EAAQ;AAAA,UAChB,QAAQA,EAAQ;AAAA,UAChB,WAAW;AAAA,QAAA;AAEb,YAAI;AACF,WAAArJ,IAAA6J,EAAc,sBAAd,QAAA7J,EAAA,KAAA6J,GAAkCR,EAAQ;AAAA,QAC5C,QAAQ;AAAA,QAGR;AACA,eAAAvC,GAAU5E,GAAM6E,GAAU,SAAS,GACnC2B,GAAA,GACO;AAAA,MACT;AAAA,MACA,CAAClP,GAAMuJ,GAAW+D,IAAW4B,EAAY;AAAA,IAAA,GAGrCwB,KAAmBhG;AAAA,MACvB,CACEhC,GACA6E,GACAvG,MACG;;AACH,QAAK8D,MAIDkC,EAAQ,YACZhG,EAAM,eAAA,IAINI,KAAAZ,IAAAQ,EAAM,eAAc,UAApB,QAAAI,EAAA,KAAAZ,IACA4J,GAAiB1H,GAAM6E,GAAUvG,GAAOA,EAAM,eAAe,EAAI;AAAA,MACnE;AAAA,MACA,CAAC8D,GAAUsF,EAAgB;AAAA,IAAA,GAQvBO,KAAiBtL,EAA2B,IAAI,GAEhDuL,KAAmBlG,EAAY,MAAM;AACzC,YAAMmG,IAAQF,GAAe;AAE7B,MADAA,GAAe,UAAU,MACpBE,MACDA,EAAM,aAAW,aAAaA,EAAM,SAAS,GACjDA,EAAM,QAAA;AAAA,IACR,GAAG,CAAA,CAAE,GAECC,KAAmBpG;AAAA,MACvB,CAAC6C,GAAkBvG,MAA0C;AAE3D,YADI,CAAC8D,KAAYkC,EAAQ,WAAW2D,GAAe,WAC/C3J,EAAM,WAAW,KAAK,CAACA,EAAM,UAAW;AAC5C,cAAMhF,IAASgF,EAAM;AAGrB,YAAI,CAACA,EAAM,cAAc,SAAShF,CAAM,EAAG;AAG3C,cAAM+O,IAAU/O,EAAO,QAAQ6F,EAAoB;AACnD,YAAIkJ,KAAW/J,EAAM,cAAc,SAAS+J,CAAO,EAAG;AACtD,cAAMC,IAAUhK,EAAM,eAChBiK,IAAQjK,EAAM,gBAAgB;AAEpC,QAAKiK,KAAOjK,EAAM,eAAA;AAClB,cAAMkK,IAAW,CAACC,GAAiBC,MAAoB;AACrD,gBAAMP,IAAQF,GAAe;AAG7B,cAFAC,GAAA,GAEI,GAACC,KAAS7D,EAAQ,YAEpBoD;AAAA,YACE;AAAA,YACAS,EAAM;AAAA,YACN;AAAA,cACE,WAAWA,EAAM;AAAA,cACjB,SAASA,EAAM;AAAA,cACf,SAASA,EAAM;AAAA,YAAA;AAAA,YAEjBA,EAAM;AAAA,YACN;AAAA,UAAA,GAEF;AACA,YAAA5B,GAAc,UAAUgC;AACxB,kBAAMxC,IAAYxB,GAAe;AACjC,YAAIwB,MACFA,EAAU,cAAc0C,GACxB1C,EAAU,cAAc2C,GAExB3C,EAAU,YAAY,CAACwC,IAEzBzC,GAAA;AAAA,UACF;AAAA,QACF,GACMW,IAAS,CAACkC,MAAuB;AACrC,gBAAMR,IAAQF,GAAe;AAC7B,cAAI,CAACE,KAASQ,EAAK,cAAcR,EAAM,UAAW;AAClD,gBAAMS,IAAY,KAAK;AAAA,YACrBD,EAAK,UAAUR,EAAM;AAAA,YACrBQ,EAAK,UAAUR,EAAM;AAAA,UAAA;AAEvB,UAAII,IACEK,IAAYtJ,MAAe4I,GAAA,IACtBU,IAAYxJ,MACrBoJ,EAASG,EAAK,SAASA,EAAK,OAAO;AAAA,QAEvC,GACME,IAAQ,CAACtB,MAAsB;;AACnC,UAAIA,EAAI,gBAAczJ,IAAAmK,GAAe,YAAf,gBAAAnK,EAAwB,cAC5CoK,GAAA;AAAA,QAEJ;AACA,eAAO,iBAAiB,eAAezB,CAAM,GAC7C,OAAO,iBAAiB,aAAaoC,CAAK,GAC1C,OAAO,iBAAiB,iBAAiBA,CAAK,GAC9CZ,GAAe,UAAU;AAAA,UACvB,IAAIpD;AAAA,UACJ,WAAWvG,EAAM;AAAA,UACjB,aAAaA,EAAM;AAAA,UACnB,cAAcA,EAAM;AAAA,UACpB,cAAcA,EAAM;AAAA,UACpB,SAAAgK;AAAA,UACA,WAAWC,IACP,WAAW,MAAM;AACf,kBAAMJ,IAAQF,GAAe;AAC7B,YAAIE,KAAOK,EAASL,EAAM,cAAcA,EAAM,YAAY;AAAA,UAC5D,GAAG9I,EAAa,IAChB;AAAA,UACJ,SAAS,MAAM;AACb,mBAAO,oBAAoB,eAAeoH,CAAM,GAChD,OAAO,oBAAoB,aAAaoC,CAAK,GAC7C,OAAO,oBAAoB,iBAAiBA,CAAK;AAAA,UACnD;AAAA,QAAA;AAAA,MAEJ;AAAA,MACA,CAACzG,GAAUsF,IAAkB5B,IAAcoC,EAAgB;AAAA,IAAA;AAK7D,IAAA3K,EAAU,MAAM;AACd,MAAK6E,MACH8F,GAAA,GACI5D,EAAQ,WAASkB,GAAW,QAAQ,EAAK;AAAA,IAEjD,GAAG,CAACpD,GAAU8F,EAAgB,CAAC,GAG/B3K,EAAU,MAAM2K,IAAkB,CAACA,EAAgB,CAAC,GAMpD3K,EAAU,MAAM;AACd,YAAMK,IAAO8D,EAAQ;AACrB,UAAI,CAACU,KAAY,CAACxE,EAAM;AACxB,YAAMkL,IAAc,CAACxK,MAAsB;AACzC,QAAIiI,GAAc,WAAWjI,EAAM,gBAAkB,eAAA;AAAA,MACvD,GACMyK,IAAgB,CAACzK,MAAiB;AACtC,SAAI2J,GAAe,WAAW1B,GAAc,YAC1CjI,EAAM,eAAA;AAAA,MAEV;AACA,aAAAV,EAAK,iBAAiB,aAAakL,GAAa,EAAE,SAAS,IAAO,GAClElL,EAAK,iBAAiB,eAAemL,CAAa,GAC3C,MAAM;AACX,QAAAnL,EAAK,oBAAoB,aAAakL,CAAW,GACjDlL,EAAK,oBAAoB,eAAemL,CAAa;AAAA,MACvD;AAAA,IACF,GAAG,CAAC3G,CAAQ,CAAC,GAKb7E,EAAU,MAAM;AACd,UAAI,CAAC0G,GAAM;AACX,YAAM+E,IAAY,CAAC1K,MAAyB;AAC1C,QAAIA,EAAM,QAAQ,YAAU6G,EAAQ,EAAK;AAAA,MAC3C;AACA,oBAAO,iBAAiB,WAAW6D,CAAS,GACrC,MAAM,OAAO,oBAAoB,WAAWA,CAAS;AAAA,IAC9D,GAAG,CAAC/E,IAAMkB,CAAO,CAAC,GAIlB5H,EAAU,MAAM;AACd,UAAI,CAAC0G,MAAQA,GAAK,QAAQ,WAAY;AACtC,YAAMgF,IAAa,CAAC3K,MAAsB;;AACxC,cAAMzE,IAAOyE,EAAM;AACnB,SAAI,CAACzE,KAAQ,GAACiE,IAAA4D,EAAQ,YAAR,QAAA5D,EAAiB,SAASjE,QAAOsL,EAAQ,EAAK;AAAA,MAC9D,GACMvH,IAAO8D,EAAQ;AACrB,aAAA9D,KAAA,QAAAA,EAAM,iBAAiB,YAAYqL,IAC5B,MAAMrL,KAAA,gBAAAA,EAAM,oBAAoB,YAAYqL;AAAA,IACrD,GAAG,CAAChF,IAAMkB,CAAO,CAAC,GAMlBxH,GAA0B,MAAM;AAC9B,MAAKgE,MACD2C,EAAQ,WAASa,EAAQ,EAAK,GAC9BpH,KAASqG,GAAgB9H,EAAE,+BAA+B,CAAC;AAAA,IACjE,GAAG,CAACqF,GAAS5D,GAASoH,GAAS7I,CAAC,CAAC,GAQjCqB,GAA0B,MAAM;;AAC9B,YAAMuL,IAAUpH,GAAgB;AAChC,MAAAA,GAAgB,UAAU;AAC1B,YAAMG,IAAOR,EAAQ;AACrB,UAAI,CAACyH,KAAW,CAACjH,EAAM;AACvB,YAAMrJ,IAAS,SAAS;AAExB,UADIA,MAAWsQ,EAAQ,WACnBtQ,MAAW,QAAQA,MAAW,SAAS,KAAM;AACjD,UAAIqJ,EAAK,SAASiH,EAAQ,OAAO,GAAG;AAClC,QAAAA,EAAQ,QAAQ,MAAA;AAChB;AAAA,MACF;AACA,YAAMC,IAASD,EAAQ,WACnB,MAAM;AAAA,QACJjH,EAAK,iBAA8B,kBAAkB;AAAA,MAAA,EACrD;AAAA,QACA,CAACrE,MAASA,EAAK,aAAa,gBAAgB,MAAMsL,EAAQ;AAAA,MAAA,IAE5D;AACJ,UAAIC,GAAQ;AAEV,QAAAA,EAAO,aAAa,YAAY,IAAI,GACpCA,EAAO,MAAA;AACP;AAAA,MACF;AACA,OAAArL,IAAA4D,EAAQ,YAAR,QAAA5D,EAAiB;AAAA,IACnB,GAAG,CAAC6D,CAAO,CAAC;AAEZ,UAAMyH,KAAqBzM,EAAOwE,CAAe;AACjD,IAAAiI,GAAmB,UAAUjI;AAC7B,UAAMkI,KAAqB1M,EAAO,EAAK;AAGvC,IAAAgB,GAA0B,MAAM;;AAC9B,MAAI0L,GAAmB,YAAY1H,MACnC0H,GAAmB,UAAU1H,IAC7B7D,IAAAsL,GAAmB,YAAnB,QAAAtL,EAAA,KAAAsL,IAA6BzH;AAAA,IAC/B,GAAG,CAACA,CAAO,CAAC,GAGZhE,GAA0B,MAAM;AAC9B,YAAMC,IAAO8D,EAAQ;AACrB,MAAK9D,MACLA,EAAK,MAAM,YAAY,aAAa,OAAOtG,CAAI,CAAC,GAChDsG,EAAK,MAAM,YAAY,YAAY,GAAGiD,CAAS,IAAI;AAAA,IACrD,GAAG,CAACvJ,GAAMuJ,CAAS,CAAC;AAKpB,UAAMyI,KAAclP,GAASxB,EAAM;AACnC,IAAA+E,GAA0B,MAAM;AAC9B,YAAMC,IAAO8D,EAAQ;AACrB,MAAK9D,MACLA,EAAK,MAAM;AAAA,QACT;AAAA,QACA,mJAAmJtG,CAAI,2HAC9BuJ,CAAS;AAAA,MAAA,GAEpIjD,EAAK,MAAM;AAAA,QACT;AAAA,QACA,QAAQ0L,KAAc,CAAC,OAAOzI,CAAS;AAAA,MAAA;AAAA,IAE3C,GAAG,CAACvJ,GAAMuJ,GAAWyI,EAAW,CAAC;AAGjC,UAAMC,KAAa5M,EAAuB,IAAI,GACxC6M,KAAcpH,KAAY,EAAQlB,GAClCuI,KAAUnH;AAAA,MACd,MAAOkH,KAAczP,GAASnB,IAAQtB,GAAM,GAAG,CAAC,IAAI;AAAA,MACpD,CAACkS,IAAa5Q,IAAQtB,CAAI;AAAA,IAAA;AAE5B,IAAAqG,GAA0B,MAAM;AAC9B,YAAMC,IAAO2L,GAAW;AACxB,MAAI,CAAC3L,KAAQ,CAAC6L,OACd7L,EAAK,MAAM,YAAY,UAAU,OAAO6L,GAAQ,IAAI,CAAC,CAAC,GACtD7L,EAAK,MAAM,YAAY,UAAU,OAAO6L,GAAQ,IAAI,CAAC,CAAC,GACtD7L,EAAK,MAAM,YAAY,UAAU,GAAG,GACpCA,EAAK,MAAM,YAAY,UAAU,GAAG;AAAA,IACtC,GAAG,CAAC6L,EAAO,CAAC;AAGZ,UAAMC,KAAgB1H;AAAA,MACpB,CAAC6C,MAAqB;;AAMpB,cAAM8E,IAAU,MAAM;AAAA,YACpB7L,IAAA4D,EAAQ,YAAR,gBAAA5D,EAAiB,iBAA8B,wBAC7C,CAAA;AAAA,QAAC,GAEC8L,IAAKD,EAAQ;AAAA,UACjB,CAAC/L,MAASA,EAAK,aAAa,gBAAgB,MAAMiH;AAAA,QAAA,GAE9CgF,KAAanL,IAAAiL,EAAQC,IAAK,CAAC,KAAKD,EAAQC,IAAK,CAAC,MAAjC,gBAAAlL,EAAqC;AAAA,UACtD;AAAA;AAEF,QAAAyE;AAAA,UACE9K;AAAA,YACEqM,GAAY,QAAQ,OAAO,CAAC7H,MAAUA,EAAM,OAAOgI,CAAQ;AAAA,YAC3DJ,GAAQ;AAAA,UAAA;AAAA,QACV,GAEFL,GAAgB9H,EAAE,uBAAuB,CAAC,GAC1C2E,KAAA,QAAAA,EAAiB4D,IACjB,sBAAsB,MAAM;AAC1B,gBAAM5C,IAAOP,EAAQ;AACrB,cAAI,CAACO,EAAM;AACX,gBAAMpI,IAAO,MAAM;AAAA,YACjBoI,EAAK,iBAA8B,kBAAkB;AAAA,UAAA,EACrD,KAAK,CAACrE,MAASA,EAAK,aAAa,gBAAgB,MAAMiM,CAAS,GAC5DvQ,KACJO,KAAA,gBAAAA,EAAM,cAAiC,cACvCoI,EAAK,cAAiC,QAAQ;AAChD,UAAI3I,MAAe,MAAA,MACT,MAAA;AAAA,QACZ,CAAC;AAAA,MACH;AAAA,MACA,CAAC6J,GAAQlC,GAAgB3E,CAAC;AAAA,IAAA,GAOtB,CAACwN,IAAYC,EAAa,IAAI/M,EAAwB,IAAI,GAC1DgN,IAAmBrN,EAIf,IAAI,GACRsN,KAAiBtN,EAA6C,IAAI,GAClEuN,KAAiBvN,EAAO,CAAC,GAEzBwN,KAAYnI,EAAY,MAAe;;AAC3C,YAAMkH,IAAUc,EAAiB,SAC3B/H,IAAOP,EAAQ;AACrB,UAAI,CAACwH,KAAW,CAACjH,EAAM,QAAO;AAC9B,YAAMrE,IAAO,MAAM;AAAA,QACjBqE,EAAK,iBAA8B,kBAAkB;AAAA,MAAA,EACrD,KAAK,CAAC5K,MAASA,EAAK,aAAa,gBAAgB,MAAM6R,EAAQ,EAAE,GAC7D5B,IAAM1J,KAAA,gBAAAA,EAAM;AAClB,UAAI,CAACA,KAAQ,CAAC0J,KAAOA,EAAI,UAAU;AACjC,eAAI,YAAY,QAAQ4B,EAAQ,aAC9Bc,EAAiB,UAAU,MAC3Bd,EAAQ,QAAQ,EAAK,IAEhB;AAET,MAAAc,EAAiB,UAAU;AAC3B,YAAMI,MACJtM,IAAA,OAAO,eAAP,gBAAAA,EAAA,aAAoB,oCAAoC,YACxD,OACG,iBAAiBmE,CAAI,EACrB,iBAAiB,sBAAsB,EACvC,WAAW;AAChB,aAAArE,EAAK,eAAe;AAAA,QAClB,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,UAAUwM,IAAe,SAAS;AAAA,MAAA,CACnC,GACDL,GAAcb,EAAQ,EAAE,GACpBe,GAAe,WAAS,aAAaA,GAAe,OAAO,GAC/DA,GAAe,UAAU;AAAA,QACvB,MAAMF,GAAc,IAAI;AAAA,QACxB7K;AAAA,MAAA,GAEFgK,EAAQ,QAAQ,EAAI,GACb;AAAA,IACT,GAAG,CAAA,CAAE,GAECmB,KAAerI;AAAA,MACnB,CAAC6C,MACC,IAAI,QAAiB,CAACyF,MAAY;;AAChC,SAAAxM,IAAAkM,EAAiB,YAAjB,QAAAlM,EAA0B,QAAQ,KAClC,qBAAqBoM,GAAe,OAAO;AAG3C,cAAMK,IAAW,WAAW,MAAM;AAChC,gBAAMrB,IAAUc,EAAiB;AACjC,WAAId,KAAA,gBAAAA,EAAS,aAAYsB,KACrB,CAACL,GAAA,KAAeH,EAAiB,YAAYd,MAC/Cc,EAAiB,UAAU,MAC3BQ,EAAO,EAAK;AAAA,QAEhB,GAAGvL,EAAc,GACXuL,IAAS,CAACC,MAAsB;AACpC,uBAAaF,CAAQ,GACrBD,EAAQG,CAAQ;AAAA,QAClB;AACA,QAAAT,EAAiB,UAAU;AAAA,UACzB,IAAInF;AAAA,UACJ,UAAU,YAAY,IAAA,IAAQ5F;AAAA,UAC9B,SAASuL;AAAA,QAAA;AAEX,cAAME,IAAO,MAAM;AACjB,UAAKV,EAAiB,WAClB,CAACG,GAAA,KAAeH,EAAiB,YACnCE,GAAe,UAAU,sBAAsBQ,CAAI;AAAA,QAEvD;AACA,QAAAR,GAAe,UAAU,sBAAsBQ,CAAI;AAAA,MACrD,CAAC;AAAA,MACH,CAACP,EAAS;AAAA,IAAA;AAIZ,IAAAxM,GAA0B,MAAM;AAC9B,MAAIqM,EAAiB,WAASG,GAAA;AAAA,IAChC,CAAC,GAED5M;AAAA,MACE,MAAM,MAAM;;AACV,6BAAqB2M,GAAe,OAAO,GACvCD,GAAe,WAAS,aAAaA,GAAe,OAAO,IAC/DnM,IAAAkM,EAAiB,YAAjB,QAAAlM,EAA0B,QAAQ,KAClCkM,EAAiB,UAAU;AAAA,MAC7B;AAAA,MACA,CAAA;AAAA,IAAC;AAIH,UAAMW,KAAcrI;AAAA,MAClB,OAAO;AAAA,QACL,aAAauC,GAAUhN,GAAGC,GAAG;AAI3B,cAFI,CAACsK,KAAYP,EAAW,WACxB,CAAC,OAAO,SAAShK,CAAC,KAAK,CAAC,OAAO,SAASC,CAAC,KACzC,CAACuL,EAAS,KAAK,CAAChM,MAASA,EAAK,OAAOwN,CAAQ,EAAG,QAAO;AAG3D,gBAAMd,IAAQjE;AAAA,YACZuD;AAAA,YACA;AAAA,YACAwB;AAAA,YACA,KAAK,MAAMhN,CAAC;AAAA,YACZ,KAAK,MAAMC,CAAC;AAAA,YACZR;AAAA,YACA;AAAA,UAAA;AAEF,iBAAIyM,MAAUV,KAAUF,EAAO9K,GAAU0L,GAAOzM,CAAI,CAAC,GAC9C;AAAA,QACT;AAAA,QACA,eAAeuN,GAAUlN,GAAGC,GAAG;AAG7B,cAFI,CAACwK,KAAYP,EAAW,WACxB,CAAC,OAAO,SAASlK,CAAC,KAAK,CAAC,OAAO,SAASC,CAAC,KACzC,CAACyL,EAAS,KAAK,CAAChM,MAASA,EAAK,OAAOwN,CAAQ,EAAG,QAAO;AAC3D,gBAAMd,IAAQjE;AAAA,YACZuD;AAAA,YACA;AAAA,YACAwB;AAAA,YACA,KAAK,MAAMlN,CAAC;AAAA,YACZ,KAAK,MAAMC,CAAC;AAAA,YACZN;AAAA,YACA;AAAA,UAAA;AAEF,iBAAIyM,MAAUV,KAAUF,EAAO9K,GAAU0L,GAAOzM,CAAI,CAAC,GAC9C;AAAA,QACT;AAAA,QACA,cAAA+S;AAAA,QACA,eAAe;AACb,iBAAO;AAAA,YACL,MAAA/S;AAAA,YACA,SAAAyG;AAAA,YACA,SAAA4D;AAAA,YACA,QAAQkB,GAAcQ,CAAQ;AAAA,YAC9B,YAAYhC,KAAc;AAAA,UAAA;AAAA,QAE9B;AAAA,MAAA;AAAA,MAEF;AAAA,QACEe;AAAA,QACArE;AAAA,QACA4D;AAAA,QACA0B;AAAA,QACA/L;AAAA,QACA6L;AAAA,QACAN;AAAA,QACAwH;AAAA,QACAhJ;AAAA,MAAA;AAAA,IACF;AAEF,IAAAuJ,GAAoBpJ,GAAK,MAAMmJ,IAAa,CAACA,EAAW,CAAC,GACzDE,GAAqB/T,IAAoB6T,IAAa/Q,CAAE;AAExD,UAAMkR,KAAexI;AAAA,MACnB,OAAO;AAAA,QACL,SAASF;AAAA,QACT,SAAAT;AAAA,QACA,eAAAP;AAAA,QACA,YAAAC;AAAA,QACA,YAAAyI;AAAA,QACA,cAAcxI;AAAA,QACd,YAAA0D;AAAA,QACA,MAAAf;AAAA,QACA,WAAW,EAAQhD;AAAA,QACnB,eAAAyI;AAAA,QACA,mBAAAjE;AAAA,QACA,cAAAC;AAAA,QACA,kBAAAsC;AAAA,QACA,kBAAAI;AAAA,MAAA;AAAA,MAEF;AAAA,QACEhG;AAAA,QACAT;AAAA,QACAP;AAAA,QACAC;AAAA,QACAyI;AAAA,QACAxI;AAAA,QACA0D;AAAA,QACAf;AAAA,QACAhD;AAAA,QACAyI;AAAA,QACAjE;AAAA,QACAC;AAAA,QACAsC;AAAA,QACAI;AAAA,MAAA;AAAA,IACF,GASI2C,KAAmBzI,GAAmB,MAAM;AAChD,UAAI9H,MAAe,OAAW,QAAOmB;AACrC,YAAMqP,IAAsB,CAAA,GACtBtR,wBAAW,IAAA,GACXuR,IAA0B,CAAA;AAsBhC,aAnBAvP,GAAmBC,GAAU,CAACG,MAAU;AACtC,cAAM+I,IAAW/I,EAAM,MAAM;AAC7B,YAAI+I,KAAY,CAACnL,EAAK,IAAImL,CAAQ,GAAG;AACnC,gBAAMqG,IAAUC,GAAarP,GAAO;AAAA,YAClC,KAAK,UAAU+I,CAAQ,IAAI/I,EAAM,OAAO,EAAE;AAAA,UAAA,CAC3C;AACD,UAAApC,EAAK,IAAImL,GAAUqG,CAAO,GAC1BF,EAAI,KAAKE,CAAO;AAAA,QAClB,OAAO;AACL,gBAAMA,IAAUC,GAAarP,GAAO;AAAA,YAClC,KACEA,EAAM,QAAQ,OACV,YAAYmP,EAAQ,MAAM,KAC1B,aAAanP,EAAM,GAAG;AAAA,UAAA,CAC7B;AACD,UAAAmP,EAAQ,KAAKC,CAAO,GACpBF,EAAI,KAAKE,CAAO;AAAA,QAClB;AAAA,MACF,CAAC,GACIvJ,IACE;AAAA,QACL,GAAGjH,GAAW,CAAC,GAAGhB,EAAK,KAAA,CAAM,GAAG2J,CAAQ,EAAE;AAAA,UACxC,CAACwB,MAAanL,EAAK,IAAImL,CAAQ;AAAA,QAAA;AAAA,QAEjC,GAAGoG;AAAA,MAAA,IALgBD;AAAA,IAOvB,GAAG,CAACxQ,GAAYmB,GAAUgG,GAAS0B,CAAQ,CAAC;AAE5C,WACE,gBAAAhF;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAKoD;AAAA,QACL,kBAAe;AAAA,QACf,qBAAmB7H;AAAA,QACnB,gBAAcwI,KAAY;AAAA,QAC1B,gBAAcT,KAAW;AAAA,QACzB,WAAW,sBAAsBJ,KAAa,EAAE,GAAG,KAAA;AAAA,QAEnD,UAAA;AAAA,UAAA,gBAAAhD,EAAC,SAAI,MAAK,UAAS,aAAU,UAAS,WAAU,cAC7C,UAAA4F,GAAA,CACH;AAAA,UACA,gBAAA9F;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,KAAKqD;AAAA,cACL,MAAK;AAAA,cACL,cAAYd;AAAA,cACZ,UAAU;AAAA,cACV,gBAAcwB,KAAY;AAAA,cAC1B,gBAAcT,KAAW;AAAA,cACzB,WAAW9G,GAAsB,EAAE,SAAA8G,GAAS;AAAA,cAE5C,UAAA;AAAA,gBAAA,gBAAApD,EAACjD,GAAqB,UAArB,EAA8B,OAAOwP,IACnC,UAAAC,IACH;AAAA,gBACCvB;AAAA;AAAA;AAAA,kBAGC,gBAAAjL;AAAA,oBAAC;AAAA,oBAAA;AAAA,sBACC,KAAKgL;AAAA,sBACL,MAAK;AAAA,sBACL,WAAW;AAAA,wBACT;AAAA,wBACA;AAAA,wBACA;AAAA,sBAAA,EACA,KAAK,GAAG;AAAA,sBAEV,UAAA,gBAAAlL;AAAA,wBAAC;AAAA,wBAAA;AAAA,0BACC,MAAK;AAAA,0BACL,SAAS6C;AAAA,0BACT,WAAW;AAAA,4BACT;AAAA,4BACA;AAAA,4BACA;AAAA,4BACA;AAAA,4BACA;AAAA,0BAAA,EACA,KAAK,GAAG;AAAA,0BAEV,UAAA;AAAA,8CAACkK,IAAA,EAAK,eAAY,QAAO,WAAU,aAAY;AAAA,4BAC9C9O,EAAE,mBAAmB;AAAA,0BAAA;AAAA,wBAAA;AAAA,sBAAA;AAAA,oBACxB;AAAA,kBAAA;AAAA,oBAEA;AAAA,cAAA;AAAA,YAAA;AAAA,UAAA;AAAA,QACN;AAAA,MAAA;AAAA,IAAA;AAAA,EAGN;AACF;AACAoE,GAAkB,cAAc;AAEzB,MAAM2K,KAAgB,OAAO,OAAO3K,IAAmB;AAAA,EAC5D,QAAQzE;AACV,CAAC;","x_google_ignoreList":[0]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"header-settings-BSH9Gk0J.js","sources":["../../src/components/header-settings/header-settings.agent.ts","../../src/components/header-settings/header-settings.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — HeaderSettings. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { HeaderSettingsHandle } from './header-settings';\n\nexport const headerSettingsAgent: AgentAdapter<HeaderSettingsHandle> = {\n id: 'header-settings',\n // Each setter persists a single preference value (locale / theme /\n // accessibility) — `set_value` semantics, not an ephemeral view switch.\n capabilities: ['set_value'],\n // Read-back for all three setters. None of these preferences is\n // recoverable from the DOM — `useTheme` resolves preference + OS into\n // a single applied class, so `theme: 'system'` and `theme: 'light'`\n // both paint `.theme-light` — and `set_locale` swallows unknown tags.\n // Without these slots an agent cannot distinguish \"switched to\n // Italian\" from \"the tag was dropped on the floor\". All four are UI\n // preferences: no PHI, no patient-identifiable data (§7).\n state: {\n locale: {\n type: 'string',\n descriptionKey: 'ui.agent.headerSettings.state.locale',\n description:\n 'Active IETF language tag (e.g. \"en\", \"it\", \"ar\"). Read after `set_locale` to confirm the switch landed — an unknown tag is silently dropped and leaves this unchanged.',\n read: (handle) => handle.getLocale(),\n },\n theme: {\n type: \"'light' | 'dark' | 'system'\",\n descriptionKey: 'ui.agent.headerSettings.state.theme',\n description:\n \"Stored base-theme preference. `'system'` means no override is set and the OS decides — read `resolvedTheme` for what is actually painted.\",\n read: (handle) => handle.getTheme(),\n },\n accessibility: {\n type: \"'default' | 'accessible' | 'system'\",\n descriptionKey: 'ui.agent.headerSettings.state.accessibility',\n description:\n \"Stored AAA-contrast preference. `'system'` means no override is set and `prefers-contrast` decides.\",\n read: (handle) => handle.getAccessibility(),\n },\n resolvedTheme: {\n type: \"'light' | 'dark' | 'light-accessible' | 'dark-accessible'\",\n descriptionKey: 'ui.agent.headerSettings.state.resolvedTheme',\n description:\n 'The theme actually applied to the document once preference and OS signals resolve. This is what makes a `set_theme(\"system\")` or `set_accessibility(\"system\")` write verifiable.',\n read: (handle) => handle.getResolvedTheme(),\n },\n },\n actions: {\n set_locale: {\n safety: 'write',\n argsType: '{ locale: string }',\n argsSchema: {\n type: 'object',\n properties: {\n locale: {\n type: 'string',\n description:\n 'IETF language tag (e.g. \"en\", \"it\", \"ar\"). Unknown tags are silently dropped.',\n },\n },\n required: ['locale'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.headerSettings.actions.setLocale',\n description:\n 'Switch the active locale to the given IETF tag. Unknown tags are silently dropped — read the `locale` state slot afterwards to confirm.',\n errors: [\n 'Silently ignored when the tag names a locale the kit ships no bundle for — `locale` is unchanged.',\n ],\n examples: [{ args: { locale: 'it' }, note: 'Switch to Italian.' }],\n invoke: (handle, args: { locale: string }) => {\n // Validation happens inside the handle so the agent surface\n // accepts arbitrary tags and silently drops unknown ones.\n handle.setLocale(args.locale);\n },\n },\n set_theme: {\n safety: 'write',\n argsType: '{ theme: \"light\" | \"dark\" | \"system\" }',\n argsSchema: {\n type: 'object',\n properties: { theme: { enum: ['light', 'dark', 'system'] } },\n required: ['theme'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.headerSettings.actions.setTheme',\n description:\n 'Switch the theme preference. Verify with the `theme` slot (the stored preference) and `resolvedTheme` (what is actually painted).',\n examples: [\n { args: { theme: 'dark' }, note: 'Switch to the dark theme.' },\n ],\n invoke: (handle, args: { theme: 'light' | 'dark' | 'system' }) => {\n handle.setTheme(args.theme);\n },\n },\n set_accessibility: {\n safety: 'write',\n argsType: '{ accessibility: \"default\" | \"accessible\" | \"system\" }',\n argsSchema: {\n type: 'object',\n properties: {\n accessibility: {\n enum: ['default', 'accessible', 'system'],\n description:\n \"`'system'` clears the override and follows `prefers-contrast`.\",\n },\n },\n required: ['accessibility'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.headerSettings.actions.setAccessibility',\n description:\n 'Switch the accessibility preference. Verify with the `accessibility` slot (the stored preference) and `resolvedTheme` (what is actually painted).',\n examples: [\n {\n args: { accessibility: 'accessible' },\n note: 'Enable the AAA-accessible profile.',\n },\n ],\n invoke: (\n handle,\n args: { accessibility: 'default' | 'accessible' | 'system' },\n ) => {\n handle.setAccessibility(args.accessibility);\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'header-settings',\n description: 'Marks the HeaderSettings wrapper.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop (forwarded via HTMLAttributes).',\n },\n },\n};\n","import {\n forwardRef,\n useCallback,\n useImperativeHandle,\n useMemo,\n useRef,\n type FocusEvent,\n type HTMLAttributes,\n type KeyboardEvent,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Settings } from 'lucide-react';\nimport { IconButton } from '../button/icon-button';\nimport { DropdownMenu } from '../dropdown-menu/dropdown-menu';\nimport {\n LocalePicker,\n LOCALE_STORAGE_KEY,\n useInitialLocale,\n} from '../locale-picker/locale-picker';\nimport {\n useTheme,\n type AccessibilityPreference,\n type ResolvedTheme,\n type ThemePreference,\n} from '../../hooks';\nimport { useLocale } from '../../hooks/use-locale';\nimport { LOCALE_META, type Locale } from '../../i18n/locale-meta';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { headerSettingsAgent } from './header-settings.agent';\n\nfunction safeWriteStorage(key: string, value: string): void {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(key, value);\n } catch {\n /* Storage can throw in private mode — silent-fail per use-theme.ts. */\n }\n}\n\nfunction applyDocumentAttrs(locale: Locale): void {\n if (typeof document === 'undefined') return;\n const root = document.documentElement;\n root.lang = locale;\n root.dir = LOCALE_META[locale].dir;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst wrapperVariants = cva('ds:inline-flex ds:items-center', {\n variants: {\n align: {\n start: '',\n end: '',\n },\n },\n defaultVariants: { align: 'end' },\n});\n\n// The language flyout hosts the searchable locale list, so it takes a\n// popover width rather than the menu's minimum.\nconst languageFlyoutClasses = 'ds:w-[var(--popover-size-md)]';\n\nfunction isLocale(tag: string): tag is Locale {\n return Object.prototype.hasOwnProperty.call(LOCALE_META, tag);\n}\n\n/* ------------------------------------------------------------------ */\n/* LanguageSub */\n/* */\n/* One menu row naming the setting and showing the current language */\n/* (\"Language · English ›\"), laid out like DropdownMenu.ChoiceSub. It */\n/* opens a flyout beside the menu holding LocalePicker.SearchList, so */\n/* the 18 locales stay searchable. The flyout is a dialog, not a menu: */\n/* it holds a search combobox and a listbox, which a menu may not own. */\n/* ------------------------------------------------------------------ */\n\nfunction LanguageSub({ locale }: { locale: string }) {\n const { t } = useTranslation('ui');\n const current = LOCALE_META[isLocale(locale) ? locale : 'en'];\n\n // Radix focuses the flyout itself when a keyboard user opens it. Hand\n // that focus on to the search field so typing filters at once.\n const handleFocus = (event: FocusEvent<HTMLDivElement>) => {\n if (event.target !== event.currentTarget) return;\n event.currentTarget\n .querySelector<HTMLInputElement>('input')\n ?.focus({ preventScroll: true });\n };\n\n // The flyout closes on the \"back\" arrow (ArrowLeft, or ArrowRight in\n // RTL). Inside the search field that key moves the caret instead,\n // unless the caret is already at the start of the field. Capture\n // phase, so Radix's own handler on the flyout never sees the key.\n const handleKeyDownCapture = (event: KeyboardEvent<HTMLDivElement>) => {\n const target = event.target;\n if (!(target instanceof HTMLInputElement)) return;\n // Keys pressed while an IME is composing (Japanese, Chinese) belong to\n // the composition, never to the menu.\n if (event.nativeEvent.isComposing) {\n event.stopPropagation();\n return;\n }\n if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return;\n if (target.selectionStart !== 0 || target.selectionEnd !== 0) {\n event.stopPropagation();\n }\n };\n\n return (\n <DropdownMenu.Sub>\n <DropdownMenu.SubTrigger aria-haspopup=\"dialog\" data-value={current.code}>\n <span className=\"ds:flex ds:min-w-0 ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <span className=\"ds:truncate\">\n {t('navigation.headerSettings.language.label')}\n </span>\n <span\n lang={current.code}\n className=\"ds:shrink-0 ds:text-[color:var(--muted-foreground)] ds:[[data-highlighted]_&]:text-current\"\n >\n {current.nativeName}\n </span>\n </span>\n </DropdownMenu.SubTrigger>\n {/* Radix renders a `menu`; override to `dialog` and drop the\n menu-only `aria-orientation`, which a dialog may not carry. */}\n <DropdownMenu.SubContent\n role=\"dialog\"\n aria-orientation={undefined}\n className={languageFlyoutClasses}\n onFocus={handleFocus}\n onKeyDownCapture={handleKeyDownCapture}\n // Escape that cancels an IME conversion must not close the menu.\n onEscapeKeyDown={(escapeEvent) => {\n if (escapeEvent.isComposing) escapeEvent.preventDefault();\n }}\n >\n <LocalePicker.SearchList />\n </DropdownMenu.SubContent>\n </DropdownMenu.Sub>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport interface HeaderSettingsProps\n extends\n Omit<HTMLAttributes<HTMLDivElement>, 'onChange'>,\n VariantProps<typeof wrapperVariants> {\n /** Anchor side for the dropdown. Defaults to `end` (matches LTR + RTL). */\n align?: 'start' | 'end';\n /**\n * Size of the cog trigger only. Forwards to the underlying\n * `IconButton`. Defaults to `md` to preserve the existing visual.\n * Use `sm` when composing alongside other `<Button size=\"sm\">`\n * actions in a header row — keeps the visual rhythm consistent.\n *\n * The menu itself (language, appearance and accessible-mode rows)\n * stays at kit defaults regardless — this prop only sizes the\n * trigger.\n */\n size?: 'sm' | 'md' | 'lg';\n /** Disable the trigger entirely. */\n disabled?: boolean;\n}\n\nexport interface HeaderSettingsHandle {\n /**\n * Switch the active locale. Widened to `string` (vs. `Locale`) so\n * agent surfaces with untyped inputs can call through without\n * extra casting — invalid tags no-op silently.\n */\n setLocale: (next: string) => void;\n setTheme: (next: ThemePreference) => void;\n setAccessibility: (next: AccessibilityPreference) => void;\n /* ---- read-back for the three setters above -------------------- */\n /** Active IETF language tag, as i18next resolved it. */\n getLocale: () => string;\n /** Stored base-theme preference (`'system'` when no override is set). */\n getTheme: () => ThemePreference;\n /** Stored AAA-contrast preference (`'system'` when no override is set). */\n getAccessibility: () => AccessibilityPreference;\n /**\n * The theme actually painted once preference + OS signals resolve.\n * `theme: 'system'` and `theme: 'light'` both render `.theme-light`,\n * so this is what makes a `setTheme('system')` write verifiable.\n */\n getResolvedTheme: () => ResolvedTheme;\n}\n\n/* ------------------------------------------------------------------ */\n/* HeaderSettings */\n/* */\n/* Single button → single DropdownMenu surface, laid out as a View */\n/* menu: a Language row whose flyout holds the searchable locale list, */\n/* an Appearance ChoiceSub (light / dark / system) and an Accessible */\n/* mode SwitchItem. Every row reads and writes the same hooks */\n/* (`useLocale`, `useTheme`) as the standalone components, so there is */\n/* no state duplication. */\n/* ------------------------------------------------------------------ */\n\nexport const HeaderSettings = forwardRef<HTMLDivElement, HeaderSettingsProps>(\n (props, ref) => {\n const {\n align = 'end',\n size = 'md',\n disabled = false,\n className,\n id,\n ...rest\n } = props as HeaderSettingsProps & { id?: string };\n\n const { t } = useTranslation('ui');\n const theme = useTheme();\n const { locale, setLocale: setLocaleI18n } = useLocale();\n // The language search only mounts with its flyout, so apply the saved\n // (or browser) language here, on mount.\n useInitialLocale();\n\n const forwardedRef = useRef<HTMLDivElement | null>(null);\n useImperativeHandle(ref, () => forwardedRef.current as HTMLDivElement, []);\n\n // Same side-effect chain as LocalePicker's internal helper:\n // i18next.changeLanguage → document.dir/lang → persist.\n // Inlined here (rather than exported from locale-picker) because\n // it's three small calls; the LocalePicker.SearchList component\n // continues to own its own copy for inline use, and both apply\n // the same persistence key (`alfadocs-ui.locale`) so a write from\n // either path is visible to the other on next mount.\n const setLocaleWithPersistence = useCallback(\n (next: Locale) => {\n void setLocaleI18n(next);\n applyDocumentAttrs(next);\n safeWriteStorage(LOCALE_STORAGE_KEY, next);\n },\n [setLocaleI18n],\n );\n const setLocaleRef = useRef(setLocaleWithPersistence);\n setLocaleRef.current = setLocaleWithPersistence;\n // Assigned during render (not in an effect) so an agent reading the\n // slot immediately after `set_locale` sees the settled value rather\n // than the pre-commit one.\n const localeRef = useRef(locale);\n localeRef.current = locale;\n\n const themeRef = useRef(theme);\n themeRef.current = theme;\n const agentHandle = useMemo<HeaderSettingsHandle>(\n () => ({\n setLocale: (next: string) => {\n // Mirrors LocalePicker's gating — silently drop unknown tags\n // rather than crash mid-cascade. `LOCALES_WITH_BUNDLES` is\n // re-imported via the LOCALE_META keys so this file doesn't\n // need the resources module on the build-agent-catalog path.\n if (Object.prototype.hasOwnProperty.call(LOCALE_META, next)) {\n setLocaleRef.current(next as Locale);\n }\n },\n setTheme: (next) => themeRef.current.setTheme(next),\n setAccessibility: (next) => themeRef.current.setAccessibility(next),\n // Read-back. None of the three preferences is recoverable from\n // the DOM: `useTheme` resolves preference + OS into one applied\n // class, so `theme: 'system'` and `theme: 'light'` both paint\n // `.theme-light`. Without these an agent cannot tell a switch\n // that landed from one that was dropped.\n getLocale: () => localeRef.current,\n getTheme: () => themeRef.current.theme,\n getAccessibility: () => themeRef.current.accessibility,\n getResolvedTheme: () => themeRef.current.resolvedTheme,\n }),\n [],\n );\n useAgentRegistration(headerSettingsAgent, agentHandle, id);\n\n const accessibleChecked = theme.accessibility === 'accessible';\n\n return (\n <div\n ref={forwardedRef}\n data-component=\"header-settings\"\n data-component-id={id}\n className={wrapperVariants({ align, className })}\n {...rest}\n >\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <IconButton\n size={size}\n disabled={disabled}\n icon={<Settings aria-hidden />}\n aria-label={t('navigation.headerSettings.trigger')}\n />\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align={align}>\n <LanguageSub locale={locale} />\n <DropdownMenu.Separator />\n <DropdownMenu.ChoiceSub\n label={t('navigation.headerSettings.appearance.label')}\n value={theme.theme}\n onValueChange={theme.setTheme}\n options={[\n {\n value: 'light',\n label: t('navigation.headerSettings.appearance.light'),\n },\n {\n value: 'dark',\n label: t('navigation.headerSettings.appearance.dark'),\n },\n {\n value: 'system',\n label: t('navigation.headerSettings.appearance.system'),\n },\n ]}\n />\n {/* Writes through useTheme, so the document gets the\n `theme-accessible` class at once (including the Lexend\n swap for Latin scripts, see src/tokens/index.css). */}\n <DropdownMenu.SwitchItem\n checked={accessibleChecked}\n onCheckedChange={(next) =>\n theme.setAccessibility(next ? 'accessible' : 'default')\n }\n >\n {t('navigation.headerSettings.appearance.accessible')}\n </DropdownMenu.SwitchItem>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n </div>\n );\n },\n);\n\nHeaderSettings.displayName = 'HeaderSettings';\n"],"names":["headerSettingsAgent","handle","args","safeWriteStorage","key","value","applyDocumentAttrs","locale","root","LOCALE_META","wrapperVariants","cva","languageFlyoutClasses","isLocale","tag","LanguageSub","t","useTranslation","current","handleFocus","event","_a","handleKeyDownCapture","target","jsxs","DropdownMenu","jsx","escapeEvent","LocalePicker","HeaderSettings","forwardRef","props","ref","align","size","disabled","className","id","rest","theme","useTheme","setLocaleI18n","useLocale","useInitialLocale","forwardedRef","useRef","useImperativeHandle","setLocaleWithPersistence","useCallback","next","LOCALE_STORAGE_KEY","setLocaleRef","localeRef","themeRef","agentHandle","useMemo","useAgentRegistration","accessibleChecked","IconButton","Settings"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"map-view-BuVfJMEa.js","sources":["../../src/components/map-view/map-view.agent.ts","../../src/components/map-view/map-view.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — MapView. */\n/* */\n/* Read-safety actions on the kit's Google Maps wrapper. State is the */\n/* current centre / zoom / selected marker; actions pan, zoom, and */\n/* select markers programmatically. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { MapViewHandle, MapLatLng } from './map-view';\n\nexport const mapViewAgent: AgentAdapter<MapViewHandle> = {\n id: 'map-view',\n // pan → scroll (viewport move); set_zoom → set_value; select_marker → pick\n // (NON-persisting marker focus, no value state slot).\n capabilities: ['scroll', 'set_value', 'pick'],\n // Every action routes through the imperative bridge, which only exists\n // once the map has loaded: consent granted (the default is\n // `consentGranted={false}`) and Google Maps finished loading. Until then\n // all three actions are silent no-ops. `consentGranted` says whether the\n // gate is passed, and a null `center` after it means the map is still\n // loading. `center` / `zoom` are read off the live\n // map because Google clamps zoom and animates pans, so requested is not\n // applied; `selectedMarkerId` is the only confirmation the host accepted\n // a `select_marker` proposal.\n //\n // A9: marker ids only (`MapMarker.id` is a stable opaque id). Never\n // `MapMarker.label`, never the `address` prop (consumer-supplied free\n // text, PII in any patient-address deployment), never `apiKey`.\n state: {\n consentGranted: {\n type: 'boolean',\n descriptionKey: 'ui.agent.mapView.state.consentGranted',\n description:\n 'True when the GDPR consent gate has been passed. Read this FIRST: while it is false every action is a silent no-op against a placeholder, and nothing else in the surface says so. When it is true but `center` is still null, Google Maps is loading; wait for `center` before acting.',\n read: (handle) => handle.isConsentGranted(),\n },\n markerCount: {\n type: 'number',\n descriptionKey: 'ui.agent.mapView.state.markerCount',\n description:\n 'Number of markers the consumer passed. Zero means there is nothing for `select_marker` to select. A count only — no ids, labels or positions.',\n read: (handle) => handle.getMarkerCount(),\n },\n selectedMarkerId: {\n type: 'string | null',\n descriptionKey: 'ui.agent.mapView.state.selectedMarkerId',\n description:\n 'Id of the marker the host currently holds as selected, or null. Selection is fully controlled by the consumer, so `select_marker` only proposes — this slot is the only way to see whether the proposal was accepted.',\n read: (handle) => handle.getSelectedMarkerId(),\n },\n center: {\n type: '{ lat: number; lng: number } | null',\n descriptionKey: 'ui.agent.mapView.state.center',\n description:\n 'Live map centre in lat/lng, or null until the map has loaded (consent not granted, or Google Maps still loading). The read-back for `pan_to`, and the sign that the map is ready.',\n read: (handle) => handle.getCenter(),\n },\n zoom: {\n type: 'number | null',\n descriptionKey: 'ui.agent.mapView.state.zoom',\n description:\n \"Live zoom level, or null until the map has loaded. Google clamps zoom to the map type's range, so this is not necessarily the value last passed to `set_zoom`.\",\n read: (handle) => handle.getZoom(),\n },\n },\n actions: {\n pan_to: {\n // Ephemeral viewport move, no data loss → read.\n safety: 'read',\n argsType: '{ position: { lat: number; lng: number } }',\n argsSchema: {\n type: 'object',\n properties: {\n position: {\n type: 'object',\n properties: {\n lat: { type: 'number', description: 'Latitude in degrees.' },\n lng: { type: 'number', description: 'Longitude in degrees.' },\n },\n required: ['lat', 'lng'],\n },\n },\n required: ['position'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.mapView.actions.panTo',\n description:\n 'Pan the map to a new centre without changing zoom. Read the `center` slot back to confirm — Google animates the pan, so the applied centre settles after the call.',\n errors: [\n 'Silent no-op until the map has loaded: while `consentGranted` is false (only the consent placeholder shows) or while `center` is still null (Google Maps is loading).',\n ],\n invoke: (handle, args: { position: MapLatLng }) => {\n handle.panTo(args.position);\n },\n },\n set_zoom: {\n // Ephemeral viewport zoom, no data loss → read.\n safety: 'read',\n argsType: '{ zoom: number }',\n argsSchema: {\n type: 'object',\n properties: {\n zoom: {\n type: 'number',\n description: 'Zoom level, typical range 1–20.',\n },\n },\n required: ['zoom'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.mapView.actions.setZoom',\n description:\n 'Set the map zoom level (typical range 1–20). Read the `zoom` slot back — Google clamps the request to the map type’s supported range, so requested and applied can differ.',\n errors: [\n 'Silent no-op until the map has loaded: while `consentGranted` is false (only the consent placeholder shows) or while `center` is still null (Google Maps is loading).',\n \"Requested zoom is clamped to the map type's range; `zoom` reports what was actually applied.\",\n ],\n invoke: (handle, args: { zoom: number }) => {\n handle.setZoom(args.zoom);\n },\n },\n select_marker: {\n // Ephemeral marker focus, no data loss → read.\n safety: 'read',\n argsType: '{ id: string | null }',\n argsSchema: {\n type: 'object',\n properties: {\n id: {\n type: ['string', 'null'],\n description: 'Marker id to select, or null to clear the selection.',\n },\n },\n required: ['id'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.mapView.actions.selectMarker',\n description:\n \"Propose a marker selection by id, or pass null to clear it. Fires the host's `onMarkerClick`; selection is controlled by the host, so read the `selectedMarkerId` slot back to see whether it accepted.\",\n errors: [\n 'Silent no-op until the map has loaded: while `consentGranted` is false (only the consent placeholder shows) or while `center` is still null (Google Maps is loading).',\n 'The host owns `selectedMarkerId` and may ignore the proposal; `selectedMarkerId` is unchanged when it does.',\n ],\n invoke: (handle, args: { id: string | null }) => {\n handle.selectMarker(args.id);\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'map-view',\n description: 'Marks the element as a kit MapView.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* MapView — kit wrapper over @vis.gl/react-google-maps. */\n/* */\n/* - Loads the Google Maps JS API on demand via the library's */\n/* `APIProvider`; consumer supplies the key (no kit-side cache). */\n/* - Defaults to a CONSENT-GATED placeholder (`consentGranted={false}`) */\n/* so the third-party load never happens before the consumer flips */\n/* the opt-in. GDPR-safe by default. */\n/* - Theme-reactive: the Google Maps `styles` JSON re-resolves on every */\n/* `documentElement.class` mutation (same pattern as Sparkline). */\n/* Consumers may pass `mapId` to switch to a cloud-styled map */\n/* instead, in which case `styles` is ignored. */\n/* - `data-component=\"map-view\"` lives on the outer span; the inner */\n/* `<Map>` mounts inside it. */\n/* ------------------------------------------------------------------ */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type HTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { MapPin, ExternalLink } from 'lucide-react';\nimport {\n APIProvider,\n Map as GoogleMap,\n AdvancedMarker,\n Marker,\n Pin,\n useApiIsLoaded,\n useMap,\n useMapsLibrary,\n} from '@vis.gl/react-google-maps';\nimport { Button } from '../button';\nimport { Skeleton } from '../skeleton';\nimport { VisuallyHidden } from '../visually-hidden';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { mapViewAgent } from './map-view.agent';\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport interface MapLatLng {\n lat: number;\n lng: number;\n}\n\nexport interface MapMarker {\n /** Stable id — used for keyed re-rendering and `onMarkerClick`. */\n id: string;\n /** Position in lat/lng. */\n position: MapLatLng;\n /** Optional accessible label — falls back to the id. */\n label?: string;\n}\n\nexport interface MapViewHandle {\n /** Pan the map to a new centre without changing zoom. */\n panTo: (position: MapLatLng) => void;\n /** Set zoom (typical range 1–20). */\n setZoom: (zoom: number) => void;\n /** Programmatically select a marker (fires `onMarkerClick`). */\n selectMarker: (id: string | null) => void;\n /* ---- read-back ------------------------------------------------- */\n /**\n * True once the consent gate has been passed. The map may still be\n * loading: the three actions above stay silent no-ops until\n * `getCenter` returns a value.\n */\n isConsentGranted: () => boolean;\n /** Live map centre, or `null` until the map has loaded. */\n getCenter: () => MapLatLng | null;\n /**\n * Live zoom level, or `null` until the map has loaded.\n * Google clamps to the map type's range, so this is not necessarily\n * the value last passed to `setZoom`.\n */\n getZoom: () => number | null;\n /**\n * The controlled `selectedMarkerId` prop as the host currently holds\n * it. `selectMarker` only proposes a selection — the host is free to\n * ignore it, and this is the only way to see whether it did.\n */\n getSelectedMarkerId: () => string | null;\n /** Number of markers passed to the component. Count only, no ids. */\n getMarkerCount: () => number;\n}\n\n/**\n * The slice of `MapViewHandle` that needs a live `google.maps.Map`.\n * Built inside the `APIProvider` subtree by `MapImperativeBridge`; the\n * outer component composes it with the props-derived getters, and holds\n * `null` whenever the subtree is unmounted.\n */\ntype MapBridgeHandle = Pick<\n MapViewHandle,\n 'panTo' | 'setZoom' | 'selectMarker' | 'getCenter' | 'getZoom'\n>;\n\nexport interface MapViewProps\n extends\n Omit<HTMLAttributes<HTMLDivElement>, 'onClick'>,\n VariantProps<typeof mapViewVariants> {\n /** Opaque instance id — emitted as `data-component-id`. */\n id?: string;\n /** Google Maps JS API key. Consumer-owned; never cached by the kit. */\n apiKey: string;\n /** Map centre (lat/lng). Required so the consent placeholder can also use it. */\n center: MapLatLng;\n /** Initial zoom. Default 15 (city-block detail, matches booking site). */\n zoom?: number;\n /**\n * Markers to render. The first marker auto-selects when no\n * `selectedMarkerId` is given.\n */\n markers?: MapMarker[];\n /** Controlled selection — fires `onMarkerClick` with the new id (or null on map click). */\n selectedMarkerId?: string | null;\n /** Fires when a marker is clicked, or `null` when the map background is clicked. */\n onMarkerClick?: (id: string | null) => void;\n /**\n * GDPR consent gate. When `false` (default) the component renders a\n * placeholder with a translated CTA — the Maps JS API is **not**\n * loaded. Flip to `true` once the consumer has captured opt-in.\n */\n consentGranted?: boolean;\n /** Fires when the consumer clicks the \"Load map\" CTA in the placeholder. */\n onConsentRequest?: () => void;\n /**\n * Optional address string shown in the consent placeholder so the\n * surface is useful before the map loads. Also used to build the\n * fallback \"Open in Google Maps\" link target.\n */\n address?: string;\n /**\n * Cloud-styled-map id. When set, takes precedence over the JSON\n * `styles` array and disables the theme-bridge re-fire. Use when\n * you've provisioned a styled map in Google Cloud Console.\n */\n mapId?: string;\n /**\n * Override the consent-placeholder description text. The default\n * (`t('mapView.consentDescription')`) is a generic IP-disclosure\n * line. Consumers operating under specific GDPR / ePrivacy\n * disclosures (jurisdiction, named controller, policy link) should\n * supply their own text via this prop. Pass any `ReactNode` — a\n * paragraph, a localised `<Trans>` instance, etc.\n */\n consentDescription?: ReactNode;\n /**\n * Replace the kit-rendered \"Load map\" button with custom CTA chrome.\n * Use when the consent dialog needs a policy link, a specific\n * jurisdiction phrasing, or a different surface (Tooltip-wrapped\n * button, link to a settings page, etc.). When omitted the kit\n * renders its own `<Button>` — that button calls `onConsentRequest`\n * if provided, otherwise flips MapView's internal opt-in state so\n * the map loads inline.\n */\n consentCta?: ReactNode;\n /**\n * Visual surface. Default `bordered` (current behaviour: 1px\n * `--border` outline + `--radius-md`). `elevated` replaces the\n * border with `--shadow-card`, matching `<Card variant=\"elevated\">`.\n * `bare` drops both — map is flush against the page canvas.\n */\n surface?: 'bordered' | 'elevated' | 'bare';\n /** Accessible label for the map region. Falls back to `t('mapView.label')`. */\n ariaLabel?: string;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst mapViewVariants = cva(\n ['ds:relative ds:overflow-hidden ds:block', 'ds:bg-[var(--muted)]'].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:[--map-block-size:14rem]',\n md: 'ds:[--map-block-size:20rem]',\n lg: 'ds:[--map-block-size:28rem]',\n // `fill` defers sizing to the parent. The outer takes\n // `block-size: 100%` so the inner (also 100%) has something\n // to inherit from. Use inside a viewport-locked column —\n // `<PracticeResults variant=\"map-first\">` wires this through\n // automatically; standalone consumers must give the parent\n // a constrained block-size or the map collapses to 0.\n fill: 'ds:[block-size:100%]',\n },\n surface: {\n bordered:\n 'ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--border)]',\n elevated:\n 'ds:rounded-[var(--radius-md)] ds:shadow-[var(--shadow-card)] ds:[:where(&)]:border-[length:var(--surface-border-width,var(--border-width-sm))] ds:border-[color:var(--card-border)]',\n bare: 'ds:rounded-none ds:border-0',\n },\n },\n defaultVariants: { size: 'md', surface: 'bordered' },\n },\n);\n\n// Inner block-size: percentage when `size=\"fill\"`, rem-token otherwise.\n// Splitting this out (instead of compound-variants) keeps the size\n// switch readable and avoids enumerating every (size × surface) pair.\nconst innerSurfaceVariants = cva('ds:block ds:inline-size-full', {\n variants: {\n size: {\n sm: 'ds:[block-size:var(--map-block-size)]',\n md: 'ds:[block-size:var(--map-block-size)]',\n lg: 'ds:[block-size:var(--map-block-size)]',\n fill: 'ds:[block-size:100%]',\n },\n },\n defaultVariants: { size: 'md' },\n});\n\nconst consentChromeVariants = cva(\n [\n 'ds:absolute ds:inset-0',\n 'ds:flex ds:flex-col ds:items-center ds:justify-center',\n 'ds:gap-[var(--spacing-sm)]',\n 'ds:p-[var(--spacing-md)]',\n 'ds:bg-[var(--muted)] ds:text-[var(--foreground)]',\n 'ds:text-center',\n ].join(' '),\n);\n\nconst consentTitleVariants = cva('type-heading-3 ds:m-0');\n\nconst consentDescriptionVariants = cva(\n 'type-body-sm ds:text-[var(--muted-foreground)] ds:[max-inline-size:28rem] ds:m-0',\n);\n\n/* ------------------------------------------------------------------ */\n/* Inner imperative bridge */\n/* */\n/* `useMap()` only resolves inside the APIProvider tree, so the */\n/* imperative actions live in a tiny inner component that the outer */\n/* `MapView` mounts conditionally. It exposes the `panTo` / `setZoom` */\n/* etc. to the forwardRef via a `useImperativeHandle` callback prop. */\n/* ------------------------------------------------------------------ */\n\ninterface MapImperativeBridgeProps {\n /** Called with the live handle on mount, and with `null` on unmount. */\n onHandleReady: (handle: MapBridgeHandle | null) => void;\n onMarkerSelect: (id: string | null) => void;\n}\n\nfunction MapImperativeBridge({\n onHandleReady,\n onMarkerSelect,\n}: MapImperativeBridgeProps): null {\n const map = useMap();\n useEffect(() => {\n if (!map) return;\n onHandleReady({\n panTo: (position) => map.panTo(position),\n setZoom: (zoom) => map.setZoom(zoom),\n selectMarker: (id) => onMarkerSelect(id),\n // Read straight off the live map: Google clamps `setZoom` to the\n // map type's range and animates `panTo`, so requested and applied\n // are not the same value.\n getCenter: () => map.getCenter()?.toJSON() ?? null,\n getZoom: () => map.getZoom() ?? null,\n });\n // Drop the handle when the subtree unmounts (consent revoked, or the\n // component tears down) so the outer getters answer `null` instead of\n // reporting a dead map's last known position.\n return () => onHandleReady(null);\n }, [map, onHandleReady, onMarkerSelect]);\n return null;\n}\n\n/* ------------------------------------------------------------------ */\n/* Library gates */\n/* */\n/* APIProvider reports LOADED as soon as `google.maps.importLibrary` */\n/* exists when another loader installed it (Google's bootstrap, a host */\n/* Places loader), before the `maps` library itself has arrived. <Map> */\n/* would then run `new google.maps.Map` and throw, taking the host's */\n/* React tree down. The map waits for `maps`, and the markers for */\n/* `marker`, whoever loaded the API. Before the API loads, <Map> only */\n/* renders its empty container, and once a constructor exists nothing */\n/* can throw, so both pass straight through as they always did. */\n/* ------------------------------------------------------------------ */\n\ntype GoogleMapsGlobal = {\n google?: { maps?: { Map?: unknown; Marker?: unknown } };\n};\nconst hasConstructor = (name: 'Map' | 'Marker'): boolean =>\n typeof (globalThis as GoogleMapsGlobal).google?.maps?.[name] === 'function';\n\n/** What the map area shows while Google's map library is on its way.\n * Exported for its story; not part of the public API. */\nexport function MapViewLoading(): ReactNode {\n const { t } = useTranslation('ui');\n return (\n <div\n role=\"status\"\n data-testid=\"map-view-loading\"\n className=\"ds:[inline-size:100%] ds:[block-size:100%]\"\n >\n <Skeleton variant=\"rectangular\" width=\"100%\" height=\"100%\" />\n <VisuallyHidden>{t('common.loading')}</VisuallyHidden>\n </div>\n );\n}\n\nfunction MapsLibraryGate({ children }: { children: ReactNode }): ReactNode {\n const apiIsLoaded = useApiIsLoaded();\n const maps = useMapsLibrary('maps');\n if (maps || !apiIsLoaded || hasConstructor('Map')) return children;\n return <MapViewLoading />;\n}\n\nfunction MarkerLibraryGate({ children }: { children: ReactNode }): ReactNode {\n const marker = useMapsLibrary('marker');\n return marker || hasConstructor('Marker') ? children : null;\n}\n\n/* ------------------------------------------------------------------ */\n/* Consent placeholder */\n/* ------------------------------------------------------------------ */\n\ninterface ConsentPlaceholderProps {\n address: string | undefined;\n description: ReactNode;\n /**\n * Click handler for the \"Load map\" button. Always rendered. When the\n * consumer provides `onConsentRequest` it owns the state transition\n * (typically: open a GDPR dialog, then flip `consentGranted` to true\n * after acceptance). When omitted, the kit's `MapView` falls back to\n * its own internal opt-in toggle — clicking grants consent for this\n * MapView instance only, no consumer plumbing required. This default\n * fixes a regression where the button was conditionally rendered and\n * any consumer omitting `onConsentRequest` left the patient with no\n * way to load the map (booking-website 0.31.0 hit this).\n */\n onLoadMap: () => void;\n openInGoogleMapsHref: string;\n /**\n * Custom CTA — replaces the kit-rendered `<Button>` when the consumer\n * needs a different surface (e.g. a Tooltip-wrapped button with a\n * policy link). The kit's button is still the recommended path; this\n * slot exists for consumers operating under specific compliance UX\n * requirements (jurisdiction, named controller, policy link). Pass\n * any `ReactNode`.\n */\n consentCta: ReactNode | undefined;\n}\n\nfunction ConsentPlaceholder({\n address,\n description,\n onLoadMap,\n openInGoogleMapsHref,\n consentCta,\n}: ConsentPlaceholderProps): ReactNode {\n const { t } = useTranslation('ui');\n return (\n <div className={consentChromeVariants()} data-testid=\"map-view-consent\">\n <MapPin\n aria-hidden=\"true\"\n className=\"ds:size-6 ds:text-[var(--muted-foreground)]\"\n />\n <p className={consentTitleVariants()}>{t('mapView.consentTitle')}</p>\n {address ? (\n <p\n className={consentDescriptionVariants()}\n data-testid=\"map-view-address\"\n >\n {address}\n </p>\n ) : null}\n <p className={consentDescriptionVariants()}>{description}</p>\n <div className=\"ds:flex ds:gap-[var(--spacing-sm)] ds:flex-wrap ds:items-center ds:justify-center\">\n {consentCta ?? (\n <Button\n type=\"button\"\n intent=\"primary\"\n size=\"sm\"\n onClick={onLoadMap}\n data-testid=\"map-view-load-cta\"\n >\n {t('mapView.consentCta')}\n </Button>\n )}\n <a\n href={openInGoogleMapsHref}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-2xs)] ds:text-[var(--primary)] ds:underline ds:underline-offset-2\"\n >\n {t('mapView.openInGoogleMaps')}\n <ExternalLink aria-hidden=\"true\" className=\"ds:size-3\" />\n </a>\n </div>\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* MapView */\n/* ------------------------------------------------------------------ */\n\nexport const MapView = forwardRef<MapViewHandle, MapViewProps>(\n (\n {\n id,\n apiKey,\n center,\n zoom = 15,\n markers,\n selectedMarkerId,\n onMarkerClick,\n consentGranted = false,\n onConsentRequest,\n address,\n consentDescription,\n consentCta,\n mapId,\n size,\n surface,\n ariaLabel,\n className,\n ...rest\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation('ui');\n const rawId = useId();\n const instanceId = useMemo(\n () => `map-${rawId.replace(/[^a-zA-Z0-9-_]/g, '')}`,\n [rawId],\n );\n\n // Reduced-motion gating. Google's own pan / zoom animations\n // happen inside the Maps JS API and the kit can't reach into\n // those — but the kit's own programmatic `panTo` calls (triggered\n // by prop changes via the controlled-sync effect below) can be\n // suppressed. When `prefers-reduced-motion: reduce` is set, we\n // skip the synthetic `panTo` so the consumer's prop change\n // results in a hard recenter rather than an animated glide.\n const [reducedMotion, setReducedMotion] = useState(false);\n useEffect(() => {\n if (typeof window === 'undefined') return undefined;\n const mql = window.matchMedia('(prefers-reduced-motion: reduce)');\n const sync = (): void => setReducedMotion(mql.matches);\n sync();\n mql.addEventListener('change', sync);\n return () => mql.removeEventListener('change', sync);\n }, []);\n\n // The \"Open in Google Maps\" fallback link — works without any\n // third-party script load. Uses the modern `?api=1&query=…` form\n // which the booking site already employs.\n const openInGoogleMapsHref = useMemo(() => {\n const query = address\n ? encodeURIComponent(address)\n : `${center.lat},${center.lng}`;\n return `https://www.google.com/maps/search/?api=1&query=${query}`;\n }, [address, center.lat, center.lng]);\n\n // 0.33.5: removed the kit's `getGoogleMapsTheme()` JSON-styles\n // override. Previously, when `mapId` was absent the kit painted\n // water / roads / landscape with kit tokens — a calm muted-grey\n // palette that diverged from the standard Google Maps appearance\n // users expect in every other maps surface they touch. Google's\n // default (blue water, beige land, named-road colours) is more\n // familiar and reads as a \"real map\" rather than a stylised one.\n //\n // Consumers wanting brand-themed colours opt in via `mapId` and\n // configure the palette in Google Cloud Console — that's the\n // Google-recommended path. The `getGoogleMapsTheme` export stays\n // in `src/tokens/google-maps-theme.ts` so consumers wanting the\n // old behaviour can apply the styles themselves, but the kit\n // does NOT install them by default any more.\n //\n // Side benefit: dropped the MutationObserver that previously\n // watched documentElement.class for theme switches — no more\n // observer churn on every theme toggle.\n\n // Imperative handle plumbing — populated by the inner bridge once\n // the APIProvider tree resolves a `Map` instance.\n const handleRef = useRef<MapBridgeHandle | null>(null);\n const onHandleReady = useCallback((handle: MapBridgeHandle | null) => {\n handleRef.current = handle;\n }, []);\n\n // Read in the OUTER component, not through `handleRef` — these three\n // must still answer when the map subtree is unmounted, which is\n // exactly the situation an agent needs explaining. Assigned during\n // render, below, once `effectiveConsent` exists.\n const consentRef = useRef(false);\n const selectedMarkerIdRef = useRef<string | null>(null);\n const markerCountRef = useRef(0);\n\n const buildHandle = useCallback(\n (): MapViewHandle => ({\n panTo: (position) => handleRef.current?.panTo(position),\n setZoom: (z) => handleRef.current?.setZoom(z),\n selectMarker: (markerId) => handleRef.current?.selectMarker(markerId),\n // Without `isConsentGranted` an agent has no way to learn that\n // its pan / zoom / select was swallowed by the GDPR gate rather\n // than applied: under the default (`consentGranted={false}`) the\n // whole Maps subtree is unmounted and every action optional-chains\n // into nothing.\n isConsentGranted: () => consentRef.current,\n getCenter: () => handleRef.current?.getCenter() ?? null,\n getZoom: () => handleRef.current?.getZoom() ?? null,\n getSelectedMarkerId: () => selectedMarkerIdRef.current,\n getMarkerCount: () => markerCountRef.current,\n }),\n [],\n );\n useImperativeHandle(ref, buildHandle, [buildHandle]);\n\n const agentHandle = useMemo<MapViewHandle>(\n () => buildHandle(),\n [buildHandle],\n );\n useAgentRegistration(mapViewAgent, agentHandle, id);\n\n // Controlled-feeling propagation: vis.gl's `<Map>` reads `center`\n // and `zoom` as initial values only (via `defaultCenter` /\n // `defaultZoom`). To honour the documented \"live prop\" contract\n // we shim post-mount sync through the imperative bridge — a\n // parent that swaps offices by changing `center` re-centres the\n // map. User drag does NOT trigger this because the prop doesn't\n // change on user gesture, so the effect doesn't fire and the\n // map stays where the user left it.\n useEffect(() => {\n // Skip the animated pan under reduced-motion preference; the\n // map will still recentre on the next render via the agent\n // handle's `panTo`, but Google's own glide animation runs\n // either way (kit can't reach inside it). At least the kit's\n // own initiated pan is gated.\n if (reducedMotion) return;\n handleRef.current?.panTo(center);\n // Including `center` (the object reference) instead of\n // `center.lat`/`center.lng` would fire on every parent render\n // even when the coordinates are identical, fighting user drag.\n // The destructured deps are intentional.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [center.lat, center.lng, reducedMotion]);\n useEffect(() => {\n handleRef.current?.setZoom(zoom);\n }, [zoom]);\n\n // Internal opt-in fallback. The `consentGranted` prop is the\n // controlled path — consumer flips it after capturing GDPR\n // acceptance through their own dialog and re-renders. When the\n // consumer omits `onConsentRequest` they're opting out of that\n // workflow, so the kit needs a sensible default click handler on\n // the placeholder's button. `internalConsent` tracks that opt-in\n // for this instance only; the map renders when either signal is\n // truthy. The 0.31.0 regression was conditionally rendering the\n // button on `onConsentRequest` — patients of consumers without the\n // hook saw the placeholder with no way to proceed.\n const [internalConsent, setInternalConsent] = useState(false);\n const effectiveConsent = consentGranted || internalConsent;\n // Mirror the three props-derived agent state slots. Assigned during\n // render so a read immediately after a prop change sees the settled\n // value. Ids and a count only — never `MapMarker.label`, never the\n // `address` prop (consumer-supplied free text, PII in any\n // patient-address deployment), never `apiKey`.\n consentRef.current = effectiveConsent;\n selectedMarkerIdRef.current = selectedMarkerId ?? null;\n markerCountRef.current = (markers ?? []).length;\n const handleLoadMap = useCallback(() => {\n if (onConsentRequest) {\n onConsentRequest();\n // The consumer typically flips `consentGranted` to true on the\n // next render. Flip the internal state too so the map still\n // loads if the consumer forgets to update its prop (the\n // common-case footgun this fallback exists to defuse).\n setInternalConsent(true);\n return;\n }\n setInternalConsent(true);\n }, [onConsentRequest]);\n\n return (\n <div\n className={mapViewVariants({ size, surface, className })}\n data-component=\"map-view\"\n data-component-id={id ?? instanceId}\n role=\"region\"\n aria-label={ariaLabel ?? t('mapView.label')}\n {...rest}\n >\n <div className={innerSurfaceVariants({ size })}>\n {effectiveConsent ? (\n <APIProvider\n apiKey={apiKey}\n // Pull the active i18next locale through so map UI text\n // (zoom controls, attribution) localises to match the\n // surrounding kit chrome.\n language={i18n.language}\n >\n <MapsLibraryGate>\n <GoogleMap\n defaultCenter={center}\n defaultZoom={zoom}\n mapId={mapId}\n gestureHandling=\"cooperative\"\n disableDefaultUI={false}\n onClick={() => onMarkerClick?.(null)}\n // `<Map>` reads its own bounding rect for tile sizing.\n // Without explicit dimensions it collapses to 0×0, so\n // we pass kit-class sizing through `className` — vis.gl\n // forwards `className` straight to the rendered root.\n className=\"ds:[inline-size:100%] ds:[block-size:100%]\"\n >\n <MapImperativeBridge\n onHandleReady={onHandleReady}\n onMarkerSelect={(markerId) => onMarkerClick?.(markerId)}\n />\n <MarkerLibraryGate>\n {(markers ?? []).map((marker) => {\n // Selection state is exposed to the consumer via\n // `data-selected` on the marker root so consumers can\n // style their own InfoWindow / sidebar highlight from\n // it. The kit does NOT swap the Pin's fill colour on\n // selection — `--accent` (magenta-500 in light theme)\n // fails AA on white per 05-accessibility.mdx, and the\n // alternative tokens that pass (`--info`, `--success`)\n // carry semantic baggage. Visual selection state is\n // the consumer's call.\n const isSelected =\n selectedMarkerId != null &&\n selectedMarkerId === marker.id;\n const accessibleLabel = t('mapView.markerLabel', {\n label: marker.label ?? marker.id,\n });\n // Pin implementation switches on whether the\n // consumer supplied `mapId`. Google's\n // AdvancedMarkerElement requires the Map instance to\n // be initialised with a valid Map ID — without one\n // the API logs an error (\"La mappa è stata\n // inizializzata senza un ID mappa valido\") and any\n // AdvancedMarker rendered against that map fails to\n // appear. Cloud Map IDs are an opt-in feature; many\n // consumers (booking-website env without\n // GOOGLE_MAPS_MAP_ID, the OSS demo, etc.) legitimately\n // omit it.\n //\n // Fall back to the classic <Marker> (a thin wrapper\n // around google.maps.Marker) when mapId is absent.\n // Google has formally deprecated google.maps.Marker\n // but it still renders cleanly and produces no\n // console errors; the only loss is the brand-tinted\n // <Pin> chrome (which Marker doesn't accept as a\n // child). When a consumer wants the styled pin they\n // can opt back in by supplying `mapId`.\n if (mapId) {\n return (\n <AdvancedMarker\n key={marker.id}\n position={marker.position}\n // `title` becomes the HTML `title` attribute on\n // Google's marker wrapper — that's a tooltip, not\n // a reliable accessible name. The wrapper also\n // receives `aria-label` which Google honours as\n // the SR-announced name. Both are set so sighted\n // hover tooltips and SR labels stay aligned.\n title={accessibleLabel}\n aria-label={accessibleLabel}\n data-selected={isSelected ? 'true' : 'false'}\n onClick={() => onMarkerClick?.(marker.id)}\n >\n <Pin\n background={'var(--primary)'}\n borderColor={'var(--primary)'}\n glyphColor={'var(--primary-foreground)'}\n />\n </AdvancedMarker>\n );\n }\n return (\n <Marker\n key={marker.id}\n position={marker.position}\n title={accessibleLabel}\n onClick={() => onMarkerClick?.(marker.id)}\n />\n );\n })}\n </MarkerLibraryGate>\n </GoogleMap>\n </MapsLibraryGate>\n </APIProvider>\n ) : (\n <ConsentPlaceholder\n address={address}\n description={\n consentDescription ?? t('mapView.consentDescription')\n }\n onLoadMap={handleLoadMap}\n consentCta={consentCta}\n openInGoogleMapsHref={openInGoogleMapsHref}\n />\n )}\n </div>\n </div>\n );\n },\n);\nMapView.displayName = 'MapView';\n"],"names":["mapViewAgent","handle","args","mapViewVariants","cva","innerSurfaceVariants","consentChromeVariants","consentTitleVariants","consentDescriptionVariants","MapImperativeBridge","onHandleReady","onMarkerSelect","map","useMap","useEffect","position","zoom","id","_a","hasConstructor","name","_b","MapViewLoading","useTranslation","jsxs","jsx","Skeleton","VisuallyHidden","MapsLibraryGate","children","apiIsLoaded","useApiIsLoaded","useMapsLibrary","MarkerLibraryGate","ConsentPlaceholder","address","description","onLoadMap","openInGoogleMapsHref","consentCta","t","MapPin","Button","ExternalLink","MapView","forwardRef","apiKey","center","markers","selectedMarkerId","onMarkerClick","consentGranted","onConsentRequest","consentDescription","mapId","size","surface","ariaLabel","className","rest","ref","i18n","rawId","useId","instanceId","useMemo","reducedMotion","setReducedMotion","useState","mql","sync","handleRef","useRef","useCallback","consentRef","selectedMarkerIdRef","markerCountRef","buildHandle","z","markerId","useImperativeHandle","agentHandle","useAgentRegistration","internalConsent","setInternalConsent","effectiveConsent","handleLoadMap","APIProvider","GoogleMap","marker","isSelected","accessibleLabel","AdvancedMarker","Pin","Marker"],"mappings":"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"}
|