@conduction/nextcloud-vue 2.140.0 → 2.141.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.
Files changed (74) hide show
  1. package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue.js +1 -1
  2. package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js +10 -2
  3. package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js.map +1 -1
  4. package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue3.js.map +1 -1
  5. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
  6. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +11 -3
  7. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  8. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  9. package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
  10. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +12 -0
  11. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
  12. package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js +57 -40
  13. package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
  14. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
  15. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +1 -0
  16. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  17. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  18. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +5 -3
  19. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  20. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +1 -0
  21. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  22. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +65 -1
  23. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
  24. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +120 -69
  25. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
  26. package/dist/esm/components/CnMapWidget/CnMapWidget.vue.js +1 -1
  27. package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js +47 -9
  28. package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js.map +1 -1
  29. package/dist/esm/components/CnMapWidget/CnMapWidget.vue3.js.map +1 -1
  30. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
  31. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +3 -3
  32. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  33. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  34. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  35. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +2 -0
  36. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  37. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +1 -1
  38. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  39. package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue.js +1 -1
  40. package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue2.js +10 -0
  41. package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue2.js.map +1 -1
  42. package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue3.js +34 -26
  43. package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue3.js.map +1 -1
  44. package/dist/esm/l10n/en.json.js +2 -1
  45. package/dist/esm/l10n/en.json.js.map +1 -1
  46. package/dist/esm/l10n/nl.json.js +2 -1
  47. package/dist/esm/l10n/nl.json.js.map +1 -1
  48. package/dist/esm/library-style.js +1 -1
  49. package/dist/esm/nextcloud-vue.css +652 -391
  50. package/dist/esm/utils/groupSublines.js +120 -0
  51. package/dist/esm/utils/groupSublines.js.map +1 -0
  52. package/dist/nextcloud-vue.cjs.js +974 -638
  53. package/dist/nextcloud-vue.cjs.js.map +2 -2
  54. package/dist/nextcloud-vue.css +652 -391
  55. package/l10n/en.json +2 -1
  56. package/l10n/nl.json +2 -1
  57. package/package.json +1 -1
  58. package/src/components/CnAssignDialog/CnAssignDialog.vue +10 -2
  59. package/src/components/CnCellRenderer/CnCellRenderer.vue +11 -3
  60. package/src/components/CnChartWidget/CnChartWidget.md +1 -0
  61. package/src/components/CnChartWidget/CnChartWidget.vue +49 -4
  62. package/src/components/CnDashboardPage/CnDashboardPage.vue +1 -0
  63. package/src/components/CnDataTable/CnDataTable.vue +6 -3
  64. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +101 -3
  65. package/src/components/CnMapWidget/CnMapWidget.vue +47 -9
  66. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +3 -3
  67. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +20 -1
  68. package/src/components/CnRecordListWidget/CnRecordNoteRows.vue +33 -9
  69. package/src/css/dialog.css +13 -1
  70. package/src/css/look-board-detail.css +12 -9
  71. package/src/css/look-board-index.css +90 -7
  72. package/src/css/look-board.css +92 -0
  73. package/src/css/table.css +12 -0
  74. package/src/utils/groupSublines.js +125 -0
@@ -1 +1 @@
1
- {"version":3,"file":"CnDashboardPage.vue2.js","sources":["../../../../src/components/CnDashboardPage/CnDashboardPage.vue"],"sourcesContent":["<!--\n CnDashboardPage — Top-level dashboard page with GridStack widget grid.\n\n The dashboard equivalent of CnIndexPage. Assembles a complete dashboard\n from a widget definition array and a layout array. Supports:\n - Custom widgets via scoped slots (#widget-{widgetId})\n - Nextcloud Dashboard API widgets (auto-rendered)\n - Tile widgets (quick-access links)\n - Drag-and-drop editing mode\n - Header with title, actions, and edit toggle\n-->\n<template>\n\t<div\n\t\tclass=\"cn-dashboard-page\"\n\t\t:class=\"{ 'cn-dashboard-page--board': isBoardLook }\"\n\t\t:style=\"{ '--cn-dashboard-grid-margin': `${gridMargin}px` }\"\n\t\tdata-testid=\"cn-dashboard-page\">\n\t\t<!-- Header. `showHeader: false` drops the whole row (title, description,\n\t\t header actions, edit toggle) for a page that opens with its own\n\t\t heading, such as a greeting; the title then stays as a visually\n\t\t hidden heading so the main landmark keeps its name. -->\n\t\t<h2 v-if=\"!showHeader && title\" class=\"hidden-visually\" data-testid=\"cn-dashboard-page-hidden-title\">\n\t\t\t{{ resolvedTitle }}\n\t\t</h2>\n\t\t<div v-if=\"showHeader\" class=\"cn-dashboard-page__header\" data-testid=\"cn-dashboard-page-header\">\n\t\t\t<div class=\"cn-dashboard-page__header-left\">\n\t\t\t\t<div v-if=\"title || $slots['title-meta']\" class=\"cn-dashboard-page__title-row\">\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"isBoardLook ? 'h1' : 'h2'\"\n\t\t\t\t\t\tv-if=\"title\"\n\t\t\t\t\t\tclass=\"cn-dashboard-page__title\">\n\t\t\t\t\t\t{{ resolvedTitle }}\n\t\t\t\t\t</component>\n\t\t\t\t\t<!-- @slot title-meta Content on the title's row, right of the title (e.g. a page-wide picker). Fill it from a manifest with `page.slots: { \"title-meta\": \"<RegistryName>\" }`. -->\n\t\t\t\t\t<slot name=\"title-meta\" />\n\t\t\t\t</div>\n\t\t\t\t<CnHeaderTrail\n\t\t\t\t\t:breadcrumb=\"breadcrumb\"\n\t\t\t\t\t:current=\"title ? resolvedTitle : ''\"\n\t\t\t\t\t:meta=\"resolvedHeaderMeta\" />\n\t\t\t\t<!-- `dateRange.placement: \"description\"`: the segmented period\n\t\t\t\t group ends the description line, after its page filters\n\t\t\t\t (\"Week 41 · alle teams · [Deze week | Dit kwartaal | Dit jaar]\"). -->\n\t\t\t\t<div\n\t\t\t\t\tv-if=\"datePeriodInDescription || descriptionFilters.length > 0\"\n\t\t\t\t\tclass=\"cn-dashboard-page__description cn-dashboard-page__description--with-period\"\n\t\t\t\t\tdata-testid=\"cn-dashboard-page-subtitle\">\n\t\t\t\t\t<span v-if=\"subtitleText\">{{ subtitleText }}</span>\n\t\t\t\t\t<span v-if=\"subtitleText\" aria-hidden=\"true\">&middot;</span>\n\t\t\t\t\t<!-- The page filters with `placement: \"description\"`, in the\n\t\t\t\t\t order the page declares them: a select as a compact\n\t\t\t\t\t select (DqDoorlooptijd \"alle zaaktypen\"), a\n\t\t\t\t\t `control: \"segmented\"` one as a segmented group that\n\t\t\t\t\t writes the workspace context (DqProcesanalyse\n\t\t\t\t\t \"Gemiddeld | Mediaan\"). -->\n\t\t\t\t\t<template v-for=\"(pf, pfIndex) in descriptionFilters\" :key=\"pf.key\">\n\t\t\t\t\t\t<CnSegmentedControl\n\t\t\t\t\t\t\tv-if=\"pf.control === 'segmented'\"\n\t\t\t\t\t\t\tsize=\"compact\"\n\t\t\t\t\t\t\tmode=\"toggle\"\n\t\t\t\t\t\t\t:options=\"pageFilterSegments(pf)\"\n\t\t\t\t\t\t\t:modelValue=\"workspaceContext[pf.key]\"\n\t\t\t\t\t\t\t:ariaLabel=\"pf.label ? effectiveTranslate(pf.label) : pf.key\"\n\t\t\t\t\t\t\t:data-testid=\"'cn-page-filter-' + pf.key\"\n\t\t\t\t\t\t\t@update:modelValue=\"onPageFilterChange(pf, $event)\" />\n\t\t\t\t\t\t<template v-else>\n\t\t\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t\t\tclass=\"cn-dashboard-page__description-select\"\n\t\t\t\t\t\t\t\t:modelValue=\"selectedPageFilterOption(pf)\"\n\t\t\t\t\t\t\t\t:options=\"pageFilterSegments(pf)\"\n\t\t\t\t\t\t\t\t:clearable=\"pf.clearable === true\"\n\t\t\t\t\t\t\t\t:placeholder=\"pf.placeholder ? effectiveTranslate(pf.placeholder) : undefined\"\n\t\t\t\t\t\t\t\t:loading=\"pageFilterLoading[pf.key] === true\"\n\t\t\t\t\t\t\t\t:ariaLabelCombobox=\"pf.label ? effectiveTranslate(pf.label) : pf.key\"\n\t\t\t\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t\t\t\t:data-testid=\"'cn-page-filter-' + pf.key\"\n\t\t\t\t\t\t\t\t@update:modelValue=\"onPageFilterChange(pf, $event)\" />\n\t\t\t\t\t\t\t<span v-if=\"segmentedFollows(pfIndex)\" aria-hidden=\"true\">&middot;</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</template>\n\t\t\t\t\t<CnSegmentedControl\n\t\t\t\t\t\tv-if=\"datePeriodInDescription\"\n\t\t\t\t\t\tsize=\"compact\"\n\t\t\t\t\t\tmode=\"toggle\"\n\t\t\t\t\t\t:options=\"segmentedOptions\"\n\t\t\t\t\t\t:modelValue=\"segmentedValue\"\n\t\t\t\t\t\t:ariaLabel=\"datePeriodLabel\"\n\t\t\t\t\t\tdata-testid=\"cn-dashboard-page-date-segmented\"\n\t\t\t\t\t\t@update:modelValue=\"onSegmentPick\" />\n\t\t\t\t</div>\n\t\t\t\t<p v-else-if=\"subtitleText\" class=\"cn-dashboard-page__description\" data-testid=\"cn-dashboard-page-subtitle\">\n\t\t\t\t\t{{ subtitleText }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t\t<div class=\"cn-dashboard-page__header-actions\">\n\t\t\t\t<!-- The page's view switch (`views`), unless a greeting header\n\t\t\t\t widget on the page draws it. Its options control the view\n\t\t\t\t region below the grid. -->\n\t\t\t\t<CnSegmentedControl\n\t\t\t\t\tv-if=\"showsPageViewSwitch && !switchInRow\"\n\t\t\t\t\tclass=\"cn-page-view-switch\"\n\t\t\t\t\t:options=\"viewSwitchOptions\"\n\t\t\t\t\t:modelValue=\"activeViewId\"\n\t\t\t\t\t:ariaLabel=\"viewSwitchLabel\"\n\t\t\t\t\t:controls=\"viewRegionId\"\n\t\t\t\t\tdata-testid=\"cn-dashboard-page-view-switch\"\n\t\t\t\t\t@update:modelValue=\"selectView\" />\n\t\t\t\t<!-- Declarative header actions (#91 Wave 3): a manifest\n\t\t\t\t `headerActions[]` renders as buttons (open-form / api-call /\n\t\t\t\t toggle / navigate / refresh) with visibleWhen gating,\n\t\t\t\t before the slot content so app-provided buttons stay\n\t\t\t\t right-most next to the edit toggle. -->\n\t\t\t\t<template v-if=\"!isBoardLook\">\n\t\t\t\t\t<CnActionButtons\n\t\t\t\t\t\tv-if=\"headerActions && headerActions.length\"\n\t\t\t\t\t\t:actions=\"linkedHeaderActions\"\n\t\t\t\t\t\tdata-testid=\"cn-dashboard-page-header-actions\" />\n\t\t\t\t\t<!-- @slot header-actions Inline buttons rendered in the dashboard header next to the edit toggle. Used by every existing consumer (decidesk, launchpad, opencatalogi, pipelinq, procest). -->\n\t\t\t\t\t<slot name=\"header-actions\" />\n\t\t\t\t\t<!-- @slot actions Back-compat alias for `#header-actions`. Prefer `#header-actions` in new code. -->\n\t\t\t\t\t<slot name=\"actions\" />\n\t\t\t\t</template>\n\t\t\t\t<CnActionButtons\n\t\t\t\t\tv-else-if=\"boardSecondaryHeaderActions.length\"\n\t\t\t\t\t:actions=\"boardSecondaryHeaderActions\"\n\t\t\t\t\tdata-testid=\"cn-dashboard-page-header-actions-secondary\" />\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"allowEdit\"\n\t\t\t\t\t:variant=\"isEditing ? 'primary' : 'secondary'\"\n\t\t\t\t\t@click=\"toggleEdit\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Pencil v-if=\"!isEditing\" :size=\"20\" />\n\t\t\t\t\t\t<Check v-else :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ isEditing ? shownDoneLabel : shownEditLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<!-- With `userLayout`, edit mode offers a way back to the\n\t\t\t\t manifest: the page's own grid and the chosen view return\n\t\t\t\t to the layout the app ships. Other views keep theirs. -->\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"userLayout && isEditing\"\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\tdata-testid=\"cn-dashboard-page-reset-layout\"\n\t\t\t\t\t@click=\"resetLayout\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Restore :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ t('nextcloud-vue', 'Reset layout') }}\n\t\t\t\t</NcButton>\n\t\t\t\t<!-- In-app edit button (ADR-041). Renders only when Buildiq is\n\t\t\t\t reachable; self-wires from the cnManifestEditor / cnOpenBuildAvailable\n\t\t\t\t provided by CnAppRoot. Sits inline with the page's action buttons. -->\n\t\t\t\t<CnBuildiqEditButton v-if=\"!isBoardLook\" />\n\t\t\t\t<!-- Page-level overflow Actions menu (Refresh + the mandatory\n\t\t\t\t trio Request a feature / Report a bug / Documentation).\n\t\t\t\t Separate from the per-widget menus. `docs-anchor` deep-links\n\t\t\t\t the docs item to THIS page's section. -->\n\t\t\t\t<CnActionsMenu\n\t\t\t\t\tv-if=\"showActionsMenu\"\n\t\t\t\t\t:showRefresh=\"showRefresh\"\n\t\t\t\t\t:showRequestFeature=\"showRequestFeature\"\n\t\t\t\t\t:showReportBug=\"showReportBug\"\n\t\t\t\t\t:showDocumentation=\"showDocumentation\"\n\t\t\t\t\t:documentationUrl=\"documentationUrl\"\n\t\t\t\t\t:docsAnchor=\"resolvedPageId\"\n\t\t\t\t\t:documentationLabel=\"documentationLabel\"\n\t\t\t\t\t:refreshLabel=\"refreshLabel\"\n\t\t\t\t\t:requestFeatureLabel=\"requestFeatureLabel\"\n\t\t\t\t\t:actionsMenuLabel=\"actionsMenuLabel\"\n\t\t\t\t\t:refreshing=\"refreshing\"\n\t\t\t\t\t:widgetId=\"resolvedPageId\"\n\t\t\t\t\t:title=\"title\"\n\t\t\t\t\t:surface=\"`dashboard:${resolvedPageId}`\"\n\t\t\t\t\t:specRef=\"specRef\"\n\t\t\t\t\trefreshChannel=\"cn:page:refresh\"\n\t\t\t\t\ttestidBase=\"cn-dashboard-page\"\n\t\t\t\t\t@refresh=\"onActionsRefresh\"\n\t\t\t\t\t@requestFeature=\"onActionsRequestFeature\">\n\t\t\t\t\t<!-- @slot action-items Additional NcActionButton-family\n\t\t\t\t\t items appended inside the page-level overflow menu,\n\t\t\t\t\t after Refresh / Documentation / Request a feature. -->\n\t\t\t\t\t<template v-if=\"hasActionItemsSlot\" #action-items>\n\t\t\t\t\t\t<slot name=\"action-items\" />\n\t\t\t\t\t</template>\n\t\t\t\t</CnActionsMenu>\n\t\t\t\t<!-- Board look: the row reads the secondary header actions, Edit\n\t\t\t\t layout, Actions, the buildiq square, then the primary header\n\t\t\t\t actions rightmost (screens-dashboard-parity). -->\n\t\t\t\t<template v-if=\"isBoardLook\">\n\t\t\t\t\t<CnBuildiqEditButton />\n\t\t\t\t\t<CnActionButtons\n\t\t\t\t\t\tv-if=\"boardPrimaryHeaderActions.length\"\n\t\t\t\t\t\t:actions=\"boardPrimaryHeaderActions\"\n\t\t\t\t\t\tdata-testid=\"cn-dashboard-page-header-actions\" />\n\t\t\t\t\t<slot name=\"header-actions\" />\n\t\t\t\t\t<slot name=\"actions\" />\n\t\t\t\t</template>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- The switch row (screens-dashboard-greeting-header): in the board\n\t\t look the page's view switch sits under the header, left, and the\n\t\t page's `viewLinks` sit right of it as small pills (DqMijnWerk). -->\n\t\t<div\n\t\t\tv-if=\"showHeader && (switchInRow || resolvedViewLinks.length > 0)\"\n\t\t\tclass=\"cn-dashboard-page__switch-row\"\n\t\t\tdata-testid=\"cn-dashboard-page-switch-row\">\n\t\t\t<CnSegmentedControl\n\t\t\t\tv-if=\"switchInRow\"\n\t\t\t\tclass=\"cn-page-view-switch\"\n\t\t\t\t:options=\"viewSwitchOptions\"\n\t\t\t\t:modelValue=\"activeViewId\"\n\t\t\t\t:ariaLabel=\"viewSwitchLabel\"\n\t\t\t\t:controls=\"viewRegionId\"\n\t\t\t\tdata-testid=\"cn-dashboard-page-view-switch\"\n\t\t\t\t@update:modelValue=\"selectView\" />\n\t\t\t<span class=\"cn-dashboard-page__switch-row-spacer\" />\n\t\t\t<component\n\t\t\t\t:is=\"link.tag\"\n\t\t\t\tv-for=\"link in resolvedViewLinks\"\n\t\t\t\t:key=\"link.key\"\n\t\t\t\tv-bind=\"link.attrs\"\n\t\t\t\tclass=\"cn-dashboard-page__view-link\"\n\t\t\t\tdata-testid=\"cn-dashboard-page-view-link\">\n\t\t\t\t<CnWidgetIcon\n\t\t\t\t\tv-if=\"link.icon\"\n\t\t\t\t\t:name=\"link.icon\"\n\t\t\t\t\t:size=\"14\"\n\t\t\t\t\tclass=\"cn-dashboard-page__view-link-icon\" />\n\t\t\t\t{{ link.label }}\n\t\t\t</component>\n\t\t</div>\n\n\t\t<!-- Date-range header (optional).\n\t\t Rendered only when `dateRange.enabled === true` AND\n\t\t `dateRange.showHeaderPicker !== false`. The range STATE\n\t\t (currentRange / cnDashboardDateRange) is always initialised\n\t\t when the feature is enabled, so per-chart-widget date chips\n\t\t keep working even when this header picker is hidden — set\n\t\t `showHeaderPicker: false` to rely solely on the per-widget\n\t\t chips. The picker is wired to `currentRange` (data) which\n\t\t mirrors the provided `cnDashboardDateRange` ref; all change\n\t\t handling, persistence, and event emission lives in\n\t\t `onDateRangeChange`. -->\n\t\t<div\n\t\t\tv-if=\"showHeaderDateRange && !datePeriodInDescription\"\n\t\t\tclass=\"cn-dashboard-page__date-range\"\n\t\t\t:class=\"{\n\t\t\t\t'cn-dashboard-page__date-range--pills': dateRangeControl === 'pills',\n\t\t\t\t'cn-dashboard-page__date-range--segmented': dateRangeControl === 'segmented',\n\t\t\t}\"\n\t\t\tdata-testid=\"cn-dashboard-page-date-range\">\n\t\t\t<!-- Segmented mode (`dateRange.control: 'segmented'`): the presets as\n\t\t\t one compact segmented group in a row of its own, driving the\n\t\t\t same range change as a pill. A custom range, when offered, is\n\t\t\t the last segment and opens the from/to popover. -->\n\t\t\t<div\n\t\t\t\tv-if=\"dateRangeControl === 'segmented'\"\n\t\t\t\tclass=\"cn-dashboard-page__date-segmented\"\n\t\t\t\tdata-testid=\"cn-dashboard-page-date-segmented\">\n\t\t\t\t<CnSegmentedControl\n\t\t\t\t\tsize=\"compact\"\n\t\t\t\t\tmode=\"toggle\"\n\t\t\t\t\t:options=\"segmentedOptions\"\n\t\t\t\t\t:modelValue=\"segmentedValue\"\n\t\t\t\t\t:ariaLabel=\"datePeriodLabel\"\n\t\t\t\t\t@update:modelValue=\"onSegmentPick\" />\n\t\t\t\t<NcActions\n\t\t\t\t\tv-if=\"hasCustomPreset && currentRange && currentRange.preset === 'custom'\"\n\t\t\t\t\t:forceMenu=\"true\"\n\t\t\t\t\tcontainer=\"body\"\n\t\t\t\t\tclass=\"cn-dashboard-page__date-pill-custom\"\n\t\t\t\t\tdata-testid=\"cn-dashboard-page-date-segment-custom\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<CalendarRange :size=\"18\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange && currentRange.from)\"\n\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'From')\"\n\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('from', $event)\" />\n\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange && currentRange.to)\"\n\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'To')\"\n\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('to', $event)\" />\n\t\t\t\t</NcActions>\n\t\t\t</div>\n\t\t\t<!-- Pills mode (`dateRange.control: 'pills'`): a compact segmented\n\t\t\t toggle-button row replaces the bulky select + two date inputs.\n\t\t\t Each preset is a pill; the active one drives the dashboard window\n\t\t\t exactly like the picker does (same `onDateRangeChange`). A\n\t\t\t de-emphasised \"Custom range\" pill opens a small from/to popover\n\t\t\t so the arbitrary-window affordance is kept without two bare\n\t\t\t date inputs being always visible. -->\n\t\t\t<div\n\t\t\t\tv-else-if=\"dateRangeControl === 'pills'\"\n\t\t\t\tclass=\"cn-dashboard-page__date-pills\"\n\t\t\t\trole=\"group\"\n\t\t\t\t:aria-label=\"datePillsGroupLabel\"\n\t\t\t\tdata-testid=\"cn-dashboard-page-date-pills\">\n\t\t\t\t<button\n\t\t\t\t\tv-for=\"preset in pillPresets\"\n\t\t\t\t\t:key=\"preset.id\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-dashboard-page__date-pill\"\n\t\t\t\t\t:class=\"{ 'cn-dashboard-page__date-pill--active': currentRange && currentRange.preset === preset.id }\"\n\t\t\t\t\t:aria-pressed=\"String(Boolean(currentRange && currentRange.preset === preset.id))\"\n\t\t\t\t\t:data-testid=\"`cn-dashboard-page-date-pill-${preset.id}`\"\n\t\t\t\t\t@click=\"onPillPick(preset)\">\n\t\t\t\t\t{{ preset.label }}\n\t\t\t\t</button>\n\t\t\t\t<NcActions\n\t\t\t\t\tv-if=\"hasCustomPreset\"\n\t\t\t\t\t:forceMenu=\"true\"\n\t\t\t\t\tcontainer=\"body\"\n\t\t\t\t\tclass=\"cn-dashboard-page__date-pill-custom\"\n\t\t\t\t\tdata-testid=\"cn-dashboard-page-date-pill-custom\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tclass=\"cn-dashboard-page__date-pill cn-dashboard-page__date-pill--custom\"\n\t\t\t\t\t\t\t:class=\"{ 'cn-dashboard-page__date-pill--active': currentRange && currentRange.preset === 'custom' }\">\n\t\t\t\t\t\t\t{{ customRangeLabel }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange && currentRange.from)\"\n\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'From')\"\n\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('from', $event)\" />\n\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange && currentRange.to)\"\n\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'To')\"\n\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('to', $event)\" />\n\t\t\t\t</NcActions>\n\t\t\t</div>\n\t\t\t<!-- Default (picker) mode: the original select + two date inputs. -->\n\t\t\t<CnDateRangePicker\n\t\t\t\tv-else\n\t\t\t\t:value=\"currentRange\"\n\t\t\t\t:presets=\"effectivePresets\"\n\t\t\t\t@input=\"onDateRangeChange\" />\n\t\t</div>\n\n\t\t<!-- Page-level filter controls (optional). Each selection is written\n\t\t into the reactive workspace context so any widget can read it via a\n\t\t `@page.<key>` / `@workspace.<key>` token (e.g. an endpoint KPI's URL\n\t\t interpolating a chosen period). -->\n\t\t<div\n\t\t\tv-if=\"rowPageFilters.length > 0\"\n\t\t\tclass=\"cn-dashboard-page__page-filters\"\n\t\t\tdata-testid=\"cn-dashboard-page-page-filters\">\n\t\t\t<template v-for=\"pf in rowPageFilters\" :key=\"pf.key\">\n\t\t\t\t<CnSegmentedControl\n\t\t\t\t\tv-if=\"pf.control === 'segmented'\"\n\t\t\t\t\tsize=\"compact\"\n\t\t\t\t\tmode=\"toggle\"\n\t\t\t\t\t:options=\"pageFilterSegments(pf)\"\n\t\t\t\t\t:modelValue=\"workspaceContext[pf.key]\"\n\t\t\t\t\t:ariaLabel=\"pf.label ? effectiveTranslate(pf.label) : pf.key\"\n\t\t\t\t\t:data-testid=\"'cn-page-filter-' + pf.key\"\n\t\t\t\t\t@update:modelValue=\"onPageFilterChange(pf, $event)\" />\n\t\t\t\t<label\n\t\t\t\t\tv-else\n\t\t\t\t\tclass=\"cn-dashboard-page__page-filter\">\n\t\t\t\t\t<span v-if=\"pf.label\" class=\"cn-dashboard-page__page-filter-label\">{{ effectiveTranslate(pf.label) }}</span>\n\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t:modelValue=\"selectedPageFilterOption(pf)\"\n\t\t\t\t\t\t:options=\"pageFilterSegments(pf)\"\n\t\t\t\t\t\t:clearable=\"pf.clearable === true\"\n\t\t\t\t\t\t:placeholder=\"pf.placeholder ? effectiveTranslate(pf.placeholder) : undefined\"\n\t\t\t\t\t\t:loading=\"pageFilterLoading[pf.key] === true\"\n\t\t\t\t\t\t:inputLabel=\"pf.label ? effectiveTranslate(pf.label) : pf.key\"\n\t\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t\t:data-testid=\"'cn-page-filter-' + pf.key\"\n\t\t\t\t\t\t@update:modelValue=\"onPageFilterChange(pf, $event)\" />\n\t\t\t\t</label>\n\t\t\t</template>\n\t\t</div>\n\n\t\t<!-- Declarative in-body sections, `placement: \"before-grid\"` — host-app\n\t\t section components (e.g. a bespoke funnel / time-series chart reading\n\t\t a custom REST endpoint) rendered ABOVE the widget grid. Independent of\n\t\t the grid's loading / empty state so an analytics dashboard can be all\n\t\t sections and no grid widgets. -->\n\t\t<CnBodySections\n\t\t\tv-if=\"hasBodyWidgets\"\n\t\t\t:sections=\"bodyWidgets\"\n\t\t\t:context=\"sectionContext\"\n\t\t\tplacement=\"before-grid\"\n\t\t\tdata-testid=\"cn-dashboard-body-sections-before-grid\" />\n\n\t\t<!-- Loading state -->\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- Widget predicates still settling: hold the grid's first paint\n\t\t so a conditional widget is present or absent from the first\n\t\t frame instead of popping in after load and reflowing the page.\n\t\t Edit mode skips the gate — it renders the authored layout with\n\t\t every widget regardless of conditions. -->\n\t\t<NcLoadingIcon v-else-if=\"!widgetConditionsSettled && !gridEditable\" />\n\n\t\t<!-- Empty state. Suppressed when the page renders declarative body\n\t\t sections (before-grid / after-grid / end): a page can legitimately\n\t\t have no grid widgets yet still show bodyWidget content, so\n\t\t \"No widgets configured\" would be a false negative. -->\n\t\t<div v-else-if=\"!hasWidgets && !hasBodyWidgets && !hasViews\" class=\"cn-dashboard-page__empty\">\n\t\t\t<!-- @slot empty Replaces the default empty state shown when the dashboard has no widgets. Defaults to an `NcEmptyContent` block. -->\n\t\t\t<slot name=\"empty\">\n\t\t\t\t<CnEmptyContent :description=\"emptyLabel\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<ViewDashboardOutline :size=\"48\" />\n\t\t\t\t\t</template>\n\t\t\t\t</CnEmptyContent>\n\t\t\t</slot>\n\t\t</div>\n\n\t\t<!-- Widget-ref content items (manifest-widget-ref-page-content-type).\n\t\t Rendered above the classic GridStack grid when present. Each item\n\t\t is a `{ type: 'widget-ref', ref: 'openregister://widget/…' }` entry\n\t\t from the manifest's `pages[].config.content[]` array. -->\n\t\t<div\n\t\t\tv-else-if=\"widgetRefItems.length > 0\"\n\t\t\tclass=\"cn-dashboard-page__content\">\n\t\t\t<CnWidgetRefItem\n\t\t\t\tv-for=\"(item, idx) in widgetRefItems\"\n\t\t\t\t:key=\"item.ref + '-' + idx\"\n\t\t\t\t:refUri=\"item.ref\"\n\t\t\t\tclass=\"cn-dashboard-page__content-item\" />\n\t\t</div>\n\n\t\t<!-- Dashboard grid (classic widgets+layout mode).\n\t\t Uses v-else so the `v-else-if=\"!hasWidgets\"` empty state and the\n\t\t `v-else-if=\"widgetRefItems.length > 0\"` content-items section\n\t\t are mutually exclusive with the grid.\n\t\t :key remounts the grid when in-app edit mode flips (ADR-041): the\n\t\t manifest is raw (non-reactive) until useManifestEditor.enter()\n\t\t observes it in place, so a grid mounted pre-edit never subscribed\n\t\t to the layout/widgets arrays — in-place pushes (Add widget) keep\n\t\t the same array identity and can't re-render it. One remount per\n\t\t edit flip re-subscribes against the now-reactive graph. -->\n\t\t<!-- KPI row (`config.kpiRow`): the named widgets sit above the grid in\n\t\t an auto-fit CnKpiGrid (each tile at least 200px wide) and are not\n\t\t GridStack items, so they neither reflow with the grid nor appear\n\t\t in the emitted layout. -->\n\t\t<CnKpiGrid\n\t\t\tv-if=\"gridSectionsShown && kpiRowItems.length > 0\"\n\t\t\tcolumns=\"auto\"\n\t\t\tclass=\"cn-dashboard-page__kpi-row\"\n\t\t\tdata-testid=\"cn-dashboard-page-kpi-row\">\n\t\t\t<div\n\t\t\t\tv-for=\"item in kpiRowItems\"\n\t\t\t\t:key=\"`kpi-${item.widgetId}`\"\n\t\t\t\tclass=\"cn-dashboard-page__kpi-cell\"\n\t\t\t\t:data-testid=\"`cn-dashboard-page-kpi-${item.widgetId}`\">\n\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\tv-if=\"isStatsBlock(item)\"\n\t\t\t\t\tv-bind=\"kpiWrapperProps(item)\"\n\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t<CnStatsBlockWidget\n\t\t\t\t\t\tv-bind=\"getStatsBlockProps(item)\"\n\t\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t\t:data-source=\"getWidgetDataSource(item)\" />\n\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\tv-else-if=\"registryRenderer(item)\"\n\t\t\t\t\tv-bind=\"kpiWrapperProps(item)\"\n\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t<template v-if=\"widgetHeaderNote(item) || widgetHeaderAction(item)\" #actions>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"widgetHeaderNote(item)\"\n\t\t\t\t\t\t\tclass=\"cn-dashboard-page__widget-note\"\n\t\t\t\t\t\t\tdata-testid=\"cn-dashboard-widget-header-note\">{{ widgetHeaderNote(item) }}</span>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\tv-if=\"widgetHeaderAction(item)\"\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"cn-dashboard-page__widget-action\"\n\t\t\t\t\t\t\tdata-testid=\"cn-dashboard-widget-header-action\"\n\t\t\t\t\t\t\t@click=\"widgetHeaderAction(item).run()\">\n\t\t\t\t\t\t\t{{ widgetHeaderAction(item).label }}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</template>\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"registryRenderer(item)\"\n\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t:content=\"registryWidgetBindings(item)\"\n\t\t\t\t\t\tv-bind=\"{ ...registryWidgetProps(item), ...containerBindings(item) }\"\n\t\t\t\t\t\t@header=\"onWidgetHeader(item, $event)\" />\n\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\tv-else-if=\"hasWidgetSlot(item.widgetId)\"\n\t\t\t\t\tv-bind=\"kpiWrapperProps(item)\"\n\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t<slot :name=\"'widget-' + item.widgetId\" :item=\"item\" :widget=\"getWidgetDef(item.widgetId)\" />\n\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\tv-else\n\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t:showTitle=\"false\"\n\t\t\t\t\t:showRefresh=\"false\">\n\t\t\t\t\t<div class=\"cn-dashboard-page__unknown\">\n\t\t\t\t\t\t{{ unavailableLabel }}\n\t\t\t\t\t</div>\n\t\t\t\t</CnWidgetWrapper>\n\t\t\t</div>\n\t\t</CnKpiGrid>\n\n\t\t<!-- The view switch for a page without a header row, when no greeting\n\t\t header widget draws it. -->\n\t\t<div\n\t\t\tv-if=\"gridSectionsShown && !showHeader && showsPageViewSwitch\"\n\t\t\tclass=\"cn-dashboard-page__view-switch\">\n\t\t\t<CnSegmentedControl\n\t\t\t\tclass=\"cn-page-view-switch\"\n\t\t\t\t:options=\"viewSwitchOptions\"\n\t\t\t\t:modelValue=\"activeViewId\"\n\t\t\t\t:ariaLabel=\"viewSwitchLabel\"\n\t\t\t\t:controls=\"viewRegionId\"\n\t\t\t\tdata-testid=\"cn-dashboard-page-view-switch\"\n\t\t\t\t@update:modelValue=\"selectView\" />\n\t\t</div>\n\t\t<!-- One grid per section: the page's own layout, then the chosen\n\t\t view (`views`) in a region the view switch controls. Both are the\n\t\t same grid with the same widget rendering below. A view grid is\n\t\t keyed on its view, so switching mounts the other view's grid. -->\n\t\t<CnDashboardGrid\n\t\t\tv-for=\"section in gridSections\"\n\t\t\t:key=\"`cn-dashboard-grid-${section.key}-${gridEditable ? 'editing' : 'live'}`\"\n\t\t\tv-bind=\"section.attrs\"\n\t\t\t:layout=\"section.layout\"\n\t\t\t:editable=\"section.editable\"\n\t\t\t:columns=\"columns\"\n\t\t\t:columnOpts=\"gridColumnOpts\"\n\t\t\t:cellHeight=\"cellHeight\"\n\t\t\t:margin=\"gridMargin\"\n\t\t\t:float=\"gridFloat\"\n\t\t\t:sideColumn=\"section.sideColumn\"\n\t\t\t@layoutChange=\"section.view ? onViewLayoutChange($event) : onLayoutChange($event)\">\n\t\t\t<template #widget=\"{ item }\">\n\t\t\t\t<!-- In-app edit overlay (ADR-041): a single launchpad-style\n\t\t\t\t configure cog opens the per-widget style/config editor,\n\t\t\t\t which itself carries the delete affordance — so no separate\n\t\t\t\t remove button here. Shown only while the page is in edit\n\t\t\t\t mode. -->\n\t\t\t\t<div v-if=\"gridEditable\" class=\"cn-dashboard-page__widget-edit\">\n\t\t\t\t\t<NcButton variant=\"tertiary\" :aria-label=\"t('nextcloud-vue', 'Configure widget')\" @click=\"configureWidget(item)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<Cog :size=\"18\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\t\t\t\t<!-- requiresApp gate — when a widget declares `requiresApp`\n\t\t\t\t (any widget type) and the owning app is not installed,\n\t\t\t\t replace its body with an \"Install …\" CTA. Because all\n\t\t\t\t fleet data lives in OpenRegister, an app can surface\n\t\t\t\t another app's data; this keeps the tile honest when the\n\t\t\t\t owning app is absent instead of showing an empty value. -->\n\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\tv-if=\"missingRequiredApp(item)\"\n\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t:showTitle=\"widgetShowTitle(item)\">\n\t\t\t\t\t<!-- Compact on purpose: a two-row tile is about 150px, less\n\t\t\t\t\t a title row. NcEmptyContent's 64px icon, 20px name,\n\t\t\t\t\t description and button did not fit, so the icon ran out\n\t\t\t\t\t at the top and the button at the bottom. The button\n\t\t\t\t\t already says \"Install {app}\", so there is no separate\n\t\t\t\t\t name, and the text keeps to two lines. -->\n\t\t\t\t\t<div class=\"cn-dashboard-page__requires-app cn-requires-app cn-requires-app--compact\"\n\t\t\t\t\t\tdata-testid=\"cn-requires-app\">\n\t\t\t\t\t\t<p class=\"cn-requires-app__description\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'This widget shows data from another app that isn\\'t installed yet.') }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t\t\t:href=\"appInstallUrl(missingRequiredApp(item))\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Download :size=\"18\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ installAppLabel(missingRequiredApp(item)) }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\t\t\t\t</CnWidgetWrapper>\n\n\t\t\t\t<!-- Tile widget -->\n\t\t\t\t<CnTileWidget\n\t\t\t\t\tv-else-if=\"isTile(item)\"\n\t\t\t\t\t:tile=\"getTileConfig(item)\" />\n\n\t\t\t\t<!-- Custom slot widget — apps provide their own rendering -->\n\t\t\t\t<!-- Every page-side wrapper carries `widget-id`: the chrome's\n\t\t\t\t Refresh broadcasts `cn:widget:refresh` with that id in the\n\t\t\t\t payload, and without it the payload's empty widgetId\n\t\t\t\t matches no subscriber — the per-widget Refresh silently\n\t\t\t\t does nothing. -->\n\t\t\t\t<template v-else-if=\"hasWidgetSlot(item.widgetId)\">\n\t\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t\t:iconUrl=\"getWidgetIconUrl(item)\"\n\t\t\t\t\t\t:iconClass=\"getWidgetIconClass(item)\"\n\t\t\t\t\t\t:showTitle=\"widgetShowTitle(item)\"\n\t\t\t\t\t\t:borderless=\"widgetBorderless(item)\"\n\t\t\t\t\t\t:flush=\"item.flush !== false\"\n\t\t\t\t\t\t:buttons=\"getWidgetButtons(item)\"\n\t\t\t\t\t\t:headerLink=\"getWidgetHeaderLink(item)\"\n\t\t\t\t\t\t:headerActions=\"getWidgetHeaderActions(item)\"\n\t\t\t\t\t\t:styleConfig=\"item.styleConfig || {}\"\n\t\t\t\t\t\t:titleIconPosition=\"getWidgetTitleIconPosition(item)\"\n\t\t\t\t\t\t:titleIconColor=\"getWidgetTitleIconColor(item)\"\n\t\t\t\t\t\t:titleIconVariant=\"getWidgetTitleIconVariant(item)\"\n\t\t\t\t\t\t:showRefresh=\"getWidgetShowRefresh(item)\"\n\t\t\t\t\t\t:showActions=\"widgetShowActions(item)\"\n\t\t\t\t\t\t:documentationUrl=\"getWidgetDocumentationUrl(item)\"\n\t\t\t\t\t\t:docsAnchor=\"getWidgetDocsAnchor(item)\"\n\t\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t\t<!-- @slot widget-{widgetId}-title-icon Per-widget custom title icon (e.g. `#widget-my-work-title-icon`). Scope: `{ item, widget }`. -->\n\t\t\t\t\t\t<template v-if=\"$slots['widget-' + item.widgetId + '-title-icon']\" #title-icon>\n\t\t\t\t\t\t\t<slot :name=\"'widget-' + item.widgetId + '-title-icon'\" :item=\"item\" :widget=\"getWidgetDef(item.widgetId)\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<!-- @slot widget-{widgetId}-actions Per-widget custom header actions (e.g. `#widget-my-work-actions`). Scope: `{ item, widget }`. -->\n\t\t\t\t\t\t<template v-if=\"$slots['widget-' + item.widgetId + '-actions']\" #actions>\n\t\t\t\t\t\t\t<slot :name=\"'widget-' + item.widgetId + '-actions'\" :item=\"item\" :widget=\"getWidgetDef(item.widgetId)\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<!-- Opt-in per-widget date chip (`layout[].dateChip: true`).\n\t\t\t\t\t\t Mirrors the chart-widget chip below — same popover,\n\t\t\t\t\t\t same handlers, same SHARED dashboard range — so\n\t\t\t\t\t\t custom widgets that consume `cnDashboardDateRange`\n\t\t\t\t\t\t can surface the range in their own header instead\n\t\t\t\t\t\t of (or alongside) the page-level picker. Keep the\n\t\t\t\t\t\t two blocks in sync when editing either. -->\n\t\t\t\t\t\t<template v-if=\"dateRangeEnabled && item.dateChip === true\" #title-meta>\n\t\t\t\t\t\t\t<NcActions\n\t\t\t\t\t\t\t\tv-model:open=\"openChipPicker[item.widgetId]\"\n\t\t\t\t\t\t\t\t:forceMenu=\"true\"\n\t\t\t\t\t\t\t\tcontainer=\"body\"\n\t\t\t\t\t\t\t\t:data-testid=\"`cn-dashboard-page-date-chip-${item.widgetId}`\"\n\t\t\t\t\t\t\t\tclass=\"cn-dashboard-page__date-chip-trigger\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<span class=\"cn-dashboard-page__date-chip\" :title=\"dateChipTitle\">\n\t\t\t\t\t\t\t\t\t\t{{ dashboardRangeChipLabel }}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\t\tv-for=\"preset in effectivePresets\"\n\t\t\t\t\t\t\t\t\t:key=\"preset.id\"\n\t\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t\t@click=\"onChipPresetPick(preset, item)\">\n\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t<CalendarRange v-if=\"currentRange.preset === preset.id\" :size=\"16\" />\n\t\t\t\t\t\t\t\t\t\t<span v-else class=\"cn-dashboard-page__date-chip-preset-spacer\" />\n\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t\t{{ preset.label }}\n\t\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t\t<NcActionSeparator />\n\t\t\t\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange.from)\"\n\t\t\t\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'From')\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('from', $event)\" />\n\t\t\t\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange.to)\"\n\t\t\t\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'To')\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('to', $event)\" />\n\t\t\t\t\t\t\t</NcActions>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<!-- @slot widget-{widgetId} Per-widget body content (e.g. `#widget-my-work`). Apps inject custom widget rendering here. Scope: `{ item, widget }`. -->\n\t\t\t\t\t\t<slot :name=\"'widget-' + item.widgetId\" :item=\"item\" :widget=\"getWidgetDef(item.widgetId)\" />\n\t\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t</template>\n\n\t\t\t\t<!-- Chart widget — manifest-driven apexcharts mount -->\n\t\t\t\t<template v-else-if=\"isChart(item)\">\n\t\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t:class=\"{ 'cn-dashboard-page__chart-fit': isChartFitted(item) }\"\n\t\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t\t:iconUrl=\"getWidgetIconUrl(item)\"\n\t\t\t\t\t\t:iconClass=\"getWidgetIconClass(item)\"\n\t\t\t\t\t\t:showTitle=\"widgetShowTitle(item)\"\n\t\t\t\t\t\t:showActions=\"widgetShowActions(item)\"\n\t\t\t\t\t\t:borderless=\"widgetBorderless(item)\"\n\t\t\t\t\t\t:flush=\"item.flush !== false\"\n\t\t\t\t\t\t:buttons=\"getWidgetButtons(item)\"\n\t\t\t\t\t\t:headerLink=\"getWidgetHeaderLink(item)\"\n\t\t\t\t\t\t:headerActions=\"getWidgetHeaderActions(item)\"\n\t\t\t\t\t\t:styleConfig=\"item.styleConfig || {}\"\n\t\t\t\t\t\t:titleIconPosition=\"getWidgetTitleIconPosition(item)\"\n\t\t\t\t\t\t:titleIconColor=\"getWidgetTitleIconColor(item)\"\n\t\t\t\t\t\t:titleIconVariant=\"getWidgetTitleIconVariant(item)\"\n\t\t\t\t\t\t:showRefresh=\"getWidgetShowRefresh(item)\"\n\t\t\t\t\t\t:documentationUrl=\"getWidgetDocumentationUrl(item)\"\n\t\t\t\t\t\t:docsAnchor=\"getWidgetDocsAnchor(item)\"\n\t\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t\t<template v-if=\"dateRangeEnabled && (item.dateChip === true || formatChartDateRange(item))\" #title-meta>\n\t\t\t\t\t\t\t<NcActions\n\t\t\t\t\t\t\t\tv-model:open=\"openChipPicker[item.widgetId]\"\n\t\t\t\t\t\t\t\t:forceMenu=\"true\"\n\t\t\t\t\t\t\t\tcontainer=\"body\"\n\t\t\t\t\t\t\t\t:data-testid=\"`cn-dashboard-page-date-chip-${item.widgetId}`\"\n\t\t\t\t\t\t\t\tclass=\"cn-dashboard-page__date-chip-trigger\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<span class=\"cn-dashboard-page__date-chip\" :title=\"dateChipTitle\">\n\t\t\t\t\t\t\t\t\t\t{{ formatChartDateRange(item) || dashboardRangeChipLabel }}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\t\tv-for=\"preset in effectivePresets\"\n\t\t\t\t\t\t\t\t\t:key=\"preset.id\"\n\t\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t\t@click=\"onChipPresetPick(preset, item)\">\n\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t<CalendarRange v-if=\"currentRange.preset === preset.id\" :size=\"16\" />\n\t\t\t\t\t\t\t\t\t\t<span v-else class=\"cn-dashboard-page__date-chip-preset-spacer\" />\n\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t\t{{ preset.label }}\n\t\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t\t<NcActionSeparator />\n\t\t\t\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange.from)\"\n\t\t\t\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'From')\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('from', $event)\" />\n\t\t\t\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange.to)\"\n\t\t\t\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'To')\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('to', $event)\" />\n\t\t\t\t\t\t\t</NcActions>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<CnChartWidget\n\t\t\t\t\t\t\tv-bind=\"getChartProps(item)\"\n\t\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t\t:data-source=\"getWidgetDataSource(item)\" />\n\t\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t</template>\n\n\t\t\t\t<!-- Stats-block widget — manifest-driven CnStatsBlock with a\n\t\t\t\t GraphQL-resolved count via `dataSource`.\n\n\t\t\t\t This used to render WITHOUT CnWidgetWrapper, because\n\t\t\t\t CnStatsBlock drew its own grey bordered card and wrapping\n\t\t\t\t it produced a double card (outer + inner titles, two\n\t\t\t\t boxes). The KPI card is flat as of 2026-08-30, so the\n\t\t\t\t opposite is now true: without the wrapper the tile has no\n\t\t\t\t chrome at all. It is wrapped like every other widget, and\n\t\t\t\t the duplicate title is gone because `stats-block` is\n\t\t\t\t registered as a card widget — card widgets default to\n\t\t\t\t headerless, so only CnStatsBlock's own title renders. -->\n\t\t\t\t<template v-else-if=\"isStatsBlock(item)\">\n\t\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t\t:iconUrl=\"getWidgetIconUrl(item)\"\n\t\t\t\t\t\t:iconClass=\"getWidgetIconClass(item)\"\n\t\t\t\t\t\t:showTitle=\"widgetShowTitle(item)\"\n\t\t\t\t\t\t:showActions=\"widgetShowActions(item)\"\n\t\t\t\t\t\t:borderless=\"widgetBorderless(item)\"\n\t\t\t\t\t\t:flush=\"item.flush !== false\"\n\t\t\t\t\t\t:class=\"{ 'cn-dashboard-page__card-fit': isCardWidget(item) }\"\n\t\t\t\t\t\t:buttons=\"getWidgetButtons(item)\"\n\t\t\t\t\t\t:headerLink=\"getWidgetHeaderLink(item)\"\n\t\t\t\t\t\t:headerActions=\"getWidgetHeaderActions(item)\"\n\t\t\t\t\t\t:styleConfig=\"item.styleConfig || {}\"\n\t\t\t\t\t\t:documentationUrl=\"getWidgetDocumentationUrl(item)\"\n\t\t\t\t\t\t:docsAnchor=\"getWidgetDocsAnchor(item)\"\n\t\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t\t<CnStatsBlockWidget\n\t\t\t\t\t\t\tv-bind=\"getStatsBlockProps(item)\"\n\t\t\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t\t\t:data-source=\"getWidgetDataSource(item)\" />\n\t\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t</template>\n\n\t\t\t\t<!-- Integration widget — resolved from the pluggable\n\t\t\t\t integration registry (AD-19 surface fallback). -->\n\t\t\t\t<template v-else-if=\"isIntegration(item)\">\n\t\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t\t:iconUrl=\"getWidgetIconUrl(item)\"\n\t\t\t\t\t\t:iconClass=\"getWidgetIconClass(item)\"\n\t\t\t\t\t\t:showTitle=\"widgetShowTitle(item)\"\n\t\t\t\t\t\t:showActions=\"widgetShowActions(item)\"\n\t\t\t\t\t\t:borderless=\"widgetBorderless(item)\"\n\t\t\t\t\t\t:flush=\"item.flush !== false\"\n\t\t\t\t\t\t:buttons=\"getWidgetButtons(item)\"\n\t\t\t\t\t\t:headerLink=\"getWidgetHeaderLink(item)\"\n\t\t\t\t\t\t:headerActions=\"getWidgetHeaderActions(item)\"\n\t\t\t\t\t\t:styleConfig=\"item.styleConfig || {}\"\n\t\t\t\t\t\t:titleIconPosition=\"getWidgetTitleIconPosition(item)\"\n\t\t\t\t\t\t:titleIconColor=\"getWidgetTitleIconColor(item)\"\n\t\t\t\t\t\t:titleIconVariant=\"getWidgetTitleIconVariant(item)\"\n\t\t\t\t\t\t:showRefresh=\"getWidgetShowRefresh(item)\"\n\t\t\t\t\t\t:documentationUrl=\"getWidgetDocumentationUrl(item)\"\n\t\t\t\t\t\t:docsAnchor=\"getWidgetDocsAnchor(item)\"\n\t\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t\t<!-- Mount-mode integration leaf (openregister#2127):\n\t\t\t\t\t\t rendered through CnLeafMountHost so a cross-Vue-major\n\t\t\t\t\t\t leaf mounts its own framework into a bare element. -->\n\t\t\t\t\t\t<CnLeafMountHost\n\t\t\t\t\t\t\tv-if=\"isMountIntegration(item)\"\n\t\t\t\t\t\t\t:provider=\"integrationProviderFor(item)\"\n\t\t\t\t\t\t\t:mountProps=\"getIntegrationMountProps(item)\" />\n\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t:is=\"resolveIntegrationWidget(item)\"\n\t\t\t\t\t\t\tv-else-if=\"resolveIntegrationWidget(item)\"\n\t\t\t\t\t\t\tv-bind=\"getIntegrationProps(item)\" />\n\t\t\t\t\t\t<div v-else class=\"cn-dashboard-page__unknown\">\n\t\t\t\t\t\t\t{{ unavailableLabel }}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t</template>\n\n\t\t\t\t<!-- NC Dashboard API widget -->\n\t\t\t\t<template v-else-if=\"isNcWidget(item)\">\n\t\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t\t:iconUrl=\"getWidgetIconUrl(item)\"\n\t\t\t\t\t\t:iconClass=\"getWidgetIconClass(item)\"\n\t\t\t\t\t\t:showTitle=\"widgetShowTitle(item)\"\n\t\t\t\t\t\t:showActions=\"widgetShowActions(item)\"\n\t\t\t\t\t\t:buttons=\"getWidgetButtons(item)\"\n\t\t\t\t\t\t:headerLink=\"getWidgetHeaderLink(item)\"\n\t\t\t\t\t\t:headerActions=\"getWidgetHeaderActions(item)\"\n\t\t\t\t\t\t:styleConfig=\"item.styleConfig || {}\"\n\t\t\t\t\t\t:showRefresh=\"getWidgetShowRefresh(item)\"\n\t\t\t\t\t\t:documentationUrl=\"getWidgetDocumentationUrl(item)\"\n\t\t\t\t\t\t:docsAnchor=\"getWidgetDocsAnchor(item)\"\n\t\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t\t<CnWidgetRenderer\n\t\t\t\t\t\t\t:widget=\"getWidgetDef(item.widgetId)\"\n\t\t\t\t\t\t\t:unavailableText=\"unavailableLabel\" />\n\t\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t</template>\n\n\t\t\t\t<!-- Dashboard widget library (cn-widget-library): a widget whose\n\t\t\t\t `type` is registered in dashboardWidgetRegistry renders here —\n\t\t\t\t this is how catalog widgets added via \"Add widget…\" appear. -->\n\t\t\t\t<template v-else-if=\"registryRenderer(item)\">\n\t\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t\t:showTitle=\"widgetShowTitle(item)\"\n\t\t\t\t\t\t:showActions=\"widgetShowActions(item)\"\n\t\t\t\t\t\t:showRefresh=\"getWidgetShowRefresh(item)\"\n\t\t\t\t\t\t:borderless=\"widgetBorderless(item)\"\n\t\t\t\t\t\t:flush=\"item.flush !== false\"\n\t\t\t\t\t\t:titleIconPosition=\"getWidgetTitleIconPosition(item)\"\n\t\t\t\t\t\t:titleIconColor=\"getWidgetTitleIconColor(item)\"\n\t\t\t\t\t\t:titleIconVariant=\"getWidgetTitleIconVariant(item)\"\n\t\t\t\t\t\t:class=\"{ 'cn-dashboard-page__card-fit': isCardWidget(item) }\"\n\t\t\t\t\t\t:buttons=\"getWidgetButtons(item)\"\n\t\t\t\t\t\t:headerLink=\"getWidgetHeaderLink(item)\"\n\t\t\t\t\t\t:headerActions=\"getWidgetHeaderActions(item)\"\n\t\t\t\t\t\t:styleConfig=\"item.styleConfig || {}\"\n\t\t\t\t\t\t:documentationUrl=\"getWidgetDocumentationUrl(item)\"\n\t\t\t\t\t\t:docsAnchor=\"getWidgetDocsAnchor(item)\"\n\t\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t\t<!-- Opt-in per-widget date chip (`layout[].dateChip: true`) for\n\t\t\t\t\t\t registered card widgets (stat / gauge / delta). Same popover\n\t\t\t\t\t\t and SHARED dashboard range as the custom-widget chip above; it\n\t\t\t\t\t\t lets an abstract KPI tile carry its own period selector. Requires\n\t\t\t\t\t\t the widget header (`showTitle !== false`). Keep in sync with the\n\t\t\t\t\t\t custom-slot chip block. -->\n\t\t\t\t\t\t<template v-if=\"(dateRangeEnabled && item.dateChip === true) || widgetHeaderCount(item) !== null\" #title-meta>\n\t\t\t\t\t\t\t<!-- The total a registry widget reported (`headerCount`), a chip after the title. -->\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-if=\"widgetHeaderCount(item) !== null\"\n\t\t\t\t\t\t\t\tclass=\"cn-dashboard-page__widget-count\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-dashboard-widget-header-count\">{{ widgetHeaderCount(item) }}</span>\n\t\t\t\t\t\t\t<NcActions\n\t\t\t\t\t\t\t\tv-if=\"dateRangeEnabled && item.dateChip === true\"\n\t\t\t\t\t\t\t\tv-model:open=\"openChipPicker[item.widgetId]\"\n\t\t\t\t\t\t\t\t:forceMenu=\"true\"\n\t\t\t\t\t\t\t\tcontainer=\"body\"\n\t\t\t\t\t\t\t\t:data-testid=\"`cn-dashboard-page-date-chip-${item.widgetId}`\"\n\t\t\t\t\t\t\t\tclass=\"cn-dashboard-page__date-chip-trigger\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<span class=\"cn-dashboard-page__date-chip\" :title=\"dateChipTitle\">\n\t\t\t\t\t\t\t\t\t\t{{ dashboardRangeChipLabel }}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\t\tv-for=\"preset in effectivePresets\"\n\t\t\t\t\t\t\t\t\t:key=\"preset.id\"\n\t\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t\t@click=\"onChipPresetPick(preset, item)\">\n\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t<CalendarRange v-if=\"currentRange && currentRange.preset === preset.id\" :size=\"16\" />\n\t\t\t\t\t\t\t\t\t\t<span v-else class=\"cn-dashboard-page__date-chip-preset-spacer\" />\n\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t\t{{ preset.label }}\n\t\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t\t<NcActionSeparator />\n\t\t\t\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange && currentRange.from)\"\n\t\t\t\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'From')\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('from', $event)\" />\n\t\t\t\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange && currentRange.to)\"\n\t\t\t\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'To')\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('to', $event)\" />\n\t\t\t\t\t\t\t</NcActions>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<!-- `widget-id` reaches the renderer's own refresh\n\t\t\t\t\t\t subscription (useEndpointSource matches it against\n\t\t\t\t\t\t `cn:widget:refresh` payloads) — the chrome above\n\t\t\t\t\t\t broadcasts with the same id. -->\n\t\t\t\t\t\t<!-- A renderer that reports its own header (`header` event:\n\t\t\t\t\t\t `{ link, note, action }`, e.g. record-list's \"3 in total\"),\n\t\t\t\t\t\t as on a detail page. -->\n\t\t\t\t\t\t<template v-if=\"widgetHeaderNote(item) || widgetHeaderAction(item)\" #actions>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-if=\"widgetHeaderNote(item)\"\n\t\t\t\t\t\t\t\tclass=\"cn-dashboard-page__widget-note\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-dashboard-widget-header-note\">{{ widgetHeaderNote(item) }}</span>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tv-if=\"widgetHeaderAction(item)\"\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"cn-dashboard-page__widget-action\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-dashboard-widget-header-action\"\n\t\t\t\t\t\t\t\t@click=\"widgetHeaderAction(item).run()\">\n\t\t\t\t\t\t\t\t{{ widgetHeaderAction(item).label }}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t:is=\"registryRenderer(item)\"\n\t\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t\t:content=\"registryWidgetBindings(item)\"\n\t\t\t\t\t\t\tv-bind=\"{ ...registryWidgetProps(item), ...containerBindings(item), ...cellChromeBindings(item) }\"\n\t\t\t\t\t\t\t@header=\"onWidgetHeader(item, $event)\" />\n\t\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t</template>\n\n\t\t\t\t<!-- Unknown widget fallback -->\n\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\tv-else\n\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t:showTitle=\"widgetShowTitle(item)\"\n\t\t\t\t\t:showRefresh=\"false\">\n\t\t\t\t\t<div class=\"cn-dashboard-page__unknown\">\n\t\t\t\t\t\t{{ unavailableLabel }}\n\t\t\t\t\t</div>\n\t\t\t\t</CnWidgetWrapper>\n\t\t\t</template>\n\t\t</CnDashboardGrid>\n\n\t\t<!-- The chosen view has nothing to draw: say so in the region, never\n\t\t leave a blank area under the switch. -->\n\t\t<div\n\t\t\tv-if=\"gridSectionsShown && viewIsEmpty\"\n\t\t\t:id=\"viewRegionId\"\n\t\t\trole=\"region\"\n\t\t\t:aria-label=\"activeView ? activeView.label : null\"\n\t\t\tclass=\"cn-page-view-region cn-page-view-region--empty\"\n\t\t\tdata-testid=\"cn-dashboard-page-view-empty\">\n\t\t\t<CnEmptyContent :description=\"viewEmptyText\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<ViewDashboardOutline :size=\"48\" />\n\t\t\t\t</template>\n\t\t\t</CnEmptyContent>\n\t\t</div>\n\n\t\t<!-- Declarative in-body sections, `placement: \"after-grid\"` — host-app\n\t\t section components rendered BELOW the widget grid. -->\n\t\t<CnBodySections\n\t\t\tv-if=\"hasBodyWidgets\"\n\t\t\t:sections=\"bodyWidgets\"\n\t\t\t:context=\"sectionContext\"\n\t\t\tplacement=\"after-grid\"\n\t\t\tdata-testid=\"cn-dashboard-body-sections-after-grid\" />\n\n\t\t<!-- Declarative in-body sections, `placement: \"end\"` (the default\n\t\t placement) — the last body content. Sections with no `placement`\n\t\t (or an explicit `end`) land here; `before-grid` / `after-grid` are\n\t\t filtered out so each section renders exactly once. -->\n\t\t<CnBodySections\n\t\t\tv-if=\"hasBodyWidgets\"\n\t\t\t:sections=\"endPlacementSections\"\n\t\t\t:context=\"sectionContext\"\n\t\t\t:placement=\"null\"\n\t\t\tdata-testid=\"cn-dashboard-body-sections-end\" />\n\n\t\t<!-- Per-widget style/config editor (ADR-041). Opened by the\n\t\t per-widget configure cog while editing; the modal's own Delete\n\t\t button removes the widget. -->\n\t\t<CnWidgetStyleEditorModal\n\t\t\tv-if=\"showWidgetConfig\"\n\t\t\t:show=\"showWidgetConfig\"\n\t\t\t:widget=\"configWidget\"\n\t\t\t:deletable=\"true\"\n\t\t\t@save=\"onWidgetConfigSave\"\n\t\t\t@delete=\"onWidgetConfigDelete\"\n\t\t\t@close=\"showWidgetConfig = false\" />\n\t</div>\n</template>\n\n<script>\nimport { getCurrentUser } from '@nextcloud/auth'\nimport { getCanonicalLocale, translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionInput, NcActions, NcActionSeparator, NcButton, NcLoadingIcon, NcSelect } from '@nextcloud/vue'\nimport { inject, provide, ref, watch } from 'vue'\nimport CalendarRange from 'vue-material-design-icons/CalendarRange.vue'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport Cog from 'vue-material-design-icons/Cog.vue'\nimport Download from 'vue-material-design-icons/Download.vue'\nimport Pencil from 'vue-material-design-icons/Pencil.vue'\nimport Restore from 'vue-material-design-icons/Restore.vue'\nimport ViewDashboardOutline from 'vue-material-design-icons/ViewDashboardOutline.vue'\nimport CnWidgetStyleEditorModal from '../../dialogs/CnWidgetStyleEditorModal.vue'\nimport CnBodySections from '../CnBodySections/CnBodySections.vue'\nimport CnBuildiqEditButton from '../CnBuildiqEditButton/CnBuildiqEditButton.vue'\nimport CnChartWidget from '../CnChartWidget/CnChartWidget.vue'\nimport CnDashboardGrid from '../CnDashboardGrid/CnDashboardGrid.vue'\nimport CnDateRangePicker, { DEFAULT_DATE_RANGE_PRESETS, resolvePresetWindow, translatePresetLabel } from '../CnDateRangePicker/CnDateRangePicker.vue'\nimport CnEmptyContent from '../CnEmptyContent/CnEmptyContent.vue'\nimport CnKpiGrid from '../CnKpiGrid/CnKpiGrid.vue'\nimport CnHeaderTrail from '../CnPageHeader/CnHeaderTrail.vue'\nimport CnSegmentedControl from '../CnSegmentedControl/CnSegmentedControl.vue'\nimport CnStatsBlockWidget from '../CnStatsBlockWidget/CnStatsBlockWidget.vue'\nimport CnTileWidget from '../CnTileWidget/CnTileWidget.vue'\nimport CnWidgetIcon from '../CnWidgetGrid/CnWidgetIcon.vue'\nimport CnWidgetRefItem from '../CnWidgetRefItem/CnWidgetRefItem.vue'\nimport CnWidgetRenderer from '../CnWidgetRenderer/CnWidgetRenderer.vue'\nimport CnWidgetWrapper from '../CnWidgetWrapper/CnWidgetWrapper.vue'\nimport { interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport { useIntegrationRegistry } from '../../composables/useIntegrationRegistry.js'\nimport { normalizeLook } from '../../composables/useLook.js'\nimport { pageFilters } from '../../mixins/pageFilters.js'\nimport { pageViews } from '../../mixins/pageViews.js'\nimport { mergeUserLayout, resolveUserLayoutApi } from '../../store/plugins/dashboardLayouts.js'\nimport { headerActionAsLink } from '../../utils/actionLink.js'\nimport { dispatchAction } from '../../utils/actionsDispatcher.js'\nimport { isAppInstalled } from '../../utils/appInstalled.js'\nimport { contentHeaderLink } from '../../utils/contentHeaderLink.js'\nimport { pickDeclaredProps } from '../../utils/declaredProps.js'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\nimport { HEADING_LEVEL } from '../../utils/headingLevel.js'\nimport { generatedPageFilterOptions, periodText, rangePeriodText } from '../../utils/periodOptions.js'\nimport { isOptionalUnresolved, resolveFilterValue } from '../../utils/resolveFilterTokens.js'\nimport { userLocale } from '../../utils/userLocale.js'\nimport { compareVisibleWhen, evaluateWorkspaceCondition, isWorkspaceCondition, readVisibleWhenValue } from '../../utils/visibleWhen.js'\nimport { resolveWidgetHeaderActions } from '../../utils/widgetHeaderActions.js'\nimport { canonicalWidgetType } from '../../utils/widgetTypeAliases.js'\nimport { CnActionButtons } from '../CnActionButtons/index.js'\nimport { CnActionsMenu } from '../CnActionsMenu/index.js'\nimport { CnLeafMountHost } from '../CnLeafMountHost/index.js'\nimport { BUILT_IN_WIDGETS } from '../CnWidgetGrid/builtInWidgets.js'\nimport { getWidgetTypeEntry } from '../CnWidgetGrid/dashboardWidgetRegistry.js'\n\n// Registers the dashboard widget catalog (stat, delta, gauge, ...) whenever this\n// page's chunk loads, so a fresh dashboard does not depend on the app's main.js.\nimport '../CnWidgetGrid/registerDashboardWidgets.js'\n\n/** Surfaces understood by the pluggable integration registry (AD-19). */\nconst INTEGRATION_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\n\n/**\n * Subset of `widgetDef.props` keys that the chart widget dispatcher\n * forwards to CnChartWidget. Unknown keys on `props` are ignored so\n * the manifest stays forward-compatible (e.g. `dataSource` is\n * round-tripped through manifest validators but not yet read here).\n *\n * `chartKind` is renamed to `type` because apexcharts' own component\n * prop is also called `type`, and `widgetDef.type` already means\n * \"dispatcher selector\" in this file.\n */\nconst CHART_PROP_KEYS = [\n\t'series',\n\t'categories',\n\t'labels',\n\t'options',\n\t'colors',\n\t'toolbar',\n\t'legend',\n\t'height',\n\t'width',\n\t'unavailableLabel',\n\t// Display passthrough (Wave 1, nextcloud-vue#91): additive presentation\n\t// keys forwarded verbatim to CnChartWidget.\n\t'horizontal',\n\t'legendPosition',\n\t'valueFormat',\n\t// Value-axis baseline guard: lets a manifest opt a chart out of the\n\t// zero-baseline default (`'fit'`) when its series lives far from zero.\n\t'valueAxisBaseline',\n\t'colorMap',\n\t'emptyLabel',\n\t// In-widget view switcher (Wave 3, nextcloud-vue#91): named display\n\t// views toggling which series / value format render.\n\t'views',\n\t// Endpoint data binding (Wave 2, nextcloud-vue#91): WITHOUT this key the\n\t// chart's endpointSource never reaches CnChartWidget on a dashboard\n\t// surface (getChartProps only forwards this allowlist), so the fleet's\n\t// trend charts silently render empty. `dataSource` is forwarded\n\t// separately via the template's :data-source binding (getWidgetDataSource),\n\t// so the Wave-3 aggregate/drilldown inside it already flow through.\n\t'endpointSource',\n\t// `bar-list` / `matrix` presentation keys.\n\t'barMax',\n\t'matrixLabelWidth',\n\t'footnote',\n\t'highlight',\n\t'cellSource',\n\t'emptyCellLabel',\n\t// A norm line and month categories on a line chart (DqDoorlooptijd).\n\t'referenceLines',\n\t'categoryFormat',\n]\n\n/**\n * CnDashboardPage — Top-level dashboard page component.\n *\n * The dashboard equivalent of CnIndexPage. Renders a configurable grid\n * of widgets from a `widgets` definition array and a `layout` array.\n *\n * Widget types (priority order, first match wins):\n * 1. **Tile** — Items with `type: 'tile'` render as quick-access tiles\n * 2. **Custom slot** — App provides rendering via `#widget-{widgetId}`\n * (escape hatch — beats every built-in branch when a slot exists)\n * 3. **Chart** — Items with `type: 'chart'` mount CnChartWidget; chart\n * inputs (chartKind, series, options, …) ride `widgetDef.props`,\n * plus an optional `dataSource` block resolves `series` /\n * `categories` from a GraphQL query.\n * 4. **Stats-block** — Items with `type: 'stats-block'` mount\n * CnStatsBlockWidget; the count comes from `widgetDef.dataSource`\n * (shorthand `{ register, schema, filter?, aggregate: 'count' }`\n * or raw GraphQL `{ graphql: { query, variables?, selectors } }`).\n * 5. **NC Dashboard API** — Widgets with `itemApiVersions` auto-rendered\n * 6. **Unknown fallback** — `unavailableLabel` text inside a wrapper\n *\n * Basic usage with custom widgets\n * ```vue\n * <CnDashboardPage\n * title=\"Dashboard\"\n * :widgets=\"widgetDefs\"\n * :layout=\"savedLayout\"\n * @layout-change=\"saveLayout\">\n * <template #widget-cases-by-status=\"{ item }\">\n * <StatusChart :data=\"statusData\" />\n * </template>\n * <template #widget-my-work=\"{ item }\">\n * <MyWorkList :items=\"workItems\" />\n * </template>\n * </CnDashboardPage>\n * ```\n *\n * With NC Dashboard API widgets\n * ```vue\n * <CnDashboardPage\n * title=\"Dashboard\"\n * :widgets=\"[...appWidgets, ...ncWidgets]\"\n * :layout=\"layout\"\n * @layout-change=\"saveLayout\" />\n * ```\n *\n * With manifest-driven chart widgets (no consumer code required)\n * ```js\n * const widgets = [{\n * id: 'sla-trend',\n * title: 'SLA trend',\n * type: 'chart',\n * props: {\n * chartKind: 'line', // line|bar|donut|area|pie|radialBar\n * series: [{ name: 'SLA %', data: [82, 85, 88, 91] }],\n * categories: ['Q1', 'Q2', 'Q3', 'Q4'],\n * options: { stroke: { width: 3 } }, // deep-merged with defaults\n * // dataSource is reserved for a future cycle — round-tripped\n * // through manifest validators but not yet read at render time:\n * // dataSource: { url: '/index.php/apps/myapp/api/charts/sla' }\n * // dataSource: { register: 'cases', schema: 'case',\n * // groupBy: 'caseType', aggregate: 'count' }\n * },\n * }]\n * ```\n */\n\n/**\n * A widget's content with each `@config.<key>` string (at any depth) filled\n * from the app config; an unset optional token (`@config.<key>?`) becomes ''\n * and an unset required one stays as written. Content without a token comes\n * back as the same object, so the widget is not handed a new one each render.\n *\n * @param {unknown} value The content, or a part of it.\n * @param {object} config The app config.\n * @return {unknown} The content with the config values in.\n * @spec openspec/changes/pl4-dashboard-config/specs/pl4-dashboard-config/spec.md#requirement-a-dashboard-widget-can-name-an-app-setting\n */\nfunction fillConfigTokens(value, config) {\n\tif (typeof value === 'string') {\n\t\tif (!value.startsWith('@config.')) {\n\t\t\treturn value\n\t\t}\n\t\tconst resolved = resolveFilterValue(value, { config })\n\t\treturn isOptionalUnresolved(resolved) ? '' : resolved\n\t}\n\tif (Array.isArray(value)) {\n\t\tconst filled = value.map((entry) => fillConfigTokens(entry, config))\n\t\treturn filled.some((entry, index) => entry !== value[index]) ? filled : value\n\t}\n\tif (value && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype) {\n\t\tconst entries = Object.entries(value).map(([key, entry]) => [key, fillConfigTokens(entry, config)])\n\t\treturn entries.some(([key, entry]) => entry !== value[key]) ? Object.fromEntries(entries) : value\n\t}\n\treturn value\n}\n\nconst filledByContent = new WeakMap()\n\n/**\n * `fillConfigTokens` once per content object and config, so a widget whose\n * content names a setting keeps one content object between renders.\n *\n * @param {object} content The widget content.\n * @param {object} config The app config.\n * @return {object} The filled content.\n */\nfunction filledContent(content, config) {\n\tif (!content || typeof content !== 'object') {\n\t\treturn content\n\t}\n\tconst key = JSON.stringify(config)\n\tconst cached = filledByContent.get(content)\n\tif (cached && cached.key === key) {\n\t\treturn cached.value\n\t}\n\tconst value = fillConfigTokens(content, config)\n\tfilledByContent.set(content, { key, value })\n\treturn value\n}\n\nexport default {\n\tname: 'CnDashboardPage',\n\n\tcomponents: {\n\t\tCnHeaderTrail,\n\t\tNcActions,\n\t\tNcActionButton,\n\t\tNcActionInput,\n\t\tNcActionSeparator,\n\t\tNcButton,\n\t\tCnEmptyContent,\n\t\tNcLoadingIcon,\n\t\tNcSelect,\n\t\tPencil,\n\t\tRestore,\n\t\tCheck,\n\t\tCog,\n\t\tCalendarRange,\n\t\tViewDashboardOutline,\n\t\tDownload,\n\t\tCnDashboardGrid,\n\t\tCnWidgetWrapper,\n\t\tCnWidgetRenderer,\n\t\tCnTileWidget,\n\t\tCnChartWidget,\n\t\tCnStatsBlockWidget,\n\t\tCnWidgetRefItem,\n\t\tCnBodySections,\n\t\tCnDateRangePicker,\n\t\tCnActionsMenu,\n\t\tCnActionButtons,\n\t\tCnBuildiqEditButton,\n\t\tCnWidgetStyleEditorModal,\n\t\tCnLeafMountHost,\n\t\tCnSegmentedControl,\n\t\tCnKpiGrid,\n\t\tCnWidgetIcon,\n\t},\n\n\tmixins: [pageFilters, pageViews],\n\n\tinject: {\n\t\t/**\n\t\t * Buildiq in-app edit state (ADR-041), provided by CnAppRoot as a ref.\n\t\t * When true the dashboard grid becomes drag/resize/remove-able even\n\t\t * without the consumer's own `allowEdit` toggle.\n\t\t */\n\t\tcnEditingBody: { default: false },\n\t\t/**\n\t\t * Reactive AI context holder provided by CnAppRoot. Overwritten\n\t\t * on created() and watched for prop changes. Reset on beforeUnmount().\n\t\t */\n\t\tcnAiContext: { default: null },\n\t\t/**\n\t\t * Consumer widget registry provided by CnAppRoot — the SAME injection\n\t\t * CnWidgetGrid and CnDetailPage read, so an app-registered widget\n\t\t * resolves identically on all three surfaces (REQ-MVR-005: a custom\n\t\t * widget overrides a built-in of the same name).\n\t\t */\n\t\tcnRegistry: { default: () => ({}) },\n\t\t/**\n\t\t * The page's action dispatcher, provided by CnPageRenderer: a card's\n\t\t * header action runs through it, so `open-modal` reaches the app's\n\t\t * registry dialogs, as on a detail page. Null outside the renderer.\n\t\t *\n\t\t * @spec openspec/changes/dashboard-card-action-dialog/specs/dashboard-page/spec.md#requirement-a-dashboard-card-header-action-dispatches-through-the-page\n\t\t */\n\t\tcnDispatchAction: { default: null },\n\t\t/**\n\t\t * Host translate function provided by CnAppRoot as\n\t\t * `cnTranslate: this.translate` (bound to the host app's id). The\n\t\t * manifest-authored page title/description are run through it.\n\t\t * Defaults to an identity function so an untranslated key renders\n\t\t * as itself.\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/**\n\t\t * The look the app is drawn in (`board` or `nextcloud`), provided by\n\t\t * CnAppRoot. The board look draws the screens' dashboard header, period\n\t\t * group and KPI row.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-parity/specs/dashboard-page/spec.md#requirement-the-board-dashboard-header\n\t\t */\n\t\tcnLook: { default: 'nextcloud' },\n\t},\n\n\t/**\n\t * Expose the authored (untranslated) widget titles to descendants.\n\t *\n\t * CnActionsMenu needs the English source for the bug-report deep link, but\n\t * it sits inside CnWidgetWrapper inside the widget renderer — threading a\n\t * second title prop would mean touching every one of the ~20 renderers and\n\t * relying on each to forward it. An inject resolves by widget id instead,\n\t * and degrades to '' where no dashboard provides it.\n\t *\n\t * @return {object} The provided resolver.\n\t */\n\tprovide() {\n\t\treturn {\n\t\t\tcnWidgetTitleSource: (widgetId) => this.getWidgetTitleSource(widgetId),\n\t\t\t// The page id, for widgets that key per-person state by dashboard (notepad).\n\t\t\tcnDashboardPageId: () => this.resolvedPageId,\n\t\t\t// Widget titles sit one level under the page title: h1 in the board\n\t\t\t// look, h2 in the Nextcloud look and as the hidden title.\n\t\t\t[HEADING_LEVEL]: () => (this.showHeader && this.title && this.isBoardLook ? 2 : 3),\n\t\t}\n\t},\n\n\tprops: {\n\t\t/** Page title */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * A breadcrumb under the title (manifest `config.breadcrumb`): one\n\t\t * crumb `{ label, route?, params?, href?, icon?, separator? }` or a\n\t\t * list; the title follows as the current crumb. Drawn as the detail\n\t\t * header's breadcrumb row. Null (the default) draws none.\n\t\t *\n\t\t * @type {object|Array<object>|null}\n\t\t * @spec openspec/changes/page-header-breadcrumb/specs/page-header/spec.md#requirement-a-list-dashboard-or-settings-page-can-show-a-breadcrumb-and-a-meta-note\n\t\t */\n\t\tbreadcrumb: {\n\t\t\ttype: [Object, Array],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * A note after the breadcrumb and a middle dot (manifest `config.headerMeta`).\n\t\t *\n\t\t * @spec openspec/changes/page-header-breadcrumb/specs/page-header/spec.md#requirement-a-list-dashboard-or-settings-page-can-show-a-breadcrumb-and-a-meta-note\n\t\t */\n\t\theaderMeta: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Page description (shown below title) */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether the header row renders: title, description, header actions\n\t\t * and the edit toggle. `false` (manifest `config.showHeader: false`)\n\t\t * drops it for a page whose first widget is its heading; the title\n\t\t * then renders visually hidden so the page keeps an accessible name.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-dashboard-page-can-hide-its-header\n\t\t */\n\t\tshowHeader: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * The ids of the widgets that form the KPI row above the grid\n\t\t * (manifest `config.kpiRow`). They render in an auto-fit CnKpiGrid and\n\t\t * are left out of the GridStack grid and of the emitted layout. An id\n\t\t * that names no widget is skipped with a development warning.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-parity/specs/dashboard-page/spec.md#requirement-a-kpi-row-above-the-grid\n\t\t * @type {Array<string>}\n\t\t */\n\t\tkpiRow: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Greet the reader in the header subtitle (manifest `config.greeting`):\n\t\t * `true` (or `\"first\"`) writes \"Good afternoon, Pieter · Monday 5\n\t\t * October 2026\", `\"full\"` uses the whole display name. The page\n\t\t * `description`, when set, follows after another middle dot. Off by\n\t\t * default: the subtitle is the description alone, as before.\n\t\t * `\"date\"` leads with the date alone, and `{ label }` puts the\n\t\t * translated label where the greeting would be (\"Customer contact ·\n\t\t * Wednesday 7 October 2026 · ...\").\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-greeting-header/specs/dashboard-page/spec.md#requirement-the-header-subtitle-can-greet-the-reader\n\t\t * @spec openspec/changes/dashboard-greeting-label/specs/dashboard-page/spec.md#requirement-the-header-subtitle-can-lead-with-a-label-or-the-date\n\t\t * @type {boolean|string|object}\n\t\t */\n\t\tgreeting: {\n\t\t\ttype: [Boolean, String, Object],\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Links drawn as small pills on the switch row under the header\n\t\t * (manifest `config.viewLinks`), as DqMijnWerk's \"Uw wachtrij / Aan\n\t\t * mij toegewezen / Dag afsluiten\". Each `{ label, icon?, route?,\n\t\t * href? }`: `route` is a route name or a `{ name, params?, query? }`\n\t\t * location, `href` a plain URL; `label` goes through the host\n\t\t * translate function. An entry without a label or a target is skipped.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-greeting-header/specs/dashboard-page/spec.md#requirement-a-switch-row-carries-the-view-switch-and-link-pills\n\t\t * @type {Array<object>}\n\t\t */\n\t\tviewLinks: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Whether the header draws the page Actions menu (manifest\n\t\t * `config.showActionsMenu`). `false` removes it, for a board page\n\t\t * whose header carries only the buildiq square and the primary.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-greeting-header/specs/dashboard-page/spec.md#requirement-the-header-can-drop-the-page-actions-menu\n\t\t * @type {boolean}\n\t\t */\n\t\tshowActionsMenu: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Whether a widget draws its overflow Actions menu when neither its\n\t\t * placement nor its definition says (`showActions`). `false` (manifest\n\t\t * `config.showWidgetActions: false`) drops the menu from every such\n\t\t * widget, for a dashboard whose widgets carry a header link and\n\t\t * nothing else. A widget that sets `showActions: true` keeps its menu.\n\t\t * Card widgets have no menu either way.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-a-dashboard-can-drop-the-widget-actions-menu\n\t\t */\n\t\tshowWidgetActions: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * GridStack's `float` for this dashboard (manifest\n\t\t * `config.gridFloat`). True (the default) keeps every widget on its\n\t\t * row. False packs widgets upward, so a size-to-content widget that\n\t\t * shrinks closes the gap under it instead of leaving an empty band.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-a-dashboard-closes-the-gap-a-shrinking-or-hidden-widget-leaves\n\t\t */\n\t\tgridFloat: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * A side column of a fixed width for the page's own grid (manifest\n\t\t * `config.gridSideColumn`): `{ width, from? }`, see CnDashboardGrid's\n\t\t * `sideColumn`. A view declares its own `gridSideColumn`, because two\n\t\t * views of one page can split differently (DqMijnWerk 320px beside\n\t\t * the main column, DqMijnTeam two halves).\n\t\t *\n\t\t * @spec openspec/changes/dashboard-side-column-width/specs/dashboard-side-column-width/spec.md#requirement-a-dashboard-can-draw-its-side-column-at-a-fixed-width\n\t\t */\n\t\tgridSideColumn: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Widget definitions array. Each widget defines metadata for rendering.\n\t\t *\n\t\t * Custom widgets: `{ id: 'my-widget', title: 'My Widget', type: 'custom' }`\n\t\t * NC API widgets: `{ id: 'calendar', title: 'Calendar', itemApiVersions: [1,2], ... }`\n\t\t * Tile widgets: `{ id: 'tile-files', type: 'tile', title: 'Files', icon: 'M12...', iconType: 'svg', backgroundColor: '#0082c9', textColor: '#fff', linkType: 'app', linkValue: 'files' }`\n\t\t * Chart widgets: `{ id: 'sla', type: 'chart', title: 'SLA trend',\n\t\t * props: { chartKind: 'line', series: [{ name: 'SLA %', data: [82, 88, 91] }],\n\t\t * categories: ['Q1', 'Q2', 'Q3'], options: { stroke: { width: 3 } } } }`\n\t\t *\n\t\t * @type {Array<{ id: string, title: string, type: string, iconUrl: string, iconClass: string, buttons: Array, itemApiVersions: number[], reloadInterval: number, props: object }>}\n\t\t */\n\t\twidgets: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Layout array defining widget positions in the grid.\n\t\t *\n\t\t * Each item: `{ id: 'unique-id', widgetId: 'my-widget', gridX: 0, gridY: 0, gridWidth: 4, gridHeight: 3 }`\n\t\t *\n\t\t * Additional properties (showTitle, styleConfig, tile config) are passed through.\n\t\t *\n\t\t * @type {Array<{ id: string|number, widgetId: string, gridX: number, gridY: number, gridWidth: number, gridHeight: number, showTitle: boolean, styleConfig: object }>}\n\t\t */\n\t\tlayout: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Declarative content items. Each item is a `widget-ref` entry from the\n\t\t * manifest's `pages[].config.content[]` array:\n\t\t *\n\t\t * `{ type: 'widget-ref', ref: 'openregister://widget/<schemaSlug>/<widgetSlug>' }`\n\t\t *\n\t\t * CnDashboardPage renders each widget-ref item as a `CnWidgetRefItem`\n\t\t * which resolves the widget from OR's registry at runtime and renders\n\t\t * the resolved component. Only `widget-ref` entries are processed; unknown\n\t\t * `type` values are skipped with a `console.warn`.\n\t\t *\n\t\t * When both `content` (widget-ref items) and `widgets`+`layout` (classic\n\t\t * GridStack layout) are present, `content` items are rendered above the\n\t\t * grid in a stacked list.\n\t\t *\n\t\t * @type {Array<{ type: string, ref: string }>}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Declarative IN-BODY sections (host-app section components) rendered\n\t\t * ALONGSIDE the widget grid — the dashboard equivalent of CnDetailPage's\n\t\t * `bodyWidgets`. Each entry:\n\t\t *\n\t\t * `{ id?, component, title?, props?, placement?, colSpan? }`\n\t\t *\n\t\t * - `component` — registry name resolved from the v2 `cnRegistry` first,\n\t\t * then the legacy `cnCustomComponents` map (the SAME resolver\n\t\t * `type:\"custom\"` pages use). A bespoke funnel / time-series / channel\n\t\t * chart that reads a custom REST endpoint stays a registered component\n\t\t * and surfaces here without a rewrite.\n\t\t * - `props` — token-resolved against the page context: `@workspace.<key>`\n\t\t * / `@page.<key>` (page-level workspace state), `@config.<key>` (app\n\t\t * config), and the time / `@me` tokens. An unresolved optional token is\n\t\t * dropped so the child sees `undefined`.\n\t\t * - `placement` — `before-grid` (above the widget grid) | `after-grid`\n\t\t * (below it) | `end` (the default; same as `after-grid`). `before-grid`\n\t\t * renders even when the dashboard has no grid widgets.\n\t\t * - `colSpan` — 1–12 grid span when sections at one placement share a row.\n\t\t *\n\t\t * Empty / omitted (default `[]`) renders nothing — the current behaviour.\n\t\t * The section context (`{ register, schema, objectId, workspace, config }`)\n\t\t * is also `provide`d on `cnSectionContext` so a section component can\n\t\t * inject it instead of taking explicit props. See `CnBodySections`.\n\t\t *\n\t\t * @type {Array<{id?: string, component: string, title?: string, props?: object, placement?: string, colSpan?: number}>}\n\t\t */\n\t\tbodyWidgets: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Page-level app config map exposed to declarative widget / section\n\t\t * config via the `@config.<key>` token (e.g. the reporting `currency`\n\t\t * the setup wizard captures). Provided to descendants on `cnAppConfig`,\n\t\t * so a stat widget's `format: { style: 'currency', currency:\n\t\t * '@config.currency' }` formats with the configured value (falling back\n\t\t * to the literal default — `EUR` — when unset) and an endpoint KPI's URL\n\t\t * can interpolate `@config.<key>`. A manifest renderer typically seeds\n\t\t * this from `loadState(appId, 'config', {})`. Empty (default) leaves\n\t\t * every `@config.<key>` token to fall back to its literal default.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tappConfig: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** Whether the dashboard is loading */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether to show the edit toggle button */\n\t\tallowEdit: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Number of grid columns */\n\t\tcolumns: {\n\t\t\ttype: Number,\n\t\t\tdefault: 12,\n\t\t},\n\n\t\t/** Grid cell height in pixels */\n\t\tcellHeight: {\n\t\t\ttype: Number,\n\t\t\tdefault: 80,\n\t\t},\n\n\t\t/** Grid margin in pixels */\n\t\tgridMargin: {\n\t\t\ttype: Number,\n\t\t\tdefault: 12,\n\t\t},\n\n\t\t/** Label for the edit button */\n\t\teditLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Edit'),\n\t\t},\n\n\t\t/** Label for the done button (when editing) */\n\t\tdoneLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Done'),\n\t\t},\n\n\t\t/** Label for the empty state */\n\t\temptyLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'No widgets configured'),\n\t\t},\n\n\t\t/** Label for unavailable widgets */\n\t\tunavailableLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Widget not available'),\n\t\t},\n\n\t\t/**\n\t\t * Rendering surface forwarded to integration widgets (widgets\n\t\t * whose `type === 'integration'`). Drives the AD-19 surface\n\t\t * fallback on `resolveWidget(integrationId, surface)`.\n\t\t *\n\t\t * @type {'user-dashboard'|'app-dashboard'|'detail-page'|'single-entity'}\n\t\t */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'app-dashboard',\n\t\t\tvalidator: (value) => INTEGRATION_SURFACES.includes(value),\n\t\t},\n\n\t\t/**\n\t\t * Object context forwarded to integration widgets:\n\t\t * `{ register, schema, objectId }`. Optional — most dashboards\n\t\t * aren't object-scoped, but CnDetailPage passes one through so\n\t\t * `CnFilesCard` / `CnTagsCard` / `CnAuditTrailCard` know which\n\t\t * object's sub-resources to fetch.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tintegrationContext: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Optional per-app install/enable status map used by the\n\t\t * `requiresApp` widget gate. Shape: `{ [appId]: { installed:\n\t\t * boolean, enabled: boolean, category?: string } }` — typically\n\t\t * the `dependency_statuses` initial state a consuming app injects.\n\t\t * When a widget definition carries `requiresApp` (a string or\n\t\t * array of app ids) and a required app is not enabled here, that\n\t\t * widget renders an \"Install …\" call-to-action instead of its\n\t\t * normal content. When this prop is `null` the gate falls back to\n\t\t * the `isAppInstalled()` runtime check (`OC.appswebroots` →\n\t\t * capabilities), so the gate works with or without injected data.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tappStatuses: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Optional date-range header descriptor. When `enabled: true`\n\t\t * the dashboard renders a `CnDateRangePicker` between the\n\t\t * header and the widget grid, persists the chosen range to\n\t\t * `localStorage` (when `persistKey` is set), emits\n\t\t * `@date-range-change` on every change, AND provides a\n\t\t * reactive `cnDashboardDateRange` ref to every descendant\n\t\t * widget.\n\t\t *\n\t\t * When the prop is `null` (default), `false`, or\n\t\t * `{ enabled: false }`, the header row is NOT rendered and the\n\t\t * existing dashboard layout stays unchanged. The provide is\n\t\t * still installed (always) but its value stays `null` so\n\t\t * descendant chart widgets fall back to their\n\t\t * `dataSource.bucket.staticRange` (or skip the query\n\t\t * entirely).\n\t\t *\n\t\t * Shape:\n\t\t * ```ts\n\t\t * {\n\t\t * enabled: boolean,\n\t\t * control?: 'picker' | 'pills',\n\t\t * default?: { from: string, to: string, preset?: string },\n\t\t * persistKey?: string,\n\t\t * presets?: Array<{ id: string, label: string, days: number|null }>,\n\t\t * }\n\t\t * ```\n\t\t *\n\t\t * `control` selects the header control style: the default `'picker'`\n\t\t * renders the `CnDateRangePicker` (a preset select + two date\n\t\t * inputs); `'pills'` renders a compact segmented toggle-button row\n\t\t * (one pill per preset, plus a de-emphasised \"Custom range\" popover\n\t\t * pill). Both drive the same shared range.\n\t\t *\n\t\t * A preset with no numeric `days` / `hours` (other than the manual\n\t\t * `custom` entry) — e.g. `{ id: 'all', label: 'All', days: null }` —\n\t\t * is an \"All\" / CLEAR preset: picking it removes the window so\n\t\t * date-bound widgets show their unfiltered count. An explicit\n\t\t * `clear: true` forces the same behaviour.\n\t\t *\n\t\t * The active window is published into the page-level workspace\n\t\t * context as `dateFrom` / `dateTo` / `datePreset`, so any declarative\n\t\t * widget can scope itself to it via the optional filter tokens\n\t\t * `@workspace.dateFrom?` / `@workspace.dateTo?` (an empty bound, i.e.\n\t\t * the \"All\" range, drops the token so the filter is omitted).\n\t\t *\n\t\t * Default preset when no explicit `default` and no persisted\n\t\t * state is found: `last-7` (`now − 7d → now`).\n\t\t *\n\t\t * Per-widget surfacing: chart widgets with a `dataSource.bucket`\n\t\t * get an in-header date chip automatically; CUSTOM and registered\n\t\t * card widgets (`stat` / `gauge` / `delta` KPI tiles) opt in via\n\t\t * `layout[].dateChip: true` (same popover, writes the same shared\n\t\t * range — so an abstract KPI card carries its own period selector).\n\t\t * The chip needs the widget header (`showTitle !== false`) and shows\n\t\t * the active preset's label (e.g. `7d` / `All`), staying clickable\n\t\t * even on an unbounded (\"All\") range. Set `showHeaderPicker: false`\n\t\t * to rely solely on the per-widget chips.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tdateRange: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Optional declarative header actions (#91 Wave 3) rendered as buttons\n\t\t * in the dashboard header via CnActionButtons — `open-form` (schema\n\t\t * create dialog), `api-call` (POST/PUT + toast + refresh), `toggle`\n\t\t * (two-way state button), `navigate` / `open-modal` / `refresh`, each\n\t\t * with an optional `visibleWhen` predicate. An entry with `href` is a\n\t\t * link button, never dispatched: an absolute `http(s)`, `mailto:`,\n\t\t * `tel:` or `//host/...` URL as written, an instance path (leading `/`) through\n\t\t * `generateUrl()`, in a new tab with `target: '_blank'`. Empty (the\n\t\t * default) renders nothing; the `#header-actions` slot still works\n\t\t * alongside it for bespoke buttons.\n\t\t *\n\t\t * @type {Array<object>}\n\t\t */\n\t\theaderActions: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Optional page-level filter controls rendered in the dashboard header.\n\t\t * Each selection is written into the reactive page-level workspace\n\t\t * context (the same bag `cnWorkspaceContext` provides), so any widget can\n\t\t * read it via a `@page.<key>` / `@workspace.<key>` token — e.g. a period\n\t\t * selector that every endpoint-bound KPI's URL interpolates.\n\t\t *\n\t\t * Each entry: `{ key, label?, type?: 'select', control?, placement?,\n\t\t * options: [{ value, label }], default? }`. `key` is the workspace-context\n\t\t * key written on change; `default` (or the first option) seeds it on\n\t\t * mount. The control is a select, or with `control: 'segmented'` a\n\t\t * compact segmented group; `placement: 'description'` puts a segmented\n\t\t * group on the header's description line, after the period group\n\t\t * (DqProcesanalyse \"Gemiddeld | Mediaan\"), and a select before it\n\t\t * (DqDoorlooptijd \"alle zaaktypen\"). An endpoint widget can read\n\t\t * the value in its `responsePath` too (`phaseDays.@workspace.measure`).\n\t\t * `optionsFrom` reads the options instead of listing them: `{ url,\n\t\t * params?, responsePath?, valueField?, labelField? }` from an app\n\t\t * endpoint, or `{ register, schema, filter?, valueField?, labelField? }`\n\t\t * from OpenRegister objects (value `id`, label `title` or `name` by\n\t\t * default; tokens resolve). `clearable: true` lets the reader clear the\n\t\t * select back to \"all\" (`placeholder`, e.g. \"All case types\"), which\n\t\t * writes null and seeds nothing. `type: 'quarter'` generates its\n\t\t * options: the current quarter first, then `count - 1` (default 7)\n\t\t * before it, valued `YYYY-Qn` and seeded with the current one;\n\t\t * `type: 'year'` does the same for years (default 5, valued `YYYY`). Empty\n\t\t * (the default) renders no controls and leaves the context untouched.\n\t\t * `control: 'none'` seeds its value like any page filter but draws no\n\t\t * control: a fixed period the widgets read and the description names\n\t\t * (`{filter.<key>}`).\n\t\t *\n\t\t * @type {Array<{key: string, label?: string, type?: string, control?: ('select'|'segmented'), placement?: ('row'|'description'), options?: Array<{value: (string|number), label: string}>, optionsFrom?: object, clearable?: boolean, placeholder?: string, default?: (string|number)}>}\n\t\t */\n\t\tpageFilters: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Show the built-in Refresh item in the page-level overflow Actions\n\t\t * menu. On by default. The default handler emits `@refresh` and,\n\t\t * unless suppressed, fires the `cn:page:refresh` event-bus channel —\n\t\t * which the built-in data widgets subscribe to, so the action works\n\t\t * with no host wiring at all. A `@refresh` listener that calls\n\t\t * `preventDefault()` replaces that default rather than adding to it.\n\t\t *\n\t\t * This is ALSO the default for each widget's own overflow menu: when\n\t\t * `false`, the Refresh item is dropped from every widget too (handy\n\t\t * for a read-only dashboard whose widgets have no refetch wired —\n\t\t * Request-a-feature stays). A widget can still opt back in (or out)\n\t\t * individually via `showRefresh` / `hideRefresh` on its definition or\n\t\t * layout entry.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowRefresh: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Show the built-in Refresh item on each **custom-slot** widget\n\t\t * (distinct from the page-level `showRefresh`). Tri-state:\n\t\t * - `true` / `false` — force it on or off for all custom widgets.\n\t\t * - `null` (the default) — **auto**: show it only when the app using\n\t\t * `CnDashboardPage` attached a `@widget-refresh` listener (i.e. it\n\t\t * will actually handle the refresh). Apps that refresh widgets\n\t\t * centrally by another route (e.g. a header button bumping a shared\n\t\t * signal) leave it unset and get no dead per-widget buttons.\n\t\t *\n\t\t * Built-in chart / NC / integration widgets always show Refresh\n\t\t * (they refresh via the `cn:widget:refresh` bus or their renderer).\n\t\t *\n\t\t * @type {boolean|null}\n\t\t */\n\t\twidgetShowRefresh: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Show the built-in Request-a-feature item in the page-level\n\t\t * overflow Actions menu. On by default; opens the forge's\n\t\t * feature-request issue form when mounted under CnAppRoot.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowRequestFeature: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Show the built-in \"Report a bug\" item in the page-level overflow\n\t\t * Actions menu. On by default — the trio Request a feature / Report a\n\t\t * bug / Documentation is the contract for every Conduction surface.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowReportBug: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Show the built-in Documentation item in the page-level overflow\n\t\t * Actions menu. On by default; the shared menu resolves the target\n\t\t * itself, so leaving it on costs the host nothing.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowDocumentation: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Explicit documentation link for this dashboard, opened in a new tab.\n\t\t * Usually unnecessary: the page-level menu builds one from the\n\t\t * app-wide documentation base and the page id.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tdocumentationUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Pre-translated label for the Documentation action. Defaults to \"Documentation\". */\n\t\tdocumentationLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Documentation'),\n\t\t},\n\n\t\t/**\n\t\t * Stable id for this dashboard, used in the `@refresh` /\n\t\t * `@request-feature` payloads and the `surface: \"dashboard:<id>\"`\n\t\t * field on the feature-request modal. Falls back to a slugified\n\t\t * `title` when unset.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tpageId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether this page keeps a per-user layout.\n\t\t *\n\t\t * Off by default and opted into with one manifest key,\n\t\t * `config.userLayout: true`. A page without it makes NO layout request\n\t\t * and renders exactly as it did before this existed, which is the\n\t\t * property that makes shipping it safe on every dashboard at once.\n\t\t *\n\t\t * Deprecated: layout belongs to Buildiq. Kept working for one release.\n\t\t *\n\t\t * @deprecated\n\t\t * @type {boolean}\n\t\t */\n\t\tuserLayout: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * The Nextcloud app id the user layout is stored under.\n\t\t *\n\t\t * Required for `userLayout` to do anything: a preference has to be\n\t\t * addressed to an app, and storing one under an empty app id writes a\n\t\t * record nothing ever reads back.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tappId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Reads and writes the current user's layout record. Injected so the\n\t\t * component needs no store of its own and a test needs no HTTP: pass\n\t\t * `{ load, save, reset }`, or leave it and the page falls back to the\n\t\t * `dashboardLayoutsPlugin` shape over user preferences.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tuserLayoutStore: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Optional `specRef` slug. Accepted for backward compatibility with\n\t\t * hosts that bound it for the removed in-product suggestion modal;\n\t\t * no longer forwarded anywhere (the forge issue form asks for its\n\t\t * own context).\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tspecRef: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Whether a page-level refresh is in flight (disables the Refresh item and shows its spinner). */\n\t\trefreshing: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Pre-translated label for the Refresh action. */\n\t\trefreshLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Refresh'),\n\t\t},\n\n\t\t/** Pre-translated label for the Request-a-feature action. */\n\t\trequestFeatureLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Request a feature'),\n\t\t},\n\n\t\t/** Pre-translated aria-label / tooltip for the overflow menu trigger. */\n\t\tactionsMenuLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Actions'),\n\t\t},\n\t},\n\n\temits: [\n\t\t'date-range-change',\n\t\t'edit-toggle',\n\t\t'layout-change',\n\t\t'user-layout-reset',\n\t\t'page-filter-change',\n\t\t'refresh',\n\t\t'request-feature',\n\t\t'widget-refresh',\n\t\t'widget-remove',\n\t\t'widget-request-feature',\n\t],\n\n\tsetup(props) {\n\t\t// Wire the pluggable integration registry so widgets of type\n\t\t// `integration` resolve their component reactively. No-op cost\n\t\t// when no integration widgets are configured.\n\t\tconst { integrations: registryIntegrations, resolveWidget, getById } = useIntegrationRegistry()\n\n\t\t// Provide a reactive date-range ref to every descendant widget,\n\t\t// ALWAYS — even when the feature is off. Descendants can then\n\t\t// `inject('cnDashboardDateRange', ref(null))` without a fallback\n\t\t// dance, and the value stays `null` (= no range) until the user\n\t\t// picks one. CnChartWidget reads this via inject() to drive its\n\t\t// bucket-shorthand variables.\n\t\tconst dashboardDateRange = ref(null)\n\t\tprovide('cnDashboardDateRange', dashboardDateRange)\n\n\t\t// Page-level WORKSPACE CONTEXT — a reactive bag of shared keys that\n\t\t// widgets on this page both write (e.g. a page-level client picker sets\n\t\t// `selectedClient`) and read (a client-overview list filters on\n\t\t// `@workspace.selectedClient`). Provided ALWAYS — like cnDashboardDateRange — so\n\t\t// descendants can `inject('cnWorkspaceContext')` without a fallback dance;\n\t\t// the bag starts empty and stays inert for dashboards that don't use it.\n\t\tconst workspaceContext = ref({})\n\t\tprovide('cnWorkspaceContext', workspaceContext)\n\n\t\t// Page-level APP CONFIG — exposed to declarative widget / section config\n\t\t// via the `@config.<key>` token (e.g. the reporting currency the setup\n\t\t// wizard captures). Provided ALWAYS (like cnWorkspaceContext) and kept in\n\t\t// sync with the `appConfig` prop so a late-loaded config re-resolves\n\t\t// downstream tokens. Descendants `inject('cnAppConfig', ref({}))`.\n\t\t// The config an ancestor provides (the app root) is the base; the\n\t\t// page's own `appConfig` wins key by key.\n\t\tconst inheritedConfig = inject('cnAppConfig', null)\n\t\tconst unwrapConfig = (value) => {\n\t\t\tconst raw = value && typeof value === 'object' && 'value' in value ? value.value : value\n\t\t\treturn raw && typeof raw === 'object' ? raw : {}\n\t\t}\n\t\tconst mergedConfig = () => ({ ...unwrapConfig(inheritedConfig), ...(props.appConfig || {}) })\n\t\tconst appConfigRef = ref(mergedConfig())\n\t\tprovide('cnAppConfig', appConfigRef)\n\t\twatch(\n\t\t\t[() => props.appConfig, () => unwrapConfig(inheritedConfig)],\n\t\t\t() => {\n\t\t\t\tappConfigRef.value = mergedConfig()\n\t\t\t},\n\t\t\t{ deep: true },\n\t\t)\n\n\t\treturn {\n\t\t\tregistryIntegrations,\n\t\t\tresolveRegistryWidget: resolveWidget,\n\t\t\tgetRegistryProvider: getById,\n\t\t\tdashboardDateRange,\n\t\t\tworkspaceContext,\n\t\t\tappConfigRef,\n\t\t}\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tisEditing: false,\n\t\t\t/**\n\t\t\t * This user's arranged layout, when `userLayout` is on.\n\t\t\t *\n\t\t\t * 🔴 IT IS A SEPARATE ARRAY, NOT THE `layout` PROP. Drag and resize\n\t\t\t * write into the prop IN PLACE so the in-place manifest editor can\n\t\t\t * diff them, which is right for an admin editing the page for\n\t\t\t * everyone and wrong for a user arranging it for themselves: the\n\t\t\t * same mutation would rewrite the manifest. So a user layout lives\n\t\t\t * here and the prop is never touched.\n\t\t\t *\n\t\t\t * @type {Array<object>|null}\n\t\t\t */\n\t\t\tuserLayoutItems: null,\n\t\t\t/** Whether a stored record has been asked for yet. */\n\t\t\tuserLayoutLoaded: false,\n\t\t\t/** Whether this edit session changed anything worth saving. */\n\t\t\tuserLayoutDirty: false,\n\t\t\t/** Whether the per-widget style/config editor modal is open. */\n\t\t\tshowWidgetConfig: false,\n\t\t\t/** widgetId of the widget currently being configured (drives `configWidget`). */\n\t\t\tconfigWidgetId: null,\n\t\t\t/**\n\t\t\t * Local mirror of the picker's current value. Initialised\n\t\t\t * in `created()` from `dateRange.default` → persisted\n\t\t\t * state → `last-7` fallback, and kept in sync with the\n\t\t\t * provided `dashboardDateRange` ref via a watcher.\n\t\t\t *\n\t\t\t * @type {{ from: string, to: string, preset: string }|null}\n\t\t\t */\n\t\t\tcurrentRange: null,\n\t\t\t/**\n\t\t\t * Per-widget open/close state for the in-chart date-range\n\t\t\t * popover. Keyed by widgetId so each chart widget's chip\n\t\t\t * tracks its own NcActions open state independently. Vue 2\n\t\t\t * reactivity caveat — entries are created lazily via\n\t\t\t * Vue.set when needed.\n\t\t\t *\n\t\t\t * @type {Record<string, boolean>}\n\t\t\t */\n\t\t\topenChipPicker: {},\n\t\t\t// What a registry widget reported for its card header (`header` event), by widget id.\n\t\t\twidgetHeaders: {},\n\t\t\t/**\n\t\t\t * Pre-translated tooltip for the chart-widget date-range\n\t\t\t * chip — kept as a data field rather than a computed so the\n\t\t\t * lib's `translate` is evaluated once at component creation\n\t\t\t * and not on every render.\n\t\t\t */\n\t\t\tdateChipTitle: t('nextcloud-vue', 'Change date range'),\n\t\t\t/**\n\t\t\t * Evaluated `visibleWhen` outcome per conditional widget, keyed\n\t\t\t * by widget id: `{ met, value }` — whether the widget's cell may\n\t\t\t * show, and the raw field value the predicate read (handed to\n\t\t\t * banners so they can interpolate `{value}` into their text and\n\t\t\t * skip re-fetching). Feeds `displayLayout`, which collapses the\n\t\t\t * grid cell of a widget whose condition is unmet — a widget that\n\t\t\t * renders nothing (or a whole card that should not exist yet)\n\t\t\t * would otherwise leave its wrapper card and reserved grid row\n\t\t\t * behind as a tall empty box.\n\t\t\t *\n\t\t\t * @type {Record<string, {met: boolean, value: unknown}>}\n\t\t\t */\n\t\t\twidgetConditionOutcome: {},\n\t\t\t/**\n\t\t\t * Whether the initial predicate evaluation has finished. The\n\t\t\t * grid's FIRST paint waits for it (only when the page actually\n\t\t\t * has conditional widgets), so a conditional widget is present\n\t\t\t * or absent from the first rendered frame — never popping in\n\t\t\t * after load and reflowing everything below it (WCAG-hostile\n\t\t\t * layout shift). Set synchronously when there is nothing to\n\t\t\t * evaluate; never reset once true (a later live change may\n\t\t\t * still reflow, which is the correct behaviour for a state\n\t\t\t * that truly changed).\n\t\t\t */\n\t\t\twidgetConditionsSettled: false,\n\t\t\t/**\n\t\t\t * Monotonic id of the newest evaluateWidgetConditions() run.\n\t\t\t * Each run captures its own id and writes outcomes only while it\n\t\t\t * is still the newest — an older run resolving late (slow\n\t\t\t * endpoint) must not overwrite fresher verdicts, and only the\n\t\t\t * newest run may prune outcomes for removed defs.\n\t\t\t */\n\t\t\twidgetEvalSeq: 0,\n\t\t\t/**\n\t\t\t * Signature of the last-evaluated conditional set — the sorted\n\t\t\t * `[id, visibleWhen]` pairs. The deep `widgets` watch fires on\n\t\t\t * ANY def edit (a title tweak, a color change); re-running the\n\t\t\t * predicates is only warranted when this signature actually\n\t\t\t * changed, otherwise an authoring session would refetch every\n\t\t\t * conditional endpoint on every keystroke.\n\t\t\t */\n\t\t\twidgetEvalSignature: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Effective translate function: the injected `cnTranslate` (the host\n\t\t * app's bound `t()`), identity by default.\n\t\t *\n\t\t * @return {(key: string) => string}\n\t\t */\n\t\teffectiveTranslate() {\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate : (key) => key\n\t\t},\n\n\t\t/**\n\t\t * The header actions handed to CnActionButtons, an entry with `href`\n\t\t * in its link form (resolved URL, anchor target, no handler). An\n\t\t * `href` may carry `@workspace.<key>` / `@page.<key>` tokens, filled\n\t\t * (URL-encoded) from the page filters, so a download link asks for\n\t\t * what the page shows.\n\t\t *\n\t\t * @spec openspec/changes/header-action-href/specs/header-action-href/spec.md#requirement-a-header-action-with-href-is-a-link-that-runs-and-emits-nothing\n\t\t * @return {Array<object>}\n\t\t */\n\t\tlinkedHeaderActions() {\n\t\t\tconst workspace = Object.fromEntries(Object.entries(this.workspaceContext || {})\n\t\t\t\t.map(([key, value]) => [key, (value === undefined || value === null) ? value : encodeURIComponent(String(value))]))\n\t\t\treturn (this.headerActions || [])\n\t\t\t\t.map((entry) => ((entry && typeof entry.href === 'string' && entry.href.includes('@'))\n\t\t\t\t\t? { ...entry, href: interpolateUrlTokens(entry.href, { workspace }) }\n\t\t\t\t\t: entry))\n\t\t\t\t.map(headerActionAsLink)\n\t\t},\n\n\t\t/**\n\t\t * Under the board look the header reads the secondary actions, the\n\t\t * edit toggle and Actions menu, the buildiq square, then the primary\n\t\t * actions, as on an index page (PtDashboard, DqDashboard).\n\t\t *\n\t\t * @return {Array<object>} The header actions that are not `variant: \"primary\"`.\n\t\t */\n\t\tboardSecondaryHeaderActions() {\n\t\t\treturn this.linkedHeaderActions.filter((entry) => entry?.variant !== 'primary')\n\t\t},\n\n\t\t/**\n\t\t * @return {Array<object>} The `variant: \"primary\"` header actions, drawn after the buildiq square.\n\t\t */\n\t\tboardPrimaryHeaderActions() {\n\t\t\treturn this.linkedHeaderActions.filter((entry) => entry?.variant === 'primary')\n\t\t},\n\n\t\t/**\n\t\t * The greeting for the time of day, with the reader's first (or\n\t\t * full) name when known, or '' when `greeting` is off.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-greeting-header/specs/dashboard-page/spec.md#requirement-the-header-subtitle-can-greet-the-reader\n\t\t * @return {string}\n\t\t */\n\t\tgreetingLine() {\n\t\t\tif (this.greeting && typeof this.greeting === 'object') {\n\t\t\t\tconst label = typeof this.greeting.label === 'string' ? this.greeting.label.trim() : ''\n\t\t\t\treturn label ? this.effectiveTranslate(label) : ''\n\t\t\t}\n\t\t\tif (this.greeting !== true && this.greeting !== 'first' && this.greeting !== 'full') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tlet user\n\t\t\ttry {\n\t\t\t\tuser = getCurrentUser()\n\t\t\t} catch {\n\t\t\t\tuser = null\n\t\t\t}\n\t\t\tconst displayName = (user && typeof user.displayName === 'string') ? user.displayName.trim() : ''\n\t\t\tconst name = this.greeting === 'full' ? displayName : displayName.split(/\\s+/)[0]\n\t\t\tconst hour = new Date().getHours()\n\t\t\tif (hour < 12) {\n\t\t\t\treturn name ? t('nextcloud-vue', 'Good morning, {name}', { name }) : t('nextcloud-vue', 'Good morning')\n\t\t\t}\n\t\t\tif (hour < 18) {\n\t\t\t\treturn name ? t('nextcloud-vue', 'Good afternoon, {name}', { name }) : t('nextcloud-vue', 'Good afternoon')\n\t\t\t}\n\t\t\treturn name ? t('nextcloud-vue', 'Good evening, {name}', { name }) : t('nextcloud-vue', 'Good evening')\n\t\t},\n\n\t\t/**\n\t\t * The header subtitle: with `greeting` on, the greeting (or the\n\t\t * label), today's date written out and the description, joined by a\n\t\t * middle dot; with `greeting: \"date\"` the date leads, capitalised;\n\t\t * else the description alone, as before.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-greeting-header/specs/dashboard-page/spec.md#requirement-the-header-subtitle-can-greet-the-reader\n\t\t * @spec openspec/changes/dashboard-greeting-label/specs/dashboard-page/spec.md#requirement-the-header-subtitle-can-lead-with-a-label-or-the-date\n\t\t * @return {string}\n\t\t */\n\t\t/**\n\t\t * `headerMeta` through the host translate, with `{today}` written out as\n\t\t * today's date (DqDagAfsluiten \"Dag afsluiten, woensdag 7 oktober\").\n\t\t *\n\t\t * @spec openspec/changes/record-list-notes/specs/record-list-notes/spec.md#requirement-a-dashboard-header-meta-can-name-today\n\t\t * @return {string}\n\t\t */\n\t\tresolvedHeaderMeta() {\n\t\t\tif (!this.headerMeta) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst meta = this.effectiveTranslate(this.headerMeta)\n\t\t\tif (!meta.includes('{today}')) {\n\t\t\t\treturn meta\n\t\t\t}\n\t\t\tconst options = { weekday: 'long', day: 'numeric', month: 'long' }\n\t\t\tlet today\n\t\t\ttry {\n\t\t\t\ttoday = new Intl.DateTimeFormat(getCanonicalLocale() || undefined, options).format(new Date())\n\t\t\t} catch {\n\t\t\t\ttoday = new Intl.DateTimeFormat(undefined, options).format(new Date())\n\t\t\t}\n\t\t\treturn meta.split('{today}').join(today)\n\t\t},\n\n\t\tsubtitleText() {\n\t\t\tconst description = this.description ? this.resolvedDescription : ''\n\t\t\tconst dateOnly = this.greeting === 'date'\n\t\t\tconst greeting = this.greetingLine\n\t\t\tif (greeting === '' && !dateOnly) {\n\t\t\t\treturn description\n\t\t\t}\n\t\t\tconst options = { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }\n\t\t\tlet date\n\t\t\ttry {\n\t\t\t\tdate = new Intl.DateTimeFormat(getCanonicalLocale() || undefined, options).format(new Date())\n\t\t\t} catch {\n\t\t\t\tdate = new Intl.DateTimeFormat(undefined, options).format(new Date())\n\t\t\t}\n\t\t\tif (dateOnly) {\n\t\t\t\tdate = date.charAt(0).toLocaleUpperCase() + date.slice(1)\n\t\t\t}\n\t\t\treturn [greeting, date, description].filter((part) => part !== '').join(' · ')\n\t\t},\n\n\t\t/**\n\t\t * Whether the page's view switch sits on the switch row under the\n\t\t * header (board look) rather than among the header actions.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-greeting-header/specs/dashboard-page/spec.md#requirement-a-switch-row-carries-the-view-switch-and-link-pills\n\t\t * @return {boolean}\n\t\t */\n\t\tswitchInRow() {\n\t\t\treturn this.isBoardLook && this.showsPageViewSwitch\n\t\t},\n\n\t\t/**\n\t\t * `viewLinks` as render descriptors: a router link for a route, an\n\t\t * anchor for an href, the label translated. Entries without a label\n\t\t * or a target are dropped.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-greeting-header/specs/dashboard-page/spec.md#requirement-a-switch-row-carries-the-view-switch-and-link-pills\n\t\t * @return {Array<{key: string, tag: string, attrs: object, label: string, icon: string}>}\n\t\t */\n\t\tresolvedViewLinks() {\n\t\t\tconst links = Array.isArray(this.viewLinks) ? this.viewLinks : []\n\t\t\tconst out = []\n\t\t\tlinks.forEach((link, index) => {\n\t\t\t\tif (!link || typeof link.label !== 'string' || link.label === '') {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst icon = typeof link.icon === 'string' ? link.icon : ''\n\t\t\t\tconst label = this.effectiveTranslate(link.label)\n\t\t\t\tif (link.route && this.$router) {\n\t\t\t\t\tconst to = typeof link.route === 'string' ? { name: link.route } : link.route\n\t\t\t\t\tout.push({ key: `route-${index}`, tag: 'router-link', attrs: { to }, label, icon })\n\t\t\t\t} else if (typeof link.href === 'string' && link.href !== '') {\n\t\t\t\t\tout.push({ key: `href-${index}`, tag: 'a', attrs: { href: link.href }, label, icon })\n\t\t\t\t}\n\t\t\t})\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * The page title run through the host translate function so a\n\t\t * manifest-authored source string localises. The open view's\n\t\t * `title`, when it has one, takes its place (\"My team\").\n\t\t *\n\t\t * @spec openspec/changes/view-title/specs/view-switch-containers/spec.md#requirement-the-page-title-follows-the-open-view\n\t\t * @return {string}\n\t\t */\n\t\tresolvedTitle() {\n\t\t\tconst view = this.hasViews ? this.activeView : null\n\t\t\tif (view && view.title) {\n\t\t\t\treturn view.title\n\t\t\t}\n\t\t\treturn this.title ? this.effectiveTranslate(this.title) : this.title\n\t\t},\n\n\t\t/**\n\t\t * The page description run through the host translate function.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedDescription() {\n\t\t\tif (!this.description) {\n\t\t\t\treturn this.description\n\t\t\t}\n\t\t\t// `{filter.<key>}`: the page filter's active choice, read as a period\n\t\t\t// (DqProcesanalyse \"Afgehandelde zaken januari tot en met september 2026\").\n\t\t\t// `{dateRange}`: the dashboard's active date range, read as a period\n\t\t\t// (DqDashboard \"Hoe het team ervoor staat · oktober 2026\"); `{today|<format>}`:\n\t\t\t// today through a row template format (DqTermijnen \"Week 41 · alle teams\").\n\t\t\treturn this.effectiveTranslate(this.description)\n\t\t\t\t.replace(/\\{filter\\.([\\w-]+)\\}/g, (token, key) => this.pageFilterPeriodText(key))\n\t\t\t\t.replace(/\\{dateRange\\}/g, () => this.dateRangePeriodText())\n\t\t\t\t.replace(/\\{today\\|([\\w:]+)\\}/g, (token, format) => fillTemplate(`{today|${format}}`, { today: new Date().toISOString() }))\n\t\t},\n\n\t\t/**\n\t\t * Whether the widget grid should be drag/resize/remove-able — the\n\t\t * consumer's own edit toggle OR the Buildiq in-app editor (ADR-041).\n\t\t * Unwraps the injected `cnEditingBody` ref.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tgridEditable() {\n\t\t\treturn this.isEditing || this.editingBody\n\t\t},\n\n\t\t/**\n\t\t * Whether Buildiq is editing the page (the injected `cnEditingBody`\n\t\t * ref, or a plain boolean). Buildiq is the layout editor: while it\n\t\t * edits, the grid shows and changes the manifest layout, also on a\n\t\t * page with `userLayout`.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\teditingBody() {\n\t\t\tconst e = this.cnEditingBody\n\t\t\treturn Boolean(e && typeof e === 'object' && 'value' in e ? e.value : e)\n\t\t},\n\n\t\t/** @return {boolean} Whether the grid shows this user's arrangement. */\n\t\tshowsUserLayout() {\n\t\t\treturn this.userLayout && !this.editingBody && Array.isArray(this.userLayoutItems)\n\t\t},\n\n\t\t/**\n\t\t * The layout actually handed to the grid. In live (non-edit) mode,\n\t\t * widgets that would render nothing right now — a `visibleWhen`\n\t\t * that has not evaluated true, or a banner with no text — are\n\t\t * REMOVED and the remaining items are re-compacted upward:\n\t\t * GridStack runs `float: true`, so a hidden widget otherwise keeps\n\t\t * its wrapper card and its reserved grid row, and a dashboard whose\n\t\t * fail-safe-hidden widgets are (correctly) hidden opens on a column\n\t\t * of tall empty cards.\n\t\t *\n\t\t * Purely a display transform: the authored `layout` prop is never\n\t\t * mutated (`onLayoutChange` merges geometry back into the FULL\n\t\t * authored array by id, so collapsed items survive round-trips), and\n\t\t * edit mode returns the authored layout untouched so hidden widgets\n\t\t * stay visible, placeable and configurable while editing.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tdisplayLayout() {\n\t\t\tif (this.gridEditable) {\n\t\t\t\treturn this.renderedLayout\n\t\t\t}\n\t\t\tconst items = this.renderedLayout || []\n\t\t\tconst visible = items.filter((item) => !this.isCollapsedWidget(item))\n\t\t\tif (visible.length === items.length) {\n\t\t\t\treturn items\n\t\t\t}\n\t\t\treturn this.compactDisplayLayout(visible)\n\t\t},\n\n\t\t/**\n\t\t * The responsive columns of the grid. Under the board look a phone gets\n\t\t * one column: below 640px the widgets stack in reading order (top to\n\t\t * bottom, then left to right) instead of squeezing six columns into\n\t\t * 150px. Without the board look the grid keeps its fixed columns.\n\t\t *\n\t\t * @return {object|null} GridStack `columnOpts`, or null.\n\t\t * @spec openspec/changes/screens-dashboard-phone/specs/dashboard-phone/spec.md#requirement-a-board-dashboard-stacks-on-a-phone\n\t\t */\n\t\tgridColumnOpts() {\n\t\t\tif (!this.isBoardLook) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn { columnMax: this.columns, breakpoints: [{ w: 640, c: 1 }], layout: 'list', breakpointForWindow: true }\n\t\t},\n\n\t\t/**\n\t\t * The layout this page renders: the user's arrangement when they have\n\t\t * one, the manifest otherwise.\n\t\t *\n\t\t * Falling back to the manifest is what makes every failure safe. A\n\t\t * record that has not loaded yet, an instance with no preference\n\t\t * route, a user who has never arranged the page: all three render the\n\t\t * page the admin shipped, which is the page that was there before.\n\t\t *\n\t\t * @return {Array<object>} The layout.\n\t\t */\n\t\trenderedLayout() {\n\t\t\tconst base = this.showsUserLayout ? this.userLayoutItems : this.layout\n\t\t\t// The KPI row is not part of the grid.\n\t\t\tif (Array.isArray(this.kpiRow) && this.kpiRow.length > 0 && Array.isArray(base)) {\n\t\t\t\treturn base.filter((item) => !this.kpiRow.includes(item.widgetId))\n\t\t\t}\n\n\t\t\treturn base\n\t\t},\n\n\t\t/**\n\t\t * Effective Refresh visibility for custom-slot widgets. An explicit\n\t\t * `widgetShowRefresh` prop wins; when unset (`null`), show Refresh\n\t\t * only if the app attached a `@widget-refresh` listener that will\n\t\t * handle it. (The page always attaches its own `@refresh` re-emitter\n\t\t * to each wrapper, so wrapper-level auto-detection can't be relied on\n\t\t * here — we resolve it at the page instead.)\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\teffectiveWidgetShowRefresh() {\n\t\t\tif (this.widgetShowRefresh !== null) {\n\t\t\t\treturn this.widgetShowRefresh\n\t\t\t}\n\t\t\t// `$.vnode.props`, not `$attrs`: a declared emit is stripped out of\n\t\t\t// `$attrs`. And the key is `onWidgetRefresh` — Vue's compiler\n\t\t\t// camelizes every `v-on` argument, so the hyphenated\n\t\t\t// `$attrs['onWidget-refresh']` this used to read was `undefined`\n\t\t\t// unconditionally and the auto-detect never once fired.\n\t\t\treturn Boolean(this.$.vnode.props?.onWidgetRefresh)\n\t\t},\n\n\t\t/**\n\t\t * Stable id for the page-level Actions menu. Prefers the explicit\n\t\t * `pageId` prop; falls back to a slugified `title`, then\n\t\t * `'dashboard'`.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedPageId() {\n\t\t\tif (this.pageId) {\n\t\t\t\treturn this.pageId\n\t\t\t}\n\t\t\tconst slug = (this.title || '').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '')\n\t\t\treturn slug || 'dashboard'\n\t\t},\n\n\t\t/**\n\t\t * Whether the caller supplied an `action-items` slot — forwarded\n\t\t * conditionally so the shared CnActionsMenu doesn't treat an\n\t\t * always-present pass-through template as content.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\thasActionItemsSlot() {\n\t\t\treturn Boolean(this.$slots['action-items']) || Boolean(this.$slots && this.$slots['action-items'])\n\t\t},\n\n\t\t/**\n\t\t * True when the date-range header should render. `false`,\n\t\t * `null`, and `{ enabled: false }` all collapse to `false`.\n\t\t */\n\t\tdateRangeEnabled() {\n\t\t\treturn !!(this.dateRange && this.dateRange.enabled === true)\n\t\t},\n\n\t\t/**\n\t\t * True when the header date-range picker should render. The\n\t\t * range feature must be enabled AND `showHeaderPicker` must not\n\t\t * be explicitly false. Defaults to showing the header (backwards\n\t\t * compatible) — consumers that drive the range entirely through\n\t\t * per-widget chart chips set `dateRange.showHeaderPicker: false`\n\t\t * to drop the redundant header control.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tshowHeaderDateRange() {\n\t\t\treturn this.dateRangeEnabled && this.dateRange.showHeaderPicker !== false\n\t\t},\n\n\t\t/**\n\t\t * Whether the segmented period group sits at the end of the\n\t\t * description line (`dateRange.placement: \"description\"`) instead of\n\t\t * in a row of its own. Only for the segmented control without a\n\t\t * custom range, whose from/to popover keeps the row of its own.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/page-header-breadcrumb/specs/page-header/spec.md#requirement-a-dashboard-can-show-its-period-on-the-description-line\n\t\t */\n\t\tdatePeriodInDescription() {\n\t\t\treturn this.showHeaderDateRange && this.dateRangeControl === 'segmented'\n\t\t\t\t&& this.dateRange.placement === 'description' && !this.hasCustomPreset\n\t\t},\n\n\t\t/**\n\t\t * The page filters drawn as a segmented group on the description\n\t\t * line (`control: \"segmented\"`, `placement: \"description\"`).\n\t\t * Without a header row they fall back to the filter row.\n\t\t *\n\t\t * @spec openspec/changes/dashboard-board-termijnen/specs/dashboard-page/spec.md#requirement-a-page-filter-as-a-segmented-group-on-the-description-line\n\t\t * @return {Array<object>}\n\t\t */\n\t\tdescriptionPageFilters() {\n\t\t\tif (!this.showHeader) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn (this.pageFilters || []).filter((pf) => pf && pf.key && pf.control === 'segmented' && pf.placement === 'description')\n\t\t},\n\n\t\t/**\n\t\t * The page filters drawn in the filter row under the header: every\n\t\t * filter the description line does not draw.\n\t\t *\n\t\t * @spec openspec/changes/dashboard-board-termijnen/specs/dashboard-page/spec.md#requirement-a-page-filter-as-a-segmented-group-on-the-description-line\n\t\t * @return {Array<object>}\n\t\t */\n\t\trowPageFilters() {\n\t\t\tconst inDescription = [...this.descriptionPageFilters, ...this.descriptionSelectFilters]\n\t\t\t// `control: \"none\"` holds a value for the widgets and the\n\t\t\t// description and draws no control (DqDoorlooptijd's fixed period).\n\t\t\treturn (this.pageFilters || []).filter((pf) => pf && pf.key && pf.control !== 'none' && !inDescription.includes(pf))\n\t\t},\n\n\t\t/**\n\t\t * The select page filters drawn on the description line\n\t\t * (`placement: \"description\"`, any control but `segmented`), before\n\t\t * the period group: DqDoorlooptijd's \"alle zaaktypen\". Without a\n\t\t * header row they fall back to the filter row.\n\t\t *\n\t\t * @spec openspec/changes/dashboard-select-filter-in-description/specs/dashboard-select-filter-in-description/spec.md#requirement-a-select-page-filter-can-sit-on-the-description-line\n\t\t * @return {Array<object>}\n\t\t */\n\t\tdescriptionSelectFilters() {\n\t\t\tif (!this.showHeader) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn (this.pageFilters || []).filter((pf) => pf && pf.key && pf.control !== 'segmented' && pf.control !== 'none' && pf.placement === 'description')\n\t\t},\n\n\t\t/**\n\t\t * Every page filter the description line draws, in the order the\n\t\t * page declares them, selects and segmented groups alike.\n\t\t *\n\t\t * @spec openspec/changes/dashboard-description-filters-in-order/specs/dashboard-description-filters-in-order/spec.md#requirement-the-description-line-draws-its-page-filters-in-declared-order\n\t\t * @return {Array<object>}\n\t\t */\n\t\tdescriptionFilters() {\n\t\t\tconst drawn = [...this.descriptionPageFilters, ...this.descriptionSelectFilters]\n\t\t\treturn (this.pageFilters || []).filter((pf) => drawn.includes(pf))\n\t\t},\n\n\t\t/**\n\t\t * The edit button's label through the app's translate: a manifest's\n\t\t * `editLabel` (\"Edit layout\", DqDashboard) reads in the user's language.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tshownEditLabel() {\n\t\t\treturn this.effectiveTranslate(this.editLabel)\n\t\t},\n\n\t\t/**\n\t\t * The done button's label through the app's translate.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tshownDoneLabel() {\n\t\t\treturn this.effectiveTranslate(this.doneLabel)\n\t\t},\n\n\t\t/**\n\t\t * The preset list passed to the picker. Falls back to the\n\t\t * `DEFAULT_DATE_RANGE_PRESETS` constant when the consumer\n\t\t * doesn't supply one.\n\t\t */\n\t\teffectivePresets() {\n\t\t\tconst presets = Array.isArray(this.dateRange?.presets) && this.dateRange.presets.length > 0\n\t\t\t\t? this.dateRange.presets\n\t\t\t\t: DEFAULT_DATE_RANGE_PRESETS\n\t\t\t// Labels in the user's language (screens-dashboard-i18n): the app's\n\t\t\t// catalogue first, then the library's own for the default labels.\n\t\t\treturn presets.map((p) => ({ ...p, label: translatePresetLabel(p.label, this.effectiveTranslate) }))\n\t\t},\n\n\t\t/**\n\t\t * Which header date-range control to render. `'pills'` swaps the\n\t\t * select + two date inputs for a compact segmented pill row; any\n\t\t * other value (or none) keeps the default `CnDateRangePicker`.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tdateRangeControl() {\n\t\t\tconst control = this.dateRange?.control\n\t\t\treturn control === 'pills' || control === 'segmented' ? control : 'picker'\n\t\t},\n\n\t\t/**\n\t\t * Whether the app takes the board look (`cnLook` is `board`).\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-parity/specs/dashboard-page/spec.md#requirement-the-board-dashboard-header\n\t\t * @return {boolean}\n\t\t */\n\t\tisBoardLook() {\n\t\t\treturn normalizeLook(this.cnLook) === 'board'\n\t\t},\n\n\t\t/**\n\t\t * The options of the segmented period group: the presets, and the\n\t\t * custom range, when offered, as the last segment.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-parity/specs/dashboard-page/spec.md#requirement-the-period-as-a-segmented-group\n\t\t * @return {Array<{value: string, label: string}>}\n\t\t */\n\t\tsegmentedOptions() {\n\t\t\tconst options = this.pillPresets.map((p) => ({ value: p.id, label: p.label }))\n\t\t\tif (this.hasCustomPreset) {\n\t\t\t\toptions.push({ value: 'custom', label: this.customRangeLabel })\n\t\t\t}\n\t\t\treturn options\n\t\t},\n\n\t\t/**\n\t\t * The segment that is pressed: the current range's preset.\n\t\t *\n\t\t * @return {string|null}\n\t\t */\n\t\tsegmentedValue() {\n\t\t\treturn (this.currentRange && this.currentRange.preset) || null\n\t\t},\n\n\t\t/**\n\t\t * Accessible name of the period group.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tdatePeriodLabel() {\n\t\t\treturn t('nextcloud-vue', 'Period')\n\t\t},\n\n\t\t/**\n\t\t * The KPI row's widgets as layout-like items (`{ widgetId }`), in the\n\t\t * order `kpiRow` lists them.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-parity/specs/dashboard-page/spec.md#requirement-a-kpi-row-above-the-grid\n\t\t * @return {Array<{widgetId: string}>}\n\t\t */\n\t\tkpiRowItems() {\n\t\t\tconst ids = Array.isArray(this.kpiRow) ? this.kpiRow : []\n\t\t\tconst items = []\n\t\t\tfor (const id of ids) {\n\t\t\t\tif (this.getWidgetDef(id) || this.hasWidgetSlot(id)) {\n\t\t\t\t\t// A tile a page control hides surrenders its cell.\n\t\t\t\t\tif (!this.gridEditable && this.isHiddenByWorkspace(id)) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\titems.push({ widgetId: id })\n\t\t\t\t} else if (process.env.NODE_ENV !== 'production') {\n\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\tconsole.warn(`[CnDashboardPage] kpiRow names the widget \"${id}\", which is not defined; skipped.`)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn items\n\t\t},\n\n\t\t/**\n\t\t * Compact, always-present label for the per-widget date chip\n\t\t * (`layout[].dateChip`). Prefers the active preset's own label (e.g.\n\t\t * `7d` / `30d` / `All`) so a KPI card surfaces a tidy period token;\n\t\t * falls back to the concrete `from – to` span for a manual range, and\n\t\t * to a generic \"Date range\" when neither is known. NEVER empty, so the\n\t\t * chip stays clickable even on an unbounded (\"All\") range.\n\t\t *\n\t\t * @return {string} The chip label.\n\t\t */\n\t\tdashboardRangeChipLabel() {\n\t\t\tconst rng = this.currentRange || this.dashboardDateRange\n\t\t\tif (rng && rng.preset && rng.preset !== 'custom') {\n\t\t\t\tconst preset = this.effectivePresets.find((p) => p && p.id === rng.preset)\n\t\t\t\tif (preset && preset.label) {\n\t\t\t\t\treturn preset.label\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn this.formatDashboardDateRange() || t('nextcloud-vue', 'Date range')\n\t\t},\n\n\t\t/**\n\t\t * Preset list rendered as pills — `effectivePresets` minus the\n\t\t * manual `custom` entry (which surfaces as a separate de-emphasised\n\t\t * popover pill instead of a bare toggle).\n\t\t *\n\t\t * @return {Array<{ id: string, label: string }>}\n\t\t */\n\t\tpillPresets() {\n\t\t\treturn this.effectivePresets.filter((p) => p && p.id !== 'custom')\n\t\t},\n\n\t\t/**\n\t\t * Whether a `custom` preset exists in the list — drives the optional\n\t\t * \"Custom range\" popover pill in pills mode.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\thasCustomPreset() {\n\t\t\treturn this.effectivePresets.some((p) => p && p.id === 'custom')\n\t\t},\n\n\t\t/**\n\t\t * Accessible label for the pill toggle group.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tdatePillsGroupLabel() {\n\t\t\treturn t('nextcloud-vue', 'Date range')\n\t\t},\n\n\t\t/**\n\t\t * Label for the custom-range pill: the `custom` preset's own label\n\t\t * when set, else a sensible default.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tcustomRangeLabel() {\n\t\t\tconst c = this.effectivePresets.find((p) => p && p.id === 'custom')\n\t\t\treturn (c && c.label) || t('nextcloud-vue', 'Custom range')\n\t\t},\n\n\t\t/**\n\t\t * True when the dashboard has either classic grid widgets (via\n\t\t * `layout`) or declarative `content[]` widget-ref items to render.\n\t\t */\n\t\thasWidgets() {\n\t\t\t// Depend on the (always-reactive) edit flag so this computed\n\t\t\t// re-evaluates when in-app edit mode flips. Manifest arrays are raw\n\t\t\t// until useManifestEditor.enter() observes them in place — a cache\n\t\t\t// built pre-edit has no reactive deps and would stay frozen forever,\n\t\t\t// keeping the empty state on screen after the first Add widget.\n\t\t\t// Re-evaluating post-enter re-subscribes against the reactive graph.\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unused-expressions -- the read IS the effect: it registers the reactive dependency.\n\t\t\tthis.gridEditable\n\t\t\treturn this.layout.length > 0 || this.widgetRefItems.length > 0\n\t\t},\n\n\t\t/**\n\t\t * Whether the grid sections render at all: not while loading, not\n\t\t * while the widget predicates settle, not on the empty page and not\n\t\t * on a widget-ref content page.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-page-declares-views-that-each-hold-a-widget-grid\n\t\t */\n\t\tgridSectionsShown() {\n\t\t\tif (this.loading || (!this.widgetConditionsSettled && !this.gridEditable)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif (!this.hasWidgets && !this.hasBodyWidgets && !this.hasViews) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn this.widgetRefItems.length === 0\n\t\t},\n\n\t\t/**\n\t\t * The chosen view's layout as the grid draws it: in live mode the\n\t\t * widgets that would draw nothing leave and the rest close up, as\n\t\t * for the page's own layout.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t * @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-view-with-nothing-to-draw-says-so\n\t\t */\n\t\tviewDisplayLayout() {\n\t\t\tconst items = this.activeViewLayout\n\t\t\tif (this.gridEditable) {\n\t\t\t\treturn items\n\t\t\t}\n\t\t\tconst visible = items.filter((item) => !this.isCollapsedWidget(item))\n\t\t\treturn visible.length === items.length ? items : this.compactDisplayLayout(visible)\n\t\t},\n\n\t\t/**\n\t\t * Whether the chosen view has nothing to draw.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-view-with-nothing-to-draw-says-so\n\t\t */\n\t\tviewIsEmpty() {\n\t\t\treturn this.hasViews && this.viewDisplayLayout.length === 0\n\t\t},\n\n\t\t/**\n\t\t * The grids this page draws. Without views: the page's own layout,\n\t\t * as it always was. With views: the page's own layout when it has\n\t\t * items, then the chosen view's layout in the region the switch\n\t\t * controls (left out when the view is empty; the empty state takes\n\t\t * the region then).\n\t\t *\n\t\t * @return {Array<{key: string, view: boolean, layout: Array<object>, editable: boolean, attrs: object}>}\n\t\t * @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-page-declares-views-that-each-hold-a-widget-grid\n\t\t */\n\t\tgridSections() {\n\t\t\tif (!this.gridSectionsShown) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst page = { key: 'page', view: false, layout: this.displayLayout, editable: this.gridEditable, sideColumn: this.gridSideColumn, attrs: {} }\n\t\t\tif (!this.hasViews) {\n\t\t\t\treturn [page]\n\t\t\t}\n\t\t\tconst sections = this.displayLayout.length > 0 ? [page] : []\n\t\t\tif (!this.viewIsEmpty) {\n\t\t\t\tsections.push({\n\t\t\t\t\tkey: `view-${this.activeViewId}`,\n\t\t\t\t\tview: true,\n\t\t\t\t\tlayout: this.viewDisplayLayout,\n\t\t\t\t\t// With `userLayout` the user arranges the view too; the\n\t\t\t\t\t// arrangement is kept per view (pageViews mixin).\n\t\t\t\t\teditable: this.gridEditable,\n\t\t\t\t\tsideColumn: this.activeView.gridSideColumn || null,\n\t\t\t\t\tattrs: {\n\t\t\t\t\t\tid: this.viewRegionId,\n\t\t\t\t\t\trole: 'region',\n\t\t\t\t\t\t'aria-label': this.activeView.label,\n\t\t\t\t\t\tclass: 'cn-page-view-region',\n\t\t\t\t\t\t'data-testid': 'cn-dashboard-page-view-region',\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn sections\n\t\t},\n\n\t\t/**\n\t\t * The widget settings object handed to CnWidgetStyleEditorModal,\n\t\t * built from the widget definition currently being configured\n\t\t * (`configWidgetId`). Carries the chrome fields the editor reads /\n\t\t * mutates (`title`, `styleConfig`, `showTitle`, `customTitle`,\n\t\t * `customIcon`, `content`) plus the widget `id`. Returns an empty\n\t\t * shell when nothing is selected so the modal's `required` widget\n\t\t * prop never sees null.\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\tconfigWidget() {\n\t\t\tconst def = this.getWidgetDef(this.configWidgetId) || {}\n\t\t\t// Bridge legacy data-driven widgets (chart / stats-block / table that\n\t\t\t// carry top-level `props` + `dataSource` instead of `content`) into a\n\t\t\t// `content` shape so their config form pre-fills. Once saved, the\n\t\t\t// content-aware getters take over.\n\t\t\tlet content = def.content || {}\n\t\t\tif ((!content || Object.keys(content).length === 0) && (def.props || def.dataSource)) {\n\t\t\t\tcontent = {}\n\t\t\t\tif (def.title) {\n\t\t\t\t\tcontent.title = def.title\n\t\t\t\t}\n\t\t\t\tif (def.props) {\n\t\t\t\t\tcontent.props = def.props\n\t\t\t\t\tif (def.props.chartKind) {\n\t\t\t\t\t\tcontent.chartKind = def.props.chartKind\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (def.dataSource) {\n\t\t\t\t\tcontent.dataSource = def.dataSource\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tid: def.id || this.configWidgetId,\n\t\t\t\ttype: def.type || '',\n\t\t\t\ttitle: def.title || '',\n\t\t\t\tstyleConfig: def.styleConfig || {},\n\t\t\t\t// Left raw (possibly undefined) so the modal can apply the\n\t\t\t\t// card-aware default rather than being handed a coerced `true`.\n\t\t\t\tshowTitle: def.showTitle,\n\t\t\t\tcustomTitle: def.customTitle || '',\n\t\t\t\tcustomIcon: def.customIcon || '',\n\t\t\t\tcontent,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Filtered list of `widget-ref` items from `content[]`.\n\t\t * Unknown `type` values are logged and excluded so future\n\t\t * content item types can be added without breaking existing\n\t\t * dashboards.\n\t\t *\n\t\t * @return {Array<{ type: 'widget-ref', ref: string }>}\n\t\t */\n\t\twidgetRefItems() {\n\t\t\tconst out = []\n\t\t\tfor (const item of this.content) {\n\t\t\t\tif (!item || typeof item !== 'object') {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (item.type === 'widget-ref') {\n\t\t\t\t\tout.push(item)\n\t\t\t\t} else {\n\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\tconsole.warn(`[CnDashboardPage] Unknown content item type \"${item.type}\" — only \"widget-ref\" is supported. Item will be skipped.`)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Whether any in-body sections are configured (drives the three\n\t\t * placement mounts of CnBodySections).\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\thasBodyWidgets() {\n\t\t\treturn Array.isArray(this.bodyWidgets) && this.bodyWidgets.length > 0\n\t\t},\n\n\t\t/**\n\t\t * Sections that land at the END placement: those with no `placement` (the\n\t\t * default) or an explicit `placement: \"end\"`. The two named placement\n\t\t * mounts (`before-grid` / `after-grid`) filter by their own value, so this\n\t\t * computed excludes them to avoid double-rendering.\n\t\t *\n\t\t * @return {Array}\n\t\t */\n\t\tendPlacementSections() {\n\t\t\tconst named = ['before-grid', 'after-grid']\n\t\t\treturn (Array.isArray(this.bodyWidgets) ? this.bodyWidgets : [])\n\t\t\t\t.filter((s) => !s || !s.placement || !named.includes(s.placement))\n\t\t},\n\n\t\t/**\n\t\t * Page context forwarded to CnBodySections for token resolution\n\t\t * (`@workspace.<key>` / `@page.<key>` / `@config.<key>` + time tokens) AND\n\t\t * provided on `cnSectionContext` for host section components that inject.\n\t\t * The optional object scoping (`objectId` / `register` / `schema`) is read\n\t\t * from `integrationContext` so an object-scoped dashboard can resolve\n\t\t * `@objectId` / `@object.<field>` too.\n\t\t *\n\t\t * @return {{objectId: (string|null), register: string, schema: string, workspace: object, config: object}}\n\t\t */\n\t\tsectionContext() {\n\t\t\tconst ic = this.integrationContext || {}\n\t\t\treturn {\n\t\t\t\tobjectId: (ic.objectId !== undefined && ic.objectId !== null) ? String(ic.objectId) : null,\n\t\t\t\tregister: ic.register || '',\n\t\t\t\tschema: ic.schema || '',\n\t\t\t\tworkspace: this.workspaceContext,\n\t\t\t\tconfig: this.appConfigRef,\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\t/**\n\t\t * Re-evaluate the widget predicates when the defs change — the\n\t\t * in-app editor (ADR-041) mutates widget defs in place and \"Add\n\t\t * widget\" pushes into the same array, so a deep watch is the only\n\t\t * signal that a widget's `visibleWhen` was added or edited.\n\t\t */\n\t\twidgets: {\n\t\t\tdeep: true,\n\t\t\thandler() {\n\t\t\t\tthis.evaluateWidgetConditions()\n\t\t\t},\n\t\t},\n\n\t\t/** A view's widgets carry predicates too. */\n\t\tviews: {\n\t\t\tdeep: true,\n\t\t\thandler() {\n\t\t\t\tthis.evaluateWidgetConditions()\n\t\t\t},\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.pushAiContext()\n\t\tthis.initDateRange()\n\t\tthis.initPageFilters()\n\t\tthis.loadPageFilterOptions()\n\t\tthis.evaluateWidgetConditions()\n\t\tthis.loadUserLayout()\n\t},\n\n\tbeforeUnmount() {\n\t\tif (this.cnAiContext) {\n\t\t\tthis.cnAiContext.pageKind = 'custom'\n\t\t\tthis.cnAiContext.registerSlug = undefined\n\t\t\tthis.cnAiContext.schemaSlug = undefined\n\t\t}\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Re-emit the page-level CnActionsMenu `@refresh` to the host,\n\t\t * passing the synthetic event through so a host listener can\n\t\t * `preventDefault()` the built-in default (event-bus emit on\n\t\t * `cn:page:refresh`). Distinct from `@widget-refresh`, which the\n\t\t * per-widget menus emit.\n\t\t *\n\t\t * @param {{ widgetId: string, title: string }} payload Action payload.\n\t\t * @param {{ defaultPrevented: boolean, preventDefault: () => void }} ev Synthetic event.\n\t\t * @return {void}\n\t\t */\n\t\tonActionsRefresh(payload, ev) {\n\t\t\t/**\n\t\t\t * @event refresh User clicked Refresh in the page-level overflow\n\t\t\t * Actions menu. Payload: `{ widgetId, title }`. Handlers may\n\t\t\t * call the second arg's `preventDefault()` to suppress the\n\t\t\t * built-in default (event-bus emit on `cn:page:refresh`).\n\t\t\t * @type {{ widgetId: string, title: string }}\n\t\t\t */\n\t\t\tthis.$emit('refresh', payload, ev)\n\t\t},\n\n\t\t/**\n\t\t * Re-emit the page-level CnActionsMenu `@request-feature` to the\n\t\t * host. Distinct from `@widget-request-feature`.\n\t\t *\n\t\t * @param {{ widgetId: string, title: string }} payload Action payload.\n\t\t * @param {{ defaultPrevented: boolean, preventDefault: () => void }} ev Synthetic event.\n\t\t * @return {void}\n\t\t */\n\t\tonActionsRequestFeature(payload, ev) {\n\t\t\t/**\n\t\t\t * @event request-feature User clicked Request a feature in the\n\t\t\t * page-level overflow Actions menu. Payload: `{ widgetId,\n\t\t\t * title }`. Handlers may call the second arg's\n\t\t\t * `preventDefault()` to suppress the built-in default\n\t\t\t * (opening the forge's feature-request issue form).\n\t\t\t * @type {{ widgetId: string, title: string }}\n\t\t\t */\n\t\t\tthis.$emit('request-feature', payload, ev)\n\t\t},\n\n\t\t/**\n\t\t * Forward a widget's `@refresh` from CnWidgetWrapper to the\n\t\t * dashboard host. The host wires this to its data-fetching layer\n\t\t * (e.g. re-fetching the GraphQL aggregate for a chart). Payload\n\t\t * is the layout item so consumers can route by widget id.\n\t\t *\n\t\t * @param {object} item Layout item descriptor.\n\t\t * @return {void}\n\t\t */\n\t\tonWidgetRefresh(item) {\n\t\t\t/**\n\t\t\t * @event widget-refresh User clicked Refresh in a widget's\n\t\t\t * overflow action menu. Payload: the layout item descriptor.\n\t\t\t */\n\t\t\tthis.$emit('widget-refresh', item)\n\t\t},\n\n\t\t/**\n\t\t * Forward a widget's `@request-feature` from CnWidgetWrapper to\n\t\t * the dashboard host. The host decides where to send the user\n\t\t * (typically an issue tracker).\n\t\t *\n\t\t * @param {object} item Layout item descriptor.\n\t\t * @return {void}\n\t\t */\n\t\tonWidgetRequestFeature(item) {\n\t\t\t/**\n\t\t\t * @event widget-request-feature User clicked Request a\n\t\t\t * feature in a widget's overflow action menu. Payload: the\n\t\t\t * layout item descriptor.\n\t\t\t */\n\t\t\tthis.$emit('widget-request-feature', item)\n\t\t},\n\n\t\t/**\n\t\t * Format a chart widget's bucket date range as a short readable\n\t\t * chip, rendered inside CnWidgetWrapper's `#title-meta` slot.\n\t\t * Returns null when the bucket has neither a `staticRange` nor\n\t\t * resolved `from`/`to` via the reactive dashboard `dateRange`\n\t\t * provide (in which case the chip simply doesn't render).\n\t\t *\n\t\t * @param {object} item Layout item descriptor with chart shorthand.\n\t\t * @return {string|null} `\"2026-05-18 → 2026-05-25\"` or null.\n\t\t */\n\t\tformatChartDateRange(item) {\n\t\t\tconst ds = this.getWidgetDataSource(item) || {}\n\t\t\tconst bucket = ds.bucket || {}\n\t\t\t// 1. Bucket-level staticRange wins (explicit per-widget freeze).\n\t\t\tconst sr = bucket.staticRange || {}\n\t\t\tlet from = sr.from || null\n\t\t\tlet to = sr.to || null\n\t\t\t// 2. Fall back to the dashboard-level reactive dateRange when\n\t\t\t// the bucket uses fromVar/toVar shorthand. Vue 2.7's setup\n\t\t\t// auto-unwraps refs when accessed via `this`, so\n\t\t\t// `this.dashboardDateRange` IS the current value (not the\n\t\t\t// ref). Assignments in setRange() / initial-range\n\t\t\t// methods write through to the ref's `.value` automatically.\n\t\t\tif ((!from || !to) && this.dashboardDateRange) {\n\t\t\t\tconst rng = this.dashboardDateRange\n\t\t\t\tif (bucket.fromVar && rng[bucket.fromVar]) {\n\t\t\t\t\tfrom = from || rng[bucket.fromVar]\n\t\t\t\t}\n\t\t\t\tif (bucket.toVar && rng[bucket.toVar]) {\n\t\t\t\t\tto = to || rng[bucket.toVar]\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn this.formatRangeLabel(from, to)\n\t\t},\n\n\t\t/**\n\t\t * Format the SHARED dashboard date range as a compact chip label.\n\t\t * Used by the opt-in custom-widget date chip (`layout[].dateChip`),\n\t\t * which has no per-widget dataSource to derive a window from —\n\t\t * the chip always surfaces the dashboard-level range.\n\t\t *\n\t\t * @return {string|null} `\"18 May – 25 May\"` or null when no range is set.\n\t\t */\n\t\tformatDashboardDateRange() {\n\t\t\tconst rng = this.dashboardDateRange\n\t\t\tif (!rng) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.formatRangeLabel(rng.from || null, rng.to || null)\n\t\t},\n\n\t\t/**\n\t\t * Friendly compact label: \"18 May – 25 May\" / \"18 Dec 2025 – 2 Jan 2026\".\n\t\t * The year is only shown when a bound falls outside the current\n\t\t * year, keeping the common same-year case short while staying\n\t\t * unambiguous for older / cross-year windows.\n\t\t *\n\t\t * @param {string|null} from ISO-8601 lower bound (or null).\n\t\t * @param {string|null} to ISO-8601 upper bound (or null).\n\t\t * @return {string|null} Formatted label, or null when both bounds are empty.\n\t\t */\n\t\t/**\n\t\t * A page filter's active choice read as a period, for `{filter.<key>}`\n\t\t * in the description: the declared (or generated) option the workspace\n\t\t * holds, its label through the host translate.\n\t\t *\n\t\t * @param {string} key The page filter's key.\n\t\t * @return {string} The period, '' when the filter or its choice is missing.\n\t\t * @spec openspec/changes/description-period-from-filter/specs/description-period-from-filter/spec.md#requirement-a-dashboard-description-reads-the-active-period-of-a-page-filter\n\t\t */\n\t\tpageFilterPeriodText(key) {\n\t\t\tconst pf = (this.pageFilters || []).find((filter) => filter && filter.key === key)\n\t\t\tif (!pf) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst options = Array.isArray(pf.options) ? pf.options : (generatedPageFilterOptions(pf) || this.pageFilterFetched[pf.key] || [])\n\t\t\tconst option = options.find((o) => o && o.value === this.workspaceContext[pf.key])\n\t\t\tif (!option) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn periodText({ ...option, label: option.label ? this.effectiveTranslate(option.label) : String(option.value) }, new Date(), userLocale())\n\t\t},\n\n\t\t/**\n\t\t * The dashboard's active date range read as a period, for\n\t\t * `{dateRange}` in the description: a calendar preset as its month,\n\t\t * quarter or year, another preset as its translated label, a custom\n\t\t * range as its dates.\n\t\t *\n\t\t * @return {string} The period, '' without an active range.\n\t\t * @spec openspec/changes/description-period-from-date-range/specs/description-period-from-date-range/spec.md#requirement-a-dashboard-description-reads-the-active-date-range-as-a-period\n\t\t */\n\t\tdateRangePeriodText() {\n\t\t\tconst rng = this.currentRange || this.dashboardDateRange\n\t\t\tif (!this.dateRangeEnabled || !rng) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst preset = rng.preset && rng.preset !== 'custom'\n\t\t\t\t? this.effectivePresets.find((p) => p && p.id === rng.preset)\n\t\t\t\t: null\n\t\t\tconst label = preset ? translatePresetLabel(preset.label, this.effectiveTranslate) : ''\n\t\t\treturn rangePeriodText(rng, preset ? { ...preset, label } : null, userLocale())\n\t\t\t\t|| this.formatRangeLabel(rng.from || null, rng.to || null)\n\t\t\t\t|| ''\n\t\t},\n\n\t\tformatRangeLabel(from, to) {\n\t\t\tif (!from && !to) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst toDate = (v) => {\n\t\t\t\tif (typeof v !== 'string' || v.length < 10) {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\tconst d = new Date(`${v.slice(0, 10)}T00:00:00`)\n\t\t\t\treturn Number.isNaN(d.getTime()) ? null : d\n\t\t\t}\n\t\t\tconst fromDate = toDate(from)\n\t\t\tconst toDateValue = toDate(to)\n\t\t\tconst thisYear = new Date().getFullYear()\n\t\t\tconst needsYear = [fromDate, toDateValue].some((d) => d && d.getFullYear() !== thisYear)\n\t\t\tconst fmt = (d) => {\n\t\t\t\tif (!d) {\n\t\t\t\t\treturn ''\n\t\t\t\t}\n\t\t\t\treturn d.toLocaleDateString(userLocale(), {\n\t\t\t\t\tday: 'numeric',\n\t\t\t\t\tmonth: 'short',\n\t\t\t\t\t...(needsYear ? { year: 'numeric' } : {}),\n\t\t\t\t})\n\t\t\t}\n\t\t\tconst left = fmt(fromDate)\n\t\t\tconst right = fmt(toDateValue)\n\t\t\tif (left && right) {\n\t\t\t\treturn `${left} – ${right}`\n\t\t\t}\n\t\t\treturn (left || right) || null\n\t\t},\n\n\t\t/**\n\t\t * Handle a preset pick from the in-chip date-range popover. The\n\t\t * popover renders the same preset list the global picker uses\n\t\t * (effectivePresets). On click we resolve the preset to a from/to\n\t\t * window, build a `{ from, to, preset }` value, and forward to the\n\t\t * existing `onDateRangeChange` — same handler the top picker uses.\n\t\t * Effect: the chip is a per-chart shortcut to the dashboard-wide\n\t\t * range, not a per-widget override.\n\t\t *\n\t\t * @param {{ label: string, value: string }} preset Preset descriptor.\n\t\t * @param {object} _item Layout item (unused — included so the\n\t\t * binding shape matches the template's `@click` signature).\n\t\t * @return {void}\n\t\t */\n\t\tonChipPresetPick(preset, _item) {\n\t\t\tif (!preset || !preset.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (preset.id === 'custom') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.isClearPreset(preset)) {\n\t\t\t\tthis.onDateRangeChange({ from: '', to: '', preset: preset.id })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst win = resolvePresetWindow(preset.id, this.effectivePresets)\n\t\t\tif (!win) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.onDateRangeChange({ ...win, preset: preset.id })\n\t\t},\n\n\t\t/**\n\t\t * Handle a press on a segment of the period group\n\t\t * (`dateRange.control: \"segmented\"`): the same range change as a pill.\n\t\t * The custom segment keeps the current window and opens the from/to\n\t\t * popover.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-parity/specs/dashboard-page/spec.md#requirement-the-period-as-a-segmented-group\n\t\t * @param {string} value The preset id of the pressed segment.\n\t\t * @return {void}\n\t\t */\n\t\tonSegmentPick(value) {\n\t\t\tif (value === 'custom') {\n\t\t\t\tthis.onDateRangeChange({\n\t\t\t\t\tfrom: this.currentRange?.from || '',\n\t\t\t\t\tto: this.currentRange?.to || '',\n\t\t\t\t\tpreset: 'custom',\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst preset = this.pillPresets.find((p) => p.id === value)\n\t\t\tif (preset) {\n\t\t\t\tthis.onPillPick(preset)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Props shared by the wrapper of a KPI row tile.\n\t\t *\n\t\t * @param {{widgetId: string}} item The row item.\n\t\t * @return {object}\n\t\t */\n\t\tkpiWrapperProps(item) {\n\t\t\treturn {\n\t\t\t\twidgetId: item.widgetId,\n\t\t\t\ttitle: this.getWidgetTitle(item),\n\t\t\t\teyebrow: this.getWidgetEyebrow(item),\n\t\t\t\ttitleTone: this.getWidgetTitleTone(item),\n\t\t\t\tsubtitle: this.getWidgetSubtitle(item),\n\t\t\t\tshowTitle: this.widgetShowTitle(item),\n\t\t\t\tshowActions: this.widgetShowActions(item),\n\t\t\t\tshowRefresh: this.getWidgetShowRefresh(item),\n\t\t\t\tborderless: this.widgetBorderless(item),\n\t\t\t\tflush: true,\n\t\t\t\tclass: { 'cn-dashboard-page__card-fit': this.isCardWidget(item) },\n\t\t\t\tbuttons: this.getWidgetButtons(item),\n\t\t\t\theaderLink: this.getWidgetHeaderLink(item),\n\t\t\t\tstyleConfig: item.styleConfig || {},\n\t\t\t\tdocumentationUrl: this.getWidgetDocumentationUrl(item),\n\t\t\t\tdocsAnchor: this.getWidgetDocsAnchor(item),\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Handle a header date-range pill click (pills mode). Resolves the\n\t\t * preset to a from/to window and forwards to `onDateRangeChange` —\n\t\t * the same handler the select picker uses — so the active range\n\t\t * drives every widget identically. Re-clicking the active pill\n\t\t * re-resolves (cheap no-op for fixed presets).\n\t\t *\n\t\t * @param {{ id: string, label: string }} preset The picked preset.\n\t\t * @return {void}\n\t\t */\n\t\tonPillPick(preset) {\n\t\t\tif (!preset || !preset.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// An \"All\" / clear preset removes the window (empty from/to) so\n\t\t\t// optional date tokens drop and widgets show the unfiltered count.\n\t\t\tif (this.isClearPreset(preset)) {\n\t\t\t\tthis.onDateRangeChange({ from: '', to: '', preset: preset.id })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst win = resolvePresetWindow(preset.id, this.effectivePresets)\n\t\t\tif (!win) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.onDateRangeChange({ ...win, preset: preset.id })\n\t\t},\n\n\t\t/**\n\t\t * Handle a manual datetime-input change inside the in-chip popover.\n\t\t * The `<input type=\"datetime-local\">` emits a local \"YYYY-MM-DDTHH:mm\"\n\t\t * string (or a DOM Event in some NcActionInput versions); we\n\t\t * normalise to an ISO-8601 UTC string for storage and forward\n\t\t * `{ from, to, preset: 'custom' }` to `onDateRangeChange`.\n\t\t *\n\t\t * @param {'from'|'to'} field The half being edited.\n\t\t * @param {Date|string|Event} value Date from the picker, local\n\t\t * datetime string, or a raw input Event.\n\t\t * @return {void}\n\t\t */\n\t\tonChipDateInput(field, value) {\n\t\t\tconst next = {\n\t\t\t\tfrom: this.currentRange?.from || '',\n\t\t\t\tto: this.currentRange?.to || '',\n\t\t\t\tpreset: 'custom',\n\t\t\t}\n\t\t\t// NcActionInput's date types are backed by a date picker that\n\t\t\t// emits a Date — NOT a string and NOT an input Event. Handle the\n\t\t\t// Date first; without it every manual edit fell through to '' and\n\t\t\t// silently CLEARED the half being edited.\n\t\t\tif (value instanceof Date) {\n\t\t\t\tnext[field] = Number.isNaN(value.getTime()) ? '' : value.toISOString()\n\t\t\t} else {\n\t\t\t\tconst raw = typeof value === 'string'\n\t\t\t\t\t? value\n\t\t\t\t\t: (value && value.target ? value.target.value : '')\n\t\t\t\tnext[field] = raw ? this.localDateTimeInputToIso(raw) : ''\n\t\t\t}\n\t\t\tthis.onDateRangeChange(next)\n\t\t},\n\n\t\t/**\n\t\t * Coerce a stored ISO-8601 string into the `Date` that\n\t\t * `NcActionInput`'s date types require — they are backed by a date\n\t\t * picker whose model is typed `Date` and which renders EMPTY for a\n\t\t * string. Returns null for missing / unparseable input.\n\t\t *\n\t\t * @param {string} iso ISO-8601 timestamp.\n\t\t * @return {Date|null} Date for the picker model, or null.\n\t\t */\n\t\ttoPickerDate(iso) {\n\t\t\tif (!iso) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst d = new Date(iso)\n\t\t\treturn Number.isNaN(d.getTime()) ? null : d\n\t\t},\n\n\t\t/**\n\t\t * Parse a local \"YYYY-MM-DDTHH:mm\" datetime-local value into an\n\t\t * ISO-8601 UTC string. `new Date(local)` interprets the bare\n\t\t * string in the runtime's local timezone, matching what the\n\t\t * native input shows the user.\n\t\t *\n\t\t * @param {string} local Local datetime-local input value.\n\t\t * @return {string} ISO-8601 UTC string, or empty when unparseable.\n\t\t */\n\t\tlocalDateTimeInputToIso(local) {\n\t\t\tconst d = new Date(local)\n\t\t\treturn Number.isNaN(d.getTime()) ? '' : d.toISOString()\n\t\t},\n\n\t\t/**\n\t\t * Push pageKind = 'dashboard' into the reactive cnAiContext.\n\t\t * registerSlug/schemaSlug are populated when the dashboard page\n\t\t * receives those props (some dashboards are schema-specific).\n\t\t */\n\t\tpushAiContext() {\n\t\t\tif (!this.cnAiContext) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.cnAiContext.pageKind = 'dashboard'\n\t\t\t// Dashboard pages don't universally carry register/schema props —\n\t\t\t// leave them undefined (they'll be whatever the previous page set,\n\t\t\t// but we reset to undefined here for a clean context).\n\t\t\tthis.cnAiContext.registerSlug = undefined\n\t\t\tthis.cnAiContext.schemaSlug = undefined\n\t\t\tthis.cnAiContext.objectUuid = undefined\n\t\t},\n\n\t\t/**\n\t\t * Resolve the initial date-range value when the feature is on.\n\t\t * Priority: explicit `dateRange.default` → persisted\n\t\t * `localStorage` entry (when `persistKey`) → `last-7` preset.\n\t\t * No-ops when the feature is disabled. Emits\n\t\t * `date-range-change` if a non-null value was resolved so\n\t\t * consumers can wire their initial fetch to the same event.\n\t\t */\n\t\tinitDateRange() {\n\t\t\tif (!this.dateRangeEnabled) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlet initial = null\n\t\t\t// 1. Persisted state (when a key is set).\n\t\t\tif (this.dateRange?.persistKey) {\n\t\t\t\tinitial = this.readPersisted(this.dateRange.persistKey)\n\t\t\t}\n\t\t\t// 2. Explicit consumer-supplied default. A default may be given\n\t\t\t// as an explicit { from, to } window OR as just a preset id\n\t\t\t// (e.g. `default: { preset: 'last-7' }`) — in the latter case\n\t\t\t// we resolve the window from the preset so the manifest can\n\t\t\t// declare a starting range by name without hard-coding dates.\n\t\t\tif (!initial && this.dateRange?.default) {\n\t\t\t\tconst def = this.dateRange.default\n\t\t\t\tif ((!def.from || !def.to) && def.preset && def.preset !== 'custom') {\n\t\t\t\t\tconst win = resolvePresetWindow(def.preset, this.effectivePresets)\n\t\t\t\t\tif (win) {\n\t\t\t\t\t\tinitial = { from: win.from, to: win.to, preset: def.preset }\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!initial) {\n\t\t\t\t\tinitial = {\n\t\t\t\t\t\tfrom: def.from || null,\n\t\t\t\t\t\tto: def.to || null,\n\t\t\t\t\t\tpreset: def.preset || 'custom',\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// 3. Last-7 fallback.\n\t\t\tif (!initial) {\n\t\t\t\tconst win = resolvePresetWindow('last-7', this.effectivePresets)\n\t\t\t\tif (win) {\n\t\t\t\t\tinitial = { from: win.from, to: win.to, preset: 'last-7' }\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (initial) {\n\t\t\t\tthis.currentRange = initial\n\t\t\t\tthis.dashboardDateRange = initial\n\t\t\t\tthis.syncRangeToWorkspace(initial)\n\t\t\t\t/**\n\t\t\t\t * @event date-range-change Fired whenever the dashboard's effective date range changes (initial resolve, picker change, or persisted-range restore). Payload: `{ from, to, preset }`.\n\t\t\t\t */\n\t\t\t\tthis.$emit('date-range-change', { ...initial })\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Handle a picker change. Persists (when `persistKey` is\n\t\t * set), updates the provided ref, emits `date-range-change`.\n\t\t *\n\t\t * @param {{ from: string, to: string, preset: string }} value\n\t\t * The new range, emitted by `CnDateRangePicker`.\n\t\t */\n\t\tonDateRangeChange(value) {\n\t\t\tthis.currentRange = value\n\t\t\tthis.dashboardDateRange = value\n\t\t\tthis.syncRangeToWorkspace(value)\n\t\t\tif (this.dateRange?.persistKey) {\n\t\t\t\tthis.persistRange(this.dateRange.persistKey, value)\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event date-range-change Fired whenever the dashboard's effective date range changes. Payload: `{ from, to, preset }`.\n\t\t\t */\n\t\t\tthis.$emit('date-range-change', { ...value })\n\t\t},\n\n\t\t/**\n\t\t * Publish the active window into the shared `cnWorkspaceContext` as\n\t\t * `dateFrom` / `dateTo` / `datePreset` so every declarative widget can\n\t\t * read it via the existing `@workspace.dateFrom?` / `@workspace.dateTo?`\n\t\t * filter tokens (e.g. a stat tile that scopes its count to the picked\n\t\t * window). An empty / null half writes `''`, which leaves an optional\n\t\t * token unresolved so `dropOptionalUnresolved` omits it — i.e. an \"All\"\n\t\t * range removes the date filter rather than sending a bound.\n\t\t *\n\t\t * @param {{ from?: string, to?: string, preset?: string }|null} value The range.\n\t\t * @return {void}\n\t\t */\n\t\tsyncRangeToWorkspace(value) {\n\t\t\tconst v = value || {}\n\t\t\tthis.workspaceContext.dateFrom = v.from || ''\n\t\t\tthis.workspaceContext.dateTo = v.to || ''\n\t\t\tthis.workspaceContext.datePreset = v.preset || ''\n\t\t},\n\n\t\t/**\n\t\t * Whether a preset clears the window (an \"All\" / unbounded option) rather\n\t\t * than resolving to a from/to span. True for an explicit `clear: true`,\n\t\t * or any non-`custom` preset that carries no numeric `days` / `hours`\n\t\t * (so a manifest can declare `{ id: 'all', label: 'All', days: null }`\n\t\t * without an extra flag). The `custom` preset is excluded — it opens the\n\t\t * manual from/to popover instead.\n\t\t *\n\t\t * @param {object} preset The preset descriptor.\n\t\t * @return {boolean}\n\t\t */\n\t\tisClearPreset(preset) {\n\t\t\tif (!preset) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif (preset.clear === true) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn preset.id !== 'custom'\n\t\t\t\t&& typeof preset.days !== 'number'\n\t\t\t\t&& typeof preset.hours !== 'number'\n\t\t},\n\n\t\t/**\n\t\t * Read a persisted range from `localStorage`. Returns `null`\n\t\t * when the key is missing, the stored value isn't valid JSON,\n\t\t * or the parsed value doesn't have both `from` and `to`\n\t\t * strings. Storage failures (private windows, opaque iframes)\n\t\t * are swallowed.\n\t\t *\n\t\t * @param {string} key The localStorage key.\n\t\t * @return {{ from: string, to: string, preset: string }|null}\n\t\t */\n\t\treadPersisted(key) {\n\t\t\ttry {\n\t\t\t\tif (typeof localStorage === 'undefined') {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\tconst raw = localStorage.getItem(key)\n\t\t\t\tif (!raw) {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\tconst parsed = JSON.parse(raw)\n\t\t\t\tif (!parsed || typeof parsed.from !== 'string' || typeof parsed.to !== 'string') {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tfrom: parsed.from,\n\t\t\t\t\tto: parsed.to,\n\t\t\t\t\tpreset: typeof parsed.preset === 'string' ? parsed.preset : 'custom',\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Persist a range to `localStorage`. Swallows errors (quota\n\t\t * exhaustion, private-window restrictions) — the picker\n\t\t * keeps working in-memory.\n\t\t *\n\t\t * @param {string} key The localStorage key.\n\t\t * @param {object} value The range to persist.\n\t\t */\n\t\tpersistRange(key, value) {\n\t\t\ttry {\n\t\t\t\tif (typeof localStorage === 'undefined') {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlocalStorage.setItem(key, JSON.stringify(value))\n\t\t\t} catch {\n\t\t\t\t// Intentionally swallowed — non-fatal.\n\t\t\t}\n\t\t},\n\n\t\ttoggleEdit() {\n\t\t\tconst leaving = this.isEditing\n\t\t\tthis.isEditing = !this.isEditing\n\n\t\t\t// 🔴 ONE SAVE PER EDIT SESSION, ON THE WAY OUT. Saving on every\n\t\t\t// drag writes a record per pixel gesture and races the next drag;\n\t\t\t// the user's arrangement is finished when they say it is.\n\t\t\tif (leaving) {\n\t\t\t\tthis.saveUserLayout()\n\t\t\t\tthis.saveViewUserLayouts()\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * @event edit-toggle Emitted when the user toggles edit mode. Payload: `true` when entering edit mode, `false` when leaving.\n\t\t\t */\n\t\t\tthis.$emit('edit-toggle', this.isEditing)\n\t\t},\n\n\t\t/**\n\t\t * Read this user's arrangement, when the page keeps one.\n\t\t *\n\t\t * A page without `userLayout` makes NO request at all, which is the\n\t\t * opt-out the requirement asks for: not a request that answers\n\t\t * nothing, an absence of one.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadUserLayout() {\n\t\t\tif (!this.userLayout || !this.appId) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst record = await this.userLayoutApi().load(this.appId, this.resolvedPageId)\n\t\t\t\tthis.userLayoutItems = mergeUserLayout(this.layout, record)\n\t\t\t} catch {\n\t\t\t\t// The manifest layout is the documented fallback, so a store\n\t\t\t\t// that cannot answer leaves the page exactly as the admin\n\t\t\t\t// shipped it rather than empty.\n\t\t\t\tthis.userLayoutItems = null\n\t\t\t} finally {\n\t\t\t\tthis.userLayoutLoaded = true\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Store this user's arrangement, if they changed one.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync saveUserLayout() {\n\t\t\tif (!this.userLayout || !this.appId || !this.userLayoutDirty) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tthis.userLayoutDirty = false\n\t\t\ttry {\n\t\t\t\tawait this.userLayoutApi().save(\n\t\t\t\t\tthis.appId,\n\t\t\t\t\tthis.resolvedPageId,\n\t\t\t\t\tthis.userLayoutItems || [],\n\t\t\t\t)\n\t\t\t} catch {\n\t\t\t\t// Nothing is said. The arrangement stands for this session and\n\t\t\t\t// a toast on a failed layout write would be noise on an\n\t\t\t\t// instance that simply has no preference route.\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The edit-mode reset: the page's own grid and the chosen view return\n\t\t * to the manifest layout. Other views keep this user's arrangement.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/page-view-user-layouts/specs/view-switch-containers/spec.md#requirement-resetting-a-view-restores-its-manifest-layout\n\t\t */\n\t\tasync resetLayout() {\n\t\t\tawait Promise.all([this.resetUserLayout(), this.resetViewUserLayout()])\n\t\t},\n\n\t\t/**\n\t\t * Drop this user's arrangement and return to the manifest.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync resetUserLayout() {\n\t\t\tif (!this.userLayout || !this.appId) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tawait this.userLayoutApi().reset(this.appId, this.resolvedPageId)\n\t\t\t} catch {\n\t\t\t\t// Same posture as the save: the grid below returns to the\n\t\t\t\t// manifest either way, which is what the user asked for.\n\t\t\t}\n\n\t\t\tthis.userLayoutDirty = false\n\t\t\tthis.userLayoutItems = mergeUserLayout(this.layout, null)\n\t\t\t/**\n\t\t\t * @event user-layout-reset Emitted when the user drops their own arrangement and the page returns to the manifest layout.\n\t\t\t */\n\t\t\tthis.$emit('user-layout-reset')\n\t\t},\n\n\t\t/**\n\t\t * The geometry fields of one grid update, and nothing else.\n\t\t *\n\t\t * The grid emits a freshly-mapped item; copying it whole would carry\n\t\t * whatever else the grid put on it over the widget's own definition.\n\t\t *\n\t\t * @param {object} update One item from the grid's layout change.\n\t\t * @return {object} Its geometry.\n\t\t */\n\t\tgeometryFrom(update) {\n\t\t\tconst geometry = {}\n\t\t\tfor (const field of ['gridX', 'gridY', 'gridWidth', 'gridHeight']) {\n\t\t\t\tif (update?.[field] !== undefined) {\n\t\t\t\t\tgeometry[field] = update[field]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn geometry\n\t\t},\n\n\t\t/**\n\t\t * The three calls a user layout needs, from the injected store or the\n\t\t * default one.\n\t\t *\n\t\t * @return {{ load: (appId: string, pageId: string) => Promise<object|null>, save: (appId: string, pageId: string, layout: Array<object>) => Promise<boolean>, reset: (appId: string, pageId: string) => Promise<boolean> }} The api.\n\t\t */\n\t\tuserLayoutApi() {\n\t\t\treturn resolveUserLayoutApi(this.userLayoutStore)\n\t\t},\n\n\t\tonLayoutChange(updated) {\n\t\t\t// A USER ARRANGEMENT NEVER TOUCHES THE MANIFEST. The in-place\n\t\t\t// write below is for the admin editor, which edits the page for\n\t\t\t// everybody; doing it for a user rearranging their own dashboard\n\t\t\t// would rewrite the page for everyone who opens it after them.\n\t\t\t// While Buildiq edits, the drag is the admin's and goes below.\n\t\t\tif (this.showsUserLayout) {\n\t\t\t\tthis.userLayoutDirty = true\n\t\t\t\tthis.userLayoutItems = this.userLayoutItems.map((item) => {\n\t\t\t\t\tconst u = (Array.isArray(updated) ? updated : []).find((candidate) => String(candidate.id) === String(item.id)\n\t\t\t\t\t\t|| candidate.widgetId === item.widgetId)\n\n\t\t\t\t\treturn (u ? { ...item, ...this.geometryFrom(u) } : item)\n\t\t\t\t})\n\t\t\t\tthis.$emit('layout-change', this.userLayoutItems)\n\t\t\t\t// Outside an in-page edit session no Done will come to save\n\t\t\t\t// the arrangement, so it is saved now.\n\t\t\t\tif (!this.isEditing) {\n\t\t\t\t\tthis.saveUserLayout()\n\t\t\t\t}\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Write the new geometry back into the layout items IN PLACE so the\n\t\t\t// in-place manifest editor's diff (ADR-041) captures drag/resize —\n\t\t\t// CnDashboardGrid emits a freshly-mapped array, which on its own\n\t\t\t// never reaches the diffed manifest, so a resize would survive the\n\t\t\t// session (GridStack DOM) but vanish on reload.\n\t\t\tif (Array.isArray(updated) && Array.isArray(this.layout)) {\n\t\t\t\tfor (const u of updated) {\n\t\t\t\t\tconst item = this.layout.find((l) => String(l.id) === String(u.id))\n\t\t\t\t\t\t|| this.layout.find((l) => l.widgetId === u.widgetId)\n\t\t\t\t\tif (!item) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif (u.gridX !== undefined) {\n\t\t\t\t\t\titem.gridX = u.gridX\n\t\t\t\t\t}\n\t\t\t\t\tif (u.gridY !== undefined) {\n\t\t\t\t\t\titem.gridY = u.gridY\n\t\t\t\t\t}\n\t\t\t\t\tif (u.gridWidth !== undefined) {\n\t\t\t\t\t\titem.gridWidth = u.gridWidth\n\t\t\t\t\t}\n\t\t\t\t\tif (u.gridHeight !== undefined) {\n\t\t\t\t\t\titem.gridHeight = u.gridHeight\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event layout-change Emitted when the user finishes dragging/resizing a widget. Payload: the updated layout array `[{ widgetId, x, y, w, h }, ...]`.\n\t\t\t */\n\t\t\tthis.$emit('layout-change', this.layout)\n\t\t},\n\n\t\t/**\n\t\t * Whether a widget def is a banner (alias-canonicalised by type\n\t\t * name, so a consumer-registry override of `banner` keeps the same\n\t\t * declarative semantics its config promises).\n\t\t *\n\t\t * @param {object} def Widget definition.\n\t\t * @return {boolean}\n\t\t */\n\t\tisBannerDef(def) {\n\t\t\treturn !!def && !!def.type\n\t\t\t\t&& (def.type === 'banner' || canonicalWidgetType(def.type) === 'banner')\n\t\t},\n\n\t\t/**\n\t\t * The cell-visibility inputs of a widget def. `visibleWhen` may sit\n\t\t * at the def's TOP LEVEL (any widget type — the declarative way to\n\t\t * gate a whole card, e.g. an object-table that should only exist\n\t\t * while its queue is non-empty), in the `content` blob (the shape\n\t\t * the registry branch forwards to CnBannerWidget), or in the legacy\n\t\t * manifest `props` blob (the fallback getStatsBlockProps and\n\t\t * getChartProps already honour for their own widget types). `text`\n\t\t * is only meaningful for banners: it is what the banner would show,\n\t\t * which for an attention card is its `title` when it has no `text`.\n\t\t *\n\t\t * @param {object} def Widget definition.\n\t\t * `layout` is returned so the page can tell an attention card from a\n\t\t * plain banner: only the former keeps its cell when its check fails.\n\t\t *\n\t\t * @spec openspec/changes/link-cards-page/specs/link-cards-page/spec.md#requirement-an-attention-card-with-a-title-keeps-its-cell\n\t\t * @spec openspec/changes/live-check-follow-ups/specs/live-check-follow-ups/spec.md#requirement-an-attention-card-says-when-it-could-not-check\n\t\t * @return {{ text: string, visibleWhen: (object|null), layout: string }}\n\t\t */\n\t\twidgetDisplayConfig(def) {\n\t\t\tconst content = (def && typeof def.content === 'object' && def.content) || {}\n\t\t\tconst props = (def && typeof def.props === 'object' && def.props) || {}\n\t\t\t// An attention card (`layout: \"attention\"`) is headed by `title`,\n\t\t\t// and its title only FALLS BACK to `text`. Reading `text` alone\n\t\t\t// called a card with a title and a reason empty, and gave its cell\n\t\t\t// up before its `visibleWhen` was even looked at.\n\t\t\tconst layout = content.layout || props.layout || ''\n\t\t\tconst title = layout === 'attention' ? (content.title || props.title || '') : ''\n\t\t\treturn {\n\t\t\t\t// A banner with only a bold `lead` has words to show too.\n\t\t\t\ttext: content.text || props.text || content.lead || props.lead || title || '',\n\t\t\t\tvisibleWhen: (def && def.visibleWhen) || content.visibleWhen || props.visibleWhen || null,\n\t\t\t\tlayout,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether a layout item would render nothing right now — a widget\n\t\t * whose `visibleWhen` has not evaluated true, or a banner with no\n\t\t * text at all — and must therefore surrender its grid cell in live\n\t\t * mode instead of leaving an empty card behind.\n\t\t *\n\t\t * One exception: an attention card whose `visibleWhen` request FAILED\n\t\t * keeps its cell, so the card can say it could not check. A collapsed\n\t\t * cell reads as \"nothing needs attention\", which a failed count does\n\t\t * not know. A count that was read and does not meet the condition\n\t\t * still collapses.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {boolean} true when the cell must collapse.\n\t\t * @spec openspec/changes/live-check-follow-ups/specs/live-check-follow-ups/spec.md#requirement-an-attention-card-says-when-it-could-not-check\n\t\t */\n\t\tisCollapsedWidget(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (!def || !def.type) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst { text, visibleWhen, layout } = this.widgetDisplayConfig(def)\n\t\t\tif (this.isBannerDef(def) && text === '') {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (!visibleWhen) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\t// A workspace condition (a page control's choice) is answered at\n\t\t\t// once from the reactive bag; nothing is fetched for it.\n\t\t\tif (isWorkspaceCondition(visibleWhen)) {\n\t\t\t\treturn !evaluateWorkspaceCondition(visibleWhen, this.workspaceContext)\n\t\t\t}\n\t\t\tconst outcome = this.widgetConditionOutcome[item.widgetId]\n\t\t\tif (outcome && outcome.failed === true && layout === 'attention' && this.isBannerDef(def)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn !outcome || outcome.met !== true\n\t\t},\n\n\t\t/**\n\t\t * Whether a page control (a workspace condition on `visibleWhen`)\n\t\t * hides this widget right now. Other conditions are not looked at.\n\t\t *\n\t\t * @param {string} widgetId The widget id.\n\t\t * @return {boolean} True when the widget must not draw.\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-widget-can-be-shown-by-a-workspace-value\n\t\t */\n\t\tisHiddenByWorkspace(widgetId) {\n\t\t\tconst def = this.getWidgetDef(widgetId)\n\t\t\tif (!def || !def.type) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst { visibleWhen } = this.widgetDisplayConfig(def)\n\t\t\treturn isWorkspaceCondition(visibleWhen) && !evaluateWorkspaceCondition(visibleWhen, this.workspaceContext)\n\t\t},\n\n\t\t/**\n\t\t * Evaluate every conditional widget's `visibleWhen` into\n\t\t * `widgetConditionOutcome` — the verdict AND the raw field value,\n\t\t * read through the same shared util primitives CnBannerWidget uses.\n\t\t * Runs on created() and again whenever `widgets` changes (the\n\t\t * in-app editor mutates defs in place). Fail-safe like the banner\n\t\t * itself: any fetch/shape error counts as \"not met\", so a broken\n\t\t * predicate collapses the cell rather than breaking the page. The\n\t\t * outcome of a failed read carries `failed: true` and the `reason`,\n\t\t * which `isCollapsedWidget` and CnBannerWidget use to show an\n\t\t * attention card's \"Could not check\" line instead of nothing.\n\t\t *\n\t\t * Flips `widgetConditionsSettled` when the initial round is done —\n\t\t * synchronously when there is nothing to evaluate, so a dashboard\n\t\t * without conditional widgets never waits.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/live-check-follow-ups/specs/live-check-follow-ups/spec.md#requirement-an-attention-card-says-when-it-could-not-check\n\t\t */\n\t\tasync evaluateWidgetConditions() {\n\t\t\tconst defs = [...(this.widgets || []), ...this.normalizedViews.flatMap((view) => view.widgets)]\n\t\t\tconst conditional = defs.filter((def) => def && def.id && def.type\n\t\t\t\t&& this.widgetDisplayConfig(def).visibleWhen\n\t\t\t\t&& !isWorkspaceCondition(this.widgetDisplayConfig(def).visibleWhen))\n\t\t\t// Skip when the CONDITIONAL SET is unchanged: the deep `widgets`\n\t\t\t// watch fires on any def edit, but only an added/removed/edited\n\t\t\t// predicate warrants refetching every conditional endpoint.\n\t\t\tconst signature = JSON.stringify(conditional\n\t\t\t\t.map((def) => [def.id, this.widgetDisplayConfig(def).visibleWhen])\n\t\t\t\t.sort((a, b) => String(a[0]).localeCompare(String(b[0]))))\n\t\t\tif (signature === this.widgetEvalSignature && this.widgetConditionsSettled) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.widgetEvalSignature = signature\n\t\t\tconst seq = ++this.widgetEvalSeq\n\t\t\tif (conditional.length === 0) {\n\t\t\t\tthis.widgetConditionsSettled = true\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait Promise.all(conditional.map(async (def) => {\n\t\t\t\tconst cond = this.widgetDisplayConfig(def).visibleWhen\n\t\t\t\tlet outcome\n\t\t\t\ttry {\n\t\t\t\t\t// `sink` keeps the first row of a source query, for a banner that names it.\n\t\t\t\t\tconst sink = {}\n\t\t\t\t\tconst value = await readVisibleWhenValue(cond, undefined, sink)\n\t\t\t\t\toutcome = { met: compareVisibleWhen(value, cond.op || 'eq', cond.value), value }\n\t\t\t\t\tif (sink.row) {\n\t\t\t\t\t\toutcome.row = sink.row\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Fail-safe: not met. But the failure is kept, and said\n\t\t\t\t\t// out loud: a failed count and \"nothing to report\" look\n\t\t\t\t\t// the same on screen.\n\t\t\t\t\toutcome = { met: false, value: null, failed: true, reason: typeof error?.message === 'string' ? error.message : String(error ?? '') }\n\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\tconsole.warn(`[CnDashboardPage] visibleWhen of widget \"${def.id}\" could not be evaluated:`, error?.message || error)\n\t\t\t\t}\n\t\t\t\t// A newer run owns the map now — a stale verdict (possibly for\n\t\t\t\t// a def that no longer exists) must not overwrite its writes.\n\t\t\t\tif (seq === this.widgetEvalSeq) {\n\t\t\t\t\tthis.widgetConditionOutcome[def.id] = outcome\n\t\t\t\t}\n\t\t\t}))\n\t\t\tif (seq !== this.widgetEvalSeq) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Prune outcomes for defs that left the conditional set — pruned\n\t\t\t// AFTER the run (not before) so a still-visible widget never\n\t\t\t// flashes collapsed while its re-evaluation is in flight.\n\t\t\tconst live = new Set(conditional.map((def) => def.id))\n\t\t\tfor (const id of Object.keys(this.widgetConditionOutcome)) {\n\t\t\t\tif (!live.has(id)) {\n\t\t\t\t\tdelete this.widgetConditionOutcome[id]\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.widgetConditionsSettled = true\n\t\t},\n\n\t\t/**\n\t\t * The v-bind payload for a registry-rendered widget. Banners get the\n\t\t * page's evaluated `conditionOutcome` merged in, so CnBannerWidget\n\t\t * renders from the verdict this page already fetched — no second\n\t\t * request, no invisible-until-self-evaluated flash inside the cell —\n\t\t * and can interpolate the predicate's field value into its text\n\t\t * (`{value}`). Every other widget type receives its stored content\n\t\t * unchanged: their cell-level `visibleWhen` is consumed entirely by\n\t\t * this page, never forwarded as a component prop.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {object}\n\t\t */\n\t\tregistryWidgetBindings(item) {\n\t\t\tconst content = filledContent(this.collectionContent(this.getWidgetContent(item)), this.appConfigRef || {})\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (!this.isBannerDef(def)) {\n\t\t\t\treturn content\n\t\t\t}\n\t\t\tconst outcome = this.widgetConditionOutcome[item.widgetId]\n\t\t\treturn outcome ? { ...content, conditionOutcome: outcome } : content\n\t\t},\n\n\t\t/**\n\t\t * The content keys a registry widget receives as props: only the ones\n\t\t * its renderer declares. An undeclared key would otherwise fall through\n\t\t * as an attribute onto the renderer's root component and could override\n\t\t * a value the widget computes for it. The whole content still arrives\n\t\t * as `content`. A renderer that forwards its own attributes\n\t\t * (`inheritAttrs: false`) keeps receiving every key.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {object} The bindings the renderer declares.\n\t\t * @spec openspec/changes/dashboard-declared-widget-props/specs/dashboard-page/spec.md#requirement-a-dashboard-widget-receives-only-the-content-keys-it-declares\n\t\t */\n\t\tregistryWidgetProps(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn pickDeclaredProps(this.registryRenderer(item), this.registryWidgetBindings(item), def?.type || item.widgetId)\n\t\t},\n\n\t\t/**\n\t\t * What a container widget (registry `container`, such as `tabs`) needs\n\t\t * beside its content: the page's widget definitions, so its tabs find\n\t\t * the widgets they name, and the consumer registry for custom child\n\t\t * types. Empty for every other widget, so a leaf gets no extra\n\t\t * attributes on its root.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {object} The extra bindings.\n\t\t * @spec openspec/changes/dashboard-tabs-children/specs/dashboard-page/spec.md#requirement-a-tabs-widget-on-a-dashboard-renders-the-widgets-its-tabs-name\n\t\t */\n\t\tcontainerBindings(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (!def || !def.type) {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\tconst entry = getWidgetTypeEntry(def.type) || getWidgetTypeEntry(canonicalWidgetType(def.type))\n\t\t\tif (!entry || entry.container !== true) {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\tconst own = Array.isArray(this.widgets) ? this.widgets.filter(Boolean) : []\n\t\t\tconst fromView = this.activeView && Array.isArray(this.activeView.widgets) ? this.activeView.widgets.filter(Boolean) : []\n\t\t\treturn {\n\t\t\t\tavailableWidgets: [...own, ...fromView],\n\t\t\t\tcnRegistry: this.cnRegistry || {},\n\t\t\t\tsurface: this.surface,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * What a widget that draws its own card needs inside a dashboard cell,\n\t\t * which already draws the titled card: the built-in `card-grid` gets\n\t\t * `chromeless`, so it adds no second frame, title or Actions menu.\n\t\t * Empty for every other widget.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {object} The extra bindings.\n\t\t * @spec openspec/changes/card-grid-dashboard-frame/specs/card-grid-dashboard-frame/spec.md#requirement-a-card-grid-on-a-dashboard-draws-no-frame-of-its-own\n\t\t */\n\t\tcellChromeBindings(item) {\n\t\t\treturn this.registryRenderer(item) === BUILT_IN_WIDGETS['card-grid'] ? { chromeless: true } : {}\n\t\t},\n\n\t\t/**\n\t\t * A widget's content with the board's quiet collection footer: in the\n\t\t * board look a dashboard that drops the widget Actions menu\n\t\t * (`showWidgetActions: false`) also drops the Add footer of its list\n\t\t * widgets, whose Add is the menu's create entry at the bottom of the\n\t\t * card. A widget that says `content.allowCreate` keeps its own value.\n\t\t * Otherwise the content is returned as is.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-legacy-widgets/specs/dashboard-page/spec.md#requirement-a-board-dashboard-without-widget-actions-drops-the-add-footer\n\t\t * @param {object} content The widget's stored content.\n\t\t * @return {object}\n\t\t */\n\t\tcollectionContent(content) {\n\t\t\tif (!this.isBoardLook || this.showWidgetActions !== false) {\n\t\t\t\treturn content\n\t\t\t}\n\t\t\tif (content && Object.hasOwn(content, 'allowCreate')) {\n\t\t\t\treturn content\n\t\t\t}\n\t\t\treturn { ...content, allowCreate: false }\n\t\t},\n\n\t\t/**\n\t\t * Re-compact a filtered layout upward, display-only. GridStack runs\n\t\t * `float: true`, so removing an item does not close its row — this\n\t\t * skyline pass does, preserving the authored order (gridY, then\n\t\t * gridX) and every item's own column, width and height. Items are\n\t\t * shallow-copied only when their gridY actually moves.\n\t\t *\n\t\t * @param {Array<object>} items Layout items to compact.\n\t\t * @return {Array<object>} New array with recomputed gridY values.\n\t\t */\n\t\tcompactDisplayLayout(items) {\n\t\t\tconst heights = new Array(Math.max(1, this.columns)).fill(0)\n\t\t\treturn [...items]\n\t\t\t\t.sort((a, b) => ((a.gridY ?? 0) - (b.gridY ?? 0)) || ((a.gridX ?? 0) - (b.gridX ?? 0)))\n\t\t\t\t.map((item) => {\n\t\t\t\t\tconst x = Math.min(Math.max(0, item.gridX ?? 0), heights.length - 1)\n\t\t\t\t\tconst w = Math.max(1, item.gridWidth ?? 1)\n\t\t\t\t\tconst h = Math.max(1, item.gridHeight ?? 1)\n\t\t\t\t\tconst to = Math.min(x + w, heights.length)\n\t\t\t\t\t// An item authored wider than the grid is clamped in the\n\t\t\t\t\t// RETURNED geometry too, not just in the skyline pass —\n\t\t\t\t\t// otherwise GridStack re-places a widget the pack thought\n\t\t\t\t\t// was narrower and the two can disagree on gridY.\n\t\t\t\t\tconst effectiveWidth = to - x\n\t\t\t\t\tlet y = 0\n\t\t\t\t\tfor (let c = x; c < to; c++) {\n\t\t\t\t\t\ty = Math.max(y, heights[c])\n\t\t\t\t\t}\n\t\t\t\t\tfor (let c = x; c < to; c++) {\n\t\t\t\t\t\theights[c] = y + h\n\t\t\t\t\t}\n\t\t\t\t\tif (y === (item.gridY ?? 0) && effectiveWidth === w) {\n\t\t\t\t\t\treturn item\n\t\t\t\t\t}\n\t\t\t\t\tconst out = { ...item, gridY: y }\n\t\t\t\t\tif (effectiveWidth !== w) {\n\t\t\t\t\t\tout.gridWidth = effectiveWidth\n\t\t\t\t\t}\n\t\t\t\t\treturn out\n\t\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Resolve a layout item's widget definition from `widgets[]`.\n\t\t *\n\t\t * Deliberately a METHOD, not a cached computed `widgetMap`. The\n\t\t * `widgets` prop array is mutated IN PLACE by the in-app editor\n\t\t * (CnBuildiqEditButton's \"Add widget…\" pushes onto\n\t\t * `page.config.widgets`), and a computed over a prop array does not\n\t\t * subscribe to that array's observer — so the map never invalidated\n\t\t * and every freshly added widget rendered the `unavailableLabel`\n\t\t * placeholder (with its raw id as the title) until a full reload.\n\t\t * A method re-runs on every render, so the lookup cannot go stale.\n\t\t *\n\t\t * @param {string} widgetId The layout item's `widgetId`.\n\t\t * @return {object|null} The matching widget definition, or null.\n\t\t */\n\t\tgetWidgetDef(widgetId) {\n\t\t\tconst list = Array.isArray(this.widgets) ? this.widgets : []\n\t\t\treturn list.find((w) => w && w.id === widgetId) || this.findViewWidget(widgetId)\n\t\t},\n\n\t\t/**\n\t\t * The app id(s) a widget depends on, declared via `requiresApp`\n\t\t * (a single id string or an array of ids). Empty array when the\n\t\t * widget has no cross-app dependency.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {string[]} Required app ids (possibly empty).\n\t\t */\n\t\trequiredAppsFor(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tconst req = def && def.requiresApp\n\t\t\tif (!req) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn Array.isArray(req) ? req.filter(Boolean) : [req]\n\t\t},\n\n\t\t/**\n\t\t * Whether a given app counts as available. Prefers the injected\n\t\t * `appStatuses` map (an app is available when `enabled`, or when\n\t\t * only `installed` is known); falls back to the `isAppInstalled()`\n\t\t * runtime check when no status was injected for that app.\n\t\t *\n\t\t * @param {string} appId Nextcloud app id.\n\t\t * @return {boolean} True when the app is present/usable.\n\t\t */\n\t\tisAppAvailable(appId) {\n\t\t\tconst status = this.appStatuses && this.appStatuses[appId]\n\t\t\tif (status) {\n\t\t\t\tif (typeof status.enabled === 'boolean') {\n\t\t\t\t\treturn status.enabled\n\t\t\t\t}\n\t\t\t\tif (typeof status.installed === 'boolean') {\n\t\t\t\t\treturn status.installed\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn isAppInstalled(appId)\n\t\t},\n\n\t\t/**\n\t\t * The first required app that is missing for a widget, or null when\n\t\t * all its `requiresApp` dependencies are available. Drives the\n\t\t * install-CTA gate that replaces the widget body for any widget\n\t\t * type (stat, chart, object-list, …) surfacing another app's data.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {(string|null)} Missing app id, or null.\n\t\t */\n\t\tmissingRequiredApp(item) {\n\t\t\tfor (const appId of this.requiredAppsFor(item)) {\n\t\t\t\tif (!this.isAppAvailable(appId)) {\n\t\t\t\t\treturn appId\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * App-store deep link used by the install CTA. Prefers the\n\t\t * injected per-app `category` (when present) so the user lands on\n\t\t * the right App Store section; otherwise links to the app's own\n\t\t * App Store entry.\n\t\t *\n\t\t * @param {string} appId Nextcloud app id.\n\t\t * @return {string} Settings/apps URL.\n\t\t */\n\t\tappInstallUrl(appId) {\n\t\t\tconst category = this.appStatuses && this.appStatuses[appId] && this.appStatuses[appId].category\n\t\t\treturn category\n\t\t\t\t? `/index.php/settings/apps/${encodeURIComponent(category)}/${encodeURIComponent(appId)}`\n\t\t\t\t: `/index.php/settings/apps/${encodeURIComponent(appId)}`\n\t\t},\n\n\t\t/**\n\t\t * Human-readable \"Install {app}\" heading for the gate CTA.\n\t\t *\n\t\t * @param {string} appId Nextcloud app id.\n\t\t * @return {string} Localized install label.\n\t\t */\n\t\tinstallAppLabel(appId) {\n\t\t\treturn t('nextcloud-vue', 'Install {app}', { app: appId })\n\t\t},\n\n\t\t/**\n\t\t * The dashboardWidgetRegistry renderer for a layout item, when its widget\n\t\t * definition's `type` is a registered catalog widget and no consumer\n\t\t * `#widget-{id}` slot handles it. This is how widgets added via the\n\t\t * in-app \"Add widget…\" flow (ADR-041) render on a dashboard.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {(object|null)} The widget renderer component, or null.\n\t\t */\n\t\tregistryRenderer(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (!def || !def.type) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\t// `integration` is NOT ours to resolve — it has its own branch\n\t\t\t// (isIntegrationWidget -> resolveRegistryWidget(integrationId)),\n\t\t\t// and one without an `integrationId` must fall through to\n\t\t\t// `unavailableLabel`. Claiming it here for BUILT_IN_WIDGETS\n\t\t\t// .integration would render a widget where the page means to say\n\t\t\t// \"unavailable\". CnDetailPage excludes the same type for the same\n\t\t\t// reason.\n\t\t\tif (def.type === 'integration') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\t// Same three-layer order as CnWidgetGrid and CnDetailPage:\n\t\t\t// consumer registry -> dashboard catalog -> BUILT_IN_WIDGETS.\n\t\t\t//\n\t\t\t// This method used to read the catalog ALONE, which made a\n\t\t\t// dashboard the odd surface out in two ways, both silent:\n\t\t\t//\n\t\t\t// - a consumer override was IGNORED whenever the catalog carried\n\t\t\t// the same name. `chart` and `stat` are in both, so an app that\n\t\t\t// registers its own (hrmq registers a TrendChartWidget under\n\t\t\t// `chart`) got the library's component instead — the widget\n\t\t\t// still rendered, just the wrong one, which is worse than a\n\t\t\t// blank. REQ-MVR-005 mandates custom-over-built-in.\n\t\t\t// - a BUILT_IN-only type — `integration`, `metadata` — resolved\n\t\t\t// to nothing and the widget did not appear at all.\n\t\t\t//\n\t\t\t// #709 unified CnWidgetGrid and CnDetailPage but missed this one.\n\t\t\tconst consumer = (this.cnRegistry || {})[def.type]\n\t\t\tif (consumer) {\n\t\t\t\treturn consumer.component ?? consumer\n\t\t\t}\n\t\t\t// THE TYPE AS WRITTEN WINS; the alias is only a fallback.\n\t\t\t//\n\t\t\t// `object-table` and `table` are two DIFFERENT registered widgets\n\t\t\t// (CnHostedObjectTable vs CnObjectListWidget2), and\n\t\t\t// WIDGET_TYPE_ALIASES nonetheless maps the first onto the second.\n\t\t\t// Canonicalising before the lookup therefore resolved an\n\t\t\t// `object-table` dashboard widget to the `table` renderer: a widget\n\t\t\t// still appeared, nothing threw, it was simply the wrong component\n\t\t\t// and the stored `content` blob never reached the props the host\n\t\t\t// adapter maps it onto. That is the failure this method's own\n\t\t\t// comment above calls \"worse than a blank\".\n\t\t\t//\n\t\t\t// Caught by larpingapp e2e on the 2.8.2 -> 2.9.2 bump:\n\t\t\t// `.cn-widget-object-table` was not in the DOM at all.\n\t\t\t//\n\t\t\t// Aliases keep working for a spelling that is NOT registered in its\n\t\t\t// own right — `map-viewer` still reaches `map`.\n\t\t\tconst entry = getWidgetTypeEntry(def.type)\n\t\t\t\t|| getWidgetTypeEntry(canonicalWidgetType(def.type))\n\t\t\tif (entry && entry.renderer) {\n\t\t\t\treturn entry.renderer\n\t\t\t}\n\t\t\treturn BUILT_IN_WIDGETS[def.type] || BUILT_IN_WIDGETS[canonicalWidgetType(def.type)] || null\n\t\t},\n\n\t\t/**\n\t\t * Whether a registry widget renders a self-contained \"card\" surface\n\t\t * (a single KPI / gauge / delta tile) that must size to its tile\n\t\t * without an inner scrollbar. Driven by the registry entry's\n\t\t * `card: true` hint (stat / gauge / delta). Card widgets are\n\t\t * rendered `flush` (no wrapper padding) and the wrapper content area\n\t\t * is switched to centred, non-scrolling layout via the\n\t\t * `cn-dashboard-page__card-fit` class — fixing the stray vertical /\n\t\t * horizontal scrollbars on short KPI / gauge tiles.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {boolean} true when the matching registry entry is a card.\n\t\t */\n\t\tisCardWidget(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (!def || !def.type) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\t// Same precedence as registryRenderer: the type as written first, the\n\t\t\t// alias only as a fallback. Canonicalising first read the card flag\n\t\t\t// off a DIFFERENT widget's entry, so the chrome could disagree with\n\t\t\t// the component actually rendered.\n\t\t\tconst entry = getWidgetTypeEntry(def.type)\n\t\t\t\t|| getWidgetTypeEntry(canonicalWidgetType(def.type))\n\t\t\treturn Boolean(entry && entry.card === true)\n\t\t},\n\n\t\t/**\n\t\t * The stored content/config for a catalog widget (passed to its renderer).\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {object}\n\t\t */\n\t\tgetWidgetContent(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn (def && def.content && typeof def.content === 'object') ? def.content : {}\n\t\t},\n\n\t\t/**\n\t\t * Remove a widget from the dashboard while editing (ADR-041): drops it from\n\t\t * `config.widgets` + `config.layout` (the working manifest, by reference)\n\t\t * and emits the updated layout so consumers persist.\n\t\t *\n\t\t * Splices in place rather than emitting fresh arrays. `widgets` / `layout`\n\t\t * ARE the working manifest's arrays — CnBuildiqEditButton.onAddWidgetSubmit\n\t\t * pushes straight into them, and onWidgetConfigSave mutates a def in place —\n\t\t * so mutation is what actually removes the widget from the page. Filtering\n\t\t * into new arrays and emitting them only told listeners about the removal,\n\t\t * and nothing listens (`@widget-remove` has no consumer in the library or in\n\t\t * Buildiq), so Delete was a no-op.\n\t\t *\n\t\t * @spec openspec/changes/dashboard-widget-system/specs/dashboard-page/spec.md\n\t\t * @param {object} item Layout item to remove.\n\t\t */\n\t\tremoveWidget(item) {\n\t\t\tconst id = item.widgetId\n\t\t\tconst layoutIndex = this.layout.findIndex((l) => l.widgetId === id)\n\t\t\t/*\n\t\t\t * `layout` and `widgets` are the working manifest's own arrays, passed by\n\t\t\t * reference on purpose: the edit button pushes into them to add a widget,\n\t\t\t * and onWidgetConfigSave mutates a def in place to save one. Emitting a\n\t\t\t * copy instead leaves the manifest untouched — exactly the bug this\n\t\t\t * replaces — so the mutation is deliberate here.\n\t\t\t */\n\t\t\tif (layoutIndex !== -1) {\n\t\t\t\t// eslint-disable-next-line vue/no-mutating-props\n\t\t\t\tthis.layout.splice(layoutIndex, 1)\n\t\t\t}\n\t\t\tif (Array.isArray(this.widgets)) {\n\t\t\t\tconst widgetIndex = this.widgets.findIndex((w) => w.id === id)\n\t\t\t\tif (widgetIndex !== -1) {\n\t\t\t\t\t// eslint-disable-next-line vue/no-mutating-props\n\t\t\t\t\tthis.widgets.splice(widgetIndex, 1)\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.$emit('layout-change', this.layout)\n\t\t\t/**\n\t\t\t * @event widget-remove Emitted when a widget is removed via the in-place editor.\n\t\t\t * @type {{ id: string, widgets: Array }}\n\t\t\t */\n\t\t\tthis.$emit('widget-remove', id, this.widgets)\n\t\t},\n\n\t\t/**\n\t\t * Open the per-widget style/config editor for a layout item.\n\t\t * Launchpad-style cog: selects the widget and shows the modal.\n\t\t *\n\t\t * @param {object} item Layout item to configure.\n\t\t */\n\t\tconfigureWidget(item) {\n\t\t\tthis.configWidgetId = item.widgetId\n\t\t\tthis.showWidgetConfig = true\n\t\t},\n\n\t\t/**\n\t\t * Persist the editor's changes onto the matching widget definition\n\t\t * IN PLACE (so the in-place manifest editor picks them up) and close\n\t\t * the modal. Mirrors the relevant chrome fields onto the layout\n\t\t * entry's `styleConfig` too, since the grid reads styleConfig from\n\t\t * the layout item.\n\t\t *\n\t\t * @param {object} edited The widget object mutated by the editor.\n\t\t */\n\t\tonWidgetConfigSave(edited) {\n\t\t\tconst def = Array.isArray(this.widgets)\n\t\t\t\t? this.widgets.find((w) => w.id === this.configWidgetId)\n\t\t\t\t: null\n\t\t\tif (def) {\n\t\t\t\tdef.title = edited.title !== undefined ? edited.title : def.title\n\t\t\t\tdef.styleConfig = edited.styleConfig || {}\n\t\t\t\tdef.showTitle = edited.showTitle !== false\n\t\t\t\tdef.customTitle = edited.customTitle || null\n\t\t\t\tdef.customIcon = edited.customIcon || null\n\t\t\t\tif (edited.content !== undefined) {\n\t\t\t\t\tdef.content = edited.content\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst layoutItem = this.layout.find((l) => l.widgetId === this.configWidgetId)\n\t\t\tif (layoutItem) {\n\t\t\t\tlayoutItem.styleConfig = edited.styleConfig || {}\n\t\t\t}\n\t\t\tthis.showWidgetConfig = false\n\t\t\tthis.$emit('layout-change', this.layout)\n\t\t},\n\n\t\t/**\n\t\t * Delete from inside the editor — drop the widget and close.\n\t\t *\n\t\t * @param {object} _w The widget the editor wants deleted (unused; we\n\t\t * route by `configWidgetId`).\n\t\t */\n\t\tonWidgetConfigDelete(_w) {\n\t\t\tthis.removeWidget({ widgetId: this.configWidgetId })\n\t\t\tthis.showWidgetConfig = false\n\t\t},\n\n\t\t/**\n\t\t * Whether a segmented group follows the description filter at\n\t\t * `index`: a select is set off from one by a dot (\"alle zaaktypen ·\n\t\t * Maand | Kwartaal | Jaar\"), not from another select or the line's end.\n\t\t *\n\t\t * @param {number} index Index in `descriptionFilters`.\n\t\t * @return {boolean}\n\t\t */\n\t\tsegmentedFollows(index) {\n\t\t\tconst next = this.descriptionFilters[index + 1]\n\t\t\treturn next ? next.control === 'segmented' : this.datePeriodInDescription\n\t\t},\n\n\t\t/**\n\t\t * The line under a widget's title (`subtitle` on the widget\n\t\t * definition), translated; empty when it carries none.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {string}\n\t\t * @spec openspec/changes/page-header-breadcrumb/specs/page-header/spec.md#requirement-a-dashboard-widget-card-can-carry-a-line-under-its-title\n\t\t */\n\t\tgetWidgetSubtitle(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tconst subtitle = def && typeof def.subtitle === 'string' ? def.subtitle : ''\n\t\t\treturn subtitle ? this.effectiveTranslate(subtitle) : ''\n\t\t},\n\n\t\t/**\n\t\t * The widget's title tone (`titleTone` on its definition): `side`\n\t\t * titles the card as a side card in the board look.\n\t\t *\n\t\t * @param {object} item The layout item.\n\t\t * @return {string} `side`, or ''.\n\t\t * @spec openspec/changes/widget-side-title-tone/specs/widget-side-title-tone/spec.md#requirement-a-widget-can-be-titled-as-a-side-card\n\t\t */\n\t\tgetWidgetTitleTone(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def && def.titleTone === 'side' ? 'side' : ''\n\t\t},\n\n\t\t/**\n\t\t * The line above a widget's title (`eyebrow` on the widget\n\t\t * definition: \"Saldo per week\" above \"Prognose 13 weken\"), through the\n\t\t * host translate, or '' for none.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {string}\n\t\t * @spec openspec/changes/widget-title-eyebrow/specs/dashboard-page/spec.md#requirement-a-widget-card-can-carry-a-line-above-its-title\n\t\t */\n\t\tgetWidgetEyebrow(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tconst eyebrow = def && typeof def.eyebrow === 'string' ? def.eyebrow : ''\n\t\t\treturn eyebrow ? this.effectiveTranslate(eyebrow) : ''\n\t\t},\n\n\t\t/**\n\t\t * The widget's title as AUTHORED — the untranslated manifest source\n\t\t * string — resolved by widget id rather than by item, so a descendant\n\t\t * that only knows its own id can ask for it.\n\t\t *\n\t\t * Provided to descendants as `cnWidgetTitleSource` and used to build\n\t\t * the \"Report a bug\" issue title. getWidgetTitle() below is the\n\t\t * display chokepoint and runs the def title through the host translate\n\t\t * function, so the CnActionsMenu inside CnWidgetWrapper only ever saw\n\t\t * the TRANSLATED title: a report filed from a French UI arrived as\n\t\t * \"[BUG] Activité récente\", and one from a Russian UI in Cyrillic,\n\t\t * unreadable to a maintainer even though the English msgid was right\n\t\t * here in the manifest.\n\t\t *\n\t\t * Deliberately DIVERGES from getWidgetTitle's precedence: the two\n\t\t * customTitle values are skipped, not just left untranslated. They\n\t\t * are a person's own words in their own language, so returning them\n\t\t * reopens the exact failure above — and a renamed placement does not\n\t\t * identify the widget COMPONENT the bug is about, while the manifest\n\t\t * title (English, the msgid) does. When the def carries no title this\n\t\t * returns '' and CnActionsMenu falls back to the surface slug, which\n\t\t * is English by construction.\n\t\t *\n\t\t * @param {string} widgetId The widget's id.\n\t\t * @return {string} The manifest title, or '' when the def has none.\n\t\t */\n\t\tgetWidgetTitleSource(widgetId) {\n\t\t\treturn this.getWidgetDef(widgetId)?.title || ''\n\t\t},\n\n\t\tgetWidgetTitle(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\t// Prefer a per-placement override, then the widget def's customTitle\n\t\t\t// (set by the in-place style editor cog), then the def's base title.\n\t\t\t//\n\t\t\t// Only the def's base title goes through the host translate function.\n\t\t\t// It is the manifest-authored source string, exactly like the page\n\t\t\t// title on `resolvedTitle` above. The two customTitle values are NOT\n\t\t\t// translated: a person typed them into the style editor in their own\n\t\t\t// words, so looking them up in a translation table is wrong, and a\n\t\t\t// miss would be indistinguishable from a hit.\n\t\t\t//\n\t\t\t// This is the single display-time chokepoint for every widget type\n\t\t\t// (slot, chart, stats-block, integration, NC-API, registry and the\n\t\t\t// unknown fallback all bind `:title=\"getWidgetTitle(item)\"`), which\n\t\t\t// is why the fix belongs here rather than at each call site.\n\t\t\t// `configWidget()` deliberately stays raw: it pre-fills the config\n\t\t\t// modal, and translating there would persist a translated string\n\t\t\t// back into the widget definition on save.\n\t\t\tconst title = item.customTitle\n\t\t\t\t|| def?.customTitle\n\t\t\t\t|| (def?.title ? this.effectiveTranslate(def.title) : '')\n\t\t\t\t|| item.widgetId\n\t\t\treturn this.titleHoldsCount(item) ? this.fillTitleCount(item, title) : title\n\t\t},\n\n\t\t/**\n\t\t * Whether the widget's title carries `{count}`, the total its widget\n\t\t * reports; such a card shows the total in its title, not as a chip.\n\t\t *\n\t\t * @param {object} item Layout placement entry.\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/widget-title-count/specs/widget-title-count/spec.md#requirement-a-widget-title-can-carry-the-total-its-widget-reports\n\t\t */\n\t\ttitleHoldsCount(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tconst raw = item.customTitle || def?.customTitle || def?.title || ''\n\t\t\treturn typeof raw === 'string' && raw.includes('{count}')\n\t\t},\n\n\t\t/**\n\t\t * The title with `{count}` filled from the reported total, or the token\n\t\t * dropped (with the space before it) while no total has arrived.\n\t\t *\n\t\t * @param {object} item Layout placement entry.\n\t\t * @param {string} title The title, translated.\n\t\t * @return {string}\n\t\t * @spec openspec/changes/widget-title-count/specs/widget-title-count/spec.md#requirement-a-widget-title-can-carry-the-total-its-widget-reports\n\t\t */\n\t\tfillTitleCount(item, title) {\n\t\t\tconst reported = this.widgetHeaders[item.widgetId]\n\t\t\tif (reported && Number.isFinite(reported.count)) {\n\t\t\t\treturn title.replace(/\\{count\\}/g, String(reported.count))\n\t\t\t}\n\t\t\treturn title.replace(/\\s*\\{count\\}/g, '').trim()\n\t\t},\n\n\t\t/**\n\t\t * Whether a widget's title header renders. Tri-state, resolved from the\n\t\t * layout placement first, then the widget def. The def fallback matters\n\t\t * because the in-place style editor persists `showTitle` onto the\n\t\t * widget def (see onWidgetConfigSave), while hand-written manifests\n\t\t * may set it on either object — mirrors getWidgetTitle's def fallback.\n\t\t *\n\t\t * When neither sets it, the default depends on the family: card widgets\n\t\t * (stat / gauge / delta) headline themselves via `content.label`, so a\n\t\t * chrome header would only repeat it — or, when no title was ever set,\n\t\t * show the raw type name (\"stat\"). Cards therefore default headerless;\n\t\t * every other widget defaults to showing the header.\n\t\t *\n\t\t * @param {object} item the layout placement.\n\t\t * @return {boolean}\n\t\t */\n\t\twidgetShowTitle(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tconst value = item.showTitle !== undefined ? item.showTitle : def?.showTitle\n\t\t\tif (value === undefined || value === null) {\n\t\t\t\t// A banner that names no title draws no title row: it used to show\n\t\t\t\t// its widget id (\"attention-first\") as the card title.\n\t\t\t\tif (this.isBannerDef(def) && !item.customTitle && !def?.customTitle && !def?.title) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\treturn !this.isCardWidget(item)\n\t\t\t}\n\t\t\treturn value !== false\n\t\t},\n\n\t\t/**\n\t\t * Whether a widget's card chrome is suppressed. Only an explicit\n\t\t * `layout[].borderless: true` suppresses it.\n\t\t *\n\t\t * HEADERLESS IS NOT CHROMELESS. This used to derive \"no header\" ⇒ \"no\n\t\t * card\", which conflates two different intentions and was already known\n\t\t * to push authors into the wrong shape — a headerless tile lost its card\n\t\t * and drew its own box inside the grid cell instead, a card inside a\n\t\t * card.\n\t\t *\n\t\t * Since the KPI card went flat (2026-08-30) that derivation does not\n\t\t * merely look wrong, it erases the tile: a flat card in a borderless\n\t\t * wrapper has NO chrome at all. Measured on buildiq, whose dashboard\n\t\t * renders `CnStatsBlock` inside a headerless `#widget-apps` custom slot\n\t\t * — three KPI tiles with no card, no border and no background.\n\t\t *\n\t\t * The registered-widget branches carried a second copy of this rule for\n\t\t * exactly that reason; there is now one rule for every family, so a\n\t\t * custom slot and a registered widget cannot disagree about it.\n\t\t *\n\t\t * A greeting header that declares `content.ground: true` sits on the\n\t\t * page ground, so it asks for no card either: one key on the widget\n\t\t * instead of a second one on its placement.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-a-greeting-can-sit-on-the-page-ground\n\t\t * @param {object} item the layout placement.\n\t\t * @return {boolean}\n\t\t */\n\t\twidgetBorderless(item) {\n\t\t\tif (item.borderless === true) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn Boolean(def && def.type === 'header' && this.getWidgetContent(item).ground === true)\n\t\t},\n\n\t\t/**\n\t\t * Whether a widget's overflow Actions menu renders. Same tri-state +\n\t\t * layout-then-def resolution as widgetShowTitle, and the same card\n\t\t * default: cards are the \"card\" family (docs/architecture/cards-and-widgets.md)\n\t\t * and carry no Actions menu — a KPI tile has no refreshable surface of\n\t\t * its own and the menu eats the header width it needs.\n\t\t *\n\t\t * @param {object} item the layout placement.\n\t\t * @return {boolean}\n\t\t */\n\t\twidgetShowActions(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tconst value = item.showActions !== undefined ? item.showActions : def?.showActions\n\t\t\tif (value === undefined || value === null) {\n\t\t\t\treturn this.showWidgetActions && !this.isCardWidget(item)\n\t\t\t}\n\t\t\treturn value !== false\n\t\t},\n\n\t\t/**\n\t\t * Documentation URL for a widget's overflow Actions menu. Prefers a\n\t\t * per-widget `documentationUrl` on the widget def, then falls back to\n\t\t * the page-level `documentationUrl` so every widget on a documented\n\t\t * page surfaces the Documentation item — matching the page header menu.\n\t\t *\n\t\t * @param {object} item Layout item descriptor.\n\t\t * @return {string} The resolved documentation URL, or '' when none.\n\t\t */\n\t\tgetWidgetDocumentationUrl(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.documentationUrl || this.documentationUrl || ''\n\t\t},\n\n\t\tgetWidgetIconUrl(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.iconUrl || null\n\t\t},\n\n\t\tgetWidgetIconClass(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.iconClass || null\n\t\t},\n\n\t\tgetWidgetButtons(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\t// `showButtons: false` on the placement or the definition drops\n\t\t\t// the footer links (\"More events\"), for a placement whose card\n\t\t\t// says enough without them (zuiddrecht-pixel-gaps-3).\n\t\t\tif (item?.showButtons === false || def?.showButtons === false) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn def?.buttons || []\n\t\t},\n\n\t\t/**\n\t\t * The widget's manifest `headerActions`, resolved for its card's title\n\t\t * row; a click goes through the page's dispatcher when the renderer\n\t\t * provides one (so `open-modal` opens a registry dialog), else through\n\t\t * the action dispatcher with the page's router.\n\t\t *\n\t\t * @spec openspec/changes/dashboard-widget-header-actions/specs/dashboard-widget-header-actions/spec.md#requirement-a-dashboard-card-draws-its-widgets-header-actions\n\t\t * @spec openspec/changes/dashboard-card-action-dialog/specs/dashboard-page/spec.md#requirement-a-dashboard-card-header-action-dispatches-through-the-page\n\t\t * @param {object} item Layout placement entry.\n\t\t * @return {Array<object>} The buttons, or none.\n\t\t */\n\t\tgetWidgetHeaderActions(item) {\n\t\t\treturn resolveWidgetHeaderActions(this.getWidgetDef(item.widgetId), {\n\t\t\t\ttranslate: (key) => this.effectiveTranslate(key),\n\t\t\t\tdispatch: (action) => (typeof this.cnDispatchAction === 'function'\n\t\t\t\t\t? this.cnDispatchAction(action)\n\t\t\t\t\t: dispatchAction(action, { router: this.$router || null })),\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The widget's header text link (`headerLink` on the layout entry,\n\t\t * else on the widget definition), forwarded to CnWidgetWrapper.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-widget-header-carries-a-text-link\n\t\t * @param {object} item Layout placement entry.\n\t\t * @return {object|null}\n\t\t */\n\t\tgetWidgetHeaderLink(item) {\n\t\t\tif (item?.headerLink && typeof item.headerLink === 'object') {\n\t\t\t\treturn item.headerLink\n\t\t\t}\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (def?.headerLink && typeof def.headerLink === 'object') {\n\t\t\t\treturn def.headerLink\n\t\t\t}\n\t\t\t// Then what the widget itself reported (`header` event): its link with\n\t\t\t// `{total}` filled and its tokens resolved.\n\t\t\t// A widget that reports no link (facts reports only its action) keeps\n\t\t\t// the link its content asks for.\n\t\t\tconst reported = this.widgetHeaders[item.widgetId]\n\t\t\tif (reported && reported.link) {\n\t\t\t\treturn reported.link\n\t\t\t}\n\t\t\t// Last, what the widget's own content asks for (`headerLink`, or the\n\t\t\t// `viewAllRoute` / `viewAllLabel` of the tasks widget).\n\t\t\treturn contentHeaderLink(item?.content) || contentHeaderLink(def?.content)\n\t\t},\n\n\t\t/**\n\t\t * Keep what a registry widget reports for its card header: the link, the\n\t\t * note (\"3 in total\") and one action, as CnDetailWidgetHost does on a\n\t\t * detail page.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-widget-header/specs/dashboard-page/spec.md#requirement-a-dashboard-card-shows-the-header-its-widget-reports\n\t\t * @param {object} item Layout placement entry.\n\t\t * @param {{link?: object|null, note?: string, action?: object|null}} header What the widget reported.\n\t\t */\n\t\tonWidgetHeader(item, header) {\n\t\t\tif (!item || !item.widgetId || !header || typeof header !== 'object' || header instanceof Event) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst link = header.link && typeof header.link === 'object' ? header.link : null\n\t\t\tconst note = typeof header.note === 'string' ? header.note : ''\n\t\t\tconst count = Number.isFinite(header.count) ? header.count : null\n\t\t\tconst action = header.action && typeof header.action.run === 'function' && header.action.label ? header.action : null\n\t\t\t// Only a changed header is kept: a new object here re-renders the card,\n\t\t\t// and a widget that reads again on render would report again, for ever.\n\t\t\tconst before = this.widgetHeaders[item.widgetId]\n\t\t\tconst same = before && JSON.stringify(before.link) === JSON.stringify(link) && before.note === note && (before.count ?? null) === count\n\t\t\t\t&& (before.action ? before.action.label : '') === (action ? action.label : '')\n\t\t\tif (same) {\n\t\t\t\tbefore.action = action\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.widgetHeaders = { ...this.widgetHeaders, [item.widgetId]: { link, note, action, count } }\n\t\t},\n\n\t\t/**\n\t\t * The header note a registry widget reported.\n\t\t *\n\t\t * @param {object} item Layout placement entry.\n\t\t * @return {string}\n\t\t */\n\t\twidgetHeaderNote(item) {\n\t\t\tconst reported = this.widgetHeaders[item.widgetId]\n\t\t\treturn reported ? reported.note : ''\n\t\t},\n\n\t\t/**\n\t\t * The total a registry widget reported for its card header\n\t\t * (record-list `headerCount`), or null.\n\t\t *\n\t\t * @param {object} item Layout placement entry.\n\t\t * @return {number|null}\n\t\t * @spec openspec/changes/screens-record-list-row-action/specs/record-list/spec.md\n\t\t */\n\t\twidgetHeaderCount(item) {\n\t\t\tif (this.titleHoldsCount(item)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst reported = this.widgetHeaders[item.widgetId]\n\t\t\treturn reported && Number.isFinite(reported.count) ? reported.count : null\n\t\t},\n\n\t\t/**\n\t\t * The header action a registry widget reported.\n\t\t *\n\t\t * @param {object} item Layout placement entry.\n\t\t * @return {{label: string, run: Function}|null}\n\t\t */\n\t\twidgetHeaderAction(item) {\n\t\t\tconst reported = this.widgetHeaders[item.widgetId]\n\t\t\treturn reported ? reported.action : null\n\t\t},\n\n\t\t/**\n\t\t * Whether a widget's overflow Actions menu shows the Refresh item.\n\t\t * An explicit per-widget flag wins — on the widget definition or\n\t\t * the layout item, as either `hideRefresh: true` or\n\t\t * `showRefresh: false`. Otherwise custom-slot widgets (which have no\n\t\t * built-in refetch path) resolve via the `widgetShowRefresh` tri-state\n\t\t * — the explicit prop, else whether a `@widget-refresh` listener is\n\t\t * wired (see `effectiveWidgetShowRefresh`) — while built-in widgets\n\t\t * (chart / NC / integration) inherit the page-level `showRefresh`. So a\n\t\t * read-only overview whose widgets have no refetch wired drops the dead\n\t\t * Refresh item from every widget menu while keeping Request-a-feature.\n\t\t *\n\t\t * @param {object} item Layout placement entry.\n\t\t * @return {boolean}\n\t\t */\n\t\tgetWidgetShowRefresh(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId) || {}\n\t\t\tif (def.hideRefresh === true || item.hideRefresh === true) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif (typeof def.showRefresh === 'boolean') {\n\t\t\t\treturn def.showRefresh\n\t\t\t}\n\t\t\tif (typeof item.showRefresh === 'boolean') {\n\t\t\t\treturn item.showRefresh\n\t\t\t}\n\t\t\tif (this.hasWidgetSlot(item.widgetId)) {\n\t\t\t\treturn this.effectiveWidgetShowRefresh\n\t\t\t}\n\t\t\treturn this.showRefresh\n\t\t},\n\n\t\tgetWidgetTitleIconPosition(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.titleIconPosition || 'right'\n\t\t},\n\n\t\tgetWidgetTitleIconColor(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.titleIconColor || null\n\t\t},\n\n\t\t/**\n\t\t * The widget's semantic header-icon colour. Read from the widget\n\t\t * definition's `titleIconVariant`; defaults to `primary`, which is\n\t\t * why EVERY widget's header icon is now coloured rather than only the\n\t\t * ones an app happened to configure. A widget whose subject already\n\t\t * carries a meaning names it — a Concepts list is `warning`, a\n\t\t * Published list `success`, a Depublished list `error`.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {string} A CnWidgetWrapper `titleIconVariant` value.\n\t\t */\n\t\tgetWidgetTitleIconVariant(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.titleIconVariant || 'primary'\n\t\t},\n\n\t\t/**\n\t\t * The widget's own section in the app's documentation, forwarded to\n\t\t * the shared Actions menu so its Documentation item deep-links to\n\t\t * THIS widget rather than the docs homepage. Falls back to the widget\n\t\t * type, which is how the library's own catalog widgets are documented,\n\t\t * and finally to the widget id.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {string} An anchor slug / path / URL.\n\t\t */\n\t\tgetWidgetDocsAnchor(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.docsAnchor || def?.type || item.widgetId || ''\n\t\t},\n\n\t\tisTile(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.type === 'tile'\n\t\t},\n\n\t\t/**\n\t\t * The tile config for a `type: \"tile\"` widget def.\n\t\t *\n\t\t * Read from `content` first, then the def's top level — the same\n\t\t * dual-shape read CnDashTileWidget does. A tile authored through the\n\t\t * Add-widget modal keeps the form's fields in `content`; only preset\n\t\t * and legacy tiles carry them at the top level. Reading the top level\n\t\t * alone left every authored tile with no icon, no link and CnTileWidget's\n\t\t * fallback blue, while its title still showed — the one field the modal\n\t\t * also writes there.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {object|null} the tile config, or null when no def matches.\n\t\t */\n\t\tgetTileConfig(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (!def) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst c = (def.content && typeof def.content === 'object') ? def.content : {}\n\t\t\treturn {\n\t\t\t\t// The modal resolves the header title, so the top level wins here.\n\t\t\t\t// `||`, not `??`: an empty-string def.title (never actually chosen\n\t\t\t\t// by the modal) must still fall through to content.title, which the\n\t\t\t\t// form validates as required and so is always populated.\n\t\t\t\ttitle: def.title || c.title,\n\t\t\t\tsubtitle: c.subtitle ?? def.subtitle,\n\t\t\t\ticon: c.icon ?? def.icon,\n\t\t\t\ticonType: c.iconType ?? def.iconType,\n\t\t\t\tbackgroundColor: c.backgroundColor ?? def.backgroundColor,\n\t\t\t\ttextColor: c.textColor ?? def.textColor,\n\t\t\t\tlinkType: c.linkType ?? def.linkType,\n\t\t\t\tlinkValue: c.linkValue ?? def.linkValue,\n\t\t\t}\n\t\t},\n\n\t\tisNcWidget(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.itemApiVersions && def.itemApiVersions.length > 0\n\t\t},\n\n\t\t/**\n\t\t * Whether this layout item resolves to an integration-typed\n\t\t * widget — `def.type === 'integration'` with an `integrationId`\n\t\t * pointing at a provider registered on the pluggable\n\t\t * integration registry. Mirrors `isTile` / `isChart`.\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {boolean} true when the matching widgetDef is an integration widget\n\t\t */\n\t\tisIntegration(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.type === 'integration' && typeof def.integrationId === 'string'\n\t\t},\n\n\t\t/**\n\t\t * Resolve the Vue component for an integration widget, applying\n\t\t * the AD-19 surface fallback. Returns null when the integration\n\t\t * isn't registered (renders the unavailable fallback instead).\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {object|null} Vue component, or null.\n\t\t */\n\t\tresolveIntegrationWidget(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (!def || typeof def.integrationId !== 'string') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.resolveRegistryWidget(def.integrationId, this.surface)\n\t\t},\n\n\t\t/**\n\t\t * Props passed to an integration widget: the rendering surface,\n\t\t * the (optional) object context, and any extra `props` declared\n\t\t * on the widget definition (per-widget props win on overlap).\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {object} Props object for the widget component.\n\t\t */\n\t\tgetIntegrationProps(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn {\n\t\t\t\tsurface: this.surface,\n\t\t\t\t...(this.integrationContext || {}),\n\t\t\t\t...(def?.props || {}),\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The registry provider descriptor behind an integration widget def,\n\t\t * carrying `mount`/`unmount` when it is a mount-mode leaf\n\t\t * (openregister#2127). Null when unregistered.\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {object|null} Provider descriptor, or null.\n\t\t */\n\t\tintegrationProviderFor(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (!def || typeof def.integrationId !== 'string' || typeof this.getRegistryProvider !== 'function') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.getRegistryProvider(def.integrationId)\n\t\t},\n\n\t\t/**\n\t\t * Whether an integration widget resolves to a mount-mode leaf\n\t\t * (`renderMode: 'mount'`) — rendered through CnLeafMountHost rather\n\t\t * than as a component under the host's Vue runtime.\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {boolean} true when the integration is mount-mode.\n\t\t */\n\t\tisMountIntegration(item) {\n\t\t\tif (!this.isIntegration(item)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst provider = this.integrationProviderFor(item)\n\t\t\treturn Boolean(provider)\n\t\t\t\t&& provider.renderMode === 'mount'\n\t\t\t\t&& typeof provider.mount === 'function'\n\t\t\t\t&& typeof provider.unmount === 'function'\n\t\t},\n\n\t\t/**\n\t\t * Props forwarded to a mount-mode leaf's `mount(el, props)` — the same\n\t\t * context an SFC integration widget receives, plus an explicit\n\t\t * `integrationContext` bag for leaves that read it directly.\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {object} Mount props.\n\t\t */\n\t\tgetIntegrationMountProps(item) {\n\t\t\treturn {\n\t\t\t\t...this.getIntegrationProps(item),\n\t\t\t\tintegrationContext: { ...(this.integrationContext || {}) },\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether this layout item resolves to a chart-typed widget\n\t\t * definition. Mirrors `isTile` and `isNcWidget`. Used by the\n\t\t * dispatcher template to mount CnChartWidget.\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {boolean} true when the matching widgetDef.type is 'chart'\n\t\t */\n\t\tisChart(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.type === 'chart'\n\t\t},\n\n\t\t/**\n\t\t * Whether this layout item resolves to a stats-block widget\n\t\t * definition. Mirrors `isChart`. Used by the dispatcher\n\t\t * template to mount CnStatsBlockWidget.\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {boolean} true when the matching widgetDef.type is 'stats-block'\n\t\t */\n\t\tisStatsBlock(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.type === 'stats-block'\n\t\t},\n\n\t\t/**\n\t\t * Read the manifest `dataSource` block from a widget\n\t\t * definition. Returns `null` when none is set so the child\n\t\t * components can render their fallback (or stay loading).\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {object|null} The dataSource block or null\n\t\t */\n\t\tgetWidgetDataSource(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\t// Prefer the in-app-editable `content.dataSource` (ADR-041), else the\n\t\t\t// legacy top-level manifest `dataSource`.\n\t\t\treturn (def?.content && def.content.dataSource) || def?.dataSource || null\n\t\t},\n\n\t\t/**\n\t\t * Build the v-bind payload for CnStatsBlockWidget from a\n\t\t * stats-block widget definition. Forwards `props.countLabel`,\n\t\t * `props.variant`, `props.showZeroCount`, `props.horizontal`,\n\t\t * `props.route`, and `props.iconClass` plus the widgetDef's\n\t\t * `title`. The `dataSource` is bound separately by the template\n\t\t * (see `getWidgetDataSource`) so the prop appears clearly in\n\t\t * the template even when it lives on the widgetDef root.\n\t\t *\n\t\t * `iconClass` is a Nextcloud core CSS class (`icon-link`, …)\n\t\t * applied to the widget's wrapping `<div>` — a lightweight icon\n\t\t * path that doesn't require MDI dynamic-import. See\n\t\t * CnStatsBlockWidget for usage notes.\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {object} v-bind payload for CnStatsBlockWidget\n\t\t */\n\t\tgetStatsBlockProps(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\t// In-app-editable cards carry config in `content` (set by\n\t\t\t// CnStatsBlockWidgetForm); legacy manifests use top-level props.\n\t\t\tconst content = def?.content || {}\n\t\t\tconst props = content.props || def?.props || {}\n\t\t\tconst out = { title: content.title || def?.title || item.widgetId }\n\t\t\t// `vertical` / `filled` carry the KPI card's look. They are the\n\t\t\t// library's own defaults, so a manifest need not set them — but a\n\t\t\t// manifest that DOES set them must reach the component, or the\n\t\t\t// declaration is a silent no-op that reads like configuration.\n\t\t\tfor (const key of ['countLabel', 'variant', 'showZeroCount', 'horizontal', 'vertical', 'filled', 'route', 'iconClass', 'format', 'layout']) {\n\t\t\t\tif (props[key] !== undefined) {\n\t\t\t\t\tout[key] = props[key]\n\t\t\t\t}\n\t\t\t}\n\t\t\t// `content.layout: \"stacked\"`, the key a stat tile takes, works on\n\t\t\t// a stats block too (zuiddrecht-pixel-gaps-3).\n\t\t\tif (out.layout === undefined && typeof content.layout === 'string') {\n\t\t\t\tout.layout = content.layout\n\t\t\t}\n\t\t\t// `countLabel` is the unit beside the number (\"0 cases\", \"0 tasks\").\n\t\t\t// It is manifest-authored prose and was being forwarded raw, so a\n\t\t\t// Dutch account read \"0 cases\" beside a translated widget title.\n\t\t\t// The other keys in the loop are enums, booleans, routes and class\n\t\t\t// names, none of which are translatable.\n\t\t\tif (typeof out.countLabel === 'string' && out.countLabel) {\n\t\t\t\tout.countLabel = this.effectiveTranslate(out.countLabel)\n\t\t\t}\n\t\t\t// Multi-entry mode (ADR-049): prefer `content.entries`, then\n\t\t\t// `props.entries`. A legacy manifest that declared `entries` at the\n\t\t\t// widgetDef ROOT (a common opencatalogi shape) was silently dropped\n\t\t\t// because the dispatcher only forwards `content` — honour it with a\n\t\t\t// one-time deprecation warning so those cards render while authors\n\t\t\t// migrate the key under `content`.\n\t\t\t// Grid layout (`layout: \"grid\"`): stat tiles in columns.\n\t\t\tconst stats = content.stats !== undefined ? content.stats : props.stats\n\t\t\tif (Array.isArray(stats)) {\n\t\t\t\tout.stats = stats\n\t\t\t}\n\t\t\tconst columns = content.columns !== undefined ? content.columns : props.columns\n\t\t\tif (columns !== undefined) {\n\t\t\t\tout.columns = Number(columns)\n\t\t\t}\n\t\t\t// `tiles: \"box\"`: each grid tile on a surface of its own.\n\t\t\tconst tiles = content.tiles !== undefined ? content.tiles : props.tiles\n\t\t\tif (typeof tiles === 'string') {\n\t\t\t\tout.tiles = tiles\n\t\t\t}\n\t\t\tconst contentEntries = content.entries !== undefined ? content.entries : props.entries\n\t\t\tif (contentEntries !== undefined) {\n\t\t\t\tout.entries = contentEntries\n\t\t\t} else if (Array.isArray(def?.entries)) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[CnDashboardPage] stats-block \"${item.widgetId}\" declares \\`entries\\` at the widget-def root — `\n\t\t\t\t\t+ 'move it under `content.entries`. Root-level `entries` is deprecated and will stop being read.')\n\t\t\t\tout.entries = def.entries\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Build the v-bind payload for CnChartWidget from a chart-typed\n\t\t * widget definition. Translates `props.chartKind` → `type` (so\n\t\t * the manifest's free-form `chartKind` does not collide with\n\t\t * apexcharts' own reserved `type` prop) and forwards the\n\t\t * supported subset (`series`, `categories`, `labels`, `options`,\n\t\t * `colors`, `toolbar`, `legend`, `height`, `width`,\n\t\t * `unavailableLabel`, plus the display passthrough `horizontal`,\n\t\t * `legendPosition`, `valueFormat`, `colorMap`, `emptyLabel`).\n\t\t *\n\t\t * Unknown keys on `props` (including the reserved `dataSource`\n\t\t * union) are ignored at render time so manifest authors can ship\n\t\t * forward-compatible declarations.\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {object} v-bind payload for CnChartWidget\n\t\t */\n\t\tgetChartProps(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\t// In-app-editable charts (ADR-041) carry their config in `content`\n\t\t\t// (set by CnChartWidgetForm); legacy manifest charts use `props`.\n\t\t\tconst content = def?.content || {}\n\t\t\tconst props = content.props || def?.props || {}\n\t\t\tconst out = {}\n\t\t\tconst chartKind = content.chartKind || props.chartKind\n\t\t\tif (chartKind) {\n\t\t\t\tout.type = chartKind\n\t\t\t}\n\t\t\tfor (const key of CHART_PROP_KEYS) {\n\t\t\t\tconst v = content[key] !== undefined ? content[key] : props[key]\n\t\t\t\tif (v !== undefined) {\n\t\t\t\t\tout[key] = v\n\t\t\t\t}\n\t\t\t}\n\t\t\t// A dashboard tile's height is fixed by its grid units, so the chart\n\t\t\t// has to fit the tile — CnChartWidget's standalone default is a\n\t\t\t// pinned 250px, which is taller than the content box of a typical\n\t\t\t// h=4 tile (4 × cellHeight, less the widget header) and turned every\n\t\t\t// chart tile into a scroll region: the tile scrolled the graph\n\t\t\t// instead of showing it. An authored `height` still wins, so a\n\t\t\t// manifest can pin one deliberately.\n\t\t\tif (out.height === undefined) {\n\t\t\t\tout.height = '100%'\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Whether a chart tile's graph sizes itself to the tile — i.e. the\n\t\t * resolved height is a percentage. Only those tiles get the\n\t\t * `chart-fit` class, whose `overflow: hidden` is what stops the\n\t\t * wrapper showing a scrollbar for a sub-pixel rounding difference.\n\t\t *\n\t\t * An AUTHORED pixel height survives `getChartProps`, and clipping that\n\t\t * is not a rounding difference: on a tile shorter than the authored\n\t\t * height the bottom of the graph became unreachable, with the scroll\n\t\t * affordance removed. Such a tile keeps the wrapper's default\n\t\t * `overflow: auto` so the graph stays reachable.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {boolean} True when the chart fits its tile.\n\t\t */\n\t\tisChartFitted(item) {\n\t\t\tconst height = this.getChartProps(item).height\n\t\t\treturn typeof height === 'string' && height.trim().endsWith('%')\n\t\t},\n\n\t\thasWidgetSlot(widgetId) {\n\t\t\treturn !!this.$slots['widget-' + widgetId]\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-dashboard-page {\n\tpadding: 20px;\n\tmax-width: 1800px;\n\t/* Centre the leftover space once the cap engages, so a wide screen shows\n\t an even gutter instead of one dead column on the right. Matches\n\t .cn-detail-page. */\n\tmargin-inline: auto;\n\t/* Scroll the dashboard itself when its widgets are taller than the host\n\t region (height:100% is a no-op when the host height is content-sized, so\n\t this only kicks in when an ancestor constrains the height). */\n\theight: 100%;\n\toverflow-y: auto;\n\tbox-sizing: border-box;\n}\n\n.cn-dashboard-page__header {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: flex-start;\n\tmargin-bottom: 20px;\n\tflex-wrap: wrap;\n\tgap: 12px;\n\t/* Clear the Nextcloud navigation toggle button (44px wide, absolutely\n\t positioned at the left edge of .app-content) plus 12px breathing\n\t room. Only the HEADER shifts right — body widgets keep full width. */\n\tpadding-inline-start: 56px;\n}\n\n.cn-dashboard-page__header-left {\n\tmin-width: 0;\n}\n\n.cn-dashboard-page__title-row {\n\tdisplay: flex;\n\talign-items: center;\n\tflex-wrap: wrap;\n\tgap: 12px;\n}\n\n.cn-dashboard-page__title {\n\tmargin: 0;\n\tfont-size: 20px;\n\tfont-weight: 700;\n}\n\n.cn-dashboard-page__description {\n\tmargin: 4px 0 0;\n\tfont-size: 14px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* Board look (screens-dashboard-parity): h1 28/700, a 15px grey subtitle 6px\n under it, and 40px buttons with a 10px gap. */\n.cn-dashboard-page--board .cn-dashboard-page__title {\n\tfont-size: 28px;\n\tfont-weight: 700;\n\tline-height: 1.2;\n}\n\n.cn-dashboard-page--board .cn-dashboard-page__description {\n\tmargin: 6px 0 0;\n\tfont-size: 15px;\n}\n\n.cn-dashboard-page--board .cn-dashboard-page__header-actions {\n\tgap: 10px;\n}\n\n.cn-dashboard-page--board .cn-dashboard-page__header-actions :deep(.button-vue) {\n\tmin-height: var(--cn-board-control-height, 40px);\n\theight: var(--cn-board-control-height, 40px);\n}\n\n/* The switch row under the header (screens-dashboard-greeting-header): the\n view switch left, the `viewLinks` pills right (DqMijnWerk: pills 34px high,\n radius 17, 13px/600, a 14px icon, primary light on primary deep). */\n.cn-dashboard-page__switch-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 10px;\n\tmargin-bottom: var(--cn-board-section-gap, 20px);\n}\n\n.cn-dashboard-page__switch-row-spacer {\n\tflex: 1 1 auto;\n}\n\n.cn-dashboard-page__view-link {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\theight: 34px;\n\tpadding: 0 12px;\n\tborder-radius: 17px;\n\tbackground: var(--color-primary-element-light);\n\tcolor: var(--color-primary-element-light-text);\n\tfont-size: 13px;\n\tfont-weight: 600;\n\twhite-space: nowrap;\n\ttext-decoration: none !important;\n}\n\n.cn-dashboard-page__view-link:hover {\n\tbackground: var(--color-primary-element-light-hover, var(--color-primary-element-light));\n}\n\n.cn-dashboard-page__view-link:focus-visible {\n\toutline: 2px solid var(--color-main-text);\n\toutline-offset: 2px;\n}\n\n.cn-dashboard-page__view-link-icon {\n\tdisplay: inline-flex;\n}\n\n/* The period group, in a row of its own between the header and the KPI row. */\n.cn-dashboard-page__date-range--segmented {\n\tmargin-bottom: 16px;\n}\n\n/* The period group at the end of the description line. */\n.cn-dashboard-page__description--with-period {\n\talign-items: center;\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n}\n\n/* A select on the description line takes the width of its choice, not a\n form field's, and no margin of its own. */\n.cn-dashboard-page__description-select {\n\tmin-width: 180px;\n\tmax-width: 280px;\n\tmargin: 0;\n}\n\n.cn-dashboard-page__date-segmented {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n}\n\n/* The KPI row above the grid: tiles are cells of the auto-fit grid. */\n.cn-dashboard-page__kpi-row {\n\tmargin-bottom: var(--cn-board-section-gap, 16px);\n}\n\n/* Board look: GridStack insets every card by the grid margin on each side, so\n the cards started a margin to the right of the KPI row and the header. The\n grid reaches out by that margin, so the card edges line up with the page's\n (dashboard-grid-flush). */\n.cn-dashboard-page--board :deep(.cn-dashboard-grid) {\n\twidth: auto;\n\tmargin-inline: calc(-1 * var(--cn-dashboard-grid-margin, 12px));\n}\n\n.cn-dashboard-page__kpi-cell {\n\tdisplay: flex;\n\tmin-width: 0;\n}\n\n.cn-dashboard-page__kpi-cell > * {\n\tflex: 1 1 auto;\n\tmin-width: 0;\n}\n\n/* NOTE: the date-range chip's trigger/chip/preset-spacer rules live in the\n UNSCOPED <style> block below, anchored on the trigger's `data-testid`, not\n here. Consumers (pipelinq, …) split the library across webpack chunks with\n no shared runtime chunk, so a rendered CnDashboardPage instance can carry a\n different `data-v-*` scope id than the one baked into this scoped CSS — the\n scoped chip rules then silently don't match and the chip collapses into\n NcActions' ~30px icon slot (text wraps to \"Last / 30 / days\"). The\n data-testid is stable across chunks, so those rules match regardless. */\n\n.cn-dashboard-page__header-actions {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\tflex-shrink: 0;\n\t/* Keeps the actions hard right even when a wide action set (pipelinq's six\n\t buttons) wraps onto its own line. The header's `justify-content:\n\t space-between` only distributes items WITHIN a line, so once the actions\n\t wrap they become the sole item on line 2 and would otherwise sit flush\n\t left, under the title. No-op while title and actions share a line. */\n\tmargin-left: auto;\n}\n\n/* Date-range header band. Kept compact so it doesn't open a tall gap\n above the grid; the pills variant is a single tidy toggle row. */\n.cn-dashboard-page__date-range {\n\tmargin-bottom: 12px;\n}\n\n.cn-dashboard-page__date-range--pills {\n\tmargin-bottom: 8px;\n}\n\n.cn-dashboard-page__date-pills {\n\tdisplay: flex;\n\talign-items: center;\n\tflex-wrap: wrap;\n\tgap: 6px;\n}\n\n.cn-dashboard-page__date-pill {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tpadding: 5px 14px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: 999px;\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tline-height: 1.2;\n\twhite-space: nowrap;\n\tcursor: pointer;\n\ttransition: background-color 100ms ease, border-color 100ms ease, color 100ms ease;\n}\n\n.cn-dashboard-page__date-pill:hover {\n\tbackground: var(--color-background-hover);\n}\n\n.cn-dashboard-page__date-pill:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n.cn-dashboard-page__date-pill--active {\n\tbackground: var(--color-primary-element);\n\tborder-color: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n}\n\n.cn-dashboard-page__date-pill--active:hover {\n\tbackground: var(--color-primary-element-hover, var(--color-primary-element));\n}\n\n/* The custom-range pill is de-emphasised — dashed outline, muted text —\n so it reads as an escape hatch rather than a primary option. */\n.cn-dashboard-page__date-pill--custom {\n\tborder-style: dashed;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-dashboard-page__date-pill-custom :deep(.action-item__menutoggle) {\n\tmin-width: 0;\n\tmin-height: 0;\n\tpadding: 0;\n\tbackground: transparent;\n\tborder: none;\n}\n\n.cn-dashboard-page__date-pill-custom :deep(.button-vue),\n.cn-dashboard-page__date-pill-custom :deep(.button-vue__wrapper),\n.cn-dashboard-page__date-pill-custom :deep(.button-vue__icon) {\n\twidth: auto !important;\n\tmin-width: 0 !important;\n\toverflow: visible !important;\n}\n\n.cn-dashboard-page__empty {\n\tpadding: 60px 20px;\n}\n\n/* The page's view switch on a page without a header row: at the end of its\n own row, above the grids, where the header would have put it. */\n.cn-dashboard-page__view-switch {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\tmargin-bottom: 12px;\n}\n\n/* A view the switch shows with nothing to draw. */\n.cn-page-view-region--empty {\n\tpadding: 40px 20px;\n}\n\n.cn-dashboard-page__page-filters {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 16px;\n\talign-items: flex-end;\n\tmargin-bottom: 12px;\n}\n\n.cn-dashboard-page__page-filter {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmin-width: 200px;\n}\n\n.cn-dashboard-page__page-filter-label {\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-dashboard-page__widget-edit {\n\tposition: absolute;\n\ttop: 4px;\n\tinset-inline-end: 4px;\n\tz-index: 5;\n\tbackground: var(--color-main-background);\n\tborder-radius: var(--border-radius);\n\tbox-shadow: 0 1px 4px var(--color-box-shadow, rgba(0, 0, 0, 0.2));\n}\n\n/* Card-fit registry widgets (stat / gauge / delta): the tile content is a\n self-contained card that should size to the tile and centre vertically,\n never scroll. CnWidgetWrapper's content area defaults to overflow:auto +\n 16px padding, which produced stray scrollbars on short KPI / gauge tiles\n and a horizontal scrollbar when a long currency value met the icon. Here\n we drop the inner scroll, add comfortable padding back (flush removed it),\n and centre the card. */\n/* `safe` centre so an overflowing tile does not spill out of the top, where\n flex overflow cannot be scrolled back to. Same as detail-page.css. */\n.cn-dashboard-page__card-fit :deep(.cn-widget-wrapper__content),\n.cn-dashboard-page__card-fit.cn-widget-wrapper--flush :deep(.cn-widget-wrapper__content) {\n\toverflow: hidden;\n\tdisplay: flex;\n\tflex-direction: column;\n\tjustify-content: center;\n\tjustify-content: safe center;\n\tpadding: 8px 14px;\n}\n\n/* Chart tiles whose graph FITS the tile (see isChartFitted — a percentage\n height, which getChartProps supplies unless the author pinned pixels), so\n the wrapper's default `overflow: auto` content area has nothing to scroll —\n and leaving it on means any rounding difference between the box and the SVG\n shows up as a scrollbar the user has to drag to see the whole graph. Same\n shape as the card-fit rule above, minus the padding: chart tiles render\n `flush`, and apexcharts already draws its own margins. */\n.cn-dashboard-page__chart-fit :deep(.cn-widget-wrapper__content) {\n\toverflow: hidden;\n\tdisplay: flex;\n\tflex-direction: column;\n\tmin-height: 0;\n}\n\n/* Card content (stat / gauge / delta) must fit the tile width: let the\n widget shrink and its value/label truncate instead of pushing past the\n tile edge (the horizontal clip on long currency values). */\n.cn-dashboard-page__card-fit :deep(.cn-stat-widget),\n.cn-dashboard-page__card-fit :deep(.cn-gauge-widget),\n.cn-dashboard-page__card-fit :deep(.cn-delta-widget) {\n\tmin-width: 0;\n\tmax-width: 100%;\n}\n\n.cn-dashboard-page__unknown {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\theight: 100%;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n\tpadding: 16px;\n}\n\n/* widget-ref content items */\n.cn-dashboard-page__content {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 16px;\n}\n\n.cn-dashboard-page__content-item {\n\twidth: 100%;\n}\n/* On a phone (screens-dashboard-phone) the touch targets of a board dashboard\n are 44px: the widget Actions menu and the KPI tiles. */\n@media (max-width: 640px) {\n\t.cn-dashboard-page--board :deep(.cn-widget-wrapper__actions .action-item__menutoggle),\n\t.cn-dashboard-page--board :deep(.cn-widget-wrapper__actions .button-vue) {\n\t\tmin-height: 44px;\n\t}\n\n\t.cn-dashboard-page--board .cn-dashboard-page__kpi-cell {\n\t\tmin-height: 44px;\n\t}\n\n\t/* The widget Actions menu shows its icon only, so the card title keeps\n\t the room; the name stays for assistive tech. */\n\t.cn-dashboard-page--board :deep(.cn-widget-wrapper__actions .action-item__menutoggle) {\n\t\tmin-width: 44px;\n\t}\n\n\t.cn-dashboard-page--board :deep(.cn-widget-wrapper__actions .action-item__menutoggle .button-vue__text) {\n\t\tposition: absolute;\n\t\twidth: 1px;\n\t\theight: 1px;\n\t\toverflow: hidden;\n\t\tclip-path: inset(50%);\n\t\twhite-space: nowrap;\n\t}\n}\n\n/* What a registry widget reports for its card header (`header` event): the\n note beside the link (\"3 in total\") and one action, as on a detail page. */\n.cn-dashboard-page__widget-count {\n\talign-self: center;\n\tpadding: 1px 8px;\n\tborder-radius: 10px;\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n\tfont-size: 13px;\n\tfont-weight: 600;\n}\n\n.cn-dashboard-page__widget-note {\n\talign-self: center;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n\twhite-space: nowrap;\n}\n\n.cn-dashboard-page__widget-action {\n\tdisplay: inline-flex;\n\talign-items: center;\n\talign-self: center;\n\tmin-height: 32px;\n\tpadding: 0 14px;\n\tborder: 0;\n\tborder-radius: 16px;\n\tbackground: var(--color-primary-element-light);\n\tcolor: var(--color-primary-element-light-text, var(--color-primary-element));\n\tfont: inherit;\n\tfont-size: 13px;\n\tfont-weight: 700;\n\twhite-space: nowrap;\n\tcursor: pointer;\n}\n\n.cn-dashboard-page__widget-action:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n</style>\n\n<!-- Unscoped, anchored on the stable `data-testid` NcActions renders on both\n the trigger and (forwarded) the teleported <body> popper. Everything about\n the date chip lives here rather than in scoped CSS because a consumer that\n splits the library across webpack chunks (pipelinq) can render a\n CnDashboardPage instance whose `data-v-*` scope id differs from the one\n compiled into the scoped stylesheet — scoped rules then don't match and the\n chip collapses into NcActions' ~30px icon slot. The data-testid is chunk-\n stable, so these rules always match. Classes stay `cn-`-prefixed so the\n unscoped rules can't collide with anything outside this widget. -->\n<style>\n/* Trigger: strip NcActions' default button chrome down to just the chip span. */\n[data-testid^=\"cn-dashboard-page-date-chip-\"].cn-dashboard-page__date-chip-trigger {\n\tdisplay: inline-flex;\n}\n\n/* The toggle is a chrome-less carrier for the pill — the pill IS the control.\n NcButton paints its own background, ~30px box and `--border-radius-element`\n corners on hover / focus / :active / aria-expanded; left alone that draws a\n rounded SQUARE behind (and around) the wider, fully-rounded pill. Every\n state is neutralised with `!important` because NcButton's own state rules\n are more specific than a plain class selector. */\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-item__menutoggle,\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-item__menutoggle:hover,\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-item__menutoggle:focus,\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-item__menutoggle:focus-visible,\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-item__menutoggle:active,\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-item__menutoggle[aria-expanded=\"true\"] {\n\tmin-width: 0 !important;\n\tmin-height: 0 !important;\n\theight: auto !important;\n\tpadding: 0 !important;\n\tbackground: transparent !important;\n\tbackground-color: transparent !important;\n\tborder: none !important;\n\tbox-shadow: none !important;\n\tborder-radius: 999px;\n}\n\n/* The chip text lives in NcActions' icon slot, whose default toggle is sized\n for a single icon and clips/wraps wider content. Let the toggle + its icon\n wrapper grow to the chip's natural width so \"Last 30 days\" reads on one\n line — and keep them shrink-wrapped so the pill isn't offset inside a wider\n box (which is what pushed the chip outside its own trigger). */\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .button-vue,\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .button-vue__wrapper,\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .button-vue__icon {\n\twidth: auto !important;\n\tmin-width: 0 !important;\n\theight: auto !important;\n\tmin-height: 0 !important;\n\toverflow: visible !important;\n}\n\n/* The width above is NOT enough on its own, and this rule is what actually\n frees the pill. NcButton pins an icon-only button to a square clickable area\n with an `!important` of its own:\n\n .button-vue[data-v-…]:has(.button-vue__text:empty):not(.button-vue--wide) {\n width: var(--button-size) !important; // --default-clickable-area, 34px\n }\n\n NcActions fills the trigger's text slot from its `menuName` prop, which the\n chip does not use (its label is markup, not a string), so `.button-vue__text`\n renders empty and that rule always matches here. Two `!important`\n declarations are settled by SPECIFICITY, and theirs is (0,5,0) against the\n (0,2,0) of the plain descendant selector above — so the button stayed 34px\n wide while its icon wrapper grew to the pill's ~106px. Combined with the\n `overflow: visible` above, the pill then rendered centred on a 34px box and\n spilled ~36px out each side, over the widget title.\n\n This selector re-states their `:has()` predicate — so it applies exactly\n where theirs does, and drops out with it on a browser without `:has()` — and\n adds the trigger's own three hooks, reaching (0,7,0). Keep it ahead of\n whatever NcButton declares: tests/components/CnDashboardPageDateChip.spec.js\n reads both selectors out of the installed NcButton stylesheet and fails when\n this margin disappears. */\n[data-testid^=\"cn-dashboard-page-date-chip-\"].cn-dashboard-page__date-chip-trigger.action-item\n\t.button-vue.action-item__menutoggle:has(.button-vue__text:empty) {\n\twidth: auto !important;\n\tmin-width: 0 !important;\n}\n\n.cn-dashboard-page__date-chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\t/* Breathing room from the widget title / header edge — the chip sits in\n\t CnWidgetWrapper's `#title-meta` slot, flush against its neighbours. */\n\tmargin-inline: 4px;\n\tpadding: 2px 10px;\n\tborder-radius: 999px;\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 12px;\n\tfont-variant-numeric: tabular-nums;\n\twhite-space: nowrap;\n\tcursor: pointer;\n\ttransition: background 100ms ease, color 100ms ease;\n}\n\n[data-testid^=\"cn-dashboard-page-date-chip-\"]:hover .cn-dashboard-page__date-chip,\n[data-testid^=\"cn-dashboard-page-date-chip-\"]:focus-within .cn-dashboard-page__date-chip {\n\tbackground: var(--color-primary-element-light, var(--color-background-darker));\n\tcolor: var(--color-main-text);\n}\n\n/* Open state: the pill itself goes primary. The active affordance is the\n pill's own colour — never a separate box painted behind it. */\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-item__menutoggle[aria-expanded=\"true\"] .cn-dashboard-page__date-chip {\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n}\n\n/* Keyboard focus needs a visible ring now that the button chrome is gone. */\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-item__menutoggle:focus-visible .cn-dashboard-page__date-chip {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n/* Empty span keeping preset NcActionButtons' labels aligned with the row that\n shows the current-selection CalendarRange icon (NcActionButton icon slot is\n ~20px). Lives in the teleported popper, so it's unscoped too. */\n.cn-dashboard-page__date-chip-preset-spacer {\n\tdisplay: inline-block;\n\twidth: 16px;\n\theight: 16px;\n}\n\n.action-item__popper[data-testid^=\"cn-dashboard-page-date-chip-\"] .v-popper__inner,\n[data-testid^=\"cn-dashboard-page-date-chip-\"].v-popper__popper .v-popper__inner {\n\toverflow: visible;\n}\n\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-input__form,\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-input {\n\tmin-width: 240px;\n}\n</style>\n"],"names":["CnHeaderTrail","CnEmptyContent","CnDashboardGrid","CnWidgetWrapper","CnWidgetRenderer","CnTileWidget","CnChartWidget","CnStatsBlockWidget","CnWidgetRefItem","CnBodySections","CnDateRangePicker","CnActionsMenu","CnActionButtons","CnBuildiqEditButton","CnWidgetStyleEditorModal","CnLeafMountHost","CnSegmentedControl","CnKpiGrid","CnWidgetIcon","t"],"mappings":"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"}
1
+ {"version":3,"file":"CnDashboardPage.vue2.js","sources":["../../../../src/components/CnDashboardPage/CnDashboardPage.vue"],"sourcesContent":["<!--\n CnDashboardPage — Top-level dashboard page with GridStack widget grid.\n\n The dashboard equivalent of CnIndexPage. Assembles a complete dashboard\n from a widget definition array and a layout array. Supports:\n - Custom widgets via scoped slots (#widget-{widgetId})\n - Nextcloud Dashboard API widgets (auto-rendered)\n - Tile widgets (quick-access links)\n - Drag-and-drop editing mode\n - Header with title, actions, and edit toggle\n-->\n<template>\n\t<div\n\t\tclass=\"cn-dashboard-page\"\n\t\t:class=\"{ 'cn-dashboard-page--board': isBoardLook }\"\n\t\t:style=\"{ '--cn-dashboard-grid-margin': `${gridMargin}px` }\"\n\t\tdata-testid=\"cn-dashboard-page\">\n\t\t<!-- Header. `showHeader: false` drops the whole row (title, description,\n\t\t header actions, edit toggle) for a page that opens with its own\n\t\t heading, such as a greeting; the title then stays as a visually\n\t\t hidden heading so the main landmark keeps its name. -->\n\t\t<h2 v-if=\"!showHeader && title\" class=\"hidden-visually\" data-testid=\"cn-dashboard-page-hidden-title\">\n\t\t\t{{ resolvedTitle }}\n\t\t</h2>\n\t\t<div v-if=\"showHeader\" class=\"cn-dashboard-page__header\" data-testid=\"cn-dashboard-page-header\">\n\t\t\t<div class=\"cn-dashboard-page__header-left\">\n\t\t\t\t<div v-if=\"title || $slots['title-meta']\" class=\"cn-dashboard-page__title-row\">\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"isBoardLook ? 'h1' : 'h2'\"\n\t\t\t\t\t\tv-if=\"title\"\n\t\t\t\t\t\tclass=\"cn-dashboard-page__title\">\n\t\t\t\t\t\t{{ resolvedTitle }}\n\t\t\t\t\t</component>\n\t\t\t\t\t<!-- @slot title-meta Content on the title's row, right of the title (e.g. a page-wide picker). Fill it from a manifest with `page.slots: { \"title-meta\": \"<RegistryName>\" }`. -->\n\t\t\t\t\t<slot name=\"title-meta\" />\n\t\t\t\t</div>\n\t\t\t\t<CnHeaderTrail\n\t\t\t\t\t:breadcrumb=\"breadcrumb\"\n\t\t\t\t\t:current=\"title ? resolvedTitle : ''\"\n\t\t\t\t\t:meta=\"resolvedHeaderMeta\" />\n\t\t\t\t<!-- `dateRange.placement: \"description\"`: the segmented period\n\t\t\t\t group ends the description line, after its page filters\n\t\t\t\t (\"Week 41 · alle teams · [Deze week | Dit kwartaal | Dit jaar]\"). -->\n\t\t\t\t<div\n\t\t\t\t\tv-if=\"datePeriodInDescription || descriptionFilters.length > 0\"\n\t\t\t\t\tclass=\"cn-dashboard-page__description cn-dashboard-page__description--with-period\"\n\t\t\t\t\tdata-testid=\"cn-dashboard-page-subtitle\">\n\t\t\t\t\t<span v-if=\"subtitleText\">{{ subtitleText }}</span>\n\t\t\t\t\t<span v-if=\"subtitleText\" aria-hidden=\"true\">&middot;</span>\n\t\t\t\t\t<!-- The page filters with `placement: \"description\"`, in the\n\t\t\t\t\t order the page declares them: a select as a compact\n\t\t\t\t\t select (DqDoorlooptijd \"alle zaaktypen\"), a\n\t\t\t\t\t `control: \"segmented\"` one as a segmented group that\n\t\t\t\t\t writes the workspace context (DqProcesanalyse\n\t\t\t\t\t \"Gemiddeld | Mediaan\"). -->\n\t\t\t\t\t<template v-for=\"(pf, pfIndex) in descriptionFilters\" :key=\"pf.key\">\n\t\t\t\t\t\t<CnSegmentedControl\n\t\t\t\t\t\t\tv-if=\"pf.control === 'segmented'\"\n\t\t\t\t\t\t\tsize=\"compact\"\n\t\t\t\t\t\t\tmode=\"toggle\"\n\t\t\t\t\t\t\t:options=\"pageFilterSegments(pf)\"\n\t\t\t\t\t\t\t:modelValue=\"workspaceContext[pf.key]\"\n\t\t\t\t\t\t\t:ariaLabel=\"pf.label ? effectiveTranslate(pf.label) : pf.key\"\n\t\t\t\t\t\t\t:data-testid=\"'cn-page-filter-' + pf.key\"\n\t\t\t\t\t\t\t@update:modelValue=\"onPageFilterChange(pf, $event)\" />\n\t\t\t\t\t\t<template v-else>\n\t\t\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t\t\tclass=\"cn-dashboard-page__description-select\"\n\t\t\t\t\t\t\t\t:modelValue=\"selectedPageFilterOption(pf)\"\n\t\t\t\t\t\t\t\t:options=\"pageFilterSegments(pf)\"\n\t\t\t\t\t\t\t\t:clearable=\"pf.clearable === true\"\n\t\t\t\t\t\t\t\t:placeholder=\"pf.placeholder ? effectiveTranslate(pf.placeholder) : undefined\"\n\t\t\t\t\t\t\t\t:loading=\"pageFilterLoading[pf.key] === true\"\n\t\t\t\t\t\t\t\t:ariaLabelCombobox=\"pf.label ? effectiveTranslate(pf.label) : pf.key\"\n\t\t\t\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t\t\t\t:data-testid=\"'cn-page-filter-' + pf.key\"\n\t\t\t\t\t\t\t\t@update:modelValue=\"onPageFilterChange(pf, $event)\" />\n\t\t\t\t\t\t\t<span v-if=\"segmentedFollows(pfIndex)\" aria-hidden=\"true\">&middot;</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</template>\n\t\t\t\t\t<CnSegmentedControl\n\t\t\t\t\t\tv-if=\"datePeriodInDescription\"\n\t\t\t\t\t\tsize=\"compact\"\n\t\t\t\t\t\tmode=\"toggle\"\n\t\t\t\t\t\t:options=\"segmentedOptions\"\n\t\t\t\t\t\t:modelValue=\"segmentedValue\"\n\t\t\t\t\t\t:ariaLabel=\"datePeriodLabel\"\n\t\t\t\t\t\tdata-testid=\"cn-dashboard-page-date-segmented\"\n\t\t\t\t\t\t@update:modelValue=\"onSegmentPick\" />\n\t\t\t\t</div>\n\t\t\t\t<p v-else-if=\"subtitleText\" class=\"cn-dashboard-page__description\" data-testid=\"cn-dashboard-page-subtitle\">\n\t\t\t\t\t{{ subtitleText }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t\t<div class=\"cn-dashboard-page__header-actions\">\n\t\t\t\t<!-- The page's view switch (`views`), unless a greeting header\n\t\t\t\t widget on the page draws it. Its options control the view\n\t\t\t\t region below the grid. -->\n\t\t\t\t<CnSegmentedControl\n\t\t\t\t\tv-if=\"showsPageViewSwitch && !switchInRow\"\n\t\t\t\t\tclass=\"cn-page-view-switch\"\n\t\t\t\t\t:options=\"viewSwitchOptions\"\n\t\t\t\t\t:modelValue=\"activeViewId\"\n\t\t\t\t\t:ariaLabel=\"viewSwitchLabel\"\n\t\t\t\t\t:controls=\"viewRegionId\"\n\t\t\t\t\tdata-testid=\"cn-dashboard-page-view-switch\"\n\t\t\t\t\t@update:modelValue=\"selectView\" />\n\t\t\t\t<!-- Declarative header actions (#91 Wave 3): a manifest\n\t\t\t\t `headerActions[]` renders as buttons (open-form / api-call /\n\t\t\t\t toggle / navigate / refresh) with visibleWhen gating,\n\t\t\t\t before the slot content so app-provided buttons stay\n\t\t\t\t right-most next to the edit toggle. -->\n\t\t\t\t<template v-if=\"!isBoardLook\">\n\t\t\t\t\t<CnActionButtons\n\t\t\t\t\t\tv-if=\"headerActions && headerActions.length\"\n\t\t\t\t\t\t:actions=\"linkedHeaderActions\"\n\t\t\t\t\t\tdata-testid=\"cn-dashboard-page-header-actions\" />\n\t\t\t\t\t<!-- @slot header-actions Inline buttons rendered in the dashboard header next to the edit toggle. Used by every existing consumer (decidesk, launchpad, opencatalogi, pipelinq, procest). -->\n\t\t\t\t\t<slot name=\"header-actions\" />\n\t\t\t\t\t<!-- @slot actions Back-compat alias for `#header-actions`. Prefer `#header-actions` in new code. -->\n\t\t\t\t\t<slot name=\"actions\" />\n\t\t\t\t</template>\n\t\t\t\t<CnActionButtons\n\t\t\t\t\tv-else-if=\"boardSecondaryHeaderActions.length\"\n\t\t\t\t\t:actions=\"boardSecondaryHeaderActions\"\n\t\t\t\t\tdata-testid=\"cn-dashboard-page-header-actions-secondary\" />\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"allowEdit\"\n\t\t\t\t\t:variant=\"isEditing ? 'primary' : 'secondary'\"\n\t\t\t\t\t@click=\"toggleEdit\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Pencil v-if=\"!isEditing\" :size=\"20\" />\n\t\t\t\t\t\t<Check v-else :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ isEditing ? shownDoneLabel : shownEditLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<!-- With `userLayout`, edit mode offers a way back to the\n\t\t\t\t manifest: the page's own grid and the chosen view return\n\t\t\t\t to the layout the app ships. Other views keep theirs. -->\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"userLayout && isEditing\"\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\tdata-testid=\"cn-dashboard-page-reset-layout\"\n\t\t\t\t\t@click=\"resetLayout\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Restore :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ t('nextcloud-vue', 'Reset layout') }}\n\t\t\t\t</NcButton>\n\t\t\t\t<!-- In-app edit button (ADR-041). Renders only when Buildiq is\n\t\t\t\t reachable; self-wires from the cnManifestEditor / cnOpenBuildAvailable\n\t\t\t\t provided by CnAppRoot. Sits inline with the page's action buttons. -->\n\t\t\t\t<CnBuildiqEditButton v-if=\"!isBoardLook\" />\n\t\t\t\t<!-- Page-level overflow Actions menu (Refresh + the mandatory\n\t\t\t\t trio Request a feature / Report a bug / Documentation).\n\t\t\t\t Separate from the per-widget menus. `docs-anchor` deep-links\n\t\t\t\t the docs item to THIS page's section. -->\n\t\t\t\t<CnActionsMenu\n\t\t\t\t\tv-if=\"showActionsMenu\"\n\t\t\t\t\t:showRefresh=\"showRefresh\"\n\t\t\t\t\t:showRequestFeature=\"showRequestFeature\"\n\t\t\t\t\t:showReportBug=\"showReportBug\"\n\t\t\t\t\t:showDocumentation=\"showDocumentation\"\n\t\t\t\t\t:documentationUrl=\"documentationUrl\"\n\t\t\t\t\t:docsAnchor=\"resolvedPageId\"\n\t\t\t\t\t:documentationLabel=\"documentationLabel\"\n\t\t\t\t\t:refreshLabel=\"refreshLabel\"\n\t\t\t\t\t:requestFeatureLabel=\"requestFeatureLabel\"\n\t\t\t\t\t:actionsMenuLabel=\"actionsMenuLabel\"\n\t\t\t\t\t:refreshing=\"refreshing\"\n\t\t\t\t\t:widgetId=\"resolvedPageId\"\n\t\t\t\t\t:title=\"title\"\n\t\t\t\t\t:surface=\"`dashboard:${resolvedPageId}`\"\n\t\t\t\t\t:specRef=\"specRef\"\n\t\t\t\t\trefreshChannel=\"cn:page:refresh\"\n\t\t\t\t\ttestidBase=\"cn-dashboard-page\"\n\t\t\t\t\t@refresh=\"onActionsRefresh\"\n\t\t\t\t\t@requestFeature=\"onActionsRequestFeature\">\n\t\t\t\t\t<!-- @slot action-items Additional NcActionButton-family\n\t\t\t\t\t items appended inside the page-level overflow menu,\n\t\t\t\t\t after Refresh / Documentation / Request a feature. -->\n\t\t\t\t\t<template v-if=\"hasActionItemsSlot\" #action-items>\n\t\t\t\t\t\t<slot name=\"action-items\" />\n\t\t\t\t\t</template>\n\t\t\t\t</CnActionsMenu>\n\t\t\t\t<!-- Board look: the row reads the secondary header actions, Edit\n\t\t\t\t layout, Actions, the buildiq square, then the primary header\n\t\t\t\t actions rightmost (screens-dashboard-parity). -->\n\t\t\t\t<template v-if=\"isBoardLook\">\n\t\t\t\t\t<CnBuildiqEditButton />\n\t\t\t\t\t<CnActionButtons\n\t\t\t\t\t\tv-if=\"boardPrimaryHeaderActions.length\"\n\t\t\t\t\t\t:actions=\"boardPrimaryHeaderActions\"\n\t\t\t\t\t\tdata-testid=\"cn-dashboard-page-header-actions\" />\n\t\t\t\t\t<slot name=\"header-actions\" />\n\t\t\t\t\t<slot name=\"actions\" />\n\t\t\t\t</template>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- The switch row (screens-dashboard-greeting-header): in the board\n\t\t look the page's view switch sits under the header, left, and the\n\t\t page's `viewLinks` sit right of it as small pills (DqMijnWerk). -->\n\t\t<div\n\t\t\tv-if=\"showHeader && (switchInRow || resolvedViewLinks.length > 0)\"\n\t\t\tclass=\"cn-dashboard-page__switch-row\"\n\t\t\tdata-testid=\"cn-dashboard-page-switch-row\">\n\t\t\t<CnSegmentedControl\n\t\t\t\tv-if=\"switchInRow\"\n\t\t\t\tclass=\"cn-page-view-switch\"\n\t\t\t\t:options=\"viewSwitchOptions\"\n\t\t\t\t:modelValue=\"activeViewId\"\n\t\t\t\t:ariaLabel=\"viewSwitchLabel\"\n\t\t\t\t:controls=\"viewRegionId\"\n\t\t\t\tdata-testid=\"cn-dashboard-page-view-switch\"\n\t\t\t\t@update:modelValue=\"selectView\" />\n\t\t\t<span class=\"cn-dashboard-page__switch-row-spacer\" />\n\t\t\t<component\n\t\t\t\t:is=\"link.tag\"\n\t\t\t\tv-for=\"link in resolvedViewLinks\"\n\t\t\t\t:key=\"link.key\"\n\t\t\t\tv-bind=\"link.attrs\"\n\t\t\t\tclass=\"cn-dashboard-page__view-link\"\n\t\t\t\tdata-testid=\"cn-dashboard-page-view-link\">\n\t\t\t\t<CnWidgetIcon\n\t\t\t\t\tv-if=\"link.icon\"\n\t\t\t\t\t:name=\"link.icon\"\n\t\t\t\t\t:size=\"14\"\n\t\t\t\t\tclass=\"cn-dashboard-page__view-link-icon\" />\n\t\t\t\t{{ link.label }}\n\t\t\t</component>\n\t\t</div>\n\n\t\t<!-- Date-range header (optional).\n\t\t Rendered only when `dateRange.enabled === true` AND\n\t\t `dateRange.showHeaderPicker !== false`. The range STATE\n\t\t (currentRange / cnDashboardDateRange) is always initialised\n\t\t when the feature is enabled, so per-chart-widget date chips\n\t\t keep working even when this header picker is hidden — set\n\t\t `showHeaderPicker: false` to rely solely on the per-widget\n\t\t chips. The picker is wired to `currentRange` (data) which\n\t\t mirrors the provided `cnDashboardDateRange` ref; all change\n\t\t handling, persistence, and event emission lives in\n\t\t `onDateRangeChange`. -->\n\t\t<div\n\t\t\tv-if=\"showHeaderDateRange && !datePeriodInDescription\"\n\t\t\tclass=\"cn-dashboard-page__date-range\"\n\t\t\t:class=\"{\n\t\t\t\t'cn-dashboard-page__date-range--pills': dateRangeControl === 'pills',\n\t\t\t\t'cn-dashboard-page__date-range--segmented': dateRangeControl === 'segmented',\n\t\t\t}\"\n\t\t\tdata-testid=\"cn-dashboard-page-date-range\">\n\t\t\t<!-- Segmented mode (`dateRange.control: 'segmented'`): the presets as\n\t\t\t one compact segmented group in a row of its own, driving the\n\t\t\t same range change as a pill. A custom range, when offered, is\n\t\t\t the last segment and opens the from/to popover. -->\n\t\t\t<div\n\t\t\t\tv-if=\"dateRangeControl === 'segmented'\"\n\t\t\t\tclass=\"cn-dashboard-page__date-segmented\"\n\t\t\t\tdata-testid=\"cn-dashboard-page-date-segmented\">\n\t\t\t\t<CnSegmentedControl\n\t\t\t\t\tsize=\"compact\"\n\t\t\t\t\tmode=\"toggle\"\n\t\t\t\t\t:options=\"segmentedOptions\"\n\t\t\t\t\t:modelValue=\"segmentedValue\"\n\t\t\t\t\t:ariaLabel=\"datePeriodLabel\"\n\t\t\t\t\t@update:modelValue=\"onSegmentPick\" />\n\t\t\t\t<NcActions\n\t\t\t\t\tv-if=\"hasCustomPreset && currentRange && currentRange.preset === 'custom'\"\n\t\t\t\t\t:forceMenu=\"true\"\n\t\t\t\t\tcontainer=\"body\"\n\t\t\t\t\tclass=\"cn-dashboard-page__date-pill-custom\"\n\t\t\t\t\tdata-testid=\"cn-dashboard-page-date-segment-custom\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<CalendarRange :size=\"18\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange && currentRange.from)\"\n\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'From')\"\n\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('from', $event)\" />\n\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange && currentRange.to)\"\n\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'To')\"\n\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('to', $event)\" />\n\t\t\t\t</NcActions>\n\t\t\t</div>\n\t\t\t<!-- Pills mode (`dateRange.control: 'pills'`): a compact segmented\n\t\t\t toggle-button row replaces the bulky select + two date inputs.\n\t\t\t Each preset is a pill; the active one drives the dashboard window\n\t\t\t exactly like the picker does (same `onDateRangeChange`). A\n\t\t\t de-emphasised \"Custom range\" pill opens a small from/to popover\n\t\t\t so the arbitrary-window affordance is kept without two bare\n\t\t\t date inputs being always visible. -->\n\t\t\t<div\n\t\t\t\tv-else-if=\"dateRangeControl === 'pills'\"\n\t\t\t\tclass=\"cn-dashboard-page__date-pills\"\n\t\t\t\trole=\"group\"\n\t\t\t\t:aria-label=\"datePillsGroupLabel\"\n\t\t\t\tdata-testid=\"cn-dashboard-page-date-pills\">\n\t\t\t\t<button\n\t\t\t\t\tv-for=\"preset in pillPresets\"\n\t\t\t\t\t:key=\"preset.id\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-dashboard-page__date-pill\"\n\t\t\t\t\t:class=\"{ 'cn-dashboard-page__date-pill--active': currentRange && currentRange.preset === preset.id }\"\n\t\t\t\t\t:aria-pressed=\"String(Boolean(currentRange && currentRange.preset === preset.id))\"\n\t\t\t\t\t:data-testid=\"`cn-dashboard-page-date-pill-${preset.id}`\"\n\t\t\t\t\t@click=\"onPillPick(preset)\">\n\t\t\t\t\t{{ preset.label }}\n\t\t\t\t</button>\n\t\t\t\t<NcActions\n\t\t\t\t\tv-if=\"hasCustomPreset\"\n\t\t\t\t\t:forceMenu=\"true\"\n\t\t\t\t\tcontainer=\"body\"\n\t\t\t\t\tclass=\"cn-dashboard-page__date-pill-custom\"\n\t\t\t\t\tdata-testid=\"cn-dashboard-page-date-pill-custom\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tclass=\"cn-dashboard-page__date-pill cn-dashboard-page__date-pill--custom\"\n\t\t\t\t\t\t\t:class=\"{ 'cn-dashboard-page__date-pill--active': currentRange && currentRange.preset === 'custom' }\">\n\t\t\t\t\t\t\t{{ customRangeLabel }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange && currentRange.from)\"\n\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'From')\"\n\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('from', $event)\" />\n\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange && currentRange.to)\"\n\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'To')\"\n\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('to', $event)\" />\n\t\t\t\t</NcActions>\n\t\t\t</div>\n\t\t\t<!-- Default (picker) mode: the original select + two date inputs. -->\n\t\t\t<CnDateRangePicker\n\t\t\t\tv-else\n\t\t\t\t:value=\"currentRange\"\n\t\t\t\t:presets=\"effectivePresets\"\n\t\t\t\t@input=\"onDateRangeChange\" />\n\t\t</div>\n\n\t\t<!-- Page-level filter controls (optional). Each selection is written\n\t\t into the reactive workspace context so any widget can read it via a\n\t\t `@page.<key>` / `@workspace.<key>` token (e.g. an endpoint KPI's URL\n\t\t interpolating a chosen period). -->\n\t\t<div\n\t\t\tv-if=\"rowPageFilters.length > 0\"\n\t\t\tclass=\"cn-dashboard-page__page-filters\"\n\t\t\tdata-testid=\"cn-dashboard-page-page-filters\">\n\t\t\t<template v-for=\"pf in rowPageFilters\" :key=\"pf.key\">\n\t\t\t\t<CnSegmentedControl\n\t\t\t\t\tv-if=\"pf.control === 'segmented'\"\n\t\t\t\t\tsize=\"compact\"\n\t\t\t\t\tmode=\"toggle\"\n\t\t\t\t\t:options=\"pageFilterSegments(pf)\"\n\t\t\t\t\t:modelValue=\"workspaceContext[pf.key]\"\n\t\t\t\t\t:ariaLabel=\"pf.label ? effectiveTranslate(pf.label) : pf.key\"\n\t\t\t\t\t:data-testid=\"'cn-page-filter-' + pf.key\"\n\t\t\t\t\t@update:modelValue=\"onPageFilterChange(pf, $event)\" />\n\t\t\t\t<label\n\t\t\t\t\tv-else\n\t\t\t\t\tclass=\"cn-dashboard-page__page-filter\">\n\t\t\t\t\t<span v-if=\"pf.label\" class=\"cn-dashboard-page__page-filter-label\">{{ effectiveTranslate(pf.label) }}</span>\n\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t:modelValue=\"selectedPageFilterOption(pf)\"\n\t\t\t\t\t\t:options=\"pageFilterSegments(pf)\"\n\t\t\t\t\t\t:clearable=\"pf.clearable === true\"\n\t\t\t\t\t\t:placeholder=\"pf.placeholder ? effectiveTranslate(pf.placeholder) : undefined\"\n\t\t\t\t\t\t:loading=\"pageFilterLoading[pf.key] === true\"\n\t\t\t\t\t\t:inputLabel=\"pf.label ? effectiveTranslate(pf.label) : pf.key\"\n\t\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t\t:data-testid=\"'cn-page-filter-' + pf.key\"\n\t\t\t\t\t\t@update:modelValue=\"onPageFilterChange(pf, $event)\" />\n\t\t\t\t</label>\n\t\t\t</template>\n\t\t</div>\n\n\t\t<!-- Declarative in-body sections, `placement: \"before-grid\"` — host-app\n\t\t section components (e.g. a bespoke funnel / time-series chart reading\n\t\t a custom REST endpoint) rendered ABOVE the widget grid. Independent of\n\t\t the grid's loading / empty state so an analytics dashboard can be all\n\t\t sections and no grid widgets. -->\n\t\t<CnBodySections\n\t\t\tv-if=\"hasBodyWidgets\"\n\t\t\t:sections=\"bodyWidgets\"\n\t\t\t:context=\"sectionContext\"\n\t\t\tplacement=\"before-grid\"\n\t\t\tdata-testid=\"cn-dashboard-body-sections-before-grid\" />\n\n\t\t<!-- Loading state -->\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- Widget predicates still settling: hold the grid's first paint\n\t\t so a conditional widget is present or absent from the first\n\t\t frame instead of popping in after load and reflowing the page.\n\t\t Edit mode skips the gate — it renders the authored layout with\n\t\t every widget regardless of conditions. -->\n\t\t<NcLoadingIcon v-else-if=\"!widgetConditionsSettled && !gridEditable\" />\n\n\t\t<!-- Empty state. Suppressed when the page renders declarative body\n\t\t sections (before-grid / after-grid / end): a page can legitimately\n\t\t have no grid widgets yet still show bodyWidget content, so\n\t\t \"No widgets configured\" would be a false negative. -->\n\t\t<div v-else-if=\"!hasWidgets && !hasBodyWidgets && !hasViews\" class=\"cn-dashboard-page__empty\">\n\t\t\t<!-- @slot empty Replaces the default empty state shown when the dashboard has no widgets. Defaults to an `NcEmptyContent` block. -->\n\t\t\t<slot name=\"empty\">\n\t\t\t\t<CnEmptyContent :description=\"emptyLabel\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<ViewDashboardOutline :size=\"48\" />\n\t\t\t\t\t</template>\n\t\t\t\t</CnEmptyContent>\n\t\t\t</slot>\n\t\t</div>\n\n\t\t<!-- Widget-ref content items (manifest-widget-ref-page-content-type).\n\t\t Rendered above the classic GridStack grid when present. Each item\n\t\t is a `{ type: 'widget-ref', ref: 'openregister://widget/…' }` entry\n\t\t from the manifest's `pages[].config.content[]` array. -->\n\t\t<div\n\t\t\tv-else-if=\"widgetRefItems.length > 0\"\n\t\t\tclass=\"cn-dashboard-page__content\">\n\t\t\t<CnWidgetRefItem\n\t\t\t\tv-for=\"(item, idx) in widgetRefItems\"\n\t\t\t\t:key=\"item.ref + '-' + idx\"\n\t\t\t\t:refUri=\"item.ref\"\n\t\t\t\tclass=\"cn-dashboard-page__content-item\" />\n\t\t</div>\n\n\t\t<!-- Dashboard grid (classic widgets+layout mode).\n\t\t Uses v-else so the `v-else-if=\"!hasWidgets\"` empty state and the\n\t\t `v-else-if=\"widgetRefItems.length > 0\"` content-items section\n\t\t are mutually exclusive with the grid.\n\t\t :key remounts the grid when in-app edit mode flips (ADR-041): the\n\t\t manifest is raw (non-reactive) until useManifestEditor.enter()\n\t\t observes it in place, so a grid mounted pre-edit never subscribed\n\t\t to the layout/widgets arrays — in-place pushes (Add widget) keep\n\t\t the same array identity and can't re-render it. One remount per\n\t\t edit flip re-subscribes against the now-reactive graph. -->\n\t\t<!-- KPI row (`config.kpiRow`): the named widgets sit above the grid in\n\t\t an auto-fit CnKpiGrid (each tile at least 200px wide) and are not\n\t\t GridStack items, so they neither reflow with the grid nor appear\n\t\t in the emitted layout. -->\n\t\t<CnKpiGrid\n\t\t\tv-if=\"gridSectionsShown && kpiRowItems.length > 0\"\n\t\t\tcolumns=\"auto\"\n\t\t\tclass=\"cn-dashboard-page__kpi-row\"\n\t\t\tdata-testid=\"cn-dashboard-page-kpi-row\">\n\t\t\t<div\n\t\t\t\tv-for=\"item in kpiRowItems\"\n\t\t\t\t:key=\"`kpi-${item.widgetId}`\"\n\t\t\t\tclass=\"cn-dashboard-page__kpi-cell\"\n\t\t\t\t:data-testid=\"`cn-dashboard-page-kpi-${item.widgetId}`\">\n\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\tv-if=\"isStatsBlock(item)\"\n\t\t\t\t\tv-bind=\"kpiWrapperProps(item)\"\n\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t<CnStatsBlockWidget\n\t\t\t\t\t\tv-bind=\"getStatsBlockProps(item)\"\n\t\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t\t:data-source=\"getWidgetDataSource(item)\" />\n\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\tv-else-if=\"registryRenderer(item)\"\n\t\t\t\t\tv-bind=\"kpiWrapperProps(item)\"\n\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t<template v-if=\"widgetHeaderNote(item) || widgetHeaderAction(item)\" #actions>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"widgetHeaderNote(item)\"\n\t\t\t\t\t\t\tclass=\"cn-dashboard-page__widget-note\"\n\t\t\t\t\t\t\tdata-testid=\"cn-dashboard-widget-header-note\">{{ widgetHeaderNote(item) }}</span>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\tv-if=\"widgetHeaderAction(item)\"\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"cn-dashboard-page__widget-action\"\n\t\t\t\t\t\t\tdata-testid=\"cn-dashboard-widget-header-action\"\n\t\t\t\t\t\t\t@click=\"widgetHeaderAction(item).run()\">\n\t\t\t\t\t\t\t{{ widgetHeaderAction(item).label }}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</template>\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"registryRenderer(item)\"\n\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t:content=\"registryWidgetBindings(item)\"\n\t\t\t\t\t\tv-bind=\"{ ...registryWidgetProps(item), ...containerBindings(item) }\"\n\t\t\t\t\t\t@header=\"onWidgetHeader(item, $event)\" />\n\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\tv-else-if=\"hasWidgetSlot(item.widgetId)\"\n\t\t\t\t\tv-bind=\"kpiWrapperProps(item)\"\n\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t<slot :name=\"'widget-' + item.widgetId\" :item=\"item\" :widget=\"getWidgetDef(item.widgetId)\" />\n\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\tv-else\n\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t:showTitle=\"false\"\n\t\t\t\t\t:showRefresh=\"false\">\n\t\t\t\t\t<div class=\"cn-dashboard-page__unknown\">\n\t\t\t\t\t\t{{ unavailableLabel }}\n\t\t\t\t\t</div>\n\t\t\t\t</CnWidgetWrapper>\n\t\t\t</div>\n\t\t</CnKpiGrid>\n\n\t\t<!-- The view switch for a page without a header row, when no greeting\n\t\t header widget draws it. -->\n\t\t<div\n\t\t\tv-if=\"gridSectionsShown && !showHeader && showsPageViewSwitch\"\n\t\t\tclass=\"cn-dashboard-page__view-switch\">\n\t\t\t<CnSegmentedControl\n\t\t\t\tclass=\"cn-page-view-switch\"\n\t\t\t\t:options=\"viewSwitchOptions\"\n\t\t\t\t:modelValue=\"activeViewId\"\n\t\t\t\t:ariaLabel=\"viewSwitchLabel\"\n\t\t\t\t:controls=\"viewRegionId\"\n\t\t\t\tdata-testid=\"cn-dashboard-page-view-switch\"\n\t\t\t\t@update:modelValue=\"selectView\" />\n\t\t</div>\n\t\t<!-- One grid per section: the page's own layout, then the chosen\n\t\t view (`views`) in a region the view switch controls. Both are the\n\t\t same grid with the same widget rendering below. A view grid is\n\t\t keyed on its view, so switching mounts the other view's grid. -->\n\t\t<CnDashboardGrid\n\t\t\tv-for=\"section in gridSections\"\n\t\t\t:key=\"`cn-dashboard-grid-${section.key}-${gridEditable ? 'editing' : 'live'}`\"\n\t\t\tv-bind=\"section.attrs\"\n\t\t\t:layout=\"section.layout\"\n\t\t\t:editable=\"section.editable\"\n\t\t\t:columns=\"columns\"\n\t\t\t:columnOpts=\"gridColumnOpts\"\n\t\t\t:cellHeight=\"cellHeight\"\n\t\t\t:margin=\"gridMargin\"\n\t\t\t:float=\"gridFloat\"\n\t\t\t:sideColumn=\"section.sideColumn\"\n\t\t\t@layoutChange=\"section.view ? onViewLayoutChange($event) : onLayoutChange($event)\">\n\t\t\t<template #widget=\"{ item }\">\n\t\t\t\t<!-- In-app edit overlay (ADR-041): a single launchpad-style\n\t\t\t\t configure cog opens the per-widget style/config editor,\n\t\t\t\t which itself carries the delete affordance — so no separate\n\t\t\t\t remove button here. Shown only while the page is in edit\n\t\t\t\t mode. -->\n\t\t\t\t<div v-if=\"gridEditable\" class=\"cn-dashboard-page__widget-edit\">\n\t\t\t\t\t<NcButton variant=\"tertiary\" :aria-label=\"t('nextcloud-vue', 'Configure widget')\" @click=\"configureWidget(item)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<Cog :size=\"18\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\t\t\t\t<!-- requiresApp gate — when a widget declares `requiresApp`\n\t\t\t\t (any widget type) and the owning app is not installed,\n\t\t\t\t replace its body with an \"Install …\" CTA. Because all\n\t\t\t\t fleet data lives in OpenRegister, an app can surface\n\t\t\t\t another app's data; this keeps the tile honest when the\n\t\t\t\t owning app is absent instead of showing an empty value. -->\n\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\tv-if=\"missingRequiredApp(item)\"\n\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t:showTitle=\"widgetShowTitle(item)\">\n\t\t\t\t\t<!-- Compact on purpose: a two-row tile is about 150px, less\n\t\t\t\t\t a title row. NcEmptyContent's 64px icon, 20px name,\n\t\t\t\t\t description and button did not fit, so the icon ran out\n\t\t\t\t\t at the top and the button at the bottom. The button\n\t\t\t\t\t already says \"Install {app}\", so there is no separate\n\t\t\t\t\t name, and the text keeps to two lines. -->\n\t\t\t\t\t<div class=\"cn-dashboard-page__requires-app cn-requires-app cn-requires-app--compact\"\n\t\t\t\t\t\tdata-testid=\"cn-requires-app\">\n\t\t\t\t\t\t<p class=\"cn-requires-app__description\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'This widget shows data from another app that isn\\'t installed yet.') }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t\t\t:href=\"appInstallUrl(missingRequiredApp(item))\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Download :size=\"18\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ installAppLabel(missingRequiredApp(item)) }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\t\t\t\t</CnWidgetWrapper>\n\n\t\t\t\t<!-- Tile widget -->\n\t\t\t\t<CnTileWidget\n\t\t\t\t\tv-else-if=\"isTile(item)\"\n\t\t\t\t\t:tile=\"getTileConfig(item)\" />\n\n\t\t\t\t<!-- Custom slot widget — apps provide their own rendering -->\n\t\t\t\t<!-- Every page-side wrapper carries `widget-id`: the chrome's\n\t\t\t\t Refresh broadcasts `cn:widget:refresh` with that id in the\n\t\t\t\t payload, and without it the payload's empty widgetId\n\t\t\t\t matches no subscriber — the per-widget Refresh silently\n\t\t\t\t does nothing. -->\n\t\t\t\t<template v-else-if=\"hasWidgetSlot(item.widgetId)\">\n\t\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t\t:iconUrl=\"getWidgetIconUrl(item)\"\n\t\t\t\t\t\t:iconClass=\"getWidgetIconClass(item)\"\n\t\t\t\t\t\t:showTitle=\"widgetShowTitle(item)\"\n\t\t\t\t\t\t:borderless=\"widgetBorderless(item)\"\n\t\t\t\t\t\t:flush=\"item.flush !== false\"\n\t\t\t\t\t\t:buttons=\"getWidgetButtons(item)\"\n\t\t\t\t\t\t:headerLink=\"getWidgetHeaderLink(item)\"\n\t\t\t\t\t\t:headerActions=\"getWidgetHeaderActions(item)\"\n\t\t\t\t\t\t:styleConfig=\"item.styleConfig || {}\"\n\t\t\t\t\t\t:titleIconPosition=\"getWidgetTitleIconPosition(item)\"\n\t\t\t\t\t\t:titleIconColor=\"getWidgetTitleIconColor(item)\"\n\t\t\t\t\t\t:titleIconVariant=\"getWidgetTitleIconVariant(item)\"\n\t\t\t\t\t\t:showRefresh=\"getWidgetShowRefresh(item)\"\n\t\t\t\t\t\t:showActions=\"widgetShowActions(item)\"\n\t\t\t\t\t\t:documentationUrl=\"getWidgetDocumentationUrl(item)\"\n\t\t\t\t\t\t:docsAnchor=\"getWidgetDocsAnchor(item)\"\n\t\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t\t<!-- @slot widget-{widgetId}-title-icon Per-widget custom title icon (e.g. `#widget-my-work-title-icon`). Scope: `{ item, widget }`. -->\n\t\t\t\t\t\t<template v-if=\"$slots['widget-' + item.widgetId + '-title-icon']\" #title-icon>\n\t\t\t\t\t\t\t<slot :name=\"'widget-' + item.widgetId + '-title-icon'\" :item=\"item\" :widget=\"getWidgetDef(item.widgetId)\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<!-- @slot widget-{widgetId}-actions Per-widget custom header actions (e.g. `#widget-my-work-actions`). Scope: `{ item, widget }`. -->\n\t\t\t\t\t\t<template v-if=\"$slots['widget-' + item.widgetId + '-actions']\" #actions>\n\t\t\t\t\t\t\t<slot :name=\"'widget-' + item.widgetId + '-actions'\" :item=\"item\" :widget=\"getWidgetDef(item.widgetId)\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<!-- Opt-in per-widget date chip (`layout[].dateChip: true`).\n\t\t\t\t\t\t Mirrors the chart-widget chip below — same popover,\n\t\t\t\t\t\t same handlers, same SHARED dashboard range — so\n\t\t\t\t\t\t custom widgets that consume `cnDashboardDateRange`\n\t\t\t\t\t\t can surface the range in their own header instead\n\t\t\t\t\t\t of (or alongside) the page-level picker. Keep the\n\t\t\t\t\t\t two blocks in sync when editing either. -->\n\t\t\t\t\t\t<template v-if=\"dateRangeEnabled && item.dateChip === true\" #title-meta>\n\t\t\t\t\t\t\t<NcActions\n\t\t\t\t\t\t\t\tv-model:open=\"openChipPicker[item.widgetId]\"\n\t\t\t\t\t\t\t\t:forceMenu=\"true\"\n\t\t\t\t\t\t\t\tcontainer=\"body\"\n\t\t\t\t\t\t\t\t:data-testid=\"`cn-dashboard-page-date-chip-${item.widgetId}`\"\n\t\t\t\t\t\t\t\tclass=\"cn-dashboard-page__date-chip-trigger\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<span class=\"cn-dashboard-page__date-chip\" :title=\"dateChipTitle\">\n\t\t\t\t\t\t\t\t\t\t{{ dashboardRangeChipLabel }}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\t\tv-for=\"preset in effectivePresets\"\n\t\t\t\t\t\t\t\t\t:key=\"preset.id\"\n\t\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t\t@click=\"onChipPresetPick(preset, item)\">\n\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t<CalendarRange v-if=\"currentRange.preset === preset.id\" :size=\"16\" />\n\t\t\t\t\t\t\t\t\t\t<span v-else class=\"cn-dashboard-page__date-chip-preset-spacer\" />\n\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t\t{{ preset.label }}\n\t\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t\t<NcActionSeparator />\n\t\t\t\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange.from)\"\n\t\t\t\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'From')\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('from', $event)\" />\n\t\t\t\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange.to)\"\n\t\t\t\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'To')\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('to', $event)\" />\n\t\t\t\t\t\t\t</NcActions>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<!-- @slot widget-{widgetId} Per-widget body content (e.g. `#widget-my-work`). Apps inject custom widget rendering here. Scope: `{ item, widget }`. -->\n\t\t\t\t\t\t<slot :name=\"'widget-' + item.widgetId\" :item=\"item\" :widget=\"getWidgetDef(item.widgetId)\" />\n\t\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t</template>\n\n\t\t\t\t<!-- Chart widget — manifest-driven apexcharts mount -->\n\t\t\t\t<template v-else-if=\"isChart(item)\">\n\t\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t:class=\"{ 'cn-dashboard-page__chart-fit': isChartFitted(item) }\"\n\t\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t\t:iconUrl=\"getWidgetIconUrl(item)\"\n\t\t\t\t\t\t:iconClass=\"getWidgetIconClass(item)\"\n\t\t\t\t\t\t:showTitle=\"widgetShowTitle(item)\"\n\t\t\t\t\t\t:showActions=\"widgetShowActions(item)\"\n\t\t\t\t\t\t:borderless=\"widgetBorderless(item)\"\n\t\t\t\t\t\t:flush=\"item.flush !== false\"\n\t\t\t\t\t\t:buttons=\"getWidgetButtons(item)\"\n\t\t\t\t\t\t:headerLink=\"getWidgetHeaderLink(item)\"\n\t\t\t\t\t\t:headerActions=\"getWidgetHeaderActions(item)\"\n\t\t\t\t\t\t:styleConfig=\"item.styleConfig || {}\"\n\t\t\t\t\t\t:titleIconPosition=\"getWidgetTitleIconPosition(item)\"\n\t\t\t\t\t\t:titleIconColor=\"getWidgetTitleIconColor(item)\"\n\t\t\t\t\t\t:titleIconVariant=\"getWidgetTitleIconVariant(item)\"\n\t\t\t\t\t\t:showRefresh=\"getWidgetShowRefresh(item)\"\n\t\t\t\t\t\t:documentationUrl=\"getWidgetDocumentationUrl(item)\"\n\t\t\t\t\t\t:docsAnchor=\"getWidgetDocsAnchor(item)\"\n\t\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t\t<template v-if=\"dateRangeEnabled && (item.dateChip === true || formatChartDateRange(item))\" #title-meta>\n\t\t\t\t\t\t\t<NcActions\n\t\t\t\t\t\t\t\tv-model:open=\"openChipPicker[item.widgetId]\"\n\t\t\t\t\t\t\t\t:forceMenu=\"true\"\n\t\t\t\t\t\t\t\tcontainer=\"body\"\n\t\t\t\t\t\t\t\t:data-testid=\"`cn-dashboard-page-date-chip-${item.widgetId}`\"\n\t\t\t\t\t\t\t\tclass=\"cn-dashboard-page__date-chip-trigger\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<span class=\"cn-dashboard-page__date-chip\" :title=\"dateChipTitle\">\n\t\t\t\t\t\t\t\t\t\t{{ formatChartDateRange(item) || dashboardRangeChipLabel }}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\t\tv-for=\"preset in effectivePresets\"\n\t\t\t\t\t\t\t\t\t:key=\"preset.id\"\n\t\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t\t@click=\"onChipPresetPick(preset, item)\">\n\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t<CalendarRange v-if=\"currentRange.preset === preset.id\" :size=\"16\" />\n\t\t\t\t\t\t\t\t\t\t<span v-else class=\"cn-dashboard-page__date-chip-preset-spacer\" />\n\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t\t{{ preset.label }}\n\t\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t\t<NcActionSeparator />\n\t\t\t\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange.from)\"\n\t\t\t\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'From')\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('from', $event)\" />\n\t\t\t\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange.to)\"\n\t\t\t\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'To')\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('to', $event)\" />\n\t\t\t\t\t\t\t</NcActions>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<CnChartWidget\n\t\t\t\t\t\t\tv-bind=\"getChartProps(item)\"\n\t\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t\t:data-source=\"getWidgetDataSource(item)\" />\n\t\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t</template>\n\n\t\t\t\t<!-- Stats-block widget — manifest-driven CnStatsBlock with a\n\t\t\t\t GraphQL-resolved count via `dataSource`.\n\n\t\t\t\t This used to render WITHOUT CnWidgetWrapper, because\n\t\t\t\t CnStatsBlock drew its own grey bordered card and wrapping\n\t\t\t\t it produced a double card (outer + inner titles, two\n\t\t\t\t boxes). The KPI card is flat as of 2026-08-30, so the\n\t\t\t\t opposite is now true: without the wrapper the tile has no\n\t\t\t\t chrome at all. It is wrapped like every other widget, and\n\t\t\t\t the duplicate title is gone because `stats-block` is\n\t\t\t\t registered as a card widget — card widgets default to\n\t\t\t\t headerless, so only CnStatsBlock's own title renders. -->\n\t\t\t\t<template v-else-if=\"isStatsBlock(item)\">\n\t\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t\t:iconUrl=\"getWidgetIconUrl(item)\"\n\t\t\t\t\t\t:iconClass=\"getWidgetIconClass(item)\"\n\t\t\t\t\t\t:showTitle=\"widgetShowTitle(item)\"\n\t\t\t\t\t\t:showActions=\"widgetShowActions(item)\"\n\t\t\t\t\t\t:borderless=\"widgetBorderless(item)\"\n\t\t\t\t\t\t:flush=\"item.flush !== false\"\n\t\t\t\t\t\t:class=\"{ 'cn-dashboard-page__card-fit': isCardWidget(item) }\"\n\t\t\t\t\t\t:buttons=\"getWidgetButtons(item)\"\n\t\t\t\t\t\t:headerLink=\"getWidgetHeaderLink(item)\"\n\t\t\t\t\t\t:headerActions=\"getWidgetHeaderActions(item)\"\n\t\t\t\t\t\t:styleConfig=\"item.styleConfig || {}\"\n\t\t\t\t\t\t:documentationUrl=\"getWidgetDocumentationUrl(item)\"\n\t\t\t\t\t\t:docsAnchor=\"getWidgetDocsAnchor(item)\"\n\t\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t\t<CnStatsBlockWidget\n\t\t\t\t\t\t\tv-bind=\"getStatsBlockProps(item)\"\n\t\t\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t\t\t:data-source=\"getWidgetDataSource(item)\" />\n\t\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t</template>\n\n\t\t\t\t<!-- Integration widget — resolved from the pluggable\n\t\t\t\t integration registry (AD-19 surface fallback). -->\n\t\t\t\t<template v-else-if=\"isIntegration(item)\">\n\t\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t\t:iconUrl=\"getWidgetIconUrl(item)\"\n\t\t\t\t\t\t:iconClass=\"getWidgetIconClass(item)\"\n\t\t\t\t\t\t:showTitle=\"widgetShowTitle(item)\"\n\t\t\t\t\t\t:showActions=\"widgetShowActions(item)\"\n\t\t\t\t\t\t:borderless=\"widgetBorderless(item)\"\n\t\t\t\t\t\t:flush=\"item.flush !== false\"\n\t\t\t\t\t\t:buttons=\"getWidgetButtons(item)\"\n\t\t\t\t\t\t:headerLink=\"getWidgetHeaderLink(item)\"\n\t\t\t\t\t\t:headerActions=\"getWidgetHeaderActions(item)\"\n\t\t\t\t\t\t:styleConfig=\"item.styleConfig || {}\"\n\t\t\t\t\t\t:titleIconPosition=\"getWidgetTitleIconPosition(item)\"\n\t\t\t\t\t\t:titleIconColor=\"getWidgetTitleIconColor(item)\"\n\t\t\t\t\t\t:titleIconVariant=\"getWidgetTitleIconVariant(item)\"\n\t\t\t\t\t\t:showRefresh=\"getWidgetShowRefresh(item)\"\n\t\t\t\t\t\t:documentationUrl=\"getWidgetDocumentationUrl(item)\"\n\t\t\t\t\t\t:docsAnchor=\"getWidgetDocsAnchor(item)\"\n\t\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t\t<!-- Mount-mode integration leaf (openregister#2127):\n\t\t\t\t\t\t rendered through CnLeafMountHost so a cross-Vue-major\n\t\t\t\t\t\t leaf mounts its own framework into a bare element. -->\n\t\t\t\t\t\t<CnLeafMountHost\n\t\t\t\t\t\t\tv-if=\"isMountIntegration(item)\"\n\t\t\t\t\t\t\t:provider=\"integrationProviderFor(item)\"\n\t\t\t\t\t\t\t:mountProps=\"getIntegrationMountProps(item)\" />\n\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t:is=\"resolveIntegrationWidget(item)\"\n\t\t\t\t\t\t\tv-else-if=\"resolveIntegrationWidget(item)\"\n\t\t\t\t\t\t\tv-bind=\"getIntegrationProps(item)\" />\n\t\t\t\t\t\t<div v-else class=\"cn-dashboard-page__unknown\">\n\t\t\t\t\t\t\t{{ unavailableLabel }}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t</template>\n\n\t\t\t\t<!-- NC Dashboard API widget -->\n\t\t\t\t<template v-else-if=\"isNcWidget(item)\">\n\t\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t\t:iconUrl=\"getWidgetIconUrl(item)\"\n\t\t\t\t\t\t:iconClass=\"getWidgetIconClass(item)\"\n\t\t\t\t\t\t:showTitle=\"widgetShowTitle(item)\"\n\t\t\t\t\t\t:showActions=\"widgetShowActions(item)\"\n\t\t\t\t\t\t:buttons=\"getWidgetButtons(item)\"\n\t\t\t\t\t\t:headerLink=\"getWidgetHeaderLink(item)\"\n\t\t\t\t\t\t:headerActions=\"getWidgetHeaderActions(item)\"\n\t\t\t\t\t\t:styleConfig=\"item.styleConfig || {}\"\n\t\t\t\t\t\t:showRefresh=\"getWidgetShowRefresh(item)\"\n\t\t\t\t\t\t:documentationUrl=\"getWidgetDocumentationUrl(item)\"\n\t\t\t\t\t\t:docsAnchor=\"getWidgetDocsAnchor(item)\"\n\t\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t\t<CnWidgetRenderer\n\t\t\t\t\t\t\t:widget=\"getWidgetDef(item.widgetId)\"\n\t\t\t\t\t\t\t:unavailableText=\"unavailableLabel\" />\n\t\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t</template>\n\n\t\t\t\t<!-- Dashboard widget library (cn-widget-library): a widget whose\n\t\t\t\t `type` is registered in dashboardWidgetRegistry renders here —\n\t\t\t\t this is how catalog widgets added via \"Add widget…\" appear. -->\n\t\t\t\t<template v-else-if=\"registryRenderer(item)\">\n\t\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t\t:showTitle=\"widgetShowTitle(item)\"\n\t\t\t\t\t\t:showActions=\"widgetShowActions(item)\"\n\t\t\t\t\t\t:showRefresh=\"getWidgetShowRefresh(item)\"\n\t\t\t\t\t\t:borderless=\"widgetBorderless(item)\"\n\t\t\t\t\t\t:flush=\"item.flush !== false\"\n\t\t\t\t\t\t:titleIconPosition=\"getWidgetTitleIconPosition(item)\"\n\t\t\t\t\t\t:titleIconColor=\"getWidgetTitleIconColor(item)\"\n\t\t\t\t\t\t:titleIconVariant=\"getWidgetTitleIconVariant(item)\"\n\t\t\t\t\t\t:class=\"{ 'cn-dashboard-page__card-fit': isCardWidget(item) }\"\n\t\t\t\t\t\t:buttons=\"getWidgetButtons(item)\"\n\t\t\t\t\t\t:headerLink=\"getWidgetHeaderLink(item)\"\n\t\t\t\t\t\t:headerActions=\"getWidgetHeaderActions(item)\"\n\t\t\t\t\t\t:styleConfig=\"item.styleConfig || {}\"\n\t\t\t\t\t\t:documentationUrl=\"getWidgetDocumentationUrl(item)\"\n\t\t\t\t\t\t:docsAnchor=\"getWidgetDocsAnchor(item)\"\n\t\t\t\t\t\t@refresh=\"onWidgetRefresh(item)\"\n\t\t\t\t\t\t@requestFeature=\"onWidgetRequestFeature(item)\">\n\t\t\t\t\t\t<!-- Opt-in per-widget date chip (`layout[].dateChip: true`) for\n\t\t\t\t\t\t registered card widgets (stat / gauge / delta). Same popover\n\t\t\t\t\t\t and SHARED dashboard range as the custom-widget chip above; it\n\t\t\t\t\t\t lets an abstract KPI tile carry its own period selector. Requires\n\t\t\t\t\t\t the widget header (`showTitle !== false`). Keep in sync with the\n\t\t\t\t\t\t custom-slot chip block. -->\n\t\t\t\t\t\t<template v-if=\"(dateRangeEnabled && item.dateChip === true) || widgetHeaderCount(item) !== null\" #title-meta>\n\t\t\t\t\t\t\t<!-- The total a registry widget reported (`headerCount`), a chip after the title. -->\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-if=\"widgetHeaderCount(item) !== null\"\n\t\t\t\t\t\t\t\tclass=\"cn-dashboard-page__widget-count\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-dashboard-widget-header-count\">{{ widgetHeaderCount(item) }}</span>\n\t\t\t\t\t\t\t<NcActions\n\t\t\t\t\t\t\t\tv-if=\"dateRangeEnabled && item.dateChip === true\"\n\t\t\t\t\t\t\t\tv-model:open=\"openChipPicker[item.widgetId]\"\n\t\t\t\t\t\t\t\t:forceMenu=\"true\"\n\t\t\t\t\t\t\t\tcontainer=\"body\"\n\t\t\t\t\t\t\t\t:data-testid=\"`cn-dashboard-page-date-chip-${item.widgetId}`\"\n\t\t\t\t\t\t\t\tclass=\"cn-dashboard-page__date-chip-trigger\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<span class=\"cn-dashboard-page__date-chip\" :title=\"dateChipTitle\">\n\t\t\t\t\t\t\t\t\t\t{{ dashboardRangeChipLabel }}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\t\tv-for=\"preset in effectivePresets\"\n\t\t\t\t\t\t\t\t\t:key=\"preset.id\"\n\t\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t\t@click=\"onChipPresetPick(preset, item)\">\n\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t<CalendarRange v-if=\"currentRange && currentRange.preset === preset.id\" :size=\"16\" />\n\t\t\t\t\t\t\t\t\t\t<span v-else class=\"cn-dashboard-page__date-chip-preset-spacer\" />\n\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t\t{{ preset.label }}\n\t\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t\t<NcActionSeparator />\n\t\t\t\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange && currentRange.from)\"\n\t\t\t\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'From')\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('from', $event)\" />\n\t\t\t\t\t\t\t\t<NcActionInput\n\t\t\t\t\t\t\t\t\ttype=\"datetime-local\"\n\t\t\t\t\t\t\t\t\tisNativePicker\n\t\t\t\t\t\t\t\t\t:modelValue=\"toPickerDate(currentRange && currentRange.to)\"\n\t\t\t\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'To')\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"onChipDateInput('to', $event)\" />\n\t\t\t\t\t\t\t</NcActions>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<!-- `widget-id` reaches the renderer's own refresh\n\t\t\t\t\t\t subscription (useEndpointSource matches it against\n\t\t\t\t\t\t `cn:widget:refresh` payloads) — the chrome above\n\t\t\t\t\t\t broadcasts with the same id. -->\n\t\t\t\t\t\t<!-- A renderer that reports its own header (`header` event:\n\t\t\t\t\t\t `{ link, note, action }`, e.g. record-list's \"3 in total\"),\n\t\t\t\t\t\t as on a detail page. -->\n\t\t\t\t\t\t<template v-if=\"widgetHeaderNote(item) || widgetHeaderAction(item)\" #actions>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-if=\"widgetHeaderNote(item)\"\n\t\t\t\t\t\t\t\tclass=\"cn-dashboard-page__widget-note\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-dashboard-widget-header-note\">{{ widgetHeaderNote(item) }}</span>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tv-if=\"widgetHeaderAction(item)\"\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"cn-dashboard-page__widget-action\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-dashboard-widget-header-action\"\n\t\t\t\t\t\t\t\t@click=\"widgetHeaderAction(item).run()\">\n\t\t\t\t\t\t\t\t{{ widgetHeaderAction(item).label }}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t:is=\"registryRenderer(item)\"\n\t\t\t\t\t\t\t:widgetId=\"item.widgetId\"\n\t\t\t\t\t\t\t:content=\"registryWidgetBindings(item)\"\n\t\t\t\t\t\t\tv-bind=\"{ ...registryWidgetProps(item), ...containerBindings(item), ...cellChromeBindings(item) }\"\n\t\t\t\t\t\t\t@header=\"onWidgetHeader(item, $event)\" />\n\t\t\t\t\t</CnWidgetWrapper>\n\t\t\t\t</template>\n\n\t\t\t\t<!-- Unknown widget fallback -->\n\t\t\t\t<CnWidgetWrapper\n\t\t\t\t\tv-else\n\t\t\t\t\t:title=\"getWidgetTitle(item)\"\n\t\t\t\t\t:eyebrow=\"getWidgetEyebrow(item)\"\n\t\t\t\t\t:titleTone=\"getWidgetTitleTone(item)\"\n\t\t\t\t\t:subtitle=\"getWidgetSubtitle(item)\"\n\t\t\t\t\t:showTitle=\"widgetShowTitle(item)\"\n\t\t\t\t\t:showRefresh=\"false\">\n\t\t\t\t\t<div class=\"cn-dashboard-page__unknown\">\n\t\t\t\t\t\t{{ unavailableLabel }}\n\t\t\t\t\t</div>\n\t\t\t\t</CnWidgetWrapper>\n\t\t\t</template>\n\t\t</CnDashboardGrid>\n\n\t\t<!-- The chosen view has nothing to draw: say so in the region, never\n\t\t leave a blank area under the switch. -->\n\t\t<div\n\t\t\tv-if=\"gridSectionsShown && viewIsEmpty\"\n\t\t\t:id=\"viewRegionId\"\n\t\t\trole=\"region\"\n\t\t\t:aria-label=\"activeView ? activeView.label : null\"\n\t\t\tclass=\"cn-page-view-region cn-page-view-region--empty\"\n\t\t\tdata-testid=\"cn-dashboard-page-view-empty\">\n\t\t\t<CnEmptyContent :description=\"viewEmptyText\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<ViewDashboardOutline :size=\"48\" />\n\t\t\t\t</template>\n\t\t\t</CnEmptyContent>\n\t\t</div>\n\n\t\t<!-- Declarative in-body sections, `placement: \"after-grid\"` — host-app\n\t\t section components rendered BELOW the widget grid. -->\n\t\t<CnBodySections\n\t\t\tv-if=\"hasBodyWidgets\"\n\t\t\t:sections=\"bodyWidgets\"\n\t\t\t:context=\"sectionContext\"\n\t\t\tplacement=\"after-grid\"\n\t\t\tdata-testid=\"cn-dashboard-body-sections-after-grid\" />\n\n\t\t<!-- Declarative in-body sections, `placement: \"end\"` (the default\n\t\t placement) — the last body content. Sections with no `placement`\n\t\t (or an explicit `end`) land here; `before-grid` / `after-grid` are\n\t\t filtered out so each section renders exactly once. -->\n\t\t<CnBodySections\n\t\t\tv-if=\"hasBodyWidgets\"\n\t\t\t:sections=\"endPlacementSections\"\n\t\t\t:context=\"sectionContext\"\n\t\t\t:placement=\"null\"\n\t\t\tdata-testid=\"cn-dashboard-body-sections-end\" />\n\n\t\t<!-- Per-widget style/config editor (ADR-041). Opened by the\n\t\t per-widget configure cog while editing; the modal's own Delete\n\t\t button removes the widget. -->\n\t\t<CnWidgetStyleEditorModal\n\t\t\tv-if=\"showWidgetConfig\"\n\t\t\t:show=\"showWidgetConfig\"\n\t\t\t:widget=\"configWidget\"\n\t\t\t:deletable=\"true\"\n\t\t\t@save=\"onWidgetConfigSave\"\n\t\t\t@delete=\"onWidgetConfigDelete\"\n\t\t\t@close=\"showWidgetConfig = false\" />\n\t</div>\n</template>\n\n<script>\nimport { getCurrentUser } from '@nextcloud/auth'\nimport { getCanonicalLocale, translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionInput, NcActions, NcActionSeparator, NcButton, NcLoadingIcon, NcSelect } from '@nextcloud/vue'\nimport { inject, provide, ref, watch } from 'vue'\nimport CalendarRange from 'vue-material-design-icons/CalendarRange.vue'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport Cog from 'vue-material-design-icons/Cog.vue'\nimport Download from 'vue-material-design-icons/Download.vue'\nimport Pencil from 'vue-material-design-icons/Pencil.vue'\nimport Restore from 'vue-material-design-icons/Restore.vue'\nimport ViewDashboardOutline from 'vue-material-design-icons/ViewDashboardOutline.vue'\nimport CnWidgetStyleEditorModal from '../../dialogs/CnWidgetStyleEditorModal.vue'\nimport CnBodySections from '../CnBodySections/CnBodySections.vue'\nimport CnBuildiqEditButton from '../CnBuildiqEditButton/CnBuildiqEditButton.vue'\nimport CnChartWidget from '../CnChartWidget/CnChartWidget.vue'\nimport CnDashboardGrid from '../CnDashboardGrid/CnDashboardGrid.vue'\nimport CnDateRangePicker, { DEFAULT_DATE_RANGE_PRESETS, resolvePresetWindow, translatePresetLabel } from '../CnDateRangePicker/CnDateRangePicker.vue'\nimport CnEmptyContent from '../CnEmptyContent/CnEmptyContent.vue'\nimport CnKpiGrid from '../CnKpiGrid/CnKpiGrid.vue'\nimport CnHeaderTrail from '../CnPageHeader/CnHeaderTrail.vue'\nimport CnSegmentedControl from '../CnSegmentedControl/CnSegmentedControl.vue'\nimport CnStatsBlockWidget from '../CnStatsBlockWidget/CnStatsBlockWidget.vue'\nimport CnTileWidget from '../CnTileWidget/CnTileWidget.vue'\nimport CnWidgetIcon from '../CnWidgetGrid/CnWidgetIcon.vue'\nimport CnWidgetRefItem from '../CnWidgetRefItem/CnWidgetRefItem.vue'\nimport CnWidgetRenderer from '../CnWidgetRenderer/CnWidgetRenderer.vue'\nimport CnWidgetWrapper from '../CnWidgetWrapper/CnWidgetWrapper.vue'\nimport { interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport { useIntegrationRegistry } from '../../composables/useIntegrationRegistry.js'\nimport { normalizeLook } from '../../composables/useLook.js'\nimport { pageFilters } from '../../mixins/pageFilters.js'\nimport { pageViews } from '../../mixins/pageViews.js'\nimport { mergeUserLayout, resolveUserLayoutApi } from '../../store/plugins/dashboardLayouts.js'\nimport { headerActionAsLink } from '../../utils/actionLink.js'\nimport { dispatchAction } from '../../utils/actionsDispatcher.js'\nimport { isAppInstalled } from '../../utils/appInstalled.js'\nimport { contentHeaderLink } from '../../utils/contentHeaderLink.js'\nimport { pickDeclaredProps } from '../../utils/declaredProps.js'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\nimport { HEADING_LEVEL } from '../../utils/headingLevel.js'\nimport { generatedPageFilterOptions, periodText, rangePeriodText } from '../../utils/periodOptions.js'\nimport { isOptionalUnresolved, resolveFilterValue } from '../../utils/resolveFilterTokens.js'\nimport { userLocale } from '../../utils/userLocale.js'\nimport { compareVisibleWhen, evaluateWorkspaceCondition, isWorkspaceCondition, readVisibleWhenValue } from '../../utils/visibleWhen.js'\nimport { resolveWidgetHeaderActions } from '../../utils/widgetHeaderActions.js'\nimport { canonicalWidgetType } from '../../utils/widgetTypeAliases.js'\nimport { CnActionButtons } from '../CnActionButtons/index.js'\nimport { CnActionsMenu } from '../CnActionsMenu/index.js'\nimport { CnLeafMountHost } from '../CnLeafMountHost/index.js'\nimport { BUILT_IN_WIDGETS } from '../CnWidgetGrid/builtInWidgets.js'\nimport { getWidgetTypeEntry } from '../CnWidgetGrid/dashboardWidgetRegistry.js'\n\n// Registers the dashboard widget catalog (stat, delta, gauge, ...) whenever this\n// page's chunk loads, so a fresh dashboard does not depend on the app's main.js.\nimport '../CnWidgetGrid/registerDashboardWidgets.js'\n\n/** Surfaces understood by the pluggable integration registry (AD-19). */\nconst INTEGRATION_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\n\n/**\n * Subset of `widgetDef.props` keys that the chart widget dispatcher\n * forwards to CnChartWidget. Unknown keys on `props` are ignored so\n * the manifest stays forward-compatible (e.g. `dataSource` is\n * round-tripped through manifest validators but not yet read here).\n *\n * `chartKind` is renamed to `type` because apexcharts' own component\n * prop is also called `type`, and `widgetDef.type` already means\n * \"dispatcher selector\" in this file.\n */\nconst CHART_PROP_KEYS = [\n\t'series',\n\t'categories',\n\t'labels',\n\t'options',\n\t'colors',\n\t'toolbar',\n\t'legend',\n\t'height',\n\t'width',\n\t'unavailableLabel',\n\t// Display passthrough (Wave 1, nextcloud-vue#91): additive presentation\n\t// keys forwarded verbatim to CnChartWidget.\n\t'horizontal',\n\t'legendPosition',\n\t'valueFormat',\n\t// Value-axis baseline guard: lets a manifest opt a chart out of the\n\t// zero-baseline default (`'fit'`) when its series lives far from zero.\n\t'valueAxisBaseline',\n\t'colorMap',\n\t'emptyLabel',\n\t// In-widget view switcher (Wave 3, nextcloud-vue#91): named display\n\t// views toggling which series / value format render.\n\t'views',\n\t// Endpoint data binding (Wave 2, nextcloud-vue#91): WITHOUT this key the\n\t// chart's endpointSource never reaches CnChartWidget on a dashboard\n\t// surface (getChartProps only forwards this allowlist), so the fleet's\n\t// trend charts silently render empty. `dataSource` is forwarded\n\t// separately via the template's :data-source binding (getWidgetDataSource),\n\t// so the Wave-3 aggregate/drilldown inside it already flow through.\n\t'endpointSource',\n\t// `bar-list` / `matrix` presentation keys.\n\t'barMax',\n\t'barValueAtEnd',\n\t'matrixLabelWidth',\n\t'footnote',\n\t'highlight',\n\t'cellSource',\n\t'emptyCellLabel',\n\t// A norm line and month categories on a line chart (DqDoorlooptijd).\n\t'referenceLines',\n\t'categoryFormat',\n]\n\n/**\n * CnDashboardPage — Top-level dashboard page component.\n *\n * The dashboard equivalent of CnIndexPage. Renders a configurable grid\n * of widgets from a `widgets` definition array and a `layout` array.\n *\n * Widget types (priority order, first match wins):\n * 1. **Tile** — Items with `type: 'tile'` render as quick-access tiles\n * 2. **Custom slot** — App provides rendering via `#widget-{widgetId}`\n * (escape hatch — beats every built-in branch when a slot exists)\n * 3. **Chart** — Items with `type: 'chart'` mount CnChartWidget; chart\n * inputs (chartKind, series, options, …) ride `widgetDef.props`,\n * plus an optional `dataSource` block resolves `series` /\n * `categories` from a GraphQL query.\n * 4. **Stats-block** — Items with `type: 'stats-block'` mount\n * CnStatsBlockWidget; the count comes from `widgetDef.dataSource`\n * (shorthand `{ register, schema, filter?, aggregate: 'count' }`\n * or raw GraphQL `{ graphql: { query, variables?, selectors } }`).\n * 5. **NC Dashboard API** — Widgets with `itemApiVersions` auto-rendered\n * 6. **Unknown fallback** — `unavailableLabel` text inside a wrapper\n *\n * Basic usage with custom widgets\n * ```vue\n * <CnDashboardPage\n * title=\"Dashboard\"\n * :widgets=\"widgetDefs\"\n * :layout=\"savedLayout\"\n * @layout-change=\"saveLayout\">\n * <template #widget-cases-by-status=\"{ item }\">\n * <StatusChart :data=\"statusData\" />\n * </template>\n * <template #widget-my-work=\"{ item }\">\n * <MyWorkList :items=\"workItems\" />\n * </template>\n * </CnDashboardPage>\n * ```\n *\n * With NC Dashboard API widgets\n * ```vue\n * <CnDashboardPage\n * title=\"Dashboard\"\n * :widgets=\"[...appWidgets, ...ncWidgets]\"\n * :layout=\"layout\"\n * @layout-change=\"saveLayout\" />\n * ```\n *\n * With manifest-driven chart widgets (no consumer code required)\n * ```js\n * const widgets = [{\n * id: 'sla-trend',\n * title: 'SLA trend',\n * type: 'chart',\n * props: {\n * chartKind: 'line', // line|bar|donut|area|pie|radialBar\n * series: [{ name: 'SLA %', data: [82, 85, 88, 91] }],\n * categories: ['Q1', 'Q2', 'Q3', 'Q4'],\n * options: { stroke: { width: 3 } }, // deep-merged with defaults\n * // dataSource is reserved for a future cycle — round-tripped\n * // through manifest validators but not yet read at render time:\n * // dataSource: { url: '/index.php/apps/myapp/api/charts/sla' }\n * // dataSource: { register: 'cases', schema: 'case',\n * // groupBy: 'caseType', aggregate: 'count' }\n * },\n * }]\n * ```\n */\n\n/**\n * A widget's content with each `@config.<key>` string (at any depth) filled\n * from the app config; an unset optional token (`@config.<key>?`) becomes ''\n * and an unset required one stays as written. Content without a token comes\n * back as the same object, so the widget is not handed a new one each render.\n *\n * @param {unknown} value The content, or a part of it.\n * @param {object} config The app config.\n * @return {unknown} The content with the config values in.\n * @spec openspec/changes/pl4-dashboard-config/specs/pl4-dashboard-config/spec.md#requirement-a-dashboard-widget-can-name-an-app-setting\n */\nfunction fillConfigTokens(value, config) {\n\tif (typeof value === 'string') {\n\t\tif (!value.startsWith('@config.')) {\n\t\t\treturn value\n\t\t}\n\t\tconst resolved = resolveFilterValue(value, { config })\n\t\treturn isOptionalUnresolved(resolved) ? '' : resolved\n\t}\n\tif (Array.isArray(value)) {\n\t\tconst filled = value.map((entry) => fillConfigTokens(entry, config))\n\t\treturn filled.some((entry, index) => entry !== value[index]) ? filled : value\n\t}\n\tif (value && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype) {\n\t\tconst entries = Object.entries(value).map(([key, entry]) => [key, fillConfigTokens(entry, config)])\n\t\treturn entries.some(([key, entry]) => entry !== value[key]) ? Object.fromEntries(entries) : value\n\t}\n\treturn value\n}\n\nconst filledByContent = new WeakMap()\n\n/**\n * `fillConfigTokens` once per content object and config, so a widget whose\n * content names a setting keeps one content object between renders.\n *\n * @param {object} content The widget content.\n * @param {object} config The app config.\n * @return {object} The filled content.\n */\nfunction filledContent(content, config) {\n\tif (!content || typeof content !== 'object') {\n\t\treturn content\n\t}\n\tconst key = JSON.stringify(config)\n\tconst cached = filledByContent.get(content)\n\tif (cached && cached.key === key) {\n\t\treturn cached.value\n\t}\n\tconst value = fillConfigTokens(content, config)\n\tfilledByContent.set(content, { key, value })\n\treturn value\n}\n\nexport default {\n\tname: 'CnDashboardPage',\n\n\tcomponents: {\n\t\tCnHeaderTrail,\n\t\tNcActions,\n\t\tNcActionButton,\n\t\tNcActionInput,\n\t\tNcActionSeparator,\n\t\tNcButton,\n\t\tCnEmptyContent,\n\t\tNcLoadingIcon,\n\t\tNcSelect,\n\t\tPencil,\n\t\tRestore,\n\t\tCheck,\n\t\tCog,\n\t\tCalendarRange,\n\t\tViewDashboardOutline,\n\t\tDownload,\n\t\tCnDashboardGrid,\n\t\tCnWidgetWrapper,\n\t\tCnWidgetRenderer,\n\t\tCnTileWidget,\n\t\tCnChartWidget,\n\t\tCnStatsBlockWidget,\n\t\tCnWidgetRefItem,\n\t\tCnBodySections,\n\t\tCnDateRangePicker,\n\t\tCnActionsMenu,\n\t\tCnActionButtons,\n\t\tCnBuildiqEditButton,\n\t\tCnWidgetStyleEditorModal,\n\t\tCnLeafMountHost,\n\t\tCnSegmentedControl,\n\t\tCnKpiGrid,\n\t\tCnWidgetIcon,\n\t},\n\n\tmixins: [pageFilters, pageViews],\n\n\tinject: {\n\t\t/**\n\t\t * Buildiq in-app edit state (ADR-041), provided by CnAppRoot as a ref.\n\t\t * When true the dashboard grid becomes drag/resize/remove-able even\n\t\t * without the consumer's own `allowEdit` toggle.\n\t\t */\n\t\tcnEditingBody: { default: false },\n\t\t/**\n\t\t * Reactive AI context holder provided by CnAppRoot. Overwritten\n\t\t * on created() and watched for prop changes. Reset on beforeUnmount().\n\t\t */\n\t\tcnAiContext: { default: null },\n\t\t/**\n\t\t * Consumer widget registry provided by CnAppRoot — the SAME injection\n\t\t * CnWidgetGrid and CnDetailPage read, so an app-registered widget\n\t\t * resolves identically on all three surfaces (REQ-MVR-005: a custom\n\t\t * widget overrides a built-in of the same name).\n\t\t */\n\t\tcnRegistry: { default: () => ({}) },\n\t\t/**\n\t\t * The page's action dispatcher, provided by CnPageRenderer: a card's\n\t\t * header action runs through it, so `open-modal` reaches the app's\n\t\t * registry dialogs, as on a detail page. Null outside the renderer.\n\t\t *\n\t\t * @spec openspec/changes/dashboard-card-action-dialog/specs/dashboard-page/spec.md#requirement-a-dashboard-card-header-action-dispatches-through-the-page\n\t\t */\n\t\tcnDispatchAction: { default: null },\n\t\t/**\n\t\t * Host translate function provided by CnAppRoot as\n\t\t * `cnTranslate: this.translate` (bound to the host app's id). The\n\t\t * manifest-authored page title/description are run through it.\n\t\t * Defaults to an identity function so an untranslated key renders\n\t\t * as itself.\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/**\n\t\t * The look the app is drawn in (`board` or `nextcloud`), provided by\n\t\t * CnAppRoot. The board look draws the screens' dashboard header, period\n\t\t * group and KPI row.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-parity/specs/dashboard-page/spec.md#requirement-the-board-dashboard-header\n\t\t */\n\t\tcnLook: { default: 'nextcloud' },\n\t},\n\n\t/**\n\t * Expose the authored (untranslated) widget titles to descendants.\n\t *\n\t * CnActionsMenu needs the English source for the bug-report deep link, but\n\t * it sits inside CnWidgetWrapper inside the widget renderer — threading a\n\t * second title prop would mean touching every one of the ~20 renderers and\n\t * relying on each to forward it. An inject resolves by widget id instead,\n\t * and degrades to '' where no dashboard provides it.\n\t *\n\t * @return {object} The provided resolver.\n\t */\n\tprovide() {\n\t\treturn {\n\t\t\tcnWidgetTitleSource: (widgetId) => this.getWidgetTitleSource(widgetId),\n\t\t\t// The page id, for widgets that key per-person state by dashboard (notepad).\n\t\t\tcnDashboardPageId: () => this.resolvedPageId,\n\t\t\t// Widget titles sit one level under the page title: h1 in the board\n\t\t\t// look, h2 in the Nextcloud look and as the hidden title.\n\t\t\t[HEADING_LEVEL]: () => (this.showHeader && this.title && this.isBoardLook ? 2 : 3),\n\t\t}\n\t},\n\n\tprops: {\n\t\t/** Page title */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * A breadcrumb under the title (manifest `config.breadcrumb`): one\n\t\t * crumb `{ label, route?, params?, href?, icon?, separator? }` or a\n\t\t * list; the title follows as the current crumb. Drawn as the detail\n\t\t * header's breadcrumb row. Null (the default) draws none.\n\t\t *\n\t\t * @type {object|Array<object>|null}\n\t\t * @spec openspec/changes/page-header-breadcrumb/specs/page-header/spec.md#requirement-a-list-dashboard-or-settings-page-can-show-a-breadcrumb-and-a-meta-note\n\t\t */\n\t\tbreadcrumb: {\n\t\t\ttype: [Object, Array],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * A note after the breadcrumb and a middle dot (manifest `config.headerMeta`).\n\t\t *\n\t\t * @spec openspec/changes/page-header-breadcrumb/specs/page-header/spec.md#requirement-a-list-dashboard-or-settings-page-can-show-a-breadcrumb-and-a-meta-note\n\t\t */\n\t\theaderMeta: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Page description (shown below title) */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether the header row renders: title, description, header actions\n\t\t * and the edit toggle. `false` (manifest `config.showHeader: false`)\n\t\t * drops it for a page whose first widget is its heading; the title\n\t\t * then renders visually hidden so the page keeps an accessible name.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-dashboard-page-can-hide-its-header\n\t\t */\n\t\tshowHeader: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * The ids of the widgets that form the KPI row above the grid\n\t\t * (manifest `config.kpiRow`). They render in an auto-fit CnKpiGrid and\n\t\t * are left out of the GridStack grid and of the emitted layout. An id\n\t\t * that names no widget is skipped with a development warning.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-parity/specs/dashboard-page/spec.md#requirement-a-kpi-row-above-the-grid\n\t\t * @type {Array<string>}\n\t\t */\n\t\tkpiRow: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Greet the reader in the header subtitle (manifest `config.greeting`):\n\t\t * `true` (or `\"first\"`) writes \"Good afternoon, Pieter · Monday 5\n\t\t * October 2026\", `\"full\"` uses the whole display name. The page\n\t\t * `description`, when set, follows after another middle dot. Off by\n\t\t * default: the subtitle is the description alone, as before.\n\t\t * `\"date\"` leads with the date alone, and `{ label }` puts the\n\t\t * translated label where the greeting would be (\"Customer contact ·\n\t\t * Wednesday 7 October 2026 · ...\").\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-greeting-header/specs/dashboard-page/spec.md#requirement-the-header-subtitle-can-greet-the-reader\n\t\t * @spec openspec/changes/dashboard-greeting-label/specs/dashboard-page/spec.md#requirement-the-header-subtitle-can-lead-with-a-label-or-the-date\n\t\t * @type {boolean|string|object}\n\t\t */\n\t\tgreeting: {\n\t\t\ttype: [Boolean, String, Object],\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Links drawn as small pills on the switch row under the header\n\t\t * (manifest `config.viewLinks`), as DqMijnWerk's \"Uw wachtrij / Aan\n\t\t * mij toegewezen / Dag afsluiten\". Each `{ label, icon?, route?,\n\t\t * href? }`: `route` is a route name or a `{ name, params?, query? }`\n\t\t * location, `href` a plain URL; `label` goes through the host\n\t\t * translate function. An entry without a label or a target is skipped.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-greeting-header/specs/dashboard-page/spec.md#requirement-a-switch-row-carries-the-view-switch-and-link-pills\n\t\t * @type {Array<object>}\n\t\t */\n\t\tviewLinks: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Whether the header draws the page Actions menu (manifest\n\t\t * `config.showActionsMenu`). `false` removes it, for a board page\n\t\t * whose header carries only the buildiq square and the primary.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-greeting-header/specs/dashboard-page/spec.md#requirement-the-header-can-drop-the-page-actions-menu\n\t\t * @type {boolean}\n\t\t */\n\t\tshowActionsMenu: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Whether a widget draws its overflow Actions menu when neither its\n\t\t * placement nor its definition says (`showActions`). `false` (manifest\n\t\t * `config.showWidgetActions: false`) drops the menu from every such\n\t\t * widget, for a dashboard whose widgets carry a header link and\n\t\t * nothing else. A widget that sets `showActions: true` keeps its menu.\n\t\t * Card widgets have no menu either way.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-a-dashboard-can-drop-the-widget-actions-menu\n\t\t */\n\t\tshowWidgetActions: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * GridStack's `float` for this dashboard (manifest\n\t\t * `config.gridFloat`). True (the default) keeps every widget on its\n\t\t * row. False packs widgets upward, so a size-to-content widget that\n\t\t * shrinks closes the gap under it instead of leaving an empty band.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-a-dashboard-closes-the-gap-a-shrinking-or-hidden-widget-leaves\n\t\t */\n\t\tgridFloat: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * A side column of a fixed width for the page's own grid (manifest\n\t\t * `config.gridSideColumn`): `{ width, from? }`, see CnDashboardGrid's\n\t\t * `sideColumn`. A view declares its own `gridSideColumn`, because two\n\t\t * views of one page can split differently (DqMijnWerk 320px beside\n\t\t * the main column, DqMijnTeam two halves).\n\t\t *\n\t\t * @spec openspec/changes/dashboard-side-column-width/specs/dashboard-side-column-width/spec.md#requirement-a-dashboard-can-draw-its-side-column-at-a-fixed-width\n\t\t */\n\t\tgridSideColumn: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Widget definitions array. Each widget defines metadata for rendering.\n\t\t *\n\t\t * Custom widgets: `{ id: 'my-widget', title: 'My Widget', type: 'custom' }`\n\t\t * NC API widgets: `{ id: 'calendar', title: 'Calendar', itemApiVersions: [1,2], ... }`\n\t\t * Tile widgets: `{ id: 'tile-files', type: 'tile', title: 'Files', icon: 'M12...', iconType: 'svg', backgroundColor: '#0082c9', textColor: '#fff', linkType: 'app', linkValue: 'files' }`\n\t\t * Chart widgets: `{ id: 'sla', type: 'chart', title: 'SLA trend',\n\t\t * props: { chartKind: 'line', series: [{ name: 'SLA %', data: [82, 88, 91] }],\n\t\t * categories: ['Q1', 'Q2', 'Q3'], options: { stroke: { width: 3 } } } }`\n\t\t *\n\t\t * @type {Array<{ id: string, title: string, type: string, iconUrl: string, iconClass: string, buttons: Array, itemApiVersions: number[], reloadInterval: number, props: object }>}\n\t\t */\n\t\twidgets: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Layout array defining widget positions in the grid.\n\t\t *\n\t\t * Each item: `{ id: 'unique-id', widgetId: 'my-widget', gridX: 0, gridY: 0, gridWidth: 4, gridHeight: 3 }`\n\t\t *\n\t\t * Additional properties (showTitle, styleConfig, tile config) are passed through.\n\t\t *\n\t\t * @type {Array<{ id: string|number, widgetId: string, gridX: number, gridY: number, gridWidth: number, gridHeight: number, showTitle: boolean, styleConfig: object }>}\n\t\t */\n\t\tlayout: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Declarative content items. Each item is a `widget-ref` entry from the\n\t\t * manifest's `pages[].config.content[]` array:\n\t\t *\n\t\t * `{ type: 'widget-ref', ref: 'openregister://widget/<schemaSlug>/<widgetSlug>' }`\n\t\t *\n\t\t * CnDashboardPage renders each widget-ref item as a `CnWidgetRefItem`\n\t\t * which resolves the widget from OR's registry at runtime and renders\n\t\t * the resolved component. Only `widget-ref` entries are processed; unknown\n\t\t * `type` values are skipped with a `console.warn`.\n\t\t *\n\t\t * When both `content` (widget-ref items) and `widgets`+`layout` (classic\n\t\t * GridStack layout) are present, `content` items are rendered above the\n\t\t * grid in a stacked list.\n\t\t *\n\t\t * @type {Array<{ type: string, ref: string }>}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Declarative IN-BODY sections (host-app section components) rendered\n\t\t * ALONGSIDE the widget grid — the dashboard equivalent of CnDetailPage's\n\t\t * `bodyWidgets`. Each entry:\n\t\t *\n\t\t * `{ id?, component, title?, props?, placement?, colSpan? }`\n\t\t *\n\t\t * - `component` — registry name resolved from the v2 `cnRegistry` first,\n\t\t * then the legacy `cnCustomComponents` map (the SAME resolver\n\t\t * `type:\"custom\"` pages use). A bespoke funnel / time-series / channel\n\t\t * chart that reads a custom REST endpoint stays a registered component\n\t\t * and surfaces here without a rewrite.\n\t\t * - `props` — token-resolved against the page context: `@workspace.<key>`\n\t\t * / `@page.<key>` (page-level workspace state), `@config.<key>` (app\n\t\t * config), and the time / `@me` tokens. An unresolved optional token is\n\t\t * dropped so the child sees `undefined`.\n\t\t * - `placement` — `before-grid` (above the widget grid) | `after-grid`\n\t\t * (below it) | `end` (the default; same as `after-grid`). `before-grid`\n\t\t * renders even when the dashboard has no grid widgets.\n\t\t * - `colSpan` — 1–12 grid span when sections at one placement share a row.\n\t\t *\n\t\t * Empty / omitted (default `[]`) renders nothing — the current behaviour.\n\t\t * The section context (`{ register, schema, objectId, workspace, config }`)\n\t\t * is also `provide`d on `cnSectionContext` so a section component can\n\t\t * inject it instead of taking explicit props. See `CnBodySections`.\n\t\t *\n\t\t * @type {Array<{id?: string, component: string, title?: string, props?: object, placement?: string, colSpan?: number}>}\n\t\t */\n\t\tbodyWidgets: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Page-level app config map exposed to declarative widget / section\n\t\t * config via the `@config.<key>` token (e.g. the reporting `currency`\n\t\t * the setup wizard captures). Provided to descendants on `cnAppConfig`,\n\t\t * so a stat widget's `format: { style: 'currency', currency:\n\t\t * '@config.currency' }` formats with the configured value (falling back\n\t\t * to the literal default — `EUR` — when unset) and an endpoint KPI's URL\n\t\t * can interpolate `@config.<key>`. A manifest renderer typically seeds\n\t\t * this from `loadState(appId, 'config', {})`. Empty (default) leaves\n\t\t * every `@config.<key>` token to fall back to its literal default.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tappConfig: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** Whether the dashboard is loading */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether to show the edit toggle button */\n\t\tallowEdit: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Number of grid columns */\n\t\tcolumns: {\n\t\t\ttype: Number,\n\t\t\tdefault: 12,\n\t\t},\n\n\t\t/** Grid cell height in pixels */\n\t\tcellHeight: {\n\t\t\ttype: Number,\n\t\t\tdefault: 80,\n\t\t},\n\n\t\t/** Grid margin in pixels */\n\t\tgridMargin: {\n\t\t\ttype: Number,\n\t\t\tdefault: 12,\n\t\t},\n\n\t\t/** Label for the edit button */\n\t\teditLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Edit'),\n\t\t},\n\n\t\t/** Label for the done button (when editing) */\n\t\tdoneLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Done'),\n\t\t},\n\n\t\t/** Label for the empty state */\n\t\temptyLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'No widgets configured'),\n\t\t},\n\n\t\t/** Label for unavailable widgets */\n\t\tunavailableLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Widget not available'),\n\t\t},\n\n\t\t/**\n\t\t * Rendering surface forwarded to integration widgets (widgets\n\t\t * whose `type === 'integration'`). Drives the AD-19 surface\n\t\t * fallback on `resolveWidget(integrationId, surface)`.\n\t\t *\n\t\t * @type {'user-dashboard'|'app-dashboard'|'detail-page'|'single-entity'}\n\t\t */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'app-dashboard',\n\t\t\tvalidator: (value) => INTEGRATION_SURFACES.includes(value),\n\t\t},\n\n\t\t/**\n\t\t * Object context forwarded to integration widgets:\n\t\t * `{ register, schema, objectId }`. Optional — most dashboards\n\t\t * aren't object-scoped, but CnDetailPage passes one through so\n\t\t * `CnFilesCard` / `CnTagsCard` / `CnAuditTrailCard` know which\n\t\t * object's sub-resources to fetch.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tintegrationContext: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Optional per-app install/enable status map used by the\n\t\t * `requiresApp` widget gate. Shape: `{ [appId]: { installed:\n\t\t * boolean, enabled: boolean, category?: string } }` — typically\n\t\t * the `dependency_statuses` initial state a consuming app injects.\n\t\t * When a widget definition carries `requiresApp` (a string or\n\t\t * array of app ids) and a required app is not enabled here, that\n\t\t * widget renders an \"Install …\" call-to-action instead of its\n\t\t * normal content. When this prop is `null` the gate falls back to\n\t\t * the `isAppInstalled()` runtime check (`OC.appswebroots` →\n\t\t * capabilities), so the gate works with or without injected data.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tappStatuses: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Optional date-range header descriptor. When `enabled: true`\n\t\t * the dashboard renders a `CnDateRangePicker` between the\n\t\t * header and the widget grid, persists the chosen range to\n\t\t * `localStorage` (when `persistKey` is set), emits\n\t\t * `@date-range-change` on every change, AND provides a\n\t\t * reactive `cnDashboardDateRange` ref to every descendant\n\t\t * widget.\n\t\t *\n\t\t * When the prop is `null` (default), `false`, or\n\t\t * `{ enabled: false }`, the header row is NOT rendered and the\n\t\t * existing dashboard layout stays unchanged. The provide is\n\t\t * still installed (always) but its value stays `null` so\n\t\t * descendant chart widgets fall back to their\n\t\t * `dataSource.bucket.staticRange` (or skip the query\n\t\t * entirely).\n\t\t *\n\t\t * Shape:\n\t\t * ```ts\n\t\t * {\n\t\t * enabled: boolean,\n\t\t * control?: 'picker' | 'pills',\n\t\t * default?: { from: string, to: string, preset?: string },\n\t\t * persistKey?: string,\n\t\t * presets?: Array<{ id: string, label: string, days: number|null }>,\n\t\t * }\n\t\t * ```\n\t\t *\n\t\t * `control` selects the header control style: the default `'picker'`\n\t\t * renders the `CnDateRangePicker` (a preset select + two date\n\t\t * inputs); `'pills'` renders a compact segmented toggle-button row\n\t\t * (one pill per preset, plus a de-emphasised \"Custom range\" popover\n\t\t * pill). Both drive the same shared range.\n\t\t *\n\t\t * A preset with no numeric `days` / `hours` (other than the manual\n\t\t * `custom` entry) — e.g. `{ id: 'all', label: 'All', days: null }` —\n\t\t * is an \"All\" / CLEAR preset: picking it removes the window so\n\t\t * date-bound widgets show their unfiltered count. An explicit\n\t\t * `clear: true` forces the same behaviour.\n\t\t *\n\t\t * The active window is published into the page-level workspace\n\t\t * context as `dateFrom` / `dateTo` / `datePreset`, so any declarative\n\t\t * widget can scope itself to it via the optional filter tokens\n\t\t * `@workspace.dateFrom?` / `@workspace.dateTo?` (an empty bound, i.e.\n\t\t * the \"All\" range, drops the token so the filter is omitted).\n\t\t *\n\t\t * Default preset when no explicit `default` and no persisted\n\t\t * state is found: `last-7` (`now − 7d → now`).\n\t\t *\n\t\t * Per-widget surfacing: chart widgets with a `dataSource.bucket`\n\t\t * get an in-header date chip automatically; CUSTOM and registered\n\t\t * card widgets (`stat` / `gauge` / `delta` KPI tiles) opt in via\n\t\t * `layout[].dateChip: true` (same popover, writes the same shared\n\t\t * range — so an abstract KPI card carries its own period selector).\n\t\t * The chip needs the widget header (`showTitle !== false`) and shows\n\t\t * the active preset's label (e.g. `7d` / `All`), staying clickable\n\t\t * even on an unbounded (\"All\") range. Set `showHeaderPicker: false`\n\t\t * to rely solely on the per-widget chips.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tdateRange: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Optional declarative header actions (#91 Wave 3) rendered as buttons\n\t\t * in the dashboard header via CnActionButtons — `open-form` (schema\n\t\t * create dialog), `api-call` (POST/PUT + toast + refresh), `toggle`\n\t\t * (two-way state button), `navigate` / `open-modal` / `refresh`, each\n\t\t * with an optional `visibleWhen` predicate. An entry with `href` is a\n\t\t * link button, never dispatched: an absolute `http(s)`, `mailto:`,\n\t\t * `tel:` or `//host/...` URL as written, an instance path (leading `/`) through\n\t\t * `generateUrl()`, in a new tab with `target: '_blank'`. Empty (the\n\t\t * default) renders nothing; the `#header-actions` slot still works\n\t\t * alongside it for bespoke buttons.\n\t\t *\n\t\t * @type {Array<object>}\n\t\t */\n\t\theaderActions: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Optional page-level filter controls rendered in the dashboard header.\n\t\t * Each selection is written into the reactive page-level workspace\n\t\t * context (the same bag `cnWorkspaceContext` provides), so any widget can\n\t\t * read it via a `@page.<key>` / `@workspace.<key>` token — e.g. a period\n\t\t * selector that every endpoint-bound KPI's URL interpolates.\n\t\t *\n\t\t * Each entry: `{ key, label?, type?: 'select', control?, placement?,\n\t\t * options: [{ value, label }], default? }`. `key` is the workspace-context\n\t\t * key written on change; `default` (or the first option) seeds it on\n\t\t * mount. The control is a select, or with `control: 'segmented'` a\n\t\t * compact segmented group; `placement: 'description'` puts a segmented\n\t\t * group on the header's description line, after the period group\n\t\t * (DqProcesanalyse \"Gemiddeld | Mediaan\"), and a select before it\n\t\t * (DqDoorlooptijd \"alle zaaktypen\"). An endpoint widget can read\n\t\t * the value in its `responsePath` too (`phaseDays.@workspace.measure`).\n\t\t * `optionsFrom` reads the options instead of listing them: `{ url,\n\t\t * params?, responsePath?, valueField?, labelField? }` from an app\n\t\t * endpoint, or `{ register, schema, filter?, valueField?, labelField? }`\n\t\t * from OpenRegister objects (value `id`, label `title` or `name` by\n\t\t * default; tokens resolve). `clearable: true` lets the reader clear the\n\t\t * select back to \"all\" (`placeholder`, e.g. \"All case types\"), which\n\t\t * writes null and seeds nothing. `type: 'quarter'` generates its\n\t\t * options: the current quarter first, then `count - 1` (default 7)\n\t\t * before it, valued `YYYY-Qn` and seeded with the current one;\n\t\t * `type: 'year'` does the same for years (default 5, valued `YYYY`). Empty\n\t\t * (the default) renders no controls and leaves the context untouched.\n\t\t * `control: 'none'` seeds its value like any page filter but draws no\n\t\t * control: a fixed period the widgets read and the description names\n\t\t * (`{filter.<key>}`).\n\t\t *\n\t\t * @type {Array<{key: string, label?: string, type?: string, control?: ('select'|'segmented'), placement?: ('row'|'description'), options?: Array<{value: (string|number), label: string}>, optionsFrom?: object, clearable?: boolean, placeholder?: string, default?: (string|number)}>}\n\t\t */\n\t\tpageFilters: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Show the built-in Refresh item in the page-level overflow Actions\n\t\t * menu. On by default. The default handler emits `@refresh` and,\n\t\t * unless suppressed, fires the `cn:page:refresh` event-bus channel —\n\t\t * which the built-in data widgets subscribe to, so the action works\n\t\t * with no host wiring at all. A `@refresh` listener that calls\n\t\t * `preventDefault()` replaces that default rather than adding to it.\n\t\t *\n\t\t * This is ALSO the default for each widget's own overflow menu: when\n\t\t * `false`, the Refresh item is dropped from every widget too (handy\n\t\t * for a read-only dashboard whose widgets have no refetch wired —\n\t\t * Request-a-feature stays). A widget can still opt back in (or out)\n\t\t * individually via `showRefresh` / `hideRefresh` on its definition or\n\t\t * layout entry.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowRefresh: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Show the built-in Refresh item on each **custom-slot** widget\n\t\t * (distinct from the page-level `showRefresh`). Tri-state:\n\t\t * - `true` / `false` — force it on or off for all custom widgets.\n\t\t * - `null` (the default) — **auto**: show it only when the app using\n\t\t * `CnDashboardPage` attached a `@widget-refresh` listener (i.e. it\n\t\t * will actually handle the refresh). Apps that refresh widgets\n\t\t * centrally by another route (e.g. a header button bumping a shared\n\t\t * signal) leave it unset and get no dead per-widget buttons.\n\t\t *\n\t\t * Built-in chart / NC / integration widgets always show Refresh\n\t\t * (they refresh via the `cn:widget:refresh` bus or their renderer).\n\t\t *\n\t\t * @type {boolean|null}\n\t\t */\n\t\twidgetShowRefresh: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Show the built-in Request-a-feature item in the page-level\n\t\t * overflow Actions menu. On by default; opens the forge's\n\t\t * feature-request issue form when mounted under CnAppRoot.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowRequestFeature: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Show the built-in \"Report a bug\" item in the page-level overflow\n\t\t * Actions menu. On by default — the trio Request a feature / Report a\n\t\t * bug / Documentation is the contract for every Conduction surface.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowReportBug: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Show the built-in Documentation item in the page-level overflow\n\t\t * Actions menu. On by default; the shared menu resolves the target\n\t\t * itself, so leaving it on costs the host nothing.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowDocumentation: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Explicit documentation link for this dashboard, opened in a new tab.\n\t\t * Usually unnecessary: the page-level menu builds one from the\n\t\t * app-wide documentation base and the page id.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tdocumentationUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Pre-translated label for the Documentation action. Defaults to \"Documentation\". */\n\t\tdocumentationLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Documentation'),\n\t\t},\n\n\t\t/**\n\t\t * Stable id for this dashboard, used in the `@refresh` /\n\t\t * `@request-feature` payloads and the `surface: \"dashboard:<id>\"`\n\t\t * field on the feature-request modal. Falls back to a slugified\n\t\t * `title` when unset.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tpageId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether this page keeps a per-user layout.\n\t\t *\n\t\t * Off by default and opted into with one manifest key,\n\t\t * `config.userLayout: true`. A page without it makes NO layout request\n\t\t * and renders exactly as it did before this existed, which is the\n\t\t * property that makes shipping it safe on every dashboard at once.\n\t\t *\n\t\t * Deprecated: layout belongs to Buildiq. Kept working for one release.\n\t\t *\n\t\t * @deprecated\n\t\t * @type {boolean}\n\t\t */\n\t\tuserLayout: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * The Nextcloud app id the user layout is stored under.\n\t\t *\n\t\t * Required for `userLayout` to do anything: a preference has to be\n\t\t * addressed to an app, and storing one under an empty app id writes a\n\t\t * record nothing ever reads back.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tappId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Reads and writes the current user's layout record. Injected so the\n\t\t * component needs no store of its own and a test needs no HTTP: pass\n\t\t * `{ load, save, reset }`, or leave it and the page falls back to the\n\t\t * `dashboardLayoutsPlugin` shape over user preferences.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tuserLayoutStore: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Optional `specRef` slug. Accepted for backward compatibility with\n\t\t * hosts that bound it for the removed in-product suggestion modal;\n\t\t * no longer forwarded anywhere (the forge issue form asks for its\n\t\t * own context).\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tspecRef: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Whether a page-level refresh is in flight (disables the Refresh item and shows its spinner). */\n\t\trefreshing: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Pre-translated label for the Refresh action. */\n\t\trefreshLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Refresh'),\n\t\t},\n\n\t\t/** Pre-translated label for the Request-a-feature action. */\n\t\trequestFeatureLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Request a feature'),\n\t\t},\n\n\t\t/** Pre-translated aria-label / tooltip for the overflow menu trigger. */\n\t\tactionsMenuLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Actions'),\n\t\t},\n\t},\n\n\temits: [\n\t\t'date-range-change',\n\t\t'edit-toggle',\n\t\t'layout-change',\n\t\t'user-layout-reset',\n\t\t'page-filter-change',\n\t\t'refresh',\n\t\t'request-feature',\n\t\t'widget-refresh',\n\t\t'widget-remove',\n\t\t'widget-request-feature',\n\t],\n\n\tsetup(props) {\n\t\t// Wire the pluggable integration registry so widgets of type\n\t\t// `integration` resolve their component reactively. No-op cost\n\t\t// when no integration widgets are configured.\n\t\tconst { integrations: registryIntegrations, resolveWidget, getById } = useIntegrationRegistry()\n\n\t\t// Provide a reactive date-range ref to every descendant widget,\n\t\t// ALWAYS — even when the feature is off. Descendants can then\n\t\t// `inject('cnDashboardDateRange', ref(null))` without a fallback\n\t\t// dance, and the value stays `null` (= no range) until the user\n\t\t// picks one. CnChartWidget reads this via inject() to drive its\n\t\t// bucket-shorthand variables.\n\t\tconst dashboardDateRange = ref(null)\n\t\tprovide('cnDashboardDateRange', dashboardDateRange)\n\n\t\t// Page-level WORKSPACE CONTEXT — a reactive bag of shared keys that\n\t\t// widgets on this page both write (e.g. a page-level client picker sets\n\t\t// `selectedClient`) and read (a client-overview list filters on\n\t\t// `@workspace.selectedClient`). Provided ALWAYS — like cnDashboardDateRange — so\n\t\t// descendants can `inject('cnWorkspaceContext')` without a fallback dance;\n\t\t// the bag starts empty and stays inert for dashboards that don't use it.\n\t\tconst workspaceContext = ref({})\n\t\tprovide('cnWorkspaceContext', workspaceContext)\n\n\t\t// Page-level APP CONFIG — exposed to declarative widget / section config\n\t\t// via the `@config.<key>` token (e.g. the reporting currency the setup\n\t\t// wizard captures). Provided ALWAYS (like cnWorkspaceContext) and kept in\n\t\t// sync with the `appConfig` prop so a late-loaded config re-resolves\n\t\t// downstream tokens. Descendants `inject('cnAppConfig', ref({}))`.\n\t\t// The config an ancestor provides (the app root) is the base; the\n\t\t// page's own `appConfig` wins key by key.\n\t\tconst inheritedConfig = inject('cnAppConfig', null)\n\t\tconst unwrapConfig = (value) => {\n\t\t\tconst raw = value && typeof value === 'object' && 'value' in value ? value.value : value\n\t\t\treturn raw && typeof raw === 'object' ? raw : {}\n\t\t}\n\t\tconst mergedConfig = () => ({ ...unwrapConfig(inheritedConfig), ...(props.appConfig || {}) })\n\t\tconst appConfigRef = ref(mergedConfig())\n\t\tprovide('cnAppConfig', appConfigRef)\n\t\twatch(\n\t\t\t[() => props.appConfig, () => unwrapConfig(inheritedConfig)],\n\t\t\t() => {\n\t\t\t\tappConfigRef.value = mergedConfig()\n\t\t\t},\n\t\t\t{ deep: true },\n\t\t)\n\n\t\treturn {\n\t\t\tregistryIntegrations,\n\t\t\tresolveRegistryWidget: resolveWidget,\n\t\t\tgetRegistryProvider: getById,\n\t\t\tdashboardDateRange,\n\t\t\tworkspaceContext,\n\t\t\tappConfigRef,\n\t\t}\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tisEditing: false,\n\t\t\t/**\n\t\t\t * This user's arranged layout, when `userLayout` is on.\n\t\t\t *\n\t\t\t * 🔴 IT IS A SEPARATE ARRAY, NOT THE `layout` PROP. Drag and resize\n\t\t\t * write into the prop IN PLACE so the in-place manifest editor can\n\t\t\t * diff them, which is right for an admin editing the page for\n\t\t\t * everyone and wrong for a user arranging it for themselves: the\n\t\t\t * same mutation would rewrite the manifest. So a user layout lives\n\t\t\t * here and the prop is never touched.\n\t\t\t *\n\t\t\t * @type {Array<object>|null}\n\t\t\t */\n\t\t\tuserLayoutItems: null,\n\t\t\t/** Whether a stored record has been asked for yet. */\n\t\t\tuserLayoutLoaded: false,\n\t\t\t/** Whether this edit session changed anything worth saving. */\n\t\t\tuserLayoutDirty: false,\n\t\t\t/** Whether the per-widget style/config editor modal is open. */\n\t\t\tshowWidgetConfig: false,\n\t\t\t/** widgetId of the widget currently being configured (drives `configWidget`). */\n\t\t\tconfigWidgetId: null,\n\t\t\t/**\n\t\t\t * Local mirror of the picker's current value. Initialised\n\t\t\t * in `created()` from `dateRange.default` → persisted\n\t\t\t * state → `last-7` fallback, and kept in sync with the\n\t\t\t * provided `dashboardDateRange` ref via a watcher.\n\t\t\t *\n\t\t\t * @type {{ from: string, to: string, preset: string }|null}\n\t\t\t */\n\t\t\tcurrentRange: null,\n\t\t\t/**\n\t\t\t * Per-widget open/close state for the in-chart date-range\n\t\t\t * popover. Keyed by widgetId so each chart widget's chip\n\t\t\t * tracks its own NcActions open state independently. Vue 2\n\t\t\t * reactivity caveat — entries are created lazily via\n\t\t\t * Vue.set when needed.\n\t\t\t *\n\t\t\t * @type {Record<string, boolean>}\n\t\t\t */\n\t\t\topenChipPicker: {},\n\t\t\t// What a registry widget reported for its card header (`header` event), by widget id.\n\t\t\twidgetHeaders: {},\n\t\t\t/**\n\t\t\t * Pre-translated tooltip for the chart-widget date-range\n\t\t\t * chip — kept as a data field rather than a computed so the\n\t\t\t * lib's `translate` is evaluated once at component creation\n\t\t\t * and not on every render.\n\t\t\t */\n\t\t\tdateChipTitle: t('nextcloud-vue', 'Change date range'),\n\t\t\t/**\n\t\t\t * Evaluated `visibleWhen` outcome per conditional widget, keyed\n\t\t\t * by widget id: `{ met, value }` — whether the widget's cell may\n\t\t\t * show, and the raw field value the predicate read (handed to\n\t\t\t * banners so they can interpolate `{value}` into their text and\n\t\t\t * skip re-fetching). Feeds `displayLayout`, which collapses the\n\t\t\t * grid cell of a widget whose condition is unmet — a widget that\n\t\t\t * renders nothing (or a whole card that should not exist yet)\n\t\t\t * would otherwise leave its wrapper card and reserved grid row\n\t\t\t * behind as a tall empty box.\n\t\t\t *\n\t\t\t * @type {Record<string, {met: boolean, value: unknown}>}\n\t\t\t */\n\t\t\twidgetConditionOutcome: {},\n\t\t\t/**\n\t\t\t * Whether the initial predicate evaluation has finished. The\n\t\t\t * grid's FIRST paint waits for it (only when the page actually\n\t\t\t * has conditional widgets), so a conditional widget is present\n\t\t\t * or absent from the first rendered frame — never popping in\n\t\t\t * after load and reflowing everything below it (WCAG-hostile\n\t\t\t * layout shift). Set synchronously when there is nothing to\n\t\t\t * evaluate; never reset once true (a later live change may\n\t\t\t * still reflow, which is the correct behaviour for a state\n\t\t\t * that truly changed).\n\t\t\t */\n\t\t\twidgetConditionsSettled: false,\n\t\t\t/**\n\t\t\t * Monotonic id of the newest evaluateWidgetConditions() run.\n\t\t\t * Each run captures its own id and writes outcomes only while it\n\t\t\t * is still the newest — an older run resolving late (slow\n\t\t\t * endpoint) must not overwrite fresher verdicts, and only the\n\t\t\t * newest run may prune outcomes for removed defs.\n\t\t\t */\n\t\t\twidgetEvalSeq: 0,\n\t\t\t/**\n\t\t\t * Signature of the last-evaluated conditional set — the sorted\n\t\t\t * `[id, visibleWhen]` pairs. The deep `widgets` watch fires on\n\t\t\t * ANY def edit (a title tweak, a color change); re-running the\n\t\t\t * predicates is only warranted when this signature actually\n\t\t\t * changed, otherwise an authoring session would refetch every\n\t\t\t * conditional endpoint on every keystroke.\n\t\t\t */\n\t\t\twidgetEvalSignature: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Effective translate function: the injected `cnTranslate` (the host\n\t\t * app's bound `t()`), identity by default.\n\t\t *\n\t\t * @return {(key: string) => string}\n\t\t */\n\t\teffectiveTranslate() {\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate : (key) => key\n\t\t},\n\n\t\t/**\n\t\t * The header actions handed to CnActionButtons, an entry with `href`\n\t\t * in its link form (resolved URL, anchor target, no handler). An\n\t\t * `href` may carry `@workspace.<key>` / `@page.<key>` tokens, filled\n\t\t * (URL-encoded) from the page filters, so a download link asks for\n\t\t * what the page shows.\n\t\t *\n\t\t * @spec openspec/changes/header-action-href/specs/header-action-href/spec.md#requirement-a-header-action-with-href-is-a-link-that-runs-and-emits-nothing\n\t\t * @return {Array<object>}\n\t\t */\n\t\tlinkedHeaderActions() {\n\t\t\tconst workspace = Object.fromEntries(Object.entries(this.workspaceContext || {})\n\t\t\t\t.map(([key, value]) => [key, (value === undefined || value === null) ? value : encodeURIComponent(String(value))]))\n\t\t\treturn (this.headerActions || [])\n\t\t\t\t.map((entry) => ((entry && typeof entry.href === 'string' && entry.href.includes('@'))\n\t\t\t\t\t? { ...entry, href: interpolateUrlTokens(entry.href, { workspace }) }\n\t\t\t\t\t: entry))\n\t\t\t\t.map(headerActionAsLink)\n\t\t},\n\n\t\t/**\n\t\t * Under the board look the header reads the secondary actions, the\n\t\t * edit toggle and Actions menu, the buildiq square, then the primary\n\t\t * actions, as on an index page (PtDashboard, DqDashboard).\n\t\t *\n\t\t * @return {Array<object>} The header actions that are not `variant: \"primary\"`.\n\t\t */\n\t\tboardSecondaryHeaderActions() {\n\t\t\treturn this.linkedHeaderActions.filter((entry) => entry?.variant !== 'primary')\n\t\t},\n\n\t\t/**\n\t\t * @return {Array<object>} The `variant: \"primary\"` header actions, drawn after the buildiq square.\n\t\t */\n\t\tboardPrimaryHeaderActions() {\n\t\t\treturn this.linkedHeaderActions.filter((entry) => entry?.variant === 'primary')\n\t\t},\n\n\t\t/**\n\t\t * The greeting for the time of day, with the reader's first (or\n\t\t * full) name when known, or '' when `greeting` is off.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-greeting-header/specs/dashboard-page/spec.md#requirement-the-header-subtitle-can-greet-the-reader\n\t\t * @return {string}\n\t\t */\n\t\tgreetingLine() {\n\t\t\tif (this.greeting && typeof this.greeting === 'object') {\n\t\t\t\tconst label = typeof this.greeting.label === 'string' ? this.greeting.label.trim() : ''\n\t\t\t\treturn label ? this.effectiveTranslate(label) : ''\n\t\t\t}\n\t\t\tif (this.greeting !== true && this.greeting !== 'first' && this.greeting !== 'full') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tlet user\n\t\t\ttry {\n\t\t\t\tuser = getCurrentUser()\n\t\t\t} catch {\n\t\t\t\tuser = null\n\t\t\t}\n\t\t\tconst displayName = (user && typeof user.displayName === 'string') ? user.displayName.trim() : ''\n\t\t\tconst name = this.greeting === 'full' ? displayName : displayName.split(/\\s+/)[0]\n\t\t\tconst hour = new Date().getHours()\n\t\t\tif (hour < 12) {\n\t\t\t\treturn name ? t('nextcloud-vue', 'Good morning, {name}', { name }) : t('nextcloud-vue', 'Good morning')\n\t\t\t}\n\t\t\tif (hour < 18) {\n\t\t\t\treturn name ? t('nextcloud-vue', 'Good afternoon, {name}', { name }) : t('nextcloud-vue', 'Good afternoon')\n\t\t\t}\n\t\t\treturn name ? t('nextcloud-vue', 'Good evening, {name}', { name }) : t('nextcloud-vue', 'Good evening')\n\t\t},\n\n\t\t/**\n\t\t * The header subtitle: with `greeting` on, the greeting (or the\n\t\t * label), today's date written out and the description, joined by a\n\t\t * middle dot; with `greeting: \"date\"` the date leads, capitalised;\n\t\t * else the description alone, as before.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-greeting-header/specs/dashboard-page/spec.md#requirement-the-header-subtitle-can-greet-the-reader\n\t\t * @spec openspec/changes/dashboard-greeting-label/specs/dashboard-page/spec.md#requirement-the-header-subtitle-can-lead-with-a-label-or-the-date\n\t\t * @return {string}\n\t\t */\n\t\t/**\n\t\t * `headerMeta` through the host translate, with `{today}` written out as\n\t\t * today's date (DqDagAfsluiten \"Dag afsluiten, woensdag 7 oktober\").\n\t\t *\n\t\t * @spec openspec/changes/record-list-notes/specs/record-list-notes/spec.md#requirement-a-dashboard-header-meta-can-name-today\n\t\t * @return {string}\n\t\t */\n\t\tresolvedHeaderMeta() {\n\t\t\tif (!this.headerMeta) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst meta = this.effectiveTranslate(this.headerMeta)\n\t\t\tif (!meta.includes('{today}')) {\n\t\t\t\treturn meta\n\t\t\t}\n\t\t\tconst options = { weekday: 'long', day: 'numeric', month: 'long' }\n\t\t\tlet today\n\t\t\ttry {\n\t\t\t\ttoday = new Intl.DateTimeFormat(getCanonicalLocale() || undefined, options).format(new Date())\n\t\t\t} catch {\n\t\t\t\ttoday = new Intl.DateTimeFormat(undefined, options).format(new Date())\n\t\t\t}\n\t\t\treturn meta.split('{today}').join(today)\n\t\t},\n\n\t\tsubtitleText() {\n\t\t\tconst description = this.description ? this.resolvedDescription : ''\n\t\t\tconst dateOnly = this.greeting === 'date'\n\t\t\tconst greeting = this.greetingLine\n\t\t\tif (greeting === '' && !dateOnly) {\n\t\t\t\treturn description\n\t\t\t}\n\t\t\tconst options = { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }\n\t\t\tlet date\n\t\t\ttry {\n\t\t\t\tdate = new Intl.DateTimeFormat(getCanonicalLocale() || undefined, options).format(new Date())\n\t\t\t} catch {\n\t\t\t\tdate = new Intl.DateTimeFormat(undefined, options).format(new Date())\n\t\t\t}\n\t\t\tif (dateOnly) {\n\t\t\t\tdate = date.charAt(0).toLocaleUpperCase() + date.slice(1)\n\t\t\t}\n\t\t\treturn [greeting, date, description].filter((part) => part !== '').join(' · ')\n\t\t},\n\n\t\t/**\n\t\t * Whether the page's view switch sits on the switch row under the\n\t\t * header (board look) rather than among the header actions.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-greeting-header/specs/dashboard-page/spec.md#requirement-a-switch-row-carries-the-view-switch-and-link-pills\n\t\t * @return {boolean}\n\t\t */\n\t\tswitchInRow() {\n\t\t\treturn this.isBoardLook && this.showsPageViewSwitch\n\t\t},\n\n\t\t/**\n\t\t * `viewLinks` as render descriptors: a router link for a route, an\n\t\t * anchor for an href, the label translated. Entries without a label\n\t\t * or a target are dropped.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-greeting-header/specs/dashboard-page/spec.md#requirement-a-switch-row-carries-the-view-switch-and-link-pills\n\t\t * @return {Array<{key: string, tag: string, attrs: object, label: string, icon: string}>}\n\t\t */\n\t\tresolvedViewLinks() {\n\t\t\tconst links = Array.isArray(this.viewLinks) ? this.viewLinks : []\n\t\t\tconst out = []\n\t\t\tlinks.forEach((link, index) => {\n\t\t\t\tif (!link || typeof link.label !== 'string' || link.label === '') {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst icon = typeof link.icon === 'string' ? link.icon : ''\n\t\t\t\tconst label = this.effectiveTranslate(link.label)\n\t\t\t\tif (link.route && this.$router) {\n\t\t\t\t\tconst to = typeof link.route === 'string' ? { name: link.route } : link.route\n\t\t\t\t\tout.push({ key: `route-${index}`, tag: 'router-link', attrs: { to }, label, icon })\n\t\t\t\t} else if (typeof link.href === 'string' && link.href !== '') {\n\t\t\t\t\tout.push({ key: `href-${index}`, tag: 'a', attrs: { href: link.href }, label, icon })\n\t\t\t\t}\n\t\t\t})\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * The page title run through the host translate function so a\n\t\t * manifest-authored source string localises. The open view's\n\t\t * `title`, when it has one, takes its place (\"My team\").\n\t\t *\n\t\t * @spec openspec/changes/view-title/specs/view-switch-containers/spec.md#requirement-the-page-title-follows-the-open-view\n\t\t * @return {string}\n\t\t */\n\t\tresolvedTitle() {\n\t\t\tconst view = this.hasViews ? this.activeView : null\n\t\t\tif (view && view.title) {\n\t\t\t\treturn view.title\n\t\t\t}\n\t\t\treturn this.title ? this.effectiveTranslate(this.title) : this.title\n\t\t},\n\n\t\t/**\n\t\t * The page description run through the host translate function.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedDescription() {\n\t\t\tif (!this.description) {\n\t\t\t\treturn this.description\n\t\t\t}\n\t\t\t// `{filter.<key>}`: the page filter's active choice, read as a period\n\t\t\t// (DqProcesanalyse \"Afgehandelde zaken januari tot en met september 2026\").\n\t\t\t// `{dateRange}`: the dashboard's active date range, read as a period\n\t\t\t// (DqDashboard \"Hoe het team ervoor staat · oktober 2026\"); `{today|<format>}`:\n\t\t\t// today through a row template format (DqTermijnen \"Week 41 · alle teams\").\n\t\t\treturn this.effectiveTranslate(this.description)\n\t\t\t\t.replace(/\\{filter\\.([\\w-]+)\\}/g, (token, key) => this.pageFilterPeriodText(key))\n\t\t\t\t.replace(/\\{dateRange\\}/g, () => this.dateRangePeriodText())\n\t\t\t\t.replace(/\\{today\\|([\\w:]+)\\}/g, (token, format) => fillTemplate(`{today|${format}}`, { today: new Date().toISOString() }))\n\t\t},\n\n\t\t/**\n\t\t * Whether the widget grid should be drag/resize/remove-able — the\n\t\t * consumer's own edit toggle OR the Buildiq in-app editor (ADR-041).\n\t\t * Unwraps the injected `cnEditingBody` ref.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tgridEditable() {\n\t\t\treturn this.isEditing || this.editingBody\n\t\t},\n\n\t\t/**\n\t\t * Whether Buildiq is editing the page (the injected `cnEditingBody`\n\t\t * ref, or a plain boolean). Buildiq is the layout editor: while it\n\t\t * edits, the grid shows and changes the manifest layout, also on a\n\t\t * page with `userLayout`.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\teditingBody() {\n\t\t\tconst e = this.cnEditingBody\n\t\t\treturn Boolean(e && typeof e === 'object' && 'value' in e ? e.value : e)\n\t\t},\n\n\t\t/** @return {boolean} Whether the grid shows this user's arrangement. */\n\t\tshowsUserLayout() {\n\t\t\treturn this.userLayout && !this.editingBody && Array.isArray(this.userLayoutItems)\n\t\t},\n\n\t\t/**\n\t\t * The layout actually handed to the grid. In live (non-edit) mode,\n\t\t * widgets that would render nothing right now — a `visibleWhen`\n\t\t * that has not evaluated true, or a banner with no text — are\n\t\t * REMOVED and the remaining items are re-compacted upward:\n\t\t * GridStack runs `float: true`, so a hidden widget otherwise keeps\n\t\t * its wrapper card and its reserved grid row, and a dashboard whose\n\t\t * fail-safe-hidden widgets are (correctly) hidden opens on a column\n\t\t * of tall empty cards.\n\t\t *\n\t\t * Purely a display transform: the authored `layout` prop is never\n\t\t * mutated (`onLayoutChange` merges geometry back into the FULL\n\t\t * authored array by id, so collapsed items survive round-trips), and\n\t\t * edit mode returns the authored layout untouched so hidden widgets\n\t\t * stay visible, placeable and configurable while editing.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tdisplayLayout() {\n\t\t\tif (this.gridEditable) {\n\t\t\t\treturn this.renderedLayout\n\t\t\t}\n\t\t\tconst items = this.renderedLayout || []\n\t\t\tconst visible = items.filter((item) => !this.isCollapsedWidget(item))\n\t\t\tif (visible.length === items.length) {\n\t\t\t\treturn items\n\t\t\t}\n\t\t\treturn this.compactDisplayLayout(visible)\n\t\t},\n\n\t\t/**\n\t\t * The responsive columns of the grid. Under the board look a phone gets\n\t\t * one column: below 640px the widgets stack in reading order (top to\n\t\t * bottom, then left to right) instead of squeezing six columns into\n\t\t * 150px. Without the board look the grid keeps its fixed columns.\n\t\t *\n\t\t * @return {object|null} GridStack `columnOpts`, or null.\n\t\t * @spec openspec/changes/screens-dashboard-phone/specs/dashboard-phone/spec.md#requirement-a-board-dashboard-stacks-on-a-phone\n\t\t */\n\t\tgridColumnOpts() {\n\t\t\tif (!this.isBoardLook) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn { columnMax: this.columns, breakpoints: [{ w: 640, c: 1 }], layout: 'list', breakpointForWindow: true }\n\t\t},\n\n\t\t/**\n\t\t * The layout this page renders: the user's arrangement when they have\n\t\t * one, the manifest otherwise.\n\t\t *\n\t\t * Falling back to the manifest is what makes every failure safe. A\n\t\t * record that has not loaded yet, an instance with no preference\n\t\t * route, a user who has never arranged the page: all three render the\n\t\t * page the admin shipped, which is the page that was there before.\n\t\t *\n\t\t * @return {Array<object>} The layout.\n\t\t */\n\t\trenderedLayout() {\n\t\t\tconst base = this.showsUserLayout ? this.userLayoutItems : this.layout\n\t\t\t// The KPI row is not part of the grid.\n\t\t\tif (Array.isArray(this.kpiRow) && this.kpiRow.length > 0 && Array.isArray(base)) {\n\t\t\t\treturn base.filter((item) => !this.kpiRow.includes(item.widgetId))\n\t\t\t}\n\n\t\t\treturn base\n\t\t},\n\n\t\t/**\n\t\t * Effective Refresh visibility for custom-slot widgets. An explicit\n\t\t * `widgetShowRefresh` prop wins; when unset (`null`), show Refresh\n\t\t * only if the app attached a `@widget-refresh` listener that will\n\t\t * handle it. (The page always attaches its own `@refresh` re-emitter\n\t\t * to each wrapper, so wrapper-level auto-detection can't be relied on\n\t\t * here — we resolve it at the page instead.)\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\teffectiveWidgetShowRefresh() {\n\t\t\tif (this.widgetShowRefresh !== null) {\n\t\t\t\treturn this.widgetShowRefresh\n\t\t\t}\n\t\t\t// `$.vnode.props`, not `$attrs`: a declared emit is stripped out of\n\t\t\t// `$attrs`. And the key is `onWidgetRefresh` — Vue's compiler\n\t\t\t// camelizes every `v-on` argument, so the hyphenated\n\t\t\t// `$attrs['onWidget-refresh']` this used to read was `undefined`\n\t\t\t// unconditionally and the auto-detect never once fired.\n\t\t\treturn Boolean(this.$.vnode.props?.onWidgetRefresh)\n\t\t},\n\n\t\t/**\n\t\t * Stable id for the page-level Actions menu. Prefers the explicit\n\t\t * `pageId` prop; falls back to a slugified `title`, then\n\t\t * `'dashboard'`.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedPageId() {\n\t\t\tif (this.pageId) {\n\t\t\t\treturn this.pageId\n\t\t\t}\n\t\t\tconst slug = (this.title || '').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '')\n\t\t\treturn slug || 'dashboard'\n\t\t},\n\n\t\t/**\n\t\t * Whether the caller supplied an `action-items` slot — forwarded\n\t\t * conditionally so the shared CnActionsMenu doesn't treat an\n\t\t * always-present pass-through template as content.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\thasActionItemsSlot() {\n\t\t\treturn Boolean(this.$slots['action-items']) || Boolean(this.$slots && this.$slots['action-items'])\n\t\t},\n\n\t\t/**\n\t\t * True when the date-range header should render. `false`,\n\t\t * `null`, and `{ enabled: false }` all collapse to `false`.\n\t\t */\n\t\tdateRangeEnabled() {\n\t\t\treturn !!(this.dateRange && this.dateRange.enabled === true)\n\t\t},\n\n\t\t/**\n\t\t * True when the header date-range picker should render. The\n\t\t * range feature must be enabled AND `showHeaderPicker` must not\n\t\t * be explicitly false. Defaults to showing the header (backwards\n\t\t * compatible) — consumers that drive the range entirely through\n\t\t * per-widget chart chips set `dateRange.showHeaderPicker: false`\n\t\t * to drop the redundant header control.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tshowHeaderDateRange() {\n\t\t\treturn this.dateRangeEnabled && this.dateRange.showHeaderPicker !== false\n\t\t},\n\n\t\t/**\n\t\t * Whether the segmented period group sits at the end of the\n\t\t * description line (`dateRange.placement: \"description\"`) instead of\n\t\t * in a row of its own. Only for the segmented control without a\n\t\t * custom range, whose from/to popover keeps the row of its own.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/page-header-breadcrumb/specs/page-header/spec.md#requirement-a-dashboard-can-show-its-period-on-the-description-line\n\t\t */\n\t\tdatePeriodInDescription() {\n\t\t\treturn this.showHeaderDateRange && this.dateRangeControl === 'segmented'\n\t\t\t\t&& this.dateRange.placement === 'description' && !this.hasCustomPreset\n\t\t},\n\n\t\t/**\n\t\t * The page filters drawn as a segmented group on the description\n\t\t * line (`control: \"segmented\"`, `placement: \"description\"`).\n\t\t * Without a header row they fall back to the filter row.\n\t\t *\n\t\t * @spec openspec/changes/dashboard-board-termijnen/specs/dashboard-page/spec.md#requirement-a-page-filter-as-a-segmented-group-on-the-description-line\n\t\t * @return {Array<object>}\n\t\t */\n\t\tdescriptionPageFilters() {\n\t\t\tif (!this.showHeader) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn (this.pageFilters || []).filter((pf) => pf && pf.key && pf.control === 'segmented' && pf.placement === 'description')\n\t\t},\n\n\t\t/**\n\t\t * The page filters drawn in the filter row under the header: every\n\t\t * filter the description line does not draw.\n\t\t *\n\t\t * @spec openspec/changes/dashboard-board-termijnen/specs/dashboard-page/spec.md#requirement-a-page-filter-as-a-segmented-group-on-the-description-line\n\t\t * @return {Array<object>}\n\t\t */\n\t\trowPageFilters() {\n\t\t\tconst inDescription = [...this.descriptionPageFilters, ...this.descriptionSelectFilters]\n\t\t\t// `control: \"none\"` holds a value for the widgets and the\n\t\t\t// description and draws no control (DqDoorlooptijd's fixed period).\n\t\t\treturn (this.pageFilters || []).filter((pf) => pf && pf.key && pf.control !== 'none' && !inDescription.includes(pf))\n\t\t},\n\n\t\t/**\n\t\t * The select page filters drawn on the description line\n\t\t * (`placement: \"description\"`, any control but `segmented`), before\n\t\t * the period group: DqDoorlooptijd's \"alle zaaktypen\". Without a\n\t\t * header row they fall back to the filter row.\n\t\t *\n\t\t * @spec openspec/changes/dashboard-select-filter-in-description/specs/dashboard-select-filter-in-description/spec.md#requirement-a-select-page-filter-can-sit-on-the-description-line\n\t\t * @return {Array<object>}\n\t\t */\n\t\tdescriptionSelectFilters() {\n\t\t\tif (!this.showHeader) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn (this.pageFilters || []).filter((pf) => pf && pf.key && pf.control !== 'segmented' && pf.control !== 'none' && pf.placement === 'description')\n\t\t},\n\n\t\t/**\n\t\t * Every page filter the description line draws, in the order the\n\t\t * page declares them, selects and segmented groups alike.\n\t\t *\n\t\t * @spec openspec/changes/dashboard-description-filters-in-order/specs/dashboard-description-filters-in-order/spec.md#requirement-the-description-line-draws-its-page-filters-in-declared-order\n\t\t * @return {Array<object>}\n\t\t */\n\t\tdescriptionFilters() {\n\t\t\tconst drawn = [...this.descriptionPageFilters, ...this.descriptionSelectFilters]\n\t\t\treturn (this.pageFilters || []).filter((pf) => drawn.includes(pf))\n\t\t},\n\n\t\t/**\n\t\t * The edit button's label through the app's translate: a manifest's\n\t\t * `editLabel` (\"Edit layout\", DqDashboard) reads in the user's language.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tshownEditLabel() {\n\t\t\treturn this.effectiveTranslate(this.editLabel)\n\t\t},\n\n\t\t/**\n\t\t * The done button's label through the app's translate.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tshownDoneLabel() {\n\t\t\treturn this.effectiveTranslate(this.doneLabel)\n\t\t},\n\n\t\t/**\n\t\t * The preset list passed to the picker. Falls back to the\n\t\t * `DEFAULT_DATE_RANGE_PRESETS` constant when the consumer\n\t\t * doesn't supply one.\n\t\t */\n\t\teffectivePresets() {\n\t\t\tconst presets = Array.isArray(this.dateRange?.presets) && this.dateRange.presets.length > 0\n\t\t\t\t? this.dateRange.presets\n\t\t\t\t: DEFAULT_DATE_RANGE_PRESETS\n\t\t\t// Labels in the user's language (screens-dashboard-i18n): the app's\n\t\t\t// catalogue first, then the library's own for the default labels.\n\t\t\treturn presets.map((p) => ({ ...p, label: translatePresetLabel(p.label, this.effectiveTranslate) }))\n\t\t},\n\n\t\t/**\n\t\t * Which header date-range control to render. `'pills'` swaps the\n\t\t * select + two date inputs for a compact segmented pill row; any\n\t\t * other value (or none) keeps the default `CnDateRangePicker`.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tdateRangeControl() {\n\t\t\tconst control = this.dateRange?.control\n\t\t\treturn control === 'pills' || control === 'segmented' ? control : 'picker'\n\t\t},\n\n\t\t/**\n\t\t * Whether the app takes the board look (`cnLook` is `board`).\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-parity/specs/dashboard-page/spec.md#requirement-the-board-dashboard-header\n\t\t * @return {boolean}\n\t\t */\n\t\tisBoardLook() {\n\t\t\treturn normalizeLook(this.cnLook) === 'board'\n\t\t},\n\n\t\t/**\n\t\t * The options of the segmented period group: the presets, and the\n\t\t * custom range, when offered, as the last segment.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-parity/specs/dashboard-page/spec.md#requirement-the-period-as-a-segmented-group\n\t\t * @return {Array<{value: string, label: string}>}\n\t\t */\n\t\tsegmentedOptions() {\n\t\t\tconst options = this.pillPresets.map((p) => ({ value: p.id, label: p.label }))\n\t\t\tif (this.hasCustomPreset) {\n\t\t\t\toptions.push({ value: 'custom', label: this.customRangeLabel })\n\t\t\t}\n\t\t\treturn options\n\t\t},\n\n\t\t/**\n\t\t * The segment that is pressed: the current range's preset.\n\t\t *\n\t\t * @return {string|null}\n\t\t */\n\t\tsegmentedValue() {\n\t\t\treturn (this.currentRange && this.currentRange.preset) || null\n\t\t},\n\n\t\t/**\n\t\t * Accessible name of the period group.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tdatePeriodLabel() {\n\t\t\treturn t('nextcloud-vue', 'Period')\n\t\t},\n\n\t\t/**\n\t\t * The KPI row's widgets as layout-like items (`{ widgetId }`), in the\n\t\t * order `kpiRow` lists them.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-parity/specs/dashboard-page/spec.md#requirement-a-kpi-row-above-the-grid\n\t\t * @return {Array<{widgetId: string}>}\n\t\t */\n\t\tkpiRowItems() {\n\t\t\tconst ids = Array.isArray(this.kpiRow) ? this.kpiRow : []\n\t\t\tconst items = []\n\t\t\tfor (const id of ids) {\n\t\t\t\tif (this.getWidgetDef(id) || this.hasWidgetSlot(id)) {\n\t\t\t\t\t// A tile a page control hides surrenders its cell.\n\t\t\t\t\tif (!this.gridEditable && this.isHiddenByWorkspace(id)) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\titems.push({ widgetId: id })\n\t\t\t\t} else if (process.env.NODE_ENV !== 'production') {\n\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\tconsole.warn(`[CnDashboardPage] kpiRow names the widget \"${id}\", which is not defined; skipped.`)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn items\n\t\t},\n\n\t\t/**\n\t\t * Compact, always-present label for the per-widget date chip\n\t\t * (`layout[].dateChip`). Prefers the active preset's own label (e.g.\n\t\t * `7d` / `30d` / `All`) so a KPI card surfaces a tidy period token;\n\t\t * falls back to the concrete `from – to` span for a manual range, and\n\t\t * to a generic \"Date range\" when neither is known. NEVER empty, so the\n\t\t * chip stays clickable even on an unbounded (\"All\") range.\n\t\t *\n\t\t * @return {string} The chip label.\n\t\t */\n\t\tdashboardRangeChipLabel() {\n\t\t\tconst rng = this.currentRange || this.dashboardDateRange\n\t\t\tif (rng && rng.preset && rng.preset !== 'custom') {\n\t\t\t\tconst preset = this.effectivePresets.find((p) => p && p.id === rng.preset)\n\t\t\t\tif (preset && preset.label) {\n\t\t\t\t\treturn preset.label\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn this.formatDashboardDateRange() || t('nextcloud-vue', 'Date range')\n\t\t},\n\n\t\t/**\n\t\t * Preset list rendered as pills — `effectivePresets` minus the\n\t\t * manual `custom` entry (which surfaces as a separate de-emphasised\n\t\t * popover pill instead of a bare toggle).\n\t\t *\n\t\t * @return {Array<{ id: string, label: string }>}\n\t\t */\n\t\tpillPresets() {\n\t\t\treturn this.effectivePresets.filter((p) => p && p.id !== 'custom')\n\t\t},\n\n\t\t/**\n\t\t * Whether a `custom` preset exists in the list — drives the optional\n\t\t * \"Custom range\" popover pill in pills mode.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\thasCustomPreset() {\n\t\t\treturn this.effectivePresets.some((p) => p && p.id === 'custom')\n\t\t},\n\n\t\t/**\n\t\t * Accessible label for the pill toggle group.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tdatePillsGroupLabel() {\n\t\t\treturn t('nextcloud-vue', 'Date range')\n\t\t},\n\n\t\t/**\n\t\t * Label for the custom-range pill: the `custom` preset's own label\n\t\t * when set, else a sensible default.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tcustomRangeLabel() {\n\t\t\tconst c = this.effectivePresets.find((p) => p && p.id === 'custom')\n\t\t\treturn (c && c.label) || t('nextcloud-vue', 'Custom range')\n\t\t},\n\n\t\t/**\n\t\t * True when the dashboard has either classic grid widgets (via\n\t\t * `layout`) or declarative `content[]` widget-ref items to render.\n\t\t */\n\t\thasWidgets() {\n\t\t\t// Depend on the (always-reactive) edit flag so this computed\n\t\t\t// re-evaluates when in-app edit mode flips. Manifest arrays are raw\n\t\t\t// until useManifestEditor.enter() observes them in place — a cache\n\t\t\t// built pre-edit has no reactive deps and would stay frozen forever,\n\t\t\t// keeping the empty state on screen after the first Add widget.\n\t\t\t// Re-evaluating post-enter re-subscribes against the reactive graph.\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unused-expressions -- the read IS the effect: it registers the reactive dependency.\n\t\t\tthis.gridEditable\n\t\t\treturn this.layout.length > 0 || this.widgetRefItems.length > 0\n\t\t},\n\n\t\t/**\n\t\t * Whether the grid sections render at all: not while loading, not\n\t\t * while the widget predicates settle, not on the empty page and not\n\t\t * on a widget-ref content page.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-page-declares-views-that-each-hold-a-widget-grid\n\t\t */\n\t\tgridSectionsShown() {\n\t\t\tif (this.loading || (!this.widgetConditionsSettled && !this.gridEditable)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif (!this.hasWidgets && !this.hasBodyWidgets && !this.hasViews) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn this.widgetRefItems.length === 0\n\t\t},\n\n\t\t/**\n\t\t * The chosen view's layout as the grid draws it: in live mode the\n\t\t * widgets that would draw nothing leave and the rest close up, as\n\t\t * for the page's own layout.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t * @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-view-with-nothing-to-draw-says-so\n\t\t */\n\t\tviewDisplayLayout() {\n\t\t\tconst items = this.activeViewLayout\n\t\t\tif (this.gridEditable) {\n\t\t\t\treturn items\n\t\t\t}\n\t\t\tconst visible = items.filter((item) => !this.isCollapsedWidget(item))\n\t\t\treturn visible.length === items.length ? items : this.compactDisplayLayout(visible)\n\t\t},\n\n\t\t/**\n\t\t * Whether the chosen view has nothing to draw.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-view-with-nothing-to-draw-says-so\n\t\t */\n\t\tviewIsEmpty() {\n\t\t\treturn this.hasViews && this.viewDisplayLayout.length === 0\n\t\t},\n\n\t\t/**\n\t\t * The grids this page draws. Without views: the page's own layout,\n\t\t * as it always was. With views: the page's own layout when it has\n\t\t * items, then the chosen view's layout in the region the switch\n\t\t * controls (left out when the view is empty; the empty state takes\n\t\t * the region then).\n\t\t *\n\t\t * @return {Array<{key: string, view: boolean, layout: Array<object>, editable: boolean, attrs: object}>}\n\t\t * @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-page-declares-views-that-each-hold-a-widget-grid\n\t\t */\n\t\tgridSections() {\n\t\t\tif (!this.gridSectionsShown) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst page = { key: 'page', view: false, layout: this.displayLayout, editable: this.gridEditable, sideColumn: this.gridSideColumn, attrs: {} }\n\t\t\tif (!this.hasViews) {\n\t\t\t\treturn [page]\n\t\t\t}\n\t\t\tconst sections = this.displayLayout.length > 0 ? [page] : []\n\t\t\tif (!this.viewIsEmpty) {\n\t\t\t\tsections.push({\n\t\t\t\t\tkey: `view-${this.activeViewId}`,\n\t\t\t\t\tview: true,\n\t\t\t\t\tlayout: this.viewDisplayLayout,\n\t\t\t\t\t// With `userLayout` the user arranges the view too; the\n\t\t\t\t\t// arrangement is kept per view (pageViews mixin).\n\t\t\t\t\teditable: this.gridEditable,\n\t\t\t\t\tsideColumn: this.activeView.gridSideColumn || null,\n\t\t\t\t\tattrs: {\n\t\t\t\t\t\tid: this.viewRegionId,\n\t\t\t\t\t\trole: 'region',\n\t\t\t\t\t\t'aria-label': this.activeView.label,\n\t\t\t\t\t\tclass: 'cn-page-view-region',\n\t\t\t\t\t\t'data-testid': 'cn-dashboard-page-view-region',\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn sections\n\t\t},\n\n\t\t/**\n\t\t * The widget settings object handed to CnWidgetStyleEditorModal,\n\t\t * built from the widget definition currently being configured\n\t\t * (`configWidgetId`). Carries the chrome fields the editor reads /\n\t\t * mutates (`title`, `styleConfig`, `showTitle`, `customTitle`,\n\t\t * `customIcon`, `content`) plus the widget `id`. Returns an empty\n\t\t * shell when nothing is selected so the modal's `required` widget\n\t\t * prop never sees null.\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\tconfigWidget() {\n\t\t\tconst def = this.getWidgetDef(this.configWidgetId) || {}\n\t\t\t// Bridge legacy data-driven widgets (chart / stats-block / table that\n\t\t\t// carry top-level `props` + `dataSource` instead of `content`) into a\n\t\t\t// `content` shape so their config form pre-fills. Once saved, the\n\t\t\t// content-aware getters take over.\n\t\t\tlet content = def.content || {}\n\t\t\tif ((!content || Object.keys(content).length === 0) && (def.props || def.dataSource)) {\n\t\t\t\tcontent = {}\n\t\t\t\tif (def.title) {\n\t\t\t\t\tcontent.title = def.title\n\t\t\t\t}\n\t\t\t\tif (def.props) {\n\t\t\t\t\tcontent.props = def.props\n\t\t\t\t\tif (def.props.chartKind) {\n\t\t\t\t\t\tcontent.chartKind = def.props.chartKind\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (def.dataSource) {\n\t\t\t\t\tcontent.dataSource = def.dataSource\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tid: def.id || this.configWidgetId,\n\t\t\t\ttype: def.type || '',\n\t\t\t\ttitle: def.title || '',\n\t\t\t\tstyleConfig: def.styleConfig || {},\n\t\t\t\t// Left raw (possibly undefined) so the modal can apply the\n\t\t\t\t// card-aware default rather than being handed a coerced `true`.\n\t\t\t\tshowTitle: def.showTitle,\n\t\t\t\tcustomTitle: def.customTitle || '',\n\t\t\t\tcustomIcon: def.customIcon || '',\n\t\t\t\tcontent,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Filtered list of `widget-ref` items from `content[]`.\n\t\t * Unknown `type` values are logged and excluded so future\n\t\t * content item types can be added without breaking existing\n\t\t * dashboards.\n\t\t *\n\t\t * @return {Array<{ type: 'widget-ref', ref: string }>}\n\t\t */\n\t\twidgetRefItems() {\n\t\t\tconst out = []\n\t\t\tfor (const item of this.content) {\n\t\t\t\tif (!item || typeof item !== 'object') {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (item.type === 'widget-ref') {\n\t\t\t\t\tout.push(item)\n\t\t\t\t} else {\n\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\tconsole.warn(`[CnDashboardPage] Unknown content item type \"${item.type}\" — only \"widget-ref\" is supported. Item will be skipped.`)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Whether any in-body sections are configured (drives the three\n\t\t * placement mounts of CnBodySections).\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\thasBodyWidgets() {\n\t\t\treturn Array.isArray(this.bodyWidgets) && this.bodyWidgets.length > 0\n\t\t},\n\n\t\t/**\n\t\t * Sections that land at the END placement: those with no `placement` (the\n\t\t * default) or an explicit `placement: \"end\"`. The two named placement\n\t\t * mounts (`before-grid` / `after-grid`) filter by their own value, so this\n\t\t * computed excludes them to avoid double-rendering.\n\t\t *\n\t\t * @return {Array}\n\t\t */\n\t\tendPlacementSections() {\n\t\t\tconst named = ['before-grid', 'after-grid']\n\t\t\treturn (Array.isArray(this.bodyWidgets) ? this.bodyWidgets : [])\n\t\t\t\t.filter((s) => !s || !s.placement || !named.includes(s.placement))\n\t\t},\n\n\t\t/**\n\t\t * Page context forwarded to CnBodySections for token resolution\n\t\t * (`@workspace.<key>` / `@page.<key>` / `@config.<key>` + time tokens) AND\n\t\t * provided on `cnSectionContext` for host section components that inject.\n\t\t * The optional object scoping (`objectId` / `register` / `schema`) is read\n\t\t * from `integrationContext` so an object-scoped dashboard can resolve\n\t\t * `@objectId` / `@object.<field>` too.\n\t\t *\n\t\t * @return {{objectId: (string|null), register: string, schema: string, workspace: object, config: object}}\n\t\t */\n\t\tsectionContext() {\n\t\t\tconst ic = this.integrationContext || {}\n\t\t\treturn {\n\t\t\t\tobjectId: (ic.objectId !== undefined && ic.objectId !== null) ? String(ic.objectId) : null,\n\t\t\t\tregister: ic.register || '',\n\t\t\t\tschema: ic.schema || '',\n\t\t\t\tworkspace: this.workspaceContext,\n\t\t\t\tconfig: this.appConfigRef,\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\t/**\n\t\t * Re-evaluate the widget predicates when the defs change — the\n\t\t * in-app editor (ADR-041) mutates widget defs in place and \"Add\n\t\t * widget\" pushes into the same array, so a deep watch is the only\n\t\t * signal that a widget's `visibleWhen` was added or edited.\n\t\t */\n\t\twidgets: {\n\t\t\tdeep: true,\n\t\t\thandler() {\n\t\t\t\tthis.evaluateWidgetConditions()\n\t\t\t},\n\t\t},\n\n\t\t/** A view's widgets carry predicates too. */\n\t\tviews: {\n\t\t\tdeep: true,\n\t\t\thandler() {\n\t\t\t\tthis.evaluateWidgetConditions()\n\t\t\t},\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.pushAiContext()\n\t\tthis.initDateRange()\n\t\tthis.initPageFilters()\n\t\tthis.loadPageFilterOptions()\n\t\tthis.evaluateWidgetConditions()\n\t\tthis.loadUserLayout()\n\t},\n\n\tbeforeUnmount() {\n\t\tif (this.cnAiContext) {\n\t\t\tthis.cnAiContext.pageKind = 'custom'\n\t\t\tthis.cnAiContext.registerSlug = undefined\n\t\t\tthis.cnAiContext.schemaSlug = undefined\n\t\t}\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Re-emit the page-level CnActionsMenu `@refresh` to the host,\n\t\t * passing the synthetic event through so a host listener can\n\t\t * `preventDefault()` the built-in default (event-bus emit on\n\t\t * `cn:page:refresh`). Distinct from `@widget-refresh`, which the\n\t\t * per-widget menus emit.\n\t\t *\n\t\t * @param {{ widgetId: string, title: string }} payload Action payload.\n\t\t * @param {{ defaultPrevented: boolean, preventDefault: () => void }} ev Synthetic event.\n\t\t * @return {void}\n\t\t */\n\t\tonActionsRefresh(payload, ev) {\n\t\t\t/**\n\t\t\t * @event refresh User clicked Refresh in the page-level overflow\n\t\t\t * Actions menu. Payload: `{ widgetId, title }`. Handlers may\n\t\t\t * call the second arg's `preventDefault()` to suppress the\n\t\t\t * built-in default (event-bus emit on `cn:page:refresh`).\n\t\t\t * @type {{ widgetId: string, title: string }}\n\t\t\t */\n\t\t\tthis.$emit('refresh', payload, ev)\n\t\t},\n\n\t\t/**\n\t\t * Re-emit the page-level CnActionsMenu `@request-feature` to the\n\t\t * host. Distinct from `@widget-request-feature`.\n\t\t *\n\t\t * @param {{ widgetId: string, title: string }} payload Action payload.\n\t\t * @param {{ defaultPrevented: boolean, preventDefault: () => void }} ev Synthetic event.\n\t\t * @return {void}\n\t\t */\n\t\tonActionsRequestFeature(payload, ev) {\n\t\t\t/**\n\t\t\t * @event request-feature User clicked Request a feature in the\n\t\t\t * page-level overflow Actions menu. Payload: `{ widgetId,\n\t\t\t * title }`. Handlers may call the second arg's\n\t\t\t * `preventDefault()` to suppress the built-in default\n\t\t\t * (opening the forge's feature-request issue form).\n\t\t\t * @type {{ widgetId: string, title: string }}\n\t\t\t */\n\t\t\tthis.$emit('request-feature', payload, ev)\n\t\t},\n\n\t\t/**\n\t\t * Forward a widget's `@refresh` from CnWidgetWrapper to the\n\t\t * dashboard host. The host wires this to its data-fetching layer\n\t\t * (e.g. re-fetching the GraphQL aggregate for a chart). Payload\n\t\t * is the layout item so consumers can route by widget id.\n\t\t *\n\t\t * @param {object} item Layout item descriptor.\n\t\t * @return {void}\n\t\t */\n\t\tonWidgetRefresh(item) {\n\t\t\t/**\n\t\t\t * @event widget-refresh User clicked Refresh in a widget's\n\t\t\t * overflow action menu. Payload: the layout item descriptor.\n\t\t\t */\n\t\t\tthis.$emit('widget-refresh', item)\n\t\t},\n\n\t\t/**\n\t\t * Forward a widget's `@request-feature` from CnWidgetWrapper to\n\t\t * the dashboard host. The host decides where to send the user\n\t\t * (typically an issue tracker).\n\t\t *\n\t\t * @param {object} item Layout item descriptor.\n\t\t * @return {void}\n\t\t */\n\t\tonWidgetRequestFeature(item) {\n\t\t\t/**\n\t\t\t * @event widget-request-feature User clicked Request a\n\t\t\t * feature in a widget's overflow action menu. Payload: the\n\t\t\t * layout item descriptor.\n\t\t\t */\n\t\t\tthis.$emit('widget-request-feature', item)\n\t\t},\n\n\t\t/**\n\t\t * Format a chart widget's bucket date range as a short readable\n\t\t * chip, rendered inside CnWidgetWrapper's `#title-meta` slot.\n\t\t * Returns null when the bucket has neither a `staticRange` nor\n\t\t * resolved `from`/`to` via the reactive dashboard `dateRange`\n\t\t * provide (in which case the chip simply doesn't render).\n\t\t *\n\t\t * @param {object} item Layout item descriptor with chart shorthand.\n\t\t * @return {string|null} `\"2026-05-18 → 2026-05-25\"` or null.\n\t\t */\n\t\tformatChartDateRange(item) {\n\t\t\tconst ds = this.getWidgetDataSource(item) || {}\n\t\t\tconst bucket = ds.bucket || {}\n\t\t\t// 1. Bucket-level staticRange wins (explicit per-widget freeze).\n\t\t\tconst sr = bucket.staticRange || {}\n\t\t\tlet from = sr.from || null\n\t\t\tlet to = sr.to || null\n\t\t\t// 2. Fall back to the dashboard-level reactive dateRange when\n\t\t\t// the bucket uses fromVar/toVar shorthand. Vue 2.7's setup\n\t\t\t// auto-unwraps refs when accessed via `this`, so\n\t\t\t// `this.dashboardDateRange` IS the current value (not the\n\t\t\t// ref). Assignments in setRange() / initial-range\n\t\t\t// methods write through to the ref's `.value` automatically.\n\t\t\tif ((!from || !to) && this.dashboardDateRange) {\n\t\t\t\tconst rng = this.dashboardDateRange\n\t\t\t\tif (bucket.fromVar && rng[bucket.fromVar]) {\n\t\t\t\t\tfrom = from || rng[bucket.fromVar]\n\t\t\t\t}\n\t\t\t\tif (bucket.toVar && rng[bucket.toVar]) {\n\t\t\t\t\tto = to || rng[bucket.toVar]\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn this.formatRangeLabel(from, to)\n\t\t},\n\n\t\t/**\n\t\t * Format the SHARED dashboard date range as a compact chip label.\n\t\t * Used by the opt-in custom-widget date chip (`layout[].dateChip`),\n\t\t * which has no per-widget dataSource to derive a window from —\n\t\t * the chip always surfaces the dashboard-level range.\n\t\t *\n\t\t * @return {string|null} `\"18 May – 25 May\"` or null when no range is set.\n\t\t */\n\t\tformatDashboardDateRange() {\n\t\t\tconst rng = this.dashboardDateRange\n\t\t\tif (!rng) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.formatRangeLabel(rng.from || null, rng.to || null)\n\t\t},\n\n\t\t/**\n\t\t * Friendly compact label: \"18 May – 25 May\" / \"18 Dec 2025 – 2 Jan 2026\".\n\t\t * The year is only shown when a bound falls outside the current\n\t\t * year, keeping the common same-year case short while staying\n\t\t * unambiguous for older / cross-year windows.\n\t\t *\n\t\t * @param {string|null} from ISO-8601 lower bound (or null).\n\t\t * @param {string|null} to ISO-8601 upper bound (or null).\n\t\t * @return {string|null} Formatted label, or null when both bounds are empty.\n\t\t */\n\t\t/**\n\t\t * A page filter's active choice read as a period, for `{filter.<key>}`\n\t\t * in the description: the declared (or generated) option the workspace\n\t\t * holds, its label through the host translate.\n\t\t *\n\t\t * @param {string} key The page filter's key.\n\t\t * @return {string} The period, '' when the filter or its choice is missing.\n\t\t * @spec openspec/changes/description-period-from-filter/specs/description-period-from-filter/spec.md#requirement-a-dashboard-description-reads-the-active-period-of-a-page-filter\n\t\t */\n\t\tpageFilterPeriodText(key) {\n\t\t\tconst pf = (this.pageFilters || []).find((filter) => filter && filter.key === key)\n\t\t\tif (!pf) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst options = Array.isArray(pf.options) ? pf.options : (generatedPageFilterOptions(pf) || this.pageFilterFetched[pf.key] || [])\n\t\t\tconst option = options.find((o) => o && o.value === this.workspaceContext[pf.key])\n\t\t\tif (!option) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn periodText({ ...option, label: option.label ? this.effectiveTranslate(option.label) : String(option.value) }, new Date(), userLocale())\n\t\t},\n\n\t\t/**\n\t\t * The dashboard's active date range read as a period, for\n\t\t * `{dateRange}` in the description: a calendar preset as its month,\n\t\t * quarter or year, another preset as its translated label, a custom\n\t\t * range as its dates.\n\t\t *\n\t\t * @return {string} The period, '' without an active range.\n\t\t * @spec openspec/changes/description-period-from-date-range/specs/description-period-from-date-range/spec.md#requirement-a-dashboard-description-reads-the-active-date-range-as-a-period\n\t\t */\n\t\tdateRangePeriodText() {\n\t\t\tconst rng = this.currentRange || this.dashboardDateRange\n\t\t\tif (!this.dateRangeEnabled || !rng) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst preset = rng.preset && rng.preset !== 'custom'\n\t\t\t\t? this.effectivePresets.find((p) => p && p.id === rng.preset)\n\t\t\t\t: null\n\t\t\tconst label = preset ? translatePresetLabel(preset.label, this.effectiveTranslate) : ''\n\t\t\treturn rangePeriodText(rng, preset ? { ...preset, label } : null, userLocale())\n\t\t\t\t|| this.formatRangeLabel(rng.from || null, rng.to || null)\n\t\t\t\t|| ''\n\t\t},\n\n\t\tformatRangeLabel(from, to) {\n\t\t\tif (!from && !to) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst toDate = (v) => {\n\t\t\t\tif (typeof v !== 'string' || v.length < 10) {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\tconst d = new Date(`${v.slice(0, 10)}T00:00:00`)\n\t\t\t\treturn Number.isNaN(d.getTime()) ? null : d\n\t\t\t}\n\t\t\tconst fromDate = toDate(from)\n\t\t\tconst toDateValue = toDate(to)\n\t\t\tconst thisYear = new Date().getFullYear()\n\t\t\tconst needsYear = [fromDate, toDateValue].some((d) => d && d.getFullYear() !== thisYear)\n\t\t\tconst fmt = (d) => {\n\t\t\t\tif (!d) {\n\t\t\t\t\treturn ''\n\t\t\t\t}\n\t\t\t\treturn d.toLocaleDateString(userLocale(), {\n\t\t\t\t\tday: 'numeric',\n\t\t\t\t\tmonth: 'short',\n\t\t\t\t\t...(needsYear ? { year: 'numeric' } : {}),\n\t\t\t\t})\n\t\t\t}\n\t\t\tconst left = fmt(fromDate)\n\t\t\tconst right = fmt(toDateValue)\n\t\t\tif (left && right) {\n\t\t\t\treturn `${left} – ${right}`\n\t\t\t}\n\t\t\treturn (left || right) || null\n\t\t},\n\n\t\t/**\n\t\t * Handle a preset pick from the in-chip date-range popover. The\n\t\t * popover renders the same preset list the global picker uses\n\t\t * (effectivePresets). On click we resolve the preset to a from/to\n\t\t * window, build a `{ from, to, preset }` value, and forward to the\n\t\t * existing `onDateRangeChange` — same handler the top picker uses.\n\t\t * Effect: the chip is a per-chart shortcut to the dashboard-wide\n\t\t * range, not a per-widget override.\n\t\t *\n\t\t * @param {{ label: string, value: string }} preset Preset descriptor.\n\t\t * @param {object} _item Layout item (unused — included so the\n\t\t * binding shape matches the template's `@click` signature).\n\t\t * @return {void}\n\t\t */\n\t\tonChipPresetPick(preset, _item) {\n\t\t\tif (!preset || !preset.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (preset.id === 'custom') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.isClearPreset(preset)) {\n\t\t\t\tthis.onDateRangeChange({ from: '', to: '', preset: preset.id })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst win = resolvePresetWindow(preset.id, this.effectivePresets)\n\t\t\tif (!win) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.onDateRangeChange({ ...win, preset: preset.id })\n\t\t},\n\n\t\t/**\n\t\t * Handle a press on a segment of the period group\n\t\t * (`dateRange.control: \"segmented\"`): the same range change as a pill.\n\t\t * The custom segment keeps the current window and opens the from/to\n\t\t * popover.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-parity/specs/dashboard-page/spec.md#requirement-the-period-as-a-segmented-group\n\t\t * @param {string} value The preset id of the pressed segment.\n\t\t * @return {void}\n\t\t */\n\t\tonSegmentPick(value) {\n\t\t\tif (value === 'custom') {\n\t\t\t\tthis.onDateRangeChange({\n\t\t\t\t\tfrom: this.currentRange?.from || '',\n\t\t\t\t\tto: this.currentRange?.to || '',\n\t\t\t\t\tpreset: 'custom',\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst preset = this.pillPresets.find((p) => p.id === value)\n\t\t\tif (preset) {\n\t\t\t\tthis.onPillPick(preset)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Props shared by the wrapper of a KPI row tile.\n\t\t *\n\t\t * @param {{widgetId: string}} item The row item.\n\t\t * @return {object}\n\t\t */\n\t\tkpiWrapperProps(item) {\n\t\t\treturn {\n\t\t\t\twidgetId: item.widgetId,\n\t\t\t\ttitle: this.getWidgetTitle(item),\n\t\t\t\teyebrow: this.getWidgetEyebrow(item),\n\t\t\t\ttitleTone: this.getWidgetTitleTone(item),\n\t\t\t\tsubtitle: this.getWidgetSubtitle(item),\n\t\t\t\tshowTitle: this.widgetShowTitle(item),\n\t\t\t\tshowActions: this.widgetShowActions(item),\n\t\t\t\tshowRefresh: this.getWidgetShowRefresh(item),\n\t\t\t\tborderless: this.widgetBorderless(item),\n\t\t\t\tflush: true,\n\t\t\t\tclass: { 'cn-dashboard-page__card-fit': this.isCardWidget(item) },\n\t\t\t\tbuttons: this.getWidgetButtons(item),\n\t\t\t\theaderLink: this.getWidgetHeaderLink(item),\n\t\t\t\tstyleConfig: item.styleConfig || {},\n\t\t\t\tdocumentationUrl: this.getWidgetDocumentationUrl(item),\n\t\t\t\tdocsAnchor: this.getWidgetDocsAnchor(item),\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Handle a header date-range pill click (pills mode). Resolves the\n\t\t * preset to a from/to window and forwards to `onDateRangeChange` —\n\t\t * the same handler the select picker uses — so the active range\n\t\t * drives every widget identically. Re-clicking the active pill\n\t\t * re-resolves (cheap no-op for fixed presets).\n\t\t *\n\t\t * @param {{ id: string, label: string }} preset The picked preset.\n\t\t * @return {void}\n\t\t */\n\t\tonPillPick(preset) {\n\t\t\tif (!preset || !preset.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// An \"All\" / clear preset removes the window (empty from/to) so\n\t\t\t// optional date tokens drop and widgets show the unfiltered count.\n\t\t\tif (this.isClearPreset(preset)) {\n\t\t\t\tthis.onDateRangeChange({ from: '', to: '', preset: preset.id })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst win = resolvePresetWindow(preset.id, this.effectivePresets)\n\t\t\tif (!win) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.onDateRangeChange({ ...win, preset: preset.id })\n\t\t},\n\n\t\t/**\n\t\t * Handle a manual datetime-input change inside the in-chip popover.\n\t\t * The `<input type=\"datetime-local\">` emits a local \"YYYY-MM-DDTHH:mm\"\n\t\t * string (or a DOM Event in some NcActionInput versions); we\n\t\t * normalise to an ISO-8601 UTC string for storage and forward\n\t\t * `{ from, to, preset: 'custom' }` to `onDateRangeChange`.\n\t\t *\n\t\t * @param {'from'|'to'} field The half being edited.\n\t\t * @param {Date|string|Event} value Date from the picker, local\n\t\t * datetime string, or a raw input Event.\n\t\t * @return {void}\n\t\t */\n\t\tonChipDateInput(field, value) {\n\t\t\tconst next = {\n\t\t\t\tfrom: this.currentRange?.from || '',\n\t\t\t\tto: this.currentRange?.to || '',\n\t\t\t\tpreset: 'custom',\n\t\t\t}\n\t\t\t// NcActionInput's date types are backed by a date picker that\n\t\t\t// emits a Date — NOT a string and NOT an input Event. Handle the\n\t\t\t// Date first; without it every manual edit fell through to '' and\n\t\t\t// silently CLEARED the half being edited.\n\t\t\tif (value instanceof Date) {\n\t\t\t\tnext[field] = Number.isNaN(value.getTime()) ? '' : value.toISOString()\n\t\t\t} else {\n\t\t\t\tconst raw = typeof value === 'string'\n\t\t\t\t\t? value\n\t\t\t\t\t: (value && value.target ? value.target.value : '')\n\t\t\t\tnext[field] = raw ? this.localDateTimeInputToIso(raw) : ''\n\t\t\t}\n\t\t\tthis.onDateRangeChange(next)\n\t\t},\n\n\t\t/**\n\t\t * Coerce a stored ISO-8601 string into the `Date` that\n\t\t * `NcActionInput`'s date types require — they are backed by a date\n\t\t * picker whose model is typed `Date` and which renders EMPTY for a\n\t\t * string. Returns null for missing / unparseable input.\n\t\t *\n\t\t * @param {string} iso ISO-8601 timestamp.\n\t\t * @return {Date|null} Date for the picker model, or null.\n\t\t */\n\t\ttoPickerDate(iso) {\n\t\t\tif (!iso) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst d = new Date(iso)\n\t\t\treturn Number.isNaN(d.getTime()) ? null : d\n\t\t},\n\n\t\t/**\n\t\t * Parse a local \"YYYY-MM-DDTHH:mm\" datetime-local value into an\n\t\t * ISO-8601 UTC string. `new Date(local)` interprets the bare\n\t\t * string in the runtime's local timezone, matching what the\n\t\t * native input shows the user.\n\t\t *\n\t\t * @param {string} local Local datetime-local input value.\n\t\t * @return {string} ISO-8601 UTC string, or empty when unparseable.\n\t\t */\n\t\tlocalDateTimeInputToIso(local) {\n\t\t\tconst d = new Date(local)\n\t\t\treturn Number.isNaN(d.getTime()) ? '' : d.toISOString()\n\t\t},\n\n\t\t/**\n\t\t * Push pageKind = 'dashboard' into the reactive cnAiContext.\n\t\t * registerSlug/schemaSlug are populated when the dashboard page\n\t\t * receives those props (some dashboards are schema-specific).\n\t\t */\n\t\tpushAiContext() {\n\t\t\tif (!this.cnAiContext) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.cnAiContext.pageKind = 'dashboard'\n\t\t\t// Dashboard pages don't universally carry register/schema props —\n\t\t\t// leave them undefined (they'll be whatever the previous page set,\n\t\t\t// but we reset to undefined here for a clean context).\n\t\t\tthis.cnAiContext.registerSlug = undefined\n\t\t\tthis.cnAiContext.schemaSlug = undefined\n\t\t\tthis.cnAiContext.objectUuid = undefined\n\t\t},\n\n\t\t/**\n\t\t * Resolve the initial date-range value when the feature is on.\n\t\t * Priority: explicit `dateRange.default` → persisted\n\t\t * `localStorage` entry (when `persistKey`) → `last-7` preset.\n\t\t * No-ops when the feature is disabled. Emits\n\t\t * `date-range-change` if a non-null value was resolved so\n\t\t * consumers can wire their initial fetch to the same event.\n\t\t */\n\t\tinitDateRange() {\n\t\t\tif (!this.dateRangeEnabled) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlet initial = null\n\t\t\t// 1. Persisted state (when a key is set).\n\t\t\tif (this.dateRange?.persistKey) {\n\t\t\t\tinitial = this.readPersisted(this.dateRange.persistKey)\n\t\t\t}\n\t\t\t// 2. Explicit consumer-supplied default. A default may be given\n\t\t\t// as an explicit { from, to } window OR as just a preset id\n\t\t\t// (e.g. `default: { preset: 'last-7' }`) — in the latter case\n\t\t\t// we resolve the window from the preset so the manifest can\n\t\t\t// declare a starting range by name without hard-coding dates.\n\t\t\tif (!initial && this.dateRange?.default) {\n\t\t\t\tconst def = this.dateRange.default\n\t\t\t\tif ((!def.from || !def.to) && def.preset && def.preset !== 'custom') {\n\t\t\t\t\tconst win = resolvePresetWindow(def.preset, this.effectivePresets)\n\t\t\t\t\tif (win) {\n\t\t\t\t\t\tinitial = { from: win.from, to: win.to, preset: def.preset }\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!initial) {\n\t\t\t\t\tinitial = {\n\t\t\t\t\t\tfrom: def.from || null,\n\t\t\t\t\t\tto: def.to || null,\n\t\t\t\t\t\tpreset: def.preset || 'custom',\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// 3. Last-7 fallback.\n\t\t\tif (!initial) {\n\t\t\t\tconst win = resolvePresetWindow('last-7', this.effectivePresets)\n\t\t\t\tif (win) {\n\t\t\t\t\tinitial = { from: win.from, to: win.to, preset: 'last-7' }\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (initial) {\n\t\t\t\tthis.currentRange = initial\n\t\t\t\tthis.dashboardDateRange = initial\n\t\t\t\tthis.syncRangeToWorkspace(initial)\n\t\t\t\t/**\n\t\t\t\t * @event date-range-change Fired whenever the dashboard's effective date range changes (initial resolve, picker change, or persisted-range restore). Payload: `{ from, to, preset }`.\n\t\t\t\t */\n\t\t\t\tthis.$emit('date-range-change', { ...initial })\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Handle a picker change. Persists (when `persistKey` is\n\t\t * set), updates the provided ref, emits `date-range-change`.\n\t\t *\n\t\t * @param {{ from: string, to: string, preset: string }} value\n\t\t * The new range, emitted by `CnDateRangePicker`.\n\t\t */\n\t\tonDateRangeChange(value) {\n\t\t\tthis.currentRange = value\n\t\t\tthis.dashboardDateRange = value\n\t\t\tthis.syncRangeToWorkspace(value)\n\t\t\tif (this.dateRange?.persistKey) {\n\t\t\t\tthis.persistRange(this.dateRange.persistKey, value)\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event date-range-change Fired whenever the dashboard's effective date range changes. Payload: `{ from, to, preset }`.\n\t\t\t */\n\t\t\tthis.$emit('date-range-change', { ...value })\n\t\t},\n\n\t\t/**\n\t\t * Publish the active window into the shared `cnWorkspaceContext` as\n\t\t * `dateFrom` / `dateTo` / `datePreset` so every declarative widget can\n\t\t * read it via the existing `@workspace.dateFrom?` / `@workspace.dateTo?`\n\t\t * filter tokens (e.g. a stat tile that scopes its count to the picked\n\t\t * window). An empty / null half writes `''`, which leaves an optional\n\t\t * token unresolved so `dropOptionalUnresolved` omits it — i.e. an \"All\"\n\t\t * range removes the date filter rather than sending a bound.\n\t\t *\n\t\t * @param {{ from?: string, to?: string, preset?: string }|null} value The range.\n\t\t * @return {void}\n\t\t */\n\t\tsyncRangeToWorkspace(value) {\n\t\t\tconst v = value || {}\n\t\t\tthis.workspaceContext.dateFrom = v.from || ''\n\t\t\tthis.workspaceContext.dateTo = v.to || ''\n\t\t\tthis.workspaceContext.datePreset = v.preset || ''\n\t\t},\n\n\t\t/**\n\t\t * Whether a preset clears the window (an \"All\" / unbounded option) rather\n\t\t * than resolving to a from/to span. True for an explicit `clear: true`,\n\t\t * or any non-`custom` preset that carries no numeric `days` / `hours`\n\t\t * (so a manifest can declare `{ id: 'all', label: 'All', days: null }`\n\t\t * without an extra flag). The `custom` preset is excluded — it opens the\n\t\t * manual from/to popover instead.\n\t\t *\n\t\t * @param {object} preset The preset descriptor.\n\t\t * @return {boolean}\n\t\t */\n\t\tisClearPreset(preset) {\n\t\t\tif (!preset) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif (preset.clear === true) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn preset.id !== 'custom'\n\t\t\t\t&& typeof preset.days !== 'number'\n\t\t\t\t&& typeof preset.hours !== 'number'\n\t\t},\n\n\t\t/**\n\t\t * Read a persisted range from `localStorage`. Returns `null`\n\t\t * when the key is missing, the stored value isn't valid JSON,\n\t\t * or the parsed value doesn't have both `from` and `to`\n\t\t * strings. Storage failures (private windows, opaque iframes)\n\t\t * are swallowed.\n\t\t *\n\t\t * @param {string} key The localStorage key.\n\t\t * @return {{ from: string, to: string, preset: string }|null}\n\t\t */\n\t\treadPersisted(key) {\n\t\t\ttry {\n\t\t\t\tif (typeof localStorage === 'undefined') {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\tconst raw = localStorage.getItem(key)\n\t\t\t\tif (!raw) {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\tconst parsed = JSON.parse(raw)\n\t\t\t\tif (!parsed || typeof parsed.from !== 'string' || typeof parsed.to !== 'string') {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tfrom: parsed.from,\n\t\t\t\t\tto: parsed.to,\n\t\t\t\t\tpreset: typeof parsed.preset === 'string' ? parsed.preset : 'custom',\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Persist a range to `localStorage`. Swallows errors (quota\n\t\t * exhaustion, private-window restrictions) — the picker\n\t\t * keeps working in-memory.\n\t\t *\n\t\t * @param {string} key The localStorage key.\n\t\t * @param {object} value The range to persist.\n\t\t */\n\t\tpersistRange(key, value) {\n\t\t\ttry {\n\t\t\t\tif (typeof localStorage === 'undefined') {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlocalStorage.setItem(key, JSON.stringify(value))\n\t\t\t} catch {\n\t\t\t\t// Intentionally swallowed — non-fatal.\n\t\t\t}\n\t\t},\n\n\t\ttoggleEdit() {\n\t\t\tconst leaving = this.isEditing\n\t\t\tthis.isEditing = !this.isEditing\n\n\t\t\t// 🔴 ONE SAVE PER EDIT SESSION, ON THE WAY OUT. Saving on every\n\t\t\t// drag writes a record per pixel gesture and races the next drag;\n\t\t\t// the user's arrangement is finished when they say it is.\n\t\t\tif (leaving) {\n\t\t\t\tthis.saveUserLayout()\n\t\t\t\tthis.saveViewUserLayouts()\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * @event edit-toggle Emitted when the user toggles edit mode. Payload: `true` when entering edit mode, `false` when leaving.\n\t\t\t */\n\t\t\tthis.$emit('edit-toggle', this.isEditing)\n\t\t},\n\n\t\t/**\n\t\t * Read this user's arrangement, when the page keeps one.\n\t\t *\n\t\t * A page without `userLayout` makes NO request at all, which is the\n\t\t * opt-out the requirement asks for: not a request that answers\n\t\t * nothing, an absence of one.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadUserLayout() {\n\t\t\tif (!this.userLayout || !this.appId) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst record = await this.userLayoutApi().load(this.appId, this.resolvedPageId)\n\t\t\t\tthis.userLayoutItems = mergeUserLayout(this.layout, record)\n\t\t\t} catch {\n\t\t\t\t// The manifest layout is the documented fallback, so a store\n\t\t\t\t// that cannot answer leaves the page exactly as the admin\n\t\t\t\t// shipped it rather than empty.\n\t\t\t\tthis.userLayoutItems = null\n\t\t\t} finally {\n\t\t\t\tthis.userLayoutLoaded = true\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Store this user's arrangement, if they changed one.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync saveUserLayout() {\n\t\t\tif (!this.userLayout || !this.appId || !this.userLayoutDirty) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tthis.userLayoutDirty = false\n\t\t\ttry {\n\t\t\t\tawait this.userLayoutApi().save(\n\t\t\t\t\tthis.appId,\n\t\t\t\t\tthis.resolvedPageId,\n\t\t\t\t\tthis.userLayoutItems || [],\n\t\t\t\t)\n\t\t\t} catch {\n\t\t\t\t// Nothing is said. The arrangement stands for this session and\n\t\t\t\t// a toast on a failed layout write would be noise on an\n\t\t\t\t// instance that simply has no preference route.\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The edit-mode reset: the page's own grid and the chosen view return\n\t\t * to the manifest layout. Other views keep this user's arrangement.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/page-view-user-layouts/specs/view-switch-containers/spec.md#requirement-resetting-a-view-restores-its-manifest-layout\n\t\t */\n\t\tasync resetLayout() {\n\t\t\tawait Promise.all([this.resetUserLayout(), this.resetViewUserLayout()])\n\t\t},\n\n\t\t/**\n\t\t * Drop this user's arrangement and return to the manifest.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync resetUserLayout() {\n\t\t\tif (!this.userLayout || !this.appId) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tawait this.userLayoutApi().reset(this.appId, this.resolvedPageId)\n\t\t\t} catch {\n\t\t\t\t// Same posture as the save: the grid below returns to the\n\t\t\t\t// manifest either way, which is what the user asked for.\n\t\t\t}\n\n\t\t\tthis.userLayoutDirty = false\n\t\t\tthis.userLayoutItems = mergeUserLayout(this.layout, null)\n\t\t\t/**\n\t\t\t * @event user-layout-reset Emitted when the user drops their own arrangement and the page returns to the manifest layout.\n\t\t\t */\n\t\t\tthis.$emit('user-layout-reset')\n\t\t},\n\n\t\t/**\n\t\t * The geometry fields of one grid update, and nothing else.\n\t\t *\n\t\t * The grid emits a freshly-mapped item; copying it whole would carry\n\t\t * whatever else the grid put on it over the widget's own definition.\n\t\t *\n\t\t * @param {object} update One item from the grid's layout change.\n\t\t * @return {object} Its geometry.\n\t\t */\n\t\tgeometryFrom(update) {\n\t\t\tconst geometry = {}\n\t\t\tfor (const field of ['gridX', 'gridY', 'gridWidth', 'gridHeight']) {\n\t\t\t\tif (update?.[field] !== undefined) {\n\t\t\t\t\tgeometry[field] = update[field]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn geometry\n\t\t},\n\n\t\t/**\n\t\t * The three calls a user layout needs, from the injected store or the\n\t\t * default one.\n\t\t *\n\t\t * @return {{ load: (appId: string, pageId: string) => Promise<object|null>, save: (appId: string, pageId: string, layout: Array<object>) => Promise<boolean>, reset: (appId: string, pageId: string) => Promise<boolean> }} The api.\n\t\t */\n\t\tuserLayoutApi() {\n\t\t\treturn resolveUserLayoutApi(this.userLayoutStore)\n\t\t},\n\n\t\tonLayoutChange(updated) {\n\t\t\t// A USER ARRANGEMENT NEVER TOUCHES THE MANIFEST. The in-place\n\t\t\t// write below is for the admin editor, which edits the page for\n\t\t\t// everybody; doing it for a user rearranging their own dashboard\n\t\t\t// would rewrite the page for everyone who opens it after them.\n\t\t\t// While Buildiq edits, the drag is the admin's and goes below.\n\t\t\tif (this.showsUserLayout) {\n\t\t\t\tthis.userLayoutDirty = true\n\t\t\t\tthis.userLayoutItems = this.userLayoutItems.map((item) => {\n\t\t\t\t\tconst u = (Array.isArray(updated) ? updated : []).find((candidate) => String(candidate.id) === String(item.id)\n\t\t\t\t\t\t|| candidate.widgetId === item.widgetId)\n\n\t\t\t\t\treturn (u ? { ...item, ...this.geometryFrom(u) } : item)\n\t\t\t\t})\n\t\t\t\tthis.$emit('layout-change', this.userLayoutItems)\n\t\t\t\t// Outside an in-page edit session no Done will come to save\n\t\t\t\t// the arrangement, so it is saved now.\n\t\t\t\tif (!this.isEditing) {\n\t\t\t\t\tthis.saveUserLayout()\n\t\t\t\t}\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Write the new geometry back into the layout items IN PLACE so the\n\t\t\t// in-place manifest editor's diff (ADR-041) captures drag/resize —\n\t\t\t// CnDashboardGrid emits a freshly-mapped array, which on its own\n\t\t\t// never reaches the diffed manifest, so a resize would survive the\n\t\t\t// session (GridStack DOM) but vanish on reload.\n\t\t\tif (Array.isArray(updated) && Array.isArray(this.layout)) {\n\t\t\t\tfor (const u of updated) {\n\t\t\t\t\tconst item = this.layout.find((l) => String(l.id) === String(u.id))\n\t\t\t\t\t\t|| this.layout.find((l) => l.widgetId === u.widgetId)\n\t\t\t\t\tif (!item) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif (u.gridX !== undefined) {\n\t\t\t\t\t\titem.gridX = u.gridX\n\t\t\t\t\t}\n\t\t\t\t\tif (u.gridY !== undefined) {\n\t\t\t\t\t\titem.gridY = u.gridY\n\t\t\t\t\t}\n\t\t\t\t\tif (u.gridWidth !== undefined) {\n\t\t\t\t\t\titem.gridWidth = u.gridWidth\n\t\t\t\t\t}\n\t\t\t\t\tif (u.gridHeight !== undefined) {\n\t\t\t\t\t\titem.gridHeight = u.gridHeight\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event layout-change Emitted when the user finishes dragging/resizing a widget. Payload: the updated layout array `[{ widgetId, x, y, w, h }, ...]`.\n\t\t\t */\n\t\t\tthis.$emit('layout-change', this.layout)\n\t\t},\n\n\t\t/**\n\t\t * Whether a widget def is a banner (alias-canonicalised by type\n\t\t * name, so a consumer-registry override of `banner` keeps the same\n\t\t * declarative semantics its config promises).\n\t\t *\n\t\t * @param {object} def Widget definition.\n\t\t * @return {boolean}\n\t\t */\n\t\tisBannerDef(def) {\n\t\t\treturn !!def && !!def.type\n\t\t\t\t&& (def.type === 'banner' || canonicalWidgetType(def.type) === 'banner')\n\t\t},\n\n\t\t/**\n\t\t * The cell-visibility inputs of a widget def. `visibleWhen` may sit\n\t\t * at the def's TOP LEVEL (any widget type — the declarative way to\n\t\t * gate a whole card, e.g. an object-table that should only exist\n\t\t * while its queue is non-empty), in the `content` blob (the shape\n\t\t * the registry branch forwards to CnBannerWidget), or in the legacy\n\t\t * manifest `props` blob (the fallback getStatsBlockProps and\n\t\t * getChartProps already honour for their own widget types). `text`\n\t\t * is only meaningful for banners: it is what the banner would show,\n\t\t * which for an attention card is its `title` when it has no `text`.\n\t\t *\n\t\t * @param {object} def Widget definition.\n\t\t * `layout` is returned so the page can tell an attention card from a\n\t\t * plain banner: only the former keeps its cell when its check fails.\n\t\t *\n\t\t * @spec openspec/changes/link-cards-page/specs/link-cards-page/spec.md#requirement-an-attention-card-with-a-title-keeps-its-cell\n\t\t * @spec openspec/changes/live-check-follow-ups/specs/live-check-follow-ups/spec.md#requirement-an-attention-card-says-when-it-could-not-check\n\t\t * @return {{ text: string, visibleWhen: (object|null), layout: string }}\n\t\t */\n\t\twidgetDisplayConfig(def) {\n\t\t\tconst content = (def && typeof def.content === 'object' && def.content) || {}\n\t\t\tconst props = (def && typeof def.props === 'object' && def.props) || {}\n\t\t\t// An attention card (`layout: \"attention\"`) is headed by `title`,\n\t\t\t// and its title only FALLS BACK to `text`. Reading `text` alone\n\t\t\t// called a card with a title and a reason empty, and gave its cell\n\t\t\t// up before its `visibleWhen` was even looked at.\n\t\t\tconst layout = content.layout || props.layout || ''\n\t\t\tconst title = layout === 'attention' ? (content.title || props.title || '') : ''\n\t\t\treturn {\n\t\t\t\t// A banner with only a bold `lead` has words to show too.\n\t\t\t\ttext: content.text || props.text || content.lead || props.lead || title || '',\n\t\t\t\tvisibleWhen: (def && def.visibleWhen) || content.visibleWhen || props.visibleWhen || null,\n\t\t\t\tlayout,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether a layout item would render nothing right now — a widget\n\t\t * whose `visibleWhen` has not evaluated true, or a banner with no\n\t\t * text at all — and must therefore surrender its grid cell in live\n\t\t * mode instead of leaving an empty card behind.\n\t\t *\n\t\t * One exception: an attention card whose `visibleWhen` request FAILED\n\t\t * keeps its cell, so the card can say it could not check. A collapsed\n\t\t * cell reads as \"nothing needs attention\", which a failed count does\n\t\t * not know. A count that was read and does not meet the condition\n\t\t * still collapses.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {boolean} true when the cell must collapse.\n\t\t * @spec openspec/changes/live-check-follow-ups/specs/live-check-follow-ups/spec.md#requirement-an-attention-card-says-when-it-could-not-check\n\t\t */\n\t\tisCollapsedWidget(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (!def || !def.type) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst { text, visibleWhen, layout } = this.widgetDisplayConfig(def)\n\t\t\tif (this.isBannerDef(def) && text === '') {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (!visibleWhen) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\t// A workspace condition (a page control's choice) is answered at\n\t\t\t// once from the reactive bag; nothing is fetched for it.\n\t\t\tif (isWorkspaceCondition(visibleWhen)) {\n\t\t\t\treturn !evaluateWorkspaceCondition(visibleWhen, this.workspaceContext)\n\t\t\t}\n\t\t\tconst outcome = this.widgetConditionOutcome[item.widgetId]\n\t\t\tif (outcome && outcome.failed === true && layout === 'attention' && this.isBannerDef(def)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn !outcome || outcome.met !== true\n\t\t},\n\n\t\t/**\n\t\t * Whether a page control (a workspace condition on `visibleWhen`)\n\t\t * hides this widget right now. Other conditions are not looked at.\n\t\t *\n\t\t * @param {string} widgetId The widget id.\n\t\t * @return {boolean} True when the widget must not draw.\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-widget-can-be-shown-by-a-workspace-value\n\t\t */\n\t\tisHiddenByWorkspace(widgetId) {\n\t\t\tconst def = this.getWidgetDef(widgetId)\n\t\t\tif (!def || !def.type) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst { visibleWhen } = this.widgetDisplayConfig(def)\n\t\t\treturn isWorkspaceCondition(visibleWhen) && !evaluateWorkspaceCondition(visibleWhen, this.workspaceContext)\n\t\t},\n\n\t\t/**\n\t\t * Evaluate every conditional widget's `visibleWhen` into\n\t\t * `widgetConditionOutcome` — the verdict AND the raw field value,\n\t\t * read through the same shared util primitives CnBannerWidget uses.\n\t\t * Runs on created() and again whenever `widgets` changes (the\n\t\t * in-app editor mutates defs in place). Fail-safe like the banner\n\t\t * itself: any fetch/shape error counts as \"not met\", so a broken\n\t\t * predicate collapses the cell rather than breaking the page. The\n\t\t * outcome of a failed read carries `failed: true` and the `reason`,\n\t\t * which `isCollapsedWidget` and CnBannerWidget use to show an\n\t\t * attention card's \"Could not check\" line instead of nothing.\n\t\t *\n\t\t * Flips `widgetConditionsSettled` when the initial round is done —\n\t\t * synchronously when there is nothing to evaluate, so a dashboard\n\t\t * without conditional widgets never waits.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/live-check-follow-ups/specs/live-check-follow-ups/spec.md#requirement-an-attention-card-says-when-it-could-not-check\n\t\t */\n\t\tasync evaluateWidgetConditions() {\n\t\t\tconst defs = [...(this.widgets || []), ...this.normalizedViews.flatMap((view) => view.widgets)]\n\t\t\tconst conditional = defs.filter((def) => def && def.id && def.type\n\t\t\t\t&& this.widgetDisplayConfig(def).visibleWhen\n\t\t\t\t&& !isWorkspaceCondition(this.widgetDisplayConfig(def).visibleWhen))\n\t\t\t// Skip when the CONDITIONAL SET is unchanged: the deep `widgets`\n\t\t\t// watch fires on any def edit, but only an added/removed/edited\n\t\t\t// predicate warrants refetching every conditional endpoint.\n\t\t\tconst signature = JSON.stringify(conditional\n\t\t\t\t.map((def) => [def.id, this.widgetDisplayConfig(def).visibleWhen])\n\t\t\t\t.sort((a, b) => String(a[0]).localeCompare(String(b[0]))))\n\t\t\tif (signature === this.widgetEvalSignature && this.widgetConditionsSettled) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.widgetEvalSignature = signature\n\t\t\tconst seq = ++this.widgetEvalSeq\n\t\t\tif (conditional.length === 0) {\n\t\t\t\tthis.widgetConditionsSettled = true\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait Promise.all(conditional.map(async (def) => {\n\t\t\t\tconst cond = this.widgetDisplayConfig(def).visibleWhen\n\t\t\t\tlet outcome\n\t\t\t\ttry {\n\t\t\t\t\t// `sink` keeps the first row of a source query, for a banner that names it.\n\t\t\t\t\tconst sink = {}\n\t\t\t\t\tconst value = await readVisibleWhenValue(cond, undefined, sink)\n\t\t\t\t\toutcome = { met: compareVisibleWhen(value, cond.op || 'eq', cond.value), value }\n\t\t\t\t\tif (sink.row) {\n\t\t\t\t\t\toutcome.row = sink.row\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Fail-safe: not met. But the failure is kept, and said\n\t\t\t\t\t// out loud: a failed count and \"nothing to report\" look\n\t\t\t\t\t// the same on screen.\n\t\t\t\t\toutcome = { met: false, value: null, failed: true, reason: typeof error?.message === 'string' ? error.message : String(error ?? '') }\n\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\tconsole.warn(`[CnDashboardPage] visibleWhen of widget \"${def.id}\" could not be evaluated:`, error?.message || error)\n\t\t\t\t}\n\t\t\t\t// A newer run owns the map now — a stale verdict (possibly for\n\t\t\t\t// a def that no longer exists) must not overwrite its writes.\n\t\t\t\tif (seq === this.widgetEvalSeq) {\n\t\t\t\t\tthis.widgetConditionOutcome[def.id] = outcome\n\t\t\t\t}\n\t\t\t}))\n\t\t\tif (seq !== this.widgetEvalSeq) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Prune outcomes for defs that left the conditional set — pruned\n\t\t\t// AFTER the run (not before) so a still-visible widget never\n\t\t\t// flashes collapsed while its re-evaluation is in flight.\n\t\t\tconst live = new Set(conditional.map((def) => def.id))\n\t\t\tfor (const id of Object.keys(this.widgetConditionOutcome)) {\n\t\t\t\tif (!live.has(id)) {\n\t\t\t\t\tdelete this.widgetConditionOutcome[id]\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.widgetConditionsSettled = true\n\t\t},\n\n\t\t/**\n\t\t * The v-bind payload for a registry-rendered widget. Banners get the\n\t\t * page's evaluated `conditionOutcome` merged in, so CnBannerWidget\n\t\t * renders from the verdict this page already fetched — no second\n\t\t * request, no invisible-until-self-evaluated flash inside the cell —\n\t\t * and can interpolate the predicate's field value into its text\n\t\t * (`{value}`). Every other widget type receives its stored content\n\t\t * unchanged: their cell-level `visibleWhen` is consumed entirely by\n\t\t * this page, never forwarded as a component prop.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {object}\n\t\t */\n\t\tregistryWidgetBindings(item) {\n\t\t\tconst content = filledContent(this.collectionContent(this.getWidgetContent(item)), this.appConfigRef || {})\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (!this.isBannerDef(def)) {\n\t\t\t\treturn content\n\t\t\t}\n\t\t\tconst outcome = this.widgetConditionOutcome[item.widgetId]\n\t\t\treturn outcome ? { ...content, conditionOutcome: outcome } : content\n\t\t},\n\n\t\t/**\n\t\t * The content keys a registry widget receives as props: only the ones\n\t\t * its renderer declares. An undeclared key would otherwise fall through\n\t\t * as an attribute onto the renderer's root component and could override\n\t\t * a value the widget computes for it. The whole content still arrives\n\t\t * as `content`. A renderer that forwards its own attributes\n\t\t * (`inheritAttrs: false`) keeps receiving every key.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {object} The bindings the renderer declares.\n\t\t * @spec openspec/changes/dashboard-declared-widget-props/specs/dashboard-page/spec.md#requirement-a-dashboard-widget-receives-only-the-content-keys-it-declares\n\t\t */\n\t\tregistryWidgetProps(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn pickDeclaredProps(this.registryRenderer(item), this.registryWidgetBindings(item), def?.type || item.widgetId)\n\t\t},\n\n\t\t/**\n\t\t * What a container widget (registry `container`, such as `tabs`) needs\n\t\t * beside its content: the page's widget definitions, so its tabs find\n\t\t * the widgets they name, and the consumer registry for custom child\n\t\t * types. Empty for every other widget, so a leaf gets no extra\n\t\t * attributes on its root.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {object} The extra bindings.\n\t\t * @spec openspec/changes/dashboard-tabs-children/specs/dashboard-page/spec.md#requirement-a-tabs-widget-on-a-dashboard-renders-the-widgets-its-tabs-name\n\t\t */\n\t\tcontainerBindings(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (!def || !def.type) {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\tconst entry = getWidgetTypeEntry(def.type) || getWidgetTypeEntry(canonicalWidgetType(def.type))\n\t\t\tif (!entry || entry.container !== true) {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\tconst own = Array.isArray(this.widgets) ? this.widgets.filter(Boolean) : []\n\t\t\tconst fromView = this.activeView && Array.isArray(this.activeView.widgets) ? this.activeView.widgets.filter(Boolean) : []\n\t\t\treturn {\n\t\t\t\tavailableWidgets: [...own, ...fromView],\n\t\t\t\tcnRegistry: this.cnRegistry || {},\n\t\t\t\tsurface: this.surface,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * What a widget that draws its own card needs inside a dashboard cell,\n\t\t * which already draws the titled card: the built-in `card-grid` gets\n\t\t * `chromeless`, so it adds no second frame, title or Actions menu.\n\t\t * Empty for every other widget.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {object} The extra bindings.\n\t\t * @spec openspec/changes/card-grid-dashboard-frame/specs/card-grid-dashboard-frame/spec.md#requirement-a-card-grid-on-a-dashboard-draws-no-frame-of-its-own\n\t\t */\n\t\tcellChromeBindings(item) {\n\t\t\treturn this.registryRenderer(item) === BUILT_IN_WIDGETS['card-grid'] ? { chromeless: true } : {}\n\t\t},\n\n\t\t/**\n\t\t * A widget's content with the board's quiet collection footer: in the\n\t\t * board look a dashboard that drops the widget Actions menu\n\t\t * (`showWidgetActions: false`) also drops the Add footer of its list\n\t\t * widgets, whose Add is the menu's create entry at the bottom of the\n\t\t * card. A widget that says `content.allowCreate` keeps its own value.\n\t\t * Otherwise the content is returned as is.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-legacy-widgets/specs/dashboard-page/spec.md#requirement-a-board-dashboard-without-widget-actions-drops-the-add-footer\n\t\t * @param {object} content The widget's stored content.\n\t\t * @return {object}\n\t\t */\n\t\tcollectionContent(content) {\n\t\t\tif (!this.isBoardLook || this.showWidgetActions !== false) {\n\t\t\t\treturn content\n\t\t\t}\n\t\t\tif (content && Object.hasOwn(content, 'allowCreate')) {\n\t\t\t\treturn content\n\t\t\t}\n\t\t\treturn { ...content, allowCreate: false }\n\t\t},\n\n\t\t/**\n\t\t * Re-compact a filtered layout upward, display-only. GridStack runs\n\t\t * `float: true`, so removing an item does not close its row — this\n\t\t * skyline pass does, preserving the authored order (gridY, then\n\t\t * gridX) and every item's own column, width and height. Items are\n\t\t * shallow-copied only when their gridY actually moves.\n\t\t *\n\t\t * @param {Array<object>} items Layout items to compact.\n\t\t * @return {Array<object>} New array with recomputed gridY values.\n\t\t */\n\t\tcompactDisplayLayout(items) {\n\t\t\tconst heights = new Array(Math.max(1, this.columns)).fill(0)\n\t\t\treturn [...items]\n\t\t\t\t.sort((a, b) => ((a.gridY ?? 0) - (b.gridY ?? 0)) || ((a.gridX ?? 0) - (b.gridX ?? 0)))\n\t\t\t\t.map((item) => {\n\t\t\t\t\tconst x = Math.min(Math.max(0, item.gridX ?? 0), heights.length - 1)\n\t\t\t\t\tconst w = Math.max(1, item.gridWidth ?? 1)\n\t\t\t\t\tconst h = Math.max(1, item.gridHeight ?? 1)\n\t\t\t\t\tconst to = Math.min(x + w, heights.length)\n\t\t\t\t\t// An item authored wider than the grid is clamped in the\n\t\t\t\t\t// RETURNED geometry too, not just in the skyline pass —\n\t\t\t\t\t// otherwise GridStack re-places a widget the pack thought\n\t\t\t\t\t// was narrower and the two can disagree on gridY.\n\t\t\t\t\tconst effectiveWidth = to - x\n\t\t\t\t\tlet y = 0\n\t\t\t\t\tfor (let c = x; c < to; c++) {\n\t\t\t\t\t\ty = Math.max(y, heights[c])\n\t\t\t\t\t}\n\t\t\t\t\tfor (let c = x; c < to; c++) {\n\t\t\t\t\t\theights[c] = y + h\n\t\t\t\t\t}\n\t\t\t\t\tif (y === (item.gridY ?? 0) && effectiveWidth === w) {\n\t\t\t\t\t\treturn item\n\t\t\t\t\t}\n\t\t\t\t\tconst out = { ...item, gridY: y }\n\t\t\t\t\tif (effectiveWidth !== w) {\n\t\t\t\t\t\tout.gridWidth = effectiveWidth\n\t\t\t\t\t}\n\t\t\t\t\treturn out\n\t\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Resolve a layout item's widget definition from `widgets[]`.\n\t\t *\n\t\t * Deliberately a METHOD, not a cached computed `widgetMap`. The\n\t\t * `widgets` prop array is mutated IN PLACE by the in-app editor\n\t\t * (CnBuildiqEditButton's \"Add widget…\" pushes onto\n\t\t * `page.config.widgets`), and a computed over a prop array does not\n\t\t * subscribe to that array's observer — so the map never invalidated\n\t\t * and every freshly added widget rendered the `unavailableLabel`\n\t\t * placeholder (with its raw id as the title) until a full reload.\n\t\t * A method re-runs on every render, so the lookup cannot go stale.\n\t\t *\n\t\t * @param {string} widgetId The layout item's `widgetId`.\n\t\t * @return {object|null} The matching widget definition, or null.\n\t\t */\n\t\tgetWidgetDef(widgetId) {\n\t\t\tconst list = Array.isArray(this.widgets) ? this.widgets : []\n\t\t\treturn list.find((w) => w && w.id === widgetId) || this.findViewWidget(widgetId)\n\t\t},\n\n\t\t/**\n\t\t * The app id(s) a widget depends on, declared via `requiresApp`\n\t\t * (a single id string or an array of ids). Empty array when the\n\t\t * widget has no cross-app dependency.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {string[]} Required app ids (possibly empty).\n\t\t */\n\t\trequiredAppsFor(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tconst req = def && def.requiresApp\n\t\t\tif (!req) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn Array.isArray(req) ? req.filter(Boolean) : [req]\n\t\t},\n\n\t\t/**\n\t\t * Whether a given app counts as available. Prefers the injected\n\t\t * `appStatuses` map (an app is available when `enabled`, or when\n\t\t * only `installed` is known); falls back to the `isAppInstalled()`\n\t\t * runtime check when no status was injected for that app.\n\t\t *\n\t\t * @param {string} appId Nextcloud app id.\n\t\t * @return {boolean} True when the app is present/usable.\n\t\t */\n\t\tisAppAvailable(appId) {\n\t\t\tconst status = this.appStatuses && this.appStatuses[appId]\n\t\t\tif (status) {\n\t\t\t\tif (typeof status.enabled === 'boolean') {\n\t\t\t\t\treturn status.enabled\n\t\t\t\t}\n\t\t\t\tif (typeof status.installed === 'boolean') {\n\t\t\t\t\treturn status.installed\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn isAppInstalled(appId)\n\t\t},\n\n\t\t/**\n\t\t * The first required app that is missing for a widget, or null when\n\t\t * all its `requiresApp` dependencies are available. Drives the\n\t\t * install-CTA gate that replaces the widget body for any widget\n\t\t * type (stat, chart, object-list, …) surfacing another app's data.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {(string|null)} Missing app id, or null.\n\t\t */\n\t\tmissingRequiredApp(item) {\n\t\t\tfor (const appId of this.requiredAppsFor(item)) {\n\t\t\t\tif (!this.isAppAvailable(appId)) {\n\t\t\t\t\treturn appId\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * App-store deep link used by the install CTA. Prefers the\n\t\t * injected per-app `category` (when present) so the user lands on\n\t\t * the right App Store section; otherwise links to the app's own\n\t\t * App Store entry.\n\t\t *\n\t\t * @param {string} appId Nextcloud app id.\n\t\t * @return {string} Settings/apps URL.\n\t\t */\n\t\tappInstallUrl(appId) {\n\t\t\tconst category = this.appStatuses && this.appStatuses[appId] && this.appStatuses[appId].category\n\t\t\treturn category\n\t\t\t\t? `/index.php/settings/apps/${encodeURIComponent(category)}/${encodeURIComponent(appId)}`\n\t\t\t\t: `/index.php/settings/apps/${encodeURIComponent(appId)}`\n\t\t},\n\n\t\t/**\n\t\t * Human-readable \"Install {app}\" heading for the gate CTA.\n\t\t *\n\t\t * @param {string} appId Nextcloud app id.\n\t\t * @return {string} Localized install label.\n\t\t */\n\t\tinstallAppLabel(appId) {\n\t\t\treturn t('nextcloud-vue', 'Install {app}', { app: appId })\n\t\t},\n\n\t\t/**\n\t\t * The dashboardWidgetRegistry renderer for a layout item, when its widget\n\t\t * definition's `type` is a registered catalog widget and no consumer\n\t\t * `#widget-{id}` slot handles it. This is how widgets added via the\n\t\t * in-app \"Add widget…\" flow (ADR-041) render on a dashboard.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {(object|null)} The widget renderer component, or null.\n\t\t */\n\t\tregistryRenderer(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (!def || !def.type) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\t// `integration` is NOT ours to resolve — it has its own branch\n\t\t\t// (isIntegrationWidget -> resolveRegistryWidget(integrationId)),\n\t\t\t// and one without an `integrationId` must fall through to\n\t\t\t// `unavailableLabel`. Claiming it here for BUILT_IN_WIDGETS\n\t\t\t// .integration would render a widget where the page means to say\n\t\t\t// \"unavailable\". CnDetailPage excludes the same type for the same\n\t\t\t// reason.\n\t\t\tif (def.type === 'integration') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\t// Same three-layer order as CnWidgetGrid and CnDetailPage:\n\t\t\t// consumer registry -> dashboard catalog -> BUILT_IN_WIDGETS.\n\t\t\t//\n\t\t\t// This method used to read the catalog ALONE, which made a\n\t\t\t// dashboard the odd surface out in two ways, both silent:\n\t\t\t//\n\t\t\t// - a consumer override was IGNORED whenever the catalog carried\n\t\t\t// the same name. `chart` and `stat` are in both, so an app that\n\t\t\t// registers its own (hrmq registers a TrendChartWidget under\n\t\t\t// `chart`) got the library's component instead — the widget\n\t\t\t// still rendered, just the wrong one, which is worse than a\n\t\t\t// blank. REQ-MVR-005 mandates custom-over-built-in.\n\t\t\t// - a BUILT_IN-only type — `integration`, `metadata` — resolved\n\t\t\t// to nothing and the widget did not appear at all.\n\t\t\t//\n\t\t\t// #709 unified CnWidgetGrid and CnDetailPage but missed this one.\n\t\t\tconst consumer = (this.cnRegistry || {})[def.type]\n\t\t\tif (consumer) {\n\t\t\t\treturn consumer.component ?? consumer\n\t\t\t}\n\t\t\t// THE TYPE AS WRITTEN WINS; the alias is only a fallback.\n\t\t\t//\n\t\t\t// `object-table` and `table` are two DIFFERENT registered widgets\n\t\t\t// (CnHostedObjectTable vs CnObjectListWidget2), and\n\t\t\t// WIDGET_TYPE_ALIASES nonetheless maps the first onto the second.\n\t\t\t// Canonicalising before the lookup therefore resolved an\n\t\t\t// `object-table` dashboard widget to the `table` renderer: a widget\n\t\t\t// still appeared, nothing threw, it was simply the wrong component\n\t\t\t// and the stored `content` blob never reached the props the host\n\t\t\t// adapter maps it onto. That is the failure this method's own\n\t\t\t// comment above calls \"worse than a blank\".\n\t\t\t//\n\t\t\t// Caught by larpingapp e2e on the 2.8.2 -> 2.9.2 bump:\n\t\t\t// `.cn-widget-object-table` was not in the DOM at all.\n\t\t\t//\n\t\t\t// Aliases keep working for a spelling that is NOT registered in its\n\t\t\t// own right — `map-viewer` still reaches `map`.\n\t\t\tconst entry = getWidgetTypeEntry(def.type)\n\t\t\t\t|| getWidgetTypeEntry(canonicalWidgetType(def.type))\n\t\t\tif (entry && entry.renderer) {\n\t\t\t\treturn entry.renderer\n\t\t\t}\n\t\t\treturn BUILT_IN_WIDGETS[def.type] || BUILT_IN_WIDGETS[canonicalWidgetType(def.type)] || null\n\t\t},\n\n\t\t/**\n\t\t * Whether a registry widget renders a self-contained \"card\" surface\n\t\t * (a single KPI / gauge / delta tile) that must size to its tile\n\t\t * without an inner scrollbar. Driven by the registry entry's\n\t\t * `card: true` hint (stat / gauge / delta). Card widgets are\n\t\t * rendered `flush` (no wrapper padding) and the wrapper content area\n\t\t * is switched to centred, non-scrolling layout via the\n\t\t * `cn-dashboard-page__card-fit` class — fixing the stray vertical /\n\t\t * horizontal scrollbars on short KPI / gauge tiles.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {boolean} true when the matching registry entry is a card.\n\t\t */\n\t\tisCardWidget(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (!def || !def.type) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\t// Same precedence as registryRenderer: the type as written first, the\n\t\t\t// alias only as a fallback. Canonicalising first read the card flag\n\t\t\t// off a DIFFERENT widget's entry, so the chrome could disagree with\n\t\t\t// the component actually rendered.\n\t\t\tconst entry = getWidgetTypeEntry(def.type)\n\t\t\t\t|| getWidgetTypeEntry(canonicalWidgetType(def.type))\n\t\t\treturn Boolean(entry && entry.card === true)\n\t\t},\n\n\t\t/**\n\t\t * The stored content/config for a catalog widget (passed to its renderer).\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {object}\n\t\t */\n\t\tgetWidgetContent(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn (def && def.content && typeof def.content === 'object') ? def.content : {}\n\t\t},\n\n\t\t/**\n\t\t * Remove a widget from the dashboard while editing (ADR-041): drops it from\n\t\t * `config.widgets` + `config.layout` (the working manifest, by reference)\n\t\t * and emits the updated layout so consumers persist.\n\t\t *\n\t\t * Splices in place rather than emitting fresh arrays. `widgets` / `layout`\n\t\t * ARE the working manifest's arrays — CnBuildiqEditButton.onAddWidgetSubmit\n\t\t * pushes straight into them, and onWidgetConfigSave mutates a def in place —\n\t\t * so mutation is what actually removes the widget from the page. Filtering\n\t\t * into new arrays and emitting them only told listeners about the removal,\n\t\t * and nothing listens (`@widget-remove` has no consumer in the library or in\n\t\t * Buildiq), so Delete was a no-op.\n\t\t *\n\t\t * @spec openspec/changes/dashboard-widget-system/specs/dashboard-page/spec.md\n\t\t * @param {object} item Layout item to remove.\n\t\t */\n\t\tremoveWidget(item) {\n\t\t\tconst id = item.widgetId\n\t\t\tconst layoutIndex = this.layout.findIndex((l) => l.widgetId === id)\n\t\t\t/*\n\t\t\t * `layout` and `widgets` are the working manifest's own arrays, passed by\n\t\t\t * reference on purpose: the edit button pushes into them to add a widget,\n\t\t\t * and onWidgetConfigSave mutates a def in place to save one. Emitting a\n\t\t\t * copy instead leaves the manifest untouched — exactly the bug this\n\t\t\t * replaces — so the mutation is deliberate here.\n\t\t\t */\n\t\t\tif (layoutIndex !== -1) {\n\t\t\t\t// eslint-disable-next-line vue/no-mutating-props\n\t\t\t\tthis.layout.splice(layoutIndex, 1)\n\t\t\t}\n\t\t\tif (Array.isArray(this.widgets)) {\n\t\t\t\tconst widgetIndex = this.widgets.findIndex((w) => w.id === id)\n\t\t\t\tif (widgetIndex !== -1) {\n\t\t\t\t\t// eslint-disable-next-line vue/no-mutating-props\n\t\t\t\t\tthis.widgets.splice(widgetIndex, 1)\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.$emit('layout-change', this.layout)\n\t\t\t/**\n\t\t\t * @event widget-remove Emitted when a widget is removed via the in-place editor.\n\t\t\t * @type {{ id: string, widgets: Array }}\n\t\t\t */\n\t\t\tthis.$emit('widget-remove', id, this.widgets)\n\t\t},\n\n\t\t/**\n\t\t * Open the per-widget style/config editor for a layout item.\n\t\t * Launchpad-style cog: selects the widget and shows the modal.\n\t\t *\n\t\t * @param {object} item Layout item to configure.\n\t\t */\n\t\tconfigureWidget(item) {\n\t\t\tthis.configWidgetId = item.widgetId\n\t\t\tthis.showWidgetConfig = true\n\t\t},\n\n\t\t/**\n\t\t * Persist the editor's changes onto the matching widget definition\n\t\t * IN PLACE (so the in-place manifest editor picks them up) and close\n\t\t * the modal. Mirrors the relevant chrome fields onto the layout\n\t\t * entry's `styleConfig` too, since the grid reads styleConfig from\n\t\t * the layout item.\n\t\t *\n\t\t * @param {object} edited The widget object mutated by the editor.\n\t\t */\n\t\tonWidgetConfigSave(edited) {\n\t\t\tconst def = Array.isArray(this.widgets)\n\t\t\t\t? this.widgets.find((w) => w.id === this.configWidgetId)\n\t\t\t\t: null\n\t\t\tif (def) {\n\t\t\t\tdef.title = edited.title !== undefined ? edited.title : def.title\n\t\t\t\tdef.styleConfig = edited.styleConfig || {}\n\t\t\t\tdef.showTitle = edited.showTitle !== false\n\t\t\t\tdef.customTitle = edited.customTitle || null\n\t\t\t\tdef.customIcon = edited.customIcon || null\n\t\t\t\tif (edited.content !== undefined) {\n\t\t\t\t\tdef.content = edited.content\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst layoutItem = this.layout.find((l) => l.widgetId === this.configWidgetId)\n\t\t\tif (layoutItem) {\n\t\t\t\tlayoutItem.styleConfig = edited.styleConfig || {}\n\t\t\t}\n\t\t\tthis.showWidgetConfig = false\n\t\t\tthis.$emit('layout-change', this.layout)\n\t\t},\n\n\t\t/**\n\t\t * Delete from inside the editor — drop the widget and close.\n\t\t *\n\t\t * @param {object} _w The widget the editor wants deleted (unused; we\n\t\t * route by `configWidgetId`).\n\t\t */\n\t\tonWidgetConfigDelete(_w) {\n\t\t\tthis.removeWidget({ widgetId: this.configWidgetId })\n\t\t\tthis.showWidgetConfig = false\n\t\t},\n\n\t\t/**\n\t\t * Whether a segmented group follows the description filter at\n\t\t * `index`: a select is set off from one by a dot (\"alle zaaktypen ·\n\t\t * Maand | Kwartaal | Jaar\"), not from another select or the line's end.\n\t\t *\n\t\t * @param {number} index Index in `descriptionFilters`.\n\t\t * @return {boolean}\n\t\t */\n\t\tsegmentedFollows(index) {\n\t\t\tconst next = this.descriptionFilters[index + 1]\n\t\t\treturn next ? next.control === 'segmented' : this.datePeriodInDescription\n\t\t},\n\n\t\t/**\n\t\t * The line under a widget's title (`subtitle` on the widget\n\t\t * definition), translated; empty when it carries none.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {string}\n\t\t * @spec openspec/changes/page-header-breadcrumb/specs/page-header/spec.md#requirement-a-dashboard-widget-card-can-carry-a-line-under-its-title\n\t\t */\n\t\tgetWidgetSubtitle(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tconst subtitle = def && typeof def.subtitle === 'string' ? def.subtitle : ''\n\t\t\treturn subtitle ? this.effectiveTranslate(subtitle) : ''\n\t\t},\n\n\t\t/**\n\t\t * The widget's title tone (`titleTone` on its definition): `side`\n\t\t * titles the card as a side card in the board look.\n\t\t *\n\t\t * @param {object} item The layout item.\n\t\t * @return {string} `side`, or ''.\n\t\t * @spec openspec/changes/widget-side-title-tone/specs/widget-side-title-tone/spec.md#requirement-a-widget-can-be-titled-as-a-side-card\n\t\t */\n\t\tgetWidgetTitleTone(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def && def.titleTone === 'side' ? 'side' : ''\n\t\t},\n\n\t\t/**\n\t\t * The line above a widget's title (`eyebrow` on the widget\n\t\t * definition: \"Saldo per week\" above \"Prognose 13 weken\"), through the\n\t\t * host translate, or '' for none.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {string}\n\t\t * @spec openspec/changes/widget-title-eyebrow/specs/dashboard-page/spec.md#requirement-a-widget-card-can-carry-a-line-above-its-title\n\t\t */\n\t\tgetWidgetEyebrow(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tconst eyebrow = def && typeof def.eyebrow === 'string' ? def.eyebrow : ''\n\t\t\treturn eyebrow ? this.effectiveTranslate(eyebrow) : ''\n\t\t},\n\n\t\t/**\n\t\t * The widget's title as AUTHORED — the untranslated manifest source\n\t\t * string — resolved by widget id rather than by item, so a descendant\n\t\t * that only knows its own id can ask for it.\n\t\t *\n\t\t * Provided to descendants as `cnWidgetTitleSource` and used to build\n\t\t * the \"Report a bug\" issue title. getWidgetTitle() below is the\n\t\t * display chokepoint and runs the def title through the host translate\n\t\t * function, so the CnActionsMenu inside CnWidgetWrapper only ever saw\n\t\t * the TRANSLATED title: a report filed from a French UI arrived as\n\t\t * \"[BUG] Activité récente\", and one from a Russian UI in Cyrillic,\n\t\t * unreadable to a maintainer even though the English msgid was right\n\t\t * here in the manifest.\n\t\t *\n\t\t * Deliberately DIVERGES from getWidgetTitle's precedence: the two\n\t\t * customTitle values are skipped, not just left untranslated. They\n\t\t * are a person's own words in their own language, so returning them\n\t\t * reopens the exact failure above — and a renamed placement does not\n\t\t * identify the widget COMPONENT the bug is about, while the manifest\n\t\t * title (English, the msgid) does. When the def carries no title this\n\t\t * returns '' and CnActionsMenu falls back to the surface slug, which\n\t\t * is English by construction.\n\t\t *\n\t\t * @param {string} widgetId The widget's id.\n\t\t * @return {string} The manifest title, or '' when the def has none.\n\t\t */\n\t\tgetWidgetTitleSource(widgetId) {\n\t\t\treturn this.getWidgetDef(widgetId)?.title || ''\n\t\t},\n\n\t\tgetWidgetTitle(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\t// Prefer a per-placement override, then the widget def's customTitle\n\t\t\t// (set by the in-place style editor cog), then the def's base title.\n\t\t\t//\n\t\t\t// Only the def's base title goes through the host translate function.\n\t\t\t// It is the manifest-authored source string, exactly like the page\n\t\t\t// title on `resolvedTitle` above. The two customTitle values are NOT\n\t\t\t// translated: a person typed them into the style editor in their own\n\t\t\t// words, so looking them up in a translation table is wrong, and a\n\t\t\t// miss would be indistinguishable from a hit.\n\t\t\t//\n\t\t\t// This is the single display-time chokepoint for every widget type\n\t\t\t// (slot, chart, stats-block, integration, NC-API, registry and the\n\t\t\t// unknown fallback all bind `:title=\"getWidgetTitle(item)\"`), which\n\t\t\t// is why the fix belongs here rather than at each call site.\n\t\t\t// `configWidget()` deliberately stays raw: it pre-fills the config\n\t\t\t// modal, and translating there would persist a translated string\n\t\t\t// back into the widget definition on save.\n\t\t\tconst title = item.customTitle\n\t\t\t\t|| def?.customTitle\n\t\t\t\t|| (def?.title ? this.effectiveTranslate(def.title) : '')\n\t\t\t\t|| item.widgetId\n\t\t\treturn this.titleHoldsCount(item) ? this.fillTitleCount(item, title) : title\n\t\t},\n\n\t\t/**\n\t\t * Whether the widget's title carries `{count}`, the total its widget\n\t\t * reports; such a card shows the total in its title, not as a chip.\n\t\t *\n\t\t * @param {object} item Layout placement entry.\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/widget-title-count/specs/widget-title-count/spec.md#requirement-a-widget-title-can-carry-the-total-its-widget-reports\n\t\t */\n\t\ttitleHoldsCount(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tconst raw = item.customTitle || def?.customTitle || def?.title || ''\n\t\t\treturn typeof raw === 'string' && raw.includes('{count}')\n\t\t},\n\n\t\t/**\n\t\t * The title with `{count}` filled from the reported total, or the token\n\t\t * dropped (with the space before it) while no total has arrived.\n\t\t *\n\t\t * @param {object} item Layout placement entry.\n\t\t * @param {string} title The title, translated.\n\t\t * @return {string}\n\t\t * @spec openspec/changes/widget-title-count/specs/widget-title-count/spec.md#requirement-a-widget-title-can-carry-the-total-its-widget-reports\n\t\t */\n\t\tfillTitleCount(item, title) {\n\t\t\tconst reported = this.widgetHeaders[item.widgetId]\n\t\t\tif (reported && Number.isFinite(reported.count)) {\n\t\t\t\treturn title.replace(/\\{count\\}/g, String(reported.count))\n\t\t\t}\n\t\t\treturn title.replace(/\\s*\\{count\\}/g, '').trim()\n\t\t},\n\n\t\t/**\n\t\t * Whether a widget's title header renders. Tri-state, resolved from the\n\t\t * layout placement first, then the widget def. The def fallback matters\n\t\t * because the in-place style editor persists `showTitle` onto the\n\t\t * widget def (see onWidgetConfigSave), while hand-written manifests\n\t\t * may set it on either object — mirrors getWidgetTitle's def fallback.\n\t\t *\n\t\t * When neither sets it, the default depends on the family: card widgets\n\t\t * (stat / gauge / delta) headline themselves via `content.label`, so a\n\t\t * chrome header would only repeat it — or, when no title was ever set,\n\t\t * show the raw type name (\"stat\"). Cards therefore default headerless;\n\t\t * every other widget defaults to showing the header.\n\t\t *\n\t\t * @param {object} item the layout placement.\n\t\t * @return {boolean}\n\t\t */\n\t\twidgetShowTitle(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tconst value = item.showTitle !== undefined ? item.showTitle : def?.showTitle\n\t\t\tif (value === undefined || value === null) {\n\t\t\t\t// A banner that names no title draws no title row: it used to show\n\t\t\t\t// its widget id (\"attention-first\") as the card title.\n\t\t\t\tif (this.isBannerDef(def) && !item.customTitle && !def?.customTitle && !def?.title) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\treturn !this.isCardWidget(item)\n\t\t\t}\n\t\t\treturn value !== false\n\t\t},\n\n\t\t/**\n\t\t * Whether a widget's card chrome is suppressed. Only an explicit\n\t\t * `layout[].borderless: true` suppresses it.\n\t\t *\n\t\t * HEADERLESS IS NOT CHROMELESS. This used to derive \"no header\" ⇒ \"no\n\t\t * card\", which conflates two different intentions and was already known\n\t\t * to push authors into the wrong shape — a headerless tile lost its card\n\t\t * and drew its own box inside the grid cell instead, a card inside a\n\t\t * card.\n\t\t *\n\t\t * Since the KPI card went flat (2026-08-30) that derivation does not\n\t\t * merely look wrong, it erases the tile: a flat card in a borderless\n\t\t * wrapper has NO chrome at all. Measured on buildiq, whose dashboard\n\t\t * renders `CnStatsBlock` inside a headerless `#widget-apps` custom slot\n\t\t * — three KPI tiles with no card, no border and no background.\n\t\t *\n\t\t * The registered-widget branches carried a second copy of this rule for\n\t\t * exactly that reason; there is now one rule for every family, so a\n\t\t * custom slot and a registered widget cannot disagree about it.\n\t\t *\n\t\t * A greeting header that declares `content.ground: true` sits on the\n\t\t * page ground, so it asks for no card either: one key on the widget\n\t\t * instead of a second one on its placement.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-a-greeting-can-sit-on-the-page-ground\n\t\t * @param {object} item the layout placement.\n\t\t * @return {boolean}\n\t\t */\n\t\twidgetBorderless(item) {\n\t\t\tif (item.borderless === true) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn Boolean(def && def.type === 'header' && this.getWidgetContent(item).ground === true)\n\t\t},\n\n\t\t/**\n\t\t * Whether a widget's overflow Actions menu renders. Same tri-state +\n\t\t * layout-then-def resolution as widgetShowTitle, and the same card\n\t\t * default: cards are the \"card\" family (docs/architecture/cards-and-widgets.md)\n\t\t * and carry no Actions menu — a KPI tile has no refreshable surface of\n\t\t * its own and the menu eats the header width it needs.\n\t\t *\n\t\t * @param {object} item the layout placement.\n\t\t * @return {boolean}\n\t\t */\n\t\twidgetShowActions(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tconst value = item.showActions !== undefined ? item.showActions : def?.showActions\n\t\t\tif (value === undefined || value === null) {\n\t\t\t\treturn this.showWidgetActions && !this.isCardWidget(item)\n\t\t\t}\n\t\t\treturn value !== false\n\t\t},\n\n\t\t/**\n\t\t * Documentation URL for a widget's overflow Actions menu. Prefers a\n\t\t * per-widget `documentationUrl` on the widget def, then falls back to\n\t\t * the page-level `documentationUrl` so every widget on a documented\n\t\t * page surfaces the Documentation item — matching the page header menu.\n\t\t *\n\t\t * @param {object} item Layout item descriptor.\n\t\t * @return {string} The resolved documentation URL, or '' when none.\n\t\t */\n\t\tgetWidgetDocumentationUrl(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.documentationUrl || this.documentationUrl || ''\n\t\t},\n\n\t\tgetWidgetIconUrl(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.iconUrl || null\n\t\t},\n\n\t\tgetWidgetIconClass(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.iconClass || null\n\t\t},\n\n\t\tgetWidgetButtons(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\t// `showButtons: false` on the placement or the definition drops\n\t\t\t// the footer links (\"More events\"), for a placement whose card\n\t\t\t// says enough without them (zuiddrecht-pixel-gaps-3).\n\t\t\tif (item?.showButtons === false || def?.showButtons === false) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn def?.buttons || []\n\t\t},\n\n\t\t/**\n\t\t * The widget's manifest `headerActions`, resolved for its card's title\n\t\t * row; a click goes through the page's dispatcher when the renderer\n\t\t * provides one (so `open-modal` opens a registry dialog), else through\n\t\t * the action dispatcher with the page's router.\n\t\t *\n\t\t * @spec openspec/changes/dashboard-widget-header-actions/specs/dashboard-widget-header-actions/spec.md#requirement-a-dashboard-card-draws-its-widgets-header-actions\n\t\t * @spec openspec/changes/dashboard-card-action-dialog/specs/dashboard-page/spec.md#requirement-a-dashboard-card-header-action-dispatches-through-the-page\n\t\t * @param {object} item Layout placement entry.\n\t\t * @return {Array<object>} The buttons, or none.\n\t\t */\n\t\tgetWidgetHeaderActions(item) {\n\t\t\treturn resolveWidgetHeaderActions(this.getWidgetDef(item.widgetId), {\n\t\t\t\ttranslate: (key) => this.effectiveTranslate(key),\n\t\t\t\tdispatch: (action) => (typeof this.cnDispatchAction === 'function'\n\t\t\t\t\t? this.cnDispatchAction(action)\n\t\t\t\t\t: dispatchAction(action, { router: this.$router || null })),\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The widget's header text link (`headerLink` on the layout entry,\n\t\t * else on the widget definition), forwarded to CnWidgetWrapper.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-widget-header-carries-a-text-link\n\t\t * @param {object} item Layout placement entry.\n\t\t * @return {object|null}\n\t\t */\n\t\tgetWidgetHeaderLink(item) {\n\t\t\tif (item?.headerLink && typeof item.headerLink === 'object') {\n\t\t\t\treturn item.headerLink\n\t\t\t}\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (def?.headerLink && typeof def.headerLink === 'object') {\n\t\t\t\treturn def.headerLink\n\t\t\t}\n\t\t\t// Then what the widget itself reported (`header` event): its link with\n\t\t\t// `{total}` filled and its tokens resolved.\n\t\t\t// A widget that reports no link (facts reports only its action) keeps\n\t\t\t// the link its content asks for.\n\t\t\tconst reported = this.widgetHeaders[item.widgetId]\n\t\t\tif (reported && reported.link) {\n\t\t\t\treturn reported.link\n\t\t\t}\n\t\t\t// Last, what the widget's own content asks for (`headerLink`, or the\n\t\t\t// `viewAllRoute` / `viewAllLabel` of the tasks widget).\n\t\t\treturn contentHeaderLink(item?.content) || contentHeaderLink(def?.content)\n\t\t},\n\n\t\t/**\n\t\t * Keep what a registry widget reports for its card header: the link, the\n\t\t * note (\"3 in total\") and one action, as CnDetailWidgetHost does on a\n\t\t * detail page.\n\t\t *\n\t\t * @spec openspec/changes/screens-dashboard-widget-header/specs/dashboard-page/spec.md#requirement-a-dashboard-card-shows-the-header-its-widget-reports\n\t\t * @param {object} item Layout placement entry.\n\t\t * @param {{link?: object|null, note?: string, action?: object|null}} header What the widget reported.\n\t\t */\n\t\tonWidgetHeader(item, header) {\n\t\t\tif (!item || !item.widgetId || !header || typeof header !== 'object' || header instanceof Event) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst link = header.link && typeof header.link === 'object' ? header.link : null\n\t\t\tconst note = typeof header.note === 'string' ? header.note : ''\n\t\t\tconst count = Number.isFinite(header.count) ? header.count : null\n\t\t\tconst action = header.action && typeof header.action.run === 'function' && header.action.label ? header.action : null\n\t\t\t// Only a changed header is kept: a new object here re-renders the card,\n\t\t\t// and a widget that reads again on render would report again, for ever.\n\t\t\tconst before = this.widgetHeaders[item.widgetId]\n\t\t\tconst same = before && JSON.stringify(before.link) === JSON.stringify(link) && before.note === note && (before.count ?? null) === count\n\t\t\t\t&& (before.action ? before.action.label : '') === (action ? action.label : '')\n\t\t\tif (same) {\n\t\t\t\tbefore.action = action\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.widgetHeaders = { ...this.widgetHeaders, [item.widgetId]: { link, note, action, count } }\n\t\t},\n\n\t\t/**\n\t\t * The header note a registry widget reported.\n\t\t *\n\t\t * @param {object} item Layout placement entry.\n\t\t * @return {string}\n\t\t */\n\t\twidgetHeaderNote(item) {\n\t\t\tconst reported = this.widgetHeaders[item.widgetId]\n\t\t\treturn reported ? reported.note : ''\n\t\t},\n\n\t\t/**\n\t\t * The total a registry widget reported for its card header\n\t\t * (record-list `headerCount`), or null.\n\t\t *\n\t\t * @param {object} item Layout placement entry.\n\t\t * @return {number|null}\n\t\t * @spec openspec/changes/screens-record-list-row-action/specs/record-list/spec.md\n\t\t */\n\t\twidgetHeaderCount(item) {\n\t\t\tif (this.titleHoldsCount(item)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst reported = this.widgetHeaders[item.widgetId]\n\t\t\treturn reported && Number.isFinite(reported.count) ? reported.count : null\n\t\t},\n\n\t\t/**\n\t\t * The header action a registry widget reported.\n\t\t *\n\t\t * @param {object} item Layout placement entry.\n\t\t * @return {{label: string, run: Function}|null}\n\t\t */\n\t\twidgetHeaderAction(item) {\n\t\t\tconst reported = this.widgetHeaders[item.widgetId]\n\t\t\treturn reported ? reported.action : null\n\t\t},\n\n\t\t/**\n\t\t * Whether a widget's overflow Actions menu shows the Refresh item.\n\t\t * An explicit per-widget flag wins — on the widget definition or\n\t\t * the layout item, as either `hideRefresh: true` or\n\t\t * `showRefresh: false`. Otherwise custom-slot widgets (which have no\n\t\t * built-in refetch path) resolve via the `widgetShowRefresh` tri-state\n\t\t * — the explicit prop, else whether a `@widget-refresh` listener is\n\t\t * wired (see `effectiveWidgetShowRefresh`) — while built-in widgets\n\t\t * (chart / NC / integration) inherit the page-level `showRefresh`. So a\n\t\t * read-only overview whose widgets have no refetch wired drops the dead\n\t\t * Refresh item from every widget menu while keeping Request-a-feature.\n\t\t *\n\t\t * @param {object} item Layout placement entry.\n\t\t * @return {boolean}\n\t\t */\n\t\tgetWidgetShowRefresh(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId) || {}\n\t\t\tif (def.hideRefresh === true || item.hideRefresh === true) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif (typeof def.showRefresh === 'boolean') {\n\t\t\t\treturn def.showRefresh\n\t\t\t}\n\t\t\tif (typeof item.showRefresh === 'boolean') {\n\t\t\t\treturn item.showRefresh\n\t\t\t}\n\t\t\tif (this.hasWidgetSlot(item.widgetId)) {\n\t\t\t\treturn this.effectiveWidgetShowRefresh\n\t\t\t}\n\t\t\treturn this.showRefresh\n\t\t},\n\n\t\tgetWidgetTitleIconPosition(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.titleIconPosition || 'right'\n\t\t},\n\n\t\tgetWidgetTitleIconColor(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.titleIconColor || null\n\t\t},\n\n\t\t/**\n\t\t * The widget's semantic header-icon colour. Read from the widget\n\t\t * definition's `titleIconVariant`; defaults to `primary`, which is\n\t\t * why EVERY widget's header icon is now coloured rather than only the\n\t\t * ones an app happened to configure. A widget whose subject already\n\t\t * carries a meaning names it — a Concepts list is `warning`, a\n\t\t * Published list `success`, a Depublished list `error`.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {string} A CnWidgetWrapper `titleIconVariant` value.\n\t\t */\n\t\tgetWidgetTitleIconVariant(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.titleIconVariant || 'primary'\n\t\t},\n\n\t\t/**\n\t\t * The widget's own section in the app's documentation, forwarded to\n\t\t * the shared Actions menu so its Documentation item deep-links to\n\t\t * THIS widget rather than the docs homepage. Falls back to the widget\n\t\t * type, which is how the library's own catalog widgets are documented,\n\t\t * and finally to the widget id.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {string} An anchor slug / path / URL.\n\t\t */\n\t\tgetWidgetDocsAnchor(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.docsAnchor || def?.type || item.widgetId || ''\n\t\t},\n\n\t\tisTile(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.type === 'tile'\n\t\t},\n\n\t\t/**\n\t\t * The tile config for a `type: \"tile\"` widget def.\n\t\t *\n\t\t * Read from `content` first, then the def's top level — the same\n\t\t * dual-shape read CnDashTileWidget does. A tile authored through the\n\t\t * Add-widget modal keeps the form's fields in `content`; only preset\n\t\t * and legacy tiles carry them at the top level. Reading the top level\n\t\t * alone left every authored tile with no icon, no link and CnTileWidget's\n\t\t * fallback blue, while its title still showed — the one field the modal\n\t\t * also writes there.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {object|null} the tile config, or null when no def matches.\n\t\t */\n\t\tgetTileConfig(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (!def) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst c = (def.content && typeof def.content === 'object') ? def.content : {}\n\t\t\treturn {\n\t\t\t\t// The modal resolves the header title, so the top level wins here.\n\t\t\t\t// `||`, not `??`: an empty-string def.title (never actually chosen\n\t\t\t\t// by the modal) must still fall through to content.title, which the\n\t\t\t\t// form validates as required and so is always populated.\n\t\t\t\ttitle: def.title || c.title,\n\t\t\t\tsubtitle: c.subtitle ?? def.subtitle,\n\t\t\t\ticon: c.icon ?? def.icon,\n\t\t\t\ticonType: c.iconType ?? def.iconType,\n\t\t\t\tbackgroundColor: c.backgroundColor ?? def.backgroundColor,\n\t\t\t\ttextColor: c.textColor ?? def.textColor,\n\t\t\t\tlinkType: c.linkType ?? def.linkType,\n\t\t\t\tlinkValue: c.linkValue ?? def.linkValue,\n\t\t\t}\n\t\t},\n\n\t\tisNcWidget(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.itemApiVersions && def.itemApiVersions.length > 0\n\t\t},\n\n\t\t/**\n\t\t * Whether this layout item resolves to an integration-typed\n\t\t * widget — `def.type === 'integration'` with an `integrationId`\n\t\t * pointing at a provider registered on the pluggable\n\t\t * integration registry. Mirrors `isTile` / `isChart`.\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {boolean} true when the matching widgetDef is an integration widget\n\t\t */\n\t\tisIntegration(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.type === 'integration' && typeof def.integrationId === 'string'\n\t\t},\n\n\t\t/**\n\t\t * Resolve the Vue component for an integration widget, applying\n\t\t * the AD-19 surface fallback. Returns null when the integration\n\t\t * isn't registered (renders the unavailable fallback instead).\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {object|null} Vue component, or null.\n\t\t */\n\t\tresolveIntegrationWidget(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (!def || typeof def.integrationId !== 'string') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.resolveRegistryWidget(def.integrationId, this.surface)\n\t\t},\n\n\t\t/**\n\t\t * Props passed to an integration widget: the rendering surface,\n\t\t * the (optional) object context, and any extra `props` declared\n\t\t * on the widget definition (per-widget props win on overlap).\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {object} Props object for the widget component.\n\t\t */\n\t\tgetIntegrationProps(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn {\n\t\t\t\tsurface: this.surface,\n\t\t\t\t...(this.integrationContext || {}),\n\t\t\t\t...(def?.props || {}),\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The registry provider descriptor behind an integration widget def,\n\t\t * carrying `mount`/`unmount` when it is a mount-mode leaf\n\t\t * (openregister#2127). Null when unregistered.\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {object|null} Provider descriptor, or null.\n\t\t */\n\t\tintegrationProviderFor(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\tif (!def || typeof def.integrationId !== 'string' || typeof this.getRegistryProvider !== 'function') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.getRegistryProvider(def.integrationId)\n\t\t},\n\n\t\t/**\n\t\t * Whether an integration widget resolves to a mount-mode leaf\n\t\t * (`renderMode: 'mount'`) — rendered through CnLeafMountHost rather\n\t\t * than as a component under the host's Vue runtime.\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {boolean} true when the integration is mount-mode.\n\t\t */\n\t\tisMountIntegration(item) {\n\t\t\tif (!this.isIntegration(item)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst provider = this.integrationProviderFor(item)\n\t\t\treturn Boolean(provider)\n\t\t\t\t&& provider.renderMode === 'mount'\n\t\t\t\t&& typeof provider.mount === 'function'\n\t\t\t\t&& typeof provider.unmount === 'function'\n\t\t},\n\n\t\t/**\n\t\t * Props forwarded to a mount-mode leaf's `mount(el, props)` — the same\n\t\t * context an SFC integration widget receives, plus an explicit\n\t\t * `integrationContext` bag for leaves that read it directly.\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {object} Mount props.\n\t\t */\n\t\tgetIntegrationMountProps(item) {\n\t\t\treturn {\n\t\t\t\t...this.getIntegrationProps(item),\n\t\t\t\tintegrationContext: { ...(this.integrationContext || {}) },\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether this layout item resolves to a chart-typed widget\n\t\t * definition. Mirrors `isTile` and `isNcWidget`. Used by the\n\t\t * dispatcher template to mount CnChartWidget.\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {boolean} true when the matching widgetDef.type is 'chart'\n\t\t */\n\t\tisChart(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.type === 'chart'\n\t\t},\n\n\t\t/**\n\t\t * Whether this layout item resolves to a stats-block widget\n\t\t * definition. Mirrors `isChart`. Used by the dispatcher\n\t\t * template to mount CnStatsBlockWidget.\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {boolean} true when the matching widgetDef.type is 'stats-block'\n\t\t */\n\t\tisStatsBlock(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\treturn def?.type === 'stats-block'\n\t\t},\n\n\t\t/**\n\t\t * Read the manifest `dataSource` block from a widget\n\t\t * definition. Returns `null` when none is set so the child\n\t\t * components can render their fallback (or stay loading).\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {object|null} The dataSource block or null\n\t\t */\n\t\tgetWidgetDataSource(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\t// Prefer the in-app-editable `content.dataSource` (ADR-041), else the\n\t\t\t// legacy top-level manifest `dataSource`.\n\t\t\treturn (def?.content && def.content.dataSource) || def?.dataSource || null\n\t\t},\n\n\t\t/**\n\t\t * Build the v-bind payload for CnStatsBlockWidget from a\n\t\t * stats-block widget definition. Forwards `props.countLabel`,\n\t\t * `props.variant`, `props.showZeroCount`, `props.horizontal`,\n\t\t * `props.route`, and `props.iconClass` plus the widgetDef's\n\t\t * `title`. The `dataSource` is bound separately by the template\n\t\t * (see `getWidgetDataSource`) so the prop appears clearly in\n\t\t * the template even when it lives on the widgetDef root.\n\t\t *\n\t\t * `iconClass` is a Nextcloud core CSS class (`icon-link`, …)\n\t\t * applied to the widget's wrapping `<div>` — a lightweight icon\n\t\t * path that doesn't require MDI dynamic-import. See\n\t\t * CnStatsBlockWidget for usage notes.\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {object} v-bind payload for CnStatsBlockWidget\n\t\t */\n\t\tgetStatsBlockProps(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\t// In-app-editable cards carry config in `content` (set by\n\t\t\t// CnStatsBlockWidgetForm); legacy manifests use top-level props.\n\t\t\tconst content = def?.content || {}\n\t\t\tconst props = content.props || def?.props || {}\n\t\t\tconst out = { title: content.title || def?.title || item.widgetId }\n\t\t\t// `vertical` / `filled` carry the KPI card's look. They are the\n\t\t\t// library's own defaults, so a manifest need not set them — but a\n\t\t\t// manifest that DOES set them must reach the component, or the\n\t\t\t// declaration is a silent no-op that reads like configuration.\n\t\t\tfor (const key of ['countLabel', 'variant', 'showZeroCount', 'horizontal', 'vertical', 'filled', 'route', 'iconClass', 'format', 'layout']) {\n\t\t\t\tif (props[key] !== undefined) {\n\t\t\t\t\tout[key] = props[key]\n\t\t\t\t}\n\t\t\t}\n\t\t\t// `content.layout: \"stacked\"`, the key a stat tile takes, works on\n\t\t\t// a stats block too (zuiddrecht-pixel-gaps-3).\n\t\t\tif (out.layout === undefined && typeof content.layout === 'string') {\n\t\t\t\tout.layout = content.layout\n\t\t\t}\n\t\t\t// `countLabel` is the unit beside the number (\"0 cases\", \"0 tasks\").\n\t\t\t// It is manifest-authored prose and was being forwarded raw, so a\n\t\t\t// Dutch account read \"0 cases\" beside a translated widget title.\n\t\t\t// The other keys in the loop are enums, booleans, routes and class\n\t\t\t// names, none of which are translatable.\n\t\t\tif (typeof out.countLabel === 'string' && out.countLabel) {\n\t\t\t\tout.countLabel = this.effectiveTranslate(out.countLabel)\n\t\t\t}\n\t\t\t// Multi-entry mode (ADR-049): prefer `content.entries`, then\n\t\t\t// `props.entries`. A legacy manifest that declared `entries` at the\n\t\t\t// widgetDef ROOT (a common opencatalogi shape) was silently dropped\n\t\t\t// because the dispatcher only forwards `content` — honour it with a\n\t\t\t// one-time deprecation warning so those cards render while authors\n\t\t\t// migrate the key under `content`.\n\t\t\t// Grid layout (`layout: \"grid\"`): stat tiles in columns.\n\t\t\tconst stats = content.stats !== undefined ? content.stats : props.stats\n\t\t\tif (Array.isArray(stats)) {\n\t\t\t\tout.stats = stats\n\t\t\t}\n\t\t\tconst columns = content.columns !== undefined ? content.columns : props.columns\n\t\t\tif (columns !== undefined) {\n\t\t\t\tout.columns = Number(columns)\n\t\t\t}\n\t\t\t// `tiles: \"box\"`: each grid tile on a surface of its own.\n\t\t\tconst tiles = content.tiles !== undefined ? content.tiles : props.tiles\n\t\t\tif (typeof tiles === 'string') {\n\t\t\t\tout.tiles = tiles\n\t\t\t}\n\t\t\tconst contentEntries = content.entries !== undefined ? content.entries : props.entries\n\t\t\tif (contentEntries !== undefined) {\n\t\t\t\tout.entries = contentEntries\n\t\t\t} else if (Array.isArray(def?.entries)) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[CnDashboardPage] stats-block \"${item.widgetId}\" declares \\`entries\\` at the widget-def root — `\n\t\t\t\t\t+ 'move it under `content.entries`. Root-level `entries` is deprecated and will stop being read.')\n\t\t\t\tout.entries = def.entries\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Build the v-bind payload for CnChartWidget from a chart-typed\n\t\t * widget definition. Translates `props.chartKind` → `type` (so\n\t\t * the manifest's free-form `chartKind` does not collide with\n\t\t * apexcharts' own reserved `type` prop) and forwards the\n\t\t * supported subset (`series`, `categories`, `labels`, `options`,\n\t\t * `colors`, `toolbar`, `legend`, `height`, `width`,\n\t\t * `unavailableLabel`, plus the display passthrough `horizontal`,\n\t\t * `legendPosition`, `valueFormat`, `colorMap`, `emptyLabel`).\n\t\t *\n\t\t * Unknown keys on `props` (including the reserved `dataSource`\n\t\t * union) are ignored at render time so manifest authors can ship\n\t\t * forward-compatible declarations.\n\t\t *\n\t\t * @param {object} item Layout item\n\t\t * @return {object} v-bind payload for CnChartWidget\n\t\t */\n\t\tgetChartProps(item) {\n\t\t\tconst def = this.getWidgetDef(item.widgetId)\n\t\t\t// In-app-editable charts (ADR-041) carry their config in `content`\n\t\t\t// (set by CnChartWidgetForm); legacy manifest charts use `props`.\n\t\t\tconst content = def?.content || {}\n\t\t\tconst props = content.props || def?.props || {}\n\t\t\tconst out = {}\n\t\t\tconst chartKind = content.chartKind || props.chartKind\n\t\t\tif (chartKind) {\n\t\t\t\tout.type = chartKind\n\t\t\t}\n\t\t\tfor (const key of CHART_PROP_KEYS) {\n\t\t\t\tconst v = content[key] !== undefined ? content[key] : props[key]\n\t\t\t\tif (v !== undefined) {\n\t\t\t\t\tout[key] = v\n\t\t\t\t}\n\t\t\t}\n\t\t\t// A dashboard tile's height is fixed by its grid units, so the chart\n\t\t\t// has to fit the tile — CnChartWidget's standalone default is a\n\t\t\t// pinned 250px, which is taller than the content box of a typical\n\t\t\t// h=4 tile (4 × cellHeight, less the widget header) and turned every\n\t\t\t// chart tile into a scroll region: the tile scrolled the graph\n\t\t\t// instead of showing it. An authored `height` still wins, so a\n\t\t\t// manifest can pin one deliberately.\n\t\t\tif (out.height === undefined) {\n\t\t\t\tout.height = '100%'\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Whether a chart tile's graph sizes itself to the tile — i.e. the\n\t\t * resolved height is a percentage. Only those tiles get the\n\t\t * `chart-fit` class, whose `overflow: hidden` is what stops the\n\t\t * wrapper showing a scrollbar for a sub-pixel rounding difference.\n\t\t *\n\t\t * An AUTHORED pixel height survives `getChartProps`, and clipping that\n\t\t * is not a rounding difference: on a tile shorter than the authored\n\t\t * height the bottom of the graph became unreachable, with the scroll\n\t\t * affordance removed. Such a tile keeps the wrapper's default\n\t\t * `overflow: auto` so the graph stays reachable.\n\t\t *\n\t\t * @param {object} item Layout item.\n\t\t * @return {boolean} True when the chart fits its tile.\n\t\t */\n\t\tisChartFitted(item) {\n\t\t\tconst height = this.getChartProps(item).height\n\t\t\treturn typeof height === 'string' && height.trim().endsWith('%')\n\t\t},\n\n\t\thasWidgetSlot(widgetId) {\n\t\t\treturn !!this.$slots['widget-' + widgetId]\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-dashboard-page {\n\tpadding: 20px;\n\tmax-width: 1800px;\n\t/* Centre the leftover space once the cap engages, so a wide screen shows\n\t an even gutter instead of one dead column on the right. Matches\n\t .cn-detail-page. */\n\tmargin-inline: auto;\n\t/* Scroll the dashboard itself when its widgets are taller than the host\n\t region (height:100% is a no-op when the host height is content-sized, so\n\t this only kicks in when an ancestor constrains the height). */\n\theight: 100%;\n\toverflow-y: auto;\n\tbox-sizing: border-box;\n}\n\n.cn-dashboard-page__header {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: flex-start;\n\tmargin-bottom: 20px;\n\tflex-wrap: wrap;\n\tgap: 12px;\n\t/* Clear the Nextcloud navigation toggle button (44px wide, absolutely\n\t positioned at the left edge of .app-content) plus 12px breathing\n\t room. Only the HEADER shifts right — body widgets keep full width. */\n\tpadding-inline-start: 56px;\n}\n\n.cn-dashboard-page__header-left {\n\tmin-width: 0;\n}\n\n.cn-dashboard-page__title-row {\n\tdisplay: flex;\n\talign-items: center;\n\tflex-wrap: wrap;\n\tgap: 12px;\n}\n\n.cn-dashboard-page__title {\n\tmargin: 0;\n\tfont-size: 20px;\n\tfont-weight: 700;\n}\n\n.cn-dashboard-page__description {\n\tmargin: 4px 0 0;\n\tfont-size: 14px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* Board look (screens-dashboard-parity): h1 28/700, a 15px grey subtitle 6px\n under it, and 40px buttons with a 10px gap. */\n.cn-dashboard-page--board .cn-dashboard-page__title {\n\tfont-size: 28px;\n\tfont-weight: 700;\n\tline-height: 1.2;\n}\n\n.cn-dashboard-page--board .cn-dashboard-page__description {\n\tmargin: 6px 0 0;\n\tfont-size: 15px;\n}\n\n.cn-dashboard-page--board .cn-dashboard-page__header-actions {\n\tgap: 10px;\n}\n\n.cn-dashboard-page--board .cn-dashboard-page__header-actions :deep(.button-vue) {\n\tmin-height: var(--cn-board-control-height, 40px);\n\theight: var(--cn-board-control-height, 40px);\n}\n\n/* The switch row under the header (screens-dashboard-greeting-header): the\n view switch left, the `viewLinks` pills right (DqMijnWerk: pills 34px high,\n radius 17, 13px/600, a 14px icon, primary light on primary deep). */\n.cn-dashboard-page__switch-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 10px;\n\tmargin-bottom: var(--cn-board-section-gap, 20px);\n}\n\n.cn-dashboard-page__switch-row-spacer {\n\tflex: 1 1 auto;\n}\n\n.cn-dashboard-page__view-link {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\theight: 34px;\n\tpadding: 0 12px;\n\tborder-radius: 17px;\n\tbackground: var(--color-primary-element-light);\n\tcolor: var(--color-primary-element-light-text);\n\tfont-size: 13px;\n\tfont-weight: 600;\n\twhite-space: nowrap;\n\ttext-decoration: none !important;\n}\n\n.cn-dashboard-page__view-link:hover {\n\tbackground: var(--color-primary-element-light-hover, var(--color-primary-element-light));\n}\n\n.cn-dashboard-page__view-link:focus-visible {\n\toutline: 2px solid var(--color-main-text);\n\toutline-offset: 2px;\n}\n\n.cn-dashboard-page__view-link-icon {\n\tdisplay: inline-flex;\n}\n\n/* The period group, in a row of its own between the header and the KPI row. */\n.cn-dashboard-page__date-range--segmented {\n\tmargin-bottom: 16px;\n}\n\n/* The period group at the end of the description line. */\n.cn-dashboard-page__description--with-period {\n\talign-items: center;\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n}\n\n/* A select on the description line takes the width of its choice, not a\n form field's, and no margin of its own. */\n.cn-dashboard-page__description-select {\n\tmin-width: 180px;\n\tmax-width: 280px;\n\tmargin: 0;\n}\n\n.cn-dashboard-page__date-segmented {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n}\n\n/* The KPI row above the grid: tiles are cells of the auto-fit grid. */\n.cn-dashboard-page__kpi-row {\n\tmargin-bottom: var(--cn-board-section-gap, 16px);\n}\n\n/* Board look: GridStack insets every card by the grid margin on each side, so\n the cards started a margin to the right of the KPI row and the header. The\n grid reaches out by that margin, so the card edges line up with the page's\n (dashboard-grid-flush). */\n.cn-dashboard-page--board :deep(.cn-dashboard-grid) {\n\twidth: auto;\n\tmargin-inline: calc(-1 * var(--cn-dashboard-grid-margin, 12px));\n}\n\n.cn-dashboard-page__kpi-cell {\n\tdisplay: flex;\n\tmin-width: 0;\n}\n\n.cn-dashboard-page__kpi-cell > * {\n\tflex: 1 1 auto;\n\tmin-width: 0;\n}\n\n/* NOTE: the date-range chip's trigger/chip/preset-spacer rules live in the\n UNSCOPED <style> block below, anchored on the trigger's `data-testid`, not\n here. Consumers (pipelinq, …) split the library across webpack chunks with\n no shared runtime chunk, so a rendered CnDashboardPage instance can carry a\n different `data-v-*` scope id than the one baked into this scoped CSS — the\n scoped chip rules then silently don't match and the chip collapses into\n NcActions' ~30px icon slot (text wraps to \"Last / 30 / days\"). The\n data-testid is stable across chunks, so those rules match regardless. */\n\n.cn-dashboard-page__header-actions {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\tflex-shrink: 0;\n\t/* Keeps the actions hard right even when a wide action set (pipelinq's six\n\t buttons) wraps onto its own line. The header's `justify-content:\n\t space-between` only distributes items WITHIN a line, so once the actions\n\t wrap they become the sole item on line 2 and would otherwise sit flush\n\t left, under the title. No-op while title and actions share a line. */\n\tmargin-left: auto;\n}\n\n/* Date-range header band. Kept compact so it doesn't open a tall gap\n above the grid; the pills variant is a single tidy toggle row. */\n.cn-dashboard-page__date-range {\n\tmargin-bottom: 12px;\n}\n\n.cn-dashboard-page__date-range--pills {\n\tmargin-bottom: 8px;\n}\n\n.cn-dashboard-page__date-pills {\n\tdisplay: flex;\n\talign-items: center;\n\tflex-wrap: wrap;\n\tgap: 6px;\n}\n\n.cn-dashboard-page__date-pill {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tpadding: 5px 14px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: 999px;\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tline-height: 1.2;\n\twhite-space: nowrap;\n\tcursor: pointer;\n\ttransition: background-color 100ms ease, border-color 100ms ease, color 100ms ease;\n}\n\n.cn-dashboard-page__date-pill:hover {\n\tbackground: var(--color-background-hover);\n}\n\n.cn-dashboard-page__date-pill:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n.cn-dashboard-page__date-pill--active {\n\tbackground: var(--color-primary-element);\n\tborder-color: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n}\n\n.cn-dashboard-page__date-pill--active:hover {\n\tbackground: var(--color-primary-element-hover, var(--color-primary-element));\n}\n\n/* The custom-range pill is de-emphasised — dashed outline, muted text —\n so it reads as an escape hatch rather than a primary option. */\n.cn-dashboard-page__date-pill--custom {\n\tborder-style: dashed;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-dashboard-page__date-pill-custom :deep(.action-item__menutoggle) {\n\tmin-width: 0;\n\tmin-height: 0;\n\tpadding: 0;\n\tbackground: transparent;\n\tborder: none;\n}\n\n.cn-dashboard-page__date-pill-custom :deep(.button-vue),\n.cn-dashboard-page__date-pill-custom :deep(.button-vue__wrapper),\n.cn-dashboard-page__date-pill-custom :deep(.button-vue__icon) {\n\twidth: auto !important;\n\tmin-width: 0 !important;\n\toverflow: visible !important;\n}\n\n.cn-dashboard-page__empty {\n\tpadding: 60px 20px;\n}\n\n/* The page's view switch on a page without a header row: at the end of its\n own row, above the grids, where the header would have put it. */\n.cn-dashboard-page__view-switch {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\tmargin-bottom: 12px;\n}\n\n/* A view the switch shows with nothing to draw. */\n.cn-page-view-region--empty {\n\tpadding: 40px 20px;\n}\n\n.cn-dashboard-page__page-filters {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 16px;\n\talign-items: flex-end;\n\tmargin-bottom: 12px;\n}\n\n.cn-dashboard-page__page-filter {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmin-width: 200px;\n}\n\n.cn-dashboard-page__page-filter-label {\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-dashboard-page__widget-edit {\n\tposition: absolute;\n\ttop: 4px;\n\tinset-inline-end: 4px;\n\tz-index: 5;\n\tbackground: var(--color-main-background);\n\tborder-radius: var(--border-radius);\n\tbox-shadow: 0 1px 4px var(--color-box-shadow, rgba(0, 0, 0, 0.2));\n}\n\n/* Card-fit registry widgets (stat / gauge / delta): the tile content is a\n self-contained card that should size to the tile and centre vertically,\n never scroll. CnWidgetWrapper's content area defaults to overflow:auto +\n 16px padding, which produced stray scrollbars on short KPI / gauge tiles\n and a horizontal scrollbar when a long currency value met the icon. Here\n we drop the inner scroll, add comfortable padding back (flush removed it),\n and centre the card. */\n/* `safe` centre so an overflowing tile does not spill out of the top, where\n flex overflow cannot be scrolled back to. Same as detail-page.css. */\n.cn-dashboard-page__card-fit :deep(.cn-widget-wrapper__content),\n.cn-dashboard-page__card-fit.cn-widget-wrapper--flush :deep(.cn-widget-wrapper__content) {\n\toverflow: hidden;\n\tdisplay: flex;\n\tflex-direction: column;\n\tjustify-content: center;\n\tjustify-content: safe center;\n\tpadding: 8px 14px;\n}\n\n/* Chart tiles whose graph FITS the tile (see isChartFitted — a percentage\n height, which getChartProps supplies unless the author pinned pixels), so\n the wrapper's default `overflow: auto` content area has nothing to scroll —\n and leaving it on means any rounding difference between the box and the SVG\n shows up as a scrollbar the user has to drag to see the whole graph. Same\n shape as the card-fit rule above, minus the padding: chart tiles render\n `flush`, and apexcharts already draws its own margins. */\n.cn-dashboard-page__chart-fit :deep(.cn-widget-wrapper__content) {\n\toverflow: hidden;\n\tdisplay: flex;\n\tflex-direction: column;\n\tmin-height: 0;\n}\n\n/* Card content (stat / gauge / delta) must fit the tile width: let the\n widget shrink and its value/label truncate instead of pushing past the\n tile edge (the horizontal clip on long currency values). */\n.cn-dashboard-page__card-fit :deep(.cn-stat-widget),\n.cn-dashboard-page__card-fit :deep(.cn-gauge-widget),\n.cn-dashboard-page__card-fit :deep(.cn-delta-widget) {\n\tmin-width: 0;\n\tmax-width: 100%;\n}\n\n.cn-dashboard-page__unknown {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\theight: 100%;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n\tpadding: 16px;\n}\n\n/* widget-ref content items */\n.cn-dashboard-page__content {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 16px;\n}\n\n.cn-dashboard-page__content-item {\n\twidth: 100%;\n}\n/* On a phone (screens-dashboard-phone) the touch targets of a board dashboard\n are 44px: the widget Actions menu and the KPI tiles. */\n@media (max-width: 640px) {\n\t.cn-dashboard-page--board :deep(.cn-widget-wrapper__actions .action-item__menutoggle),\n\t.cn-dashboard-page--board :deep(.cn-widget-wrapper__actions .button-vue) {\n\t\tmin-height: 44px;\n\t}\n\n\t.cn-dashboard-page--board .cn-dashboard-page__kpi-cell {\n\t\tmin-height: 44px;\n\t}\n\n\t/* The widget Actions menu shows its icon only, so the card title keeps\n\t the room; the name stays for assistive tech. */\n\t.cn-dashboard-page--board :deep(.cn-widget-wrapper__actions .action-item__menutoggle) {\n\t\tmin-width: 44px;\n\t}\n\n\t.cn-dashboard-page--board :deep(.cn-widget-wrapper__actions .action-item__menutoggle .button-vue__text) {\n\t\tposition: absolute;\n\t\twidth: 1px;\n\t\theight: 1px;\n\t\toverflow: hidden;\n\t\tclip-path: inset(50%);\n\t\twhite-space: nowrap;\n\t}\n}\n\n/* What a registry widget reports for its card header (`header` event): the\n note beside the link (\"3 in total\") and one action, as on a detail page. */\n.cn-dashboard-page__widget-count {\n\talign-self: center;\n\tpadding: 1px 8px;\n\tborder-radius: 10px;\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n\tfont-size: 13px;\n\tfont-weight: 600;\n}\n\n.cn-dashboard-page__widget-note {\n\talign-self: center;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n\twhite-space: nowrap;\n}\n\n.cn-dashboard-page__widget-action {\n\tdisplay: inline-flex;\n\talign-items: center;\n\talign-self: center;\n\tmin-height: 32px;\n\tpadding: 0 14px;\n\tborder: 0;\n\tborder-radius: 16px;\n\tbackground: var(--color-primary-element-light);\n\tcolor: var(--color-primary-element-light-text, var(--color-primary-element));\n\tfont: inherit;\n\tfont-size: 13px;\n\tfont-weight: 700;\n\twhite-space: nowrap;\n\tcursor: pointer;\n}\n\n.cn-dashboard-page__widget-action:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n</style>\n\n<!-- Unscoped, anchored on the stable `data-testid` NcActions renders on both\n the trigger and (forwarded) the teleported <body> popper. Everything about\n the date chip lives here rather than in scoped CSS because a consumer that\n splits the library across webpack chunks (pipelinq) can render a\n CnDashboardPage instance whose `data-v-*` scope id differs from the one\n compiled into the scoped stylesheet — scoped rules then don't match and the\n chip collapses into NcActions' ~30px icon slot. The data-testid is chunk-\n stable, so these rules always match. Classes stay `cn-`-prefixed so the\n unscoped rules can't collide with anything outside this widget. -->\n<style>\n/* Trigger: strip NcActions' default button chrome down to just the chip span. */\n[data-testid^=\"cn-dashboard-page-date-chip-\"].cn-dashboard-page__date-chip-trigger {\n\tdisplay: inline-flex;\n}\n\n/* The toggle is a chrome-less carrier for the pill — the pill IS the control.\n NcButton paints its own background, ~30px box and `--border-radius-element`\n corners on hover / focus / :active / aria-expanded; left alone that draws a\n rounded SQUARE behind (and around) the wider, fully-rounded pill. Every\n state is neutralised with `!important` because NcButton's own state rules\n are more specific than a plain class selector. */\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-item__menutoggle,\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-item__menutoggle:hover,\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-item__menutoggle:focus,\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-item__menutoggle:focus-visible,\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-item__menutoggle:active,\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-item__menutoggle[aria-expanded=\"true\"] {\n\tmin-width: 0 !important;\n\tmin-height: 0 !important;\n\theight: auto !important;\n\tpadding: 0 !important;\n\tbackground: transparent !important;\n\tbackground-color: transparent !important;\n\tborder: none !important;\n\tbox-shadow: none !important;\n\tborder-radius: 999px;\n}\n\n/* The chip text lives in NcActions' icon slot, whose default toggle is sized\n for a single icon and clips/wraps wider content. Let the toggle + its icon\n wrapper grow to the chip's natural width so \"Last 30 days\" reads on one\n line — and keep them shrink-wrapped so the pill isn't offset inside a wider\n box (which is what pushed the chip outside its own trigger). */\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .button-vue,\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .button-vue__wrapper,\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .button-vue__icon {\n\twidth: auto !important;\n\tmin-width: 0 !important;\n\theight: auto !important;\n\tmin-height: 0 !important;\n\toverflow: visible !important;\n}\n\n/* The width above is NOT enough on its own, and this rule is what actually\n frees the pill. NcButton pins an icon-only button to a square clickable area\n with an `!important` of its own:\n\n .button-vue[data-v-…]:has(.button-vue__text:empty):not(.button-vue--wide) {\n width: var(--button-size) !important; // --default-clickable-area, 34px\n }\n\n NcActions fills the trigger's text slot from its `menuName` prop, which the\n chip does not use (its label is markup, not a string), so `.button-vue__text`\n renders empty and that rule always matches here. Two `!important`\n declarations are settled by SPECIFICITY, and theirs is (0,5,0) against the\n (0,2,0) of the plain descendant selector above — so the button stayed 34px\n wide while its icon wrapper grew to the pill's ~106px. Combined with the\n `overflow: visible` above, the pill then rendered centred on a 34px box and\n spilled ~36px out each side, over the widget title.\n\n This selector re-states their `:has()` predicate — so it applies exactly\n where theirs does, and drops out with it on a browser without `:has()` — and\n adds the trigger's own three hooks, reaching (0,7,0). Keep it ahead of\n whatever NcButton declares: tests/components/CnDashboardPageDateChip.spec.js\n reads both selectors out of the installed NcButton stylesheet and fails when\n this margin disappears. */\n[data-testid^=\"cn-dashboard-page-date-chip-\"].cn-dashboard-page__date-chip-trigger.action-item\n\t.button-vue.action-item__menutoggle:has(.button-vue__text:empty) {\n\twidth: auto !important;\n\tmin-width: 0 !important;\n}\n\n.cn-dashboard-page__date-chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\t/* Breathing room from the widget title / header edge — the chip sits in\n\t CnWidgetWrapper's `#title-meta` slot, flush against its neighbours. */\n\tmargin-inline: 4px;\n\tpadding: 2px 10px;\n\tborder-radius: 999px;\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 12px;\n\tfont-variant-numeric: tabular-nums;\n\twhite-space: nowrap;\n\tcursor: pointer;\n\ttransition: background 100ms ease, color 100ms ease;\n}\n\n[data-testid^=\"cn-dashboard-page-date-chip-\"]:hover .cn-dashboard-page__date-chip,\n[data-testid^=\"cn-dashboard-page-date-chip-\"]:focus-within .cn-dashboard-page__date-chip {\n\tbackground: var(--color-primary-element-light, var(--color-background-darker));\n\tcolor: var(--color-main-text);\n}\n\n/* Open state: the pill itself goes primary. The active affordance is the\n pill's own colour — never a separate box painted behind it. */\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-item__menutoggle[aria-expanded=\"true\"] .cn-dashboard-page__date-chip {\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n}\n\n/* Keyboard focus needs a visible ring now that the button chrome is gone. */\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-item__menutoggle:focus-visible .cn-dashboard-page__date-chip {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n/* Empty span keeping preset NcActionButtons' labels aligned with the row that\n shows the current-selection CalendarRange icon (NcActionButton icon slot is\n ~20px). Lives in the teleported popper, so it's unscoped too. */\n.cn-dashboard-page__date-chip-preset-spacer {\n\tdisplay: inline-block;\n\twidth: 16px;\n\theight: 16px;\n}\n\n.action-item__popper[data-testid^=\"cn-dashboard-page-date-chip-\"] .v-popper__inner,\n[data-testid^=\"cn-dashboard-page-date-chip-\"].v-popper__popper .v-popper__inner {\n\toverflow: visible;\n}\n\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-input__form,\n[data-testid^=\"cn-dashboard-page-date-chip-\"] .action-input {\n\tmin-width: 240px;\n}\n</style>\n"],"names":["CnHeaderTrail","CnEmptyContent","CnDashboardGrid","CnWidgetWrapper","CnWidgetRenderer","CnTileWidget","CnChartWidget","CnStatsBlockWidget","CnWidgetRefItem","CnBodySections","CnDateRangePicker","CnActionsMenu","CnActionButtons","CnBuildiqEditButton","CnWidgetStyleEditorModal","CnLeafMountHost","CnSegmentedControl","CnKpiGrid","CnWidgetIcon","t"],"mappings":"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"}