@alfadocs/ui-kit-debug 1.41.0 → 1.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/{calendar-workspace-UllCER2k.js → calendar-workspace-qlxrxCqm.js} +1980 -1967
- package/dist/_chunks/calendar-workspace-qlxrxCqm.js.map +1 -0
- package/dist/_chunks/{help-me-write-templates-GB70jnV9.js → help-me-write-templates-B-m7zgJa.js} +242 -231
- package/dist/_chunks/help-me-write-templates-B-m7zgJa.js.map +1 -0
- package/dist/_chunks/{notes-panel-_diLt8Cj.js → notes-panel-CRAovkjx.js} +84 -68
- package/dist/_chunks/notes-panel-CRAovkjx.js.map +1 -0
- package/dist/_chunks/{rich-text-editor-D7AKKAQ2.js → rich-text-editor-DUMeifwc.js} +1195 -1138
- package/dist/_chunks/rich-text-editor-DUMeifwc.js.map +1 -0
- package/dist/agent-catalog.json +1 -1
- package/dist/components/notes-panel/index.js +1 -1
- package/dist/components/notes-panel/notes-panel.d.ts +32 -0
- package/dist/components/notes-panel/notes-panel.d.ts.map +1 -1
- package/dist/components/rich-text-editor/index.js +1 -1
- package/dist/components/rich-text-editor/rich-text-editor.d.ts.map +1 -1
- package/dist/i18n/locales/ar.d.ts +1 -0
- package/dist/i18n/locales/ar.d.ts.map +1 -1
- package/dist/i18n/locales/ar.js +2 -1
- package/dist/i18n/locales/ar.js.map +1 -1
- package/dist/i18n/locales/de.d.ts +1 -0
- package/dist/i18n/locales/de.d.ts.map +1 -1
- package/dist/i18n/locales/de.js +2 -1
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/el.d.ts +1 -0
- package/dist/i18n/locales/el.d.ts.map +1 -1
- package/dist/i18n/locales/el.js +2 -1
- package/dist/i18n/locales/el.js.map +1 -1
- package/dist/i18n/locales/en.d.ts +1 -0
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/en.js +2 -1
- package/dist/i18n/locales/en.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +1 -0
- package/dist/i18n/locales/es.d.ts.map +1 -1
- package/dist/i18n/locales/es.js +2 -1
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +1 -0
- package/dist/i18n/locales/fr.d.ts.map +1 -1
- package/dist/i18n/locales/fr.js +2 -1
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hi.d.ts +1 -0
- package/dist/i18n/locales/hi.d.ts.map +1 -1
- package/dist/i18n/locales/hi.js +2 -1
- package/dist/i18n/locales/hi.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +1 -0
- package/dist/i18n/locales/it.d.ts.map +1 -1
- package/dist/i18n/locales/it.js +2 -1
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/ja.d.ts +1 -0
- package/dist/i18n/locales/ja.d.ts.map +1 -1
- package/dist/i18n/locales/ja.js +2 -1
- package/dist/i18n/locales/ja.js.map +1 -1
- package/dist/i18n/locales/nl.d.ts +1 -0
- package/dist/i18n/locales/nl.d.ts.map +1 -1
- package/dist/i18n/locales/nl.js +2 -1
- package/dist/i18n/locales/nl.js.map +1 -1
- package/dist/i18n/locales/pl.d.ts +1 -0
- package/dist/i18n/locales/pl.d.ts.map +1 -1
- package/dist/i18n/locales/pl.js +2 -1
- package/dist/i18n/locales/pl.js.map +1 -1
- package/dist/i18n/locales/pt.d.ts +1 -0
- package/dist/i18n/locales/pt.d.ts.map +1 -1
- package/dist/i18n/locales/pt.js +2 -1
- package/dist/i18n/locales/pt.js.map +1 -1
- package/dist/i18n/locales/ro.d.ts +1 -0
- package/dist/i18n/locales/ro.d.ts.map +1 -1
- package/dist/i18n/locales/ro.js +2 -1
- package/dist/i18n/locales/ro.js.map +1 -1
- package/dist/i18n/locales/ru.d.ts +1 -0
- package/dist/i18n/locales/ru.d.ts.map +1 -1
- package/dist/i18n/locales/ru.js +2 -1
- package/dist/i18n/locales/ru.js.map +1 -1
- package/dist/i18n/locales/sq.d.ts +1 -0
- package/dist/i18n/locales/sq.d.ts.map +1 -1
- package/dist/i18n/locales/sq.js +2 -1
- package/dist/i18n/locales/sq.js.map +1 -1
- package/dist/i18n/locales/sv.d.ts +1 -0
- package/dist/i18n/locales/sv.d.ts.map +1 -1
- package/dist/i18n/locales/sv.js +2 -1
- package/dist/i18n/locales/sv.js.map +1 -1
- package/dist/i18n/locales/tr.d.ts +1 -0
- package/dist/i18n/locales/tr.d.ts.map +1 -1
- package/dist/i18n/locales/tr.js +2 -1
- package/dist/i18n/locales/tr.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +1 -0
- package/dist/i18n/locales/zh.d.ts.map +1 -1
- package/dist/i18n/locales/zh.js +2 -1
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/locales/ar.json +2 -1
- package/dist/locales/de.json +2 -1
- package/dist/locales/el.json +2 -1
- package/dist/locales/en.json +2 -1
- package/dist/locales/es.json +2 -1
- package/dist/locales/fr.json +2 -1
- package/dist/locales/hi.json +2 -1
- package/dist/locales/it.json +2 -1
- package/dist/locales/ja.json +2 -1
- package/dist/locales/nl.json +2 -1
- package/dist/locales/pl.json +2 -1
- package/dist/locales/pt.json +2 -1
- package/dist/locales/ro.json +2 -1
- package/dist/locales/ru.json +2 -1
- package/dist/locales/sq.json +2 -1
- package/dist/locales/sv.json +2 -1
- package/dist/locales/tr.json +2 -1
- package/dist/locales/zh.json +2 -1
- package/dist/patterns/calendar/calendar.journey.d.ts +11 -0
- package/dist/patterns/calendar/calendar.journey.d.ts.map +1 -1
- package/dist/patterns/calendar/calendar.sheets.d.ts +20 -0
- package/dist/patterns/calendar/calendar.sheets.d.ts.map +1 -1
- package/dist/patterns/calendar/index.js +1 -1
- package/dist/patterns/help-me-write-templates/help-me-write-templates.d.ts.map +1 -1
- package/dist/patterns/help-me-write-templates/index.js +1 -1
- package/package.json +1 -1
- package/dist/_chunks/calendar-workspace-UllCER2k.js.map +0 -1
- package/dist/_chunks/help-me-write-templates-GB70jnV9.js.map +0 -1
- package/dist/_chunks/notes-panel-_diLt8Cj.js.map +0 -1
- package/dist/_chunks/rich-text-editor-D7AKKAQ2.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar-workspace-qlxrxCqm.js","sources":["../../node_modules/lucide-react/dist/esm/icons/cake.mjs","../../node_modules/lucide-react/dist/esm/icons/calendar-search.mjs","../../node_modules/lucide-react/dist/esm/icons/clipboard-paste.mjs","../../node_modules/lucide-react/dist/esm/icons/funnel.mjs","../../node_modules/lucide-react/dist/esm/icons/history.mjs","../../node_modules/lucide-react/dist/esm/icons/id-card.mjs","../../node_modules/lucide-react/dist/esm/icons/list-plus.mjs","../../node_modules/lucide-react/dist/esm/icons/move.mjs","../../node_modules/lucide-react/dist/esm/icons/save.mjs","../../node_modules/lucide-react/dist/esm/icons/sliders-horizontal.mjs","../../node_modules/lucide-react/dist/esm/icons/sticky-note.mjs","../../src/patterns/calendar/calendar.data.ts","../../src/patterns/calendar/calendar.types.ts","../../src/patterns/calendar/calendar.preferences.ts","../../src/patterns/calendar/calendar.model.ts","../../src/patterns/calendar/calendar-workspace.model.ts","../../src/patterns/calendar/calendar-upcoming-panel.tsx","../../src/patterns/calendar/calendar-editor-hydration.tsx","../../src/patterns/calendar/calendar-patient-picker.tsx","../../src/patterns/calendar/calendar-rail-settle.ts","../../src/patterns/calendar/calendar-series-scope-chooser.tsx","../../src/patterns/calendar/calendar.host.ts","../../src/patterns/calendar/calendar-bookings-panel.tsx","../../src/patterns/calendar/calendar.sheets.tsx","../../src/patterns/calendar/calendar-privacy.tsx","../../src/patterns/calendar/calendar-info-hover.tsx","../../src/patterns/calendar/calendar-appointment-details.sections.tsx","../../src/patterns/calendar/calendar-appointment-details.tsx","../../src/patterns/calendar/calendar-notes-tool.tsx","../../src/patterns/calendar/calendar.surface.tsx","../../src/patterns/calendar/calendar-waiting-list-panel.tsx","../../src/patterns/calendar/calendar-workspace.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M20 21v-8a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v8\", key: \"1w3rig\" }],\n [\"path\", { d: \"M4 16s.5-1 2-1 2.5 2 4 2 2.5-2 4-2 2.5 2 4 2 2-1 2-1\", key: \"n2jgmb\" }],\n [\"path\", { d: \"M2 21h20\", key: \"1nyx9w\" }],\n [\"path\", { d: \"M7 8v3\", key: \"1qtyvj\" }],\n [\"path\", { d: \"M12 8v3\", key: \"hwp4zt\" }],\n [\"path\", { d: \"M17 8v3\", key: \"1i6e5u\" }],\n [\"path\", { d: \"M7 4h.01\", key: \"1bh4kh\" }],\n [\"path\", { d: \"M12 4h.01\", key: \"1ujb9j\" }],\n [\"path\", { d: \"M17 4h.01\", key: \"1upcoc\" }]\n];\nconst Cake = createLucideIcon(\"cake\", __iconNode);\n\nexport { __iconNode, Cake as default };\n//# sourceMappingURL=cake.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M16 2v4\", key: \"4m81vk\" }],\n [\"path\", { d: \"M21 11.75V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h7.25\", key: \"1jrsq6\" }],\n [\"path\", { d: \"m22 22-1.875-1.875\", key: \"13zax7\" }],\n [\"path\", { d: \"M3 10h18\", key: \"8toen8\" }],\n [\"path\", { d: \"M8 2v4\", key: \"1cmpym\" }],\n [\"circle\", { cx: \"18\", cy: \"18\", r: \"3\", key: \"1xkwt0\" }]\n];\nconst CalendarSearch = createLucideIcon(\"calendar-search\", __iconNode);\n\nexport { __iconNode, CalendarSearch as default };\n//# sourceMappingURL=calendar-search.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M11 14h10\", key: \"1w8e9d\" }],\n [\"path\", { d: \"M16 4h2a2 2 0 0 1 2 2v1.344\", key: \"1e62lh\" }],\n [\"path\", { d: \"m17 18 4-4-4-4\", key: \"z2g111\" }],\n [\"path\", { d: \"M8 4H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 1.793-1.113\", key: \"bjbb7m\" }],\n [\"rect\", { x: \"8\", y: \"2\", width: \"8\", height: \"4\", rx: \"1\", key: \"ublpy\" }]\n];\nconst ClipboardPaste = createLucideIcon(\"clipboard-paste\", __iconNode);\n\nexport { __iconNode, ClipboardPaste as default };\n//# sourceMappingURL=clipboard-paste.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z\",\n key: \"sc7q7i\"\n }\n ]\n];\nconst Funnel = createLucideIcon(\"funnel\", __iconNode);\n\nexport { __iconNode, Funnel as default };\n//# sourceMappingURL=funnel.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\", key: \"1357e3\" }],\n [\"path\", { d: \"M3 3v5h5\", key: \"1xhq8a\" }],\n [\"path\", { d: \"M12 7v5l4 2\", key: \"1fdv2h\" }]\n];\nconst History = createLucideIcon(\"history\", __iconNode);\n\nexport { __iconNode, History as default };\n//# sourceMappingURL=history.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M16 10h2\", key: \"8sgtl7\" }],\n [\"path\", { d: \"M16 14h2\", key: \"epxaof\" }],\n [\"path\", { d: \"M6.17 15a3 3 0 0 1 5.66 0\", key: \"n6f512\" }],\n [\"circle\", { cx: \"9\", cy: \"11\", r: \"2\", key: \"yxgjnd\" }],\n [\"rect\", { x: \"2\", y: \"5\", width: \"20\", height: \"14\", rx: \"2\", key: \"qneu4z\" }]\n];\nconst IdCard = createLucideIcon(\"id-card\", __iconNode);\n\nexport { __iconNode, IdCard as default };\n//# sourceMappingURL=id-card.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M16 5H3\", key: \"m91uny\" }],\n [\"path\", { d: \"M11 12H3\", key: \"51ecnj\" }],\n [\"path\", { d: \"M16 19H3\", key: \"zzsher\" }],\n [\"path\", { d: \"M18 9v6\", key: \"1twb98\" }],\n [\"path\", { d: \"M21 12h-6\", key: \"bt1uis\" }]\n];\nconst ListPlus = createLucideIcon(\"list-plus\", __iconNode);\n\nexport { __iconNode, ListPlus as default };\n//# sourceMappingURL=list-plus.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 2v20\", key: \"t6zp3m\" }],\n [\"path\", { d: \"m15 19-3 3-3-3\", key: \"11eu04\" }],\n [\"path\", { d: \"m19 9 3 3-3 3\", key: \"1mg7y2\" }],\n [\"path\", { d: \"M2 12h20\", key: \"9i4pu4\" }],\n [\"path\", { d: \"m5 9-3 3 3 3\", key: \"j64kie\" }],\n [\"path\", { d: \"m9 5 3-3 3 3\", key: \"l8vdw6\" }]\n];\nconst Move = createLucideIcon(\"move\", __iconNode);\n\nexport { __iconNode, Move as default };\n//# sourceMappingURL=move.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z\",\n key: \"1c8476\"\n }\n ],\n [\"path\", { d: \"M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7\", key: \"1ydtos\" }],\n [\"path\", { d: \"M7 3v4a1 1 0 0 0 1 1h7\", key: \"t51u73\" }]\n];\nconst Save = createLucideIcon(\"save\", __iconNode);\n\nexport { __iconNode, Save as default };\n//# sourceMappingURL=save.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M10 5H3\", key: \"1qgfaw\" }],\n [\"path\", { d: \"M12 19H3\", key: \"yhmn1j\" }],\n [\"path\", { d: \"M14 3v4\", key: \"1sua03\" }],\n [\"path\", { d: \"M16 17v4\", key: \"1q0r14\" }],\n [\"path\", { d: \"M21 12h-9\", key: \"1o4lsq\" }],\n [\"path\", { d: \"M21 19h-5\", key: \"1rlt1p\" }],\n [\"path\", { d: \"M21 5h-7\", key: \"1oszz2\" }],\n [\"path\", { d: \"M8 10v4\", key: \"tgpxqk\" }],\n [\"path\", { d: \"M8 12H3\", key: \"a7s4jb\" }]\n];\nconst SlidersHorizontal = createLucideIcon(\"sliders-horizontal\", __iconNode);\n\nexport { __iconNode, SlidersHorizontal as default };\n//# sourceMappingURL=sliders-horizontal.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M21 9a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 15 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2z\",\n key: \"1dfntj\"\n }\n ],\n [\"path\", { d: \"M15 3v5a1 1 0 0 0 1 1h5\", key: \"6s6qgf\" }]\n];\nconst StickyNote = createLucideIcon(\"sticky-note\", __iconNode);\n\nexport { __iconNode, StickyNote as default };\n//# sourceMappingURL=sticky-note.mjs.map\n","/**\n * Calendar pattern — the READ MODEL the host supplies, stable for a page\n * load: the practice's resources, catalogue, agenda extras and lookups.\n * It mirrors what the demo once read straight from its fixture module —\n * one property per constant, one method per fixture-backed helper — so\n * the demos hand in their fixtures and the platform island hands in what\n * `/internalApi/...` returned, and the model, panels and surface compute\n * from either without knowing which.\n *\n * Provided once with `<CalendarDataProvider value={data}>`; components\n * read it with `useCalendarData()`, pure model functions take it as an\n * explicit `data` parameter — never a module-level global.\n *\n * Every REQUIRED member is one the shipped runtime actually reads. A\n * member is optional for one of two reasons, and its own doc comment\n * says which: either only the story-only Final State demo\n * (`src/patterns/demos/calendar/`) reads it, so a platform host\n * mounting `CalendarWorkspace` can leave it out; or its ABSENCE is a\n * state the pattern must tell apart from emptiness (`priceLists`), in\n * which case `undefined` means \"we were never told\" and `[]` means\n * \"there is none\" — see `catalogueStateOf` in `calendar.types.ts`.\n */\nimport {\n createContext,\n createElement,\n useContext,\n type ReactNode,\n} from 'react';\nimport type { CalendarResource } from '../../components/calendar';\nimport type { PaletteSwatch } from '../../components/color-picker';\nimport type { AppointmentItem } from '../../components/appointment-card';\nimport type { NotesPanelNote } from '../../components/notes-panel';\nimport type { TasksPanelItem } from '../../components/tasks-panel';\nimport type {\n CalendarAppointmentMeta,\n CalendarBaseEvent,\n CalendarBookingContact,\n CalendarBranch,\n CalendarBusinessHours,\n CalendarDayHours,\n CalendarCare,\n CalendarCareEntry,\n CalendarCareLink,\n CalendarCarePlan,\n CalendarClosure,\n CalendarHistoryEntry,\n CalendarHoliday,\n CalendarOperatorGroup,\n CalendarPatient,\n CalendarPracticeFeatures,\n CalendarPriceList,\n CalendarTaskDetail,\n CalendarWaitingEntry,\n FreeSlotQuery,\n} from './calendar.types';\n/* Type-only: the cycle with `calendar.model` is erased at build. */\nimport type { CalendarFreeSlot } from './calendar.model';\n\n/** What the host has loaded for one local `Y-m-d`. */\nexport type DayLoadState = 'loading' | 'ready' | 'error';\n\nexport interface CalendarData {\n /* ---- resources ------------------------------------------------- */\n chairs: readonly CalendarResource[];\n operators: readonly CalendarResource[];\n /** Operator groups (platform `OperatorGroup`) for the grouped filter. */\n operatorGroups: readonly CalendarOperatorGroup[];\n /** Operators the practice has disabled (platform `isActive === false`). */\n inactiveOperatorIds: readonly string[];\n /** Operator id → local ISO dates the operator is away. */\n operatorAbsences: Record<string, readonly string[]>;\n /** Operator id → absence display title (a sibling map, optional per operator). */\n operatorAbsenceTitles: Record<string, string>;\n /**\n * Appointment colours the host accepts. When omitted, the workspace uses\n * its documented Google-style fallback palette for demos and legacy hosts.\n * A platform host should provide its configured DoctorColor values so a\n * colour selected in the editor always maps back to a writable colour id.\n */\n appointmentPalette?: readonly PaletteSwatch[];\n\n /* ---- calendar shape -------------------------------------------- */\n holidays: readonly CalendarHoliday[];\n /** Practice-closed local ISO dates. */\n closedDates: readonly string[];\n /** JS `getDay()` numbers the practice does not work. Optional: the\n * shipped workspace derives its hidden days from `businessHours` and\n * the weekend toggle; only the Final State demo reads this. */\n nonWorkingDays?: readonly number[];\n businessHours: CalendarBusinessHours;\n /**\n * Per-DATE closed periods — the one member that can say \"shut 13:00–14:00\".\n * `businessHours` holds one range per weekday, so a split shift arrives as\n * its envelope and the lunch closure inside it would read as bookable.\n * Keyed by local `Y-m-d`; each window is minutes from local midnight,\n * `1440` the following midnight, disjoint and ascending. The finder never\n * offers a slot that overlaps one, and the grid washes it on every column\n * of that date. A date without a key is one the host said nothing about:\n * it adds no closure and takes nothing away from `businessHours`.\n * Optional — the demos and hosts without per-date hours leave it out.\n */\n closedIntervals?: Readonly<Record<string, ReadonlyArray<CalendarDayHours>>>;\n /**\n * Per-DATE load state, keyed by local `Y-m-d` — for a host that fills\n * the grid one range at a time. The grid washes every cell of a day\n * that is not `'ready'` and the finder refuses to answer from one,\n * because \"no row here\" and \"no row here YET\" are different answers.\n * ABSENCE and presence differ: omit it and every rendered day is taken\n * as loaded (the shape every host had before this existed); provide it\n * and a date it does not name is NOT ready, so a host that knows its\n * own days must name them all. Optional.\n */\n dayLoadState?: Readonly<Record<string, DayLoadState>>;\n /** The clock every relative label and ledger stamp is pinned to. */\n nowIso: string;\n /** The date the calendar opens on. */\n initialDateIso: string;\n\n /* ---- catalogue ------------------------------------------------- */\n cares: readonly CalendarCare[];\n /** The practice's price lists. THREE states, never two — see\n * `catalogueStateOf`. Omit it (`undefined`) when the host has no\n * care/price-list catalogue to hand over, as the platform island\n * does; `[]` says the practice genuinely has none. Either way the\n * \"From price list\" relation is withheld rather than rendered over\n * nothing, and neither is ever papered over with an invented list. */\n priceLists?: readonly CalendarPriceList[];\n /** Optional: no shipped code reads the flat list — the panels go\n * through `carePlanById` / `openCarePlansForPatient`. */\n carePlans?: readonly CalendarCarePlan[];\n patients: readonly CalendarPatient[];\n /** Optional host typeahead. Omit for client filtering of `patients`.\n * The picker debounces nonblank queries, aborts superseded requests and\n * keeps the host's result order, including matches by phone or number.\n * Before resolving, make returned records available through `patientById`\n * so other patient-dependent fields can resolve the chosen id. Reject\n * failures; an empty array means a successful search with no matches. */\n searchPatients?(\n query: string,\n options: { signal: AbortSignal },\n ): Promise<readonly CalendarPatient[]>;\n /**\n * Optional host free-slot search. Omit it and the finder keeps its\n * in-memory search over the loaded rows; provide it and the panel asks\n * the practice's own finder instead.\n *\n * Called on Search and after every busy-set change — at most one call\n * in flight, and one per background refresh tick while the panel is\n * open. Abort a superseded call through `options.signal`; reject on\n * failure (the panel says so and offers a retry); `[]` is a successful\n * search with nothing free. Slots arrive floored at `nowIso` on\n * whatever step the host's calendar interval implies — the kit names\n * none. `medicalDeviceIds` are the host's own strings, round-tripped\n * untouched, and `operatorIds` / `chairIds` are never empty: the panel\n * publishes the empty answer itself rather than ask about nothing.\n */\n searchFreeSlots?(\n query: FreeSlotQuery,\n options: { signal: AbortSignal },\n ): Promise<readonly CalendarFreeSlot[]>;\n /** The host's LOAD STAMP — a change re-runs the last server search (the\n * platform island hands in `loadedAt.getTime()`). Omit it and the busy\n * set alone triggers the re-search. */\n revision?: number;\n\n /* ---- the agenda's extras, by event id -------------------------- */\n /** The appointments and tasks as the host loaded them, no resource axis. */\n baseEvents: readonly CalendarBaseEvent[];\n /** Event id → appointment extras (patient, operator, chair, care, billing). */\n metaById: Record<string, CalendarAppointmentMeta>;\n /** Event id → the note the patient left on the online booking form. */\n bookingNotes: Record<string, string>;\n /** Event id → what the person typed on the booking website. */\n bookingContacts: Record<string, CalendarBookingContact>;\n /** Task-event id → its chair / operator axis (tasks carry no meta).\n * Optional: the shipped workspace drops tasks at the feed boundary;\n * only the Final State demo, which shows them, reads this. */\n taskAxis?: Record<string, { chairId: string; operatorId: string }>;\n /** Event id → platform-shaped task detail. */\n taskDetails: Record<string, CalendarTaskDetail>;\n /** The waiting list as loaded — the journey seeds its state from it. */\n waitingList: readonly CalendarWaitingEntry[];\n /** Event id → the modification ledger as loaded. Optional: the\n * workspace reads the ledger off `CalendarJourney.history`, which the\n * host seeds however it likes. */\n appointmentHistory?: Record<string, CalendarHistoryEntry[]>;\n\n /* ---- practice facts the panels gate on ------------------------- */\n practiceFeatures: CalendarPracticeFeatures;\n branches: readonly CalendarBranch[];\n /** Care id → the medical devices it needs. */\n careDevices: Readonly<Record<string, readonly string[]>>;\n /** Patient id → required documents still unsigned. */\n unsignedRequiredDocs: Readonly<Record<string, number>>;\n /** Patients with an advanced e-signature (AES) setup. */\n patientsWithAes: ReadonlySet<string>;\n /** Appointment id → the deposit paid online when booking. */\n paidOnline: Readonly<Record<string, number>>;\n /** Appointment id → the phone typed on the booking site. */\n bookingPhones: Readonly<Record<string, string>>;\n\n /* ---- lookups --------------------------------------------------- */\n patientById(id: string): CalendarPatient | undefined;\n patientNotes(patientId: string): NotesPanelNote[];\n patientAppointments(patientId: string): AppointmentItem[];\n patientTasks(patientId: string): TasksPanelItem[];\n careById(id: string): CalendarCare | undefined;\n carePlanById(id: string): CalendarCarePlan | undefined;\n /** Optional: no shipped code calls it — the editor links through\n * `openCarePlansForPatient`, the details panel through\n * `carePlanById`. */\n carePlansForPatient?(patientId: string): CalendarCarePlan[];\n /** Plans the editor may link to: not discarded or closed, with undone lines. */\n openCarePlansForPatient(patientId: string): CalendarCarePlan[];\n /** The care entries a link resolves to — plan lines in plan order, or\n * the price-list picks. Unknown ids are dropped. */\n careEntriesFromLink(link: CalendarCareLink): CalendarCareEntry[];\n /** Closed dates plus holidays, unless the practice stays open on them. */\n practiceClosedOn(dateIso: string): boolean;\n /** Why a date (or, given an operator, that column) cannot take a\n * booking — closed > holiday > absence; null when it can. */\n closureOn(dateIso: string, operatorId?: string): CalendarClosure | null;\n /** Local dates in [from, to] with practice hours that are neither\n * closed nor a holiday. */\n openDatesBetween(from: Date, to: Date): string[];\n /** Waiting-since instant for an entry (platform `createdAt`). */\n waitingSinceIso(entry: CalendarWaitingEntry): string;\n}\n\nconst CalendarDataContext = createContext<CalendarData | null>(null);\n\n/** Wrap whatever renders the calendar's panels and surface — one provider\n * per subtree is fine (a rail renders its panels outside the page tree). */\nexport function CalendarDataProvider({\n value,\n children,\n}: {\n value: CalendarData;\n children?: ReactNode;\n}) {\n return createElement(CalendarDataContext.Provider, { value }, children);\n}\n\nexport function useCalendarData(): CalendarData {\n const data = useContext(CalendarDataContext);\n if (!data) {\n throw new Error(\n 'useCalendarData: render inside a <CalendarDataProvider value={…}>',\n );\n }\n return data;\n}\n","/**\n * Calendar pattern — the DOMAIN TYPES and the pure helpers over them:\n * patient, phone, care, care entry, care link, care plan (+ entry), price\n * list, sign channel / document, appointment meta, task detail, base\n * event, booking contact, business hours, closure, holiday, operator\n * group / filter group, waiting entry, history entry, practice features\n * and branch. Nothing here reads fixture data: every helper takes what it\n * needs as an argument, so the demos and the platform host share one\n * vocabulary. The read model built from these lives in `calendar.data.ts`.\n *\n * Type names keep their `Demo*` prefix for now — a later sweep renames\n * them `Calendar*` in one go.\n */\nimport type {\n CalendarEvent,\n CalendarEventStatus,\n CalendarResource,\n} from '../../components/calendar';\nimport type { CarePlanState } from '../../components/_shared/entity-card';\nimport type { SignatureParty } from '../../components/signature-status-chip';\n\n/** Platform `DoctorPatientPhoneNumber` carries a free-text label; the\n * demo fixes the vocabulary so the printed call sheet can localise it. */\nexport type CalendarPhoneLabel = 'mobile' | 'home' | 'work';\n\nexport interface CalendarPhoneNumber {\n label: CalendarPhoneLabel;\n number: string;\n}\n\n/** One highlighted anamnesis answer, as the platform's details dialog\n * lists it: the question, the Si/No, the free answer and the interview\n * date. Texts are display strings — the host localises them. */\nexport interface CalendarAnamnesisAnswer {\n question: string;\n yes: boolean;\n answer?: string;\n interviewIso: string;\n}\n\n/**\n * A patient as the HOST knows them. Only the identity — `id` and `name` —\n * is required: a host whose appointment feed carries a patient id and a\n * display name and nothing else supplies exactly those two, and every\n * reader below treats each remaining field as \"the host did not tell us\".\n *\n * The rule for a reader: never render a row, chip or label that asserts a\n * value for a field the host omitted — an empty fiscal code printed under\n * a \"Fiscal code\" label is a claim about the record, not a blank. Omit the\n * row; where every row of a section would go, omit the section.\n */\nexport interface CalendarPatient {\n id: string;\n name: string;\n dobIso?: string;\n phone?: string;\n email?: string;\n /* Notify-channel capability, absent = capable (the platform\n patient's smsEnabled/emailEnabled). The\n move-confirm dialog defaults its notify checkboxes from\n channel presence AND these flags. */\n smsEnabled?: boolean;\n emailEnabled?: boolean;\n city?: string;\n /** Optional profile photo — Avatar falls back to the initials circle. */\n avatarSrc?: string;\n /* Full patient-record slice (the platform \"scheda paziente\") — the\n Patient details rail tab renders these. All synthetic. */\n sex?: 'f' | 'm';\n fiscalCode?: string;\n address?: string;\n province?: string;\n postalCode?: string;\n patientSinceIso?: string;\n lastVisitIso?: string;\n priceList?: string;\n discountPct?: number;\n unpaidAmount?: number;\n allergies?: string;\n diagnosis?: string;\n /* Anamnesis attention counts (the platform popover's warnings):\n answers the practice flagged, and answers past their validity. */\n highlightedAnamnesisCount?: number;\n expiredAnamnesisCount?: number;\n /** The highlighted answers themselves — the platform details dialog\n * lists these, the popover only counts them. */\n highlightedAnamnesisAnswers?: CalendarAnamnesisAnswer[];\n /** Every labelled number for the call sheet; absent = `phone` is the\n * mobile (see `patientPhones`). */\n phones?: CalendarPhoneNumber[];\n}\n\n/** A public holiday (platform `GetHolidaysService`): a local ISO date plus\n * its display name — the host localises it (the platform's holiday\n * service already returns a named day). */\nexport interface CalendarHoliday {\n dateIso: string;\n name: string;\n}\n\n/** Practice-level calendar flags (platform `keep_open_on_holidays`). */\nexport interface CalendarPractice {\n openOnHolidays: boolean;\n}\n\n/** An operator group (platform `OperatorGroup`) — the operator filter\n * lists members under their group with a per-group select-all. */\nexport interface CalendarOperatorGroup {\n id: string;\n name: string;\n operatorIds: readonly string[];\n}\n\n/** One section of the grouped operator filter. */\nexport interface CalendarOperatorFilterGroup {\n id: string;\n name: string;\n operators: CalendarResource[];\n}\n\n/** Virtual bucket id for operators outside every group (platform id 0). */\nexport const OPERATOR_GROUP_NONE_ID = 'grp-none';\n\n/**\n * The platform's `GetGroupedOperatorService` rule: unknown member ids are\n * dropped, empty groups omitted, ungrouped operators fall into the virtual\n * bucket (only when it has members), members sort active-first then by\n * `sequenceNumber`, and every group — bucket included — sorts by name in\n * the given locale.\n */\nexport function buildOperatorFilterGroups(args: {\n groups: readonly CalendarOperatorGroup[];\n operators: readonly CalendarResource[];\n inactiveIds: readonly string[];\n withoutGroupLabel: string;\n locale: string;\n}): CalendarOperatorFilterGroup[] {\n const byId = new Map(args.operators.map((o) => [o.id, o]));\n const inactive = new Set(args.inactiveIds);\n const rank = (o: CalendarResource): number =>\n o.sequenceNumber ?? Number.MAX_SAFE_INTEGER;\n const sortMembers = (members: CalendarResource[]): CalendarResource[] =>\n [...members].sort((a, b) => {\n const activeDelta =\n Number(inactive.has(a.id)) - Number(inactive.has(b.id));\n return activeDelta !== 0 ? activeDelta : rank(a) - rank(b);\n });\n const grouped = new Set<string>();\n const sections: CalendarOperatorFilterGroup[] = [];\n for (const group of args.groups) {\n const members = group.operatorIds\n .map((id) => byId.get(id))\n .filter((o): o is CalendarResource => o !== undefined);\n if (members.length === 0) continue;\n members.forEach((o) => grouped.add(o.id));\n sections.push({\n id: group.id,\n name: group.name,\n operators: sortMembers(members),\n });\n }\n const ungrouped = args.operators.filter((o) => !grouped.has(o.id));\n if (ungrouped.length > 0) {\n sections.push({\n id: OPERATOR_GROUP_NONE_ID,\n name: args.withoutGroupLabel,\n operators: sortMembers(ungrouped),\n });\n }\n return sections.sort((a, b) => a.name.localeCompare(b.name, args.locale));\n}\n\n/** One care/treatment recorded on an appointment. Catalogued when `careId`\n * resolves in the host's care catalogue; ad hoc otherwise (a typed name, no code). */\nexport interface CalendarCareEntry {\n careId?: string;\n name: string;\n /** Tariff code — catalogue entries only. */\n code?: string;\n /** FDI two-digit tooth codes, e.g. ['26']. */\n elements?: string[];\n /** Phase labels, rendered as [a, b] after the name. */\n phases?: string[];\n}\n\n/** Platform `appointmentCareVisualization` — disabled / name / code /\n * name_and_code: how the card describes its cares. */\nexport type CareDescriptionMode = 'off' | 'name' | 'code' | 'nameCode';\n\n/** Platform `color_association_type_*`: which colour a NEW or MOVED\n * appointment inherits. Stored colours never repaint on a switch. */\nexport type ColorAssociation = 'care' | 'operator' | 'chair';\n\n/**\n * Platform care/treatment slice for the find-free-slots tool: picking a\n * care derives the slot duration, the eligible operators/chairs, and the\n * appointment colour (platform `FreeSlotController` care-driven search).\n */\nexport interface CalendarCare {\n id: string;\n name: string;\n /** Tariff code (Italian price-list style) — unique per care. */\n code: string;\n durationMin: number;\n operatorIds: string[];\n chairIds: string[];\n colorHex: string;\n priceCents: number;\n /** Catalogue phases (platform `care.carePhases`) — a price-list row\n * books a subset of them, exactly as a plan line does. */\n phases?: string[];\n}\n\n/**\n * The card's care line (platform `getAppointmentNameSuffixAndPopoverName`):\n * the free-text description leads, the cares follow joined with ', ',\n * phases in [brackets]. Under Code an uncoded ad hoc care shows its name\n * (the platform prints a blank). `undefined` when nothing remains.\n */\nexport function careSuffix(\n input: { description?: string; cares?: CalendarCareEntry[] },\n mode: CareDescriptionMode,\n): string | undefined {\n const phases = (e: CalendarCareEntry): string =>\n e.phases && e.phases.length > 0 ? ` [${e.phases.join(', ')}]` : '';\n const describe = (e: CalendarCareEntry): string => {\n switch (mode) {\n case 'name':\n return `${e.name}${phases(e)}`;\n case 'code':\n return e.code ?? e.name;\n case 'nameCode':\n return `${e.name}${e.code ? ` (${e.code})` : ''}${phases(e)}`;\n default:\n return '';\n }\n };\n const careBlock =\n mode === 'off' ? '' : (input.cares ?? []).map(describe).join(', ');\n const parts = [input.description?.trim() ?? '', careBlock].filter(\n (p) => p.length > 0,\n );\n return parts.length > 0 ? parts.join(' / ') : undefined;\n}\n\n/** The always-on derived label — what `meta.care` and `event.suffix`\n * carry regardless of the user's care-description setting. */\nexport function careLabel(cares: CalendarCareEntry[]): string {\n return careSuffix({ cares }, 'name') ?? '';\n}\n\n/** What `associationColor` resolves its ids against — the practice's\n * operators, chairs and care catalogue. `CalendarData` satisfies it. */\nexport interface AssociationColorSources {\n operators: readonly CalendarResource[];\n chairs: readonly CalendarResource[];\n cares: readonly CalendarCare[];\n}\n\n/** The colour an appointment inherits under an association (platform\n * `determineColorIdForResource`): the operator's, the chair's, or the\n * first catalogued care's. `undefined` = keep whatever it has. */\nexport function associationColor(\n association: ColorAssociation,\n ctx: { operatorId?: string; chairId?: string; cares?: CalendarCareEntry[] },\n sources: AssociationColorSources,\n): string | undefined {\n switch (association) {\n case 'operator':\n return sources.operators.find((o) => o.id === ctx.operatorId)?.color;\n case 'chair':\n return sources.chairs.find((c) => c.id === ctx.chairId)?.color;\n case 'care': {\n const first = ctx.cares?.find((e) => e.careId);\n return first\n ? sources.cares.find((c) => c.id === first.careId)?.colorHex\n : undefined;\n }\n default:\n return undefined;\n }\n}\n\n/** A practice price list (platform `PriceList`). */\nexport interface CalendarPriceList {\n id: string;\n name: string;\n}\n\n/** One treatment line of a care plan (platform `CarePlanEntry`). */\nexport interface CalendarCarePlanEntry {\n id: string;\n careId: string;\n /** FDI two-digit tooth codes. */\n elements?: string[];\n done: boolean;\n executionDateIso?: string;\n billed?: boolean;\n /** Phase labels — an appointment may book a subset of them. */\n phases?: string[];\n /** Overrides the care's catalogue duration. */\n durationMin?: number;\n /** Overrides the care's catalogue price. */\n priceCents?: number;\n}\n\n/** A patient's care plan (platform `CarePlan`) in the kit CarePlanCard's\n * state vocabulary; amounts in cents. */\nexport interface CalendarCarePlan {\n id: string;\n patientId: string;\n number: string;\n name: string;\n state: CarePlanState;\n acceptedIso?: string;\n amounts?: {\n priceCents?: number;\n billedAmountCents?: number;\n dueCents?: number;\n };\n entries: CalendarCarePlanEntry[];\n}\n\n/** What a saved appointment carries about where its treatments came\n * from (platform `carePlanId` + entry ids, or price-list picks). */\nexport type CalendarCareLink =\n | {\n kind: 'plan';\n planId: string;\n /** Plan order, never tick order. */\n entryIds: string[];\n phasesByEntry?: Record<string, string[]>;\n }\n | {\n kind: 'priceList';\n priceListId: string;\n /** `phases` are the booked subset of the care's catalogue phases;\n * `billed` locks the row (the platform refuses to touch an\n * already-invoiced treatment). */\n items: Array<{\n careId: string;\n priceCents: number;\n phases?: string[];\n billed?: boolean;\n }>;\n };\n\n/** Channel a signature request went out on (platform `requiredObjectsSignMode`). */\nexport type CalendarSignChannel = 'sms' | 'email';\n\n/** One document to sign on an appointment — each party's standing. */\nexport interface CalendarSignDocument {\n id: string;\n name: string;\n operator: SignatureParty;\n patient: SignatureParty;\n}\n\n/**\n * Per-appointment extras the CalendarEvent shape does not carry — the\n * details panel and the peek card read these by event id.\n */\nexport interface CalendarAppointmentMeta {\n patientId: string;\n /** Absent = nobody assigned yet — a Backlog \"No operator\" item. */\n operatorId?: string;\n chairId: string;\n /** Derived care label — `careLabel(cares)`, tasks keep the task title.\n * Also the event's always-on `suffix`. */\n care: string;\n /** The care entries the label derives from (tasks: empty). */\n cares: CalendarCareEntry[];\n /** Outstanding billable amount in EUR, when any. */\n billableAmount?: number;\n /** Where the cares came from — a care plan's lines or a price list. */\n careLink?: CalendarCareLink;\n /** Telehealth session to join (platform `telehealthSessionId`). */\n telehealthSessionCode?: string;\n /** Documents attached for signature, with each party's standing. */\n documentsToSign?: CalendarSignDocument[];\n /** Channel the signature request already went out on, if any. */\n signRequestedVia?: CalendarSignChannel;\n /** When the online booking was made (platform `createdAt`). */\n bookedAtIso?: string;\n /** Note the patient typed on the booking form. */\n bookingNote?: string;\n}\n\n/**\n * Platform-shaped task detail (the `TaskDTO` slice the legacy task page\n * shows) — the demo's task-details rail panel reads these by event id.\n */\nexport interface CalendarTaskDetail {\n /** SystemTaskType key, or 'custom' with `typeLabel` (platform TaskType). */\n type: 'recall' | 'payment' | 'collection' | 'other' | 'custom';\n /** Practice-defined type name — custom types only. */\n typeLabel?: string;\n /** Free-text body (platform `note`). */\n note?: string;\n /** Lifecycle flag (platform `done`). */\n done: boolean;\n /** Assignee display name (platform `practiceUser`). */\n assigneeName?: string;\n /** Linked company name (platform `doctorCompany`). */\n companyName?: string;\n /** Provenance — created by hand or by a workflow automation. */\n createdBy: 'user' | 'workflow';\n /** Creator display name when `createdBy === 'user'`. */\n createdByName?: string;\n createdAtIso: string;\n}\n\n/** Base events WITHOUT `resourceId` — the surface maps each event onto the\n * chair or the operator axis depending on the active view. */\nexport interface CalendarBaseEvent {\n event: CalendarEvent;\n meta: CalendarAppointmentMeta | null; // null for the closed-day block\n /** Care entries even without meta (online bookings); tasks carry []. */\n cares: CalendarCareEntry[];\n}\n\n/**\n * What an online booking actually carries (platform parity): the details\n * the person typed on the booking website — name, SMS-verified phone,\n * email and a free-text note — but NO patient record. Assigning one is\n * the triage job (the platform's `BookingPatientDetails` +\n * `appointment_form.search_patient_for_booking_appointment_below`).\n */\nexport interface CalendarBookingContact {\n typedName: string;\n phone: string;\n email: string;\n note: string;\n /** When the booking was made (platform `createdAt`). */\n bookedAtIso: string;\n}\n\n/** One contiguous working range, minutes from local midnight. */\nexport interface CalendarDayHours {\n startMin: number;\n endMin: number;\n}\n\n/**\n * Weekly hours keyed by JS `getDay()` (0 = Sunday … 6 = Saturday). A\n * missing weekday means closed all day; one range per day is the demo's\n * deliberate simplification (the platform allows split shifts).\n */\nexport type CalendarWeeklyHours = Partial<Record<number, CalendarDayHours>>;\n\nexport interface CalendarBusinessHours {\n /** The practice's own opening hours. */\n practice: CalendarWeeklyHours;\n /** Per-operator weekly hours — intersect with `practice` when used. */\n operators: Record<string, CalendarWeeklyHours>;\n}\n\n/** Why a date (or, given an operator, that column) cannot take a booking.\n * Precedence closed > holiday > absence: a practice-level closure applies\n * to every column, so it wins over one operator's day off. */\nexport type CalendarClosure =\n | { kind: 'closed' }\n | { kind: 'holiday'; name: string }\n | { kind: 'absence'; operatorId: string; title?: string };\n\n/**\n * Platform `WaitingListEntry` shape — exactly ONE of the three mutually\n * exclusive connections per entry (the platform enforces this):\n * - `appointmentId`: the patient already HAS an appointment; the entry\n * means \"bring it forward if a slot frees up\" (schedule = move mode);\n * - `patientId` (+ optional description): waiting for a first free slot\n * (schedule = create mode, pre-seeded with operator/colour);\n * - `description` only: a free-text hold with no patient linked.\n * `operatorId` and `colorHex` (platform `colorId`) are the DEFAULTS the\n * future appointment is created with, not display decoration.\n */\nexport interface CalendarWaitingEntry {\n id: string;\n patientId?: string;\n appointmentId?: string; // into APPOINTMENT_SPECS ids\n description?: string;\n operatorId?: string;\n colorHex?: string;\n createdDay: number; // offset from the demo Monday (negative = before)\n /** Story-only: the patient's number can receive WhatsApp messages. */\n whatsappCapable?: boolean;\n /** Host: the number WhatsApp can reach (platform `whatsappPhoneNumber`).\n * Set, it IS the WhatsApp number and `whatsappCapable` is not read. */\n whatsappPhoneNumber?: string;\n /** The row's photo (its own patient's, or the linked appointment's)\n * when the host's `patientById` record carries no `avatarSrc`. */\n patientAvatarUrl?: string;\n}\n\nexport type CalendarHistoryKind =\n | 'created'\n | 'moved'\n | 'resized'\n | 'status'\n | 'edited'\n | 'deleted'\n | 'confirmedByPatient';\n\n/** Form fields an edit can touch (the platform's audit vocabulary). */\nexport type CalendarHistoryField =\n | 'patient'\n | 'type'\n | 'care'\n | 'operator'\n | 'chair'\n | 'colour'\n | 'time'\n | 'duration';\n\n/** One ledger line — who did what to the appointment, and when. */\nexport type CalendarHistoryEntry = {\n id: string;\n atIso: string;\n actor: string;\n} & (\n | { kind: 'created' }\n | { kind: 'moved'; fromIso: string; toIso: string }\n | { kind: 'resized'; fromMin: number; toMin: number }\n | { kind: 'status'; from: CalendarEventStatus; to: CalendarEventStatus }\n | { kind: 'edited'; fields: CalendarHistoryField[] }\n | { kind: 'deleted' }\n /** The patient confirmed by link; the host sends `actor: ''`. */\n | { kind: 'confirmedByPatient' }\n);\n\n/** Every labelled phone number — the single `phone` is the mobile when a\n * patient carries no explicit list (platform prints each label: number).\n * A patient the host supplied without either has no numbers to print,\n * which is not the same as one labelled blank: the list comes back empty\n * and the caller omits the block. */\nexport function patientPhones(patient: CalendarPatient): CalendarPhoneNumber[] {\n if (patient.phones) return patient.phones;\n return patient.phone ? [{ label: 'mobile', number: patient.phone }] : [];\n}\n\n/* ------------------------------------------------------------------ */\n/* Three states, never two */\n/* */\n/* The whole half-known-patient contract lives in this block, so no */\n/* reader has to re-derive it and no two readers can derive it */\n/* differently. Three states, and every panel below distinguishes all */\n/* three: */\n/* */\n/* A an id we could NOT resolve -> \"we did not load this patient\" */\n/* NEVER \"no patient assigned\" / \"no patient linked\". */\n/* B a field ABSENT from a record we did get (`undefined`) */\n/* -> \"we were not told\". NEVER \"none on file\". */\n/* C a field PRESENT and empty (`''`) -> \"none on file\" is true. */\n/* */\n/* Two rules fall out. Whether a thing EXISTS — is a patient assigned, */\n/* is an entry linked, does a filter match — is decided by the ID */\n/* (`PatientRef.assigned`), never by whether the record resolved. */\n/* Whether a CHANNEL is usable is decided by `patientChannelState`, */\n/* which answers `unknown` (not `none`) whenever we were not told. */\n/* ------------------------------------------------------------------ */\n\n/**\n * A patient as the calendar can see them at one point: the id a row,\n * an event or a waiting entry carries, plus the record if the host's\n * `patientById` could answer.\n */\nexport interface PatientRef {\n /** The id, as a string. `''` — and ONLY `''` — means nobody is booked. */\n readonly id: string;\n /** The record, when the host could resolve the id. */\n readonly record?: CalendarPatient;\n /** Someone is booked here, resolved or not. The existence test. */\n readonly assigned: boolean;\n /** Someone is booked and their record did not load — state A. */\n readonly unresolved: boolean;\n}\n\n/** A patient id as a string, `''` when there is none. A host id of `0`\n * IS an id, so the test is `!= null` and never truthiness. */\nexport function patientIdOf(id: string | number | null | undefined): string {\n return id == null ? '' : String(id);\n}\n\n/** Pair the id a row carries with whatever the host made of it. */\nexport function patientRefOf(\n id: string | number | null | undefined,\n record: CalendarPatient | undefined,\n): PatientRef {\n const key = patientIdOf(id);\n const found = key ? record : undefined;\n return {\n id: key,\n record: found,\n assigned: key !== '',\n unresolved: key !== '' && found === undefined,\n };\n}\n\n/** What to CALL this patient: the record's name, else the title the row\n * already carries, else the caller's localised \"record not loaded\".\n * Never blank — a blank name renders an initials-less avatar — and\n * never the \"no patient assigned\" of an unbooked slot. */\nexport function patientRefName(\n ref: PatientRef,\n rowTitle: string | undefined,\n notLoadedLabel: string,\n): string {\n return (\n [ref.record?.name, rowTitle].find(\n (candidate) => candidate !== undefined && candidate.trim() !== '',\n ) ?? notLoadedLabel\n );\n}\n\n/** Why a notify / signing channel is or is not usable for a patient. */\nexport type PatientChannelState =\n /** On file, and the patient takes messages there. */\n | 'ready'\n /** On file, and the patient opted this channel out. */\n | 'optedOut'\n /** The record loaded and really carries nothing here — state C, the\n * only state in which \"none on file\" may be said. */\n | 'none'\n /** We were not told: no record at all, or the record omits the field\n * — states A and B. Says nothing about what the practice holds. */\n | 'unknown';\n\n/** The state of one channel for one patient reference. */\nexport function patientChannelState(\n ref: PatientRef,\n channel: 'sms' | 'email',\n): PatientChannelState {\n const record = ref.record;\n if (!record) return 'unknown';\n const value = channel === 'sms' ? record.phone : record.email;\n if (value === undefined) return 'unknown';\n if (value.trim() === '') return 'none';\n const optIn = channel === 'sms' ? record.smsEnabled : record.emailEnabled;\n return optIn === false ? 'optedOut' : 'ready';\n}\n\n/** A channel the kit can hand a destination to right now — the test for\n * seeding a checkbox ON, or for defaulting a sign mode to it. */\nexport function channelReady(state: PatientChannelState): boolean {\n return state === 'ready';\n}\n\n/** A channel the kit must leave OFFERED. `unknown` belongs here: the\n * host may well succeed on send, and disabling the control would claim\n * the practice holds nothing — a claim about a record we never saw. */\nexport function channelOfferable(state: PatientChannelState): boolean {\n return state === 'ready' || state === 'unknown';\n}\n\n/** The reason a channel is not offered — `null` when it IS offered, so\n * a caller never has to invent a string for a state it cannot reach. */\nexport function channelReasonKey(\n state: PatientChannelState,\n keys: { optedOut: string; none: string },\n): string | null {\n if (state === 'optedOut') return keys.optedOut;\n if (state === 'none') return keys.none;\n return null;\n}\n\n/* ------------------------------------------------------------------ */\n/* CATALOGUE PRESENCE — the same three states, one level up. */\n/* */\n/* A host-supplied catalogue (`CalendarData.priceLists`) answers the */\n/* SAME question `patientChannelState` answers for a channel, about a */\n/* collection rather than a field: */\n/* absent (`undefined`) -> `unknown`, \"we were never told\". */\n/* present and empty -> `none`, \"the practice really has none\". */\n/* present with items -> `ready`. */\n/* */\n/* One decision differs from a notify channel, deliberately. A channel */\n/* we know nothing about stays OFFERED, because the host may still */\n/* succeed on send. A catalogue we have nothing for cannot be offered */\n/* on the same optimism: the picker would have no options and no id to */\n/* default to, so `unknown` and `none` BOTH withhold the control */\n/* (1.17.0's rule: withhold, do not explain). The states stay apart */\n/* anyway so that no code can read an empty array as a claim about */\n/* what the practice holds, and so a host can tell the two apart. */\n/* ------------------------------------------------------------------ */\n\n/** Whether a host-supplied catalogue can back a control. */\nexport type CatalogueState =\n /** At least one entry — a picker can be filled and defaulted. */\n | 'ready'\n /** The host handed us the collection and it is empty: the practice\n * really has none. The only state in which \"none\" may be said. */\n | 'none'\n /** The host never handed us the collection. Says nothing about what\n * the practice holds. */\n | 'unknown';\n\n/** The state of one host-supplied catalogue. Takes the raw member, so\n * `undefined` reaches it intact — never `?? []` at the call site. */\nexport function catalogueStateOf(\n items: readonly unknown[] | undefined,\n): CatalogueState {\n if (items === undefined) return 'unknown';\n return items.length === 0 ? 'none' : 'ready';\n}\n\n/** A catalogue that can back a picker right now. `unknown` is NOT\n * offerable here — unlike `channelOfferable`, see the note above. */\nexport function catalogueUsable(state: CatalogueState): boolean {\n return state === 'ready';\n}\n\n/** Practice-level toggles the platform gates the editor and popover on. */\nexport interface CalendarPracticeFeatures {\n /** `FIND_FREE_SLOTS_BY_CARE` — devices per care, the device line. */\n findFreeSlotsByCare: boolean;\n /** `RECURRING_PRICE_LIST_CARE_PLAN_ENTRIES` — the care-plan cleanup. */\n recurringPriceListCarePlanEntries: boolean;\n /** Payment automation active on the practice (no upsell when true). */\n paymentAutomation: boolean;\n /** `FeatureToggle::PAU_UPSELL` — show the upsell hook when PAU is off. */\n pauUpsell: boolean;\n}\n\n/** A practice branch (platform `CarePlanBranch`) — the select shows only\n * when the practice has more than one. */\nexport interface CalendarBranch {\n id: string;\n /** Display name — the host localises it. */\n name: string;\n}\n\n/**\n * One free-slot question for a host that answers SERVER-side\n * (`CalendarData.searchFreeSlots`). The scope is already narrowed to what\n * the chosen care makes eligible, so the host asks its own finder for\n * exactly this and nothing wider. `from` / `to` are local wall-clock\n * instants. The STEP is the host's — the kit names none, so the server\n * answers on whatever grid the practice's calendar interval implies.\n */\nexport interface FreeSlotQuery {\n /** Search from here — clamped to midnight of the host's `nowIso` day. */\n from: Date;\n /** Last date to look at (inclusive). */\n to: Date;\n /** The appointment length the answer must fit. */\n durationMin: number;\n /** Operator ids in scope — never empty. */\n operatorIds: readonly string[];\n /** Chair ids in scope — never empty. */\n chairIds: readonly string[];\n /** The care the search was scoped to, when one was chosen. */\n careId?: string;\n /** The host's own medical-device strings, round-tripped untouched. */\n medicalDeviceIds?: readonly string[];\n}\n","/**\n * Calendar pattern — remembered per-user preferences.\n *\n * SHIPPED runtime module of the calendar pattern: everything exported\n * here is public API of `@alfadocs/ui-kit/patterns/calendar`.\n *\n * The platform stores each user's calendar view and chair/operator\n * selections server-side (`DoctorAddressUser.calendarView`,\n * `calendarSelectedChairIds`, `calendarSelectedOperatorIds`, written by\n * `setCalendarView` and the events-fetch side effect) and its display\n * knobs in per-user settings. `CalendarPreferenceAdapter` is that seam:\n * a host passes `CalendarWorkspace` a `preferences` adapter backed by\n * whatever it already has — a PATCH-on-change client, `localStorage`,\n * anything with get / set / clear — and the workspace, its surface and\n * its cog all read and write through it.\n *\n * The default is `memoryPreferenceAdapter`, a module-level map: it\n * survives remounts, re-renders and locale switches within one page\n * load and resets on reload. Deliberately NOT `localStorage` and not\n * the kit's `usePersistentState` — an unconfigured host (and every\n * Storybook story) must not leak one mount's selections into the next,\n * or into Chromatic. A host that wants durable preferences supplies the\n * adapter.\n *\n * The adapter validates nothing; each call site passes a `read` guard,\n * so a stale or foreign stored shape falls back to the default rather\n * than leaking into render.\n */\nimport {\n useCallback,\n useState,\n type Dispatch,\n type SetStateAction,\n} from 'react';\n\n/** The per-user preference store — the platform's server-side seam. */\nexport interface CalendarPreferenceAdapter {\n get(key: string): unknown;\n set(key: string, value: unknown): void;\n clear(): void;\n}\n\nconst store = new Map<string, unknown>();\n\n/** Session-scoped, per-reload store — the default adapter. */\nexport const memoryPreferenceAdapter: CalendarPreferenceAdapter = {\n get: (key) => store.get(key),\n set: (key, value) => {\n store.set(key, value);\n },\n clear: () => {\n store.clear();\n },\n};\n\n/** Forget everything in the default adapter — the tests' `afterEach`. */\nexport function resetCalendarPreferences(): void {\n memoryPreferenceAdapter.clear();\n}\n\n/**\n * The storage keys the workspace remembers, in one place.\n *\n * The VALUES are load-bearing: they are what is already sitting in every\n * host store and browser that has run this workspace. Renaming a key\n * here silently forgets that user's view, weekend choice, chair and\n * operator selections and cog settings — change a value only with a\n * migration. The member names are free to change; the strings are not.\n */\nexport const CALENDAR_PREFERENCE_KEYS = {\n view: 'calendarWorkspace.view',\n display: 'calendarWorkspace.display',\n showWeekends: 'calendarWorkspace.showWeekends',\n chairIds: 'calendarWorkspace.chairIds',\n operatorIds: 'calendarWorkspace.operatorIds',\n} as const;\n\n/**\n * `useState` whose value is remembered through the adapter. `read`\n * validates the stored value — a stale or foreign shape falls back to\n * `defaultValue` rather than leaking into render. Writes happen on set,\n * never on mount, so merely opening a story remembers nothing.\n */\nexport function usePersistedPreference<T>(\n key: string,\n defaultValue: T | (() => T),\n read: (raw: unknown) => T | undefined,\n adapter: CalendarPreferenceAdapter = memoryPreferenceAdapter,\n): [T, Dispatch<SetStateAction<T>>] {\n const [value, setValue] = useState<T>(() => {\n const remembered = read(adapter.get(key));\n if (remembered !== undefined) return remembered;\n return typeof defaultValue === 'function'\n ? (defaultValue as () => T)()\n : defaultValue;\n });\n const set = useCallback<Dispatch<SetStateAction<T>>>(\n (action) => {\n /* The write rides the updater so functional updates see the latest\n value; a repeated run only re-sets the same map entry. */\n setValue((prev) => {\n const next =\n typeof action === 'function'\n ? (action as (previous: T) => T)(prev)\n : action;\n adapter.set(key, next);\n return next;\n });\n },\n [adapter, key],\n );\n return [value, set];\n}\n\n/* ---- validate-on-read helpers ------------------------------------ */\n\n/** One of a closed set of string literals, else undefined. */\nexport function readEnum<T extends string>(\n allowed: readonly T[],\n): (raw: unknown) => T | undefined {\n return (raw) =>\n typeof raw === 'string' && (allowed as readonly string[]).includes(raw)\n ? (raw as T)\n : undefined;\n}\n\nexport function readBoolean(raw: unknown): boolean | undefined {\n return typeof raw === 'boolean' ? raw : undefined;\n}\n\n/**\n * A remembered id selection, kept to the ids that still exist (a retired\n * chair or operator drops out silently). Any non-array is rejected; an\n * empty array is a real \"nothing selected\" choice.\n */\nexport function readIdList(\n known: ReadonlyArray<{ id: string }>,\n): (raw: unknown) => string[] | undefined {\n const knownIds = new Set(known.map((item) => item.id));\n return (raw) => {\n if (!Array.isArray(raw)) return undefined;\n const ids: string[] = [];\n for (const item of raw) {\n if (\n typeof item === 'string' &&\n knownIds.has(item) &&\n !ids.includes(item)\n ) {\n ids.push(item);\n }\n }\n return ids;\n };\n}\n","/**\n * Calendar demo — the pure model: row and display types, the editor's\n * prefill / draft shapes, recurrence, the history ledger, the Backlog\n * queue, closures and availability shading, the print-sheet builder and\n * the free-slot search. No React, no i18n lookups (`closureReason`\n * takes the caller's `t`). Shared by the Final State (rail) demo and the\n * Increment 1 workspace, so both compute from one source. Every read of\n * practice data goes through the explicit `data: CalendarData` parameter\n * — the host supplies it, the model never reaches for a module global.\n */\nimport type { TFunction } from 'i18next';\nimport { Ban, Check, Clock, Stethoscope, ThumbsUp, UserX } from 'lucide-react';\nimport {\n type CalendarEvent,\n type CalendarEventStatus,\n type CalendarResource,\n} from '../../components/calendar';\nimport { GOOGLE_CALENDAR_PALETTE } from '../../components/color-picker';\nimport { signatureStatusOf } from '../../components/signature-status-chip';\nimport type { WorkflowStatusTone } from '../../components/workflow-status';\nimport type { CalendarData } from './calendar.data';\nimport {\n type CareDescriptionMode,\n type ColorAssociation,\n type CalendarBaseEvent,\n type CalendarBookingContact,\n type CalendarCareEntry,\n type CalendarCareLink,\n type CalendarClosure,\n type CalendarDayHours,\n type CalendarHistoryEntry,\n type CalendarHistoryField,\n type CalendarPatient,\n type CalendarPhoneNumber,\n type CalendarSignDocument,\n type CalendarWaitingEntry,\n type CatalogueState,\n type PatientRef,\n associationColor,\n careSuffix,\n catalogueStateOf,\n patientIdOf,\n patientPhones,\n patientRefOf,\n} from './calendar.types';\nimport { readBoolean, readEnum, readIdList } from './calendar.preferences';\n\n/* ------------------------------------------------------------------ */\n/* Shared bits */\n/* ------------------------------------------------------------------ */\n\n/* Status → ui-namespace key (the kit's own localised status labels). */\nexport const STATUS_UI_KEY: Record<CalendarEventStatus, string> = {\n confirmed: 'calendar.status.confirmed',\n waiting: 'calendar.status.waiting',\n in_care: 'calendar.status.inCare',\n done: 'calendar.status.done',\n cancelled: 'calendar.status.cancelled',\n absent: 'calendar.status.absent',\n};\n\nexport interface CalendarRow {\n event: CalendarEvent;\n chairId?: string;\n operatorId?: string;\n /** Set on every occurrence of a repeating series. */\n series?: CalendarSeries;\n /** Care entries — the card's care line derives from these per cog mode. */\n cares?: CalendarCareEntry[];\n /** Free-text description (platform `name`); fixtures carry none. */\n description?: string;\n /** Where the cares came from — a care plan's lines or a price list. */\n careLink?: CalendarCareLink;\n}\n\n/**\n * A drag/resize of a PATIENT appointment awaiting confirmation (the\n * retired appointment-workflow pattern's move-confirm design). Rows stay\n * UN-mutated while the dialog is open, so the OLD end/chair/operator are\n * read live from the matching `CalendarRow`; `event` is FullCalendar's\n * post-drop snapshot and already carries the NEW resourceId.\n */\nexport interface PendingMove {\n event: CalendarEvent;\n kind: 'drop' | 'resize';\n oldStart: Date;\n newStart: Date;\n oldEnd?: Date;\n /** Post-drop end, snapshotted so a re-commit cannot re-apply the delta. */\n newEnd?: Date;\n /** Post-drop column. `event.resourceId` still reports the OLD one. */\n newResourceId?: string;\n revert?: () => void;\n}\n\n/* Only PATIENT appointments confirm a drag/resize (platform parity):\n tasks, the background/internal washes, the closed-day block and\n UNASSIGNED events (no patientId — nobody to notify) apply silently. */\nexport function movesSilently(event: CalendarEvent): boolean {\n return Boolean(\n event.isTask || event.isInternal || patientIdOf(event.patientId) === '',\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Who is booked — resolved through the host's lookup */\n/* */\n/* The ONE place the calendar turns a host id into a `PatientRef`. */\n/* Everything downstream asks the ref whether someone is booked */\n/* (`assigned`) and whether we managed to load them (`unresolved`), so */\n/* no panel re-derives the distinction and no two panels derive it */\n/* differently. See the block over `PatientRef` in `calendar.types.ts`. */\n/* ------------------------------------------------------------------ */\n\n/** The reference for one patient id — the record when the host could\n * answer, and always the id itself. */\nexport function patientRefById(\n id: string | number | null | undefined,\n data: CalendarData,\n): PatientRef {\n const key = patientIdOf(id);\n return patientRefOf(key, key ? data.patientById(key) : undefined);\n}\n\n/** The reference for the patient an appointment carries. */\nexport function eventPatientRef(\n event: CalendarEvent,\n data: CalendarData,\n): PatientRef {\n return patientRefById(event.patientId, data);\n}\n\n/* An online booking still awaiting processing — the ONE predicate behind\n the Backlog's Bookings type; it stays flagged until BOTH a patient\n record and an operator are set. */\nexport function isPendingBooking(event: CalendarEvent): boolean {\n return event.hasUnassignedPatient === true && event.isBookedOnline === true;\n}\n\nexport function selectPendingBookings(rows: CalendarRow[]): CalendarRow[] {\n return rows.filter((r) => isPendingBooking(r.event));\n}\n\n/**\n * What a grid click focused in the rail. A FRESH object per click (not a\n * bare id) so re-clicking the same event re-docks its panel after the user\n * collapsed the rail — the registrar's effect keys on the object identity.\n */\nexport type RailFocus =\n | { kind: 'appointment'; eventId: string }\n | { kind: 'task'; eventId: string }\n | null;\n\n/**\n * The RANGE views of the standard calendar experience — a dedicated\n * segmented split button in the header (Day · 3 days · Working week ·\n * Week · Month). The chair/operator axis and the columns/timeline\n * orientation are NOT views: they are per-user display settings and live\n * in the cog. Month has no resource variant (platform parity) — it is\n * always the plain calendar.\n */\nexport type ViewOptionId =\n | 'day'\n | 'threeDays'\n | 'workingWeek'\n | 'week'\n | 'month';\n\nexport interface ViewOption {\n id: ViewOptionId;\n /** CalendarView stem — composed with the cog's group-by axis. */\n stem: 'Day' | 'ThreeDays' | 'Week' | 'Month';\n /** Working week trims the weekend regardless of the Sundays setting. */\n workingWeek?: boolean;\n}\n\nexport const VIEW_OPTIONS: ViewOption[] = [\n { id: 'day', stem: 'Day' },\n { id: 'threeDays', stem: 'ThreeDays' },\n { id: 'workingWeek', stem: 'Week', workingWeek: true },\n { id: 'week', stem: 'Week' },\n { id: 'month', stem: 'Month' },\n];\n\n/**\n * On-the-fly DISPLAY settings — the platform buries these per-user knobs in\n * Settings; the sketch surfaces them in a header cog so users adjust the\n * view without leaving the agenda. The view knobs are display-only and\n * instantly reversible. The cog also carries the two per-user data-entry\n * defaults (care description, colour association): they govern what NEW or\n * MOVED appointments get, never what is already painted. Default duration\n * and the business hours themselves stay in Settings.\n */\nexport interface DisplaySettings {\n /** Which resource axis the columns/rows group by. */\n resourceKind: 'chair' | 'operator' | 'none';\n /** Vertical resource columns vs the horizontal timeline. */\n orientation: 'vertical' | 'horizontal';\n zebraRows: boolean;\n showTime: boolean;\n slotDuration: '00:15' | '00:30' | '01:00';\n window: 'working' | 'extended' | 'full';\n /** How the card describes its cares (platform care visualization). */\n careDescription: CareDescriptionMode;\n /** Which colour a new or moved appointment inherits. */\n colorAssociation: ColorAssociation;\n}\n\nexport const DEFAULT_DISPLAY: DisplaySettings = {\n resourceKind: 'chair',\n orientation: 'vertical',\n zebraRows: false,\n showTime: true,\n slotDuration: '00:30',\n /* Extended, not working: the practice's own hours ARE the working\n window, so at 08:00–19:00 every wash would sit outside the visible\n axis and the shading would only appear after a cog visit. */\n window: 'extended',\n /* Name, not the platform's 'disabled' default — that would blank every\n card's care line on first paint. */\n careDescription: 'name',\n colorAssociation: 'care',\n};\n\n/* ---- remembered preferences: validate on read -------------------- */\n\n/** A remembered range view, only while the segment still exists. */\nexport function readViewOptionId(raw: unknown): ViewOptionId | undefined {\n return VIEW_OPTIONS.some((o) => o.id === raw)\n ? (raw as ViewOptionId)\n : undefined;\n}\n\nexport const DISPLAY_READERS: {\n [K in keyof DisplaySettings]: (\n raw: unknown,\n ) => DisplaySettings[K] | undefined;\n} = {\n resourceKind: readEnum(['chair', 'operator', 'none']),\n orientation: readEnum(['vertical', 'horizontal']),\n zebraRows: readBoolean,\n showTime: readBoolean,\n slotDuration: readEnum(['00:15', '00:30', '01:00']),\n window: readEnum(['working', 'extended', 'full']),\n careDescription: readEnum(['off', 'name', 'code', 'nameCode']),\n colorAssociation: readEnum(['care', 'operator', 'chair']),\n};\n\nexport function readDisplayField<K extends keyof DisplaySettings>(\n target: DisplaySettings,\n field: K,\n raw: unknown,\n): void {\n const value = DISPLAY_READERS[field](raw);\n if (value !== undefined) target[field] = value;\n}\n\n/**\n * Remembered display settings, validated PER FIELD over the defaults —\n * a stale shape from an earlier session keeps every knob it still knows\n * and never wipes the newer ones. Anything but an object is rejected.\n */\nexport function readDisplaySettings(raw: unknown): DisplaySettings | undefined {\n if (!raw || typeof raw !== 'object') return undefined;\n const source = raw as Record<string, unknown>;\n const next: DisplaySettings = { ...DEFAULT_DISPLAY };\n for (const field of Object.keys(DISPLAY_READERS) as Array<\n keyof DisplaySettings\n >) {\n readDisplayField(next, field, source[field]);\n }\n return next;\n}\n\n/** Remembered chair / operator selections, kept to the practice's ids. */\nexport function readChairIds(\n data: CalendarData,\n): (raw: unknown) => string[] | undefined {\n return readIdList(data.chairs);\n}\nexport function readOperatorIds(\n data: CalendarData,\n): (raw: unknown) => string[] | undefined {\n return readIdList(data.operators);\n}\n\n/** Tri-state for a select-all row over `ids`. */\nexport function selectionState(\n selected: readonly string[],\n ids: readonly string[],\n): boolean | 'indeterminate' {\n const count = ids.filter((id) => selected.includes(id)).length;\n if (count === 0) return false;\n return count === ids.length ? true : 'indeterminate';\n}\n\n/** Time-only Intl options for the peek's semantic `<time>` pair. */\nexport const PEEK_TIME_FORMAT: Intl.DateTimeFormatOptions = {\n hour: '2-digit',\n minute: '2-digit',\n hour12: false,\n};\n\nexport const DAY_WINDOWS: Record<\n DisplaySettings['window'],\n { min: string; max: string }\n> = {\n working: { min: '08:00', max: '19:00' },\n extended: { min: '07:00', max: '21:00' },\n full: { min: '00:00', max: '24:00' },\n};\n\nexport function formatTimeRange(\n locale: string,\n start: Date | string,\n end?: Date | string,\n): string {\n const s = new Date(start);\n const e = end ? new Date(end) : s;\n try {\n const fmt = new Intl.DateTimeFormat(locale, {\n hour: '2-digit',\n minute: '2-digit',\n hour12: false,\n });\n return typeof fmt.formatRange === 'function'\n ? fmt.formatRange(s, e)\n : `${fmt.format(s)} – ${fmt.format(e)}`;\n } catch {\n return '';\n }\n}\n\nexport function formatDay(locale: string, value: Date | string): string {\n try {\n return new Intl.DateTimeFormat(locale, {\n weekday: 'long',\n day: 'numeric',\n month: 'long',\n year: 'numeric',\n }).format(parseEventDate(value));\n } catch {\n return '';\n }\n}\n\n/** Completed years between a birth date and the practice's fixed \"now\" —\n * the platform popover's \"(NN anni)\" beside the patient's name. Pinned\n * to `data.nowIso` so the figure never drifts under a test. */\nexport function patientAgeYears(dobIso: string, data: CalendarData): number {\n const dob = parseEventDate(dobIso);\n const on = parseEventDate(data.nowIso);\n let age = on.getFullYear() - dob.getFullYear();\n const monthDelta = on.getMonth() - dob.getMonth();\n if (monthDelta < 0 || (monthDelta === 0 && on.getDate() < dob.getDate())) {\n age -= 1;\n }\n return Math.max(0, age);\n}\n\n/** Per-appointment capabilities from the host's canonical read. Omitted\n * capabilities preserve the existing editor behaviour. Locked fields\n * are omitted from drafts, so the host must preserve their stored values. */\nexport interface CalendarEditorCapabilities {\n editCare?: boolean;\n editPatient?: boolean;\n editDescription?: boolean;\n editRecurrence?: boolean;\n /** False disables the status control and omits status from the draft. */\n editStatus?: boolean;\n}\n\n/** The editor field an arrival lands focus on. */\nexport type EditorInitialFocus = 'patient' | 'operator';\n\nexport interface EditorPrefill {\n /** Set = the editor EDITS this existing event; unset = create. */\n editEventId?: string;\n patientId?: string;\n isTelehealth?: boolean;\n date?: Date;\n time?: { hours: number; minutes: number };\n durationMin?: number;\n operatorId?: string;\n chairId?: string;\n colorHex?: string;\n care?: string;\n /** Care entries riding along (an edit, or a find-free-slots hand-off). */\n cares?: CalendarCareEntry[];\n /** The plan lines or price-list picks the cares came from. */\n careLink?: CalendarCareLink;\n allDay?: boolean;\n status?: CalendarEventStatus;\n /** Online-booking triage: what the person typed on the booking site\n * (no patient record yet). Drives the booker block + the platform's\n * \"search for this patient below\" call to action. */\n bookingContact?: CalendarBookingContact;\n /** The waiting-list entry this save settles — it leaves the queue when\n * the save lands (Schedule creates, Bring forward moves). */\n waitingEntryId?: string;\n /** Backlog hand-off: what this edit must settle — a booking needs a\n * patient AND an operator; an operator-less appointment needs one. */\n callToAction?: 'processBooking' | 'assignOperator';\n /** The platform's `simpleSave`. `false` — a deep-link arrival that has\n * somewhere to go back to — splits Save into \"save and go back\" and\n * \"save and continue\"; anything else keeps the one Save. */\n simpleSave?: boolean;\n /** Lands focus on this field once the panel has settled (a booking's\n * assign intent). A hint, never saved: an absent or disabled field, or\n * no value, moves no focus. */\n initialFocus?: EditorInitialFocus;\n}\n\n/* ------------------------------------------------------------------ */\n/* Recurrence — the platform's rule, plus the two gaps it leaves */\n/* */\n/* Platform's modal collects exactly three things: the \"Si ripete\" */\n/* checkbox, a frequency (six values), and a repetition COUNT (2-100). */\n/* Its DoctorAppointment row also carries `recurrence_until`, and the */\n/* entity refuses COUNT and UNTIL together — but no input ever sets */\n/* UNTIL, so \"repeat until a date\" is unreachable from the UI. Nothing */\n/* anywhere consults the practice's opening hours, so a platform */\n/* series happily lands occurrences on closed days. This demo keeps */\n/* platform's vocabulary and closes both gaps: the count/until choice */\n/* the entity already models, and a closed-day skip. */\n/* ------------------------------------------------------------------ */\n\n/** Platform's six `recurrence_frequency` values, in its dropdown order. */\nexport type RecurrenceFrequency =\n | 'daily'\n | 'weekly'\n | 'monthly'\n | 'quarterly'\n | 'semiannual'\n | 'yearly';\n\n/** Repetition cap — platform asserts 2..100 on the entity. */\nexport const RECURRENCE_MAX_COUNT = 100;\n\n/** Dropdown order, matching the platform modal's own. */\nexport const RECURRENCE_FREQUENCIES: readonly RecurrenceFrequency[] = [\n 'daily',\n 'weekly',\n 'monthly',\n 'quarterly',\n 'semiannual',\n 'yearly',\n] as const;\n\n/** Literal map (not a template) so key extractors see every key. */\nexport const RECURRENCE_LABEL_KEY: Record<RecurrenceFrequency, string> = {\n daily: 'recurrenceDaily',\n weekly: 'recurrenceWeekly',\n monthly: 'recurrenceMonthly',\n quarterly: 'recurrenceQuarterly',\n semiannual: 'recurrenceSemiannual',\n yearly: 'recurrenceYearly',\n};\n\nexport interface EditorRecurrence {\n frequency: RecurrenceFrequency;\n /** Count XOR until — the exclusivity `DoctorAppointment` enforces. */\n ends: 'count' | 'until';\n /** Occurrences INCLUDING the first, when `ends === 'count'`. */\n count: number;\n /** Last date an occurrence may land on, when `ends === 'until'`. */\n untilDate?: Date;\n /** Beyond platform: drop occurrences the practice could not honour. */\n skipClosedDays: boolean;\n}\n\n/** Step per frequency. Platform's RRULE factory has no QUARTERLY or\n * SEMIANNUAL freq either — it rewrites both to MONTHLY with INTERVAL\n * 3 / 6, which is the same arithmetic. */\nexport const RECURRENCE_STEP: Record<\n RecurrenceFrequency,\n { days?: number; months?: number }\n> = {\n daily: { days: 1 },\n weekly: { days: 7 },\n monthly: { months: 1 },\n quarterly: { months: 3 },\n semiannual: { months: 6 },\n yearly: { months: 12 },\n};\n\n/** Month arithmetic that never rolls over: 31 Jan + 1 month is 28/29\n * Feb, not 2/3 March (what a naive `setMonth` would give). */\nexport function addMonthsClamped(base: Date, months: number): Date {\n const d = new Date(base);\n const day = d.getDate();\n d.setDate(1);\n d.setMonth(d.getMonth() + months);\n const lastDay = new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate();\n d.setDate(Math.min(day, lastDay));\n return d;\n}\n\n/**\n * A day this appointment cannot be honoured: the practice is shut (no\n * business hours for that weekday) or the chosen operator is away.\n * Chair-only bookings check the practice alone.\n */\nexport function isUnbookableDay(\n date: Date,\n operatorId: string | undefined,\n data: CalendarData,\n): boolean {\n if (!data.businessHours.practice[date.getDay()]) return true;\n if (!operatorId) return false;\n return (data.operatorAbsences[operatorId] ?? []).includes(localIsoDate(date));\n}\n\n/**\n * Expand a rule into the dates that actually get booked. Skipped\n * candidates do NOT consume the count — asking for 4 appointments\n * yields 4 appointments, with the closed days stepped over rather than\n * silently swallowing an occurrence.\n */\nexport function expandRecurrence(\n start: Date,\n rule: EditorRecurrence,\n operatorId: string | undefined,\n data: CalendarData,\n): { dates: Date[]; skipped: number } {\n const step = RECURRENCE_STEP[rule.frequency];\n const wanted =\n rule.ends === 'count'\n ? Math.min(Math.max(rule.count, 1), RECURRENCE_MAX_COUNT)\n : RECURRENCE_MAX_COUNT;\n const dates: Date[] = [];\n let skipped = 0;\n /* Candidate walk, not an occurrence walk — bounded so a rule that\n skips everything (a weekly series on a closed weekday) terminates. */\n for (let n = 0; dates.length < wanted && n < 1000; n += 1) {\n const candidate = step.days\n ? new Date(start.getTime() + n * step.days * 86400000)\n : addMonthsClamped(start, n * (step.months ?? 1));\n if (rule.ends === 'until' && n > 0) {\n if (!rule.untilDate) break;\n const cutoff = new Date(rule.untilDate);\n cutoff.setHours(23, 59, 59, 999);\n if (candidate > cutoff) break;\n }\n /* The anchor is the slot the operator PICKED, not a repeat — it is\n never skipped, so a rule can never expand to nothing and swallow\n the appointment silently. The skip governs the repeats only. */\n if (\n n > 0 &&\n rule.skipClosedDays &&\n isUnbookableDay(candidate, operatorId, data)\n ) {\n skipped += 1;\n continue;\n }\n dates.push(candidate);\n }\n return { dates, skipped };\n}\n\n/** What an occurrence knows about the series it belongs to — drives the\n * details panel's read-only summary (platform disables the recurrence\n * inputs once an appointment exists, so this is the only place the\n * rule surfaces after saving). */\nexport interface CalendarSeries {\n id: string;\n frequency: RecurrenceFrequency;\n /** 1-based position of this occurrence. */\n index: number;\n total: number;\n lastIso: string;\n /** Candidates dropped as closed/absent days. */\n skipped: number;\n}\n\nexport interface EditorDraft {\n editEventId?: string;\n patientId?: string;\n isTelehealth: boolean;\n date: Date;\n time: { hours: number; minutes: number };\n durationMin: number;\n operatorId?: string;\n chairId?: string;\n colorHex: string;\n care?: string;\n cares?: CalendarCareEntry[];\n careLink?: CalendarCareLink;\n /** The waiting-list entry this save settles (removed from the queue). */\n waitingEntryId?: string;\n allDay?: boolean;\n /** Platform \"Lista d'attesa\" checkbox — also queue the patient. */\n addToWaitingList?: boolean;\n /** Edit mode only — the platform changes status from the popover, but\n the rail's details-as-form surface owns it here. */\n status?: CalendarEventStatus;\n /** Create only, matching platform (its recurrence inputs go disabled\n the moment an appointment id exists). */\n recurrence?: EditorRecurrence;\n}\n\n/** Full-edit prefill for an existing grid event. */\nexport function editPrefillFromRow(row: CalendarRow): EditorPrefill {\n const start = new Date(String(row.event.start));\n const end = row.event.end ? new Date(String(row.event.end)) : undefined;\n return {\n editEventId: row.event.id,\n patientId: patientIdOf(row.event.patientId) || undefined,\n isTelehealth: row.event.isTelehealth,\n date: start,\n time: { hours: start.getHours(), minutes: start.getMinutes() },\n /* Carry the all-day flag: without it an all-day event re-opens in the\n form as a timed appointment and Save would silently convert it. */\n allDay: row.event.allDay,\n durationMin: end\n ? Math.round((end.getTime() - start.getTime()) / 60000)\n : undefined,\n operatorId: row.operatorId,\n chairId: row.chairId,\n colorHex: row.event.backgroundColor,\n care: row.description,\n cares: row.cares,\n careLink: row.careLink,\n status: row.event.status,\n };\n}\n\n/**\n * The slot an open editor is composing, mirrored on the grid as a draft\n * placeholder so the user can see WHICH timeslot they picked. Carries\n * `editEventId` when editing an existing appointment — the mirror is\n * suppressed there, since the real card is already on the grid.\n */\nexport interface DraftSlot {\n editEventId?: string;\n date: Date;\n time: { hours: number; minutes: number };\n durationMin: number;\n allDay: boolean;\n chairId?: string;\n operatorId?: string;\n}\n\n/**\n * A slot edit made ON THE GRID (dragging or resizing the draft mirror),\n * pushed back into the open editor. Applied by `tick` so it patches only\n * the slot fields — the patient, care, colour and the rest of the form\n * survive untouched.\n */\nexport interface SlotPatch {\n tick: number;\n date?: Date;\n time?: { hours: number; minutes: number };\n durationMin?: number;\n chairId?: string;\n operatorId?: string;\n}\n\n/* Drag/resize granularity — 15 minutes, independent of the visual slot\n precision, matching Google Calendar and Outlook. */\nexport const DRAFT_SNAP = '00:15';\n\n/* Radix Select items cannot carry an empty-string value. */\nexport const NONE = 'none';\n\n/* Duration — preset steps plus free typing. The Combobox only displays\n values present in `options`, so the committed value joins the preset\n list; `allowCreate` turns any typed number into a committable row, and\n the numeric-prefix filter keeps that row visible (cmdk's fuzzy default\n would match \"10\" against \"120\" and suppress it). */\nexport const DURATION_PRESETS_MIN = [15, 30, 45, 60, 90, 120];\n\nexport function durationDigitsFilter(\n candidate: string,\n search: string,\n): number {\n const digits = search.replace(/\\D/g, '');\n return digits.length === 0 || candidate.replace(/\\D/g, '').startsWith(digits)\n ? 1\n : 0;\n}\n\n/**\n * The editor's opening colour (platform `_setStateColorId` on mount): an\n * existing appointment keeps its stored colour; a new one under operator or\n * chair association adopts the preselected resource's colour, under care\n * association the hand-off's colour, else the first catalogued care's.\n */\nexport function initialEditorColor(\n prefill: EditorPrefill | undefined,\n association: ColorAssociation,\n data: CalendarData,\n): string {\n if (prefill?.editEventId && prefill.colorHex) return prefill.colorHex;\n const derived =\n association === 'care'\n ? (prefill?.colorHex ??\n associationColor('care', { cares: prefill?.cares }, data))\n : (associationColor(\n association,\n { operatorId: prefill?.operatorId, chairId: prefill?.chairId },\n data,\n ) ?? prefill?.colorHex);\n return derived ?? GOOGLE_CALENDAR_PALETTE[6].hex;\n}\n\n/** A plan line's booked appointments — entry id → [{ eventId, startIso }]\n * in start order (the checklist's \"scheduled\" chips, the rail's links). */\nexport function scheduleByEntryId(\n rows: ReadonlyArray<{\n event: { id: string; start: string | Date };\n careLink?: CalendarCareLink;\n }>,\n): Record<string, Array<{ eventId: string; startIso: string }>> {\n const out: Record<string, Array<{ eventId: string; startIso: string }>> = {};\n for (const row of rows) {\n if (row.careLink?.kind !== 'plan') continue;\n const startIso = new Date(String(row.event.start)).toISOString();\n for (const entryId of row.careLink.entryIds) {\n (out[entryId] ??= []).push({ eventId: row.event.id, startIso });\n }\n }\n for (const list of Object.values(out)) {\n list.sort((a, b) => a.startIso.localeCompare(b.startIso));\n }\n return out;\n}\n\n/** What a link implies for the form (platform `_getAppointmentDuration`,\n * `_getColorIdFromCarePlanEntry` / `_getColorIdFromPriceList`): the\n * summed duration, the FIRST line's care colour in plan order, a label. */\nexport function deriveCareLinkDefaults(\n link: CalendarCareLink | undefined,\n data: CalendarData,\n): {\n durationMin?: number;\n colorHex?: string;\n description?: string;\n} {\n if (!link) return {};\n const lines: Array<{ name: string; colorHex: string; durationMin: number }> =\n [];\n if (link.kind === 'plan') {\n const plan = data.carePlanById(link.planId);\n for (const entry of plan?.entries ?? []) {\n if (!link.entryIds.includes(entry.id)) continue;\n const care = data.careById(entry.careId);\n if (care) {\n lines.push({\n name: care.name,\n colorHex: care.colorHex,\n durationMin: entry.durationMin ?? care.durationMin,\n });\n }\n }\n } else {\n for (const item of link.items) {\n const care = data.careById(item.careId);\n if (care) {\n lines.push({\n name: care.name,\n colorHex: care.colorHex,\n durationMin: care.durationMin,\n });\n }\n }\n }\n if (lines.length === 0) return {};\n return {\n durationMin: lines.reduce((sum, l) => sum + l.durationMin, 0),\n colorHex: lines[0].colorHex,\n description: lines.map((l) => l.name).join(', '),\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Details depth — signing summary + the modification ledger */\n/* ------------------------------------------------------------------ */\n\n/** `Omit` that keeps a union's variants apart (plain Omit collapses it). */\nexport type DistributiveOmit<T, K extends PropertyKey> = T extends unknown\n ? Omit<T, K>\n : never;\n\n/** A ledger line before the journey stamps id, time and actor onto it. */\nexport type HistoryInput = DistributiveOmit<\n CalendarHistoryEntry,\n 'id' | 'atIso' | 'actor'\n>;\n\n/** Absolute stamp for booked-at and ledger lines — day and time. */\nexport const DETAIL_STAMP_FORMAT: Intl.DateTimeFormatOptions = {\n weekday: 'short',\n day: 'numeric',\n month: 'short',\n hour: '2-digit',\n minute: '2-digit',\n};\n\n/** Live stamps advance from the practice clock, never the real one. */\nexport function historyStampIso(seq: number, data: CalendarData): string {\n const d = new Date(data.nowIso);\n d.setMinutes(d.getMinutes() + seq);\n const pad = (n: number): string => String(n).padStart(2, '0');\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(\n d.getHours(),\n )}:${pad(d.getMinutes())}:00`;\n}\n\n/** Timeline 'newest-first' is a plain column — DOM order must already be. */\nexport function sortHistoryNewestFirst(\n entries: readonly CalendarHistoryEntry[],\n): CalendarHistoryEntry[] {\n return (\n entries\n .map((entry) => {\n const parsed = Date.parse(entry.atIso);\n return { entry, time: Number.isFinite(parsed) ? parsed : -Infinity };\n })\n /* Unreadable dates stay last, in input order; equal instants are stable. */\n .sort((a, b) => (a.time === b.time ? 0 : b.time - a.time))\n .map(({ entry }) => entry)\n );\n}\n\n/** Documents still awaiting a required party (the chip's own rule). */\nexport function signingSummary(docs: readonly CalendarSignDocument[]): {\n toSign: number;\n allSigned: boolean;\n} {\n const toSign = docs.filter((d) => {\n const status = signatureStatusOf(d.operator, d.patient);\n return status !== 'signed' && status !== 'notRequired';\n }).length;\n return { toSign, allSigned: docs.length > 0 && toSign === 0 };\n}\n\n/**\n * What a Save changed, as ledger lines: a status change, a move (start\n * differs), a resize (other duration) and one `edited` line naming the\n * other fields that differ. Empty when nothing changed.\n */\nexport function historyEntriesFromEdit(\n prev: CalendarRow,\n draft: EditorDraft,\n data: CalendarData,\n): HistoryInput[] {\n const out: HistoryInput[] = [];\n if (draft.status && prev.event.status && draft.status !== prev.event.status) {\n out.push({ kind: 'status', from: prev.event.status, to: draft.status });\n }\n const fields: CalendarHistoryField[] = [];\n const timed = !draft.allDay && !prev.event.allDay;\n if (timed) {\n const prevStart = new Date(String(prev.event.start));\n const nextStart = new Date(draft.date);\n nextStart.setHours(draft.time.hours, draft.time.minutes, 0, 0);\n if (nextStart.getTime() !== prevStart.getTime()) {\n out.push({\n kind: 'moved',\n fromIso: prevStart.toISOString(),\n toIso: nextStart.toISOString(),\n });\n }\n const prevMin = prev.event.end\n ? Math.round(\n (new Date(String(prev.event.end)).getTime() - prevStart.getTime()) /\n 60000,\n )\n : undefined;\n if (prevMin !== undefined && prevMin !== draft.durationMin) {\n out.push({ kind: 'resized', fromMin: prevMin, toMin: draft.durationMin });\n }\n } else if (Boolean(draft.allDay) !== Boolean(prev.event.allDay)) {\n fields.push('time');\n }\n const prevPatient = patientIdOf(prev.event.patientId) || undefined;\n if (draft.patientId !== prevPatient) fields.push('patient');\n if (Boolean(draft.isTelehealth) !== Boolean(prev.event.isTelehealth)) {\n fields.push('type');\n }\n const nextCares = draft.careLink\n ? data.careEntriesFromLink(draft.careLink)\n : (draft.cares ?? prev.cares);\n if (\n careSuffix({ description: draft.care, cares: nextCares }, 'name') !==\n careSuffix({ description: prev.description, cares: prev.cares }, 'name')\n ) {\n fields.push('care');\n }\n if (draft.operatorId !== prev.operatorId) fields.push('operator');\n if (draft.chairId !== prev.chairId) fields.push('chair');\n if (\n draft.colorHex.toLowerCase() !==\n (prev.event.backgroundColor ?? '').toLowerCase()\n ) {\n fields.push('colour');\n }\n if (fields.length > 0) out.push({ kind: 'edited', fields });\n return out;\n}\n\n/** One \"From price list\" row: a care pick and its (editable) price. */\nexport interface PriceRow {\n key: number;\n careId: string;\n priceCents: number | null;\n /** Booked subset of the care's catalogue phases (platform per-row\n * phase checkboxes); empty when the care has none. */\n phases?: string[];\n /** Already invoiced — the whole row is read-only (platform \"Azione\n * non consentita: Prestazione già fatturata\"). */\n billed?: boolean;\n}\n\nexport const EMPTY_SCHEDULE: Record<\n string,\n Array<{ eventId: string; startIso: string }>\n> = {};\n\n/** Whether the host gave us a price-list catalogue at all: `ready`,\n * `none` (told, and empty) or `unknown` (never told). Both non-ready\n * states withhold the \"From price list\" relation — see the CATALOGUE\n * PRESENCE note in `calendar.types.ts`. */\nexport function priceListState(data: CalendarData): CatalogueState {\n return catalogueStateOf(data.priceLists);\n}\n\n/** The patient's price list by name, else the practice default —\n * `undefined` when there is no catalogue to default into. The absence\n * is RETURNED, never papered over: a fabricated id would name a price\n * list the practice does not have, and `priceLists[0].id` on an empty\n * catalogue threw and took the whole calendar down with it. */\nexport function priceListIdFor(\n patientId: string | undefined,\n data: CalendarData,\n): string | undefined {\n const lists = data.priceLists ?? [];\n const name = patientId ? data.patientById(patientId)?.priceList : undefined;\n return lists.find((l) => l.name === name)?.id ?? lists[0]?.id;\n}\n\n/* Status chip spec — the SAME icon + semantic tone as the card's disc,\n so the labelled chip and the grid symbol are one vocabulary. */\nexport const STATUS_CHIP: Record<\n CalendarEventStatus,\n {\n variant: 'success' | 'info' | 'warning' | 'error' | 'accentSoft';\n tone: WorkflowStatusTone;\n Icon: typeof ThumbsUp;\n }\n> = {\n confirmed: { variant: 'success', tone: 'success', Icon: ThumbsUp },\n waiting: { variant: 'info', tone: 'info', Icon: Clock },\n in_care: { variant: 'accentSoft', tone: 'accent', Icon: Stethoscope },\n done: { variant: 'success', tone: 'success', Icon: Check },\n cancelled: { variant: 'error', tone: 'error', Icon: Ban },\n absent: { variant: 'warning', tone: 'warning', Icon: UserX },\n};\n\n/* ------------------------------------------------------------------ */\n/* Backlog model — the queue types, its derivation and the hand-offs */\n/* (the rail panel that renders it stays with the stories). */\n/* ------------------------------------------------------------------ */\n\nexport type BacklogType =\n | 'booking'\n | 'waiting'\n | 'unconfirmed'\n | 'noOperator'\n | 'signature';\n\n/** The filter strip's segments — every type, or all of them grouped. */\nexport type BacklogFilter = BacklogType | 'all';\n\n/** Group order in the All view (and the strip's segment order). */\nexport const BACKLOG_TYPES: readonly BacklogType[] = [\n 'booking',\n 'waiting',\n 'unconfirmed',\n 'noOperator',\n 'signature',\n];\n\n/** One row of the queue. `startIso` sorts each group in day order. */\nexport type BacklogItem =\n | { type: 'booking'; id: string; startIso: string; row: CalendarRow }\n | {\n type: 'waiting';\n id: string;\n startIso: string;\n entry: CalendarWaitingEntry;\n }\n | { type: 'unconfirmed'; id: string; startIso: string; row: CalendarRow }\n | { type: 'noOperator'; id: string; startIso: string; row: CalendarRow }\n | {\n type: 'signature';\n id: string;\n startIso: string;\n row: CalendarRow;\n toSign: number;\n };\n\n/** A concluded appointment has nobody left to assign. */\nexport const SETTLED_STATUSES: ReadonlySet<CalendarEventStatus> = new Set([\n 'done',\n 'cancelled',\n 'absent',\n]);\n\n/** Epoch ms of an event start — date-only starts are LOCAL midnight. */\nexport function eventStartMs(iso: string): number {\n return new Date(iso.length === 10 ? `${iso}T00:00:00` : iso).getTime();\n}\n\n/** What the waiting-list entry is about, if a loaded appointment. */\nexport function waitingEntryAppointment(\n entry: CalendarWaitingEntry,\n data: CalendarData,\n): CalendarBaseEvent | undefined {\n return entry.appointmentId\n ? data.baseEvents.find((b) => b.event.id === entry.appointmentId)\n : undefined;\n}\n\n/**\n * Derive the whole queue from live state. Bookings, operator-less\n * appointments and pending signatures span the fixture week; unconfirmed\n * appointments are scoped to the grid's visible range (the week would\n * list every not-yet-confirmed filler row). Groups sort by day.\n */\nexport function buildBacklog(\n args: {\n rows: CalendarRow[];\n waitingList: CalendarWaitingEntry[];\n visibleRange: { start: number; end: number } | null;\n },\n data: CalendarData,\n): BacklogItem[] {\n const { rows, waitingList, visibleRange } = args;\n const items: BacklogItem[] = [];\n for (const row of rows) {\n const e = row.event;\n if (e.isTask || e.isInternal || isClosureEvent(e)) continue;\n const startIso = String(e.start);\n if (isPendingBooking(e)) {\n items.push({ type: 'booking', id: `booking-${e.id}`, startIso, row });\n continue;\n }\n if (patientIdOf(e.patientId) === '') continue;\n const status = e.status ?? 'confirmed';\n if (status === 'waiting' && visibleRange) {\n const ms = eventStartMs(startIso);\n if (ms >= visibleRange.start && ms < visibleRange.end) {\n items.push({\n type: 'unconfirmed',\n id: `unconfirmed-${e.id}`,\n startIso,\n row,\n });\n }\n }\n if (!row.operatorId && !SETTLED_STATUSES.has(status)) {\n items.push({\n type: 'noOperator',\n id: `noOperator-${e.id}`,\n startIso,\n row,\n });\n }\n const toSign = signingSummary(\n data.metaById[e.id]?.documentsToSign ?? [],\n ).toSign;\n if (toSign > 0) {\n items.push({\n type: 'signature',\n id: `signature-${e.id}`,\n startIso,\n row,\n toSign,\n });\n }\n }\n for (const entry of waitingList) {\n const linked = entry.appointmentId\n ? rows.find((r) => r.event.id === entry.appointmentId)\n : undefined;\n items.push({\n type: 'waiting',\n id: `waiting-${entry.id}`,\n startIso: linked\n ? String(linked.event.start)\n : data.waitingSinceIso(entry),\n entry,\n });\n }\n return items.sort(\n (a, b) =>\n BACKLOG_TYPES.indexOf(a.type) - BACKLOG_TYPES.indexOf(b.type) ||\n eventStartMs(a.startIso) - eventStartMs(b.startIso),\n );\n}\n\n/** Per-type counts — the strip's segment badges. */\nexport function backlogCounts(\n items: readonly BacklogItem[],\n): Record<BacklogType, number> {\n const counts: Record<BacklogType, number> = {\n booking: 0,\n waiting: 0,\n unconfirmed: 0,\n noOperator: 0,\n signature: 0,\n };\n for (const item of items) counts[item.type] += 1;\n return counts;\n}\n\n/** The patient behind a row (bookings have none — a typed name only),\n * as the reference: `assigned` says whether anyone is booked at all,\n * which is what a \"no patient\" label may key on — never the record. */\nexport function backlogPatientRef(\n item: BacklogItem,\n data: CalendarData,\n): PatientRef {\n if (item.type === 'waiting') {\n const linked = waitingEntryAppointment(item.entry, data);\n return patientRefById(\n item.entry.patientId ?? linked?.meta?.patientId,\n data,\n );\n }\n return eventPatientRef(item.row.event, data);\n}\n\n/** The record behind a queue row, when the host could load it. */\nexport function backlogPatient(\n item: BacklogItem,\n data: CalendarData,\n): CalendarPatient | undefined {\n return backlogPatientRef(item, data).record;\n}\n\n/** The row's headline — patient name, the booker's typed name, or the\n * free-text hold. */\nexport function backlogName(\n item: BacklogItem,\n data: CalendarData,\n /** Localised stand-in while the host is still fetching the row's\n * details — such a row carries no title of its own. */\n pendingDetailsLabel?: string,\n): string | undefined {\n if (item.type === 'waiting') {\n return backlogPatient(item, data)?.name ?? item.entry.description;\n }\n if (item.row.event.detailsPending) return pendingDetailsLabel;\n return item.row.event.title;\n}\n\n/**\n * Text search over what the ROW renders: the patient's name (own, or the\n * linked appointment's) and the description (own, or the linked\n * appointment's care). Case-insensitive substring; empty matches all.\n */\nexport function waitingEntryMatches(\n entry: CalendarWaitingEntry,\n query: string,\n data: CalendarData,\n): boolean {\n const needle = query.trim().toLocaleLowerCase();\n if (!needle) return true;\n const appointment = waitingEntryAppointment(entry, data);\n const patientId = entry.patientId ?? appointment?.meta?.patientId;\n const patient = patientId ? data.patientById(patientId) : undefined;\n const haystack = [patient?.name, entry.description, appointment?.meta?.care]\n .filter((s): s is string => Boolean(s))\n .join(' ')\n .toLocaleLowerCase();\n return haystack.includes(needle);\n}\n\n/** Text search over a row: name, care line, note and operator. */\nexport function backlogItemMatches(\n item: BacklogItem,\n query: string,\n data: CalendarData,\n): boolean {\n if (item.type === 'waiting') {\n return waitingEntryMatches(item.entry, query, data);\n }\n const needle = query.trim().toLocaleLowerCase();\n if (!needle) return true;\n const { event } = item.row;\n const operator = data.operators.find((o) => o.id === item.row.operatorId);\n const haystack = [\n event.title,\n typeof event.suffix === 'string' ? event.suffix : undefined,\n item.row.description,\n data.bookingNotes[event.id],\n operator?.title,\n ]\n .filter((s): s is string => Boolean(s))\n .join(' ')\n .toLocaleLowerCase();\n return haystack.includes(needle);\n}\n\n/** The strip segment plus the text search, in one pass. */\nexport function filterBacklog(\n items: readonly BacklogItem[],\n filter: BacklogFilter,\n query: string,\n data: CalendarData,\n): BacklogItem[] {\n return items.filter(\n (item) =>\n (filter === 'all' || item.type === filter) &&\n backlogItemMatches(item, query, data),\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Waiting-list quick views — the platform's \"Visualizza:\" dropdown, */\n/* client-side over the WAITING rows only. */\n/* ------------------------------------------------------------------ */\n\nexport type WaitingQuickView =\n | 'all'\n | 'noAppointment'\n | 'scheduledOver30'\n | 'waitingOver30';\n\nexport const WAITING_QUICK_VIEWS: readonly WaitingQuickView[] = [\n 'all',\n 'noAppointment',\n 'scheduledOver30',\n 'waitingOver30',\n];\n\n/** Literal map (not a template) so key extractors see every key. */\nexport const WAITING_QUICK_VIEW_LABEL_KEY: Record<WaitingQuickView, string> = {\n all: 'quickViewAll',\n noAppointment: 'quickViewNoAppointment',\n scheduledOver30: 'quickViewScheduledOver30',\n waitingOver30: 'quickViewWaitingOver30',\n};\n\n/** The platform's threshold for both \"over 30 days\" quick views. */\nexport const WAITING_QUICK_VIEW_DAYS = 30;\n\n/** Whether an entry passes a quick view, measured from the practice clock. */\nexport function waitingEntryInQuickView(\n entry: CalendarWaitingEntry,\n view: WaitingQuickView,\n data: CalendarData,\n): boolean {\n if (view === 'all') return true;\n /* \"Pazienti senza appuntamento\" — the platform reads BOTH halves of\n its label: a patient, and no appointment yet. */\n if (view === 'noAppointment') {\n return !entry.appointmentId && Boolean(entry.patientId);\n }\n const cutoffMs = WAITING_QUICK_VIEW_DAYS * 86400000;\n const nowMs = new Date(data.nowIso).getTime();\n if (view === 'waitingOver30') {\n return nowMs - eventStartMs(data.waitingSinceIso(entry)) > cutoffMs;\n }\n const appointment = waitingEntryAppointment(entry, data);\n if (!appointment) return false;\n return nowMs - eventStartMs(String(appointment.event.start)) > cutoffMs;\n}\n\n/** Apply a quick view to a queue — every non-waiting row passes through\n * untouched (the platform's dropdown only ever saw waiting entries). */\nexport function filterWaitingQuickView(\n items: readonly BacklogItem[],\n view: WaitingQuickView,\n data: CalendarData,\n): BacklogItem[] {\n if (view === 'all') return [...items];\n return items.filter(\n (item) =>\n item.type !== 'waiting' ||\n waitingEntryInQuickView(item.entry, view, data),\n );\n}\n\n/**\n * Process an online booking: the editor opens for THAT event with the\n * booker's typed details, a patient pre-selected — the id the booking\n * already carries, or a typed-name match — and BOTH the patient and the\n * operator marked required, the two things it needs to leave the queue.\n */\nexport function processBookingPrefill(\n row: CalendarRow,\n data: CalendarData,\n): EditorPrefill {\n const contact = data.bookingContacts[row.event.id];\n const matched = contact\n ? data.patients.find(\n (p) => p.name.toLowerCase() === contact.typedName.toLowerCase(),\n )\n : undefined;\n /* The typed-name match is a SUGGESTION over the records we happen to\n hold; the id the booking already carries is a fact. Never let the\n lookup erase it — a host with no `patients` would lose the patient. */\n const carried = patientIdOf(row.event.patientId) || undefined;\n return {\n ...editPrefillFromRow(row),\n bookingContact: contact,\n patientId: matched?.id ?? carried,\n callToAction: 'processBooking',\n };\n}\n\n/** Assign an operator: the editor opens for the event with the operator\n * select as the call to action. */\nexport function assignOperatorPrefill(row: CalendarRow): EditorPrefill {\n return { ...editPrefillFromRow(row), callToAction: 'assignOperator' };\n}\n\n/**\n * Whether the editor's Backlog call to action is settled: processing a\n * booking needs the patient record AND the operator, assigning needs the\n * operator; with no call to action Save is never held back.\n */\nexport function callToActionSatisfied(\n callToAction: EditorPrefill['callToAction'],\n draft: { patientId?: string; operatorId?: string },\n): boolean {\n switch (callToAction) {\n case 'processBooking':\n return Boolean(draft.patientId && draft.operatorId);\n case 'assignOperator':\n return Boolean(draft.operatorId);\n default:\n return true;\n }\n}\n\n/** Confirm a waiting appointment in place; other rows untouched. */\nexport function confirmAppointment(\n rows: readonly CalendarRow[],\n eventId: string,\n): CalendarRow[] {\n return rows.map((r) =>\n r.event.id === eventId && r.event.status !== 'confirmed'\n ? { ...r, event: { ...r.event, status: 'confirmed' } }\n : r,\n );\n}\n\n/** What the waiting-list rail sub-view is showing: the queue, or the\n * entry form (add when `entry` is absent, edit when present). */\nexport type BacklogSubView =\n | { kind: 'queue' }\n | { kind: 'form'; entry?: CalendarWaitingEntry };\n\n/** What the entry form commits — the journey assigns the id on add. */\nexport interface WaitingEntryDraft {\n id?: string;\n patientId?: string;\n operatorId?: string;\n colorHex: string;\n description?: string;\n}\n\n/** Platform AddModal rule: an entry needs a patient OR a description. */\nexport function waitingEntryIsValid(\n draft: Pick<WaitingEntryDraft, 'patientId' | 'description'>,\n): boolean {\n return Boolean(draft.patientId) || Boolean(draft.description?.trim());\n}\n\n/**\n * Commit the entry form: with an id the matching entry is updated in\n * place (its link and waiting-since survive); without one a new entry\n * joins the end of the queue as of the demo's today.\n */\nexport function upsertWaitingEntry(\n list: readonly CalendarWaitingEntry[],\n draft: WaitingEntryDraft,\n newId: string,\n): CalendarWaitingEntry[] {\n const description = draft.description?.trim() || undefined;\n if (draft.id) {\n const id = draft.id;\n return list.map((e) =>\n e.id === id\n ? {\n ...e,\n patientId: draft.patientId,\n operatorId: draft.operatorId,\n colorHex: draft.colorHex,\n description,\n /* A new patient re-derives the WhatsApp capability; the same\n patient keeps what the entry already knew. */\n whatsappCapable:\n e.patientId === draft.patientId\n ? e.whatsappCapable\n : Boolean(draft.patientId),\n }\n : e,\n );\n }\n return [\n ...list,\n {\n id: newId,\n patientId: draft.patientId,\n operatorId: draft.operatorId,\n colorHex: draft.colorHex,\n description,\n createdDay: 2, // the demo's \"today\" (Wednesday)\n whatsappCapable: Boolean(draft.patientId),\n },\n ];\n}\n\n/* ------------------------------------------------------------------ */\n/* Find free slots — the search constants and the slot shape (the */\n/* panel stays with the stories); then the availability shading. */\n/* ------------------------------------------------------------------ */\n\n/* Radix Select items cannot carry an empty-string value. */\nexport const ANY = 'any';\nexport const FREE_SLOT_CAP = 20;\nexport const SLOT_STEP_MIN = 30;\n\n/** Platform `FreeSlot::MAX_DAYS_TO_LOOK_AHEAD` — the finder warns past it. */\nexport const FREE_SLOT_MAX_RANGE_DAYS = 185;\n\n/** The From→To span the finder opens on — the platform's own default. */\nexport const FREE_SLOT_DEFAULT_HORIZON_DAYS = 30;\n\n/** Whole days between two dates — the finder's range rule. */\nexport function rangeDays(from: Date, to: Date): number {\n return Math.round((to.getTime() - from.getTime()) / 86400000);\n}\n\nexport interface CalendarFreeSlot {\n start: Date;\n durationMin: number;\n chairId: string;\n operatorId: string;\n /** The care the search was scoped to — carries name/colour into the\n * prefill when a projected slot is clicked on the grid. */\n careId?: string;\n /** The device a SERVER answer allocated: the host's own string. */\n medicalDeviceId?: string;\n}\n\n/* ------------------------------------------------------------------ */\n/* Availability shading — the complement of `data.businessHours` washes */\n/* unavailable time grey as untitled background events (isInternal). */\n/* ------------------------------------------------------------------ */\n\n/** Local ISO date (YYYY-MM-DD) — the fixtures' local-wall-clock idiom;\n * absence lookups and shading ids key on local days, never UTC. */\nexport function localIsoDate(d: Date): string {\n const pad = (n: number): string => String(n).padStart(2, '0');\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;\n}\n\n/** The closed complement of one day's working range — up to two\n * segments (midnight→open, close→midnight); a closed day (undefined\n * hours) is one full-day segment. Minutes from local midnight. */\nexport function dayComplement(\n hours: CalendarDayHours | undefined,\n): Array<{ startMin: number; endMin: number }> {\n if (!hours) return [{ startMin: 0, endMin: 24 * 60 }];\n const segments: Array<{ startMin: number; endMin: number }> = [];\n if (hours.startMin > 0) {\n segments.push({ startMin: 0, endMin: hours.startMin });\n }\n if (hours.endMin < 24 * 60) {\n segments.push({ startMin: hours.endMin, endMin: 24 * 60 });\n }\n return segments;\n}\n\n/** Intersect an operator's day with the practice's — closed (undefined)\n * when either side is closed or the overlap is empty. */\nexport function intersectDayHours(\n a: CalendarDayHours | undefined,\n b: CalendarDayHours | undefined,\n): CalendarDayHours | undefined {\n if (!a || !b) return undefined;\n const startMin = Math.max(a.startMin, b.startMin);\n const endMin = Math.min(a.endMin, b.endMin);\n return startMin < endMin ? { startMin, endMin } : undefined;\n}\n\n/**\n * Project the COMPLEMENT of the business hours as background events\n * (`unavail-` ids — distinct from the find-slots glow's `avail-`\n * namespace): chair and plain axes shade outside the PRACTICE hours;\n * the operator axis shades outside each operator's own hours\n * (intersected with the practice's), with absence days\n * (`data.operatorAbsences`) washing that operator's whole column.\n * Untitled ON PURPOSE: a titled isInternal event renders the Calendar's\n * \"✓ Free\" bookable chip — these washes are decorative unavailability,\n * painted by FC's own `.fc-bg-event` rule through the\n * `--fc-bg-event-color` override on the Calendar's className.\n */\nexport function buildUnavailabilityEvents(\n args: {\n axisKind: DisplaySettings['resourceKind'];\n rangeStart: Date;\n rangeEnd: Date;\n visibleChairIds: string[];\n visibleOperatorIds: string[];\n /** True only when `hiddenDates` actually removes the absent column —\n * the kit honours it in `resourceTimeGrid*` (vertical) views only. */\n columnsHiddenWhenAbsent: boolean;\n /** Month: daygrid paints a background fill for day-spanning events\n * only, so emit ONE all-day wash per fully closed day and nothing for\n * a partial day (a timed slice renders no fill there). */\n wholeDayOnly?: boolean;\n },\n data: CalendarData,\n): CalendarEvent[] {\n const events: CalendarEvent[] = [];\n const pushSegments = (\n day: Date,\n hours: CalendarDayHours | undefined,\n resourceId?: string,\n ): void => {\n const dateIso = localIsoDate(day);\n if (args.wholeDayOnly) {\n const segments = dayComplement(hours);\n const wholeDay =\n segments.length === 1 &&\n segments[0].startMin === 0 &&\n segments[0].endMin === 24 * 60;\n if (!wholeDay) return;\n events.push({\n id: `unavail-${dateIso}-${resourceId ?? 'all'}-day`,\n title: '',\n start: dateIso,\n allDay: true,\n isInternal: true,\n ...(resourceId === undefined ? {} : { resourceId }),\n });\n return;\n }\n const segments = dayComplement(hours);\n /* The host's per-date closures (a lunch break inside a split shift)\n wash the same way, on every column of that date. A day with no\n hours is washed whole already, so they add nothing there. */\n const closed = hours ? (data.closedIntervals?.[dateIso] ?? []) : [];\n [...segments, ...closed].forEach((seg, i) => {\n const start = new Date(day);\n start.setMinutes(seg.startMin);\n /* endMin 1440 rolls into the next local midnight. */\n const end = new Date(day);\n end.setMinutes(seg.endMin);\n events.push({\n id: `unavail-${dateIso}-${resourceId ?? 'all'}-${i < segments.length ? i : `closed-${i - segments.length}`}`,\n title: '',\n start: start.toISOString(),\n end: end.toISOString(),\n isInternal: true,\n ...(resourceId === undefined ? {} : { resourceId }),\n });\n });\n };\n const cursor = new Date(args.rangeStart);\n cursor.setHours(0, 0, 0, 0);\n const last = new Date(args.rangeEnd);\n last.setHours(0, 0, 0, 0);\n while (cursor.getTime() <= last.getTime()) {\n /* A closed date or holiday washes the full day on every column. */\n const practiceHours = data.practiceClosedOn(localIsoDate(cursor))\n ? undefined\n : data.businessHours.practice[cursor.getDay()];\n if (args.axisKind === 'none') {\n pushSegments(cursor, practiceHours);\n } else if (args.axisKind === 'chair') {\n for (const chairId of args.visibleChairIds) {\n pushSegments(cursor, practiceHours, chairId);\n }\n } else {\n const dateIso = localIsoDate(cursor);\n for (const operatorId of args.visibleOperatorIds) {\n if (data.operatorAbsences[operatorId]?.includes(dateIso)) {\n /* Absent: full-day wash — unless the column is genuinely gone\n via `hiddenDates` (washing a removed column double-paints).\n On the horizontal timeline `hiddenDates` is inert, so the row\n survives and MUST still read as unavailable. */\n if (!args.columnsHiddenWhenAbsent) {\n pushSegments(cursor, undefined, operatorId);\n }\n continue;\n }\n pushSegments(\n cursor,\n intersectDayHours(\n practiceHours,\n data.businessHours.operators[operatorId]?.[cursor.getDay()],\n ),\n operatorId,\n );\n }\n }\n cursor.setDate(cursor.getDate() + 1);\n }\n return events;\n}\n\n/* A TOKEN reference, not a colour: under the demo's pinned tinted scheme\n the card copies backgroundColor verbatim into --calendar-event-accent\n (the solid scheme would try to parse it — keep the demo tinted). */\nexport const CLOSURE_HOLIDAY_ACCENT = 'var(--warning)';\n\n/** Closure banners (closed date · holiday · operator absence) share one\n * id prefix — the peek and click handlers route on it. */\nexport function isClosureEvent(event: CalendarEvent): boolean {\n return event.id.startsWith('closure-');\n}\n\n/**\n * All-day closure banners, one per visible column (platform: one closeDay\n * event per resource) — chair/operator axes need a resourceId or FC drops\n * the event; `'none'` (plain axis, and Month later) gets one resource-less.\n */\nexport function buildClosureBanners(\n args: {\n axisKind: DisplaySettings['resourceKind'];\n rangeStart: Date;\n rangeEnd: Date;\n visibleChairIds: string[];\n visibleOperatorIds: string[];\n /** The absent column is already gone via `hiddenDates` — no banner. */\n columnsHiddenWhenAbsent: boolean;\n labels: {\n closed: string;\n holiday: (name: string) => string;\n absence: (title?: string) => string;\n };\n },\n data: CalendarData,\n): CalendarEvent[] {\n const events: CalendarEvent[] = [];\n /* Graphite — the closed-day fixture's precedent — for closed and absent;\n the holiday banner wears the kit warning tint via its token. */\n const graphite = GOOGLE_CALENDAR_PALETTE[10];\n const push = (\n kind: CalendarClosure['kind'],\n dateIso: string,\n title: string,\n tint: Pick<CalendarEvent, 'backgroundColor' | 'textColor'>,\n resourceId?: string,\n ): void => {\n events.push({\n id: `closure-${kind}-${dateIso}-${resourceId ?? 'all'}`,\n title,\n start: dateIso,\n allDay: true,\n editable: false,\n startEditable: false,\n ...tint,\n ...(resourceId === undefined ? {} : { resourceId }),\n });\n };\n const columns: Array<string | undefined> =\n args.axisKind === 'chair'\n ? args.visibleChairIds\n : args.axisKind === 'operator'\n ? args.visibleOperatorIds\n : [undefined];\n const cursor = new Date(args.rangeStart);\n cursor.setHours(0, 0, 0, 0);\n const last = new Date(args.rangeEnd);\n last.setHours(0, 0, 0, 0);\n while (cursor.getTime() <= last.getTime()) {\n const dateIso = localIsoDate(cursor);\n const holiday = data.holidays.find((h) => h.dateIso === dateIso);\n if (data.closedDates.includes(dateIso)) {\n for (const column of columns) {\n push(\n 'closed',\n dateIso,\n args.labels.closed,\n {\n backgroundColor: graphite.hex,\n textColor: graphite.textColor,\n },\n column,\n );\n }\n } else if (holiday) {\n /* The banner names the day whatever the practice does with it; only\n the wash and bookability read `openOnHolidays` (platform parity). */\n for (const column of columns) {\n push(\n 'holiday',\n dateIso,\n args.labels.holiday(holiday.name),\n {\n backgroundColor: CLOSURE_HOLIDAY_ACCENT,\n },\n column,\n );\n }\n }\n /* Absences land ONLY on the absent operator's own column: on the chair\n or plain axis a banner would read as the chairs being closed — the\n toast, the editor's warning and the finder still surface them. */\n if (\n args.axisKind === 'operator' &&\n !args.columnsHiddenWhenAbsent &&\n !data.practiceClosedOn(dateIso)\n ) {\n for (const operatorId of args.visibleOperatorIds) {\n if (!data.operatorAbsences[operatorId]?.includes(dateIso)) continue;\n push(\n 'absence',\n dateIso,\n args.labels.absence(data.operatorAbsenceTitles[operatorId]),\n { backgroundColor: graphite.hex, textColor: graphite.textColor },\n operatorId,\n );\n }\n }\n cursor.setDate(cursor.getDate() + 1);\n }\n return events;\n}\n\n/* ------------------------------------------------------------------ */\n/* Day-print call sheet — what the Printer action outputs (decision 6):*/\n/* the platform's dayTemplate PDF, never the visual grid. The pure */\n/* builder first; the portalled DataTable sheet that renders it follows.*/\n/* ------------------------------------------------------------------ */\n\nexport interface PrintRow {\n id: string;\n start: Date;\n end?: Date;\n allDay: boolean;\n /** Masked exactly like the grid card under the privacy toggle. */\n patientName: string;\n /** Every labelled number; empty under privacy. */\n phones: CalendarPhoneNumber[];\n /** Free-text description (platform `name`) — unmasked, like the card. */\n description?: string;\n /** Care entries with their tooth elements — unmasked, like the card. */\n careLines: CalendarCareEntry[];\n chairId?: string;\n operatorId?: string;\n status?: CalendarEventStatus;\n /** An online booking still without a patient record. */\n unassigned: boolean;\n}\n\nexport interface PrintGroup {\n id: string;\n kind: 'chair' | 'operator' | 'all' | 'no-operator';\n title?: string;\n rows: PrintRow[];\n}\n\n/** Closed date · holiday · operator absence (the closures vocabulary),\n * plus the plain non-working weekday the full Week view shows. */\nexport type PrintDayNote = CalendarClosure | { kind: 'nonWorking' };\n\nexport interface PrintDaySection {\n date: Date;\n groups: PrintGroup[];\n tasks: Array<{ id: string; start: Date; allDay: boolean; title: string }>;\n notes: PrintDayNote[];\n}\n\nexport interface PrintSheetInput {\n rows: CalendarRow[];\n days: Date[];\n axisKind: DisplaySettings['resourceKind'];\n visibleChairIds: string[];\n visibleOperatorIds: string[];\n privacy: boolean;\n}\n\n/** A date-only start (all-day rows) is already a local day; anything\n * else parses as the wall clock the fixtures and the editor write. */\nexport function parseEventDate(value: string | Date): Date {\n return typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2}$/.test(value)\n ? new Date(`${value}T00:00:00`)\n : new Date(value);\n}\n\n/** The title privacy mode shows. TOTAL in the masked branch: a host\n * that supplies an EMPTY `privacyModeTitle` gets the bullets, never a\n * blank and never a fallback that would leak what we do or do not hold\n * on the one surface whose job is to say nothing. */\nexport function maskedTitle(event: CalendarEvent, privacy: boolean): string {\n if (!privacy) return event.title;\n const mask = event.privacyModeTitle;\n return mask !== undefined && mask.trim() !== '' ? mask : '•••';\n}\n\nexport function printRowOf(\n row: CalendarRow,\n privacy: boolean,\n data: CalendarData,\n): PrintRow {\n const { event } = row;\n const patient = eventPatientRef(event, data).record;\n const contact = data.bookingContacts[event.id];\n /* The record's numbers FIRST, then the booking contact — a patient the\n host supplied without a phone has none to print, which is not a\n reason to lose the number the booker typed. The old shape stopped at\n the record and printed nothing. */\n let phones: CalendarPhoneNumber[] = [];\n if (!privacy) {\n phones = patient ? patientPhones(patient) : [];\n if (phones.length === 0 && contact) {\n phones = [{ label: 'mobile', number: contact.phone }];\n }\n }\n return {\n id: event.id,\n start: parseEventDate(event.start),\n end: event.end ? parseEventDate(event.end) : undefined,\n allDay: Boolean(event.allDay),\n patientName: maskedTitle(event, privacy),\n phones,\n description: row.description,\n careLines: row.cares ?? [],\n chairId: row.chairId,\n operatorId: row.operatorId,\n status: event.status,\n unassigned: event.hasUnassignedPatient === true,\n };\n}\n\nexport function byStart(a: PrintRow, b: PrintRow): number {\n if (a.allDay !== b.allDay) return a.allDay ? -1 : 1;\n return a.start.getTime() - b.start.getTime();\n}\n\n/**\n * One section per printable day: the appointments the grid would show\n * (same chair/operator filter), grouped by the active axis, plus the\n * day's tasks and closure notes for the footer. Ids and keys only — the\n * sheet localises, so this stays unit-testable.\n */\nexport function buildPrintSheet(\n input: PrintSheetInput,\n data: CalendarData,\n): PrintDaySection[] {\n const { rows, days, axisKind, visibleChairIds, visibleOperatorIds, privacy } =\n input;\n const visible = rows.filter(\n (r) =>\n (!r.chairId || visibleChairIds.includes(r.chairId)) &&\n (!r.operatorId || visibleOperatorIds.includes(r.operatorId)),\n );\n const chairs = data.chairs.filter((c) => visibleChairIds.includes(c.id));\n const operators = data.operators.filter((o) =>\n visibleOperatorIds.includes(o.id),\n );\n return days.map((day) => {\n const dateIso = localIsoDate(day);\n const onDay = visible.filter(\n (r) => localIsoDate(parseEventDate(r.event.start)) === dateIso,\n );\n const appointments = onDay\n .filter(\n (r) =>\n !r.event.isTask &&\n !r.event.isInternal &&\n !r.event.isDraft &&\n !isClosureEvent(r.event),\n )\n .map((r) => printRowOf(r, privacy, data))\n .sort(byStart);\n let groups: PrintGroup[];\n if (axisKind === 'chair') {\n groups = chairs.map((c) => ({\n id: c.id,\n kind: 'chair',\n title: c.title,\n rows: appointments.filter((a) => a.chairId === c.id),\n }));\n } else if (axisKind === 'operator') {\n groups = operators.map((o) => ({\n id: o.id,\n kind: 'operator',\n title: o.title,\n rows: appointments.filter((a) => a.operatorId === o.id),\n }));\n /* The grid drops operator-less rows from its operator columns; the\n call sheet still lists them — the desk has to phone them too. */\n const unallocated = appointments.filter((a) => !a.operatorId);\n if (unallocated.length > 0) {\n groups.push({\n id: 'no-operator',\n kind: 'no-operator',\n rows: unallocated,\n });\n }\n } else {\n groups = [{ id: 'all', kind: 'all', rows: appointments }];\n }\n const tasks = onDay\n .filter((r) => r.event.isTask)\n .map((r) => ({\n id: r.event.id,\n start: parseEventDate(r.event.start),\n allDay: Boolean(r.event.allDay),\n title: maskedTitle(r.event, privacy),\n }))\n .sort((a, b) =>\n a.allDay !== b.allDay\n ? a.allDay\n ? -1\n : 1\n : a.start.getTime() - b.start.getTime(),\n );\n const notes: PrintDayNote[] = [];\n const closure = data.closureOn(dateIso);\n if (closure) {\n notes.push(closure);\n } else if (!data.businessHours.practice[day.getDay()]) {\n notes.push({ kind: 'nonWorking' });\n }\n if (!data.practiceClosedOn(dateIso)) {\n for (const o of operators) {\n const absence = data.closureOn(dateIso, o.id);\n if (absence?.kind === 'absence') notes.push(absence);\n }\n }\n return { date: day, groups, tasks, notes };\n });\n}\n\n/* AG Grid needs pixel row heights up front — a display:none subtree\n cannot be measured. One accessible body-sm line (16px × 1.6) plus cell\n padding; the default theme's 14px lines print a little airier. */\nexport const PRINT_LINE_PX = 26;\nexport const PRINT_ROW_PAD_PX = 10;\n/** Characters per wrapped line of free text in the cares column. */\nexport const PRINT_WRAP_CHARS = 22;\n/** Cells and headers tighten to the small step — the sheet has to fit an\n * A4 portrait; the var is read on the cell itself, so no cascade fight. */\nexport const PRINT_CELL_CLASS =\n 'ds:[--ag-cell-horizontal-padding:var(--spacing-sm)]';\n\n/** Every line the two stacked cells need; `minLines` lets the plain axis\n * reserve the two-line chair / operator cell. */\nexport function printRowHeight(row: PrintRow, minLines = 1): number {\n /* The booked-online notice wraps onto two lines in the patient column. */\n const patientLines = 1 + row.phones.length + (row.unassigned ? 2 : 0);\n const careLines =\n (row.description\n ? Math.ceil(row.description.length / PRINT_WRAP_CHARS)\n : 0) +\n row.careLines.reduce(\n (n, care) => n + 1 + (care.elements?.length ? 1 : 0),\n 0,\n );\n return (\n PRINT_ROW_PAD_PX +\n PRINT_LINE_PX * Math.max(patientLines, careLines, minLines, 1)\n );\n}\n\n/* Why a slot is refused, in words — shared by the grid's toasts and the\n editor's inline warning. */\nexport function closureReason(\n t: TFunction,\n locale: string,\n closure: CalendarClosure,\n date: Date,\n data: CalendarData,\n): string {\n const day = formatDay(locale, date);\n switch (closure.kind) {\n case 'closed':\n return t('calendarWorkspace.closures.closedReason', { date: day });\n case 'holiday':\n return t('calendarWorkspace.closures.holidayReason', {\n date: day,\n name: closure.name,\n });\n case 'absence':\n return t('calendarWorkspace.closures.absenceReason', {\n date: day,\n operator:\n data.operators.find((o) => o.id === closure.operatorId)?.title ?? '',\n });\n }\n}\n\n/** External seeding for the finder — e.g. the waiting list's per-entry\n * \"find slots\" action prefills the filters AND carries the patient\n * (plus care text/colour) through to the Book prefill. */\nexport interface FindSlotsSeed {\n tick: number;\n operatorId?: string;\n chairId?: string;\n durationMin?: number;\n patientId?: string;\n care?: string;\n /** A linked appointment's cares — ride into Book as linked cares. */\n cares?: CalendarCareEntry[];\n colorHex?: string;\n /**\n * Set when the search is a RESCHEDULE: booking a slot must move this\n * appointment rather than create a second one.\n */\n rescheduleEventId?: string;\n /** The waiting entry the search came from — cleared once it is booked. */\n waitingEntryId?: string;\n}\n\n/** Booking context that rides ALONG with a projection — so booking by\n * clicking a green range on the GRID prefills the same patient/care\n * the panel's own Book button would. */\nexport type AvailabilityContext = Pick<\n FindSlotsSeed,\n 'patientId' | 'care' | 'cares' | 'colorHex'\n> & {\n /** Optional search scope, retained for resource-axis consumers. */\n scopeOperatorId?: string;\n scopeChairId?: string;\n};\n\n/** One painted free range — see `mergeAvailabilityRanges`. */\nexport interface AvailabilityRange {\n /** Stable per range: `<resource or day>:<start ms>`. */\n key: string;\n start: Date;\n end: Date;\n /** The column the range belongs to on a resource axis. */\n resourceId?: string;\n}\n\n/**\n * Found slots as CONTIGUOUS ranges: one per resource on the chair and\n * operator axes, one per day on the plain grid. Touching or overlapping\n * slots collapse into a single range with a single label. The search\n * emits one slot per chair x operator pair at every step, so painting\n * them one by one stacks chips at the same minute and lights every step\n * of the day where any pair is free.\n */\nexport function mergeAvailabilityRanges(\n slots: readonly CalendarFreeSlot[],\n axisKind: 'none' | 'chair' | 'operator',\n): AvailabilityRange[] {\n const groups = new Map<\n string,\n { resourceId?: string; slots: CalendarFreeSlot[] }\n >();\n for (const slot of slots) {\n const resourceId =\n axisKind === 'operator'\n ? slot.operatorId\n : axisKind === 'chair'\n ? slot.chairId\n : undefined;\n const groupKey = resourceId ?? localIsoDate(slot.start);\n const group = groups.get(groupKey) ?? { resourceId, slots: [] };\n group.slots.push(slot);\n groups.set(groupKey, group);\n }\n const ranges: AvailabilityRange[] = [];\n for (const [groupKey, group] of groups) {\n const sorted = [...group.slots].sort(\n (a, b) => a.start.getTime() - b.start.getTime(),\n );\n let current: AvailabilityRange | null = null;\n for (const slot of sorted) {\n const startMs = slot.start.getTime();\n const endMs = startMs + slot.durationMin * 60000;\n if (current && startMs <= current.end.getTime()) {\n if (endMs > current.end.getTime()) current.end = new Date(endMs);\n continue;\n }\n current = {\n key: `${groupKey}:${startMs}`,\n start: new Date(startMs),\n end: new Date(endMs),\n ...(group.resourceId ? { resourceId: group.resourceId } : {}),\n };\n ranges.push(current);\n }\n }\n return ranges.sort((a, b) => a.start.getTime() - b.start.getTime());\n}\n\nexport interface CalendarFreeBand extends AvailabilityRange {\n /** Original bookable answers, in finder order, never a fabricated union slot. */\n options: readonly CalendarFreeSlot[];\n /** Distinct chair x operator combinations, not the number of start times. */\n optionCount: number;\n}\n\n/** Union free time per local day while retaining the original booking choices. */\nexport function buildFreeBands(\n slots: readonly CalendarFreeSlot[],\n): CalendarFreeBand[] {\n const valid = slots.filter(\n (slot) =>\n Number.isFinite(slot.start.getTime()) &&\n Number.isFinite(slot.durationMin) &&\n slot.durationMin > 0 &&\n Number.isFinite(\n new Date(slot.start.getTime() + slot.durationMin * 60000).getTime(),\n ),\n );\n const segments: CalendarFreeSlot[] = [];\n for (const slot of valid) {\n const end = slot.start.getTime() + slot.durationMin * 60000;\n if (!Number.isFinite(end)) continue;\n for (let start = slot.start.getTime(); start < end; ) {\n const midnight = new Date(start);\n midnight.setHours(24, 0, 0, 0);\n const segmentEnd = Math.min(end, midnight.getTime());\n segments.push({\n ...slot,\n start: new Date(start),\n durationMin: (segmentEnd - start) / 60000,\n });\n start = segmentEnd;\n }\n }\n return mergeAvailabilityRanges(segments, 'none').map((range) => {\n const options = [\n ...new Map(\n valid\n .filter(\n (slot) =>\n slot.start.getTime() < range.end.getTime() &&\n slot.start.getTime() + slot.durationMin * 60000 >\n range.start.getTime(),\n )\n .map((slot) => [\n JSON.stringify([\n slot.start.getTime(),\n slot.durationMin,\n slot.chairId,\n slot.operatorId,\n slot.careId,\n slot.medicalDeviceId,\n ]),\n slot,\n ]),\n ).values(),\n ];\n return {\n ...range,\n options,\n optionCount: new Set(\n options.map((slot) => JSON.stringify([slot.chairId, slot.operatorId])),\n ).size,\n };\n });\n}\n\n/**\n * The in-memory free-slot search over the loaded rows: closed dates and\n * holidays yield nothing, an operator away that day drops out of it, an\n * operator with hours of their own is held to them, a per-date closure\n * (`closedIntervals`) is never offered over, a day the host is still\n * loading (`dayLoadState`) is not answered from at all, and a slot clashes\n * with any row on its chair or a non-task row's operator.\n */\nexport function searchFreeSlots(\n args: {\n rows: CalendarRow[];\n chairs: readonly CalendarResource[];\n operators: readonly CalendarResource[];\n durationMin: number;\n fromDate: Date;\n toDate: Date;\n careId?: string;\n },\n data: CalendarData,\n): CalendarFreeSlot[] {\n const duration = args.durationMin;\n /* The host's clock: a slot that has already begun is not free. The\n platform's finder starts from now, never from opening time, and a\n receptionist reading \"09:00\" at half past twelve would book the past. */\n const nowMs = new Date(data.nowIso).getTime();\n const notBefore = Number.isNaN(nowMs) ? Number.NEGATIVE_INFINITY : nowMs;\n /* Timed busy windows, pre-parsed once. All-day events skipped (tasks\n carry no operator commitment on the platform). */\n const busy = args.rows\n .filter((r) => !r.event.allDay && r.event.end)\n .map((r) => ({\n chairId: r.chairId,\n operatorId: r.event.isTask ? undefined : r.operatorId,\n start: new Date(String(r.event.start)).getTime(),\n end: new Date(String(r.event.end)).getTime(),\n }));\n const found: CalendarFreeSlot[] = [];\n const cursor = new Date(args.fromDate);\n cursor.setHours(0, 0, 0, 0);\n const last = new Date(args.toDate);\n last.setHours(0, 0, 0, 0);\n while (cursor.getTime() <= last.getTime()) {\n const dateIso = localIsoDate(cursor);\n /* A day whose rows are still arriving cannot be searched: the busy\n set for it is incomplete, so \"free\" would be a guess dressed as an\n answer. Only when the host keeps the map at all — its ABSENCE says\n every day is loaded, which is every host that predates it. */\n if (data.dayLoadState && data.dayLoadState[dateIso] !== 'ready') {\n cursor.setDate(cursor.getDate() + 1);\n continue;\n }\n /* Practice hours per weekday; the weekend, a closed date and a\n holiday all yield no slots. */\n const dayHours = data.businessHours.practice[cursor.getDay()];\n if (!dayHours || data.practiceClosedOn(dateIso)) {\n cursor.setDate(cursor.getDate() + 1);\n continue;\n }\n const dayOperators = args.operators.filter(\n (o) => !(data.operatorAbsences[o.id] ?? []).includes(dateIso),\n );\n /* The host's per-date closures: a slot may not overlap one. */\n const closed = data.closedIntervals?.[dateIso] ?? [];\n for (const chair of args.chairs) {\n for (const operator of dayOperators) {\n /* An operator the hours map names is held to their own day, and\n one whose entry has nothing for this weekday is off; an operator\n the map does not name keeps the practice's hours — that is the\n host's \"unrestricted\" answer, not a missing one. */\n const operatorWeek = data.businessHours.operators[operator.id];\n const hours = operatorWeek\n ? intersectDayHours(dayHours, operatorWeek[cursor.getDay()])\n : dayHours;\n if (!hours) continue;\n for (\n let minute = hours.startMin;\n minute + duration <= hours.endMin;\n minute += SLOT_STEP_MIN\n ) {\n if (\n closed.some(\n (w) => minute < w.endMin && minute + duration > w.startMin,\n )\n ) {\n continue;\n }\n const start = new Date(cursor);\n start.setHours(Math.floor(minute / 60), minute % 60, 0, 0);\n const startMs = start.getTime();\n if (startMs < notBefore) continue;\n const endMs = startMs + duration * 60000;\n const clash = busy.some(\n (b) =>\n startMs < b.end &&\n endMs > b.start &&\n (b.chairId === chair.id || b.operatorId === operator.id),\n );\n if (clash) continue;\n found.push({\n start,\n durationMin: duration,\n chairId: chair.id,\n operatorId: operator.id,\n careId: args.careId,\n });\n }\n }\n }\n cursor.setDate(cursor.getDate() + 1);\n }\n /* Chronological read per day. */\n found.sort((a, b) => a.start.getTime() - b.start.getTime());\n return found;\n}\n","/**\n * Calendar demo, Increment 1 — the pure model the rail-hosted surface\n * adds on top of `calendar.model.ts`: the four-way range view with its\n * keyboard shortcuts, the extended display settings (default duration,\n * name display, map link), the practice-hours time axis, the platform's\n * filter semantics (nothing ticked = everyone) and the split-button\n * badge count. No React, no i18n lookups. Every read of practice data\n * goes through the explicit `data: CalendarData` parameter.\n */\nimport type { AppointmentItem } from '../../components/appointment-card';\nimport type {\n CalendarEvent,\n CalendarResource,\n} from '../../components/calendar';\nimport {\n APPOINTMENT_PALETTE,\n type PaletteSwatch,\n} from '../../components/color-picker';\nimport {\n contrastRatio,\n hexToHsl,\n} from '../../components/color-picker/color-utils';\nimport type { CalendarData } from './calendar.data';\nimport {\n type CalendarPatient,\n type CalendarWaitingEntry,\n type PatientChannelState,\n type PatientRef,\n channelReady,\n patientChannelState,\n patientIdOf,\n patientRefName,\n} from './calendar.types';\nimport { readBoolean, readEnum } from './calendar.preferences';\nimport {\n DAY_WINDOWS,\n DEFAULT_DISPLAY,\n type CalendarRow,\n type DisplaySettings,\n type EditorDraft,\n type EditorPrefill,\n NONE,\n type WaitingQuickView,\n eventPatientRef,\n eventStartMs,\n maskedTitle,\n patientRefById,\n readDisplaySettings,\n waitingEntryInQuickView,\n} from './calendar.model';\n\n/* ------------------------------------------------------------------ */\n/* The rail's tools — their ids, their strip order, and which of them */\n/* a given host can actually back */\n/* ------------------------------------------------------------------ */\n\n/* The MINIMAL Control Room: up to six tools, in strip order. The\n editor id doubles as the details tool — ONE entry wearing whichever\n form the last request asked for, so the strip never grows a second\n appointment tab. Lives here rather than beside the workspace so the\n surface can read it without importing back into its own parent. */\nexport const WORKSPACE_TOOL = {\n appointments: 'appointments',\n editor: 'appointment-editor',\n waitingList: 'waiting-list',\n notes: 'patient-notes',\n bookings: 'online-bookings',\n findSlots: 'find-slots',\n} as const;\n\n/** One of the workspace rail's six tools. Notes requires patient context. */\nexport type CalendarWorkspaceToolId =\n (typeof WORKSPACE_TOOL)[keyof typeof WORKSPACE_TOOL];\n\n/** Strip order — the order the rail registers the tools in, and the\n * order a host's `availableTools` is normalised back to. */\nexport const ALL_WORKSPACE_TOOLS: readonly CalendarWorkspaceToolId[] = [\n WORKSPACE_TOOL.appointments,\n WORKSPACE_TOOL.editor,\n WORKSPACE_TOOL.waitingList,\n WORKSPACE_TOOL.notes,\n WORKSPACE_TOOL.bookings,\n WORKSPACE_TOOL.findSlots,\n];\n\n/**\n * Which tools this host can back with real data, as a membership set.\n *\n * Appointments is forced in whatever the caller asked for: the rail\n * docks it as its resting panel, so leaving it out would leave an empty\n * dock rather than a smaller rail. An id the kit does not know is\n * ignored rather than thrown on — a host on a newer contract than the\n * kit it mounts must not crash the agenda.\n */\nexport function resolveAvailableTools(\n requested: readonly string[],\n): ReadonlySet<CalendarWorkspaceToolId> {\n const available = new Set<CalendarWorkspaceToolId>(\n ALL_WORKSPACE_TOOLS.filter((id) => requested.includes(id)),\n );\n available.add(WORKSPACE_TOOL.appointments);\n return available;\n}\n\n/* ------------------------------------------------------------------ */\n/* Range view — Day · 3 days · Week · Month, one dropdown, one key each */\n/* ------------------------------------------------------------------ */\n\n/** The platform's four ranges; \"Working week\" became the Show-weekends\n * item, so it is no longer a view of its own. */\nexport type WorkspaceViewId = 'day' | 'threeDays' | 'week' | 'month';\n\nexport const WORKSPACE_VIEWS: readonly WorkspaceViewId[] = [\n 'day',\n 'threeDays',\n 'week',\n 'month',\n] as const;\n\n/** CalendarView stem per range — composed with the column axis. */\nexport const WORKSPACE_VIEW_STEM: Record<\n WorkspaceViewId,\n 'Day' | 'ThreeDays' | 'Week' | 'Month'\n> = {\n day: 'Day',\n threeDays: 'ThreeDays',\n week: 'Week',\n month: 'Month',\n};\n\n/** Google-Calendar-style single-key shortcuts (X = 3 days, as GCal). */\nexport const VIEW_SHORTCUT_KEYS: Record<WorkspaceViewId, string> = {\n day: 'D',\n threeDays: 'X',\n week: 'W',\n month: 'M',\n};\n\nexport const readWorkspaceViewId = readEnum(WORKSPACE_VIEWS);\n\n/** The range a bare key press selects, case-insensitive; undefined when\n * the key is not a shortcut. */\nexport function viewForShortcutKey(key: string): WorkspaceViewId | undefined {\n const upper = key.toUpperCase();\n return WORKSPACE_VIEWS.find((id) => VIEW_SHORTCUT_KEYS[id] === upper);\n}\n\n/** Where a bare letter must keep its meaning: text entry, menus, dialogs\n * and other composite widgets that own their keyboard. */\nconst SHORTCUT_BLOCKED_SELECTOR = [\n 'input',\n 'textarea',\n 'select',\n '[contenteditable=\"\"]',\n '[contenteditable=\"true\"]',\n '[role=\"menu\"]',\n '[role=\"menubar\"]',\n '[role=\"listbox\"]',\n '[role=\"combobox\"]',\n '[role=\"textbox\"]',\n '[role=\"dialog\"]',\n '[role=\"alertdialog\"]',\n].join(', ');\n\nexport function shortcutAllowedOn(target: EventTarget | null): boolean {\n if (!(target instanceof Element)) return true;\n return target.closest(SHORTCUT_BLOCKED_SELECTOR) === null;\n}\n\n/** The keydown shape the shortcut resolver reads — a subset of\n * KeyboardEvent so tests can pass plain objects. */\nexport interface ShortcutKeydown {\n key: string;\n altKey: boolean;\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n repeat: boolean;\n defaultPrevented: boolean;\n target: EventTarget | null;\n}\n\n/** The range a page-level keydown switches to, or undefined when the\n * press must be left alone (modifier, auto-repeat, typing, an open\n * menu or dialog, already handled). */\nexport function shortcutViewForKeydown(\n event: ShortcutKeydown,\n): WorkspaceViewId | undefined {\n if (event.defaultPrevented || event.repeat) return undefined;\n if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {\n return undefined;\n }\n if (!shortcutAllowedOn(event.target)) return undefined;\n return viewForShortcutKey(event.key);\n}\n\n/** Weekend visibility is a per-user choice now (platform hidden days):\n * off hides Saturday and Sunday in every range view. */\nexport function weekendHiddenDays(showWeekends: boolean): number[] {\n return showWeekends ? [] : [0, 6];\n}\n\n/* ------------------------------------------------------------------ */\n/* Display settings — the Final State knobs plus the platform's four */\n/* ------------------------------------------------------------------ */\n\nexport type OperatorNameDisplay = 'full' | 'initials';\nexport type ChairNameDisplay = 'full' | 'short';\n\nexport interface WorkspaceDisplaySettings extends DisplaySettings {\n /** The per-user default appointment length (platform 30). */\n defaultDurationMin: number;\n /** Column header treatment for people: dot + name, or initials disc. */\n operatorNameDisplay: OperatorNameDisplay;\n /** Column header treatment for chairs: full name or the short code. */\n chairNameDisplay: ChairNameDisplay;\n /** Show the Google Maps link in the appointment details. */\n mapsLink: boolean;\n}\n\nexport const DEFAULT_DURATION_RANGE = { min: 5, max: 240, step: 5 } as const;\n\nexport const DEFAULT_WORKSPACE_DISPLAY: WorkspaceDisplaySettings = {\n ...DEFAULT_DISPLAY,\n /* Practice hours, not extended: the platform's time axis follows the\n practice's opening and closing; the cog window stays an override. */\n window: 'working',\n defaultDurationMin: 30,\n operatorNameDisplay: 'initials',\n chairNameDisplay: 'full',\n mapsLink: false,\n};\n\nconst readOperatorNameDisplay = readEnum<OperatorNameDisplay>([\n 'full',\n 'initials',\n]);\nconst readChairNameDisplay = readEnum<ChairNameDisplay>(['full', 'short']);\n\nfunction readDurationMin(raw: unknown): number | undefined {\n if (typeof raw !== 'number' || !Number.isFinite(raw)) return undefined;\n const rounded = Math.round(raw);\n return rounded >= DEFAULT_DURATION_RANGE.min &&\n rounded <= DEFAULT_DURATION_RANGE.max\n ? rounded\n : undefined;\n}\n\n/** Remembered Increment 1 display settings, validated per field over the\n * Increment 1 defaults (a Final State shape keeps every knob it knows). */\nexport function readWorkspaceDisplaySettings(\n raw: unknown,\n): WorkspaceDisplaySettings | undefined {\n if (!raw || typeof raw !== 'object') return undefined;\n const source = raw as Record<string, unknown>;\n /* The base reader fills unknown fields with the Final State defaults —\n re-apply the Increment 1 default for the one that differs unless the\n stored shape names it. */\n const base = readDisplaySettings(raw) ?? { ...DEFAULT_DISPLAY };\n const next: WorkspaceDisplaySettings = {\n ...DEFAULT_WORKSPACE_DISPLAY,\n ...base,\n window:\n source.window === undefined\n ? DEFAULT_WORKSPACE_DISPLAY.window\n : base.window,\n };\n const duration = readDurationMin(source.defaultDurationMin);\n if (duration !== undefined) next.defaultDurationMin = duration;\n const operatorName = readOperatorNameDisplay(source.operatorNameDisplay);\n if (operatorName !== undefined) next.operatorNameDisplay = operatorName;\n const chairName = readChairNameDisplay(source.chairNameDisplay);\n if (chairName !== undefined) next.chairNameDisplay = chairName;\n const mapsLink = readBoolean(source.mapsLink);\n if (mapsLink !== undefined) next.mapsLink = mapsLink;\n return next;\n}\n\n/* ------------------------------------------------------------------ */\n/* Time axis — practice hours by default */\n/* ------------------------------------------------------------------ */\n\nfunction minutesToClock(min: number): string {\n const pad = (n: number): string => String(n).padStart(2, '0');\n return `${pad(Math.floor(min / 60))}:${pad(min % 60)}`;\n}\n\n/** Earliest opening and latest closing across the practice's week —\n * the platform's `openingTime` / `closingTime` for the time axis. */\nexport function practiceDayWindow(data: CalendarData): {\n min: string;\n max: string;\n} {\n const days = Object.values(data.businessHours.practice).filter(\n (hours): hours is NonNullable<typeof hours> => hours !== undefined,\n );\n if (days.length === 0) return DAY_WINDOWS.working;\n const startMin = Math.min(...days.map((d) => d.startMin));\n const endMin = Math.max(...days.map((d) => d.endMin));\n return { min: minutesToClock(startMin), max: minutesToClock(endMin) };\n}\n\n/** The axis for a cog window: `working` is the practice's own hours;\n * extended and full stay the Final State overrides. */\nexport function workspaceDayWindow(\n window: DisplaySettings['window'],\n data: CalendarData,\n): { min: string; max: string } {\n return window === 'working' ? practiceDayWindow(data) : DAY_WINDOWS[window];\n}\n\n/* ------------------------------------------------------------------ */\n/* Filters — platform semantics: nothing ticked shows everyone */\n/* ------------------------------------------------------------------ */\n\n/** The ids a selection shows: the ticked ones, or all when none is. */\nexport function effectiveIds(\n selected: readonly string[],\n all: readonly string[],\n): string[] {\n return selected.length > 0 ? [...selected] : [...all];\n}\n\n/** Tick or untick `ids` in a selection (a row or a whole group). */\nexport function toggleSelectedIds(\n prev: readonly string[],\n ids: readonly string[],\n checked: boolean | 'indeterminate',\n): string[] {\n return checked === true\n ? [...prev, ...ids.filter((id) => !prev.includes(id))]\n : prev.filter((id) => !ids.includes(id));\n}\n\n/** What the Reset chip counts: every ticked chair and operator. */\nexport function activeFilterCount(\n selectedChairIds: readonly string[],\n selectedOperatorIds: readonly string[],\n): number {\n return selectedChairIds.length + selectedOperatorIds.length;\n}\n\n/* ---- disabled operators (parity spec §D.11) ---------------------- */\n\n/**\n * Disabled operators holding at least one appointment that STARTS inside\n * the visible range — the platform's carve-out\n * (`NewCalendar/Library.js`: `isActive(op) || hasAppointments(op)`).\n * Their column stands whatever the \"Show disabled operators\" switch\n * says, so hiding the operator can never hide an appointment.\n */\nexport function bookedDisabledOperatorIds(\n rows: readonly CalendarRow[],\n inactiveIds: readonly string[],\n range: { start: number; end: number } | null,\n): string[] {\n if (!range) return [];\n const inactive = new Set(inactiveIds);\n const booked = new Set<string>();\n for (const row of rows) {\n const id = row.operatorId;\n if (!id || !inactive.has(id) || booked.has(id)) continue;\n if (row.event.isTask || row.event.isInternal) continue;\n const startMs = new Date(String(row.event.start)).getTime();\n if (startMs >= range.start && startMs < range.end) booked.add(id);\n }\n return inactiveIds.filter((id) => booked.has(id));\n}\n\n/**\n * The operators the grid may give a column to when NOTHING is ticked:\n * every active one, the disabled ones while the switch reveals them, and\n * any disabled operator the carve-out keeps. An explicit selection still\n * wins over all three (platform: `kept.filter(selected)`).\n */\nexport function columnableOperatorIds(args: {\n operators: readonly CalendarResource[];\n inactiveIds: readonly string[];\n showDisabled: boolean;\n keepIds: readonly string[];\n}): string[] {\n const inactive = new Set(args.inactiveIds);\n const keep = new Set(args.keepIds);\n return args.operators\n .filter((o) => !inactive.has(o.id) || args.showDisabled || keep.has(o.id))\n .map((o) => o.id);\n}\n\n/** The operators the filter list offers — disabled ones only once the\n * session switch reveals them (the carve-out is a column, not a row). */\nexport function listedOperators(\n operators: readonly CalendarResource[],\n inactiveIds: readonly string[],\n showDisabled: boolean,\n): CalendarResource[] {\n if (showDisabled) return [...operators];\n const inactive = new Set(inactiveIds);\n return operators.filter((o) => !inactive.has(o.id));\n}\n\n/* ------------------------------------------------------------------ */\n/* Column headers and badges */\n/* ------------------------------------------------------------------ */\n\n/** Chair column label per the cog: the full name, or the fixture's short\n * code (the platform's \"first two letters\" setting). */\nexport function chairResourceTitle(\n chair: CalendarResource,\n mode: ChairNameDisplay,\n): string {\n if (mode === 'full') return chair.title;\n return chair.shortTitle ?? chair.title.replace(/\\s+/g, '').slice(0, 2);\n}\n\n/** Operator column label: the plain name, or the name plus the muted\n * Disabled marker when the practice has disabled them. The kit Calendar\n * renders a resource header from its `title`, so the marker rides\n * there — and reaches the Avatar's accessible name under initials. */\nexport function operatorResourceTitle(\n operator: CalendarResource,\n isDisabled: boolean,\n disabledLabel: string,\n): string {\n return isDisabled ? `${operator.title} · ${disabledLabel}` : operator.title;\n}\n\n/** Whole minutes between two instants — the resize toast's figure. */\nexport function minutesBetween(\n start: Date | string,\n end: Date | string,\n): number {\n return Math.round(\n (new Date(end).getTime() - new Date(start).getTime()) / 60000,\n );\n}\n\n/** Re-ends one appointment. The resize path writes through this twice —\n * once for the drag, once for the Undo that restores the old end — so\n * the two can never drift apart. */\nexport function rowsWithEnd(\n rows: readonly CalendarRow[],\n eventId: string,\n end: Date,\n): CalendarRow[] {\n return rows.map((row) =>\n row.event.id === eventId ? { ...row, event: { ...row.event, end } } : row,\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Dialogs — recurring scope, the editor's platform extras, placement */\n/* (Move… / Copy…) and the post-save visibility check */\n/* ------------------------------------------------------------------ */\n\n/** The platform's recurring-mode chooser (move, delete, save on edit). */\nexport type RecurringScope = 'this' | 'following' | 'all';\n\nexport const RECURRING_SCOPES: readonly RecurringScope[] = [\n 'this',\n 'following',\n 'all',\n] as const;\n\n/** Literal map (not a template) so key extractors see every key. */\nexport const RECURRING_SCOPE_LABEL_KEY: Record<RecurringScope, string> = {\n this: 'scopeThis',\n following: 'scopeFollowing',\n all: 'scopeAll',\n};\n\n/** How the create form asks for the required documents' signature. */\nexport type RequiredDocsSignMode = 'sms' | 'email' | 'none';\n\n/** What the editor reports beside the draft — the platform-only choices\n * the shared `EditorDraft` never needed. */\nexport interface EditorDraftExtras {\n recurringSaveMode?: RecurringScope;\n requiredDocsSignMode?: RequiredDocsSignMode;\n branchId?: string;\n}\n\n/** Delete confirmation choices — the recurring scope and, for a\n * price-list recurrence parent, the care-plan cleanup. */\nexport interface DeleteOptions {\n scope: RecurringScope;\n removeFromCarePlan?: boolean;\n}\n\n/** The occurrences a scope names, in series order — the event itself\n * for `this`, it and its later occurrences for `following`, the whole\n * series for `all`. A row outside a series only ever names itself. */\nexport function seriesScopeEventIds(\n rows: readonly CalendarRow[],\n eventId: string,\n scope: RecurringScope,\n): string[] {\n const row = rows.find((r) => r.event.id === eventId);\n if (!row?.series || scope === 'this') return [eventId];\n const series = row.series;\n return rows\n .filter(\n (r) =>\n r.series?.id === series.id &&\n (scope === 'all' || r.series.index >= series.index),\n )\n .sort((a, b) => (a.series?.index ?? 0) - (b.series?.index ?? 0))\n .map((r) => r.event.id);\n}\n\n/** Every timed appointment overlapping `[start, end)` — cancelled and\n * absent ones, tasks, washes and the row itself never count (platform\n * busy check). */\nexport function slotConflicts(\n rows: readonly CalendarRow[],\n slot: {\n start: Date;\n end: Date;\n chairId?: string;\n operatorId?: string;\n excludeEventId?: string;\n },\n): { chairBusy: boolean; operatorBusy: boolean } {\n const startMs = slot.start.getTime();\n const endMs = slot.end.getTime();\n let chairBusy = false;\n let operatorBusy = false;\n for (const row of rows) {\n const event = row.event;\n if (event.id === slot.excludeEventId) continue;\n if (event.isTask || event.isInternal || event.allDay || !event.end) {\n continue;\n }\n if (event.status === 'cancelled' || event.status === 'absent') continue;\n const rowStart = new Date(event.start).getTime();\n const rowEnd = new Date(event.end).getTime();\n if (!(rowStart < endMs && startMs < rowEnd)) continue;\n if (slot.chairId && row.chairId === slot.chairId) chairBusy = true;\n if (slot.operatorId && row.operatorId === slot.operatorId) {\n operatorBusy = true;\n }\n }\n return { chairBusy, operatorBusy };\n}\n\n/** Devices the chosen cares need, deduplicated, in care order. */\nexport function devicesForCares(\n cares: readonly { careId?: string }[] | undefined,\n devicesByCare: Readonly<Record<string, readonly string[]>>,\n): string[] {\n const out: string[] = [];\n for (const care of cares ?? []) {\n for (const device of care.careId\n ? (devicesByCare[care.careId] ?? [])\n : []) {\n if (!out.includes(device)) out.push(device);\n }\n }\n return out;\n}\n\n/**\n * Which sign / notify channels a patient can take a request on — as the\n * FOUR-state `PatientChannelState`, not a boolean.\n *\n * A boolean here was the bug: it folded \"the record says the practice\n * holds no number\" together with \"we were never told\", and every caller\n * then printed the first as the second (\"No SMS-enabled number on\n * file\") for a patient the host had simply supplied without a `phone`.\n * Callers now read the state: `channelReady` seeds a control ON,\n * `channelOfferable` decides whether to disable it at all, and\n * `channelReasonKey` gives a reason ONLY in the states that have one.\n */\nexport function signChannelStates(ref: PatientRef): {\n sms: PatientChannelState;\n email: PatientChannelState;\n} {\n return {\n sms: patientChannelState(ref, 'sms'),\n email: patientChannelState(ref, 'email'),\n };\n}\n\n/** The platform's default: SMS when the patient can take one, else\n * email, else nothing. \"Can take one\" is `ready` alone — a channel we\n * know nothing about is not a channel to send on by default. */\nexport function defaultSignMode(ref: PatientRef): RequiredDocsSignMode {\n const channels = signChannelStates(ref);\n return channelReady(channels.sms)\n ? 'sms'\n : channelReady(channels.email)\n ? 'email'\n : 'none';\n}\n\n/** The patient's address as one line — the map link's search text, and\n * the link's own label. Empty when the host supplied no address at all,\n * which is the caller's signal to leave the map row out rather than\n * offer a search for nothing. */\nexport function patientAddressLine(patient: CalendarPatient): string {\n return [patient.address, patient.postalCode, patient.city]\n .filter((part): part is string => Boolean(part))\n .join(', ');\n}\n\n/** The map link's own LABEL — street and city, the pair the popover has\n * always printed. The postcode belongs in the search query, not in the\n * visible text, so widening `patientAddressLine` for the URL must not\n * drag the label along with it. */\nexport function patientAddressLabel(patient: CalendarPatient): string {\n return [patient.address, patient.city]\n .filter((part): part is string => Boolean(part))\n .join(', ');\n}\n\n/** Google Maps search for the patient's address — the popover's map link. */\nexport function patientMapsUrl(patient: CalendarPatient): string {\n const query = patientAddressLine(patient);\n return `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(query)}`;\n}\n\n/** A CREATE mode armed by a deep link (`createParameters`) or the\n * Backlog's Schedule: the next empty-slot click opens the editor with\n * this context already filled in (platform `_switchMode('create')`). */\nexport interface CreateModeRequest {\n tick: number;\n prefill: EditorPrefill;\n /** Named in the banner when the context carries a patient. */\n patientName?: string;\n}\n\n/* The inks the kit itself pairs with a swatch (`PaletteSwatch.textColor`),\n read off the appointment palette rather than re-typed as literals. */\nconst BANNER_INKS: readonly string[] = [\n ...new Set(\n APPOINTMENT_PALETTE.map((swatch) => swatch.textColor).filter(\n (ink): ink is NonNullable<PaletteSwatch['textColor']> => Boolean(ink),\n ),\n ),\n];\n\n/** Legible ink for a mode banner tinted with an appointment colour. The\n * Google palette ships no text colour, so the pair is settled by the\n * kit's own contrast maths rather than by eye. */\nexport function bannerTextColor(backgroundHex?: string): string | undefined {\n if (!backgroundHex) return undefined;\n const bg = hexToHsl(backgroundHex);\n let best: string | undefined;\n let bestRatio = 0;\n for (const ink of BANNER_INKS) {\n const ratio = contrastRatio(hexToHsl(ink), bg);\n if (ratio > bestRatio) {\n bestRatio = ratio;\n best = ink;\n }\n }\n return best;\n}\n\n/** A Move… or Copy… armed from the details dialog: the next empty-slot\n * click places the source appointment there. */\nexport interface PlacementRequest {\n kind: 'move' | 'copy';\n eventId: string;\n /** Copy only — carry the linked treatments along (platform's two copies). */\n withTreatments?: boolean;\n /** Armed from a waiting-list Reschedule — the entry leaves the queue\n * once the move lands (platform parity). */\n waitingEntryId?: string;\n}\n\n/** The platform's \"Copia & incolla\": the same appointment on a new slot\n * with a fresh id — never a series member, treatments only on request.\n * An all-day source stays all-day on the target date. */\nexport function copyRowAt(\n source: CalendarRow,\n target: {\n start: Date;\n resourceId?: string;\n axisKind: DisplaySettings['resourceKind'];\n },\n id: string,\n withTreatments: boolean,\n): CalendarRow {\n const sourceStart = new Date(source.event.start);\n const sourceEnd = source.event.end ? new Date(source.event.end) : undefined;\n const durationMs = sourceEnd\n ? sourceEnd.getTime() - sourceStart.getTime()\n : 0;\n const pad2 = (n: number): string => String(n).padStart(2, '0');\n const start = new Date(target.start);\n const startValue = source.event.allDay\n ? `${start.getFullYear()}-${pad2(start.getMonth() + 1)}-${pad2(start.getDate())}`\n : start.toISOString();\n const endValue =\n source.event.allDay || !sourceEnd\n ? undefined\n : new Date(start.getTime() + durationMs).toISOString();\n const rehomed =\n target.axisKind === 'chair' && target.resourceId\n ? { chairId: target.resourceId }\n : target.axisKind === 'operator' && target.resourceId\n ? { operatorId: target.resourceId }\n : {};\n const event: CalendarEvent = {\n ...source.event,\n id,\n start: startValue,\n end: endValue,\n resourceId: undefined,\n isRecurring: undefined,\n isRecurrenceParent: undefined,\n ...(rehomed.operatorId ? { operatorId: rehomed.operatorId } : {}),\n };\n return {\n event,\n chairId: source.chairId,\n operatorId: source.operatorId,\n ...rehomed,\n description: source.description,\n cares: withTreatments ? source.cares : undefined,\n careLink: withTreatments ? source.careLink : undefined,\n series: undefined,\n };\n}\n\n/** Apply an edit saved with \"this and following\" / \"all\" to the other\n * occurrences: each keeps its own day shifted by the same delta as the\n * edited one, and takes the edited duration, allocation, colour, status,\n * type and description. */\nexport function applySeriesEdit(\n rows: readonly CalendarRow[],\n primaryPrev: CalendarRow,\n draft: EditorDraft,\n siblingIds: readonly string[],\n data: CalendarData,\n): CalendarRow[] {\n if (siblingIds.length === 0 || draft.allDay) return [...rows];\n const prevStart = new Date(primaryPrev.event.start);\n const nextStart = new Date(draft.date);\n nextStart.setHours(draft.time.hours, draft.time.minutes, 0, 0);\n const deltaMs = nextStart.getTime() - prevStart.getTime();\n const linkedCares = draft.careLink\n ? data.careEntriesFromLink(draft.careLink)\n : undefined;\n return rows.map((row) => {\n if (!siblingIds.includes(row.event.id) || row.event.allDay) return row;\n const start = new Date(new Date(row.event.start).getTime() + deltaMs);\n const end = new Date(start.getTime() + draft.durationMin * 60000);\n return {\n ...row,\n chairId: draft.chairId,\n operatorId: draft.operatorId,\n description: draft.care,\n cares: linkedCares ?? draft.cares ?? row.cares,\n event: {\n ...row.event,\n start: start.toISOString(),\n end: end.toISOString(),\n status: draft.status ?? row.event.status,\n backgroundColor: draft.colorHex,\n isTelehealth: draft.isTelehealth || undefined,\n operatorId: draft.operatorId,\n },\n };\n });\n}\n\n/** What the post-save toast needs to decide whether the saved\n * appointment is on screen: its day and its allocation. */\nexport interface SaveNotice {\n tick: number;\n date: Date;\n chairId?: string;\n operatorId?: string;\n}\n\n/** Why a saved appointment is not on the grid right now — empty when it\n * is visible. The \"Go to\" action undoes exactly these. */\nexport function hiddenReasons(\n notice: Pick<SaveNotice, 'date' | 'chairId' | 'operatorId'>,\n view: {\n visibleRange: { start: number; end: number } | null;\n hiddenDays: readonly number[];\n selectedChairIds: readonly string[];\n selectedOperatorIds: readonly string[];\n },\n): Array<'range' | 'weekend' | 'chair' | 'operator'> {\n const out: Array<'range' | 'weekend' | 'chair' | 'operator'> = [];\n const t = notice.date.getTime();\n if (\n !view.visibleRange ||\n t < view.visibleRange.start ||\n t >= view.visibleRange.end\n ) {\n out.push('range');\n }\n if (view.hiddenDays.includes(notice.date.getDay())) out.push('weekend');\n if (\n notice.chairId &&\n view.selectedChairIds.length > 0 &&\n !view.selectedChairIds.includes(notice.chairId)\n ) {\n out.push('chair');\n }\n if (\n notice.operatorId &&\n view.selectedOperatorIds.length > 0 &&\n !view.selectedOperatorIds.includes(notice.operatorId)\n ) {\n out.push('operator');\n }\n return out;\n}\n\n/* ------------------------------------------------------------------ */\n/* Upcoming appointments — the rail's default panel */\n/* ------------------------------------------------------------------ */\n\n/**\n * The platform DASHBOARD widget's window (`upcomingAppointmentsAction`):\n * NOW → `forwardDays` later at 23:59:59.999, cancelled excluded, date\n * ascending, no row limit. `backDays` is 0 at rest — the kit timeline's\n * presets and its edge loaders widen the derived window in place of a\n * fetch, so the panel can look further than the platform's seven days.\n */\nexport interface UpcomingWindow {\n /** Days of history the panel has been widened to; 0 starts at NOW. */\n backDays: number;\n /** Days ahead — the platform's seven at rest. */\n forwardDays: number;\n}\n\n/** Platform default: now to the end of the seventh day. */\nexport const UPCOMING_FORWARD_DAYS = 7;\n/** How far one widening step reaches at either edge. */\nexport const UPCOMING_STEP_DAYS = 7;\n/** Where the widening stops — the demo's own ceiling, not the platform's. */\nexport const UPCOMING_MAX_DAYS = 180;\n\nexport const DEFAULT_UPCOMING_WINDOW: UpcomingWindow = {\n backDays: 0,\n forwardDays: UPCOMING_FORWARD_DAYS,\n};\n\n/** Whole calendar days between two instants, midnight to midnight. */\nfunction dayDelta(fromIso: string, toIso: string): number {\n const from = new Date(fromIso);\n from.setHours(0, 0, 0, 0);\n const to = new Date(toIso);\n to.setHours(0, 0, 0, 0);\n return Math.round((to.getTime() - from.getTime()) / 86_400_000);\n}\n\n/**\n * Epoch bounds of a window, inclusive of its closing second.\n *\n * The start always lands on a day boundary — midnight of\n * `nowIso - backDays` — never at the exact instant of `now`. At rest\n * (`backDays: 0`) that means \"the beginning of today\", not \"this second\":\n * a row that has already started (waiting room, in the chair) stays in\n * the window instead of disappearing the moment it begins. Widening\n * (`widenUpcomingWindow('earlier', …)`) reaches further back a whole day\n * at a time from that same floor.\n */\nexport function upcomingWindowBounds(\n nowIso: string,\n window: UpcomingWindow,\n): { startMs: number; endMs: number } {\n const start = new Date(nowIso);\n start.setDate(start.getDate() - window.backDays);\n start.setHours(0, 0, 0, 0);\n const end = new Date(nowIso);\n end.setDate(end.getDate() + window.forwardDays);\n end.setHours(23, 59, 59, 999);\n return { startMs: start.getTime(), endMs: end.getTime() };\n}\n\n/** One widening step at either edge, capped at the ceiling. */\nexport function widenUpcomingWindow(\n window: UpcomingWindow,\n edge: 'earlier' | 'later',\n): UpcomingWindow {\n const grow = (days: number): number =>\n Math.min(UPCOMING_MAX_DAYS, days + UPCOMING_STEP_DAYS);\n return edge === 'earlier'\n ? { ...window, backDays: grow(window.backDays) }\n : { ...window, forwardDays: grow(window.forwardDays) };\n}\n\n/** Widen just far enough to reach `targetIso` — the timeline's presets and\n * its jump-to-date land on days the default seven never covered. */\nexport function upcomingWindowCovering(\n window: UpcomingWindow,\n nowIso: string,\n targetIso: string,\n): UpcomingWindow {\n const delta = dayDelta(nowIso, targetIso);\n const reach = (days: number, wanted: number): number =>\n Math.min(UPCOMING_MAX_DAYS, Math.max(days, wanted));\n return delta < 0\n ? { ...window, backDays: reach(window.backDays, -delta) }\n : { ...window, forwardDays: reach(window.forwardDays, delta) };\n}\n\n/**\n * The rows the widget lists: appointments starting inside the window,\n * cancelled excluded, date ascending. Background washes and the composing\n * draft never qualify; tasks are already out of the Increment 1 feed.\n */\nexport function upcomingAppointmentRows(\n rows: CalendarRow[],\n bounds: { startMs: number; endMs: number },\n): CalendarRow[] {\n return rows\n .filter((row) => {\n const event = row.event;\n if (event.isTask || event.isInternal || event.isDraft) return false;\n if (event.status === 'cancelled') return false;\n const startMs = new Date(event.start).getTime();\n return startMs >= bounds.startMs && startMs <= bounds.endMs;\n })\n .sort(\n (a, b) =>\n new Date(a.event.start).getTime() - new Date(b.event.start).getTime(),\n );\n}\n\n/**\n * One agenda row as the kit timeline's item — identity, allocation and\n * care lines; the row id stays the event id so a click maps straight\n * back onto the grid.\n *\n * The card prints its own \"no patient assigned\" whenever `patient` is\n * absent, so absence here has to mean exactly that: the appointment\n * carries NO patient id. A row that carries one but whose record the\n * host could not resolve still names its patient — from the record, from\n * the title the row already carries, and only then from\n * `unresolvedPatientLabel`, which must say the record was not loaded and\n * never that nobody is booked.\n */\nexport function upcomingAppointmentItem(\n row: CalendarRow,\n privacy: boolean,\n data: CalendarData,\n /** Localised name-of-last-resort for an unresolvable patient id. */\n unresolvedPatientLabel: string,\n /** Localised stand-in for a row whose details the host is still\n * fetching (`detailsPending`). Such a row carries no patient id and\n * no title, so without it the feed would print a nameless line. */\n pendingDetailsLabel?: string,\n): AppointmentItem {\n const event = row.event;\n const start = new Date(event.start);\n const end = event.end ? new Date(event.end) : start;\n const operator = data.operators.find((o) => o.id === row.operatorId);\n const chair = data.chairs.find((c) => c.id === row.chairId);\n const ref = eventPatientRef(event, data);\n /* Privacy is TOTAL: the mask is the answer, and an empty\n `privacyModeTitle` degrades to the bullets, never to a sentence\n about our lookup — leaking the record's state on the one surface\n whose job is to say nothing would be worse than saying nothing. */\n const patientName = privacy\n ? maskedTitle(event, true)\n : patientRefName(ref, event.title, unresolvedPatientLabel);\n return {\n id: event.id,\n startIso:\n typeof event.start === 'string' ? event.start : start.toISOString(),\n durationMin: Math.max(\n 0,\n Math.round((end.getTime() - start.getTime()) / 60_000),\n ),\n state: event.status ?? 'confirmed',\n type: event.isTelehealth ? 'telehealth' : 'inPractice',\n operator: operator ? { name: operator.title } : undefined,\n chair: chair?.title,\n /* Still loading: the row says so in its own words rather than read\n as an appointment nobody is booked into. */\n patient: event.detailsPending\n ? { name: pendingDetailsLabel ?? unresolvedPatientLabel }\n : ref.assigned\n ? { name: patientName }\n : undefined,\n treatments: row.cares?.map((care) => ({\n careName: care.name,\n elements: care.elements,\n })),\n flags: {\n bookedOnline: event.isBookedOnline,\n noPatientAssigned: event.hasUnassignedPatient,\n highlightedAnamnesis: event.hasHighlightedAnamnesis,\n billable: event.hasBillableAmount,\n },\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Online bookings — the platform's \"Prenotazioni online da */\n/* controllare\" query, behind Increment 1's toolbar button */\n/* ------------------------------------------------------------------ */\n\n/** How far back the platform's booking query looks, on `createdAt`. */\nexport const ONLINE_BOOKINGS_WINDOW_DAYS = 30;\n\n/**\n * Bookings still to check: created online (or through the API) within\n * the last 30 days, not cancelled, and still missing a patient OR an\n * operator. Mirrors the repository query behind the platform's alert\n * strip; Increment 1 renders the same count on a toolbar button.\n */\nexport function onlineBookingsToCheck(\n rows: readonly CalendarRow[],\n data: CalendarData,\n): CalendarRow[] {\n const cutoff =\n new Date(data.nowIso).getTime() - ONLINE_BOOKINGS_WINDOW_DAYS * 86_400_000;\n return rows.filter((row) => {\n const event = row.event;\n if (event.isBookedOnline !== true) return false;\n if (event.status === 'cancelled') return false;\n if (event.hasUnassignedPatient !== true && row.operatorId) return false;\n const bookedAt = data.bookingContacts[String(event.id)]?.bookedAtIso;\n return bookedAt ? new Date(bookedAt).getTime() >= cutoff : true;\n });\n}\n\n/**\n * One row of the platform's \"Prenotazioni online\" page, which Increment 1\n * hosts in the rail instead of sending the user to a separate page.\n * Columns mirror it: when it was booked, what was asked for, whether it\n * was paid online, and what is still missing before it is a real\n * appointment.\n */\nexport interface BookingRowView {\n row: CalendarRow;\n eventId: string;\n /** The appointment's own start. */\n start: Date;\n /** Platform `createdAt` — \"del <date>\" under the appointment date. */\n bookedAt: Date | null;\n /** The booking reason, or the platform's \"Non specificato\". */\n reason: string | null;\n chairTitle: string | null;\n /** Stripe amount when the patient paid at booking. */\n paidOnline: number | null;\n needsPatient: boolean;\n needsOperator: boolean;\n /** Booked after the user last opened the page — the \"(Nuovo)\" marker. */\n isNew: boolean;\n}\n\nexport function bookingRowView(\n row: CalendarRow,\n data: CalendarData,\n lastSeenMs?: number | null,\n createdAtIso?: string,\n): BookingRowView {\n const event = row.event;\n const id = String(event.id);\n const contact = data.bookingContacts[id];\n const bookedAtIso = createdAtIso ?? contact?.bookedAtIso;\n const bookedAt = bookedAtIso ? new Date(bookedAtIso) : null;\n const chair = data.chairs.find((c) => c.id === row.chairId);\n return {\n row,\n eventId: id,\n start: new Date(event.start as string),\n bookedAt: bookedAt && Number.isFinite(bookedAt.getTime()) ? bookedAt : null,\n reason: row.description ?? null,\n chairTitle: chair?.title ?? null,\n paidOnline: data.paidOnline[id] ?? null,\n needsPatient: event.hasUnassignedPatient === true,\n needsOperator: !row.operatorId,\n isNew:\n bookedAt && lastSeenMs != null ? bookedAt.getTime() >= lastSeenMs : false,\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Waiting list — the platform's nine-input advanced filter form and */\n/* the row view its table renders */\n/* ------------------------------------------------------------------ */\n\n/** The nine advanced inputs, all optional. Empty = the input is unset;\n * `operatorId` also accepts `NONE`, the platform's \"no operator\". */\nexport interface WaitingListFilters {\n patientId: string;\n patientAssigned: '' | 'yes' | 'no';\n operatorId: string;\n appointmentScheduled: '' | 'yes' | 'no';\n appointmentFrom?: Date;\n appointmentTo?: Date;\n waitingFrom?: Date;\n waitingTo?: Date;\n description: string;\n}\n\nexport const EMPTY_WAITING_FILTERS: WaitingListFilters = {\n patientId: '',\n patientAssigned: '',\n operatorId: '',\n appointmentScheduled: '',\n description: '',\n};\n\n/** How many of the nine inputs carry a value — the toggle's badge. */\nexport function waitingFiltersActiveCount(filters: WaitingListFilters): number {\n return [\n filters.patientId,\n filters.patientAssigned,\n filters.operatorId,\n filters.appointmentScheduled,\n filters.appointmentFrom,\n filters.appointmentTo,\n filters.waitingFrom,\n filters.waitingTo,\n filters.description.trim(),\n ].filter(Boolean).length;\n}\n\n/**\n * One waiting row resolved the way the platform's serializer resolves\n * it: the entry's OWN patient, the linked appointment with its patient,\n * care line and colour, and the operator default. `noConnection` is the\n * platform's \"Nessun collegamento\" test — none of the four is present.\n */\nexport interface WaitingListRowView {\n entry: CalendarWaitingEntry;\n /** The entry's OWN patient, id and record together. `assigned` is what\n * decides whether this entry has a patient — the record may simply\n * not have loaded. */\n patientRef: PatientRef;\n /** Platform `patientId` / `patientName` / `patientPhoneNumber` — the\n * record alone, when the host could load it. */\n patient?: CalendarPatient;\n /** The linked appointment, live from the grid's rows. */\n appointment?: CalendarRow;\n /** Platform `appointmentPatientId` — the linked appointment's patient,\n * id and record together. */\n appointmentPatientRef: PatientRef;\n /** The linked appointment's patient record, when it loaded. */\n appointmentPatient?: CalendarPatient;\n /** Platform `operatorName`. */\n operatorTitle?: string;\n /** Platform `appointmentName` — the linked appointment's care line. */\n appointmentName?: string;\n /** The row's one photo: the resolved patient record's, else the\n * entry's own `patientAvatarUrl`. Absent = initials. */\n avatarSrc?: string;\n /** Someone is booked on this row — the entry's own patient or the\n * linked appointment's. Keyed on the IDS: a record we could not load\n * is still a patient. */\n patientAssigned: boolean;\n noConnection: boolean;\n}\n\nexport function waitingListRowView(\n entry: CalendarWaitingEntry,\n rows: readonly CalendarRow[],\n data: CalendarData,\n): WaitingListRowView {\n const appointment = entry.appointmentId\n ? rows.find((row) => row.event.id === entry.appointmentId)\n : undefined;\n const patientRef = patientRefById(entry.patientId, data);\n const appointmentPatientRef = patientRefById(\n appointment?.event.patientId,\n data,\n );\n const operatorTitle = entry.operatorId\n ? data.operators.find((o) => o.id === entry.operatorId)?.title\n : undefined;\n const patientAssigned = patientRef.assigned || appointmentPatientRef.assigned;\n return {\n entry,\n patientRef,\n patient: patientRef.record,\n appointment,\n appointmentPatientRef,\n appointmentPatient: appointmentPatientRef.record,\n operatorTitle,\n avatarSrc:\n (patientRef.record ?? appointmentPatientRef.record)?.avatarSrc ??\n entry.patientAvatarUrl,\n appointmentName: appointment\n ? appointment.cares?.map((care) => care.name).join(', ') ||\n appointment.description ||\n String(appointment.event.title)\n : undefined,\n patientAssigned,\n /* \"No link\" is an EXISTENCE claim, so it keys on the ids: an entry\n whose patient id we could not resolve is linked to a patient, and\n saying otherwise is the same lie as \"no patient assigned\". */\n noConnection: !patientAssigned && !appointment && !operatorTitle,\n };\n}\n\n/** Whole-day bounds — the platform's \"dal / al\" read inclusively at both\n * ends, so an appointment at 09:00 on the \"al\" day still matches. */\nfunction withinDayBounds(\n value: string | Date | undefined,\n from?: Date,\n to?: Date,\n): boolean {\n if (!from && !to) return true;\n if (value === undefined) return true;\n const ms = eventStartMs(\n typeof value === 'string' ? value : value.toISOString(),\n );\n if (from && ms < startOfDayMs(from)) return false;\n if (to && ms > endOfDayMs(to)) return false;\n return true;\n}\n\nfunction startOfDayMs(date: Date): number {\n const copy = new Date(date);\n copy.setHours(0, 0, 0, 0);\n return copy.getTime();\n}\n\nfunction endOfDayMs(date: Date): number {\n const copy = new Date(date);\n copy.setHours(23, 59, 59, 999);\n return copy.getTime();\n}\n\n/**\n * The platform's advanced predicates, in its own order. A patient\n * matches the entry's OWN patient or the linked appointment's; the\n * operator and the description only ever read the ENTRY's own fields.\n */\nexport function waitingEntryMatchesFilters(\n view: WaitingListRowView,\n filters: WaitingListFilters,\n data: CalendarData,\n): boolean {\n const { entry } = view;\n if (filters.patientId) {\n const ids = [view.patientRef.id, view.appointmentPatientRef.id];\n if (!ids.includes(filters.patientId)) return false;\n }\n if (filters.patientAssigned) {\n /* Whether a patient is ASSIGNED is an id question. Keying it on the\n resolved record made the \"No\" view return every entry that HAS a\n patient on a host whose `patientById` cannot answer — the exact\n inverse of what the user asked for. */\n const assigned = view.patientAssigned;\n if (filters.patientAssigned === 'yes' && !assigned) return false;\n if (filters.patientAssigned === 'no' && assigned) return false;\n }\n if (filters.operatorId) {\n if (filters.operatorId === NONE && entry.operatorId) return false;\n if (\n filters.operatorId !== NONE &&\n entry.operatorId !== filters.operatorId\n ) {\n return false;\n }\n }\n if (filters.appointmentScheduled) {\n const scheduled = Boolean(entry.appointmentId);\n if (filters.appointmentScheduled === 'yes' && !scheduled) return false;\n if (filters.appointmentScheduled === 'no' && scheduled) return false;\n }\n if (\n !withinDayBounds(\n view.appointment ? String(view.appointment.event.start) : undefined,\n filters.appointmentFrom,\n filters.appointmentTo,\n )\n ) {\n return false;\n }\n if (\n !withinDayBounds(\n data.waitingSinceIso(entry),\n filters.waitingFrom,\n filters.waitingTo,\n )\n ) {\n return false;\n }\n const needle = filters.description.trim().toLocaleLowerCase();\n if (needle) {\n const haystack = entry.description?.toLocaleLowerCase() ?? '';\n if (!haystack.includes(needle)) return false;\n }\n return true;\n}\n\n/** The quick view first, then the advanced predicates — the platform's\n * own order (`_filterForAdvancedSearch` re-runs the view). */\nexport function filterWaitingEntries(\n entries: readonly CalendarWaitingEntry[],\n rows: readonly CalendarRow[],\n quickView: WaitingQuickView,\n filters: WaitingListFilters,\n data: CalendarData,\n): WaitingListRowView[] {\n return entries\n .filter((entry) => waitingEntryInQuickView(entry, quickView, data))\n .map((entry) => waitingListRowView(entry, rows, data))\n .filter((view) => waitingEntryMatchesFilters(view, filters, data));\n}\n\n/* ------------------------------------------------------------------ */\n/* Waiting list — the grouped card list (Option B) */\n/* ------------------------------------------------------------------ */\n\n/** What an entry is FOR. The domain allows exactly one connection, so\n * the test is a precedence, and an entry never lands in two groups. */\nexport type WaitingEntryKind = 'linked' | 'patient' | 'memo';\n\n/** Render order: bring forward, first slot, free-text reminders. */\nexport const WAITING_ENTRY_KINDS: readonly WaitingEntryKind[] = [\n 'linked',\n 'patient',\n 'memo',\n];\n\n/** Keyed on the IDS, never on what resolved: an appointment off the\n * loaded range is still a link, an unloaded patient still a patient. */\nexport function waitingEntryKind(\n entry: CalendarWaitingEntry,\n): WaitingEntryKind {\n if (entry.appointmentId) return 'linked';\n if (patientIdOf(entry.patientId) !== '') return 'patient';\n return 'memo';\n}\n\n/** The non-empty groups, in render order, rows in queue order. */\nexport function groupWaitingRows(\n views: readonly WaitingListRowView[],\n): { kind: WaitingEntryKind; rows: WaitingListRowView[] }[] {\n return WAITING_ENTRY_KINDS.map((kind) => ({\n kind,\n rows: views.filter((view) => waitingEntryKind(view.entry) === kind),\n })).filter((group) => group.rows.length > 0);\n}\n\n/** How many entries each quick view holds, from the rows in hand. */\nexport function waitingQuickViewCounts(\n entries: readonly CalendarWaitingEntry[],\n data: CalendarData,\n): Record<WaitingQuickView, number> {\n const count = (view: WaitingQuickView): number =>\n entries.filter((entry) => waitingEntryInQuickView(entry, view, data))\n .length;\n return {\n all: count('all'),\n noAppointment: count('noAppointment'),\n scheduledOver30: count('scheduledOver30'),\n waitingOver30: count('waitingOver30'),\n };\n}\n\n/** The number WhatsApp may be handed, `''` when there is none. The host's\n * own `whatsappPhoneNumber` wins; the story flag reads the record. */\nexport function waitingWhatsAppNumber(view: WaitingListRowView): string {\n const { entry } = view;\n if (entry.whatsappPhoneNumber !== undefined) {\n return entry.whatsappPhoneNumber.trim();\n }\n const contact = view.patientRef.assigned\n ? view.patientRef.record\n : view.appointmentPatientRef.record;\n return entry.whatsappCapable ? (contact?.phone ?? '') : '';\n}\n\n/** A host's read of the queue, so the panel can show a first load. */\nexport interface CalendarWaitingListState {\n status: 'loading' | 'ready' | 'error';\n onRetry?: () => void;\n}\n","import { useEffect, useMemo, useRef, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Clock, Stethoscope } from 'lucide-react';\nimport { AppointmentTimeline } from '../../components/appointment-timeline';\nimport type { AppointmentItem } from '../../components/appointment-card';\nimport { WorkflowStatusDisplay } from '../../components/workflow-status';\nimport { Avatar } from '../../components/avatar/avatar';\nimport { Badge } from '../../components/badge/badge';\nimport { Skeleton } from '../../components/skeleton/skeleton';\nimport { appointmentStateWorkflow } from '../../components/_shared/entity-card';\nimport { useCalendarData } from './calendar.data';\nimport type { CalendarRow } from './calendar.model';\nimport {\n DEFAULT_UPCOMING_WINDOW,\n UPCOMING_MAX_DAYS,\n type UpcomingWindow,\n upcomingAppointmentItem,\n upcomingAppointmentRows,\n upcomingWindowBounds,\n upcomingWindowCovering,\n widenUpcomingWindow,\n} from './calendar-workspace.model';\n\n/* ------------------------------------------------------------------ */\n/* UpcomingAppointmentsPanel — \"Oggi operativo\" (Option A) */\n/* */\n/* The rail's default panel, widened past the plain day-grouped list: */\n/* a summary strip, an \"In studio ora\" band for today's rows already */\n/* under way (waiting room / in the chair), and the day-grouped list */\n/* for everything else — today's settled (concluded / no-show) rows */\n/* dimmed in place, the very next appointment to start ringed. */\n/* */\n/* Zero new data: `waiting` / `in_care` / `done` are the platform's */\n/* own states, already carried by `AppointmentItem.state`. The one */\n/* platform gap — `DoctorAppointment.lastStateUpdate`, which the */\n/* \"since\" elapsed time in the live band needs — is not yet in the */\n/* read model; a host that cannot supply it per row simply omits */\n/* `stateSinceByEventId[id]`, and that row's elapsed time is left out */\n/* rather than guessed. */\n/* ------------------------------------------------------------------ */\n\n/** Local calendar day key (`YYYY-MM-DD`), timezone-naive on `Date`. */\nfunction dayKey(iso: string): string {\n const d = new Date(iso);\n const m = `${d.getMonth() + 1}`.padStart(2, '0');\n const day = `${d.getDate()}`.padStart(2, '0');\n return `${d.getFullYear()}-${m}-${day}`;\n}\n\n/**\n * One wall-clock instant, anchored to the host's `nowIso` at the moment it\n * last changed and advanced by real elapsed time since — so relative\n * labels keep ticking while the panel is open, but a fixed `nowIso` (every\n * story, every test) never drifts on its own: nothing advances until a\n * full minute of real time has actually passed, which no test waits for.\n * One `setInterval`, minute resolution, cleared on unmount, paused while\n * the tab is hidden.\n */\nfunction useTickingNow(nowIso: string): Date {\n const anchor = useRef({ iso: nowIso, wallMs: Date.now() });\n if (anchor.current.iso !== nowIso) {\n anchor.current = { iso: nowIso, wallMs: Date.now() };\n }\n const [, setTick] = useState(0);\n useEffect(() => {\n let id: ReturnType<typeof setInterval> | undefined;\n const stop = () => {\n if (id !== undefined) clearInterval(id);\n id = undefined;\n };\n const start = () => {\n stop();\n id = setInterval(() => setTick((t) => t + 1), 60_000);\n };\n const onVisibility = () => {\n if (typeof document === 'undefined') return;\n if (document.hidden) stop();\n else start();\n };\n if (typeof document === 'undefined' || !document.hidden) start();\n document.addEventListener?.('visibilitychange', onVisibility);\n return () => {\n stop();\n document.removeEventListener?.('visibilitychange', onVisibility);\n };\n }, []);\n const elapsedMs = Date.now() - anchor.current.wallMs;\n return new Date(new Date(anchor.current.iso).getTime() + elapsedMs);\n}\n\n/** \"in 18 minutes\" / \"18 minutes ago\" — via Intl.RelativeTimeFormat, never\n * hand-built. `fromMs` is the anchor (\"now\"); `toMs` the target instant. */\nfunction relativeMinutes(fromMs: number, toMs: number, locale: string): string {\n const diffMin = Math.round((toMs - fromMs) / 60_000);\n return new Intl.RelativeTimeFormat(locale, { numeric: 'auto' }).format(\n diffMin,\n 'minute',\n );\n}\n\n/** A DURATION (\"12 min\", \"1 h 5 min\"), not a relative time: the label\n * already says \"since\", and \"since in 12 minutes\" is nonsense. */\nfunction elapsedDuration(fromMs: number, toMs: number, locale: string): string {\n const total = Math.max(0, Math.round((toMs - fromMs) / 60_000));\n const unit = (value: number, name: 'hour' | 'minute') =>\n new Intl.NumberFormat(locale, {\n style: 'unit',\n unit: name,\n unitDisplay: 'short',\n }).format(value);\n if (total < 60) return unit(total, 'minute');\n const minutes = total % 60;\n const hours = unit(Math.floor(total / 60), 'hour');\n return minutes === 0 ? hours : `${hours} ${unit(minutes, 'minute')}`;\n}\n\ninterface LiveRow {\n item: AppointmentItem;\n sinceIso?: string;\n}\n\nexport interface UpcomingAppointmentsPanelProps {\n rows: CalendarRow[];\n locale: string;\n /** Privacy mode masks every name in the strip, the band and the list — a\n * clinic-wide \"who is here / who is coming in\" is exactly what it hides. */\n privacy: boolean;\n /** Selects the appointment on the grid, which docks its details. */\n onOpenAppointment: (eventId: string) => void;\n /**\n * `DoctorAppointment.lastStateUpdate`, keyed by appointment id, for rows\n * the live band shows. Optional: the platform read model does not carry\n * this field yet (see `calendar.sheets` note above the panel), and a row\n * missing from this map shows its state with no elapsed time rather than\n * one derived from its start time or invented.\n */\n stateSinceByEventId?: Readonly<Record<string, string>>;\n /**\n * The host is still fetching rows. Shows content-shaped Skeleton\n * placeholders instead of the list, `aria-busy=\"true\"`, and no spinner\n * or \"Loading…\" text. A refresh (rows already present) keeps the old\n * rows on screen instead of blanking them — pass `loading` only for the\n * first read.\n */\n loading?: boolean;\n}\n\nexport function UpcomingAppointmentsPanel({\n rows,\n locale,\n privacy,\n onOpenAppointment,\n stateSinceByEventId,\n loading = false,\n}: UpcomingAppointmentsPanelProps) {\n const { t } = useTranslation();\n const data = useCalendarData();\n const [range, setRange] = useState<UpcomingWindow>(DEFAULT_UPCOMING_WINDOW);\n const now = useTickingNow(data.nowIso);\n const nowMs = now.getTime();\n const todayKey = dayKey(data.nowIso);\n\n const unresolvedPatientLabel = t(\n 'calendarWorkspace.details.patientNotLoaded',\n );\n const allItems = useMemo(\n () =>\n upcomingAppointmentRows(\n rows,\n upcomingWindowBounds(data.nowIso, range),\n ).map((row) =>\n upcomingAppointmentItem(\n row,\n privacy,\n data,\n unresolvedPatientLabel,\n t('calendar.eventKind.pendingDetails'),\n ),\n ),\n [rows, range, privacy, data, unresolvedPatientLabel, t],\n );\n\n const todaysItems = useMemo(\n () => allItems.filter((item) => dayKey(item.startIso) === todayKey),\n [allItems, todayKey],\n );\n const live = useMemo<LiveRow[]>(\n () =>\n todaysItems\n .filter((item) => item.state === 'waiting' || item.state === 'in_care')\n .sort((a, b) => +new Date(a.startIso) - +new Date(b.startIso))\n .map((item) => ({\n item,\n sinceIso: stateSinceByEventId?.[item.id],\n })),\n [todaysItems, stateSinceByEventId],\n );\n const liveIds = useMemo(\n () => new Set(live.map((row) => row.item.id)),\n [live],\n );\n\n /* Everything the day-grouped list still shows: the live band replaces\n those rows there, but settled (done / no-show) rows stay — dimmed —\n and the very next future start gets the ring. */\n const nextItem = useMemo(\n () =>\n allItems.find(\n (item) => !liveIds.has(item.id) && +new Date(item.startIso) >= nowMs,\n ),\n [allItems, liveIds, nowMs],\n );\n const listItems = useMemo<AppointmentItem[]>(\n () =>\n allItems\n .filter((item) => !liveIds.has(item.id))\n .map((item) => ({\n ...item,\n dimmed: item.state === 'done' || item.state === 'absent',\n next: item.id === nextItem?.id,\n })),\n [allItems, liveIds, nextItem],\n );\n\n const summary = (\n <div\n data-component=\"calendar-upcoming-summary\"\n role=\"group\"\n aria-label={t('calendarWorkspace.inc1.rail.upcomingSummaryLabel')}\n className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)] ds:border-b ds:border-[color:var(--card-border)] ds:px-[var(--spacing-sm)] ds:py-[var(--spacing-xs)]\"\n >\n <Badge variant=\"info\" size=\"sm\">\n {t('calendarWorkspace.inc1.rail.upcomingSummaryLive', {\n n: live.length,\n })}\n </Badge>\n {nextItem ? (\n <Badge variant=\"accentSoft\" size=\"sm\">\n {t('calendarWorkspace.inc1.rail.upcomingSummaryNext', {\n time: relativeMinutes(\n nowMs,\n new Date(nextItem.startIso).getTime(),\n locale,\n ),\n })}\n </Badge>\n ) : null}\n <Badge variant=\"neutral\" size=\"sm\">\n {t('calendarWorkspace.inc1.rail.upcomingSummaryToday', {\n n: todaysItems.length,\n })}\n </Badge>\n </div>\n );\n\n const liveBand =\n live.length > 0 ? (\n <section\n data-component=\"calendar-upcoming-live-band\"\n aria-labelledby=\"calendar-upcoming-live-heading\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)] ds:border-b ds:border-[color:var(--card-border)] ds:px-[var(--spacing-sm)] ds:py-[var(--spacing-xs)]\"\n >\n <h3\n id=\"calendar-upcoming-live-heading\"\n className=\"type-eyebrow ds:m-0 ds:flex ds:items-center ds:gap-[var(--spacing-2xs)] ds:text-[color:var(--info-foreground)]\"\n >\n <Stethoscope aria-hidden=\"true\" className=\"ds:size-3.5 ds:shrink-0\" />\n {t('calendarWorkspace.inc1.rail.upcomingLiveTitle')}\n </h3>\n {/* eslint-disable-next-line jsx-a11y/no-redundant-roles -- role=\"list\" is NOT redundant: WebKit drops implicit list semantics when list-style is none */}\n <ul\n role=\"list\"\n className=\"ds:m-0 ds:flex ds:list-none ds:flex-col ds:gap-[var(--spacing-xs)] ds:p-0\"\n >\n {live.map(({ item, sinceIso }) => {\n const workflow = appointmentStateWorkflow(item.state);\n const StateIcon = workflow.Icon;\n const stateLabel = t(`appointmentCard.state.${item.state}`);\n /* Never invented: a row absent from `stateSinceByEventId` shows\n its state with no elapsed time at all. */\n const elapsed = sinceIso\n ? elapsedDuration(new Date(sinceIso).getTime(), nowMs, locale)\n : undefined;\n return (\n <li key={item.id}>\n <button\n type=\"button\"\n onClick={() => onOpenAppointment(item.id)}\n data-component=\"calendar-upcoming-live-row\"\n data-appointment-id={item.id}\n className=\"ds:flex ds:w-full ds:items-center ds:gap-[var(--spacing-sm)] ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--card-border)] ds:bg-[color:color-mix(in_srgb,var(--info)_8%,var(--card))] ds:p-[var(--spacing-sm)] ds:text-start ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none ds:hover:bg-[color:color-mix(in_srgb,var(--info)_14%,var(--card))] ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-[color:var(--ring)]\"\n >\n {item.patient ? (\n <Avatar\n name={item.patient.name}\n src={item.patient.avatarUrl}\n size=\"sm\"\n aria-hidden=\"true\"\n role=\"presentation\"\n aria-label={undefined}\n />\n ) : null}\n <span className=\"ds:min-w-0 ds:flex-1\">\n <span className=\"ds:block ds:truncate type-title-item\">\n {item.patient?.name ?? t('appointmentCard.noPatient')}\n </span>\n </span>\n <WorkflowStatusDisplay\n size=\"sm\"\n value={item.state}\n option={{\n value: item.state,\n label: elapsed\n ? t('calendarWorkspace.inc1.rail.upcomingLiveElapsed', {\n state: stateLabel,\n elapsed,\n })\n : stateLabel,\n icon: <StateIcon aria-hidden=\"true\" />,\n tone: workflow.tone,\n }}\n />\n </button>\n </li>\n );\n })}\n </ul>\n </section>\n ) : null;\n\n const loadingSkeleton = (\n <div\n aria-hidden=\"true\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:p-[var(--spacing-sm)]\"\n >\n {[0, 1, 2].map((index) => (\n <div\n key={index}\n className=\"ds:flex ds:items-center ds:gap-[var(--spacing-sm)]\"\n >\n <Skeleton variant=\"circular\" size=\"sm\" stagger={index * 2} />\n <Skeleton\n variant=\"text\"\n size=\"sm\"\n stagger={index * 2 + 1}\n width=\"70%\"\n />\n </div>\n ))}\n </div>\n );\n\n return (\n <div\n data-component=\"calendar-upcoming-panel\"\n aria-busy={loading ? 'true' : undefined}\n className=\"ds:flex ds:h-full ds:min-h-0 ds:flex-col\"\n >\n {loading ? (\n loadingSkeleton\n ) : (\n <AppointmentTimeline\n items={listItems}\n nowIso={data.nowIso}\n locale={locale}\n /* Clinic-wide, so each row leads with the patient — the widget\n answers \"who is coming in\", not \"which of my slots\". */\n showPatient\n hideDefaultStatus\n title={t('calendarWorkspace.inc1.rail.appointmentsTitle')}\n emptyTitle={t('calendarWorkspace.inc1.rail.appointmentsEmpty')}\n emptyDescription={t(\n 'calendarWorkspace.inc1.rail.appointmentsEmptyBody',\n )}\n headerExtra={\n <>\n {summary}\n {liveBand}\n </>\n }\n onOpenAppointment={(item) => onOpenAppointment(item.id)}\n onLoadEarlier={() =>\n setRange((prev) => widenUpcomingWindow(prev, 'earlier'))\n }\n onLoadLater={() =>\n setRange((prev) => widenUpcomingWindow(prev, 'later'))\n }\n hasMoreEarlier={range.backDays < UPCOMING_MAX_DAYS}\n hasMoreLater={range.forwardDays < UPCOMING_MAX_DAYS}\n onJumpToDate={(dateIso) =>\n setRange((prev) =>\n upcomingWindowCovering(prev, data.nowIso, dateIso),\n )\n }\n />\n )}\n </div>\n );\n}\n\n/** Icon re-export so callers that only need the panel's own glyph (e.g. a\n * rail tool registration) don't have to import lucide-react directly. */\nexport { Clock as UpcomingAppointmentsPanelIcon };\n","import { useEffect, useRef, useState, type ReactNode } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Alert } from '../../components/alert';\nimport { Button } from '../../components/button';\nimport { Skeleton } from '../../components/skeleton';\nimport type {\n CalendarEditorCapabilities,\n CalendarRow,\n EditorPrefill,\n RecurrenceFrequency,\n} from './calendar.model';\nimport {\n RECURRING_SCOPES,\n type RecurringScope,\n} from './calendar-workspace.model';\n\n/** The host's recurring occurrence. Rows never carry `CalendarRow.series`\n * for such a host: the scope question is asked from this snapshot. */\nexport interface CalendarEditorSeries {\n /** The occurrence being edited, as a local Date on the host's wall clock. */\n occurrence: Date;\n /** Scopes the host can honour, in display order. Non-empty; the kit\n * renders exactly this list and never adds a scope. */\n scopes: readonly RecurringScope[];\n /** Merged over snapshot.capabilities once a scope is chosen. */\n capabilitiesByScope?: Partial<\n Record<RecurringScope, CalendarEditorCapabilities>\n >;\n /** Offer the care-plan clean-up question in the delete dialog. */\n offersCarePlanCleanup?: boolean;\n /** Reserved for summary lines; the editor does not require it. */\n summary?: { frequency?: RecurrenceFrequency; index?: number; total?: number };\n}\n\nexport type CalendarAppointmentEditorSnapshot =\n | {\n status: 'ready';\n prefill: EditorPrefill & {\n editEventId: string;\n date: Date;\n time: { hours: number; minutes: number };\n durationMin: number;\n };\n capabilities?: CalendarEditorCapabilities;\n series?: CalendarEditorSeries;\n }\n | { status: 'refused'; reason: string; retryable?: boolean };\n\nexport type CalendarAppointmentEditorLoader = (\n eventId: string,\n options: { signal: AbortSignal },\n) => Promise<CalendarAppointmentEditorSnapshot>;\n\ntype ReadySnapshot = Extract<\n CalendarAppointmentEditorSnapshot,\n { status: 'ready' }\n>;\n/** An absent series is valid; a present one names a real occurrence and\n * at least one known scope. */\nfunction seriesIsValid(\n series: CalendarEditorSeries | undefined,\n prefill: ReadySnapshot['prefill'],\n): boolean {\n return (\n series == null ||\n (series.occurrence instanceof Date &&\n Number.isFinite(series.occurrence.getTime()) &&\n series.occurrence.getFullYear() === prefill.date.getFullYear() &&\n series.occurrence.getMonth() === prefill.date.getMonth() &&\n series.occurrence.getDate() === prefill.date.getDate() &&\n series.occurrence.getHours() === prefill.time.hours &&\n series.occurrence.getMinutes() === prefill.time.minutes &&\n Array.isArray(series.scopes) &&\n series.scopes.length > 0 &&\n series.scopes.every((scope) => RECURRING_SCOPES.includes(scope)))\n );\n}\n\ninterface LoadResult {\n eventId: string;\n source: CalendarAppointmentEditorLoader;\n value:\n | CalendarAppointmentEditorSnapshot\n | { status: 'error'; reason: string };\n}\n\n/** The editor is not mounted until the host returns its canonical data.\n * Mounting this boundary per open also reloads a previously closed editor. */\n/* Label widths of the placeholder fields; uneven, as real labels are. */\nconst EDITOR_SKELETON_LABELS = ['25%', '33%', '20%', '40%', '25%'] as const;\n\nexport function CalendarEditorHydration({\n eventId,\n load,\n onCancel,\n children,\n}: {\n eventId?: string;\n load?: CalendarAppointmentEditorLoader;\n /** Return to the host while loading or when the editor read fails. */\n onCancel?: () => void;\n children: (snapshot?: ReadySnapshot) => ReactNode;\n}) {\n const { t } = useTranslation();\n const failureMessage = useRef('');\n failureMessage.current = t('emptyState.error.description');\n const [result, setResult] = useState<LoadResult>();\n const [retry, setRetry] = useState(0);\n useEffect(() => {\n if (!eventId || !load) return;\n const controller = new AbortController();\n setResult(undefined);\n Promise.resolve()\n .then(() => load(eventId, { signal: controller.signal }))\n .then((value) => {\n if (controller.signal.aborted) return;\n if (value.status === 'ready') {\n const prefill = value.prefill;\n if (\n prefill.editEventId !== eventId ||\n !(prefill.date instanceof Date) ||\n !Number.isFinite(prefill.date.getTime()) ||\n !Number.isFinite(prefill.durationMin) ||\n prefill.durationMin < 0 ||\n (prefill.durationMin === 0 && !prefill.allDay) ||\n !Number.isInteger(prefill.time?.hours) ||\n prefill.time.hours < 0 ||\n prefill.time.hours > 23 ||\n !Number.isInteger(prefill.time?.minutes) ||\n prefill.time.minutes < 0 ||\n prefill.time.minutes > 59 ||\n !seriesIsValid(value.series, prefill)\n )\n throw new Error(failureMessage.current);\n }\n setResult({ eventId, source: load, value });\n })\n .catch((error: unknown) => {\n if (!controller.signal.aborted)\n setResult({\n eventId,\n source: load,\n value: {\n status: 'error',\n reason:\n error instanceof Error && error.message.trim()\n ? error.message\n : failureMessage.current,\n },\n });\n });\n return () => controller.abort();\n }, [eventId, load, retry]);\n\n if (!eventId || !load) return children();\n const value =\n result?.eventId === eventId && result.source === load\n ? result.value\n : undefined;\n if (value?.status === 'ready') return children(value);\n return (\n <div\n data-component=\"calendar-editor-hydration\"\n data-event-id={eventId}\n data-status={value?.status ?? 'loading'}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:p-[var(--spacing-md)]\"\n >\n {value ? (\n <Alert variant={value.status === 'error' ? 'error' : 'warning'}>\n <Alert.Description>{value.reason}</Alert.Description>\n </Alert>\n ) : (\n /* A form-shaped placeholder: a label over a field, five times, so the\n editor's fields have somewhere to land. */\n <div\n aria-busy=\"true\"\n data-editor-loading=\"\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n <span role=\"status\" className=\"ds:sr-only\">\n {t('common.loading')}\n </span>\n {EDITOR_SKELETON_LABELS.map((width, index) => (\n <div\n key={index}\n aria-hidden=\"true\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\"\n >\n <Skeleton\n variant=\"text\"\n size=\"sm\"\n stagger={index}\n width={width}\n />\n <Skeleton\n variant=\"rounded\"\n stagger={index}\n height=\"calc(var(--spacing-xl) + var(--spacing-sm))\"\n />\n </div>\n ))}\n </div>\n )}\n {onCancel ? (\n <Button intent=\"outline\" onClick={onCancel}>\n {t('calendarWorkspace.editor.cancel')}\n </Button>\n ) : null}\n {value && (value.status === 'error' || value.retryable) ? (\n <Button\n intent=\"outline\"\n onClick={() => setRetry((previous) => previous + 1)}\n >\n {t('emptyState.error.cta')}\n </Button>\n ) : null}\n </div>\n );\n}\n\n/** Display-only projection. It never reaches journey.setRows. */\nexport function rowWithCanonicalEditor(\n row: CalendarRow,\n snapshot: ReadySnapshot,\n patientName: string,\n): CalendarRow {\n const prefill = snapshot.prefill;\n const start = new Date(prefill.date);\n start.setHours(prefill.time.hours, prefill.time.minutes, 0, 0);\n return {\n ...row,\n chairId: prefill.chairId,\n operatorId: prefill.operatorId,\n description: prefill.care,\n cares: prefill.cares,\n careLink: prefill.careLink,\n event: {\n ...row.event,\n title: patientName,\n patientId: prefill.patientId,\n start,\n end: new Date(start.getTime() + prefill.durationMin * 60000),\n allDay: prefill.allDay,\n status: prefill.status,\n backgroundColor: prefill.colorHex,\n isTelehealth: prefill.isTelehealth,\n hasUnassignedPatient: !prefill.patientId,\n },\n };\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Combobox } from '../../components/combobox';\nimport { Button } from '../../components/button';\nimport { useCalendarData, type CalendarData } from './calendar.data';\nimport type { CalendarPatient } from './calendar.types';\n\ninterface PatientPickerProps {\n value: string;\n onValueChange: (value: string) => void;\n selectedLabel?: string;\n size?: 'sm' | 'md';\n disabled?: boolean;\n}\n\n/** One id-valued patient control for the editor and waiting surfaces. */\nexport function CalendarPatientPicker(props: PatientPickerProps) {\n const data = useCalendarData();\n const { t } = useTranslation();\n const selectedLabel =\n data.patientById(props.value)?.name ??\n props.selectedLabel ??\n t('calendarWorkspace.details.patientNotLoaded');\n if (data.searchPatients) {\n return (\n <PatientSearchPicker\n {...props}\n selectedLabel={selectedLabel}\n searchPatients={data.searchPatients}\n />\n );\n }\n return (\n <Combobox\n {...props}\n options={[\n ...(props.value && !data.patients.some((p) => p.id === props.value)\n ? [{ value: props.value, label: selectedLabel }]\n : []),\n ...data.patients.map((p) => ({ value: p.id, label: p.name })),\n ]}\n placeholder={t('calendarWorkspace.editor.patientSearch')}\n clearable\n />\n );\n}\n\ntype SearchPatients = NonNullable<CalendarData['searchPatients']>;\ninterface SearchState {\n query: string;\n source: SearchPatients;\n status: 'loading' | 'ready' | 'error';\n patients: readonly CalendarPatient[];\n}\n\nfunction PatientSearchPicker({\n value,\n onValueChange,\n selectedLabel,\n size,\n disabled,\n searchPatients,\n}: PatientPickerProps & { searchPatients: SearchPatients }) {\n const { t } = useTranslation();\n const [query, setQuery] = useState('');\n const [retry, setRetry] = useState(0);\n const [picked, setPicked] = useState<CalendarPatient>();\n const [state, setState] = useState<SearchState>();\n const inputRef = useRef<HTMLInputElement>(null);\n const trimmedQuery = query.trim();\n\n useEffect(() => {\n if (!trimmedQuery) return;\n const controller = new AbortController();\n const base = { query: trimmedQuery, source: searchPatients };\n setState({ ...base, status: 'loading', patients: [] });\n const timer = setTimeout(() => {\n Promise.resolve()\n .then(() => searchPatients(trimmedQuery, { signal: controller.signal }))\n .then(\n (patients) => {\n if (!controller.signal.aborted)\n setState({ ...base, status: 'ready', patients });\n },\n () => {\n if (!controller.signal.aborted)\n setState({ ...base, status: 'error', patients: [] });\n },\n );\n }, 250);\n return () => {\n clearTimeout(timer);\n controller.abort();\n };\n }, [trimmedQuery, searchPatients, retry]);\n\n const current =\n state?.query === trimmedQuery && state.source === searchPatients;\n const status = !trimmedQuery ? 'idle' : current ? state.status : 'loading';\n const patients = current && status === 'ready' ? state.patients : [];\n const message =\n status === 'loading'\n ? t('inputs.search.loading')\n : status === 'error'\n ? t('emptyState.error.description')\n : status === 'idle'\n ? t('calendarWorkspace.editor.patientSearch')\n : patients.length === 0\n ? t('inputs.combobox.empty')\n : '';\n const options = patients.map((patient) => ({\n value: patient.id,\n label: patient.name,\n }));\n if (value && !patients.some((patient) => patient.id === value)) {\n options.push({\n value,\n label: picked?.id === value ? picked.name : (selectedLabel ?? ''),\n });\n }\n\n return (\n <div\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\"\n data-component=\"calendar-patient-picker\"\n data-status={status}\n >\n <Combobox\n ref={inputRef}\n options={options}\n value={value}\n onValueChange={(next) => {\n setPicked(\n (prev) =>\n patients.find((patient) => patient.id === next) ??\n (prev?.id === next ? prev : undefined),\n );\n onValueChange(next);\n }}\n onQueryChange={setQuery}\n onOpenChange={(open) => {\n // Retry lives outside the popover. Preserve its failed query\n // when focusing that button dismisses the option list.\n if (!open && status !== 'error') setQuery('');\n }}\n /* Keep the held option for its label, but do not present it as a\n * search match unless the server actually returned it. */\n filter={(candidate) =>\n !trimmedQuery || patients.some((p) => p.id === candidate) ? 1 : 0\n }\n size={size}\n disabled={disabled}\n placeholder={t('calendarWorkspace.editor.patientSearch')}\n emptyMessage={message || undefined}\n clearable\n />\n {/* A retained selection can keep Command.Empty hidden. Status lives\n * outside the listbox so loading and errors are still announced. */}\n <p role=\"status\" className=\"type-body-sm ds:text-muted-foreground\">\n {message}\n </p>\n {status === 'error' ? (\n <Button\n size=\"sm\"\n intent=\"ghost\"\n onClick={() => {\n setRetry((prev) => prev + 1);\n inputRef.current?.focus();\n }}\n >\n {t('emptyState.error.cta')}\n </Button>\n ) : null}\n </div>\n );\n}\n","import { useEffect, type RefObject } from 'react';\nimport type { EditorInitialFocus } from './calendar.model';\n\n/** Frames to wait on a rail entrance before acting anyway (about 1.5s). */\nconst MAX_FRAMES = 90;\n\n/* Every presence layer above the node is at rest: `present`, and no\n transition of its own still running (the rail panel and body fade). */\nfunction isSettled(node: HTMLElement): boolean {\n let layer = node.closest<HTMLElement>('[data-presence]');\n while (layer) {\n if (layer.dataset.presence !== 'present') return false;\n if (layer.getAnimations().some((a) => a.playState === 'running'))\n return false;\n layer =\n layer.parentElement?.closest<HTMLElement>('[data-presence]') ?? null;\n }\n return true;\n}\n\n/**\n * Runs `run` once the node's rail entrance has settled, so a focus scroll\n * never fights the motion. A node that is absent is a silent no-op.\n * Returns the cancel.\n */\nexport function whenRailSettled(\n getNode: () => HTMLElement | null | undefined,\n run: (node: HTMLElement) => void,\n): () => void {\n let frame = 0;\n let frames = 0;\n let calm = 0;\n const tick = (): void => {\n const node = getNode();\n if (!node) return;\n frames += 1;\n calm = isSettled(node) ? calm + 1 : 0;\n // Two calm frames: a transition only exists after the next style pass.\n if (calm >= 2 || frames >= MAX_FRAMES) return run(node);\n frame = requestAnimationFrame(tick);\n };\n frame = requestAnimationFrame(tick);\n return () => cancelAnimationFrame(frame);\n}\n\nconst CONTROLS = 'input, button, textarea, [role=\"combobox\"]';\n\n/* The field's first control a user could act on; none means fall back. */\nfunction firstEnabledControl(field: HTMLElement): HTMLElement | null {\n for (const node of field.querySelectorAll<HTMLElement>(CONTROLS)) {\n if (\n node.matches(\n ':disabled, [aria-disabled=\"true\"], [aria-hidden=\"true\"], [tabindex=\"-1\"], [type=\"hidden\"]',\n )\n )\n continue;\n if (node.getClientRects().length === 0) continue;\n return node;\n }\n return null;\n}\n\n/**\n * Lands the editor on one field once its panel has settled. No field, an\n * absent field or a disabled one leaves focus where it was, silently.\n */\nexport function useEditorInitialFocus(\n field: EditorInitialFocus | undefined,\n fields: Record<EditorInitialFocus, RefObject<HTMLElement | null>>,\n): void {\n const target = field ? fields[field] : undefined;\n useEffect(() => {\n if (!target) return undefined;\n return whenRailSettled(\n () => target.current,\n (wrapper) => {\n const control = firstEnabledControl(wrapper);\n if (!control) return;\n control.scrollIntoView({ block: 'center' });\n control.focus({ preventScroll: true });\n },\n );\n }, [target]);\n}\n","import { useId, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Alert } from '../../components/alert';\nimport { Button } from '../../components/button';\nimport { Radio, RadioGroup } from '../../components/radio-group';\nimport {\n RECURRING_SCOPE_LABEL_KEY,\n type RecurringScope,\n} from './calendar-workspace.model';\n\nexport interface CalendarSeriesScopeChooserProps {\n /** The host's scopes in display order, rendered exactly as given. */\n scopes: readonly RecurringScope[];\n /** The occurrence being edited, named in the body for `locale`. */\n occurrence: Date;\n locale: string;\n /** Starts checked; defaults to, and falls back on, `scopes[0]`. */\n defaultScope?: RecurringScope;\n /** Warn for a moved start; editors suppress this until date or time changes. */\n warnOnWholeSeries?: boolean;\n onContinue: (scope: RecurringScope) => void;\n onCancel: () => void;\n}\n\n/** Asks which appointments of a series an edit applies to. The host's\n * list is the only source of scopes: the kit never adds one. */\nexport function CalendarSeriesScopeChooser(\n props: CalendarSeriesScopeChooserProps,\n) {\n const { t } = useTranslation();\n const titleId = useId();\n const warningId = useId();\n const [picked, setPicked] = useState(props.defaultScope);\n const { scopes } = props;\n const scope = picked && scopes.includes(picked) ? picked : scopes[0];\n /* A whole-series move drops the individually edited occurrences. */\n const warns = scope === 'all' && props.warnOnWholeSeries !== false;\n let date: string;\n try {\n date = new Intl.DateTimeFormat(props.locale, {\n dateStyle: 'full',\n timeStyle: 'short',\n }).format(props.occurrence);\n } catch {\n date = props.occurrence.toLocaleString();\n }\n return (\n <section\n data-component=\"calendar-series-scope-chooser\"\n aria-labelledby={titleId}\n className=\"ds:flex ds:min-w-0 ds:flex-col ds:gap-[var(--spacing-md)] ds:text-start\"\n >\n <h3 id={titleId} className=\"type-title-item ds:m-0\">\n {t('calendarWorkspace.editor.seriesChooserTitle')}\n </h3>\n <p className=\"type-body ds:m-0\">\n {t('calendarWorkspace.editor.seriesChooserBody', { date })}\n </p>\n <RadioGroup\n label={t('calendarWorkspace.editor.recurringSaveMode')}\n value={scope}\n onValueChange={(value) => setPicked(value as RecurringScope)}\n >\n {scopes.map((option) => (\n <Radio\n key={option}\n value={option}\n label={t(\n `calendarWorkspace.editor.${RECURRING_SCOPE_LABEL_KEY[option]}`,\n )}\n aria-describedby={option === 'all' && warns ? warningId : undefined}\n />\n ))}\n </RadioGroup>\n {warns ? (\n <Alert variant=\"warning\" announce=\"polite\">\n <Alert.Description id={warningId}>\n {t('calendarWorkspace.editor.seriesAllDiscardsOverrides')}\n </Alert.Description>\n </Alert>\n ) : null}\n <div className=\"ds:flex ds:flex-wrap ds:justify-end ds:gap-[var(--spacing-sm)]\">\n <Button intent=\"outline\" onClick={props.onCancel}>\n {t('calendarWorkspace.editor.cancel')}\n </Button>\n <Button\n intent=\"primary\"\n disabled={!scope}\n onClick={() => props.onContinue(scope)}\n >\n {t('calendarWorkspace.editor.seriesChooserContinue')}\n </Button>\n </div>\n </section>\n );\n}\n","/**\n * Calendar pattern — the SHEET HOST seam: who OPENS and CLOSES the\n * calendar's secondary surfaces (editor, details, finder, Backlog, care\n * plan). The panels and the page surface ask this context, never a\n * concrete host, so the same panels work docked in a rail or thrown in a\n * dialog: `CalendarWorkspace` maps it onto the Control Room rail's dock,\n * with `close()` returning to the Appointments panel; the Final State\n * demo maps it onto its own dock / undock.\n *\n * SHIPPED runtime module of the calendar pattern: everything exported\n * here is public API of `@alfadocs/ui-kit/patterns/calendar`. A host that\n * renders the pattern's panels outside `CalendarWorkspace` provides its\n * own `SheetHostProvider`.\n */\nimport { createContext, useContext } from 'react';\n\nexport type SheetId =\n | 'appointment-editor'\n | 'appointment-details'\n | 'find-slots'\n | 'backlog'\n | 'patient-care-plan';\n\nexport interface SheetHostContext {\n open(id: SheetId): void;\n close(): void;\n /** Optional patient-context rail tool. Standalone panel hosts may omit it. */\n openNotes?: (patientId: string, noteId?: string) => void;\n}\n\nconst SheetHostReactContext = createContext<SheetHostContext | null>(null);\n\n/** Wrap whatever renders the panels and the surface — one provider per\n * subtree is fine (a rail renders its panels outside the page tree). */\nexport const SheetHostProvider = SheetHostReactContext.Provider;\n\nexport function useSheetHost(): SheetHostContext {\n const host = useContext(SheetHostReactContext);\n if (!host) {\n throw new Error('useSheetHost: render inside a SheetHostProvider');\n }\n return host;\n}\n","/* The online-bookings rail panel's card: AppointmentCard's anatomy (time\n block, avatar, title, meta, reason) with one joined action strip in the\n footer. Kept out of calendar.sheets.tsx, which several panels share. */\nimport { forwardRef, type ReactNode } from 'react';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport {\n Armchair,\n Eye,\n EyeOff,\n MapPin,\n Pencil,\n Plus,\n UserX,\n Video,\n} from 'lucide-react';\nimport { appointmentStateWorkflow } from '../../components/_shared/entity-card';\nimport { Avatar } from '../../components/avatar';\nimport { Badge } from '../../components/badge';\nimport { Button, IconButton } from '../../components/button';\nimport { ButtonGroup } from '../../components/button-group';\nimport { Skeleton } from '../../components/skeleton';\nimport { Tag } from '../../components/tag';\nimport { Timestamp } from '../../components/timestamp';\nimport { TransactionChip } from '../../components/transaction-chip';\nimport { WhatsAppGlyph } from '../../components/whatsapp-button';\nimport { WorkflowStatusDisplay } from '../../components/workflow-status';\nimport { useCalendarData } from './calendar.data';\nimport { eventPatientRef, formatDay } from './calendar.model';\nimport type { CalendarRow } from './calendar.model';\nimport {\n upcomingAppointmentItem,\n type BookingRowView,\n} from './calendar-workspace.model';\n\n/** Which half of the booking the user asked to complete: a hint for the\n * host editor's landing step. Absent means the plain \"edit\" entry. */\nexport type BookingCompleteIntent = 'patient' | 'operator';\n\nconst bookingKey = (suffix: string): string =>\n `calendarWorkspace.inc1.bookings.${suffix}`;\n\n/** The appointment status the queue treats as normal, and so never shows. */\nconst NORMAL_STATUS = 'confirmed';\n\n/**\n * The digits `wa.me` needs from the SMS-verified booking number, or null.\n * A host may hand over a redacted display value (\"+39 *** 121\"): anything\n * but a plain number is refused rather than turned into a wrong chat.\n */\nexport function bookingWhatsAppDigits(\n phone: string | undefined,\n): string | null {\n if (!phone || !/^\\+?[\\d\\s().-]+$/.test(phone.trim())) return null;\n const digits = phone.replace(/\\D/g, '');\n return digits.length >= 7 && digits.length <= 15 ? digits : null;\n}\n\n/** \"Fri 18 Sep\": the rail is narrow, and the year is never in doubt in a\n * thirty-day queue. Accessible names keep the long form. */\nfunction shortDay(locale: string, value: Date): string {\n try {\n return new Intl.DateTimeFormat(locale, {\n weekday: 'short',\n day: 'numeric',\n month: 'short',\n }).format(value);\n } catch {\n return formatDay(locale, value);\n }\n}\n\n/* Accessible themes raise every member to the kit's target, both ways:\n an icon member is otherwise a fixed 32px square. */\nconst ACCESSIBLE_TARGET =\n 'ds:[.theme-accessible_&]:[min-block-size:var(--min-target-size)] ds:[.theme-accessible_&]:[min-inline-size:var(--min-target-size)]';\n\n/* `--warning-foreground`, not `--warning-readable`: the latter is 3.5:1 on\n a light card, enough for a glyph and too little for a small label. */\n/* `whitespace-nowrap`: the group measures its members at natural width to\n decide what spills into the menu, and a wrapped label would fool it. */\nconst stripMemberVariants = cva(`${ACCESSIBLE_TARGET} ds:whitespace-nowrap`, {\n variants: {\n tone: {\n neutral: '',\n missing: 'ds:!text-[color:var(--warning-foreground)]',\n },\n },\n defaultVariants: { tone: 'neutral' },\n});\n\nconst bookingCardVariants = cva(\n [\n 'ds:relative ds:flex ds:min-w-0 ds:flex-col ds:gap-[var(--spacing-sm)]',\n 'ds:rounded-[var(--radius-md)] ds:p-[var(--spacing-sm)]',\n 'ds:border ds:border-[color:var(--card-border)] ds:[.theme-accessible_&]:border-2',\n 'ds:text-[color:var(--card-foreground)] ds:shadow-[var(--shadow-sm)]',\n 'ds:forced-colors:border-[CanvasText]',\n 'ds:focus:outline-[length:var(--focus-ring-width)] ds:focus:outline-solid ds:focus:outline-[color:var(--ring)] ds:focus:outline-offset-[length:var(--focus-ring-offset)]',\n ].join(' '),\n {\n variants: {\n /* A new booking wears a steady, faint accent tint; the Badge beside\n its title is the channel that is not colour. */\n tint: {\n none: 'ds:bg-[var(--card)]',\n new: 'ds:bg-[color:color-mix(in_srgb,var(--accent)_5%,var(--card))]',\n },\n },\n defaultVariants: { tint: 'none' },\n },\n);\n\n/* The addressed card's accent outline: it arrives, holds and settles back\n to the card's own border. With motion off it holds steady instead. */\nconst bookingRingVariants = cva(\n [\n 'ds:pointer-events-none ds:absolute ds:inset-0 ds:rounded-[var(--radius-md)]',\n 'ds:border-2 ds:border-[color:var(--accent)] ds:opacity-0',\n 'ds:animate-[booking-addressed_calc(var(--animation-duration)*9)_var(--ease-in-out)]',\n 'ds:motion-reduce:animate-none ds:motion-reduce:opacity-100',\n 'ds:[.theme-accessible_&]:animate-none ds:[.theme-accessible_&]:opacity-100',\n 'ds:forced-colors:border-[Highlight]',\n ].join(' '),\n);\n\nconst titleVariants = cva('ds:min-w-0 ds:truncate type-title-item', {\n variants: {\n tone: {\n named: 'ds:text-[color:var(--foreground)]',\n missing: 'ds:text-[color:var(--warning-foreground)]',\n },\n },\n defaultVariants: { tone: 'named' },\n});\n\nconst avatarPlaceholderVariants = cva(\n 'ds:inline-flex ds:size-8 ds:shrink-0 ds:items-center ds:justify-center ds:rounded-[var(--radius-full)] ds:bg-[color:var(--muted)]',\n {\n variants: {\n tone: {\n hidden: 'ds:text-[color:var(--muted-foreground)]',\n missing:\n 'ds:border ds:border-dashed ds:border-[color:var(--warning-readable)] ds:text-[color:var(--warning-foreground)]',\n },\n },\n },\n);\n\n/* The title is the card's activator: its ::after stretches over the top\n block only, so the footer's strip is never under a second hit area. */\nconst TITLE_ACTIVATOR_CLASS = [\n 'ds:inline-flex ds:min-w-0 ds:flex-1 ds:basis-24 ds:cursor-pointer',\n 'ds:border-0 ds:bg-transparent ds:p-0 ds:text-start',\n 'ds:focus-visible:outline-none',\n \"ds:after:absolute ds:after:inset-0 ds:after:rounded-[var(--radius-sm)] ds:after:content-['']\",\n 'ds:focus-visible:after:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:after:outline-solid',\n 'ds:focus-visible:after:outline-[color:var(--ring)]',\n 'ds:focus-visible:after:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:after:outline-[CanvasText]',\n].join(' ');\n\nconst META_CLASS =\n 'type-eyebrow ds:flex ds:flex-wrap ds:items-center ds:gap-x-[var(--spacing-sm)] ds:gap-y-[var(--spacing-2xs)] ds:text-[color:var(--muted-foreground)]';\n\nexport interface BookingCardProps {\n view: BookingRowView;\n locale?: string;\n /** Masked title, no photo, no contact, no reason, no WhatsApp number. */\n privacy?: boolean;\n /** False withholds the assign segments and the pencil: a host that cannot\n * complete a booking is never offered a control it would refuse. */\n canComplete: boolean;\n onComplete?: (row: CalendarRow, intent?: BookingCompleteIntent) => void;\n onShowInCalendar: (eventId: string) => void;\n /** The host addressed this card: ring it (see `BookingsPanel`). */\n addressed?: boolean;\n /** Changes on every address, so a repeat address replays the ring. */\n addressKey?: string | number;\n}\n\nexport const BookingCard = forwardRef<HTMLDivElement, BookingCardProps>(\n (\n {\n view,\n locale,\n privacy = false,\n canComplete,\n onComplete,\n onShowInCalendar,\n addressed = false,\n addressKey,\n },\n ref,\n ) => {\n const { t } = useTranslation();\n const data = useCalendarData();\n const lng = locale ?? 'en';\n const { row } = view;\n const item = upcomingAppointmentItem(\n row,\n privacy,\n data,\n t('calendarWorkspace.details.patientNotLoaded'),\n );\n const record = eventPatientRef(row.event, data).record;\n const contact = privacy ? undefined : data.bookingContacts[view.eventId];\n /* Privacy: the number never leaves this line, so it cannot reach an\n attribute, a label or the click handler. */\n const whatsAppDigits = bookingWhatsAppDigits(contact?.phone);\n const title = item.patient?.name ?? t(bookingKey('needsPatient'));\n const when = formatDay(lng, view.start);\n const named = (action: string): string =>\n t(bookingKey('actionNamed'), { action, who: title, when });\n const complete = (intent?: BookingCompleteIntent): void => {\n if (canComplete) onComplete?.(row, intent);\n };\n const bothMissing = view.needsPatient && view.needsOperator;\n const status = item.state;\n const statusWorkflow = appointmentStateWorkflow(status);\n const StatusIcon = statusWorkflow.Icon;\n const TypeIcon = item.type === 'telehealth' ? Video : MapPin;\n const whatsAppLabel = t(bookingKey('whatsapp'));\n const whatsAppReason = t(\n privacy\n ? 'calendarWorkspace.privacy.hidden'\n : bookingKey('whatsappNoNumber'),\n );\n\n let avatar: ReactNode;\n if (!item.patient) {\n avatar = (\n <span className={avatarPlaceholderVariants({ tone: 'missing' })}>\n <UserX aria-hidden=\"true\" className=\"ds:size-4\" />\n </span>\n );\n } else if (privacy) {\n avatar = (\n <span className={avatarPlaceholderVariants({ tone: 'hidden' })}>\n <EyeOff aria-hidden=\"true\" className=\"ds:size-4\" />\n </span>\n );\n } else {\n avatar = (\n <Avatar\n name={item.patient.name}\n src={record?.avatarSrc}\n size=\"sm\"\n className=\"ds:shrink-0\"\n aria-hidden=\"true\"\n role=\"presentation\"\n aria-label={undefined}\n />\n );\n }\n\n return (\n <div\n ref={ref}\n role=\"listitem\"\n data-component=\"calendar-booking-card\"\n data-booking-id={view.eventId}\n data-new={view.isNew ? '' : undefined}\n data-addressed={addressed ? '' : undefined}\n aria-current={addressed ? 'true' : undefined}\n tabIndex={addressed ? -1 : undefined}\n className={bookingCardVariants({ tint: view.isNew ? 'new' : 'none' })}\n >\n {addressed ? (\n <>\n <span className=\"ds:sr-only\">{t(bookingKey('current'))}</span>\n <span\n key={`${view.eventId}:${addressKey ?? ''}`}\n aria-hidden=\"true\"\n data-booking-ring=\"addressed\"\n className={bookingRingVariants()}\n />\n </>\n ) : null}\n {/* Wraps: in a rail too narrow for three columns the text column\n drops under the time and avatar, and takes the full width. */}\n <div className=\"ds:relative ds:flex ds:min-w-0 ds:flex-wrap ds:items-start ds:gap-[var(--spacing-sm)]\">\n <span className=\"ds:flex ds:min-w-20 ds:shrink-0 ds:flex-col ds:items-start ds:gap-[var(--spacing-2xs)]\">\n <span className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)] ds:whitespace-nowrap ds:text-[color:var(--muted-foreground)]\">\n <TypeIcon\n aria-hidden=\"true\"\n className=\"ds:size-3.5 ds:shrink-0\"\n />\n <span className=\"ds:sr-only\">\n {t(`appointmentCard.type.${item.type}`)}\n </span>\n <Timestamp\n value={item.startIso}\n format=\"absolute\"\n shape=\"bare\"\n locale={locale}\n absoluteFormat={{ hour: 'numeric', minute: '2-digit' }}\n className=\"type-body-sm ds:font-medium ds:text-[color:var(--foreground)] ds:tabular-nums\"\n />\n </span>\n <span className=\"type-eyebrow ds:text-[color:var(--muted-foreground)]\">\n {t('appointmentCard.duration', { count: item.durationMin })}\n </span>\n </span>\n {avatar}\n <div className=\"ds:flex ds:min-w-0 ds:flex-1 ds:basis-40 ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <div className=\"ds:flex ds:min-w-0 ds:flex-wrap ds:items-center ds:gap-x-[var(--spacing-xs)] ds:gap-y-[var(--spacing-2xs)]\">\n <button\n type=\"button\"\n className={TITLE_ACTIVATOR_CLASS}\n aria-label={named(\n t(bookingKey(canComplete ? 'edit' : 'showInCalendar')),\n )}\n onClick={() =>\n canComplete ? complete() : onShowInCalendar(view.eventId)\n }\n >\n <span\n className={titleVariants({\n tone: item.patient ? 'named' : 'missing',\n })}\n >\n {title}\n </span>\n </button>\n {view.isNew ? (\n <Badge size=\"sm\" variant=\"brand\" data-booking-new=\"\">\n {t(bookingKey('new'))}\n </Badge>\n ) : null}\n {view.paidOnline !== null && view.paidOnline > 0 ? (\n /* The details panel's own name for this money, so the same\n deposit reads the same on both surfaces. */\n <TransactionChip\n data-booking-paid=\"\"\n state=\"settled\"\n amount={view.paidOnline}\n currency=\"EUR\"\n locale={locale}\n size=\"sm\"\n showLabel\n label={t('calendarWorkspace.details.paidOnline')}\n showIcon={false}\n />\n ) : null}\n {status !== NORMAL_STATUS ? (\n <WorkflowStatusDisplay\n size=\"sm\"\n value={status}\n option={{\n value: status,\n label: t(`appointmentCard.state.${status}`),\n icon: <StatusIcon aria-hidden=\"true\" />,\n tone: statusWorkflow.tone,\n }}\n className=\"ds:shrink-0\"\n />\n ) : null}\n </div>\n <div className={META_CLASS}>\n {item.operator ? <span>{item.operator.name}</span> : null}\n <span>{shortDay(lng, view.start)}</span>\n {view.chairTitle ? (\n <span className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-2xs)]\">\n <Armchair\n aria-hidden=\"true\"\n className=\"ds:size-3 ds:shrink-0\"\n />\n {view.chairTitle}\n </span>\n ) : null}\n {view.needsOperator ? (\n <span className=\"ds:text-[color:var(--warning-foreground)]\">\n {t(bookingKey('needsOperator'))}\n </span>\n ) : null}\n </div>\n {privacy ? (\n <span className=\"type-body-sm ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)] ds:text-[color:var(--muted-foreground)]\">\n <EyeOff\n aria-hidden=\"true\"\n className=\"ds:size-3.5 ds:shrink-0\"\n />\n {t('calendarWorkspace.privacy.hidden')}\n </span>\n ) : (\n <span className=\"type-body-sm ds:truncate ds:text-[color:var(--foreground)]\">\n {view.reason ?? t(bookingKey('noReason'))}\n </span>\n )}\n {item.treatments && item.treatments.length > 0 ? (\n <div className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-2xs)]\">\n {item.treatments.map((treatment, index) => (\n <Tag\n key={`${treatment.careName}-${index}`}\n label={treatment.careName}\n variant=\"neutral\"\n fill=\"outline\"\n size=\"sm\"\n maxInlineSize=\"12rem\"\n />\n ))}\n </div>\n ) : null}\n </div>\n </div>\n {contact ? (\n /* Host-redacted contact values are display text, never dial\n or email actions. */\n <div\n data-booking-contact=\"\"\n className=\"type-body-sm ds:flex ds:min-w-0 ds:flex-wrap ds:gap-x-[var(--spacing-sm)] ds:text-[color:var(--muted-foreground)] ds:[overflow-wrap:anywhere]\"\n >\n {[contact.typedName, contact.phone, contact.email]\n .filter((value) => value.trim() !== '')\n .map((value) => (\n <span key={value} className=\"ds:min-w-0\">\n {value}\n </span>\n ))}\n </div>\n ) : null}\n <div className=\"ds:flex ds:min-w-0 ds:flex-col ds:gap-[var(--spacing-xs)] ds:border-t ds:border-dashed ds:border-[color:var(--border)] ds:pt-[var(--spacing-sm)]\">\n <ButtonGroup\n size=\"sm\"\n overflow=\"menu\"\n label={named(t(bookingKey('actionsLabel')))}\n data-booking-actions=\"\"\n >\n {canComplete && view.needsPatient ? (\n <Button\n key=\"patient\"\n startIcon={<Plus />}\n className={stripMemberVariants({ tone: 'missing' })}\n aria-label={named(t(bookingKey('assignPatient')))}\n data-booking-action=\"assign-patient\"\n onClick={() => complete('patient')}\n >\n {t(\n bookingKey(\n bothMissing ? 'assignPatientShort' : 'assignPatient',\n ),\n )}\n </Button>\n ) : null}\n {canComplete && view.needsOperator ? (\n <Button\n key=\"operator\"\n startIcon={<Plus />}\n className={stripMemberVariants({ tone: 'missing' })}\n aria-label={named(t(bookingKey('assignOperator')))}\n data-booking-action=\"assign-operator\"\n onClick={() => complete('operator')}\n >\n {t(\n bookingKey(\n bothMissing ? 'assignOperatorShort' : 'assignOperator',\n ),\n )}\n </Button>\n ) : null}\n <IconButton\n key=\"show\"\n icon={<Eye />}\n className={stripMemberVariants()}\n aria-label={t(bookingKey('showInCalendarNamed'), { when })}\n tooltip={t(bookingKey('showInCalendar'))}\n data-booking-action=\"show\"\n onClick={() => onShowInCalendar(view.eventId)}\n />\n {/* Both missing: either assign segment already opens the editor,\n so the pencil steps aside and the strip fits the rail. */}\n {canComplete && !bothMissing ? (\n <IconButton\n key=\"edit\"\n icon={<Pencil />}\n className={stripMemberVariants()}\n aria-label={named(t(bookingKey('edit')))}\n tooltip={t(bookingKey('edit'))}\n data-booking-action=\"edit\"\n onClick={() => complete()}\n />\n ) : null}\n {/* A plain member in the strip's own colour: the brand green of\n WhatsAppButton is not wanted here. `aria-disabled`, not the\n native attribute, so the reason's tooltip can be reached. */}\n <IconButton\n key=\"whatsapp\"\n icon={<WhatsAppGlyph aria-hidden=\"true\" />}\n className={stripMemberVariants()}\n aria-label={\n whatsAppDigits\n ? named(whatsAppLabel)\n : `${whatsAppLabel}: ${whatsAppReason}`\n }\n tooltip={whatsAppDigits ? whatsAppLabel : whatsAppReason}\n aria-disabled={whatsAppDigits ? undefined : true}\n /* Pinned while disabled: the overflow menu would list it as\n a live item, and it has nothing to do. */\n data-overflow-pin={whatsAppDigits ? undefined : true}\n data-booking-action=\"whatsapp\"\n onClick={() => {\n if (!whatsAppDigits) return;\n window.open(\n `https://wa.me/${whatsAppDigits}`,\n '_blank',\n 'noopener,noreferrer',\n );\n }}\n />\n </ButtonGroup>\n {view.bookedAt ? (\n <span className=\"type-body-sm ds:text-end ds:text-[color:var(--muted-foreground)]\">\n {t(bookingKey('bookedOn'), {\n date: shortDay(lng, view.bookedAt),\n })}\n </span>\n ) : null}\n </div>\n </div>\n );\n },\n);\nBookingCard.displayName = 'BookingCard';\n\n/** The first read's placeholders, in the card's own shape: time block,\n * avatar, three lines, and the strip under its divider. */\nexport function BookingCardsSkeleton() {\n return (\n <div\n aria-hidden=\"true\"\n data-bookings-loading=\"\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n {[0, 1, 2].map((index) => (\n <div\n key={index}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--border)] ds:p-[var(--spacing-sm)]\"\n >\n <div className=\"ds:flex ds:items-start ds:gap-[var(--spacing-sm)]\">\n <div className=\"ds:flex ds:w-20 ds:shrink-0 ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <Skeleton\n variant=\"text\"\n size=\"sm\"\n stagger={index * 2}\n width=\"70%\"\n />\n <Skeleton\n variant=\"text\"\n size=\"sm\"\n stagger={index * 2}\n width=\"50%\"\n />\n </div>\n <Skeleton variant=\"circular\" size=\"sm\" stagger={index * 2} />\n <div className=\"ds:flex ds:min-w-0 ds:flex-1 ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <Skeleton\n variant=\"text\"\n size=\"sm\"\n stagger={index * 2}\n width={index === 1 ? '40%' : '60%'}\n />\n <Skeleton\n variant=\"text\"\n size=\"sm\"\n stagger={index * 2 + 1}\n width=\"80%\"\n />\n <Skeleton\n variant=\"text\"\n size=\"sm\"\n stagger={index * 2 + 1}\n width=\"33%\"\n />\n </div>\n </div>\n <div className=\"ds:border-t ds:border-dashed ds:border-[color:var(--border)] ds:pt-[var(--spacing-sm)]\">\n <Skeleton\n variant=\"rounded\"\n stagger={index * 2 + 1}\n width=\"66%\"\n height=\"var(--spacing-xl)\"\n />\n </div>\n </div>\n ))}\n </div>\n );\n}\n","/**\n * Calendar demo — the SECONDARY SURFACES (the sheets): task details, the\n * patient record / notes / appointments / tasks panels, the appointment\n * editor (create, edit and details in ONE form) with its identity and\n * extras blocks, the patient care plan, the Final State's Backlog and\n * Increment 1's platform waiting list with their shared entry form,\n * Increment 1's online-bookings panel, the find-free-slots finder and\n * the front-desk print sheet.\n *\n * The editor's form is a DENSITY-TIERED grid: a container query on the\n * panel's own inline size pairs its short fields from 30rem and moves the\n * label beside the control from 44rem, so it fits the rail without\n * scrolling. No target shrinks — only the column count and the label's\n * position change.\n *\n * Every panel composes kit primitives over the host-supplied read model\n * (`useCalendarData()`, see `calendar.data.ts`) and the pure model in\n * `calendar.model.ts`; none knows WHERE it is hosted — the open / close\n * seam is `calendar.host.ts`, which the Final State demo maps onto its\n * full Control Room rail and the shipped `CalendarWorkspace` onto a\n * minimal five-tool one. Nothing here imports from the stories module,\n * the demos or the shared story shell.\n */\nimport {\n Fragment,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type FormEvent,\n type ReactNode,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { CalendarPatientPicker } from './calendar-patient-picker';\nimport { useEditorInitialFocus } from './calendar-rail-settle';\nimport { toastWarning } from '../../components/toast';\nimport type { CalendarEditorCapabilities } from './calendar.model';\nimport type { CalendarEditorSeries } from './calendar-editor-hydration';\nimport { CalendarSeriesScopeChooser } from './calendar-series-scope-chooser';\nimport type { ColDef, GridOptions } from 'ag-grid-community';\nimport type { CustomCellRendererProps } from 'ag-grid-react';\nimport { useTranslation } from 'react-i18next';\nimport { getErrorMessage } from '../../components/_shared/get-error-message';\nimport {\n Armchair,\n CalendarClock,\n CalendarDays,\n CalendarPlus,\n CalendarSearch,\n UserCog,\n ClipboardList,\n Copy,\n Hourglass,\n Check,\n Clock,\n Euro,\n Globe,\n HeartPulse,\n Stethoscope,\n Mail,\n MessageSquare,\n TriangleAlert,\n Video,\n Repeat,\n Pencil,\n Plus,\n Trash2,\n Save,\n X,\n Funnel,\n History as HistoryIcon,\n ArrowLeft,\n ArrowRight,\n PenLine,\n Send,\n Move,\n LayoutList,\n CircleDashed,\n Lock,\n ClipboardPaste,\n MapPin,\n Smartphone,\n} from 'lucide-react';\nimport {\n type CalendarEvent,\n type CalendarEventStatus,\n type CalendarResource,\n} from '../../components/calendar';\nimport {\n PatientDetails,\n type PatientDetailsSection,\n} from '../../components/patient-details';\nimport { VisuallyHidden } from '../../components/visually-hidden';\nimport {\n NotesPanel,\n type NotesPanelNote,\n type NotesPanelProps,\n type NotesPanelSubmission,\n type AiConsentGate,\n} from '../../components/notes-panel';\nimport { ClinicalNoteCard } from '../../components/clinical-note-card';\nimport { NoteTimeline } from '../../components/note-timeline';\nimport { AppointmentTimeline } from '../../components/appointment-timeline';\nimport { TasksPanel, type TasksPanelItem } from '../../components/tasks-panel';\nimport { Avatar } from '../../components/avatar';\nimport { EmptyState } from '../../components/empty-state';\nimport { PanelHeader } from '../../components/panel-header';\nimport { PanelSubview } from '../../components/panel-subview';\nimport { ScrollArea } from '../../components/scroll-area';\nimport { FormField } from '../../components/form-field';\nimport { Combobox } from '../../components/combobox';\nimport { Radio, RadioGroup } from '../../components/radio-group';\nimport { TextInput } from '../../components/text-input';\nimport { TextArea } from '../../components/text-area';\nimport { SearchInput } from '../../components/search-input';\nimport { NumberInput } from '../../components/number-input';\nimport { TimePicker } from '../../components/time-picker';\nimport {\n ColorPicker,\n GOOGLE_CALENDAR_PALETTE,\n} from '../../components/color-picker';\nimport {\n WhatsAppButton,\n WhatsAppGlyph,\n} from '../../components/whatsapp-button';\nimport { Badge } from '../../components/badge';\nimport { DataTable } from '../../components/data-table';\nimport { Checkbox } from '../../components/checkbox';\nimport { Tag } from '../../components/tag';\nimport { DropdownMenu } from '../../components/dropdown-menu';\nimport { CarePlanCard } from '../../components/care-plan-card';\nimport { CarePlanEntryCard } from '../../components/care-plan-entry-card';\nimport {\n Accordion,\n AccordionItem,\n AccordionTrigger,\n AccordionContent,\n} from '../../components/accordion';\nimport { KeyValuePair } from '../../components/key-value-pair';\nimport { Timestamp } from '../../components/timestamp';\nimport { Switch } from '../../components/switch';\nimport { Button, IconButton } from '../../components/button';\nimport { ButtonGroup } from '../../components/button-group';\nimport { IconButtonGroup } from '../../components/icon-button-group';\nimport {\n Collapsible,\n CollapsibleTrigger,\n CollapsibleContent,\n} from '../../components/collapsible';\nimport { DatePicker } from '../../components/date-picker';\nimport { Dialog } from '../../components/dialog';\nimport { Popover } from '../../components/popover';\nimport { Select } from '../../components/select';\nimport { Alert } from '../../components/alert';\nimport { Timeline } from '../../components/timeline';\nimport { SignatureStatusChip } from '../../components/signature-status-chip';\nimport {\n WorkflowStatusDisplay,\n type WorkflowStatusOption,\n} from '../../components/workflow-status';\nimport {\n type ColorAssociation,\n associationColor,\n careLabel,\n type CalendarCareLink,\n type CalendarCarePlan,\n type CalendarAnamnesisAnswer,\n type CalendarCarePlanEntry,\n buildOperatorFilterGroups,\n type CalendarOperatorGroup,\n type CalendarPatient,\n type CalendarWaitingEntry,\n type CalendarHistoryEntry,\n type CalendarSignChannel,\n type PatientRef,\n channelOfferable,\n channelReasonKey,\n catalogueUsable,\n patientChannelState,\n patientRefName,\n type FreeSlotQuery,\n} from './calendar.types';\nimport { useSheetHost } from './calendar.host';\nimport { useCalendarData, type CalendarData } from './calendar.data';\nimport {\n STATUS_UI_KEY,\n type CalendarRow,\n type DisplaySettings,\n formatTimeRange,\n formatDay,\n sortHistoryNewestFirst,\n selectionState,\n patientAgeYears,\n type EditorPrefill,\n type RecurrenceFrequency,\n RECURRENCE_MAX_COUNT,\n RECURRENCE_FREQUENCIES,\n RECURRENCE_LABEL_KEY,\n addMonthsClamped,\n type EditorDraft,\n type DraftSlot,\n type SlotPatch,\n NONE,\n DURATION_PRESETS_MIN,\n durationDigitsFilter,\n initialEditorColor,\n deriveCareLinkDefaults,\n DETAIL_STAMP_FORMAT,\n signingSummary,\n type PriceRow,\n EMPTY_SCHEDULE,\n priceListIdFor,\n priceListState,\n STATUS_CHIP,\n type BacklogType,\n type BacklogFilter,\n BACKLOG_TYPES,\n type BacklogItem,\n eventStartMs,\n waitingEntryAppointment,\n backlogCounts,\n backlogPatientRef,\n backlogName,\n eventPatientRef,\n patientRefById,\n filterBacklog,\n type WaitingQuickView,\n WAITING_QUICK_VIEWS,\n WAITING_QUICK_VIEW_LABEL_KEY,\n filterWaitingQuickView,\n processBookingPrefill,\n assignOperatorPrefill,\n callToActionSatisfied,\n type WaitingEntryDraft,\n waitingEntryIsValid,\n ANY,\n FREE_SLOT_CAP,\n FREE_SLOT_DEFAULT_HORIZON_DAYS,\n rangeDays,\n type CalendarFreeSlot,\n localIsoDate,\n type PrintRow,\n type PrintDayNote,\n type PrintDaySection,\n PRINT_CELL_CLASS,\n printRowHeight,\n closureReason,\n type FindSlotsSeed,\n type AvailabilityContext,\n /* Aliased: `serverSearch` below is the HOST's seam of the same name. */\n searchFreeSlots as computeFreeSlotsLocally,\n} from './calendar.model';\nimport {\n bookingRowView,\n toggleSelectedIds,\n type RecurringScope,\n RECURRING_SCOPES,\n RECURRING_SCOPE_LABEL_KEY,\n type RequiredDocsSignMode,\n type EditorDraftExtras,\n type DeleteOptions,\n slotConflicts,\n devicesForCares,\n signChannelStates,\n defaultSignMode,\n patientAddressLabel,\n patientAddressLine,\n patientMapsUrl,\n} from './calendar-workspace.model';\nimport {\n BookingCard,\n BookingCardsSkeleton,\n type BookingCompleteIntent,\n} from './calendar-bookings-panel';\n\n/** The operators a NEW booking may take — the practice's ACTIVE cast, as\n * on the platform. A disabled operator reaches a list only through\n * `platform.operatorOptions` (the appointment that already holds her);\n * lookups by id stay inclusive so her own rows still name her. */\nexport function activeOperators(data: CalendarData): CalendarResource[] {\n return data.operators.filter((o) => !data.inactiveOperatorIds.includes(o.id));\n}\n\n/** Why the WhatsApp affordance cannot act, as an i18n key. Decided in ONE\n * place so the waiting list's two rows — the backlog card and the grid\n * cell — cannot drift apart again.\n *\n * Three states, never two (see `patientChannelState`). `unknown` folds\n * \"no record at all\" together with \"a record that omits the number\", so\n * a caller reading it as \"no record\" told a patient the row had just\n * rendered by name that their record had failed to load. Only\n * `ref.unresolved` — the lookup we really did fail — may say that; a\n * record we DID load and that simply carries no number says so itself,\n * and never claims the practice holds nothing (that is state `none`,\n * which keeps the platform's own SMS reason). */\nexport function whatsAppUnavailableKey(ref: PatientRef): string {\n if (ref.unresolved) return 'calendarWorkspace.details.patientNotLoaded';\n if (ref.assigned && patientChannelState(ref, 'sms') === 'unknown') {\n return 'calendarWorkspace.details.patientPhoneUnknown';\n }\n return 'calendarWorkspace.waitingList.whatsappDisabled';\n}\n\n/* ------------------------------------------------------------------ */\n/* Task details — the platform DoctorReminder slice for one task */\n/* (type, note, due, assignee, operator, company, provenance), shaped */\n/* like the appointment panel above. Tasks carry NO chair on the */\n/* platform, so none is shown here. */\n/* ------------------------------------------------------------------ */\n\nexport function TaskDetailsPanel({\n row,\n locale,\n}: {\n row: CalendarRow;\n locale: string;\n}) {\n const data = useCalendarData();\n const { t } = useTranslation();\n const { t: tUi } = useTranslation();\n const key = (suffix: string): string => `calendarWorkspace.task.${suffix}`;\n const detailKey = (suffix: string): string =>\n `calendarWorkspace.details.${suffix}`;\n\n const detail = data.taskDetails[row.event.id];\n const patientRef = eventPatientRef(row.event, data);\n const patient = patientRef.record;\n const operator = data.operators.find((o) => o.id === row.operatorId);\n\n /* Platform semantics: `done` wins; an open task whose due instant is\n behind the fixed demo clock reads as overdue. Both strings are the\n local-wall-clock shape the fixtures emit, so the lexicographic\n compare is a date compare. */\n const status: 'open' | 'done' | 'overdue' = detail?.done\n ? 'done'\n : (\n row.event.allDay\n ? String(row.event.start).slice(0, 10) < data.nowIso.slice(0, 10)\n : String(row.event.start) < data.nowIso\n )\n ? 'overdue'\n : 'open';\n const typeLabel = detail\n ? detail.type === 'custom'\n ? (detail.typeLabel ?? '')\n : t(key(`types.${detail.type}`))\n : '';\n\n const sections = useMemo<PatientDetailsSection[]>(() => {\n const taskFields: PatientDetailsSection['fields'] = [\n {\n id: 'due',\n label: t(key('due')),\n value: formatDay(locale, row.event.start),\n },\n {\n id: 'time',\n label: t(key('time')),\n value: row.event.allDay\n ? tUi('calendar.allDay')\n : formatTimeRange(locale, row.event.start, row.event.end),\n },\n ...(typeLabel\n ? [{ id: 'type', label: t(key('type')), value: typeLabel }]\n : []),\n ...(detail?.assigneeName\n ? [\n {\n id: 'assignee',\n label: t(key('assignee')),\n value: detail.assigneeName,\n },\n ]\n : []),\n ...(operator\n ? [\n {\n id: 'operator',\n label: t(detailKey('operator')),\n value: operator.title,\n },\n ]\n : []),\n ...(detail?.companyName\n ? [\n {\n id: 'company',\n label: t(key('company')),\n value: detail.companyName,\n },\n ]\n : []),\n ...(detail\n ? [\n {\n id: 'created',\n label: t(key('created')),\n value: `${formatDay(locale, detail.createdAtIso)} · ${\n detail.createdBy === 'workflow'\n ? t(key('automation'))\n : (detail.createdByName ?? '')\n }`,\n },\n ]\n : []),\n ...(detail?.note\n ? [{ id: 'note', label: t(key('note')), value: detail.note }]\n : []),\n ];\n /* One row per fact the HOST supplied. A field it left out is not a\n blank row under its label — a blank date of birth reads as \"we\n hold none\", which is a claim about the record we cannot make. */\n const patientFields: PatientDetailsSection['fields'] = patient\n ? [\n ...(patient.dobIso\n ? [\n {\n id: 'dob',\n label: t(detailKey('dob')),\n kind: 'dob' as const,\n editValue: patient.dobIso,\n },\n ]\n : []),\n ...(patient.phone\n ? [\n {\n id: 'phone',\n label: t(detailKey('phone')),\n kind: 'phone' as const,\n value: patient.phone,\n },\n ]\n : []),\n ...(patient.email\n ? [\n {\n id: 'email',\n label: t(detailKey('email')),\n kind: 'email' as const,\n value: patient.email,\n },\n ]\n : []),\n ...(patient.city\n ? [\n {\n id: 'city',\n label: t(detailKey('city')),\n value: patient.city,\n },\n ]\n : []),\n ]\n : [];\n return [\n { id: 'task', heading: t(key('sectionTask')), fields: taskFields },\n /* No rows left to show ⇒ no Patient heading over an empty list. */\n ...(patientFields.length > 0\n ? [\n {\n id: 'patient',\n heading: t(detailKey('sectionPatient')),\n fields: patientFields,\n },\n ]\n : []),\n ];\n }, [t, tUi, locale, row, patient, detail, operator, typeLabel]);\n\n return (\n <PatientDetails\n id=\"demo-task-details\"\n panelTitle={t(key('region'))}\n title={row.event.title}\n avatar={\n patient ? { name: patient.name, src: patient.avatarSrc } : undefined\n }\n /* The ID the task carries — the panel's deep links answer to it\n whether or not the record loaded. */\n patientId={patientRef.id || undefined}\n locale={locale}\n sections={sections}\n headerChips={\n <span className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-2xs)]\">\n <Badge variant=\"neutral\" size=\"sm\" withDot>\n {t(key(`status.${status}`))}\n </Badge>\n {detail?.createdBy === 'workflow' ? (\n <Badge variant=\"neutral\" size=\"sm\">\n {t(key('automation'))}\n </Badge>\n ) : null}\n </span>\n }\n />\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Patient record — the patient's own details tab (the \"Patient */\n/* details\" panel the patient-record context docks), alongside the */\n/* appointment/task details when a selection carries a patient. */\n/* ------------------------------------------------------------------ */\n\nexport function PatientRecordPanel({\n patientId,\n locale,\n}: {\n patientId: string;\n locale: string;\n}) {\n const data = useCalendarData();\n const { t } = useTranslation();\n const key = (suffix: string): string => `calendarWorkspace.patient.${suffix}`;\n const detailKey = (suffix: string): string =>\n `calendarWorkspace.details.${suffix}`;\n const patient = data.patientById(patientId);\n\n const sections = useMemo<PatientDetailsSection[]>(() => {\n if (!patient) return [];\n const [firstName, ...familyParts] = patient.name.split(' ');\n const lastName = familyParts.join(' ');\n const euro = (amount: number): string =>\n new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: 'EUR',\n }).format(amount);\n const personalFields: PatientDetailsSection['fields'] = [\n ...(lastName\n ? [{ id: 'lastName', label: t(key('lastName')), value: lastName }]\n : []),\n { id: 'firstName', label: t(key('firstName')), value: firstName },\n ...(patient.sex\n ? [\n {\n id: 'sex',\n label: t(key('sex')),\n kind: 'sex' as const,\n editValue: patient.sex,\n },\n ]\n : []),\n ...(patient.dobIso\n ? [\n {\n id: 'dob',\n label: t(detailKey('dob')),\n kind: 'dob' as const,\n editValue: patient.dobIso,\n },\n ]\n : []),\n ...(patient.fiscalCode\n ? [\n {\n id: 'fiscalCode',\n label: t(key('fiscalCode')),\n kind: 'fiscalCode' as const,\n editValue: patient.fiscalCode,\n mono: true,\n copyable: true,\n copyText: patient.fiscalCode,\n },\n ]\n : []),\n ];\n const contactFields: PatientDetailsSection['fields'] = [\n ...(patient.phone\n ? [\n {\n id: 'phone',\n label: t(detailKey('phone')),\n kind: 'phone' as const,\n value: patient.phone,\n },\n ]\n : []),\n ...(patient.email\n ? [\n {\n id: 'email',\n label: t(detailKey('email')),\n kind: 'email' as const,\n value: patient.email,\n },\n ]\n : []),\n ...(patient.address\n ? [{ id: 'address', label: t(key('address')), value: patient.address }]\n : []),\n ...(patient.city\n ? [{ id: 'city', label: t(detailKey('city')), value: patient.city }]\n : []),\n ...(patient.province\n ? [\n {\n id: 'province',\n label: t(key('province')),\n value: patient.province,\n },\n ]\n : []),\n ...(patient.postalCode\n ? [\n {\n id: 'postalCode',\n label: t(key('postalCode')),\n value: patient.postalCode,\n },\n ]\n : []),\n ];\n const clinicalFields: PatientDetailsSection['fields'] = [\n ...(patient.allergies\n ? [\n {\n id: 'allergies',\n label: t(key('allergies')),\n value: patient.allergies,\n sensitive: true,\n },\n ]\n : []),\n ...(patient.diagnosis\n ? [\n {\n id: 'diagnosis',\n label: t(key('diagnosis')),\n value: patient.diagnosis,\n },\n ]\n : []),\n ];\n const adminFields: PatientDetailsSection['fields'] = [\n ...(patient.patientSinceIso\n ? [\n {\n id: 'patientSince',\n label: t(key('patientSince')),\n value: formatDay(locale, patient.patientSinceIso),\n },\n ]\n : []),\n ...(patient.lastVisitIso\n ? [\n {\n id: 'lastVisit',\n label: t(key('lastVisit')),\n value: formatDay(locale, patient.lastVisitIso),\n },\n ]\n : []),\n ...(patient.priceList\n ? [\n {\n id: 'priceList',\n label: t(key('priceList')),\n value: patient.priceList,\n },\n ]\n : []),\n ...(patient.discountPct !== undefined\n ? [\n {\n id: 'discount',\n label: t(key('discount')),\n value: `${patient.discountPct}%`,\n },\n ]\n : []),\n ...(patient.unpaidAmount !== undefined\n ? [\n {\n id: 'unpaid',\n label: t(key('unpaid')),\n value: euro(patient.unpaidAmount),\n },\n ]\n : []),\n ];\n const built: PatientDetailsSection[] = [\n {\n id: 'personal',\n heading: t(key('sectionPersonal')),\n fields: personalFields,\n },\n {\n id: 'contact',\n heading: t(key('sectionContact')),\n fields: contactFields,\n },\n {\n id: 'clinical',\n heading: t(key('sectionClinical')),\n fields: clinicalFields,\n },\n {\n id: 'administrative',\n heading: t(key('sectionAdmin')),\n collapsible: true,\n defaultOpen: false,\n fields: adminFields,\n },\n ];\n return built.filter((section) => section.fields.length > 0);\n }, [t, locale, patient]);\n\n if (!patient) return null;\n return (\n <PatientDetails\n id=\"demo-patient-details\"\n aria-label={t(key('region'))}\n title={patient.name}\n avatar={{ name: patient.name, src: patient.avatarSrc }}\n patientId={patient.id}\n locale={locale}\n sections={sections}\n />\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Patient-scoped rail panels — same primitives as the clinic tools, */\n/* filtered to the selected appointment's patient. */\n/* ------------------------------------------------------------------ */\n\n/**\n * Where a note WRITE goes. The workspace builds one of these from its\n * `CalendarJourney` and hands it down; the panel renders `notes` and\n * reports intent, holding no note state and composing no note text of\n * its own. Nothing the kit invented — a draft paragraph, a transcript,\n * an author's name — can reach a patient's record through it.\n */\nexport interface PatientNotesSeam {\n /** The patient's notes as the HOST holds them, newest first. */\n notes: NotesPanelNote[];\n /** Commit what was typed. The host stamps the id, date and author. */\n onAddNote: (submission: NotesPanelSubmission) => void | Promise<void>;\n /** Replace a note's body: HTML for an HTML note, else plain text. */\n onEditNote: (noteId: string, content: string) => void | Promise<void>;\n onDeleteNote: (noteId: string) => void | Promise<void>;\n onTogglePin: (noteId: string) => void | Promise<void>;\n /** The practice's own drafting endpoint. Omitted → no AI affordance. */\n onRequestAiDraft?: NotesPanelProps['onRequestAiDraft'];\n /** The host's live transcription. Omitted → no microphone. */\n onDictate?: NotesPanelProps['onDictate'];\n /**\n * The patient's recorded AI-consent state, gating Help-me-write and both\n * mics. Omitted → today's ungated behaviour (matches `NotesPanel`).\n */\n aiConsent?: AiConsentGate;\n /** Template variables for the composer's \"Insert variable\" menu. See\n * `RichTextEditor`. */\n variables?: NotesPanelProps['variables'];\n /** Decide whether a `[[TOKEN]]` is valid. See `RichTextEditor`. */\n validateVariable?: NotesPanelProps['validateVariable'];\n /** The invalid `[[TOKEN]]`s in the draft. See `RichTextEditor`. */\n onVariableValidityChange?: NotesPanelProps['onVariableValidityChange'];\n /** Bring your own Help-me-write surface (e.g. practice templates). See\n * `RichTextEditor`. */\n renderHelpMeWrite?: NotesPanelProps['renderHelpMeWrite'];\n /** Upload an image yourself and resolve its URL. See `RichTextEditor`. */\n onUploadImage?: NotesPanelProps['onUploadImage'];\n /** An AI call ran out of credits. See `RichTextEditor`. */\n onAiCreditsExhausted?: NotesPanelProps['onAiCreditsExhausted'];\n /** Rendered just above the composer — e.g. the templates pattern's\n * `undoNotice`. See `NotesPanel`. */\n composerBefore?: NotesPanelProps['composerBefore'];\n /** Rendered just after the composer — e.g. the templates pattern's\n * `manager`. See `NotesPanel`. */\n composerAfter?: NotesPanelProps['composerAfter'];\n /** The host's read. Absent while `onLoad` is present reads as loading. */\n status?: 'loading' | 'ready' | 'error';\n total?: number | null;\n /** True once `notes` is the full list rather than a preview. */\n complete?: boolean;\n canAddClinicalNote?: boolean;\n /** Whether this reader may write notes. Beats the panel's `editable`. */\n writable?: boolean;\n onLoad?: (scope: 'preview' | 'all') => void;\n onRetry?: () => void;\n}\n\nconst noop = (): void => undefined;\n\nexport function PatientNotesPanel(\n props: Parameters<typeof PatientNotesPanelContent>[0],\n) {\n return <PatientNotesPanelContent key={props.patientId} {...props} />;\n}\n\nfunction PatientNotesPanelContent({\n patientId,\n seam,\n editable = false,\n currentNoteId,\n currentNoteKey,\n}: {\n patientId: string;\n /**\n * Where every write goes. WITHOUT one the panel is a read-only\n * timeline read from the host's read model: there is nowhere to\n * persist to, so no write is offered and none can be lost.\n */\n seam?: PatientNotesSeam;\n /**\n * Whether this reader may write when `seam.writable` is absent: note\n * writes follow the notes, not `practice_appointment_edit`. False (or\n * no `seam`) leaves the composer, the pin, the in-place edit and the\n * delete dialog unmounted.\n */\n editable?: boolean;\n /** Address one note, exactly as `NotesPanel` does. */\n currentNoteId?: string;\n currentNoteKey?: string | number;\n}) {\n const data = useCalendarData();\n const { t, i18n: runtimeI18n } = useTranslation();\n const key = (suffix: string): string => `calendarWorkspace.details.${suffix}`;\n /* The host's list, or — with no seam wired — the read model, shown\n without any affordance that would pretend to change it. */\n /* A clinical note stays as written unless the host says otherwise:\n NotesPanel offers its pencil on every note it is not told to spare. */\n const notes = (seam?.notes ?? data.patientNotes(patientId)).map((note) =>\n note.clinical && note.actions?.edit === undefined\n ? { ...note, actions: { ...note.actions, edit: false } }\n : note,\n );\n const writable =\n seam !== undefined && (seam.writable ?? (seam.onLoad ? false : editable));\n const [deleting, setDeleting] = useState<NotesPanelNote | null>(null);\n const [writeError, setWriteError] = useState<string | null>(null);\n const [pending, setPending] = useState(false);\n const writeOwner = useRef(0);\n const abandonWrite = (): void => {\n writeOwner.current += 1;\n setPending(false);\n setWriteError(null);\n };\n const panelRootRef = useRef<HTMLDivElement>(null);\n const deletedRef = useRef(false);\n /* One read per patient unless the list is complete; the seam is rebuilt\n every render, so the effect reads a ref. */\n const seamRef = useRef(seam);\n seamRef.current = seam;\n const requestedPatient = useRef<string | null>(null);\n const hasLoader = Boolean(seam?.onLoad);\n useEffect(() => {\n const current = seamRef.current;\n if (\n current?.onLoad &&\n current.complete !== true &&\n current?.status !== 'loading' &&\n current?.status !== 'error' &&\n requestedPatient.current !== patientId\n ) {\n requestedPatient.current = patientId;\n current.onLoad('all');\n }\n }, [patientId, seam?.status, seam?.complete, hasLoader]);\n useEffect(\n () => () => {\n writeOwner.current += 1;\n },\n [patientId],\n );\n /* Every row carries the SAME action words, so the accessible name adds\n the note's own date — otherwise a screen reader reads a list of\n identical \"Edit note\" buttons. */\n const noteStamp = (note: NotesPanelNote): string => {\n try {\n return new Intl.DateTimeFormat(\n runtimeI18n.language,\n DETAIL_STAMP_FORMAT,\n ).format(new Date(note.dateIso));\n } catch {\n return note.dateIso;\n }\n };\n /* A sync delete closes at once; a promise closes when it lands and a\n rejection keeps the dialog open with the host's reason. */\n const settle = (result: void | Promise<void>, close: () => void): void => {\n const owner = ++writeOwner.current;\n if (!result || typeof result.then !== 'function') return close();\n setWriteError(null);\n setPending(true);\n Promise.resolve(result)\n .then(\n () => {\n if (writeOwner.current === owner) close();\n },\n (error: unknown) => {\n if (writeOwner.current !== owner) return;\n setWriteError(getErrorMessage(error, t(key('noteSaveFailed'))));\n },\n )\n .finally(() => {\n if (writeOwner.current === owner) setPending(false);\n });\n };\n const confirmDelete = (): void => {\n const noteId = deleting?.id;\n if (!seam || !noteId) return setDeleting(null);\n settle(seam.onDeleteNote(noteId), () => {\n deletedRef.current = true;\n setDeleting(null);\n });\n };\n /* The confirmed row's buttons unmount with it, so Radix's own focus\n restore would land on <body>: take the first remaining note action,\n else the composer above the list. */\n const focusAfterDelete = (): void => {\n const root = panelRootRef.current;\n const next =\n root?.querySelector<HTMLElement>('[data-note-action]') ??\n root?.querySelector<HTMLElement>('textarea');\n next?.focus();\n };\n const writeAlert = writeError ? (\n <Alert variant=\"error\">\n <Alert.Description>{writeError}</Alert.Description>\n </Alert>\n ) : null;\n return (\n <>\n {/* `display: contents` — a focus scope for the note actions without\n adding a box to the panel's own layout. */}\n <div ref={panelRootRef} className=\"ds:contents\">\n <NotesPanel\n notes={notes}\n status={seam?.status ?? (seam?.onLoad ? 'loading' : 'ready')}\n onRetry={seam?.onRetry}\n /* Until a loading host says otherwise, no clinical write. */\n canAddClinicalNote={seam?.canAddClinicalNote ?? !seam?.onLoad}\n currentNoteId={currentNoteId}\n currentNoteKey={currentNoteKey}\n /* Every write is the host's. No composer, no pin and no\n per-note action without one — a note this panel accepted\n and then dropped would be worse than no notes at all. */\n onRequestAiDraft={writable ? seam?.onRequestAiDraft : undefined}\n onDictate={writable ? seam?.onDictate : undefined}\n aiConsent={writable ? seam?.aiConsent : undefined}\n variables={writable ? seam?.variables : undefined}\n validateVariable={writable ? seam?.validateVariable : undefined}\n onVariableValidityChange={\n writable ? seam?.onVariableValidityChange : undefined\n }\n renderHelpMeWrite={writable ? seam?.renderHelpMeWrite : undefined}\n onUploadImage={writable ? seam?.onUploadImage : undefined}\n onAiCreditsExhausted={\n writable ? seam?.onAiCreditsExhausted : undefined\n }\n composerBefore={writable ? seam?.composerBefore : undefined}\n composerAfter={writable ? seam?.composerAfter : undefined}\n onAddNote={writable ? seam?.onAddNote : undefined}\n /* In place, in the composer that wrote the note (never a dialog).\n A note keeps its clinical flag, so only the content goes on. */\n onEditNote={\n writable && seam\n ? (noteId, submission) =>\n seam.onEditNote(noteId, submission.content)\n : undefined\n }\n /* The host reports a refused pin itself. */\n onTogglePin={\n writable && seam\n ? (id) => void Promise.resolve(seam.onTogglePin(id)).catch(noop)\n : undefined\n }\n noteActions={\n writable\n ? (note) => (\n <>\n {(note.actions?.delete ?? !note.deleted) ? (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n data-note-action=\"delete\"\n icon={<Trash2 aria-hidden=\"true\" />}\n aria-label={t(key('noteDeleteNamed'), {\n date: noteStamp(note),\n })}\n tooltip={t(key('noteDelete'))}\n onClick={() => {\n abandonWrite();\n setDeleting(note);\n }}\n />\n ) : null}\n </>\n )\n : undefined\n }\n />\n </div>\n {writable ? (\n <>\n <Dialog\n open={deleting !== null}\n onOpenChange={(open) => {\n if (!open) {\n abandonWrite();\n setDeleting(null);\n }\n }}\n >\n <Dialog.Content\n size=\"sm\"\n variant=\"alert\"\n onCloseAutoFocus={(event) => {\n if (!deletedRef.current) return;\n deletedRef.current = false;\n event.preventDefault();\n focusAfterDelete();\n }}\n >\n <Dialog.Header>\n <Dialog.Title>{t(key('noteDeleteTitle'))}</Dialog.Title>\n <Dialog.Description>\n {t(key('noteDeleteBody'))}\n </Dialog.Description>\n </Dialog.Header>\n {writeAlert ? <Dialog.Body>{writeAlert}</Dialog.Body> : null}\n <Dialog.Footer divider>\n <Button\n intent=\"outline\"\n onClick={() => {\n abandonWrite();\n setDeleting(null);\n }}\n >\n {t(key('noteDeleteCancel'))}\n </Button>\n <Button\n intent=\"destructive\"\n startIcon={<Trash2 aria-hidden=\"true\" />}\n loading={pending}\n onClick={confirmDelete}\n >\n {t(key('noteDeleteConfirm'))}\n </Button>\n </Dialog.Footer>\n </Dialog.Content>\n </Dialog>\n </>\n ) : null}\n </>\n );\n}\n\n/**\n * The latest few notes for the appointment details panel (N-C3, N-C5), in\n * the notes tool's order and read-only. See more or a click on a note\n * hands over to the host's Notes tool on the same seam.\n */\nexport function PatientNotesPreview({\n patientId,\n seam,\n onOpenNotes,\n limit = 3,\n}: {\n patientId: string;\n seam: PatientNotesSeam;\n /** Open the notes tool, addressed to one note when an id is given. */\n onOpenNotes?: (noteId?: string) => void;\n limit?: number;\n}) {\n const { t } = useTranslation();\n const key = (suffix: string): string => `calendarWorkspace.details.${suffix}`;\n const headingId = useId();\n /* Read the latest notes once per patient, only when the host holds none. */\n const seamRef = useRef(seam);\n seamRef.current = seam;\n const hasLoader = Boolean(seam.onLoad);\n useEffect(() => {\n const current = seamRef.current;\n if (\n current.notes.length === 0 &&\n current.status !== 'loading' &&\n current.complete !== true\n ) {\n current.onLoad?.('preview');\n }\n }, [patientId, hasLoader]);\n const status = seam.status ?? (seam.onLoad ? 'loading' : 'ready');\n /* Pinned lead, exactly as `NotesPanel` orders the full list. */\n const shown = [...seam.notes]\n .sort((a, b) => Number(b.pinned ?? false) - Number(a.pinned ?? false))\n .slice(0, limit);\n const count = seam.total ?? (status === 'ready' ? seam.notes.length : null);\n const { onLoad } = seam;\n const retry = onLoad ? () => onLoad('preview') : seam.onRetry;\n return (\n <section\n data-component=\"calendar-patient-notes-preview\"\n aria-labelledby={headingId}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\"\n >\n <div className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-xs)]\">\n <h3\n id={headingId}\n className=\"type-label ds:m-0 ds:uppercase ds:text-[color:var(--muted-foreground)]\"\n >\n {count === null\n ? t('notesPanel.title')\n : t(key('notesPreviewTitle'), { count })}\n </h3>\n </div>\n {status === 'error' ? (\n <Alert variant=\"error\">\n <Alert.Description>{t('notesPanel.loadError')}</Alert.Description>\n {retry ? (\n <Alert.Action>\n <Button intent=\"secondary\" size=\"sm\" onClick={retry}>\n {t('notesPanel.retry')}\n </Button>\n </Alert.Action>\n ) : null}\n </Alert>\n ) : null}\n {shown.length > 0 ? (\n <ul className=\"ds:m-0 ds:flex ds:list-none ds:flex-col ds:gap-[var(--spacing-xs)] ds:p-0\">\n {shown.map(({ actions: _actions, ...note }, index) => (\n <li key={note.id ?? index}>\n {/* The separate button addresses this note from the keyboard. */}\n <ClinicalNoteCard\n surface=\"flat\"\n truncate\n {...note}\n className={\n note.id && onOpenNotes ? 'ds:cursor-pointer' : undefined\n }\n onClick={(event) => {\n const target = event.target as Element;\n if (note.id && !target.closest('button, a'))\n onOpenNotes?.(note.id);\n }}\n />\n {note.id && onOpenNotes ? (\n <Button\n intent=\"ghost\"\n size=\"sm\"\n className=\"ds:[min-block-size:var(--min-target-size)] ds:sm:[min-block-size:var(--min-target-size)]\"\n onClick={() => onOpenNotes(note.id)}\n >\n {t(key('notesPreviewOpenNote'), { number: index + 1 })}\n </Button>\n ) : null}\n </li>\n ))}\n </ul>\n ) : status === 'loading' ? (\n <>\n <span role=\"status\" className=\"ds:sr-only\">\n {t('notesPanel.loading')}\n </span>\n <NoteTimeline notes={[]} loading loadingRows={2} />\n </>\n ) : status === 'ready' ? (\n <p className=\"ds:m-0 type-body-sm ds:text-[color:var(--muted-foreground)]\">\n {t(key('notesPreviewEmpty'))}\n </p>\n ) : null}\n {(count ?? 0) > 0 && onOpenNotes ? (\n <Button\n intent=\"ghost\"\n size=\"sm\"\n className=\"ds:[min-block-size:var(--min-target-size)] ds:sm:[min-block-size:var(--min-target-size)]\"\n onClick={() => onOpenNotes()}\n >\n {t(key('notesPreviewOpen'))}\n </Button>\n ) : null}\n </section>\n );\n}\n\nexport function PatientAppointmentsTimeline({\n patientId,\n locale,\n}: {\n patientId: string;\n locale?: string;\n}) {\n const data = useCalendarData();\n const items = useMemo(\n () => data.patientAppointments(patientId),\n [patientId, data],\n );\n return (\n <AppointmentTimeline items={items} nowIso={data.nowIso} locale={locale} />\n );\n}\n\n/** The appointment's modification ledger as a kit Timeline, newest first,\n * shared by the editor's History sub-view and the read-only details panel.\n * An empty ledger shows the \"No changes recorded\" empty state. */\nexport function AppointmentHistoryTimeline({\n history,\n locale,\n}: {\n history: readonly CalendarHistoryEntry[];\n locale?: string;\n}) {\n const { t, i18n: runtimeI18n } = useTranslation();\n const detailKey = (suffix: string): string =>\n `calendarWorkspace.details.${suffix}`;\n const formatStamp = (iso: string): string => {\n try {\n return new Intl.DateTimeFormat(\n locale ?? runtimeI18n.language,\n DETAIL_STAMP_FORMAT,\n ).format(new Date(iso));\n } catch {\n return iso;\n }\n };\n const workflowOption = (value: CalendarEventStatus): WorkflowStatusOption => {\n const { Icon, tone } = STATUS_CHIP[value];\n return {\n value,\n label: t(STATUS_UI_KEY[value]),\n icon: <Icon aria-hidden=\"true\" />,\n tone,\n };\n };\n /* Ledger line → tone, dot glyph and the from/to detail. */\n const describeHistory = (\n entry: CalendarHistoryEntry,\n ): {\n type: 'info' | 'success' | 'warning' | 'error' | 'neutral';\n icon: ReactNode;\n detail?: ReactNode;\n } => {\n switch (entry.kind) {\n case 'created':\n return {\n type: 'success',\n icon: <CalendarPlus size={16} aria-hidden=\"true\" />,\n };\n case 'moved':\n return {\n type: 'info',\n icon: <Move size={16} aria-hidden=\"true\" />,\n detail: t(detailKey('history.movedDetail'), {\n from: formatStamp(entry.fromIso),\n to: formatStamp(entry.toIso),\n }),\n };\n case 'resized':\n return {\n type: 'info',\n icon: <Clock size={16} aria-hidden=\"true\" />,\n detail: t(detailKey('history.resizedDetail'), {\n from: entry.fromMin,\n to: entry.toMin,\n }),\n };\n case 'status': {\n const StatusGlyph = STATUS_CHIP[entry.to].Icon;\n const fromOption = workflowOption(entry.from);\n const toOption = workflowOption(entry.to);\n const transitionLabel = t(detailKey('history.statusDetail'), {\n from: fromOption.label,\n to: toOption.label,\n });\n return {\n type:\n entry.to === 'cancelled' || entry.to === 'absent'\n ? 'warning'\n : 'neutral',\n icon: <StatusGlyph size={16} aria-hidden=\"true\" />,\n detail: (\n <div role=\"group\" aria-label={transitionLabel}>\n <div\n aria-hidden=\"true\"\n className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\"\n >\n <WorkflowStatusDisplay\n value={entry.from}\n option={fromOption}\n size=\"sm\"\n />\n <ArrowRight\n className=\"ds:size-4 ds:shrink-0 ds:rtl:rotate-180\"\n aria-hidden=\"true\"\n />\n <WorkflowStatusDisplay\n value={entry.to}\n option={toOption}\n size=\"sm\"\n />\n </div>\n </div>\n ),\n };\n }\n case 'edited':\n return {\n type: 'neutral',\n icon: <Pencil size={16} aria-hidden=\"true\" />,\n /* The platform log carries no field list: no \"Changed\" line. */\n detail:\n entry.fields.length > 0\n ? t(detailKey('history.editedDetail'), {\n fields: entry.fields\n .map((f) => t(detailKey(`history.fields.${f}`)))\n .join(', '),\n })\n : undefined,\n };\n case 'confirmedByPatient': {\n const ConfirmedGlyph = STATUS_CHIP.confirmed.Icon;\n return {\n type: 'success',\n icon: <ConfirmedGlyph size={16} aria-hidden=\"true\" />,\n };\n }\n case 'deleted':\n return {\n type: 'error',\n icon: <Trash2 size={16} aria-hidden=\"true\" />,\n };\n }\n };\n if (history.length === 0) {\n return (\n <EmptyState\n variant=\"first-use\"\n size=\"sm\"\n title={t(detailKey('historyEmpty'))}\n />\n );\n }\n return (\n <Timeline order=\"newest-first\" aria-label={t(detailKey('historyTitle'))}>\n {sortHistoryNewestFirst(history).map((entry) => {\n const shape = describeHistory(entry);\n return (\n <Timeline.Event\n key={entry.id}\n eventId={entry.id}\n type={shape.type}\n className=\"ds:[column-gap:var(--spacing-sm)] ds:[padding-block-end:var(--spacing-lg)] ds:before:bg-[var(--primary)]\"\n >\n <Timeline.Dot icon={shape.icon} />\n <Timeline.Content\n title={t(detailKey(`history.${entry.kind}`))}\n description={shape.detail}\n className=\"ds:[padding-block-end:0] ds:[&>[data-component=card]]:border-[color:var(--card-border)] ds:[&>[data-component=card]]:shadow-[var(--shadow-card)]\"\n /* No author (a patient confirming by link): no blank avatar. */\n actor={entry.actor.trim() ? { name: entry.actor } : undefined}\n >\n <span className=\"ds:mt-[var(--spacing-sm)] ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n <CalendarClock\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:shrink-0 ds:text-[color:var(--muted-foreground)]\"\n />\n <Timeline.Timestamp\n date={entry.atIso}\n relative={false}\n locale={locale ?? runtimeI18n.language}\n />\n </span>\n </Timeline.Content>\n </Timeline.Event>\n );\n })}\n </Timeline>\n );\n}\n\nexport function PatientTasksPanel({ patientId }: { patientId: string }) {\n const data = useCalendarData();\n const [tasks, setTasks] = useState<TasksPanelItem[]>(() =>\n data.patientTasks(patientId),\n );\n return (\n <TasksPanel\n items={tasks}\n nowIso={data.nowIso}\n onToggleDone={(item) =>\n setTasks((prev) =>\n prev.map((task) =>\n task.id === item.id\n ? { ...task, status: task.status === 'done' ? 'open' : 'done' }\n : task,\n ),\n )\n }\n onDismissTask={(item) =>\n setTasks((prev) => prev.filter((task) => task.id !== item.id))\n }\n />\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Appointment editor — the platform AppointmentForm redesigned as a */\n/* rail tool: no modal, no create-mode strip. Core platform fields: */\n/* patient, type (in practice / telehealth), date + start + duration, */\n/* operator + chair, colour (GOOGLE_CALENDAR_PALETTE — the platform's */\n/* default DoctorColor set), */\n/* care/description, care-plan / price-list linking, email/SMS */\n/* reminders, recurrence. Platform-only depth (medical-device */\n/* conflicts, per-patient reminder gating, recurrence edit rules, */\n/* save-and-… variants) deliberately stays behind — see the demo mdx. */\n/* ------------------------------------------------------------------ */\n\nexport function DurationCombobox({\n value,\n onChange,\n}: {\n value: number | null;\n onChange: (next: number | null) => void;\n}) {\n const { t } = useTranslation();\n const unit = t('calendarWorkspace.editor.durationUnit');\n const options = useMemo(() => {\n const minutes = DURATION_PRESETS_MIN.includes(value ?? -1)\n ? DURATION_PRESETS_MIN\n : [...DURATION_PRESETS_MIN, ...(value != null ? [value] : [])].sort(\n (a, b) => a - b,\n );\n return minutes.map((m) => ({ value: String(m), label: `${m} ${unit}` }));\n }, [value, unit]);\n const selectedLabel = value != null ? `${value} ${unit}` : '';\n return (\n <Combobox\n options={options}\n value={value != null ? String(value) : ''}\n onValueChange={(next) => onChange(next ? Number(next) : null)}\n /* An untouched query (still the selected value's own label) must\n NOT filter — opening the list shows every preset so the value\n can be swapped in one click; filtering starts only once the\n user actually types something else. */\n filter={(candidate, search) =>\n search === selectedLabel ? 1 : durationDigitsFilter(candidate, search)\n }\n allowCreate\n onCreate={(raw) => {\n const parsed = Number.parseInt(raw.replace(/\\D/g, ''), 10);\n if (Number.isNaN(parsed)) return;\n onChange(Math.min(480, Math.max(5, parsed)));\n }}\n />\n );\n}\n\n/** Channels the editor's send-reminder group may offer. */\nexport type ReminderChannel = 'whatsapp' | 'sms' | 'email';\n\n/** The Final State's full set — the default when a host says nothing. */\nexport const REMINDER_CHANNELS: readonly ReminderChannel[] = [\n 'whatsapp',\n 'sms',\n 'email',\n];\n\n/* DENSITY TIERS. The PANEL's own inline size drives the column count (a\n container query, never the viewport), so the sheet fits without\n scrolling as the rail widens. No interactive target ever shrinks. */\n\n/** Names the container the tiers below query — a plain block wrapper, so\n * the declaration never lands on a flex parent. */\nconst EDITOR_TIER_CONTAINER = 'ds:@container/apptform';\n\n/** The form: one column under 30rem, pairs from 30rem, three from 44rem. */\nconst EDITOR_FORM_GRID =\n 'ds:m-0 ds:grid ds:min-w-0 ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:border-0 ds:p-[var(--spacing-md)] ds:@[480px]/apptform:grid-cols-2 ds:@[704px]/apptform:grid-cols-3';\n\n/** A child that needs the whole row at every tier. */\nconst EDITOR_FIELD_WIDE = 'ds:col-span-full ds:min-w-0';\n\n/** A short field that shares a row from tier 2 and keeps its label above\n * the control — for the two controls with an intrinsically wide layout\n * (the time segments, the swatch grid) that need the whole cell. */\nconst EDITOR_FIELD_SHORT_STACKED = 'ds:min-w-0 ds:[&>div]:min-w-0';\n\n/** A short field: one cell from tier 2, and from tier 3 the label moves\n * beside the control — FormField's own horizontal template, applied at a\n * breakpoint because `orientation` is a prop and cannot answer a query. */\nconst EDITOR_FIELD_SHORT = `${EDITOR_FIELD_SHORT_STACKED} ds:@[704px]/apptform:grid ds:@[704px]/apptform:grid-cols-[minmax(0,max-content)_minmax(0,1fr)] ds:@[704px]/apptform:items-center ds:@[704px]/apptform:gap-x-[var(--spacing-sm)]`;\n\n/** The platform facts the Increment 1 editor adds — every field optional,\n * so a host that passes nothing gets the Final State form unchanged. */\nexport interface EditorPlatformOptions {\n /** Practice branches (platform \"Branca\"); the select shows for > 1. */\n branches?: readonly { id: string; name: string }[];\n /** Care id → device names; drives the read-only devices line. */\n devicesByCare?: Readonly<Record<string, readonly string[]>>;\n /** Required documents still unsigned for a patient (sign-mode radios). */\n unsignedRequiredDocs?: (patientId: string) => number;\n /** The agenda, for the busy chair / busy operator warnings. */\n rows?: readonly CalendarRow[];\n /** Enter in a text field submits (the platform's modal never did). */\n submitOnEnter?: boolean;\n /** The edited appointment belongs to a series — offer the save scope. */\n recurringScope?: boolean;\n /** Price-list recurrence parent — ask about the care-plan lines on delete. */\n carePlanCleanup?: boolean;\n /** Operator options for the select — defaults to the shared active\n * cast. A host whose appointment is held by an operator the practice\n * has since DISABLED passes the wider list, so the name still shows\n * (a new appointment keeps the active cast, as on the platform). */\n operatorOptions?: readonly { id: string; title: string }[];\n /** Reminder channels in the action footer — defaults to all three.\n * The platform has NO \"send reminder now\" action on the calendar; its\n * only outbound bridge is the popover's WhatsApp Snippets island, so\n * Increment 1 narrows this to `['whatsapp']` (audit A2). */\n reminderChannels?: readonly ReminderChannel[];\n /** Offer the Final State's extra recurrence rules — the \"Ends: after N\n * / on a date\" choice and the skip-closed-days switch. The platform's\n * modal only ever sets a repetition count, so Increment 1 turns this\n * off and keeps frequency + count alone (audit A3). */\n recurrenceExtras?: boolean;\n /** Warn — never block — when the chosen operator is away that day, as\n * a third sibling of the busy warnings. Off: an absence keeps the\n * date-side closure banner and holds the save (audit C9). */\n operatorAbsenceWarning?: boolean;\n /** Show the reminder checkboxes only once a patient is chosen, and\n * disable each channel the patient cannot take, with the platform's\n * \"(disabled)\" suffix on the label (audit C10). */\n reminderCapability?: boolean;\n /** Show \"First visit\" only once a patient is chosen (audit C11). */\n firstVisitRequiresPatient?: boolean;\n /** Give each price-list row its catalogue phases, and lock a row the\n * practice has already invoiced (audit C12). */\n priceListPhases?: boolean;\n /** Refuse a description longer than this and say so (platform: 255\n * characters, silently blocking; audit C14). */\n descriptionMaxLength?: number;\n /** Where \"save and go back\" goes — the deep link's origin. Only ever\n * reached from a prefill with `simpleSave: false` (audit C13). */\n onSaveAndReturn?: () => void;\n}\n\nexport function AppointmentEditorPanel({\n prefill,\n onSave,\n onDelete,\n onDuplicate,\n panelTitle,\n headerIcon,\n identity,\n after,\n closeOnSave = true,\n returnsOnCancel = false,\n onDraftChange,\n onPatientContextChange,\n slotPatch,\n colorAssociation,\n locale,\n scheduleByEntry = EMPTY_SCHEDULE,\n history,\n onMove,\n onCopy,\n onWhatsApp,\n readOnly = false,\n capabilities: hostCapabilities,\n series,\n platform,\n className,\n}: {\n prefill?: EditorPrefill;\n capabilities?: CalendarEditorCapabilities;\n /** A host-read occurrence: its scope is asked before the form. */\n series?: CalendarEditorSeries;\n /** The editor closes only after acceptance. A rejection leaves the\n * draft intact and displays its safe, user-facing Error message. */\n onSave: (\n draft: EditorDraft,\n extras?: EditorDraftExtras,\n ) => void | Promise<void>;\n /** Live composition feed — the grid mirrors the slot being filled as a\n * draft placeholder while this panel is open. Emits `null` on unmount\n * so the placeholder clears with the panel. */\n onDraftChange?: (draft: DraftSlot | null) => void;\n /** Reports the current patient to an optional workspace Notes rail tool. */\n onPatientContextChange?: (patientId?: string) => void;\n /** Slot edits made on the grid (dragging or resizing the draft mirror).\n * Applied by `tick` and only to the slot fields, so everything else\n * the user has typed survives. */\n slotPatch?: SlotPatch | null;\n /** Edit mode only — removes the event; confirmed via an alert dialog\n * that also asks the recurring scope and the care-plan cleanup. */\n onDelete?: (eventId: string, options?: DeleteOptions) => void;\n /** Edit mode only — re-seeds the CREATE editor from the current form\n * state (everything but the identity). Unset hides the Duplicate icon\n * altogether, leaving Copy… placement as the one copy path. */\n onDuplicate?: (prefill: EditorPrefill) => void;\n /** Panel-chrome heading override — \"Appointment details\" reuses this\n * SAME form so read and edit are one surface, not two paradigms. */\n panelTitle?: string;\n headerIcon?: ReactNode;\n /** Identity block (avatar · name · status chip) above the form. */\n identity?: ReactNode;\n /** Read-only extras (billing, patient contact) below the form. */\n after?: ReactNode;\n closeOnSave?: boolean;\n /** Cancel returns somewhere (the details panel), so an unchanged edit\n * may cancel too. */\n returnsOnCancel?: boolean;\n /** The cog's colour association: the default colour on create and the\n * re-colour when the chair/operator select changes. */\n colorAssociation: ColorAssociation;\n /** BCP 47 locale for the checklist's scheduled-date chips and prices. */\n locale?: string;\n /** Plan line id → its booked appointments (`scheduleByEntryId`). */\n scheduleByEntry?: Record<\n string,\n Array<{ eventId: string; startIso: string }>\n >;\n /** Details only — the ledger behind the History sub-view (newest first). */\n history?: CalendarHistoryEntry[];\n /** Edit only — arm the grid's move mode (the platform's \"Sposta\"). */\n onMove?: () => void;\n /** Edit only — arm the grid's copy mode; a linked appointment offers\n * the platform's two copies (appointment only / with treatments). */\n onCopy?: (withTreatments: boolean) => void;\n /** Bridge the WhatsApp reminder to the legacy Snippets island. */\n onWhatsApp?: () => void;\n /** No edit permission: every write action goes, the form locks and a\n * note says why. */\n readOnly?: boolean;\n /** Platform parity extras — see `EditorPlatformOptions`. */\n platform?: EditorPlatformOptions;\n /** Root class — a dialog host bounds the panel's height through it. */\n className?: string;\n}) {\n const { t } = useTranslation();\n const data = useCalendarData();\n const { t: tUi, i18n: runtimeI18n } = useTranslation();\n const key = (suffix: string): string => `calendarWorkspace.editor.${suffix}`;\n const detailKey = (suffix: string): string =>\n `calendarWorkspace.details.${suffix}`;\n const bookingKey = (suffix: string): string =>\n `calendarWorkspace.bookingTriage.${suffix}`;\n const { close: closeSheet, open: openSheet } = useSheetHost();\n\n const isEdit = Boolean(prefill?.editEventId);\n /* S-C5 R2: ask the scope first (not a read-only viewer, who cannot\n save); that scope's capabilities merge over the snapshot's. */\n const seriesScopes = isEdit && !readOnly ? series?.scopes : undefined;\n const [seriesScope, setSeriesScope] = useState<RecurringScope>();\n const [changingScope, setChangingScope] = useState(false);\n const choosingScope =\n Boolean(seriesScopes) && (!seriesScope || changingScope);\n const capabilities: CalendarEditorCapabilities | undefined = seriesScope\n ? { ...hostCapabilities, ...series?.capabilitiesByScope?.[seriesScope] }\n : hostCapabilities;\n const canEditCare = capabilities?.editCare !== false;\n const operatorOptions = platform?.operatorOptions ?? activeOperators(data);\n const [saving, setSaving] = useState(false);\n const [accepted, setAccepted] = useState(false);\n const [saveError, setSaveError] = useState<string>();\n const savingRef = useRef(false);\n const acceptedRef = useRef(false);\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n const [patientId, setPatientId] = useState(prefill?.patientId ?? '');\n useEffect(() => {\n onPatientContextChange?.(patientId || undefined);\n }, [patientId, onPatientContextChange]);\n const [type, setType] = useState<'in_practice' | 'telehealth'>(\n prefill?.isTelehealth ? 'telehealth' : 'in_practice',\n );\n const [date, setDate] = useState<Date | undefined>(\n () => prefill?.date ?? new Date(`${data.initialDateIso}T00:00:00`),\n );\n const [time, setTime] = useState<{ hours: number; minutes: number }>(\n prefill?.time ?? { hours: 9, minutes: 0 },\n );\n const [durationMin, setDurationMin] = useState<number | null>(\n prefill?.durationMin ?? 30,\n );\n const [operatorId, setOperatorId] = useState(prefill?.operatorId ?? NONE);\n const [chairId, setChairId] = useState(prefill?.chairId ?? NONE);\n const [colorHex, setColorHex] = useState(() =>\n isEdit\n ? (prefill?.colorHex ?? '')\n : initialEditorColor(prefill, colorAssociation, data),\n );\n const [care, setCare] = useState(prefill?.care ?? '');\n const [emailReminder, setEmailReminder] = useState(true);\n const [smsReminder, setSmsReminder] = useState(false);\n /* Modal-parity fields — visual in the demo (no persistence target),\n but present so the rail form MATCHES the modal users know. */\n const [firstVisit, setFirstVisit] = useState('no');\n /* Link care — the platform's care-plan / price-list relation, live. */\n const linkPrefill = prefill?.careLink;\n const [careLink, setCareLink] = useState<string>(linkPrefill?.kind ?? NONE);\n const [carePlanId, setCarePlanId] = useState(\n linkPrefill?.kind === 'plan' ? linkPrefill.planId : '',\n );\n const [entryIds, setEntryIds] = useState<string[]>(() =>\n linkPrefill?.kind === 'plan' ? [...linkPrefill.entryIds] : [],\n );\n const [phaseSelection, setPhaseSelection] = useState<\n Record<string, string[]>\n >(() =>\n linkPrefill?.kind === 'plan' ? { ...linkPrefill.phasesByEntry } : {},\n );\n /* No catalogue means no id to seed with. `''` is the honest seed —\n an invented id would name a price list the practice has not got —\n and the relation that would read it is withheld below. */\n const [priceListId, setPriceListId] = useState<string>(() =>\n linkPrefill?.kind === 'priceList'\n ? linkPrefill.priceListId\n : (priceListIdFor(prefill?.patientId, data) ?? ''),\n );\n const priceRowKeyRef = useRef(0);\n const [priceRows, setPriceRows] = useState<PriceRow[]>(() =>\n linkPrefill?.kind === 'priceList' && linkPrefill.items.length > 0\n ? linkPrefill.items.map((item) => ({\n key: (priceRowKeyRef.current += 1),\n careId: item.careId,\n priceCents: item.priceCents,\n phases: item.phases ? [...item.phases] : undefined,\n billed: item.billed,\n }))\n : [{ key: (priceRowKeyRef.current += 1), careId: '', priceCents: null }],\n );\n const activeLocale = locale ?? runtimeI18n.language ?? 'en';\n /* Plans the patient may link to. CREATE auto-selects the first open\n plan (platform enableCarePlanOption + auto-select) unless the price\n list was chosen; EDIT locks the relation. */\n const openPlans = useMemo(\n () => (patientId ? data.openCarePlansForPatient(patientId) : []),\n [patientId, data],\n );\n const lastPatientRef = useRef(patientId);\n useEffect(() => {\n if (isEdit) return;\n if (openPlans.length > 0) {\n setCareLink((prev) => (prev === 'priceList' ? prev : 'plan'));\n setCarePlanId((prev) =>\n openPlans.some((p) => p.id === prev) ? prev : openPlans[0].id,\n );\n } else {\n setCareLink((prev) => (prev === 'plan' ? NONE : prev));\n setCarePlanId('');\n }\n if (lastPatientRef.current !== patientId) {\n lastPatientRef.current = patientId;\n const nextId = priceListIdFor(patientId || undefined, data) ?? '';\n setPriceListId(nextId);\n /* The mirror of the 'plan' reset above, and the half that was\n missing: on a host with no catalogue this blanks the id while\n `careLink` stayed 'priceList', so the form held a relation with\n nothing to name — uncorrectable, because the Select that would\n name it is withheld. Dropping the relation HERE is visible (the\n radio moves to None and the treatments table goes with it)\n rather than at save time, where it would be silent. */\n if (nextId === '')\n setCareLink((prev) => (prev === 'priceList' ? NONE : prev));\n }\n }, [isEdit, openPlans, patientId, data]);\n const plan = carePlanId ? data.carePlanById(carePlanId) : undefined;\n /* WITHHOLD (1.17.0's rule) rather than render over nothing. With no\n price-list catalogue the \"From price list\" relation has no options\n to list and no id to default to, so the radio and the list select\n are not rendered at all. `unknown` (the host never handed one over,\n as the platform island does not) and `none` (handed over, empty)\n both withhold — neither licenses a claim about what the practice\n holds, and neither may be papered over with a fabricated list.\n The radio survives for an appointment that ALREADY carries the\n relation: withholding it there would read as \"not linked\", which is\n a claim about a link we can see. */\n const priceLists = data.priceLists ?? [];\n const priceListCatalogue = priceListState(data);\n /* The vocabulary's own predicate, never a re-spelled `=== 'ready'`:\n a duplicated literal here is what would let `catalogueUsable` change\n meaning while the UI quietly kept the old one. */\n const priceListOffered = catalogueUsable(priceListCatalogue);\n const priceListRelationShown = priceListOffered || careLink === 'priceList';\n /* A relation group needs at least one relation it can back. EDIT keeps\n it regardless — it is locked, and must still name what the\n appointment has. */\n const linkCareShown =\n isEdit || priceListRelationShown || openPlans.length > 0;\n /* The linked plan stays listed in EDIT even once its lines are done. */\n const planChoices =\n plan && !openPlans.some((p) => p.id === plan.id)\n ? [plan, ...openPlans]\n : openPlans;\n /* Undone lines, plus any already ticked (platform lists undone only). */\n const planEntries = plan\n ? plan.entries.filter((e) => !e.done || entryIds.includes(e.id))\n : [];\n const entryState = (\n entry: CalendarCarePlanEntry,\n ): boolean | 'indeterminate' => {\n if (!entryIds.includes(entry.id)) return false;\n if (entry.phases && entry.phases.length > 0) {\n const picked = phaseSelection[entry.id] ?? [];\n return picked.length < entry.phases.length ? 'indeterminate' : true;\n }\n return true;\n };\n /* Ticking a line ticks all its phases; the last phase off drops the\n line (platform CarePlanEntryCheckBoxes). */\n const toggleEntry = (\n entry: CalendarCarePlanEntry,\n checked: boolean | 'indeterminate',\n ): void => {\n const on = checked !== false;\n setEntryIds((prev) =>\n on\n ? prev.includes(entry.id)\n ? prev\n : [...prev, entry.id]\n : prev.filter((id) => id !== entry.id),\n );\n setPhaseSelection((prev) => {\n const next = { ...prev };\n if (on && entry.phases && entry.phases.length > 0) {\n next[entry.id] = [...entry.phases];\n } else {\n delete next[entry.id];\n }\n return next;\n });\n };\n const togglePhase = (\n entry: CalendarCarePlanEntry,\n phase: string,\n checked: boolean | 'indeterminate',\n ): void => {\n const current = phaseSelection[entry.id] ?? [];\n const picked =\n checked === true\n ? current.includes(phase)\n ? current\n : [...current, phase]\n : current.filter((p) => p !== phase);\n const ordered = (entry.phases ?? []).filter((p) => picked.includes(p));\n setPhaseSelection((prev) => {\n const next = { ...prev };\n if (ordered.length > 0) next[entry.id] = ordered;\n else delete next[entry.id];\n return next;\n });\n setEntryIds((prev) =>\n ordered.length > 0\n ? prev.includes(entry.id)\n ? prev\n : [...prev, entry.id]\n : prev.filter((id) => id !== entry.id),\n );\n };\n const patchPriceRow = (key: number, patch: Partial<PriceRow>): void =>\n setPriceRows((prev) =>\n prev.map((r) => (r.key === key ? { ...r, ...patch } : r)),\n );\n const addPriceRow = (): void =>\n setPriceRows((prev) => [\n ...prev,\n { key: (priceRowKeyRef.current += 1), careId: '', priceCents: null },\n ]);\n const removePriceRow = (key: number): void =>\n setPriceRows((prev) =>\n prev.length > 1 ? prev.filter((r) => r.key !== key) : prev,\n );\n /* Picking a care seeds every catalogue phase, mirroring the platform's\n select-all default; a phase toggle keeps catalogue order. */\n const togglePriceRowPhase = (\n row: PriceRow,\n phase: string,\n checked: boolean,\n ): void => {\n const catalogue = data.careById(row.careId)?.phases ?? [];\n const current = row.phases ?? [];\n const picked = checked\n ? [...current, phase]\n : current.filter((p) => p !== phase);\n patchPriceRow(row.key, {\n phases: catalogue.filter((p) => picked.includes(p)),\n });\n };\n const togglePriceRowAllPhases = (row: PriceRow, checked: boolean): void =>\n patchPriceRow(row.key, {\n phases: checked ? [...(data.careById(row.careId)?.phases ?? [])] : [],\n });\n /* What Save stores: plan lines in PLAN order with their phases, or the\n price-list picks (blank rows dropped); nothing when unlinked. */\n const currentLink = useMemo<CalendarCareLink | undefined>(() => {\n if (!canEditCare) return prefill?.careLink;\n if (careLink === 'plan' && plan) {\n const ordered = plan.entries\n .filter((e) => entryIds.includes(e.id))\n .map((e) => e.id);\n if (ordered.length === 0) return undefined;\n const phasesByEntry = Object.fromEntries(\n ordered\n .filter((id) => (phaseSelection[id]?.length ?? 0) > 0)\n .map((id) => [id, phaseSelection[id]]),\n );\n return {\n kind: 'plan',\n planId: plan.id,\n entryIds: ordered,\n phasesByEntry:\n Object.keys(phasesByEntry).length > 0 ? phasesByEntry : undefined,\n };\n }\n if (careLink === 'priceList') {\n const items = priceRows\n .filter((r) => r.careId)\n .map((r) => ({\n careId: r.careId,\n priceCents: r.priceCents ?? data.careById(r.careId)?.priceCents ?? 0,\n ...(r.phases && r.phases.length > 0 ? { phases: r.phases } : {}),\n ...(r.billed ? { billed: true } : {}),\n }));\n /* Backstop to the reset above: `priceListId` must NAME a list, and\n '' names none. A relation pointing at a list that does not exist\n is worse than no relation — nothing downstream can resolve it,\n and the Select that would correct it is withheld. */\n if (items.length > 0 && priceListId)\n return { kind: 'priceList', priceListId, items };\n }\n return undefined;\n }, [\n careLink,\n plan,\n entryIds,\n phaseSelection,\n priceListId,\n priceRows,\n data,\n canEditCare,\n prefill?.careLink,\n ]);\n /* Link → form: duration = the lines' sum; colour = the first line's\n care, only under colour-by-care (the allocation selects own it\n otherwise). Skipped on mount so a saved appointment keeps its values. */\n const linkKey = JSON.stringify(currentLink ?? null);\n const appliedLinkRef = useRef<string | null>(null);\n useEffect(() => {\n if (!canEditCare) return;\n if (appliedLinkRef.current === null || appliedLinkRef.current === linkKey) {\n appliedLinkRef.current = linkKey;\n return;\n }\n appliedLinkRef.current = linkKey;\n const defaults = deriveCareLinkDefaults(currentLink, data);\n if (defaults.durationMin !== undefined)\n setDurationMin(defaults.durationMin);\n if (defaults.colorHex && colorAssociation === 'care') {\n setColorHex(defaults.colorHex);\n }\n }, [linkKey, currentLink, colorAssociation, data, canEditCare]);\n const linkedCares = !canEditCare\n ? prefill?.cares\n : currentLink\n ? data.careEntriesFromLink(currentLink)\n : prefill?.cares;\n const [allDay, setAllDay] = useState(prefill?.allDay ?? false);\n\n /* Grid → form: apply a drag/resize of the mirror. Keyed on `tick` so\n the same patch never re-applies and the round trip settles (the emit\n effect below then re-mirrors the patched values). */\n const appliedPatchRef = useRef(0);\n useEffect(() => {\n if (!slotPatch || slotPatch.tick === appliedPatchRef.current) return;\n appliedPatchRef.current = slotPatch.tick;\n if (slotPatch.date) setDate(slotPatch.date);\n if (slotPatch.time) setTime(slotPatch.time);\n if (slotPatch.durationMin) setDurationMin(slotPatch.durationMin);\n if (slotPatch.chairId) setChairId(slotPatch.chairId);\n if (slotPatch.operatorId) setOperatorId(slotPatch.operatorId);\n /* The mirror dragged onto another column re-colours like the select. */\n const resourceColor =\n colorAssociation === 'chair' && slotPatch.chairId\n ? associationColor('chair', { chairId: slotPatch.chairId }, data)\n : colorAssociation === 'operator' && slotPatch.operatorId\n ? associationColor(\n 'operator',\n { operatorId: slotPatch.operatorId },\n data,\n )\n : undefined;\n if (resourceColor) setColorHex(resourceColor);\n }, [slotPatch, colorAssociation, data]);\n\n /* Form → grid. Only the fields that DRAW the block matter — retyping\n the description must not re-render the calendar. */\n useEffect(() => {\n if (!onDraftChange) return;\n onDraftChange(\n date\n ? {\n editEventId: prefill?.editEventId,\n date,\n time,\n durationMin: durationMin ?? 30,\n allDay,\n chairId: chairId === NONE ? undefined : chairId,\n operatorId: operatorId === NONE ? undefined : operatorId,\n }\n : null,\n );\n }, [\n onDraftChange,\n prefill?.editEventId,\n date,\n time,\n durationMin,\n allDay,\n chairId,\n operatorId,\n ]);\n useEffect(() => () => onDraftChange?.(null), [onDraftChange]);\n const [repeats, setRepeats] = useState(false);\n const [recurrence, setRecurrence] = useState<RecurrenceFrequency>('weekly');\n /* Platform stops at a repetition COUNT; the demo also offers the\n UNTIL date its entity already models (the two are exclusive). */\n const [recurrenceEnds, setRecurrenceEnds] = useState<'count' | 'until'>(\n 'count',\n );\n const [recurrenceCount, setRecurrenceCount] = useState<number | null>(4);\n const [recurrenceUntil, setRecurrenceUntil] = useState<Date | undefined>();\n const [skipClosedDays, setSkipClosedDays] = useState(true);\n /* The hint is a sibling of the checkbox, so wire it explicitly —\n a screen reader gets the \"why\", not just the label. */\n const skipHintId = useId();\n /* Audit A3 — the platform's modal sets a repetition COUNT and nothing\n else, so Increment 1 opts out of the end-date choice and the\n closed-day skip. Every other host keeps them. */\n const recurrenceExtras = platform?.recurrenceExtras !== false;\n const [addToWaitingList, setAddToWaitingList] = useState(false);\n const [status, setStatus] = useState<CalendarEventStatus | undefined>(\n prefill?.status ?? (isEdit ? undefined : 'confirmed'),\n );\n\n /* Dirty tracking — Save/Cancel stay INACTIVE until something actually\n changed from the opening snapshot. */\n const serializeDraft = (): string =>\n JSON.stringify({\n patientId,\n type,\n dateMs: date?.getTime() ?? null,\n time,\n durationMin,\n operatorId,\n chairId,\n colorHex,\n care,\n emailReminder,\n smsReminder,\n firstVisit,\n careLink,\n carePlanId,\n entryIds,\n phaseSelection,\n priceListId,\n priceRows,\n allDay,\n repeats,\n recurrence,\n recurrenceEnds,\n recurrenceCount,\n recurrenceUntilMs: recurrenceUntil?.getTime() ?? null,\n skipClosedDays,\n addToWaitingList,\n status,\n });\n const initialDraftRef = useRef<string | null>(null);\n if (initialDraftRef.current === null) {\n initialDraftRef.current = serializeDraft();\n }\n const dirty = serializeDraft() !== initialDraftRef.current;\n /* Create is a COMMIT, not an amendment. A prefilled draft (waiting\n list → find free slots → new appointment) is already exactly what\n the operator wants, so Save stays live with nothing retyped; only\n edit gates on an actual change. */\n /* Not bookable: a typed date on a closed day or holiday, or the chosen\n operator away that day (the chair axis cannot show absences). */\n const rawClosure = date\n ? data.closureOn(\n localIsoDate(date),\n operatorId === NONE ? undefined : operatorId,\n )\n : null;\n /* Audit C9 — the platform WARNS that the operator is away and saves\n anyway, so Increment 1 moves the absence out of the closure banner\n and into the busy-warning trio; the practice's own closures stay. */\n const absenceWarns = platform?.operatorAbsenceWarning === true;\n const operatorAbsent = absenceWarns && rawClosure?.kind === 'absence';\n const closure = operatorAbsent ? null : rawClosure;\n /* Save gates on a slot the user is CHOOSING — create, or an edit that\n moved the date/operator into the closure. An inherited conflict only\n warns, so it can still be resolved here (cancelled, reassigned). */\n const slotChosen =\n !isEdit ||\n date?.getTime() !== prefill?.date?.getTime() ||\n (operatorId === NONE ? undefined : operatorId) !== prefill?.operatorId;\n /* A Backlog hand-off holds Save until its call to action is settled —\n otherwise the item would silently stay queued after a save. */\n const ctaSatisfied = callToActionSatisfied(prefill?.callToAction, {\n patientId: patientId || undefined,\n operatorId: operatorId === NONE ? undefined : operatorId,\n });\n /* Audit C14 — the platform blocks the save on an over-long\n description, silently; here the field says why. */\n const descriptionMax = platform?.descriptionMaxLength;\n const descriptionTooLong =\n descriptionMax !== undefined && care.length > descriptionMax;\n /* Audit C13 — the platform's `simpleSave` flag, carried by the prefill\n a deep link built; anything else keeps the single Save. */\n const twoStepSave = prefill?.simpleSave === false;\n const canSave =\n !saving &&\n !accepted &&\n (isEdit ? dirty : Boolean(date)) &&\n !(closure && slotChosen) &&\n !descriptionTooLong &&\n ctaSatisfied;\n const canCancel = accepted || returnsOnCancel || (isEdit ? dirty : true);\n\n /* The send-reminder channels follow the FORM's patient (works in\n details and in create once a patient is chosen). The REF, not the\n record: everything that asks \"is a patient chosen?\" keys on the id,\n so a host whose `patientById` cannot answer still gets the patient\n half of the form. */\n const formRef = patientRefById(patientId, data);\n /* What to CALL the chosen patient when the options cannot: the record,\n else the appointment's own title, else the honest \"not loaded\". */\n const editedEventTitle = prefill?.editEventId\n ? data.baseEvents.find((b) => b.event.id === prefill.editEventId)?.event\n .title\n : undefined;\n const formPatientLabel = patientRefName(\n formRef,\n editedEventTitle,\n t(detailKey('patientNotLoaded')),\n );\n const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);\n /* Platform parity (Increment 1): the delete dialog's recurring scope and\n care-plan cleanup, the save scope on edit, the required-documents\n sign mode and the branch. */\n const [deleteScope, setDeleteScope] = useState<RecurringScope>('this');\n const [removeFromCarePlan, setRemoveFromCarePlan] = useState(false);\n const [recurringSaveMode, setRecurringSaveMode] =\n useState<RecurringScope>('this');\n const [signMode, setSignMode] = useState<RequiredDocsSignMode>(() =>\n defaultSignMode(formRef),\n );\n const signPatientRef = useRef(patientId);\n useEffect(() => {\n if (signPatientRef.current === patientId) return;\n signPatientRef.current = patientId;\n setSignMode(defaultSignMode(patientRefById(patientId, data)));\n }, [patientId, data]);\n const branches = platform?.branches ?? [];\n const [branchId, setBranchId] = useState(() => branches[0]?.id ?? '');\n /* Keyed by the ID the form holds — the host's unsigned-documents seam\n answers to the id, and a record that did not load is not a reason to\n under-report what the patient still has to sign. */\n const unsignedDocs =\n !isEdit && formRef.assigned && platform?.unsignedRequiredDocs\n ? platform.unsignedRequiredDocs(formRef.id)\n : 0;\n /* FOUR states per channel, not two — see `patientChannelState`. A\n channel we were never told about stays offered; only a record that\n loaded may be quoted as holding nothing. */\n const signChannels = signChannelStates(formRef);\n const smsOffered = channelOfferable(signChannels.sms);\n const emailOffered = channelOfferable(signChannels.email);\n const smsReasonKey = channelReasonKey(signChannels.sms, {\n optedOut: key('signModeSmsDisabled'),\n none: key('signModeSmsDisabled'),\n });\n const emailReasonKey = channelReasonKey(signChannels.email, {\n optedOut: key('signModeEmailDisabled'),\n none: key('signModeEmailDisabled'),\n });\n /* Audit C10 / C11 — the platform hangs the reminders and the\n first-visit question off the patient, and disables a channel the\n patient cannot take. Off, both stay visible and enabled. Whether a\n patient IS chosen is the id's question, never the record's. */\n const gateOnPatient = platform?.reminderCapability === true;\n const showReminders = !gateOnPatient || formRef.assigned;\n const showFirstVisit =\n platform?.firstVisitRequiresPatient !== true || formRef.assigned;\n const requiredDevices = platform?.devicesByCare\n ? devicesForCares(linkedCares, platform.devicesByCare)\n : [];\n const slotStart = date ? new Date(date) : undefined;\n if (slotStart) slotStart.setHours(time.hours, time.minutes, 0, 0);\n const busy =\n platform?.rows && slotStart && !allDay\n ? slotConflicts(platform.rows, {\n start: slotStart,\n end: new Date(slotStart.getTime() + (durationMin ?? 30) * 60000),\n chairId: chairId === NONE ? undefined : chairId,\n operatorId: operatorId === NONE ? undefined : operatorId,\n excludeEventId: prefill?.editEventId,\n })\n : { chairBusy: false, operatorBusy: false };\n const scopeApplies =\n !seriesScopes &&\n isEdit &&\n platform?.recurringScope === true &&\n capabilities?.editRecurrence !== false;\n const cleanupApplies =\n isEdit &&\n (seriesScopes\n ? series?.offersCarePlanCleanup === true\n : platform?.carePlanCleanup === true);\n /* R3: the delete dialog offers the host's scopes, else the demo's. */\n const deleteScopes =\n seriesScopes ?? (scopeApplies ? RECURRING_SCOPES : undefined);\n const deleteChoice = deleteScopes?.includes(deleteScope)\n ? deleteScope\n : (deleteScopes?.[0] ?? 'this');\n /* Answer 23: \"all\" with a moved start drops the edited occurrences. */\n const seriesStartChanged =\n series != null &&\n slotStart != null &&\n Math.floor(slotStart.getTime() / 60000) !==\n Math.floor(series.occurrence.getTime() / 60000);\n const discardsOverrides = seriesScope === 'all' && seriesStartChanged;\n /* Focus follows the swap; opening the panel moves no focus, unless the\n prefill names a field (a booking's assign intent). */\n const patientFieldRef = useRef<HTMLDivElement>(null);\n const operatorFieldRef = useRef<HTMLDivElement>(null);\n useEditorInitialFocus(prefill?.initialFocus, {\n patient: patientFieldRef,\n operator: operatorFieldRef,\n });\n const chooserRef = useRef<HTMLDivElement>(null);\n const scopeChangeRef = useRef<HTMLButtonElement>(null);\n const choosingRef = useRef(choosingScope);\n useEffect(() => {\n if (choosingRef.current === choosingScope) return;\n choosingRef.current = choosingScope;\n if (!choosingScope) scopeChangeRef.current?.focus();\n else\n chooserRef.current\n ?.querySelector<HTMLElement>('[role=\"radio\"][aria-checked=\"true\"]')\n ?.focus();\n }, [choosingScope]);\n const saveExtras: EditorDraftExtras = {\n recurringSaveMode:\n seriesScope ?? (scopeApplies ? recurringSaveMode : undefined),\n requiredDocsSignMode: unsignedDocs > 0 ? signMode : undefined,\n branchId:\n canEditCare && careLink === 'priceList' && branches.length > 1\n ? branchId\n : undefined,\n };\n\n /* Rail SUB-VIEW: History swaps the pinned chrome and the form for the\n kit Timeline; the form stays mounted (hidden) so edits survive the\n round trip. Focus lands on the sub-view's header, then returns. */\n const [subView, setSubView] = useState<'form' | 'history'>('form');\n const historyBtnRef = useRef<HTMLButtonElement>(null);\n const historyHeaderRef = useRef<HTMLElement>(null);\n const prevSubViewRef = useRef(subView);\n useEffect(() => {\n const prev = prevSubViewRef.current;\n if (prev === subView) return;\n prevSubViewRef.current = subView;\n if (subView === 'history') historyHeaderRef.current?.focus();\n else historyBtnRef.current?.focus();\n }, [subView]);\n const panelLocale = locale ?? runtimeI18n.language;\n /* `simpleSave: false` (a deep-link arrival) splits Save in two: go\n back to wherever the link came from, or stay on the form. */\n const handleSave = async (options?: {\n keepOpen?: boolean;\n andReturn?: boolean;\n }): Promise<void> => {\n /* Read-only withholds the Save controls and disables the fieldset,\n but this is the one place the host's writer is called — refuse\n here too, so no future path can reach `onSave` and close the\n panel as if the appointment had been written. */\n if (\n readOnly ||\n savingRef.current ||\n acceptedRef.current ||\n !canSave ||\n !date\n )\n return;\n savingRef.current = true;\n setSaving(true);\n setSaveError(undefined);\n try {\n await onSave(\n {\n editEventId: prefill?.editEventId,\n ...(capabilities?.editPatient === false\n ? {}\n : { patientId: patientId || undefined }),\n isTelehealth: type === 'telehealth',\n date,\n time,\n durationMin: durationMin ?? 30,\n operatorId: operatorId === NONE ? undefined : operatorId,\n chairId: chairId === NONE ? undefined : chairId,\n colorHex,\n ...(capabilities?.editDescription === false\n ? {}\n : { care: care || undefined }),\n allDay: allDay || undefined,\n ...(canEditCare\n ? { cares: prefill?.cares, careLink: currentLink }\n : {}),\n waitingEntryId: prefill?.waitingEntryId,\n addToWaitingList: addToWaitingList || undefined,\n ...(capabilities?.editStatus === false\n ? {}\n : { status: isEdit ? status : undefined }),\n /* Create-only, matching platform: once an appointment exists its\n recurrence inputs are disabled, so an edit never re-rules a\n series from this form. */\n recurrence:\n !isEdit && capabilities?.editRecurrence !== false && repeats\n ? {\n frequency: recurrence,\n ends: recurrenceExtras ? recurrenceEnds : 'count',\n count: recurrenceCount ?? 2,\n untilDate: recurrenceExtras ? recurrenceUntil : undefined,\n skipClosedDays: recurrenceExtras ? skipClosedDays : false,\n }\n : undefined,\n },\n saveExtras,\n );\n /* The host returns no persisted identity or refreshed diff baseline.\n This mounted draft must never submit again, even if navigation\n fails or Save-and-continue keeps the editor open. A new seed or\n canonical reload creates the next editable form. */\n acceptedRef.current = true;\n if (mountedRef.current) setAccepted(true);\n } catch (error) {\n if (mountedRef.current)\n setSaveError(\n error instanceof Error && error.message.trim()\n ? error.message\n : t('patientDetails.edit.saveFailed'),\n );\n return;\n } finally {\n savingRef.current = false;\n if (mountedRef.current) setSaving(false);\n }\n if (!mountedRef.current) return;\n try {\n if (options?.andReturn) platform?.onSaveAndReturn?.();\n } catch {\n toastWarning(t('emptyState.error.title'));\n }\n try {\n if (closeOnSave && !options?.keepOpen) closeSheet();\n } catch {\n toastWarning(t('emptyState.error.title'));\n }\n };\n\n /* Enter in a text field submits (Increment 1) through the form's\n implicit submission: the hidden default button gates on `canSave`,\n and a click on any other button in the form is ignored here. */\n const submitButtonRef = useRef<HTMLButtonElement>(null);\n const handleFormSubmit = (event: FormEvent<HTMLFormElement>): void => {\n event.preventDefault();\n const submitter = (event.nativeEvent as SubmitEvent).submitter;\n if (submitter !== submitButtonRef.current) return;\n /* On a split-Save arrival Enter is the harmless half — it saves\n without navigating away. */\n if (canSave && platform?.submitOnEnter)\n handleSave({ keepOpen: twoStepSave });\n };\n\n /* Confirmed destructive path — the platform popover's delete,\n redesigned: alert dialog → remove → undock the panel. */\n const handleDeleteConfirmed = (): void => {\n if (savingRef.current || acceptedRef.current) return;\n setConfirmDeleteOpen(false);\n if (prefill?.editEventId) {\n onDelete?.(prefill.editEventId, {\n scope: deleteChoice,\n removeFromCarePlan: cleanupApplies ? removeFromCarePlan : undefined,\n });\n }\n closeSheet();\n };\n\n /* The platform popover's \"copy\" — everything the form currently holds\n EXCEPT the event identity re-seeds the CREATE editor. A linked\n appointment offers the platform's two copies: appointment only, or\n appointment and treatments (the same lines ride along). */\n const handleDuplicate = (withTreatments: boolean): void => {\n if (savingRef.current || acceptedRef.current) return;\n if (!onDuplicate) return;\n onDuplicate({\n patientId: patientId || undefined,\n isTelehealth: type === 'telehealth',\n date,\n time,\n durationMin: durationMin ?? 30,\n operatorId: operatorId === NONE ? undefined : operatorId,\n chairId: chairId === NONE ? undefined : chairId,\n colorHex,\n care: care || undefined,\n cares: currentLink && !withTreatments ? undefined : prefill?.cares,\n careLink: withTreatments ? currentLink : undefined,\n });\n openSheet('appointment-editor');\n };\n\n return (\n <div\n className={['ds:flex ds:h-full ds:flex-col', className]\n .filter(Boolean)\n .join(' ')}\n >\n {/* History SUB-VIEW — the platform's modification log as a kit\n Timeline in place of the form (which stays mounted, hidden). */}\n {subView === 'history' ? (\n <>\n <PanelHeader\n ref={historyHeaderRef}\n tabIndex={-1}\n title={t(detailKey('historyTitle'))}\n icon={<HistoryIcon aria-hidden=\"true\" />}\n sticky\n divider\n actions={\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<ArrowLeft aria-hidden=\"true\" />}\n flipIconInRtl\n aria-label={t(detailKey('historyBack'))}\n tooltip={t(detailKey('historyBack'))}\n onClick={() => setSubView('form')}\n />\n }\n />\n {}\n <div\n /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- the history timeline scrolls inside the rail; axe scrollable-region-focusable needs the tab stop */\n tabIndex={0}\n className=\"ds:[min-block-size:0] ds:flex-1 ds:overflow-y-auto ds:p-[var(--spacing-md)]\"\n >\n <AppointmentHistoryTimeline\n history={history ?? []}\n locale={locale}\n />\n </div>\n </>\n ) : null}\n {/* Pinned top chrome: the header and the identity only. The\n actions live in the footer below the form. */}\n <div\n hidden={subView !== 'form'}\n className=\"ds:relative ds:z-10 ds:shrink-0 ds:bg-[var(--background)] ds:shadow-[var(--shadow-sm)]\"\n >\n <PanelHeader\n title={panelTitle ?? t(key(isEdit ? 'editTitle' : 'title'))}\n icon={headerIcon ?? <CalendarPlus aria-hidden=\"true\" />}\n sticky\n divider\n actions={\n history ? (\n <>\n {history ? (\n <IconButton\n ref={historyBtnRef}\n size=\"sm\"\n intent=\"ghost\"\n icon={<HistoryIcon aria-hidden=\"true\" />}\n aria-label={t(detailKey('historyAction'))}\n tooltip={t(detailKey('historyAction'))}\n onClick={() => setSubView('history')}\n />\n ) : null}\n </>\n ) : undefined\n }\n />\n {identity}\n {saving || accepted ? (\n <p role=\"status\" className=\"type-body-sm ds:p-[var(--spacing-sm)]\">\n {accepted && date\n ? t('calendarWorkspace.inc1.save.toast', {\n date: formatDay(locale ?? runtimeI18n.language, date),\n })\n : t('common.loading')}\n </p>\n ) : null}\n {saveError ? (\n <Alert variant=\"error\">\n <Alert.Description>{saveError}</Alert.Description>\n </Alert>\n ) : null}\n </div>\n {/* The body scrolls on its own (the tool registers `fill`) so the\n header/identity above and the action footer below stay PINNED —\n the same persistent-chrome idea as the panel header. */}\n <div\n hidden={subView !== 'form'}\n /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- the form body scrolls inside the rail; axe scrollable-region-focusable needs the tab stop */\n tabIndex={0}\n className=\"ds:[min-block-size:0] ds:flex-1 ds:overflow-y-auto\"\n >\n {/* The density container: the tiers query THIS box's inline size,\n so the panel's own width decides the column count. */}\n {choosingScope && series ? (\n <div ref={chooserRef} className=\"ds:p-[var(--spacing-md)]\">\n <CalendarSeriesScopeChooser\n scopes={series.scopes}\n occurrence={series.occurrence}\n locale={locale ?? runtimeI18n.language}\n defaultScope={seriesScope}\n warnOnWholeSeries={seriesStartChanged}\n onContinue={(scope) => {\n setSeriesScope(scope);\n setChangingScope(false);\n }}\n onCancel={() =>\n seriesScope ? setChangingScope(false) : closeSheet()\n }\n />\n </div>\n ) : null}\n <div className={EDITOR_TIER_CONTAINER} hidden={choosingScope}>\n {/* A real form, so Enter in a text field submits natively; the\n hidden button FIRST in tree order is the default button. */}\n <form className=\"ds:contents\" onSubmit={handleFormSubmit}>\n <button\n ref={submitButtonRef}\n type=\"submit\"\n hidden\n tabIndex={-1}\n disabled={!canSave || !platform?.submitOnEnter}\n />\n {/* A disabled fieldset locks every control at once in read-only\n mode (no edit permission) — links and the extras stay live. */}\n <fieldset\n disabled={readOnly || saving || accepted}\n className={EDITOR_FORM_GRID}\n >\n {readOnly ? (\n <Alert\n variant=\"info\"\n announce=\"off\"\n className={EDITOR_FIELD_WIDE}\n icon={<Lock aria-hidden=\"true\" />}\n >\n <Alert.Title as=\"p\">\n {t(detailKey('readOnlyTitle'))}\n </Alert.Title>\n <Alert.Description>\n {t(detailKey('readOnlyBody'))}\n </Alert.Description>\n </Alert>\n ) : null}\n {seriesScopes && seriesScope ? (\n <Alert variant=\"info\" className={EDITOR_FIELD_WIDE}>\n <Alert.Description>\n {t(key('seriesScopeReadout'), {\n scope: t(key(RECURRING_SCOPE_LABEL_KEY[seriesScope])),\n })}\n {seriesScope !== 'this' && ` ${t(key('seriesClashNote'))}`}\n </Alert.Description>\n <Alert.Action>\n <Button\n ref={scopeChangeRef}\n size=\"sm\"\n intent=\"outline\"\n onClick={() => setChangingScope(true)}\n >\n {t(key('seriesScopeChange'))}\n </Button>\n </Alert.Action>\n </Alert>\n ) : null}\n {discardsOverrides ? (\n <Alert\n variant=\"warning\"\n announce=\"polite\"\n className={EDITOR_FIELD_WIDE}\n >\n <Alert.Description>\n {t(key('seriesAllDiscardsOverrides'))}\n </Alert.Description>\n </Alert>\n ) : null}\n {isEdit ? (\n <FormField\n label={t(detailKey('status'))}\n className={EDITOR_FIELD_SHORT}\n >\n <Select\n options={(\n Object.keys(STATUS_UI_KEY) as CalendarEventStatus[]\n ).map((s) => ({ value: s, label: tUi(STATUS_UI_KEY[s]) }))}\n value={status}\n onValueChange={(v) => setStatus(v as CalendarEventStatus)}\n disabled={capabilities?.editStatus === false}\n />\n </FormField>\n ) : null}\n {/* FIELD ORDER + CONTROL TYPES mirror the platform's\n appointment modal, so users carry their muscle memory into\n the rail: type → patient → first visit → link-care →\n description → date/time/duration/colour → the boolean\n options → recurrence → allocation. */}\n {/* A labelled RadioGroup renders its own fieldset, so the grid\n cell is a wrapper — the legend stays above its radios. */}\n <div className=\"ds:min-w-0\">\n <RadioGroup\n label={t(key('type'))}\n variant=\"horizontal\"\n value={type}\n onValueChange={(v) =>\n setType(v as 'in_practice' | 'telehealth')\n }\n >\n <Radio value=\"in_practice\" label={t(key('typeInPractice'))} />\n <Radio value=\"telehealth\" label={t(key('typeTelehealth'))} />\n </RadioGroup>\n </div>\n {/* Online-booking triage (platform parity): the booking carries\n the typed name / SMS-verified phone / email / note but no\n patient record, so those details lead and the platform's\n \"search for this patient below\" hint shows until one is\n assigned. */}\n {prefill?.bookingContact ? (\n <div\n className={`${EDITOR_FIELD_WIDE} ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)] ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--card-border)] ds:bg-[color:var(--muted)] ds:p-[var(--spacing-sm)]`}\n >\n <span className=\"type-label ds:flex ds:items-center ds:gap-[var(--spacing-2xs)] ds:text-[color:var(--muted-foreground)]\">\n <Globe size={12} aria-hidden=\"true\" />\n {t(bookingKey('bookedOnlineBy'))}\n </span>\n <span className=\"ds:font-[var(--font-weight-semibold)] ds:text-start\">\n {prefill.bookingContact.typedName}\n </span>\n <a\n className=\"type-body-sm\"\n href={`tel:${prefill.bookingContact.phone.replace(/\\s/g, '')}`}\n >\n {prefill.bookingContact.phone}\n </a>\n <a\n className=\"type-body-sm ds:truncate\"\n href={`mailto:${prefill.bookingContact.email}`}\n >\n {prefill.bookingContact.email}\n </a>\n <span className=\"type-body-sm ds:text-start ds:text-[color:var(--muted-foreground)]\">\n {`${t(bookingKey('note'))}: ${prefill.bookingContact.note}`}\n </span>\n <span className=\"type-body-sm ds:text-start ds:text-[color:var(--muted-foreground)]\">\n {`${t(detailKey('bookedAt'))}: `}\n <Timestamp\n value={prefill.bookingContact.bookedAtIso}\n format=\"absolute\"\n shape=\"bare\"\n locale={panelLocale}\n absoluteFormat={DETAIL_STAMP_FORMAT}\n />\n </span>\n {!patientId ? (\n <span className=\"type-body-sm ds:text-start ds:text-[color:var(--info-foreground)]\">\n {t(bookingKey('searchPatientHint'))}\n </span>\n ) : null}\n </div>\n ) : null}\n {prefill?.callToAction && !ctaSatisfied ? (\n <Alert\n variant=\"info\"\n announce=\"polite\"\n className={EDITOR_FIELD_WIDE}\n >\n <Alert.Description>\n {t(\n prefill.callToAction === 'processBooking'\n ? 'calendarWorkspace.backlog.processIncomplete'\n : 'calendarWorkspace.backlog.assignIncomplete',\n )}\n </Alert.Description>\n </Alert>\n ) : null}\n <FormField\n ref={patientFieldRef}\n className={EDITOR_FIELD_WIDE}\n label={t(key('patient'))}\n required={prefill?.callToAction === 'processBooking'}\n description={\n prefill?.callToAction === 'processBooking'\n ? t('calendarWorkspace.backlog.processPatientHint')\n : undefined\n }\n >\n <CalendarPatientPicker\n value={patientId}\n disabled={capabilities?.editPatient === false}\n onValueChange={setPatientId}\n selectedLabel={formPatientLabel}\n />\n </FormField>\n {/* Required documents (create, patient chosen): how the signature\n request goes out — the platform's required-objects sign mode. */}\n {unsignedDocs > 0 ? (\n <div className={EDITOR_FIELD_WIDE}>\n <RadioGroup\n label={t(key('signMode'), { count: unsignedDocs })}\n value={signMode}\n onValueChange={(v) =>\n setSignMode(v as RequiredDocsSignMode)\n }\n >\n {/* The reason rides the LABEL, as the reminder\n checkboxes below do: a disabled radio is out of the\n tab order, so a hover-only tooltip reaches nobody. */}\n <Radio\n value=\"sms\"\n label={\n smsReasonKey === null\n ? t(key('signModeSms'))\n : `${t(key('signModeSms'))} — ${t(smsReasonKey)}`\n }\n disabled={!smsOffered}\n disabledReason={\n smsReasonKey === null ? undefined : t(smsReasonKey)\n }\n />\n <Radio\n value=\"email\"\n label={\n emailReasonKey === null\n ? t(key('signModeEmail'))\n : `${t(key('signModeEmail'))} — ${t(emailReasonKey)}`\n }\n disabled={!emailOffered}\n disabledReason={\n emailReasonKey === null ? undefined : t(emailReasonKey)\n }\n />\n <Radio value=\"none\" label={t(key('signModeNone'))} />\n </RadioGroup>\n </div>\n ) : null}\n {showFirstVisit ? (\n <FormField\n className={EDITOR_FIELD_SHORT}\n label={t(key('firstVisit'))}\n >\n <Select\n options={[\n { value: 'no', label: t(key('firstVisitNo')) },\n { value: 'yes', label: t(key('firstVisitYes')) },\n { value: 'unknown', label: t(key('firstVisitUnknown')) },\n ]}\n value={firstVisit}\n onValueChange={setFirstVisit}\n />\n </FormField>\n ) : null}\n {/* Link care (platform AppointmentForm): the radios appear once a\n patient is picked; From care plan needs an open plan with\n pending lines and is auto-selected on create; an existing\n appointment's relation is locked, its lines still tickable. */}\n {canEditCare && (patientId || isEdit) && linkCareShown ? (\n <div className={EDITOR_FIELD_WIDE}>\n <RadioGroup\n label={t(key('linkCare'))}\n variant=\"horizontal\"\n value={careLink}\n onValueChange={setCareLink}\n disabled={isEdit}\n /* Group-level text (aria-describedby) — a disabled radio is\n not focusable, so a tooltip alone never reaches keyboard\n or screen-reader users. */\n description={\n isEdit\n ? t(key('linkCareLocked'))\n : openPlans.length === 0\n ? t(key('linkPlanDisabled'))\n : undefined\n }\n >\n <Radio value={NONE} label={t(key('linkNone'))} />\n <Radio\n value=\"plan\"\n label={t(key('linkPlan'))}\n disabled={!isEdit && openPlans.length === 0}\n disabledReason={\n !isEdit && openPlans.length === 0\n ? t(key('linkPlanDisabled'))\n : undefined\n }\n />\n {priceListRelationShown ? (\n <Radio\n value=\"priceList\"\n label={t(key('linkPriceList'))}\n />\n ) : null}\n </RadioGroup>\n </div>\n ) : null}\n {canEditCare && (patientId || isEdit) && careLink === 'plan' ? (\n <>\n <FormField\n className={EDITOR_FIELD_WIDE}\n label={t(key('plan'))}\n >\n <Select\n options={planChoices.map((p) => ({\n value: p.id,\n label: `${p.number} · ${p.name}`,\n }))}\n value={carePlanId}\n onValueChange={(v) => {\n setCarePlanId(v);\n setEntryIds([]);\n setPhaseSelection({});\n }}\n placeholder={t(key('planSelect'))}\n disabled={isEdit}\n />\n </FormField>\n {planEntries.length > 0 ? (\n <fieldset\n className={`${EDITOR_FIELD_WIDE} ds:m-0 ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:border-0 ds:p-0`}\n >\n <legend className=\"type-label ds:mb-[var(--spacing-2xs)] ds:p-0\">\n {t(key('planEntries'))}\n </legend>\n {planEntries.map((entry) => {\n const entryCare = data.careById(entry.careId);\n return (\n <div\n key={entry.id}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\"\n >\n {/* Tags stay static — a control inside the label\n would nest interactive content. */}\n <Checkbox\n checked={entryState(entry)}\n onCheckedChange={(c) => toggleEntry(entry, c)}\n label={\n <span className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-2xs)]\">\n <span>{entryCare?.name ?? entry.careId}</span>\n {entryCare ? (\n <span className=\"type-meta ds:tabular-nums ds:text-[color:var(--muted-foreground)]\">\n {entryCare.code}\n </span>\n ) : null}\n {entry.elements?.map((el) => (\n <Tag\n key={el}\n label={el}\n variant=\"info\"\n size=\"sm\"\n />\n ))}\n {scheduleByEntry[entry.id]?.map((s) => (\n <Tag\n key={s.eventId}\n label={t(key('entryScheduled'), {\n date: formatDay(\n activeLocale,\n s.startIso,\n ),\n })}\n variant=\"neutral\"\n fill=\"outline\"\n size=\"sm\"\n leading={\n <CalendarClock aria-hidden=\"true\" />\n }\n />\n ))}\n </span>\n }\n />\n {entry.phases && entry.phases.length > 0 ? (\n /* Named group: a screen reader hears each phase\n under its treatment line, not a bare \"Phase 1\". */\n <div\n role=\"group\"\n aria-label={entryCare?.name ?? entry.careId}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)] ds:ps-[var(--spacing-xl)]\"\n >\n {entry.phases.map((phase) => (\n <Checkbox\n key={phase}\n size=\"sm\"\n label={phase}\n checked={(\n phaseSelection[entry.id] ?? []\n ).includes(phase)}\n onCheckedChange={(c) =>\n togglePhase(entry, phase, c)\n }\n />\n ))}\n </div>\n ) : null}\n </div>\n );\n })}\n </fieldset>\n ) : null}\n </>\n ) : null}\n {canEditCare &&\n (patientId || isEdit) &&\n careLink === 'priceList' ? (\n <>\n {/* Withheld with no catalogue: an empty combobox would\n claim to name this appointment's price list. The care\n rows below stand on their own — they read `data.cares`,\n not the catalogue. */}\n {priceListOffered ? (\n <FormField\n className={EDITOR_FIELD_SHORT}\n label={t(key('priceList'))}\n >\n <Select\n options={priceLists.map((l) => ({\n value: l.id,\n label: l.name,\n }))}\n value={priceListId}\n onValueChange={(v) =>\n setPriceListId(v || (priceLists[0]?.id ?? ''))\n }\n disabled={isEdit}\n />\n </FormField>\n ) : null}\n {/* Branch (platform \"Branca\") — only a multi-branch practice\n sees it. */}\n {branches.length > 1 ? (\n <FormField\n className={EDITOR_FIELD_SHORT}\n label={t(key('branch'))}\n >\n <Select\n options={branches.map((b) => ({\n value: b.id,\n label: b.name,\n }))}\n value={branchId}\n onValueChange={setBranchId}\n disabled={isEdit}\n />\n </FormField>\n ) : null}\n <div\n role=\"list\"\n aria-label={t(key('priceListRows'))}\n className={`${EDITOR_FIELD_WIDE} ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]`}\n >\n {priceRows.map((row) => {\n /* Audit C12 — a row the practice has already invoiced\n is read-only, and every row carries its care's\n catalogue phases. */\n const rowCare = row.careId\n ? data.careById(row.careId)\n : undefined;\n const rowPhases = platform?.priceListPhases\n ? (rowCare?.phases ?? [])\n : [];\n const picked = row.phases ?? [];\n const locked =\n platform?.priceListPhases === true &&\n row.billed === true;\n /* Both refusals get their own name: \"already\n invoiced\" and \"the last row stays\". */\n const removeKey = locked\n ? 'priceListBilled'\n : priceRows.length === 1\n ? 'priceListLastRow'\n : 'priceListRemove';\n const allPhases =\n rowPhases.length > 0 &&\n picked.length === rowPhases.length\n ? true\n : picked.length > 0\n ? 'indeterminate'\n : false;\n return (\n <div\n key={row.key}\n role=\"listitem\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\"\n >\n <div className=\"ds:flex ds:items-end ds:gap-[var(--spacing-xs)]\">\n <FormField\n label={t(key('priceListCare'))}\n className=\"ds:min-w-0 ds:flex-1\"\n >\n <Combobox\n options={data.cares.map((c) => ({\n value: c.id,\n label: `${c.name} (${c.code})`,\n }))}\n value={row.careId}\n disabled={locked}\n onValueChange={(v) =>\n patchPriceRow(row.key, {\n careId: v,\n priceCents: v\n ? (data.careById(v)?.priceCents ?? null)\n : null,\n phases:\n v && platform?.priceListPhases\n ? [...(data.careById(v)?.phases ?? [])]\n : undefined,\n })\n }\n placeholder={t(key('priceListSearch'))}\n clearable\n size=\"sm\"\n />\n </FormField>\n <FormField label={t(key('priceListPrice'))}>\n <NumberInput\n mode=\"currency\"\n currency=\"EUR\"\n locale={activeLocale}\n min={0}\n variant=\"plain\"\n size=\"sm\"\n inline=\"md\"\n disabled={locked}\n value={\n row.priceCents == null\n ? null\n : row.priceCents / 100\n }\n onChange={(v) =>\n patchPriceRow(row.key, {\n priceCents:\n v == null ? null : Math.round(v * 100),\n })\n }\n />\n </FormField>\n {/* The reason rides the accessible NAME, and\n `aria-disabled` keeps the button focusable —\n a natively disabled one drops out of the tab\n order and swallows hover, so its tooltip is\n read by nobody. */}\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n icon={<Trash2 aria-hidden=\"true\" />}\n aria-label={t(key(removeKey))}\n tooltip={t(key(removeKey))}\n aria-disabled={\n removeKey === 'priceListRemove'\n ? undefined\n : true\n }\n onClick={() => {\n if (removeKey === 'priceListRemove') {\n removePriceRow(row.key);\n }\n }}\n />\n </div>\n {rowPhases.length > 0 ? (\n /* Named group: a phase is heard under its own\n treatment, never as a bare \"Impression\". */\n <div\n role=\"group\"\n aria-label={rowCare?.name ?? row.careId}\n className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-md)] ds:ps-[var(--spacing-xs)]\"\n >\n <Checkbox\n size=\"sm\"\n label={t(key('priceListAllPhases'))}\n checked={allPhases}\n disabled={locked}\n onCheckedChange={(c) =>\n togglePriceRowAllPhases(row, c !== false)\n }\n />\n {rowPhases.map((phase) => (\n <Checkbox\n key={phase}\n size=\"sm\"\n label={phase}\n checked={picked.includes(phase)}\n disabled={locked}\n onCheckedChange={(c) =>\n togglePriceRowPhase(row, phase, c === true)\n }\n />\n ))}\n </div>\n ) : null}\n {locked ? (\n <span className=\"type-body-sm ds:text-start ds:text-[color:var(--warning-foreground)]\">\n {t(key('priceListBilled'))}\n </span>\n ) : null}\n </div>\n );\n })}\n </div>\n <div className={EDITOR_FIELD_WIDE}>\n <Button\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Plus aria-hidden=\"true\" />}\n onClick={addPriceRow}\n >\n {t(key('priceListAdd'))}\n </Button>\n </div>\n </>\n ) : null}\n <FormField\n className={EDITOR_FIELD_WIDE}\n label={t(key('description'))}\n error={\n descriptionTooLong\n ? t(key('descriptionTooLong'), { max: descriptionMax })\n : undefined\n }\n >\n <TextInput\n value={care}\n disabled={capabilities?.editDescription === false}\n onChange={(e) => setCare(e.target.value)}\n />\n </FormField>\n {linkedCares?.length ? (\n <KeyValuePair\n className={EDITOR_FIELD_WIDE}\n label={t(key('cares'))}\n value={careLabel(linkedCares)}\n />\n ) : null}\n {/* Required medical devices — read-only, no picker (platform\n FIND_FREE_SLOTS_BY_CARE). */}\n {requiredDevices.length > 0 ? (\n <KeyValuePair\n className={EDITOR_FIELD_WIDE}\n label={t(key('devices'))}\n value={`${t(key('devicesRequired'), {\n count: requiredDevices.length,\n })} · ${requiredDevices.join(', ')}`}\n />\n ) : null}\n <FormField className={EDITOR_FIELD_SHORT} label={t(key('date'))}>\n <DatePicker value={date} onChange={setDate} />\n </FormField>\n <FormField\n className={EDITOR_FIELD_SHORT_STACKED}\n label={t(key('time'))}\n >\n <TimePicker value={time} onChange={setTime} />\n </FormField>\n <FormField\n className={EDITOR_FIELD_SHORT}\n label={t(key('duration'))}\n >\n <DurationCombobox\n value={durationMin}\n onChange={setDurationMin}\n />\n </FormField>\n <FormField\n className={EDITOR_FIELD_SHORT_STACKED}\n label={t(detailKey('color'))}\n >\n <ColorPicker\n variant=\"inline\"\n compact\n size=\"sm\"\n palette={\n data.appointmentPalette?.slice() ?? GOOGLE_CALENDAR_PALETTE\n }\n value={colorHex}\n onChange={setColorHex}\n />\n </FormField>\n {/* The closure banner follows the whole date block rather than\n splitting date from start time, so the pair keeps its row. */}\n {closure && date ? (\n <Alert\n variant=\"warning\"\n announce=\"polite\"\n className={EDITOR_FIELD_WIDE}\n >\n <Alert.Description>\n {closureReason(\n t,\n runtimeI18n.language,\n closure,\n date,\n data,\n )}\n </Alert.Description>\n </Alert>\n ) : null}\n {/* The standalone booleans share ONE wrapping row inside a\n single labelled group: five separate rows spent ~142px of\n column on five 19.6px controls. */}\n <fieldset\n className={`${EDITOR_FIELD_WIDE} ds:m-0 ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:border-0 ds:p-0`}\n >\n <legend className=\"type-label ds:text-foreground ds:p-0\">\n {t(key('options'))}\n </legend>\n <div className=\"ds:flex ds:flex-wrap ds:gap-x-[var(--spacing-md)] ds:gap-y-[var(--spacing-sm)]\">\n {showReminders ? (\n <>\n {/* Disabled ONLY on a reason we can defend: a\n record that loaded and holds nothing, or an\n opt-out. A channel the host never told us about\n stays tickable — the host refuses on send if it\n must, which beats telling the practice it has\n no number for a patient we never loaded. */}\n <Checkbox\n label={\n gateOnPatient && smsReasonKey !== null\n ? `${t(key('smsReminder'))} ${t(key('reminderDisabled'))}`\n : t(key('smsReminder'))\n }\n checked={smsReminder && (!gateOnPatient || smsOffered)}\n disabled={gateOnPatient && !smsOffered}\n disabledReason={\n gateOnPatient && smsReasonKey !== null\n ? t(smsReasonKey)\n : undefined\n }\n onCheckedChange={(c) => setSmsReminder(c === true)}\n />\n <Checkbox\n label={\n gateOnPatient && emailReasonKey !== null\n ? `${t(key('emailReminder'))} ${t(key('reminderDisabled'))}`\n : t(key('emailReminder'))\n }\n checked={\n emailReminder && (!gateOnPatient || emailOffered)\n }\n disabled={gateOnPatient && !emailOffered}\n disabledReason={\n gateOnPatient && emailReasonKey !== null\n ? t(emailReasonKey)\n : undefined\n }\n onCheckedChange={(c) => setEmailReminder(c === true)}\n />\n </>\n ) : null}\n <Checkbox\n label={t(key('allDay'))}\n checked={allDay}\n onCheckedChange={(c) => setAllDay(c === true)}\n />\n {/* Repeat and Waiting list are CREATE-only, exactly as in\n platform — an existing occurrence reads its rule back\n from the details panel's series line instead. */}\n {!isEdit ? (\n <>\n <Checkbox\n label={t(key('repeats'))}\n disabled={capabilities?.editRecurrence === false}\n checked={repeats}\n onCheckedChange={(c) => setRepeats(c === true)}\n />\n <Checkbox\n label={t(key('addToWaitingList'))}\n checked={addToWaitingList}\n onCheckedChange={(c) => setAddToWaitingList(c === true)}\n />\n </>\n ) : null}\n </div>\n </fieldset>\n {!isEdit ? (\n <>\n {repeats ? (\n <>\n <FormField\n className={EDITOR_FIELD_SHORT}\n label={t(key('recurrence'))}\n >\n <Select\n options={RECURRENCE_FREQUENCIES.map((value) => ({\n value,\n label: t(key(RECURRENCE_LABEL_KEY[value])),\n }))}\n value={recurrence}\n onValueChange={(v) =>\n setRecurrence(v as RecurrenceFrequency)\n }\n />\n </FormField>\n {/* Count XOR until — the exclusivity the platform entity\n already enforces, surfaced as a choice for the first\n time (its modal only ever sets the count, which is\n why Increment 1 opts out of this pair). */}\n {recurrenceExtras ? (\n <FormField\n className={EDITOR_FIELD_SHORT}\n label={t(key('recurrenceEnds'))}\n >\n <Select\n options={[\n {\n value: 'count',\n label: t(key('recurrenceEndsCount')),\n },\n {\n value: 'until',\n label: t(key('recurrenceEndsUntil')),\n },\n ]}\n value={recurrenceEnds}\n onValueChange={(v) => {\n const next = v as 'count' | 'until';\n setRecurrenceEnds(next);\n /* Seed a plausible cutoff so \"on a date\" is\n never an empty field that books nothing. */\n if (\n next === 'until' &&\n !recurrenceUntil &&\n date\n ) {\n setRecurrenceUntil(addMonthsClamped(date, 1));\n }\n }}\n />\n </FormField>\n ) : null}\n {!recurrenceExtras || recurrenceEnds === 'count' ? (\n <FormField\n className={EDITOR_FIELD_SHORT}\n label={t(key('recurrenceCount'))}\n >\n <NumberInput\n value={recurrenceCount}\n min={2}\n max={RECURRENCE_MAX_COUNT}\n onChange={setRecurrenceCount}\n />\n </FormField>\n ) : (\n <FormField\n className={EDITOR_FIELD_SHORT}\n label={t(key('recurrenceUntil'))}\n >\n <DatePicker\n value={recurrenceUntil}\n onChange={setRecurrenceUntil}\n minDate={date}\n />\n </FormField>\n )}\n {recurrenceExtras ? (\n <div\n className={`${EDITOR_FIELD_WIDE} ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]`}\n >\n <Checkbox\n label={t(key('skipClosedDays'))}\n aria-describedby={skipHintId}\n checked={skipClosedDays}\n onCheckedChange={(c) =>\n setSkipClosedDays(c === true)\n }\n />\n <span\n id={skipHintId}\n className=\"type-body-sm ds:text-start ds:text-[color:var(--muted-foreground)]\"\n >\n {t(key('skipClosedDaysHint'))}\n </span>\n </div>\n ) : null}\n </>\n ) : null}\n </>\n ) : null}\n {/* Allocation — resource (chair) then operator, the modal's\n closing pair. */}\n <FormField\n className={EDITOR_FIELD_SHORT}\n label={t(detailKey('chair'))}\n >\n <Select\n options={[\n { value: NONE, label: t(key('unassigned')) },\n ...(chairId !== NONE &&\n !data.chairs.some((chair) => chair.id === chairId)\n ? [\n {\n value: chairId,\n label: `${t(detailKey('chair'))} (${chairId})`,\n disabled: true,\n },\n ]\n : []),\n ...data.chairs.map((c) => ({\n value: c.id,\n label: c.title,\n })),\n ]}\n value={chairId}\n onValueChange={(next) => {\n setChairId(next);\n /* Platform fires COLOR_EVENT_SET_TO_CHAIR_COLOR on every\n change; the ColorPicker below still overrides. */\n if (colorAssociation === 'chair') {\n const c = associationColor(\n 'chair',\n { chairId: next },\n data,\n );\n if (c) setColorHex(c);\n }\n }}\n />\n </FormField>\n <FormField\n ref={operatorFieldRef}\n className={EDITOR_FIELD_SHORT}\n label={t(detailKey('operator'))}\n required={Boolean(prefill?.callToAction)}\n description={\n prefill?.callToAction === 'processBooking'\n ? t('calendarWorkspace.backlog.processOperatorHint')\n : prefill?.callToAction === 'assignOperator'\n ? t('calendarWorkspace.backlog.assignOperatorHint')\n : undefined\n }\n >\n <Select\n options={[\n { value: NONE, label: t(key('unassigned')) },\n ...(operatorId !== NONE &&\n !operatorOptions.some(\n (operator) => operator.id === operatorId,\n )\n ? [\n {\n value: operatorId,\n label:\n data.operators.find(\n (operator) => operator.id === operatorId,\n )?.title ??\n `${t(detailKey('operator'))} (${operatorId})`,\n disabled: true,\n },\n ]\n : []),\n ...operatorOptions.map((o) => ({\n value: o.id,\n label: o.title,\n })),\n ]}\n value={operatorId}\n onValueChange={(next) => {\n setOperatorId(next);\n if (colorAssociation === 'operator') {\n const c = associationColor(\n 'operator',\n {\n operatorId: next,\n },\n data,\n );\n if (c) setColorHex(c);\n }\n }}\n />\n </FormField>\n {/* Busy chair / busy operator — the platform warns, never\n blocks (its confirm string was dead code). */}\n {busy.chairBusy ? (\n <Alert\n variant=\"warning\"\n announce=\"polite\"\n className={EDITOR_FIELD_WIDE}\n >\n <Alert.Description>{t(key('chairBusy'))}</Alert.Description>\n </Alert>\n ) : null}\n {busy.operatorBusy ? (\n <Alert\n variant=\"warning\"\n announce=\"polite\"\n className={EDITOR_FIELD_WIDE}\n >\n <Alert.Description>\n {t(key('operatorBusy'))}\n </Alert.Description>\n </Alert>\n ) : null}\n {operatorAbsent ? (\n <Alert\n variant=\"warning\"\n announce=\"polite\"\n className={EDITOR_FIELD_WIDE}\n >\n <Alert.Description>\n {t(key('operatorAbsent'))}\n </Alert.Description>\n </Alert>\n ) : null}\n {/* Series member: which occurrences the save applies to (the\n platform's recurring-mode chooser, asked up front). */}\n {scopeApplies ? (\n <div className={EDITOR_FIELD_WIDE}>\n <RadioGroup\n label={t(key('recurringSaveMode'))}\n value={recurringSaveMode}\n onValueChange={(v) =>\n setRecurringSaveMode(v as RecurringScope)\n }\n >\n {RECURRING_SCOPES.map((scope) => (\n <Radio\n key={scope}\n value={scope}\n label={t(key(RECURRING_SCOPE_LABEL_KEY[scope]))}\n />\n ))}\n </RadioGroup>\n </div>\n ) : null}\n {after ? <div className={EDITOR_FIELD_WIDE}>{after}</div> : null}\n </fieldset>\n </form>\n </div>\n </div>\n {/* ACTION FOOTER — Save / Cancel / Duplicate / Delete and the\n reminder channels sit BELOW the scrolling form, pinned, so\n the primary action never scrolls away with the fields.\n Container-query wrapper: under 480px of panel width the\n labels collapse to icon-only so both groups still fit. */}\n <fieldset\n hidden={subView !== 'form' || choosingScope}\n disabled={saving}\n className=\"ds:relative ds:z-10 ds:m-0 ds:min-w-0 ds:shrink-0 ds:border-0 ds:border-t ds:border-[color:var(--border)] ds:bg-[var(--background)] ds:p-0\"\n >\n <div className=\"ds:@container/apptstrip\">\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)] ds:p-[var(--spacing-md)] ds:pt-[var(--spacing-sm)]\">\n {/* No Join-telehealth control: the kit has no room to open,\n and the session code is a bearer credential — anyone\n holding it enters the video room as either party, so it\n must not reach a toast, a log, a label or a URL here. The\n platform owns the join; the kit does not repeat the code. */}\n {formRef.assigned && !readOnly && !accepted ? (\n <SendReminderGroup\n onWhatsApp={onWhatsApp}\n channels={platform?.reminderChannels}\n />\n ) : null}\n <span className=\"ds:ms-auto ds:flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n {/* No Create-document menu: every item (bill, folder,\n from template, empty, ID, web camera) opens a platform\n document surface the kit cannot reach, so the trigger,\n the six items and the create-bill confirm are all\n withheld rather than shown as an empty menu. */}\n {/* Move… / Copy… (platform popover \"Sposta\" / \"Copia &\n incolla\"): the dialog closes and the next empty-slot\n click places the appointment; a linked one offers the\n two copies as a menu. */}\n {isEdit && !readOnly && !accepted && (onMove || onCopy) ? (\n <DropdownMenu.Root>\n <IconButtonGroup\n role=\"toolbar\"\n aria-label={t(detailKey('placementLabel'))}\n >\n {onMove ? (\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n icon={<Move aria-hidden=\"true\" />}\n aria-label={t(detailKey('move'))}\n tooltip={t(detailKey('move'))}\n onClick={onMove}\n />\n ) : null}\n {onCopy && currentLink ? (\n <DropdownMenu.Trigger asChild>\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n icon={<ClipboardPaste aria-hidden=\"true\" />}\n aria-label={t(detailKey('copy'))}\n tooltip={t(detailKey('copy'))}\n />\n </DropdownMenu.Trigger>\n ) : onCopy ? (\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n icon={<ClipboardPaste aria-hidden=\"true\" />}\n aria-label={t(detailKey('copy'))}\n tooltip={t(detailKey('copy'))}\n onClick={() => onCopy(false)}\n />\n ) : null}\n </IconButtonGroup>\n <DropdownMenu.Content align=\"end\">\n <DropdownMenu.Item\n startIcon={<Copy aria-hidden=\"true\" />}\n onSelect={() => onCopy?.(false)}\n >\n {t(key('duplicateAppointmentOnly'))}\n </DropdownMenu.Item>\n <DropdownMenu.Item\n startIcon={<ClipboardList aria-hidden=\"true\" />}\n onSelect={() => onCopy?.(true)}\n >\n {t(key('duplicateWithTreatments'))}\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n ) : null}\n {readOnly ? null : (\n <DropdownMenu.Root>\n <IconButtonGroup\n role=\"toolbar\"\n aria-label={t(key('actionsLabel'))}\n >\n {/* Audit C13 — a `simpleSave: false` arrival has an\n origin to return to, so the platform splits Save. */}\n {twoStepSave ? (\n <IconButton\n size=\"sm\"\n intent=\"primary\"\n icon={<ArrowLeft aria-hidden=\"true\" />}\n flipIconInRtl\n aria-label={t(key('saveAndReturn'))}\n tooltip={t(key('saveAndReturn'))}\n disabled={!canSave}\n onClick={() => handleSave({ andReturn: true })}\n />\n ) : null}\n <IconButton\n size=\"sm\"\n intent={twoStepSave ? 'outline' : 'primary'}\n icon={<Save aria-hidden=\"true\" />}\n aria-label={t(key(twoStepSave ? 'saveAndStay' : 'save'))}\n tooltip={t(key(twoStepSave ? 'saveAndStay' : 'save'))}\n disabled={!canSave}\n onClick={() => handleSave({ keepOpen: twoStepSave })}\n />\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n icon={<X aria-hidden=\"true\" />}\n aria-label={t(key('cancel'))}\n tooltip={t(key('cancel'))}\n disabled={!canCancel}\n onClick={() => closeSheet()}\n />\n {/* Linked: the platform's two-option copy as a menu — the\n Trigger is a DIRECT group child, Root sits outside\n (TreatmentLineActions precedent). A host that leaves\n `onDuplicate` unset gets no icon at all: the platform's\n ONLY copy path is Copy… placement (audit A4). */}\n {isEdit && !accepted && onDuplicate && currentLink ? (\n <DropdownMenu.Trigger asChild>\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n icon={<Copy aria-hidden=\"true\" />}\n aria-label={t(key('duplicate'))}\n tooltip={t(key('duplicate'))}\n />\n </DropdownMenu.Trigger>\n ) : isEdit && !accepted && onDuplicate ? (\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n icon={<Copy aria-hidden=\"true\" />}\n aria-label={t(key('duplicate'))}\n tooltip={t(key('duplicate'))}\n onClick={() => handleDuplicate(false)}\n />\n ) : null}\n {isEdit && !accepted ? (\n <IconButton\n size=\"sm\"\n intent=\"destructive\"\n icon={<Trash2 aria-hidden=\"true\" />}\n aria-label={t(key('delete'))}\n tooltip={t(key('delete'))}\n onClick={() => setConfirmDeleteOpen(true)}\n />\n ) : null}\n </IconButtonGroup>\n {onDuplicate ? (\n <DropdownMenu.Content align=\"end\">\n <DropdownMenu.Item\n startIcon={<Copy aria-hidden=\"true\" />}\n onSelect={() => handleDuplicate(false)}\n >\n {t(key('duplicateAppointmentOnly'))}\n </DropdownMenu.Item>\n <DropdownMenu.Item\n startIcon={<ClipboardList aria-hidden=\"true\" />}\n onSelect={() => handleDuplicate(true)}\n >\n {t(key('duplicateWithTreatments'))}\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n ) : null}\n </DropdownMenu.Root>\n )}\n </span>\n </div>\n </div>\n </fieldset>\n {isEdit ? (\n <Dialog open={confirmDeleteOpen} onOpenChange={setConfirmDeleteOpen}>\n <Dialog.Content size=\"sm\" variant=\"alert\">\n <Dialog.Header>\n <Dialog.Title>{t(key('deleteConfirmTitle'))}</Dialog.Title>\n <Dialog.Description>\n {t(key('deleteConfirmBody'))}\n </Dialog.Description>\n </Dialog.Header>\n {deleteScopes || cleanupApplies ? (\n <Dialog.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n {deleteScopes ? (\n <RadioGroup\n label={t(key('deleteScope'))}\n value={deleteChoice}\n onValueChange={(v) => setDeleteScope(v as RecurringScope)}\n >\n {deleteScopes.map((scope) => (\n <Radio\n key={scope}\n value={scope}\n label={t(key(RECURRING_SCOPE_LABEL_KEY[scope]))}\n />\n ))}\n </RadioGroup>\n ) : null}\n {cleanupApplies ? (\n <RadioGroup\n label={t(key('carePlanCleanup'))}\n value={removeFromCarePlan ? 'remove' : 'keep'}\n onValueChange={(v) => setRemoveFromCarePlan(v === 'remove')}\n >\n <Radio value=\"remove\" label={t(key('carePlanRemove'))} />\n <Radio value=\"keep\" label={t(key('carePlanKeep'))} />\n </RadioGroup>\n ) : null}\n </Dialog.Body>\n ) : null}\n <Dialog.Footer divider>\n <Dialog.Close asChild>\n <Button intent=\"outline\">{t(key('deleteCancel'))}</Button>\n </Dialog.Close>\n <Button\n intent=\"destructive\"\n startIcon={<Trash2 aria-hidden=\"true\" />}\n onClick={handleDeleteConfirmed}\n >\n {t(key('deleteConfirm'))}\n </Button>\n </Dialog.Footer>\n </Dialog.Content>\n </Dialog>\n ) : null}\n </div>\n );\n}\n\n/* Labelled indicator chips — whenever a grid card carries the disc\n symbols, the peek and the details panel spell them out: icon + full\n label in a semantic Badge (same tone vocabulary as the discs). */\nexport function IndicatorChips({ event }: { event: CalendarEvent }) {\n const { t } = useTranslation();\n const key = (suffix: string): string =>\n `calendarWorkspace.details.indicators.${suffix}`;\n const chips: Array<{\n id: string;\n icon: ReactNode;\n label: string;\n variant: 'info' | 'warning' | 'accentSoft';\n }> = [];\n if (event.isBookedOnline) {\n chips.push({\n id: 'online',\n icon: <Globe aria-hidden=\"true\" />,\n label: t(key('bookedOnline')),\n variant: 'info',\n });\n }\n if (event.hasUnassignedPatient) {\n chips.push({\n id: 'unassigned',\n icon: <TriangleAlert aria-hidden=\"true\" />,\n label: t(key('unassignedPatient')),\n variant: 'warning',\n });\n }\n if (event.hasHighlightedAnamnesis) {\n chips.push({\n id: 'anamnesis',\n icon: <HeartPulse aria-hidden=\"true\" />,\n label: t(key('anamnesis')),\n variant: 'accentSoft',\n });\n }\n if (event.hasBillableAmount) {\n chips.push({\n id: 'billable',\n icon: <Euro aria-hidden=\"true\" />,\n label: t(key('billable')),\n variant: 'warning',\n });\n }\n if (event.isTelehealth) {\n chips.push({\n id: 'telehealth',\n icon: <Video aria-hidden=\"true\" />,\n label: t(key('telehealth')),\n variant: 'info',\n });\n }\n if (event.isRecurring) {\n chips.push({\n id: 'recurring',\n icon: <Repeat aria-hidden=\"true\" />,\n label: t(key('recurring')),\n variant: 'info',\n });\n }\n if (chips.length === 0) return null;\n return (\n <span className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-2xs)]\">\n {chips.map((chip) => (\n <Badge\n key={chip.id}\n variant={chip.variant}\n size=\"sm\"\n leading={chip.icon}\n >\n {chip.label}\n </Badge>\n ))}\n </span>\n );\n}\n\n/* Identity strip above the details-as-form surface: avatar · name ·\n status chip — the read-at-a-glance layer over the editable form. */\nexport function AppointmentIdentity({\n row,\n patientRef,\n showAge = false,\n onOpenPatient,\n anamnesisAnswers,\n}: {\n row: CalendarRow;\n /** Who this appointment is for: the id it carries and the record, when\n * the host could resolve it. */\n patientRef: PatientRef;\n /** Append the platform popover's \"(NN anni)\" to the name (audit C15). */\n showAge?: boolean;\n /** Set = the name becomes the platform's patient-folder link. */\n onOpenPatient?: (patient: CalendarPatient) => void;\n /** The highlighted anamnesis answers themselves — the platform's\n * details dialog lists them, the popover only counts (audit C16). */\n anamnesisAnswers?: readonly CalendarAnamnesisAnswer[];\n}) {\n const { t } = useTranslation();\n const data = useCalendarData();\n const { t: tUi, i18n: runtimeI18n } = useTranslation();\n const key = (suffix: string): string => `calendarWorkspace.details.${suffix}`;\n const patient = patientRef.record;\n const highlighted = patient?.highlightedAnamnesisCount ?? 0;\n const expired = patient?.expiredAnamnesisCount ?? 0;\n const answers = anamnesisAnswers ?? [];\n /* Record, else the row's own title, else the honest label — never the\n empty string a blank title used to leave behind, which rendered a\n nameless heading over an initials-less avatar. */\n const displayName = patientRefName(\n patientRef,\n row.event.title,\n t(key('patientNotLoaded')),\n );\n /* No date of birth from the host ⇒ no \"(NN years old)\" beside the\n name; an age is a fact, not a formatting flourish. */\n const age =\n showAge && patient?.dobIso\n ? patientAgeYears(patient.dobIso, data)\n : undefined;\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:p-[var(--spacing-md)] ds:pb-0\">\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-sm)]\">\n <Avatar name={displayName} src={patient?.avatarSrc} />\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)] ds:[min-inline-size:0]\">\n {/* The platform popover links the name to the patient folder\n and prints the age beside it. */}\n <span className=\"ds:flex ds:flex-wrap ds:items-baseline ds:gap-[var(--spacing-2xs)] ds:text-start\">\n {onOpenPatient && patient ? (\n <Button\n size=\"sm\"\n intent=\"link\"\n onClick={() => onOpenPatient(patient)}\n >\n {displayName}\n </Button>\n ) : (\n <span className=\"ds:font-[var(--font-weight-semibold)] ds:truncate\">\n {displayName}\n </span>\n )}\n {age !== undefined ? (\n <span className=\"type-body-sm ds:text-[color:var(--muted-foreground)]\">\n {t(key('patientAge'), { n: age })}\n </span>\n ) : null}\n </span>\n {/* Said ONCE, next to the name it qualifies. Without it the\n panel's silence is ambiguous: \"we could not load this\n patient\" and \"this patient has nothing recorded\" render\n identically, and the reader cannot tell which. */}\n {patientRef.unresolved ? (\n <span className=\"type-body-sm ds:text-start ds:text-[color:var(--muted-foreground)]\">\n {t(key('patientNotLoaded'))}\n </span>\n ) : null}\n {row.event.status ? (\n <span>\n <Badge\n variant={STATUS_CHIP[row.event.status].variant}\n size=\"sm\"\n leading={(() => {\n const StatusGlyph = STATUS_CHIP[row.event.status].Icon;\n return <StatusGlyph aria-hidden=\"true\" />;\n })()}\n >\n {tUi(STATUS_UI_KEY[row.event.status])}\n </Badge>\n </span>\n ) : null}\n <IndicatorChips event={row.event} />\n </div>\n </div>\n {/* The platform popover's anamnesis warnings: the two counts and\n the highlighted answers. Present from mount, so announce=\"off\";\n Title as a <p> keeps the panel's h2 alone. */}\n {highlighted + expired > 0 ? (\n <Alert\n variant=\"warning\"\n announce=\"off\"\n icon={<HeartPulse aria-hidden=\"true\" />}\n >\n <Alert.Title as=\"p\">{t(key('anamnesisTitle'))}</Alert.Title>\n <Alert.Description>\n {[\n highlighted > 0\n ? t(key('anamnesisHighlighted'), { n: highlighted })\n : null,\n expired > 0 ? t(key('anamnesisExpired'), { n: expired }) : null,\n ]\n .filter((s): s is string => s !== null)\n .join(' · ')}\n </Alert.Description>\n {answers.length > 0 ? (\n /* Question · Si/No · answer · interview date, the platform\n details dialog's \"Anamnesi in risalto\" card. A list, not a\n Description — that one renders a <p>. */\n <ul className=\"type-body-sm ds:m-0 ds:mt-[var(--spacing-xs)] ds:flex ds:list-none ds:flex-col ds:gap-[var(--spacing-2xs)] ds:p-0\">\n {answers.map((answer) => (\n <li key={answer.question} className=\"ds:text-start\">\n <span className=\"ds:font-[var(--font-weight-semibold)]\">\n {answer.question}\n </span>\n {` · ${t(key(answer.yes ? 'anamnesisYes' : 'anamnesisNo'))}`}\n {answer.answer ? ` · ${answer.answer}` : ''}\n {` · ${formatDay(runtimeI18n.language, answer.interviewIso)}`}\n </li>\n ))}\n </ul>\n ) : null}\n {/* No Renew action: re-issuing the anamnesis is a platform\n flow the kit cannot start. The expired COUNT stays — it is\n a clinical fact about this appointment, not an offer. */}\n </Alert>\n ) : null}\n </div>\n );\n}\n\n/* Send-reminder split group — platform channels (WhatsApp / SMS /\n email), labelled so the choice is explicit. Lives in the editor's\n pinned header row beside the action icons. Demo-only send: a polite\n announcement, no real dispatch. */\nexport function SendReminderGroup({\n onWhatsApp,\n channels: allowed = REMINDER_CHANNELS,\n}: {\n /** When set, the WhatsApp segment bridges to the legacy Snippets\n * island instead of the demo-fake send. */\n onWhatsApp?: () => void;\n /** Which channels to offer — defaults to all three. Increment 1 keeps\n * the WhatsApp bridge alone, the platform's only outbound path. */\n channels?: readonly ReminderChannel[];\n}) {\n const { t } = useTranslation();\n const key = (suffix: string): string => `calendarWorkspace.details.${suffix}`;\n const [sentVia, setSentVia] = useState('');\n const channels = [\n {\n id: 'whatsapp' as const,\n label: t(key('remindWhatsApp')),\n icon: <WhatsAppGlyph aria-hidden=\"true\" />,\n },\n {\n id: 'sms' as const,\n label: t(key('remindSms')),\n icon: <MessageSquare aria-hidden=\"true\" />,\n },\n {\n id: 'email' as const,\n label: t(key('remindEmail')),\n icon: <Mail aria-hidden=\"true\" />,\n },\n ].filter((channel) => allowed.includes(channel.id));\n if (channels.length === 0) return null;\n return (\n <>\n <ButtonGroup aria-label={t(key('remind'))}>\n {channels.map((channel) => (\n <Button\n key={channel.id}\n size=\"sm\"\n intent=\"outline\"\n startIcon={channel.icon}\n aria-label={channel.label}\n title={channel.label}\n onClick={() =>\n channel.id === 'whatsapp' && onWhatsApp\n ? onWhatsApp()\n : setSentVia(channel.label)\n }\n >\n <span className=\"ds:hidden ds:@[480px]/apptstrip:inline\">\n {channel.label}\n </span>\n </Button>\n ))}\n </ButtonGroup>\n <VisuallyHidden aria-live=\"polite\">\n {sentVia ? t(key('remindSent'), { channel: sentVia }) : ''}\n </VisuallyHidden>\n </>\n );\n}\n\n/** The platform popover facts the Final State never modelled — every\n * field optional, so a host that passes nothing sees the extras as before. */\nexport interface ExtrasPlatformOptions {\n /** Deposit paid online when booking (Stripe). */\n paidOnlineAmount?: number;\n /** The patient's outstanding balance. */\n toCollectAmount?: number;\n /** The user's map-link setting (the display cog). */\n mapsLink?: boolean;\n /** The phone typed on the booking site, when it differs from the record. */\n bookingPhone?: string;\n}\n\n/* Read-only extras below the form: billing + patient contact. */\nexport function AppointmentExtras({\n row,\n patient,\n locale,\n signRequestedVia,\n onRequestSignature,\n onRequestSignatureOnDevice,\n readOnly = false,\n platform,\n}: {\n row: CalendarRow;\n patient?: CalendarPatient;\n locale: string;\n /** Channel the signature request went out on (journey state wins). */\n signRequestedVia?: CalendarSignChannel;\n onRequestSignature?: (eventId: string, channel: CalendarSignChannel) => void;\n /** \"On this device…\" — bridges to the legacy e-signature flow. */\n onRequestSignatureOnDevice?: () => void;\n /** No edit permission: the request menu and the setup links go. */\n readOnly?: boolean;\n /** Platform parity extras — see `ExtrasPlatformOptions`. */\n platform?: ExtrasPlatformOptions;\n}) {\n const data = useCalendarData();\n const { t } = useTranslation();\n const key = (suffix: string): string => `calendarWorkspace.details.${suffix}`;\n const { t: tUi } = useTranslation();\n const meta = data.metaById[row.event.id];\n /* Signing: the request channel is APPOINTMENT-level on the platform\n (`requiredObjectsSignMode`), so the line and the action sit above the\n per-document chips. In-panel change → live region, not a toast. */\n const docs = meta?.documentsToSign ?? [];\n const signing = signingSummary(docs);\n const [signReadout, setSignReadout] = useState('');\n const requestSignature = (channel: CalendarSignChannel): void => {\n onRequestSignature?.(row.event.id, channel);\n setSignReadout(\n t(key('signingRequestedReadout'), {\n channel: t(key(channel === 'sms' ? 'remindSms' : 'remindEmail')),\n }),\n );\n };\n const requestedLine =\n signRequestedVia === 'sms'\n ? t(key('signingRequestedSms'))\n : signRequestedVia === 'email'\n ? t(key('signingRequestedEmail'))\n : t(key('signingNotRequested'));\n const link = row.careLink;\n const linkedPlan =\n link?.kind === 'plan' ? data.carePlanById(link.planId) : undefined;\n const linkedEntries =\n link?.kind === 'plan' && linkedPlan\n ? linkedPlan.entries.filter((e) => link.entryIds.includes(e.id))\n : [];\n const priceListName =\n link?.kind === 'priceList'\n ? (data.priceLists ?? []).find((l) => l.id === link.priceListId)?.name\n : undefined;\n const money = new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: 'EUR',\n });\n const line = 'ds:flex ds:items-baseline ds:gap-[var(--spacing-xs)]';\n const label =\n 'type-body-sm ds:text-[color:var(--muted-foreground)] ds:shrink-0';\n /* Which patient lines below have something to say. The LABEL keeps the\n pair the popover has always printed (street, city); the postcode\n rides in the search query alone, so widening the URL never widened\n what a full patient's row reads as. */\n const mapQuery = patient ? patientAddressLine(patient) : '';\n const mapLabel = patient ? patientAddressLabel(patient) : '';\n const showMapRow = Boolean(platform?.mapsLink) && mapQuery !== '';\n /* The booking phone is an APPOINTMENT fact — the number typed on the\n booking site — so it survives a record that did not load; every\n other row here is read off the record and goes with it. */\n const hasPatientFacts = Boolean(\n patient?.dobIso ||\n patient?.phone ||\n patient?.email ||\n patient?.city ||\n platform?.bookingPhone ||\n showMapRow,\n );\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:border-t ds:border-[var(--border)] ds:pt-[var(--spacing-md)]\">\n {/* The rule, read-only — platform disables its recurrence inputs\n once an appointment exists, so this is where an occurrence\n says what series it belongs to and how far it runs. */}\n {row.series ? (\n <div className={line}>\n <span className={label}>{t(key('seriesLabel'))}</span>\n <span>\n {t(key('seriesSummary'), {\n frequency: t(\n `calendarWorkspace.editor.${\n RECURRENCE_LABEL_KEY[row.series.frequency]\n }`,\n ),\n index: row.series.index,\n total: row.series.total,\n last: formatDay(locale, row.series.lastIso),\n })}\n {row.series.skipped > 0\n ? ` · ${t(key('seriesSkipped'), { n: row.series.skipped })}`\n : ''}\n </span>\n </div>\n ) : null}\n {/* Linked treatments — the platform popover's \"Piano di cura\" link\n plus one line per entry (name, code, teeth, done, billed, the\n booked phases); a price-list pick lists its items and prices. */}\n {link ? (\n <>\n <h3 className=\"type-label ds:m-0 ds:uppercase ds:text-[color:var(--muted-foreground)]\">\n {t(key('sectionTreatments'))}\n </h3>\n {link.kind === 'plan' && linkedPlan ? (\n <>\n {/* STATIC — which plan this appointment belongs to is a\n fact about it and stays. There is no in-calendar\n care-plan panel to dock, so the line names the plan\n and offers no hop. */}\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n <ClipboardList\n size={14}\n aria-hidden=\"true\"\n className=\"ds:shrink-0\"\n />\n <span>\n {t(key('planLine'), {\n number: linkedPlan.number,\n name: linkedPlan.name,\n })}\n </span>\n </div>\n {linkedEntries.map((entry) => {\n const entryCare = data.careById(entry.careId);\n const phases = link.phasesByEntry?.[entry.id];\n return (\n <div\n key={entry.id}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\"\n >\n <span className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-2xs)]\">\n <span>{entryCare?.name ?? entry.careId}</span>\n {entryCare ? (\n <span className=\"type-meta ds:tabular-nums ds:text-[color:var(--muted-foreground)]\">\n {entryCare.code}\n </span>\n ) : null}\n {entry.elements?.map((el) => (\n <Tag key={el} label={el} variant=\"info\" size=\"sm\" />\n ))}\n {entry.done ? (\n <Badge variant=\"success\" size=\"sm\" withDot>\n {tUi('carePlanEntryCard.flag.done')}\n </Badge>\n ) : null}\n {entry.billed ? (\n <Badge variant=\"neutral\" size=\"sm\">\n {tUi('carePlanEntryCard.flag.billed')}\n </Badge>\n ) : null}\n </span>\n {phases && phases.length > 0 ? (\n <span className=\"type-body-sm ds:text-[color:var(--muted-foreground)]\">\n {t(key('phasesScheduled'), {\n phases: phases.join(', '),\n })}\n </span>\n ) : null}\n </div>\n );\n })}\n </>\n ) : null}\n {link.kind === 'priceList' ? (\n <>\n <div className={line}>\n <span className={label}>{t(key('priceListLine'))}</span>\n <span>{priceListName ?? link.priceListId}</span>\n </div>\n {link.items.map((item, index) => {\n const itemCare = data.careById(item.careId);\n return (\n <div\n key={`${item.careId}-${index}`}\n className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-2xs)]\"\n >\n <span>{itemCare?.name ?? item.careId}</span>\n {itemCare ? (\n <span className=\"type-meta ds:tabular-nums ds:text-[color:var(--muted-foreground)]\">\n {itemCare.code}\n </span>\n ) : null}\n <span className=\"ds:ms-auto ds:tabular-nums\">\n {money.format(item.priceCents / 100)}\n </span>\n </div>\n );\n })}\n </>\n ) : null}\n </>\n ) : null}\n {/* Documents to sign — the platform popover's FEA block: a headline\n count, one kit chip per document, the requested-via line and the\n demo-fake request menu (SMS gated on the patient's opt-in). */}\n {docs.length > 0 ? (\n <>\n <h3 className=\"type-label ds:m-0 ds:uppercase ds:text-[color:var(--muted-foreground)]\">\n {t(key('sectionSigning'))}\n </h3>\n <span\n className={`ds:flex ds:items-center ds:gap-[var(--spacing-2xs)] ds:font-[var(--font-weight-semibold)] ${\n signing.toSign > 0\n ? 'ds:text-[color:var(--warning-foreground)]'\n : 'ds:text-[color:var(--success-foreground)]'\n }`}\n >\n {signing.toSign > 0 ? (\n <PenLine size={16} aria-hidden=\"true\" />\n ) : (\n <Check size={16} aria-hidden=\"true\" />\n )}\n {signing.toSign === 0\n ? t(key('signingAllSigned'))\n : signing.toSign === 1\n ? t(key('signingToSignOne'))\n : t(key('signingToSignMany'), { n: signing.toSign })}\n </span>\n {docs.map((doc) => (\n <div\n key={doc.id}\n className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\"\n >\n <span className=\"ds:[min-inline-size:0] ds:truncate\">\n {doc.name}\n </span>\n <SignatureStatusChip\n className=\"ds:ms-auto\"\n size=\"sm\"\n operator={doc.operator}\n patient={doc.patient}\n />\n </div>\n ))}\n {signing.toSign > 0 ? (\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n <span className=\"type-body-sm ds:text-[color:var(--muted-foreground)]\">\n {requestedLine}\n </span>\n {readOnly ? null : (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Send aria-hidden=\"true\" />}\n >\n {t(key('signingRequest'))}\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n <DropdownMenu.Item\n startIcon={<MessageSquare aria-hidden=\"true\" />}\n disabled={patient?.smsEnabled === false}\n description={\n patient?.smsEnabled === false\n ? t(key('signingSmsDisabled'))\n : undefined\n }\n onSelect={() => requestSignature('sms')}\n >\n {t(key('signingViaSms'))}\n </DropdownMenu.Item>\n <DropdownMenu.Item\n startIcon={<Mail aria-hidden=\"true\" />}\n onSelect={() => requestSignature('email')}\n >\n {t(key('signingViaEmail'))}\n </DropdownMenu.Item>\n {/* The on-device flow (signee, operator, OTP) stays a\n legacy island — the item only bridges to it. */}\n {onRequestSignatureOnDevice ? (\n <DropdownMenu.Item\n startIcon={<Smartphone aria-hidden=\"true\" />}\n onSelect={onRequestSignatureOnDevice}\n >\n {t(key('signingOnDevice'))}\n </DropdownMenu.Item>\n ) : null}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n )}\n <VisuallyHidden aria-live=\"polite\">{signReadout}</VisuallyHidden>\n </div>\n ) : null}\n {/* No \"Enable advanced e-signature\" link: the setup lives on a\n platform settings surface the kit cannot open, so the offer\n is withheld rather than dead-ended. */}\n </>\n ) : null}\n {/* Booked online — when, and the note the patient typed. The channel\n is the \"Booked online\" chip above (one value on the platform). */}\n {row.event.isBookedOnline && meta?.bookedAtIso ? (\n <>\n <h3 className=\"type-label ds:m-0 ds:uppercase ds:text-[color:var(--muted-foreground)]\">\n {t(key('sectionBooking'))}\n </h3>\n <div className={line}>\n <span className={label}>{t(key('bookedAt'))}</span>\n <Timestamp\n value={meta.bookedAtIso}\n format=\"absolute\"\n shape=\"bare\"\n locale={locale}\n absoluteFormat={DETAIL_STAMP_FORMAT}\n />\n </div>\n {meta.bookingNote ? (\n <div className={line}>\n <span className={label}>{t(key('bookingNote'))}</span>\n <span>{meta.bookingNote}</span>\n </div>\n ) : null}\n </>\n ) : null}\n {meta?.billableAmount !== undefined ? (\n <div className={line}>\n <span className={label}>{t(key('billable'))}</span>\n <span>\n {new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: 'EUR',\n }).format(meta.billableAmount)}\n </span>\n </div>\n ) : null}\n {/* The popover's money lines the Final State lacked: paid online\n (a booking deposit) and to collect. */}\n {platform?.paidOnlineAmount ? (\n <div className={line}>\n <span className={label}>{t(key('paidOnline'))}</span>\n <span className=\"ds:text-[color:var(--success-foreground)]\">\n {money.format(platform.paidOnlineAmount)}\n </span>\n </div>\n ) : null}\n {platform?.toCollectAmount ? (\n <div className={line}>\n <span className={label}>{t(key('toCollect'))}</span>\n <span className=\"ds:text-[color:var(--warning-foreground)]\">\n {money.format(platform.toCollectAmount)}\n </span>\n </div>\n ) : null}\n {/* No \"Automate payments\" link: it opens the Payment-automation\n surface, which the kit cannot reach. The money lines above stay\n — paid online and to collect are facts, not an upsell. */}\n {/* One line per contact fact the host actually supplied — and no\n Patient heading at all when it supplied none. A \"Phone\" row with\n nothing after it says the practice holds no number for this\n patient, which is a different (and possibly false) claim from\n \"we did not load the record\". */}\n {hasPatientFacts ? (\n <>\n <h3 className=\"type-label ds:m-0 ds:uppercase ds:text-[color:var(--muted-foreground)]\">\n {t(key('sectionPatient'))}\n </h3>\n {patient?.dobIso ? (\n <div className={line}>\n <span className={label}>{t(key('dob'))}</span>\n <span>{formatDay(locale, patient.dobIso)}</span>\n </div>\n ) : null}\n {patient?.phone ? (\n <div className={line}>\n <span className={label}>{t(key('phone'))}</span>\n <a href={`tel:${patient.phone.replace(/\\s/g, '')}`}>\n {patient.phone}\n </a>\n </div>\n ) : null}\n {patient?.email ? (\n <div className={line}>\n <span className={label}>{t(key('email'))}</span>\n <a className=\"ds:truncate\" href={`mailto:${patient.email}`}>\n {patient.email}\n </a>\n </div>\n ) : null}\n {patient?.city ? (\n <div className={line}>\n <span className={label}>{t(key('city'))}</span>\n <span>{patient.city}</span>\n </div>\n ) : null}\n {platform?.bookingPhone ? (\n <div className={line}>\n <span className={label}>{t(key('bookingPhone'))}</span>\n <a href={`tel:${platform.bookingPhone.replace(/\\s/g, '')}`}>\n {platform.bookingPhone}\n </a>\n </div>\n ) : null}\n {/* The map link follows the display cog (platform\n `showPatientAddressMapLink`) — and needs an address to\n search for: a link over an empty query finds nothing. */}\n {showMapRow && patient ? (\n <div className={line}>\n <span className={label}>{t(key('address'))}</span>\n <a\n className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-2xs)]\"\n href={patientMapsUrl(patient)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={`${t(key('mapsLink'))} — ${mapLabel}`}\n >\n <MapPin size={14} aria-hidden=\"true\" />\n {mapLabel}\n </a>\n </div>\n ) : null}\n </>\n ) : null}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Care plan — the selected patient's plans as a contextual rail tool. */\n/* Composed from the kit CarePlanCard (summary) + a kit Accordion of */\n/* CarePlanEntryCard rows (the card's own `entries` prop renders the */\n/* same list but cannot carry a navigation action), with the lines */\n/* linked to the selected appointment marked and a Show-on-calendar */\n/* hop per booked appointment. Open full plan is demo-fake (toast). */\n/* ------------------------------------------------------------------ */\n\nexport function PatientCarePlanPanel({\n plans,\n linkedPlanId,\n linkedEntryIds,\n schedule,\n locale,\n onReveal,\n}: {\n plans: CalendarCarePlan[];\n /** The selected appointment's plan — listed first, entries expanded. */\n linkedPlanId?: string;\n linkedEntryIds: string[];\n schedule: Record<string, Array<{ eventId: string; startIso: string }>>;\n locale: string;\n /** Navigate the grid to the appointment and select it. */\n onReveal: (eventId: string) => void;\n}) {\n const data = useCalendarData();\n const { t } = useTranslation();\n const key = (suffix: string): string =>\n `calendarWorkspace.carePlan.${suffix}`;\n const ordered = [...plans].sort((a, b) =>\n a.id === linkedPlanId ? -1 : b.id === linkedPlanId ? 1 : 0,\n );\n return (\n <div data-component=\"calendar-care-plan\" className=\"ds:flex ds:flex-col\">\n <PanelHeader\n title={t(key('region'))}\n icon={<ClipboardList aria-hidden=\"true\" />}\n sticky\n divider\n />\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)] ds:p-[var(--spacing-md)]\">\n {ordered.map((plan) => {\n const done = plan.entries.filter((e) => e.done).length;\n const isLinkedPlan = plan.id === linkedPlanId;\n return (\n <div\n key={plan.id}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <CarePlanCard\n id={`demo-care-plan-${plan.id}`}\n number={plan.number}\n name={plan.name}\n state={plan.state}\n dates={\n plan.acceptedIso\n ? { acceptedIso: plan.acceptedIso }\n : undefined\n }\n amounts={plan.amounts}\n progress={{ done, total: plan.entries.length }}\n locale={locale}\n />\n <Accordion\n type=\"single\"\n collapsible\n variant=\"separated\"\n defaultValue={isLinkedPlan ? 'entries' : undefined}\n >\n <AccordionItem value=\"entries\">\n <AccordionTrigger>\n {t(key('entriesToggle'), { count: plan.entries.length })}\n </AccordionTrigger>\n <AccordionContent>\n <ul className=\"ds:m-0 ds:flex ds:list-none ds:flex-col ds:gap-[var(--spacing-sm)] ds:p-0\">\n {plan.entries.map((entry) => {\n const care = data.careById(entry.careId);\n const linked =\n isLinkedPlan && linkedEntryIds.includes(entry.id);\n const booked = schedule[entry.id] ?? [];\n const phaseCount = entry.phases?.length ?? 0;\n return (\n <li\n key={entry.id}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\"\n >\n <CarePlanEntryCard\n id={`demo-care-plan-entry-${entry.id}`}\n surface=\"flat\"\n locale={locale}\n careName={care?.name ?? entry.careId}\n code={care?.code}\n elements={entry.elements}\n done={entry.done}\n executionDateIso={entry.executionDateIso}\n billed={entry.billed}\n price={{\n priceCents:\n entry.priceCents ?? care?.priceCents,\n }}\n phases={\n phaseCount > 0\n ? {\n executed: entry.done ? phaseCount : 0,\n total: phaseCount,\n detail: (entry.phases ?? []).map(\n (label) => ({\n label,\n executed: entry.done,\n }),\n ),\n }\n : undefined\n }\n plannedAppointment={\n !entry.done && booked[0]\n ? {\n dateIso: booked[0].startIso,\n appointmentId: booked[0].eventId,\n }\n : undefined\n }\n label={\n linked ? t(key('linkedToThis')) : undefined\n }\n className={\n linked\n ? 'ds:border-s-[length:var(--spacing-2xs)] ds:border-s-[color:var(--primary)] ds:ps-[var(--spacing-sm)]'\n : undefined\n }\n />\n {booked.map((b) => (\n <div key={b.eventId}>\n <Button\n size=\"sm\"\n intent=\"ghost\"\n startIcon={\n <CalendarClock aria-hidden=\"true\" />\n }\n onClick={() => onReveal(b.eventId)}\n >\n {t(key('showOnCalendar'))} ·{' '}\n {formatDay(locale, b.startIso)}\n </Button>\n </div>\n ))}\n </li>\n );\n })}\n </ul>\n </AccordionContent>\n </AccordionItem>\n </Accordion>\n </div>\n );\n })}\n {/* No \"Open full plan\" footer: the care-plan page is a platform\n route the kit holds no address for, so the panel ends on its\n last accordion rather than on an empty footer. */}\n </div>\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Backlog — ONE rail work queue for everything the agenda still owes */\n/* an action. Five types, each a segment of the filter strip with its */\n/* count: online bookings to process (the platform's booking triage — */\n/* patient record AND operator before a booking leaves the queue), the */\n/* platform WaitingListEntry queue (add/edit as a rail sub-view, */\n/* Schedule seeds create, Bring forward re-opens the LINKED */\n/* appointment for editing — the entry leaves when the save lands), */\n/* unconfirmed appointments in the visible range, appointments booked */\n/* without an operator, and appointments whose documents still await a */\n/* signature. Rows share one card idiom (avatar · name · when), a */\n/* per-type body and a trailing action; the strip badge is the total. */\n/* ------------------------------------------------------------------ */\n\n/** Panel-list canon: every row is its own elevated card (the NotesPanel\n * treatment — card bg, border, shadow). */\nconst BACKLOG_CARD_CLASS =\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--card-border)] ds:[.theme-accessible_&]:border-2 ds:bg-[color:var(--card)] ds:shadow-[var(--shadow-sm)] ds:p-[var(--spacing-sm)]';\n\nconst BACKLOG_LINE_CLASS =\n 'type-body-sm ds:flex ds:items-center ds:gap-[var(--spacing-2xs)]';\n\n/** The shared row shell: avatar (or a waiting placeholder), headline,\n * when-line, then the per-type body and the trailing action strip. */\nfunction BacklogRow({\n name,\n avatarName,\n avatarSrc,\n when,\n children,\n actions,\n}: {\n name: string;\n /** Set = an `Avatar` for this person; unset = the hourglass placeholder. */\n avatarName?: string;\n /** The person's photo; the Avatar falls back to initials without it. */\n avatarSrc?: string;\n when: ReactNode;\n children?: ReactNode;\n actions: ReactNode;\n}) {\n return (\n <li className={BACKLOG_CARD_CLASS}>\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n {avatarName ? (\n <Avatar name={avatarName} src={avatarSrc} size=\"sm\" />\n ) : (\n <span\n aria-hidden=\"true\"\n className=\"ds:flex ds:h-8 ds:w-8 ds:shrink-0 ds:items-center ds:justify-center ds:rounded-[var(--radius-full)] ds:bg-[var(--muted)] ds:text-[color:var(--muted-foreground)]\"\n >\n <Hourglass size={16} />\n </span>\n )}\n <div className=\"ds:flex ds:flex-col ds:[min-inline-size:0]\">\n <span className=\"ds:font-[var(--font-weight-semibold)] ds:truncate ds:text-start\">\n {name}\n </span>\n <span className=\"type-body-sm ds:text-start ds:text-[color:var(--muted-foreground)]\">\n {when}\n </span>\n </div>\n </div>\n {children}\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-2xs)]\">\n {actions}\n </div>\n </li>\n );\n}\n\n/** Day · time of an appointment row, as one semantic `<time>`. */\nfunction BacklogWhen({ iso, locale }: { iso: string; locale: string }) {\n return (\n <Timestamp\n value={eventStartMs(iso)}\n format=\"absolute\"\n shape=\"bare\"\n locale={locale}\n absoluteFormat={DETAIL_STAMP_FORMAT}\n />\n );\n}\n\n/**\n * The details panel's request-signature idiom on a queue row: the\n * appointment-level requested-via line, the SMS/email menu (SMS gated on\n * the patient's opt-in) and a polite readout — nothing is dispatched.\n */\nfunction SignatureRequestMenu({\n row,\n patient,\n requestedVia,\n onRequest,\n}: {\n row: CalendarRow;\n patient?: CalendarPatient;\n requestedVia?: CalendarSignChannel;\n onRequest: (eventId: string, channel: CalendarSignChannel) => void;\n}) {\n const { t } = useTranslation();\n const key = (suffix: string): string => `calendarWorkspace.details.${suffix}`;\n const [readout, setReadout] = useState('');\n const request = (channel: CalendarSignChannel): void => {\n onRequest(row.event.id, channel);\n setReadout(\n t(key('signingRequestedReadout'), {\n channel: t(key(channel === 'sms' ? 'remindSms' : 'remindEmail')),\n }),\n );\n };\n return (\n <>\n <span className=\"type-body-sm ds:text-[color:var(--muted-foreground)]\">\n {requestedVia === 'sms'\n ? t(key('signingRequestedSms'))\n : requestedVia === 'email'\n ? t(key('signingRequestedEmail'))\n : t(key('signingNotRequested'))}\n </span>\n <span className=\"ds:ms-auto\">\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Send aria-hidden=\"true\" />}\n >\n {t(key('signingRequest'))}\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n <DropdownMenu.Item\n startIcon={<MessageSquare aria-hidden=\"true\" />}\n disabled={patient?.smsEnabled === false}\n description={\n patient?.smsEnabled === false\n ? t(key('signingSmsDisabled'))\n : undefined\n }\n onSelect={() => request('sms')}\n >\n {t(key('signingViaSms'))}\n </DropdownMenu.Item>\n <DropdownMenu.Item\n startIcon={<Mail aria-hidden=\"true\" />}\n onSelect={() => request('email')}\n >\n {t(key('signingViaEmail'))}\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n </span>\n <VisuallyHidden aria-live=\"polite\">{readout}</VisuallyHidden>\n </>\n );\n}\n\nexport function BacklogPanel({\n items,\n locale,\n seed,\n signRequests,\n onProcess,\n onFocusEvent,\n onConfirm,\n onRequestSignature,\n onScheduleWaiting,\n onRemoveWaiting,\n onFindSlotsForWaiting,\n onUpsertWaiting,\n quickView = false,\n onOpenEntryForm,\n onPlaceWaiting,\n}: {\n items: BacklogItem[];\n locale: string;\n /** A fresh tick preselects `type` — how every caller opens the queue\n * on one segment without reaching into panel state. */\n seed: { tick: number; type: BacklogFilter };\n /** Event id → the channel a signature request went out on this session. */\n signRequests: Record<string, CalendarSignChannel>;\n /** Dock the editor prefilled (Process booking, Assign operator). */\n onProcess: (prefill: EditorPrefill) => void;\n /** Ring the appointment on the grid so it is clear which one is meant. */\n onFocusEvent: (eventId: string) => void;\n /** Unconfirmed → confirmed, in place. */\n onConfirm: (eventId: string) => void;\n onRequestSignature: (eventId: string, channel: CalendarSignChannel) => void;\n onScheduleWaiting: (entry: CalendarWaitingEntry) => void;\n onRemoveWaiting: (entry: CalendarWaitingEntry) => void;\n /** Hand the entry to the find-free-slots tool, prefilled. */\n onFindSlotsForWaiting: (entry: CalendarWaitingEntry) => void;\n /** The entry form's Save — add (no id) or update (id) in the queue. */\n onUpsertWaiting: (draft: WaitingEntryDraft) => void;\n /** Increment 1: the platform's waiting-list quick views above the queue. */\n quickView?: boolean;\n /** Set = Add entry and the row's edit open the HOST's entry form (a\n * dialog) instead of the in-panel sub-view. */\n onOpenEntryForm?: (entry?: CalendarWaitingEntry) => void;\n /** Set = Schedule / Reschedule hands the entry to the host's placement\n * mode (create / move banner) instead of opening the editor at once. */\n onPlaceWaiting?: (entry: CalendarWaitingEntry) => void;\n}) {\n const { t } = useTranslation();\n const data = useCalendarData();\n const { t: tUi } = useTranslation();\n const key = (suffix: string): string => `calendarWorkspace.backlog.${suffix}`;\n const waitingKey = (suffix: string): string =>\n `calendarWorkspace.waitingList.${suffix}`;\n const { open: openSheet } = useSheetHost();\n const [filter, setFilter] = useState<BacklogFilter>(seed.type);\n const [query, setQuery] = useState('');\n /* Platform \"Visualizza:\" — only meaningful on the waiting segment. */\n const [quickViewId, setQuickViewId] = useState<WaitingQuickView>('all');\n const [readout, setReadout] = useState('');\n\n /* The entry form is a PanelSubview over the queue: the queue stays\n mounted beneath it, so its filter, search and scroll survive, and the\n subview hands focus back to whichever button opened it. */\n const [formOpen, setFormOpen] = useState(false);\n /* Kept while the subview leaves, so its title does not flip mid-exit. */\n const [formEntry, setFormEntry] = useState<CalendarWaitingEntry>();\n const openEntryForm = (entry?: CalendarWaitingEntry): void => {\n setFormEntry(entry);\n setFormOpen(true);\n };\n\n /* A caller's seed (header button, grid, tests) lands on its segment\n and back on the queue, even while the panel is already open. */\n const prevSeedTickRef = useRef(seed.tick);\n useEffect(() => {\n if (prevSeedTickRef.current === seed.tick) return;\n prevSeedTickRef.current = seed.tick;\n setFilter(seed.type);\n setFormOpen(false);\n }, [seed]);\n\n const counts = useMemo(() => backlogCounts(items), [items]);\n const quickViewActive = quickView && filter === 'waiting';\n const filtered = useMemo(() => {\n const base = filterBacklog(items, filter, query, data);\n return quickView && filter === 'waiting'\n ? filterWaitingQuickView(base, quickViewId, data)\n : base;\n }, [items, filter, query, quickView, quickViewId, data]);\n const typeLabel = (type: BacklogType): string =>\n t(\n key(\n type === 'booking'\n ? 'typeBooking'\n : type === 'waiting'\n ? 'typeWaiting'\n : type === 'unconfirmed'\n ? 'typeUnconfirmed'\n : type === 'noOperator'\n ? 'typeNoOperator'\n : 'typeSignature',\n ),\n );\n const segments: Array<{\n value: BacklogFilter;\n label: string;\n count: number;\n icon: ReactNode;\n }> = [\n {\n value: 'all',\n label: t(key('typeAll')),\n count: items.length,\n icon: <LayoutList aria-hidden=\"true\" />,\n },\n {\n value: 'booking',\n label: typeLabel('booking'),\n count: counts.booking,\n /* Globe — the kit's established online-booking glyph. */\n icon: <Globe aria-hidden=\"true\" />,\n },\n {\n value: 'waiting',\n label: typeLabel('waiting'),\n count: counts.waiting,\n icon: <Hourglass aria-hidden=\"true\" />,\n },\n {\n value: 'unconfirmed',\n label: typeLabel('unconfirmed'),\n count: counts.unconfirmed,\n icon: <CircleDashed aria-hidden=\"true\" />,\n },\n {\n value: 'noOperator',\n label: typeLabel('noOperator'),\n count: counts.noOperator,\n icon: <Stethoscope aria-hidden=\"true\" />,\n },\n {\n value: 'signature',\n label: typeLabel('signature'),\n count: counts.signature,\n icon: <PenLine aria-hidden=\"true\" />,\n },\n ];\n\n const renderRow = (item: BacklogItem): ReactNode => {\n const ref = backlogPatientRef(item, data);\n const patient = ref.record;\n /* An occupancy-first host draws a row before it knows whose it is;\n the queue says so rather than print a blank headline. */\n const pendingDetails = tUi('calendar.eventKind.pendingDetails');\n switch (item.type) {\n case 'booking': {\n const { row } = item;\n const note = data.bookingNotes[row.event.id];\n return (\n <BacklogRow\n key={item.id}\n name={backlogName(item, data, pendingDetails) ?? ''}\n avatarName={row.event.title}\n when={<BacklogWhen iso={item.startIso} locale={locale} />}\n actions={\n <Button\n size=\"sm\"\n intent=\"outline\"\n onClick={() => {\n /* Seed the editor for THIS event (edit mode) with the\n booking's typed details, then ring it on the grid. */\n onProcess(processBookingPrefill(row, data));\n onFocusEvent(row.event.id);\n openSheet('appointment-editor');\n }}\n >\n {t(key('processBooking'))}\n </Button>\n }\n >\n {typeof row.event.suffix === 'string' ? (\n <span className=\"type-body-sm ds:text-start ds:text-[color:var(--muted-foreground)]\">\n {row.event.suffix}\n </span>\n ) : null}\n {note ? (\n <span className=\"type-body-sm ds:text-start ds:text-[color:var(--muted-foreground)]\">\n {note}\n </span>\n ) : null}\n </BacklogRow>\n );\n }\n case 'waiting': {\n const { entry } = item;\n const appointment = waitingEntryAppointment(entry, data);\n const operator = data.operators.find(\n (o) => o.id === (entry.operatorId ?? appointment?.meta?.operatorId),\n );\n /* Platform row: appointment-linked entries show the linked\n appointment's care as their description. */\n const description = appointment\n ? appointment.meta?.care\n : patient\n ? entry.description\n : undefined;\n return (\n <BacklogRow\n key={item.id}\n /* \"No patient linked\" is an EXISTENCE claim, so it is\n reachable only when the entry carries NO patient id.\n An id we could not resolve names itself instead — the row\n is linked to somebody, and printing the unbooked label\n over it is the same lie the Appointments panel used to\n tell. */\n name={\n backlogName(item, data) ??\n (ref.assigned\n ? t('calendarWorkspace.details.patientNotLoaded')\n : t(waitingKey('noPatient')))\n }\n avatarName={patient?.name}\n avatarSrc={patient?.avatarSrc}\n when={t(waitingKey('since'), {\n date: formatDay(locale, data.waitingSinceIso(entry)),\n })}\n actions={\n <>\n <Button\n size=\"sm\"\n intent=\"outline\"\n onClick={() => {\n /* Increment 1 hands the entry to the page's placement\n mode; the rail seeds the create editor from it and\n Bring forward re-opens the linked appointment. */\n if (onPlaceWaiting) {\n onPlaceWaiting(entry);\n return;\n }\n onScheduleWaiting(entry);\n openSheet('appointment-editor');\n }}\n >\n {t(\n waitingKey(entry.appointmentId ? 'reschedule' : 'schedule'),\n )}\n </Button>\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n icon={<CalendarSearch />}\n aria-label={t('calendarWorkspace.actions.findFreeSlots')}\n tooltip={t('calendarWorkspace.actions.findFreeSlots')}\n onClick={() => {\n onFindSlotsForWaiting(entry);\n openSheet('find-slots');\n }}\n />\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n icon={<Pencil />}\n aria-label={t(waitingKey('edit'))}\n tooltip={\n entry.appointmentId\n ? t(waitingKey('editLinkedDisabled'))\n : t(waitingKey('edit'))\n }\n /* Platform parity: a linked entry's fields belong to its\n appointment — the row stays read-only. */\n disabled={!!entry.appointmentId}\n data-entry-edit={entry.id}\n onClick={() => {\n if (onOpenEntryForm) {\n onOpenEntryForm(entry);\n return;\n }\n openEntryForm(entry);\n }}\n />\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n icon={<Trash2 />}\n aria-label={t(waitingKey('remove'))}\n tooltip={t(waitingKey('remove'))}\n onClick={() => onRemoveWaiting(entry)}\n />\n {/* Glyph-only brand circle, end-aligned — the FAB variant\n resolves its own concise aria-label. */}\n <span className=\"ds:ms-auto\">\n <WhatsAppButton\n variant=\"fab\"\n size=\"sm\"\n phoneNumber={\n entry.whatsappCapable ? (patient?.phone ?? '') : ''\n }\n title={\n entry.whatsappCapable && patient?.phone\n ? undefined\n : t(whatsAppUnavailableKey(ref))\n }\n />\n </span>\n </>\n }\n >\n {appointment ? (\n <span className={BACKLOG_LINE_CLASS}>\n <CalendarDays\n size={14}\n aria-hidden=\"true\"\n className=\"ds:shrink-0\"\n />\n {t(waitingKey('appointmentOn'), {\n date: formatDay(locale, appointment.event.start),\n })}\n </span>\n ) : null}\n {operator ? (\n <span className={BACKLOG_LINE_CLASS}>\n <Stethoscope\n size={14}\n aria-hidden=\"true\"\n className=\"ds:shrink-0\"\n />\n {operator.title}\n </span>\n ) : null}\n {description ? (\n <span className=\"type-body-sm ds:text-start ds:text-[color:var(--muted-foreground)]\">\n {description}\n </span>\n ) : null}\n </BacklogRow>\n );\n }\n case 'unconfirmed': {\n const { row } = item;\n return (\n <BacklogRow\n key={item.id}\n name={backlogName(item, data, pendingDetails) ?? ''}\n avatarName={patient?.name}\n avatarSrc={patient?.avatarSrc}\n when={<BacklogWhen iso={item.startIso} locale={locale} />}\n actions={\n <>\n <Button\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Check aria-hidden=\"true\" />}\n onClick={() => {\n onConfirm(row.event.id);\n setReadout(\n t(key('confirmedReadout'), { name: row.event.title }),\n );\n }}\n >\n {t(key('confirm'))}\n </Button>\n {/* No send-reminder group: all three channels here are\n demo fakes — no host handler stands behind WhatsApp,\n SMS or e-mail — so the group is withheld rather than\n offered and left to announce a send that never\n happened. */}\n </>\n }\n >\n <span className={BACKLOG_LINE_CLASS}>\n <Badge size=\"sm\" variant=\"warning\">\n {tUi(STATUS_UI_KEY.waiting)}\n </Badge>\n {typeof row.event.suffix === 'string' ? (\n <span className=\"ds:truncate ds:text-[color:var(--muted-foreground)]\">\n {row.event.suffix}\n </span>\n ) : null}\n </span>\n </BacklogRow>\n );\n }\n case 'noOperator': {\n const { row } = item;\n return (\n <BacklogRow\n key={item.id}\n name={backlogName(item, data, pendingDetails) ?? ''}\n avatarName={patient?.name}\n avatarSrc={patient?.avatarSrc}\n when={<BacklogWhen iso={item.startIso} locale={locale} />}\n actions={\n <Button\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Stethoscope aria-hidden=\"true\" />}\n onClick={() => {\n onProcess(assignOperatorPrefill(row));\n onFocusEvent(row.event.id);\n openSheet('appointment-editor');\n }}\n >\n {t(key('assignOperator'))}\n </Button>\n }\n >\n {typeof row.event.suffix === 'string' ? (\n <span className=\"type-body-sm ds:text-start ds:text-[color:var(--muted-foreground)]\">\n {row.event.suffix}\n </span>\n ) : null}\n </BacklogRow>\n );\n }\n case 'signature': {\n const { row } = item;\n return (\n <BacklogRow\n key={item.id}\n name={backlogName(item, data, pendingDetails) ?? ''}\n avatarName={patient?.name}\n avatarSrc={patient?.avatarSrc}\n when={<BacklogWhen iso={item.startIso} locale={locale} />}\n actions={\n <SignatureRequestMenu\n row={row}\n patient={patient}\n requestedVia={\n signRequests[row.event.id] ??\n data.metaById[row.event.id]?.signRequestedVia\n }\n onRequest={onRequestSignature}\n />\n }\n >\n <span\n className={`${BACKLOG_LINE_CLASS} ds:font-[var(--font-weight-semibold)] ds:text-[color:var(--warning-foreground)]`}\n >\n <PenLine size={14} aria-hidden=\"true\" className=\"ds:shrink-0\" />\n {item.toSign === 1\n ? t('calendarWorkspace.details.signingToSignOne')\n : t('calendarWorkspace.details.signingToSignMany', {\n n: item.toSign,\n })}\n </span>\n </BacklogRow>\n );\n }\n }\n };\n\n const emptyFor = (\n type: BacklogFilter,\n ): { title: string; description: string } => {\n const suffix =\n type === 'all'\n ? 'All'\n : type === 'booking'\n ? 'Booking'\n : type === 'waiting'\n ? 'Waiting'\n : type === 'unconfirmed'\n ? 'Unconfirmed'\n : type === 'noOperator'\n ? 'NoOperator'\n : 'Signature';\n return {\n title: t(key(`empty${suffix}Title`)),\n description: t(key(`empty${suffix}Description`)),\n };\n };\n const empty = emptyFor(filter);\n const groups = BACKLOG_TYPES.map((type) => ({\n type,\n rows: filtered.filter((item) => item.type === type),\n })).filter((g) => g.rows.length > 0);\n\n return (\n <div\n data-component=\"calendar-backlog\"\n className=\"ds:flex ds:h-full ds:flex-col\"\n >\n <PanelSubview.Host>\n {/* Same chrome as every other rail panel: the sticky PanelHeader owns\n the title row (Add entry, then the rail's injected actions); the\n segmented type strip and the search ride its filters row so they\n stay visible as the queue scrolls. */}\n <PanelHeader\n title={t(key('tool'))}\n icon={<LayoutList aria-hidden=\"true\" />}\n sticky\n divider\n actions={\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n icon={<Plus aria-hidden=\"true\" />}\n aria-label={t(waitingKey('addEntry'))}\n tooltip={t(waitingKey('addEntry'))}\n onClick={() => {\n if (onOpenEntryForm) {\n onOpenEntryForm();\n return;\n }\n openEntryForm();\n }}\n />\n }\n filters={\n <div className=\"ds:flex ds:w-full ds:flex-col ds:gap-[var(--spacing-xs)]\">\n {/* One joined strip; in a narrow rail the labels fold to their\n glyph + count first, then trailing segments spill into the\n overflow menu — never a second line. */}\n <ButtonGroup\n label={t(key('typeFilter'))}\n overflow=\"menu\"\n collapseToIcons\n >\n {segments.map((segment) => {\n const active = filter === segment.value;\n return (\n <Button\n key={segment.value}\n size=\"sm\"\n startIcon={segment.icon}\n endIcon={\n <Badge size=\"sm\" variant={active ? 'brand' : 'neutral'}>\n {segment.count}\n </Badge>\n }\n aria-pressed={active}\n aria-label={t(key('typeCount'), {\n type: segment.label,\n n: segment.count,\n })}\n onClick={() => setFilter(segment.value)}\n >\n {segment.label}\n </Button>\n );\n })}\n </ButtonGroup>\n {quickViewActive ? (\n <Select\n size=\"sm\"\n aria-label={t(key('quickView'))}\n options={WAITING_QUICK_VIEWS.map((view) => ({\n value: view,\n label: t(key(WAITING_QUICK_VIEW_LABEL_KEY[view])),\n }))}\n value={quickViewId}\n onValueChange={(next) => {\n if (next) setQuickViewId(next);\n }}\n />\n ) : null}\n {/* `onInput` (raw) rather than the debounced `onChange`: a\n handful of rows need no debounce, and the filter answers\n keystrokes. */}\n <SearchInput\n size=\"sm\"\n variant=\"inline\"\n value={query}\n onInput={setQuery}\n aria-label={t(key('searchLabel'))}\n placeholder={t(key('searchPlaceholder'))}\n />\n </div>\n }\n />\n {/* The queue owns its scroll: the Host is a clipped box, so the\n header stays put and the subview covers exactly this panel. */}\n <ScrollArea orientation=\"vertical\" className=\"ds:min-h-0 ds:flex-1\">\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:p-[var(--spacing-md)]\">\n {filtered.length === 0 ? (\n query.trim() || (quickViewActive && quickViewId !== 'all') ? (\n <EmptyState\n variant=\"no-results\"\n size=\"sm\"\n title={t(key('noResultsTitle'))}\n description={t(key('noResultsDescription'))}\n />\n ) : (\n <EmptyState\n variant=\"first-use\"\n size=\"sm\"\n title={empty.title}\n description={empty.description}\n />\n )\n ) : filter === 'all' ? (\n groups.map((group) => (\n <section\n key={group.type}\n aria-label={typeLabel(group.type)}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\"\n >\n <h3 className=\"type-label ds:m-0 ds:flex ds:items-center ds:gap-[var(--spacing-xs)] ds:uppercase ds:text-start ds:text-[color:var(--muted-foreground)]\">\n {typeLabel(group.type)}\n <Badge\n size=\"sm\"\n variant=\"neutral\"\n aria-label={String(group.rows.length)}\n >\n {group.rows.length}\n </Badge>\n </h3>\n {/* eslint-disable-next-line jsx-a11y/no-redundant-roles -- role=\"list\" is NOT redundant: WebKit drops implicit list semantics when list-style is none */}\n <ul\n role=\"list\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n {group.rows.map(renderRow)}\n </ul>\n </section>\n ))\n ) : (\n /* eslint-disable-next-line jsx-a11y/no-redundant-roles -- role=\"list\" is NOT redundant: WebKit drops implicit list semantics when list-style is none */\n <ul\n role=\"list\"\n aria-label={typeLabel(filter)}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n {filtered.map(renderRow)}\n </ul>\n )}\n </div>\n </ScrollArea>\n <VisuallyHidden aria-live=\"polite\">{readout}</VisuallyHidden>\n {onOpenEntryForm ? null : (\n <WaitingListEntrySubview\n open={formOpen}\n entry={formEntry}\n onSave={(draft) => {\n onUpsertWaiting(draft);\n setFormOpen(false);\n }}\n onCancel={() => setFormOpen(false)}\n />\n )}\n </PanelSubview.Host>\n </div>\n );\n}\n\nconst bookingKey = (suffix: string): string =>\n `calendarWorkspace.inc1.bookings.${suffix}`;\n\n/* ------------------------------------------------------------------ */\n/* BookingsPanel — the platform's \"Prenotazioni online\" page, hosted in */\n/* the rail. Same columns and the same row actions: every one opens the */\n/* editor to complete the booking. The page itself survives, because */\n/* the booking e-mail and the top-bar notification both link to it. */\n/* ------------------------------------------------------------------ */\n\nexport function BookingsPanel({\n bookings,\n locale,\n privacy = false,\n status = 'ready',\n lastSeenIso,\n createdAtById,\n currentBookingId,\n currentBookingKey,\n onRetry,\n onShowInCalendar,\n onComplete,\n}: {\n bookings: readonly CalendarRow[];\n locale?: string;\n /** Masks the patient names, in step with the grid. */\n privacy?: boolean;\n status?: 'loading' | 'ready' | 'error';\n lastSeenIso?: string | null;\n createdAtById?: Readonly<Record<string, string>>;\n /** The booking the host is addressing: scrolled to, focused, and ringed\n * in the accent until the ring settles. Unknown ids are ignored. */\n currentBookingId?: string;\n /** Bump on every address, so the SAME booking addressed twice scrolls,\n * focuses and rings again. An address is a request, not a value. */\n currentBookingKey?: string | number;\n onRetry?: () => void;\n /** Steers the grid to the booking and rings its card. */\n onShowInCalendar: (eventId: string) => void;\n /** Opens the editor to complete it (platform \"Completa appuntamento\").\n * `intent` says which assign segment was pressed; the pencil sends none. */\n onComplete?: (row: CalendarRow, intent?: BookingCompleteIntent) => void;\n}) {\n const { t } = useTranslation();\n const data = useCalendarData();\n const views = useMemo(\n () =>\n bookings.map((row) =>\n bookingRowView(\n row,\n data,\n lastSeenIso ? new Date(lastSeenIso).getTime() : null,\n createdAtById?.[row.event.id],\n ),\n ),\n [bookings, data, lastSeenIso, createdAtById],\n );\n const currentCardRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n if (!currentBookingId) return;\n // `center`, as NotesPanel: `nearest` parks the card against the edge.\n currentCardRef.current?.scrollIntoView({ block: 'center' });\n currentCardRef.current?.focus();\n }, [currentBookingId, currentBookingKey]);\n return (\n <div\n data-component=\"calendar-bookings\"\n data-status={status}\n className=\"ds:flex ds:h-full ds:flex-col\"\n >\n <PanelHeader\n title={t(bookingKey('title'))}\n icon={<Globe aria-hidden=\"true\" />}\n sticky\n divider\n />\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:p-[var(--spacing-md)]\">\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t(bookingKey('intro'))}\n </p>\n {status === 'loading' ? (\n <>\n <p role=\"status\" className=\"ds:sr-only\">\n {t('common.loading')}\n </p>\n {/* A first read has no cards to keep on screen, so it shows where\n they will land, in the card's own shape. A refresh keeps the\n cards it has and only marks the list busy. */}\n {views.length === 0 ? <BookingCardsSkeleton /> : null}\n </>\n ) : status === 'error' ? (\n <Alert variant=\"error\">\n <Alert.Description>\n {t('emptyState.error.description')}\n </Alert.Description>\n {onRetry ? (\n <Button size=\"sm\" intent=\"outline\" onClick={onRetry}>\n {t('emptyState.error.cta')}\n </Button>\n ) : null}\n </Alert>\n ) : null}\n {views.length === 0 ? (\n status === 'ready' ? (\n <EmptyState\n variant=\"first-use\"\n size=\"sm\"\n title={t(bookingKey('emptyTitle'))}\n />\n ) : null\n ) : (\n // eslint-disable-next-line jsx-a11y/no-redundant-roles -- role=\"list\" is NOT redundant: WebKit drops implicit list semantics when list-style is none\n <ul\n role=\"list\"\n aria-busy={status === 'loading'}\n className=\"ds:m-0 ds:flex ds:list-none ds:flex-col ds:gap-[var(--spacing-sm)] ds:p-0\"\n >\n {views.map((view) => {\n const addressed = view.eventId === currentBookingId;\n return (\n /* No <li> wrapper: the card is its own role=\"listitem\". */\n <BookingCard\n key={view.eventId}\n ref={addressed ? currentCardRef : undefined}\n view={view}\n locale={locale}\n privacy={privacy}\n canComplete={Boolean(onComplete) && status === 'ready'}\n onComplete={onComplete}\n onShowInCalendar={onShowInCalendar}\n addressed={addressed}\n addressKey={currentBookingKey}\n />\n );\n })}\n </ul>\n )}\n </div>\n </div>\n );\n}\n\n/* The waiting-list panel itself lives in `calendar-waiting-list-panel.tsx`;\n the entry form below is shared by it, the Backlog and the tool-level form. */\n/* One form state behind both chromes: the tool-level form the workspace\n docks and the PanelSubview the Backlog slides over its queue. */\nfunction useWaitingEntryForm({\n entry,\n readOnly,\n onSave,\n}: {\n entry?: CalendarWaitingEntry;\n readOnly: boolean;\n onSave: (draft: WaitingEntryDraft) => void;\n}) {\n const [patientId, setPatientId] = useState(entry?.patientId ?? '');\n const [operatorId, setOperatorId] = useState(entry?.operatorId ?? NONE);\n const [colorHex, setColorHex] = useState(\n entry?.colorHex ?? GOOGLE_CALENDAR_PALETTE[6].hex,\n );\n const [description, setDescription] = useState(entry?.description ?? '');\n /* Shown on a refused submit; any patient/description edit clears it\n (the platform's `useEffect(() => setError(false), [...])`). */\n const [showError, setShowError] = useState(false);\n\n /* Refill without remounting: a subview that mounts already open has no\n entrance to play and no trigger to hand focus back to. */\n const reset = useCallback((next?: CalendarWaitingEntry) => {\n setPatientId(next?.patientId ?? '');\n setOperatorId(next?.operatorId ?? NONE);\n setColorHex(next?.colorHex ?? GOOGLE_CALENDAR_PALETTE[6].hex);\n setDescription(next?.description ?? '');\n setShowError(false);\n }, []);\n\n const submit = (): void => {\n /* Backstop to the withheld Save: the host seam behind `onSave` is\n inert without the edit permission, and calling it would close this\n form as though the queue had taken the entry. */\n if (readOnly) return;\n if (!waitingEntryIsValid({ patientId, description })) {\n setShowError(true);\n return;\n }\n onSave({\n id: entry?.id,\n patientId: patientId || undefined,\n operatorId: operatorId === NONE ? undefined : operatorId,\n colorHex,\n description: description.trim() || undefined,\n });\n };\n\n return {\n patientId,\n setPatientId,\n operatorId,\n setOperatorId,\n colorHex,\n setColorHex,\n description,\n setDescription,\n showError,\n setShowError,\n reset,\n submit,\n };\n}\n\n/** The four fields and the refused-submit error, shared by both chromes. */\nfunction WaitingEntryFields({\n form,\n entry,\n readOnly,\n}: {\n form: ReturnType<typeof useWaitingEntryForm>;\n entry?: CalendarWaitingEntry;\n readOnly: boolean;\n}) {\n const data = useCalendarData();\n const { t } = useTranslation();\n /* The REF, not the record: an entry that carries an id IS linked even\n when the host's `patientById` could not answer, and the combobox\n below is the one control that decides that answer. */\n const formRef = patientRefById(form.patientId, data);\n /* What to CALL the linked patient when the options cannot: the record,\n else the entry's own description, else the honest \"not loaded\" —\n the same three steps the queue row and its commands already take. */\n const formPatientLabel = patientRefName(\n formRef,\n entry?.description,\n t('calendarWorkspace.details.patientNotLoaded'),\n );\n return (\n <>\n {/* One disabled fieldset locks all four fields at once — the same\n idiom the appointment editor uses at `EDITOR_FORM_GRID`. */}\n <fieldset\n disabled={readOnly}\n className=\"ds:m-0 ds:flex ds:min-w-0 ds:flex-col ds:gap-[var(--spacing-md)] ds:border-0 ds:p-0\"\n >\n {readOnly ? (\n <Alert\n variant=\"info\"\n announce=\"off\"\n icon={<Lock aria-hidden=\"true\" />}\n >\n <Alert.Title as=\"p\">\n {t('calendarWorkspace.details.readOnlyTitle')}\n </Alert.Title>\n <Alert.Description>\n {t('calendarWorkspace.inc1.readOnly.waitingLockedBody')}\n </Alert.Description>\n </Alert>\n ) : null}\n <FormField label={t('calendarWorkspace.editor.patient')}>\n <CalendarPatientPicker\n value={form.patientId}\n selectedLabel={formPatientLabel}\n onValueChange={(value) => {\n form.setPatientId(value);\n form.setShowError(false);\n }}\n />\n </FormField>\n <FormField label={t('calendarWorkspace.details.operator')}>\n <Select\n options={[\n {\n value: NONE,\n label: t('calendarWorkspace.editor.unassigned'),\n },\n ...activeOperators(data).map((o) => ({\n value: o.id,\n label: o.title,\n })),\n ]}\n value={form.operatorId}\n onValueChange={form.setOperatorId}\n />\n </FormField>\n <FormField label={t('calendarWorkspace.details.color')}>\n <ColorPicker\n variant=\"inline\"\n compact\n size=\"sm\"\n palette={\n data.appointmentPalette?.slice() ?? GOOGLE_CALENDAR_PALETTE\n }\n value={form.colorHex}\n onChange={form.setColorHex}\n />\n </FormField>\n <FormField label={t('calendarWorkspace.editor.description')}>\n <TextArea\n value={form.description}\n onChange={(e) => {\n form.setDescription(e.target.value);\n form.setShowError(false);\n }}\n minRows={2}\n autoResize\n />\n </FormField>\n </fieldset>\n {form.showError ? (\n <Alert variant=\"error\">\n <Alert.Description>\n {t('calendarWorkspace.waitingList.formError')}\n </Alert.Description>\n </Alert>\n ) : null}\n </>\n );\n}\n\n/**\n * The platform's waiting-list AddModal as a rail sub-view — same field\n * order (patient, operator, colour, description) and its one rule:\n * a patient OR a description, checked on submit with an inline error.\n */\nexport function WaitingListEntryForm({\n entry,\n onSave,\n onCancel,\n chrome = 'panel',\n readOnly = false,\n}: {\n /** Set = edit this entry; unset = add a new one. */\n entry?: CalendarWaitingEntry;\n onSave: (draft: WaitingEntryDraft) => void;\n onCancel: () => void;\n /** No edit permission: the fields lock, Save is withheld and `submit`\n * refuses — the same three layers the appointment editor uses, so no\n * path can close this form as if a queue entry had been written. */\n readOnly?: boolean;\n /** `'dialog'` drops the rail's back arrow — the dialog's own Close and\n * the form's Cancel already dismiss it. */\n chrome?: 'panel' | 'dialog';\n}) {\n const { t } = useTranslation();\n const key = (suffix: string): string =>\n `calendarWorkspace.waitingList.${suffix}`;\n const headerRef = useRef<HTMLElement>(null);\n useEffect(() => {\n headerRef.current?.focus();\n }, []);\n const form = useWaitingEntryForm({ entry, readOnly, onSave });\n\n return (\n <>\n <PanelHeader\n ref={headerRef}\n tabIndex={-1}\n title={t(key(entry ? 'editTitle' : 'addTitle'))}\n icon={<Hourglass aria-hidden=\"true\" />}\n sticky\n divider\n actions={\n chrome === 'panel' ? (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<ArrowLeft aria-hidden=\"true\" />}\n flipIconInRtl\n aria-label={t(key('back'))}\n tooltip={t(key('back'))}\n onClick={onCancel}\n />\n ) : undefined\n }\n />\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)] ds:p-[var(--spacing-md)]\">\n <WaitingEntryFields form={form} entry={entry} readOnly={readOnly} />\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n {/* Withheld, not disabled — the same call the editor makes at\n its own action bar. Cancel stays: leaving is always allowed. */}\n {readOnly ? null : (\n <Button\n size=\"sm\"\n intent=\"primary\"\n startIcon={<Save aria-hidden=\"true\" />}\n onClick={form.submit}\n >\n {t(key(entry ? 'formSave' : 'formAdd'))}\n </Button>\n )}\n <Button size=\"sm\" intent=\"outline\" onClick={onCancel}>\n {t('calendarWorkspace.editor.cancel')}\n </Button>\n </div>\n </div>\n </>\n );\n}\n\n/**\n * The same entry form as a `PanelSubview`: it slides over the queue it was\n * opened from, pins Cancel and Save, and hands focus back to the opener.\n */\nexport function WaitingListEntrySubview({\n open,\n entry,\n onSave,\n onCancel,\n readOnly = false,\n}: {\n open: boolean;\n /** Set = edit this entry; unset = add a new one. */\n entry?: CalendarWaitingEntry;\n onSave: (draft: WaitingEntryDraft) => void;\n onCancel: () => void;\n readOnly?: boolean;\n}) {\n const { t } = useTranslation();\n const key = (suffix: string): string =>\n `calendarWorkspace.waitingList.${suffix}`;\n const form = useWaitingEntryForm({ entry, readOnly, onSave });\n /* Filled on OPEN, never by a new `key`: it fills while the subview is\n still transparent, so the swap is never seen. */\n const { reset } = form;\n useEffect(() => {\n if (open) reset(entry);\n }, [open, entry, reset]);\n\n return (\n <PanelSubview\n open={open}\n onBack={onCancel}\n icon={<Hourglass aria-hidden=\"true\" />}\n title={t(key(entry ? 'editTitle' : 'addTitle'))}\n backLabel={t(key('back'))}\n data-waiting-entry-form=\"\"\n footer={\n <>\n <Button intent=\"secondary\" onClick={onCancel}>\n {t('calendarWorkspace.editor.cancel')}\n </Button>\n {/* Withheld, not disabled, as on the tool-level form. */}\n {readOnly ? null : (\n <Button\n intent=\"primary\"\n data-action=\"save-waiting-entry\"\n onClick={form.submit}\n >\n {t(key(entry ? 'formSave' : 'formAdd'))}\n </Button>\n )}\n </>\n }\n >\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)] ds:p-[var(--spacing-md)]\">\n <WaitingEntryFields form={form} entry={entry} readOnly={readOnly} />\n </div>\n </PanelSubview>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Day-print call sheet — the portalled DataTable sheet that renders */\n/* `buildPrintSheet` (calendar.model.ts); print-only, never the grid. */\n/* ------------------------------------------------------------------ */\n\nfunction PrintPatientCell({ data }: CustomCellRendererProps<PrintRow>) {\n const { t } = useTranslation();\n if (!data) return null;\n return (\n <div className=\"ds:flex ds:flex-col ds:whitespace-normal type-body-sm\">\n <span className=\"ds:font-[var(--font-weight-semibold)]\">\n {data.patientName}\n </span>\n {data.phones.map((phone) => (\n <span key={`${phone.label}:${phone.number}`}>\n {t(`calendarWorkspace.print.phoneLabels.${phone.label}`)}:{' '}\n <span dir=\"ltr\">{phone.number}</span>\n </span>\n ))}\n {data.unassigned ? (\n <span>{t('calendarWorkspace.print.bookedOnline')}</span>\n ) : null}\n </div>\n );\n}\n\nfunction PrintCaresCell({ data }: CustomCellRendererProps<PrintRow>) {\n const { t } = useTranslation();\n if (!data) return null;\n return (\n <div className=\"ds:flex ds:flex-col ds:whitespace-normal type-body-sm\">\n {data.description ? <span>{data.description}</span> : null}\n {data.careLines.map((care, index) => (\n <Fragment key={`${care.careId ?? care.name}-${index}`}>\n <span>{care.name}</span>\n {care.elements && care.elements.length > 0 ? (\n <span>\n {t('calendarWorkspace.print.onElements', {\n elements: care.elements.join(', '),\n })}\n </span>\n ) : null}\n </Fragment>\n ))}\n </div>\n );\n}\n\n/* Plain axis only: chair over operator, so the sheet keeps its width. */\nfunction PrintAllocationCell({ data }: CustomCellRendererProps<PrintRow>) {\n const practice = useCalendarData();\n if (!data) return null;\n return (\n <div className=\"ds:flex ds:flex-col ds:whitespace-normal type-body-sm\">\n <span>\n {practice.chairs.find((c) => c.id === data.chairId)?.title ?? '—'}\n </span>\n <span>\n {practice.operators.find((o) => o.id === data.operatorId)?.title ?? '—'}\n </span>\n </div>\n );\n}\n\n/**\n * The call sheet itself. A portal to `document.body`: the shell's AppFrame\n * is an `h-dvh overflow-hidden` clamp that prints one screenful, so the\n * sheet lives outside it — hidden on screen, the only thing on paper.\n */\nexport function PrintSheet({\n sections,\n rangeTitle,\n axisKind,\n visibleChairIds,\n visibleOperatorIds,\n privacy,\n locale,\n}: {\n sections: PrintDaySection[];\n rangeTitle: string;\n axisKind: DisplaySettings['resourceKind'];\n visibleChairIds: string[];\n visibleOperatorIds: string[];\n privacy: boolean;\n locale: string;\n}) {\n const data = useCalendarData();\n const { t } = useTranslation();\n const { t: tUi } = useTranslation();\n const key = (suffix: string): string => `calendarWorkspace.print.${suffix}`;\n\n /* Fixed pixel widths (measured against the longest fixture strings at\n 14px), never `flex`: the grid sits in a display:none subtree, so\n nothing may depend on measuring the container. A grouped axis drops\n its own column (the heading carries it); the plain axis stacks chair\n over operator. 700px in all, inside an A4 portrait's default margins. */\n const columnDefs = useMemo<ColDef<PrintRow>[]>(() => {\n const cols: ColDef<PrintRow>[] = [\n {\n colId: 'time',\n headerName: t(key('columns.time')),\n width: 110,\n valueGetter: (p) =>\n !p.data\n ? ''\n : p.data.allDay\n ? tUi('calendar.allDay')\n : formatTimeRange(locale, p.data.start, p.data.end),\n },\n {\n colId: 'patient',\n headerName: t(key('columns.patient')),\n width: 192,\n cellRenderer: PrintPatientCell,\n },\n {\n colId: 'cares',\n headerName: t(key('columns.cares')),\n width: 176,\n cellRenderer: PrintCaresCell,\n },\n ];\n if (axisKind === 'chair') {\n cols.push({\n colId: 'operator',\n headerName: t(key('columns.operator')),\n width: 132,\n valueGetter: (p) =>\n data.operators.find((o) => o.id === p.data?.operatorId)?.title ?? '—',\n });\n } else if (axisKind === 'operator') {\n cols.push({\n colId: 'chair',\n headerName: t(key('columns.chair')),\n width: 64,\n valueGetter: (p) =>\n data.chairs.find((c) => c.id === p.data?.chairId)?.title ?? '—',\n });\n } else {\n cols.push({\n colId: 'allocation',\n headerName: t(key('columns.allocation')),\n width: 132,\n cellRenderer: PrintAllocationCell,\n });\n }\n cols.push({\n colId: 'status',\n headerName: t(key('columns.status')),\n width: 90,\n valueGetter: (p) =>\n p.data?.status ? tUi(STATUS_UI_KEY[p.data.status]) : '',\n });\n return cols;\n }, [axisKind, locale, t, tUi, data]);\n const minLines = axisKind === 'none' ? 2 : 1;\n\n /* `domLayout: 'print'` wins over the kit's autoHeight (spread after it)\n and turns row + column virtualisation off, so every cell exists in\n the DOM before the browser snapshots the page. */\n const gridOptions = useMemo<GridOptions<PrintRow>>(\n () => ({\n domLayout: 'print',\n suppressColumnVirtualisation: true,\n suppressCellFocus: true,\n getRowId: (p) => p.data.id,\n getRowHeight: (p) => (p.data ? printRowHeight(p.data, minLines) : null),\n defaultColDef: {\n sortable: false,\n resizable: false,\n filter: false,\n floatingFilter: false,\n suppressHeaderMenuButton: true,\n suppressMovable: true,\n cellClass: PRINT_CELL_CLASS,\n headerClass: PRINT_CELL_CLASS,\n },\n }),\n [minLines],\n );\n\n if (typeof document === 'undefined') return null;\n\n const chairNames =\n visibleChairIds.length >= data.chairs.length\n ? t(key('allChairs'))\n : data.chairs\n .filter((c) => visibleChairIds.includes(c.id))\n .map((c) => c.title)\n .join(', ');\n const operators = activeOperators(data);\n const operatorNames =\n visibleOperatorIds.length >= operators.length\n ? t(key('allOperators'))\n : operators\n .filter((o) => visibleOperatorIds.includes(o.id))\n .map((o) => o.title)\n .join(', ');\n const noteLabel = (note: PrintDayNote): string => {\n switch (note.kind) {\n case 'closed':\n return t('calendarWorkspace.print.closedDay');\n case 'holiday':\n return t('calendarWorkspace.closures.holidayBanner', {\n name: note.name,\n });\n case 'nonWorking':\n return t(key('closedDay'));\n case 'absence': {\n const name =\n data.operators.find((o) => o.id === note.operatorId)?.title ?? '';\n return note.title\n ? t(key('absenceTitled'), { name, title: note.title })\n : t(key('absence'), { name });\n }\n }\n };\n\n return createPortal(\n <section\n data-component=\"calendar-print-sheet\"\n aria-label={t(key('region'))}\n className=\"ds:hidden ds:print:block ds:bg-[color:var(--background)] ds:py-[var(--spacing-sm)] ds:text-[color:var(--foreground)]\"\n >\n <h1 className=\"type-title-page\">\n {t(key('heading'), { range: rangeTitle })}\n </h1>\n <p className=\"type-body-sm\">\n {tUi('calendar.resourceLabel.chairs')}: {chairNames} ·{' '}\n {tUi('calendar.resourceLabel.operators')}: {operatorNames}\n </p>\n {privacy ? <p className=\"type-body-sm\">{t(key('privacyNote'))}</p> : null}\n {sections.map((section, index) => {\n const dateIso = localIsoDate(section.date);\n const hasRows = section.groups.some((g) => g.rows.length > 0);\n return (\n <section\n key={dateIso}\n data-print-day={dateIso}\n /* A day with a table starts a fresh page; empty days are\n one-liners and stack. */\n className={\n hasRows && index > 0 ? 'ds:break-before-page' : undefined\n }\n >\n <h2 className=\"type-title-section ds:mt-[var(--spacing-md)]\">\n {formatDay(locale, section.date)}\n </h2>\n {hasRows ? (\n section.groups.map((group) => (\n <div\n key={group.id}\n className=\"ds:mt-[var(--spacing-sm)] ds:break-inside-avoid\"\n >\n {group.kind === 'all' ? null : (\n <h3 className=\"type-title-item\">\n {group.title ?? t(key('noOperator'))}\n </h3>\n )}\n {group.rows.length === 0 ? (\n <p className=\"type-body-sm\">{t(key('noAppointments'))}</p>\n ) : (\n /* AG Grid asks for a row's height once, when the node\n is created — a height signature in the key remounts\n the grid when masking or an edit changes a row. */\n <DataTable<PrintRow>\n key={group.rows\n .map((r) => printRowHeight(r, minLines))\n .join('.')}\n columnDefs={columnDefs}\n rowData={group.rows}\n printMode\n density=\"compact\"\n bordered\n gridId={`print-${dateIso}-${group.id}`}\n gridOptions={gridOptions}\n />\n )}\n </div>\n ))\n ) : (\n <p className=\"type-body-sm\">{t(key('noAppointments'))}</p>\n )}\n {section.tasks.length > 0 ? (\n <div className=\"type-body-sm ds:mt-[var(--spacing-sm)]\">\n <p>{t(key('tasks'), { n: section.tasks.length })}</p>\n <ul className=\"ds:m-0 ds:list-none ds:p-0\">\n {section.tasks.map((task) => (\n <li key={task.id}>\n {task.allDay\n ? tUi('calendar.allDay')\n : formatTimeRange(locale, task.start)}{' '}\n · {task.title}\n </li>\n ))}\n </ul>\n </div>\n ) : null}\n {section.notes.map((note) => (\n <p\n key={`${note.kind}-${note.kind === 'absence' ? note.operatorId : ''}`}\n className=\"type-body-sm\"\n >\n {noteLabel(note)}\n </p>\n ))}\n </section>\n );\n })}\n </section>,\n document.body,\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Find free slots — the platform's FindFreeSlots app (a modal there) */\n/* redesigned as a rail tool: picking a care derives duration + the */\n/* eligible operators/chairs + the appointment colour; the search runs */\n/* in memory over the demo week against the practice business hours */\n/* (data.businessHours); closed dates, holidays and an operator's */\n/* absence days yield no slots, and the empty state says why when the */\n/* range itself is the reason; Book prefills the rail editor and */\n/* navigates the grid to the slot. Platform-only depth (cross-practice */\n/* search and operator weekly hours) deliberately stays behind; the */\n/* medical device, the look-ahead ceiling, the +30-day pager, the */\n/* business-hours advisory and the grouped multi-select operator and */\n/* chair scope all arrive with the `platform` prop. */\n/* ------------------------------------------------------------------ */\n\n/** Panel-list canon: an elevated card per slot row. */\nconst FREE_SLOT_CARD_CLASS =\n 'ds:flex ds:items-center ds:gap-[var(--spacing-xs)] ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--card-border)] ds:[.theme-accessible_&]:border-2 ds:bg-[color:var(--card)] ds:shadow-[var(--shadow-sm)] ds:p-[var(--spacing-xs)] ds:ps-[var(--spacing-sm)]';\n\n/** List-only mode makes the WHOLE row the affordance. */\nconst FREE_SLOT_BUTTON_CLASS = [\n FREE_SLOT_CARD_CLASS,\n 'ds:w-full ds:cursor-pointer ds:text-start ds:transition-colors',\n 'ds:hover:bg-[color:var(--muted)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n].join(' ');\n\n/** The platform depth the dialog host asks for (decision 6). Every field\n * is optional, so the rail keeps exactly the behaviour it had. */\nexport interface FindSlotsPlatformOptions {\n /** Results as clickable rows and NO grid projection — the dialog host. */\n listOnly?: boolean;\n /** Care id → medical devices it needs (`FIND_FREE_SLOTS_BY_CARE`). */\n devicesByCare?: Readonly<Record<string, readonly string[]>>;\n /** Warn past the platform's look-ahead ceiling; the search still runs. */\n maxRangeDays?: number;\n /** \"Show more slots\" pushes the To date out by this many days. */\n pagerStepDays?: number;\n /** Advisory: the practice has at least one business-hours row. */\n practiceHasBusinessHours?: boolean;\n /** Advisory: at least one operator has business-hours rows. */\n operatorsHaveBusinessHours?: boolean;\n /** The advisory's scheduler link. */\n onOpenScheduler?: () => void;\n /** Operator and chair scope as grouped checklists (the platform's\n * `OperatorDropdown` / `ChairDropdown`) instead of one Select plus\n * \"Any\". Nothing ticked means every eligible resource, exactly as\n * the platform's empty selection does server-side. */\n multiSelectScope?: boolean;\n /** Group sections for that operator checklist (platform\n * `GetGroupedOperatorService`); absent = one flat list. */\n operatorGroups?: readonly CalendarOperatorGroup[];\n}\n\n/** One section of a scope checklist; `name` null = an ungrouped flat list. */\ninterface ScopeSection {\n id: string;\n name: string | null;\n options: readonly CalendarResource[];\n}\n\n/**\n * The platform's `OperatorDropdown` / `ChairDropdown` as the kit's\n * Popover-checklist idiom — a MultiSelect would wrap its tags and reflow\n * the form under it. A \"Select all\" tri-state leads (the platform's\n * \"Seleziona / deseleziona tutti\"), then one tri-state per group over\n * its members. Nothing ticked means every option, so the trigger says\n * the scope rather than a count until a selection narrows it.\n */\nfunction ScopeChecklist({\n label,\n countLabel,\n hint,\n icon,\n sections,\n selected,\n onChange,\n}: {\n label: string;\n /** Trigger name while a selection narrows the scope. */\n countLabel: string;\n hint: string;\n icon: ReactNode;\n sections: readonly ScopeSection[];\n selected: readonly string[];\n onChange: (next: string[]) => void;\n}) {\n const { t } = useTranslation();\n const selectAll = t('calendarWorkspace.filters.selectAll');\n const allIds = sections.flatMap((section) =>\n section.options.map((option) => option.id),\n );\n const grouped = sections.some((section) => section.name !== null);\n const optionRow = (option: CalendarResource) => (\n <Checkbox\n key={option.id}\n label={option.title}\n checked={selected.includes(option.id)}\n onCheckedChange={(checked) =>\n onChange(toggleSelectedIds(selected, [option.id], checked))\n }\n />\n );\n\n return (\n <Popover>\n <Popover.Trigger asChild>\n <Button\n intent=\"outline\"\n startIcon={icon}\n endIcon={\n selected.length > 0 ? (\n <Badge size=\"sm\" variant=\"brand\">\n {selected.length}\n </Badge>\n ) : undefined\n }\n aria-label={selected.length > 0 ? countLabel : label}\n >\n {label}\n </Button>\n </Popover.Trigger>\n <Popover.Content align=\"start\" className=\"ds:w-72\">\n <Popover.Heading>{label}</Popover.Heading>\n <Popover.Description>{hint}</Popover.Description>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:pt-[var(--spacing-sm)]\">\n <Checkbox\n label={selectAll}\n checked={selectionState(selected, allIds)}\n onCheckedChange={(checked) =>\n onChange(toggleSelectedIds(selected, allIds, checked))\n }\n />\n {grouped\n ? sections.map((section) => {\n const memberIds = section.options.map((option) => option.id);\n return (\n <div\n key={section.id}\n role=\"group\"\n aria-label={section.name ?? label}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <Checkbox\n label={\n <>\n <span className=\"ds:font-[var(--font-weight-semibold)]\">\n {section.name}\n </span>\n <VisuallyHidden>{` · ${selectAll}`}</VisuallyHidden>\n </>\n }\n checked={selectionState(selected, memberIds)}\n onCheckedChange={(checked) =>\n onChange(\n toggleSelectedIds(selected, memberIds, checked),\n )\n }\n />\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:ps-[var(--spacing-md)]\">\n {section.options.map(optionRow)}\n </div>\n </div>\n );\n })\n : sections.flatMap((section) => section.options).map(optionRow)}\n </div>\n </Popover.Content>\n </Popover>\n );\n}\n\n/** How long a moved busy set settles before the server is asked again. */\nconst SERVER_SEARCH_DEBOUNCE_MS = 300;\n\n/** Everything about the rows that can make a published answer wrong:\n * which row, when it runs, whose time it takes. Tasks are excluded, as\n * in the in-memory search; title, colour and patient cannot make a free\n * minute busy, so a re-render of those must not cost a request. */\nfunction busySignature(rows: readonly CalendarRow[]): string {\n return rows\n .filter((row) => !row.event.isTask)\n .map((row) =>\n [\n row.event.id,\n String(row.event.start),\n String(row.event.end ?? ''),\n row.event.allDay === true ? '1' : '0',\n row.chairId ?? '',\n row.operatorId ?? '',\n ].join('|'),\n )\n .sort()\n .join(';');\n}\n\n/** Two answers to one search, slot for slot. */\nfunction sameFreeSlots(a: CalendarFreeSlot[], b: CalendarFreeSlot[]): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (\n a[i].start.getTime() !== b[i].start.getTime() ||\n a[i].durationMin !== b[i].durationMin ||\n a[i].chairId !== b[i].chairId ||\n a[i].operatorId !== b[i].operatorId\n ) {\n return false;\n }\n }\n return true;\n}\n\nexport function FindFreeSlotsPanel({\n rows,\n locale,\n seed,\n onBookSlot,\n onShowInCalendar,\n onSearchRange,\n platform,\n canBook = true,\n}: {\n rows: CalendarRow[];\n locale: string;\n /** Prefill context (the tool keys its panel by seed.tick). */\n seed?: FindSlotsSeed | null;\n onBookSlot: (prefill: EditorPrefill) => void;\n /** False for a viewer without the appointment-edit right: the slots\n * still list and project, but no row offers Book. */\n canBook?: boolean;\n /** Platform depth the rail never needed — absent = rail behaviour. */\n platform?: FindSlotsPlatformOptions;\n /** Project the found free ranges onto the grid (null = clear) — the\n * Calendar dims booked cards and glows the free ranges. The context\n * carries the seeded patient/care into grid-click bookings. */\n onShowInCalendar: (\n slots: CalendarFreeSlot[] | null,\n fromDate?: Date,\n context?: AvailabilityContext,\n ) => void;\n /** Retained for host compatibility; projection supports every grid axis. */\n gridAxis?: 'none' | 'chair' | 'operator';\n /**\n * The window a search is about to cover, raised BEFORE it runs.\n *\n * The projection's busy set is `rows` and nothing else, so a host whose rows\n * cover only the visible grid would have this report booked time as free\n * over a range it was never told about. A host that loads on this call gets\n * a corrected search for nothing: new rows re-render the panel and the\n * search runs again.\n */\n onSearchRange?: (range: { from: Date; to: Date }) => void;\n}) {\n const { t } = useTranslation();\n const data = useCalendarData();\n const key = (suffix: string): string =>\n `calendarWorkspace.findSlots.${suffix}`;\n const { open: openSheet } = useSheetHost();\n const seedContext: AvailabilityContext | undefined = seed\n ? {\n patientId: seed.patientId,\n care: seed.care,\n cares: seed.cares,\n colorHex: seed.colorHex,\n }\n : undefined;\n\n const listOnly = platform?.listOnly === true;\n /* The host's own finder, when it has one: the panel stops inferring\n free time from the rows it holds and asks the practice's server. */\n const serverSearch = data.searchFreeSlots;\n const [careId, setCareId] = useState('');\n /* The device is the platform's own name string — the demo carries no\n device ids, and the results annotate the chosen one. */\n const [deviceName, setDeviceName] = useState('');\n const [durationMin, setDurationMin] = useState<number | null>(\n seed?.durationMin ?? 30,\n );\n const [operatorId, setOperatorId] = useState(seed?.operatorId ?? ANY);\n const [chairId, setChairId] = useState(seed?.chairId ?? ANY);\n /* The multi-select scope's own selections (platform semantics: an\n empty selection searches every eligible resource). */\n const multiScope = platform?.multiSelectScope === true;\n const [scopeOperatorIds, setScopeOperatorIds] = useState<string[]>(() =>\n seed?.operatorId ? [seed.operatorId] : [],\n );\n const [scopeChairIds, setScopeChairIds] = useState<string[]>(() =>\n seed?.chairId ? [seed.chairId] : [],\n );\n /* Today, and the platform's own ~30-day horizon.\n\n These were the demo fixture's week — a hardcoded 2026-06-24 → 2026-06-27\n — which shipped. Any practice opening the finder outside that week\n searched a range in the past and was told, correctly and uselessly, that\n nothing was free. The host's `nowIso` is the clock the rest of the\n workspace already runs on, so it is the clock here too. */\n const [fromDate, setFromDate] = useState<Date | undefined>(() => {\n const today = new Date(data.nowIso);\n\n today.setHours(0, 0, 0, 0);\n\n return today;\n });\n const [toDate, setToDate] = useState<Date | undefined>(() => {\n const horizon = new Date(data.nowIso);\n\n horizon.setHours(0, 0, 0, 0);\n horizon.setDate(horizon.getDate() + FREE_SLOT_DEFAULT_HORIZON_DAYS);\n\n return horizon;\n });\n /* null = no search yet (show nothing below the form). */\n const [results, setResults] = useState<CalendarFreeSlot[] | null>(null);\n /* Server mode only: a question is out, or the last one failed. The\n previous answer stays on screen through both. */\n const [searching, setSearching] = useState(false);\n const [failed, setFailed] = useState(false);\n const [capped, setCapped] = useState(false);\n /* The UNCAPPED result set — the grid projection shows everything the\n search found, the list stays capped for readability. */\n const [allFound, setAllFound] = useState<CalendarFreeSlot[] | null>(null);\n /* Projection on by default — searching should light the grid up. */\n const [showOnGrid, setShowOnGrid] = useState(true);\n /* Filters collapse after a search so the RESULTS lead the panel. */\n const [filtersOpen, setFiltersOpen] = useState(true);\n\n /* The overlay must never outlive its controls: the rail unmounts this\n panel on close/tool-switch, and the cleanup clears the projection —\n so closing the panel IS the cancel gesture. (Booking via the editor\n also switches tools; the chosen slot is already in the prefill.) */\n const clearProjectionRef = useRef(onShowInCalendar);\n clearProjectionRef.current = onShowInCalendar;\n useEffect(() => () => clearProjectionRef.current(null), []);\n\n const care = data.cares.find((c) => c.id === careId);\n\n /* Care-driven derivation: duration follows the care, and a filter that\n the care makes ineligible resets to Any. */\n const handleCareChange = (next: string): void => {\n setCareId(next);\n setDeviceName('');\n const nextCare = data.cares.find((c) => c.id === next);\n if (!nextCare) return;\n setDurationMin(nextCare.durationMin);\n setOperatorId((prev) =>\n prev !== ANY && !nextCare.operatorIds.includes(prev) ? ANY : prev,\n );\n setChairId((prev) =>\n prev !== ANY && !nextCare.chairIds.includes(prev) ? ANY : prev,\n );\n /* Same rule for the checklists: a tick the care makes ineligible\n drops out rather than silently narrowing the search to nothing. */\n setScopeOperatorIds((prev) =>\n prev.filter((id) => nextCare.operatorIds.includes(id)),\n );\n setScopeChairIds((prev) =>\n prev.filter((id) => nextCare.chairIds.includes(id)),\n );\n };\n\n const eligibleOperators = care\n ? activeOperators(data).filter((o) => care.operatorIds.includes(o.id))\n : activeOperators(data);\n const eligibleChairs = care\n ? data.chairs.filter((c) => care.chairIds.includes(c.id))\n : data.chairs;\n /* What the search actually runs over. Multi-select reads the ticked\n ids (none = everyone); the single Select reads its ANY sentinel. */\n const scopedOperators = multiScope\n ? eligibleOperators.filter(\n (o) => scopeOperatorIds.length === 0 || scopeOperatorIds.includes(o.id),\n )\n : eligibleOperators.filter(\n (o) => operatorId === ANY || o.id === operatorId,\n );\n const scopedChairs = multiScope\n ? eligibleChairs.filter(\n (c) => scopeChairIds.length === 0 || scopeChairIds.includes(c.id),\n )\n : eligibleChairs.filter((c) => chairId === ANY || c.id === chairId);\n /* Patient/care and any single-resource scope ride with the projection. */\n const projectionContext: AvailabilityContext = {\n ...seedContext,\n ...(scopedOperators.length === 1\n ? { scopeOperatorId: scopedOperators[0].id }\n : {}),\n ...(scopedChairs.length === 1 ? { scopeChairId: scopedChairs[0].id } : {}),\n };\n /* The operators a \"nobody is free\" readout would name. */\n const chosenOperatorIds = multiScope\n ? scopeOperatorIds\n : operatorId === ANY\n ? []\n : [operatorId];\n /* Checklist sections: operators under their groups (the platform's\n grouped dropdown), chairs as one flat list. */\n const operatorGroups = platform?.operatorGroups;\n const operatorSections: ScopeSection[] =\n operatorGroups && operatorGroups.length > 0\n ? buildOperatorFilterGroups({\n groups: operatorGroups,\n operators: eligibleOperators,\n inactiveIds: [],\n withoutGroupLabel: t('calendarWorkspace.filters.withoutGroup'),\n locale,\n }).map((group) => ({\n id: group.id,\n name: group.name,\n options: group.operators,\n }))\n : [{ id: 'all', name: null, options: eligibleOperators }];\n const chairSections: ScopeSection[] = [\n { id: 'all', name: null, options: eligibleChairs },\n ];\n\n /* The question a SERVER search asks, or null when there is nothing to\n ask about — an empty scope, or a range entirely behind the clock, both\n the caller's cue to publish the empty answer itself. `from` clamps to\n today: the answer is floored at now anyway. */\n const buildQuery = (from: Date, to: Date): FreeSlotQuery | null => {\n const today = new Date(data.nowIso);\n\n today.setHours(0, 0, 0, 0);\n\n const start = from.getTime() < today.getTime() ? today : from;\n if (to.getTime() < start.getTime()) return null;\n if (scopedOperators.length === 0 || scopedChairs.length === 0) return null;\n\n return {\n from: start,\n to,\n durationMin: durationMin ?? care?.durationMin ?? 30,\n operatorIds: scopedOperators.map((operator) => operator.id),\n chairIds: scopedChairs.map((chair) => chair.id),\n ...(care ? { careId: care.id } : {}),\n ...(deviceName ? { medicalDeviceIds: [deviceName] } : {}),\n };\n };\n\n /* One search, kept as a question and its answer: `computeSlots` reads\n the busy set and the scope as they are NOW, `publish` shows the answer.\n `runSearch` asks the host first; the recompute below never does. */\n const computeSlots = (from: Date, to: Date): CalendarFreeSlot[] =>\n computeFreeSlotsLocally(\n {\n rows,\n chairs: scopedChairs,\n operators: scopedOperators,\n durationMin: durationMin ?? care?.durationMin ?? 30,\n fromDate: from,\n toDate: to,\n careId: care?.id,\n },\n data,\n );\n const publish = (found: CalendarFreeSlot[], from: Date): void => {\n /* Cap the list — the note tells the presenter how it was trimmed. */\n setCapped(found.length > FREE_SLOT_CAP);\n setResults(found.slice(0, FREE_SLOT_CAP));\n setAllFound(found);\n /* A live projection follows each new answer — never in list-only\n mode, where the dialog hides the grid behind its backdrop. */\n if (showOnGrid && !listOnly) {\n onShowInCalendar(found, from, projectionContext);\n }\n };\n /* The busy set and load stamp the LAST question was asked under. */\n const searchStamp = useMemo(\n () => (serverSearch ? `${busySignature(rows)}#${data.revision ?? ''}` : ''),\n [serverSearch, rows, data.revision],\n );\n const askedStampRef = useRef<string | null>(null);\n /* One answer at a time: a new question aborts the one in flight. */\n const abortRef = useRef<AbortController | null>(null);\n useEffect(() => () => abortRef.current?.abort(), []);\n const askServer = (from: Date, to: Date): void => {\n if (!serverSearch) return;\n askedStampRef.current = searchStamp;\n const query = buildQuery(from, to);\n abortRef.current?.abort();\n if (!query) {\n /* Nobody eligible, or no range left: that IS the answer. */\n setSearching(false);\n setFailed(false);\n publish([], from);\n return;\n }\n const controller = new AbortController();\n abortRef.current = controller;\n setSearching(true);\n setFailed(false);\n serverSearch(query, { signal: controller.signal }).then(\n (found) => {\n if (controller.signal.aborted) return;\n setSearching(false);\n /* The host answers in its finder's order; the readouts do not. */\n publish(\n [...found].sort((a, b) => a.start.getTime() - b.start.getTime()),\n query.from,\n );\n },\n () => {\n if (controller.signal.aborted) return;\n setSearching(false);\n setFailed(true);\n },\n );\n };\n /* The window the last search covered. A recompute answers THIS, not the\n form's inputs, which may have been edited since without a new search. */\n const searchedRef = useRef<{ from: Date; to: Date } | null>(null);\n const runSearch = (range?: { to?: Date }): void => {\n const to = range?.to ?? toDate;\n if (!fromDate || !to) return;\n searchedRef.current = { from: fromDate, to };\n if (serverSearch) {\n /* No `onSearchRange`: it exists to make the panel's OWN rows cover\n the window, and a server answer does not read them. */\n askServer(fromDate, to);\n } else {\n /* Say what is about to be searched, BEFORE searching it: the busy\n set is `rows` and nothing else, so a host whose rows cover only\n the visible grid would have this report booked time as free. A\n host that loads on the call gets a corrected answer for free —\n the rows land and the recompute below re-runs, silently. */\n onSearchRange?.({ from: fromDate, to });\n publish(computeSlots(fromDate, to), fromDate);\n }\n /* Collapse the form — the results must be visible WITHOUT scrolling. */\n setFiltersOpen(false);\n };\n /* The corrected second answer. Rows, or the read model, that change AFTER\n a search recompute that search silently: no `onSearchRange`, so a host\n that loads on it is never sent round again, and an identical answer\n changes nothing, so nothing here can loop. The scope and the clock are\n read through refs: the effect keys on the busy set, not on the form. */\n const computeRef = useRef(computeSlots);\n computeRef.current = computeSlots;\n const publishRef = useRef(publish);\n publishRef.current = publish;\n const allFoundRef = useRef(allFound);\n allFoundRef.current = allFound;\n useEffect(() => {\n if (serverSearch) return;\n const searched = searchedRef.current;\n const previous = allFoundRef.current;\n if (!searched || previous === null) return;\n const next = computeRef.current(searched.from, searched.to);\n if (sameFreeSlots(previous, next)) return;\n publishRef.current(next, searched.from);\n }, [rows, data, serverSearch]);\n /* Server mode's own correction: the same question again when the busy\n set moves or the load stamp ticks. Debounced, so a refresh landing\n its rows over several renders costs ONE request; never right after a\n search, which already answered for this very stamp. */\n const askServerRef = useRef(askServer);\n askServerRef.current = askServer;\n useEffect(() => {\n if (!serverSearch || askedStampRef.current === null) return;\n if (askedStampRef.current === searchStamp) return;\n const searched = searchedRef.current;\n if (!searched) return;\n const timer = setTimeout(\n () => askServerRef.current(searched.from, searched.to),\n SERVER_SEARCH_DEBOUNCE_MS,\n );\n\n return () => clearTimeout(timer);\n }, [serverSearch, searchStamp]);\n const handleSearch = (): void => runSearch();\n\n /* Platform \"Mostra altri slot\": push the To date out and re-search. */\n const pagerStepDays = platform?.pagerStepDays;\n const handleShowMore = (): void => {\n if (!pagerStepDays) return;\n const base = toDate ?? fromDate ?? new Date();\n const next = new Date(base);\n next.setDate(next.getDate() + pagerStepDays);\n setToDate(next);\n runSearch({ to: next });\n };\n\n /* A seeded open (the waiting-list handoff) searches IMMEDIATELY — the\n user arrives at results for that patient, not an empty form. */\n const autoSearchedRef = useRef(false);\n useEffect(() => {\n if (seed && !autoSearchedRef.current) {\n autoSearchedRef.current = true;\n handleSearch();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- mount-only seeded kick-off\n }, []);\n\n const handleShowOnGridChange = (checked: boolean): void => {\n setShowOnGrid(checked);\n onShowInCalendar(checked ? allFound : null, fromDate, projectionContext);\n };\n\n /* Say WHY nothing came back when the range itself is the reason: every\n day closed, or the chosen operator away on every open day. */\n const noResultsDescription = (): string => {\n const open =\n fromDate && toDate ? data.openDatesBetween(fromDate, toDate) : [];\n if (open.length === 0) return t(key('noResultsClosed'));\n /* Every operator in scope away on every open day — the platform\n names them all in one sentence. */\n if (\n chosenOperatorIds.length > 0 &&\n chosenOperatorIds.every((id) =>\n open.every((d) => (data.operatorAbsences[id] ?? []).includes(d)),\n )\n ) {\n return t(key('noResultsOperatorAbsent'), {\n name: chosenOperatorIds\n .map((id) => data.operators.find((o) => o.id === id)?.title ?? '')\n .filter(Boolean)\n .join(', '),\n });\n }\n return t(key('noResultsDescription'));\n };\n\n const handleBook = (slot: CalendarFreeSlot): void => {\n if (!canBook) return;\n onBookSlot({\n date: slot.start,\n time: { hours: slot.start.getHours(), minutes: slot.start.getMinutes() },\n durationMin: slot.durationMin,\n operatorId: slot.operatorId,\n chairId: slot.chairId,\n /* An explicitly chosen care wins; otherwise the seed context (the\n waiting entry's colour/description) carries through — and the\n WAITING PATIENT lands pre-selected in the editor. */\n colorHex: care?.colorHex ?? seed?.colorHex,\n /* A chosen catalogue care rides as a linked care, not as the\n free-text description (the editor's initialiser may still\n swap the colour for the operator's/chair's). */\n care: care ? undefined : seed?.care,\n cares: care\n ? [{ careId: care.id, name: care.name, code: care.code }]\n : seed?.cares,\n patientId: seed?.patientId,\n });\n openSheet('appointment-editor');\n };\n\n /* The devices the chosen care needs — the select only exists for a\n care that has some (platform `FIND_FREE_SLOTS_BY_CARE`). */\n const careDevices: readonly string[] =\n platform?.devicesByCare && care\n ? (platform.devicesByCare[care.id] ?? [])\n : [];\n /* Past the platform's look-ahead ceiling the search still runs — the\n warning is advisory there too. */\n const maxRangeDays = platform?.maxRangeDays;\n const rangeTooLong = Boolean(\n maxRangeDays &&\n fromDate &&\n toDate &&\n rangeDays(fromDate, toDate) > maxRangeDays,\n );\n const missingPracticeHours = platform?.practiceHasBusinessHours === false;\n const missingOperatorHours = platform?.operatorsHaveBusinessHours === false;\n\n /* Group results by day for the semibold day headings. */\n const grouped = useMemo(() => {\n if (!results) return [];\n const byDay = new Map<string, CalendarFreeSlot[]>();\n for (const slot of results) {\n const dayKey = `${slot.start.getFullYear()}-${slot.start.getMonth()}-${slot.start.getDate()}`;\n const list = byDay.get(dayKey);\n if (list) list.push(slot);\n else byDay.set(dayKey, [slot]);\n }\n return [...byDay.entries()];\n }, [results]);\n\n return (\n <div className=\"ds:flex ds:flex-col\">\n <PanelHeader\n title={t(key('tool'))}\n icon={<CalendarSearch aria-hidden=\"true\" />}\n sticky\n divider\n />\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)] ds:p-[var(--spacing-md)]\">\n {canBook ? null : (\n <Alert\n variant=\"info\"\n announce=\"off\"\n icon={<Lock aria-hidden=\"true\" />}\n >\n <Alert.Title as=\"p\">\n {t('calendarWorkspace.details.readOnlyTitle')}\n </Alert.Title>\n <Alert.Description>\n {t('calendarWorkspace.inc1.readOnly.createBlocked')}\n </Alert.Description>\n </Alert>\n )}\n {/* Platform advisory: without business hours nothing can be found.\n The form stays usable — the alert only says where to fix it. */}\n {missingPracticeHours || missingOperatorHours ? (\n <Alert variant=\"error\">\n <Alert.Description>\n <span className=\"ds:flex ds:flex-col ds:items-start ds:gap-[var(--spacing-2xs)]\">\n {missingPracticeHours ? (\n <span>{t(key('noPracticeBusinessHours'))}</span>\n ) : null}\n {missingOperatorHours ? (\n <span>{t(key('noOperatorBusinessHours'))}</span>\n ) : null}\n {platform?.onOpenScheduler ? (\n <Button\n size=\"sm\"\n intent=\"link\"\n onClick={platform.onOpenScheduler}\n >\n {t(key('openScheduler'))}\n </Button>\n ) : null}\n </span>\n </Alert.Description>\n </Alert>\n ) : null}\n {/* Collapsible filter block — open for the first search, then\n auto-collapsed so the result list leads; reopen via the\n Filters trigger to refine. */}\n <Collapsible open={filtersOpen} onOpenChange={setFiltersOpen}>\n <CollapsibleTrigger asChild>\n <Button\n size=\"sm\"\n intent=\"outline\"\n startIcon={<Funnel aria-hidden=\"true\" />}\n >\n {t(key('filters'))}\n </Button>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)] ds:pt-[var(--spacing-md)]\">\n <FormField label={t(key('care'))}>\n <Combobox\n options={data.cares.map((c) => ({\n value: c.id,\n label: c.name,\n }))}\n value={careId}\n onValueChange={handleCareChange}\n placeholder={t(key('careSearch'))}\n clearable\n />\n </FormField>\n <FormField label={t(key('duration'))}>\n <DurationCombobox\n value={durationMin}\n onChange={setDurationMin}\n />\n </FormField>\n {multiScope ? (\n /* Platform parity: grouped checklists, not one Select. */\n <div\n role=\"group\"\n aria-label={t(key('scope'))}\n className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)]\"\n >\n <ScopeChecklist\n label={t(key('operators'))}\n countLabel={t(key('operatorsScoped'), {\n selected: scopeOperatorIds.length,\n total: eligibleOperators.length,\n })}\n hint={t(key('everyoneOperators'))}\n icon={<UserCog aria-hidden=\"true\" />}\n sections={operatorSections}\n selected={scopeOperatorIds}\n onChange={setScopeOperatorIds}\n />\n <ScopeChecklist\n label={t(key('chairs'))}\n countLabel={t(key('chairsScoped'), {\n selected: scopeChairIds.length,\n total: eligibleChairs.length,\n })}\n hint={t(key('everyoneChairs'))}\n icon={<Armchair aria-hidden=\"true\" />}\n sections={chairSections}\n selected={scopeChairIds}\n onChange={setScopeChairIds}\n />\n </div>\n ) : (\n <>\n <FormField label={t(key('operator'))}>\n <Select\n options={[\n { value: ANY, label: t(key('any')) },\n ...eligibleOperators.map((o) => ({\n value: o.id,\n label: o.title,\n })),\n ]}\n value={operatorId}\n onValueChange={setOperatorId}\n />\n </FormField>\n <FormField label={t(key('chair'))}>\n <Select\n options={[\n { value: ANY, label: t(key('any')) },\n ...eligibleChairs.map((c) => ({\n value: c.id,\n label: c.title,\n })),\n ]}\n value={chairId}\n onValueChange={setChairId}\n />\n </FormField>\n </>\n )}\n {careDevices.length > 0 ? (\n <FormField label={t(key('device'))}>\n <Select\n options={[\n { value: ANY, label: t(key('any')) },\n ...careDevices.map((name) => ({\n value: name,\n label: name,\n })),\n ]}\n value={deviceName || ANY}\n onValueChange={(next) =>\n setDeviceName(next === ANY ? '' : next)\n }\n />\n </FormField>\n ) : null}\n <FormField label={t(key('from'))}>\n <DatePicker value={fromDate} onChange={setFromDate} />\n </FormField>\n <FormField label={t(key('to'))}>\n <DatePicker value={toDate} onChange={setToDate} />\n </FormField>\n {rangeTooLong ? (\n <Alert variant=\"warning\">\n <Alert.Description>\n {t(key('rangeTooLong'), { days: maxRangeDays })}\n </Alert.Description>\n </Alert>\n ) : null}\n <div>\n <Button\n intent=\"primary\"\n onClick={handleSearch}\n disabled={searching}\n >\n {t(key('search'))}\n </Button>\n </div>\n </div>\n </CollapsibleContent>\n </Collapsible>\n {/* A question is out; the last answer stays put below it. */}\n {searching ? (\n <span\n role=\"status\"\n data-testid=\"find-slots-searching\"\n className=\"type-body-sm ds:text-start ds:text-[color:var(--muted-foreground)]\"\n >\n {t(key('searching'))}\n </span>\n ) : null}\n {/* The server refused: the panel's own words, never the host's\n error. The retry is `tonal`, the intent the Alert paints\n itself — a `link` reads primary violet on the tint at 4.13:1. */}\n {failed ? (\n <Alert variant=\"error\">\n <Alert.Description>{t(key('searchFailed'))}</Alert.Description>\n <Alert.Action>\n {/* The kit's shared retry word, as the patient picker's. */}\n <Button size=\"sm\" intent=\"tonal\" onClick={handleSearch}>\n {t('emptyState.error.cta')}\n </Button>\n </Alert.Action>\n </Alert>\n ) : null}\n {results === null ? null : results.length === 0 ? (\n <EmptyState\n variant=\"no-results\"\n size=\"sm\"\n title={t(key('noResultsTitle'))}\n description={noResultsDescription()}\n />\n ) : (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {/* Availability projection: dims booked cards on the grid and\n glows every found free range (the UNCAPPED set). Hidden in\n list-only mode — the dialog covers the grid. */}\n {listOnly ? null : (\n <Switch\n label={t(key('showInCalendar'))}\n checked={showOnGrid}\n onCheckedChange={handleShowOnGridChange}\n />\n )}\n {capped ? (\n <span className=\"type-body-sm ds:text-start ds:text-[color:var(--muted-foreground)]\">\n {t(key('capNote'))}\n </span>\n ) : null}\n {grouped.map(([dayKey, slots]) => (\n <div\n key={dayKey}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\"\n >\n <span className=\"type-body-sm ds:font-[var(--font-weight-semibold)] ds:text-start\">\n {formatDay(locale, slots[0].start)}\n </span>\n {/* eslint-disable-next-line jsx-a11y/no-redundant-roles -- role=\"list\" is NOT redundant: WebKit drops implicit list semantics when list-style is none */}\n <ul\n role=\"list\"\n className=\"ds:m-0 ds:flex ds:list-none ds:flex-col ds:gap-[var(--spacing-2xs)] ds:p-0\"\n >\n {slots.map((slot) => {\n const allocation = [\n data.chairs.find((c) => c.id === slot.chairId)?.title,\n data.operators.find((o) => o.id === slot.operatorId)\n ?.title,\n deviceName || undefined,\n ]\n .filter(Boolean)\n .join(' · ');\n const when = formatTimeRange(\n locale,\n slot.start,\n new Date(slot.start.getTime() + slot.durationMin * 60000),\n );\n const facts = (\n <div className=\"ds:flex ds:flex-col ds:[min-inline-size:0]\">\n <span className=\"type-body-sm ds:font-[var(--font-weight-semibold)] ds:text-start\">\n {when}\n </span>\n <span className=\"type-body-sm ds:truncate ds:text-start ds:text-[color:var(--muted-foreground)]\">\n {allocation}\n </span>\n </div>\n );\n /* The card is the button in list-only mode — unless\n booking is refused, when every row is facts only. */\n const rowIsButton = listOnly && canBook;\n return (\n <li\n key={`${slot.start.getTime()}-${slot.chairId}-${slot.operatorId}`}\n /* Panel-list canon: elevated card per row. */\n className={\n rowIsButton ? undefined : FREE_SLOT_CARD_CLASS\n }\n >\n {rowIsButton ? (\n <button\n type=\"button\"\n className={FREE_SLOT_BUTTON_CLASS}\n onClick={() => handleBook(slot)}\n >\n {facts}\n <span className=\"type-body-sm ds:ms-auto ds:shrink-0 ds:text-[color:var(--muted-foreground)]\">\n {t(key('book'))}\n </span>\n </button>\n ) : (\n <>\n {facts}\n {canBook ? (\n <span className=\"ds:ms-auto\">\n <Button\n size=\"sm\"\n intent=\"outline\"\n onClick={() => handleBook(slot)}\n >\n {t(key('book'))}\n </Button>\n </span>\n ) : null}\n </>\n )}\n </li>\n );\n })}\n </ul>\n </div>\n ))}\n {pagerStepDays ? (\n <div>\n <Button size=\"sm\" intent=\"outline\" onClick={handleShowMore}>\n {t(key('showMore'))}\n </Button>\n </div>\n ) : null}\n </div>\n )}\n </div>\n </div>\n );\n}\n","/* Privacy mode, rail side. The rule is the grid's and the hover peek's:\n mask the identity, drop what is personal, keep time, place and status.\n These are the pieces every rail surface shares to say so. */\nimport { EyeOff } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { EmptyState } from '../../components/empty-state';\nimport { PanelHeader } from '../../components/panel-header';\nimport { SectionCard } from '../../components/section-card';\nimport { VisuallyHidden } from '../../components/visually-hidden';\n\nconst privacyKey = (suffix: string): string =>\n `calendarWorkspace.privacy.${suffix}`;\n\n/** The mask privacy mode shows for a name. TOTAL, as `maskedTitle` is: an\n * empty or absent host mask degrades to the bullets, never to a blank. */\nexport function privacyMask(mask?: string): string {\n return mask !== undefined && mask.trim() !== '' ? mask : '•••';\n}\n\n/** One muted line where a personal value would have been. */\nexport function PrivacyHiddenLine({ block }: { block?: string }) {\n const { t } = useTranslation();\n return (\n <p\n data-privacy=\"hidden\"\n data-block={block}\n className=\"ds:m-0 ds:flex ds:items-center ds:gap-[var(--spacing-xs)] type-body-sm ds:text-[color:var(--muted-foreground)]\"\n >\n <EyeOff aria-hidden=\"true\" className=\"ds:size-4 ds:shrink-0\" />\n {t(privacyKey('hidden'))}\n </p>\n );\n}\n\n/** The patient card under privacy: the grid's mask, no photo, no contact\n * fields and no chips. Keeps `data-card=\"patient\"` for host hooks. */\nexport function PrivacyIdentityCard({ mask }: { mask?: string }) {\n const { t } = useTranslation();\n return (\n <SectionCard\n data-card=\"patient\"\n data-privacy=\"masked\"\n headingLevel={3}\n title={\n <span className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n <EyeOff aria-hidden=\"true\" className=\"ds:size-4 ds:shrink-0\" />\n <VisuallyHidden>{t('appointmentPeek.hiddenName')}: </VisuallyHidden>\n {privacyMask(mask)}\n </span>\n }\n >\n <PrivacyHiddenLine />\n </SectionCard>\n );\n}\n\n/** A whole rail panel withheld under privacy: a form or a notes list that\n * could only open by showing what the mask hides. */\nexport function PrivacyNoticePanel({\n title,\n icon,\n onTurnOff,\n}: {\n /** The panel's own title, so the rail still says which tool this is. */\n title: string;\n icon?: ReactNode;\n /** Absent: the notice explains, and the toolbar's toggle is the way out. */\n onTurnOff?: () => void;\n}) {\n const { t } = useTranslation();\n return (\n <div\n data-component=\"calendar-privacy-notice\"\n className=\"ds:flex ds:h-full ds:flex-col\"\n >\n <PanelHeader title={title} icon={icon} sticky divider />\n <div className=\"ds:p-[var(--spacing-md)]\">\n <EmptyState\n variant=\"first-use\"\n size=\"sm\"\n title={t(privacyKey('hidden'))}\n description={t(privacyKey('noticeBody'))}\n primaryAction={\n onTurnOff\n ? { label: t(privacyKey('turnOff')), onClick: onTurnOff }\n : undefined\n }\n />\n </div>\n </div>\n );\n}\n","/**\n * The hover card body the details panel's chips share: an eyebrow naming\n * the kind of thing, a heading restating the chip in words, and the facts\n * the chip could not fit. Ported from the calendar-rail demo's hover\n * grammar; `PatientSummaryCard.flagHover` renders it around its own chip,\n * and `InfoHover` wraps the chips the panel renders itself.\n */\nimport type { ReactNode } from 'react';\nimport { HoverCard } from '../../components/hover-card';\n\nexport interface InfoHoverFact {\n text: ReactNode;\n /** A caveat or provenance note, quieter than the rest. */\n muted?: boolean;\n}\n\nexport function InfoHoverBody({\n eyebrow,\n heading,\n facts,\n}: {\n eyebrow: string;\n heading: string;\n facts?: readonly InfoHoverFact[];\n}): ReactNode {\n return (\n <>\n <HoverCard.Eyebrow>{eyebrow}</HoverCard.Eyebrow>\n <HoverCard.Heading>{heading}</HoverCard.Heading>\n {facts && facts.length > 0 ? (\n <HoverCard.Body>\n <ul className=\"ds:m-0 ds:flex ds:list-none ds:flex-col ds:gap-[var(--spacing-2xs)] ds:p-0 type-body-sm\">\n {facts.map((fact, index) => (\n <li\n key={index}\n className={\n fact.muted\n ? 'ds:text-[color:var(--muted-foreground)]'\n : undefined\n }\n >\n {fact.text}\n </li>\n ))}\n </ul>\n </HoverCard.Body>\n ) : null}\n </>\n );\n}\n\nconst TRIGGER =\n 'ds:inline-flex ds:cursor-pointer ds:rounded-[var(--radius-full)] ds:p-0 ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]';\n\n/**\n * Wraps a chip the panel renders itself in the same card. It carries no\n * open button: the pattern has no seam to open invoicing or the anamnesis.\n */\nexport function InfoHover({\n id,\n eyebrow,\n heading,\n facts,\n children,\n}: {\n /** Stamped as `data-chip-hover`, the trigger's DOM hook. */\n id: string;\n eyebrow: string;\n heading: string;\n facts?: readonly InfoHoverFact[];\n /** The chip; its visible text is the trigger's accessible name. */\n children: ReactNode;\n}): ReactNode {\n return (\n <HoverCard>\n {/* A real button: `asChild` onto a bare span stamps `aria-haspopup`\n on something a keyboard can never reach. */}\n <HoverCard.Trigger asChild>\n <button type=\"button\" data-chip-hover={id} className={TRIGGER}>\n {children}\n </button>\n </HoverCard.Trigger>\n <HoverCard.Content side=\"bottom\" align=\"start\" size=\"sm\">\n <InfoHoverBody eyebrow={eyebrow} heading={heading} facts={facts} />\n </HoverCard.Content>\n </HoverCard>\n );\n}\n","/* The cards of the appointment details panel (P-C2), laid out as the\n calendar-rail demo lays them out and built on the kit's primitives. Each\n reads CalendarAppointmentDetails only and prints one row per member the\n host sent: an absent member renders nothing, and a card with nothing to\n show renders no card. Contact is printed as read; masking is the host's. */\nimport {\n Armchair,\n Building2,\n Cake,\n CalendarDays,\n ClipboardList,\n Clock,\n HeartPulse,\n Hourglass,\n Mail,\n MapPin,\n Phone,\n Repeat,\n Smartphone,\n Video,\n} from 'lucide-react';\nimport type { ReactElement, ReactNode } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Avatar } from '../../components/avatar';\nimport { Badge } from '../../components/badge';\nimport { DescriptionList } from '../../components/description-list';\nimport { PatientSummaryCard } from '../../components/patient-summary-card';\nimport { SectionCard } from '../../components/section-card';\nimport { Timestamp } from '../../components/timestamp';\nimport { TransactionChip } from '../../components/transaction-chip';\nimport { TreatmentReceipt } from '../../components/treatment-receipt';\nimport type { PatientField } from '../../components/_shared/patient-fields';\nimport type { CalendarAppointmentDetails } from './calendar-appointment-details';\nimport { useCalendarData } from './calendar.data';\nimport {\n DETAIL_STAMP_FORMAT,\n formatDay,\n formatTimeRange,\n patientAgeYears,\n RECURRENCE_LABEL_KEY,\n} from './calendar.model';\nimport { patientPhones } from './calendar.types';\nimport {\n patientAddressLabel,\n patientAddressLine,\n patientMapsUrl,\n} from './calendar-workspace.model';\nimport {\n InfoHover,\n InfoHoverBody,\n type InfoHoverFact,\n} from './calendar-info-hover';\n\ninterface CardProps {\n details: CalendarAppointmentDetails;\n locale: string;\n}\n\ninterface Row {\n id: string;\n label: string;\n icon?: ReactElement;\n value: ReactNode;\n}\n\nconst key = (suffix: string): string => `calendarWorkspace.details.${suffix}`;\nconst MUTED = 'type-body-sm ds:text-[color:var(--muted-foreground)]';\nconst telLink = (number: string) => (\n <a href={`tel:${number.replace(/\\s/g, '')}`}>{number}</a>\n);\nconst mailLink = (email: string) => <a href={`mailto:${email}`}>{email}</a>;\nconst euro = (locale: string, amount: number): string =>\n new Intl.NumberFormat(locale, { style: 'currency', currency: 'EUR' }).format(\n amount,\n );\n\n/** Term and detail pairs; nothing at all without a row. */\nfunction Rows({ rows }: { rows: Array<Row | false | null | undefined | ''> }) {\n const shown = rows.filter((entry): entry is Row => !!entry);\n if (shown.length === 0) return null;\n return (\n <DescriptionList layout=\"inline\" density=\"compact\">\n {shown.map((entry) => (\n <DescriptionList.Row\n key={entry.id}\n data-row={entry.id}\n icon={entry.icon}\n >\n <DescriptionList.Term>{entry.label}</DescriptionList.Term>\n <DescriptionList.Detail>{entry.value}</DescriptionList.Detail>\n </DescriptionList.Row>\n ))}\n </DescriptionList>\n );\n}\n\n/**\n * The kit's PatientSummaryCard: identity, the attention chips, the money\n * chips and the contact fields. Every chip explains itself in a hover\n * card; money reads worst first (owed, to invoice, paid online), labelled\n * and without glyphs.\n */\nexport function DetailsPatientCard({\n details,\n locale,\n mapsLink = false,\n}: CardProps & {\n /** The user's map-link setting (platform `showPatientAddressMapLink`). */\n mapsLink?: boolean;\n}) {\n const { t } = useTranslation();\n const data = useCalendarData();\n const { patient, signing, money, booking } = details;\n if (!patient) return null;\n const signingShown = signing && signing.required > 0 ? signing : undefined;\n const pending = (signingShown?.toComplete ?? 0) > 0;\n const signingFacts: InfoHoverFact[] = signingShown\n ? [\n {\n text: !pending\n ? t(key('signingAllSigned'))\n : signingShown.requestedVia === 'sms'\n ? t(key('signingRequestedSms'))\n : signingShown.requestedVia === 'email'\n ? t(key('signingRequestedEmail'))\n : t(key('signingNotRequested')),\n },\n ...(signingShown.aesSetUp\n ? []\n : [{ text: t(key('aesMissing')), muted: true }]),\n ]\n : [];\n const highlighted = patient.highlightedAnamnesisCount ?? 0;\n const expired = patient.expiredAnamnesisCount ?? 0;\n const answerFacts: InfoHoverFact[] = (\n patient.highlightedAnamnesisAnswers ?? []\n ).map((answer) => ({\n text: [\n answer.question,\n t(key(answer.yes ? 'anamnesisYes' : 'anamnesisNo')),\n answer.answer,\n formatDay(locale, answer.interviewIso),\n ]\n .filter(Boolean)\n .join(' · '),\n }));\n const query = patientAddressLine(patient);\n const addressLabel = patientAddressLabel(patient) || query;\n const fields: PatientField[] = [\n ...(patient.dobIso\n ? [\n {\n id: 'dob',\n label: t(key('dob')),\n icon: <Cake />,\n value: `${formatDay(locale, patient.dobIso)} ${t(\n key('patientAge'),\n {\n n: patientAgeYears(patient.dobIso, data),\n },\n )}`,\n },\n ]\n : []),\n ...patientPhones(patient).map((phone, index) => {\n const hasLabel =\n phone.label === 'mobile' ||\n phone.label === 'home' ||\n phone.label === 'work';\n return {\n id: `phone-${index}`,\n label: hasLabel\n ? t(`calendarWorkspace.print.phoneLabels.${phone.label}`)\n : t(key('phone')),\n icon: phone.label === 'mobile' ? <Smartphone /> : <Phone />,\n value: telLink(phone.number),\n };\n }),\n ...(patient.email\n ? [\n {\n id: 'email',\n label: t(key('email')),\n icon: <Mail />,\n value: mailLink(patient.email),\n },\n ]\n : []),\n ...(mapsLink\n ? [\n {\n id: 'address',\n label: t(key('address')),\n icon: <MapPin />,\n value: query ? (\n <a\n href={patientMapsUrl(patient)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={`${t(key('mapsLink'))}: ${addressLabel}`}\n >\n {addressLabel}\n </a>\n ) : (\n <span className={MUTED}>{t(key('noAddress'))}</span>\n ),\n },\n ]\n : []),\n ];\n const unpaid = money?.unpaidAmount ?? 0;\n const billable = money?.billableAmount ?? 0;\n const paidOnline = booking?.paidOnlineAmount ?? 0;\n /* A money chip under its hover card: the amount again, and whose it is. */\n const chip = (\n state: 'debt' | 'to-invoice' | 'settled',\n amount: number,\n id: string,\n headingKey: string,\n factKey: string,\n /** The money's own name, where the state's word would mislead. */\n label?: string,\n ) => (\n <InfoHover\n id={id}\n eyebrow={t(key('hoverBilling'))}\n heading={t(key(headingKey), { amount: euro(locale, amount) })}\n facts={[{ text: t(key(factKey)) }]}\n >\n <TransactionChip\n data-chip={id}\n state={state}\n amount={amount}\n currency=\"EUR\"\n locale={locale}\n size=\"md\"\n showLabel\n label={label}\n showIcon={false}\n />\n </InfoHover>\n );\n return (\n <PatientSummaryCard\n data-card=\"patient\"\n name={patient.name}\n avatarUrl={patient.avatarSrc}\n locale={locale}\n surface=\"elevated\"\n density=\"compact\"\n flags={{\n unsignedDocumentsCount: signingShown?.toComplete ?? 0,\n highlightedAnamnesisCount: highlighted,\n }}\n flagHover={{\n ...(signingShown\n ? {\n unsignedDocuments: (\n <InfoHoverBody\n eyebrow={t(key('sectionSigning'))}\n heading={\n signingShown.toComplete === 1\n ? t(key('signingToSignOne'))\n : t(key('signingToSignMany'), {\n n: signingShown.toComplete,\n })\n }\n facts={signingFacts}\n />\n ),\n }\n : {}),\n highlightedAnamnesis: (\n <InfoHoverBody\n eyebrow={t(key('anamnesisTitle'))}\n heading={t(key('anamnesisHighlighted'), { n: highlighted })}\n facts={answerFacts}\n />\n ),\n }}\n extraChips={\n unpaid > 0 || billable > 0 || paidOnline > 0 || expired > 0 ? (\n <>\n {/* One group, so no other chip lands between the money chips. */}\n <span className=\"ds:inline-flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n {unpaid > 0\n ? chip(\n 'debt',\n unpaid,\n 'unpaid',\n 'hoverUnpaidHeading',\n 'hoverUnpaidFact',\n )\n : null}\n {billable > 0\n ? chip(\n 'to-invoice',\n billable,\n 'billable',\n 'hoverBillableHeading',\n 'hoverBillableFact',\n )\n : null}\n {paidOnline > 0\n ? chip(\n 'settled',\n paidOnline,\n 'paidOnline',\n 'hoverPaidOnlineHeading',\n 'hoverPaidOnlineFact',\n /* A deposit is settled money, but \"Settled\" hides where\n it came from: the chip says what its hover card says. */\n t(key('paidOnline')),\n )\n : null}\n </span>\n {expired > 0 ? (\n <InfoHover\n id=\"anamnesisExpired\"\n eyebrow={t(key('anamnesisTitle'))}\n heading={t(key('anamnesisExpired'), { n: expired })}\n facts={[{ text: t(key('hoverAnamnesisExpiredFact')) }]}\n >\n <Badge\n data-chip=\"anamnesisExpired\"\n variant=\"warning\"\n size=\"md\"\n leading={<HeartPulse />}\n >\n {t(key('anamnesisExpired'), { n: expired })}\n </Badge>\n </InfoHover>\n ) : null}\n </>\n ) : undefined\n }\n /* Controlled, so a field this patient has and the last one did not (a\n third phone, the address once the map link is on) is shown too. */\n visibleFieldOrder={fields.map((field) => field.id)}\n sections={\n fields.length > 0\n ? [{ id: 'contact', heading: t(key('sectionPatient')), fields }]\n : undefined\n }\n />\n );\n}\n\n/**\n * When, how long, who and where, the series rule, and what the booking\n * site recorded. Operator and chair names come from the calendar data, so\n * an id the data does not know prints no row. `description` is the host's\n * slot for the description, above the facts.\n */\nexport function DetailsAppointmentCard({\n details,\n locale,\n description,\n privacy = false,\n}: CardProps & {\n description?: ReactNode;\n /** Privacy mode: what the booker typed is dropped; when they booked stays. */\n privacy?: boolean;\n}) {\n const { t } = useTranslation();\n const data = useCalendarData();\n const { appointment, booking, patient } = details;\n const editor = (suffix: string) => t(`calendarWorkspace.editor.${suffix}`);\n /* A zone-less wall clock parses as local time. */\n const start = new Date(appointment.startIso);\n const end = new Date(start.getTime() + appointment.durationMin * 60_000);\n const timed = Number.isFinite(start.getTime());\n const operator = data.operators.find((o) => o.id === appointment.operatorId);\n const chair = data.chairs.find((c) => c.id === appointment.chairId);\n const { recurrence } = appointment;\n const frequencyKey = recurrence && RECURRENCE_LABEL_KEY[recurrence.frequency];\n const frequency = frequencyKey\n ? t(`calendarWorkspace.editor.${frequencyKey}`)\n : undefined;\n const bookingRows: Array<Row | false | undefined | ''> = booking\n ? [\n booking.bookedAtIso && {\n id: 'bookedAt',\n label: t(key('bookedAt')),\n value: (\n <Timestamp\n value={booking.bookedAtIso}\n format=\"absolute\"\n shape=\"bare\"\n locale={locale}\n absoluteFormat={DETAIL_STAMP_FORMAT}\n />\n ),\n },\n booking.typedName && {\n id: 'bookingName',\n label: t(key('bookingName')),\n value: booking.typedName,\n },\n booking.phone && {\n id: 'bookingPhone',\n label: t(key('bookingPhone')),\n value: telLink(booking.phone),\n },\n booking.email && {\n id: 'bookingEmail',\n label: t(key('bookingEmail')),\n value: mailLink(booking.email),\n },\n booking.note && {\n id: 'bookingNote',\n label: t(key('bookingNote')),\n value: booking.note,\n },\n /* With a patient the amount is a chip on the patient card. */\n !patient &&\n booking.paidOnlineAmount !== undefined && {\n id: 'paidOnline',\n label: t(key('paidOnline')),\n value: euro(locale, booking.paidOnlineAmount),\n },\n ]\n : [];\n /* Privacy keeps the one booking fact that names nobody: when. */\n const shownBookingRows = privacy\n ? bookingRows.filter((row) => row && row.id === 'bookedAt')\n : bookingRows;\n const hasBooking = shownBookingRows.some(Boolean);\n return (\n <SectionCard\n data-card=\"appointment\"\n title={t(key('sectionAppointment'))}\n headingLevel={3}\n >\n {description}\n <Rows\n rows={[\n timed && {\n id: 'date',\n label: editor('date'),\n icon: <CalendarDays />,\n value: formatDay(locale, start),\n },\n timed && {\n id: 'time',\n label: t(key('time')),\n icon: <Clock />,\n value: appointment.allDay\n ? editor('allDay')\n : formatTimeRange(locale, start, end),\n },\n !appointment.allDay && {\n id: 'duration',\n label: editor('duration'),\n icon: <Hourglass />,\n value: `${appointment.durationMin} ${editor('durationUnit')}`,\n },\n appointment.isTelehealth && {\n id: 'type',\n label: editor('type'),\n icon: <Video />,\n value: editor('typeTelehealth'),\n },\n operator && {\n id: 'operator',\n label: t(key('operator')),\n /* A person, as on the grid: the avatar fills the icon slot. */\n icon: (\n <Avatar\n name={operator.title}\n src={operator.avatarSrc}\n size=\"xs\"\n />\n ),\n value: operator.title,\n },\n chair && {\n id: 'chair',\n label: t(key('chair')),\n icon: <Armchair />,\n value: (\n <Badge variant=\"neutral\" size=\"sm\" leading={<Armchair />}>\n {chair.title}\n </Badge>\n ),\n },\n appointment.branchLabel && {\n id: 'branch',\n label: editor('branch'),\n icon: <Building2 />,\n value: appointment.branchLabel,\n },\n frequency &&\n recurrence && {\n id: 'series',\n label: t(key('seriesLabel')),\n icon: <Repeat />,\n value:\n recurrence.count === undefined\n ? frequency\n : t(key('seriesRule'), {\n frequency,\n count: recurrence.count,\n }),\n },\n ]}\n />\n {hasBooking ? (\n <div\n data-block=\"booking\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\"\n >\n <h4 className=\"ds:m-0 type-label ds:text-[color:var(--muted-foreground)]\">\n {t(key('sectionBooking'))}\n </h4>\n <Rows rows={shownBookingRows} />\n </div>\n ) : null}\n </SectionCard>\n );\n}\n\n/** The linked plan, by number when the host has one, and the kit's\n * TreatmentReceipt: one line per treatment, a price only when the host\n * sends one (the editor's price gate), and a total only when every line\n * is priced. */\nexport function DetailsTreatmentsCard({\n details,\n locale,\n privacy = false,\n}: CardProps & {\n /** Privacy mode: the plan's free-text name goes, as on the hover peek. */\n privacy?: boolean;\n}) {\n const { t } = useTranslation();\n const { care } = details;\n const plan = privacy ? undefined : care?.plan;\n if (!care || (!plan && care.lines.length === 0)) return null;\n return (\n <SectionCard\n data-card=\"treatments\"\n title={t(key('sectionTreatments'))}\n headingLevel={3}\n >\n {plan ? (\n <span className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)] type-title-item\">\n <ClipboardList\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:shrink-0 ds:text-[color:var(--muted-foreground)]\"\n />\n {plan.number\n ? t(key('planLine'), { number: plan.number, name: plan.name })\n : plan.name}\n </span>\n ) : null}\n {care.lines.length > 0 ? (\n <TreatmentReceipt\n lines={care.lines.map(({ entryId, careId: _careId, ...line }) => ({\n id: entryId,\n ...line,\n }))}\n locale={locale}\n currency=\"EUR\"\n />\n ) : null}\n </SectionCard>\n );\n}\n","import {\n CalendarClock,\n Camera,\n ChevronDown,\n CircleDashed,\n ClipboardList,\n ClipboardPaste,\n Copy,\n File,\n FileText,\n Folder,\n History as HistoryIcon,\n IdCard,\n Move,\n NotebookPen,\n Pencil,\n Plus,\n ReceiptEuro,\n SquareCheckBig,\n Video,\n} from 'lucide-react';\nimport {\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Alert } from '../../components/alert';\nimport { Button, IconButton } from '../../components/button';\nimport { ButtonGroup } from '../../components/button-group';\nimport type { CalendarEventStatus } from '../../components/calendar';\nimport { Counter } from '../../components/counter';\nimport { DropdownMenu } from '../../components/dropdown-menu';\nimport { EditableDescription } from '../../components/editable-description';\nimport { NoteTimeline } from '../../components/note-timeline';\nimport { PanelHeader } from '../../components/panel-header';\nimport { PanelSubview } from '../../components/panel-subview';\nimport { SectionCard } from '../../components/section-card';\nimport { PatientSummaryCard } from '../../components/patient-summary-card';\nimport { CONTENT_ENTER_CLASS, Skeleton } from '../../components/skeleton';\nimport { TreatmentReceipt } from '../../components/treatment-receipt';\nimport { TextArea } from '../../components/text-area';\nimport { Tooltip } from '../../components/tooltip';\nimport { WhatsAppGlyph } from '../../components/whatsapp-button';\nimport {\n WorkflowStatusControl,\n WorkflowStatusDisplay,\n type WorkflowStatusOption,\n} from '../../components/workflow-status';\nimport {\n sortHistoryNewestFirst,\n STATUS_CHIP,\n STATUS_UI_KEY,\n type CalendarRow,\n type RecurrenceFrequency,\n} from './calendar.model';\nimport {\n AppointmentHistoryTimeline,\n AppointmentIdentity,\n type PatientNotesSeam,\n} from './calendar.sheets';\nimport {\n patientRefOf,\n type CalendarHistoryEntry,\n type CalendarPatient,\n type CalendarSignChannel,\n} from './calendar.types';\nimport { PrivacyHiddenLine, PrivacyIdentityCard } from './calendar-privacy';\nimport {\n DetailsAppointmentCard,\n DetailsPatientCard,\n DetailsTreatmentsCard,\n} from './calendar-appointment-details.sections';\n\nexport type CalendarDocumentKind =\n | 'folder'\n | 'template'\n | 'empty'\n | 'identification'\n | 'webcam'\n | 'bill';\n\n// Legacy create-menu order; host order and duplicate kinds do not change it.\nconst DOCUMENT_KINDS: readonly CalendarDocumentKind[] = [\n 'bill',\n 'folder',\n 'template',\n 'empty',\n 'identification',\n 'webcam',\n];\n\n/** Each create-menu item's glyph, per the icon map's duty for that kind. */\nconst DOCUMENT_ICON: Record<CalendarDocumentKind, ReactNode> = {\n bill: <ReceiptEuro aria-hidden=\"true\" />,\n folder: <Folder aria-hidden=\"true\" />,\n template: <FileText aria-hidden=\"true\" />,\n empty: <File aria-hidden=\"true\" />,\n identification: <IdCard aria-hidden=\"true\" />,\n webcam: <Camera aria-hidden=\"true\" />,\n};\n\n/** One appointment occurrence as the host reads it for the read-only details\n * panel (P-C2). An absent member renders nothing: never a zero, never an\n * empty-state claim. */\nexport interface CalendarAppointmentDetails {\n /** The occurrence id the panel asked for, echoed back. */\n eventId: string;\n appointment: {\n /** Local wall clock of THIS occurrence, 'YYYY-MM-DDTHH:mm:ss', no zone. */\n startIso: string;\n durationMin: number;\n allDay: boolean;\n isTelehealth: boolean;\n /** Absent = no status recorded. */\n status?: CalendarEventStatus;\n name?: string;\n /** Host-composed heading (the platform popover title). */\n title: string;\n colorHex?: string;\n operatorId?: string;\n chairId?: string;\n branchLabel?: string;\n bookedOnline: boolean;\n /** Read side only. `requiresScope` is informational (the series rule\n * line); the scope question lives in the editor. */\n recurrence?: {\n frequency: RecurrenceFrequency;\n count?: number;\n requiresScope: boolean;\n };\n };\n /** Absent = no patient; `phones` carries every labelled number. */\n patient?: CalendarPatient;\n /** Absent = not permitted; an absent figure is gated on its own. */\n money?: { billableAmount?: number; unpaidAmount?: number };\n care?: {\n /** Without `number` the section shows the plan name alone. */\n plan?: { id: string; number?: string; name: string };\n lines: Array<{\n entryId: string;\n careId: string;\n name: string;\n code?: string;\n elementsLabel?: string;\n done: boolean;\n billed: boolean;\n phases: string[];\n /** Absent = prices withheld for this viewer. */\n priceCents?: number;\n }>;\n };\n booking?: {\n typedName?: string;\n phone?: string;\n email?: string;\n note?: string;\n bookedAtIso?: string;\n paidOnlineAmount?: number;\n };\n signing?: {\n required: number;\n toComplete: number;\n requestedVia?: CalendarSignChannel;\n aesSetUp: boolean;\n };\n history: CalendarHistoryEntry[];\n /** Host-owned; the kit never sees the session code. */\n onJoinTelehealth?: () => void;\n /** Host-composed; absent = not available. */\n whatsappUrl?: string;\n /** Host-owned bridge to the practice's WhatsApp snippets; absent = not\n * offered. With `whatsappUrl` too, the one button calls this. */\n onWhatsApp?: () => void;\n /** Server-built link to the task page, same tab; absent = not offered. */\n createTaskUrl?: string;\n /** Host owns permissions and creation/navigation. Independent of appointment readOnly. */\n documents?: {\n kinds: readonly CalendarDocumentKind[];\n onCreate: (kind: CalendarDocumentKind) => void;\n };\n}\n\nexport type CalendarAppointmentDetailsSnapshot =\n | { status: 'ready'; details: CalendarAppointmentDetails }\n | { status: 'refused'; reason: string; retryable?: boolean };\n\n/** A rejected promise is a transient failure (error with Retry); 'refused'\n * means not visible (the reason, with Retry only when retryable). */\nexport type CalendarAppointmentDetailsLoader = (\n eventId: string,\n options: { signal: AbortSignal },\n) => Promise<CalendarAppointmentDetailsSnapshot>;\n\nconst START_ISO = /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})$/;\n\n/** The host's zone-less wall clock as a local Date, or undefined when it is\n * not a real 'YYYY-MM-DDTHH:mm:ss' reading. Ranges are checked rather than\n * round-tripped, so a time inside a daylight-saving gap still parses. */\nexport function parseDetailsStartIso(\n startIso: string | undefined,\n): Date | undefined {\n const match = typeof startIso === 'string' ? START_ISO.exec(startIso) : null;\n if (!match) return undefined;\n const [year, month, day, hours, minutes, seconds] = match\n .slice(1)\n .map(Number);\n const monthEnd = new Date(0);\n monthEnd.setFullYear(year, month, 0);\n if (\n month < 1 ||\n month > 12 ||\n day < 1 ||\n day > monthEnd.getDate() ||\n hours > 23 ||\n minutes > 59 ||\n seconds > 59\n )\n return undefined;\n const start = new Date(0);\n start.setFullYear(year, month - 1, day);\n start.setHours(hours, minutes, seconds, 0);\n return start;\n}\n\ninterface LoadResult {\n eventId: string;\n source: CalendarAppointmentDetailsLoader;\n value:\n | CalendarAppointmentDetailsSnapshot\n | { status: 'error'; reason: string };\n}\n\n/* How many term : detail rows the Appointment card shows while it loads:\n date, time, operator, chair. Widths are uneven so they read as facts. */\nconst SKELETON_FACT_WIDTHS = ['40%', '33%', '50%', '25%'] as const;\n\n/**\n * The details panel while its read is in flight: the panel's own frame, with\n * every card already in place and holding a placeholder in the shape of what\n * will land there. Nothing jumps when the answer arrives, and the reader sees\n * what is coming instead of the word \"Loading\".\n */\nfunction DetailsSkeleton({ eventId }: { eventId: string }) {\n const { t } = useTranslation();\n const key = (suffix: string): string => `calendarWorkspace.details.${suffix}`;\n return (\n <div\n data-component=\"calendar-details-hydration\"\n data-event-id={eventId}\n data-status=\"loading\"\n aria-busy=\"true\"\n className=\"ds:flex ds:h-full ds:flex-col\"\n >\n <span role=\"status\" className=\"ds:sr-only\">\n {t('common.loading')}\n </span>\n <PanelHeader\n title={t(key('region'))}\n icon={<CalendarClock aria-hidden=\"true\" />}\n sticky\n divider\n />\n <div\n aria-hidden=\"true\"\n /* Cards keep their natural height; the column clips at the panel's\n edge, as the scrolling body it stands in for would. */\n className=\"ds:flex ds:min-h-0 ds:flex-1 ds:flex-col ds:gap-[var(--spacing-sm)] ds:overflow-hidden ds:p-[var(--spacing-md)] ds:[&>*]:shrink-0\"\n >\n <PatientSummaryCard\n name=\"\"\n loading\n surface=\"elevated\"\n density=\"compact\"\n />\n <SectionCard title={t(key('sectionAppointment'))} headingLevel={3}>\n <EditableDescription loading maxLines={2} />\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {SKELETON_FACT_WIDTHS.map((width, index) => (\n <div\n key={width}\n className=\"ds:flex ds:items-center ds:gap-[var(--spacing-sm)]\"\n >\n <Skeleton\n variant=\"rounded\"\n stagger={index + 2}\n width=\"var(--spacing-md)\"\n height=\"var(--spacing-md)\"\n className=\"ds:shrink-0\"\n />\n <Skeleton\n variant=\"text\"\n size=\"sm\"\n stagger={index + 2}\n width={width}\n />\n </div>\n ))}\n </div>\n </SectionCard>\n <SectionCard title={t('notesPanel.title')} headingLevel={3}>\n <NoteTimeline notes={[]} loading loadingRows={2} />\n </SectionCard>\n <SectionCard title={t(key('sectionTreatments'))} headingLevel={3}>\n <TreatmentReceipt lines={[]} loading />\n </SectionCard>\n </div>\n <div\n aria-hidden=\"true\"\n className=\"ds:flex ds:shrink-0 ds:items-center ds:gap-[var(--spacing-sm)] ds:border-t ds:border-[color:var(--border)] ds:p-[var(--spacing-md)]\"\n >\n <Skeleton variant=\"rounded\" width=\"33%\" height=\"var(--spacing-xl)\" />\n <Skeleton\n variant=\"rounded\"\n stagger={1}\n height=\"var(--spacing-xl)\"\n className=\"ds:flex-1\"\n />\n </div>\n </div>\n );\n}\n\nexport interface CalendarDetailsHydrationProps {\n /** The occurrence to read; a new id aborts the previous read. */\n eventId: string;\n load: CalendarAppointmentDetailsLoader;\n /** Mounted only with details whose eventId and startIso passed the checks. */\n children: (details: CalendarAppointmentDetails) => ReactNode;\n}\n\n/** The details panel is not mounted until the host's read answers for this\n * occurrence. A late answer for a replaced id or loader is ignored. */\nexport function CalendarDetailsHydration({\n eventId,\n load,\n children,\n}: CalendarDetailsHydrationProps) {\n const { t } = useTranslation();\n const failureMessage = useRef('');\n failureMessage.current = t('emptyState.error.description');\n const [result, setResult] = useState<LoadResult>();\n const [retry, setRetry] = useState(0);\n useEffect(() => {\n const controller = new AbortController();\n setResult(undefined);\n Promise.resolve()\n .then(() => load(eventId, { signal: controller.signal }))\n .then((value) => {\n if (controller.signal.aborted) return;\n if (\n value.status === 'ready' &&\n (value.details?.eventId !== eventId ||\n !parseDetailsStartIso(value.details.appointment?.startIso))\n )\n throw new Error(failureMessage.current);\n setResult({ eventId, source: load, value });\n })\n .catch((error: unknown) => {\n if (!controller.signal.aborted)\n setResult({\n eventId,\n source: load,\n value: {\n status: 'error',\n reason:\n error instanceof Error && error.message.trim()\n ? error.message\n : failureMessage.current,\n },\n });\n });\n return () => controller.abort();\n }, [eventId, load, retry]);\n\n const value =\n result?.eventId === eventId && result.source === load\n ? result.value\n : undefined;\n /* The read always answers after the first paint, so the skeleton always\n shows first and the panel always settles in where it stood. */\n if (value?.status === 'ready') {\n return (\n <div\n data-details-arrived=\"\"\n className={`ds:flex ds:h-full ds:min-h-0 ds:flex-col ${CONTENT_ENTER_CLASS}`}\n >\n {children(value.details)}\n </div>\n );\n }\n if (!value) return <DetailsSkeleton eventId={eventId} />;\n return (\n <div\n data-component=\"calendar-details-hydration\"\n data-event-id={eventId}\n data-status={value.status}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:p-[var(--spacing-md)]\"\n >\n <Alert variant={value.status === 'error' ? 'error' : 'warning'}>\n <Alert.Description>{value.reason}</Alert.Description>\n </Alert>\n {value.status === 'error' || value.retryable ? (\n <Button\n intent=\"outline\"\n onClick={() => setRetry((previous) => previous + 1)}\n >\n {t('emptyState.error.cta')}\n </Button>\n ) : null}\n </div>\n );\n}\n\nexport interface AppointmentDetailsPanelProps {\n /** The occurrence as the host read it (P-C2). */\n details: CalendarAppointmentDetails;\n /** The row's patient id (N-C5); defaults to the read's patient. */\n patientId?: string;\n /** The host's notes seam; without it, no notes card. */\n notesSeam?: PatientNotesSeam;\n /** Route to the host's Notes tool, optionally addressed to one note. */\n onOpenNotes?: (patientId: string, noteId?: string) => void;\n /** Withholds Edit, Move, Copy and the status change; Join, WhatsApp and\n * Create task are the host's. */\n readOnly?: boolean;\n onEdit?: () => void;\n /** Arm a Move placement: the next slot click places the appointment. */\n onMove?: () => void;\n onCopy?: (withTreatments: boolean) => void;\n /** Save a new status for this occurrence. Reject with a user-facing\n * Error and the control shows it and keeps the old status. Absent, the\n * status is shown read-only. */\n onStatusChange?: (status: CalendarEventStatus) => Promise<void>;\n /** Save a new description for this occurrence, as the pencil's sub-view\n * submits it. Reject with a user-facing Error and the sub-view stays open\n * with it. Absent, the description is read-only. */\n onDescriptionChange?: (description: string) => Promise<void>;\n /** The user's map-link setting (platform `showPatientAddressMapLink`). */\n mapsLink?: boolean;\n /** Privacy mode, as on the grid and the hover peek: the identity is\n * masked, personal fields, chips, notes and free text are dropped, and\n * time, operator, chair, status and treatments stay. */\n privacy?: boolean;\n /** The grid's mask for this appointment (`privacyModeTitle`); bullets\n * without one. Read only under `privacy`. */\n privacyTitle?: string;\n locale?: string;\n}\n\n/** The identity strip's row, from the read: a pending chip's placeholder\n * never names the appointment. Shown only when there is no patient card. */\nfunction identityRow(\n details: CalendarAppointmentDetails,\n assigned: boolean,\n): CalendarRow {\n const { appointment, patient, money } = details;\n return {\n event: {\n id: details.eventId,\n title: appointment.title,\n start: appointment.startIso,\n status: appointment.status,\n isTelehealth: appointment.isTelehealth,\n isBookedOnline: appointment.bookedOnline,\n isRecurring: appointment.recurrence !== undefined,\n hasUnassignedPatient: appointment.bookedOnline && !assigned,\n hasHighlightedAnamnesis: (patient?.highlightedAnamnesisCount ?? 0) > 0,\n hasBillableAmount: (money?.billableAmount ?? 0) > 0,\n },\n };\n}\n\nconst STATUS_ORDER: readonly CalendarEventStatus[] = [\n 'confirmed',\n 'waiting',\n 'in_care',\n 'done',\n 'cancelled',\n 'absent',\n];\n/** The control's value for an occurrence nobody has set a status on. */\nconst NO_STATUS = 'none';\n/* Accessible themes keep the kit's raised target; default themes match\n the 32px status control through Button size=\"sm\". */\nconst ACCESSIBLE_TARGET =\n 'ds:[.theme-accessible_&]:[min-block-size:var(--min-target-size)]';\nconst NOTES_PREVIEWED = 3;\n\n/** A footer action that opens a menu. The label is `children` because\n * ButtonGroup keys its collapse stage off a string child. */\nfunction MenuAction({\n children: label,\n startIcon,\n options,\n action,\n intent,\n background,\n size,\n hideLabel,\n}: {\n children: string;\n startIcon: ReactNode;\n options: ReadonlyArray<{\n label: string;\n /** Required: a menu carries an icon on every item or on none. */\n icon: ReactNode;\n action?: string;\n onSelect: () => void;\n }>;\n /** `data-action` on the trigger. */\n action: string;\n intent?: 'outline' | 'primary';\n background?: 'transparent' | 'surface';\n size?: 'sm' | 'md' | 'lg';\n hideLabel?: boolean;\n}) {\n return (\n <DropdownMenu.Root>\n <Tooltip label={label} side=\"top\">\n <DropdownMenu.Trigger asChild>\n <Button\n intent={intent}\n background={background}\n size={size}\n data-action={action}\n className={ACCESSIBLE_TARGET}\n startIcon={startIcon}\n aria-haspopup=\"menu\"\n /* The chevron stays when the label folds: it is what says this\n opens a menu rather than acting. */\n endIcon={<ChevronDown aria-hidden=\"true\" />}\n >\n {hideLabel ? <span className=\"ds:sr-only\">{label}</span> : label}\n </Button>\n </DropdownMenu.Trigger>\n </Tooltip>\n <DropdownMenu.Content align=\"end\">\n {options.map((option) => (\n <DropdownMenu.Item\n key={option.label}\n data-action={option.action}\n startIcon={option.icon}\n onSelect={option.onSelect}\n >\n {option.label}\n </DropdownMenu.Item>\n ))}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n );\n}\n\n/** The patient's latest notes, pinned first, read through the host's seam.\n * A click on a note opens the Notes tool at it; the header button opens\n * the tool from the keyboard. */\nfunction DetailsNotesCard({\n patientId,\n seam,\n onOpenNotes,\n locale,\n}: {\n patientId: string;\n seam: PatientNotesSeam;\n onOpenNotes?: (noteId?: string) => void;\n locale?: string;\n}) {\n const { t } = useTranslation();\n const key = (suffix: string): string => `calendarWorkspace.details.${suffix}`;\n const headingId = useId();\n /* Read the latest notes once per patient, only when the host holds none. */\n const seamRef = useRef(seam);\n seamRef.current = seam;\n const hasLoader = Boolean(seam.onLoad);\n useEffect(() => {\n const current = seamRef.current;\n if (\n current.notes.length === 0 &&\n current.status !== 'loading' &&\n current.complete !== true\n ) {\n current.onLoad?.('preview');\n }\n }, [patientId, hasLoader]);\n const status = seam.status ?? (seam.onLoad ? 'loading' : 'ready');\n const count = seam.total ?? (status === 'ready' ? seam.notes.length : null);\n const more = Math.max(0, (count ?? 0) - NOTES_PREVIEWED);\n const retry = seam.onLoad ? () => seam.onLoad?.('preview') : seam.onRetry;\n const openLabel =\n more > 0 ? t(key('notesMore'), { n: more }) : t(key('notesPreviewOpen'));\n return (\n <SectionCard\n /* `data-card`, not `data-component`: SectionCard's own bounding marker\n must survive, or the kit's cascade reset loses this element. */\n data-card=\"notes\"\n headingId={headingId}\n headingLevel={3}\n title={\n count === null\n ? t('notesPanel.title')\n : t(key('notesPreviewTitle'), { count })\n }\n headerAction={\n onOpenNotes && (count ?? 0) > 0 ? (\n <span className=\"ds:relative ds:inline-flex\">\n <IconButton\n icon={<NotebookPen aria-hidden=\"true\" />}\n intent=\"outline\"\n size=\"sm\"\n data-action=\"open-patient-notes\"\n aria-label={openLabel}\n tooltip={openLabel}\n onClick={() => onOpenNotes()}\n />\n {more > 0 ? (\n /* Decorative: the button's name already says the count. */\n <Counter\n variant=\"outline\"\n size=\"sm\"\n background=\"surface\"\n count={more}\n aria-hidden=\"true\"\n className=\"ds:pointer-events-none ds:absolute ds:-top-[var(--spacing-2xs)] ds:-end-[var(--spacing-2xs)]\"\n />\n ) : null}\n </span>\n ) : undefined\n }\n >\n {status === 'error' ? (\n <Alert variant=\"error\">\n <Alert.Description>{t('notesPanel.loadError')}</Alert.Description>\n {retry ? (\n <Alert.Action>\n <Button intent=\"secondary\" size=\"sm\" onClick={retry}>\n {t('notesPanel.retry')}\n </Button>\n </Alert.Action>\n ) : null}\n </Alert>\n ) : null}\n {seam.notes.length === 0 && status === 'loading' ? (\n <>\n <span role=\"status\" className=\"ds:sr-only\">\n {t('notesPanel.loading')}\n </span>\n <NoteTimeline notes={[]} loading loadingRows={2} />\n </>\n ) : status !== 'error' || seam.notes.length > 0 ? (\n /* A note click or Enter/Space on it goes straight to that note in\n the Notes tool; the header button opens the tool at the top. */\n <NoteTimeline\n notes={seam.notes}\n maxItems={NOTES_PREVIEWED}\n locale={locale}\n aria-labelledby={headingId}\n onNoteActivate={onOpenNotes}\n emptyState={\n <p className=\"ds:m-0 type-body-sm ds:text-[color:var(--muted-foreground)]\">\n {t(key('notesPreviewEmpty'))}\n </p>\n }\n />\n ) : null}\n </SectionCard>\n );\n}\n\n/** The appointment details panel (P-C2, P-C3): the patient card, the\n * appointment, notes and treatments cards, a pinned footer with the\n * status and the actions, and a History sub-view in place of the body.\n * It docks in the rail, is no dialog and asks no series scope. */\nexport function AppointmentDetailsPanel(props: AppointmentDetailsPanelProps) {\n return (\n <AppointmentDetailsPanelContent key={props.details.eventId} {...props} />\n );\n}\n\nfunction AppointmentDetailsPanelContent({\n details,\n patientId = details.patient?.id,\n notesSeam,\n onOpenNotes,\n readOnly = false,\n onEdit,\n onMove,\n onCopy,\n onStatusChange,\n onDescriptionChange,\n mapsLink,\n privacy = false,\n privacyTitle,\n locale,\n}: AppointmentDetailsPanelProps) {\n const { t, i18n: runtimeI18n } = useTranslation();\n const key = (suffix: string): string => `calendarWorkspace.details.${suffix}`;\n const shownLocale = locale ?? runtimeI18n.language;\n const card = { details, locale: shownLocale };\n /* Both sub-views stay mounted and slide over the body; PanelSubview owns\n the focus in and back. */\n const [historyOpen, setHistoryOpen] = useState(false);\n const [editingDescription, setEditingDescription] = useState(false);\n /* The description as last saved here; the read is the starting point. */\n const [description, setDescription] = useState(\n details.appointment.name ?? '',\n );\n /* A fresh read from the host wins over what was saved here. */\n useEffect(() => {\n setDescription(details.appointment.name ?? '');\n }, [details.appointment.name]);\n const [descriptionDraft, setDescriptionDraft] = useState('');\n const [descriptionSaving, setDescriptionSaving] = useState(false);\n const [descriptionError, setDescriptionError] = useState<string>();\n const descriptionFieldRef = useRef<HTMLTextAreaElement>(null);\n /* Filled when the sub-view opens, never by remounting it open. */\n useEffect(() => {\n if (!editingDescription) return;\n setDescriptionDraft(description);\n setDescriptionError(undefined);\n // eslint-disable-next-line react-hooks/exhaustive-deps -- seed once per opening\n }, [editingDescription]);\n const saveDescription = async (): Promise<void> => {\n if (!onDescriptionChange) return;\n const next = descriptionDraft.trim();\n setDescriptionSaving(true);\n setDescriptionError(undefined);\n try {\n await onDescriptionChange(next);\n setDescription(next);\n setEditingDescription(false);\n } catch (error) {\n setDescriptionError(\n error instanceof Error && error.message.trim()\n ? error.message\n : t(key('descriptionSaveFailed')),\n );\n } finally {\n setDescriptionSaving(false);\n }\n };\n /* The status as last saved here; the read is the starting point. */\n const [status, setStatus] = useState(details.appointment.status);\n useEffect(() => {\n setStatus(details.appointment.status);\n }, [details.appointment.status]);\n const [statusSaving, setStatusSaving] = useState(false);\n const [statusError, setStatusError] = useState<string>();\n const statusOptions = useMemo<WorkflowStatusOption[]>(\n () => [\n ...(status\n ? []\n : [\n {\n value: NO_STATUS,\n label: t(key('statusNone')),\n icon: <CircleDashed aria-hidden=\"true\" />,\n tone: 'neutral' as const,\n disabled: true,\n },\n ]),\n ...STATUS_ORDER.map((value) => {\n const { Icon, tone } = STATUS_CHIP[value];\n return {\n value,\n label: t(STATUS_UI_KEY[value]),\n icon: <Icon aria-hidden=\"true\" />,\n tone,\n };\n }),\n ],\n [t, status],\n );\n const changeStatus = async (next: string): Promise<void> => {\n if (!onStatusChange) return;\n const nextStatus = next as CalendarEventStatus;\n setStatusSaving(true);\n setStatusError(undefined);\n try {\n await onStatusChange(nextStatus);\n setStatus(nextStatus);\n } catch (error) {\n setStatusError(\n error instanceof Error && error.message.trim()\n ? error.message\n : t(key('statusSaveFailed')),\n );\n } finally {\n setStatusSaving(false);\n }\n };\n const notesFor = notesSeam && patientId ? patientId : undefined;\n const openNotes =\n notesFor && onOpenNotes\n ? (noteId?: string) => onOpenNotes(notesFor, noteId)\n : undefined;\n const patientRef = patientRefOf(patientId, details.patient);\n const { onJoinTelehealth: join, onWhatsApp } = details;\n /* The composed link carries the patient's number: withheld under privacy. */\n const whatsappUrl = privacy ? undefined : details.whatsappUrl;\n const { createTaskUrl } = details;\n const documents = details.documents;\n const documentKinds = DOCUMENT_KINDS.filter((kind) =>\n documents?.kinds.includes(kind),\n );\n const backLabel = t(key('historyBack'));\n const copyMenu = (details.care?.lines.length ?? 0) > 0;\n const statusLabel = t(key('status'));\n const statusValue = status ?? NO_STATUS;\n const statusControl =\n onStatusChange && !readOnly ? (\n <WorkflowStatusControl\n value={statusValue}\n options={statusOptions}\n size=\"sm\"\n saving={statusSaving}\n errorMessage={statusError}\n workflowLabel={statusLabel}\n /* The trigger itself carries the painted surface of the actions. */\n className=\"ds:[&>button]:bg-[color:var(--background)]\"\n aria-label={`${statusLabel}: ${\n statusOptions.find((option) => option.value === statusValue)?.label ??\n ''\n }`}\n onValueChange={changeStatus}\n />\n ) : status ? (\n <WorkflowStatusDisplay\n value={status}\n size=\"sm\"\n workflowLabel={statusLabel}\n option={statusOptions.find((option) => option.value === status)!}\n />\n ) : null;\n const actions: ReactNode[] = [\n join ? (\n <Button\n key=\"join\"\n intent=\"primary\"\n data-action=\"join-telehealth\"\n className={ACCESSIBLE_TARGET}\n startIcon={<Video aria-hidden=\"true\" />}\n onClick={() => join()}\n >\n {t(key('joinTelehealth'))}\n </Button>\n ) : null,\n !readOnly && onEdit ? (\n <Button\n key=\"edit\"\n data-action=\"edit-appointment\"\n className={ACCESSIBLE_TARGET}\n startIcon={<Pencil aria-hidden=\"true\" />}\n onClick={() => onEdit()}\n >\n {t('calendarWorkspace.editor.editTitle')}\n </Button>\n ) : null,\n !readOnly && onMove ? (\n <Button\n key=\"move\"\n data-action=\"move-appointment\"\n className={ACCESSIBLE_TARGET}\n startIcon={<Move aria-hidden=\"true\" />}\n onClick={() => onMove()}\n >\n {t(key('move'))}\n </Button>\n ) : null,\n !readOnly && onCopy ? (\n copyMenu ? (\n <MenuAction\n key=\"copy\"\n action=\"copy-appointment\"\n data-overflow-pin=\"true\"\n data-overflow-tip={false}\n startIcon={<ClipboardPaste aria-hidden=\"true\" />}\n options={[\n {\n label: t('calendarWorkspace.editor.duplicateAppointmentOnly'),\n icon: <Copy aria-hidden=\"true\" />,\n onSelect: () => onCopy(false),\n },\n {\n label: t('calendarWorkspace.editor.duplicateWithTreatments'),\n icon: <ClipboardList aria-hidden=\"true\" />,\n onSelect: () => onCopy(true),\n },\n ]}\n >\n {t(key('copy'))}\n </MenuAction>\n ) : (\n <Button\n key=\"copy\"\n data-action=\"copy-appointment\"\n className={ACCESSIBLE_TARGET}\n startIcon={<ClipboardPaste aria-hidden=\"true\" />}\n onClick={() => onCopy(false)}\n >\n {t(key('copy'))}\n </Button>\n )\n ) : null,\n documents && documentKinds.length > 0 ? (\n <MenuAction\n key=\"documents\"\n action=\"open-create-document\"\n data-overflow-pin=\"true\"\n data-overflow-tip={false}\n startIcon={<Plus aria-hidden=\"true\" />}\n options={documentKinds.map((kind) => ({\n label: t(key(`documents.${kind}`)),\n icon: DOCUMENT_ICON[kind],\n action: `create-document-${kind}`,\n onSelect: () => documents.onCreate(kind),\n }))}\n >\n {t(key('documents.label'))}\n </MenuAction>\n ) : null,\n onWhatsApp ? (\n <Button\n key=\"whatsapp\"\n data-action=\"open-whatsapp\"\n className={ACCESSIBLE_TARGET}\n startIcon={<WhatsAppGlyph aria-hidden=\"true\" />}\n onClick={() => onWhatsApp()}\n >\n {t(key('remindWhatsApp'))}\n </Button>\n ) : whatsappUrl ? (\n <Button\n key=\"whatsapp\"\n asChild\n data-action=\"open-whatsapp\"\n className={ACCESSIBLE_TARGET}\n startIcon={<WhatsAppGlyph aria-hidden=\"true\" />}\n >\n <a href={whatsappUrl} target=\"_blank\" rel=\"noopener noreferrer\">\n {t(key('remindWhatsApp'))}\n </a>\n </Button>\n ) : null,\n createTaskUrl ? (\n <Button\n key=\"task\"\n asChild\n data-action=\"create-task\"\n className={ACCESSIBLE_TARGET}\n startIcon={<SquareCheckBig aria-hidden=\"true\" />}\n >\n <a href={createTaskUrl}>{t(key('createTask'))}</a>\n </Button>\n ) : null,\n ].filter(Boolean);\n return (\n <div\n data-component=\"calendar-appointment-details\"\n data-event-id={details.eventId}\n className=\"ds:flex ds:h-full ds:flex-col\"\n >\n <PanelSubview.Host>\n <PanelHeader\n title={t(key('region'))}\n icon={<CalendarClock aria-hidden=\"true\" />}\n sticky\n divider\n actions={\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<HistoryIcon aria-hidden=\"true\" />}\n aria-label={t(key('historyAction'))}\n tooltip={t(key('historyAction'))}\n onClick={() => setHistoryOpen(true)}\n />\n }\n />\n <div\n /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- the body scrolls inside the rail; axe scrollable-region-focusable needs the tab stop */\n tabIndex={0}\n className=\"ds:[min-block-size:0] ds:flex-1 ds:overflow-y-auto\"\n >\n {\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:p-[var(--spacing-md)]\">\n {privacy ? (\n <PrivacyIdentityCard mask={privacyTitle} />\n ) : details.patient ? (\n <DetailsPatientCard {...card} mapsLink={mapsLink} />\n ) : (\n /* No patient card to carry the identity: a patient-less, an\n unassigned or an unresolved one keeps the strip. */\n <AppointmentIdentity\n row={identityRow(details, patientRef.assigned)}\n patientRef={patientRef}\n />\n )}\n <DetailsAppointmentCard\n {...card}\n privacy={privacy}\n description={\n /* Not keyed on the text: the pencil must survive a save, so\n the sub-view can hand focus back to it. An empty read-only\n description prints nothing. Privacy hides text and pencil. */\n privacy ? (\n description ? (\n <PrivacyHiddenLine block=\"description\" />\n ) : undefined\n ) : description || (onDescriptionChange && !readOnly) ? (\n <EditableDescription\n data-block=\"description\"\n role=\"group\"\n aria-label={t('calendarWorkspace.editor.description')}\n value={description}\n editLabel={t(key('editDescription'))}\n onEdit={\n onDescriptionChange && !readOnly\n ? () => setEditingDescription(true)\n : undefined\n }\n />\n ) : undefined\n }\n />\n {notesFor && notesSeam && privacy ? (\n <SectionCard\n data-card=\"notes\"\n title={t('notesPanel.title')}\n headingLevel={3}\n >\n <PrivacyHiddenLine />\n </SectionCard>\n ) : notesFor && notesSeam ? (\n <DetailsNotesCard\n patientId={notesFor}\n seam={notesSeam}\n onOpenNotes={openNotes}\n locale={locale}\n />\n ) : null}\n <DetailsTreatmentsCard {...card} privacy={privacy} />\n </div>\n }\n </div>\n {statusControl || actions.length > 0 ? (\n /* The body scrolls; the status and the actions stay put. Status\n keeps its own segment: it is a readout as much as a control, so it\n never folds to a bare glyph. The actions collapse to icons, then\n spill into the overflow menu, never onto a second line. */\n <div className=\"ds:flex ds:shrink-0 ds:items-center ds:justify-end ds:gap-[var(--spacing-xs)] ds:border-t ds:border-[color:var(--border)] ds:p-[var(--spacing-sm)]\">\n {statusControl}\n {actions.length > 0 ? (\n <ButtonGroup\n label={t(key('actionsLabel'))}\n overflow=\"menu\"\n collapseToIcons\n background=\"surface\"\n size=\"sm\"\n className=\"ds:min-w-0 ds:flex-1 ds:text-end\"\n >\n {actions}\n </ButtonGroup>\n ) : null}\n </div>\n ) : null}\n <PanelSubview\n open={historyOpen}\n icon={<HistoryIcon aria-hidden=\"true\" />}\n title={t(key('historyTitle'))}\n backLabel={backLabel}\n headingLevel={3}\n onBack={() => setHistoryOpen(false)}\n data-details-subview=\"history\"\n >\n <div className=\"ds:p-[var(--spacing-md)]\">\n <AppointmentHistoryTimeline\n history={sortHistoryNewestFirst(details.history)}\n locale={locale}\n />\n </div>\n </PanelSubview>\n {onDescriptionChange && !readOnly && !privacy ? (\n <PanelSubview\n open={editingDescription}\n icon={<Pencil aria-hidden=\"true\" />}\n title={t(key('editDescription'))}\n backLabel={backLabel}\n headingLevel={3}\n initialFocusRef={descriptionFieldRef}\n /* Back and Escape wait for a save in flight, as Cancel does: a\n late resolve must not close an editor the user has reopened. */\n onBack={() => {\n if (!descriptionSaving) setEditingDescription(false);\n }}\n data-details-subview=\"description\"\n footer={\n <>\n <Button\n intent=\"secondary\"\n disabled={descriptionSaving}\n onClick={() => setEditingDescription(false)}\n >\n {t(key('noteCancel'))}\n </Button>\n <Button\n intent=\"primary\"\n data-action=\"save-description\"\n loading={descriptionSaving}\n onClick={() => void saveDescription()}\n >\n {t(key('descriptionSave'))}\n </Button>\n </>\n }\n >\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:p-[var(--spacing-md)]\">\n {descriptionError ? (\n <Alert variant=\"error\">\n <Alert.Description>{descriptionError}</Alert.Description>\n </Alert>\n ) : null}\n <TextArea\n ref={descriptionFieldRef}\n value={descriptionDraft}\n minRows={6}\n autoResize\n aria-label={t('calendarWorkspace.editor.description')}\n onChange={(event) => setDescriptionDraft(event.target.value)}\n />\n </div>\n </PanelSubview>\n ) : null}\n </PanelSubview.Host>\n </div>\n );\n}\n","import { useEffect, useRef, useState, type ReactNode } from 'react';\n\n/** Keep the editor draft mounted while visiting Notes, and vice versa. */\nexport function CalendarNotesDock({\n editor,\n notes,\n active,\n request,\n}: {\n editor: ReactNode;\n notes: ReactNode;\n active: boolean;\n request: number;\n}) {\n const [visited, setVisited] = useState(active);\n const panel = useRef<HTMLDivElement>(null);\n useEffect(() => {\n if (active) {\n setVisited(true);\n // A child may already have focused the addressed note for this request.\n if (!panel.current?.contains(document.activeElement))\n panel.current?.focus();\n }\n }, [active, request]);\n return (\n <>\n <div hidden={active} className=\"ds:h-full ds:min-h-0\">\n {editor}\n </div>\n <div\n ref={panel}\n hidden={!active}\n tabIndex={-1}\n data-component=\"calendar-notes-tool\"\n className=\"ds:h-full ds:min-h-0\"\n >\n {active || visited ? notes : null}\n </div>\n </>\n );\n}\n\n/** A canonical details read may resolve a patient before the grid's names do. */\nexport function CalendarPatientContext({\n patientId,\n onChange,\n}: {\n patientId?: string;\n onChange: (patientId?: string) => void;\n}) {\n useEffect(() => {\n onChange(patientId);\n }, [patientId, onChange]);\n return null;\n}\n","/**\n * Calendar pattern — the PAGE SURFACE the workspace's rail wraps:\n * the platform's toolbar rebuilt from kit primitives (New appointment,\n * the Waiting list split button, Find free slots, the chair / operator\n * filters with platform semantics, the Reset chip, privacy, print — a\n * day dialog that prints THAT day's call sheet, not the visible range —\n * scheduler, settings and the display cog), a sticky navigation row\n * (jump-to-date, the Google-Calendar-style view menu with keyboard\n * shortcuts, today / prev / next), the parity `Calendar` grid with its\n * closures and washes, the hover peek, an immediate resize with an Undo\n * toast, the drag-move confirmation dialog (with the recurring scope),\n * the Move… / Copy… placement modes armed from the details panel, the\n * post-save \"Saved for {date} · Go to\" toast and the read-only mode.\n *\n * Domain state is owned by the host's `CalendarJourney` (calendar.journey.ts)\n * and arrives as props; practice data is read through `useCalendarData()`\n * (calendar.data.ts); the surface keeps view, filter and UI state. Its\n * secondary surfaces open through `useSheetHost()` (calendar.host.ts),\n * which the workspace maps onto the Control Room rail; only the\n * confirmations stay kit `Dialog`s.\n */\nimport {\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport {\n Armchair,\n CalendarSearch,\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n Eye,\n EyeOff,\n Globe,\n Hourglass,\n ListPlus,\n Plus,\n Printer,\n RotateCcw,\n SlidersHorizontal,\n UserCog,\n} from 'lucide-react';\nimport {\n Calendar,\n type CalendarDateClickInfo,\n type CalendarDatesSetInfo,\n type CalendarEvent,\n type CalendarEventClickMeta,\n type CalendarEventDropInfo,\n type CalendarEventResizeInfo,\n type CalendarHandle,\n type CalendarResource,\n type CalendarView,\n} from '../../components/calendar';\nimport { VisuallyHidden } from '../../components/visually-hidden';\nimport { Avatar } from '../../components/avatar';\nimport { Badge } from '../../components/badge';\nimport { Card } from '../../components/card';\nimport { Checkbox } from '../../components/checkbox';\nimport { KeyValuePair } from '../../components/key-value-pair';\nimport { Kbd } from '../../components/kbd';\nimport { NumberInput } from '../../components/number-input';\nimport { ResourceChip } from '../../components/resource-chip';\nimport { Tag } from '../../components/tag';\nimport { Switch } from '../../components/switch';\nimport { Button, IconButton } from '../../components/button';\nimport { ButtonGroup } from '../../components/button-group';\nimport { DatePicker } from '../../components/date-picker';\nimport { Dialog } from '../../components/dialog';\nimport { DropdownMenu } from '../../components/dropdown-menu';\nimport { FormField } from '../../components/form-field';\nimport { Popover } from '../../components/popover';\nimport { AppointmentPeek } from '../../components/appointment-peek';\nimport { HoverCard } from '../../components/hover-card';\nimport { Radio, RadioGroup } from '../../components/radio-group';\nimport { Select } from '../../components/select';\nimport { ScrollArea } from '../../components/scroll-area';\nimport { Tooltip } from '../../components/tooltip';\nimport { toastInfo, toastSuccess, toastWarning } from '../../components/toast';\nimport {\n associationColor,\n buildOperatorFilterGroups,\n careSuffix,\n} from './calendar.types';\nimport {\n CALENDAR_PREFERENCE_KEYS,\n type CalendarPreferenceAdapter,\n readBoolean,\n usePersistedPreference,\n} from './calendar.preferences';\nimport { useSheetHost } from './calendar.host';\nimport { useCalendarData } from './calendar.data';\nimport {\n type CalendarRow,\n type PendingMove,\n movesSilently,\n type RailFocus,\n type DisplaySettings,\n readChairIds,\n readOperatorIds,\n selectionState,\n formatTimeRange,\n formatDay,\n type EditorPrefill,\n editPrefillFromRow,\n DRAFT_SNAP,\n type HistoryInput,\n processBookingPrefill,\n localIsoDate,\n buildUnavailabilityEvents,\n type AvailabilityContext,\n type CalendarFreeSlot,\n isClosureEvent,\n buildClosureBanners,\n buildPrintSheet,\n closureReason,\n mergeAvailabilityRanges,\n buildFreeBands,\n maskedTitle,\n patientRefById,\n} from './calendar.model';\nimport {\n channelOfferable,\n channelReady,\n channelReasonKey,\n patientIdOf,\n patientRefName,\n} from './calendar.types';\nimport {\n type WorkspaceDisplaySettings,\n type WorkspaceViewId,\n WORKSPACE_VIEWS,\n WORKSPACE_VIEW_STEM,\n VIEW_SHORTCUT_KEYS,\n DEFAULT_DURATION_RANGE,\n activeFilterCount,\n bookedDisabledOperatorIds,\n chairResourceTitle,\n columnableOperatorIds,\n effectiveIds,\n listedOperators,\n operatorResourceTitle,\n workspaceDayWindow,\n minutesBetween,\n practiceDayWindow,\n readWorkspaceViewId,\n shortcutViewForKeydown,\n toggleSelectedIds,\n weekendHiddenDays,\n type CreateModeRequest,\n type PlacementRequest,\n type SaveNotice,\n type RecurringScope,\n RECURRING_SCOPES,\n RECURRING_SCOPE_LABEL_KEY,\n bannerTextColor,\n copyRowAt,\n rowsWithEnd,\n seriesScopeEventIds,\n hiddenReasons,\n WORKSPACE_TOOL,\n type CalendarWorkspaceToolId,\n signChannelStates,\n} from './calendar-workspace.model';\nimport { IndicatorChips, PrintSheet } from './calendar.sheets';\nimport type { CalendarOccurrenceMove } from './calendar.journey';\n\n/* The kit Calendar's instance id — the agent registry's handle for this\n grid and the DOM hook anything outside React reaches it by. Stable and\n host-overridable (`CalendarWorkspaceProps.id`) so two workspaces on one\n page do not collide. */\nconst DEFAULT_CALENDAR_ID = 'calendar-workspace';\n\n/* Row 2 is sticky under the app header; FullCalendar's own sticky date\n header would slide under it, so the grid's header offsets by the same\n height (FC pins it at top:0 with a three-class selector, hence the\n important). Keep the minimum separate from the measured offset so a\n classic scrollbar cannot create a resize feedback loop. */\nconst NAV_BLOCK_SIZE_CLASS = 'ds:[--inc1-nav-block-size:3.5rem]';\nconst FC_STICKY_OFFSET_CLASS =\n 'ds:[&_.fc-scrollgrid-section-sticky>*]:!top-[var(--inc1-nav-offset,var(--inc1-nav-block-size))]';\n\n/* ------------------------------------------------------------------ */\n/* The page surface — header card + sticky navigation + calendar card */\n/* ------------------------------------------------------------------ */\n\n/* A counted action: the IconButton carries the count in its accessible\n name, and the Badge is the decorative echo pinned to its corner. */\nconst BADGED_ACTION_CLASS = 'ds:relative ds:inline-flex';\nconst ACTION_BADGE_CLASS =\n 'ds:pointer-events-none ds:absolute ds:-top-1 ds:-end-1 ds:z-10';\n\nexport function CalendarSurface({\n rows,\n setRows,\n onFocus,\n locale,\n onComposeNew,\n onOpenWaitingList,\n onAddWaitingEntry,\n onOpenOnlineBookings,\n onlineBookingsCount,\n waitingBadgeCount,\n onVisibleRangeChange,\n selectedEventId,\n gotoRequest,\n onBookSlot,\n onBookSlotFromFinder,\n display,\n setDisplay,\n onHistory,\n readOnly = false,\n reviewOnlyEventIds,\n detailsOnEveryClick = false,\n placement = null,\n onPlacementEnd,\n createMode = null,\n onCreateModeEnd,\n focusScroll = null,\n saveNotice = null,\n privacy,\n onPrivacyChange,\n availability,\n availabilityContext,\n availableTools,\n schedulerLicenseKey,\n id = DEFAULT_CALENDAR_ID,\n preferences,\n onMoveOccurrence,\n}: {\n rows: CalendarRow[];\n setRows: React.Dispatch<React.SetStateAction<CalendarRow[]>>;\n onFocus: (focus: RailFocus) => void;\n locale: string;\n /** Masks patient names on the grid, the peek and the print sheet. Owned\n * by the journey so the rail's Appointments panel masks in step. */\n privacy: boolean;\n onPrivacyChange: (next: boolean) => void;\n /** The finder's live projection: free ranges glow, booked cards dim,\n * and a band opens its original choices. Null when no search is shown. */\n availability: CalendarFreeSlot[] | null;\n availabilityContext: AvailabilityContext | null;\n /** No edit permission: no drag, no slot-click create. */\n readOnly?: boolean;\n /** Host queue rows whose canonical editor data is not available yet. */\n reviewOnlyEventIds?: ReadonlySet<string>;\n /** The host reads its own details: every row click focuses, including\n * patient-less and pending rows. Off, a pending chip stays inert. */\n detailsOnEveryClick?: boolean;\n /** A Move… / Copy… armed from the details panel — the grid shows the\n * mode banner and the next empty-slot click places the appointment. */\n placement?: PlacementRequest | null;\n /** The placement landed (`true`) or was cancelled. */\n onPlacementEnd?: (landed?: boolean) => void;\n /** A create mode armed by a deep link or the Backlog's Schedule — the\n * banner stands until the next empty-slot click or Cancel. */\n createMode?: CreateModeRequest | null;\n /** The create mode landed or was cancelled. */\n onCreateModeEnd?: () => void;\n /** Deep link `focusAppointmentId`: scroll the card into view and ring\n * it. Tick-keyed so the same id can be re-focused. */\n focusScroll?: { tick: number; eventId: string } | null;\n /** A save just landed — toast \"Saved for {date}\" and, when the day is\n * off screen or filtered out, a Go to action (decision 10). */\n saveNotice?: SaveNotice | null;\n /** New appointment — seeds a clean editor (the host docks the panel). */\n onComposeNew: () => void;\n /** The split button's main segment — the waiting-list panel. */\n onOpenWaitingList: () => void;\n /** The split button's plus segment — the waiting-list entry form. */\n onAddWaitingEntry: () => void;\n /** Waiting ENTRIES only — online bookings carry their own count. */\n waitingBadgeCount: number;\n /** The Online bookings button — the platform's page hop (a toast). */\n onOpenOnlineBookings: () => void;\n /** Bookings of the last thirty days still missing a patient or an\n * operator — the count the platform's alert strip carries. */\n onlineBookingsCount: number;\n /** The grid event whose details panel is docked — ringed on the grid. */\n selectedEventId: string | null;\n /** Navigate seam — tick-keyed so re-steering to the same day works. */\n gotoRequest: { tick: number; date: Date } | null;\n /** Seed the editor prefilled (an empty-slot click, a booking to process). */\n onBookSlot: (prefill: EditorPrefill) => void;\n onBookSlotFromFinder: (prefill: EditorPrefill) => void;\n /** The cog's settings — owned by the journey (the editor reads them). */\n display: WorkspaceDisplaySettings;\n setDisplay: React.Dispatch<React.SetStateAction<WorkspaceDisplaySettings>>;\n /** Ledger feed — a committed drag or resize of a patient appointment. */\n onHistory: (eventId: string, entry: HistoryInput) => void;\n /** The grid's visible range (epoch ms) — scopes the unconfirmed queue. */\n onVisibleRangeChange: (range: { start: number; end: number }) => void;\n /** The rail tools this host can back. A toolbar control whose tool is\n * not in the set is not rendered at all — a button that opens a\n * panel the host has no data for is worse than a missing one. */\n availableTools: ReadonlySet<CalendarWorkspaceToolId>;\n /** The host's FullCalendar Scheduler licence key, handed to the kit\n * `Calendar`. Undefined leaves the component on its own environment\n * default — the grid behaves exactly as it did without this prop. */\n schedulerLicenseKey?: string;\n /** The kit Calendar's instance id — the agent registry's handle and a\n * public DOM hook. One workspace per page keeps the default. */\n id?: string;\n /** Where the toolbar's remembered choices live — the host's per-user\n * store. Defaults to the session-scoped in-memory adapter. */\n preferences?: CalendarPreferenceAdapter;\n /** The host's series move (S-C8). With it, a recurring parent's move\n * always confirms, asks the scope and hides the notify boxes. */\n onMoveOccurrence?: (move: CalendarOccurrenceMove) => Promise<void>;\n}) {\n const { t } = useTranslation();\n const data = useCalendarData();\n const { t: tUi } = useTranslation();\n const { open: openSheet } = useSheetHost();\n const key = (suffix: string): string => `calendarWorkspace.${suffix}`;\n const inc1 = (suffix: string): string => `calendarWorkspace.inc1.${suffix}`;\n\n const calRef = useRef<CalendarHandle>(null);\n const [freeBand, setFreeBand] = useState<{\n event: CalendarEvent;\n el: HTMLElement;\n source: CalendarFreeSlot[];\n } | null>(null);\n const bookingFreeBand = useRef(false);\n const freeBandId = useId();\n useEffect(() => {\n if (!freeBand) return;\n const observer = new MutationObserver(() => {\n if (!freeBand.el.isConnected) setFreeBand(null);\n });\n const root = freeBand.el.closest('[data-component=\"calendar\"]');\n if (root) observer.observe(root, { childList: true, subtree: true });\n return () => observer.disconnect();\n }, [freeBand]);\n useEffect(\n () => setFreeBand(null),\n [availability, display.resourceKind, display.orientation],\n );\n const freeOptions = useMemo(() => {\n if (!freeBand || availability !== freeBand.source) return [];\n const from = new Date(freeBand.event.start).getTime();\n const to = new Date(freeBand.event.end ?? freeBand.event.start).getTime();\n const identity = (slot: CalendarFreeSlot) =>\n JSON.stringify([\n slot.start.getTime(),\n slot.durationMin,\n slot.chairId,\n slot.operatorId,\n slot.careId,\n slot.medicalDeviceId,\n ]);\n const valid = new Set(\n buildFreeBands(availability).flatMap((band) =>\n band.options.map(identity),\n ),\n );\n return availability.filter(\n (slot) =>\n valid.delete(identity(slot)) &&\n slot.start.getTime() < to &&\n slot.start.getTime() + slot.durationMin * 60000 > from &&\n (!freeBand.event.resourceId ||\n (display.resourceKind === 'operator'\n ? slot.operatorId\n : slot.chairId) === freeBand.event.resourceId),\n );\n }, [availability, freeBand, display.resourceKind]);\n const surfaceRef = useRef<HTMLDivElement>(null);\n const navigationRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n const navigation = navigationRef.current;\n const surface = surfaceRef.current;\n if (!navigation || !surface) return;\n // Measured geometry exception: src/docs/23-constraints.mdx,\n // Runtime-computed dimensions. The minimum remains token-based.\n const measure = () => {\n surface.style.setProperty(\n '--inc1-nav-offset',\n `${navigation.getBoundingClientRect().height}px`,\n );\n };\n measure();\n const observer = new ResizeObserver(measure);\n observer.observe(navigation);\n return () => observer.disconnect();\n }, []);\n /* The Reset chip's focus destination — see `resetFilters`. */\n const chairFilterButtonRef = useRef<HTMLButtonElement>(null);\n /* REMEMBERED per user under Increment 1's own keys — the view, the\n weekend choice and the chair / operator selections (platform\n DoctorAddressUser parity), validated on read. */\n const [viewOptionId, setViewOptionId] =\n usePersistedPreference<WorkspaceViewId>(\n CALENDAR_PREFERENCE_KEYS.view,\n 'day',\n readWorkspaceViewId,\n preferences,\n );\n const [showWeekends, setShowWeekends] = usePersistedPreference<boolean>(\n CALENDAR_PREFERENCE_KEYS.showWeekends,\n true,\n readBoolean,\n preferences,\n );\n /* Platform semantics: the TICKED ids; nothing ticked shows everyone. */\n const [selectedChairIds, setSelectedChairIds] = usePersistedPreference<\n string[]\n >(\n CALENDAR_PREFERENCE_KEYS.chairIds,\n () => [],\n readChairIds(data),\n preferences,\n );\n const [selectedOperatorIds, setSelectedOperatorIds] = usePersistedPreference<\n string[]\n >(\n CALENDAR_PREFERENCE_KEYS.operatorIds,\n () => [],\n readOperatorIds(data),\n preferences,\n );\n /* Owned by the journey, not here: the rail's Appointments panel lists\n the same names, so one flag has to mask both surfaces at once. */\n const setPrivacy = (next: (prev: boolean) => boolean): void =>\n onPrivacyChange(next(privacy));\n /* The LIVE focused date (for the jump-to-date picker) is kept apart from\n the `initialDate` handed to the Calendar: feeding each `onDatesSet`\n date back into `initialDate` would make FullCalendar treat every\n echo as a navigation — an infinite loop. `mountDate` only changes on\n a view switch, where the `key` remount re-derives the whole grid. */\n const [currentDate, setCurrentDate] = useState<Date>(\n () => new Date(`${data.initialDateIso}T00:00:00`),\n );\n const currentDateRef = useRef<Date>(currentDate);\n const [mountDate, setMountDate] = useState<Date>(currentDate);\n /* ON by default (platform: automatic in operator views); the switch\n in the operator popover turns it off for the session. */\n const [onlyAvailable, setOnlyAvailable] = useState(true);\n /* Disabled (inactive) operators are OUT of the filter list until this\n session switch reveals them — never persisted, so every reload\n starts from the practice's active cast. */\n const [showDisabledOperators, setShowDisabledOperators] = useState(false);\n /* The cog sits inside the joined icon group, which clones its children\n — so its popover is controlled and anchored to the button. */\n const [settingsOpen, setSettingsOpen] = useState(false);\n const [chairFilterOpen, setChairFilterOpen] = useState(false);\n const [operatorFilterOpen, setOperatorFilterOpen] = useState(false);\n const settingsButtonRef = useRef<HTMLButtonElement>(null);\n /* A10 — the platform's \"Stampa giornata\" asks for a day first and\n prints THAT day. `printPending` fires the print one commit later,\n so the call sheet is already rebuilt for the chosen day. */\n const [printOpen, setPrintOpen] = useState(false);\n const [printDay, setPrintDay] = useState<Date>(\n () => new Date(`${data.initialDateIso}T00:00:00`),\n );\n const [printPending, setPrintPending] = useState(false);\n const [rangeTitle, setRangeTitle] = useState('');\n const [peek, setPeek] = useState<{\n event: CalendarEvent;\n el: HTMLElement;\n } | null>(null);\n /* Drag-move confirmation: the pending change + FullCalendar's revert\n stash while the dialog asks about notifying the patient. While\n non-null, NO code path may mutate `rows` — revert() dies once events\n re-parse. Resize never lands here (immediate + Undo toast). */\n const [pendingMove, setPendingMove] = useState<PendingMove | null>(null);\n const [notifySms, setNotifySms] = useState(false);\n const [notifyEmail, setNotifyEmail] = useState(false);\n const [moveReadout, setMoveReadout] = useState('');\n /* Series member: which occurrences the confirmed move applies to. */\n const [moveScope, setMoveScope] = useState<RecurringScope>('this');\n const copyCountRef = useRef(0);\n /* S-C8 M2, M3, M5: the host carries the scope of a recurring parent. */\n const hostSeriesMove = useCallback(\n (event: CalendarEvent): boolean =>\n onMoveOccurrence !== undefined && event.isRecurrenceParent === true,\n [onMoveOccurrence],\n );\n\n const visibleRangeRef = useRef<{ start: number; end: number } | null>(null);\n const [visibleRange, setVisibleRange] = useState<{\n start: Date;\n end: Date;\n } | null>(null);\n const isDateVisible = useCallback((date: Date): boolean => {\n const range = visibleRangeRef.current;\n if (!range) return false;\n const t = date.getTime();\n return t >= range.start && t < range.end;\n }, []);\n useEffect(() => {\n /* Navigate only when the target day is off-screen (3-day and week\n views carry no dateAlignment — an unconditional gotoDate would\n re-anchor the window under the user). */\n if (gotoRequest && !isDateVisible(gotoRequest.date)) {\n calRef.current?.gotoDate(gotoRequest.date);\n }\n }, [gotoRequest, isDateVisible]);\n\n const stem = WORKSPACE_VIEW_STEM[viewOptionId];\n const isMonth = stem === 'Month';\n /* Month has no resource variant (platform parity) — the plain axis. */\n const axisKind: DisplaySettings['resourceKind'] = isMonth\n ? 'none'\n : display.resourceKind;\n const calendarView: CalendarView = isMonth\n ? 'dayGridMonth'\n : axisKind === 'none'\n ? (`timeGrid${stem}` as CalendarView)\n : (`resourceTimeGrid${stem}${axisKind === 'operator' ? 'Operator' : 'Chair'}` as CalendarView);\n\n /* Plain grids show the union of free time; resource grids keep their ranges. */\n const projecting = availability !== null && availability.length > 0;\n\n const allChairIds = useMemo(() => data.chairs.map((c) => c.id), [data]);\n /* The carve-out set: disabled operators still booked in the visible\n range keep a column whatever the reveal switch says, so hiding them\n can never hide an appointment (platform Library.js). */\n const keptDisabledIds = useMemo(\n () =>\n bookedDisabledOperatorIds(\n rows,\n data.inactiveOperatorIds,\n visibleRange\n ? {\n start: visibleRange.start.getTime(),\n end: visibleRange.end.getTime(),\n }\n : null,\n ),\n [rows, visibleRange, data],\n );\n const allOperatorIds = useMemo(\n () =>\n columnableOperatorIds({\n operators: data.operators,\n inactiveIds: data.inactiveOperatorIds,\n showDisabled: showDisabledOperators,\n keepIds: keptDisabledIds,\n }),\n [showDisabledOperators, keptDisabledIds, data],\n );\n const visibleChairIds = useMemo(\n () => effectiveIds(selectedChairIds, allChairIds),\n [selectedChairIds, allChairIds],\n );\n const visibleOperatorIds = useMemo(\n () => effectiveIds(selectedOperatorIds, allOperatorIds),\n [selectedOperatorIds, allOperatorIds],\n );\n const hiddenDays = useMemo(\n () => weekendHiddenDays(showWeekends),\n [showWeekends],\n );\n /* ---- day load state → the grid's loading wash --------------------- */\n /* Map present: every VISIBLE date it does not name 'ready' is one the\n host has not finished loading. Absent: nothing to wash. */\n const loadingDates = useMemo<readonly string[] | undefined>(() => {\n const state = data.dayLoadState;\n if (!state || !visibleRange) return undefined;\n const dates: string[] = [];\n const cursor = new Date(visibleRange.start);\n cursor.setHours(0, 0, 0, 0);\n while (cursor.getTime() < visibleRange.end.getTime()) {\n const iso = localIsoDate(cursor);\n if (state[iso] !== 'ready') dates.push(iso);\n cursor.setDate(cursor.getDate() + 1);\n }\n return dates;\n }, [data.dayLoadState, visibleRange]);\n const dayWindow = workspaceDayWindow(display.window, data);\n\n /* ONE day — the day the print dialog asked for, never the visible\n range (A10). The chair/operator filters still scope it, as the\n platform's PDF uses the user's persisted selection. */\n const printDays = useMemo<Date[]>(() => {\n const day = new Date(printDay);\n day.setHours(0, 0, 0, 0);\n return [day];\n }, [printDay]);\n const printSections = useMemo(\n () =>\n buildPrintSheet(\n {\n rows,\n days: printDays,\n axisKind,\n visibleChairIds,\n visibleOperatorIds,\n privacy,\n },\n data,\n ),\n [\n rows,\n printDays,\n axisKind,\n visibleChairIds,\n visibleOperatorIds,\n privacy,\n data,\n ],\n );\n /* The sheet is rebuilt by the commit that stored the chosen day, so\n printing one effect later can never print the previous day. */\n useEffect(() => {\n if (!printPending) return;\n setPrintPending(false);\n window.print();\n }, [printPending]);\n\n const fcEvents = useMemo<CalendarEvent[]>(() => {\n const mapped = rows\n /* Platform behaviour: a filtered-out chair/operator hides its\n events in EVERY view, not only its column. */\n .filter(\n (r) =>\n (!r.chairId || visibleChairIds.includes(r.chairId)) &&\n (!r.operatorId || visibleOperatorIds.includes(r.operatorId)),\n )\n .map((r) => ({\n ...r.event,\n resourceId: axisKind === 'operator' ? r.operatorId : r.chairId,\n suffix: careSuffix(\n { description: r.description, cares: r.cares },\n display.careDescription,\n ),\n /* Per-event `editable: true` is the COMPONENT's documented escape\n hatch from a calendar-level `editable={false}` — so host row\n data could re-open drag and resize on a read-only grid. Here\n `readOnly` is a permission, not a default, and a permission\n nothing in the payload may widen: both flags are overwritten\n AFTER the spread. */\n ...(readOnly || reviewOnlyEventIds?.has(r.event.id)\n ? { editable: false, startEditable: false }\n : {}),\n }));\n /* The shading window follows the live focused date so navigation\n stays shaded and bannered (Month spans up to 42 days). */\n const shadeFrom = new Date(currentDate);\n shadeFrom.setDate(shadeFrom.getDate() - (isMonth ? 42 : 7));\n const shadeTo = new Date(currentDate);\n shadeTo.setDate(shadeTo.getDate() + (isMonth ? 42 : 13));\n const columnsHiddenWhenAbsent =\n onlyAvailable && display.orientation === 'vertical' && !isMonth;\n const closureBanners = buildClosureBanners(\n {\n axisKind,\n rangeStart: shadeFrom,\n rangeEnd: shadeTo,\n visibleChairIds,\n visibleOperatorIds,\n columnsHiddenWhenAbsent,\n labels: {\n closed: t(key('print.closedDay')),\n holiday: (name) => t(key('closures.holidayBanner'), { name }),\n absence: (title) =>\n title\n ? t(key('closures.operatorAbsentTitled'), { title })\n : t(key('closures.operatorAbsent')),\n },\n },\n data,\n );\n /* Availability projection (\"Show in calendar\"): each free slot becomes\n a background event on its axis column, deduped per start+resource\n (the search emits one slot per chair x operator pair). */\n const availabilityEvents: CalendarEvent[] = [];\n if (projecting && availability) {\n const ranges =\n axisKind === 'none'\n ? buildFreeBands(availability)\n : mergeAvailabilityRanges(availability, axisKind);\n for (const range of ranges) {\n availabilityEvents.push({\n id: `avail-${range.key}`,\n title:\n 'optionCount' in range && typeof range.optionCount === 'number'\n ? `${t(key('findSlots.free'))} · ${t(key('findSlots.freeOptions'), { count: range.optionCount })}`\n : t(key('findSlots.free')),\n start: range.start.toISOString(),\n end: range.end.toISOString(),\n isInternal: true,\n ...(range.resourceId ? { resourceId: range.resourceId } : {}),\n });\n }\n }\n /* Availability mode repaints EVERY background event as a bookable\n green range, so the grey out-of-hours wash cannot coexist with a\n live projection — the projection wins. */\n const unavailabilityEvents = projecting\n ? []\n : buildUnavailabilityEvents(\n {\n axisKind,\n rangeStart: shadeFrom,\n rangeEnd: shadeTo,\n visibleChairIds,\n visibleOperatorIds,\n columnsHiddenWhenAbsent,\n wholeDayOnly: isMonth,\n },\n data,\n );\n return [\n ...mapped,\n ...availabilityEvents,\n ...unavailabilityEvents,\n ...closureBanners,\n ];\n }, [\n rows,\n axisKind,\n availability,\n projecting,\n visibleChairIds,\n visibleOperatorIds,\n currentDate,\n onlyAvailable,\n display.orientation,\n display.careDescription,\n isMonth,\n readOnly,\n reviewOnlyEventIds,\n t,\n data,\n ]);\n\n /* Column headers per the cog: operators as an initials disc or a dot\n plus the full name (the kit's two person treatments), chairs by\n their full name or the short code. */\n const resources: CalendarResource[] | undefined =\n axisKind === 'none'\n ? undefined\n : axisKind === 'operator'\n ? data.operators\n .filter((o) => visibleOperatorIds.includes(o.id))\n .map((o) => ({\n ...o,\n /* The column says WHY it is there — but only where the\n header renders text: under the initials treatment the\n Avatar derives its letters from the title, so a marker\n would corrupt them. */\n title: operatorResourceTitle(\n o,\n data.inactiveOperatorIds.includes(o.id) &&\n display.operatorNameDisplay !== 'initials',\n t(inc1('filters.disabledOperator')),\n ),\n ...(onlyAvailable\n ? { hiddenDates: data.operatorAbsences[o.id] }\n : {}),\n }))\n : data.chairs\n .filter((c) => visibleChairIds.includes(c.id))\n .map((c) => ({\n ...c,\n title: chairResourceTitle(c, display.chairNameDisplay),\n }));\n\n /* The appointment a Move… / Copy… is placing; the mode ends by itself\n if that row vanishes (deleted from elsewhere). */\n const placementRow = placement\n ? rows.find((r) => r.event.id === placement.eventId)\n : undefined;\n useEffect(() => {\n if (placement && !placementRow) onPlacementEnd?.();\n }, [placement, placementRow, onPlacementEnd]);\n /* ONE banner expression: a placement wins, else a create mode, else\n nothing. The tint follows whichever appointment or context is in\n play so the banner reads as the card it is about. */\n const activeMode: 'move' | 'copy' | 'create' | 'default' =\n placement && placementRow\n ? placement.kind\n : createMode\n ? 'create'\n : 'default';\n const modeColorHex =\n placement && placementRow\n ? placementRow.event.backgroundColor\n : createMode?.prefill.colorHex;\n /* The tint is an appointment colour, so the ink is derived, never\n assumed — the Google palette ships no text colour of its own. */\n const modeInkHex = bannerTextColor(modeColorHex);\n const modeBannerLabel =\n placement && placementRow\n ? t(inc1(`placement.${placement.kind}Banner`), {\n name: privacy\n ? (placementRow.event.privacyModeTitle ?? '•••')\n : placementRow.event.title,\n })\n : createMode\n ? createMode.patientName && !privacy\n ? t(inc1('placement.createBannerNamed'), {\n name: createMode.patientName,\n })\n : t(inc1('placement.createBanner'))\n : undefined;\n const endMode = useCallback(() => {\n if (placement) {\n onPlacementEnd?.();\n return;\n }\n onCreateModeEnd?.();\n }, [placement, onPlacementEnd, onCreateModeEnd]);\n\n /* Deep link `focusAppointmentId`: once the card is on the grid, scroll\n it into view and flash the kit's focus highlight. */\n const lastFocusScrollRef = useRef(0);\n useEffect(() => {\n if (!focusScroll || focusScroll.tick === lastFocusScrollRef.current) return;\n if (!rows.some((r) => r.event.id === focusScroll.eventId)) return;\n lastFocusScrollRef.current = focusScroll.tick;\n /* FullCalendar paints the card after this commit — wait a frame. */\n const id = window.setTimeout(\n () => calRef.current?.focusEvent(focusScroll.eventId),\n 0,\n );\n return () => window.clearTimeout(id);\n }, [focusScroll, rows]);\n\n /* Post-save toast (decision 10): \"Saved for {date}\", plus a Go to\n action that undoes exactly what hides the day — the range, the\n weekend setting or a chair / operator filter. Keyed on the tick so\n a re-render never re-toasts. */\n const lastNoticeTickRef = useRef(0);\n useEffect(() => {\n if (!saveNotice || saveNotice.tick === lastNoticeTickRef.current) return;\n lastNoticeTickRef.current = saveNotice.tick;\n const reasons = hiddenReasons(saveNotice, {\n visibleRange: visibleRangeRef.current,\n hiddenDays,\n selectedChairIds,\n selectedOperatorIds,\n });\n const message = t(inc1('save.toast'), {\n date: formatDay(locale, saveNotice.date),\n });\n if (reasons.length === 0) {\n toastSuccess(message);\n return;\n }\n const description = reasons.includes('range')\n ? t(inc1('save.hiddenRange'))\n : reasons.includes('weekend')\n ? t(inc1('save.hiddenWeekend'))\n : t(inc1('save.hiddenFilter'));\n toastSuccess(message, {\n description,\n action: {\n label: t(inc1('save.goTo')),\n onClick: () => {\n if (reasons.includes('chair')) setSelectedChairIds([]);\n if (reasons.includes('operator')) setSelectedOperatorIds([]);\n if (reasons.includes('weekend')) setShowWeekends(true);\n calRef.current?.gotoDate(saveNotice.date);\n },\n },\n });\n }, [\n saveNotice,\n hiddenDays,\n selectedChairIds,\n selectedOperatorIds,\n setSelectedChairIds,\n setSelectedOperatorIds,\n setShowWeekends,\n t,\n locale,\n ]);\n\n /* ---- interactions ---------------------------------------------- */\n\n const handleEventClick = useCallback(\n (event: CalendarEvent) => {\n setPeek(null);\n /* While placing, the grid waits for an empty slot. */\n if (placement) return;\n if (reviewOnlyEventIds?.has(event.id)) {\n onFocus({ kind: 'appointment', eventId: event.id });\n return;\n }\n /* Only a ROW can open. A closure banner, an availability range or a\n background wash has no row behind it and stays ignored. */\n const row = rows.find((r) => r.event.id === event.id);\n /* With the host's details read every row opens its details first,\n patient-less or still pending (P-C3, answer 24). Without it a\n pending chip stays inert. */\n if (row && detailsOnEveryClick) {\n onFocus({ kind: 'appointment', eventId: event.id });\n return;\n }\n if (row?.event.detailsPending) return;\n /* `patientIdOf`, not truthiness: a host id of `0` is an id, and\n reading it as \"no patient\" would send a booked appointment down\n the triage path instead of docking its details. */\n if (patientIdOf(event.patientId) === '') {\n if (!row) return;\n onFocus(null);\n /* An online booking awaiting triage opens on its processing flow.\n Any other patient-less appointment — a block, a reminder, a\n draft the desk typed without a patient — is an ordinary row the\n platform lets you edit, so it opens for editing. The details\n panel is built around the patient; the editor is the useful\n destination when there is none. */\n onBookSlot(\n event.hasUnassignedPatient && row.event.isBookedOnline\n ? processBookingPrefill(row, data)\n : editPrefillFromRow(row),\n );\n openSheet('appointment-editor');\n return;\n }\n /* Card click → the docked details panel directly (decision 1). */\n onFocus({ kind: 'appointment', eventId: event.id });\n },\n [\n onFocus,\n rows,\n onBookSlot,\n openSheet,\n placement,\n data,\n reviewOnlyEventIds,\n detailsOnEveryClick,\n ],\n );\n\n const handlePeekOpen = useCallback(\n (event: CalendarEvent, meta: CalendarEventClickMeta) => {\n if (\n event.allDay &&\n patientIdOf(event.patientId) === '' &&\n !isClosureEvent(event)\n ) {\n return;\n }\n setPeek({ event, el: meta.el });\n },\n [],\n );\n const handlePeekClose = useCallback(() => setPeek(null), []);\n\n /* FC re-fires datesSet on re-renders with an IDENTICAL range — every\n side effect keys on the range actually changing. */\n const lastRangeRef = useRef('');\n const handleDatesSet = useCallback(\n (info: CalendarDatesSetInfo) => {\n currentDateRef.current = info.currentDate;\n visibleRangeRef.current = {\n start: info.start.getTime(),\n end: info.end.getTime(),\n };\n setRangeTitle(info.title);\n const rangeKey = `${info.internalView}:${info.start.getTime()}-${info.end.getTime()}`;\n if (rangeKey !== lastRangeRef.current) {\n lastRangeRef.current = rangeKey;\n setFreeBand(null);\n setPeek(null);\n setVisibleRange({ start: info.start, end: info.end });\n /* The host hears a CHANGE, never a re-fire. A host that refetches\n on every call — the platform island does — would otherwise abort\n the finder's own range load each time the grid re-renders or\n \"Today\" lands on the week already on screen. */\n onVisibleRangeChange(visibleRangeRef.current);\n }\n setCurrentDate((prev) =>\n prev.getTime() === info.currentDate.getTime() ? prev : info.currentDate,\n );\n },\n [onVisibleRangeChange],\n );\n\n /* The COMMIT half of a drop — immediate for non-confirming events, on\n Confirm for patient ones. */\n const applyDrop = useCallback(\n (change: {\n eventId: string;\n resourceId?: string;\n oldStart: Date;\n newStart: Date;\n newEnd?: Date;\n /** Other occurrences moved by the same delta (recurring scope). */\n alsoIds?: readonly string[];\n /** Host-scoped moves record history only after the write succeeds. */\n deferHistory?: boolean;\n }) => {\n /* Row identity is this update's ownership token. A later immutable\n edit or host refresh replaces it and must not be rolled back. */\n const owned = new WeakMap<CalendarRow, CalendarRow>();\n const deltaMs = change.newStart.getTime() - change.oldStart.getTime();\n const targets = new Set([change.eventId, ...(change.alsoIds ?? [])]);\n setRows((prev) =>\n prev.map((r) => {\n if (!targets.has(r.event.id)) return r;\n const isPrimary = r.event.id === change.eventId;\n const start = isPrimary\n ? change.newStart\n : new Date(new Date(r.event.start).getTime() + deltaMs);\n const end =\n isPrimary && change.newEnd\n ? change.newEnd\n : r.event.end\n ? new Date(new Date(r.event.end).getTime() + deltaMs)\n : undefined;\n /* Re-colour only when the ACTIVE axis is the associated one\n (platform getResourceState parity). */\n const recolour =\n change.resourceId &&\n ((display.colorAssociation === 'operator' &&\n axisKind === 'operator') ||\n (display.colorAssociation === 'chair' && axisKind === 'chair'))\n ? associationColor(\n display.colorAssociation,\n axisKind === 'operator'\n ? { operatorId: change.resourceId }\n : { chairId: change.resourceId },\n data,\n )\n : undefined;\n const updated: CalendarRow = {\n ...r,\n ...(change.resourceId\n ? axisKind === 'operator'\n ? { operatorId: change.resourceId }\n : { chairId: change.resourceId }\n : {}),\n event: {\n ...r.event,\n start,\n end,\n ...(recolour ? { backgroundColor: recolour } : {}),\n },\n };\n owned.set(updated, r);\n return updated;\n }),\n );\n for (const id of targets) {\n if (change.deferHistory) break;\n const row = rows.find((r) => r.event.id === id);\n if (!row || patientIdOf(row.event.patientId) === '') continue;\n const from = new Date(row.event.start);\n onHistory(id, {\n kind: 'moved',\n fromIso: from.toISOString(),\n toIso: new Date(from.getTime() + deltaMs).toISOString(),\n });\n }\n return (current: CalendarRow[]): CalendarRow[] =>\n current.map((row) => owned.get(row) ?? row);\n },\n [setRows, axisKind, display.colorAssociation, rows, onHistory, data],\n );\n\n const applyResize = useCallback(\n (eventId: string, newEnd: Date) => {\n const before = rows.find((r) => r.event.id === eventId);\n setRows((prev) => rowsWithEnd(prev, eventId, newEnd));\n if (before?.event.end && patientIdOf(before.event.patientId) !== '') {\n const fromMin = minutesBetween(before.event.start, before.event.end);\n const toMin = minutesBetween(before.event.start, newEnd);\n if (fromMin !== toMin) {\n onHistory(eventId, { kind: 'resized', fromMin, toMin });\n }\n }\n },\n [setRows, rows, onHistory],\n );\n\n /* Notify-channel defaults: a box starts TICKED only for a channel we\n know is ready — a number on file the patient has not opted out of.\n A channel we were never told about stays offered but unticked; we\n do not promise a notification we cannot verify. */\n const seedNotifyDefaults = useCallback(\n (patientId: string) => {\n const channels = signChannelStates(patientRefById(patientId, data));\n setNotifySms(channelReady(channels.sms));\n setNotifyEmail(channelReady(channels.email));\n },\n [data],\n );\n\n const handleDrop = useCallback(\n (info: CalendarEventDropInfo) => {\n if (reviewOnlyEventIds?.has(info.event.id)) {\n info.revert?.();\n return;\n }\n /* Backstop to `editable={!readOnly}`: a gesture that reaches this\n handler without the edit right is REFUSED here, never applied\n and never announced. The prop gate is one refactor away from\n regressing; the false claim would be made in this function. */\n if (readOnly) {\n info.revert?.();\n toastWarning(t(inc1('readOnly.changeBlocked')));\n return;\n }\n const operatorForDay =\n axisKind === 'operator'\n ? (info.newResourceId ?? info.event.resourceId)\n : rows.find((r) => r.event.id === info.event.id)?.operatorId;\n const closure = data.closureOn(\n localIsoDate(info.newStart),\n operatorForDay,\n );\n if (closure) {\n info.revert?.();\n toastWarning(t(key('closures.moveReverted')), {\n description: closureReason(t, locale, closure, info.newStart, data),\n });\n return;\n }\n if (movesSilently(info.event) && !hostSeriesMove(info.event)) {\n applyDrop({\n eventId: info.event.id,\n resourceId: info.newResourceId ?? info.event.resourceId,\n oldStart: info.oldStart,\n newStart: info.newStart,\n newEnd: info.event.end ? new Date(info.event.end) : undefined,\n });\n return;\n }\n setMoveReadout('');\n setMoveScope('this');\n seedNotifyDefaults(patientIdOf(info.event.patientId));\n setPendingMove({\n event: info.event,\n kind: 'drop',\n oldStart: info.oldStart,\n newStart: info.newStart,\n newEnd: info.event.end ? new Date(info.event.end) : undefined,\n newResourceId: info.newResourceId,\n revert: info.revert,\n });\n },\n [\n applyDrop,\n seedNotifyDefaults,\n hostSeriesMove,\n axisKind,\n rows,\n t,\n locale,\n data,\n readOnly,\n reviewOnlyEventIds,\n ],\n );\n\n /* Resize saves at once (platform parity) and offers Undo in the toast\n — the one gesture whose safety net is a step back, not a question.\n The undo writes through the stable setter, never the stale rows. */\n const handleResize = useCallback(\n (info: CalendarEventResizeInfo) => {\n if (reviewOnlyEventIds?.has(info.event.id)) {\n info.revert?.();\n return;\n }\n /* Backstop to `eventDurationEditable`: FullCalendar treats duration\n editability as its own switch, so a read-only grid can still\n deliver a resize here. Snap the card back and say the change was\n refused — NEVER write, and never announce a duration the\n practice's record does not hold. */\n if (readOnly) {\n info.revert?.();\n toastWarning(t(inc1('readOnly.changeBlocked')));\n return;\n }\n const eventId = info.event.id;\n const oldEnd = info.oldEnd;\n applyResize(eventId, info.newEnd);\n if (movesSilently(info.event)) return;\n const minutes = minutesBetween(info.event.start, info.newEnd);\n const oldMinutes = minutesBetween(info.event.start, oldEnd);\n const name = privacy\n ? (info.event.privacyModeTitle ?? '•••')\n : info.event.title;\n toastInfo(t(inc1('resize.toast')), {\n description: t(inc1('resize.description'), { name, minutes }),\n action: {\n label: t(inc1('resize.undo')),\n onClick: () => {\n setRows((prev) => rowsWithEnd(prev, eventId, oldEnd));\n onHistory(eventId, {\n kind: 'resized',\n fromMin: minutes,\n toMin: oldMinutes,\n });\n toastInfo(t(inc1('resize.undone')));\n },\n },\n });\n },\n [applyResize, privacy, setRows, onHistory, t, readOnly, reviewOnlyEventIds],\n );\n\n const confirmMove = useCallback(() => {\n if (!pendingMove) return;\n const { event, oldStart, newStart, newEnd } = pendingMove;\n const hostScope = hostSeriesMove(event);\n if (onMoveOccurrence && hostScope && moveScope !== 'this') {\n /* M4: the host hears first, so a setRows that persists can tell this\n row apart; then only the dragged row moves. */\n const resourceId = pendingMove.newResourceId ?? event.resourceId;\n const before = rows.find((r) => r.event.id === event.id);\n const written = onMoveOccurrence({\n eventId: event.id,\n scope: moveScope,\n oldStart,\n newStart,\n newEnd,\n ...(axisKind === 'chair' && resourceId ? { chairId: resourceId } : {}),\n ...(axisKind === 'operator' && resourceId\n ? { operatorId: resourceId }\n : {}),\n });\n const rollback = applyDrop({\n eventId: event.id,\n resourceId,\n oldStart,\n newStart,\n newEnd,\n deferHistory: true,\n });\n setMoveReadout(t(key('moveConfirm.movedReadout')));\n setPendingMove(null);\n written.then(\n () => {\n if (before && patientIdOf(before.event.patientId) !== '') {\n onHistory(event.id, {\n kind: 'moved',\n fromIso: oldStart.toISOString(),\n toIso: newStart.toISOString(),\n });\n }\n },\n (error: unknown) => {\n setRows(rollback);\n toastWarning(\n error instanceof Error && error.message.trim()\n ? error.message\n : t(key('moveConfirm.revertReadout')),\n );\n },\n );\n return;\n }\n const alsoIds = seriesScopeEventIds(\n rows,\n pendingMove.event.id,\n moveScope,\n ).filter((id) => id !== pendingMove.event.id);\n applyDrop({\n eventId: pendingMove.event.id,\n resourceId: pendingMove.newResourceId ?? pendingMove.event.resourceId,\n oldStart: pendingMove.oldStart,\n newStart: pendingMove.newStart,\n newEnd: pendingMove.newEnd,\n alsoIds,\n });\n /* M5: a host series move offered no notify boxes to tick. */\n const channels = [\n notifySms && !hostScope ? t(key('details.remindSms')) : null,\n notifyEmail && !hostScope ? t(key('details.remindEmail')) : null,\n ].filter((c): c is string => c !== null);\n setMoveReadout(\n channels.length > 0\n ? t(key('moveConfirm.movedNotifiedReadout'), {\n channels: channels.join(', '),\n })\n : t(key('moveConfirm.movedReadout')),\n );\n setPendingMove(null);\n }, [\n pendingMove,\n notifySms,\n notifyEmail,\n applyDrop,\n t,\n rows,\n moveScope,\n hostSeriesMove,\n onMoveOccurrence,\n onHistory,\n axisKind,\n setRows,\n ]);\n\n const cancelMove = useCallback(() => {\n // revert() BEFORE clearing state — it dies once events re-parse.\n pendingMove?.revert?.();\n setMoveReadout(t(key('moveConfirm.revertReadout')));\n setPendingMove(null);\n }, [pendingMove, t]);\n\n /* Month → Day drill-down (decision 9): a cell click and the day-number\n nav link both land here. */\n const openDay = useCallback(\n (date: Date) => {\n currentDateRef.current = date;\n setMountDate(date);\n setViewOptionId('day');\n },\n [setViewOptionId],\n );\n\n const handleDateClick = useCallback(\n (info: CalendarDateClickInfo, selectedDurationMin?: number) => {\n const closure = data.closureOn(\n localIsoDate(info.date),\n axisKind === 'operator' ? info.resourceId : undefined,\n );\n if (closure) {\n setPeek(null);\n onFocus(null);\n toastWarning(t(key('closures.notBookable')), {\n description: closureReason(t, locale, closure, info.date, data),\n });\n return;\n }\n /* A live projection books only an explicit option from its band. */\n if (projecting && availability) {\n if (isMonth) openDay(info.date);\n setPeek(null);\n onFocus(null);\n return;\n }\n /* Placement (Move… / Copy… from the details panel): the click is\n the target slot, in EVERY range — an armed placement outranks the\n Month drill-down below. Move keeps the confirm dialog (it can\n notify the patient); Copy lands at once with an Undo toast. */\n if (placement && placementRow) {\n setPeek(null);\n /* This branch outranks the read-only check further down, and it\n WRITES (a copy lands at once, with a success toast). Refuse it\n here rather than letting a placement armed by any future path\n report a move the host never accepted. */\n if (readOnly) {\n onPlacementEnd?.(false);\n toastWarning(t(inc1('readOnly.changeBlocked')));\n return;\n }\n const source = placementRow;\n const sourceStart = new Date(source.event.start);\n const start = new Date(info.date);\n if (info.allDay && !source.event.allDay) {\n start.setHours(\n sourceStart.getHours(),\n sourceStart.getMinutes(),\n 0,\n 0,\n );\n }\n if (placement.kind === 'copy') {\n copyCountRef.current += 1;\n const id = `apt-copy-${copyCountRef.current}`;\n const copy = copyRowAt(\n source,\n { start, resourceId: info.resourceId, axisKind },\n id,\n placement.withTreatments === true,\n );\n setRows((prev) => [...prev, copy]);\n onHistory(id, { kind: 'created' });\n toastInfo(\n t(inc1('placement.copied'), { date: formatDay(locale, start) }),\n {\n action: {\n label: t(inc1('placement.undo')),\n onClick: () => {\n setRows((prev) => prev.filter((r) => r.event.id !== id));\n toastInfo(t(inc1('placement.copyUndone')));\n },\n },\n },\n );\n onPlacementEnd?.(true);\n return;\n }\n const durationMs = source.event.end\n ? new Date(source.event.end).getTime() - sourceStart.getTime()\n : 0;\n const newEnd = source.event.end\n ? new Date(start.getTime() + durationMs)\n : undefined;\n if (movesSilently(source.event) && !hostSeriesMove(source.event)) {\n applyDrop({\n eventId: source.event.id,\n resourceId: info.resourceId,\n oldStart: sourceStart,\n newStart: start,\n newEnd,\n });\n onPlacementEnd?.(true);\n return;\n }\n setMoveReadout('');\n setMoveScope('this');\n seedNotifyDefaults(patientIdOf(source.event.patientId));\n setPendingMove({\n event: {\n ...source.event,\n resourceId:\n axisKind === 'operator' ? source.operatorId : source.chairId,\n },\n kind: 'drop',\n oldStart: sourceStart,\n newStart: start,\n newEnd,\n newResourceId: info.resourceId,\n });\n onPlacementEnd?.(true);\n return;\n }\n if (isMonth) {\n setPeek(null);\n onFocus(null);\n openDay(info.date);\n return;\n }\n /* Read-only (no edit permission): the platform alerts on create. */\n if (readOnly) {\n setPeek(null);\n toastWarning(t(inc1('readOnly.createBlocked')));\n return;\n }\n /* Empty-slot click → the editor prefilled with the snapped slot,\n the clicked column on the active axis and the cog's default\n duration; the all-day lane pre-ticks All day. In CREATE mode the\n deep link's (or the waiting entry's) context rides along, and\n the clicked column still wins for the active axis. */\n setPeek(null);\n onFocus(null);\n onBookSlot({\n ...(createMode?.prefill ?? {}),\n date: info.date,\n /* A dragged range brings its own length; a click has none and takes\n the cog's default. */\n durationMin:\n selectedDurationMin ??\n createMode?.prefill.durationMin ??\n display.defaultDurationMin,\n ...(info.allDay\n ? { allDay: true }\n : {\n time: {\n hours: info.date.getHours(),\n minutes: info.date.getMinutes(),\n },\n }),\n ...(axisKind === 'chair' && info.resourceId\n ? { chairId: info.resourceId }\n : {}),\n ...(axisKind === 'operator' && info.resourceId\n ? { operatorId: info.resourceId }\n : {}),\n });\n if (createMode) onCreateModeEnd?.();\n },\n [\n axisKind,\n onFocus,\n onBookSlot,\n t,\n locale,\n isMonth,\n openDay,\n display.defaultDurationMin,\n readOnly,\n availability,\n projecting,\n placement,\n placementRow,\n createMode,\n onCreateModeEnd,\n setRows,\n onHistory,\n applyDrop,\n seedNotifyDefaults,\n hostSeriesMove,\n onPlacementEnd,\n data,\n ],\n );\n\n /**\n * A dragged range, as opposed to a single click.\n *\n * It books exactly what was dragged: the duration comes from the range\n * itself rather than the cog's default, which is the whole reason someone\n * drags instead of clicking. Everything else — the closure guard, the\n * placement and availability branches, read-only — is the click's, so this\n * defers to `handleDateClick` for the slot's start and only widens the\n * duration afterwards.\n */\n const handleDateSelect = useCallback(\n (range: {\n start: Date;\n end: Date;\n allDay: boolean;\n resourceId?: string;\n }) => {\n const durationMin = Math.max(\n 1,\n Math.round((range.end.getTime() - range.start.getTime()) / 60000),\n );\n\n handleDateClick(\n {\n date: range.start,\n allDay: range.allDay,\n ...(range.resourceId ? { resourceId: range.resourceId } : {}),\n },\n durationMin,\n );\n },\n [handleDateClick],\n );\n\n /* ---- header ----------------------------------------------------- */\n\n const switchView = useCallback(\n (id: WorkspaceViewId): void => {\n /* Carry the focused date across the keyed remount. */\n setMountDate(currentDateRef.current);\n setViewOptionId(id);\n },\n [setViewOptionId],\n );\n\n /* Page-level shortcuts D · X · W · M (decision 4) — bare keys only,\n never while typing or inside a menu or dialog. */\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent): void => {\n const next = shortcutViewForKeydown(event);\n if (!next) return;\n event.preventDefault();\n switchView(next);\n };\n document.addEventListener('keydown', onKeyDown);\n return () => document.removeEventListener('keydown', onKeyDown);\n }, [switchView]);\n\n const setAxis = useCallback(\n (resourceKind: DisplaySettings['resourceKind']): void => {\n setMountDate(currentDateRef.current);\n setDisplay((d) => ({ ...d, resourceKind }));\n },\n [setDisplay],\n );\n\n /* The LISTED operators — the disabled ones only once the switch\n reveals them, so a group's tri-state only ever covers rows the user\n can see. */\n const operatorGroups = useMemo(\n () =>\n buildOperatorFilterGroups({\n groups: data.operatorGroups,\n operators: listedOperators(\n data.operators,\n data.inactiveOperatorIds,\n showDisabledOperators,\n ),\n inactiveIds: data.inactiveOperatorIds,\n withoutGroupLabel: t(key('filters.withoutGroup')),\n locale,\n }),\n [t, locale, showDisabledOperators, data],\n );\n /* Hiding the disabled operators again unticks them, so the selection\n only ever holds rows the list still offers — the count badge, the\n tri-states and the Reset chip stay in step. */\n const revealDisabledOperators = (next: boolean): void => {\n setShowDisabledOperators(next);\n if (next) return;\n setSelectedOperatorIds((prev) =>\n prev.filter((id) => !data.inactiveOperatorIds.includes(id)),\n );\n };\n const filterCount = activeFilterCount(selectedChairIds, selectedOperatorIds);\n /* ONE reset (platform `_resetFilters`, minus its view switch): every\n chair, every operator, the availability toggle and the disabled\n reveal back to their defaults. The chip is the only control that\n unmounts itself, so it hands focus to the first filter button before\n it goes — never to <body>. */\n const resetFilters = (): void => {\n chairFilterButtonRef.current?.focus();\n setSelectedChairIds([]);\n setSelectedOperatorIds([]);\n setShowDisabledOperators(false);\n setOnlyAvailable(true);\n };\n\n const viewLabel = t(key(`view.${viewOptionId}`));\n const practiceWindow = practiceDayWindow(data);\n const windowOptions = [\n {\n value: 'working',\n label: t(inc1('settings.windowPractice'), {\n from: practiceWindow.min.slice(0, 2),\n to: practiceWindow.max.slice(0, 2),\n }),\n },\n { value: 'extended', label: t(key('settings.windowExtended')) },\n { value: 'full', label: t(key('settings.windowFull')) },\n ];\n\n const operatorRow = (operator: CalendarResource) => (\n <Checkbox\n key={operator.id}\n label={\n <span className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n {/* Decorative — the text beside it already names the person. */}\n <span aria-hidden=\"true\" className=\"ds:inline-flex\">\n <Avatar size=\"xs\" name={operator.title} src={operator.avatarSrc} />\n </span>\n <span>{operator.title}</span>\n {data.inactiveOperatorIds.includes(operator.id) ? (\n <Tag\n size=\"sm\"\n variant=\"neutral\"\n fill=\"outline\"\n label={t(inc1('filters.disabledOperator'))}\n />\n ) : null}\n </span>\n }\n checked={selectedOperatorIds.includes(operator.id)}\n onCheckedChange={(checked) =>\n setSelectedOperatorIds((prev) =>\n toggleSelectedIds(prev, [operator.id], checked),\n )\n }\n />\n );\n\n /* The title and both toolbar rows share ONE card with the grid, so the\n page reads as a single agenda surface rather than the platform's\n stack of panels. */\n const headerBlock = (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {/* The title and the actions share ONE line, the actions pushed to the\n end — the shape every other AlfaDocs page header takes, and it buys\n back a row of vertical space above a grid that wants all of it.\n `flex-wrap` keeps the promise at rail width: the actions drop to\n their own line rather than crushing the date, and `ms-auto` keeps\n them at the end when they do. */}\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <span className=\"ds:flex ds:flex-wrap ds:items-baseline ds:gap-[var(--spacing-sm)]\">\n <h1 className=\"type-title-page ds:m-0 ds:text-start ds:text-[color:var(--foreground)]\">\n {t(key('title'))}\n </h1>\n <span\n aria-live=\"polite\"\n className=\"type-title-item ds:whitespace-nowrap ds:text-[color:var(--muted-foreground)]\"\n >\n {rangeTitle}\n </span>\n </span>\n {/* STRIP 1 — actions only, ICON-ONLY so the row never wraps at\n rail width. A divider separates doing something from changing\n how the grid is seen; the filters live on strip 2. Counts sit\n in the accessible names, not just in the badges. */}\n <div\n role=\"group\"\n aria-label={t(key('actions.groupLabel'))}\n className=\"ds:ms-auto ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)]\"\n >\n {/* Withheld, not refused. A read-only host cannot save an\n appointment, and the primary create affordance answering a\n click with \"you do not have permission\" reads as the product\n being broken — the same failure the demo refusals were. The\n grid-click paths below DO still toast, because a grid cannot\n be withheld and silence there reads as a dead calendar. */}\n {readOnly ? null : (\n <IconButton\n intent=\"primary\"\n icon={<Plus />}\n aria-label={t(key('actions.newAppointment'))}\n tooltip={t(key('actions.newAppointment'))}\n onClick={onComposeNew}\n />\n )}\n {/* Each control below opens a rail tool, so it stands only while\n this host can back that tool with real data — a button onto\n an empty panel is worse than no button. */}\n {availableTools.has(WORKSPACE_TOOL.waitingList) ? (\n <>\n {/* Waiting list SPLIT button: main = the waiting-list panel,\n plus = the entry form; the badge counts waiting entries. */}\n <span className={BADGED_ACTION_CLASS}>\n <IconButton\n intent=\"outline\"\n icon={<Hourglass />}\n aria-label={\n waitingBadgeCount > 0\n ? t(inc1('toolbar.waitingListCount'), {\n count: waitingBadgeCount,\n })\n : t(inc1('toolbar.waitingList'))\n }\n tooltip={t(inc1('toolbar.waitingList'))}\n onClick={onOpenWaitingList}\n />\n {waitingBadgeCount > 0 ? (\n <Badge\n size=\"sm\"\n variant=\"brand\"\n aria-hidden=\"true\"\n className={ACTION_BADGE_CLASS}\n >\n {waitingBadgeCount}\n </Badge>\n ) : null}\n </span>\n <IconButton\n intent=\"outline\"\n icon={<ListPlus />}\n aria-label={t(inc1('toolbar.addToWaitingList'))}\n tooltip={t(inc1('toolbar.addToWaitingList'))}\n onClick={onAddWaitingEntry}\n />\n </>\n ) : null}\n {availableTools.has(WORKSPACE_TOOL.findSlots) ? (\n <IconButton\n intent=\"outline\"\n icon={<CalendarSearch />}\n aria-label={t(key('actions.findFreeSlots'))}\n tooltip={t(key('actions.findFreeSlots'))}\n onClick={() => openSheet('find-slots')}\n />\n ) : null}\n {/* Online bookings — the platform's alert-strip count, moved onto\n a toolbar button that opens the same bookings page. */}\n {availableTools.has(WORKSPACE_TOOL.bookings) ? (\n <span className={BADGED_ACTION_CLASS}>\n <IconButton\n intent=\"outline\"\n icon={<Globe />}\n aria-label={\n onlineBookingsCount > 0\n ? t(inc1('toolbar.onlineBookingsCount'), {\n count: onlineBookingsCount,\n })\n : t(inc1('toolbar.onlineBookings'))\n }\n tooltip={t(inc1('toolbar.onlineBookings'))}\n onClick={onOpenOnlineBookings}\n />\n {onlineBookingsCount > 0 ? (\n <Badge\n size=\"sm\"\n variant=\"warning\"\n aria-hidden=\"true\"\n className={ACTION_BADGE_CLASS}\n >\n {onlineBookingsCount}\n </Badge>\n ) : null}\n </span>\n ) : null}\n {/* Divider: doing something | changing how I see it. */}\n <span\n aria-hidden=\"true\"\n className=\"ds:mx-[var(--spacing-2xs)] ds:h-6 ds:w-px ds:bg-[color:var(--border)]\"\n />\n <ButtonGroup aria-label={t(key('actions.schedulingLabel'))}>\n <IconButton\n intent=\"outline\"\n icon={privacy ? <EyeOff /> : <Eye />}\n aria-label={t(key('actions.privacy'))}\n aria-pressed={privacy}\n tooltip={t(key('actions.privacy'))}\n onClick={() => setPrivacy((p) => !p)}\n />\n {/* A10: the platform's printer icon opens a day picker and\n prints THAT day's call sheet, not the visible range. */}\n <IconButton\n intent=\"outline\"\n icon={<Printer />}\n aria-label={t(key('actions.printDay'))}\n tooltip={t(key('actions.printDay'))}\n data-action=\"print-day\"\n onClick={() => {\n setPrintDay(currentDate);\n setPrintOpen(true);\n }}\n />\n {/* Scheduler and calendar-settings are separate platform pages\n (decision 8). No host seam carries that navigation yet, so\n neither cog is rendered — the display cog below is the kit's\n own and stays. */}\n <IconButton\n ref={settingsButtonRef}\n intent=\"outline\"\n icon={<SlidersHorizontal />}\n aria-label={t(key('settings.label'))}\n aria-haspopup=\"dialog\"\n aria-expanded={settingsOpen}\n tooltip={t(key('settings.label'))}\n onClick={() => setSettingsOpen((o) => !o)}\n />\n </ButtonGroup>\n </div>\n </div>\n {settingsOpen ? (\n <Popover open onOpenChange={setSettingsOpen}>\n <Popover.Anchor\n virtualRef={{ current: settingsButtonRef.current as HTMLElement }}\n />\n <Popover.Content\n align=\"end\"\n /* Taller than the viewport on a laptop once a practice has a few\n chairs: without a cap Floating UI shifts it up until its top\n runs off the top of the screen — measured at -139px on an\n 836px viewport — and the settings above the fold become\n unreachable. Cap to what Radix says is available and scroll\n inside, as autocomplete and the data-table toolbar do. */\n className=\"ds:w-80 ds:max-h-[var(--radix-popover-content-available-height)] ds:overflow-y-auto\"\n onCloseAutoFocus={(closeEvent) => {\n closeEvent.preventDefault();\n settingsButtonRef.current?.focus();\n }}\n >\n <Popover.Heading>{t(key('settings.label'))}</Popover.Heading>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:pt-[var(--spacing-sm)]\">\n {isMonth ? (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t(key('settings.monthNote'))}\n </p>\n ) : null}\n <div className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <span className=\"type-body-sm\">\n {t(key('settings.orientation'))}\n </span>\n <div className=\"ds:w-36\">\n <Select\n aria-label={t(key('settings.orientation'))}\n options={[\n {\n value: 'vertical',\n label: t(key('settings.orientationColumns')),\n },\n {\n value: 'horizontal',\n label: t(key('settings.orientationTimeline')),\n },\n ]}\n value={display.orientation}\n onValueChange={(orientation) => {\n setMountDate(currentDateRef.current);\n setDisplay((d) => ({\n ...d,\n orientation:\n orientation as DisplaySettings['orientation'],\n }));\n }}\n />\n </div>\n </div>\n <Switch\n label={t(key('settings.zebra'))}\n checked={display.zebraRows}\n onCheckedChange={(zebraRows) =>\n setDisplay((d) => ({ ...d, zebraRows }))\n }\n />\n <Switch\n label={t(key('settings.showTime'))}\n checked={display.showTime}\n onCheckedChange={(showTime) =>\n setDisplay((d) => ({ ...d, showTime }))\n }\n />\n <div className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <span className=\"type-body-sm\">\n {t(key('settings.slotDuration'))}\n </span>\n <div className=\"ds:w-36\">\n <Select\n aria-label={t(key('settings.slotDuration'))}\n options={[\n { value: '00:15', label: t(key('settings.slot15')) },\n { value: '00:30', label: t(key('settings.slot30')) },\n { value: '01:00', label: t(key('settings.slot60')) },\n ]}\n value={display.slotDuration}\n onValueChange={(slotDuration) =>\n setDisplay((d) => ({\n ...d,\n slotDuration:\n slotDuration as DisplaySettings['slotDuration'],\n }))\n }\n />\n </div>\n </div>\n {/* Time axis: the practice's hours by default, the two\n wider windows as overrides. */}\n <div className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <span className=\"type-body-sm\">\n {t(key('settings.window'))}\n </span>\n <div className=\"ds:w-44\">\n <Select\n aria-label={t(key('settings.window'))}\n options={windowOptions}\n value={display.window}\n onValueChange={(window) =>\n setDisplay((d) => ({\n ...d,\n window: window as DisplaySettings['window'],\n }))\n }\n />\n </div>\n </div>\n <div className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <span className=\"type-body-sm\">\n {t(key('settings.careDescription'))}\n </span>\n <div className=\"ds:w-44\">\n <Select\n aria-label={t(key('settings.careDescription'))}\n options={[\n { value: 'off', label: t(key('settings.careOff')) },\n { value: 'name', label: t(key('settings.careName')) },\n { value: 'code', label: t(key('settings.careCode')) },\n {\n value: 'nameCode',\n label: t(key('settings.careNameCode')),\n },\n ]}\n value={display.careDescription}\n onValueChange={(careDescription) =>\n setDisplay((d) => ({\n ...d,\n careDescription:\n careDescription as DisplaySettings['careDescription'],\n }))\n }\n />\n </div>\n </div>\n <div className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <span className=\"type-body-sm\">\n {t(key('settings.colorBy'))}\n </span>\n <div className=\"ds:w-44\">\n <Select\n aria-label={t(key('settings.colorBy'))}\n options={[\n { value: 'care', label: t(key('settings.colorByCare')) },\n {\n value: 'operator',\n label: t(key('settings.colorByOperator')),\n },\n {\n value: 'chair',\n label: t(key('settings.colorByChair')),\n },\n ]}\n value={display.colorAssociation}\n onValueChange={(colorAssociation) =>\n setDisplay((d) => ({\n ...d,\n colorAssociation:\n colorAssociation as DisplaySettings['colorAssociation'],\n }))\n }\n />\n </div>\n </div>\n {/* The platform's four per-user settings the cog gains. */}\n <div className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <span className=\"type-body-sm\">\n {t(inc1('settings.defaultDuration'))}\n </span>\n <NumberInput\n aria-label={t(inc1('settings.defaultDuration'))}\n size=\"sm\"\n inline=\"sm\"\n unit={t(inc1('settings.minutes'))}\n min={DEFAULT_DURATION_RANGE.min}\n max={DEFAULT_DURATION_RANGE.max}\n step={DEFAULT_DURATION_RANGE.step}\n value={display.defaultDurationMin}\n onChange={(value) => {\n if (value === null) return;\n const clamped = Math.min(\n DEFAULT_DURATION_RANGE.max,\n Math.max(DEFAULT_DURATION_RANGE.min, Math.round(value)),\n );\n setDisplay((d) => ({ ...d, defaultDurationMin: clamped }));\n }}\n />\n </div>\n <div className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <span className=\"type-body-sm\">\n {t(inc1('settings.operatorNames'))}\n </span>\n <div className=\"ds:w-36\">\n <Select\n aria-label={t(inc1('settings.operatorNames'))}\n options={[\n {\n value: 'full',\n label: t(inc1('settings.operatorFull')),\n },\n {\n value: 'initials',\n label: t(inc1('settings.operatorInitials')),\n },\n ]}\n value={display.operatorNameDisplay}\n onValueChange={(operatorNameDisplay) =>\n setDisplay((d) => ({\n ...d,\n operatorNameDisplay:\n operatorNameDisplay as WorkspaceDisplaySettings['operatorNameDisplay'],\n }))\n }\n />\n </div>\n </div>\n <div className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <span className=\"type-body-sm\">\n {t(inc1('settings.chairNames'))}\n </span>\n <div className=\"ds:w-36\">\n <Select\n aria-label={t(inc1('settings.chairNames'))}\n options={[\n { value: 'full', label: t(inc1('settings.chairFull')) },\n { value: 'short', label: t(inc1('settings.chairShort')) },\n ]}\n value={display.chairNameDisplay}\n onValueChange={(chairNameDisplay) =>\n setDisplay((d) => ({\n ...d,\n chairNameDisplay:\n chairNameDisplay as WorkspaceDisplaySettings['chairNameDisplay'],\n }))\n }\n />\n </div>\n </div>\n <Switch\n label={t(inc1('settings.mapsLink'))}\n checked={display.mapsLink}\n onCheckedChange={(mapsLink) =>\n setDisplay((d) => ({ ...d, mapsLink }))\n }\n />\n {/* The Academy tutorial is an external platform link with no\n host seam yet, so the footer strip it lived in is dropped\n rather than left as an empty bordered box. */}\n </div>\n </Popover.Content>\n </Popover>\n ) : null}\n </div>\n );\n\n /* Row 2 — NAVIGATION (decision 4), sticky inside the shared card:\n jump-to-date, the view menu, then today / prev / next. */\n const navigationRow = (\n <div\n role=\"group\"\n aria-label={t(inc1('toolbar.navigation'))}\n className=\"ds:flex ds:min-h-[var(--inc1-nav-block-size)] ds:flex-nowrap ds:items-center ds:gap-[var(--spacing-sm)] ds:overflow-x-auto ds:bg-[color:var(--card)] ds:py-[var(--spacing-xs)] ds:print:hidden\"\n >\n {/* Container width, not viewport width: filter labels yield first,\n then the view label. Icons, names and counts remain. */}\n {/* Chair filter — platform semantics: nothing ticked shows every\n chair; ticking narrows. Count badge while narrowed. */}\n <Popover open={chairFilterOpen} onOpenChange={setChairFilterOpen}>\n <Tooltip label={t(inc1('toolbar.chairs'))}>\n <Popover.Trigger asChild>\n <Button\n ref={chairFilterButtonRef}\n className=\"ds:shrink-0 ds:[min-inline-size:var(--min-target-size)] ds:[min-block-size:var(--min-target-size)] ds:@max-[768px]/calendar-nav:ps-[var(--spacing-sm)] ds:@max-[768px]/calendar-nav:pe-[var(--spacing-sm)]\"\n intent=\"outline\"\n startIcon={<Armchair />}\n endIcon={\n selectedChairIds.length > 0 ? (\n <Badge size=\"sm\" variant=\"brand\">\n {selectedChairIds.length}\n </Badge>\n ) : undefined\n }\n aria-label={\n selectedChairIds.length > 0\n ? t(inc1('toolbar.chairsCount'), {\n count: selectedChairIds.length,\n })\n : t(inc1('toolbar.chairs'))\n }\n >\n <span\n data-calendar-nav-label=\"filter\"\n className=\"ds:@max-[768px]/calendar-nav:hidden\"\n >\n {t(inc1('toolbar.chairs'))}\n </span>\n </Button>\n </Popover.Trigger>\n </Tooltip>\n <Popover.Content\n align=\"start\"\n className=\"ds:w-64 ds:max-h-[var(--radix-popover-content-available-height)] ds:overflow-y-auto\"\n >\n <Popover.Heading>{t(key('filters.chairs'))}</Popover.Heading>\n <Popover.Description>\n {t(inc1('filters.everyoneChairs'))}\n </Popover.Description>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:pt-[var(--spacing-sm)]\">\n {data.chairs.map((chair) => (\n <Checkbox\n key={chair.id}\n label={<ResourceChip label={chair.title} color={chair.color} />}\n checked={selectedChairIds.includes(chair.id)}\n onCheckedChange={(checked) =>\n setSelectedChairIds((prev) =>\n toggleSelectedIds(prev, [chair.id], checked),\n )\n }\n />\n ))}\n </div>\n </Popover.Content>\n </Popover>\n {/* Operator filter — grouped (platform GetGroupedOperatorService)\n with a tri-state row per group; nothing ticked shows everyone;\n the only-available switch defaults ON. */}\n <Popover open={operatorFilterOpen} onOpenChange={setOperatorFilterOpen}>\n <Tooltip label={t(inc1('toolbar.operators'))}>\n <Popover.Trigger asChild>\n <Button\n className=\"ds:shrink-0 ds:[min-inline-size:var(--min-target-size)] ds:[min-block-size:var(--min-target-size)] ds:@max-[768px]/calendar-nav:ps-[var(--spacing-sm)] ds:@max-[768px]/calendar-nav:pe-[var(--spacing-sm)]\"\n intent=\"outline\"\n startIcon={<UserCog />}\n endIcon={\n selectedOperatorIds.length > 0 ? (\n <Badge size=\"sm\" variant=\"brand\">\n {selectedOperatorIds.length}\n </Badge>\n ) : undefined\n }\n aria-label={\n selectedOperatorIds.length > 0\n ? t(inc1('toolbar.operatorsCount'), {\n count: selectedOperatorIds.length,\n })\n : t(inc1('toolbar.operators'))\n }\n >\n <span\n data-calendar-nav-label=\"filter\"\n className=\"ds:@max-[768px]/calendar-nav:hidden\"\n >\n {t(inc1('toolbar.operators'))}\n </span>\n </Button>\n </Popover.Trigger>\n </Tooltip>\n <Popover.Content\n align=\"start\"\n className=\"ds:w-72 ds:max-h-[var(--radix-popover-content-available-height)] ds:overflow-y-auto\"\n >\n <Popover.Heading>{t(key('filters.operators'))}</Popover.Heading>\n <Popover.Description>\n {t(inc1('filters.everyoneOperators'))}\n </Popover.Description>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:pt-[var(--spacing-sm)]\">\n {operatorGroups.length === 1 ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {operatorGroups[0].operators.map(operatorRow)}\n </div>\n ) : (\n operatorGroups.map((group) => {\n const memberIds = group.operators.map((o) => o.id);\n return (\n <div\n key={group.id}\n role=\"group\"\n aria-label={group.name}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <Checkbox\n label={\n <>\n <span className=\"ds:font-[var(--font-weight-semibold)]\">\n {group.name}\n </span>\n <VisuallyHidden>\n {` · ${t(key('filters.selectAll'))}`}\n </VisuallyHidden>\n </>\n }\n checked={selectionState(selectedOperatorIds, memberIds)}\n onCheckedChange={(checked) =>\n setSelectedOperatorIds((prev) =>\n toggleSelectedIds(prev, memberIds, checked),\n )\n }\n />\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:ps-[var(--spacing-md)]\">\n {group.operators.map(operatorRow)}\n </div>\n </div>\n );\n })\n )}\n <Switch\n label={t(key('filters.onlyAvailable'))}\n checked={onlyAvailable}\n onCheckedChange={setOnlyAvailable}\n />\n {/* Directly under it (decision 7): the practice's disabled\n operators are hidden until this reveals them. */}\n <Switch\n label={t(inc1('filters.showDisabledOperators'))}\n checked={showDisabledOperators}\n onCheckedChange={revealDisabledOperators}\n />\n </div>\n </Popover.Content>\n </Popover>\n {/* The Reset chip — visible only while a filter narrows the grid;\n never touches the view (platform's Reset also switched it). */}\n {filterCount > 0 ? (\n <Button\n intent=\"ghost\"\n size=\"sm\"\n className=\"ds:shrink-0\"\n startIcon={<RotateCcw />}\n aria-label={t(inc1('toolbar.resetFiltersCount'), {\n count: filterCount,\n })}\n onClick={resetFilters}\n >\n {`${t(inc1('toolbar.resetFilters'))} · ${filterCount}`}\n </Button>\n ) : null}\n {/* Temporal navigation closes the strip. */}\n <span className=\"ds:ms-auto ds:flex ds:shrink-0 ds:flex-nowrap ds:items-center ds:gap-[var(--spacing-sm)]\">\n <DatePicker\n aria-label={t(key('actions.jumpToDate'))}\n chrome=\"button\"\n value={currentDate}\n onChange={(date) => {\n if (date) calRef.current?.gotoDate(date);\n }}\n />\n <DropdownMenu.Root>\n <Tooltip label={t(inc1('view.menuLabel'), { view: viewLabel })}>\n <DropdownMenu.Trigger asChild>\n <Button\n className=\"ds:shrink-0 ds:[min-inline-size:var(--min-target-size)] ds:[min-block-size:var(--min-target-size)] ds:@max-[576px]/calendar-nav:ps-[var(--spacing-sm)] ds:@max-[576px]/calendar-nav:pe-[var(--spacing-sm)]\"\n intent=\"outline\"\n background=\"surface\"\n endIcon={<ChevronDown />}\n aria-label={t(inc1('view.menuLabel'), { view: viewLabel })}\n >\n <span\n data-calendar-nav-label=\"view\"\n className=\"ds:@max-[576px]/calendar-nav:hidden\"\n >\n {viewLabel}\n </span>\n </Button>\n </DropdownMenu.Trigger>\n </Tooltip>\n <DropdownMenu.Content align=\"start\">\n <DropdownMenu.Label>{t(inc1('view.range'))}</DropdownMenu.Label>\n <DropdownMenu.RadioGroup\n value={viewOptionId}\n onValueChange={(value) => switchView(value as WorkspaceViewId)}\n >\n {WORKSPACE_VIEWS.map((id) => (\n <DropdownMenu.RadioItem key={id} value={id}>\n <span className=\"ds:flex ds:items-center ds:gap-[var(--spacing-sm)]\">\n <span className=\"ds:flex-1\">{t(key(`view.${id}`))}</span>\n <Kbd keys={[VIEW_SHORTCUT_KEYS[id]]} size=\"sm\" />\n </span>\n </DropdownMenu.RadioItem>\n ))}\n </DropdownMenu.RadioGroup>\n <DropdownMenu.Separator />\n <DropdownMenu.Label>{t(inc1('view.columns'))}</DropdownMenu.Label>\n <DropdownMenu.RadioGroup\n value={display.resourceKind}\n onValueChange={(value) =>\n setAxis(value as DisplaySettings['resourceKind'])\n }\n >\n <DropdownMenu.RadioItem value=\"none\" disabled={isMonth}>\n {t(inc1('view.axisNone'))}\n </DropdownMenu.RadioItem>\n <DropdownMenu.RadioItem value=\"chair\" disabled={isMonth}>\n {t(inc1('view.axisChairs'))}\n </DropdownMenu.RadioItem>\n <DropdownMenu.RadioItem value=\"operator\" disabled={isMonth}>\n {t(inc1('view.axisOperators'))}\n </DropdownMenu.RadioItem>\n </DropdownMenu.RadioGroup>\n <DropdownMenu.Separator />\n <DropdownMenu.CheckboxItem\n checked={showWeekends}\n onCheckedChange={(checked) => setShowWeekends(checked === true)}\n >\n {t(inc1('view.showWeekends'))}\n </DropdownMenu.CheckboxItem>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n <ButtonGroup aria-label={tUi('calendar.ariaLabel')}>\n <Button\n intent=\"outline\"\n background=\"surface\"\n onClick={() => calRef.current?.today()}\n >\n {tUi('calendar.today')}\n </Button>\n {/* Directional glyphs: they mirror in RTL so the pair keeps\n pointing with the reading direction, as the kit toolbar does. */}\n <IconButton\n intent=\"outline\"\n background=\"surface\"\n icon={<ChevronLeft />}\n flipIconInRtl\n aria-label={tUi('calendar.previousPeriod')}\n tooltip={tUi('calendar.previousPeriod')}\n onClick={() => calRef.current?.prev()}\n />\n <IconButton\n intent=\"outline\"\n background=\"surface\"\n icon={<ChevronRight />}\n flipIconInRtl\n aria-label={tUi('calendar.nextPeriod')}\n tooltip={tUi('calendar.nextPeriod')}\n onClick={() => calRef.current?.next()}\n />\n </ButtonGroup>\n </span>\n </div>\n );\n\n /* ---- peek content ----------------------------------------------- */\n\n const peekMeta = peek ? data.metaById[peek.event.id] : undefined;\n const peekRow = peek\n ? rows.find((r) => r.event.id === peek.event.id)\n : undefined;\n const peekPlan =\n peekRow?.careLink?.kind === 'plan'\n ? data.carePlanById(peekRow.careLink.planId)\n : undefined;\n const peekPatient = patientRefById(peek?.event.patientId, data).record;\n const peekChair = data.chairs.find((c) => c.id === peekMeta?.chairId);\n const peekOperator = data.operators.find(\n (o) => o.id === peekMeta?.operatorId,\n );\n\n /* ---- move-confirm content --------------------------------------- */\n\n const pendingRow = pendingMove\n ? rows.find((r) => r.event.id === pendingMove.event.id)\n : undefined;\n const pendingRef = patientRefById(pendingMove?.event.patientId, data);\n const pendingHostScope = pendingMove\n ? hostSeriesMove(pendingMove.event)\n : false;\n /* Naming a patient and RESOLVING one are different questions. A row\n carrying an id has someone booked, so the dialog names them from the\n record, else the row's own title, else the honest \"not loaded\" — a\n practice authorising an SMS must be told who it goes to. */\n const pendingPatientName = pendingRef.assigned\n ? privacy && pendingMove\n ? /* The dialog sits over the grid: the same mask as the card. */\n maskedTitle(pendingRow?.event ?? pendingMove.event, true)\n : patientRefName(\n pendingRef,\n pendingRow?.event.title,\n t(key('details.patientNotLoaded')),\n )\n : null;\n /* Four states, not two. \"No mobile number on file\" is a claim about a\n RECORD we hold — sayable only when the record loaded AND carries an\n empty number. A field the host simply did not send is `unknown`, and\n an unknown channel stays OFFERED (unticked): the host refuses on\n send if it must, which beats telling the practice it has no number\n for a patient we never loaded. */\n const pendingChannels = signChannelStates(pendingRef);\n const smsOffered = channelOfferable(pendingChannels.sms);\n const emailOffered = channelOfferable(pendingChannels.email);\n const smsReasonKey = channelReasonKey(pendingChannels.sms, {\n optedOut: 'moveConfirm.smsOptedOut',\n none: 'moveConfirm.smsUnavailable',\n });\n const emailReasonKey = channelReasonKey(pendingChannels.email, {\n optedOut: 'moveConfirm.emailOptedOut',\n none: 'moveConfirm.emailUnavailable',\n });\n let moveFromValue = '';\n let moveToValue = '';\n if (pendingMove) {\n const rowEnd = pendingRow?.event.end;\n const newEnd = rowEnd\n ? new Date(\n new Date(rowEnd).getTime() +\n (pendingMove.newStart.getTime() - pendingMove.oldStart.getTime()),\n )\n : undefined;\n const oldResourceId =\n axisKind === 'operator' ? pendingRow?.operatorId : pendingRow?.chairId;\n const newResourceId =\n pendingMove.newResourceId ?? pendingMove.event.resourceId;\n const resourceChanged = Boolean(\n axisKind !== 'none' && newResourceId && newResourceId !== oldResourceId,\n );\n const resourceTitle = (id: string | undefined): string | null =>\n (axisKind === 'operator' ? data.operators : data.chairs).find(\n (res) => res.id === id,\n )?.title ?? null;\n const allDay = Boolean(pendingMove.event.allDay);\n moveFromValue = [\n formatDay(locale, pendingMove.oldStart),\n allDay ? null : formatTimeRange(locale, pendingMove.oldStart, rowEnd),\n resourceChanged ? resourceTitle(oldResourceId) : null,\n ]\n .filter((part): part is string => Boolean(part))\n .join(' · ');\n moveToValue = [\n formatDay(locale, pendingMove.newStart),\n allDay ? null : formatTimeRange(locale, pendingMove.newStart, newEnd),\n resourceChanged ? resourceTitle(newResourceId) : null,\n ]\n .filter((part): part is string => Boolean(part))\n .join(' · ');\n }\n\n return (\n <div\n ref={surfaceRef}\n className={`ds:flex ds:min-h-full ds:flex-col ds:gap-[var(--spacing-md)] ds:p-[var(--spacing-lg)] ${NAV_BLOCK_SIZE_CLASS}`}\n >\n {freeBand && freeOptions.length > 0 ? (\n <Popover\n modal\n open\n onOpenChange={(open) => {\n if (!open) setFreeBand(null);\n }}\n >\n <Popover.Anchor virtualRef={{ current: freeBand.el }} />\n <Popover.Content\n size=\"lg\"\n onCloseAutoFocus={(event: Event) => {\n event.preventDefault();\n if (!bookingFreeBand.current)\n (freeBand.el.isConnected\n ? freeBand.el\n : chairFilterButtonRef.current\n )?.focus();\n }}\n >\n <Popover.Heading>{t(key('findSlots.bandOptions'))}</Popover.Heading>\n <ScrollArea\n type=\"native\"\n role=\"region\"\n aria-label={t(key('findSlots.bandOptions'))}\n className=\"ds:max-h-[var(--popover-size-lg)]\"\n >\n <ul className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {freeOptions.map((slot, index) => (\n <li\n key={index}\n className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-md)]\"\n >\n <span id={`${freeBandId}-${index}`}>\n {formatTimeRange(\n locale,\n slot.start,\n new Date(\n slot.start.getTime() + slot.durationMin * 60000,\n ),\n )}{' '}\n ·{' '}\n {\n data.chairs.find((chair) => chair.id === slot.chairId)\n ?.title\n }{' '}\n ·{' '}\n {\n data.operators.find(\n (operator) => operator.id === slot.operatorId,\n )?.title\n }\n </span>\n {!readOnly ? (\n <Button\n aria-describedby={`${freeBandId}-${index}`}\n className=\"ds:[min-block-size:var(--min-target-size)] ds:[min-inline-size:var(--min-target-size)]\"\n onClick={() => {\n if (\n readOnly ||\n availability !== freeBand.source ||\n !freeBand.el.isConnected\n )\n return;\n const care = data.cares.find(\n (item) => item.id === slot.careId,\n );\n bookingFreeBand.current = true;\n setFreeBand(null);\n onBookSlotFromFinder({\n date: slot.start,\n time: {\n hours: slot.start.getHours(),\n minutes: slot.start.getMinutes(),\n },\n durationMin: slot.durationMin,\n operatorId: slot.operatorId,\n chairId: slot.chairId,\n colorHex:\n care?.colorHex ?? availabilityContext?.colorHex,\n care: care ? undefined : availabilityContext?.care,\n cares: care\n ? [\n {\n careId: care.id,\n name: care.name,\n code: care.code,\n },\n ]\n : availabilityContext?.cares,\n patientId: availabilityContext?.patientId,\n });\n openSheet('appointment-editor');\n }}\n >\n {t(key('findSlots.book'))}\n </Button>\n ) : null}\n </li>\n ))}\n </ul>\n </ScrollArea>\n <Popover.Close />\n </Popover.Content>\n </Popover>\n ) : null}\n {/* `overflow:visible` on purpose: Card's base sets overflow-hidden,\n which would make this card a scroll container and stop the\n navigation row (and the grid's own column headers) sticking. */}\n <Card\n variant=\"elevated\"\n className=\"ds:gap-[var(--spacing-md)] ds:p-[var(--spacing-lg)] ds:[overflow:visible] ds:print:hidden\"\n >\n {headerBlock}\n <div\n ref={navigationRef}\n className=\"ds:@container/calendar-nav ds:sticky ds:top-0 ds:z-20 ds:min-w-0 ds:print:hidden\"\n >\n {navigationRow}\n </div>\n <Calendar\n key={`${viewOptionId}-${axisKind}-${display.orientation}`}\n id={id}\n ref={calRef}\n onBackgroundEventClick={\n projecting\n ? (event, meta) => {\n if (availability && event.id.startsWith('avail-')) {\n bookingFreeBand.current = false;\n setPeek(null);\n setFreeBand({ event, el: meta.el, source: availability });\n }\n }\n : undefined\n }\n events={fcEvents}\n resources={resources}\n view={calendarView}\n /* Chairs and operators as columns are FullCalendar Scheduler\n premium views: without the host's key the grid wears the\n invalid-licence watermark. Undefined falls through to the\n component's own environment default. */\n schedulerLicenseKey={schedulerLicenseKey}\n resourceLayout={display.orientation}\n resourceLabelVariant=\"chip\"\n selectedEventId={selectedEventId}\n /* Grey out-of-hours washes (FC paints bg events from this\n variable) plus the sticky-header offset under row 2. */\n className={`ds:[--fc-bg-event-color:var(--muted-foreground)] ${FC_STICKY_OFFSET_CLASS}`}\n showResourceInitials={\n axisKind === 'operator' &&\n display.operatorNameDisplay === 'initials'\n }\n verticalResourceLabels={\n stem === 'Week' && display.orientation === 'vertical'\n }\n resourceAreaHeader={axisKind === 'operator' ? 'operators' : 'chairs'}\n resourceAreaWidth=\"14%\"\n initialDate={mountDate}\n locale={locale}\n editable={!readOnly}\n privacyMode={privacy}\n /* Placement / create banner, tinted with the appointment's or\n the context's own colour. */\n mode={activeMode}\n modeLabel={modeBannerLabel}\n modeBannerColor={modeColorHex}\n modeBannerTextColor={modeInkHex}\n onModeCancel={endMode}\n eventColorStyle=\"tinted\"\n slotEventOverlap={false}\n showTime={display.showTime}\n zebraRows={display.zebraRows}\n hiddenDays={hiddenDays}\n loadingDates={loadingDates}\n dayMaxEvents={isMonth ? 4 : true}\n /* `editable={!readOnly}` above does NOT cover this: FullCalendar\n reads duration editability from its own option, and an\n explicit value overrides `editable`. Without `!readOnly` a\n read-only grid still grew resize handles. */\n eventDurationEditable={!isMonth && !readOnly}\n slotMinTime={dayWindow.min}\n slotMaxTime={dayWindow.max}\n slotDuration={display.slotDuration}\n snapDuration={DRAFT_SNAP}\n defaultTimedEventDuration={display.defaultDurationMin}\n nowIndicator\n toolbar={false}\n stickyHeaderDates\n height=\"auto\"\n onEventClick={handleEventClick}\n onEventMouseEnter={handlePeekOpen}\n onEventMouseLeave={handlePeekClose}\n onEventDragStart={handlePeekClose}\n onEventResizeStart={handlePeekClose}\n onEventDrop={handleDrop}\n onEventResize={handleResize}\n onDateClick={handleDateClick}\n /* Drag a range to create. Off under read-only, where there is\n nothing to create. The mirror follows automatically, and the\n highlight is held rather than cleared on the next click — that\n click is usually the host opening the editor for the very slot\n just chosen, and a form that fills in over a grid which has\n forgotten the slot is how someone books the wrong time. */\n selectable={!readOnly}\n unselectAuto={false}\n onDateSelect={handleDateSelect}\n /* Dims booked cards and repaints the background events as\n bookable green ranges while a search is projected. */\n availabilityMode={projecting}\n onNavLinkDayClick={isMonth ? openDay : undefined}\n onDatesSet={handleDatesSet}\n />\n </Card>\n <PrintSheet\n sections={printSections}\n /* The heading names the printed day, not the visible range. */\n rangeTitle={formatDay(locale, printDay)}\n axisKind={axisKind}\n visibleChairIds={visibleChairIds}\n visibleOperatorIds={visibleOperatorIds}\n privacy={privacy}\n locale={locale}\n />\n {peek ? (\n /* HoverCard, not Popover: the peek IS a hover preview, so it takes the\n shared elevated surface and the side-aware arrow. `openOn=\"click\"`\n because the grid owns the open state entirely — HoverCard's own\n hover timers must not also run. */\n <HoverCard\n openOn=\"click\"\n open\n onOpenChange={(open) => {\n if (!open) setPeek(null);\n }}\n >\n <HoverCard.Anchor virtualRef={{ current: peek.el }} />\n <HoverCard.Content\n align=\"center\"\n size=\"sm\"\n className=\"ds:pointer-events-none\"\n onOpenAutoFocus={(openEvent) => {\n /* Hover peek — never steal focus from the grid. */\n openEvent.preventDefault();\n }}\n >\n {isClosureEvent(peek.event) ? (\n <>\n <HoverCard.Heading>{peek.event.title}</HoverCard.Heading>\n <HoverCard.Body>\n <span className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)] ds:pt-[var(--spacing-2xs)]\">\n <KeyValuePair\n label={t(key('details.time'))}\n value={formatDay(\n locale,\n `${String(peek.event.start).slice(0, 10)}T00:00:00`,\n )}\n />\n </span>\n </HoverCard.Body>\n </>\n ) : (\n /* The kit's AppointmentPeek: who, when, where, the status face\n and the indicator chips. Under privacy it drops the name,\n the photo and every clinical row itself. */\n <AppointmentPeek\n name={peek.event.title}\n avatarSrc={peekPatient?.avatarSrc}\n time={\n peek.event.allDay\n ? tUi('calendar.allDay')\n : formatTimeRange(\n locale,\n new Date(peek.event.start),\n new Date(peek.event.end ?? peek.event.start),\n )\n }\n location={\n peek.event.isTelehealth\n ? t('calendarWorkspace.editor.typeTelehealth')\n : peekChair?.title\n }\n telehealth={Boolean(peek.event.isTelehealth)}\n status={peek.event.status}\n details={[\n ...(peekOperator\n ? [\n {\n icon: (\n <Avatar\n size=\"xs\"\n name={peekOperator.title}\n src={peekOperator.avatarSrc}\n />\n ),\n label: t(key('details.operator')),\n value: peekOperator.title,\n },\n ]\n : []),\n ...(peekMeta?.care\n ? [\n {\n label: t(key('details.care')),\n value: peekMeta.care,\n },\n ]\n : []),\n ...(peekRow?.careLink\n ? [\n {\n label: t(key('details.treatments')),\n value:\n peekRow.careLink.kind === 'plan' && peekPlan\n ? t(key('details.planLine'), {\n number: peekPlan.number,\n name: peekPlan.name,\n })\n : `${t(key('details.priceListLine'))} · ${data\n .careEntriesFromLink(peekRow.careLink)\n .map((c) => c.name)\n .join(', ')}`,\n },\n ]\n : []),\n ]}\n flags={<IndicatorChips event={peek.event} />}\n privacy={privacy}\n />\n )}\n </HoverCard.Content>\n </HoverCard>\n ) : null}\n {/* Drag-move confirm (decision 7): the drop stays optimistic while\n the dialog asks; Confirm commits, Cancel reverts. */}\n {pendingMove ? (\n <Dialog\n open\n onOpenChange={(open) => {\n if (!open) cancelMove();\n }}\n >\n <Dialog.Content size=\"sm\" variant=\"confirmation\">\n <Dialog.Header>\n <Dialog.Title>{t(key('moveConfirm.title'))}</Dialog.Title>\n <Dialog.Description>\n <VisuallyHidden>\n {[\n pendingPatientName,\n `${t(key('moveConfirm.from'))} ${moveFromValue}`,\n `${t(key('moveConfirm.to'))} ${moveToValue}`,\n ]\n .filter(Boolean)\n .join('. ')}\n .{' '}\n </VisuallyHidden>\n {pendingHostScope ? null : t(key('moveConfirm.description'))}\n </Dialog.Description>\n </Dialog.Header>\n <Dialog.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <span className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n {pendingPatientName ? (\n <KeyValuePair\n label={t(key('moveConfirm.patient'))}\n value={pendingPatientName}\n />\n ) : null}\n <KeyValuePair\n label={t(key('moveConfirm.from'))}\n value={moveFromValue}\n />\n <KeyValuePair\n label={t(key('moveConfirm.to'))}\n value={moveToValue}\n />\n </span>\n {/* Series member: the platform's recurring-mode chooser,\n here beside the notify checkboxes it never offered. */}\n {pendingRow?.series || pendingHostScope ? (\n <RadioGroup\n label={t(key('moveConfirm.scope'))}\n value={moveScope}\n onValueChange={(value) =>\n setMoveScope(value as RecurringScope)\n }\n >\n {RECURRING_SCOPES.map((scope) => (\n <Radio\n key={scope}\n value={scope}\n label={t(\n key(`editor.${RECURRING_SCOPE_LABEL_KEY[scope]}`),\n )}\n />\n ))}\n </RadioGroup>\n ) : null}\n {/* The reason rides the LABEL: a disabled checkbox leaves the\n tab order, so a hover-only tooltip reaches nobody. A host\n series move sends no notification, so it offers none (M5). */}\n {pendingHostScope ? null : (\n <>\n <Checkbox\n label={\n smsReasonKey === null\n ? t(key('moveConfirm.notifySms'))\n : `${t(key('moveConfirm.notifySms'))} — ${t(key(smsReasonKey))}`\n }\n checked={notifySms}\n disabled={!smsOffered}\n disabledReason={\n smsReasonKey === null ? undefined : t(key(smsReasonKey))\n }\n onCheckedChange={(checked) =>\n setNotifySms(checked === true)\n }\n />\n <Checkbox\n label={\n emailReasonKey === null\n ? t(key('moveConfirm.notifyEmail'))\n : `${t(key('moveConfirm.notifyEmail'))} — ${t(key(emailReasonKey))}`\n }\n checked={notifyEmail}\n disabled={!emailOffered}\n disabledReason={\n emailReasonKey === null\n ? undefined\n : t(key(emailReasonKey))\n }\n onCheckedChange={(checked) =>\n setNotifyEmail(checked === true)\n }\n />\n </>\n )}\n </Dialog.Body>\n <Dialog.Footer>\n <Button intent=\"secondary\" onClick={cancelMove}>\n {t(key('moveConfirm.cancel'))}\n </Button>\n <Button intent=\"primary\" onClick={confirmMove}>\n {t(key('moveConfirm.confirm'))}\n </Button>\n </Dialog.Footer>\n </Dialog.Content>\n </Dialog>\n ) : null}\n {/* Print one chosen day (A10) — the platform's date step in front\n of the PDF, wearing the demo's confirmation-dialog idiom. */}\n <Dialog open={printOpen} onOpenChange={setPrintOpen}>\n <Dialog.Content size=\"sm\" variant=\"confirmation\">\n <Dialog.Header>\n <Dialog.Title>{t(inc1('print.title'))}</Dialog.Title>\n <Dialog.Description>\n {t(inc1('print.description'))}\n </Dialog.Description>\n </Dialog.Header>\n <Dialog.Body>\n <FormField label={t(inc1('print.day'))}>\n <DatePicker\n value={printDay}\n onChange={(date) => {\n if (date) setPrintDay(date);\n }}\n />\n </FormField>\n </Dialog.Body>\n <Dialog.Footer>\n <Button intent=\"secondary\" onClick={() => setPrintOpen(false)}>\n {t(key('moveConfirm.cancel'))}\n </Button>\n <Button\n intent=\"primary\"\n startIcon={<Printer />}\n onClick={() => {\n setPrintOpen(false);\n setPrintPending(true);\n }}\n >\n {t(inc1('print.confirm'))}\n </Button>\n </Dialog.Footer>\n </Dialog.Content>\n </Dialog>\n <VisuallyHidden aria-live=\"polite\">{moveReadout}</VisuallyHidden>\n </div>\n );\n}\n","/* Waiting list, the rail panel: entries grouped by what they are FOR, one\n elevated card each, quick views as chips with counts, and the entry\n form as a `PanelSubview` over the list. */\nimport {\n forwardRef,\n useId,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type FormEvent,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport {\n CalendarClock,\n CalendarDays,\n CalendarSearch,\n ChevronRight,\n Ellipsis,\n EyeOff,\n Funnel,\n Hourglass,\n Lock,\n Pencil,\n Phone,\n Plus,\n Stethoscope,\n StickyNote,\n Trash2,\n UserPlus,\n} from 'lucide-react';\nimport { cva } from 'class-variance-authority';\nimport { Alert } from '../../components/alert';\nimport { Avatar } from '../../components/avatar';\nimport { Badge } from '../../components/badge';\nimport { Button, IconButton, type ButtonProps } from '../../components/button';\nimport { ButtonGroup } from '../../components/button-group';\nimport { Card } from '../../components/card';\nimport { DatePicker } from '../../components/date-picker';\nimport { DropdownMenu } from '../../components/dropdown-menu';\nimport { EmptyState } from '../../components/empty-state';\nimport { FormField } from '../../components/form-field';\nimport { PanelHeader } from '../../components/panel-header';\nimport { PanelSubview } from '../../components/panel-subview';\nimport { ScrollArea } from '../../components/scroll-area';\nimport { Select } from '../../components/select';\nimport { CONTENT_ENTER_CLASS, Skeleton } from '../../components/skeleton';\nimport { TextArea } from '../../components/text-area';\nimport { Tooltip } from '../../components/tooltip';\nimport { VisuallyHidden } from '../../components/visually-hidden';\nimport { WhatsAppGlyph } from '../../components/whatsapp-button';\nimport { CalendarPatientPicker } from './calendar-patient-picker';\nimport { privacyMask } from './calendar-privacy';\nimport { useCalendarData } from './calendar.data';\nimport {\n NONE,\n WAITING_QUICK_VIEWS,\n WAITING_QUICK_VIEW_LABEL_KEY,\n formatTimeRange,\n parseEventDate,\n type CalendarRow,\n type WaitingEntryDraft,\n type WaitingQuickView,\n} from './calendar.model';\nimport {\n EMPTY_WAITING_FILTERS,\n filterWaitingEntries,\n groupWaitingRows,\n waitingEntryKind,\n waitingFiltersActiveCount,\n waitingQuickViewCounts,\n waitingWhatsAppNumber,\n type WaitingEntryKind,\n type WaitingListFilters,\n type WaitingListRowView,\n} from './calendar-workspace.model';\nimport {\n WaitingListEntrySubview,\n activeOperators,\n whatsAppUnavailableKey,\n} from './calendar.sheets';\nimport {\n patientRefName,\n type CalendarPatient,\n type CalendarWaitingEntry,\n} from './calendar.types';\n\nconst waitingKey = (suffix: string): string =>\n `calendarWorkspace.waitingList.${suffix}`;\n\n/** Yes / No dropdowns: the platform's `includeEmptyOption` is the kit's\n * clearable placeholder, so \"unset\" needs no sentinel value. */\ntype WaitingYesNo = '' | 'yes' | 'no';\n\n/* Accessible themes keep the kit's raised target; the default themes keep\n the 32px strip. Same theme-scoped rule the details footer uses. */\nconst ACCESSIBLE_TARGET =\n 'ds:[.theme-accessible_&]:[min-block-size:var(--min-target-size)]';\nconst ACCESSIBLE_TARGET_SQUARE = `${ACCESSIBLE_TARGET} ds:[.theme-accessible_&]:[min-inline-size:var(--min-target-size)]`;\n\n/** Literal maps (not templates) so key extractors see every key. */\nconst GROUP_LABEL_KEY: Record<WaitingEntryKind, string> = {\n linked: 'groupLinked',\n patient: 'groupPatient',\n memo: 'groupMemo',\n};\nconst CHIP_LABEL_KEY: Record<WaitingQuickView, string> = {\n all: 'chipAll',\n noAppointment: 'chipNoAppointment',\n scheduledOver30: 'chipScheduledOver30',\n waitingOver30: 'chipWaitingOver30',\n};\n\nconst GROUP_ICON: Record<WaitingEntryKind, ReactNode> = {\n linked: <CalendarClock aria-hidden=\"true\" />,\n patient: <Hourglass aria-hidden=\"true\" />,\n memo: <StickyNote aria-hidden=\"true\" />,\n};\n\n/** One muted metadata line: glyph, then text that ellipsises. */\nconst lineVariants = cva(\n 'type-body-sm ds:flex ds:min-w-0 ds:items-center ds:gap-[var(--spacing-xs)] ds:text-start ds:[&>svg]:size-3.5 ds:[&>svg]:shrink-0',\n {\n variants: {\n tone: {\n muted: 'ds:text-[color:var(--muted-foreground)]',\n /* Absent data is not a warning: muted and italic, never amber. */\n absent:\n 'ds:text-[color:var(--muted-foreground)] ds:italic ds:[&>span]:pe-[var(--spacing-2xs)]',\n body: 'ds:text-[color:var(--foreground)]',\n },\n },\n defaultVariants: { tone: 'muted' },\n },\n);\n\nconst titleVariants = cva('type-body-sm ds:min-w-0 ds:truncate ds:text-start', {\n variants: {\n tone: {\n name: 'ds:font-[var(--font-weight-semibold)] ds:text-[color:var(--foreground)]',\n /* A patient IS on the row; the record did not load. Said plainly. */\n notLoaded:\n 'ds:font-[var(--font-weight-medium)] ds:italic ds:text-[color:var(--muted-foreground)]',\n },\n },\n defaultVariants: { tone: 'name' },\n});\n\n/** Body and footer start under the name, not under the avatar. */\nconst UNDER_NAME_CLASS =\n 'ds:ps-[calc(var(--spacing-xl)+var(--spacing-sm))] ds:@max-[288px]/waitcard:ps-0';\n\nconst APPOINTMENT_LINK_CLASS = [\n lineVariants({ tone: 'body' }),\n 'ds:w-full ds:cursor-pointer ds:rounded-[var(--radius-sm)] ds:border-0 ds:bg-transparent ds:p-0',\n 'ds:min-h-[var(--spacing-lg)]',\n ACCESSIBLE_TARGET,\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n 'ds:[&>svg]:text-[color:var(--muted-foreground)] ds:hover:[&>svg]:text-[color:var(--foreground)]',\n].join(' ');\n\n/* The appointment's own colour. The hex rides a CSS custom property, the\n one CalendarEventCard sets; the paint itself lives in the class. */\nconst APPOINTMENT_DOT_CLASS =\n 'ds:size-2 ds:shrink-0 ds:rounded-[var(--radius-full)] ds:border ds:border-[color:var(--border)] ds:bg-[var(--calendar-event-accent,var(--muted-foreground))]';\n\nconst AVATAR_FALLBACK_CLASS =\n 'ds:flex ds:size-8 ds:shrink-0 ds:items-center ds:justify-center ds:rounded-[var(--radius-full)] ds:bg-[var(--muted)] ds:text-[color:var(--muted-foreground)]';\n\nfunction shortDay(\n locale: string,\n value: string | Date,\n options: { weekday?: boolean; nowIso?: string } = {},\n): string {\n try {\n const date = parseEventDate(value);\n const otherYear =\n options.nowIso !== undefined &&\n parseEventDate(options.nowIso).getFullYear() !== date.getFullYear();\n return new Intl.DateTimeFormat(locale, {\n weekday: options.weekday ? 'short' : undefined,\n day: 'numeric',\n month: 'short',\n year: otherYear ? 'numeric' : undefined,\n }).format(date);\n } catch {\n return '';\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* The joined strip's two members. ButtonGroup injects intent, size and */\n/* background into its direct children, so each member takes them and */\n/* hands them to the one button it renders. */\n/* ------------------------------------------------------------------ */\n\ntype MemberProps = Pick<ButtonProps, 'intent' | 'background'>;\n\n/** WhatsApp, in the same ink as its neighbours: a link when there is a\n * number, an `aria-disabled` button that says why when there is not. */\nfunction WhatsAppMember({\n number,\n label,\n ...member\n}: MemberProps & { number: string; label: string }) {\n const digits = number.replace(/\\D/g, '');\n if (digits === '') {\n return (\n /* `aria-disabled`, never the native attribute: a natively disabled\n button leaves the tab order, so its reason reaches nobody. */\n <IconButton\n {...member}\n size=\"sm\"\n className={ACCESSIBLE_TARGET_SQUARE}\n icon={<WhatsAppGlyph aria-hidden=\"true\" />}\n aria-label={label}\n tooltip={label}\n aria-disabled=\"true\"\n data-action=\"open-whatsapp\"\n />\n );\n }\n return (\n <Tooltip label={label}>\n <Button\n {...member}\n asChild\n size=\"sm\"\n className={`ds:w-8 ds:p-0 ds:[&>span]:shrink-0 ${ACCESSIBLE_TARGET_SQUARE}`}\n startIcon={<WhatsAppGlyph aria-hidden=\"true\" />}\n data-action=\"open-whatsapp\"\n >\n <a\n href={`https://wa.me/${digits}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={label}\n />\n </Button>\n </Tooltip>\n );\n}\n\n/** The entry's menu. Edit hands focus back to this trigger BEFORE the\n * form opens, so the subview's Back has somewhere to return to. */\nfunction EntryMenuMember({\n entryId,\n label,\n editLabel,\n editBlockedReason,\n removeLabel,\n onEdit,\n onRemove,\n ...member\n}: MemberProps & {\n entryId: string;\n label: string;\n /** Unset = this host has no entry form: the item is not rendered. */\n editLabel?: string;\n /** Set = Edit stays reachable but inert, and this is why. */\n editBlockedReason?: string;\n removeLabel: string;\n onEdit: () => void;\n onRemove: () => void;\n}) {\n const triggerRef = useRef<HTMLButtonElement>(null);\n const pendingRef = useRef<'edit' | 'remove' | null>(null);\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <IconButton\n {...member}\n ref={triggerRef}\n size=\"sm\"\n className={ACCESSIBLE_TARGET_SQUARE}\n icon={<Ellipsis />}\n aria-label={label}\n tooltip={label}\n data-entry-edit={entryId}\n />\n </DropdownMenu.Trigger>\n <DropdownMenu.Content\n align=\"end\"\n onCloseAutoFocus={(event) => {\n const pending = pendingRef.current;\n pendingRef.current = null;\n if (pending === null) return;\n event.preventDefault();\n if (pending === 'edit') {\n triggerRef.current?.focus();\n onEdit();\n } else {\n onRemove();\n }\n }}\n >\n {editLabel === undefined ? null : (\n <>\n <DropdownMenu.Item\n startIcon={<Pencil aria-hidden=\"true\" />}\n /* Not Radix `disabled`: that drops the item from arrow-key order\n and its reason with it. It stays focusable and says why. */\n aria-disabled={editBlockedReason ? 'true' : undefined}\n className={\n editBlockedReason\n ? 'ds:cursor-not-allowed ds:text-[color:var(--muted-foreground)]'\n : undefined\n }\n description={editBlockedReason}\n data-action=\"edit-waiting-entry\"\n onSelect={(event) => {\n if (editBlockedReason) {\n event.preventDefault();\n return;\n }\n pendingRef.current = 'edit';\n }}\n >\n {editLabel}\n </DropdownMenu.Item>\n <DropdownMenu.Separator />\n </>\n )}\n <DropdownMenu.Item\n startIcon={<Trash2 aria-hidden=\"true\" />}\n className=\"ds:text-[color:var(--destructive)]\"\n data-action=\"remove-waiting-entry\"\n onSelect={() => {\n pendingRef.current = 'remove';\n }}\n >\n {removeLabel}\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* One entry */\n/* ------------------------------------------------------------------ */\n\nexport interface WaitingEntryCardProps {\n view: WaitingListRowView;\n locale: string;\n privacy?: boolean;\n readOnly?: boolean;\n /** Schedule (unlinked) / Bring forward (linked). */\n onPlace: (entry: CalendarWaitingEntry) => void;\n /** Unset = no finder on this host: the button is not rendered. */\n onFindSlots?: (entry: CalendarWaitingEntry) => void;\n /** Unset = no entry form on this host: Edit and Assign are withheld. */\n onEdit?: (entry: CalendarWaitingEntry) => void;\n onRemove: (entry: CalendarWaitingEntry) => void;\n onOpenPatient?: (patient: CalendarPatient) => void;\n onOpenAppointment: (eventId: string) => void;\n}\n\n/** A waiting entry as one elevated card: who, since when, what it is\n * tied to, and the one line of actions that moves it off the list. */\nexport const WaitingEntryCard = forwardRef<HTMLElement, WaitingEntryCardProps>(\n (\n {\n view,\n locale,\n privacy = false,\n readOnly = false,\n onPlace,\n onFindSlots,\n onEdit,\n onRemove,\n onOpenPatient,\n onOpenAppointment,\n },\n ref,\n ) => {\n const { t } = useTranslation();\n const data = useCalendarData();\n const titleId = useId();\n const reasonId = useId();\n const { entry, appointment } = view;\n const kind = waitingEntryKind(entry);\n const linked = kind === 'linked';\n const memo = kind === 'memo';\n const patient = view.patient ?? view.appointmentPatient;\n const notLoaded = t('calendarWorkspace.details.patientNotLoaded');\n const hidden = t('calendarWorkspace.privacy.hidden');\n\n /* What to CALL the row, for the title and for every action's name. */\n const appointmentTitle = appointment\n ? String(appointment.event.title ?? '').trim()\n : '';\n const masked = privacy\n ? view.patientAssigned || linked\n ? privacyMask(appointment?.event.privacyModeTitle)\n : hidden\n : null;\n const plainTitle =\n patient?.name ??\n (view.patientAssigned\n ? notLoaded\n : linked\n ? appointmentTitle || t(waitingKey('appointmentNotLoaded'))\n : (entry.description ?? t(waitingKey('noDescription'))));\n const contactRef = view.patientRef.assigned\n ? view.patientRef\n : view.appointmentPatientRef;\n /* Actions name their row. An unloaded patient is named by the entry's\n own description before the honest \"not loaded\". */\n const who =\n masked ??\n (contactRef.assigned\n ? patientRefName(contactRef, entry.description, notLoaded)\n : plainTitle);\n const honestGap =\n !patient && (view.patientAssigned || (linked && appointmentTitle === ''));\n const named = (labelKey: string): string =>\n t(waitingKey('actionForRow'), { action: t(waitingKey(labelKey)), who });\n\n const whatsappNumber = privacy ? '' : waitingWhatsAppNumber(view);\n const whatsappLabel =\n whatsappNumber !== ''\n ? named('whatsappEnabled')\n : t(\n privacy\n ? 'calendarWorkspace.privacy.hidden'\n : whatsAppUnavailableKey(contactRef),\n );\n\n /* Privacy: the form would open the patient and the free text in fields. */\n const editBlockedReason = privacy\n ? hidden\n : linked\n ? t(waitingKey('editLinkedDisabled'))\n : undefined;\n\n const operatorTitle =\n view.operatorTitle ??\n (appointment?.operatorId\n ? data.operators.find((o) => o.id === appointment.operatorId)?.title\n : undefined);\n const phone = privacy ? undefined : view.patient?.phone;\n const description = memo || linked ? undefined : entry.description;\n const canWrite = !readOnly && onEdit !== undefined;\n const assignBlocked = privacy;\n const placeLabelKey = linked ? 'reschedule' : 'schedule';\n /* Booking needs a patient, so a reminder cannot be placed yet. */\n const placeBlocked = memo;\n\n /* Inline style: permitted per 23-constraints, Runtime-computed\n dimensions (CSS custom property setter; the paint is in the class). */\n const dotStyle = appointment?.event.backgroundColor\n ? ({\n '--calendar-event-accent': appointment.event.backgroundColor,\n } as CSSProperties)\n : undefined;\n\n const blockedProps = (blocked: boolean) =>\n blocked\n ? ({ 'aria-disabled': 'true', 'aria-describedby': reasonId } as const)\n : {};\n const withReason = (\n blocked: boolean,\n reason: string,\n node: ReactElement,\n ) => (blocked ? <Tooltip label={reason}>{node}</Tooltip> : node);\n\n return (\n <Card\n ref={ref}\n variant=\"elevated\"\n aria-labelledby={titleId}\n data-waiting-card=\"\"\n className=\"ds:@container/waitcard\"\n >\n <Card.Body className=\"ds:flex ds:min-w-0 ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <div className=\"ds:flex ds:min-w-0 ds:items-start ds:gap-[var(--spacing-sm)]\">\n {/* Privacy drops the photo and the initials with it. */}\n {patient && !privacy ? (\n <Avatar name={patient.name} src={view.avatarSrc} size=\"sm\" />\n ) : (\n <span aria-hidden=\"true\" className={AVATAR_FALLBACK_CLASS}>\n {privacy && (view.patientAssigned || linked) ? (\n <EyeOff size={16} />\n ) : (\n <Hourglass size={16} />\n )}\n </span>\n )}\n <div className=\"ds:flex ds:min-w-0 ds:flex-1 ds:flex-col\">\n {masked !== null ? (\n <span id={titleId} className={titleVariants()}>\n <VisuallyHidden>\n {t('appointmentPeek.hiddenName')}:{' '}\n </VisuallyHidden>\n {masked}\n </span>\n ) : patient && onOpenPatient ? (\n <span id={titleId} className=\"ds:flex ds:min-w-0\">\n <Button\n size=\"sm\"\n intent=\"link\"\n className=\"ds:min-w-0 ds:max-w-full ds:[&>span]:truncate\"\n onClick={() => onOpenPatient(patient)}\n >\n {patient.name}\n </Button>\n </span>\n ) : (\n <span\n id={titleId}\n className={titleVariants({\n tone: honestGap ? 'notLoaded' : 'name',\n })}\n >\n {plainTitle}\n </span>\n )}\n <span className=\"type-meta ds:truncate ds:text-start ds:text-[color:var(--muted-foreground)]\">\n {t(waitingKey('since'), {\n date: shortDay(locale, data.waitingSinceIso(entry), {\n nowIso: data.nowIso,\n }),\n })}\n </span>\n </div>\n <ButtonGroup\n size=\"sm\"\n label={t(waitingKey('actionForRow'), {\n action: t(waitingKey('rowActions')),\n who,\n })}\n className=\"ds:shrink-0\"\n >\n <WhatsAppMember number={whatsappNumber} label={whatsappLabel} />\n {/* Edit and Remove WRITE the queue through seams a read-only\n host refuses, so the whole menu is withheld. */}\n {readOnly ? null : (\n <EntryMenuMember\n entryId={entry.id}\n label={named('moreActions')}\n editLabel={onEdit ? t(waitingKey('edit')) : undefined}\n editBlockedReason={editBlockedReason}\n removeLabel={t(waitingKey('remove'))}\n onEdit={() => onEdit?.(entry)}\n onRemove={() => onRemove(entry)}\n />\n )}\n </ButtonGroup>\n </div>\n\n <div\n className={`ds:flex ds:min-w-0 ds:flex-col ds:gap-[var(--spacing-xs)] ${UNDER_NAME_CLASS}`}\n >\n {linked && appointment ? (\n <button\n type=\"button\"\n className={APPOINTMENT_LINK_CLASS}\n data-action=\"open-linked-appointment\"\n aria-label={t(waitingKey('actionForRow'), {\n action: t(waitingKey('openAppointment')),\n who,\n })}\n onClick={() => onOpenAppointment(String(appointment.event.id))}\n >\n <CalendarDays aria-hidden=\"true\" />\n <span className=\"ds:min-w-0 ds:truncate\">\n {[\n shortDay(locale, appointment.event.start as string | Date, {\n weekday: true,\n nowIso: data.nowIso,\n }),\n formatTimeRange(\n locale,\n appointment.event.start as string | Date,\n appointment.event.end as string | Date | undefined,\n ),\n privacy ? undefined : view.appointmentName,\n ]\n .filter(Boolean)\n .join(' · ')}\n </span>\n <span\n aria-hidden=\"true\"\n className={APPOINTMENT_DOT_CLASS}\n // eslint-disable-next-line react/forbid-dom-props -- caller-supplied appointment hex injected via a CSS variable (23-constraints §inline-style exception)\n style={dotStyle}\n />\n <ChevronRight\n aria-hidden=\"true\"\n className=\"ds:ms-auto ds:rtl:rotate-180\"\n />\n </button>\n ) : linked ? (\n <span className={lineVariants({ tone: 'absent' })}>\n <CalendarDays aria-hidden=\"true\" />\n <span className=\"ds:min-w-0 ds:truncate\">\n {t(waitingKey('appointmentNotLoaded'))}\n </span>\n </span>\n ) : null}\n {phone ? (\n <span className={lineVariants()}>\n <Phone aria-hidden=\"true\" />\n <a\n href={`tel:${phone.replace(/\\s/g, '')}`}\n dir=\"ltr\"\n className=\"ds:min-w-0 ds:truncate ds:text-[color:inherit] ds:underline-offset-4 ds:hover:underline ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-[color:var(--ring)] ds:forced-colors:focus-visible:outline-[CanvasText]\"\n >\n {phone}\n </a>\n </span>\n ) : null}\n {memo ? null : (\n <span\n className={lineVariants({\n tone: operatorTitle ? 'muted' : 'absent',\n })}\n >\n <Stethoscope aria-hidden=\"true\" />\n <span className=\"ds:min-w-0 ds:truncate\">\n {operatorTitle ?? t(waitingKey('noOperator'))}\n </span>\n </span>\n )}\n {description ? (\n privacy ? (\n <span data-privacy=\"hidden\" className={lineVariants()}>\n <EyeOff aria-hidden=\"true\" />\n <span className=\"ds:min-w-0 ds:truncate\">{hidden}</span>\n </span>\n ) : (\n <span className={lineVariants({ tone: 'body' })}>\n <span className=\"ds:min-w-0 ds:truncate\">{description}</span>\n </span>\n )\n ) : null}\n </div>\n\n <div\n className={`ds:flex ds:min-w-0 ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)] ${UNDER_NAME_CLASS}`}\n >\n {withReason(\n placeBlocked,\n t(waitingKey('assignPatientFirst')),\n <Button\n size=\"sm\"\n intent=\"primary\"\n className={ACCESSIBLE_TARGET}\n aria-label={named(placeLabelKey)}\n data-action=\"place-waiting-entry\"\n {...blockedProps(placeBlocked)}\n onClick={() => {\n if (!placeBlocked) onPlace(entry);\n }}\n >\n {t(waitingKey(placeLabelKey))}\n </Button>,\n )}\n {onFindSlots\n ? withReason(\n placeBlocked,\n t(waitingKey('assignPatientFirst')),\n <Button\n size=\"sm\"\n intent=\"outline\"\n className={ACCESSIBLE_TARGET}\n startIcon={<CalendarSearch aria-hidden=\"true\" />}\n aria-label={named('findSlot')}\n data-action=\"find-slots-for-waiting\"\n {...blockedProps(placeBlocked)}\n onClick={() => {\n if (!placeBlocked) onFindSlots(entry);\n }}\n >\n {t(waitingKey('findSlot'))}\n </Button>,\n )\n : null}\n {canWrite && memo\n ? withReason(\n assignBlocked,\n hidden,\n <Button\n size=\"sm\"\n intent=\"soft\"\n className={ACCESSIBLE_TARGET}\n startIcon={<UserPlus aria-hidden=\"true\" />}\n aria-label={named('assignPatient')}\n data-action=\"assign-patient\"\n aria-disabled={assignBlocked ? 'true' : undefined}\n onClick={() => {\n if (!assignBlocked) onEdit?.(entry);\n }}\n >\n {t(waitingKey('assignPatient'))}\n </Button>,\n )\n : null}\n {canWrite && !linked && !entry.operatorId\n ? withReason(\n assignBlocked,\n hidden,\n <Button\n size=\"sm\"\n intent=\"soft\"\n className={ACCESSIBLE_TARGET}\n startIcon={<Stethoscope aria-hidden=\"true\" />}\n aria-label={named('assignOperator')}\n data-action=\"assign-operator\"\n aria-disabled={assignBlocked ? 'true' : undefined}\n onClick={() => {\n if (!assignBlocked) onEdit?.(entry);\n }}\n >\n {t(waitingKey('assignOperator'))}\n </Button>,\n )\n : null}\n {placeBlocked ? (\n <VisuallyHidden id={reasonId}>\n {t(waitingKey('assignPatientFirst'))}\n </VisuallyHidden>\n ) : null}\n </div>\n </Card.Body>\n </Card>\n );\n },\n);\nWaitingEntryCard.displayName = 'WaitingEntryCard';\n\n/** A first read: three cards in the entry card's own anatomy. */\nfunction WaitingListSkeleton() {\n return (\n <div\n aria-hidden=\"true\"\n data-waiting-loading=\"\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n {[0, 1, 2].map((index) => (\n <Card key={index} variant=\"elevated\">\n <Card.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-sm)]\">\n <Skeleton variant=\"circular\" size=\"sm\" stagger={index * 2} />\n <div className=\"ds:flex ds:min-w-0 ds:flex-1 ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <Skeleton\n variant=\"text\"\n size=\"sm\"\n stagger={index * 2}\n width={index === 1 ? '45%' : '60%'}\n />\n <Skeleton\n variant=\"text\"\n size=\"sm\"\n stagger={index * 2 + 1}\n width=\"35%\"\n />\n </div>\n <Skeleton\n variant=\"rounded\"\n stagger={index * 2 + 1}\n width=\"calc(var(--spacing-xl) * 2)\"\n height=\"var(--spacing-xl)\"\n />\n </div>\n <div className={UNDER_NAME_CLASS}>\n <Skeleton\n variant=\"text\"\n size=\"sm\"\n stagger={index * 2 + 1}\n width={index === 2 ? '50%' : '75%'}\n />\n </div>\n <div\n className={`ds:flex ds:gap-[var(--spacing-xs)] ${UNDER_NAME_CLASS}`}\n >\n <Skeleton\n variant=\"rounded\"\n stagger={index * 2 + 2}\n width=\"calc(var(--spacing-xl) * 2)\"\n height=\"var(--spacing-xl)\"\n />\n <Skeleton\n variant=\"rounded\"\n stagger={index * 2 + 2}\n width=\"calc(var(--spacing-xl) * 3)\"\n height=\"var(--spacing-xl)\"\n />\n </div>\n </Card.Body>\n </Card>\n ))}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* The panel */\n/* ------------------------------------------------------------------ */\n\nexport interface WaitingListPanelProps {\n /** Privacy mode, in step with the grid: names masked, the photo, the\n * phone, the WhatsApp link and the free-text description withheld. */\n privacy?: boolean;\n entries: CalendarWaitingEntry[];\n /** Live grid rows — the linked appointment's date, colour and care. */\n rows: CalendarRow[];\n locale: string;\n /** No edit permission (`permissions.editAppointment === false`). Add,\n * Edit, Assign and Remove are withheld and a lock note says why. */\n readOnly?: boolean;\n /** The host's read of the queue. A first `loading` shows card-shaped\n * placeholders; a refresh keeps its cards and marks the list busy. */\n status?: 'loading' | 'ready' | 'error';\n onRetry?: () => void;\n /** Schedule / Bring forward → the host's placement hand-off. */\n onPlaceWaiting: (entry: CalendarWaitingEntry) => void;\n /** «Find a slot» → the find-slots tool, seeded by the host from the\n * entry (`FindSlotsSeed`). Unset = the button is not rendered. */\n onFindSlotsForWaiting?: (entry: CalendarWaitingEntry) => void;\n /** Delete — immediate, as on the platform (the host toasts an Undo). */\n onRemoveWaiting: (entry: CalendarWaitingEntry) => void;\n /** Add entry, a row's edit and the assign buttons → the entry form. */\n onOpenEntryForm?: (entry?: CalendarWaitingEntry) => void;\n /**\n * The entry form as a `PanelSubview` over this list. Pass the open\n * state (`null` = closed) with `onSaveEntry` and `onCancelEntry`; leave\n * all three out and the host renders its own form, as before.\n */\n entryForm?: { entry?: CalendarWaitingEntry } | null;\n onSaveEntry?: (draft: WaitingEntryDraft) => void;\n onCancelEntry?: () => void;\n /** The patient-folder hop. Unset renders the name as plain text. */\n onOpenPatient?: (patient: CalendarPatient) => void;\n /** The platform's `focusAppointmentId` deep link — steer and ring. */\n onOpenAppointment: (eventId: string) => void;\n}\n\nexport const WaitingListPanel = forwardRef<\n HTMLDivElement,\n WaitingListPanelProps\n>(\n (\n {\n entries,\n rows,\n locale,\n status = 'ready',\n onRetry,\n onPlaceWaiting,\n onFindSlotsForWaiting,\n onRemoveWaiting,\n onOpenEntryForm,\n entryForm,\n onSaveEntry,\n onCancelEntry,\n onOpenPatient,\n onOpenAppointment,\n readOnly = false,\n privacy = false,\n },\n ref,\n ) => {\n const { t } = useTranslation();\n const data = useCalendarData();\n const headerRef = useRef<HTMLElement>(null);\n const advancedId = useId();\n const [quickView, setQuickView] = useState<WaitingQuickView>('all');\n const [showAdvanced, setShowAdvanced] = useState(false);\n /* The form's own state, and the SUBMITTED copy the list filters on —\n the platform only filters when \"Filtra elenco\" is pressed. */\n const [draft, setDraft] = useState<WaitingListFilters>(\n EMPTY_WAITING_FILTERS,\n );\n const [applied, setApplied] = useState<WaitingListFilters>(\n EMPTY_WAITING_FILTERS,\n );\n\n const patch = (next: Partial<WaitingListFilters>): void =>\n setDraft((prev) => ({ ...prev, ...next }));\n\n /* Changing the quick view re-filters at once and drops the advanced\n form, exactly as `_onAdvancedSearchViewChange` does. */\n const changeQuickView = (next: WaitingQuickView): void => {\n setQuickView(next);\n setShowAdvanced(false);\n setDraft(EMPTY_WAITING_FILTERS);\n setApplied(EMPTY_WAITING_FILTERS);\n };\n\n const views = useMemo(\n () => filterWaitingEntries(entries, rows, quickView, applied, data),\n [entries, rows, quickView, applied, data],\n );\n const groups = useMemo(() => groupWaitingRows(views), [views]);\n const counts = useMemo(\n () => waitingQuickViewCounts(entries, data),\n [entries, data],\n );\n const appliedCount = waitingFiltersActiveCount(applied);\n\n /* Settle in only when the cards REPLACE the placeholders. */\n const firstRead = status === 'loading' && entries.length === 0;\n const followedLoading = useRef(false);\n if (firstRead) followedLoading.current = true;\n const enterClass = followedLoading.current ? CONTENT_ENTER_CLASS : '';\n\n /* Kept while the subview leaves, so its title does not flip mid-exit. */\n const subview = onSaveEntry !== undefined && onCancelEntry !== undefined;\n const lastEntryRef = useRef<CalendarWaitingEntry | undefined>(undefined);\n if (entryForm) lastEntryRef.current = entryForm.entry;\n\n const yesNoOptions = [\n { value: 'yes', label: t(waitingKey('filterYes')) },\n { value: 'no', label: t(waitingKey('filterNo')) },\n ];\n\n const advancedForm = (\n <form\n id={advancedId}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n onSubmit={(event: FormEvent) => {\n event.preventDefault();\n setApplied(draft);\n }}\n >\n <FormField label={t(waitingKey('filterPatient'))}>\n <CalendarPatientPicker\n size=\"sm\"\n value={draft.patientId}\n onValueChange={(value) => patch({ patientId: value })}\n />\n </FormField>\n <FormField label={t(waitingKey('filterPatientAssigned'))}>\n <Select\n size=\"sm\"\n options={yesNoOptions}\n value={draft.patientAssigned}\n placeholder={t(waitingKey('filterAny'))}\n clearable\n onValueChange={(value) =>\n patch({ patientAssigned: value as WaitingYesNo })\n }\n />\n </FormField>\n <FormField label={t(waitingKey('filterOperator'))}>\n <Select\n size=\"sm\"\n options={[\n { value: NONE, label: t('calendarWorkspace.editor.unassigned') },\n ...activeOperators(data).map((o) => ({\n value: o.id,\n label: o.title,\n })),\n ]}\n value={draft.operatorId}\n placeholder={t(waitingKey('filterAny'))}\n clearable\n onValueChange={(value) => patch({ operatorId: value })}\n />\n </FormField>\n <FormField label={t(waitingKey('filterAppointmentScheduled'))}>\n <Select\n size=\"sm\"\n options={yesNoOptions}\n value={draft.appointmentScheduled}\n placeholder={t(waitingKey('filterAny'))}\n clearable\n onValueChange={(value) =>\n patch({ appointmentScheduled: value as WaitingYesNo })\n }\n />\n </FormField>\n <FormField label={t(waitingKey('filterAppointmentFrom'))}>\n <DatePicker\n size=\"sm\"\n value={draft.appointmentFrom}\n onChange={(value) => patch({ appointmentFrom: value })}\n />\n </FormField>\n <FormField label={t(waitingKey('filterAppointmentTo'))}>\n <DatePicker\n size=\"sm\"\n value={draft.appointmentTo}\n minDate={draft.appointmentFrom}\n onChange={(value) => patch({ appointmentTo: value })}\n />\n </FormField>\n <FormField label={t(waitingKey('filterWaitingFrom'))}>\n <DatePicker\n size=\"sm\"\n value={draft.waitingFrom}\n onChange={(value) => patch({ waitingFrom: value })}\n />\n </FormField>\n <FormField label={t(waitingKey('filterWaitingTo'))}>\n <DatePicker\n size=\"sm\"\n value={draft.waitingTo}\n minDate={draft.waitingFrom}\n onChange={(value) => patch({ waitingTo: value })}\n />\n </FormField>\n <FormField label={t(waitingKey('filterDescription'))}>\n <TextArea\n value={draft.description}\n placeholder={t(waitingKey('filterDescription'))}\n onChange={(event) => patch({ description: event.target.value })}\n minRows={1}\n autoResize\n />\n </FormField>\n <div>\n <Button size=\"sm\" intent=\"primary\" type=\"submit\">\n {t(waitingKey('filterSubmit'))}\n </Button>\n </div>\n </form>\n );\n\n const advancedLabel = t(\n waitingKey(showAdvanced ? 'hideAdvanced' : 'showAdvanced'),\n );\n\n return (\n <div\n ref={ref}\n data-component=\"calendar-waiting-list\"\n data-status={status}\n className=\"ds:flex ds:h-full ds:min-h-0 ds:flex-col\"\n >\n <PanelSubview.Host>\n <PanelHeader\n ref={headerRef}\n tabIndex={-1}\n title={t(waitingKey('tool'))}\n icon={<Hourglass aria-hidden=\"true\" />}\n sticky\n divider\n actions={\n readOnly || !onOpenEntryForm ? undefined : (\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n className={ACCESSIBLE_TARGET_SQUARE}\n icon={<Plus aria-hidden=\"true\" />}\n aria-label={t(waitingKey('addEntry'))}\n tooltip={t(waitingKey('addEntry'))}\n /* Focus target when the entry sub-view closes. */\n data-entry-add=\"\"\n onClick={() => onOpenEntryForm()}\n />\n )\n }\n filters={\n <div className=\"ds:flex ds:w-full ds:min-w-0 ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <div className=\"ds:flex ds:min-w-0 ds:items-start ds:gap-[var(--spacing-xs)]\">\n {/* Toggle buttons, one pressed at a time: the platform's\n \"Visualizza\" choices, each with its count. */}\n <div\n role=\"group\"\n aria-label={t(waitingKey('quickView'))}\n className=\"ds:flex ds:min-w-0 ds:flex-1 ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\"\n >\n {WAITING_QUICK_VIEWS.map((view) => {\n const active = quickView === view;\n const full = t(\n `calendarWorkspace.backlog.${WAITING_QUICK_VIEW_LABEL_KEY[view]}`,\n );\n return (\n <Tooltip key={view} label={full}>\n <Button\n size=\"sm\"\n intent={active ? 'primary' : 'outline'}\n className={ACCESSIBLE_TARGET}\n aria-pressed={active}\n aria-label={t(waitingKey('chipCount'), {\n view: full,\n n: counts[view],\n })}\n data-quick-view={view}\n onClick={() => changeQuickView(view)}\n >\n {t(waitingKey(CHIP_LABEL_KEY[view]))}\n <span className=\"ds:ms-[var(--spacing-xs)] ds:font-[var(--font-weight-bold)]\">\n {counts[view]}\n </span>\n </Button>\n </Tooltip>\n );\n })}\n </div>\n <span className=\"ds:relative ds:shrink-0\">\n <IconButton\n size=\"sm\"\n intent=\"outline\"\n className={ACCESSIBLE_TARGET_SQUARE}\n icon={<Funnel aria-hidden=\"true\" />}\n aria-label={advancedLabel}\n tooltip={advancedLabel}\n aria-expanded={showAdvanced}\n aria-controls={showAdvanced ? advancedId : undefined}\n onClick={() => setShowAdvanced((prev) => !prev)}\n />\n {appliedCount > 0 ? (\n <Badge\n size=\"sm\"\n variant=\"brand\"\n aria-label={t(waitingKey('filtersApplied'), {\n n: appliedCount,\n })}\n className=\"ds:pointer-events-none ds:absolute ds:-top-1 ds:-end-1\"\n >\n {appliedCount}\n </Badge>\n ) : null}\n </span>\n </div>\n {showAdvanced ? advancedForm : null}\n </div>\n }\n />\n {/* The queue owns its scroll: the Host is a clipped box, so the\n header stays put and the subview covers exactly this panel. */}\n <ScrollArea orientation=\"vertical\" className=\"ds:min-h-0 ds:flex-1\">\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:p-[var(--spacing-md)]\">\n {readOnly ? (\n /* Names the missing permission ONCE, at the top: without it\n the queue reads as a list whose actions simply went away. */\n <Alert\n variant=\"info\"\n announce=\"off\"\n icon={<Lock aria-hidden=\"true\" />}\n >\n <Alert.Title as=\"p\">\n {t('calendarWorkspace.details.readOnlyTitle')}\n </Alert.Title>\n <Alert.Description>\n {t('calendarWorkspace.inc1.readOnly.waitingLockedBody')}\n </Alert.Description>\n </Alert>\n ) : null}\n {status === 'loading' ? (\n <p role=\"status\" className=\"ds:sr-only\">\n {t('common.loading')}\n </p>\n ) : status === 'error' ? (\n <Alert variant=\"error\">\n <Alert.Description>\n {t('emptyState.error.description')}\n </Alert.Description>\n {onRetry ? (\n <Button size=\"sm\" intent=\"outline\" onClick={onRetry}>\n {t('emptyState.error.cta')}\n </Button>\n ) : null}\n </Alert>\n ) : null}\n {firstRead ? (\n <WaitingListSkeleton />\n ) : views.length === 0 ? (\n status === 'ready' ? (\n <EmptyState\n variant=\"first-use\"\n size=\"sm\"\n title={t(waitingKey('emptyTitle'))}\n description={t(waitingKey('emptyDescription'))}\n />\n ) : null\n ) : (\n <div\n aria-busy={status === 'loading'}\n data-waiting-groups=\"\"\n className={`ds:flex ds:flex-col ds:gap-[var(--spacing-md)] ${enterClass}`.trim()}\n >\n {groups.map((group) => (\n <WaitingGroup\n key={group.kind}\n kind={group.kind}\n count={group.rows.length}\n >\n {group.rows.map((view) => (\n <li\n key={view.entry.id}\n data-waiting-entry={view.entry.id}\n data-kind={group.kind}\n className=\"ds:min-w-0\"\n >\n <WaitingEntryCard\n view={view}\n locale={locale}\n privacy={privacy}\n readOnly={readOnly}\n onPlace={onPlaceWaiting}\n onFindSlots={onFindSlotsForWaiting}\n onEdit={onOpenEntryForm}\n onRemove={(entry) => {\n onRemoveWaiting(entry);\n /* The card is gone; the panel's heading is\n the nearest thing still standing. */\n headerRef.current?.focus();\n }}\n onOpenPatient={onOpenPatient}\n onOpenAppointment={onOpenAppointment}\n />\n </li>\n ))}\n </WaitingGroup>\n ))}\n </div>\n )}\n </div>\n </ScrollArea>\n {subview ? (\n <WaitingListEntrySubview\n open={entryForm != null}\n entry={entryForm ? entryForm.entry : lastEntryRef.current}\n onSave={onSaveEntry}\n onCancel={onCancelEntry}\n readOnly={readOnly}\n />\n ) : null}\n </PanelSubview.Host>\n </div>\n );\n },\n);\nWaitingListPanel.displayName = 'WaitingListPanel';\n\n/** One intent group: an uppercase muted label with its count, then cards. */\nfunction WaitingGroup({\n kind,\n count,\n children,\n}: {\n kind: WaitingEntryKind;\n count: number;\n children: ReactNode;\n}) {\n const { t } = useTranslation();\n const headingId = useId();\n return (\n <section\n aria-labelledby={headingId}\n data-waiting-group={kind}\n className=\"ds:flex ds:min-w-0 ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <h3\n id={headingId}\n className=\"type-eyebrow ds:m-0 ds:flex ds:items-center ds:gap-[var(--spacing-xs)] ds:text-start ds:text-[color:var(--muted-foreground)] ds:[&>svg]:size-3.5 ds:[&>svg]:shrink-0\"\n >\n {GROUP_ICON[kind]}\n {t(waitingKey(GROUP_LABEL_KEY[kind]))}\n {/* The bare number: a count Badge otherwise voices \"notifications\". */}\n <Badge size=\"sm\" variant=\"neutral\" aria-label={String(count)}>\n {count}\n </Badge>\n </h3>\n {/* eslint-disable-next-line jsx-a11y/no-redundant-roles -- role=\"list\" is NOT redundant: WebKit drops implicit list semantics when list-style is none */}\n <ul\n role=\"list\"\n className=\"ds:m-0 ds:flex ds:list-none ds:flex-col ds:gap-[var(--spacing-sm)] ds:p-0\"\n >\n {children}\n </ul>\n </section>\n );\n}\n","/**\n * Calendar pattern — the WORKSPACE ROOT.\n *\n * The practice agenda page the platform mounts from the kit: the grid\n * and its two-strip toolbar (`calendar.surface.tsx`) beside a MINIMAL\n * Control Room rail docked inline-end — up to six tools, in strip\n * order: the upcoming Appointments panel (the rail's resting state and\n * its default), ONE appointment editor / details tool, the waiting list,\n * patient notes when in context, online bookings and the free-slot finder. Nothing else — no Inbox,\n * no Alia, no patient tabs, no care plan, no tasks. The panels are the\n * extracted modules from `calendar.sheets.tsx`; `calendar.host.ts`'s\n * open / close seam maps onto the rail's dock, with `close()` returning\n * to the Appointments panel so no path leaves an empty rail.\n *\n * Six is the ceiling, not the floor: `availableTools` narrows the set\n * to what the host can actually back with data, hiding the rail tool AND\n * the toolbar control that opens it, and routing anything aimed at a\n * withheld tool to the Appointments panel. A host with no business\n * hours, holidays or closures must withhold the free-slot finder — it\n * would otherwise report booked and shut-day times as free.\n *\n * The host owns the data and the domain state: it hands in a\n * `CalendarData` read model (`calendar.data.ts`) and a `CalendarJourney`\n * (`calendar.journey.ts`) — the demos from their fixtures and the\n * fixture-backed journey hook, the platform island from\n * `/internalApi/...`. The workspace owns what sits between the two: the\n * cog's display settings, the privacy flag, the one polite region, the\n * editor tool's mode, the placement / create modes, the deep-link\n * effects and the tasks filter. It renders NO header or sidebar — the\n * host page has its own — and expects a bounded block-size from its\n * parent (it fills it; the surface scrolls inside, the rail stays put),\n * exactly what `AppFrame`'s `<main>` gives a page.\n *\n * The confirmations stay kit `Dialog`s — they interrupt rather than\n * dock: the move confirm, the delete confirm with its recurring scope\n * and care-plan cleanup and the Create-bill confirm.\n */\nimport type { CalendarEventStatus } from '../../components/calendar';\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n type RefObject,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport type { TFunction } from 'i18next';\nimport {\n CalendarClock,\n CalendarDays,\n CalendarPlus,\n CalendarSearch,\n Globe,\n Hourglass,\n NotebookPen,\n} from 'lucide-react';\nimport { UpcomingAppointmentsPanel } from './calendar-upcoming-panel';\nimport {\n ControlRoomProvider,\n ControlRoomRail,\n useControlRoomActions,\n useControlRoomTools,\n type ControlRoomTool,\n} from '../../components/control-room-rail';\nimport { ScrollArea } from '../../components/scroll-area';\nimport { toastInfo, toastWarning } from '../../components/toast';\nimport { TooltipProvider } from '../../components/tooltip';\nimport {\n CalendarEditorHydration,\n rowWithCanonicalEditor,\n type CalendarAppointmentEditorLoader,\n} from './calendar-editor-hydration';\nimport {\n AppointmentDetailsPanel,\n CalendarDetailsHydration,\n type CalendarAppointmentDetails,\n type CalendarAppointmentDetailsLoader,\n} from './calendar-appointment-details';\nimport { VisuallyHidden } from '../../components/visually-hidden';\nimport {\n CalendarNotesDock,\n CalendarPatientContext,\n} from './calendar-notes-tool';\nimport {\n CalendarDataProvider,\n useCalendarData,\n type CalendarData,\n} from './calendar.data';\nimport type { CalendarJourney } from './calendar.journey';\nimport {\n SheetHostProvider,\n type SheetHostContext,\n type SheetId,\n} from './calendar.host';\nimport {\n CALENDAR_PREFERENCE_KEYS,\n type CalendarPreferenceAdapter,\n memoryPreferenceAdapter,\n usePersistedPreference,\n} from './calendar.preferences';\nimport {\n type ColorAssociation,\n type CalendarHistoryEntry,\n type CalendarSignChannel,\n type CalendarWaitingEntry,\n type PatientRef,\n patientRefName,\n} from './calendar.types';\nimport {\n type CalendarRow,\n type EditorDraft,\n type EditorPrefill,\n type FindSlotsSeed,\n type AvailabilityContext,\n type CalendarFreeSlot,\n type RailFocus,\n type WaitingEntryDraft,\n editPrefillFromRow,\n FREE_SLOT_MAX_RANGE_DAYS,\n historyEntriesFromEdit,\n maskedTitle,\n patientRefById,\n processBookingPrefill,\n scheduleByEntryId,\n sortHistoryNewestFirst,\n} from './calendar.model';\nimport {\n ALL_WORKSPACE_TOOLS,\n type CalendarWaitingListState,\n type CalendarWorkspaceToolId,\n DEFAULT_WORKSPACE_DISPLAY,\n resolveAvailableTools,\n WORKSPACE_TOOL,\n type WorkspaceDisplaySettings,\n readWorkspaceDisplaySettings,\n onlineBookingsToCheck,\n type CreateModeRequest,\n type PlacementRequest,\n type SaveNotice,\n type EditorDraftExtras,\n type DeleteOptions,\n seriesScopeEventIds,\n applySeriesEdit,\n} from './calendar-workspace.model';\nimport {\n AppointmentEditorPanel,\n BookingsPanel,\n AppointmentExtras,\n AppointmentIdentity,\n type EditorPlatformOptions,\n type ExtrasPlatformOptions,\n FindFreeSlotsPanel,\n type FindSlotsPlatformOptions,\n PatientNotesPanel,\n type PatientNotesSeam,\n type ReminderChannel,\n} from './calendar.sheets';\nimport type { BookingCompleteIntent } from './calendar-bookings-panel';\nimport { whenRailSettled } from './calendar-rail-settle';\nimport { CalendarSurface } from './calendar.surface';\nimport { WaitingListPanel } from './calendar-waiting-list-panel';\nimport { PrivacyNoticePanel } from './calendar-privacy';\n\n/* The rail's five tool ids and their strip order live in the model —\n the surface reads them too, and must not import back into its own\n parent. Re-exported here because this is where hosts look for them. */\nexport {\n WORKSPACE_TOOL,\n type CalendarWorkspaceToolId,\n} from './calendar-workspace.model';\n\n/* The platform's calendar has exactly ONE outbound bridge — the\n popover's WhatsApp Snippets island — and this workspace holds no seam\n to reach it: no host handler, no island to mount. So the send-reminder\n group is handed an EMPTY channel list and `SendReminderGroup` renders\n nothing at all. A control the host cannot back is withheld, never\n shown and explained. */\nconst WORKSPACE_REMINDER_CHANNELS: readonly ReminderChannel[] = [];\n\n/* The platform's own ceiling on the appointment description — longer\n text is refused, silently there and with a message here. */\nconst WORKSPACE_DESCRIPTION_MAX = 255;\n\n/* The workspace's rail carries the agenda's five tools and nothing\n else — no global tools. One stable array, so the provider never\n re-registers. */\nconst NO_GLOBAL_TOOLS: ControlRoomTool[] = [];\n\n/** Which form the one editor tool wears: `edit` is the editor opened from\n * the read-only details panel (P-C3). */\ntype EditorMode = 'create' | 'details' | 'edit';\n\n/* What the polite region says when a tool docks. The editor line is the\n create form's — details docks from a grid selection, which names the\n patient instead. */\nfunction dockMessage(toolId: string, t: TFunction): string {\n if (toolId === WORKSPACE_TOOL.appointments)\n return t('calendarWorkspace.inc1.rail.appointmentsDocked');\n if (toolId === WORKSPACE_TOOL.editor)\n return t('calendarWorkspace.rail.editorDocked');\n if (toolId === WORKSPACE_TOOL.bookings)\n return t('calendarWorkspace.inc1.bookings.title');\n if (toolId === WORKSPACE_TOOL.waitingList)\n return t('calendarWorkspace.waitingList.docked');\n return t('calendarWorkspace.inc1.rail.findSlotsDocked');\n}\n\n/* The rail IS the sheet host here: `open` docks the tool a sheet id maps\n to, and `close` returns to the Appointments panel rather than\n collapsing — no path leaves an empty rail. The rail renders panels\n outside the page tree, so each panel wears its own provider, as does\n the surface; `onAnnounce` is the one polite region they share. */\nfunction CalendarSheetHost({\n onOpenSheet,\n onAnnounce,\n onClose,\n openNotes,\n children,\n}: {\n /** Journey-side routing: records the editor's mode and answers with\n * the rail tool to dock, if any — `null` docks nothing. */\n onOpenSheet: (id: SheetId) => string | null;\n /** Speaks the dock — a programmatic `openTool` moves no focus. */\n onAnnounce: (message: string) => void;\n /** Replaces the return to the Appointments panel (the edit form). */\n onClose?: () => void;\n openNotes?: SheetHostContext['openNotes'];\n children: ReactNode;\n}) {\n const { t } = useTranslation();\n const { openTool } = useControlRoomActions();\n const host = useMemo<SheetHostContext>(\n () => ({\n openNotes,\n open: (id) => {\n const toolId = onOpenSheet(id);\n if (!toolId) return;\n openTool(toolId);\n onAnnounce(dockMessage(toolId, t));\n },\n close: () => {\n if (onClose) return onClose();\n openTool(WORKSPACE_TOOL.appointments);\n onAnnounce(dockMessage(WORKSPACE_TOOL.appointments, t));\n },\n }),\n [onOpenSheet, onAnnounce, onClose, openNotes, openTool, t],\n );\n return <SheetHostProvider value={host}>{children}</SheetHostProvider>;\n}\n\n/* The editor tool's host. With the host's details read (P-C3) details mode\n is the read-only panel, and Edit swaps the editor in UNDER that read: a\n cancel returns to it without a re-read, a new tick re-reads. */\nfunction EditorToolHost({\n details,\n withheld,\n children,\n ...host\n}: Omit<Parameters<typeof CalendarSheetHost>[0], 'children'> & {\n /** Shown in place of the form, which then never mounts (privacy mode). */\n withheld?: ReactNode;\n details?: {\n eventId: string;\n tick: number;\n load: CalendarAppointmentDetailsLoader;\n editing: boolean;\n render: (read: CalendarAppointmentDetails) => ReactNode;\n };\n children: ReactNode;\n}) {\n return (\n <CalendarSheetHost {...host}>\n {details ? (\n <CalendarDetailsHydration\n key={`details-${details.eventId}-${details.tick}`}\n eventId={details.eventId}\n load={details.load}\n >\n {(read) =>\n details.editing ? (withheld ?? children) : details.render(read)\n }\n </CalendarDetailsHydration>\n ) : (\n (withheld ?? children)\n )}\n </CalendarSheetHost>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* The default panel — the platform DASHBOARD's upcoming appointments */\n/* ------------------------------------------------------------------ */\n\n/* `PracticeController::upcomingAppointmentsAction` on the kit timeline —\n Option A (\"Oggi operativo\"): the window floors to the BEGINNING OF\n TODAY rather than the instant of `now` (`upcomingWindowBounds`, see\n calendar-workspace.model.ts), so a row already under way (waiting room,\n in the chair) does not vanish from the feed the moment it starts. The\n panel itself lives in calendar-upcoming-panel.tsx — the \"In studio ora\"\n band, the summary strip, the dimmed/next row treatment, and the\n confirmed-badge suppression are all there, kept out of this file to\n keep this diff small. The preset row and the jump-to-date still widen\n the DERIVED window instead of fetching. Tasks never reach it — they\n leave the feed at the workspace boundary.\n\n HOST NOTE: the rows must cover the whole of today, not from \"now\", or\n a patient already in the practice drops out once the start passes. */\nfunction UpcomingPanel({\n rows,\n locale,\n privacy,\n stateSinceByEventId,\n onOpenAppointment,\n}: {\n rows: CalendarRow[];\n locale: string;\n stateSinceByEventId?: Readonly<Record<string, string>>;\n /** Privacy mode masks every name in this list, as it does on the grid —\n * a clinic-wide list of who is coming in is exactly what it hides. */\n privacy: boolean;\n /** Selects the appointment on the grid, which docks its details. */\n onOpenAppointment: (eventId: string) => void;\n}) {\n return (\n <UpcomingAppointmentsPanel\n rows={rows}\n locale={locale}\n privacy={privacy}\n stateSinceByEventId={stateSinceByEventId}\n onOpenAppointment={onOpenAppointment}\n />\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Rail registrar — the five tools, and the routing that docks them */\n/* ------------------------------------------------------------------ */\n\nfunction CalendarRailTools({\n workspaceRef,\n activeToolId,\n availableTools,\n focus,\n rows,\n locale,\n privacy,\n onPrivacyOff,\n selectedRow,\n patientRef,\n onOpenSheet,\n onAnnounce,\n editorMode,\n onEditorModeChange,\n editorSeed,\n loadAppointmentEditor,\n loadAppointmentDetails,\n waitingList,\n waitingSeedTick,\n findSlotsSeed,\n history,\n signRequests,\n colorAssociation,\n mapsLink,\n readOnly,\n notesSeamFor,\n businessHours,\n onSave,\n onDelete,\n onMove,\n onCopy,\n onStatusChange,\n onDescriptionChange,\n onBookSlotFromFinder,\n onRevealAppointment,\n onRequestSignature,\n onRemoveWaiting,\n onOpenEntryForm,\n entryForm,\n onSaveEntry,\n onCancelEntry,\n onShowAvailability,\n onFinderSearchRange,\n gridAxis,\n bookings,\n bookingQueue,\n waitingListState,\n stateSinceByEventId,\n reviewOnlyEventIds,\n bookingsSeedTick,\n bookingRequest,\n onCompleteBooking,\n onPlaceWaiting,\n}: {\n /** The tools this host can back — the rail registers these and no\n * others, and every route into a tool outside the set lands on the\n * Appointments panel instead. Always contains `appointments`. */\n availableTools: ReadonlySet<CalendarWorkspaceToolId>;\n activeToolId: string | null;\n workspaceRef: RefObject<HTMLDivElement | null>;\n /** A fresh object per grid click — the routing effect keys on it. */\n focus: RailFocus;\n rows: CalendarRow[];\n locale: string;\n /** Masks every patient name in the Appointments panel, in step with\n * the grid — the rail lists the whole day's names in the open. */\n privacy: boolean;\n /** The way out a withheld panel offers: the toolbar toggle, switched off. */\n onPrivacyOff: () => void;\n selectedRow: CalendarRow | null;\n /** The selected appointment's patient: the ID it carries and the\n * record, when the host could resolve it. Read `assigned` — never the\n * record — to decide whether anyone is booked. */\n patientRef: PatientRef;\n onOpenSheet: (id: SheetId) => string | null;\n /** Speaks the dock into the workspace's one polite region. */\n onAnnounce: (message: string) => void;\n editorMode: EditorMode;\n onEditorModeChange: (mode: EditorMode) => void;\n editorSeed: { tick: number; prefill?: EditorPrefill };\n loadAppointmentEditor?: CalendarAppointmentEditorLoader;\n loadAppointmentDetails?: CalendarAppointmentDetailsLoader;\n waitingList: CalendarWaitingEntry[];\n /** A fresh tick docks the waiting-list tool (the toolbar, a hand-off). */\n waitingSeedTick: number;\n findSlotsSeed: FindSlotsSeed | null;\n history: Record<string, CalendarHistoryEntry[]>;\n signRequests: Record<string, CalendarSignChannel>;\n colorAssociation: ColorAssociation;\n /** The cog's map-link switch, read by the details extras. */\n mapsLink: boolean;\n readOnly: boolean;\n /** Where the details panel's notes sub-view writes — one seam per\n * patient, built from the host's journey. */\n notesSeamFor: (patientId: string) => PatientNotesSeam;\n /** Platform advisories the finder raises when the scheduler is empty. */\n businessHours?: { practice?: boolean; operators?: boolean };\n onSave: (\n draft: EditorDraft,\n extras?: EditorDraftExtras,\n ) => void | Promise<void>;\n onDelete: (eventId: string, options?: DeleteOptions) => void;\n onMove: () => void;\n onCopy: (withTreatments?: boolean) => void;\n /** Absent: the details panel shows the status read-only. */\n onStatusChange?: (\n eventId: string,\n status: CalendarEventStatus,\n ) => Promise<void>;\n /** Absent: the details panel's description is read-only. */\n onDescriptionChange?: (eventId: string, description: string) => Promise<void>;\n onRevealAppointment: (eventId: string) => void;\n onRequestSignature: (eventId: string, channel: CalendarSignChannel) => void;\n onRemoveWaiting: (entry: CalendarWaitingEntry) => void;\n onOpenEntryForm: (entry?: CalendarWaitingEntry) => void;\n /** Non-null while the waiting-list tool shows its entry-form sub-view. */\n entryForm: { entry?: CalendarWaitingEntry } | null;\n onSaveEntry: (draft: WaitingEntryDraft) => void;\n onCancelEntry: () => void;\n /** The finder's Book: creates, or MOVES when the search is a\n * reschedule from the waiting list. */\n onBookSlotFromFinder: (prefill: EditorPrefill) => void;\n /** Online bookings still missing a patient or an operator. */\n bookings: readonly CalendarRow[];\n bookingQueue?: CalendarOnlineBookings;\n waitingListState?: CalendarWaitingListState;\n stateSinceByEventId?: Readonly<Record<string, string>>;\n reviewOnlyEventIds: ReadonlySet<string>;\n /** A fresh tick docks the bookings tool (the toolbar button). */\n bookingsSeedTick: number;\n /** The booking a host addressed; a fresh tick addresses it again. */\n bookingRequest: { tick: number; id?: string };\n /** Opens the editor to complete a booking. */\n onCompleteBooking: (row: CalendarRow, intent?: BookingCompleteIntent) => void;\n /** Projects the finder's results onto the grid. */\n onShowAvailability: (\n slots: CalendarFreeSlot[] | null,\n fromDate?: Date,\n context?: AvailabilityContext,\n ) => void;\n /** The grid's column axis, for the finder's plain-grid projection hint. */\n gridAxis: WorkspaceDisplaySettings['resourceKind'];\n onFinderSearchRange?: (range: { from: Date; to: Date }) => void;\n onPlaceWaiting: (entry: CalendarWaitingEntry) => void;\n}): ReactNode {\n const { t } = useTranslation();\n const data = useCalendarData();\n const { openTool } = useControlRoomActions();\n /* Plan line → its booked appointments, for the editor's checklist. */\n const contextKey =\n editorMode === 'create'\n ? `create-${editorSeed.tick}`\n : `${selectedRow?.event.id ?? ''}:${patientRef.id}`;\n const [patientContext, setPatientContext] = useState<{\n key?: string;\n id?: string;\n }>({});\n const reportPatient = useCallback(\n (id?: string) => {\n setPatientContext((previous) =>\n previous.key === contextKey && previous.id === id\n ? previous\n : { key: contextKey, id },\n );\n },\n [contextKey],\n );\n const notesPatientId =\n patientContext.key === contextKey\n ? patientContext.id\n : editorMode === 'create'\n ? editorSeed.prefill?.patientId\n : patientRef.id || undefined;\n const hasNotes = availableTools.has(WORKSPACE_TOOL.notes) && !!notesPatientId;\n const [notesRequest, setNotesRequest] = useState<{\n patientId?: string;\n noteId?: string;\n tick: number;\n }>({ tick: 0 });\n const previousActiveTool = useRef(activeToolId);\n useEffect(() => {\n const leftNotes =\n previousActiveTool.current === WORKSPACE_TOOL.notes &&\n activeToolId !== WORKSPACE_TOOL.notes;\n previousActiveTool.current = activeToolId;\n setNotesRequest((previous) =>\n previous.patientId && (leftNotes || previous.patientId !== notesPatientId)\n ? { tick: previous.tick }\n : previous,\n );\n }, [activeToolId, notesPatientId]);\n const focusFrame = useRef(0);\n useEffect(() => () => cancelAnimationFrame(focusFrame.current), []);\n const previousTool = useRef<string>(WORKSPACE_TOOL.appointments);\n const openNotes = useCallback(\n (id: string, noteId?: string) => {\n if (!hasNotes || id !== notesPatientId) return;\n setNotesRequest((previous) => ({\n patientId: id,\n noteId,\n tick: previous.tick + 1,\n }));\n openTool(WORKSPACE_TOOL.notes);\n onAnnounce(t('calendarWorkspace.rail.notes'));\n },\n [hasNotes, notesPatientId, openTool, onAnnounce, t],\n );\n const schedule = useMemo(() => scheduleByEntryId(rows), [rows]);\n /* What to call a patient whose id the host gave us but whose record it\n did not — never the \"no patient assigned\" of an unbooked slot. */\n const unresolvedPatientLabel = t(\n 'calendarWorkspace.details.patientNotLoaded',\n );\n /* The selection as scalars. `focusedPatientId` is the APPOINTMENT's own\n id, not the resolved record's: an id the host could not resolve still\n means someone is booked, and only an empty one means nobody is. */\n const focusedPatientId = patientRef.id;\n /* Spoken into the polite region, so privacy masks it like the card. */\n const focusedPatientName =\n privacy && selectedRow\n ? maskedTitle(selectedRow.event, true)\n : patientRefName(\n patientRef,\n selectedRow?.event.title,\n unresolvedPatientLabel,\n );\n\n /* ---- platform parity, panel side -------------------------------- */\n\n const devicesByCare = data.practiceFeatures.findFreeSlotsByCare\n ? data.careDevices\n : undefined;\n const unsignedRequiredDocs = useCallback(\n (patientId: string): number => data.unsignedRequiredDocs[patientId] ?? 0,\n [data],\n );\n /* The platform has no \"send reminder now\" action on the calendar —\n its one outbound bridge is the popover's WhatsApp Snippets island,\n so the footer keeps that segment alone. */\n const editorPlatform = useMemo<EditorPlatformOptions>(\n () => ({\n branches: data.branches,\n devicesByCare,\n unsignedRequiredDocs,\n rows,\n submitOnEnter: true,\n reminderChannels: WORKSPACE_REMINDER_CHANNELS,\n /* Frequency + repetition count only: no end date, no closed-day\n skip — the platform's recurrence row stops there. */\n recurrenceExtras: false,\n /* The platform modal's own rules: an away operator warns and saves,\n reminders and the first-visit question hang off the patient,\n price-list rows carry phases and lock once invoiced, and a\n description over 255 characters refuses. */\n operatorAbsenceWarning: true,\n reminderCapability: true,\n firstVisitRequiresPatient: true,\n priceListPhases: true,\n descriptionMaxLength: WORKSPACE_DESCRIPTION_MAX,\n /* No `onSaveAndReturn`: the deep link's origin (a care plan, a\n patient folder) is off this page and the workspace has no way\n back to it, so the split Save is withheld — see the\n `createParameters` arrival, which drops `simpleSave: false`. */\n }),\n [data.branches, devicesByCare, unsignedRequiredDocs, rows],\n );\n /* Details adds the series scope and, for a price-list recurrence\n parent, the care-plan cleanup on delete. An appointment still held\n by a DISABLED operator widens the operator select just enough to\n name them — a new appointment never offers one. */\n const detailsPlatform = useMemo<EditorPlatformOptions>(\n () => ({\n ...editorPlatform,\n recurringScope: Boolean(selectedRow?.series),\n carePlanCleanup:\n data.practiceFeatures.recurringPriceListCarePlanEntries &&\n selectedRow?.event.isRecurrenceParent === true &&\n selectedRow.careLink?.kind === 'priceList',\n operatorOptions:\n selectedRow?.operatorId &&\n data.inactiveOperatorIds.includes(selectedRow.operatorId)\n ? data.operators\n : undefined,\n }),\n [editorPlatform, selectedRow, data],\n );\n /* Built from the ROW, not the record. Money paid online, the phone\n typed on the booking site, the AES flag and the map-link setting are\n APPOINTMENT- and PRACTICE-level facts the host supplies whether or\n not `patientById` can answer; gating the whole object on a resolved\n record dropped every one of them. Only the members genuinely read\n off the record stay conditional. */\n const extrasPlatform = useMemo<ExtrasPlatformOptions | undefined>(\n () =>\n selectedRow\n ? {\n paidOnlineAmount: data.paidOnline[selectedRow.event.id],\n toCollectAmount: patientRef.record?.unpaidAmount,\n mapsLink,\n bookingPhone: data.bookingPhones[selectedRow.event.id],\n }\n : undefined,\n [selectedRow, patientRef, mapsLink, data],\n );\n /* The finder's platform depth: a results list plus the grid projection, the medical\n device, the 185-day ceiling and the +30-day pager. */\n const findSlotsPlatform = useMemo<FindSlotsPlatformOptions>(\n () => ({\n devicesByCare,\n maxRangeDays: FREE_SLOT_MAX_RANGE_DAYS,\n pagerStepDays: 30,\n /* C7 — the platform scopes the search with grouped multi-select\n dropdowns, not one Select plus \"Any\". */\n multiSelectScope: true,\n operatorGroups: data.operatorGroups,\n practiceHasBusinessHours: businessHours?.practice ?? true,\n operatorsHaveBusinessHours: businessHours?.operators ?? true,\n /* `onOpenScheduler` withheld: the advisory's link goes to the practice's\n scheduling page and no host seam carries that navigation. The finder\n guards on the prop (`platform?.onOpenScheduler ? … : null`), so leaving\n it off takes the existing withhold branch — the advisory still states\n which hours are missing, it just does not offer to open the page. */\n }),\n [\n devicesByCare,\n data.operatorGroups,\n businessHours?.practice,\n businessHours?.operators,\n ],\n );\n\n /* ---- the six tools --------------------------------------------- */\n\n const appointmentsTool = useMemo<ControlRoomTool>(\n () => ({\n id: WORKSPACE_TOOL.appointments,\n label: t('calendarWorkspace.inc1.rail.appointments'),\n icon: <CalendarDays aria-hidden=\"true\" />,\n /* fill: the timeline owns its scroll (day anchoring + edge loads). */\n fill: true,\n panel: (\n <UpcomingPanel\n rows={rows}\n locale={locale}\n privacy={privacy}\n stateSinceByEventId={stateSinceByEventId}\n onOpenAppointment={onRevealAppointment}\n />\n ),\n }),\n [rows, locale, privacy, stateSinceByEventId, onRevealAppointment, t],\n );\n\n /* ONE tool, two forms: the create editor (keyed by the seed tick so a\n fresh request re-seeds a clean form) or the same panel in details\n mode for the selected appointment. With the host's details read,\n details is the read-only panel and `edit` is the form (P-C3). */\n const detailsMode = editorMode !== 'create' && selectedRow !== null;\n const readsDetails = detailsMode && loadAppointmentDetails !== undefined;\n const editing = readsDetails && editorMode === 'edit';\n const detailsReadOnly =\n readOnly ||\n Boolean(selectedRow && reviewOnlyEventIds.has(selectedRow.event.id));\n /* Privacy: a form opened on stored patient data would show what the mask\n hides, so it is withheld with the way out. A blank create form stays. */\n const seededPrefill = editorSeed.prefill;\n const formWithheld =\n privacy &&\n (detailsMode\n ? !readsDetails || editing\n : Boolean(\n seededPrefill?.editEventId ||\n seededPrefill?.patientId ||\n seededPrefill?.bookingContact,\n ));\n /* Where the edit form's close lands (P-C3 step 4): a save re-reads the\n details, a delete leaves for Appointments, a cancel returns as it was. */\n const editOutcome = useRef<'saved' | 'deleted' | null>(null);\n /* The event whose details panel takes focus back onto its Edit button. */\n const refocusEdit = useRef<string | null>(null);\n const [detailsTick, setDetailsTick] = useState(0);\n const saveEdit = useCallback(\n async (draft: EditorDraft, extras?: EditorDraftExtras): Promise<void> => {\n await onSave(draft, extras);\n editOutcome.current = 'saved';\n },\n [onSave],\n );\n const deleteEdit = useCallback(\n (eventId: string, options?: DeleteOptions): void => {\n editOutcome.current = 'deleted';\n onDelete(eventId, options);\n },\n [onDelete],\n );\n const closeEdit = useCallback((): void => {\n const outcome = editOutcome.current;\n editOutcome.current = null;\n onEditorModeChange('details');\n if (outcome === 'deleted') {\n openTool(WORKSPACE_TOOL.appointments);\n onAnnounce(dockMessage(WORKSPACE_TOOL.appointments, t));\n return;\n }\n if (outcome === 'saved') setDetailsTick((tick) => tick + 1);\n onAnnounce(\n t('calendarWorkspace.details.docked', { name: focusedPatientName }),\n );\n }, [onEditorModeChange, openTool, onAnnounce, focusedPatientName, t]);\n /* An untriaged online booking completes on its processing flow, as a\n booking does today; anything else opens the editor (P-C3 step 2). */\n const editFromDetails = useCallback((): void => {\n if (!selectedRow) return;\n const { event } = selectedRow;\n if (event.hasUnassignedPatient && event.isBookedOnline)\n return onCompleteBooking(selectedRow);\n editOutcome.current = null;\n refocusEdit.current = event.id;\n onEditorModeChange('edit');\n }, [selectedRow, onCompleteBooking, onEditorModeChange]);\n const renderDetails = useCallback(\n (read: CalendarAppointmentDetails): ReactNode => {\n /* The row's patient id first (N-C5): the notes seam answers to it. */\n const notesPatient = patientRef.id || read.patient?.id;\n return (\n <div\n className=\"ds:contents\"\n ref={(node) => {\n if (!node || refocusEdit.current !== read.eventId) return;\n refocusEdit.current = null;\n /* The footer's ButtonGroup keeps inert measuring copies of each\n action, so take the live one. */\n [\n ...node.querySelectorAll<HTMLElement>(\n '[data-action=\"edit-appointment\"]',\n ),\n ]\n .find((button) => !button.closest('[inert]'))\n ?.focus();\n }}\n >\n <CalendarPatientContext\n patientId={notesPatient}\n onChange={reportPatient}\n />\n <AppointmentDetailsPanel\n onOpenNotes={hasNotes ? openNotes : undefined}\n /* Deduplicate by stable id; the canonical read wins a collision. */\n details={{\n ...read,\n history: [\n ...new Map(\n [...(history[read.eventId] ?? []), ...read.history].map(\n (entry) => [entry.id, entry],\n ),\n ).values(),\n ],\n }}\n patientId={notesPatient}\n notesSeam={notesPatient ? notesSeamFor(notesPatient) : undefined}\n readOnly={detailsReadOnly}\n onEdit={editFromDetails}\n onMove={onMove}\n onCopy={onCopy}\n onStatusChange={\n onStatusChange\n ? (status) => onStatusChange(read.eventId, status)\n : undefined\n }\n onDescriptionChange={\n onDescriptionChange\n ? (description) =>\n onDescriptionChange(read.eventId, description)\n : undefined\n }\n mapsLink={mapsLink}\n privacy={privacy}\n privacyTitle={selectedRow?.event.privacyModeTitle}\n locale={locale}\n />\n </div>\n );\n },\n [\n privacy,\n selectedRow?.event.privacyModeTitle,\n patientRef.id,\n reportPatient,\n hasNotes,\n openNotes,\n history,\n notesSeamFor,\n detailsReadOnly,\n editFromDetails,\n onMove,\n onCopy,\n onStatusChange,\n onDescriptionChange,\n mapsLink,\n locale,\n ],\n );\n const editorTool = useMemo<ControlRoomTool>(\n () => ({\n id: WORKSPACE_TOOL.editor,\n label: detailsMode\n ? t('calendarWorkspace.details.region')\n : t(\n editorSeed.prefill?.editEventId\n ? 'calendarWorkspace.editor.editTitle'\n : 'calendarWorkspace.editor.title',\n ),\n icon: detailsMode ? (\n <CalendarClock aria-hidden=\"true\" />\n ) : (\n <CalendarPlus aria-hidden=\"true\" />\n ),\n /* fill: the panel owns its scroll so its save footer stays pinned. */\n fill: true,\n panel: (\n <EditorToolHost\n withheld={\n formWithheld ? (\n <PrivacyNoticePanel\n title={t(\n detailsMode && !editing\n ? 'calendarWorkspace.details.region'\n : detailsMode || seededPrefill?.editEventId\n ? 'calendarWorkspace.editor.editTitle'\n : 'calendarWorkspace.editor.title',\n )}\n icon={<CalendarClock aria-hidden=\"true\" />}\n onTurnOff={onPrivacyOff}\n />\n ) : undefined\n }\n openNotes={hasNotes ? openNotes : undefined}\n onOpenSheet={onOpenSheet}\n onAnnounce={onAnnounce}\n onClose={editing ? closeEdit : undefined}\n details={\n readsDetails && selectedRow && loadAppointmentDetails\n ? {\n eventId: selectedRow.event.id,\n tick: detailsTick,\n load: loadAppointmentDetails,\n editing,\n render: renderDetails,\n }\n : undefined\n }\n >\n <CalendarEditorHydration\n key={\n detailsMode\n ? `${editing ? 'edit' : 'details'}-${selectedRow?.event.id}`\n : `create-${editorSeed.tick}`\n }\n eventId={\n detailsMode\n ? selectedRow?.event.id\n : editorSeed.prefill?.editEventId\n }\n load={loadAppointmentEditor}\n onCancel={editing ? closeEdit : undefined}\n >\n {(snapshot) => {\n const editorPatientRef = snapshot\n ? patientRefById(snapshot.prefill.patientId, data)\n : patientRef;\n const editorPatient = editorPatientRef.record;\n const editorRow =\n snapshot && selectedRow\n ? rowWithCanonicalEditor(\n selectedRow,\n snapshot,\n patientRefName(\n editorPatientRef,\n snapshot.prefill.patientId ===\n selectedRow.event.patientId\n ? selectedRow.event.title\n : undefined,\n unresolvedPatientLabel,\n ),\n )\n : selectedRow;\n return (\n <>\n {detailsMode && editorRow ? (\n /* Details IS the create form, prefilled — ONE editing\n paradigm; no separate read-only surface, no Edit jump. */\n <AppointmentEditorPanel\n onPatientContextChange={reportPatient}\n key={`details-${editorRow.event.id}`}\n prefill={\n snapshot?.prefill ?? editPrefillFromRow(editorRow)\n }\n capabilities={snapshot?.capabilities}\n series={snapshot?.series}\n panelTitle={t(\n editing\n ? 'calendarWorkspace.editor.editTitle'\n : 'calendarWorkspace.details.region',\n )}\n returnsOnCancel={editing}\n headerIcon={<CalendarClock aria-hidden=\"true\" />}\n identity={\n /* The platform popover's identity line: the age beside\n the name, the name a link to the patient folder, and\n the highlighted anamnesis ANSWERS, not just a count. */\n <AppointmentIdentity\n row={editorRow}\n patientRef={editorPatientRef}\n showAge\n /* No `onOpenPatient`: the patient folder is a platform\n page this workspace cannot route to, so the strip\n takes its existing plain-text branch — the NAME is a\n fact and stays. */\n anamnesisAnswers={\n editorPatient?.highlightedAnamnesisAnswers\n }\n />\n }\n after={\n <AppointmentExtras\n row={editorRow}\n patient={editorPatient}\n locale={locale}\n signRequestedVia={\n signRequests[editorRow.event.id] ??\n data.metaById[editorRow.event.id]?.signRequestedVia\n }\n onRequestSignature={onRequestSignature}\n /* No `onRequestSignatureOnDevice`: the legacy on-device\n e-signature island is not mounted here, so the\n \"On this device…\" item is withheld and the menu keeps\n the SMS and e-mail requests it can honour. */\n readOnly={detailsReadOnly}\n platform={\n snapshot\n ? {\n ...extrasPlatform,\n toCollectAmount: editorPatient?.unpaidAmount,\n }\n : extrasPlatform\n }\n />\n }\n history={sortHistoryNewestFirst(\n history[editorRow.event.id] ?? [],\n )}\n onSave={editing ? saveEdit : onSave}\n onDelete={editing ? deleteEdit : onDelete}\n onMove={onMove}\n onCopy={onCopy}\n readOnly={detailsReadOnly}\n platform={detailsPlatform}\n colorAssociation={colorAssociation}\n locale={locale}\n scheduleByEntry={schedule}\n />\n ) : (\n <AppointmentEditorPanel\n onPatientContextChange={reportPatient}\n key={`create-${editorSeed.tick}`}\n prefill={\n snapshot\n ? {\n ...snapshot.prefill,\n callToAction:\n editorSeed.prefill?.callToAction ??\n snapshot.prefill.callToAction,\n waitingEntryId:\n editorSeed.prefill?.waitingEntryId ??\n snapshot.prefill.waitingEntryId,\n simpleSave:\n editorSeed.prefill?.simpleSave ??\n snapshot.prefill.simpleSave,\n bookingContact:\n editorSeed.prefill?.bookingContact ??\n snapshot.prefill.bookingContact,\n initialFocus: editorSeed.prefill?.initialFocus,\n }\n : editorSeed.prefill\n }\n capabilities={snapshot?.capabilities}\n series={snapshot?.series}\n onSave={onSave}\n onDelete={onDelete}\n /* Same permission as the details branch: without it the\n create form rendered fully enabled for a read-only\n viewer and its Save reported a row that was never\n written. */\n readOnly={\n readOnly ||\n Boolean(\n editorSeed.prefill?.editEventId &&\n reviewOnlyEventIds.has(\n editorSeed.prefill.editEventId,\n ),\n )\n }\n colorAssociation={colorAssociation}\n locale={locale}\n scheduleByEntry={schedule}\n platform={editorPlatform}\n />\n )}\n </>\n );\n }}\n </CalendarEditorHydration>\n </EditorToolHost>\n ),\n }),\n [\n formWithheld,\n seededPrefill,\n onPrivacyOff,\n detailsMode,\n hasNotes,\n openNotes,\n reportPatient,\n readsDetails,\n editing,\n detailsTick,\n loadAppointmentDetails,\n closeEdit,\n saveEdit,\n deleteEdit,\n renderDetails,\n detailsReadOnly,\n loadAppointmentEditor,\n reviewOnlyEventIds,\n unresolvedPatientLabel,\n data,\n selectedRow,\n patientRef,\n editorSeed,\n onOpenSheet,\n onAnnounce,\n onSave,\n onDelete,\n onMove,\n onCopy,\n onRequestSignature,\n signRequests,\n history,\n readOnly,\n extrasPlatform,\n detailsPlatform,\n editorPlatform,\n colorAssociation,\n locale,\n schedule,\n t,\n ],\n );\n\n /* A host's addressed booking reaches the panel once the tool is up, the\n row is in the queue and the entrance has settled: the panel scrolls and\n focuses on receipt, which would otherwise fight the motion. */\n const [bookingAddress, setBookingAddress] = useState<{\n tick: number;\n id?: string;\n }>({ tick: 0 });\n const bookingQueued =\n bookingRequest.id !== undefined &&\n bookings.some((row) => row.event.id === bookingRequest.id);\n useEffect(() => {\n if (activeToolId !== WORKSPACE_TOOL.bookings) {\n /* Left the tool: reopening it later must not replay the address. */\n setBookingAddress((prev) => (prev.id ? { tick: prev.tick } : prev));\n return undefined;\n }\n if (!bookingQueued || bookingAddress.tick === bookingRequest.tick)\n return undefined;\n return whenRailSettled(\n () =>\n workspaceRef.current?.querySelector<HTMLElement>(\n `[data-active-tool=\"${WORKSPACE_TOOL.bookings}\"] [data-tool-rail-layer=\"live\"]`,\n ),\n () => setBookingAddress(bookingRequest),\n );\n }, [\n activeToolId,\n bookingQueued,\n bookingRequest,\n bookingAddress.tick,\n workspaceRef,\n ]);\n\n /* The platform's \"Prenotazioni online\" PAGE, hosted in the rail. The\n page still exists — the booking e-mail and the top bar link to it. */\n const bookingsTool = useMemo<ControlRoomTool>(\n () => ({\n id: WORKSPACE_TOOL.bookings,\n label: t('calendarWorkspace.inc1.bookings.title'),\n icon: <Globe aria-hidden=\"true\" />,\n badgeCount: bookings.length,\n panel: (\n <CalendarSheetHost onOpenSheet={onOpenSheet} onAnnounce={onAnnounce}>\n <BookingsPanel\n bookings={bookings}\n locale={locale}\n privacy={privacy}\n status={bookingQueue?.status}\n lastSeenIso={bookingQueue?.lastSeenIso}\n createdAtById={bookingQueue?.createdAtById}\n currentBookingId={bookingAddress.id}\n currentBookingKey={bookingAddress.tick}\n onRetry={bookingQueue?.onRetry}\n onShowInCalendar={onRevealAppointment}\n onComplete={\n !readOnly &&\n (!bookingQueue ||\n (bookingQueue.canComplete === true &&\n Boolean(loadAppointmentEditor)))\n ? onCompleteBooking\n : undefined\n }\n />\n </CalendarSheetHost>\n ),\n }),\n [\n bookings,\n bookingQueue,\n bookingAddress,\n loadAppointmentEditor,\n readOnly,\n locale,\n privacy,\n onOpenSheet,\n onAnnounce,\n onRevealAppointment,\n onCompleteBooking,\n t,\n ],\n );\n\n /* The platform's waiting-list modal, 1:1 — no Backlog: \"unconfirmed\",\n \"no operator\" and \"signatures pending\" are queues production does\n not have, and online bookings sit on their own toolbar button.\n The badge counts waiting ENTRIES only (decision 5). */\n const waitingListTool = useMemo<ControlRoomTool>(\n () => ({\n id: WORKSPACE_TOOL.waitingList,\n label: t('calendarWorkspace.waitingList.tool'),\n icon: <Hourglass aria-hidden=\"true\" />,\n badgeCount: waitingList.length,\n /* SUB-VIEW, not a dialog: the entry form is a four-field FORM, so\n it docks in the rail like every other panel and the header's\n back arrow returns to the list (the History / Notes idiom). */\n panel: (\n <CalendarSheetHost onOpenSheet={onOpenSheet} onAnnounce={onAnnounce}>\n {entryForm?.entry && privacy ? (\n /* Editing an entry opens its patient and free text in fields. */\n <PrivacyNoticePanel\n title={t('calendarWorkspace.waitingList.tool')}\n icon={<Hourglass aria-hidden=\"true\" />}\n onTurnOff={onPrivacyOff}\n />\n ) : (\n <WaitingListPanel\n entries={waitingList}\n rows={rows}\n locale={locale}\n privacy={privacy}\n status={waitingListState?.status}\n onRetry={waitingListState?.onRetry}\n /* Same permission the editor keys on: without it Add, Edit\n and Remove all reached host seams a read-only host\n refuses, and the panel announced the change anyway. */\n readOnly={readOnly}\n onPlaceWaiting={onPlaceWaiting}\n onFindSlotsForWaiting={onPlaceWaiting}\n onRemoveWaiting={onRemoveWaiting}\n onOpenEntryForm={onOpenEntryForm}\n /* The entry form slides over the list as a PanelSubview. */\n entryForm={entryForm}\n onSaveEntry={onSaveEntry}\n onCancelEntry={onCancelEntry}\n /* No `onOpenPatient`: same withhold as the identity strip —\n the row keeps the patient's NAME, loses the folder hop. */\n onOpenAppointment={onRevealAppointment}\n />\n )}\n </CalendarSheetHost>\n ),\n }),\n [\n privacy,\n onPrivacyOff,\n entryForm,\n onSaveEntry,\n onCancelEntry,\n waitingList,\n waitingListState,\n rows,\n locale,\n onOpenSheet,\n onAnnounce,\n onPlaceWaiting,\n onRemoveWaiting,\n onOpenEntryForm,\n onRevealAppointment,\n readOnly,\n t,\n ],\n );\n\n const findSlotsTool = useMemo<ControlRoomTool>(\n () => ({\n id: WORKSPACE_TOOL.findSlots,\n label: t('calendarWorkspace.findSlots.tool'),\n icon: <CalendarSearch aria-hidden=\"true\" />,\n panel: (\n /* Keyed by the seed tick so a waiting-list hand-off re-seeds a\n fresh, prefilled, auto-searched panel. */\n <CalendarSheetHost onOpenSheet={onOpenSheet} onAnnounce={onAnnounce}>\n <FindFreeSlotsPanel\n key={findSlotsSeed?.tick ?? 0}\n rows={rows}\n locale={locale}\n seed={findSlotsSeed}\n onBookSlot={onBookSlotFromFinder}\n onShowInCalendar={onShowAvailability}\n onSearchRange={onFinderSearchRange}\n platform={findSlotsPlatform}\n gridAxis={gridAxis}\n canBook={!readOnly}\n />\n </CalendarSheetHost>\n ),\n }),\n [\n rows,\n locale,\n findSlotsSeed,\n gridAxis,\n onOpenSheet,\n onAnnounce,\n onBookSlotFromFinder,\n onShowAvailability,\n onFinderSearchRange,\n findSlotsPlatform,\n readOnly,\n t,\n ],\n );\n\n /* Strip order, minus the tools this host cannot back with real data.\n A tool a host has no data for must not be offered at all: the\n free-slot finder with no business hours, holidays or closures\n reports booked and shut-day times as free, and staff would ring\n patients with them. */\n const tools = useMemo<ControlRoomTool[]>(() => {\n const sharedPanel = availableTools.has(WORKSPACE_TOOL.notes) ? (\n <CalendarNotesDock\n editor={editorTool.panel}\n active={activeToolId === WORKSPACE_TOOL.notes}\n request={notesRequest.tick}\n notes={\n notesPatientId && privacy ? (\n /* Notes are free text under the patient's name: all withheld. */\n <PrivacyNoticePanel\n title={t('calendarWorkspace.rail.notes')}\n icon={<NotebookPen aria-hidden=\"true\" />}\n onTurnOff={onPrivacyOff}\n />\n ) : notesPatientId ? (\n <PatientNotesPanel\n patientId={notesPatientId}\n editable={!detailsReadOnly}\n seam={notesSeamFor(notesPatientId)}\n currentNoteId={\n notesRequest.patientId === notesPatientId\n ? notesRequest.noteId\n : undefined\n }\n currentNoteKey={notesRequest.tick}\n />\n ) : null\n }\n />\n ) : (\n editorTool.panel\n );\n const registry: Record<CalendarWorkspaceToolId, ControlRoomTool> = {\n [WORKSPACE_TOOL.appointments]: appointmentsTool,\n [WORKSPACE_TOOL.editor]: { ...editorTool, panel: sharedPanel },\n [WORKSPACE_TOOL.notes]: {\n id: WORKSPACE_TOOL.notes,\n label: t('calendarWorkspace.rail.notes'),\n icon: <NotebookPen aria-hidden=\"true\" />,\n fill: true,\n panel: sharedPanel,\n },\n [WORKSPACE_TOOL.waitingList]: waitingListTool,\n [WORKSPACE_TOOL.bookings]: bookingsTool,\n [WORKSPACE_TOOL.findSlots]: findSlotsTool,\n };\n return ALL_WORKSPACE_TOOLS.filter(\n (id) =>\n availableTools.has(id) && (id !== WORKSPACE_TOOL.notes || hasNotes),\n ).map((id) => registry[id]);\n }, [\n privacy,\n onPrivacyOff,\n hasNotes,\n detailsReadOnly,\n activeToolId,\n notesPatientId,\n notesRequest,\n notesSeamFor,\n t,\n availableTools,\n appointmentsTool,\n editorTool,\n waitingListTool,\n bookingsTool,\n findSlotsTool,\n ]);\n useControlRoomTools(tools);\n\n /* Dock a tool and speak it — falling back to the Appointments panel\n when this host cannot back the one asked for, so a hand-off into a\n hidden tool lands somewhere rather than on an empty dock. */\n const dockTool = useCallback(\n (toolId: CalendarWorkspaceToolId): void => {\n const target = availableTools.has(toolId)\n ? toolId\n : WORKSPACE_TOOL.appointments;\n openTool(target);\n onAnnounce(dockMessage(target, t));\n },\n [availableTools, openTool, onAnnounce, t],\n );\n\n /* ---- routing ----------------------------------------------------- */\n\n /* The rail OPENS on the Appointments panel: the next seven days are\n the resting state, so the dock is never blank. Runs before the\n routing effects below, which a deep link then wins on its own\n commit. */\n const openedRef = useRef(false);\n useEffect(() => {\n if (openedRef.current) return;\n openedRef.current = true;\n openTool(WORKSPACE_TOOL.appointments);\n }, [openTool]);\n\n /* A card click sets `focus` (a fresh object per click) → the editor\n tool in details mode; DESELECTING returns to the Appointments panel\n rather than collapsing the rail. Declared BEFORE the seed effects so\n an empty-slot click's deselect + editor seed resolve to the editor\n in the same commit — the later effect's announcement wins too.\n\n It reads the selection through the SCALARS above, never the row\n object: a re-keyed feed hands us a fresh `selectedRow` for the same\n appointment, and re-docking on that would yank the rail out from\n under whatever the user opened next. */\n const prevFocusRef = useRef<RailFocus>(focus);\n useEffect(() => {\n const prev = prevFocusRef.current;\n /* The SAME selection, re-rendered: a name that changed under us, a\n re-keyed feed, a new `t`. Docking again here would yank the rail\n out from under whatever the user opened after the click, and\n re-announce an arrival that already happened. `focus` is a fresh\n object per click, so identity is exactly the \"did the user select\n something?\" test. */\n if (prev === focus) return;\n prevFocusRef.current = focus;\n if (!focus) {\n if (prev) {\n openTool(WORKSPACE_TOOL.appointments);\n onAnnounce(dockMessage(WORKSPACE_TOOL.appointments, t));\n }\n return;\n }\n if (reviewOnlyEventIds.has(focus.eventId)) {\n dockTool(WORKSPACE_TOOL.bookings);\n return;\n }\n /* No patient AT ALL and no details read: the surface sends such a row\n to the editor instead, so there is nothing to dock. With the read a\n patient-less or pending row docks its details (P-C3). An id the host\n could not resolve is a real patient and always docks. */\n if (!focusedPatientId && !loadAppointmentDetails) return;\n /* A host without the editor tool has nowhere to show the selection:\n stay on the resting panel rather than dock an empty one. */\n if (!availableTools.has(WORKSPACE_TOOL.editor)) {\n dockTool(WORKSPACE_TOOL.editor);\n return;\n }\n onEditorModeChange('details');\n openTool(WORKSPACE_TOOL.editor);\n onAnnounce(\n t('calendarWorkspace.details.docked', { name: focusedPatientName }),\n );\n }, [\n focus,\n reviewOnlyEventIds,\n focusedPatientId,\n focusedPatientName,\n loadAppointmentDetails,\n availableTools,\n dockTool,\n openTool,\n onEditorModeChange,\n onAnnounce,\n t,\n ]);\n\n /* A NEW editor seed (New appointment, an empty slot, Schedule,\n Book, Process booking) docks the create form. */\n const prevSeedTickRef = useRef(editorSeed.tick);\n useEffect(() => {\n if (prevSeedTickRef.current === editorSeed.tick) return;\n prevSeedTickRef.current = editorSeed.tick;\n onEditorModeChange('create');\n dockTool(WORKSPACE_TOOL.editor);\n }, [editorSeed.tick, onEditorModeChange, dockTool]);\n\n /* A fresh find-slots seed (the waiting list's Schedule / Reschedule)\n docks the finder — seeding alone would leave it out of sight. */\n const prevFindSlotsTickRef = useRef(findSlotsSeed?.tick ?? 0);\n useEffect(() => {\n const tick = findSlotsSeed?.tick ?? 0;\n if (prevFindSlotsTickRef.current === tick) return;\n prevFindSlotsTickRef.current = tick;\n dockTool(WORKSPACE_TOOL.findSlots);\n }, [findSlotsSeed?.tick, dockTool]);\n /* The toolbar's Online bookings button docks the panel — the platform\n page still exists for the booking e-mail and the top-bar link. */\n const prevBookingsTickRef = useRef(bookingsSeedTick);\n useEffect(() => {\n if (prevBookingsTickRef.current === bookingsSeedTick) return;\n prevBookingsTickRef.current = bookingsSeedTick;\n dockTool(WORKSPACE_TOOL.bookings);\n }, [bookingsSeedTick, dockTool]);\n /* A NEW waiting-list seed (the toolbar's split button) docks the\n waiting list. */\n const prevWaitingTickRef = useRef(waitingSeedTick);\n useEffect(() => {\n if (prevWaitingTickRef.current === waitingSeedTick) return;\n prevWaitingTickRef.current = waitingSeedTick;\n dockTool(WORKSPACE_TOOL.waitingList);\n }, [waitingSeedTick, dockTool]);\n\n useEffect(() => {\n if (activeToolId !== WORKSPACE_TOOL.notes) {\n if (activeToolId) previousTool.current = activeToolId;\n return;\n }\n if (hasNotes) return;\n const target = availableTools.has(\n previousTool.current as CalendarWorkspaceToolId,\n )\n ? previousTool.current\n : WORKSPACE_TOOL.appointments;\n openTool(target);\n cancelAnimationFrame(focusFrame.current);\n focusFrame.current = requestAnimationFrame(() => {\n const root = workspaceRef.current;\n if (root?.querySelector(`[data-active-tool=\"${CSS.escape(target)}\"]`)) {\n root\n .querySelector<HTMLElement>(`[data-tool-id=\"${CSS.escape(target)}\"]`)\n ?.focus();\n }\n });\n }, [activeToolId, hasNotes, availableTools, openTool, workspaceRef]);\n\n return null;\n}\n\n/* ------------------------------------------------------------------ */\n/* The workspace — read model + rail provider + surface + docked rail */\n/* ------------------------------------------------------------------ */\n\n/** Host-owned queue membership, independent of the visible calendar range. */\nexport interface CalendarOnlineBookings {\n rows: readonly CalendarRow[];\n status: 'loading' | 'ready' | 'error';\n /** Opt in only when the host can load and persist canonical editor data. */\n canComplete?: boolean;\n /** Unknown or invalid means no booking receives a New marker. */\n lastSeenIso?: string | null;\n /** Creation timestamps when the booking has no contact payload. */\n createdAtById?: Readonly<Record<string, string>>;\n onRetry?: () => void;\n}\n\nexport interface CalendarWorkspaceProps {\n /** Optional canonical read for every existing-appointment editor route.\n * The form waits for this response; failures/refusals expose no editable\n * grid-derived prefill. Keep the callback stable and cache patient data\n * before resolving. Required for host online-booking completion. */\n loadAppointmentEditor?: CalendarAppointmentEditorLoader;\n /** The host's read for the read-only appointment details panel (P-C3).\n * With it a selection docks that panel, Edit opens the editor and a save\n * re-reads the details; without it details stays the editor form. */\n loadAppointmentDetails?: CalendarAppointmentDetailsLoader;\n /** The domain state and its handlers — the host implements them. */\n journey: CalendarJourney;\n /** The practice's read model, stable for a page load. */\n data: CalendarData;\n /** Supplied rows are authoritative, including an explicitly empty queue. */\n onlineBookings?: CalendarOnlineBookings;\n /** The host's read of the waiting list: a first `loading` shows\n * placeholders, `error` offers `onRetry`. Omitted = always ready. */\n waitingListState?: CalendarWaitingListState;\n /** When each appointment entered its current state, by event id (ISO\n * 8601). The upcoming panel shows \"waiting for 12 min\" only for rows\n * listed here; it never derives an elapsed time from the start. */\n stateSinceByEventId?: Readonly<Record<string, string>>;\n locale?: string;\n /** Host-level cog overrides. */\n initialDisplay?: Partial<WorkspaceDisplaySettings>;\n /** The platform's `practice_appointment_edit` right — false turns the\n * page read-only (no drag, no create, details without write actions). */\n permissions?: { editAppointment?: boolean };\n /** Deep link `focusAppointmentId`: open on the appointment's day, ring\n * and scroll to its card and dock its details. */\n focusAppointmentId?: string;\n /** Addresses one online booking: docks the bookings tool, then scrolls\n * to, focuses and rings its card. An id outside the queue rings nothing. */\n focusBookingId?: string;\n /** Bump to address the SAME booking again (a second notification): an\n * address is a request, not a value. */\n focusBookingKey?: string | number;\n /** Deep link `createParameters`: arrive in CREATE mode — the banner\n * stands and the next free-slot click opens the editor prefilled. */\n createParameters?: { prefill: EditorPrefill; patientName?: string };\n /** Deep link `freeSlotClicked`: jump to the slot and open the editor\n * prefilled with it. */\n freeSlot?: EditorPrefill;\n /** Platform advisories the finder raises when the scheduler is empty. */\n businessHours?: { practice?: boolean; operators?: boolean };\n /**\n * The tools this host can back with real data. Omitting one hides both\n * its rail tool and the toolbar control that opens it. Defaults to all\n * five.\n *\n * A tool a host cannot supply must not be offered: the free-slot\n * finder without the practice's business hours, holidays and closures\n * reports slots as free that are already booked or fall on days the\n * practice is shut, and staff ring patients with them. `appointments`\n * is always included — the rail docks it as its resting panel — and a\n * route into a tool left out (a deep link, a panel hand-off) lands\n * there instead of on an empty dock.\n */\n availableTools?: readonly CalendarWorkspaceToolId[];\n /**\n * The practice's FullCalendar Scheduler licence key, passed straight\n * through to the kit `Calendar`.\n *\n * Chairs and operators as columns are Scheduler premium views, so a\n * host that does not supply a key renders the \"Your license key is\n * invalid\" watermark across the resource columns. The kit ships no key\n * and invents no default: omit this and the grid behaves exactly as it\n * did before the prop existed, falling through to whatever the\n * `Calendar` component's own environment default resolves to.\n */\n schedulerLicenseKey?: string;\n /** Where the cog's settings, the view, the weekend choice and the\n * chair / operator selections are remembered — the host's per-user\n * store. Defaults to the session-scoped in-memory adapter. */\n preferences?: CalendarPreferenceAdapter;\n /** The grid's instance id — the agent registry's handle for this\n * calendar and the DOM hook anything outside React reaches it by.\n * Override it only when two workspaces share one page. */\n id?: string;\n /**\n * The window the free-slot finder is about to search, raised before it runs.\n *\n * The finder projects free time from `journey.rows` and nothing else, so a\n * host whose rows cover only the visible grid would have it report booked\n * time as FREE over a range the user chose and the host never heard about.\n * Load that range on this call: new rows re-render the panel, the search\n * runs again, and the second answer is the correct one.\n *\n * A host that offers the finder without honouring this is showing staff free\n * slots it has not checked.\n */\n onFinderSearchRange?: (range: { from: Date; to: Date }) => void;\n}\n\n/**\n * The cog's settings as the workspace opens with them: the remembered\n * entry under the workspace's own key, a caller's `initialDisplay`\n * winning for the keys it names. Exported so a host seeding its journey\n * (row colours follow `colorAssociation`) starts from the same values\n * the workspace will show.\n */\nexport function initialWorkspaceDisplay(\n initialDisplay: Partial<WorkspaceDisplaySettings> | undefined,\n preferences: CalendarPreferenceAdapter = memoryPreferenceAdapter,\n): WorkspaceDisplaySettings {\n const remembered = readWorkspaceDisplaySettings(\n preferences.get(CALENDAR_PREFERENCE_KEYS.display),\n );\n return { ...(remembered ?? DEFAULT_WORKSPACE_DISPLAY), ...initialDisplay };\n}\n\n/**\n * The workspace root: the tooltip scope, the read model, the rail scope,\n * then the page.\n *\n * `TooltipProvider` is the workspace's own, not the host's. The toolbar\n * and the panels are built from `IconButton`s carrying `tooltip`, and\n * Radix throws `Tooltip must be used within TooltipProvider` the moment\n * one renders with no provider in scope — which unmounts the whole React\n * tree, so a host that simply mounts `<CalendarWorkspace />` gets a BLANK\n * PAGE rather than a missing tooltip. A page-level pattern cannot leave\n * that to a host that has no way of knowing which Radix primitive it\n * happens to compose. Radix's provider is a plain scoped context: an\n * inner one shadows the outer value for its own subtree and registers\n * nothing globally, so a host that already has one (an app shell, the\n * Storybook decorator, this pattern's tests) is unaffected.\n * The delays are the kit defaults: shadowing means the workspace does not\n * inherit a host's tuning, which is the right trade for a page that has to\n * render at all.\n */\nexport function CalendarWorkspace({ data, ...props }: CalendarWorkspaceProps) {\n return (\n <TooltipProvider>\n <CalendarDataProvider value={data}>\n <ControlRoomProvider globalTools={NO_GLOBAL_TOOLS}>\n <CalendarWorkspaceBody data={data} {...props} />\n </ControlRoomProvider>\n </CalendarDataProvider>\n </TooltipProvider>\n );\n}\n\nfunction CalendarWorkspaceBody({\n journey,\n data,\n onlineBookings: bookingQueue,\n waitingListState,\n stateSinceByEventId,\n locale,\n initialDisplay,\n permissions,\n focusAppointmentId,\n focusBookingId,\n focusBookingKey,\n createParameters,\n freeSlot,\n businessHours,\n availableTools,\n schedulerLicenseKey,\n preferences,\n onFinderSearchRange,\n loadAppointmentEditor,\n loadAppointmentDetails,\n id,\n}: CalendarWorkspaceProps) {\n const { t, i18n } = useTranslation();\n const resolvedLocale = locale ?? i18n.language ?? 'en';\n /* Keyed on the ids themselves, not the array identity: a host that\n spells `availableTools={['appointments', …]}` inline hands us a\n fresh array every render, and the rail re-registers its tools\n whenever that set changes identity. */\n const [activeToolId, setActiveToolId] = useState<string | null>(null);\n const workspaceRef = useRef<HTMLDivElement>(null);\n const availableToolsKey = (availableTools ?? ALL_WORKSPACE_TOOLS).join('|');\n const available = useMemo(\n () => resolveAvailableTools(availableToolsKey.split('|')),\n [availableToolsKey],\n );\n const readOnly = permissions?.editAppointment === false;\n /* The cog — remembered under the workspace's own key, so this page and\n the Final State demo never trade settings; a caller's `initialDisplay`\n wins for the keys it names. */\n const [display, setDisplay] =\n usePersistedPreference<WorkspaceDisplaySettings>(\n CALENDAR_PREFERENCE_KEYS.display,\n () => ({ ...DEFAULT_WORKSPACE_DISPLAY, ...initialDisplay }),\n (raw) => {\n const remembered = readWorkspaceDisplaySettings(raw);\n return remembered ? { ...remembered, ...initialDisplay } : undefined;\n },\n preferences,\n );\n /* The host's journey: its rows are seeded from the colour association\n above; its own display entry stays untouched (never written from\n here). */\n const {\n rows: journeyRows,\n setRows,\n focus,\n setFocus,\n waitingList,\n setWaitingList,\n history,\n signRequests,\n editorSeed,\n backlogSeed,\n gotoRequest,\n findSlotsSeed,\n logHistory,\n handleRequestSignature,\n handleComposeNew,\n handleRemoveWaiting,\n handleUpsertWaiting,\n handleOpenBacklog,\n handleVisibleRangeChange,\n handleDeleteAppointment,\n handleMoveOccurrence,\n handleStatusChange,\n handleDescriptionChange,\n handleBookSlot,\n handleRevealAppointment,\n handleCreateAppointment,\n handleFindSlotsForWaiting,\n clearFindSlotsSeed,\n handleBookSlotFromFinder,\n availability,\n availabilityContext,\n handleShowAvailability,\n notesByPatient,\n notesLoadByPatient,\n handleLoadNotes,\n handleAddNote,\n handleEditNote,\n handleDeleteNote,\n handleToggleNotePin,\n requestNoteAiDraft,\n dictateNote,\n noteAiConsentFor,\n noteComposerExtrasFor,\n } = journey;\n /* A saved status repaints that occurrence on the grid at once, rather\n than waiting on the host's next read. */\n const detailsStatusChange = useMemo(\n () =>\n handleStatusChange\n ? async (eventId: string, status: CalendarEventStatus) => {\n await handleStatusChange(eventId, status);\n setRows((previous) =>\n previous.map((row) =>\n row.event.id === eventId\n ? { ...row, event: { ...row.event, status } }\n : row,\n ),\n );\n }\n : undefined,\n [handleStatusChange, setRows],\n );\n /* Patient notes are HOST state, not panel state: the details panel's\n notes sub-view renders what the journey holds and reports intent,\n so an add, edit, delete or pin is persisted by whoever owns the\n record instead of dying with the panel. A patient the host has not\n written to yet falls back to the read model. */\n const notesSeamFor = useCallback(\n (patientId: string): PatientNotesSeam => ({\n notes: notesByPatient[patientId] ?? data.patientNotes(patientId),\n onAddNote: (submission) => handleAddNote(patientId, submission),\n onEditNote: (noteId, content) =>\n handleEditNote(patientId, noteId, content),\n onDeleteNote: (noteId) => handleDeleteNote(patientId, noteId),\n onTogglePin: (noteId) => handleToggleNotePin(patientId, noteId),\n /* Absent on the journey → the affordance is never offered: the\n kit drafts no clinical prose and transcribes nothing. */\n onRequestAiDraft: requestNoteAiDraft,\n onDictate: dictateNote,\n /* Absent on the journey → the composer is ungated, matching\n today's behaviour. */\n aiConsent: noteAiConsentFor?.(patientId),\n /* Absent on the journey → no variables, no bring-your-own\n Help-me-write surface and no image upload of its own. */\n ...noteComposerExtrasFor?.(patientId),\n /* A host that reads notes on demand reports each read here. */\n ...notesLoadByPatient?.[patientId],\n onLoad: handleLoadNotes && ((scope) => handleLoadNotes(patientId, scope)),\n onRetry: handleLoadNotes && (() => handleLoadNotes(patientId, 'all')),\n }),\n [\n notesByPatient,\n notesLoadByPatient,\n handleLoadNotes,\n data,\n handleAddNote,\n handleEditNote,\n handleDeleteNote,\n handleToggleNotePin,\n requestNoteAiDraft,\n dictateNote,\n noteAiConsentFor,\n noteComposerExtrasFor,\n ],\n );\n /* Tasks are out of this page: they are dropped here, at the feed\n boundary, so the grid, the peek, the call sheet, the editor's busy\n check and the Appointments panel never see one. */\n const rows = useMemo(\n () => journeyRows.filter((r) => !r.event.isTask),\n [journeyRows],\n );\n\n const reviewOnlyEventIds = useMemo(\n () =>\n new Set(\n bookingQueue &&\n (bookingQueue.canComplete !== true ||\n bookingQueue.status !== 'ready' ||\n !loadAppointmentEditor)\n ? [\n ...bookingQueue.rows,\n ...rows.filter(\n (row) =>\n row.event.isBookedOnline &&\n (row.event.hasUnassignedPatient || !row.operatorId),\n ),\n ].map((row) => row.event.id)\n : [],\n ),\n [bookingQueue, rows, loadAppointmentEditor],\n );\n\n /* ONE polite region for the rail: a programmatic dock moves no focus,\n so the sheet host and the routing effects both speak through this. */\n const [announcement, setAnnouncementRaw] = useState('');\n /* Re-announcing the SAME string is a no-op in React, so docking the\n same tool twice would stay silent the second time. A zero-width\n space alternates the value without changing what is read out. */\n const setAnnouncement = useCallback((message: string): void => {\n setAnnouncementRaw((prev) =>\n prev === message ? `${message}\\u200B` : message,\n );\n }, []);\n /* One flag for every surface that shows a patient name: the grid, the\n peek, the print sheet AND the rail's Appointments list. */\n const [privacy, setPrivacy] = useState(false);\n const turnPrivacyOff = useCallback(() => setPrivacy(false), []);\n /* The last line spoken may name a patient and lingers in the region:\n turning privacy on empties it. The grid speaks the mode change itself. */\n useEffect(() => {\n if (privacy) setAnnouncementRaw('');\n }, [privacy]);\n /* The one editor tool's mode — the sheet host and the routing effects\n both write it, so it lives above both. */\n const [editorMode, setEditorMode] = useState<EditorMode>('create');\n const handleOpenSheet = useCallback(\n (id: SheetId): string | null => {\n /* No care-plan panel in this rail — the platform has no in-calendar\n care-plan side surface either — so the linked-plan line is static\n text and nothing routes here. A stray request docks NOTHING\n rather than falling through to the finder. */\n if (id === 'patient-care-plan') return null;\n /* A sheet whose tool this host cannot back falls back to the\n resting panel — the rail never docks nothing. */\n if (id === 'appointment-details') {\n if (!available.has(WORKSPACE_TOOL.editor))\n return WORKSPACE_TOOL.appointments;\n setEditorMode('details');\n return WORKSPACE_TOOL.editor;\n }\n if (id === 'appointment-editor') {\n if (!available.has(WORKSPACE_TOOL.editor))\n return WORKSPACE_TOOL.appointments;\n setEditorMode('create');\n return WORKSPACE_TOOL.editor;\n }\n if (id === 'backlog')\n return available.has(WORKSPACE_TOOL.waitingList)\n ? WORKSPACE_TOOL.waitingList\n : WORKSPACE_TOOL.appointments;\n if (!available.has(WORKSPACE_TOOL.findSlots))\n return WORKSPACE_TOOL.appointments;\n /* A plain Find-free-slots (the toolbar) must NOT inherit a seed\n left by a waiting-list reschedule — booking a slot would move\n that other patient's appointment. Clear it on the way in. */\n clearFindSlotsSeed();\n return WORKSPACE_TOOL.findSlots;\n },\n [clearFindSlotsSeed, available],\n );\n\n const selectedRow = focus\n ? (rows.find((r) => r.event.id === focus.eventId) ?? null)\n : null;\n /* The ONE resolution of the selected appointment's patient — the id it\n carries plus whatever the host's lookup made of it. Memoised: it is\n a dependency of the rail's tool memos, and a fresh object per render\n would rebuild every panel on every keystroke. */\n const patientRef = useMemo(\n () => patientRefById(selectedRow?.event.patientId, data),\n [selectedRow, data],\n );\n /* Decision 5: the badge counts waiting ENTRIES. Online bookings are\n counted separately, on their own toolbar button. */\n const waitingBadge = waitingList.length;\n const onlineBookings = useMemo(\n () => bookingQueue?.rows ?? onlineBookingsToCheck(rows, data),\n [bookingQueue, rows, data],\n );\n\n /* ---- platform parity (decision 14) ------------------------------ */\n\n /* Save: the journey writes the appointment; the extras apply a series\n scope, fake the sign request and raise the post-save toast. */\n const [saveNotice, setSaveNotice] = useState<SaveNotice | null>(null);\n const handleSave = useCallback(\n async (draft: EditorDraft, extras?: EditorDraftExtras): Promise<void> => {\n if (draft.editEventId && reviewOnlyEventIds.has(draft.editEventId))\n throw new Error(t('calendarWorkspace.inc1.readOnly.changeBlocked'));\n /* Backstop to the panel's own `readOnly`: the journey's writer is\n never called, and — the part that matters — no save notice is\n raised, so the grid cannot toast \"Saved for {date}\" over a row\n that was never written. */\n if (readOnly) {\n throw new Error(t('calendarWorkspace.inc1.readOnly.changeBlocked'));\n }\n const prevRow = draft.editEventId\n ? rows.find((r) => r.event.id === draft.editEventId)\n : undefined;\n /* The kit expands a scope only across a row that carries `series`\n (the demo journey). Any other row hands the extras to the host\n untouched, and no other row changes. */\n const expandsSeries = Boolean(prevRow?.series);\n await (expandsSeries\n ? handleCreateAppointment(draft)\n : handleCreateAppointment(draft, extras));\n // The write has been accepted. A local follow-up failure must not\n // reject this promise and invite the user to submit it again.\n try {\n const scope = extras?.recurringSaveMode ?? 'this';\n if (prevRow && expandsSeries && scope !== 'this') {\n const siblings = seriesScopeEventIds(\n rows,\n prevRow.event.id,\n scope,\n ).filter((id) => id !== prevRow.event.id);\n if (siblings.length > 0) {\n setRows((prev) =>\n applySeriesEdit(prev, prevRow, draft, siblings, data),\n );\n const edited = historyEntriesFromEdit(prevRow, draft, data).find(\n (entry) => entry.kind === 'edited',\n );\n for (const id of siblings) {\n logHistory(id, {\n kind: 'edited',\n fields: edited?.kind === 'edited' ? edited.fields : ['time'],\n });\n }\n toastInfo(\n t('calendarWorkspace.inc1.save.seriesEdited', {\n count: siblings.length,\n }),\n );\n }\n }\n const signMode = extras?.requiredDocsSignMode;\n if (signMode && signMode !== 'none' && draft.patientId) {\n toastInfo(\n t('calendarWorkspace.inc1.save.signRequested', {\n count: data.unsignedRequiredDocs[draft.patientId] ?? 0,\n channel: t(\n signMode === 'sms'\n ? 'calendarWorkspace.details.remindSms'\n : 'calendarWorkspace.details.remindEmail',\n ),\n }),\n );\n }\n } catch {\n toastWarning(t('emptyState.error.title'));\n }\n const date = new Date(draft.date);\n if (!draft.allDay) date.setHours(draft.time.hours, draft.time.minutes);\n setSaveNotice((prev) => ({\n tick: (prev?.tick ?? 0) + 1,\n date,\n chairId: draft.chairId,\n operatorId: draft.operatorId,\n }));\n },\n [\n rows,\n handleCreateAppointment,\n setRows,\n logHistory,\n data,\n t,\n readOnly,\n reviewOnlyEventIds,\n ],\n );\n /* Delete with the recurring scope; the care-plan cleanup only toasts. */\n const handleDelete = useCallback(\n (eventId: string, options?: DeleteOptions): void => {\n if (reviewOnlyEventIds.has(eventId)) return;\n /* Same backstop as the save: the panel withholds Delete without the\n edit right, and this refuses it if it is ever reached anyway —\n a destructive write must not be announced without being made. */\n if (readOnly) {\n toastWarning(t('calendarWorkspace.inc1.readOnly.changeBlocked'));\n return;\n }\n /* Same rule as the save: only a demo series row expands here. */\n if (rows.find((row) => row.event.id === eventId)?.series) {\n const ids = seriesScopeEventIds(\n rows,\n eventId,\n options?.scope ?? 'this',\n );\n for (const id of ids) handleDeleteAppointment(id);\n if (ids.length > 1) {\n toastInfo(\n t('calendarWorkspace.inc1.save.seriesDeleted', {\n count: ids.length,\n }),\n );\n }\n } else {\n handleDeleteAppointment(eventId, options);\n }\n if (options?.removeFromCarePlan) {\n toastInfo(t('calendarWorkspace.inc1.save.carePlanRemoved'));\n }\n },\n [rows, handleDeleteAppointment, t, readOnly, reviewOnlyEventIds],\n );\n /* Move… / Copy…: the grid waits for the slot while the details panel\n stays docked — a docked panel covers nothing, so there is nothing to\n get out of the way. */\n const [placement, setPlacement] = useState<PlacementRequest | null>(null);\n const placementRef = useRef<PlacementRequest | null>(null);\n placementRef.current = placement;\n const armPlacement = useCallback(\n (kind: 'move' | 'copy', withTreatments?: boolean) => {\n if (!selectedRow || reviewOnlyEventIds.has(selectedRow.event.id)) return;\n setPlacement({ kind, eventId: selectedRow.event.id, withTreatments });\n },\n [selectedRow, reviewOnlyEventIds],\n );\n const handleMove = useCallback(() => armPlacement('move'), [armPlacement]);\n const handleCopy = useCallback(\n (withTreatments?: boolean) => armPlacement('copy', withTreatments),\n [armPlacement],\n );\n /* A LANDED move that came from a waiting-list Reschedule settles its\n entry, exactly as the platform's move does; a cancel leaves it. */\n const endPlacement = useCallback(\n (landed?: boolean) => {\n const current = placementRef.current;\n if (landed && current?.waitingEntryId) {\n const settled = current.waitingEntryId;\n setWaitingList((prev) => prev.filter((e) => e.id !== settled));\n }\n setPlacement(null);\n },\n [setWaitingList],\n );\n /* CREATE mode: a deep link or the Backlog's Schedule arms the banner;\n the next free-slot click opens the editor with that context. */\n const [createMode, setCreateMode] = useState<CreateModeRequest | null>(null);\n const endCreateMode = useCallback(() => setCreateMode(null), []);\n /* Deep link `focusAppointmentId` — the surface scrolls and rings. */\n const [focusScroll, setFocusScroll] = useState<{\n tick: number;\n eventId: string;\n } | null>(null);\n /* Platform \"Completa appuntamento\": the editor opens with both the\n patient and the operator marked required. */\n /* The assign segment pressed rides the prefill as `initialFocus`, so the\n editor lands on that field and a host journey sees the intent too. */\n const handleCompleteBooking = useCallback(\n (row: CalendarRow, intent?: BookingCompleteIntent): void => {\n handleBookSlot({\n ...processBookingPrefill(row, data),\n initialFocus: intent,\n });\n },\n [handleBookSlot, data],\n );\n /* The toolbar button docks the rail panel — the platform's page is\n still there for the booking e-mail and the top-bar notification. */\n const [bookingsSeed, setBookingsSeed] = useState(0);\n const handleOpenOnlineBookings = useCallback((): void => {\n setBookingsSeed((tick) => tick + 1);\n }, []);\n /* `focusBookingId`: every new id or key is one request. It docks the\n tool like the toolbar button; the rail delivers the address. */\n const [bookingRequest, setBookingRequest] = useState<{\n tick: number;\n id?: string;\n }>({ tick: 0 });\n useEffect(() => {\n if (!focusBookingId) return;\n setBookingRequest((prev) => ({ tick: prev.tick + 1, id: focusBookingId }));\n setBookingsSeed((tick) => tick + 1);\n }, [focusBookingId, focusBookingKey]);\n\n /* ---- the waiting list (decision 5 + its create / move hand-offs) - */\n\n /* The entry form is a rail SUB-VIEW — a small focused form that swaps\n the waiting-list panel's body, so the list it was opened from is\n still there when it closes. */\n const [entryForm, setEntryForm] = useState<{\n entry?: CalendarWaitingEntry;\n } | null>(null);\n /* Which control opened the sub-view, so leaving it can put focus back\n there. Without this, Back and Save drop focus to <body>. */\n const entryOpenerRef = useRef<string | null>(null);\n /* Opening the form docks the waiting-list tool as well as swapping its\n body — the toolbar's plus segment can fire while another tool is up. */\n const openEntryForm = useCallback(\n (entry?: CalendarWaitingEntry): void => {\n entryOpenerRef.current = entry ? entry.id : 'add';\n setEntryForm({ entry });\n handleOpenBacklog('waiting');\n },\n [handleOpenBacklog],\n );\n const closeEntryForm = useCallback((): void => setEntryForm(null), []);\n /* The rail renders its panel outside the page tree, so the restore\n queries the document rather than a local ref. */\n const prevEntryFormRef = useRef(entryForm);\n useEffect(() => {\n const had = prevEntryFormRef.current !== null;\n prevEntryFormRef.current = entryForm;\n if (!had || entryForm !== null) return;\n const opener = entryOpenerRef.current;\n entryOpenerRef.current = null;\n const panel = document.querySelector<HTMLElement>(\n `[data-active-tool=\"${WORKSPACE_TOOL.waitingList}\"]`,\n );\n /* The subview already handed focus back to its opener (an assign\n button, the menu trigger): leave it there. */\n const active = document.activeElement;\n if (active && active !== document.body && panel?.contains(active)) return;\n const target =\n opener && opener !== 'add'\n ? panel?.querySelector<HTMLElement>(`[data-entry-edit=\"${opener}\"]`)\n : panel?.querySelector<HTMLElement>('[data-entry-add]');\n (\n target ?? panel?.querySelector<HTMLElement>('h2, [tabindex=\"-1\"]')\n )?.focus();\n }, [entryForm]);\n const handleSaveEntry = useCallback(\n (draft: WaitingEntryDraft): void => {\n /* Backstop to the form's own withheld Save. Refusing BEFORE\n `setEntryForm(null)` matters: closing the sub-view is itself an\n acceptance signal over a row the host never wrote. */\n if (readOnly) {\n toastWarning(t('calendarWorkspace.inc1.readOnly.waitingBlocked'));\n return;\n }\n handleUpsertWaiting(draft);\n setEntryForm(null);\n },\n [handleUpsertWaiting, readOnly, t],\n );\n /* Platform parity: Remove deletes without a confirmation — the Undo\n toast is the safety net (the entry returns where it was). */\n const handleRemoveWaitingEntry = useCallback(\n (entry: CalendarWaitingEntry): void => {\n /* Backstop to the withheld Remove. `handleRemoveWaiting` is a host\n seam that never reports acceptance, so without this the toast\n below claimed a patient had left the queue — and offered an Undo\n for a removal that never happened. */\n if (readOnly) {\n toastWarning(t('calendarWorkspace.inc1.readOnly.waitingBlocked'));\n return;\n }\n const index = waitingList.findIndex((e) => e.id === entry.id);\n handleRemoveWaiting(entry);\n toastInfo(t('calendarWorkspace.inc1.waitingList.removed'), {\n action: {\n label: t('calendarWorkspace.inc1.waitingList.undo'),\n onClick: () => {\n setWaitingList((prev) => {\n if (prev.some((e) => e.id === entry.id)) return prev;\n const next = [...prev];\n next.splice(index < 0 ? next.length : index, 0, entry);\n return next;\n });\n toastInfo(t('calendarWorkspace.inc1.waitingList.removeUndone'));\n },\n },\n });\n },\n [waitingList, handleRemoveWaiting, setWaitingList, readOnly, t],\n );\n /* Schedule → CREATE mode; Reschedule → MOVE mode for the linked\n appointment. Either way the grid takes over from the banner. */\n const handlePlaceWaiting = useCallback(\n (entry: CalendarWaitingEntry): void => {\n /* Schedule AND Reschedule both open the finder, seeded from the\n entry (and its linked appointment): a slot search with the right\n operator and chair already filled in beats \"click somewhere\". */\n handleFindSlotsForWaiting(entry);\n },\n [handleFindSlotsForWaiting],\n );\n\n /* ---- deep links (parity spec §A, decision 15) -------------------- */\n\n const deepLinkRef = useRef(false);\n useEffect(() => {\n if (deepLinkRef.current) return;\n deepLinkRef.current = true;\n if (focusAppointmentId) {\n handleRevealAppointment(focusAppointmentId);\n setFocusScroll({ tick: 1, eventId: focusAppointmentId });\n return;\n }\n if (createParameters) {\n /* The platform's `simpleSave=false` splits Save into \"Save and go\n back\" and \"Save and continue\". The origin it goes back to (a care\n plan, a patient folder) is a page this workspace cannot route to,\n so the arrival is forced to the SIMPLE save and the single-Save\n footer — coherent on its own — is what the editor shows. */\n setCreateMode({\n tick: 1,\n ...createParameters,\n prefill: { ...createParameters.prefill, simpleSave: true },\n });\n return;\n }\n if (freeSlot) handleBookSlot(freeSlot);\n }, [\n focusAppointmentId,\n createParameters,\n freeSlot,\n handleRevealAppointment,\n handleBookSlot,\n ]);\n\n return (\n /* One row, the host's block-size: the surface scrolls on its own\n (row 2 of the toolbar and the grid's date header stick to that\n scroller), the rail keeps its full height beside it — the same\n shape `AppFrame` gives a main region and its `endSidebar`. */\n <div\n data-component=\"calendar-workspace\"\n ref={workspaceRef}\n className=\"ds:flex ds:h-full ds:min-h-0 ds:w-full ds:items-stretch\"\n >\n <VisuallyHidden aria-live=\"polite\">{announcement}</VisuallyHidden>\n <CalendarRailTools\n workspaceRef={workspaceRef}\n activeToolId={activeToolId}\n availableTools={available}\n focus={focus}\n rows={rows}\n locale={resolvedLocale}\n privacy={privacy}\n onPrivacyOff={turnPrivacyOff}\n selectedRow={selectedRow}\n patientRef={patientRef}\n onOpenSheet={handleOpenSheet}\n onAnnounce={setAnnouncement}\n editorMode={editorMode}\n onEditorModeChange={setEditorMode}\n editorSeed={editorSeed}\n loadAppointmentEditor={loadAppointmentEditor}\n loadAppointmentDetails={loadAppointmentDetails}\n waitingList={waitingList}\n waitingSeedTick={backlogSeed.tick}\n findSlotsSeed={findSlotsSeed}\n history={history}\n signRequests={signRequests}\n colorAssociation={display.colorAssociation}\n mapsLink={display.mapsLink}\n readOnly={readOnly}\n notesSeamFor={notesSeamFor}\n businessHours={businessHours}\n onSave={handleSave}\n onDelete={handleDelete}\n onMove={handleMove}\n onCopy={handleCopy}\n onStatusChange={detailsStatusChange}\n onDescriptionChange={handleDescriptionChange}\n onRevealAppointment={handleRevealAppointment}\n onRequestSignature={handleRequestSignature}\n onRemoveWaiting={handleRemoveWaitingEntry}\n onOpenEntryForm={openEntryForm}\n entryForm={entryForm}\n onSaveEntry={handleSaveEntry}\n onCancelEntry={closeEntryForm}\n onBookSlotFromFinder={handleBookSlotFromFinder}\n onShowAvailability={handleShowAvailability}\n onFinderSearchRange={onFinderSearchRange}\n gridAxis={display.resourceKind}\n bookings={onlineBookings}\n bookingQueue={bookingQueue}\n waitingListState={waitingListState}\n stateSinceByEventId={stateSinceByEventId}\n reviewOnlyEventIds={reviewOnlyEventIds}\n bookingsSeedTick={bookingsSeed}\n bookingRequest={bookingRequest}\n onCompleteBooking={handleCompleteBooking}\n onPlaceWaiting={handlePlaceWaiting}\n />\n <ScrollArea orientation=\"vertical\" className=\"ds:min-w-0 ds:flex-1\">\n <CalendarSheetHost\n onOpenSheet={handleOpenSheet}\n onAnnounce={setAnnouncement}\n >\n <CalendarSurface\n id={id}\n availableTools={available}\n schedulerLicenseKey={schedulerLicenseKey}\n preferences={preferences}\n rows={rows}\n setRows={setRows}\n display={display}\n setDisplay={setDisplay}\n onFocus={setFocus}\n detailsOnEveryClick={loadAppointmentDetails !== undefined}\n locale={resolvedLocale}\n readOnly={readOnly}\n placement={placement}\n onPlacementEnd={endPlacement}\n createMode={createMode}\n onCreateModeEnd={endCreateMode}\n focusScroll={focusScroll}\n saveNotice={saveNotice}\n privacy={privacy}\n onPrivacyChange={setPrivacy}\n availability={availability}\n availabilityContext={availabilityContext}\n onComposeNew={\n readOnly\n ? () =>\n toastWarning(\n t('calendarWorkspace.inc1.readOnly.createBlocked'),\n )\n : handleComposeNew\n }\n /* Main split-button segment always means the queue. Without\n closing a previously opened entry form it merely re-docked the\n tool around that stale form, making \"Waiting list\" look like a\n second Add button. */\n onOpenWaitingList={() => {\n closeEntryForm();\n handleOpenBacklog('waiting');\n }}\n /* Same shape as `onComposeNew` above: a read-only viewer is\n told why instead of being handed a form whose Save is\n withheld the moment it opens. */\n onAddWaitingEntry={\n readOnly\n ? () =>\n toastWarning(\n t('calendarWorkspace.inc1.readOnly.waitingBlocked'),\n )\n : () => openEntryForm()\n }\n waitingBadgeCount={waitingBadge}\n onOpenOnlineBookings={handleOpenOnlineBookings}\n onlineBookingsCount={onlineBookings.length}\n onVisibleRangeChange={handleVisibleRangeChange}\n selectedEventId={focus?.eventId ?? null}\n gotoRequest={gotoRequest}\n onBookSlot={handleBookSlot}\n onBookSlotFromFinder={handleBookSlotFromFinder}\n reviewOnlyEventIds={reviewOnlyEventIds}\n onHistory={logHistory}\n onMoveOccurrence={handleMoveOccurrence}\n />\n </CalendarSheetHost>\n </ScrollArea>\n {/* Docked inline-end, full height, hidden below md — the shape of\n `AppFrame`'s `endSidebar` slot. The rail reads the available tools\n from the provider above; nothing pins ahead of them. */}\n <div className=\"ds:hidden ds:h-full ds:shrink-0 ds:md:flex ds:print:hidden\">\n <ControlRoomRail\n activeToolId={activeToolId}\n onActiveToolChange={setActiveToolId}\n side=\"end\"\n resizablePanel\n /* Wider than the 22rem tray default: the panels here are working\n surfaces, not trays. At 34rem a form panel pairs its fields two\n to a row instead of running to two screens, and the resize\n handle reaches 55rem for a three-column layout. */\n className=\"ds:[--tool-rail-panel-inline-size:34rem] ds:print:hidden\"\n />\n </div>\n </div>\n );\n}\n"],"names":["__iconNode","Cake","createLucideIcon","CalendarSearch","ClipboardPaste","Funnel","History","IdCard","ListPlus","Move","Save","SlidersHorizontal","StickyNote","CalendarDataContext","createContext","CalendarDataProvider","value","children","createElement","useCalendarData","data","useContext","OPERATOR_GROUP_NONE_ID","buildOperatorFilterGroups","args","byId","inactive","rank","sortMembers","members","a","b","activeDelta","grouped","sections","group","id","o","ungrouped","careSuffix","input","mode","phases","e","describe","careBlock","parts","_a","p","careLabel","cares","associationColor","association","ctx","sources","_b","c","first","_c","_d","patientPhones","patient","patientIdOf","patientRefOf","record","key","found","patientRefName","ref","rowTitle","notLoadedLabel","candidate","patientChannelState","channel","channelReady","state","channelOfferable","channelReasonKey","keys","catalogueStateOf","items","catalogueUsable","store","memoryPreferenceAdapter","resetCalendarPreferences","CALENDAR_PREFERENCE_KEYS","usePersistedPreference","defaultValue","read","adapter","setValue","useState","remembered","set","useCallback","action","prev","next","readEnum","allowed","raw","readBoolean","readIdList","known","knownIds","item","ids","STATUS_UI_KEY","movesSilently","event","patientRefById","eventPatientRef","VIEW_OPTIONS","DEFAULT_DISPLAY","DISPLAY_READERS","readDisplayField","target","field","readDisplaySettings","source","readChairIds","readOperatorIds","selectionState","selected","count","DAY_WINDOWS","formatTimeRange","locale","start","end","fmt","formatDay","parseEventDate","patientAgeYears","dobIso","dob","on","age","monthDelta","RECURRENCE_MAX_COUNT","RECURRENCE_FREQUENCIES","RECURRENCE_LABEL_KEY","addMonthsClamped","base","months","d","day","lastDay","editPrefillFromRow","row","DRAFT_SNAP","NONE","DURATION_PRESETS_MIN","durationDigitsFilter","search","digits","initialEditorColor","prefill","GOOGLE_CALENDAR_PALETTE","scheduleByEntryId","rows","out","startIso","entryId","list","deriveCareLinkDefaults","link","lines","plan","entry","care","sum","l","DETAIL_STAMP_FORMAT","sortHistoryNewestFirst","entries","parsed","signingSummary","docs","toSign","status","signatureStatusOf","historyEntriesFromEdit","draft","fields","prevStart","nextStart","prevMin","prevPatient","nextCares","EMPTY_SCHEDULE","priceListState","priceListIdFor","patientId","lists","name","STATUS_CHIP","ThumbsUp","Clock","Stethoscope","Check","Ban","UserX","eventStartMs","iso","waitingEntryAppointment","WAITING_QUICK_VIEWS","WAITING_QUICK_VIEW_LABEL_KEY","WAITING_QUICK_VIEW_DAYS","waitingEntryInQuickView","view","cutoffMs","nowMs","appointment","processBookingPrefill","contact","matched","carried","callToActionSatisfied","callToAction","waitingEntryIsValid","ANY","FREE_SLOT_CAP","SLOT_STEP_MIN","FREE_SLOT_MAX_RANGE_DAYS","FREE_SLOT_DEFAULT_HORIZON_DAYS","rangeDays","from","to","localIsoDate","pad","n","dayComplement","hours","segments","intersectDayHours","startMin","endMin","buildUnavailabilityEvents","events","pushSegments","resourceId","dateIso","closed","seg","i","cursor","last","practiceHours","chairId","operatorId","CLOSURE_HOLIDAY_ACCENT","isClosureEvent","buildClosureBanners","graphite","push","kind","title","tint","columns","holiday","h","column","maskedTitle","privacy","mask","printRowOf","phones","byStart","buildPrintSheet","days","axisKind","visibleChairIds","visibleOperatorIds","visible","r","chairs","operators","onDay","appointments","groups","unallocated","tasks","notes","closure","absence","PRINT_LINE_PX","PRINT_ROW_PAD_PX","PRINT_WRAP_CHARS","PRINT_CELL_CLASS","printRowHeight","minLines","patientLines","careLines","closureReason","t","date","mergeAvailabilityRanges","slots","slot","groupKey","ranges","sorted","current","startMs","endMs","buildFreeBands","valid","midnight","segmentEnd","range","options","searchFreeSlots","duration","notBefore","busy","dayHours","dayOperators","chair","operator","operatorWeek","minute","w","WORKSPACE_TOOL","ALL_WORKSPACE_TOOLS","resolveAvailableTools","requested","available","WORKSPACE_VIEWS","WORKSPACE_VIEW_STEM","VIEW_SHORTCUT_KEYS","readWorkspaceViewId","viewForShortcutKey","upper","SHORTCUT_BLOCKED_SELECTOR","shortcutAllowedOn","shortcutViewForKeydown","weekendHiddenDays","showWeekends","DEFAULT_DURATION_RANGE","DEFAULT_WORKSPACE_DISPLAY","readOperatorNameDisplay","readChairNameDisplay","readDurationMin","rounded","readWorkspaceDisplaySettings","operatorName","chairName","mapsLink","minutesToClock","min","practiceDayWindow","workspaceDayWindow","window","effectiveIds","all","toggleSelectedIds","checked","activeFilterCount","selectedChairIds","selectedOperatorIds","bookedDisabledOperatorIds","inactiveIds","booked","columnableOperatorIds","keep","listedOperators","showDisabled","chairResourceTitle","operatorResourceTitle","isDisabled","disabledLabel","minutesBetween","rowsWithEnd","eventId","RECURRING_SCOPES","RECURRING_SCOPE_LABEL_KEY","seriesScopeEventIds","scope","series","slotConflicts","chairBusy","operatorBusy","rowStart","rowEnd","devicesForCares","devicesByCare","device","signChannelStates","defaultSignMode","channels","patientAddressLine","part","patientAddressLabel","patientMapsUrl","query","BANNER_INKS","APPOINTMENT_PALETTE","swatch","ink","bannerTextColor","backgroundHex","bg","hexToHsl","best","bestRatio","ratio","contrastRatio","copyRowAt","withTreatments","sourceStart","sourceEnd","durationMs","pad2","startValue","endValue","rehomed","applySeriesEdit","primaryPrev","siblingIds","deltaMs","linkedCares","hiddenReasons","notice","UPCOMING_FORWARD_DAYS","UPCOMING_STEP_DAYS","UPCOMING_MAX_DAYS","DEFAULT_UPCOMING_WINDOW","dayDelta","fromIso","toIso","upcomingWindowBounds","nowIso","widenUpcomingWindow","edge","grow","upcomingWindowCovering","targetIso","delta","reach","wanted","upcomingAppointmentRows","bounds","upcomingAppointmentItem","unresolvedPatientLabel","pendingDetailsLabel","patientName","ONLINE_BOOKINGS_WINDOW_DAYS","onlineBookingsToCheck","cutoff","bookedAt","bookingRowView","lastSeenMs","createdAtIso","bookedAtIso","EMPTY_WAITING_FILTERS","waitingFiltersActiveCount","filters","waitingListRowView","patientRef","appointmentPatientRef","operatorTitle","patientAssigned","withinDayBounds","ms","startOfDayMs","endOfDayMs","copy","waitingEntryMatchesFilters","assigned","scheduled","needle","filterWaitingEntries","quickView","WAITING_ENTRY_KINDS","waitingEntryKind","groupWaitingRows","views","waitingQuickViewCounts","waitingWhatsAppNumber","dayKey","m","useTickingNow","anchor","useRef","setTick","useEffect","stop","onVisibility","elapsedMs","relativeMinutes","fromMs","toMs","diffMin","elapsedDuration","total","unit","minutes","UpcomingAppointmentsPanel","onOpenAppointment","stateSinceByEventId","loading","useTranslation","setRange","todayKey","allItems","useMemo","todaysItems","live","liveIds","nextItem","listItems","summary","jsxs","jsx","Badge","liveBand","sinceIso","workflow","appointmentStateWorkflow","StateIcon","stateLabel","elapsed","Avatar","WorkflowStatusDisplay","loadingSkeleton","index","Skeleton","AppointmentTimeline","Fragment","seriesIsValid","EDITOR_SKELETON_LABELS","CalendarEditorHydration","load","onCancel","failureMessage","result","setResult","retry","setRetry","controller","error","Alert","width","Button","previous","rowWithCanonicalEditor","snapshot","CalendarPatientPicker","props","selectedLabel","PatientSearchPicker","Combobox","onValueChange","size","disabled","searchPatients","setQuery","picked","setPicked","setState","inputRef","trimmedQuery","timer","patients","message","open","MAX_FRAMES","isSettled","node","layer","whenRailSettled","getNode","run","frame","frames","calm","tick","CONTROLS","firstEnabledControl","useEditorInitialFocus","wrapper","control","CalendarSeriesScopeChooser","titleId","useId","warningId","scopes","warns","RadioGroup","option","Radio","SheetHostReactContext","SheetHostProvider","useSheetHost","host","bookingKey","suffix","NORMAL_STATUS","bookingWhatsAppDigits","phone","shortDay","ACCESSIBLE_TARGET","stripMemberVariants","cva","bookingCardVariants","bookingRingVariants","titleVariants","avatarPlaceholderVariants","TITLE_ACTIVATOR_CLASS","META_CLASS","BookingCard","forwardRef","canComplete","onComplete","onShowInCalendar","addressed","addressKey","lng","whatsAppDigits","when","named","complete","intent","bothMissing","statusWorkflow","StatusIcon","TypeIcon","Video","MapPin","whatsAppLabel","whatsAppReason","avatar","EyeOff","Timestamp","TransactionChip","Armchair","treatment","Tag","ButtonGroup","Plus","IconButton","Eye","Pencil","WhatsAppGlyph","BookingCardsSkeleton","activeOperators","whatsAppUnavailableKey","noop","PatientNotesPanel","PatientNotesPanelContent","seam","editable","currentNoteId","currentNoteKey","runtimeI18n","note","writable","deleting","setDeleting","writeError","setWriteError","pending","setPending","writeOwner","abandonWrite","panelRootRef","deletedRef","seamRef","requestedPatient","hasLoader","noteStamp","settle","close","owner","getErrorMessage","confirmDelete","noteId","focusAfterDelete","root","writeAlert","NotesPanel","submission","Trash2","Dialog","AppointmentHistoryTimeline","history","detailKey","formatStamp","workflowOption","Icon","tone","describeHistory","CalendarPlus","StatusGlyph","fromOption","toOption","transitionLabel","ArrowRight","f","ConfirmedGlyph","EmptyState","Timeline","shape","CalendarClock","DurationCombobox","onChange","REMINDER_CHANNELS","EDITOR_TIER_CONTAINER","EDITOR_FORM_GRID","EDITOR_FIELD_WIDE","EDITOR_FIELD_SHORT_STACKED","EDITOR_FIELD_SHORT","AppointmentEditorPanel","onSave","onDelete","onDuplicate","panelTitle","headerIcon","identity","after","closeOnSave","returnsOnCancel","onDraftChange","onPatientContextChange","slotPatch","colorAssociation","scheduleByEntry","onMove","onCopy","onWhatsApp","readOnly","hostCapabilities","platform","className","tUi","closeSheet","openSheet","isEdit","seriesScopes","seriesScope","setSeriesScope","changingScope","setChangingScope","choosingScope","capabilities","canEditCare","operatorOptions","saving","setSaving","accepted","setAccepted","saveError","setSaveError","savingRef","acceptedRef","mountedRef","setPatientId","type","setType","setDate","time","setTime","durationMin","setDurationMin","setOperatorId","setChairId","colorHex","setColorHex","setCare","emailReminder","setEmailReminder","smsReminder","setSmsReminder","firstVisit","setFirstVisit","linkPrefill","careLink","setCareLink","carePlanId","setCarePlanId","entryIds","setEntryIds","phaseSelection","setPhaseSelection","priceListId","setPriceListId","priceRowKeyRef","priceRows","setPriceRows","activeLocale","openPlans","lastPatientRef","nextId","priceLists","priceListCatalogue","priceListOffered","priceListRelationShown","linkCareShown","planChoices","planEntries","entryState","toggleEntry","togglePhase","phase","ordered","patchPriceRow","patch","addPriceRow","removePriceRow","togglePriceRowPhase","catalogue","togglePriceRowAllPhases","currentLink","phasesByEntry","linkKey","appliedLinkRef","defaults","allDay","setAllDay","appliedPatchRef","resourceColor","repeats","setRepeats","recurrence","setRecurrence","recurrenceEnds","setRecurrenceEnds","recurrenceCount","setRecurrenceCount","recurrenceUntil","setRecurrenceUntil","skipClosedDays","setSkipClosedDays","skipHintId","recurrenceExtras","addToWaitingList","setAddToWaitingList","setStatus","serializeDraft","initialDraftRef","dirty","rawClosure","operatorAbsent","slotChosen","ctaSatisfied","descriptionMax","descriptionTooLong","twoStepSave","canSave","canCancel","formRef","editedEventTitle","formPatientLabel","confirmDeleteOpen","setConfirmDeleteOpen","deleteScope","setDeleteScope","removeFromCarePlan","setRemoveFromCarePlan","recurringSaveMode","setRecurringSaveMode","signMode","setSignMode","signPatientRef","branches","branchId","setBranchId","unsignedDocs","signChannels","smsOffered","emailOffered","smsReasonKey","emailReasonKey","gateOnPatient","showReminders","showFirstVisit","requiredDevices","slotStart","scopeApplies","cleanupApplies","deleteScopes","deleteChoice","seriesStartChanged","discardsOverrides","patientFieldRef","operatorFieldRef","chooserRef","scopeChangeRef","choosingRef","saveExtras","subView","setSubView","historyBtnRef","historyHeaderRef","prevSubViewRef","panelLocale","handleSave","toastWarning","submitButtonRef","handleFormSubmit","handleDeleteConfirmed","handleDuplicate","PanelHeader","HistoryIcon","ArrowLeft","Lock","FormField","Select","s","v","Globe","entryCare","Checkbox","el","rowCare","rowPhases","locked","removeKey","allPhases","NumberInput","TextInput","KeyValuePair","DatePicker","TimePicker","ColorPicker","_e","SendReminderGroup","DropdownMenu","IconButtonGroup","Copy","ClipboardList","X","IndicatorChips","chips","TriangleAlert","HeartPulse","Euro","Repeat","chip","AppointmentIdentity","showAge","onOpenPatient","anamnesisAnswers","highlighted","expired","answers","displayName","answer","sentVia","setSentVia","MessageSquare","Mail","VisuallyHidden","AppointmentExtras","signRequestedVia","onRequestSignature","onRequestSignatureOnDevice","meta","signing","signReadout","setSignReadout","requestSignature","requestedLine","linkedPlan","linkedEntries","priceListName","money","line","label","mapQuery","mapLabel","showMapRow","hasPatientFacts","itemCare","PenLine","doc","SignatureStatusChip","Send","Smartphone","BookingsPanel","bookings","lastSeenIso","createdAtById","currentBookingId","currentBookingKey","onRetry","currentCardRef","useWaitingEntryForm","description","setDescription","showError","setShowError","reset","WaitingEntryFields","form","TextArea","WaitingListEntrySubview","PanelSubview","Hourglass","PrintPatientCell","PrintCaresCell","PrintAllocationCell","practice","PrintSheet","rangeTitle","columnDefs","cols","gridOptions","chairNames","operatorNames","noteLabel","createPortal","section","hasRows","g","DataTable","task","FREE_SLOT_CARD_CLASS","FREE_SLOT_BUTTON_CLASS","ScopeChecklist","countLabel","hint","icon","selectAll","allIds","optionRow","Popover","memberIds","SERVER_SEARCH_DEBOUNCE_MS","busySignature","sameFreeSlots","FindFreeSlotsPanel","seed","onBookSlot","onSearchRange","canBook","seedContext","listOnly","serverSearch","careId","setCareId","deviceName","setDeviceName","multiScope","scopeOperatorIds","setScopeOperatorIds","scopeChairIds","setScopeChairIds","fromDate","setFromDate","today","toDate","setToDate","horizon","results","setResults","searching","setSearching","failed","setFailed","capped","setCapped","allFound","setAllFound","showOnGrid","setShowOnGrid","filtersOpen","setFiltersOpen","clearProjectionRef","handleCareChange","nextCare","eligibleOperators","eligibleChairs","scopedOperators","scopedChairs","projectionContext","chosenOperatorIds","operatorGroups","operatorSections","chairSections","buildQuery","computeSlots","computeFreeSlotsLocally","publish","searchStamp","askedStampRef","abortRef","askServer","searchedRef","runSearch","computeRef","publishRef","allFoundRef","searched","askServerRef","handleSearch","pagerStepDays","handleShowMore","autoSearchedRef","handleShowOnGridChange","noResultsDescription","handleBook","careDevices","maxRangeDays","rangeTooLong","missingPracticeHours","missingOperatorHours","byDay","Collapsible","CollapsibleTrigger","CollapsibleContent","UserCog","Switch","allocation","facts","rowIsButton","privacyKey","privacyMask","PrivacyHiddenLine","block","PrivacyIdentityCard","SectionCard","PrivacyNoticePanel","onTurnOff","InfoHoverBody","eyebrow","heading","HoverCard","fact","TRIGGER","InfoHover","MUTED","telLink","number","mailLink","email","euro","amount","Rows","shown","DescriptionList","DetailsPatientCard","details","booking","signingShown","signingFacts","answerFacts","addressLabel","hasLabel","Phone","unpaid","billable","paidOnline","headingKey","factKey","PatientSummaryCard","DetailsAppointmentCard","editor","timed","frequencyKey","frequency","bookingRows","shownBookingRows","hasBooking","CalendarDays","Building2","DetailsTreatmentsCard","TreatmentReceipt","_careId","DOCUMENT_KINDS","DOCUMENT_ICON","ReceiptEuro","Folder","FileText","File","Camera","START_ISO","parseDetailsStartIso","match","year","month","seconds","monthEnd","SKELETON_FACT_WIDTHS","DetailsSkeleton","EditableDescription","NoteTimeline","CalendarDetailsHydration","CONTENT_ENTER_CLASS","identityRow","STATUS_ORDER","NO_STATUS","NOTES_PREVIEWED","MenuAction","startIcon","background","hideLabel","Tooltip","ChevronDown","DetailsNotesCard","onOpenNotes","headingId","more","openLabel","NotebookPen","Counter","AppointmentDetailsPanel","AppointmentDetailsPanelContent","notesSeam","onEdit","onStatusChange","onDescriptionChange","privacyTitle","shownLocale","card","historyOpen","setHistoryOpen","editingDescription","setEditingDescription","descriptionDraft","setDescriptionDraft","descriptionSaving","setDescriptionSaving","descriptionError","setDescriptionError","descriptionFieldRef","saveDescription","statusSaving","setStatusSaving","statusError","setStatusError","statusOptions","CircleDashed","changeStatus","nextStatus","notesFor","openNotes","join","whatsappUrl","createTaskUrl","documents","documentKinds","backLabel","copyMenu","statusLabel","statusValue","statusControl","WorkflowStatusControl","actions","SquareCheckBig","CalendarNotesDock","active","request","visited","setVisited","panel","CalendarPatientContext","DEFAULT_CALENDAR_ID","NAV_BLOCK_SIZE_CLASS","FC_STICKY_OFFSET_CLASS","BADGED_ACTION_CLASS","ACTION_BADGE_CLASS","CalendarSurface","setRows","onFocus","onComposeNew","onOpenWaitingList","onAddWaitingEntry","onOpenOnlineBookings","onlineBookingsCount","waitingBadgeCount","onVisibleRangeChange","selectedEventId","gotoRequest","onBookSlotFromFinder","display","setDisplay","onHistory","reviewOnlyEventIds","detailsOnEveryClick","placement","onPlacementEnd","createMode","onCreateModeEnd","focusScroll","saveNotice","onPrivacyChange","availability","availabilityContext","availableTools","schedulerLicenseKey","preferences","onMoveOccurrence","inc1","calRef","freeBand","setFreeBand","bookingFreeBand","freeBandId","observer","freeOptions","band","surfaceRef","navigationRef","navigation","surface","measure","chairFilterButtonRef","viewOptionId","setViewOptionId","setShowWeekends","setSelectedChairIds","setSelectedOperatorIds","setPrivacy","currentDate","setCurrentDate","currentDateRef","mountDate","setMountDate","onlyAvailable","setOnlyAvailable","showDisabledOperators","setShowDisabledOperators","settingsOpen","setSettingsOpen","chairFilterOpen","setChairFilterOpen","operatorFilterOpen","setOperatorFilterOpen","settingsButtonRef","printOpen","setPrintOpen","printDay","setPrintDay","printPending","setPrintPending","setRangeTitle","peek","setPeek","pendingMove","setPendingMove","notifySms","setNotifySms","notifyEmail","setNotifyEmail","moveReadout","setMoveReadout","moveScope","setMoveScope","copyCountRef","hostSeriesMove","visibleRangeRef","visibleRange","setVisibleRange","isDateVisible","stem","isMonth","calendarView","projecting","allChairIds","keptDisabledIds","allOperatorIds","hiddenDays","loadingDates","dates","dayWindow","printDays","printSections","fcEvents","mapped","shadeFrom","shadeTo","columnsHiddenWhenAbsent","closureBanners","availabilityEvents","unavailabilityEvents","resources","placementRow","activeMode","modeColorHex","modeInkHex","modeBannerLabel","endMode","lastFocusScrollRef","lastNoticeTickRef","reasons","toastSuccess","handleEventClick","handlePeekOpen","handlePeekClose","lastRangeRef","handleDatesSet","info","rangeKey","applyDrop","change","owned","targets","isPrimary","recolour","updated","applyResize","newEnd","before","fromMin","toMin","seedNotifyDefaults","handleDrop","operatorForDay","handleResize","oldEnd","oldMinutes","toastInfo","confirmMove","oldStart","newStart","hostScope","written","rollback","alsoIds","cancelMove","openDay","handleDateClick","selectedDurationMin","handleDateSelect","switchView","onKeyDown","setAxis","resourceKind","revealDisabledOperators","filterCount","resetFilters","viewLabel","practiceWindow","windowOptions","operatorRow","headerBlock","Printer","closeEvent","orientation","zebraRows","showTime","slotDuration","careDescription","clamped","operatorNameDisplay","chairNameDisplay","navigationRow","ResourceChip","RotateCcw","Kbd","ChevronLeft","ChevronRight","peekMeta","peekRow","peekPlan","peekPatient","peekChair","peekOperator","pendingRow","pendingRef","pendingHostScope","pendingPatientName","pendingChannels","moveFromValue","moveToValue","oldResourceId","newResourceId","resourceChanged","resourceTitle","res","ScrollArea","Card","Calendar","openEvent","AppointmentPeek","waitingKey","ACCESSIBLE_TARGET_SQUARE","GROUP_LABEL_KEY","CHIP_LABEL_KEY","GROUP_ICON","lineVariants","UNDER_NAME_CLASS","APPOINTMENT_LINK_CLASS","APPOINTMENT_DOT_CLASS","AVATAR_FALLBACK_CLASS","otherYear","WhatsAppMember","member","EntryMenuMember","editLabel","editBlockedReason","removeLabel","onRemove","triggerRef","Ellipsis","WaitingEntryCard","onPlace","onFindSlots","reasonId","linked","memo","notLoaded","hidden","appointmentTitle","masked","plainTitle","contactRef","who","honestGap","labelKey","whatsappNumber","whatsappLabel","canWrite","assignBlocked","placeLabelKey","placeBlocked","dotStyle","blockedProps","blocked","withReason","reason","UserPlus","WaitingListSkeleton","WaitingListPanel","onPlaceWaiting","onFindSlotsForWaiting","onRemoveWaiting","onOpenEntryForm","entryForm","onSaveEntry","onCancelEntry","headerRef","advancedId","setQuickView","showAdvanced","setShowAdvanced","setDraft","applied","setApplied","changeQuickView","counts","appliedCount","firstRead","followedLoading","enterClass","subview","lastEntryRef","yesNoOptions","advancedForm","advancedLabel","full","WaitingGroup","WORKSPACE_REMINDER_CHANNELS","WORKSPACE_DESCRIPTION_MAX","NO_GLOBAL_TOOLS","dockMessage","toolId","CalendarSheetHost","onOpenSheet","onAnnounce","onClose","openTool","useControlRoomActions","EditorToolHost","withheld","UpcomingPanel","CalendarRailTools","workspaceRef","activeToolId","focus","onPrivacyOff","selectedRow","editorMode","onEditorModeChange","editorSeed","loadAppointmentEditor","loadAppointmentDetails","waitingList","waitingSeedTick","findSlotsSeed","signRequests","notesSeamFor","businessHours","onRevealAppointment","onShowAvailability","onFinderSearchRange","gridAxis","bookingQueue","waitingListState","bookingsSeedTick","bookingRequest","onCompleteBooking","contextKey","patientContext","setPatientContext","reportPatient","notesPatientId","hasNotes","notesRequest","setNotesRequest","previousActiveTool","leftNotes","focusFrame","previousTool","schedule","focusedPatientId","focusedPatientName","unsignedRequiredDocs","editorPlatform","detailsPlatform","extrasPlatform","findSlotsPlatform","appointmentsTool","detailsMode","readsDetails","editing","detailsReadOnly","seededPrefill","formWithheld","editOutcome","refocusEdit","detailsTick","setDetailsTick","saveEdit","extras","deleteEdit","closeEdit","outcome","editFromDetails","renderDetails","notesPatient","button","editorTool","editorPatientRef","editorPatient","editorRow","_f","_g","bookingAddress","setBookingAddress","bookingQueued","bookingsTool","waitingListTool","findSlotsTool","tools","sharedPanel","registry","useControlRoomTools","dockTool","openedRef","prevFocusRef","prevSeedTickRef","prevFindSlotsTickRef","prevBookingsTickRef","prevWaitingTickRef","initialWorkspaceDisplay","initialDisplay","CalendarWorkspace","TooltipProvider","ControlRoomProvider","CalendarWorkspaceBody","journey","permissions","focusAppointmentId","focusBookingId","focusBookingKey","createParameters","freeSlot","i18n","resolvedLocale","setActiveToolId","availableToolsKey","journeyRows","setFocus","setWaitingList","backlogSeed","logHistory","handleRequestSignature","handleComposeNew","handleRemoveWaiting","handleUpsertWaiting","handleOpenBacklog","handleVisibleRangeChange","handleDeleteAppointment","handleMoveOccurrence","handleStatusChange","handleDescriptionChange","handleBookSlot","handleRevealAppointment","handleCreateAppointment","handleFindSlotsForWaiting","clearFindSlotsSeed","handleBookSlotFromFinder","handleShowAvailability","notesByPatient","notesLoadByPatient","handleLoadNotes","handleAddNote","handleEditNote","handleDeleteNote","handleToggleNotePin","requestNoteAiDraft","dictateNote","noteAiConsentFor","noteComposerExtrasFor","detailsStatusChange","content","announcement","setAnnouncementRaw","setAnnouncement","turnPrivacyOff","setEditorMode","handleOpenSheet","waitingBadge","onlineBookings","setSaveNotice","prevRow","expandsSeries","siblings","edited","handleDelete","setPlacement","placementRef","armPlacement","handleMove","handleCopy","endPlacement","landed","settled","setCreateMode","endCreateMode","setFocusScroll","handleCompleteBooking","bookingsSeed","setBookingsSeed","handleOpenOnlineBookings","setBookingRequest","setEntryForm","entryOpenerRef","openEntryForm","closeEntryForm","prevEntryFormRef","had","opener","handleSaveEntry","handleRemoveWaitingEntry","handlePlaceWaiting","deepLinkRef","ControlRoomRail"],"mappings":"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","x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10]}
|