@alfadocs/ui-kit-debug 1.132.0 → 1.133.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/_chunks/calendar-appointment-editor-dialog-BHx6kUhX.js +13773 -0
  2. package/dist/_chunks/calendar-appointment-editor-dialog-BHx6kUhX.js.map +1 -0
  3. package/dist/agent-catalog.json +1 -1
  4. package/dist/browser-support.js +1 -1
  5. package/dist/i18n/locales/ar.d.ts +2 -0
  6. package/dist/i18n/locales/ar.d.ts.map +1 -1
  7. package/dist/i18n/locales/ar.js +3 -1
  8. package/dist/i18n/locales/ar.js.map +1 -1
  9. package/dist/i18n/locales/de.d.ts +2 -0
  10. package/dist/i18n/locales/de.d.ts.map +1 -1
  11. package/dist/i18n/locales/de.js +3 -1
  12. package/dist/i18n/locales/de.js.map +1 -1
  13. package/dist/i18n/locales/el.d.ts +2 -0
  14. package/dist/i18n/locales/el.d.ts.map +1 -1
  15. package/dist/i18n/locales/el.js +3 -1
  16. package/dist/i18n/locales/el.js.map +1 -1
  17. package/dist/i18n/locales/en.d.ts +2 -0
  18. package/dist/i18n/locales/en.d.ts.map +1 -1
  19. package/dist/i18n/locales/en.js +2 -0
  20. package/dist/i18n/locales/en.js.map +1 -1
  21. package/dist/i18n/locales/es.d.ts +2 -0
  22. package/dist/i18n/locales/es.d.ts.map +1 -1
  23. package/dist/i18n/locales/es.js +3 -1
  24. package/dist/i18n/locales/es.js.map +1 -1
  25. package/dist/i18n/locales/fr.d.ts +2 -0
  26. package/dist/i18n/locales/fr.d.ts.map +1 -1
  27. package/dist/i18n/locales/fr.js +3 -1
  28. package/dist/i18n/locales/fr.js.map +1 -1
  29. package/dist/i18n/locales/hi.d.ts +2 -0
  30. package/dist/i18n/locales/hi.d.ts.map +1 -1
  31. package/dist/i18n/locales/hi.js +3 -1
  32. package/dist/i18n/locales/hi.js.map +1 -1
  33. package/dist/i18n/locales/it.d.ts +2 -0
  34. package/dist/i18n/locales/it.d.ts.map +1 -1
  35. package/dist/i18n/locales/it.js +3 -1
  36. package/dist/i18n/locales/it.js.map +1 -1
  37. package/dist/i18n/locales/ja.d.ts +2 -0
  38. package/dist/i18n/locales/ja.d.ts.map +1 -1
  39. package/dist/i18n/locales/ja.js +3 -1
  40. package/dist/i18n/locales/ja.js.map +1 -1
  41. package/dist/i18n/locales/nl.d.ts +2 -0
  42. package/dist/i18n/locales/nl.d.ts.map +1 -1
  43. package/dist/i18n/locales/nl.js +3 -1
  44. package/dist/i18n/locales/nl.js.map +1 -1
  45. package/dist/i18n/locales/pl.d.ts +2 -0
  46. package/dist/i18n/locales/pl.d.ts.map +1 -1
  47. package/dist/i18n/locales/pl.js +3 -1
  48. package/dist/i18n/locales/pl.js.map +1 -1
  49. package/dist/i18n/locales/pt.d.ts +2 -0
  50. package/dist/i18n/locales/pt.d.ts.map +1 -1
  51. package/dist/i18n/locales/pt.js +3 -1
  52. package/dist/i18n/locales/pt.js.map +1 -1
  53. package/dist/i18n/locales/ro.d.ts +2 -0
  54. package/dist/i18n/locales/ro.d.ts.map +1 -1
  55. package/dist/i18n/locales/ro.js +3 -1
  56. package/dist/i18n/locales/ro.js.map +1 -1
  57. package/dist/i18n/locales/ru.d.ts +2 -0
  58. package/dist/i18n/locales/ru.d.ts.map +1 -1
  59. package/dist/i18n/locales/ru.js +3 -1
  60. package/dist/i18n/locales/ru.js.map +1 -1
  61. package/dist/i18n/locales/sq.d.ts +2 -0
  62. package/dist/i18n/locales/sq.d.ts.map +1 -1
  63. package/dist/i18n/locales/sq.js +3 -1
  64. package/dist/i18n/locales/sq.js.map +1 -1
  65. package/dist/i18n/locales/sv.d.ts +2 -0
  66. package/dist/i18n/locales/sv.d.ts.map +1 -1
  67. package/dist/i18n/locales/sv.js +3 -1
  68. package/dist/i18n/locales/sv.js.map +1 -1
  69. package/dist/i18n/locales/tr.d.ts +2 -0
  70. package/dist/i18n/locales/tr.d.ts.map +1 -1
  71. package/dist/i18n/locales/tr.js +3 -1
  72. package/dist/i18n/locales/tr.js.map +1 -1
  73. package/dist/i18n/locales/zh.d.ts +2 -0
  74. package/dist/i18n/locales/zh.d.ts.map +1 -1
  75. package/dist/i18n/locales/zh.js +3 -1
  76. package/dist/i18n/locales/zh.js.map +1 -1
  77. package/dist/index.js +1 -1
  78. package/dist/locales/ar.json +3 -1
  79. package/dist/locales/de.json +3 -1
  80. package/dist/locales/el.json +3 -1
  81. package/dist/locales/en.json +2 -0
  82. package/dist/locales/es.json +3 -1
  83. package/dist/locales/fr.json +3 -1
  84. package/dist/locales/hi.json +3 -1
  85. package/dist/locales/it.json +3 -1
  86. package/dist/locales/ja.json +3 -1
  87. package/dist/locales/nl.json +3 -1
  88. package/dist/locales/pl.json +3 -1
  89. package/dist/locales/pt.json +3 -1
  90. package/dist/locales/ro.json +3 -1
  91. package/dist/locales/ru.json +3 -1
  92. package/dist/locales/sq.json +3 -1
  93. package/dist/locales/sv.json +3 -1
  94. package/dist/locales/tr.json +3 -1
  95. package/dist/locales/zh.json +3 -1
  96. package/dist/patterns/calendar/calendar-workspace.d.ts.map +1 -1
  97. package/dist/patterns/calendar/calendar-workspace.model.d.ts.map +1 -1
  98. package/dist/patterns/calendar/calendar.journey.d.ts +4 -0
  99. package/dist/patterns/calendar/calendar.journey.d.ts.map +1 -1
  100. package/dist/patterns/calendar/calendar.sheets.d.ts.map +1 -1
  101. package/dist/patterns/calendar/calendar.surface.d.ts +15 -1
  102. package/dist/patterns/calendar/calendar.surface.d.ts.map +1 -1
  103. package/dist/patterns/calendar/calendar.types.d.ts +4 -0
  104. package/dist/patterns/calendar/calendar.types.d.ts.map +1 -1
  105. package/dist/patterns/calendar/index.js +1 -1
  106. package/package.json +1 -1
  107. package/dist/_chunks/calendar-appointment-editor-dialog-WW6V1SGh.js +0 -13663
  108. package/dist/_chunks/calendar-appointment-editor-dialog-WW6V1SGh.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"calendar-appointment-editor-dialog-WW6V1SGh.js","sources":["../../node_modules/lucide-react/dist/esm/icons/calendar-search.mjs","../../node_modules/lucide-react/dist/esm/icons/list-plus.mjs","../../node_modules/lucide-react/dist/esm/icons/list-todo.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-task-editor.tsx","../../src/patterns/calendar/calendar-editor-hydration.tsx","../../src/patterns/calendar/calendar-delete-confirm.tsx","../../src/patterns/calendar/calendar-document-scope-confirm.tsx","../../src/patterns/calendar/calendar-appointment-details.tsx","../../src/patterns/calendar/calendar-notes-tool.tsx","../../src/patterns/calendar/calendar-archive.tsx","../../src/patterns/calendar/calendar.host.ts","../../src/patterns/calendar/calendar-patient-picker.tsx","../../src/patterns/calendar/calendar-patient-locked.tsx","../../src/patterns/calendar/calendar-rail-settle.ts","../../src/patterns/calendar/calendar-series-scope-chooser.tsx","../../src/patterns/calendar/calendar-editor-guard.ts","../../src/patterns/calendar/calendar-custom-recurrence.tsx","../../src/patterns/calendar/calendar-care-rules.ts","../../src/patterns/calendar/calendar-bookings-panel.tsx","../../src/patterns/calendar/calendar.sheets.tsx","../../src/patterns/calendar/calendar-load-error.tsx","../../src/patterns/calendar/calendar-status-colours.ts","../../src/patterns/calendar/calendar-sticky-offset.ts","../../src/patterns/calendar/calendar-prompts.tsx","../../src/patterns/calendar/calendar.surface.tsx","../../src/patterns/calendar/calendar-settings-ical.tsx","../../src/patterns/calendar/calendar-settings-practice.tsx","../../src/patterns/calendar/calendar-settings-overlay.tsx","../../src/patterns/calendar/calendar-settings-panel.tsx","../../src/patterns/calendar/calendar-waiting-list-panel.tsx","../../src/patterns/calendar/calendar-workspace.tsx","../../src/patterns/calendar/calendar-appointment-editor-dialog.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: \"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: \"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: \"M13 5h8\", key: \"a7qcls\" }],\n [\"path\", { d: \"M13 12h8\", key: \"h98zly\" }],\n [\"path\", { d: \"M13 19h8\", key: \"c3s6r1\" }],\n [\"path\", { d: \"m3 17 2 2 4-4\", key: \"1jhpwq\" }],\n [\"rect\", { x: \"3\", y: \"4\", width: \"6\", height: \"6\", rx: \"1\", key: \"cif1o7\" }]\n];\nconst ListTodo = createLucideIcon(\"list-todo\", __iconNode);\n\nexport { __iconNode, ListTodo as default };\n//# sourceMappingURL=list-todo.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 `'loading'` (or not named) and the finder refuses to answer\n * from any day that is not `'ready'`, because \"no row here\" and \"no row\n * here YET\" are different answers. A day that is `'error'` is not\n * washed: it takes a flat error tint, and the workspace shows a message\n * above the grid with Retry, which calls the `onRetryLoad` prop on\n * `CalendarWorkspace` (no prop, no button).\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 (`YYYY-MM-DD`): the host reads it from\n * the page address, with `initialView`. The kit validates it: text that\n * is not a real calendar day opens on the day of `nowIso` instead. */\n initialDateIso: string;\n /**\n * The practice's billing currency as an ISO 4217 code (`'GBP'`,\n * `'CHF'`, …), read wherever the pattern prints a price (patient\n * ledger, appointment billing lines, the price-list editor). Optional\n * and additive: every host that omits it renders exactly as before —\n * every read site falls back to `'EUR'`, the kit's original hardcoded\n * assumption, so a euro-zone host needs no change.\n */\n currency?: 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 /** Companies a task may be \"about\" (platform `doctorCompany`). Omit it\n * and the task editor's \"Riguarda\" choice offers only Nobody / Patient\n * — a free-text company name is not an id and the platform would\n * reject or mis-link it, so the Company segment is withheld rather\n * than rendered over nothing to type an id into. */\n companies?: ReadonlyArray<{ id: string; name: string }>;\n /** The task types this practice offers, system and practice-defined in\n * ONE list. Omit it (or `[]`) and the Type field is withheld, as with\n * `companies`. `id` is an opaque token, unique here and never `''`;\n * `custom` only groups the select; `label` is the host's own string,\n * already translated. See calendar.mdx § Tasks. */\n taskTypes?: ReadonlyArray<{ id: string; label: string; custom?: boolean }>;\n /** Practice USER accounts a task can be assigned to (platform\n * `practiceUser`) — NOT `operators`, which is the clinician axis. Same\n * withheld-not-disabled contract; `'none'` is reserved for Nobody. */\n taskAssignees?: ReadonlyArray<{ id: string; label: string }>;\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 CalendarResource,\n} from '../../components/calendar';\nimport type { CarePlanState } from '../../components/_shared/entity-card';\nimport type { TreatmentBilling } from '../../components/treatment-receipt';\nimport type { SignatureParty } from '../../components/signature-status-chip';\nimport type {\n TaskEditorDraft,\n TaskEditorTask,\n} from '../../components/task-editor';\nimport type {\n AppointmentAnamnesisAnswer,\n AppointmentDetailsPatient,\n AppointmentHistoryEntry,\n AppointmentHistoryField,\n AppointmentHistoryChange,\n AppointmentHistoryKind,\n AppointmentPhoneLabel,\n AppointmentPhoneNumber,\n AppointmentSignChannel,\n} from '../../components/appointment-details-panel';\n\n/* The leaf shapes the details panel reads live with AppointmentDetailsPanel;\n the calendar keeps its names for them. */\n/** Platform `DoctorPatientPhoneNumber` carries a free-text label; the\n * vocabulary is fixed so the printed call sheet can localise it. */\nexport type CalendarPhoneLabel = AppointmentPhoneLabel;\nexport type CalendarPhoneNumber = AppointmentPhoneNumber;\n/** One highlighted anamnesis answer (display strings, host-localised). */\nexport type CalendarAnamnesisAnswer = AppointmentAnamnesisAnswer;\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 extends AppointmentDetailsPatient {\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 /** The patient's yearly number, formatted by the host (\"2026/14\"), for a\n * practice that numbers patients per year. Printed after the name on\n * the day list; absent = the host did not tell us, nothing prints. */\n yearlyNumber?: string;\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/**\n * The practice-wide calendar settings the Settings panel's Practice section edits.\n * A member is present only when the host grants this user that setting's\n * right (decision P18): an absent member withholds its control, never a\n * disabled one. More members arrive additively.\n */\nexport interface PracticeCalendarSettings {\n /** Keep the practice open on public holidays (platform\n * `keep_open_on_holidays`). */\n openOnHolidays?: boolean;\n /** Only offer the operators and chairs a care allows (platform Care\n * settings filter). */\n careAllocationFilter?: boolean;\n /** Patient notices, on or off by default. Only the channels listed get a\n * switch. The editor's reminder boxes and the move confirm's boxes start\n * from these, and never override a channel the patient cannot take. The\n * host passes the saved value back in `value` for them to follow. */\n patientNotices?: PracticePatientNotices;\n /** Notify the operator when a patient cancels or changes. */\n operatorNotices?: PracticeOperatorNotices;\n /** The default WhatsApp message. The kit only edits the text: it never\n * sends WhatsApp. Over `maxLength` blocks Save with an error. */\n whatsappMessage?: PracticeWhatsappMessage;\n}\n\n/**\n * Default patient notices. A channel left out gets no switch.\n *\n * `moved` is the platform's ONE \"appointment moved\" switch (it replaces the\n * old per-channel pair). The move confirm's SMS and email ticks then follow\n * `reminderSms` and `reminderEmail`. `confirmationSms` is the SMS the\n * platform sends when an appointment is created; the kit only edits the\n * switch and sends nothing.\n */\nexport interface PracticePatientNotices {\n reminderSms?: boolean;\n reminderEmail?: boolean;\n confirmationSms?: boolean;\n moved?: boolean;\n}\n\n/**\n * Operator notices. `onCancel` and `onChange` are sent when a PATIENT\n * cancels or changes; `onUserChange` is the one notice sent when a USER of\n * the practice creates, changes or cancels. A key left out gets no switch.\n */\nexport interface PracticeOperatorNotices {\n onCancel?: boolean;\n onChange?: boolean;\n onUserChange?: boolean;\n}\n\n/** The WhatsApp default message and what the host allows in it. */\nexport interface PracticeWhatsappMessage {\n value: string;\n /** Longest message the host accepts, in characters. */\n maxLength?: number;\n /** Placeholders the host replaces when it sends, inserted verbatim\n * (for example `[[PATIENT_NAME]]`). With none, no insert menu shows. */\n variables?: readonly string[];\n}\n\n/**\n * The host's seam for the Settings panel's Practice section. The section shows\n * when at least one member is present: a key of `value`, or\n * `hoursSummary`. Edits are a draft until Save; the kit calls `onSave`\n * and nothing else, so the host writes the settings and then re-feeds\n * `CalendarData` (`practiceClosedOn` and `closureOn`, which read the\n * holidays flag, and the cares' allowed lists) for the grid to follow.\n */\nexport interface CalendarPracticeSettingsSeam {\n /** The saved settings. Only the keys present here get a control. */\n value: PracticeCalendarSettings;\n /** Persist the next value. `next` is the full saved value with the\n * user's changes laid over it; `changedKeys` names the keys the user\n * changed, so a host that merges can write only those and never\n * overwrite a key another admin changed meanwhile. Reject with an Error\n * carrying the host's translated message to roll the controls back and\n * show it.\n *\n * Re-feeds: when the host passes `value` again, it becomes the saved\n * value. Keys the user has changed keep their draft; every other key\n * follows the new value. A re-feed that arrives while `onSave` runs is\n * applied once it settles. */\n onSave: (\n next: PracticeCalendarSettings,\n changedKeys: ReadonlyArray<keyof PracticeCalendarSettings>,\n ) => Promise<void>;\n /** Read-only line on opening hours, closures and absences. The kit never\n * edits hours: `href` or `onOpen` links to the host's editor, and with\n * neither the line stands alone. */\n hoursSummary?: { text: string; href?: string; onOpen?: () => void };\n /** The iCal feeds of the practice and of each operator, with revoke. An\n * IMMEDIATE action, not part of the draft: Save and Discard never touch\n * it, and a revoked link cannot come back. The host owns the token and\n * its invalidation. Withheld with no feeds. The URL is a bearer\n * credential: the kit never logs it, never puts it in an analytics hook\n * and always draws it left to right. The kit has no privacy-mode concept\n * for it, so a host that must hide it passes no feeds. */\n icalLinks?: CalendarIcalLinks;\n}\n\n/** One iCal feed: the practice, or one operator. */\nexport interface CalendarIcalFeed {\n /** Stable id the host recognises in `onRevoke`. */\n id: string;\n /** Who the feed belongs to: the practice or the operator's name. */\n label: string;\n /** The current feed link. */\n url: string;\n /** Operator photo; initials show without it. */\n avatarSrc?: string;\n /** `false` withholds Revoke on this row only: the user may see the link\n * but not revoke it. The practice feed and an operator's feed can carry\n * different rights (business-rules: `calendar_show` and\n * `doctor_operator_edit` to see, `doctor_appointment_edit` to revoke),\n * so the host sets it per feed. Default: revocable when `onRevoke` is\n * passed. */\n canRevoke?: boolean;\n}\n\n/** The iCal feeds and the revoke seam of the Practice section. */\nexport interface CalendarIcalLinks {\n feeds: ReadonlyArray<CalendarIcalFeed>;\n /** Invalidate the feed's link and return the NEW one. Reject with an\n * Error carrying the host's translated message: the old link stays and\n * the message shows. Optional: without it no row draws Revoke, the\n * confirm dialog or the \"Takes effect at once\" note, and the group is a\n * list of copy fields. Pass it only when the user may revoke (the kit\n * withholds a control the host cannot back). */\n onRevoke?: (id: string) => Promise<{ url: string }>;\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/**\n * The operator filter as ONE list (the \"one at a time\" mode): every listed\n * operator once, even when several groups hold it, active first and then by\n * `sequenceNumber` like a group's own members.\n */\nexport function flattenOperatorFilterGroups(\n groups: readonly CalendarOperatorFilterGroup[],\n inactiveIds: readonly string[],\n): CalendarResource[] {\n const inactive = new Set(inactiveIds);\n const rank = (o: CalendarResource): number =>\n o.sequenceNumber ?? Number.MAX_SAFE_INTEGER;\n const unique = new Map(\n groups.flatMap((g) => g.operators).map((o) => [o.id, o] as const),\n );\n return [...unique.values()].sort(\n (a, b) =>\n Number(inactive.has(a.id)) - Number(inactive.has(b.id)) ||\n rank(a) - rank(b),\n );\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/** \"Colour by\": what colours the cards for THIS user, worked out at draw\n * time. `appointment` is the colour stored on the appointment (the care's\n * colour when none was picked). `status` is one fixed colour per status.\n * It never writes a stored colour. */\nexport type ColorAssociation =\n | 'appointment'\n | 'care'\n | 'operator'\n | 'chair'\n | 'status';\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 /** Each phase's share of `durationMin`, in percent, keyed by the phase\n * label (platform `phase.durationPercentage`). With it, an appointment\n * that books some phases takes the sum of their shares as its length\n * (B22); without it, the whole care length. */\n phaseShares?: Record<string, number>;\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 association gives an appointment: the operator's, the\n * chair's, or the first catalogued care's. `undefined` = it has none\n * (including `appointment`, whose colour is the stored one). */\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 /** The treatment has been invoiced. Fallback when `billing` is absent. */\n billed?: boolean;\n /** The billing state; wins over `billed`. `'reversed'` reads as unbilled,\n * with the reason, in the editor's linked-entry list and the details\n * panel's care lines. The printed day list shows no billed state. */\n billing?: TreatmentBilling;\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 /** Wins over `billed`. A reversed row has no live invoice, so it\n * stays editable. */\n billing?: TreatmentBilling;\n }>;\n };\n\n/** Channel a signature request went out on (platform `requiredObjectsSignMode`). */\nexport type CalendarSignChannel = AppointmentSignChannel;\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 /** Absent = a desk-created slot with no chair yet (chairs are optional\n * on the platform) — the calendar backlog's \"Senza poltrona\" gap. */\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/**\n * What the kit hands the host to create a patient from an online booking\n * (`EditorPlatformOptions.createPatientFromBooking`): what the person typed\n * on the booking website, so the host opens its own new-patient form\n * already filled in.\n */\nexport interface CalendarBookingPatientPrefill {\n /** The name typed on the booking site (`CalendarBookingContact.typedName`). */\n name: string;\n /** The SMS-verified phone, as typed. */\n phone: string;\n /** The email typed on the booking site. May be empty. */\n email: string;\n}\n\n/**\n * The host seam behind \"Create patient\" in the editor's and the waiting-list\n * entry form's patient search. The host opens its own new-patient form\n * (`typedText` is the last text typed in the search, to prefill it) and\n * resolves with the new patient, or `null` when the user cancels (nothing\n * changes). Make the record available through `CalendarData.patientById`\n * before resolving. Reject with a safe, user-facing `Error` on failure.\n */\nexport type CalendarCreatePatient = (request: {\n typedText: string;\n}) => Promise<CalendarPatient | null>;\n\n/** A calendar task (platform `DoctorReminder`): the calendar's name for the\n * published TaskEditor's record. See `TaskEditorTask` for every field,\n * including why `dateIso` is an instant and the one-counterpart rule. */\nexport type CalendarTask = TaskEditorTask;\n\n/** The same shape without an identity: what the create seam receives and\n * what an edit save re-sends in full. See `TaskEditorDraft`. Published as\n * `CalendarTaskDraft`. */\nexport type TaskDraft = TaskEditorDraft;\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 = AppointmentHistoryKind;\n\n/** Form fields an edit can touch (the platform's audit vocabulary). */\nexport type CalendarHistoryField = AppointmentHistoryField;\n\n/** One value an edit changed, before and after. */\nexport type CalendarHistoryChange = AppointmentHistoryChange;\n\n/** One ledger line: who did what to the appointment, and when. */\nexport type CalendarHistoryEntry = AppointmentHistoryEntry;\n\n/** Every labelled phone number; see the shared helper. */\nexport { patientPhones } from '../../components/_shared/appointment-format';\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/** A host button on a prompt: its own label and what it does. */\nexport interface CalendarPromptAction {\n label: string;\n onAction: () => void;\n}\n\n/** A host message above the grid (the sleeping-patients banner, say). */\nexport interface CalendarBanner {\n /** Defaults to `info`. */\n tone?: 'info' | 'warning' | 'success';\n text: string;\n action?: CalendarPromptAction;\n /** Adds a close button. The banner hides at once and the host is told, so\n * it can remember the dismissal (the old banner could be dismissed).\n * Without it the banner has no close button. */\n onDismiss?: () => void;\n}\n\n/**\n * The prompts the old calendar kept, each a host seam. A member the host\n * leaves out is withheld: no empty banner, no disabled link.\n */\nexport interface CalendarPrompts {\n /** A banner above the grid. */\n banner?: CalendarBanner;\n /** Show the first-appointment alert (the host knows the practice has no\n * appointments). `action` adds its button, \"Go to the dashboard\" say. */\n firstAppointment?: { action?: CalendarPromptAction };\n /** The Academy calendar tutorial. An `https:` link, shown in the settings\n * overlay and opened in a new tab. Anything else is withheld. */\n academyHref?: string;\n}\n\n/**\n * The calendar archive session: the practice's global archive plus ONE\n * second archive of the same practice (the old calendar's archive mode, not\n * a linked practice). Passing it turns on the seven archive rules.\n */\nexport interface CalendarArchive {\n /** The second archive's id. A new appointment saved to it carries this id. */\n id: string;\n /** Named in the banner and in the create question. */\n name: string;\n /** The Exit action. The host ends the session and remounts the calendar. */\n onExit: () => void;\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 /** The old Show weekends switch. Still READ: a user who has not chosen\n * days yet keeps it as the matching hidden set. Never written. */\n showWeekends: 'calendarWorkspace.showWeekends',\n /** The weekdays this user hides, 0 (Sunday) to 6 (Saturday). */\n hiddenDays: 'calendarWorkspace.hiddenDays',\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 {\n type CalendarEvent,\n type CalendarEventStatus,\n type CalendarResource,\n} from '../../components/calendar';\nimport {\n APPOINTMENT_PALETTE,\n GOOGLE_CALENDAR_PALETTE,\n type PaletteSwatch,\n} from '../../components/color-picker';\nimport {\n contrastRatio,\n hexToHsl,\n} from '../../components/color-picker/color-utils';\nimport { signatureStatusOf } from '../../components/signature-status-chip';\nimport type { TreatmentBilling } from '../../components/treatment-receipt';\nimport type { WorkflowStatusTone } from '../../components/workflow-status';\nimport { APPOINTMENT_STATUS_LABEL_KEY } from '../../components/workflow-status/appointment-workflow-status';\nimport { APPOINTMENT_STATE_WORKFLOW } from '../../components/_shared/entity-card';\nimport { APPOINTMENT_STATUS_BADGE_VARIANT } from '../../components/appointment-details-panel/appointment-details-panel.identity';\nimport type { AppointmentRecurrenceFrequency } from '../../components/appointment-details-panel';\nimport {\n ageInYears,\n formatDay,\n parseEventDate,\n} from '../../components/_shared/appointment-format';\nimport type { CalendarData } from './calendar.data';\nimport type { StatusColours } from './calendar-status-colours';\nimport {\n type CareDescriptionMode,\n type ColorAssociation,\n type CalendarBaseEvent,\n type CalendarBookingContact,\n type CalendarCare,\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). One\n map with the workflow status options, so every surface says the same. */\nexport const STATUS_UI_KEY: Record<CalendarEventStatus, string> =\n APPOINTMENT_STATUS_LABEL_KEY;\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 /** The archive this appointment belongs to. Absent means the practice's\n * global archive. Every host callback for an action on this row carries it. */\n archiveId?: string;\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 /** The closure, holiday or absence the move lands on. The confirm shows\n * it as a warning line; it never blocks the move. */\n closure?: CalendarClosure;\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. `colorAssociation` is a view choice too: it picks\n * the colour each card is DRAWN with and never changes a stored colour.\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 /** Optional for saved preferences and older consumers. @default 'compact' */\n slotDensity?: 'compact' | 'comfortable';\n /** Picker colour strength. @default 'tinted' */\n eventColorStyle?: 'solid' | 'tinted';\n /** Show the opposite resource on tall cards. @default false */\n showCardContext?: boolean;\n /** Grid interval: 10, 15, 20, 30 or 60 minutes. */\n slotDuration: '00:10' | '00:15' | '00:20' | '00:30' | '01:00';\n window: 'working' | 'extended' | 'full';\n /** How the card describes its cares (platform care visualization). */\n careDescription: CareDescriptionMode;\n /** What colours the cards for this user. A view choice, computed when the\n * grid draws: it never writes a colour onto an appointment. */\n colorAssociation: ColorAssociation;\n}\n\nexport const DEFAULT_DISPLAY: DisplaySettings = {\n resourceKind: 'chair',\n orientation: 'vertical',\n zebraRows: false,\n showTime: true,\n slotDensity: 'compact',\n eventColorStyle: 'tinted',\n showCardContext: false,\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: 'appointment',\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 slotDensity: readEnum(['compact', 'comfortable']),\n eventColorStyle: readEnum(['solid', 'tinted']),\n showCardContext: readBoolean,\n slotDuration: readEnum(['00:10', '00:15', '00:20', '00:30', '01:00']),\n window: readEnum(['working', 'extended', 'full']),\n careDescription: readEnum(['off', 'name', 'code', 'nameCode']),\n colorAssociation: readEnum([\n 'appointment',\n 'care',\n 'operator',\n 'chair',\n 'status',\n ]),\n};\n\nexport function readDisplayField<K extends keyof DisplaySettings>(\n target: DisplaySettings,\n field: K,\n raw: unknown,\n): void {\n // The mapped reader has the same key as the target. Optional additive\n // fields need the indexed return type restored after TypeScript unions it.\n const value = DISPLAY_READERS[field](raw) as DisplaySettings[K] | undefined;\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\n/* Moved to the component layer with the details panel; re-exported so\n calendar importers keep their paths. */\nexport {\n DETAIL_STAMP_FORMAT,\n formatDay,\n formatTimeRange,\n parseEventDate,\n RECURRENCE_LABEL_KEY,\n sortHistoryNewestFirst,\n} from '../../components/_shared/appointment-format';\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 return ageInYears(dobIso, data.nowIso);\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 /** Why the patient is locked, already translated. Without it the field\n * says only that the patient cannot be changed here. */\n patientLockedReason?: string;\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' | 'chair';\n\n/** \"First visit\" is yes, no or unknown (rule B12). */\nexport type FirstVisitAnswer = 'yes' | 'no' | 'unknown';\n\nexport interface EditorPrefill {\n /** Set = the editor EDITS this existing event; unset = create. */\n editEventId?: string;\n patientId?: string;\n /** The reminder ticks SAVED with the appointment. An edit keeps them\n * (rule B7): a host that leaves one out reads as off in the boxes, and\n * the save then omits that field unless the user changes it, so the\n * host keeps its stored value (B23). A new appointment\n * and an online booking being completed ignore them and take the\n * practice defaults. */\n emailReminder?: boolean;\n smsReminder?: boolean;\n /** The saved first-visit answer; absent reads as unknown, and the save\n * omits `firstVisit` on an edit until the user answers. */\n firstVisit?: FirstVisitAnswer;\n /** An edit only: the appointment is in the waiting list. The editor\n * offers \"Add to waiting list\" on an edit when this is passed, ticked\n * when true, and unticking sends `addToWaitingList: false`. Leave it out\n * when the host cannot remove the entry: the tick is then withheld. */\n addToWaitingList?: boolean;\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 /** Create only: seeds the repeat fields, a Custom rule included, for a\n * host that reopens a draft. Ignored on an edit, whose rule is fixed. */\n recurrence?: EditorRecurrence;\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 /** A pure ROUTING flag, not a presentational one: this kit has no\n * task-editor panel of its own, so nothing currently sets it and the\n * appointment editor does not read it. Reserved for the task-editor\n * PR (stacked on the calendar toolbar work) to route a future\n * \"Nuova attività\" hand-off to its own panel instead of this one. */\n isTask?: boolean;\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 = AppointmentRecurrenceFrequency;\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/** RRULE weekday codes, indexed by JS `getDay()` (0 = Sunday). */\nexport const RECURRENCE_WEEKDAYS = [\n 'SU',\n 'MO',\n 'TU',\n 'WE',\n 'TH',\n 'FR',\n 'SA',\n] as const;\nexport type RecurrenceWeekday = (typeof RECURRENCE_WEEKDAYS)[number];\n\n/** One RRULE BYDAY token: a plain weekday (weekly rules) or a weekday\n * with its place in the month, `3TU` the third Tuesday and `-1TU` the\n * last one (monthly rules). */\nexport type RecurrenceByDay =\n | RecurrenceWeekday\n | `${1 | 2 | 3 | 4 | -1}${RecurrenceWeekday}`;\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'`: the\n * picked calendar day at local midnight. Platform `recurrenceUntil`\n * wants the END of that day: RRULE UNTIL at midnight drops that day's\n * occurrence, and `setRecurrenceUntil()` refuses a value before the\n * appointment's own start. */\n untilDate?: Date;\n /** Beyond platform: drop occurrences the practice could not honour. */\n skipClosedDays: boolean;\n /** Every N steps of `frequency`: platform `recurrenceInterval` (RRULE\n * INTERVAL). Absent means 1. Only the Custom rule sets it, and only\n * with `daily`, `weekly`, `monthly` or `yearly`. */\n interval?: number;\n /** Platform `recurrenceByDay` (RRULE BYDAY), set by the Custom rule\n * only. Weekly: plain codes in week order, always including the first\n * appointment's own day (`['MO', 'TH']`). Monthly: one ordinal code\n * derived from the first appointment (`['3TU']`, `['-1TU']`). Absent\n * means the plain rule. PLATFORM CAVEAT: `setRecurrenceFrequency()`\n * empties `recurrenceByDay` unless the frequency is weekly or yearly,\n * so a monthly code survives only if `setRecurrenceByDay()` runs after\n * it (or that setter changes). No platform controller writes\n * `recurrenceInterval` or `recurrenceByDay` from the calendar today. */\n byDay?: readonly RecurrenceByDay[];\n}\n\n/** Where a date's weekday falls in its month: `nth` 1–5 counted from the\n * start, `last` when no later same weekday fits in the month. */\nexport function weekdayOfMonth(date: Date): { nth: number; last: boolean } {\n const day = date.getDate();\n const daysInMonth = new Date(\n date.getFullYear(),\n date.getMonth() + 1,\n 0,\n ).getDate();\n return { nth: Math.ceil(day / 7), last: day + 7 > daysInMonth };\n}\n\n/** The `nth` weekday of a month (1–4, or -1 for the last), or undefined\n * when the month has no such day. Wall-clock time comes from `time`. */\nfunction nthWeekdayInMonth(\n year: number,\n month: number,\n weekday: number,\n nth: number,\n time: Date,\n): Date | undefined {\n const at = (day: number) =>\n new Date(year, month, day, time.getHours(), time.getMinutes());\n if (nth === -1) {\n const lastDay = new Date(year, month + 1, 0).getDate();\n const last = at(lastDay);\n return at(lastDay - ((last.getDay() - weekday + 7) % 7));\n }\n const first = at(1);\n const day = 1 + ((weekday - first.getDay() + 7) % 7) + (nth - 1) * 7;\n return day > new Date(year, month + 1, 0).getDate() ? undefined : at(day);\n}\n\n/** Candidate dates for a Custom rule (`byDay` set), in order, starting\n * with the anchor. Calendar arithmetic, so the wall-clock time holds\n * across a daylight-saving change. Weeks start on Monday (RRULE WKST). */\nfunction* customCandidates(\n start: Date,\n rule: EditorRecurrence,\n): Generator<Date> {\n const interval = Math.max(rule.interval ?? 1, 1);\n const byDay = rule.byDay ?? [];\n if (rule.frequency === 'monthly') {\n const match = /^(-?\\d)(\\w\\w)$/.exec(byDay[0] ?? '');\n if (!match) return;\n const nth = Number(match[1]);\n const weekday = RECURRENCE_WEEKDAYS.indexOf(match[2] as RecurrenceWeekday);\n yield start;\n for (let m = interval; m < 1200; m += interval) {\n const date = nthWeekdayInMonth(\n start.getFullYear(),\n start.getMonth() + m,\n weekday,\n nth,\n start,\n );\n if (date) yield date;\n }\n return;\n }\n /* Weekly: walk every `interval`-th week from the anchor's own week. */\n const days = byDay\n .map((code) => RECURRENCE_WEEKDAYS.indexOf(code as RecurrenceWeekday))\n .filter((index) => index >= 0)\n .map((index) => (index + 6) % 7)\n .sort((a, b) => a - b);\n const mondayOffset = (start.getDay() + 6) % 7;\n for (let week = 0; week < 5200; week += interval) {\n for (const offset of days) {\n const date = new Date(\n start.getFullYear(),\n start.getMonth(),\n start.getDate() - mondayOffset + week * 7 + offset,\n start.getHours(),\n start.getMinutes(),\n );\n if (date >= start) yield date;\n }\n }\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 * Whether the practice itself is closed on a date (`YYYY-MM-DD`): a closed\n * weekday, a practice closure, or a public holiday the practice does not\n * open on. One predicate for the series skip rule, so\n * neither disagrees with the grid's closed wash. An operator's absence is\n * not part of it.\n */\nexport function isPracticeClosedDay(\n dateIso: string,\n data: Pick<CalendarData, 'businessHours' | 'practiceClosedOn'>,\n): boolean {\n const weekday = new Date(`${dateIso}T00:00:00`).getDay();\n return (\n !data.businessHours.practice[weekday] || data.practiceClosedOn(dateIso)\n );\n}\n\n/**\n * A closed day for \"Skip closed days\" (PRD 03, decision P12): a closed\n * weekday (no business hours), a practice closure, a public holiday\n * unless the practice stays open on holidays, or an absence of the\n * chosen operator. The closure and holiday read is the host's own\n * `practiceClosedOn`, the one the grid wash and the booking refusal use,\n * so the series and the calendar never disagree. Chair-only bookings\n * check the practice alone.\n */\nexport function isUnbookableDay(\n date: Date,\n operatorId: string | null | undefined,\n data: CalendarData,\n): boolean {\n const dateIso = localIsoDate(date);\n if (isPracticeClosedDay(dateIso, data)) return true;\n if (!operatorId) return false;\n return (data.operatorAbsences[operatorId] ?? []).includes(dateIso);\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 | null | undefined,\n data: CalendarData,\n): { dates: Date[]; skipped: number } {\n const step = RECURRENCE_STEP[rule.frequency];\n const interval = Math.max(rule.interval ?? 1, 1);\n /* Weekday codes only mean something to a weekly or monthly rule. */\n const custom =\n rule.byDay?.length &&\n (rule.frequency === 'weekly' || rule.frequency === 'monthly')\n ? customCandidates(start, rule)\n : null;\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 let candidate: Date;\n if (custom) {\n const next = custom.next();\n if (next.done) break;\n candidate = next.value;\n } else {\n /* Calendar days, not 24-hour steps: 09:00 stays 09:00 across a\n daylight-saving change. */\n candidate = new Date(start);\n if (step.days) {\n candidate.setDate(start.getDate() + n * step.days * interval);\n } else {\n candidate = addMonthsClamped(start, n * (step.months ?? 1) * interval);\n }\n }\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 /** The Custom rule's step and weekdays, as `EditorRecurrence` carries\n * them. Absent for a plain rule. */\n interval?: number;\n byDay?: readonly RecurrenceByDay[];\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 /** Changed on its own: the occurrence is a plain appointment for edit\n * and move (no scope question, only it changes). Delete still offers\n * the three scopes. The host sets it; the kit never infers it. */\n detached?: boolean;\n}\n\nexport interface EditorDraft {\n editEventId?: string;\n /** The save carries the whole appointment (rule B23): an empty field is\n * sent as empty, never left out. `null` = no patient (cleared or never\n * chosen); absent only while the patient is locked and cannot change. */\n patientId?: string | null;\n isTelehealth: boolean;\n date: Date;\n time: { hours: number; minutes: number };\n durationMin: number;\n /** `null` = None: clear the operator. */\n operatorId?: string | null;\n /** `null` = None: clear the chair. */\n chairId?: string | null;\n colorHex: string;\n /** The description. Always sent when the editor offers it: an emptied one is `''` (rule B23), never left out. */\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 /** Always sent: `false` turns all day off. */\n allDay?: boolean;\n /** The waiting-list tick, on create and on edit. `false` on an edit of\n * an appointment in the list removes its entry. Absent when the editor\n * does not offer the tick. */\n addToWaitingList?: boolean;\n /** The two reminder ticks. Always sent on a create; on an edit sent when\n * the host passed the saved tick in the prefill or the user changed it,\n * otherwise omitted and the stored value stands. `false` also when no\n * patient is chosen or the patient cannot take the channel. */\n emailReminder?: boolean;\n smsReminder?: boolean;\n /** Sent once the editor shows the question (on an edit only when the\n * prefill carried it or the user answered); `unknown` until the user or\n * `proposeFirstVisit` answers. */\n firstVisit?: FirstVisitAnswer;\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 /** The archive the appointment is saved in. A new one gets the answer to\n * \"Global or Archive\" (absent for Global); an edit gets the row's own. */\n archiveId?: string;\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 /* Carried through so a host with no `loadAppointmentDetails` — which\n never sets `detailsMode`, and seeds the editor straight from this\n prefill instead — still routes a task row to the task editor and\n not the appointment editor underneath it. */\n isTask: row.event.isTask,\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. The 10 and 20 minute\n grids snap to their own lanes: 15 minutes would miss a 10 minute slot\n and drift off a 20 minute line. */\nexport const DRAFT_SNAP = '00:15';\n\nexport const snapForSlot = (slotDuration: string): string =>\n slotDuration === '00:10' || slotDuration === '00:20'\n ? slotDuration\n : DRAFT_SNAP;\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. It starts empty (\"none picked\"): an\n * existing appointment keeps its stored colour, a new one carries only a\n * colour the hand-off already held. The care's colour is worked out at\n * draw time (`drawnRowColors`), never written on create.\n */\nexport function initialEditorColor(prefill: EditorPrefill | undefined): string {\n return prefill?.colorHex ?? '';\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/**\n * The colours a row is DRAWN with under \"Colour by\". Worked out per draw\n * and never stored: an empty result leaves the card on its stored colour,\n * which is also what a row falls back to when the association has no\n * colour for it. `appointment` shows the stored colour, or the care's when\n * none was picked. A colour that replaces the stored one takes its own\n * ink, so a stale `textColor` never lands on the new surface.\n */\nexport function drawnRowColors(\n row: Pick<CalendarRow, 'event' | 'operatorId' | 'chairId' | 'cares'>,\n association: ColorAssociation,\n data: CalendarData,\n statusColours?: StatusColours | null,\n): Pick<CalendarEvent, 'backgroundColor' | 'textColor' | 'borderColor'> {\n if (row.event.isTask) return {};\n const stored = row.event.backgroundColor;\n const ctx = {\n operatorId: row.operatorId,\n chairId: row.chairId,\n cares: row.cares,\n };\n const status = row.event.status;\n const colour =\n association === 'appointment'\n ? stored\n ? undefined\n : associationColor('care', ctx, data)\n : association === 'status'\n ? status\n ? statusColours?.[status]\n : undefined\n : associationColor(association, ctx, data);\n if (!colour || colour.toLowerCase() === stored?.toLowerCase()) return {};\n const swatch = (data.appointmentPalette ?? GOOGLE_CALENDAR_PALETTE).find(\n (candidate) => candidate.hex.toLowerCase() === colour.toLowerCase(),\n );\n /* Operator and chair colours are host data with no swatch of their\n own, so their ink is derived from the colour, never assumed. */\n return {\n backgroundColor: colour,\n textColor: swatch?.textColor ?? bannerTextColor(colour),\n borderColor: undefined,\n };\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/** B22: a care's length for the phases chosen. With the host's\n * `phaseShares` and a phase pick, it is the sum of the picked phases'\n * shares (percent) of `base`; with no shares, no pick, or shares that\n * name none of the picked phases, it is `base` whole. */\nexport function careLengthForPhases(\n care: Pick<CalendarCare, 'phaseShares'>,\n base: number,\n picked?: readonly string[],\n): number {\n const shares = care.phaseShares;\n if (!shares || !picked || picked.length === 0) return base;\n const percent = picked.reduce((sum, phase) => sum + (shares[phase] ?? 0), 0);\n return percent > 0 ? Math.round((base * percent) / 100) : base;\n}\n\n/** What a link implies for the form (platform `_getAppointmentDuration`,\n * `_getColorIdFromCarePlanEntry` / `_getColorIdFromPriceList`): the\n * summed duration (each line's phases counted by share, B22), the FIRST\n * 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: careLengthForPhases(\n care,\n entry.durationMin ?? care.durationMin,\n link.phasesByEntry?.[entry.id],\n ),\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: careLengthForPhases(care, care.durationMin, item.phases),\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/** 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/** 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 ?? undefined) !== 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 ?? undefined) !== prev.operatorId)\n fields.push('operator');\n if ((draft.chairId ?? undefined) !== 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 /** Wins over `billed`; `'reversed'` is not locked. */\n billing?: TreatmentBilling;\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. */\ntype StatusChip = {\n variant: (typeof APPOINTMENT_STATUS_BADGE_VARIANT)[CalendarEventStatus];\n tone: WorkflowStatusTone;\n Icon: (typeof APPOINTMENT_STATE_WORKFLOW)[CalendarEventStatus]['Icon'];\n};\nconst statusChip = (status: CalendarEventStatus): StatusChip => ({\n variant: APPOINTMENT_STATUS_BADGE_VARIANT[status],\n tone: APPOINTMENT_STATE_WORKFLOW[status].tone,\n Icon: APPOINTMENT_STATE_WORKFLOW[status].Icon,\n});\nexport const STATUS_CHIP: Record<CalendarEventStatus, StatusChip> = {\n confirmed: statusChip('confirmed'),\n waiting: statusChip('waiting'),\n in_care: statusChip('in_care'),\n done: statusChip('done'),\n cancelled: statusChip('cancelled'),\n absent: statusChip('absent'),\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/** The finder's length with no care chosen (the old finder's DEFAULT_DURATION). */\nexport const FREE_SLOT_DEFAULT_DURATION_MIN = 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/** A `YYYY-MM-DD` page-address day as a local midnight, or the day of\n * `fallbackNowIso` when the text is not a real calendar day (a hand-edited\n * or stale address such as `garbage` or `2026-02-31`). */\nexport function parseIsoDate(iso: string, fallbackNowIso: string): Date {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(iso);\n if (match) {\n const [year, month, day] = [+match[1], +match[2], +match[3]];\n const date = new Date(year, month - 1, day);\n if (\n date.getFullYear() === year &&\n date.getMonth() === month - 1 &&\n date.getDate() === day\n ) {\n return date;\n }\n }\n const now = new Date(fallbackNowIso);\n return new Date(now.getFullYear(), now.getMonth(), now.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 /** The patient's yearly number; absent under privacy or when the host\n * passes none. */\n yearlyNumber?: string;\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/** 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 yearlyNumber: !privacy ? patient?.yearlyNumber || undefined : undefined,\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/** Characters per wrapped line of the name in the 192px patient column. */\nexport const PRINT_PATIENT_WRAP_CHARS = 20;\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 name and its bracketed yearly number wrap inside the patient\n column; the booked-online notice takes two more lines. */\n const nameLength =\n row.patientName.length +\n (row.yearlyNumber ? row.yearlyNumber.length + 3 : 0);\n const patientLines =\n Math.max(1, Math.ceil(nameLength / PRINT_PATIENT_WRAP_CHARS)) +\n row.phones.length +\n (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 closed, in words — shared by the grid's warnings 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\nexport interface AvailabilitySlotCell extends AvailabilityRange {\n /** Distinct chair x operator combinations sharing this exact\n * start + duration (+ resource column, on a resource axis). */\n optionCount: number;\n /** Distinct finder answers in this cell (chair, operator, care and device\n * all counted), so a click books straight away only when it is 1. */\n slotCount: number;\n}\n\n/**\n * One cell per DISTINCT start + duration, not a merged band: the grid\n * projection (\"Show in calendar\") highlights individual bookable slots\n * rather than one filled range spanning everything free. On `'none'` the\n * key is the slot's own start + duration, deduped across every chair x\n * operator pair; on a resource axis the key also carries the resource, so\n * two touching slots in the same column stay two cells, never merged into\n * one (unlike `mergeAvailabilityRanges`). `buildFreeBands` is untouched —\n * the finder's own list still unions by day, this is grid painting only.\n */\nexport function buildFreeSlotCells(\n slots: readonly CalendarFreeSlot[],\n axisKind: 'none' | 'chair' | 'operator',\n): AvailabilitySlotCell[] {\n const groups = new Map<\n string,\n {\n start: Date;\n end: Date;\n resourceId?: string;\n combos: Set<string>;\n answers: Set<string>;\n }\n >();\n for (const slot of slots) {\n if (\n !Number.isFinite(slot.start.getTime()) ||\n !Number.isFinite(slot.durationMin) ||\n slot.durationMin <= 0\n )\n continue;\n const resourceId =\n axisKind === 'operator'\n ? slot.operatorId\n : axisKind === 'chair'\n ? slot.chairId\n : undefined;\n const startMs = slot.start.getTime();\n const endMs = startMs + slot.durationMin * 60000;\n if (!Number.isFinite(endMs)) continue;\n const groupKey = `${resourceId ?? ''}:${startMs}:${endMs}`;\n const combo = JSON.stringify([slot.chairId, slot.operatorId]);\n const answer = JSON.stringify([\n slot.chairId,\n slot.operatorId,\n slot.careId,\n slot.medicalDeviceId,\n ]);\n const existing = groups.get(groupKey);\n if (existing) {\n existing.combos.add(combo);\n existing.answers.add(answer);\n } else\n groups.set(groupKey, {\n start: new Date(startMs),\n end: new Date(endMs),\n resourceId,\n combos: new Set([combo]),\n answers: new Set([answer]),\n });\n }\n return [...groups.entries()]\n .map(([groupKey, group]) => ({\n key: groupKey,\n start: group.start,\n end: group.end,\n optionCount: group.combos.size,\n slotCount: group.answers.size,\n ...(group.resourceId ? { resourceId: group.resourceId } : {}),\n }))\n .sort((a, b) => a.start.getTime() - b.start.getTime());\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 type { CalendarData } from './calendar.data';\nimport {\n type CalendarPatient,\n type CalendarWaitingEntry,\n type PatientChannelState,\n type PatientRef,\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 DISPLAY_READERS,\n readDisplayField,\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 seven 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. Settings is the toolbar button's panel (P36): it takes\n the rail in place of the open tool, as the editor does. Lives here\n rather than beside the workspace so the surface can read it without\n 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 settings: 'settings',\n} as const;\n\n/** One of the workspace rail's seven 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 WORKSPACE_TOOL.settings,\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. Settings is forced in too: the kit\n * backs it itself and the toolbar button needs somewhere to open. An id\n * 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 available.add(WORKSPACE_TOOL.settings);\n return available;\n}\n\nconst WORKSPACE_TOOL_IDS: ReadonlySet<string> = new Set(ALL_WORKSPACE_TOOLS);\n\n/** Whether `id` is one of the built-in rail tools. */\nexport function isWorkspaceToolId(id: string): id is CalendarWorkspaceToolId {\n return WORKSPACE_TOOL_IDS.has(id);\n}\n\n/** Why a host tool was left off the rail. */\nexport type ExtraToolRejection = 'reserved' | 'duplicate' | 'empty';\n\n/** The host tools the rail can carry, in the host's order. Built-in ids are\n * reserved even when withheld, a repeated id keeps its first tool, an empty\n * id is dropped, and nothing throws: a host mistake must not sink the page. */\nexport function resolveExtraTools<T extends { readonly id: string }>(\n requested: readonly T[],\n): { tools: T[]; rejected: { id: string; reason: ExtraToolRejection }[] } {\n const tools: T[] = [];\n const rejected: { id: string; reason: ExtraToolRejection }[] = [];\n const seen = new Set<string>();\n for (const tool of requested) {\n /* Typed as a string, but a plain-JS host can hand in anything. */\n const id: unknown = tool?.id;\n if (typeof id !== 'string' || id.trim() === '') {\n rejected.push({ id: typeof id === 'string' ? id : '', reason: 'empty' });\n } else if (isWorkspaceToolId(id)) {\n rejected.push({ id, reason: 'reserved' });\n } else if (seen.has(id)) {\n rejected.push({ id, reason: 'duplicate' });\n } else {\n seen.add(id);\n tools.push(tool);\n }\n }\n return { tools, rejected };\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/**\n * Where the calendar went, handed to the host after every navigation so it\n * can keep the view and the date in the page address. `view` and `axis`\n * round-trip: pass `view` back as `initialView` and `axis` as\n * `initialDisplay.resourceKind`. `axis` is left out where the column axis\n * does not apply (Month, or a calendar archive session), so restoring it\n * never overwrites the user's remembered axis.\n */\nexport interface CalendarViewChange {\n view: WorkspaceViewId;\n /** The day the grid is on, as a local `YYYY-MM-DD`. */\n date: string;\n axis?: 'chair' | 'operator' | 'none';\n}\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/** The days a user who never chose any hides: Sunday. Reset to defaults\n * returns here too. */\nexport const DEFAULT_HIDDEN_DAYS: readonly number[] = [0];\n\n/** The old \"Show weekends\" switch as the days it hides. A remembered\n * `showWeekends: false` maps to Sunday and Saturday hidden. */\nexport function weekendHiddenDays(showWeekends: boolean): number[] {\n return showWeekends ? [] : [0, 6];\n}\n\n/** The seven weekdays as `Date#getDay()` numbers, Monday first. */\nexport const WEEK_DAYS_MONDAY_FIRST: readonly number[] = [1, 2, 3, 4, 5, 6, 0];\n\n/** The user's hidden weekdays (0 Sunday to 6 Saturday, the platform's\n * `hiddenDays`), sorted. Anything else, or all seven days hidden (the grid\n * needs one), is not a valid choice: undefined, so the caller falls back. */\nexport function readHiddenDays(raw: unknown): number[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const days = new Set<number>();\n for (const day of raw) {\n if (!Number.isInteger(day) || day < 0 || day > 6) return undefined;\n days.add(day as number);\n }\n return days.size >= 7 ? undefined : [...days].sort((a, b) => a - b);\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/** The operator filter as groups with a tri-state each, or one flat list. */\nexport type OperatorListMode = 'grouped' | 'flat';\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 /** Keep cancelled appointments on the grid, faded and not draggable.\n * Off by default (HTP-6568): cancelled appointments stay hidden. */\n showCancelled: boolean;\n /** Optional for saved preferences and older consumers. @default 'grouped' */\n operatorListMode?: OperatorListMode;\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 /* The My calendar defaults follow the business-rules table (11 Nov):\n Extended hours, no care text on cards, coloured by care. A saved\n value always wins over these. */\n window: 'extended',\n careDescription: 'off',\n colorAssociation: 'care',\n defaultDurationMin: 30,\n operatorNameDisplay: 'initials',\n chairNameDisplay: 'full',\n mapsLink: false,\n showCancelled: false,\n operatorListMode: 'grouped',\n};\n\nconst readOperatorNameDisplay = readEnum<OperatorNameDisplay>([\n 'full',\n 'initials',\n]);\nconst readChairNameDisplay = readEnum<ChairNameDisplay>(['full', 'short']);\nconst readOperatorListMode = readEnum<OperatorListMode>(['grouped', 'flat']);\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 /* Per field over the workspace defaults, so a saved shape that does not\n name a field gets the table's default and one that names it keeps it. */\n const next: WorkspaceDisplaySettings = { ...DEFAULT_WORKSPACE_DISPLAY };\n for (const field of Object.keys(DISPLAY_READERS) as Array<\n keyof DisplaySettings\n >) {\n readDisplayField(next, field, source[field]);\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 const showCancelled = readBoolean(source.showCancelled);\n if (showCancelled !== undefined) next.showCancelled = showCancelled;\n const listMode = readOperatorListMode(source.operatorListMode);\n if (listMode !== undefined) next.operatorListMode = listMode;\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 /** The treatment consents the user left ticked: the host creates and\n * sends them with this save (HTP-3395). Absent = none ticked, or the\n * host offered none. They belong to the appointment the editor shows.\n * On a series edit `recurringSaveMode` arrives beside them: whether the\n * other visits get a consent of their own is the host's call (a new\n * consent every visit). Failure: reject `onSave` for the whole save, so\n * nothing changes and the editor shows the error; the kit has no\n * partial-failure state. */\n consentIds?: string[];\n /** The medical device chosen for each care that needs one (B9), when the\n * host passed `medicalDevicesForCares`. One entry per care: a care that\n * appears twice in the visit uses the same device. A care with no free\n * device is left out, and the save still goes ahead. The host stores\n * the assignment with the appointment. */\n medicalDevices?: MedicalDeviceAssignment[];\n}\n\n/** One medical device a care can use. `busy` = taken at the visit's time. */\nexport interface MedicalDeviceOption {\n id: string;\n name: string;\n busy?: boolean;\n}\n\n/** The devices one care needs, as the host sees them for a given slot. */\nexport interface CareDeviceChoice {\n careId: string;\n options: readonly MedicalDeviceOption[];\n /** The host's pick for this slot: the saved device on an edit that has\n * not moved, else the free device it would assign. */\n assignedId?: string;\n}\n\n/** What the host is asked: the cares and the slot they would use. */\nexport interface MedicalDeviceQuery {\n careIds: readonly string[];\n start: Date;\n durationMin: number;\n /** Set on an edit, so the visit's own device does not count as busy. */\n eventId?: string;\n}\n\n/** A device chosen for a care, as saved with the appointment. */\nexport interface MedicalDeviceAssignment {\n careId: string;\n deviceId: string;\n}\n\n/** The device a care ends on: the user's pick while it is still on offer\n * and free, else the host's pick if that is free too. A busy device is\n * never returned, even as the host's pick: `undefined` when none is free. */\nexport function effectiveDeviceId(\n choice: CareDeviceChoice,\n picked: string | undefined,\n): string | undefined {\n const free = (id: string | undefined): string | undefined =>\n id && choice.options.some((o) => o.id === id && !o.busy) ? id : undefined;\n return free(picked) ?? free(choice.assignedId);\n}\n\n/** Delete confirmation choices — the recurring scope and, for any\n * occurrence of a price-list series, the care-plan cleanup. */\nexport interface DeleteOptions {\n scope: RecurringScope;\n removeFromCarePlan?: boolean;\n /** The deleted appointment's own archive, when it has one. */\n archiveId?: string;\n}\n\n/** Whether an edit or a move on this row asks the scope question: it\n * belongs to a series and was not changed on its own. Delete does not\n * use it: a changed occurrence still offers the three scopes there. */\nexport function rowAsksScope(row: CalendarRow | null | undefined): boolean {\n return Boolean(row?.series && !row.series.detached);\n}\n\n/** One answer to the scope question, for the host's analytics. */\nexport interface RecurringScopeChosen {\n action: 'edit' | 'move' | 'delete';\n scope: RecurringScope;\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/** Sign mode starts on \"not now\" (rule B10): staff pick SMS or email on\n * purpose, even when the patient could take either. */\nexport function defaultSignMode(): RequiredDocsSignMode {\n return 'none';\n}\n\n/* The address line, its label and the map search moved to the component\n layer with the details panel; re-exported so importers keep their paths. */\nexport {\n patientAddressLabel,\n patientAddressLine,\n patientMapsUrl,\n} from '../../components/_shared/appointment-format';\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 ink helper lives with the draw-time colours in `calendar.model.ts`;\n re-exported so importers keep their paths. */\nexport { bannerTextColor } from './calendar.model';\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 * The clicked slot sets the date and time only: the copy keeps the\n * SOURCE chair and operator, whichever column was clicked (rule C5).\n * An all-day source stays all-day on the target date. */\nexport function copyRowAt(\n source: CalendarRow,\n target: { start: Date },\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 event: CalendarEvent = {\n ...source.event,\n id,\n start: startValue,\n end: endValue,\n resourceId: undefined,\n isRecurring: undefined,\n isRecurrenceParent: undefined,\n };\n return {\n event,\n chairId: source.chairId,\n operatorId: source.operatorId,\n description: source.description,\n cares: withTreatments ? source.cares : undefined,\n careLink: withTreatments ? source.careLink : undefined,\n series: undefined,\n /* A copy stays in the archive it was copied from (rule H7). */\n ...(source.archiveId ? { archiveId: source.archiveId } : {}),\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 ?? undefined,\n operatorId: draft.operatorId ?? undefined,\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 || undefined,\n isTelehealth: draft.isTelehealth || undefined,\n operatorId: draft.operatorId ?? undefined,\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' | 'day' | 'chair' | 'operator'> {\n const out: Array<'range' | 'day' | '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('day');\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/* Backlog queue — every appointment in the loaded range that is still */\n/* missing a patient, an operator or (where the practice has chairs) */\n/* a chair, whatever its origin. Was the platform's \"Prenotazioni */\n/* online da controllare\" query (online-only); decision 2026-09-22 */\n/* widened it to desk-created gaps too, since a chair is optional on */\n/* the platform and a desk slot can be created with no patient. */\n/* ------------------------------------------------------------------ */\n\n/**\n * True when a row still needs completing before it is a real, workable\n * appointment: no patient record, no operator, or — only where the\n * practice actually has chairs — no chair. Tasks never qualify (the\n * caller already drops them from `rows`, but a defensive check costs\n * nothing). Origin (online vs. desk-created) is irrelevant: a gap is a\n * gap regardless of how the appointment was created.\n */\nexport function appointmentNeedsCompletion(\n row: CalendarRow,\n data: CalendarData,\n): boolean {\n const event = row.event;\n if (event.isTask) return false;\n if (event.status === 'cancelled') return false;\n if (event.hasUnassignedPatient === true) return true;\n if (!row.operatorId) return true;\n if (data.chairs.length > 0 && !row.chairId) return true;\n return false;\n}\n\n/**\n * The backlog queue: every row in `rows` that still needs a patient, an\n * operator or a chair. Mirrors the platform's alert-strip query in\n * spirit, but is no longer scoped to online bookings or to a 30-day\n * window — the caller already hands in only the rows in the loaded\n * range, and a desk-created gap is exactly as real as an online one.\n */\nexport function onlineBookingsToCheck(\n rows: readonly CalendarRow[],\n data: CalendarData,\n): CalendarRow[] {\n return rows.filter((row) => appointmentNeedsCompletion(row, data));\n}\n\n/**\n * One row of the backlog queue (formerly the platform's \"Prenotazioni\n * online\" page, which Increment 1 hosts in the rail instead of sending\n * the user to a separate page). Columns mirror it: when it was booked\n * (a desk-created slot carries no `bookedAt` and groups under its own\n * appointment date instead), what was asked for, whether it was paid\n * online, and what is still missing before it is a real 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 * Null for a desk-created slot, which has no booking record. */\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 /** True only where the practice has chairs at all — see\n * `appointmentNeedsCompletion`. */\n needsChair: boolean;\n /** Badge fact, not a filter: origin no longer decides membership, but\n * the card still says where the appointment came from. */\n bookedOnline: 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 needsChair: data.chairs.length > 0 && !row.chairId,\n bookedOnline: event.isBookedOnline === true,\n isNew:\n bookedAt && lastSeenMs != null ? bookedAt.getTime() >= lastSeenMs : false,\n };\n}\n\n/** The three completion gaps a backlog card can show, in filter order.\n * Chair is only ever offered when the practice has chair resources. */\nexport type BacklogGap = 'patient' | 'operator' | 'chair';\n\n/** All three switches on by default — the uncontrolled starting point\n * for a host that does not persist the filter state itself. */\nexport const DEFAULT_BACKLOG_FILTERS: Readonly<Record<BacklogGap, boolean>> = {\n patient: true,\n operator: true,\n chair: true,\n};\n\n/** Applies the header's three switches to an already-built view list. A\n * view is kept when it carries at least one gap left switched on — an\n * appointment missing only a patient still shows with \"Senza operatore\"\n * and \"Senza poltrona\" off, since it still needs a patient. */\nexport function filterBacklogViews(\n views: readonly BookingRowView[],\n filters: Readonly<Record<BacklogGap, boolean>>,\n): BookingRowView[] {\n return views.filter(\n (view) =>\n (filters.patient && view.needsPatient) ||\n (filters.operator && view.needsOperator) ||\n (filters.chair && view.needsChair),\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 { ChevronDown, Clock, Stethoscope } from 'lucide-react';\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from '../../components/collapsible';\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\n/** Past this many people in the practice, the live band starts closed. */\nconst LIVE_BAND_OPEN_UP_TO = 3;\n\nexport function UpcomingAppointmentsPanel({\n rows,\n locale,\n privacy,\n onOpenAppointment,\n stateSinceByEventId,\n loading = false,\n}: UpcomingAppointmentsPanelProps) {\n const { t } = useTranslation('ui');\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 /* An accordion row: it sits in the timeline's fixed header, so a busy\n practice (12 people in) used to fill the panel and leave the day\n list a sliver. It starts closed past three people, and when open\n it is capped at 40% of the panel and scrolls on its own. */\n <Collapsible\n defaultOpen={live.length <= LIVE_BAND_OPEN_UP_TO}\n className=\"ds:flex ds:max-h-[45%] ds:min-h-0 ds:shrink-0 ds:flex-col ds:border-b ds:border-[color:var(--card-border)]\"\n >\n <section\n data-component=\"calendar-upcoming-live-band\"\n aria-labelledby=\"calendar-upcoming-live-heading\"\n className=\"ds:flex ds:min-h-0 ds:flex-col ds:gap-[var(--spacing-2xs)] 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:text-[color:var(--info-foreground)]\"\n >\n <CollapsibleTrigger className=\"type-eyebrow ds:group ds:flex ds:text-[color:var(--info-foreground)] ds:w-full ds:cursor-pointer ds:items-center ds:gap-[var(--spacing-2xs)] ds:rounded-[var(--radius-sm)] ds:[min-block-size:var(--min-target-size)] ds:text-start ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-[color:var(--ring)]\">\n <Stethoscope\n aria-hidden=\"true\"\n className=\"ds:size-3.5 ds:shrink-0\"\n />\n <span className=\"ds:min-w-0 ds:flex-1\">\n {t('calendarWorkspace.inc1.rail.upcomingLiveTitle')}\n </span>\n <Badge size=\"sm\" variant=\"neutral\">\n {live.length}\n </Badge>\n <ChevronDown\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:shrink-0 ds:transition-transform ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none ds:group-data-[state=open]:rotate-180\"\n />\n </CollapsibleTrigger>\n </h3>\n <CollapsibleContent className=\"ds:min-h-0 ds:overflow-y-auto\">\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 ds:pb-[var(--spacing-2xs)]\"\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(\n 'calendarWorkspace.inc1.rail.upcomingLiveElapsed',\n {\n state: stateLabel,\n elapsed,\n },\n )\n : stateLabel,\n icon: <StateIcon aria-hidden=\"true\" />,\n tone: workflow.tone,\n }}\n />\n </button>\n </li>\n );\n })}\n </ul>\n </CollapsibleContent>\n </section>\n </Collapsible>\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","/**\n * The calendar's TASK editor: the form the toolbar's \"New task\" member and\n * an `isTask` grid row open, in place of the appointment editor. A thin\n * `CalendarData` adapter over the published `TaskEditor`, which holds every\n * rule (one counterpart, withheld-not-disabled lists and seams, the Done\n * switch, the delete confirmation). This file only maps the calendar's\n * lists onto its props.\n *\n * `privacyMode=\"mask\"`: the grid route keeps the note visible under privacy\n * and masks the linked patient, as it always has. The published default,\n * the privacy notice, is for hosts that open a stored task on their own.\n */\nimport { useCallback, useMemo } from 'react';\nimport { TaskEditor } from '../../components/task-editor';\nimport { useCalendarData } from './calendar.data';\nimport type { CalendarTask, TaskDraft } from './calendar.types';\n\nexport interface CalendarTaskEditorProps {\n mode: 'create' | 'edit';\n /** Edit mode: which task to load via `loadTask`. */\n taskId?: string;\n /** Create mode: the date and time to prefill, the grid's selection or\n * now. Local wall-clock, never re-read after mount. */\n initialDate?: Date;\n onCancel: () => void;\n /** Fires once a create or update lands. */\n onSaved?: (task: CalendarTask) => void;\n onDeleted?: (id: string) => void;\n /** Must resolve WITH the saved record: the host assigns the new id. */\n onCreateTask?: (draft: TaskDraft) => Promise<CalendarTask>;\n /** Full re-send, not a patch. Resolves with nothing. */\n onUpdateTask?: (id: string, draft: TaskDraft) => Promise<void>;\n onDeleteTask?: (id: string) => Promise<void>;\n onSetTaskDone?: (id: string, done: boolean) => Promise<void>;\n loadTask?: (id: string) => Promise<CalendarTask>;\n /** Withholds every write control and disables the fieldset. */\n readOnly?: boolean;\n /** Privacy mode: the linked patient's identity is masked, never the fact\n * that one is linked. */\n privacy?: boolean;\n}\n\nexport function CalendarTaskEditor(props: CalendarTaskEditorProps) {\n const data = useCalendarData();\n /* The calendar names its rows `name` and `title`; the editor takes one\n `label`. Memoised so the pickers keep their options between renders. */\n const companies = useMemo(\n () => data.companies?.map((c) => ({ id: c.id, label: c.name })),\n [data.companies],\n );\n const operators = useMemo(\n () => data.operators.map((o) => ({ id: o.id, label: o.title })),\n [data.operators],\n );\n const resolvePatientLabel = useCallback(\n (patientId: string) => data.patientById(patientId)?.name,\n [data],\n );\n return (\n <TaskEditor\n {...props}\n variant=\"panel\"\n privacyMode=\"mask\"\n taskTypes={data.taskTypes}\n assignees={data.taskAssignees}\n companies={companies}\n operators={operators}\n patients={data.patients}\n searchPatients={data.searchPatients}\n resolvePatientLabel={resolvePatientLabel}\n />\n );\n}\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.\n *\n * An occurrence changed on its own: return `detached: true`. The editor\n * then skips the scope question, saves for that appointment only and\n * still offers `scopes` when the user deletes. It merges\n * `capabilitiesByScope.this` over `capabilities`, as a save for \"this\"\n * would. Return no `series` at all only when delete should not ask\n * either. The kit never infers either. */\nexport interface CalendarEditorSeries {\n /** The occurrence being edited, as a local Date on the host's wall clock. */\n occurrence: Date;\n /** Changed on its own: no scope question on edit (its `this` capabilities\n * apply), the scopes on delete. */\n detached?: boolean;\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: true for any\n * occurrence of a price-list series, not only the first (decision P15). */\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('ui');\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 || undefined,\n isTelehealth: prefill.isTelehealth,\n hasUnassignedPatient: !prefill.patientId,\n },\n };\n}\n","/* The calendar's delete confirm: the alert dialog the editor and the\n details panel both open. A series member asks which appointments; a\n price-list recurrence parent asks about its care-plan lines. The host's\n scopes are rendered exactly as given. */\nimport { useRef, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Trash2 } from 'lucide-react';\nimport { Alert } from '../../components/alert';\nimport { Button } from '../../components/button';\nimport { Dialog } from '../../components/dialog';\nimport { Radio, RadioGroup } from '../../components/radio-group';\nimport {\n RECURRING_SCOPE_LABEL_KEY,\n type DeleteOptions,\n type RecurringScope,\n} from './calendar-workspace.model';\n\nexport interface CalendarDeleteConfirmProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** Series scopes in display order. Absent = not a series member. */\n scopes?: readonly RecurringScope[];\n /** Ask whether to remove the treatments from the care plan. */\n offersCarePlanCleanup?: boolean;\n /** The click that confirms. A synchronous handler closes the dialog at\n * once. A promise keeps it open and the button busy until it settles:\n * a rejection shows its message here and deletes nothing. */\n onConfirm: (options: DeleteOptions) => void | Promise<void>;\n /** Where focus lands when the dialog closes without a delete. Called\n * with the close event: `preventDefault()` takes focus yourself. */\n onCloseAutoFocus?: (event: Event) => void;\n}\n\nconst key = (suffix: string): string => `calendarWorkspace.editor.${suffix}`;\n\n/* Its own component so each opening starts from \"this appointment\" and\n \"keep\": the content unmounts when the dialog closes. */\nfunction DeleteConfirmContent({\n scopes,\n offersCarePlanCleanup,\n onConfirm,\n}: Pick<\n CalendarDeleteConfirmProps,\n 'scopes' | 'offersCarePlanCleanup' | 'onConfirm'\n>) {\n const { t } = useTranslation('ui');\n const [scope, setScope] = useState<RecurringScope>('this');\n const [removeFromCarePlan, setRemoveFromCarePlan] = useState(false);\n const [pending, setPending] = useState(false);\n const [failure, setFailure] = useState<string>();\n const choice = scopes?.includes(scope) ? scope : (scopes?.[0] ?? 'this');\n const confirm = async (): Promise<void> => {\n setFailure(undefined);\n setPending(true);\n try {\n await onConfirm({\n scope: choice,\n removeFromCarePlan: offersCarePlanCleanup\n ? removeFromCarePlan\n : undefined,\n });\n } catch (error) {\n setFailure(\n error instanceof Error && error.message.trim()\n ? error.message\n : t('emptyState.error.title'),\n );\n setPending(false);\n }\n };\n return (\n <>\n <Dialog.Header>\n <Dialog.Title>{t(key('deleteConfirmTitle'))}</Dialog.Title>\n <Dialog.Description>{t(key('deleteConfirmBody'))}</Dialog.Description>\n </Dialog.Header>\n {scopes || offersCarePlanCleanup || failure ? (\n <Dialog.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n {scopes ? (\n <RadioGroup\n label={t(key('deleteScope'))}\n value={choice}\n onValueChange={(v) => setScope(v as RecurringScope)}\n >\n {scopes.map((option) => (\n <Radio\n key={option}\n value={option}\n label={t(key(RECURRING_SCOPE_LABEL_KEY[option]))}\n />\n ))}\n </RadioGroup>\n ) : null}\n {offersCarePlanCleanup ? (\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 {failure ? (\n <Alert variant=\"error\">\n <Alert.Description>{failure}</Alert.Description>\n </Alert>\n ) : null}\n </Dialog.Body>\n ) : null}\n <Dialog.Footer divider>\n <Dialog.Close asChild>\n <Button intent=\"outline\" disabled={pending}>\n {t(key('deleteCancel'))}\n </Button>\n </Dialog.Close>\n <Button\n intent=\"destructive\"\n startIcon={<Trash2 aria-hidden=\"true\" />}\n loading={pending}\n onClick={confirm}\n >\n {t(key('deleteConfirm'))}\n </Button>\n </Dialog.Footer>\n </>\n );\n}\n\nexport function CalendarDeleteConfirm({\n open,\n onOpenChange,\n scopes,\n offersCarePlanCleanup,\n onConfirm,\n onCloseAutoFocus,\n}: CalendarDeleteConfirmProps) {\n /* Escape and the overlay must not close it while the host decides. */\n const busy = useRef(false);\n return (\n <Dialog\n open={open}\n onOpenChange={(next) => {\n if (!busy.current) onOpenChange(next);\n }}\n >\n <Dialog.Content\n size=\"sm\"\n variant=\"alert\"\n onCloseAutoFocus={onCloseAutoFocus}\n >\n <DeleteConfirmContent\n scopes={scopes}\n offersCarePlanCleanup={offersCarePlanCleanup}\n onConfirm={async (options) => {\n busy.current = true;\n try {\n await onConfirm(options);\n } finally {\n busy.current = false;\n }\n onOpenChange(false);\n }}\n />\n </Dialog.Content>\n </Dialog>\n );\n}\n","/* The question asked before a document is created from one visit of a\n price-list series: this visit or all visits. The kit only asks and\n passes the answer to the host; it never marks care as done. */\nimport { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Button } from '../../components/button';\nimport { Dialog } from '../../components/dialog';\nimport { Radio, RadioGroup } from '../../components/radio-group';\n\n/** Whether the document covers the visit it was opened from or every visit. */\nexport type CalendarDocumentScope = 'visit' | 'all';\n\nexport interface CalendarDocumentScopeConfirmProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** The answer, once the user continues. */\n onConfirm: (scope: CalendarDocumentScope) => void;\n /** Where focus lands when the dialog closes. `preventDefault()` takes it. */\n onCloseAutoFocus?: (event: Event) => void;\n}\n\n/* Its own component so each opening starts again from \"this visit\". */\nfunction ScopeContent({\n onConfirm,\n}: Pick<CalendarDocumentScopeConfirmProps, 'onConfirm'>) {\n const { t } = useTranslation('ui');\n const [scope, setScope] = useState<CalendarDocumentScope>('visit');\n return (\n <>\n <Dialog.Header>\n <Dialog.Title>\n {t('calendarWorkspace.details.documentScope.title')}\n </Dialog.Title>\n <Dialog.Description>\n {t('calendarWorkspace.details.documentScope.body')}\n </Dialog.Description>\n </Dialog.Header>\n <Dialog.Body>\n <RadioGroup\n label={t('calendarWorkspace.details.documentScope.label')}\n value={scope}\n onValueChange={(v) => setScope(v as CalendarDocumentScope)}\n >\n <Radio\n value=\"visit\"\n label={t('calendarWorkspace.details.documentScope.visit')}\n />\n <Radio\n value=\"all\"\n label={t('calendarWorkspace.details.documentScope.all')}\n />\n </RadioGroup>\n </Dialog.Body>\n <Dialog.Footer divider>\n <Dialog.Close asChild>\n <Button intent=\"outline\">\n {t('calendarWorkspace.details.documentScope.cancel')}\n </Button>\n </Dialog.Close>\n <Button onClick={() => onConfirm(scope)}>\n {t('calendarWorkspace.details.documentScope.continue')}\n </Button>\n </Dialog.Footer>\n </>\n );\n}\n\nexport function CalendarDocumentScopeConfirm({\n open,\n onOpenChange,\n onConfirm,\n onCloseAutoFocus,\n}: CalendarDocumentScopeConfirmProps) {\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <Dialog.Content size=\"sm\" onCloseAutoFocus={onCloseAutoFocus}>\n <ScopeContent onConfirm={onConfirm} />\n </Dialog.Content>\n </Dialog>\n );\n}\n","/* The calendar's appointment details: an adapter over the published\n AppointmentDetailsPanel. It resolves the operator and chair labels, the\n currency and the practice clock from CalendarData, maps the notes seam\n onto the panel's notes preview, and lifts the host actions out of the\n read. The panel itself lives in components/appointment-details-panel. */\nimport {\n useEffect,\n useRef,\n useState,\n type MouseEvent,\n type ReactNode,\n} from 'react';\nimport {\n AppointmentDetailsPanel,\n parseAppointmentStartIso,\n useAppointmentDetailsRead,\n type AppointmentDetailsLoader,\n type AppointmentDetailsNotesPreview,\n type AppointmentDetailsRead,\n type AppointmentDetailsSnapshot,\n type AppointmentDocumentKind,\n DETAILS_SHORTCUT_ACTIONS,\n} from '../../components/appointment-details-panel';\nimport type { CalendarEventStatus } from '../../components/calendar';\nimport { CONTENT_ENTER_CLASS } from '../../components/skeleton';\nimport { useCalendarData } from './calendar.data';\nimport type { PatientNotesSeam } from './calendar.sheets';\nimport { CalendarDeleteConfirm } from './calendar-delete-confirm';\nimport {\n CalendarDocumentScopeConfirm,\n type CalendarDocumentScope,\n} from './calendar-document-scope-confirm';\nimport type { DeleteOptions, RecurringScope } from './calendar-workspace.model';\nimport type { CalendarHistoryEntry, CalendarPatient } from './calendar.types';\n\nexport type CalendarDocumentKind = AppointmentDocumentKind;\n\nexport type { CalendarDocumentScope };\n\n/** What the delete confirm asks for this appointment. Same meaning as\n * `CalendarEditorSeries`: `scopes` are the ones the host can honour, in\n * display order, rendered exactly as given. */\nexport interface CalendarDetailsSeries {\n scopes: readonly RecurringScope[];\n /** Offer the care-plan clean-up question. */\n offersCarePlanCleanup?: boolean;\n}\n\n/** A panel action the user completed, for the host's analytics. */\nexport type CalendarDetailsAction =\n | 'status'\n | 'edit'\n | 'move'\n | 'copy'\n | 'delete'\n | 'whatsapp'\n | 'task'\n | 'document'\n | 'video'\n | 'advanced-signature'\n | 'request-signature'\n | 'renew-anamnesis'\n | 'unlock-payments'\n | 'care-plan';\n\n/** One appointment occurrence as the host reads it for the details panel\n * (P-C2). An absent member renders nothing: never a zero, never an\n * empty-state claim. The read fields are AppointmentDetailsRead's; the\n * calendar adds its richer patient record and the host's actions. */\nexport interface CalendarAppointmentDetails extends Omit<\n AppointmentDetailsRead,\n 'patient' | 'history'\n> {\n /** Absent = no patient; `phones` carries every labelled number. */\n patient?: CalendarPatient;\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 /** Practice without WhatsApp: the button stays and calls this to open\n * the host's buy flow. Ignored when `onWhatsApp` or `whatsappUrl` is\n * set; absent = no button. */\n onBuyWhatsApp?: () => void;\n /** Server-built link to the task page, same tab; absent = not offered. */\n createTaskUrl?: string;\n /** Opens the host's signature request (SMS, email, WhatsApp or this\n * device) for this appointment. Shown beside the documents to sign, only\n * while one is still to sign; absent = withheld. Fire and forget: the\n * panel does not wait for it. */\n onRequestSignature?: () => void;\n /** The old pop-over's shortcuts: each is withheld when absent, and the\n * host decides whether it applies (the practice has no online payments,\n * the plan is linked). Links open in the same tab. This one is advanced\n * e-signature setup for this patient, offered with the \"not set up\"\n * warning when the patient has at least one required document, signed\n * or not. */\n advancedSignatureUrl?: string;\n /** The patient's record on the anamnesis section; beside the expired\n * badge. */\n renewAnamnesisUrl?: string;\n /** The payment requests page; beside the money chips. */\n unlockPaymentsUrl?: string;\n /** The linked care plan; beside the plan line. */\n carePlanUrl?: string;\n /** Host owns permissions and creation/navigation. Independent of appointment readOnly. */\n documents?: {\n kinds: readonly CalendarDocumentKind[];\n /** The kinds that first ask \"this visit or all visits\". Set only for\n * an occurrence of a price-list series; absent, no kind asks. */\n seriesScope?: { kinds: readonly CalendarDocumentKind[] };\n /** `options` carries the answer, only for a kind in `seriesScope`. */\n onCreate: (\n kind: CalendarDocumentKind,\n options?: { scope: CalendarDocumentScope },\n ) => void;\n };\n /** The appointment belongs to a series the host owns: Delete asks these\n * scopes. Absent, the calendar's own rows decide. */\n series?: CalendarDetailsSeries;\n}\n\nexport type CalendarAppointmentDetailsSnapshot =\n AppointmentDetailsSnapshot<CalendarAppointmentDetails>;\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 AppointmentDetailsLoader<CalendarAppointmentDetails>;\n\n/** The host's zone-less wall clock as a local Date; see\n * `parseAppointmentStartIso`. */\nexport const parseDetailsStartIso = parseAppointmentStartIso;\n\nexport interface CalendarDetailsHydrationProps {\n /** The occurrence to read; a new id aborts the previous read. */\n eventId: string;\n /** Keep it stable: a new function reads the occurrence again. */\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. A new\n * `load` reads the same occurrence again while the current read stays on\n * screen, so a host re-reads after a change by handing a new loader. Until\n * the first answer the panel's own shell shows the skeleton, the error with\n * Retry, or the refusal. */\nexport function CalendarDetailsHydration({\n eventId,\n load,\n children,\n}: CalendarDetailsHydrationProps) {\n /* A new loader is a new read: its identity becomes the reload key. */\n const [loader, setLoader] = useState({ load, reads: 0 });\n if (loader.load !== load) setLoader({ load, reads: loader.reads + 1 });\n const { state, retry } = useAppointmentDetailsRead({\n eventId,\n load,\n reloadKey: loader.reads,\n });\n /* The read always answers after the first paint, so the skeleton always\n shows first and the panel settles in where it stood. */\n if (state.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(state.read)}\n </div>\n );\n }\n return (\n <div\n data-component=\"calendar-details-hydration\"\n data-event-id={eventId}\n data-status={state.status}\n className=\"ds:flex ds:h-full ds:min-h-0 ds:flex-col\"\n >\n <AppointmentDetailsPanel state={state} onRetry={retry} />\n </div>\n );\n}\n\nexport interface CalendarAppointmentDetailsPanelProps {\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 /** The appointment has no patient: Assign patient is the FIRST action.\n * The host opens its own flow (the To complete one). Absent = withheld;\n * `readOnly` withholds it too. */\n onAssignPatient?: () => void;\n /** Open the patient's record: the host's navigation, given the patient\n * the panel shows. Absent = no \"Open patient record\" button. Never\n * offered with no patient or under `privacy`. Opening a record is a\n * read, so `readOnly` keeps it. */\n onOpenPatient?: (patient: CalendarPatient) => void;\n /** Sign on the practice's device, beside Request signature and only\n * while a document is still to sign. The host opens its own flow.\n * Absent = withheld. Counted as `request-signature`. */\n onSignOnDevice?: () => void;\n onEdit?: () => void;\n /** Arm a Move placement: the next slot click places the appointment. */\n onMove?: () => void;\n onCopy?: (withTreatments: boolean) => void;\n /** Delete this occurrence, after the confirm. This is how a host\n * withholds Delete: omit it (or set `readOnly`) and the panel shows none.\n * Return a promise to keep the confirm open while the host decides: a\n * rejection shows its message and deletes nothing, and the action is\n * reported only once it resolves. */\n onDelete?: (options: DeleteOptions) => void | Promise<void>;\n /** What the confirm asks: the series scopes and the care-plan clean-up.\n * Absent, it asks neither. */\n deleteConfirm?: Partial<CalendarDetailsSeries>;\n /** Delete was clicked, before the confirm. Raised once per click, even\n * if the user then cancels; `onDetailsActionUsed` hears the completion. */\n onDeleteInitiated?: () => void;\n /** An entry of Create document was picked, before the bill's \"this visit\n * or all visits\" question. Raised once per pick, even if the user then\n * cancels; `onDetailsActionUsed` hears the completion. */\n onDocumentCreateClicked?: (kind: CalendarDocumentKind) => void;\n /** Hears each completed panel action, once: a status saved, a handler\n * called, a delete confirmed, a link followed. */\n onDetailsActionUsed?: (use: { action: CalendarDetailsAction }) => 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 /** In History, say \"What changed was not recorded.\" under an edit that\n * carries no detail. Off by default. */\n noteUnrecordedEdits?: 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 shortcut links the panel renders, by their data-action. Keyed on\n * the panel's own ids, so a rename there fails to compile here. */\nconst LINK_ACTIONS: Record<string, CalendarDetailsAction> = {\n [DETAILS_SHORTCUT_ACTIONS.advancedSignature]: 'advanced-signature',\n [DETAILS_SHORTCUT_ACTIONS.renewAnamnesis]: 'renew-anamnesis',\n [DETAILS_SHORTCUT_ACTIONS.unlockPayments]: 'unlock-payments',\n [DETAILS_SHORTCUT_ACTIONS.carePlan]: 'care-plan',\n};\n\n/** The notes seam as the panel's read-only preview. */\nfunction notesPreviewOf(\n seam: PatientNotesSeam,\n patientId: string,\n): AppointmentDetailsNotesPreview {\n return {\n patientId,\n notes: seam.notes,\n /* A seam that can load and says nothing yet is loading. */\n status: seam.status ?? (seam.onLoad ? 'loading' : 'ready'),\n total: seam.total,\n onRetry: seam.onLoad ? () => seam.onLoad?.('preview') : seam.onRetry,\n };\n}\n\n/** The appointment details panel of the calendar (P-C2, P-C3): the published\n * AppointmentDetailsPanel, fed from CalendarData and the calendar's read.\n * It docks in the rail, is no dialog and asks no series scope. */\nexport function CalendarAppointmentDetailsPanel({\n details,\n patientId = details.patient?.id,\n notesSeam,\n onOpenNotes,\n readOnly = false,\n onAssignPatient,\n onOpenPatient,\n onSignOnDevice,\n onEdit,\n onMove,\n onCopy,\n onDelete,\n deleteConfirm,\n onDeleteInitiated,\n onDocumentCreateClicked,\n onDetailsActionUsed,\n onStatusChange,\n onDescriptionChange,\n mapsLink,\n noteUnrecordedEdits,\n privacy = false,\n privacyTitle,\n locale,\n}: CalendarAppointmentDetailsPanelProps) {\n const data = useCalendarData();\n const { appointment } = details;\n const [confirmingDelete, setConfirmingDelete] = useState(false);\n const [askingScopeFor, setAskingScopeFor] = useState<CalendarDocumentKind>();\n const rootRef = useRef<HTMLDivElement>(null);\n /* Closing a dialog without acting hands focus back to where its action\n lives: its own button, or the More trigger once the footer folded it\n away. The footer keeps inert measuring copies, so take the live one. */\n const returnFocusTo =\n (action: string) =>\n (event: Event): void => {\n const live = (selector: string): HTMLElement | undefined =>\n [\n ...(rootRef.current?.querySelectorAll<HTMLElement>(selector) ?? []),\n ].find((node) => !node.closest('[inert]'));\n const target =\n live(`[data-action=\"${action}\"]`) ??\n live('button[aria-haspopup=\"menu\"]:has(svg.lucide-ellipsis)');\n if (!target) return;\n event.preventDefault();\n target.focus();\n };\n const used = (action: CalendarDetailsAction): void =>\n onDetailsActionUsed?.({ action });\n /* The task and WhatsApp links are the panel's own anchors: hear them here. */\n const usedLink = (event: MouseEvent): void => {\n const link = (event.target as Element).closest<HTMLElement>(\n 'a[data-action]',\n );\n if (link?.dataset.action === 'create-task') used('task');\n if (link?.dataset.action === 'open-whatsapp') used('whatsapp');\n const followed = link?.dataset.action && LINK_ACTIONS[link.dataset.action];\n if (followed) used(followed);\n };\n const operator = data.operators.find((o) => o.id === appointment.operatorId);\n const chair = data.chairs.find((c) => c.id === appointment.chairId);\n /* The notes card needs both a seam and the patient it answers for. */\n const notesFor = notesSeam && patientId ? patientId : undefined;\n const notesShown = notesFor !== undefined && !privacy;\n /* Read the latest notes once per patient, only when the host holds none\n and only while the card shows. */\n const seamRef = useRef(notesSeam);\n seamRef.current = notesSeam;\n const hasLoader = Boolean(notesSeam?.onLoad);\n useEffect(() => {\n const current = seamRef.current;\n if (\n notesShown &&\n current &&\n current.notes.length === 0 &&\n current.status !== 'loading' &&\n current.complete !== true\n ) {\n current.onLoad?.('preview');\n }\n }, [notesShown, notesFor, hasLoader, details.eventId]);\n return (\n <div\n ref={rootRef}\n data-component=\"calendar-appointment-details\"\n data-event-id={details.eventId}\n className=\"ds:flex ds:h-full ds:min-h-0 ds:flex-col\"\n onClickCapture={usedLink}\n onAuxClickCapture={(event) => {\n /* A middle click opens the link in a new tab without a click. */\n if (event.button === 1) usedLink(event);\n }}\n >\n <AppointmentDetailsPanel\n state={{ status: 'ready', read: details }}\n patientId={patientId}\n operator={\n operator\n ? { name: operator.title, avatarSrc: operator.avatarSrc }\n : undefined\n }\n chair={chair ? { name: chair.title } : undefined}\n currency={data.currency ?? 'EUR'}\n now={data.nowIso}\n locale={locale}\n privacy={privacy}\n privacyTitle={privacyTitle}\n mapsLink={mapsLink}\n noteUnrecordedEdits={noteUnrecordedEdits}\n notesPreview={\n notesFor && notesSeam\n ? notesPreviewOf(notesSeam, notesFor)\n : undefined\n }\n onOpenNotes={\n notesFor && onOpenNotes\n ? (noteId?: string) => onOpenNotes(notesFor, noteId)\n : undefined\n }\n readOnly={readOnly}\n /* The calendar's handlers are bound to this occurrence already:\n each keeps its own arguments, without the panel's event id. */\n onStatusChange={\n onStatusChange &&\n (async (status) => {\n await onStatusChange(status);\n used('status');\n })\n }\n onDescriptionChange={\n onDescriptionChange &&\n ((description) => onDescriptionChange(description))\n }\n onAssignPatient={onAssignPatient && (() => onAssignPatient())}\n onEdit={\n onEdit &&\n (() => {\n onEdit();\n used('edit');\n })\n }\n onMove={\n onMove &&\n (() => {\n onMove();\n used('move');\n })\n }\n onCopy={\n onCopy &&\n ((withTreatments) => {\n onCopy(withTreatments);\n used('copy');\n })\n }\n onDelete={\n onDelete &&\n (() => {\n onDeleteInitiated?.();\n setConfirmingDelete(true);\n })\n }\n onJoinTelehealth={\n details.onJoinTelehealth &&\n (() => {\n details.onJoinTelehealth?.();\n used('video');\n })\n }\n onWhatsApp={\n details.onWhatsApp &&\n (() => {\n details.onWhatsApp?.();\n used('whatsapp');\n })\n }\n whatsappUrl={details.whatsappUrl}\n onBuyWhatsApp={\n details.onBuyWhatsApp && (() => details.onBuyWhatsApp?.())\n }\n createTaskUrl={details.createTaskUrl}\n onRequestSignature={\n details.onRequestSignature &&\n (() => {\n details.onRequestSignature?.();\n used('request-signature');\n })\n }\n onSignOnDevice={\n onSignOnDevice &&\n (() => {\n onSignOnDevice();\n used('request-signature');\n })\n }\n onOpenPatient={\n onOpenPatient && details.patient\n ? () => details.patient && onOpenPatient(details.patient)\n : undefined\n }\n shortcuts={{\n advancedSignatureUrl: details.advancedSignatureUrl,\n renewAnamnesisUrl: details.renewAnamnesisUrl,\n unlockPaymentsUrl: details.unlockPaymentsUrl,\n carePlanUrl: details.carePlanUrl,\n }}\n documents={\n details.documents && {\n kinds: details.documents.kinds,\n onCreate: (kind) => {\n onDocumentCreateClicked?.(kind);\n if (details.documents?.seriesScope?.kinds.includes(kind)) {\n setAskingScopeFor(kind);\n return;\n }\n details.documents?.onCreate(kind);\n used('document');\n },\n }\n }\n />\n {details.documents?.seriesScope ? (\n <CalendarDocumentScopeConfirm\n open={askingScopeFor !== undefined}\n onOpenChange={(open) => {\n if (!open) setAskingScopeFor(undefined);\n }}\n onCloseAutoFocus={returnFocusTo('open-create-document')}\n onConfirm={(scope) => {\n if (askingScopeFor) {\n details.documents?.onCreate(askingScopeFor, { scope });\n used('document');\n }\n setAskingScopeFor(undefined);\n }}\n />\n ) : null}\n {onDelete && !readOnly ? (\n <CalendarDeleteConfirm\n open={confirmingDelete}\n onOpenChange={setConfirmingDelete}\n scopes={deleteConfirm?.scopes}\n offersCarePlanCleanup={deleteConfirm?.offersCarePlanCleanup}\n onCloseAutoFocus={returnFocusTo('delete-appointment')}\n onConfirm={async (options) => {\n await onDelete(options);\n used('delete');\n }}\n />\n ) : null}\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 archive mode: the practice's global archive plus one second\n * archive of the same practice (the old calendar's archive session).\n * The host names the archive and passes `onExit`; the kit calls no API.\n */\nimport { useTranslation } from 'react-i18next';\nimport { Alert } from '../../components/alert';\nimport { Button } from '../../components/button';\nimport { Dialog } from '../../components/dialog';\nimport type { CalendarArchive } from './calendar.types';\n\n/** Names the open archive and offers Exit. */\nexport function CalendarArchiveBanner({\n archive,\n}: {\n archive: CalendarArchive;\n}) {\n const { t } = useTranslation('ui');\n return (\n <Alert\n variant=\"info\"\n announce=\"off\"\n data-component=\"calendar-archive-banner\"\n >\n <Alert.Description>\n {t('calendarWorkspace.archive.banner', { name: archive.name })}\n </Alert.Description>\n <Alert.Action>\n <Button\n type=\"button\"\n size=\"sm\"\n intent=\"outline\"\n onClick={archive.onExit}\n >\n {t('calendarWorkspace.archive.exit')}\n </Button>\n </Alert.Action>\n </Alert>\n );\n}\n\n/** Asks where a new appointment goes. Closing the dialog cancels. */\nexport function CalendarArchiveCreateDialog({\n archive,\n onChoose,\n onCancel,\n}: {\n archive: CalendarArchive;\n onChoose: (target: 'global' | 'archive') => void;\n onCancel: () => void;\n}) {\n const { t } = useTranslation('ui');\n return (\n <Dialog\n open\n onOpenChange={(open) => {\n if (!open) onCancel();\n }}\n >\n <Dialog.Content size=\"sm\" variant=\"confirmation\">\n <Dialog.Header>\n <Dialog.Title>\n {t('calendarWorkspace.archive.createTitle')}\n </Dialog.Title>\n <Dialog.Description>\n {t('calendarWorkspace.archive.createBody', { name: archive.name })}\n </Dialog.Description>\n </Dialog.Header>\n <Dialog.Footer>\n <Button type=\"button\" intent=\"secondary\" onClick={onCancel}>\n {t('calendarWorkspace.archive.cancel')}\n </Button>\n <Button\n type=\"button\"\n intent=\"outline\"\n onClick={() => onChoose('global')}\n >\n {t('calendarWorkspace.archive.global')}\n </Button>\n <Button\n type=\"button\"\n intent=\"primary\"\n onClick={() => onChoose('archive')}\n >\n {t('calendarWorkspace.archive.archive')}\n </Button>\n </Dialog.Footer>\n </Dialog.Content>\n </Dialog>\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","import { useEffect, useRef, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { PatientPicker } from '../../components/_shared/patient-picker';\nimport { useCalendarData } from './calendar.data';\nimport type { CalendarCreatePatient, CalendarPatient } from './calendar.types';\n\ninterface CalendarPatientPickerProps {\n value: string;\n onValueChange: (value: string) => void;\n selectedLabel?: string;\n size?: 'sm' | 'md';\n disabled?: boolean;\n /** The host's create-patient seam. Pass it only where the user may add a\n * patient (the editor and the waiting-list entry form, never a filter,\n * never read-only). Omitted, no \"Create patient\" action shows. */\n onCreatePatient?: CalendarCreatePatient;\n}\n\n/** One id-valued patient control for the editor and waiting surfaces: the\n * shared PatientPicker fed from `CalendarData`. */\nexport function CalendarPatientPicker({\n onCreatePatient,\n ...props\n}: CalendarPatientPickerProps) {\n const data = useCalendarData();\n const { t } = useTranslation('ui');\n const [created, setCreated] = useState<CalendarPatient>();\n const [creating, setCreating] = useState(false);\n const [error, setError] = useState<string>();\n const mountedRef = useRef(true);\n const rootRef = useRef<HTMLDivElement>(null);\n const focusNextRef = useRef(false);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n /* The button unmounts once a patient is set: hand focus to the picker. */\n useEffect(() => {\n if (!focusNextRef.current || !props.value) return;\n focusNextRef.current = false;\n rootRef.current?.querySelector<HTMLElement>('[role=\"combobox\"]')?.focus();\n }, [props.value]);\n\n const createPatient = async (typedText: string) => {\n if (!onCreatePatient || creating) return;\n setCreating(true);\n setError(undefined);\n try {\n const patient = await onCreatePatient({ typedText });\n /* null = the user cancelled: nothing changes. */\n if (patient && mountedRef.current) {\n setCreated({ id: patient.id, name: patient.name });\n focusNextRef.current = true;\n props.onValueChange(patient.id);\n }\n } catch (failure) {\n if (mountedRef.current)\n setError(\n failure instanceof Error && failure.message.trim()\n ? failure.message\n : t('calendarWorkspace.bookingTriage.createPatientFailed'),\n );\n } finally {\n if (mountedRef.current) setCreating(false);\n }\n };\n\n const selectedLabel =\n data.patientById(props.value)?.name ??\n (created?.id === props.value ? created.name : undefined) ??\n props.selectedLabel ??\n t('calendarWorkspace.details.patientNotLoaded');\n return (\n <div\n ref={rootRef}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\"\n >\n <PatientPicker\n {...props}\n selectedLabel={selectedLabel}\n patients={data.patients}\n searchPatients={data.searchPatients}\n placeholder={t('calendarWorkspace.editor.patientSearch')}\n createAction={\n onCreatePatient\n ? {\n label: t('calendarWorkspace.bookingTriage.createPatient'),\n onCreate: (typedText) => void createPatient(typedText),\n loading: creating,\n }\n : undefined\n }\n />\n {error ? (\n <p role=\"alert\" className=\"type-body-sm ds:text-destructive\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n","import { useFormField } from '../../components/form-field/form-field-context';\nimport { useCalendarData } from './calendar.data';\n\ninterface CalendarPatientLockedProps {\n /** The stored patient id; the name is resolved from `CalendarData`. */\n value: string;\n /** Names `value` when `patientById` cannot. */\n fallbackLabel: string;\n}\n\n/** The editor's Patient field when the host locks it\n * (`capabilities.editPatient === false`): the name as plain text. No\n * typeahead, no clear control, nothing to focus. Render it inside the\n * patient `FormField`, which carries the label and the reason. */\nexport function CalendarPatientLocked({\n value,\n fallbackLabel,\n}: CalendarPatientLockedProps) {\n const data = useCalendarData();\n const field = useFormField();\n return (\n <div\n id={field.id}\n role=\"group\"\n aria-label={field.label}\n aria-describedby={field.describedBy || undefined}\n data-component=\"calendar-patient-locked\"\n className=\"type-body ds:min-w-0 ds:py-[var(--spacing-xs)] ds:text-start ds:break-words ds:text-foreground\"\n >\n {data.patientById(value)?.name ?? fallbackLabel}\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('ui');\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 * The appointment editor's unsaved-data guard (decision P38, rule B18).\n *\n * The open form writes `dirty` (it holds typed data a leave would lose);\n * the workspace writes `ask` (the one question, `CalendarSettingsDiscardDialog`).\n * Every way out of the form asks through here: a click on another card,\n * the form's own Cancel, and, in the workspace, a switch of rail tool,\n * Settings, Close and Escape. Without a guard (a panel rendered outside\n * the workspace) nothing asks.\n */\nimport { createContext, useContext } from 'react';\n\nexport interface CalendarEditorGuard {\n /** Written by the open form: typed data a leave would lose. False once the\n * form saved, is saving, or is gone. */\n dirty: boolean;\n /** Written by the workspace: run `proceed` now, or once the user confirms\n * Discard. Cancel runs nothing and leaves the form as it was. */\n ask: (proceed: () => void) => void;\n}\n\nexport function createEditorGuard(): CalendarEditorGuard {\n return { dirty: false, ask: (proceed) => proceed() };\n}\n\nconst EditorGuardContext = createContext<CalendarEditorGuard | null>(null);\n\nexport const EditorGuardProvider = EditorGuardContext.Provider;\n\nexport function useEditorGuard(): CalendarEditorGuard | null {\n return useContext(EditorGuardContext);\n}\n","/* ------------------------------------------------------------------ */\n/* Custom recurrence (HTP-4261): the Google Calendar \"Custom…\" rule, */\n/* inline in the appointment editor rather than a dialog on top of it: */\n/* every N days / weeks / months / years, the weekdays of a weekly */\n/* rule, the day or the nth weekday of a monthly one, and a one-line */\n/* summary. It writes the platform's own RRULE fields */\n/* (`recurrenceInterval`, `recurrenceByDay`) through `EditorRecurrence`;*/\n/* read the platform caveats on `EditorRecurrence.byDay` / `untilDate` */\n/* before wiring a save. */\n/* ------------------------------------------------------------------ */\nimport { useId } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { format } from 'date-fns';\nimport { Repeat } from 'lucide-react';\nimport { getShortDateFormat } from '../../components/_shared/date-locale';\nimport { Button } from '../../components/button';\nimport { FormField } from '../../components/form-field';\nimport { NumberInput } from '../../components/number-input';\nimport { Select } from '../../components/select';\nimport {\n RECURRENCE_LABEL_KEY,\n RECURRENCE_WEEKDAYS,\n weekdayOfMonth,\n type EditorRecurrence,\n type RecurrenceByDay,\n type RecurrenceFrequency,\n type RecurrenceWeekday,\n} from './calendar.model';\n\nexport type CustomRecurrenceUnit = 'day' | 'week' | 'month' | 'year';\n\n/** How a monthly Custom rule picks its day, read from the first date. */\nexport type CustomMonthlyBy = 'monthDay' | 'nthWeekday' | 'lastWeekday';\n\nexport interface CustomRecurrenceValue {\n /** Every N units; `null` while the field is empty (saved as 1). */\n interval: number | null;\n unit: CustomRecurrenceUnit;\n /** Extra weekdays of a weekly rule. The first appointment's own day is\n * always added on top, so it is never stored here as a choice. */\n weekdays: readonly RecurrenceWeekday[];\n monthlyBy: CustomMonthlyBy;\n}\n\n/** Platform caps the count at 100; the interval has no upper bound\n * there, so this one only keeps the field sane. */\nconst MAX_INTERVAL = 99;\n\nconst UNIT_FREQUENCY: Record<CustomRecurrenceUnit, RecurrenceFrequency> = {\n day: 'daily',\n week: 'weekly',\n month: 'monthly',\n year: 'yearly',\n};\n\nconst UNITS: readonly CustomRecurrenceUnit[] = ['day', 'week', 'month', 'year'];\n\nconst UNIT_KEY: Record<CustomRecurrenceUnit, string> = {\n day: 'recurrenceUnitDay',\n week: 'recurrenceUnitWeek',\n month: 'recurrenceUnitMonth',\n year: 'recurrenceUnitYear',\n};\n\nconst EVERY_KEY: Record<CustomRecurrenceUnit, string> = {\n day: 'recurrenceEveryDay',\n week: 'recurrenceEveryWeek',\n month: 'recurrenceEveryMonth',\n year: 'recurrenceEveryYear',\n};\n\n/** The ordinal word for the nth weekday of the month (1–4). */\nconst ORDINAL_KEY: Record<number, string> = {\n 1: 'recurrenceOrdinal1',\n 2: 'recurrenceOrdinal2',\n 3: 'recurrenceOrdinal3',\n 4: 'recurrenceOrdinal4',\n};\n\n/** Each preset frequency as a unit and a step, for reading a saved rule\n * back into the Custom fields. */\nconst PRESET_STEP: Record<\n RecurrenceFrequency,\n { unit: CustomRecurrenceUnit; every: number }\n> = {\n daily: { unit: 'day', every: 1 },\n weekly: { unit: 'week', every: 1 },\n monthly: { unit: 'month', every: 1 },\n quarterly: { unit: 'month', every: 3 },\n semiannual: { unit: 'month', every: 6 },\n yearly: { unit: 'year', every: 1 },\n};\n\n/** Monday-first, as the practice's week and RRULE's WKST both are. */\nconst WEEK_ORDER: readonly RecurrenceWeekday[] = [\n 'MO',\n 'TU',\n 'WE',\n 'TH',\n 'FR',\n 'SA',\n 'SU',\n];\n\nconst weekdayCode = (date: Date): RecurrenceWeekday =>\n RECURRENCE_WEEKDAYS[date.getDay()];\n\nexport function defaultCustomRecurrence(): CustomRecurrenceValue {\n return { interval: 1, unit: 'week', weekdays: [], monthlyBy: 'monthDay' };\n}\n\n/** True when a saved rule needs the Custom fields to show it. */\nexport function isCustomRule(rule: EditorRecurrence): boolean {\n return (rule.interval ?? 1) > 1 || Boolean(rule.byDay?.length);\n}\n\n/** A saved rule back as Custom field values (the reverse of\n * `customRecurrenceRule`). Quarterly and six-monthly read as months. */\nexport function customRecurrenceFromRule(\n rule: EditorRecurrence,\n): CustomRecurrenceValue {\n const preset = PRESET_STEP[rule.frequency];\n const ordinal = rule.byDay?.find((code) => code.length > 2);\n return {\n interval: (rule.interval ?? 1) * preset.every,\n unit: preset.unit,\n weekdays:\n preset.unit === 'week'\n ? (rule.byDay ?? []).filter(\n (code): code is RecurrenceWeekday => code.length === 2,\n )\n : [],\n monthlyBy: !ordinal\n ? 'monthDay'\n : ordinal.startsWith('-')\n ? 'lastWeekday'\n : 'nthWeekday',\n };\n}\n\n/** The monthly choices a first date allows: the day of the month always,\n * the nth weekday for weeks 1–4, the last weekday in the last week. */\nfunction monthlyChoices(start: Date): CustomMonthlyBy[] {\n const { nth, last } = weekdayOfMonth(start);\n return [\n 'monthDay',\n ...(nth <= 4 ? (['nthWeekday'] as const) : []),\n ...(last ? (['lastWeekday'] as const) : []),\n ];\n}\n\n/** A stored monthly choice the date no longer allows falls to its twin:\n * a fifth weekday is the last one, and a weekday that is no longer the\n * last is still the nth. */\nfunction resolveMonthlyBy(\n monthlyBy: CustomMonthlyBy,\n start: Date,\n): CustomMonthlyBy {\n const choices = monthlyChoices(start);\n if (choices.includes(monthlyBy)) return monthlyBy;\n return monthlyBy === 'nthWeekday' ? 'lastWeekday' : 'nthWeekday';\n}\n\n/** The weekdays a weekly rule books: the user's picks plus the first\n * appointment's own day, in week order. The anchor is always in, so the\n * platform's RRULE (which drops a DTSTART the rule does not match) can\n * never lose the appointment the user just placed. */\nfunction weeklyDays(\n value: CustomRecurrenceValue,\n start: Date,\n): RecurrenceWeekday[] {\n const picked = new Set<RecurrenceWeekday>([\n ...value.weekdays,\n weekdayCode(start),\n ]);\n return WEEK_ORDER.filter((code) => picked.has(code));\n}\n\n/** The rule fields a Custom value saves as, for the first date `start`. */\nexport function customRecurrenceRule(\n value: CustomRecurrenceValue,\n start: Date,\n): Pick<EditorRecurrence, 'frequency' | 'interval' | 'byDay'> {\n const interval = Math.min(Math.max(value.interval ?? 1, 1), MAX_INTERVAL);\n const base = {\n frequency: UNIT_FREQUENCY[value.unit],\n ...(interval > 1 ? { interval } : {}),\n };\n if (value.unit === 'week') {\n return { ...base, byDay: weeklyDays(value, start) };\n }\n if (value.unit === 'month') {\n const monthlyBy = resolveMonthlyBy(value.monthlyBy, start);\n if (monthlyBy === 'monthDay') return base;\n const { nth } = weekdayOfMonth(start);\n const place = monthlyBy === 'lastWeekday' ? -1 : nth;\n return {\n ...base,\n byDay: [`${place}${weekdayCode(start)}` as RecurrenceByDay],\n };\n }\n return base;\n}\n\nfunction weekdayName(\n code: RecurrenceWeekday,\n locale: string,\n style: 'long' | 'short',\n): string {\n /* 4 January 2026 is a Sunday: offset by the code's getDay() index. */\n const date = new Date(2026, 0, 4 + RECURRENCE_WEEKDAYS.indexOf(code));\n return new Intl.DateTimeFormat(locale, { weekday: style }).format(date);\n}\n\n/** \"Every 3 weeks · Monday and Thursday · 5 appointments\". */\nexport function useRecurrenceSummary({\n frequency,\n custom,\n start,\n ends,\n count,\n untilDate,\n locale,\n}: {\n frequency: RecurrenceFrequency | 'custom';\n custom: CustomRecurrenceValue;\n start: Date;\n ends: 'count' | 'until';\n count: number | null;\n untilDate?: Date;\n locale: string;\n}): string {\n const { t } = useTranslation('ui');\n const key = (suffix: string) => `calendarWorkspace.editor.${suffix}`;\n const monthlyLabel = (monthlyBy: CustomMonthlyBy): string => {\n const weekday = weekdayName(weekdayCode(start), locale, 'long');\n if (monthlyBy === 'monthDay') {\n return t(key('recurrenceMonthDay'), { day: start.getDate() });\n }\n if (monthlyBy === 'lastWeekday') {\n return t(key('recurrenceLastWeekday'), { weekday });\n }\n return t(key('recurrenceNthWeekday'), {\n weekday,\n ordinal: t(key(ORDINAL_KEY[weekdayOfMonth(start).nth])),\n });\n };\n const parts: string[] = [];\n if (frequency === 'custom') {\n const every = Math.max(custom.interval ?? 1, 1);\n /* A step of one reads as the plain frequency (\"Weekly\"); the \"Every\n N weeks\" family only ever renders two or more. */\n parts.push(\n every === 1\n ? t(key(RECURRENCE_LABEL_KEY[UNIT_FREQUENCY[custom.unit]]))\n : t(key(EVERY_KEY[custom.unit]), { count: every }),\n );\n if (custom.unit === 'week') {\n const names = weeklyDays(custom, start).map((code) =>\n weekdayName(code, locale, 'long'),\n );\n parts.push(\n new Intl.ListFormat(locale, { type: 'conjunction' }).format(names),\n );\n }\n if (custom.unit === 'month') {\n parts.push(monthlyLabel(resolveMonthlyBy(custom.monthlyBy, start)));\n }\n } else {\n parts.push(t(key(RECURRENCE_LABEL_KEY[frequency])));\n }\n if (ends === 'until' && untilDate) {\n parts.push(\n /* The date picker's own short format, so the line and the Last\n date field above it never print one day two ways. */\n t(key('recurrenceSummaryUntil'), {\n date: format(untilDate, getShortDateFormat(locale)),\n }),\n );\n } else if (ends === 'count' && count) {\n parts.push(t(key('recurrenceSummaryCount'), { count }));\n }\n return parts.join(' · ');\n}\n\n/**\n * The Custom rule's fields, as cells of the editor's form grid: Repeat\n * every N, the period, then the weekday chips (weekly) or the monthly\n * choice (monthly). Controlled; `start` is the first appointment's date,\n * from which the locked weekday and the monthly choices are read.\n */\nexport function CustomRecurrenceFields({\n value,\n onChange,\n start,\n locale,\n fieldClassName,\n wideClassName,\n}: {\n value: CustomRecurrenceValue;\n onChange: (next: CustomRecurrenceValue) => void;\n start: Date;\n locale: string;\n /** The grid cell class of the \"Repeat every\" cell. It lays its two\n * fields out itself, so pass a class that sets no grid of its own. */\n fieldClassName: string;\n /** The grid cell class of a full-width row. */\n wideClassName: string;\n}) {\n const { t } = useTranslation('ui');\n const key = (suffix: string) => `calendarWorkspace.editor.${suffix}`;\n const weekdaysLabelId = useId();\n const weekdaysHintId = useId();\n const every = Math.max(value.interval ?? 1, 1);\n const anchorDay = weekdayCode(start);\n const pressed = new Set(weeklyDays(value, start));\n const monthlyBy = resolveMonthlyBy(value.monthlyBy, start);\n const weekdayLong = weekdayName(anchorDay, locale, 'long');\n\n return (\n <>\n {/* \"Repeat every [2] [weeks]\" reads as one phrase, so the number\n and its period share one cell of the form grid. */}\n <div\n className={`${fieldClassName} ds:grid ds:grid-cols-[minmax(0,6rem)_minmax(0,1fr)] ds:items-start ds:gap-x-[var(--spacing-sm)]`}\n >\n <FormField label={t(key('recurrenceInterval'))}>\n <NumberInput\n value={value.interval}\n min={1}\n max={MAX_INTERVAL}\n onChange={(interval) => onChange({ ...value, interval })}\n />\n </FormField>\n <FormField label={t(key('recurrenceUnit'))}>\n <Select\n options={UNITS.map((unit) => ({\n value: unit,\n label: t(key(UNIT_KEY[unit]), { count: every }),\n }))}\n value={value.unit}\n onValueChange={(unit) =>\n onChange({ ...value, unit: unit as CustomRecurrenceUnit })\n }\n />\n </FormField>\n </div>\n {value.unit === 'week' ? (\n <div\n className={`${wideClassName} ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]`}\n >\n <span id={weekdaysLabelId} className=\"type-label ds:text-foreground\">\n {t(key('recurrenceWeekdays'))}\n </span>\n <div\n role=\"group\"\n aria-labelledby={weekdaysLabelId}\n aria-describedby={weekdaysHintId}\n data-recurrence-weekdays=\"\"\n className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-xs)]\"\n >\n {WEEK_ORDER.map((code) => {\n const isAnchor = code === anchorDay;\n const on = pressed.has(code);\n return (\n <Button\n key={code}\n type=\"button\"\n size=\"sm\"\n intent={on ? 'primary' : 'outline'}\n aria-pressed={on}\n disabled={isAnchor}\n data-weekday={code}\n /* 32px like the editor's compact fields, raised with\n them to the full target under .theme-accessible. */\n className=\"ds:[min-block-size:var(--accessible-target-floor,auto)]\"\n onClick={() =>\n onChange({\n ...value,\n weekdays: on\n ? value.weekdays.filter((d) => d !== code)\n : [...value.weekdays, code],\n })\n }\n >\n {weekdayName(code, locale, 'short')}\n </Button>\n );\n })}\n </div>\n <span\n id={weekdaysHintId}\n className=\"type-body-sm ds:text-[color:var(--muted-foreground)]\"\n >\n {t(key('recurrenceWeekdaysHint'), { weekday: weekdayLong })}\n </span>\n </div>\n ) : null}\n {value.unit === 'month' ? (\n <FormField\n className={wideClassName}\n label={t(key('recurrenceWeekdays'))}\n >\n <Select\n options={monthlyChoices(start).map((choice) => ({\n value: choice,\n label:\n choice === 'monthDay'\n ? t(key('recurrenceMonthDay'), { day: start.getDate() })\n : choice === 'lastWeekday'\n ? t(key('recurrenceLastWeekday'), { weekday: weekdayLong })\n : t(key('recurrenceNthWeekday'), {\n weekday: weekdayLong,\n ordinal: t(key(ORDINAL_KEY[weekdayOfMonth(start).nth])),\n }),\n }))}\n value={monthlyBy}\n onValueChange={(next) =>\n onChange({ ...value, monthlyBy: next as CustomMonthlyBy })\n }\n />\n </FormField>\n ) : null}\n </>\n );\n}\n\n/** The rule in one line, under the recurrence fields. */\nexport function RecurrenceSummaryLine({\n summary,\n className,\n}: {\n summary: string;\n className: string;\n}) {\n return (\n <p\n data-recurrence-summary=\"\"\n className={`${className} type-body-sm ds:flex ds:items-center ds:gap-[var(--spacing-xs)] ds:text-[color:var(--muted-foreground)]`}\n >\n <Repeat aria-hidden=\"true\" className=\"ds:size-4 ds:shrink-0\" />\n <span>{summary}</span>\n </p>\n );\n}\n","/**\n * HTP-5059, P31 — the operator/chair restriction the cares of a NEW\n * price-list appointment place on it, shared between the editor's\n * create-mode Selects and the Find-free-slots finder so the two flows\n * cannot drift.\n *\n * Platform rule (Settings → Care settings, `CalendarCare.operatorIds` /\n * `chairIds`): a care with an EMPTY list carries no restriction, a\n * non-empty list is the set of operators/chairs allowed to perform it.\n * With several cares on one appointment the allowed set is the UNION: a\n * resource is offered when at least one chosen care allows it, and one\n * care with no restriction lifts the filter. The caller applies it on\n * CREATE only and for PRICE-LIST appointments only; an edit and a\n * care-plan appointment list every resource.\n */\nimport type { CalendarCare } from './calendar.types';\n\n/** The result of narrowing a resource list by one or more cares'\n * restrictions. `list` is always what the Select should offer: an\n * unrestricted set falls back to every resource passed in. */\nexport interface CareResourceRestriction<T extends { id: string }> {\n /** Resources to list: narrowed when `restricted`, else the full input. */\n list: T[];\n /** Every chosen care carries a restriction on this axis. */\n restricted: boolean;\n}\n\nfunction restrictionFor<T extends { id: string }>(\n resources: readonly T[],\n cares: readonly CalendarCare[],\n pick: (care: CalendarCare) => readonly string[],\n): CareResourceRestriction<T> {\n const lists = cares.map(pick);\n /* No care yet, or one care with no restriction: nothing narrows. */\n if (lists.length === 0 || lists.some((ids) => ids.length === 0)) {\n return { list: [...resources], restricted: false };\n }\n const allowed = new Set(lists.flat());\n return {\n list: resources.filter((r) => allowed.has(r.id)),\n restricted: true,\n };\n}\n\n/** The operators at least one of the cares allows. Empty `cares` (nothing\n * picked yet) is unrestricted, as is any set holding a care with an empty\n * `operatorIds`. */\nexport function allowedOperatorsFor<T extends { id: string }>(\n cares: readonly CalendarCare[],\n operators: readonly T[],\n): CareResourceRestriction<T> {\n return restrictionFor(operators, cares, (c) => c.operatorIds);\n}\n\n/** The chairs at least one of the cares allows. Mirrors `allowedOperatorsFor`. */\nexport function allowedChairsFor<T extends { id: string }>(\n cares: readonly CalendarCare[],\n chairs: readonly T[],\n): CareResourceRestriction<T> {\n return restrictionFor(chairs, cares, (c) => c.chairIds);\n}\n\n/** Whether `id` is still a legal pick under a restriction — used to\n * decide whether a care change should reset the current selection.\n * `NONE`/`ANY`-style sentinels never reach here; callers guard those\n * before calling. */\nexport function isResourceAllowed<T extends { id: string }>(\n id: string,\n restriction: CareResourceRestriction<T>,\n): boolean {\n return restriction.list.some((r) => r.id === id);\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 Globe,\n MapPin,\n Pencil,\n Stethoscope,\n UserPlus,\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 gap the user asked to complete: a hint for the host editor's\n * landing step. Absent means the plain \"edit\" entry. */\nexport type BookingCompleteIntent = 'patient' | 'operator' | 'chair';\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. Exported so\n * `BookingsPanel` (calendar.sheets.tsx) can label its date groups the\n * same way the card labels its own \"booked on\" line. */\nexport function 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. Below `sm` a small\n Button already floors at --min-target-size; from `sm` up it drops that\n floor, so the block-axis raise is needed there only. */\nconst ACCESSIBLE_TARGET =\n 'ds:sm:[min-block-size:var(--accessible-target-floor,0px)] ds:[min-inline-size:var(--accessible-target-floor,auto)]';\n\n/* No \"missing\" tone: the assign segments' `--warning-foreground` fought\n ButtonGroup's outline intent with an `!important` to say what the meta\n line's neutral Badge already says. A gap is a fact, not a warning.\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\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:[:where(&)]:border-[length:var(--surface-border-width,var(--border-width-sm))] ds:border-[color:var(--card-border)]',\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 // Clear at rest; the accessible themes hold it steady (--accessible-on\n // is 1 there) instead of playing it.\n 'ds:border-2 ds:border-[color:var(--accent)] ds:opacity-[var(--accessible-on,0)]',\n 'ds:animate-[var(--accessible-off,booking-addressed_calc(var(--animation-duration)*9)_var(--ease-in-out))]',\n 'ds:motion-reduce:animate-none ds:motion-reduce:opacity-100',\n 'ds:forced-colors:border-[Highlight]',\n ].join(' '),\n);\n\n/* The title is never the \"something is missing\" signal any more — that\n moved to the Badge in the meta line — so it always reads as plain text,\n named or the \"needs a patient\" placeholder alike. */\nconst titleVariants = cva(\n 'ds:min-w-0 ds:truncate type-title-item ds:text-[color:var(--foreground)]',\n);\n\n/* One plain `--muted` circle for every placeholder state; only the glyph\n inside (UserX vs EyeOff) tells them apart. No dashed ring: that read as\n an error state the card never meant to raise. */\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)] ds:text-[color:var(--muted-foreground)]',\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('ui');\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 gapCount = [\n view.needsPatient,\n view.needsOperator,\n view.needsChair,\n ].filter(Boolean).length;\n /* Two or three gaps at once: every assign segment goes short so the\n strip still fits the rail; one gap alone keeps the full label. */\n const bothMissing = gapCount > 1;\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\n let avatar: ReactNode;\n if (!item.patient) {\n avatar = (\n <span className={avatarPlaceholderVariants()}>\n <UserX aria-hidden=\"true\" className=\"ds:size-4\" />\n </span>\n );\n } else if (privacy) {\n avatar = (\n <span className={avatarPlaceholderVariants()}>\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 className={titleVariants()}>{title}</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.bookedOnline ? (\n <Badge\n size=\"sm\"\n variant=\"info\"\n leading={<Globe aria-hidden=\"true\" />}\n data-booking-online=\"\"\n >\n {t('calendarWorkspace.details.indicators.bookedOnline')}\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={data.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 {/* `neutral`, not `warning`: the warning chip's text fails AA\n at this eyebrow-sized `sm` badge (contrast ~4.27:1). */}\n {view.needsPatient ? (\n <Badge size=\"sm\" variant=\"neutral\">\n {t(bookingKey('needsPatient'))}\n </Badge>\n ) : null}\n {view.needsOperator ? (\n <Badge size=\"sm\" variant=\"neutral\">\n {t(bookingKey('needsOperator'))}\n </Badge>\n ) : null}\n {view.needsChair ? (\n <Badge size=\"sm\" variant=\"neutral\">\n {t(bookingKey('needsChair'))}\n </Badge>\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 {[\n { value: contact.typedName, ltr: false },\n // Phone and email are LTR data even in an RTL paragraph —\n // without `dir=\"ltr\"` the digits/punctuation can reorder.\n { value: contact.phone, ltr: true },\n { value: contact.email, ltr: true },\n ]\n .filter((entry) => entry.value.trim() !== '')\n .map((entry) => (\n <span\n key={entry.value}\n className=\"ds:min-w-0\"\n dir={entry.ltr ? 'ltr' : undefined}\n >\n {entry.value}\n </span>\n ))}\n </div>\n ) : null}\n {/* Footer row: the same shape as the details panel and the waiting\n card — a solid hairline, the secondary meta at the inline-start,\n the joined strip pinned to the inline-end. */}\n <div className=\"ds:flex ds:min-w-0 ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)] ds:border-t ds:border-[color:var(--border)] ds:pt-[var(--spacing-sm)]\">\n {view.bookedAt ? (\n <span className=\"type-body-sm ds:min-w-0 ds:truncate ds:text-[color:var(--muted-foreground)]\">\n {t(bookingKey('bookedOn'), {\n date: shortDay(lng, view.bookedAt),\n })}\n </span>\n ) : null}\n <ButtonGroup\n size=\"sm\"\n overflow=\"menu\"\n label={named(t(bookingKey('actionsLabel')))}\n data-booking-actions=\"\"\n className=\"ds:ms-auto ds:min-w-0\"\n >\n {canComplete && view.needsPatient ? (\n <Button\n key=\"patient\"\n intent=\"primary\"\n startIcon={<UserPlus />}\n className={stripMemberVariants()}\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 intent=\"primary\"\n startIcon={<Stethoscope />}\n className={stripMemberVariants()}\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 {canComplete && view.needsChair ? (\n <Button\n key=\"chair\"\n intent=\"primary\"\n startIcon={<Armchair />}\n className={stripMemberVariants()}\n aria-label={named(t(bookingKey('assignChair')))}\n data-booking-action=\"assign-chair\"\n onClick={() => complete('chair')}\n >\n {t(\n bookingKey(bothMissing ? 'assignChairShort' : 'assignChair'),\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 {/* No number reachable (no SMS-verified digits, or privacy\n withholding it): the member is absent, not a disabled one —\n there is nothing behind it to explain with a tooltip. */}\n {whatsAppDigits ? (\n <IconButton\n key=\"whatsapp\"\n icon={<WhatsAppGlyph aria-hidden=\"true\" />}\n className={stripMemberVariants()}\n aria-label={named(whatsAppLabel)}\n tooltip={whatsAppLabel}\n data-booking-action=\"whatsapp\"\n onClick={() => {\n window.open(\n `https://wa.me/${whatsAppDigits}`,\n '_blank',\n 'noopener,noreferrer',\n );\n }}\n />\n ) : null}\n </ButtonGroup>\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-[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 { CalendarPatientLocked } from './calendar-patient-locked';\nimport { AppointmentHistoryTimeline } from '../../components/appointment-details-panel/appointment-details-panel.history';\nimport {\n AppointmentIdentityStrip,\n IndicatorChips,\n} from '../../components/appointment-details-panel/appointment-details-panel.identity';\nimport { useEditorInitialFocus } from './calendar-rail-settle';\nimport { toastWarning } from '../../components/toast';\nimport { isBilled } from '../../components/treatment-receipt';\nimport type {\n CalendarEditorCapabilities,\n FirstVisitAnswer,\n} 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 {\n Armchair,\n CalendarClock,\n CalendarDays,\n CalendarPlus,\n CalendarSearch,\n UserCog,\n ClipboardList,\n Copy,\n Hourglass,\n Check,\n Globe,\n Stethoscope,\n Mail,\n MessageSquare,\n Pencil,\n Plus,\n Trash2,\n Save,\n X,\n Funnel,\n History as HistoryIcon,\n ArrowLeft,\n PenLine,\n Send,\n Move,\n LayoutList,\n ListTodo,\n CircleDashed,\n Lock,\n ClipboardPaste,\n MapPin,\n RotateCcw,\n Settings,\n Smartphone,\n} from 'lucide-react';\nimport {\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 { StateBackedTextInput } from '../../components/_shared/state-backed-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 type { AppointmentConsentItem } from '../../components/appointment-details-panel';\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 { CalendarDeleteConfirm } from './calendar-delete-confirm';\nimport { Popover } from '../../components/popover';\nimport { Select } from '../../components/select';\nimport { Alert } from '../../components/alert';\nimport { Link } from '../../components/link';\nimport { SignatureStatusChip } from '../../components/signature-status-chip';\nimport {\n type ColorAssociation,\n careLabel,\n type CalendarCareLink,\n type CalendarCarePlan,\n type CalendarAnamnesisAnswer,\n type CalendarCarePlanEntry,\n buildOperatorFilterGroups,\n type CalendarOperatorGroup,\n type CalendarBookingPatientPrefill,\n type CalendarCreatePatient,\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 type CalendarCare,\n} from './calendar.types';\nimport { useSheetHost } from './calendar.host';\nimport { useEditorGuard } from './calendar-editor-guard';\nimport {\n CustomRecurrenceFields,\n RecurrenceSummaryLine,\n customRecurrenceFromRule,\n customRecurrenceRule,\n defaultCustomRecurrence,\n isCustomRule,\n useRecurrenceSummary,\n type CustomRecurrenceValue,\n} from './calendar-custom-recurrence';\nimport { EDITOR_COMPACT_FIELDS_CLASS } from '../../components/_shared/compact-editor-fields';\nimport { useCalendarData, type CalendarData } from './calendar.data';\nimport {\n STATUS_UI_KEY,\n type CalendarRow,\n type DisplaySettings,\n formatTimeRange,\n formatDay,\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 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_DURATION_MIN,\n FREE_SLOT_DEFAULT_HORIZON_DAYS,\n rangeDays,\n type CalendarFreeSlot,\n localIsoDate,\n parseIsoDate,\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 type BookingRowView,\n type BacklogGap,\n DEFAULT_BACKLOG_FILTERS,\n toggleSelectedIds,\n type RecurringScope,\n type RecurringScopeChosen,\n RECURRING_SCOPES,\n RECURRING_SCOPE_LABEL_KEY,\n type RequiredDocsSignMode,\n type EditorDraftExtras,\n type CareDeviceChoice,\n type MedicalDeviceQuery,\n effectiveDeviceId,\n type DeleteOptions,\n type WorkspaceDisplaySettings,\n slotConflicts,\n devicesForCares,\n signChannelStates,\n defaultSignMode,\n patientAddressLabel,\n patientAddressLine,\n patientMapsUrl,\n} from './calendar-workspace.model';\nimport {\n allowedOperatorsFor,\n allowedChairsFor,\n isResourceAllowed,\n} from './calendar-care-rules';\nimport {\n BookingCard,\n BookingCardsSkeleton,\n shortDay,\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('ui');\n const { t: tUi } = useTranslation('ui');\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('ui');\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: data.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, data.currency]);\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 /** Called on the click that confirms it. Resolve once the delete has\n * landed; a rejection restores the row and the panel shows the message.\n * A clinical note is taken as kept, marked deleted, unless the note\n * says `keptOnDelete: false`: its row waits in place. */\n onDeleteNote: (noteId: string) => void | Promise<void>;\n /** `next` is the value the note moves to. A rejection rolls the pin back\n * and the panel shows the message: do not also toast it. */\n onTogglePin: (noteId: string, next: boolean) => void | Promise<void>;\n /** As `onTogglePin`, for the flag. Omitted → no flag control. */\n onToggleFlag?: (noteId: string, next: boolean) => void | Promise<void>;\n /** Hears every refused save, delete, pin or flag. See `NotesPanel`'s\n * `onWriteError`: report only the ones with `shown: false`. */\n onWriteError?: NotesPanelProps['onWriteError'];\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 /** Practice templates in the composer's AI pill. See `RichTextEditor`. */\n aiTemplates?: NotesPanelProps['aiTemplates'];\n /** After a pill action rewrote the draft. See `RichTextEditor`. */\n onAiApplied?: NotesPanelProps['onAiApplied'];\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 /** Show the editor extensions affordance. See `RichTextEditor`. */\n showExtensions?: NotesPanelProps['showExtensions'];\n /** Shows the AI-credits/bundles hover card on every AI trigger. See\n * `RichTextEditor`. */\n aiCreditsNotice?: NotesPanelProps['aiCreditsNotice'];\n /** Editor extensions offered under the toolbar's toy brick. See\n * `RichTextEditor`. */\n extensions?: NotesPanelProps['extensions'];\n extensionContext?: NotesPanelProps['extensionContext'];\n onExtensionRun?: NotesPanelProps['onExtensionRun'];\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\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 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 /* 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, and a delete keeps it in the record\n marked deleted, unless the host says otherwise. NotesPanel offers its\n pencil on every note it is not told to spare, and fades out every\n note it is not told is kept. */\n const notes = (seam?.notes ?? data.patientNotes(patientId)).map((note) =>\n note.clinical\n ? {\n ...note,\n actions:\n note.actions?.edit === undefined\n ? { ...note.actions, edit: false }\n : note.actions,\n keptOnDelete: note.keptOnDelete ?? true,\n }\n : note,\n );\n const writable =\n seam !== undefined && (seam.writable ?? (seam.onLoad ? false : editable));\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 return (\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 aiTemplates={writable ? seam?.aiTemplates : undefined}\n onAiApplied={writable ? seam?.onAiApplied : undefined}\n onUploadImage={writable ? seam?.onUploadImage : undefined}\n onAiCreditsExhausted={writable ? seam?.onAiCreditsExhausted : undefined}\n showExtensions={writable ? seam?.showExtensions : undefined}\n aiCreditsNotice={writable ? seam?.aiCreditsNotice : undefined}\n extensions={writable ? seam?.extensions : undefined}\n extensionContext={writable ? seam?.extensionContext : undefined}\n onExtensionRun={writable ? seam?.onExtensionRun : undefined}\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) => seam.onEditNote(noteId, submission.content)\n : undefined\n }\n /* Delete, pin and flag take NotesPanel's own path: the host hears\n each on the click, and the panel rolls back and explains a\n refusal. */\n onDeleteNote={writable ? seam?.onDeleteNote : undefined}\n onTogglePin={writable ? seam?.onTogglePin : undefined}\n onToggleFlag={writable ? seam?.onToggleFlag : undefined}\n onWriteError={writable ? seam?.onWriteError : undefined}\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('ui');\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(\n ({ actions: _actions, keptOnDelete: _kept, ...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 )}\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 history timeline lives with AppointmentDetailsPanel;\n re-exported here for the calendar's importers and demos. */\nexport { AppointmentHistoryTimeline };\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('ui');\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 return (\n <Combobox\n options={options}\n value={value != null ? String(value) : ''}\n onValueChange={(next) => onChange(next ? Number(next) : null)}\n filter={durationDigitsFilter}\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. The tiers never shrink a target; the\n fields' 32px is a separate, documented exception (compact-editor-fields). */\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 = `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 ${EDITOR_COMPACT_FIELDS_CLASS}`;\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 earliest same-day reminder per channel (B8). */\nexport interface SameDayReminders {\n sms?: Date | string;\n email?: Date | string;\n}\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 /** Medical devices (B9): what each chosen care can use at the visit's\n * slot. Asked once per change of cares, date, time, length or\n * appointment, and must be synchronous and pure. Cares that need no\n * device are left out of the answer. Each care shows a choice, already\n * set to `assignedId`; a pick resets when the time or length changes,\n * so the host assigns again for the new slot. The chosen devices reach\n * the host in `EditorDraftExtras.medicalDevices`. When every device is\n * busy the editor says so and the save still goes ahead. Omit it and\n * the editor shows the read-only `devicesByCare` line, or nothing. The\n * kit never masks device names: they are equipment, not patient data,\n * so a host that wants them hidden passes neutral names. */\n medicalDevicesForCares?: (\n query: MedicalDeviceQuery,\n ) => readonly CareDeviceChoice[];\n /** Required documents still unsigned for a patient (sign-mode radios). */\n unsignedRequiredDocs?: (patientId: string) => number;\n /** The treatment consents the chosen cares need for THIS appointment\n * (HTP-3395): `eventId` is set on edit and absent on create. A new\n * consent is made for every visit, so answer per appointment, never per\n * patient. Each `missing` one shows as a tick (ticked on create, unticked on edit), and\n * the ticked ids reach the host in `EditorDraftExtras.consentIds` with\n * the save: the host creates and sends them, and picks in-person or\n * remote signing itself. `requested` and `signed` ones show as text.\n * Absent, or an empty answer: the editor shows nothing. Must be\n * synchronous, pure and cheap: it is asked once per change of cares,\n * appointment or function identity, and has no loading or error state.\n * Resolve the answer first and pass a new function when it changes. */\n consentsForCares?: (\n careIds: readonly string[],\n eventId?: string,\n ) => readonly AppointmentConsentItem[];\n /** Create a patient from the online booking being processed. The editor\n * offers \"Create patient\" in the booking card while no patient is\n * chosen; the host opens its own new-patient form filled with the\n * booking name, phone and email and resolves with the new patient, or\n * with `undefined` when the user cancels (nothing changes). Make the\n * record available through `CalendarData.patientById` before resolving,\n * as `searchPatients` asks. Reject with a safe, user-facing `Error` on\n * failure. Omit it and the button is withheld. Never offered to a\n * read-only viewer or when the patient is locked. */\n createPatientFromBooking?: (\n contact: CalendarBookingPatientPrefill,\n ) => Promise<CalendarPatient | undefined>;\n /** \"Create patient\" under the patient search, for any appointment with\n * no patient chosen: the host opens its own new-patient form and\n * resolves with the new patient, or `null` on cancel (nothing changes).\n * See `CalendarCreatePatient`. Omit it and the action is withheld, as it\n * is for a read-only viewer and a locked patient. An online booking\n * with `createPatientFromBooking` keeps its own button and prefill. */\n createPatient?: CalendarCreatePatient;\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 and was not changed on\n * its own — offer the save scope. */\n recurringScope?: boolean;\n /** Delete offers the scope when the appointment belongs to a series,\n * changed on its own or not. Defaults to `recurringScope`. */\n recurringDeleteScope?: boolean;\n /** Any occurrence of a price-list series — 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. A host that\n * can persist only a repetition count turns this off and keeps\n * frequency + count alone (audit A3). */\n recurrenceExtras?: boolean;\n /** Offer the Custom rule (HTP-4261) inline: every N days, weeks, months\n * or years, the weekdays of a weekly rule, the day or nth weekday of a\n * monthly one, and a summary line. Its draft carries `interval` and\n * `byDay` (platform `recurrenceInterval` / `recurrenceByDay`), so a\n * host that cannot save them leaves this off. Defaults to\n * `recurrenceExtras`. */\n recurrenceCustom?: boolean;\n /** Show the skip-closed-days switch. Defaults to `recurrenceExtras`.\n * The platform has no closed-day skip, so a platform host that turns\n * `recurrenceExtras` on for the end date turns this off. */\n recurrenceSkipClosedDays?: boolean;\n /** Where the skip switch starts on a new series. Defaults to on. */\n recurrenceSkipClosedDaysDefault?: boolean;\n /** Show the chosen operator's absence as a third sibling of the busy\n * warnings. Off: it keeps the date-side closure banner. Either way it\n * only warns and never holds the save (audit C9, P25). */\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 /** The practice's default reminder channels (Practice settings, patient\n * notices). A new appointment and an online booking being completed\n * start the reminder boxes from them; a channel the host does not pass\n * starts OFF (the move confirm reads it the same way). An edit keeps\n * the ticks saved with the appointment (`EditorPrefill.emailReminder`\n * and `smsReminder`; one left out is not sent on a save the user did\n * not change it in, so the host keeps its stored value). A patient who\n * cannot take a channel still disables it. */\n defaultReminders?: { sms?: boolean; email?: boolean };\n /** B12: propose the first-visit answer on a NEW appointment once a\n * patient is chosen, and again when the date changes, from the patient's\n * history. Resolve `unknown` when the host cannot tell. A proposal never\n * overrides an answer the user already picked, and a failure or a late\n * answer for an earlier patient is ignored. Omit it and the answer\n * starts, and stays, on unknown until the user answers. */\n proposeFirstVisit?: (query: {\n patientId: string;\n date: Date;\n }) => FirstVisitAnswer | Promise<FirstVisitAnswer>;\n /** B8: when the chosen patient already has an appointment that day with\n * a reminder, answer the time of the EARLIEST one per channel (a\n * `Date` or an ISO string), or leave a channel out. Asked when the\n * patient or the day changes, for a channel only if its practice\n * default is on (`defaultReminders`). The editor then compares the\n * form's own time: a LATER visit has that channel's tick removed with a\n * message, an EARLIER one keeps it with a message. On an edit, leave\n * the edited appointment (`eventId`) out of the answer. A failure\n * shows nothing. Omit it and neither message appears. */\n sameDayReminders?: (query: {\n patientId: string;\n date: Date;\n eventId?: string;\n }) => SameDayReminders | Promise<SameDayReminders>;\n /** B10: the practice's signature credits. With none left, a NEW\n * appointment whose patient has unsigned required documents says so and\n * links to `buyHref` (opens in a new tab), and the sign-mode choice is withheld, since sending a\n * request uses a credit. Omit it and the editor shows neither the\n * message nor any limit on the sign mode. */\n signatureCredits?: { available: number; buyHref: string };\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 onDeleteInitiated,\n onDuplicate,\n panelTitle,\n headerIcon,\n identity,\n after,\n closeOnSave = true,\n returnsOnCancel = false,\n onDraftChange,\n onPatientContextChange,\n slotPatch,\n locale,\n scheduleByEntry = EMPTY_SCHEDULE,\n history,\n noteUnrecordedEdits,\n onMove,\n onCopy,\n onWhatsApp,\n readOnly = false,\n capabilities: hostCapabilities,\n series,\n onRecurringScopeChosen,\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 user answered the scope question: an accepted save (with the\n * scope it saved under, chosen in the host chooser or the radios) or a\n * confirmed delete. Once per save, never on Cancel or a refused save. */\n onRecurringScopeChosen?: (answer: RecurringScopeChosen) => void;\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 only: the Delete button was clicked, before the confirm. Raised\n * once per click, with the appointment's id, whatever the answer. */\n onDeleteInitiated?: (eventId: string) => 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 /** @deprecated Ignored. \"Colour by\" is a view choice: it no longer sets\n * the editor's colour. Hosts can stop passing it. */\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 /** In History, say \"What changed was not recorded.\" under an edit that\n * carries no detail. Off by default. */\n noteUnrecordedEdits?: boolean;\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('ui');\n const data = useCalendarData();\n const { t: tUi, i18n: runtimeI18n } = useTranslation('ui');\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 const editorGuard = useEditorGuard();\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 hostScopes = isEdit && !readOnly ? series?.scopes : undefined;\n /* A host occurrence changed on its own skips the edit question and\n keeps the delete one. */\n const seriesScopes = series?.detached ? undefined : hostScopes;\n const [seriesScope, setSeriesScope] = useState<RecurringScope>();\n const [changingScope, setChangingScope] = useState(false);\n const choosingScope =\n Boolean(seriesScopes) && (!seriesScope || changingScope);\n /* A changed occurrence is always \"this\": its capabilities merge too. */\n const capabilityScope =\n seriesScope ?? (series?.detached ? 'this' : undefined);\n const capabilities: CalendarEditorCapabilities | undefined = capabilityScope\n ? { ...hostCapabilities, ...series?.capabilitiesByScope?.[capabilityScope] }\n : hostCapabilities;\n const canEditCare = capabilities?.editCare !== false;\n /* The host's lock: the name shows as plain text and the draft carries no\n patient, so the host keeps the stored one. */\n const patientLocked = capabilities?.editPatient === 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 /* B8: Save was pressed on a telehealth visit with both reminders off. */\n const [reminderRefused, setReminderRefused] = useState(false);\n const reminderAlertId = useId();\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 /* The patient this form created from the booking, named for the picker\n until the host's own lookup knows them. */\n const [createdPatient, setCreatedPatient] = useState<{\n id: string;\n name: string;\n }>();\n const [creatingPatient, setCreatingPatient] = useState(false);\n /* The button unmounts once a patient is set: hand focus to the Patient\n picker, which now reads the created name (WCAG 2.4.3). */\n const focusPickerNextRef = useRef(false);\n const createPatientFromBooking = platform?.createPatientFromBooking;\n const createBookingPatient = async () => {\n const contact = prefill?.bookingContact;\n if (!contact || !createPatientFromBooking || creatingPatient) return;\n setCreatingPatient(true);\n setSaveError(undefined);\n try {\n const created = await createPatientFromBooking({\n name: contact.typedName,\n phone: contact.phone,\n email: contact.email,\n });\n if (created && mountedRef.current) {\n setCreatedPatient({ id: created.id, name: created.name });\n focusPickerNextRef.current = true;\n setPatientId(created.id);\n /* B13: a patient made from a booking starts with both reminders. */\n setEmailReminder(true);\n setSmsReminder(true);\n }\n } catch (error) {\n if (mountedRef.current)\n setSaveError(\n error instanceof Error && error.message.trim()\n ? error.message\n : t(bookingKey('createPatientFailed')),\n );\n } finally {\n if (mountedRef.current) setCreatingPatient(false);\n }\n };\n /* A locked scope keeps the stored patient: drop an unsaved pick made under\n a scope that allowed it. */\n useEffect(() => {\n if (patientLocked) setPatientId(prefill?.patientId ?? '');\n }, [patientLocked, 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 ?? parseIsoDate(data.initialDateIso, data.nowIso),\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 /* B21: a new appointment takes the practice's only active operator, and\n its only chair. A care that does not allow it clears it (rule A6). */\n const [operatorId, setOperatorId] = useState(\n prefill?.operatorId ??\n (!isEdit && operatorOptions.length === 1 ? operatorOptions[0].id : NONE),\n );\n const [chairId, setChairId] = useState(\n prefill?.chairId ??\n (!isEdit && data.chairs.length === 1 ? data.chairs[0].id : NONE),\n );\n /* Empty = none picked: the grid draws the care's colour then. Only a\n hand pick (or a stored colour on edit) is ever saved. */\n const [colorHex, setColorHex] = useState(() =>\n isEdit ? (prefill?.colorHex ?? '') : initialEditorColor(prefill),\n );\n const [care, setCare] = useState(prefill?.care ?? '');\n /* B7: an edit keeps the saved ticks; a new appointment and a booking\n being completed take the practice defaults, and a default the host\n does not pass is OFF. */\n const takesReminderDefaults = !isEdit || Boolean(prefill?.bookingContact);\n const [emailReminder, setEmailReminder] = useState(\n takesReminderDefaults\n ? platform?.defaultReminders?.email === true\n : prefill?.emailReminder === true,\n );\n const [smsReminder, setSmsReminder] = useState(\n takesReminderDefaults\n ? platform?.defaultReminders?.sms === true\n : prefill?.smsReminder === true,\n );\n /* B12: starts on unknown; an edit shows the saved answer. */\n const [firstVisit, setFirstVisit] = useState<FirstVisitAnswer>(\n prefill?.firstVisit ?? 'unknown',\n );\n /* B23: an edit whose host passed no saved value for one of these three\n leaves it out of the save while the user has not touched it, so a\n host that has not hydrated it yet never has it overwritten with\n \"off\" or \"unknown\". Touched, or passed, it is sent. */\n const openingTicks = useRef({ emailReminder, smsReminder, firstVisit });\n const savedFieldKnown = (\n field: 'emailReminder' | 'smsReminder' | 'firstVisit',\n current: boolean | FirstVisitAnswer,\n ): boolean =>\n !isEdit ||\n Boolean(prefill?.bookingContact) ||\n prefill?.[field] !== undefined ||\n current !== openingTicks.current[field];\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: isBilled(item),\n billing: item.billing,\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 ...(r.billing ? { billing: r.billing } : {}),\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. The colour is never touched:\n the care's colour is drawn, not written. Skipped on mount so a saved\n 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 }, [linkKey, currentLink, data, canEditCare]);\n const linkedCares = !canEditCare\n ? prefill?.cares\n : currentLink\n ? data.careEntriesFromLink(currentLink)\n : prefill?.cares;\n /* HTP-5059 — the catalogue cares behind the current link, resolved to\n their full `CalendarCare` (operatorIds/chairIds live there, not on\n the lighter `CalendarCareEntry`). P31: only a NEW price-list\n appointment is restricted, by the union of its cares via\n calendar-care-rules. An edit and a care-plan appointment keep every\n operator and chair listed. */\n const linkedCareIds = useMemo<string[]>(() => {\n if (careLink === 'plan' && plan) {\n return plan.entries\n .filter((e) => entryIds.includes(e.id))\n .map((e) => e.careId);\n }\n if (careLink === 'priceList') {\n return priceRows.filter((r) => r.careId).map((r) => r.careId);\n }\n /* Neither relation is active — `careLink` is still its NONE default.\n That is also the shape of a Find-free-slots handoff: the finder\n seeds `prefill.cares` (for the label/colour) but never a formal\n `careLink`, so without this fallback the restriction it should\n carry over is silently dropped and the Selects widen back to\n everyone. Mirrors the fallback `linkedCares` above already takes\n for the same reason. */\n return (prefill?.cares ?? [])\n .map((c) => c.careId)\n .filter((id): id is string => Boolean(id));\n }, [careLink, plan, entryIds, priceRows, prefill?.cares]);\n /* The restriction applies to a create only; the consents (HTP-3395) list\n the linked cares on an edit and a care plan too. */\n const selectedCareIds = useMemo<string[]>(\n () => (isEdit || careLink === 'plan' ? [] : linkedCareIds),\n [isEdit, careLink, linkedCareIds],\n );\n const selectedCares = useMemo<CalendarCare[]>(\n () =>\n selectedCareIds\n .map((id) => data.careById(id))\n .filter((c): c is CalendarCare => Boolean(c)),\n [selectedCareIds, data],\n );\n const operatorRestriction = useMemo(\n () => allowedOperatorsFor(selectedCares, operatorOptions),\n [selectedCares, operatorOptions],\n );\n const chairRestriction = useMemo(\n () => allowedChairsFor(selectedCares, data.chairs),\n [selectedCares, data.chairs],\n );\n /* CREATE only: a care change that makes the current pick ineligible\n resets it to Unassigned, mirroring the finder (calendar-care-rules).\n An edit is never restricted, so it keeps whatever it already has. */\n useEffect(() => {\n if (isEdit) return;\n setOperatorId((prev) =>\n prev !== NONE && !isResourceAllowed(prev, operatorRestriction)\n ? NONE\n : prev,\n );\n setChairId((prev) =>\n prev !== NONE && !isResourceAllowed(prev, chairRestriction) ? NONE : prev,\n );\n }, [isEdit, operatorRestriction, chairRestriction]);\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 }, [slotPatch]);\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 /* A host reopening a draft seeds the rule (create only). A Custom\n rule needs the Custom fields; without them it falls back to its\n plain frequency rather than saving a rule the form cannot show. */\n const seededRule = isEdit ? undefined : prefill?.recurrence;\n const seededCustom =\n seededRule !== undefined &&\n isCustomRule(seededRule) &&\n (platform?.recurrenceCustom ?? platform?.recurrenceExtras !== false);\n const [repeats, setRepeats] = useState(seededRule !== undefined);\n const [recurrence, setRecurrence] = useState<RecurrenceFrequency | 'custom'>(\n seededCustom ? 'custom' : (seededRule?.frequency ?? 'weekly'),\n );\n const [customRecurrence, setCustomRecurrence] =\n useState<CustomRecurrenceValue>(() =>\n seededRule && seededCustom\n ? customRecurrenceFromRule(seededRule)\n : defaultCustomRecurrence(),\n );\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 seededRule?.ends ?? 'count',\n );\n const [recurrenceCount, setRecurrenceCount] = useState<number | null>(\n seededRule?.ends === 'count' ? seededRule.count : 4,\n );\n const [recurrenceUntil, setRecurrenceUntil] = useState<Date | undefined>(\n seededRule?.untilDate,\n );\n const [skipClosedDays, setSkipClosedDays] = useState(\n seededRule?.skipClosedDays ??\n platform?.recurrenceSkipClosedDaysDefault ??\n true,\n );\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 recurrenceCustomOn = platform?.recurrenceCustom ?? recurrenceExtras;\n const skipClosedDaysOn =\n platform?.recurrenceSkipClosedDays ?? recurrenceExtras;\n /* \"On a date\" with no usable date books a single appointment: the\n expander stops at the first repeat. Hold the save, say why in the\n field, and pull an end date the start has moved past forward. */\n const dayKey = (d: Date): number =>\n d.getFullYear() * 10000 + d.getMonth() * 100 + d.getDate();\n const untilRequired =\n !isEdit &&\n repeats &&\n capabilities?.editRecurrence !== false &&\n recurrenceExtras &&\n recurrenceEnds === 'until';\n const untilInvalid =\n untilRequired &&\n (!recurrenceUntil || (date && dayKey(recurrenceUntil) < dayKey(date)));\n useEffect(() => {\n if (!untilRequired || !date || !recurrenceUntil) return;\n if (dayKey(recurrenceUntil) < dayKey(date)) {\n setRecurrenceUntil(addMonthsClamped(date, 1));\n }\n }, [untilRequired, date, recurrenceUntil]);\n const recurrenceStart = date ?? new Date(data.nowIso);\n const recurrenceSummary = useRecurrenceSummary({\n frequency: recurrence,\n custom: customRecurrence,\n start: recurrenceStart,\n ends: recurrenceExtras ? recurrenceEnds : 'count',\n count: recurrenceCount,\n untilDate: recurrenceUntil,\n locale: locale ?? runtimeI18n.language,\n });\n const [addToWaitingList, setAddToWaitingList] = useState(\n isEdit && prefill?.addToWaitingList === true,\n );\n /* B14: on an edit the tick is offered only when the host says whether the\n appointment is in the list, since only then can unticking remove it. */\n const offersWaitingTick = !isEdit || prefill?.addToWaitingList !== undefined;\n const [status, setStatus] = useState<CalendarEventStatus | undefined>(\n prefill?.status ?? (isEdit ? undefined : 'confirmed'),\n );\n\n /* Treatment consents (HTP-3395). The host seam is synchronous: asked once\n per change of cares, appointment or seam, never on every render. */\n const consentsForCares = platform?.consentsForCares;\n const consentEventId = prefill?.editEventId;\n const consentItems = useMemo<readonly AppointmentConsentItem[]>(\n () =>\n !readOnly && linkedCareIds.length > 0 && consentsForCares\n ? consentsForCares(linkedCareIds, consentEventId)\n : [],\n [readOnly, linkedCareIds, consentsForCares, consentEventId],\n );\n /* B19: a missing consent starts TICKED on create and UNTICKED on edit, so\n an unrelated edit never sends one. We keep the ids the user flipped from\n that start, so a list that changes with the cares never needs resetting. */\n const [consentsFlipped, setConsentsFlipped] = useState<readonly string[]>([]);\n const consentTicked = (id: string): boolean =>\n isEdit ? consentsFlipped.includes(id) : !consentsFlipped.includes(id);\n const consentIds = consentItems\n .filter((c) => c.state === 'missing' && consentTicked(c.id))\n .map((c) => c.id);\n\n /* Medical devices (B9). The host answers for the slot; a pick lives\n only for that slot, so a new date, time or length asks the host to\n assign again. */\n const medicalDevicesForCares = platform?.medicalDevicesForCares;\n const deviceSlotKey = `${date?.getTime() ?? ''}|${time.hours}:${time.minutes}|${durationMin ?? ''}|${allDay}`;\n const [devicePicks, setDevicePicks] = useState<{\n slot: string;\n byCare: Readonly<Record<string, string>>;\n }>({ slot: deviceSlotKey, byCare: {} });\n const pickedDevices =\n devicePicks.slot === deviceSlotKey ? devicePicks.byCare : {};\n const deviceChoices = useMemo<readonly CareDeviceChoice[]>(() => {\n if (readOnly || !medicalDevicesForCares || !date || allDay) return [];\n if (linkedCareIds.length === 0) return [];\n const start = new Date(date);\n start.setHours(time.hours, time.minutes, 0, 0);\n return medicalDevicesForCares({\n careIds: linkedCareIds,\n start,\n durationMin: durationMin ?? 30,\n ...(prefill?.editEventId ? { eventId: prefill.editEventId } : {}),\n }).filter((c) => c.options.length > 0);\n // eslint-disable-next-line react-hooks/exhaustive-deps -- the slot key stands for date, time and length\n }, [\n readOnly,\n medicalDevicesForCares,\n linkedCareIds,\n deviceSlotKey,\n prefill?.editEventId,\n ]);\n const deviceAssignments = deviceChoices.flatMap((c) => {\n const deviceId = effectiveDeviceId(c, pickedDevices[c.careId]);\n return deviceId ? [{ careId: c.careId, deviceId }] : [];\n });\n\n /* Dirty tracking — Save/Cancel stay INACTIVE until something actually\n changed from the opening snapshot. */\n /* `typed` reads a resource the lists do not carry as Unassigned: the\n selects reset such a prefill on mount, and that is not the user's. */\n const serializeDraft = (typed = false): string => {\n const autoPlan =\n typed && !isEdit && careLink === 'plan' && entryIds.length === 0;\n return JSON.stringify({\n patientId,\n type,\n dateMs: date?.getTime() ?? null,\n time,\n durationMin,\n operatorId:\n typed && !operatorOptions.some((o) => o.id === operatorId)\n ? NONE\n : operatorId,\n chairId:\n typed && !data.chairs.some((c) => c.id === chairId) ? NONE : chairId,\n colorHex,\n care,\n emailReminder,\n smsReminder,\n firstVisit,\n /* A new appointment's patient auto-selects their open plan after the\n first render: with no line ticked that is not typed data. */\n careLink: autoPlan ? NONE : careLink,\n carePlanId: autoPlan ? '' : carePlanId,\n entryIds,\n phaseSelection,\n priceListId,\n priceRows,\n allDay,\n repeats,\n recurrence,\n customRecurrence,\n recurrenceEnds,\n recurrenceCount,\n recurrenceUntilMs: recurrenceUntil?.getTime() ?? null,\n skipClosedDays,\n addToWaitingList,\n status,\n pickedDevices,\n });\n };\n const initialDraftRef = useRef<string | null>(null);\n if (initialDraftRef.current === null) {\n initialDraftRef.current = serializeDraft();\n }\n /* An edit that only sends the visit's missing consents is a change too:\n Save is live while any is ticked (an edit starts them all unticked). */\n const dirty =\n (isEdit && consentIds.length > 0) ||\n serializeDraft() !== initialDraftRef.current;\n /* B18: typed data is a change from what the form opened with (for create,\n the prefill is not typed; a consent ticked or unticked from its start is).\n Saved, saving or accepted holds nothing. */\n const typedBaselineRef = useRef<string | null>(null);\n if (typedBaselineRef.current === null) {\n typedBaselineRef.current = serializeDraft(true);\n }\n const holdsTypedData =\n (serializeDraft(true) !== typedBaselineRef.current ||\n consentsFlipped.length > 0) &&\n !saving &&\n !accepted;\n useEffect(() => {\n if (editorGuard) editorGuard.dirty = holdsTypedData;\n }, [editorGuard, holdsTypedData]);\n useEffect(\n () => () => {\n if (editorGuard) editorGuard.dirty = false;\n },\n [editorGuard],\n );\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 /* A typed date on a closed day or holiday, or the chosen operator away\n that day (the chair axis cannot show absences). Never held: the\n banner warns and Save stays live (P25). */\n const rawClosure = date\n ? data.closureOn(\n localIsoDate(date),\n operatorId === NONE ? undefined : operatorId,\n )\n : null;\n /* Audit C9 — an absence can also ride in the busy-warning trio, as a\n sibling of the chair and operator warnings, instead of the date-side\n banner; the practice's own closures keep the banner. */\n const absenceWarns = platform?.operatorAbsenceWarning === true;\n const operatorAbsent = absenceWarns && rawClosure?.kind === 'absence';\n const closure = operatorAbsent ? null : rawClosure;\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 !descriptionTooLong &&\n !untilInvalid &&\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 save scope on edit, the\n required-documents sign mode and the branch. */\n const [recurringSaveMode, setRecurringSaveMode] =\n useState<RecurringScope>('this');\n const [signMode, setSignMode] =\n useState<RequiredDocsSignMode>(defaultSignMode);\n const signPatientRef = useRef(patientId);\n useEffect(() => {\n if (signPatientRef.current === patientId) return;\n signPatientRef.current = patientId;\n setSignMode(defaultSignMode());\n }, [patientId]);\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 /* B10: with the host's credits at none, a new appointment with a patient\n says so and links to buy them; the sign mode (it spends one) goes. */\n const noSignatureCredits =\n platform?.signatureCredits !== undefined &&\n platform.signatureCredits.available <= 0;\n const signModeOffered = unsignedDocs > 0 && !noSignatureCredits;\n const creditsMessageShown =\n noSignatureCredits && unsignedDocs > 0 && !isEdit && formRef.assigned;\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 /* B12: a new appointment asks the host for the proposal when a patient is\n chosen and when the date moves. The user's own answer always wins, and\n a new patient starts again from unknown. */\n const proposeFirstVisitRef = useRef(platform?.proposeFirstVisit);\n proposeFirstVisitRef.current = platform?.proposeFirstVisit;\n const firstVisitPickedRef = useRef(false);\n const firstVisitPatientRef = useRef(patientId);\n const proposeDateMs = date?.getTime();\n useEffect(() => {\n if (isEdit) return;\n if (firstVisitPatientRef.current !== patientId) {\n firstVisitPatientRef.current = patientId;\n firstVisitPickedRef.current = false;\n setFirstVisit('unknown');\n }\n const propose = proposeFirstVisitRef.current;\n if (!patientId || !propose || proposeDateMs === undefined) return;\n let current = true;\n Promise.resolve()\n .then(() => propose({ patientId, date: new Date(proposeDateMs) }))\n .then((answer) => {\n if (\n current &&\n !firstVisitPickedRef.current &&\n (answer === 'yes' || answer === 'no' || answer === 'unknown')\n )\n setFirstVisit(answer);\n })\n .catch(() => undefined);\n return () => {\n current = false;\n };\n }, [isEdit, patientId, proposeDateMs]);\n const requiredDevices =\n platform?.devicesByCare && !medicalDevicesForCares\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 /* B8: the patient's earliest same-day reminder per channel, from the\n host. A LATER visit loses that channel's tick, an EARLIER one keeps it;\n both say so. Only a channel whose practice default is on is checked. */\n const [sameDay, setSameDay] = useState<{ sms?: number; email?: number }>({});\n const sameDayAskRef = useRef(platform?.sameDayReminders);\n sameDayAskRef.current = platform?.sameDayReminders;\n const sameDayDayMs = date ? new Date(date).setHours(0, 0, 0, 0) : undefined;\n const editedId = prefill?.editEventId;\n useEffect(() => {\n setSameDay({});\n const ask = sameDayAskRef.current;\n if (!patientId || !ask || sameDayDayMs === undefined) return;\n let current = true;\n Promise.resolve()\n .then(() =>\n ask({\n patientId,\n date: new Date(sameDayDayMs),\n eventId: editedId,\n }),\n )\n .then((answer) => {\n if (!current) return;\n const ms = (v?: Date | string): number | undefined => {\n const n = v === undefined ? NaN : new Date(v).getTime();\n return Number.isNaN(n) ? undefined : n;\n };\n setSameDay({ sms: ms(answer?.sms), email: ms(answer?.email) });\n })\n .catch(() => undefined);\n return () => {\n current = false;\n };\n }, [patientId, sameDayDayMs, editedId]);\n const sameDayOf = (channel: 'sms' | 'email'): 'earlier' | 'later' | null => {\n const first = sameDay[channel];\n if (\n first === undefined ||\n !slotStart ||\n platform?.defaultReminders?.[channel] !== true\n )\n return null;\n /* `earlier`: the patient's other visit comes first and holds the\n day's reminder. */\n return slotStart.getTime() > first ? 'earlier' : 'later';\n };\n const smsSameDay = sameDayOf('sms');\n const emailSameDay = sameDayOf('email');\n useEffect(() => {\n if (takesReminderDefaults && smsSameDay === 'earlier')\n setSmsReminder(false);\n }, [smsSameDay, takesReminderDefaults]);\n useEffect(() => {\n if (takesReminderDefaults && emailSameDay === 'earlier')\n setEmailReminder(false);\n }, [emailSameDay, takesReminderDefaults]);\n /* B8: a telehealth visit with a patient needs a reminder. Only when both\n ticks are known: an edit whose host passed neither saved value cannot\n say they are off. */\n const telehealthNoReminder =\n type === 'telehealth' &&\n formRef.assigned &&\n savedFieldKnown('emailReminder', emailReminder) &&\n savedFieldKnown('smsReminder', smsReminder) &&\n !(emailReminder && (!gateOnPatient || emailOffered)) &&\n !(smsReminder && (!gateOnPatient || smsOffered));\n const reminderRefusedShown = reminderRefused && telehealthNoReminder;\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 !hostScopes &&\n isEdit &&\n platform?.recurringScope === true &&\n capabilities?.editRecurrence !== false;\n const cleanupApplies =\n isEdit &&\n (hostScopes\n ? series?.offersCarePlanCleanup === true\n : platform?.carePlanCleanup === true);\n /* R3: the delete dialog offers the host's scopes, else the demo's. A\n changed occurrence still asks here, though its edit does not. */\n const deleteScopeApplies =\n isEdit &&\n (platform?.recurringDeleteScope ?? platform?.recurringScope) === true &&\n capabilities?.editRecurrence !== false;\n const deleteScopes =\n hostScopes ?? (deleteScopeApplies ? RECURRING_SCOPES : undefined);\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 const chairFieldRef = useRef<HTMLDivElement>(null);\n useEditorInitialFocus(prefill?.initialFocus, {\n patient: patientFieldRef,\n operator: operatorFieldRef,\n chair: chairFieldRef,\n });\n useEffect(() => {\n if (!focusPickerNextRef.current || !patientId) return;\n focusPickerNextRef.current = false;\n patientFieldRef.current\n ?.querySelector<HTMLElement>('[role=\"combobox\"]')\n ?.focus();\n }, [patientId]);\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: signModeOffered ? signMode : undefined,\n consentIds: consentIds.length > 0 ? consentIds : undefined,\n medicalDevices:\n deviceAssignments.length > 0 ? deviceAssignments : 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 if (telehealthNoReminder) {\n setReminderRefused(true);\n return;\n }\n savingRef.current = true;\n setSaving(true);\n setSaveError(undefined);\n try {\n await onSave(\n {\n editEventId: prefill?.editEventId,\n /* B23: the save carries the whole appointment, and a field left\n empty is sent as empty (null), never left out. */\n ...(patientLocked ? {} : { patientId: patientId || null }),\n isTelehealth: type === 'telehealth',\n date,\n time,\n durationMin: durationMin ?? 30,\n operatorId: operatorId === NONE ? null : operatorId,\n chairId: chairId === NONE ? null : chairId,\n colorHex,\n ...(capabilities?.editDescription === false ? {} : { care }),\n allDay,\n ...(canEditCare\n ? { cares: prefill?.cares, careLink: currentLink }\n : {}),\n waitingEntryId: prefill?.waitingEntryId,\n ...(offersWaitingTick ? { addToWaitingList } : {}),\n /* B2, B7: no patient, or a channel the patient cannot take, is\n sent as off, as the boxes show it. */\n ...(savedFieldKnown('emailReminder', emailReminder)\n ? {\n emailReminder:\n showReminders &&\n formRef.assigned &&\n emailReminder &&\n (!gateOnPatient || emailOffered),\n }\n : {}),\n ...(savedFieldKnown('smsReminder', smsReminder)\n ? {\n smsReminder:\n showReminders &&\n formRef.assigned &&\n smsReminder &&\n (!gateOnPatient || smsOffered),\n }\n : {}),\n ...(savedFieldKnown('firstVisit', firstVisit)\n ? { firstVisit: showFirstVisit ? firstVisit : 'unknown' }\n : {}),\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 ...(recurrence === 'custom'\n ? customRecurrenceRule(customRecurrence, recurrenceStart)\n : { frequency: recurrence }),\n ends: recurrenceExtras ? recurrenceEnds : 'count',\n count: recurrenceCount ?? 2,\n untilDate:\n recurrenceExtras && recurrenceEnds === 'until'\n ? recurrenceUntil\n : undefined,\n skipClosedDays: skipClosedDaysOn ? 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 /* The close that follows is the host's, after a save: it never asks. */\n if (editorGuard) editorGuard.dirty = false;\n if (saveExtras.recurringSaveMode)\n onRecurringScopeChosen?.({\n action: 'edit',\n scope: saveExtras.recurringSaveMode,\n });\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 = (options: DeleteOptions): void => {\n if (savingRef.current || acceptedRef.current) return;\n if (prefill?.editEventId) {\n if (deleteScopes)\n onRecurringScopeChosen?.({ action: 'delete', scope: options.scope });\n onDelete?.(prefill.editEventId, options);\n }\n if (editorGuard) editorGuard.dirty = false;\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 noteUnrecordedEdits={noteUnrecordedEdits}\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 {reminderRefusedShown ? (\n <Alert id={reminderAlertId} variant=\"error\" announce=\"assertive\">\n <Alert.Description>\n {t(key('telehealthNeedsReminder'))}\n </Alert.Description>\n </Alert>\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 dir=\"ltr\"\n >\n {prefill.bookingContact.phone}\n </a>\n <a\n className=\"type-body-sm ds:truncate\"\n href={`mailto:${prefill.bookingContact.email}`}\n dir=\"ltr\"\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 && !patientLocked ? (\n <span className=\"type-body-sm ds:text-start ds:text-[color:var(--info-foreground)]\">\n {t(bookingKey('searchPatientHint'))}\n </span>\n ) : null}\n {!patientId &&\n !patientLocked &&\n !readOnly &&\n createPatientFromBooking ? (\n <Button\n type=\"button\"\n size=\"sm\"\n intent=\"outline\"\n className=\"ds:self-start\"\n loading={creatingPatient}\n data-action=\"create-patient-from-booking\"\n onClick={() => void createBookingPatient()}\n >\n {t(bookingKey('createPatient'))}\n </Button>\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 patientLocked\n ? (capabilities?.patientLockedReason ??\n t(key('patientLocked')))\n : prefill?.callToAction === 'processBooking'\n ? t('calendarWorkspace.backlog.processPatientHint')\n : undefined\n }\n >\n {patientLocked ? (\n <CalendarPatientLocked\n value={prefill?.patientId ?? ''}\n fallbackLabel={formPatientLabel}\n />\n ) : (\n <CalendarPatientPicker\n value={patientId}\n onValueChange={setPatientId}\n onCreatePatient={\n readOnly ||\n (prefill?.bookingContact && createPatientFromBooking)\n ? undefined\n : platform?.createPatient\n }\n selectedLabel={\n createdPatient?.id === patientId && !formRef.record\n ? createdPatient.name\n : formPatientLabel\n }\n />\n )}\n </FormField>\n {/* Required documents (create, patient chosen): how the signature\n request goes out — the platform's required-objects sign mode. */}\n {signModeOffered ? (\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 {creditsMessageShown && platform?.signatureCredits ? (\n <Alert\n variant=\"warning\"\n announce=\"polite\"\n className={EDITOR_FIELD_WIDE}\n >\n <Alert.Description>\n {t(key('signatureCreditsNone'))}{' '}\n <Link href={platform.signatureCredits.buyHref} external>\n {t(key('signatureCreditsBuy'))}\n </Link>\n </Alert.Description>\n </Alert>\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={(next) => {\n firstVisitPickedRef.current = true;\n setFirstVisit(next as FirstVisitAnswer);\n }}\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 /* `billed` is isBilled() of the host's row: a reversed\n bill has no live invoice, so that row stays open. */\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={data.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 <StateBackedTextInput\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 {/* Treatment consents the chosen cares need (HTP-3395): the\n missing ones are created and sent with this save. */}\n {consentItems.length > 0 ? (\n <fieldset\n data-editor-consents=\"\"\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('consents'))}\n </legend>\n <p className=\"type-meta ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t(key('consentsHint'))}\n </p>\n {consentItems.map((c) =>\n c.state === 'missing' ? (\n <Checkbox\n key={c.id}\n label={c.name}\n checked={consentTicked(c.id)}\n onCheckedChange={() =>\n setConsentsFlipped((flipped) =>\n flipped.includes(c.id)\n ? flipped.filter((id) => id !== c.id)\n : [...flipped, c.id],\n )\n }\n />\n ) : (\n <p key={c.id} className=\"type-body ds:m-0\">\n {`${c.name}: ${t(\n detailKey(\n c.state === 'signed'\n ? 'consentSigned'\n : 'consentRequested',\n ),\n )}`}\n </p>\n ),\n )}\n </fieldset>\n ) : null}\n {/* Medical devices (B9): one choice per care that needs one.\n A busy device cannot be picked; with none free the editor\n says so and the save still goes ahead. */}\n {deviceChoices.length > 0 ? (\n <fieldset\n data-editor-devices=\"\"\n className={`${EDITOR_FIELD_WIDE} ds:m-0 ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:border-0 ds:p-0`}\n >\n <legend className=\"type-label ds:text-foreground ds:p-0\">\n {t(key('devices'))}\n </legend>\n {deviceChoices.map((choice) => {\n const careName =\n data.careById(choice.careId)?.name ?? choice.careId;\n const chosen = effectiveDeviceId(\n choice,\n pickedDevices[choice.careId],\n );\n const allBusy = choice.options.every((o) => o.busy);\n return (\n <div\n key={choice.careId}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\"\n >\n <FormField label={careName}>\n <Select\n options={choice.options.map((o) => ({\n value: o.id,\n label: o.busy\n ? `${o.name} (${t(key('deviceBusy'))})`\n : o.name,\n disabled: o.busy === true,\n }))}\n value={chosen ?? ''}\n placeholder={t(key('deviceNoneFree'))}\n onValueChange={(next) =>\n setDevicePicks({\n slot: deviceSlotKey,\n byCare: {\n ...pickedDevices,\n [choice.careId]: next,\n },\n })\n }\n />\n </FormField>\n {allBusy ? (\n <Alert variant=\"warning\" announce=\"polite\">\n <Alert.Description>\n {t(key('devicesAllBusy'), { care: careName })}\n </Alert.Description>\n </Alert>\n ) : null}\n </div>\n );\n })}\n </fieldset>\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 aria-invalid={reminderRefusedShown || undefined}\n aria-describedby={\n reminderRefusedShown ? reminderAlertId : undefined\n }\n onCheckedChange={(c) => {\n setReminderRefused(false);\n setSmsReminder(c === true);\n }}\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 aria-invalid={reminderRefusedShown || undefined}\n aria-describedby={\n reminderRefusedShown ? reminderAlertId : undefined\n }\n onCheckedChange={(c) => {\n setReminderRefused(false);\n setEmailReminder(c === true);\n }}\n />\n </>\n ) : null}\n <Checkbox\n label={t(key('allDay'))}\n checked={allDay}\n onCheckedChange={(c) => setAllDay(c === true)}\n />\n {/* Repeat is CREATE-only, as in platform: an existing\n occurrence reads its rule back from the details panel's\n series line. Waiting list is offered on an edit too (B14)\n when the host says whether the entry exists. */}\n {!isEdit ? (\n <Checkbox\n label={t(key('repeats'))}\n disabled={capabilities?.editRecurrence === false}\n checked={repeats}\n onCheckedChange={(c) => setRepeats(c === true)}\n />\n ) : null}\n {offersWaitingTick ? (\n <Checkbox\n label={t(key('addToWaitingList'))}\n checked={addToWaitingList}\n onCheckedChange={(c) => setAddToWaitingList(c === true)}\n />\n ) : null}\n </div>\n </fieldset>\n {showReminders && formRef.assigned\n ? (\n [\n ['sms', smsSameDay, 'smsReminder'],\n ['email', emailSameDay, 'emailReminder'],\n ] as const\n ).map(([channel, state, label]) =>\n /* A tick that an edit keeps is never removed, so it\n never says it was. */\n state === null ||\n (state === 'earlier' && !takesReminderDefaults) ? null : (\n <Alert\n key={channel}\n variant=\"info\"\n announce=\"polite\"\n className={EDITOR_FIELD_WIDE}\n >\n <Alert.Description>\n {t(\n key(\n state === 'earlier'\n ? 'sameDayReminderEarlier'\n : 'sameDayReminderLater',\n ),\n { channel: t(key(label)) },\n )}\n </Alert.Description>\n </Alert>\n ),\n )\n : null}\n {!isEdit ? (\n <>\n {repeats ? (\n <>\n <FormField\n className={EDITOR_FIELD_SHORT}\n label={t(key('recurrence'))}\n >\n <Select\n options={[\n ...RECURRENCE_FREQUENCIES.map((value) => ({\n value,\n label: t(key(RECURRENCE_LABEL_KEY[value])),\n })),\n ...(recurrenceCustomOn\n ? [\n {\n value: 'custom',\n label: t(key('recurrenceCustom')),\n },\n ]\n : []),\n ]}\n value={recurrence}\n onValueChange={(v) =>\n setRecurrence(v as RecurrenceFrequency | 'custom')\n }\n />\n </FormField>\n {/* HTP-4261: the Custom rule opens in place, never as a\n dialog on top of this one. */}\n {recurrenceCustomOn && recurrence === 'custom' ? (\n <CustomRecurrenceFields\n value={customRecurrence}\n onChange={setCustomRecurrence}\n start={recurrenceStart}\n locale={locale ?? runtimeI18n.language}\n fieldClassName={EDITOR_FIELD_SHORT_STACKED}\n wideClassName={EDITOR_FIELD_WIDE}\n />\n ) : null}\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 error={\n untilInvalid\n ? /* The grid's existing \"on or after\" message:\n the same rule, already translated. */\n t('dataTable.agGrid.minDateValidation', {\n var0: new Intl.DateTimeFormat(panelLocale, {\n dateStyle: 'medium',\n }).format(date ?? new Date(data.nowIso)),\n })\n : undefined\n }\n >\n <DatePicker\n value={recurrenceUntil}\n onChange={setRecurrenceUntil}\n minDate={date}\n />\n </FormField>\n )}\n {skipClosedDaysOn ? (\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 {recurrenceCustomOn && recurrenceSummary ? (\n <RecurrenceSummaryLine\n summary={recurrenceSummary}\n className={EDITOR_FIELD_WIDE}\n />\n ) : null}\n </>\n ) : null}\n </>\n ) : null}\n {/* Allocation — resource (chair) then operator, the modal's\n closing pair. HTP-5059: both lists narrow to what the selected\n care(s) allow on CREATE of a price-list appointment: the union\n across the cares, lifted by one care with an empty\n operatorIds/chairIds; see calendar-care-rules. */}\n <FormField\n ref={chairFieldRef}\n className={EDITOR_FIELD_SHORT}\n label={t(detailKey('chair'))}\n >\n <Select\n showDescriptions\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 ...chairRestriction.list.map((c) => ({\n value: c.id,\n label: c.title,\n })),\n ]}\n value={chairId}\n onValueChange={(next) => {\n setChairId(next);\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 showDescriptions\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 ...operatorRestriction.list.map((o) => ({\n value: o.id,\n label: o.title,\n })),\n ]}\n value={operatorId}\n onValueChange={(next) => {\n setOperatorId(next);\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={() =>\n editorGuard ? editorGuard.ask(closeSheet) : closeSheet()\n }\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={() => {\n if (prefill?.editEventId)\n onDeleteInitiated?.(prefill.editEventId);\n setConfirmDeleteOpen(true);\n }}\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 <CalendarDeleteConfirm\n open={confirmDeleteOpen}\n onOpenChange={setConfirmDeleteOpen}\n scopes={deleteScopes}\n offersCarePlanCleanup={cleanupApplies}\n onConfirm={handleDeleteConfirmed}\n />\n ) : null}\n </div>\n );\n}\n\n/* The labelled indicator chips live with AppointmentDetailsPanel;\n re-exported here for the calendar surface and its demos. */\nexport { IndicatorChips };\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('ui');\n const data = useCalendarData();\n const patient = patientRef.record;\n return (\n <AppointmentIdentityStrip\n /* Record, else the row's own title, else the honest label: never a\n blank that would leave a nameless heading. */\n name={patientRefName(\n patientRef,\n row.event.title,\n t('calendarWorkspace.details.patientNotLoaded'),\n )}\n avatarSrc={patient?.avatarSrc}\n unresolved={patientRef.unresolved}\n status={row.event.status}\n flags={row.event}\n /* No date of birth from the host: no age beside the name. */\n age={\n showAge && patient?.dobIso\n ? patientAgeYears(patient.dobIso, data)\n : undefined\n }\n onOpenPatient={\n onOpenPatient && patient ? () => onOpenPatient(patient) : undefined\n }\n highlightedAnamnesisCount={patient?.highlightedAnamnesisCount}\n expiredAnamnesisCount={patient?.expiredAnamnesisCount}\n anamnesisAnswers={anamnesisAnswers}\n />\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('ui');\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('ui');\n const key = (suffix: string): string => `calendarWorkspace.details.${suffix}`;\n const { t: tUi } = useTranslation('ui');\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: data.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 {isBilled(entry) ? (\n <Badge variant=\"neutral\" size=\"sm\">\n {tUi('carePlanEntryCard.flag.billed')}\n </Badge>\n ) : null}\n {entry.billing === 'reversed' ? (\n <Badge\n variant=\"warning\"\n size=\"sm\"\n title={tUi('treatmentReceipt.billReversed')}\n >\n {tUi('treatmentReceipt.unbilled')}\n <VisuallyHidden>\n {`, ${tUi('treatmentReceipt.billReversed')}`}\n </VisuallyHidden>\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>{money.format(meta.billableAmount)}</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, '')}`} dir=\"ltr\">\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\n className=\"ds:truncate\"\n href={`mailto:${patient.email}`}\n dir=\"ltr\"\n >\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\n href={`tel:${platform.bookingPhone.replace(/\\s/g, '')}`}\n dir=\"ltr\"\n >\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('ui');\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={isBilled(entry)}\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:[:where(&)]:border-[length:var(--surface-border-width,var(--border-width-sm))] ds:border-[color:var(--card-border)] 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('ui');\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 onCreatePatient,\n}: {\n items: BacklogItem[];\n /** \"Create patient\" in the waiting-list entry form's patient search. */\n onCreatePatient?: CalendarCreatePatient;\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('ui');\n const data = useCalendarData();\n const { t: tUi } = useTranslation('ui');\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. Uncontrolled, so a patient's name never reaches\n the input's `value` attribute; nothing here sets the query\n but typing, clear and Escape, which all come through onInput. */}\n <SearchInput\n size=\"sm\"\n variant=\"inline\"\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 onCreatePatient={onCreatePatient}\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 rail's backlog queue: every appointment in view */\n/* still missing a patient, an operator or (where the practice has */\n/* chairs) a chair, whatever its origin. Formerly the platform's */\n/* \"Prenotazioni online\" page (online-only); decision 2026-09-22 widened */\n/* it to desk-created gaps too. Same row actions: every one opens the */\n/* editor to complete the appointment. The platform's online-bookings */\n/* page itself survives for the booking e-mail and the top-bar link. */\n/* ------------------------------------------------------------------ */\n\n/** One calendar day's worth of backlog cards, oldest booking date first\n * among groups (groups themselves sort newest first — see below). A\n * desk-created card carries no `bookedAt`, so it groups under its own\n * appointment date instead. */\ninterface BookingDateGroup {\n dateKey: string;\n date: Date;\n views: BookingRowView[];\n}\n\nfunction groupBookingViewsByDate(\n views: readonly BookingRowView[],\n): BookingDateGroup[] {\n const groups = new Map<string, BookingDateGroup>();\n for (const view of views) {\n const date = view.bookedAt ?? view.start;\n const dateKey = Number.isFinite(date.getTime())\n ? date.toISOString().slice(0, 10)\n : 'unknown';\n const existing = groups.get(dateKey);\n if (existing) existing.views.push(view);\n else groups.set(dateKey, { dateKey, date, views: [view] });\n }\n // Newest booking date first — the platform's own \"Prenotazioni online\"\n // sort, kept for the desk-created groups too.\n return Array.from(groups.values()).sort(\n (a, b) => b.date.getTime() - a.date.getTime(),\n );\n}\n\n/* The cog's mark, borrowed from the rail's own badge slot: a decorative\n dot pinned to the trigger's corner. A dot, not a count, since a numeral\n beside a star and a close reads as a quantity of appointments. The\n accessible name carries the same fact in words, so it is never colour\n alone. */\nconst BACKLOG_SETTINGS_MARK_CLASS = [\n 'ds:pointer-events-none ds:absolute',\n 'ds:-top-[var(--spacing-2xs)] ds:-end-[var(--spacing-2xs)]',\n 'ds:size-[var(--spacing-sm)] ds:rounded-[var(--radius-full)]',\n 'ds:bg-[color:var(--accent)]',\n 'ds:outline-2 ds:outline-solid ds:outline-[color:var(--background)]',\n 'ds:forced-colors:bg-[Highlight] ds:forced-colors:outline-[Canvas]',\n].join(' ');\n\n/** The hint under the menu's label: the label's inset, at body weight,\n * and free to wrap where a menu row truncates. */\nconst BACKLOG_SETTINGS_HINT_CLASS = [\n 'type-meta',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:pb-[var(--spacing-xs)]',\n 'ds:text-[color:var(--muted-foreground)]',\n].join(' ');\n\n/** True while a switch the panel actually offers is off, so the list on\n * screen is not the whole backlog. A chairless practice never shows the\n * chair switch, so a stored `chair: false` cannot narrow anything. */\nfunction backlogIsNarrowed(\n filters: Readonly<Record<BacklogGap, boolean>> | undefined,\n chairsExist: boolean,\n): boolean {\n if (!filters) return false;\n return (\n !filters.patient || !filters.operator || (chairsExist && !filters.chair)\n );\n}\n\n/**\n * The queue's settings, behind one cog in the `PanelHeader` action cluster\n * beside the rail's injected star and close.\n *\n * A View menu (`DropdownMenu` with `SwitchItem`s), like the calendar\n * toolbar's display cog: each gap is a `menuitemcheckbox` that stays open\n * on toggle, and \"Reset to defaults\" restores `DEFAULT_BACKLOG_FILTERS`.\n */\nfunction BacklogSettingsMenu({\n filters,\n chairsExist,\n narrowed,\n onFiltersChange,\n}: {\n filters: Readonly<Record<BacklogGap, boolean>>;\n chairsExist: boolean;\n narrowed: boolean;\n onFiltersChange?: (filters: Readonly<Record<BacklogGap, boolean>>) => void;\n}) {\n const { t } = useTranslation('ui');\n const hintId = useId();\n const setFilter = (gap: BacklogGap, checked: boolean): void => {\n onFiltersChange?.({ ...filters, [gap]: checked });\n };\n return (\n <DropdownMenu.Root id=\"calendar-backlog-settings\">\n {/* A positioned slot, as the rail uses for its tool badges: the\n IconButton renders no children of its own, so the mark rides\n beside the trigger rather than inside it. */}\n <span className=\"ds:relative ds:inline-flex\">\n <DropdownMenu.Trigger asChild>\n <IconButton\n intent=\"ghost\"\n size=\"sm\"\n icon={<Settings aria-hidden=\"true\" />}\n data-backlog-settings=\"\"\n data-narrowed={narrowed ? '' : undefined}\n aria-label={t(\n bookingKey(narrowed ? 'settingsNarrowed' : 'settings'),\n )}\n />\n </DropdownMenu.Trigger>\n {narrowed ? (\n <span aria-hidden=\"true\" className={BACKLOG_SETTINGS_MARK_CLASS} />\n ) : null}\n </span>\n <DropdownMenu.Content\n align=\"end\"\n className=\"ds:w-64\"\n aria-describedby={hintId}\n >\n <DropdownMenu.Label>\n {t(bookingKey('settingsTitle'))}\n </DropdownMenu.Label>\n {/* A div, not a <p>: a paragraph role is not an allowed child of\n role=\"menu\", while a generic div is passed through. */}\n <div id={hintId} className={BACKLOG_SETTINGS_HINT_CLASS}>\n {t(bookingKey('settingsHint'))}\n </div>\n <DropdownMenu.Group data-component=\"calendar-backlog-filters\">\n <DropdownMenu.SwitchItem\n name=\"withoutPatient\"\n checked={filters.patient}\n onCheckedChange={(checked) => setFilter('patient', checked)}\n >\n {t(bookingKey('filterNoPatient'))}\n </DropdownMenu.SwitchItem>\n <DropdownMenu.SwitchItem\n name=\"withoutOperator\"\n checked={filters.operator}\n onCheckedChange={(checked) => setFilter('operator', checked)}\n >\n {t(bookingKey('filterNoOperator'))}\n </DropdownMenu.SwitchItem>\n {chairsExist ? (\n <DropdownMenu.SwitchItem\n name=\"withoutChair\"\n checked={filters.chair}\n onCheckedChange={(checked) => setFilter('chair', checked)}\n >\n {t(bookingKey('filterNoChair'))}\n </DropdownMenu.SwitchItem>\n ) : null}\n </DropdownMenu.Group>\n <DropdownMenu.Separator />\n <DropdownMenu.Item\n startIcon={<RotateCcw aria-hidden=\"true\" />}\n onSelect={() => onFiltersChange?.(DEFAULT_BACKLOG_FILTERS)}\n >\n {t('common.resetToDefaults')}\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n );\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 resourceKind,\n filters,\n onFiltersChange,\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 /** The grid's column axis — chair-columns hide a chairless row, so the\n * panel says so once when that is the current view. */\n resourceKind?: WorkspaceDisplaySettings['resourceKind'];\n /** The three gap switches, behind the header's settings cog. `bookings`\n * already arrives filtered by the host (`CalendarWorkspace` applies\n * `filterBacklogViews` before this panel ever sees the rows); these two\n * only drive the controls themselves and are optional so a host\n * bypassing the workspace still gets an unfiltered list rather than a\n * crash. Omit `filters` and no cog is rendered. */\n filters?: Readonly<Record<BacklogGap, boolean>>;\n onFiltersChange?: (filters: Readonly<Record<BacklogGap, boolean>>) => void;\n}) {\n const { t } = useTranslation('ui');\n const data = useCalendarData();\n const chairsExist = data.chairs.length > 0;\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 groups = useMemo(() => groupBookingViewsByDate(views), [views]);\n const hasHiddenChairRows =\n resourceKind === 'chair' && views.some((view) => view.needsChair);\n /* One reading, two places: the cog wears the mark, and an empty queue\n says the settings narrowed it rather than claiming there is nothing\n left to do — which would be a false claim while a switch is off. */\n const narrowed = backlogIsNarrowed(filters, chairsExist);\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 const renderCard = (view: BookingRowView): ReactNode => {\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 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={<ListTodo aria-hidden=\"true\" />}\n sticky\n divider\n /* Panel-owned, so it lands inline-start of the star and close the\n rail injects through PanelHeaderActionsProvider. */\n actions={\n filters ? (\n <BacklogSettingsMenu\n filters={filters}\n chairsExist={chairsExist}\n narrowed={narrowed}\n onFiltersChange={onFiltersChange}\n />\n ) : undefined\n }\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 {hasHiddenChairRows ? (\n <p className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\">\n {t(bookingKey('notShownOnChairAxis'))}\n </p>\n ) : null}\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={narrowed ? 'no-results' : 'first-use'}\n size=\"sm\"\n title={t(bookingKey('emptyTitle'))}\n description={\n narrowed ? t(bookingKey('emptyNarrowed')) : undefined\n }\n />\n ) : null\n ) : (\n <div\n aria-busy={status === 'loading'}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n {groups.map((group) => (\n <section\n key={group.dateKey}\n aria-label={shortDay(locale ?? 'en', group.date)}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <h3 className=\"type-label ds:m-0 ds:uppercase ds:text-start ds:text-[color:var(--muted-foreground)]\">\n {shortDay(locale ?? 'en', group.date)}\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 {group.views.map(renderCard)}\n </ul>\n </section>\n ))}\n </div>\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 onCreatePatient,\n}: {\n form: ReturnType<typeof useWaitingEntryForm>;\n entry?: CalendarWaitingEntry;\n readOnly: boolean;\n onCreatePatient?: CalendarCreatePatient;\n}) {\n const data = useCalendarData();\n const { t } = useTranslation('ui');\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 ${EDITOR_COMPACT_FIELDS_CLASS}`}\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 onCreatePatient={readOnly ? undefined : onCreatePatient}\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 onCreatePatient,\n}: {\n /** Set = edit this entry; unset = add a new one. */\n entry?: CalendarWaitingEntry;\n onSave: (draft: WaitingEntryDraft) => void;\n onCancel: () => void;\n /** \"Create patient\" under the patient search (not offered when read-only). */\n onCreatePatient?: CalendarCreatePatient;\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('ui');\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\n form={form}\n entry={entry}\n readOnly={readOnly}\n onCreatePatient={onCreatePatient}\n />\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 onRemove,\n readOnly = false,\n onCreatePatient,\n}: {\n open: boolean;\n /** \"Create patient\" under the patient search (not offered when read-only). */\n onCreatePatient?: CalendarCreatePatient;\n /** Set = edit this entry; unset = add a new one. */\n entry?: CalendarWaitingEntry;\n onSave: (draft: WaitingEntryDraft) => void;\n onCancel: () => void;\n /** Edit mode only: the panel's EXISTING remove seam (the card's ⋮ menu\n * `onRemove`) — reused here rather than a second one. Unset or no\n * `entry` (add mode) and the footer's leading slot is not rendered. */\n onRemove?: (entry: CalendarWaitingEntry) => void;\n readOnly?: boolean;\n}) {\n const { t } = useTranslation('ui');\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 /* Same permission the card's ⋮ menu already checks — Remove writes the\n queue through a seam a read-only host refuses, so it is withheld\n rather than disabled, exactly like the menu item. */\n const showRemove = Boolean(entry) && !readOnly && onRemove !== undefined;\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 footerAlign={showRemove ? 'between' : 'end'}\n footer={\n <>\n {showRemove ? (\n <IconButton\n size=\"sm\"\n intent=\"destructiveOutline\"\n icon={<Trash2 aria-hidden=\"true\" />}\n aria-label={t(key('remove'))}\n tooltip={t(key('remove'))}\n onClick={() => entry && onRemove?.(entry)}\n />\n ) : null}\n <span className=\"ds:ms-auto ds:flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n <Button size=\"sm\" 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 size=\"sm\"\n intent=\"primary\"\n data-action=\"save-waiting-entry\"\n onClick={form.submit}\n >\n {t(key(entry ? 'formSave' : 'formAdd'))}\n </Button>\n )}\n </span>\n </>\n }\n >\n <div className=\"ds:-m-[var(--panel-subview-inset)] ds:flex ds:flex-col ds:gap-[var(--spacing-md)] ds:p-[var(--spacing-md)]\">\n <WaitingEntryFields\n form={form}\n entry={entry}\n readOnly={readOnly}\n onCreatePatient={onCreatePatient}\n />\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('ui');\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 {data.yearlyNumber ? (\n <span className=\"ds:font-normal\">\n {' '}\n (<span dir=\"ltr\">{data.yearlyNumber}</span>)\n </span>\n ) : null}\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('ui');\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('ui');\n const { t: tUi } = useTranslation('ui');\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:min-w-0 ds:items-center ds:gap-[var(--spacing-sm)] ds:rounded-[var(--radius-md)] ds:[:where(&)]:border-[length:var(--surface-border-width,var(--border-width-sm))] ds:border-[color:var(--card-border)] ds:bg-[color:var(--card)] ds:text-[color:var(--card-foreground)] ds:shadow-[var(--shadow-sm)] ds:p-[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('ui');\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=\"primary\"\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 {/* Capped to the room Radix measures beside the trigger, as the\n toolbar's chair and operator filters: a long grouped list scrolls\n inside the popover instead of running off the screen. */}\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>{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('ui');\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 ?? FREE_SLOT_DEFAULT_DURATION_MIN,\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 /* HTP-5059 — same restriction rule as the editor: an empty\n operatorIds/chairIds on the care is unrestricted, a non-empty one is\n the closed set allowed to perform it. Shared via calendar-care-rules\n so the finder and the editor cannot drift apart. */\n const operatorRestriction = allowedOperatorsFor(\n care ? [care] : [],\n activeOperators(data),\n );\n const chairRestriction = allowedChairsFor(care ? [care] : [], data.chairs);\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) {\n /* Clearing the care (old finder: onCareSelect(null)) puts the length\n back to the default and lifts the care's limits; the ticks the\n user made stay, they are valid with no care. */\n setDurationMin(FREE_SLOT_DEFAULT_DURATION_MIN);\n return;\n }\n setDurationMin(nextCare.durationMin);\n const nextOperators = allowedOperatorsFor(\n [nextCare],\n activeOperators(data),\n );\n const nextChairs = allowedChairsFor([nextCare], data.chairs);\n setOperatorId((prev) =>\n prev !== ANY && !isResourceAllowed(prev, nextOperators) ? ANY : prev,\n );\n setChairId((prev) =>\n prev !== ANY && !isResourceAllowed(prev, nextChairs) ? 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) => isResourceAllowed(id, nextOperators)),\n );\n setScopeChairIds((prev) =>\n prev.filter((id) => isResourceAllowed(id, nextChairs)),\n );\n };\n\n const eligibleOperators = operatorRestriction.list;\n const eligibleChairs = chairRestriction.list;\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 /* The seed context (the waiting entry's colour/description) carries\n through, and the WAITING PATIENT lands pre-selected in the\n editor. A chosen care's colour is drawn, never handed off. */\n colorHex: seed?.colorHex,\n /* A chosen catalogue care rides as a linked care, not as the\n free-text description. */\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-sm)] 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 operatorName = data.operators.find(\n (o) => o.id === slot.operatorId,\n )?.title;\n /* The rail-card anatomy the waiting list and To complete\n use: a time column, the operator's avatar, then the\n range and where it is. */\n const facts = (\n <span className=\"ds:flex ds:min-w-0 ds:flex-1 ds:items-center ds:gap-[var(--spacing-sm)]\">\n <span className=\"ds:flex ds:shrink-0 ds:flex-col ds:[min-inline-size:4.5rem]\">\n <span className=\"type-body-sm ds:font-medium ds:tabular-nums ds:text-start ds:text-[color:var(--foreground)]\">\n {new Intl.DateTimeFormat(locale, {\n hour: 'numeric',\n minute: '2-digit',\n }).format(slot.start)}\n </span>\n <span className=\"type-eyebrow ds:text-start ds:text-[color:var(--muted-foreground)]\">\n {t('appointmentCard.duration', {\n count: slot.durationMin,\n })}\n </span>\n </span>\n {operatorName ? (\n <Avatar name={operatorName} size=\"sm\" />\n ) : null}\n <span className=\"ds:flex ds:min-w-0 ds:flex-col\">\n <span className=\"type-body-sm ds:sr-only\">\n {when}\n </span>\n <span className=\"type-body-sm ds:truncate ds:font-[var(--font-weight-semibold)] ds:text-start\">\n {operatorName ?? allocation}\n </span>\n {operatorName ? (\n <span className=\"type-body-sm ds:truncate ds:text-start ds:text-[color:var(--muted-foreground)]\">\n {[\n data.chairs.find((c) => c.id === slot.chairId)\n ?.title,\n deviceName || undefined,\n ]\n .filter(Boolean)\n .join(' · ')}\n </span>\n ) : null}\n </span>\n </span>\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=\"primary\"\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","import { useTranslation } from 'react-i18next';\nimport { Alert } from '../../components/alert';\nimport { Button } from '../../components/button';\n\nexport interface CalendarLoadErrorProps {\n /** Calls the host to load the visible range again. Without it the\n * message still shows and the button is withheld: a Retry the host\n * cannot back would do nothing. */\n onRetry?: () => void;\n}\n\n/** Said above the grid when the host reports that loading appointments\n * failed for the visible range. The failed days wear their own tint, so a\n * day that failed never looks free; this explains it and offers Retry. */\nexport function CalendarLoadError({ onRetry }: CalendarLoadErrorProps) {\n const { t } = useTranslation('ui');\n return (\n <Alert\n variant=\"error\"\n data-component=\"calendar-load-error\"\n data-status=\"error\"\n className=\"ds:print:hidden\"\n >\n <Alert.Title as=\"p\">{t('calendarWorkspace.loadError.title')}</Alert.Title>\n <Alert.Description>\n {t('calendarWorkspace.loadError.description')}\n </Alert.Description>\n {onRetry ? (\n <Button\n size=\"sm\"\n intent=\"outline\"\n data-retry=\"\"\n onClick={() => onRetry()}\n >\n {t('calendarWorkspace.loadError.retry')}\n </Button>\n ) : null}\n </Alert>\n );\n}\n","/* ------------------------------------------------------------------ */\n/* Colour by status: one fixed colour per appointment status (P16). */\n/* */\n/* The card paints only from a hex, but each status colour is a theme */\n/* token. So the grid resolves each token to a hex when it draws, and */\n/* again whenever the theme changes. */\n/* Nothing here is stored on an appointment (P2). */\n/* ------------------------------------------------------------------ */\nimport { useEffect, useState, type RefObject } from 'react';\nimport type { CalendarEventStatus } from '../../components/calendar';\n\nexport type StatusColours = Record<CalendarEventStatus, string>;\n\n/* One fill token per status, set for every theme in the token sheet. They\n are dedicated surface tokens, not the semantic text tokens: those are\n deep or pale in the accessible themes and would blur together. */\nexport const STATUS_COLOUR_TOKEN: StatusColours = {\n confirmed: '--calendar-status-confirmed',\n waiting: '--calendar-status-waiting',\n in_care: '--calendar-status-in-care',\n done: '--calendar-status-done',\n cancelled: '--calendar-status-cancelled',\n absent: '--calendar-status-absent',\n};\n\nconst STATUSES = Object.keys(STATUS_COLOUR_TOKEN) as CalendarEventStatus[];\n\nconst toHex = (channel: number): string =>\n Math.round(channel).toString(16).padStart(2, '0');\n\n/** The token's colour as `#rrggbb` under `anchor`, or `undefined` when it\n * does not resolve (no stylesheet, or a colour space the kit cannot read\n * as sRGB). A probe element lets the browser do the var() lookup. */\nfunction resolveToken(anchor: HTMLElement, token: string): string | undefined {\n if (!getComputedStyle(anchor).getPropertyValue(token).trim()) {\n return undefined;\n }\n const probe = anchor.ownerDocument.createElement('span');\n probe.style.color = `var(${token})`;\n anchor.appendChild(probe);\n const painted = getComputedStyle(probe).color;\n probe.remove();\n const channels = /^rgba?\\(\\s*(\\d+)[,\\s]+(\\d+)[,\\s]+(\\d+)/.exec(painted);\n return channels\n ? `#${toHex(+channels[1])}${toHex(+channels[2])}${toHex(+channels[3])}`\n : undefined;\n}\n\n/** All six status colours as hex, or `null` when any one cannot be\n * resolved: the grid then keeps the stored colour, never a half set. */\nexport function resolveStatusColours(\n anchor: HTMLElement | null,\n): StatusColours | null {\n if (!anchor || typeof getComputedStyle === 'undefined') return null;\n const out: Partial<StatusColours> = {};\n for (const status of STATUSES) {\n const hex = resolveToken(anchor, STATUS_COLOUR_TOKEN[status]);\n if (!hex) return null;\n out[status] = hex;\n }\n return out as StatusColours;\n}\n\n/* Preferences a host can theme off without touching an attribute. */\nconst THEME_MEDIA = [\n '(prefers-color-scheme: dark)',\n '(prefers-contrast: more)',\n '(forced-colors: active)',\n] as const;\n\nconst sameColours = (a: StatusColours | null, b: StatusColours | null) =>\n a === b ||\n (!!a && !!b && STATUSES.every((status) => a[status] === b[status]));\n\n/**\n * The status colours for the theme `anchorRef` sits in, kept current:\n * resolved once the anchor mounts and again when a class, theme attribute\n * or inline style changes on it or any ancestor (where a theme root puts\n * `theme-dark`), or when the OS colour scheme, contrast or forced-colours\n * preference flips (a host may theme off those with no attribute change).\n * `null` while off, before mount, or when tokens do not\n * resolve (SSR, tests without the stylesheet).\n */\nexport function useStatusColours(\n active: boolean,\n anchorRef: RefObject<HTMLElement | null>,\n): StatusColours | null {\n const [colours, setColours] = useState<StatusColours | null>(null);\n useEffect(() => {\n const anchor = anchorRef.current;\n if (!active || !anchor) return;\n const refresh = () => {\n const next = resolveStatusColours(anchor);\n setColours((prev) => (sameColours(prev, next) ? prev : next));\n };\n refresh();\n const observer = new MutationObserver(refresh);\n for (let node: HTMLElement | null = anchor; node; ) {\n observer.observe(node, {\n attributes: true,\n attributeFilter: ['class', 'data-theme', 'style'],\n });\n node = node.parentElement;\n }\n const lists =\n typeof window.matchMedia === 'function'\n ? THEME_MEDIA.map((query) => window.matchMedia(query))\n : [];\n for (const list of lists) list.addEventListener('change', refresh);\n return () => {\n observer.disconnect();\n for (const list of lists) list.removeEventListener('change', refresh);\n };\n }, [active, anchorRef]);\n return active ? colours : null;\n}\n","/* Where the workspace parks FullCalendar's sticky date header and the mode\n banner: under the sticky nav when they stick in one scrollport, at their\n own top otherwise. Measured geometry exception: src/docs/23-constraints.mdx. */\n\nexport const STICKY_HEADER_CELL =\n '.fc-scrollgrid-section-header.fc-scrollgrid-section-sticky > *';\n\n/** The kit Calendar's create, Move and Copy banner. */\nexport const MODE_BANNER = '[data-calendar-mode-banner]';\n\n/** The box `position: sticky` resolves against: the nearest ancestor that\n * is a scroll container (`clip` is not one), or null for the viewport. */\nexport function stickyScrollport(el: Element): Element | null {\n for (let node = el.parentElement; node; node = node.parentElement) {\n if (node === document.body || node === document.documentElement) break;\n const { overflowX, overflowY } = getComputedStyle(node);\n if (![overflowX, overflowY].every((o) => o === 'visible' || o === 'clip'))\n return node;\n }\n return null;\n}\n\n/** How far the header sits below its natural `top: 0` to clear the nav. The\n * kit resets `.fc-view` and its table; any other host scroll container\n * still yields 0, as an offset there covers the all-day lane. */\nexport function stickyHeaderOffset(\n navigation: HTMLElement,\n header: Element | null,\n): number {\n if (!header) return 0;\n return stickyScrollport(header) === stickyScrollport(navigation)\n ? navigation.getBoundingClientRect().height\n : 0;\n}\n\nexport interface StickyOffsets {\n /** `--inc1-nav-offset`: the nav alone, as the header sees it. */\n nav: number;\n /** `--inc1-banner-top`: where the mode banner parks. */\n bannerTop: number;\n /** `--inc1-header-offset`: the nav plus a banner in the header's scrollport. */\n header: number;\n /** `--inc1-pinned-block-size`: everything pinned above the grid's events. */\n pinned: number;\n}\n\n/** Every sticky offset the surface needs, from one measurement. */\nexport function stickyOffsets(\n navigation: HTMLElement,\n header: Element | null,\n banner: Element | null,\n): StickyOffsets {\n const navPort = stickyScrollport(navigation);\n const bannerPort = banner ? stickyScrollport(banner) : undefined;\n const nav = stickyHeaderOffset(navigation, header);\n const bannerTop =\n banner && bannerPort === navPort\n ? navigation.getBoundingClientRect().height\n : 0;\n const bannerClears =\n banner !== null &&\n header !== null &&\n bannerPort === stickyScrollport(header);\n const headerOffset =\n nav + (bannerClears ? banner.getBoundingClientRect().height : 0);\n /* Only when the header pins in the nav's scrollport; elsewhere nothing\n the kit knows about covers a focused event. */\n const pinned =\n header && nav > 0\n ? headerOffset + header.getBoundingClientRect().height\n : 0;\n return { nav, bannerTop, header: headerOffset, pinned };\n}\n\n/** Keeps the sticky offsets on `surface` current; re-measures on resize and\n * when the header or banner is inserted or replaced. A runtime `overflow`\n * change with no resize is not seen: remount. Returns the cleanup. */\nexport function trackStickyHeaderOffset(\n navigation: HTMLElement,\n surface: HTMLElement,\n): () => void {\n let header: Element | null = null;\n let banner: Element | null = null;\n const resizes = new ResizeObserver(() => measure());\n const follow = (from: Element | null, to: Element | null) => {\n if (from) resizes.unobserve(from);\n if (to) resizes.observe(to);\n return to;\n };\n const measure = () => {\n const nextHeader = surface.querySelector(STICKY_HEADER_CELL);\n const nextBanner = surface.querySelector(MODE_BANNER);\n if (nextHeader !== header) header = follow(header, nextHeader);\n if (nextBanner !== banner) banner = follow(banner, nextBanner);\n const offsets = stickyOffsets(navigation, header, banner);\n surface.style.setProperty('--inc1-nav-offset', `${offsets.nav}px`);\n surface.style.setProperty('--inc1-banner-top', `${offsets.bannerTop}px`);\n surface.style.setProperty('--inc1-header-offset', `${offsets.header}px`);\n surface.style.setProperty(\n '--inc1-pinned-block-size',\n `${offsets.pinned}px`,\n );\n };\n measure();\n resizes.observe(navigation);\n resizes.observe(surface);\n const mutations = new MutationObserver(() => {\n if (\n surface.querySelector(STICKY_HEADER_CELL) !== header ||\n surface.querySelector(MODE_BANNER) !== banner\n )\n measure();\n });\n mutations.observe(surface, { childList: true, subtree: true });\n return () => {\n resizes.disconnect();\n mutations.disconnect();\n };\n}\n","/**\n * The prompts the old calendar kept, as host seams: a banner above the\n * grid, the first-appointment alert and the Academy tutorial link. The\n * kit calls no API; each renders only when the host passes it.\n */\nimport { useTranslation } from 'react-i18next';\nimport { Alert } from '../../components/alert';\nimport { Button } from '../../components/button';\nimport type { CalendarPromptAction, CalendarPrompts } from './calendar.types';\n\nfunction PromptAction({ action }: { action: CalendarPromptAction }) {\n return (\n <Alert.Action>\n <Button\n type=\"button\"\n size=\"sm\"\n intent=\"outline\"\n onClick={action.onAction}\n >\n {action.label}\n </Button>\n </Alert.Action>\n );\n}\n\n/** The banner and the first-appointment alert, stacked above the grid. */\nexport function CalendarPromptAlerts({\n prompts,\n restoreFocus,\n}: {\n prompts?: CalendarPrompts;\n /** Called as the banner is dismissed, before it unmounts: park focus on a\n * stable element so the close button's focus is not lost to the body. */\n restoreFocus?: () => void;\n}) {\n const { t } = useTranslation('ui');\n const banner = prompts?.banner?.text ? prompts.banner : undefined;\n const first = prompts?.firstAppointment;\n if (!banner && !first) return null;\n return (\n <>\n {banner ? (\n <Alert\n variant={banner.tone ?? 'info'}\n announce=\"off\"\n data-component=\"calendar-host-banner\"\n dismissible={banner.onDismiss !== undefined}\n onOpenChange={(open) => {\n if (!open) {\n restoreFocus?.();\n banner.onDismiss?.();\n }\n }}\n >\n <Alert.Description>{banner.text}</Alert.Description>\n {banner.action ? <PromptAction action={banner.action} /> : null}\n </Alert>\n ) : null}\n {first ? (\n <Alert\n variant=\"info\"\n announce=\"off\"\n data-component=\"calendar-first-appointment\"\n >\n <Alert.Title as=\"p\">\n {t('calendarWorkspace.prompts.firstAppointmentTitle')}\n </Alert.Title>\n <Alert.Description>\n {t('calendarWorkspace.prompts.firstAppointment')}\n </Alert.Description>\n {first.action ? <PromptAction action={first.action} /> : null}\n </Alert>\n ) : null}\n </>\n );\n}\n\n/** Only an https link is offered: the href comes from the host. */\nexport function safeAcademyHref(href: string | undefined): string | undefined {\n return href && /^https:\\/\\//i.test(href.trim()) ? href.trim() : undefined;\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 forwardRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type ComponentProps,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport {\n Armchair,\n CalendarPlus,\n CalendarSearch,\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n Eye,\n EyeOff,\n Hourglass,\n ListPlus,\n ListTodo,\n Printer,\n RotateCcw,\n SlidersHorizontal,\n SquareCheckBig,\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, getInitials } from '../../components/avatar';\nimport { Badge } from '../../components/badge';\nimport { Alert } from '../../components/alert';\nimport { Card } from '../../components/card';\nimport { CalendarLoadError } from './calendar-load-error';\nimport { Checkbox } from '../../components/checkbox';\nimport { KeyValuePair } from '../../components/key-value-pair';\nimport { Kbd } from '../../components/kbd';\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 { ScrollArea } from '../../components/scroll-area';\nimport { Tooltip } from '../../components/tooltip';\nimport {\n toastError,\n toastInfo,\n toastSuccess,\n toastWarning,\n} from '../../components/toast';\nimport { useStatusColours } from './calendar-status-colours';\nimport { trackStickyHeaderOffset } from './calendar-sticky-offset';\nimport {\n buildOperatorFilterGroups,\n flattenOperatorFilterGroups,\n careSuffix,\n type CalendarPracticeSettingsSeam,\n} from './calendar.types';\nimport {\n CALENDAR_PREFERENCE_KEYS,\n type CalendarPreferenceAdapter,\n memoryPreferenceAdapter,\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 DraftSlot,\n type EditorPrefill,\n editPrefillFromRow,\n snapForSlot,\n type HistoryInput,\n processBookingPrefill,\n localIsoDate,\n parseIsoDate,\n buildUnavailabilityEvents,\n type AvailabilityContext,\n type CalendarFreeSlot,\n isClosureEvent,\n buildClosureBanners,\n buildPrintSheet,\n closureReason,\n buildFreeBands,\n buildFreeSlotCells,\n maskedTitle,\n patientRefById,\n drawnRowColors,\n} from './calendar.model';\nimport { CalendarArchiveBanner } from './calendar-archive';\nimport { CalendarPromptAlerts } from './calendar-prompts';\nimport {\n type CalendarArchive,\n type CalendarPrompts,\n type CalendarClosure,\n channelOfferable,\n channelReady,\n channelReasonKey,\n patientIdOf,\n patientRefName,\n} from './calendar.types';\nimport {\n type CalendarViewChange,\n type WorkspaceDisplaySettings,\n type WorkspaceViewId,\n WORKSPACE_VIEWS,\n WORKSPACE_VIEW_STEM,\n VIEW_SHORTCUT_KEYS,\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 DEFAULT_HIDDEN_DAYS,\n readHiddenDays,\n weekendHiddenDays,\n type CreateModeRequest,\n type PlacementRequest,\n type SaveNotice,\n type RecurringScope,\n type RecurringScopeChosen,\n rowAsksScope,\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 { CalendarSettingsBridge } from './calendar-settings-panel';\nimport { useEditorGuard } from './calendar-editor-guard';\nimport type { CalendarJourney, CalendarMoveNotify } 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';\nconst NO_NOTIFY: CalendarMoveNotify = { sms: false, email: false };\n\n/* The nav row's minimum: the 32px toolbar controls plus `py-xs` each side.\n Not a cap: accessible themes grow the row, and the sticky offsets follow\n the MEASURED height, so a classic scrollbar cannot feed back into it. */\nconst NAV_BLOCK_SIZE_CLASS = 'ds:[--inc1-nav-block-size:2.5rem]';\n/* The date header parks under the nav and any mode banner, measured by\n calendar-sticky-offset.ts. The kit resets `.fc-view` and its table; any\n other host scroll container still yields 0, keeping the all-day lane clear. */\nconst FC_STICKY_OFFSET_CLASS =\n 'ds:[&_.fc-scrollgrid-section-header.fc-scrollgrid-section-sticky>*]:!top-[var(--inc1-header-offset,0px)]';\n/* The create, Move and Copy banner parks under the nav, not behind it. */\nconst MODE_BANNER_OFFSET_CLASS =\n 'ds:[&_[data-calendar-mode-banner]]:!top-[var(--inc1-banner-top,0px)]';\n/* Keyboard focus scrolls an event clear of the pinned nav, banner and header.\n A projected free slot takes focus on its button, not on `.fc-event`. */\nconst FOCUS_CLEARANCE_CLASS =\n 'ds:[&_:is(.fc-event,.fc-bg-event_button,.fc-daygrid-more-link,a[data-navlink])]:[scroll-margin-block-start:var(--inc1-pinned-block-size,0px)]';\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 ACTION_BADGE_CLASS =\n 'ds:pointer-events-none ds:absolute ds:-top-1 ds:-end-1 ds:z-10';\n\n/* Accessible themes keep the kit's raised target (48px); the default\n themes keep the toolbar's 32px strip — the sanctioned sub-target\n exception documented beside `--min-target-size` in `src/tokens/index.css`\n — using the same theme-scoped rule the details footer uses. Applied to\n each MEMBER, not the group: the group growing taller does not stretch a\n child with its own explicit `h-8`/`w-8`. `min-block-size` beats the\n size variant's `h-8`, so the raise lands without a size override. */\nconst ACCESSIBLE_TARGET_CLASS =\n 'ds:sm:[min-block-size:var(--accessible-target-floor,0px)]';\n/* Icon-only members are square (`w-8 h-8`) — raising only the block size\n would leave them 32px wide and 48px tall. The waiting-list panel's\n `ACCESSIBLE_TARGET_SQUARE` is the same fix for the same shape. */\nconst ACCESSIBLE_TARGET_SQUARE_CLASS = `${ACCESSIBLE_TARGET_CLASS} ds:[min-inline-size:var(--accessible-target-floor,auto)]`;\n\n/** Stable empty selection for the archive, which hides the filters. */\nconst NO_IDS: string[] = [];\n\n/**\n * A rail-tool button with a badge pinned to its corner, usable as a direct\n * `ButtonGroup` member. Earlier this wrapped the `IconButton` in an extra\n * `<span>` so the badge had a positioning context — but that span, not the\n * button, became the group's actual direct child, so it picked up the\n * group's join classes (border, join radius, `-ms-px` overlap) while the\n * inner button was stripped of its own border to avoid a doubled box. The\n * span never grew a matching border, so badge-wrapped members rendered\n * borderless and a couple of pixels off the height of their neighbours.\n *\n * Fixed by dropping the wrapper: the `IconButton` itself is the group's\n * direct child (identical border, radius and sizing to every unwrapped\n * sibling), and the `Badge` is composed into its `icon` node instead,\n * positioned absolutely against the button (`ds:relative` added to the\n * button's own className). The inner icon span the badge rides alongside\n * has no `position` of its own, so the absolute badge escapes its small\n * icon-sized box and anchors to the button's real edges.\n */\nconst RailToolButton = forwardRef<\n HTMLButtonElement,\n ComponentProps<typeof IconButton> & {\n badgeCount?: number;\n badgeVariant?: 'brand' | 'warning';\n }\n>(\n (\n { badgeCount = 0, badgeVariant = 'brand', icon, className, ...iconProps },\n ref,\n ) => (\n <IconButton\n type=\"button\"\n ref={ref}\n icon={\n <>\n {icon}\n {badgeCount > 0 ? (\n <Badge\n size=\"sm\"\n variant={badgeVariant}\n aria-hidden=\"true\"\n className={ACTION_BADGE_CLASS}\n >\n {badgeCount}\n </Badge>\n ) : null}\n </>\n }\n className={`ds:relative ${className ?? ''}`.trim()}\n {...iconProps}\n />\n ),\n);\nRailToolButton.displayName = 'RailToolButton';\n\nexport function CalendarSurface({\n rows,\n setRows,\n draftSlot = null,\n onFocus,\n locale,\n onComposeNew,\n onComposeTask,\n onOpenWaitingList,\n onAddWaitingEntry,\n onOpenOnlineBookings,\n onlineBookingsCount,\n waitingBadgeCount,\n onVisibleRangeChange,\n onRetryLoad,\n selectedEventId,\n gotoRequest,\n onBookSlot,\n onBookSlotFromFinder,\n display,\n setDisplay,\n defaultDisplay,\n onHistory,\n readOnly = false,\n reviewOnlyEventIds,\n detailsOnEveryClick = false,\n gridHeld = 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 onMoveAppointment,\n onResizeAppointment,\n onCopyAppointment,\n onDeleteAppointment,\n onRecurringScopeChosen,\n onViewChange,\n initialView,\n onNavigate,\n onPeekOpen,\n settingsBridge,\n settingsOpen = false,\n onToggleSettings,\n onSettingChanged,\n onHoursOpened,\n practiceSettings,\n onMoveDropped,\n onPrintUsed,\n onJumpToDateUsed,\n calendarArchive,\n prompts,\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 /** An archive session (rules 2 to 4 and 6): no chair or operator columns\n * or filters, no drag or resize, a banner with Exit, the view on Week. */\n calendarArchive?: CalendarArchive;\n /** The host's banner, first-appointment alert and Academy link. */\n prompts?: CalendarPrompts;\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 /** New task — the create group's second member. Omit it (the host has\n * no `handleCreateTask`) and the button is withheld entirely, leaving\n * a single \"New appointment\" button; this surface does not decide\n * what the click opens, only whether to offer it. */\n onComposeTask?: () => 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 /** The open NEW-appointment form's slot, held on the grid as a dashed\n * draft card until Save or Cancel. `null` when no create form is open. */\n draftSlot?: DraftSlot | null;\n /** Seed the editor prefilled (an empty-slot click, a booking to process). */\n onBookSlot: (prefill: EditorPrefill) => void;\n /** A host tool holds the dock (`hold`): a grid click still selects, but\n * never opens the editor over it. */\n gridHeld?: boolean;\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 /** What \"Reset to defaults\" in the cog returns to: the kit defaults with\n * the host's `initialDisplay` on top. */\n defaultDisplay: 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 /** Loads the visible range again after a day came back `'error'` in\n * `CalendarData.dayLoadState`. Withheld = the message shows without a\n * Retry button. */\n onRetryLoad?: () => 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 and asks the scope. The notify boxes need\n * `onMoveAppointment` and show for \"this\" only (P9). */\n onMoveOccurrence?: CalendarJourney['handleMoveOccurrence'];\n /** The host's writes for one appointment's move, resize and copy. Each\n * is optional: without it the change reaches the host through `setRows`\n * only. A copy's Undo calls `onDeleteAppointment` with its id, and is\n * withheld when `onCopyAppointment` is set without it. */\n onMoveAppointment?: CalendarJourney['handleMoveAppointment'];\n onResizeAppointment?: CalendarJourney['handleResizeAppointment'];\n onCopyAppointment?: CalendarJourney['handleCopyAppointment'];\n onDeleteAppointment?: CalendarJourney['handleDeleteAppointment'];\n /** The user answered the scope question in the move confirm. Not raised\n * on Cancel, nor for a row changed on its own (no question is asked). */\n onRecurringScopeChosen?: (answer: RecurringScopeChosen) => void;\n /** A dragged card was dropped (past the read-only refusal): the grid's\n * Move, raised before the confirm. */\n onMoveDropped?: (eventId: string) => void;\n /** The print dialog was confirmed. */\n onPrintUsed?: () => void;\n /** A date was picked in the jump-to-date picker. */\n onJumpToDateUsed?: () => void;\n /** The grid's view, on mount and on every change. Usage reporting only. */\n onViewChange?: (view: CalendarView) => void;\n /** The view the page address names. It beats the remembered view until\n * the user picks another, and the remembered view is not overwritten. */\n initialView?: WorkspaceViewId;\n /** The grid went to another view, day or axis: once per navigation,\n * never for the first render. Hosts keep the page address with it. */\n onNavigate?: (change: CalendarViewChange) => void;\n /** An appointment's preview opened. Usage reporting only. */\n onPeekOpen?: (eventId: string) => void;\n /** Where the toolbar's Settings button and the Settings panel in the rail\n * meet: the surface publishes the panel's props here and takes the\n * button's ref from it. Without it the button is withheld. */\n settingsBridge?: CalendarSettingsBridge;\n /** The Settings panel is the open rail tool: the button's expanded state. */\n settingsOpen?: boolean;\n /** The Settings button was pressed: the workspace opens or closes the\n * panel (and asks about unsaved Practice changes). */\n onToggleSettings?: () => void;\n /** A personal setting changed in the Settings panel. Usage reporting only. */\n onSettingChanged?: (event: {\n setting: string;\n section: 'personal' | 'practice';\n }) => void;\n /** The Practice section's hours link was followed. Usage reporting only. */\n onHoursOpened?: () => void;\n /** The Settings panel's Practice section seam (see `CalendarWorkspaceProps`). */\n practiceSettings?: CalendarPracticeSettingsSeam;\n}) {\n const { t } = useTranslation('ui');\n const data = useCalendarData();\n const { t: tUi } = useTranslation('ui');\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 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 /* Match the CELL's identity, not an overlap: the projection is one\n cell per exact start+end+resource now, so a slot that merely\n overlaps the clicked interval (e.g. a staggered neighbour starting\n 15 minutes later) belongs to a DIFFERENT cell and must not be\n offered here. `valid.delete` still dedupes duplicate finder\n answers for the slot that does match. */\n return availability.filter(\n (slot) =>\n valid.delete(identity(slot)) &&\n slot.start.getTime() === from &&\n slot.start.getTime() + slot.durationMin * 60000 === to &&\n (!freeBand.event.resourceId ||\n (display.resourceKind === 'operator'\n ? slot.operatorId\n : slot.chairId) === freeBand.event.resourceId),\n );\n }, [availability, freeBand, display.resourceKind]);\n /* A click on a found free slot books it: the editor opens at once on that\n slot, filled in (functions.md \"A click in a range books it\"; platform\n contract L3). Only a cell with ONE finder answer books straight away. A\n cell is one exact start + duration, but on the plain axis several\n operator, chair or care answers can share it: the options popover then\n lists them, each with a Book action, so no answer is picked for the\n user. A read-only user sees the popover and no Book action. */\n const bookFreeSlot = (slot: CalendarFreeSlot): void => {\n if (\n readOnly ||\n !freeBand ||\n availability !== freeBand.source ||\n !freeBand.el.isConnected\n )\n return;\n const care = data.cares.find((item) => item.id === slot.careId);\n setFreeBand(null);\n onBookSlotFromFinder({\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 colorHex: availabilityContext?.colorHex,\n care: care ? undefined : availabilityContext?.care,\n cares: care\n ? [{ careId: care.id, name: care.name, code: care.code }]\n : availabilityContext?.cares,\n patientId: availabilityContext?.patientId,\n /* Keyboard and screen-reader users land on the next field to fill. */\n initialFocus: availabilityContext?.patientId ? 'operator' : 'patient',\n });\n openSheet('appointment-editor');\n };\n const onlyFreeOption = freeOptions.length === 1 ? freeOptions[0] : undefined;\n const bookFreeSlotRef = useRef(bookFreeSlot);\n bookFreeSlotRef.current = bookFreeSlot;\n useEffect(() => {\n if (onlyFreeOption && !readOnly) bookFreeSlotRef.current(onlyFreeOption);\n }, [onlyFreeOption, readOnly]);\n const surfaceRef = useRef<HTMLDivElement>(null);\n const statusColours = useStatusColours(\n display.colorAssociation === 'status',\n surfaceRef,\n );\n const navigationRef = useRef<HTMLDivElement>(null);\n /* Layout effect, so the offset is set before first paint and the CSS\n fallback (zero) is never what a host sees. */\n useLayoutEffect(() => {\n const navigation = navigationRef.current;\n const surface = surfaceRef.current;\n if (!navigation || !surface) return;\n return trackStickyHeaderOffset(navigation, surface);\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 [storedViewId, setStoredViewId] =\n usePersistedPreference<WorkspaceViewId>(\n CALENDAR_PREFERENCE_KEYS.view,\n 'day',\n readWorkspaceViewId,\n preferences,\n );\n /* The days this user hides. A user who never chose days keeps the old\n Show weekends switch as the matching set, else Sunday is hidden. */\n const [hiddenDays, setHiddenDays] = usePersistedPreference<number[]>(\n CALENDAR_PREFERENCE_KEYS.hiddenDays,\n () => {\n const legacy = readBoolean(\n (preferences ?? memoryPreferenceAdapter).get(\n CALENDAR_PREFERENCE_KEYS.showWeekends,\n ),\n );\n return legacy === undefined\n ? [...DEFAULT_HIDDEN_DAYS]\n : weekendHiddenDays(legacy);\n },\n readHiddenDays,\n preferences,\n );\n /* Platform semantics: the TICKED ids; nothing ticked shows everyone. */\n const [storedChairIds, setSelectedChairIds] = usePersistedPreference<\n string[]\n >(\n CALENDAR_PREFERENCE_KEYS.chairIds,\n () => [],\n readChairIds(data),\n preferences,\n );\n const [storedOperatorIds, setSelectedOperatorIds] = usePersistedPreference<\n string[]\n >(\n CALENDAR_PREFERENCE_KEYS.operatorIds,\n () => [],\n readOperatorIds(data),\n preferences,\n );\n /* Rule 6: an archive session starts on Week and keeps its own view, so\n the remembered one is neither read nor overwritten meanwhile. */\n const archived = calendarArchive !== undefined;\n const [archiveViewId, setArchiveViewId] = useState<WorkspaceViewId>('week');\n /* The page address names a view: it wins over the remembered one until\n the user picks a view of their own. */\n const [addressViewId, setAddressViewId] = useState(() =>\n readWorkspaceViewId(initialView),\n );\n const viewOptionId = archived\n ? archiveViewId\n : (addressViewId ?? storedViewId);\n const setViewOptionId = useCallback(\n (id: WorkspaceViewId): void => {\n if (archived) {\n setArchiveViewId(id);\n return;\n }\n setAddressViewId(undefined);\n setStoredViewId(id);\n },\n [archived, setStoredViewId],\n );\n /* Rule 3: the archive hides the filters, so what was ticked stays\n remembered but narrows nothing. */\n const selectedChairIds = archived ? NO_IDS : storedChairIds;\n const selectedOperatorIds = archived ? NO_IDS : storedOperatorIds;\n /* Rule 4: no drag, no resize. Create, Move… and Copy… still work. */\n const gridLocked = readOnly || archived;\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 parseIsoDate(data.initialDateIso, data.nowIso),\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 const [chairFilterOpen, setChairFilterOpen] = useState(false);\n const [operatorFilterOpen, setOperatorFilterOpen] = useState(false);\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 parseIsoDate(data.initialDateIso, data.nowIso),\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 /* A click, drop or copy onto a closed day, a holiday or an absent\n operator: the warning waits here for Go ahead or Cancel (P25). */\n const [closedPrompt, setClosedPrompt] = useState<{\n reason: string;\n action: 'book' | 'move';\n onConfirm: () => void;\n onCancel?: () => void;\n } | 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 &&\n event.isRecurrenceParent === true &&\n !rows.find((r) => r.event.id === event.id)?.series?.detached,\n [onMoveOccurrence, rows],\n );\n\n /* P9: the patient notice needs someone booked, and on a series it is\n offered for \"this appointment\" only. P3: and a host that can receive\n it. Only `onMoveAppointment` carries `notify`; a move of a host parent\n beyond \"this\" reaches `onMoveOccurrence` with both false. */\n const notifyOffered = useCallback(\n (event: CalendarEvent, asksScope: boolean, scope: RecurringScope) =>\n onMoveAppointment !== undefined &&\n patientRefById(event.patientId, data).assigned &&\n (!asksScope || scope === 'this'),\n [data, onMoveAppointment],\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 /* Where the grid is, for the navigation report. */\n const placeRef = useRef<{\n view: WorkspaceViewId;\n axis: CalendarViewChange['axis'];\n }>({ view: 'day', axis: undefined });\n placeRef.current = {\n view: viewOptionId,\n axis: isMonth || archived ? undefined : axisKind,\n };\n /* A layout effect, so the view is known before any rail dock that the\n workspace's ordinary effects make on mount. */\n const onViewChangeRef = useRef(onViewChange);\n onViewChangeRef.current = onViewChange;\n useLayoutEffect(() => {\n onViewChangeRef.current?.(calendarView);\n }, [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 /* ---- 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, errorDates } = useMemo<{\n loadingDates: readonly string[] | undefined;\n errorDates: readonly string[] | undefined;\n }>(() => {\n const state = data.dayLoadState;\n if (!state || !visibleRange) {\n return { loadingDates: undefined, errorDates: undefined };\n }\n /* A failed day is NOT washed as arriving: it gets its own tint and\n the Retry message, and the finder still refuses to answer from it. */\n const loading: string[] = [];\n const failed: 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 /* A failure on a day the person has hidden (weekends off) is not\n announced: the message says \"the marked days\", and none would be\n marked. */\n if (state[iso] === 'error') {\n if (!hiddenDays.includes(cursor.getDay())) failed.push(iso);\n } else if (state[iso] !== 'ready') loading.push(iso);\n cursor.setDate(cursor.getDate() + 1);\n }\n return { loadingDates: loading, errorDates: failed };\n }, [data.dayLoadState, visibleRange, hiddenDays]);\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 /* The other axis on the card, when the cog asks for it: the chair's name\n in operator columns, or the operator's initials in chair columns (the\n same initials the column header's Avatar derives), with the full\n operator name for screen readers. */\n const cardContext = useCallback(\n (r: CalendarRow): Pick<CalendarEvent, 'contextLabel' | 'contextName'> => {\n /* Always both keys, explicitly: a context the host put on the event\n is cleared too when the cog turns context off. */\n const none = { contextLabel: undefined, contextName: undefined };\n if (!display.showCardContext) return none;\n if (axisKind === 'operator') {\n return {\n contextLabel: data.chairs.find((chair) => chair.id === r.chairId)\n ?.title,\n contextName: undefined,\n };\n }\n const operator = data.operators.find(\n (candidate) => candidate.id === r.operatorId,\n );\n return operator\n ? {\n contextLabel: getInitials(operator.title),\n contextName: operator.title,\n }\n : none;\n },\n [display.showCardContext, axisKind, data.chairs, data.operators],\n );\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 /* Cancelled stays off the grid until the user asks for it. Absent is\n not cancelled and always shows. */\n .filter((r) => display.showCancelled || r.event.status !== 'cancelled')\n .map((r) => ({\n ...r.event,\n ...drawnRowColors(r, display.colorAssociation, data, statusColours),\n ...cardContext(r),\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 ...(gridLocked || reviewOnlyEventIds?.has(r.event.id)\n ? { editable: false, startEditable: false }\n : {}),\n /* A shown cancelled appointment steps back and cannot move or\n resize, whatever the row says: same overwrite-after-spread rule.\n It still opens in details on click. */\n ...(r.event.status === 'cancelled'\n ? { faded: true, 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\"): one cell per distinct\n start + duration, not a merged band — each bookable slot stays\n individually visible and clickable. The visible label is the bare\n word; the count rides the cell's extended data only (the component\n puts it in the tooltip and the accessible name, never a chip). */\n const availabilityEvents: CalendarEvent[] = [];\n if (projecting && availability) {\n for (const cell of buildFreeSlotCells(availability, axisKind)) {\n availabilityEvents.push({\n id: `avail-${cell.key}`,\n title: t(key('findSlots.free')),\n start: cell.start.toISOString(),\n end: cell.end.toISOString(),\n isInternal: true,\n optionCount: cell.optionCount,\n ...(!readOnly && cell.slotCount === 1 ? { bookable: true } : {}),\n ...(cell.resourceId ? { resourceId: cell.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 /* The open create form's slot, held as a dashed draft card (the kit's\n `isDraft`) so the user sees the time they are booking. Editing an\n existing appointment already has its card: no mirror. */\n const draftEvents: CalendarEvent[] = [];\n /* On a chair or operator axis a card with no column would draw in\n EVERY column, so a form that has not chosen one holds no card yet. */\n const draftColumn =\n axisKind === 'operator' ? draftSlot?.operatorId : draftSlot?.chairId;\n if (\n draftSlot &&\n !draftSlot.editEventId &&\n (axisKind === 'none' || draftColumn)\n ) {\n const start = new Date(draftSlot.date);\n start.setHours(draftSlot.time.hours, draftSlot.time.minutes, 0, 0);\n const end = new Date(start.getTime() + draftSlot.durationMin * 60000);\n const resourceId =\n axisKind === 'operator' ? draftSlot.operatorId : draftSlot.chairId;\n const asAllDay = draftSlot.allDay || isMonth;\n draftEvents.push({\n id: 'draft-new-appointment',\n title: t(key('actions.newAppointment')),\n start: asAllDay ? localIsoDate(start) : start.toISOString(),\n ...(asAllDay ? {} : { end: end.toISOString() }),\n allDay: asAllDay,\n isDraft: true,\n editable: false,\n ...(axisKind !== 'none' && resourceId ? { resourceId } : {}),\n });\n }\n return [\n ...mapped,\n ...draftEvents,\n ...availabilityEvents,\n ...unavailabilityEvents,\n ...closureBanners,\n ];\n }, [\n rows,\n cardContext,\n axisKind,\n availability,\n projecting,\n visibleChairIds,\n visibleOperatorIds,\n currentDate,\n onlyAvailable,\n display.orientation,\n display.careDescription,\n display.colorAssociation,\n display.showCancelled,\n statusColours,\n isMonth,\n gridLocked,\n reviewOnlyEventIds,\n readOnly,\n t,\n data,\n draftSlot,\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 ? (drawnRowColors(\n placementRow,\n display.colorAssociation,\n data,\n statusColours,\n ).backgroundColor ?? 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: maskedTitle(placementRow.event, privacy),\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('day')\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('day')) {\n const day = saveNotice.date.getDay();\n setHiddenDays((days) => days.filter((d) => d !== day));\n }\n calRef.current?.gotoDate(saveNotice.date);\n },\n },\n });\n }, [\n saveNotice,\n hiddenDays,\n selectedChairIds,\n selectedOperatorIds,\n setSelectedChairIds,\n setSelectedOperatorIds,\n setHiddenDays,\n t,\n locale,\n ]);\n\n /* ---- interactions ---------------------------------------------- */\n\n const proceedEventClick = 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 /* A held host tool: select the card, but open nothing over it. */\n if (gridHeld) {\n onFocus({ kind: 'appointment', eventId: event.id });\n return;\n }\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 gridHeld,\n ],\n );\n /* B18: a card click replaces the editor form, so it asks first when the\n form holds typed data. A row-less event (a closure, the draft) is inert. */\n const editorGuard = useEditorGuard();\n const handleEventClick = useCallback(\n (event: CalendarEvent) => {\n if (\n !editorGuard?.dirty ||\n placement ||\n !rows.some((r) => r.event.id === event.id)\n ) {\n proceedEventClick(event);\n return;\n }\n setPeek(null);\n editorGuard.ask(() => proceedEventClick(event));\n },\n [editorGuard, placement, rows, proceedEventClick],\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 /* Appointments only: a closure banner or a task has its own peek. */\n if (!isClosureEvent(event) && !event.isTask) onPeekOpen?.(event.id);\n },\n [onPeekOpen],\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 /* The host hears where the grid went once per navigation: the first\n datesSet only sets the baseline, a re-fire changes nothing. */\n const lastNavigationRef = useRef<string | null>(null);\n const onNavigateRef = useRef(onNavigate);\n onNavigateRef.current = onNavigate;\n const handleDatesSet = useCallback(\n (info: CalendarDatesSetInfo) => {\n currentDateRef.current = info.currentDate;\n const { view, axis } = placeRef.current;\n const date = localIsoDate(info.currentDate);\n const navigation = `${view}|${axis ?? ''}|${date}`;\n if (\n lastNavigationRef.current !== null &&\n lastNavigationRef.current !== navigation\n ) {\n onNavigateRef.current?.({ view, date, ...(axis ? { axis } : {}) });\n }\n lastNavigationRef.current = navigation;\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 const recordMoved = useCallback(\n (change: {\n eventId: string;\n oldStart: Date;\n newStart: Date;\n alsoIds?: readonly string[];\n }) => {\n const deltaMs = change.newStart.getTime() - change.oldStart.getTime();\n for (const id of new Set([change.eventId, ...(change.alsoIds ?? [])])) {\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 },\n [rows, onHistory],\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 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 },\n };\n owned.set(updated, r);\n return updated;\n }),\n );\n if (!change.deferHistory) recordMoved(change);\n return (current: CalendarRow[]): CalendarRow[] =>\n current.map((row) => owned.get(row) ?? row);\n },\n [setRows, axisKind, recordMoved],\n );\n\n /* The host's write rule for move, resize, copy and a copy's Undo: the\n change is already on the grid; a refusal puts it back and tells the\n user at once (an alert). A move also passes `refusedReadout`: its\n polite readout already said \"moved\" and must not keep saying it. */\n const settleWrite = useCallback(\n (\n written: Promise<unknown>,\n rollback: (rows: CalendarRow[]) => CalendarRow[],\n fallback: string,\n onSaved?: () => void,\n refusedReadout?: string,\n ) => {\n written.then(\n () => onSaved?.(),\n (error: unknown) => {\n setRows(rollback);\n const message =\n error instanceof Error && error.message.trim()\n ? error.message\n : fallback;\n if (refusedReadout !== undefined) setMoveReadout(refusedReadout);\n if (message) toastError(message);\n },\n );\n },\n [setRows],\n );\n\n /* A move that reaches the host through its write handler records its\n history only once that write succeeds. */\n const commitMove = useCallback(\n (\n change: Parameters<typeof applyDrop>[0],\n scope: RecurringScope,\n notify: CalendarMoveNotify,\n ) => {\n if (!onMoveAppointment) {\n applyDrop(change);\n return;\n }\n const resourceId = change.resourceId;\n const written = onMoveAppointment({\n eventId: change.eventId,\n scope,\n alsoEventIds: change.alsoIds ?? [],\n oldStart: change.oldStart,\n newStart: change.newStart,\n newEnd: change.newEnd,\n ...(axisKind === 'chair' && resourceId ? { chairId: resourceId } : {}),\n ...(axisKind === 'operator' && resourceId\n ? { operatorId: resourceId }\n : {}),\n notify,\n });\n const rollback = applyDrop({ ...change, deferHistory: true });\n settleWrite(\n written,\n rollback,\n t(key('moveConfirm.revertReadout')),\n () => recordMoved(change),\n t(key('moveConfirm.revertReadout')),\n );\n },\n [onMoveAppointment, applyDrop, axisKind, settleWrite, recordMoved, t],\n );\n\n /* Sets one row's end and hands back the put-back for a refused write.\n It only restores a row this call replaced, never a newer one. */\n const setEnd = useCallback(\n (eventId: string, end: Date) => {\n const owned = new WeakMap<CalendarRow, CalendarRow>();\n setRows((prev) => {\n const next = rowsWithEnd(prev, eventId, end);\n next.forEach((row, index) => {\n if (row !== prev[index]) owned.set(row, prev[index]);\n });\n return next;\n });\n return (current: CalendarRow[]): CalendarRow[] =>\n current.map((row) => owned.get(row) ?? row);\n },\n [setRows],\n );\n\n const applyResize = useCallback(\n (eventId: string, newEnd: Date) => {\n const before = rows.find((r) => r.event.id === eventId);\n const rollback = setEnd(eventId, newEnd);\n const record = (): void => {\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 return { rollback, record };\n },\n [setEnd, rows, onHistory],\n );\n\n /* Move-confirm notify ticks (business rule C3). The practice's ONE\n \"appointment moved\" switch decides whether the ticks show at all; both\n then show. A tick starts TICKED when that channel's default reminder is\n on AND the patient can take the channel; one the patient cannot take\n is disabled, with its reason. A reminder default the host does not\n pass counts as OFF (B7); an unpassed `moved` keeps the notice on. */\n const patientNotices = practiceSettings?.value.patientNotices;\n const movedNoticeOn = patientNotices?.moved !== false;\n /* A default the host does not pass is OFF, as in the editor (B7). */\n const smsDefaultOn = patientNotices?.reminderSms === true;\n const emailDefaultOn = patientNotices?.reminderEmail === true;\n const seedNotifyDefaults = useCallback(\n (patientId: string) => {\n const channels = signChannelStates(patientRefById(patientId, data));\n setNotifySms(channelReady(channels.sms) && smsDefaultOn);\n setNotifyEmail(channelReady(channels.email) && emailDefaultOn);\n },\n [data, smsDefaultOn, emailDefaultOn],\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 (gridLocked) {\n info.revert?.();\n if (readOnly) toastWarning(t(inc1('readOnly.changeBlocked')));\n return;\n }\n onMoveDropped?.(info.event.id);\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 (movesSilently(info.event) && !hostSeriesMove(info.event)) {\n const commit = (): void => {\n commitMove(\n {\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 'this',\n NO_NOTIFY,\n );\n };\n /* A closed day warns, then lets the move through (P25). */\n if (closure) {\n setClosedPrompt({\n reason: closureReason(t, locale, closure, info.newStart, data),\n action: 'move',\n onConfirm: commit,\n onCancel: () => info.revert?.(),\n });\n return;\n }\n commit();\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 ...(closure ? { closure } : {}),\n revert: info.revert,\n });\n },\n [\n commitMove,\n seedNotifyDefaults,\n hostSeriesMove,\n axisKind,\n rows,\n t,\n locale,\n data,\n readOnly,\n gridLocked,\n reviewOnlyEventIds,\n onMoveDropped,\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 (gridLocked) {\n info.revert?.();\n if (readOnly) toastWarning(t(inc1('readOnly.changeBlocked')));\n return;\n }\n const eventId = info.event.id;\n const oldEnd = info.oldEnd;\n const { rollback, record } = applyResize(eventId, info.newEnd);\n /* The toast and its Undo come only once the host has the new length:\n a refused write offers no Undo for a length it never saved, and\n Undo cannot race the first write. */\n const announce = (): void => {\n record();\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 = maskedTitle(info.event, privacy);\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 const putBack = setEnd(eventId, oldEnd);\n const log = (): void => {\n onHistory(eventId, {\n kind: 'resized',\n fromMin: minutes,\n toMin: oldMinutes,\n });\n toastInfo(t(inc1('resize.undone')));\n };\n if (onResizeAppointment) {\n settleWrite(\n onResizeAppointment({\n eventId,\n oldEnd: info.newEnd,\n newEnd: oldEnd,\n }),\n putBack,\n t(inc1('resize.undoFailed')),\n log,\n );\n } else log();\n },\n },\n });\n };\n if (onResizeAppointment) {\n settleWrite(\n onResizeAppointment({ eventId, oldEnd, newEnd: info.newEnd }),\n rollback,\n t(inc1('resize.failed')),\n announce,\n );\n } else announce();\n },\n [\n applyResize,\n setEnd,\n settleWrite,\n onResizeAppointment,\n privacy,\n onHistory,\n t,\n readOnly,\n gridLocked,\n reviewOnlyEventIds,\n ],\n );\n\n const confirmMove = useCallback(() => {\n if (!pendingMove) return;\n const { event, oldStart, newStart, newEnd } = pendingMove;\n const hostScope = hostSeriesMove(event);\n const before = rows.find((r) => r.event.id === event.id);\n const asksScope = hostScope || rowAsksScope(before);\n if (asksScope)\n onRecurringScopeChosen?.({ action: 'move', scope: moveScope });\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 written = onMoveOccurrence({\n eventId: event.id,\n scope: moveScope,\n oldStart,\n newStart,\n newEnd,\n ...(before?.archiveId ? { archiveId: before.archiveId } : {}),\n ...(axisKind === 'chair' && resourceId ? { chairId: resourceId } : {}),\n ...(axisKind === 'operator' && resourceId\n ? { operatorId: resourceId }\n : {}),\n notify: NO_NOTIFY,\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 settleWrite(\n written,\n rollback,\n t(key('moveConfirm.revertReadout')),\n () => recordMoved({ eventId: event.id, oldStart, newStart }),\n t(key('moveConfirm.revertReadout')),\n );\n return;\n }\n const alsoIds = seriesScopeEventIds(\n rows,\n pendingMove.event.id,\n moveScope,\n ).filter((id) => id !== pendingMove.event.id);\n /* P9: the notice is offered for one occurrence only. */\n const notify =\n movedNoticeOn && notifyOffered(event, asksScope, moveScope)\n ? {\n sms: notifySms,\n email: notifyEmail,\n }\n : NO_NOTIFY;\n commitMove(\n {\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 moveScope,\n notify,\n );\n const channels = [\n notify.sms ? t(key('details.remindSms')) : null,\n notify.email ? 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 movedNoticeOn,\n applyDrop,\n commitMove,\n settleWrite,\n recordMoved,\n notifyOffered,\n t,\n rows,\n moveScope,\n hostSeriesMove,\n onMoveOccurrence,\n onRecurringScopeChosen,\n axisKind,\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 /* The click's real work. `closure` is set only when a Move… placement\n lands on a closed day: the move confirm then carries the warning. */\n const proceedDateClick = useCallback(\n (\n info: CalendarDateClickInfo,\n selectedDurationMin?: number,\n closure?: CalendarClosure,\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 },\n id,\n placement.withTreatments === true,\n );\n setRows((prev) => [...prev, copy]);\n /* The host may answer with its own id: the copy takes it, and\n Undo must name the row the host holds. */\n let copyId = id;\n let undone = false;\n const written = onCopyAppointment?.({\n sourceId: source.event.id,\n row: copy,\n withTreatments: placement.withTreatments === true,\n });\n const recordCreated = (): void => {\n if (!undone) onHistory(copyId, { kind: 'created' });\n };\n if (written) {\n settleWrite(\n written.then((saved) => {\n if (!saved || saved.id === id) return;\n copyId = saved.id;\n setRows((prev) =>\n prev.map((r) =>\n r.event.id === id\n ? { ...r, event: { ...r.event, id: saved.id } }\n : r,\n ),\n );\n }),\n (current) => current.filter((r) => r.event.id !== copyId),\n t(inc1('placement.copyFailed')),\n recordCreated,\n );\n } else recordCreated();\n /* P3: a host that saves copies but cannot delete one would keep\n the copy Undo removed, so Undo is withheld. */\n const canUndo =\n !onCopyAppointment || onDeleteAppointment !== undefined;\n toastInfo(\n t(inc1('placement.copied'), { date: formatDay(locale, start) }),\n canUndo\n ? {\n action: {\n label: t(inc1('placement.undo')),\n onClick: () => {\n undone = true;\n setRows((prev) =>\n prev.filter((r) => r.event.id !== copyId),\n );\n if (!written || !onDeleteAppointment) {\n toastInfo(t(inc1('placement.copyUndone')));\n return;\n }\n /* The host removes the copy once its own save has\n landed; a refused delete puts the copy back. */\n const restore = (\n current: CalendarRow[],\n ): CalendarRow[] =>\n current.some((r) => r.event.id === copyId)\n ? current\n : [\n ...current,\n {\n ...copy,\n event: { ...copy.event, id: copyId },\n },\n ];\n written.then(\n () =>\n settleWrite(\n new Promise<unknown>((resolve) =>\n resolve(onDeleteAppointment(copyId)),\n ),\n restore,\n '',\n () => toastInfo(t(inc1('placement.copyUndone'))),\n ),\n () => undefined,\n );\n },\n },\n }\n : undefined,\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 commitMove(\n {\n eventId: source.event.id,\n resourceId: info.resourceId,\n oldStart: sourceStart,\n newStart: start,\n newEnd,\n },\n 'this',\n NO_NOTIFY,\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 ...(closure ? { closure } : {}),\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 /* A held host tool keeps its unsaved input: no create form over it,\n unless the user armed a placement (create mode) to pick this slot.\n Nor a drawn selection, which would read as an unsaved draft: only\n the select path (it brings a duration) draws one, and the click FC\n sends after it must not clear a slot create mode just booked. */\n if (gridHeld && !createMode) {\n if (selectedDurationMin !== undefined) {\n (\n calRef.current?.getApi() as { unselect?: () => void } | undefined\n )?.unselect?.();\n }\n return;\n }\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 seedNotifyDefaults,\n hostSeriesMove,\n onPlacementEnd,\n gridHeld,\n onCopyAppointment,\n onDeleteAppointment,\n settleWrite,\n commitMove,\n ],\n );\n\n /* Closed day, holiday or absent operator: warn, then let the click\n through (P25). The Month cell only opens the day, so it never warns.\n Read-only, a live projection and a held tool each have their own\n answer and are not asked. A Move… placement of a patient appointment\n carries the warning in its move confirm; every other booking asks\n here. Cancel changes nothing and keeps an armed placement armed. */\n const handleDateClick = useCallback(\n (info: CalendarDateClickInfo, selectedDurationMin?: number) => {\n const warns =\n (!isMonth || placement) &&\n !readOnly &&\n !(projecting && availability) &&\n !(gridHeld && !createMode && !placement);\n const closure = warns\n ? data.closureOn(\n localIsoDate(info.date),\n axisKind === 'operator' ? info.resourceId : undefined,\n )\n : null;\n if (!closure) {\n proceedDateClick(info, selectedDurationMin);\n return;\n }\n /* The same predicate as the drop path: a placement ends in the move\n confirm unless it moves silently and no host series owns the move. */\n const endsInConfirm =\n placement?.kind === 'move' &&\n placementRow !== undefined &&\n !(\n movesSilently(placementRow.event) &&\n !hostSeriesMove(placementRow.event)\n );\n if (endsInConfirm) {\n proceedDateClick(info, selectedDurationMin, closure);\n return;\n }\n setClosedPrompt({\n reason: closureReason(t, locale, closure, info.date, data),\n action: placement?.kind === 'move' ? 'move' : 'book',\n onConfirm: () => proceedDateClick(info, selectedDurationMin),\n onCancel: () => {\n if (selectedDurationMin !== undefined) {\n (\n calRef.current?.getApi() as { unselect?: () => void } | undefined\n )?.unselect?.();\n }\n },\n });\n },\n [\n isMonth,\n placement,\n placementRow,\n readOnly,\n projecting,\n availability,\n gridHeld,\n createMode,\n data,\n axisKind,\n proceedDateClick,\n hostSeriesMove,\n t,\n locale,\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 /* Rule H2: an archive has no 3 days view, so its key does nothing. */\n if (!next || (archived && next === 'threeDays')) return;\n event.preventDefault();\n switchView(next);\n };\n document.addEventListener('keydown', onKeyDown);\n return () => document.removeEventListener('keydown', onKeyDown);\n }, [switchView, archived]);\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 /* The panel offers \"one at a time\" only when the practice has groups\n to flatten: the same rule as the grouped popover, over every operator. */\n const practiceHasOperatorGroups = useMemo(\n () =>\n buildOperatorFilterGroups({\n groups: data.operatorGroups,\n operators: data.operators,\n inactiveIds: data.inactiveOperatorIds,\n withoutGroupLabel: '',\n locale,\n }).length > 1,\n [locale, data],\n );\n /* Flat mode: one list, no group rows. Nothing about the selection\n changes, so the count badge and the Reset chip stay in step. */\n const flatOperators = useMemo(\n () => flattenOperatorFilterGroups(operatorGroups, data.inactiveOperatorIds),\n [operatorGroups, data.inactiveOperatorIds],\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 flatOperatorList =\n practiceHasOperatorGroups && display.operatorListMode === 'flat';\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 /* One personal setting changed in the Settings panel: merge it, keep the date\n when the layout remounts the grid, and tell the host. */\n const changeSetting = (\n setting: keyof WorkspaceDisplaySettings,\n patch: Partial<WorkspaceDisplaySettings>,\n ): void => {\n if (setting === 'orientation') setMountDate(currentDateRef.current);\n setDisplay((d) => ({ ...d, ...patch }));\n onSettingChanged?.({ setting, section: 'personal' });\n };\n const changeHiddenDays = (next: number[]): void => {\n setHiddenDays(next);\n onSettingChanged?.({ setting: 'hiddenDays', section: 'personal' });\n };\n const resetSettings = (): void => {\n // The axis is the View menu's, not the panel's, so it stays; a layout\n // change remounts the grid, which must keep its date.\n setMountDate(currentDateRef.current);\n setDisplay((d) => ({ ...defaultDisplay, resourceKind: d.resourceKind }));\n // The days shown are a separate preference in the same overlay:\n // \"defaults\" covers them too (Sunday hidden).\n setHiddenDays([...DEFAULT_HIDDEN_DAYS]);\n onSettingChanged?.({ setting: 'reset', section: 'personal' });\n };\n /* The Settings panel lives in the rail, not here: hand it the latest props\n after every render, and withdraw them with the surface. */\n useEffect(() => {\n settingsBridge?.publish({\n display,\n onChange: changeSetting,\n hiddenDays,\n onHiddenDaysChange: changeHiddenDays,\n onReset: resetSettings,\n practiceHours: {\n from: practiceWindow.min.slice(0, 2),\n to: practiceWindow.max.slice(0, 2),\n },\n isMonth,\n hasOperatorGroups: practiceHasOperatorGroups,\n academyHref: prompts?.academyHref,\n practiceSettings,\n onPracticeSettingChanged: (setting) =>\n onSettingChanged?.({ setting, section: 'practice' }),\n onHoursOpened,\n });\n });\n useEffect(() => () => settingsBridge?.publish(null), [settingsBridge]);\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 {/* The live region holds ONLY the range text, so a screen reader\n announces the new range on each move and never the month\n button beside it. */}\n <span\n aria-live=\"polite\"\n className=\"type-title-item ds:whitespace-nowrap ds:text-[color:var(--muted-foreground)]\"\n data-calendar-range-title=\"\"\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 EVERY group below is `size=\"sm\"` (32px), the same height strip 2\n uses — one toolbar height across both rows. That is deliberately\n under `--min-target-size`; the exception, its reasoning and its\n accessible-theme escape are documented beside `--min-target-size`\n in `src/tokens/index.css`. Do not raise these back to `md`. */}\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` is the APPOINTMENT right. Tasks follow their own\n seam (a separate platform right), so the group stays while\n either action is available. */}\n {readOnly && !onComposeTask ? null : (\n <ButtonGroup\n intent=\"primary\"\n size=\"sm\"\n label={t(key('actions.createGroupLabel'))}\n >\n {readOnly ? null : (\n <Button\n type=\"button\"\n className={ACCESSIBLE_TARGET_CLASS}\n startIcon={<CalendarPlus aria-hidden=\"true\" />}\n data-action=\"new-appointment\"\n onClick={onComposeNew}\n >\n {t(key('actions.newAppointment'))}\n </Button>\n )}\n {onComposeTask ? (\n <Button\n type=\"button\"\n className={ACCESSIBLE_TARGET_CLASS}\n startIcon={<SquareCheckBig aria-hidden=\"true\" />}\n data-action=\"new-task\"\n onClick={onComposeTask}\n >\n {t(key('actions.newTask'))}\n </Button>\n ) : null}\n </ButtonGroup>\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. Grouped into ONE\n split-outline strip (waiting list, find slots, add to waiting\n list, the backlog) rather than five loose icon buttons. */}\n {availableTools.has(WORKSPACE_TOOL.waitingList) ||\n availableTools.has(WORKSPACE_TOOL.findSlots) ||\n availableTools.has(WORKSPACE_TOOL.bookings) ? (\n <ButtonGroup\n intent=\"outline\"\n size=\"sm\"\n label={t(key('actions.toolsLabel'))}\n >\n {/* Waiting list SPLIT button: main = the waiting-list panel,\n plus = the entry form; the badge counts waiting entries.\n Two SEPARATE conditionals, not one Fragment — `ButtonGroup`\n clones `intent`/`size` one level onto each direct child, and\n a Fragment wrapping both would swallow that for its\n contents (and warn: Fragments take no other props).\n `ACCESSIBLE_TARGET_CLASS` sits on each MEMBER, not the\n group: the group growing taller in the accessible theme\n does not stretch a child with its own explicit `h-10`, so\n every member needs the rule for itself — same as the\n details footer's IconButtons. */}\n {availableTools.has(WORKSPACE_TOOL.waitingList) ? (\n <RailToolButton\n className={ACCESSIBLE_TARGET_SQUARE_CLASS}\n icon={<Hourglass aria-hidden=\"true\" />}\n badgeCount={waitingBadgeCount}\n badgeVariant=\"brand\"\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 ) : null}\n {availableTools.has(WORKSPACE_TOOL.waitingList) ? (\n <IconButton\n type=\"button\"\n className={ACCESSIBLE_TARGET_SQUARE_CLASS}\n icon={<ListPlus aria-hidden=\"true\" />}\n aria-label={t(inc1('toolbar.addToWaitingList'))}\n tooltip={t(inc1('toolbar.addToWaitingList'))}\n onClick={onAddWaitingEntry}\n />\n ) : null}\n {availableTools.has(WORKSPACE_TOOL.findSlots) ? (\n <IconButton\n type=\"button\"\n className={ACCESSIBLE_TARGET_SQUARE_CLASS}\n icon={<CalendarSearch aria-hidden=\"true\" />}\n aria-label={t(key('actions.findFreeSlots'))}\n tooltip={t(key('actions.findFreeSlots'))}\n onClick={() => openSheet('find-slots')}\n />\n ) : null}\n {/* The backlog — \"Da completare\" (1.44.0, PR #174): the rail\n tool that replaced the old \"online bookings\" queue with\n every appointment in view missing a patient, an operator\n or a chair. This member must carry the SAME icon and\n label key as that rail tool, not the retired online-\n bookings identity — `onOpenOnlineBookings`/\n `onlineBookingsCount` are the host-facing prop names only\n (unchanged, so no host seam breaks); what they open and\n count is the backlog. */}\n {availableTools.has(WORKSPACE_TOOL.bookings) ? (\n <RailToolButton\n className={ACCESSIBLE_TARGET_SQUARE_CLASS}\n icon={<ListTodo aria-hidden=\"true\" />}\n badgeCount={onlineBookingsCount}\n badgeVariant=\"warning\"\n aria-label={\n onlineBookingsCount > 0\n ? t(inc1('toolbar.backlogCount'), {\n n: onlineBookingsCount,\n })\n : t(inc1('bookings.title'))\n }\n tooltip={t(inc1('bookings.title'))}\n onClick={onOpenOnlineBookings}\n />\n ) : null}\n </ButtonGroup>\n ) : null}\n <>\n <ButtonGroup\n intent=\"outline\"\n size=\"sm\"\n label={t(key('actions.schedulingLabel'))}\n >\n <IconButton\n type=\"button\"\n className={ACCESSIBLE_TARGET_SQUARE_CLASS}\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 type=\"button\"\n className={ACCESSIBLE_TARGET_SQUARE_CLASS}\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 {/* The cog opens the Settings panel in the tool rail, in place\n of the open tool; pressed again it closes it. Below md the\n rail shows it full screen, so the cog stays on a phone. */}\n {onToggleSettings ? (\n <IconButton\n type=\"button\"\n className={ACCESSIBLE_TARGET_SQUARE_CLASS}\n ref={settingsBridge?.buttonRef}\n intent=\"outline\"\n icon={<SlidersHorizontal />}\n aria-label={t(key('settings.label'))}\n tooltip={t(key('settings.label'))}\n aria-expanded={settingsOpen}\n onClick={onToggleSettings}\n />\n ) : null}\n </ButtonGroup>\n </>\n </div>\n </div>\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 {archived ? null : (\n <Popover open={chairFilterOpen} onOpenChange={setChairFilterOpen}>\n <Tooltip label={t(inc1('toolbar.chairs'))}>\n <Popover.Trigger asChild>\n <Button\n type=\"button\"\n ref={chairFilterButtonRef}\n size=\"sm\"\n className={`ds:shrink-0 ${ACCESSIBLE_TARGET_SQUARE_CLASS} 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={\n <ResourceChip label={chair.title} color={chair.color} />\n }\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 )}\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 {archived ? null : (\n <Popover open={operatorFilterOpen} onOpenChange={setOperatorFilterOpen}>\n <Tooltip label={t(inc1('toolbar.operators'))}>\n <Popover.Trigger asChild>\n <Button\n type=\"button\"\n size=\"sm\"\n className={`ds:shrink-0 ${ACCESSIBLE_TARGET_SQUARE_CLASS} 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 || flatOperatorList ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {(flatOperatorList\n ? flatOperators\n : operatorGroups[0].operators\n ).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 )}\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 type=\"button\"\n intent=\"ghost\"\n size=\"sm\"\n className={`ds:shrink-0 ${ACCESSIBLE_TARGET_CLASS}`}\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 {/* `size=\"sm\"` puts the date field on the row's 32px height. Its\n `className` lands on the wrapper, not the field, so both raises\n below reach the input through a descendant selector rather than\n `ACCESSIBLE_TARGET_CLASS`.\n `max-sm` mirrors what the kit Button's own `sm` variant does for\n itself (`min-h-[--min-target-size] sm:min-h-0`) and DatePicker's\n `triggerVariants` does not: below the `sm` breakpoint, where the\n pointer is a finger, every control takes the full target. Without\n it the row measured 44px buttons beside a 32px date field at\n 600px. Written as `max-sm` rather than a raise-then-reset pair so\n there is only ever one rule, never two of equal specificity\n racing on source order. */}\n <DatePicker\n aria-label={t(key('actions.jumpToDate'))}\n chrome=\"button\"\n size=\"sm\"\n className=\"ds:[&_input]:[min-block-size:var(--accessible-target-floor,auto)] ds:max-sm:[&_input]:[min-block-size:var(--min-target-size)]\"\n value={currentDate}\n onChange={(date) => {\n if (!date) return;\n calRef.current?.gotoDate(date);\n onJumpToDateUsed?.();\n }}\n />\n <DropdownMenu.Root>\n <Tooltip label={t(inc1('view.menuLabel'), { view: viewLabel })}>\n <DropdownMenu.Trigger asChild>\n <Button\n type=\"button\"\n size=\"sm\"\n className={`ds:shrink-0 ${ACCESSIBLE_TARGET_SQUARE_CLASS} 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 {(archived\n ? WORKSPACE_VIEWS.filter((id) => id !== 'threeDays')\n : WORKSPACE_VIEWS\n ).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 {archived ? null : (\n <>\n <DropdownMenu.Separator />\n <DropdownMenu.Label>\n {t(inc1('view.columns'))}\n </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 </>\n )}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n <ButtonGroup size=\"sm\" aria-label={tUi('calendar.ariaLabel')}>\n <Button\n type=\"button\"\n className={ACCESSIBLE_TARGET_CLASS}\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 type=\"button\"\n className={ACCESSIBLE_TARGET_SQUARE_CLASS}\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 type=\"button\"\n className={ACCESSIBLE_TARGET_SQUARE_CLASS}\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(\n (c) => c.id === (peekRow?.chairId ?? peekMeta?.chairId),\n );\n const peekOperator = data.operators.find(\n (o) =>\n o.id ===\n (peekRow?.operatorId ??\n peekMeta?.operatorId ??\n String(peek?.event.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 const pendingAsksScope = rowAsksScope(pendingRow) || pendingHostScope;\n const pendingNotify = pendingMove\n ? notifyOffered(pendingMove.event, pendingAsksScope, moveScope) &&\n movedNoticeOn\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 {calendarArchive ? (\n <CalendarArchiveBanner archive={calendarArchive} />\n ) : null}\n <CalendarPromptAlerts\n prompts={prompts}\n restoreFocus={() => navigationRef.current?.focus()}\n />\n {freeBand && freeOptions.length > 0 && (readOnly || !onlyFreeOption) ? (\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 (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>\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 ? null : (\n <Button\n intent=\"primary\"\n size=\"sm\"\n onClick={() => bookFreeSlot(slot)}\n >\n {t(key('findSlots.book'))}\n </Button>\n )}\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 Important, because Card's own utility sorts later and won. */}\n <Card\n variant=\"elevated\"\n className=\"ds:@container/calendar-frame 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 tabIndex={-1}\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 {errorDates && errorDates.length > 0 ? (\n <CalendarLoadError\n onRetry={\n onRetryLoad\n ? () => {\n /* The alert unmounts once the host marks the day\n loading, taking the focused button with it: park\n focus on the navigation row first. */\n navigationRef.current?.focus();\n onRetryLoad();\n }\n : undefined\n }\n />\n ) : null}\n <div className=\"ds:flex ds:items-start ds:gap-[var(--spacing-md)]\">\n <div className=\"ds:min-w-0 ds:flex-1\">\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 setPeek(null);\n setFreeBand({\n event,\n el: meta.el,\n source: availability,\n });\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 offsets under row 2. */\n className={`ds:[--fc-bg-event-color:var(--muted-foreground)] ${FC_STICKY_OFFSET_CLASS} ${MODE_BANNER_OFFSET_CLASS} ${FOCUS_CLEARANCE_CLASS}`}\n showResourceInitials={\n axisKind === 'operator' &&\n display.operatorNameDisplay === 'initials'\n }\n verticalResourceLabels={\n stem === 'Week' && display.orientation === 'vertical'\n }\n resourceAreaHeader={\n axisKind === 'operator' ? 'operators' : 'chairs'\n }\n resourceAreaWidth=\"14%\"\n initialDate={mountDate}\n locale={locale}\n editable={!gridLocked}\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={display.eventColorStyle ?? 'tinted'}\n slotDensity={display.slotDensity ?? 'compact'}\n slotEventOverlap={false}\n showTime={display.showTime}\n zebraRows={display.zebraRows}\n hiddenDays={hiddenDays}\n loadingDates={loadingDates}\n errorDates={errorDates}\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 && !gridLocked}\n slotMinTime={dayWindow.min}\n slotMaxTime={dayWindow.max}\n slotDuration={display.slotDuration}\n snapDuration={snapForSlot(display.slotDuration)}\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 </div>\n </div>\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 treatment={peekMeta?.care || peek.event.suffix}\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 ...(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 pendingMove.closure\n ? closureReason(\n t,\n locale,\n pendingMove.closure,\n pendingMove.newStart,\n data,\n )\n : null,\n ]\n .filter(Boolean)\n .join('. ')}\n .{' '}\n </VisuallyHidden>\n {pendingNotify ? t(key('moveConfirm.description')) : null}\n </Dialog.Description>\n </Dialog.Header>\n <Dialog.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {pendingMove.closure ? (\n <Alert variant=\"warning\" announce=\"off\">\n <Alert.Description>\n {closureReason(\n t,\n locale,\n pendingMove.closure,\n pendingMove.newStart,\n data,\n )}\n </Alert.Description>\n </Alert>\n ) : null}\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 {pendingAsksScope ? (\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 series\n move beyond \"this appointment\" offers none (P9). */}\n {pendingNotify ? (\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 ) : null}\n </Dialog.Body>\n <Dialog.Footer>\n <Button type=\"button\" intent=\"secondary\" onClick={cancelMove}>\n {t(key('moveConfirm.cancel'))}\n </Button>\n <Button type=\"button\" intent=\"primary\" onClick={confirmMove}>\n {t(key('moveConfirm.confirm'))}\n </Button>\n </Dialog.Footer>\n </Dialog.Content>\n </Dialog>\n ) : null}\n {/* Closed day, holiday or absent operator (P25): the grid warns and\n lets the user go ahead. Cancel leaves everything as it was. */}\n {closedPrompt ? (\n <Dialog\n open\n onOpenChange={(open) => {\n if (open) return;\n closedPrompt.onCancel?.();\n setClosedPrompt(null);\n }}\n >\n <Dialog.Content size=\"sm\" variant=\"confirmation\">\n <Dialog.Header>\n <Dialog.Title>{t(key('closures.warnTitle'))}</Dialog.Title>\n <Dialog.Description>{closedPrompt.reason}</Dialog.Description>\n </Dialog.Header>\n <Dialog.Footer>\n <Button\n type=\"button\"\n intent=\"secondary\"\n onClick={() => {\n closedPrompt.onCancel?.();\n setClosedPrompt(null);\n }}\n >\n {t(key('moveConfirm.cancel'))}\n </Button>\n <Button\n type=\"button\"\n intent=\"primary\"\n onClick={() => {\n const { onConfirm } = closedPrompt;\n setClosedPrompt(null);\n onConfirm();\n }}\n >\n {t(\n key(\n closedPrompt.action === 'move'\n ? 'closures.moveAnyway'\n : 'closures.bookAnyway',\n ),\n )}\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\n type=\"button\"\n intent=\"secondary\"\n onClick={() => setPrintOpen(false)}\n >\n {t(key('moveConfirm.cancel'))}\n </Button>\n <Button\n type=\"button\"\n intent=\"primary\"\n startIcon={<Printer />}\n onClick={() => {\n setPrintOpen(false);\n setPrintPending(true);\n onPrintUsed?.();\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","/**\n * The Practice section's \"Calendar feeds (iCal)\" group: one row for the\n * practice and one per operator, each with a read-only copy field and a\n * \"Revoke and create a new link\" button.\n *\n * Revoking is an IMMEDIATE action, not part of the section's draft: Save and\n * Discard never touch it. It asks first (alert Dialog naming the feed),\n * calls the host, shows loading on that row, then shows the NEW link and\n * announces it politely. A failure keeps the old link and shows the message.\n *\n * The link is a bearer credential: it is never logged, never handed to an\n * analytics hook, and always draws left to right.\n */\nimport { useRef, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Alert } from '../../components/alert';\nimport { Avatar } from '../../components/avatar';\nimport { Button } from '../../components/button';\nimport { CopyField } from '../../components/copy-field';\nimport { Dialog } from '../../components/dialog';\nimport { SectionCard } from '../../components/section-card';\nimport { getErrorMessage } from '../../components/_shared/get-error-message';\nimport type { CalendarIcalFeed, CalendarIcalLinks } from './calendar.types';\n\nexport interface CalendarSettingsIcalProps {\n icalLinks: CalendarIcalLinks;\n /** Prefix of every control's id (`${idPrefix}-ical-<feed id>`). */\n idPrefix: string;\n /** A revoke is in flight: the overlay must not close under it. Raised\n * `false` again when the group unmounts. */\n onBusyChange?: (busy: boolean) => void;\n}\n\n/** A link the host returned, kept against the link it replaced: a host that\n * re-feeds a different URL wins over it. */\ninterface Replacement {\n from: string;\n url: string;\n}\n\nexport function CalendarSettingsIcal({\n icalLinks,\n idPrefix,\n onBusyChange,\n}: CalendarSettingsIcalProps) {\n const { t } = useTranslation('ui');\n const key = (suffix: string): string => `calendarWorkspace.${suffix}`;\n const [asking, setAsking] = useState<CalendarIcalFeed>();\n const [revoking, setRevoking] = useState<string>();\n const [replaced, setReplaced] = useState<Record<string, Replacement>>({});\n const [errors, setErrors] = useState<Record<string, string>>({});\n const [announcement, setAnnouncement] = useState('');\n const buttons = useRef(new Map<string, HTMLButtonElement>());\n /* The row whose button gets focus back when the dialog closes. */\n const returnTo = useRef<string | undefined>(undefined);\n const busyRef = useRef(onBusyChange);\n busyRef.current = onBusyChange;\n\n const canRevoke = (feed: CalendarIcalFeed): boolean =>\n icalLinks.onRevoke !== undefined && feed.canRevoke !== false;\n const anyRevoke = icalLinks.feeds.some(canRevoke);\n\n const urlOf = (feed: CalendarIcalFeed): string => {\n const mine = replaced[feed.id];\n return mine && mine.from === feed.url ? mine.url : feed.url;\n };\n\n const revoke = async (feed: CalendarIcalFeed): Promise<void> => {\n const onRevoke = icalLinks.onRevoke;\n if (revoking !== undefined || !onRevoke) return;\n const from = feed.url;\n setAsking(undefined);\n setRevoking(feed.id);\n setAnnouncement('');\n setErrors(({ [feed.id]: _dropped, ...rest }) => rest);\n onBusyChange?.(true);\n try {\n const next = await onRevoke(feed.id);\n setReplaced((all) => ({ ...all, [feed.id]: { from, url: next.url } }));\n setAnnouncement(t(key('settings.icalRevoked'), { name: feed.label }));\n } catch (failure) {\n setErrors((all) => ({\n ...all,\n [feed.id]: getErrorMessage(failure, t(key('settings.icalFailed'))),\n }));\n } finally {\n setRevoking(undefined);\n busyRef.current?.(false);\n }\n };\n\n return (\n <SectionCard\n variant=\"outlined\"\n headingLevel={4}\n title={t(key('settings.icalTitle'))}\n >\n <p className=\"ds:m-0 type-body-sm\">{t(key('settings.icalHint'))}</p>\n <p role=\"status\" aria-live=\"polite\" className=\"ds:sr-only\">\n {announcement}\n </p>\n <ul className=\"ds:m-0 ds:flex ds:list-none ds:flex-col ds:gap-[var(--spacing-md)] ds:p-0\">\n {icalLinks.feeds.map((feed) => {\n const busy = revoking === feed.id;\n const rowId = `${idPrefix}-ical-${feed.id}`;\n return (\n <li\n key={feed.id}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\"\n >\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-sm)]\">\n <Avatar\n name={feed.label}\n src={feed.avatarSrc}\n size=\"sm\"\n className=\"ds:shrink-0\"\n aria-hidden=\"true\"\n role=\"presentation\"\n aria-label={undefined}\n />\n <span className=\"type-label ds:text-foreground\">\n {feed.label}\n </span>\n </div>\n <CopyField\n id={`${rowId}-link`}\n dir=\"ltr\"\n size=\"sm\"\n value={urlOf(feed)}\n ariaLabel={t(key('settings.icalLinkLabel'), {\n name: feed.label,\n })}\n disabled={busy}\n />\n {errors[feed.id] ? (\n <Alert variant=\"error\">\n <Alert.Description>{errors[feed.id]}</Alert.Description>\n </Alert>\n ) : null}\n {canRevoke(feed) ? (\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)]\">\n <Button\n ref={(el) => {\n if (el) buttons.current.set(feed.id, el);\n else buttons.current.delete(feed.id);\n }}\n id={`${rowId}-revoke`}\n type=\"button\"\n intent=\"outline\"\n size=\"sm\"\n loading={busy}\n aria-describedby={`${rowId}-note`}\n aria-label={t(key('settings.icalRevokeFor'), {\n name: feed.label,\n })}\n onClick={() => {\n returnTo.current = feed.id;\n setAsking(feed);\n }}\n >\n {t(key('settings.icalRevoke'))}\n </Button>\n <span id={`${rowId}-note`} className=\"type-meta\">\n {t(key('settings.icalImmediate'))}\n </span>\n </div>\n ) : null}\n </li>\n );\n })}\n </ul>\n {anyRevoke ? (\n <Dialog\n open={asking !== undefined}\n onOpenChange={(next) => {\n if (!next) setAsking(undefined);\n }}\n >\n <Dialog.Content\n size=\"sm\"\n variant=\"alert\"\n onCloseAutoFocus={(event) => {\n const target = returnTo.current\n ? buttons.current.get(returnTo.current)\n : undefined;\n if (target) {\n event.preventDefault();\n target.focus();\n }\n }}\n >\n <Dialog.Header>\n <Dialog.Title>\n {t(key('settings.icalConfirmTitle'), { name: asking?.label })}\n </Dialog.Title>\n <Dialog.Description>\n {t(key('settings.icalConfirmBody'), { name: asking?.label })}\n </Dialog.Description>\n </Dialog.Header>\n <Dialog.Footer>\n <Button\n type=\"button\"\n intent=\"secondary\"\n onClick={() => setAsking(undefined)}\n >\n {t('common.cancel')}\n </Button>\n <Button\n type=\"button\"\n intent=\"destructive\"\n onClick={() => asking && void revoke(asking)}\n >\n {t(key('settings.icalRevoke'))}\n </Button>\n </Dialog.Footer>\n </Dialog.Content>\n </Dialog>\n ) : null}\n </SectionCard>\n );\n}\n","/**\n * The Settings panel's Practice section: the settings that apply to everyone in the\n * practice. Props-driven like the panel: the kit calls no API, the host\n * passes a seam (`CalendarPracticeSettingsSeam`) and persists in `onSave`.\n *\n * Each control is withheld unless the host passes its member (P3, P18), so\n * the section is absent when no member is present. Edits are a DRAFT until\n * Save. A failed save rolls the controls back to the last saved value and\n * shows the host's message. The draft lives in this component, which\n * unmounts with the panel. The workspace asks before the rail leaves it on an unsaved\n * draft (`onDirtyChange`).\n *\n * Re-feeds: a `value` the host passes again becomes the baseline. What the\n * user changed keeps its draft (per key, and per channel inside a notice\n * group), everything else follows the new value, and a save lays only those\n * changes over that baseline, so a change another admin made to a setting\n * or channel this user did not touch is never overwritten. A\n * re-feed that arrives while a save is in flight waits until it ends.\n */\nimport { useEffect, useId, useRef, useState, type ReactNode } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Alert } from '../../components/alert';\nimport { Button } from '../../components/button';\nimport { Link } from '../../components/link';\nimport { SectionCard } from '../../components/section-card';\nimport { Switch } from '../../components/switch';\nimport { TextArea } from '../../components/text-area';\nimport { TokenInsertMenu } from '../../components/token-insert-menu';\nimport { getErrorMessage } from '../../components/_shared/get-error-message';\nimport { CalendarSettingsIcal } from './calendar-settings-ical';\nimport type {\n CalendarPracticeSettingsSeam,\n PracticeCalendarSettings,\n PracticeOperatorNotices,\n PracticePatientNotices,\n} from './calendar.types';\n\n/** The boolean controls of the section, in display order. */\nconst PRACTICE_SWITCHES = [\n { setting: 'openOnHolidays', labelKey: 'settings.practiceOpenOnHolidays' },\n {\n setting: 'careAllocationFilter',\n labelKey: 'settings.practiceCareAllocation',\n },\n] as const satisfies ReadonlyArray<{\n setting: keyof PracticeCalendarSettings;\n labelKey: string;\n}>;\n\n/** The patient notice channels, in display order. */\nconst PATIENT_NOTICE_SWITCHES = [\n { channel: 'reminderSms', labelKey: 'settings.practiceReminderSms' },\n { channel: 'reminderEmail', labelKey: 'settings.practiceReminderEmail' },\n {\n channel: 'confirmationSms',\n labelKey: 'settings.practiceConfirmationSms',\n },\n { channel: 'moved', labelKey: 'settings.practiceMoved' },\n] as const satisfies ReadonlyArray<{\n channel: keyof PracticePatientNotices;\n labelKey: string;\n}>;\n\nconst OPERATOR_NOTICE_SWITCHES = [\n { channel: 'onCancel', labelKey: 'settings.practiceOperatorOnCancel' },\n { channel: 'onChange', labelKey: 'settings.practiceOperatorOnChange' },\n {\n channel: 'onUserChange',\n labelKey: 'settings.practiceOperatorOnUserChange',\n },\n] as const satisfies ReadonlyArray<{\n channel: keyof PracticeOperatorNotices;\n labelKey: string;\n}>;\n\ntype NoticeKey = 'patientNotices' | 'operatorNotices';\n\n/** The channels of a notice group the host listed: an unlisted channel\n * gets no switch (P3). */\nfunction listedChannels<C extends string>(\n group: Partial<Record<C, boolean>> | undefined,\n all: ReadonlyArray<{ channel: C; labelKey: string }>,\n): ReadonlyArray<{ channel: C; labelKey: string }> {\n return all.filter(({ channel }) => group?.[channel] !== undefined);\n}\n\n/** The settings keys that get a control, in display order. */\nfunction presentKeys(\n value: PracticeCalendarSettings,\n): Array<keyof PracticeCalendarSettings> {\n const keys: Array<keyof PracticeCalendarSettings> = PRACTICE_SWITCHES.map(\n ({ setting }) => setting,\n ).filter((setting) => value[setting] !== undefined);\n if (listedChannels(value.patientNotices, PATIENT_NOTICE_SWITCHES).length) {\n keys.push('patientNotices');\n }\n if (listedChannels(value.operatorNotices, OPERATOR_NOTICE_SWITCHES).length) {\n keys.push('operatorNotices');\n }\n if (value.whatsappMessage !== undefined) keys.push('whatsappMessage');\n return keys;\n}\n\n/** Key-order independent signature, so a re-fed object compares equal. */\nfunction signature(value: unknown): string {\n return JSON.stringify(value, (_key, v: unknown) =>\n v && typeof v === 'object' && !Array.isArray(v)\n ? Object.fromEntries(\n Object.entries(v).sort(([a], [b]) => (a < b ? -1 : 1)),\n )\n : v,\n );\n}\n\n/**\n * `host` with the user's changes laid over it: the difference between\n * `draft` and `baseline`, per key, and per channel inside a notice group, so\n * a channel another admin changed in the same group is never overwritten.\n * The WhatsApp text keeps the host's limit and variables.\n */\nfunction layerChanges(\n host: PracticeCalendarSettings,\n baseline: PracticeCalendarSettings,\n draft: PracticeCalendarSettings,\n keys: ReadonlyArray<keyof PracticeCalendarSettings>,\n): PracticeCalendarSettings {\n const next: PracticeCalendarSettings = { ...host };\n for (const setting of keys) {\n if (setting === 'patientNotices' || setting === 'operatorNotices') {\n const mine: Partial<Record<string, boolean>> = { ...draft[setting] };\n const was: Partial<Record<string, boolean>> = { ...baseline[setting] };\n const layered: Partial<Record<string, boolean>> = { ...host[setting] };\n for (const [channel, on] of Object.entries(mine)) {\n if (on !== was[channel]) layered[channel] = on;\n }\n Object.assign(next, { [setting]: layered });\n } else if (setting === 'whatsappMessage') {\n const text = draft.whatsappMessage;\n if (text) {\n next.whatsappMessage = host.whatsappMessage\n ? { ...host.whatsappMessage, value: text.value }\n : text;\n }\n } else {\n Object.assign(next, { [setting]: draft[setting] });\n }\n }\n return next;\n}\n\n/** The iCal group shows only with at least one feed to list. */\nfunction hasIcalFeeds(seam: CalendarPracticeSettingsSeam): boolean {\n return (seam.icalLinks?.feeds.length ?? 0) > 0;\n}\n\n/** Whether the seam carries at least one member, so the section shows. */\nexport function hasPracticeMember(\n seam: CalendarPracticeSettingsSeam | undefined,\n): seam is CalendarPracticeSettingsSeam {\n if (!seam) return false;\n return (\n seam.hoursSummary !== undefined ||\n presentKeys(seam.value).length > 0 ||\n hasIcalFeeds(seam)\n );\n}\n\nexport interface CalendarSettingsPracticeProps {\n seam: CalendarPracticeSettingsSeam;\n /** Prefix of every control's agent instance id (`${idPrefix}-<setting>`). */\n idPrefix: string;\n /** A save is in flight: the overlay must not close under it. Raised\n * `false` again when the section unmounts. */\n onBusyChange?: (busy: boolean) => void;\n /** The draft differs from the saved value: the overlay asks before it\n * closes. Raised `false` again when the section unmounts. */\n onDirtyChange?: (dirty: boolean) => void;\n /** The hours link was followed (PRD event calendar_scheduler_opened). */\n onHoursOpened?: () => void;\n /** One changed key was saved (PRD event calendar_setting_changed). */\n onSettingChanged?: (setting: string) => void;\n}\n\nexport function CalendarSettingsPractice({\n seam,\n idPrefix,\n onBusyChange,\n onDirtyChange,\n onHoursOpened,\n onSettingChanged,\n}: CalendarSettingsPracticeProps) {\n const { t } = useTranslation('ui');\n const key = (suffix: string): string => `calendarWorkspace.${suffix}`;\n const { hoursSummary } = seam;\n const shownKeys = presentKeys(seam.value);\n const shown = PRACTICE_SWITCHES.filter(({ setting }) =>\n shownKeys.includes(setting),\n );\n const noticeId = useId();\n\n const [baseline, setBaseline] = useState(seam.value);\n const [draft, setDraft] = useState(seam.value);\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState<string>();\n /* A polite status: a save is a change for the whole practice, so success\n is announced, not only failure. Cleared by the next edit. */\n const [saved, setSaved] = useState(false);\n const changedKeys = shownKeys.filter(\n (setting) => signature(draft[setting]) !== signature(baseline[setting]),\n );\n const dirty = changedKeys.length > 0;\n /* The WhatsApp text is checked against the host's limit before Save is\n offered (P3: the host states the limit, the kit never sends it). */\n const whatsapp = draft.whatsappMessage;\n const tooLong =\n whatsapp?.maxLength !== undefined &&\n [...whatsapp.value].length > whatsapp.maxLength;\n const textRef = useRef<HTMLTextAreaElement>(null);\n\n /* A value the host re-feeds becomes the baseline. The keys the user\n changed keep their draft; the rest follow the host. While a save runs\n the re-feed waits: the host's value then wins once it ends. */\n const valueSignature = signature(seam.value);\n const [seenSignature, setSeenSignature] = useState(valueSignature);\n if (!saving && valueSignature !== seenSignature) {\n setSeenSignature(valueSignature);\n setBaseline(seam.value);\n setDraft(layerChanges(seam.value, baseline, draft, changedKeys));\n }\n\n const onBusyRef = useRef(onBusyChange);\n const onDirtyRef = useRef(onDirtyChange);\n /* A save and an iCal revoke can both hold the overlay open: it is busy\n while either runs. */\n const busyKinds = useRef({ save: false, revoke: false });\n const reportBusy = (kind: 'save' | 'revoke', busy: boolean): void => {\n busyKinds.current[kind] = busy;\n onBusyChange?.(busyKinds.current.save || busyKinds.current.revoke);\n };\n useEffect(() => {\n onBusyRef.current = onBusyChange;\n onDirtyRef.current = onDirtyChange;\n });\n useEffect(() => {\n onDirtyRef.current?.(dirty);\n }, [dirty]);\n /* The section can unmount mid-save or mid-edit (the host drops the seam):\n the overlay's flags must not stay set. */\n useEffect(\n () => () => {\n onBusyRef.current?.(false);\n onDirtyRef.current?.(false);\n },\n [],\n );\n\n const save = async (): Promise<void> => {\n if (!dirty || saving || tooLong) return;\n const keys = changedKeys;\n const next = layerChanges(baseline, baseline, draft, keys);\n setSaving(true);\n setError(undefined);\n setSaved(false);\n reportBusy('save', true);\n try {\n await seam.onSave(next, keys);\n setBaseline(next);\n setDraft(next);\n setSaved(true);\n for (const setting of keys) onSettingChanged?.(setting);\n } catch (failure) {\n setDraft(baseline);\n setError(getErrorMessage(failure, t(key('settings.practiceSaveFailed'))));\n } finally {\n setSaving(false);\n reportBusy('save', false);\n }\n };\n const setNotice = (\n group: NoticeKey,\n channel: string,\n next: boolean,\n ): void => {\n setError(undefined);\n setSaved(false);\n setDraft((d) => ({ ...d, [group]: { ...d[group], [channel]: next } }));\n };\n const setWhatsapp = (text: string): void => {\n setError(undefined);\n setSaved(false);\n setDraft((d) =>\n d.whatsappMessage\n ? { ...d, whatsappMessage: { ...d.whatsappMessage, value: text } }\n : d,\n );\n };\n /* Splice the placeholder in at the caret, or at the end when the field\n was never focused. */\n const insertPlaceholder = (token: string): void => {\n const current = draft.whatsappMessage?.value ?? '';\n const el = textRef.current;\n const from = el?.selectionStart ?? current.length;\n const to = el?.selectionEnd ?? current.length;\n setWhatsapp(`${current.slice(0, from)}${token}${current.slice(to)}`);\n };\n const discard = (): void => {\n if (!dirty || saving) return;\n setDraft(baseline);\n setError(undefined);\n setSaved(false);\n };\n\n let hoursLink: ReactNode = null;\n if (hoursSummary?.onOpen) {\n hoursLink = (\n <Button\n intent=\"link\"\n onClick={() => {\n onHoursOpened?.();\n hoursSummary.onOpen?.();\n }}\n >\n {t(key('settings.practiceHoursLink'))}\n </Button>\n );\n } else if (hoursSummary?.href) {\n hoursLink = (\n <Link href={hoursSummary.href} external onClick={onHoursOpened}>\n {t(key('settings.practiceHoursLink'))}\n </Link>\n );\n }\n\n const notices = shownKeys.filter(\n (setting) =>\n setting === 'patientNotices' ||\n setting === 'operatorNotices' ||\n setting === 'whatsappMessage',\n );\n const renderNoticeGroup = <C extends string>({\n group,\n titleKey,\n hintKey,\n items,\n }: {\n group: NoticeKey;\n titleKey: string;\n hintKey: string;\n items: ReadonlyArray<{ channel: C; labelKey: string }>;\n }): ReactNode => (\n <div\n role=\"group\"\n aria-labelledby={`${noticeId}-${group}`}\n aria-describedby={`${noticeId}-${group}-hint`}\n className=\"ds:flex ds:flex-col\"\n >\n <h5\n id={`${noticeId}-${group}`}\n className=\"ds:m-0 type-label ds:text-foreground\"\n >\n {t(key(titleKey))}\n </h5>\n <p id={`${noticeId}-${group}-hint`} className=\"ds:m-0 type-body-sm\">\n {t(key(hintKey))}\n </p>\n {items.map(({ channel, labelKey }) => (\n <div\n key={channel}\n className=\"ds:flex ds:min-h-[var(--min-target-size)] ds:items-center\"\n >\n <Switch\n id={`${idPrefix}-${group}-${channel}`}\n label={t(key(labelKey))}\n labelSide=\"start\"\n className=\"ds:ms-auto\"\n checked={\n (draft[group] as Partial<Record<string, boolean>> | undefined)?.[\n channel\n ] === true\n }\n onCheckedChange={(next) => setNotice(group, channel, next)}\n />\n </div>\n ))}\n </div>\n );\n\n return (\n <section\n aria-labelledby={`${idPrefix}-practice-title`}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n <h3 id={`${idPrefix}-practice-title`} className=\"ds:m-0 type-title-card\">\n {t(key('settings.practice'))}\n </h3>\n <p className=\"ds:m-0 type-body-sm\">{t(key('settings.practiceHint'))}</p>\n <p role=\"status\" className=\"ds:sr-only\">\n {saved ? t(key('settings.practiceSaved')) : ''}\n </p>\n {error ? (\n <Alert variant=\"error\">\n <Alert.Description>{error}</Alert.Description>\n </Alert>\n ) : null}\n {hoursSummary ? (\n <SectionCard\n variant=\"outlined\"\n headingLevel={4}\n title={t(key('settings.practiceHours'))}\n >\n <p className=\"ds:m-0 type-body-sm\">{hoursSummary.text}</p>\n {hoursLink ? (\n <div className=\"ds:flex ds:min-h-[var(--min-target-size)] ds:items-center\">\n {hoursLink}\n </div>\n ) : null}\n </SectionCard>\n ) : null}\n {shown.length > 0 ? (\n <SectionCard\n variant=\"outlined\"\n headingLevel={4}\n title={t(key('settings.practiceRules'))}\n >\n {shown.map(({ setting, labelKey }) => (\n <div\n key={setting}\n className=\"ds:flex ds:min-h-[var(--min-target-size)] ds:items-center\"\n >\n <Switch\n id={`${idPrefix}-${setting}`}\n label={t(key(labelKey))}\n labelSide=\"start\"\n className=\"ds:ms-auto\"\n checked={draft[setting] === true}\n onCheckedChange={(next) => {\n setError(undefined);\n setSaved(false);\n setDraft((d) => ({ ...d, [setting]: next }));\n }}\n />\n </div>\n ))}\n </SectionCard>\n ) : null}\n {notices.length > 0 ? (\n <SectionCard\n variant=\"outlined\"\n headingLevel={4}\n title={t(key('settings.practiceNotices'))}\n >\n {shownKeys.includes('patientNotices')\n ? renderNoticeGroup({\n group: 'patientNotices',\n titleKey: 'settings.practicePatientNotices',\n hintKey: 'settings.practicePatientNoticesHint',\n items: listedChannels(\n draft.patientNotices,\n PATIENT_NOTICE_SWITCHES,\n ),\n })\n : null}\n {shownKeys.includes('operatorNotices')\n ? renderNoticeGroup({\n group: 'operatorNotices',\n titleKey: 'settings.practiceOperatorNotices',\n hintKey: 'settings.practiceOperatorNoticesHint',\n items: listedChannels(\n draft.operatorNotices,\n OPERATOR_NOTICE_SWITCHES,\n ),\n })\n : null}\n {whatsapp ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <h5\n id={`${noticeId}-whatsapp`}\n className=\"ds:m-0 type-label ds:text-foreground\"\n >\n {t(key('settings.practiceWhatsapp'))}\n </h5>\n <p\n id={`${noticeId}-whatsapp-hint`}\n className=\"ds:m-0 type-body-sm\"\n >\n {t(key('settings.practiceWhatsappHint'))}\n </p>\n <TextArea\n ref={textRef}\n id={`${idPrefix}-whatsappMessage`}\n aria-labelledby={`${noticeId}-whatsapp`}\n aria-describedby={`${noticeId}-whatsapp-hint ${noticeId}-whatsapp-count`}\n aria-invalid={tooLong || undefined}\n tone={tooLong ? 'error' : 'default'}\n autoResize\n minRows={3}\n maxRows={8}\n value={whatsapp.value}\n onChange={(event) => setWhatsapp(event.target.value)}\n />\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n {whatsapp.variables && whatsapp.variables.length > 0 ? (\n <TokenInsertMenu\n id={`${idPrefix}-whatsappMessage-placeholders`}\n triggerLabel={t(key('settings.practiceWhatsappInsert'))}\n tokens={whatsapp.variables.map((token) => ({\n value: token,\n label: token,\n }))}\n onInsert={insertPlaceholder}\n />\n ) : (\n <span />\n )}\n {whatsapp.maxLength !== undefined ? (\n <span\n id={`${noticeId}-whatsapp-count`}\n className={`type-meta ds:tabular-nums ${tooLong ? 'ds:text-destructive' : 'ds:text-muted-foreground'}`}\n >\n {t(key('settings.practiceWhatsappCount'), {\n used: [...whatsapp.value].length,\n max: whatsapp.maxLength,\n })}\n </span>\n ) : null}\n </div>\n {tooLong ? (\n <p\n role=\"alert\"\n className=\"ds:m-0 type-body-sm ds:text-destructive\"\n >\n {t(key('settings.practiceWhatsappTooLong'), {\n max: whatsapp.maxLength,\n })}\n </p>\n ) : null}\n </div>\n ) : null}\n </SectionCard>\n ) : null}\n {seam.icalLinks && hasIcalFeeds(seam) ? (\n <CalendarSettingsIcal\n icalLinks={seam.icalLinks}\n idPrefix={idPrefix}\n onBusyChange={(busy) => reportBusy('revoke', busy)}\n />\n ) : null}\n {shownKeys.length > 0 ? (\n <div\n data-practice-footer=\"\"\n className=\"ds:sticky ds:bottom-0 ds:z-10 ds:flex ds:flex-wrap ds:justify-end ds:gap-[var(--spacing-sm)] ds:border-t ds:border-[color:var(--border)] ds:bg-[var(--popover)] ds:py-[var(--spacing-sm)]\"\n >\n <Button\n intent=\"outline\"\n aria-disabled={!dirty || saving || undefined}\n onClick={discard}\n >\n {t(key('settings.practiceDiscard'))}\n </Button>\n <Button\n intent=\"primary\"\n loading={saving}\n aria-disabled={!dirty || tooLong || undefined}\n onClick={() => void save()}\n >\n {t('common.save')}\n </Button>\n </div>\n ) : null}\n </section>\n );\n}\n","/**\n * Calendar settings sections, and the deprecated Sheet that wraps them.\n *\n * The workspace opens Settings in the tool rail (`CalendarSettingsPanel`,\n * decision P36). This file holds what both surfaces share: the \"My calendar\"\n * section (the per-user display settings), the Practice section\n * (`calendar-settings-practice.tsx`, only when the host passes\n * `practiceSettings` with a member) and the Academy link. They are\n * props-driven: no state of their own, no API. The host writes through\n * `onChange` and persists through its preferences adapter.\n *\n * `CalendarSettingsOverlay` is the older shape, one non-modal kit `Sheet`\n * from the inline-end edge, kept for consumers that mount it themselves.\n */\nimport { useEffect, useId, useRef, useState, type ReactNode } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { RotateCcw } from 'lucide-react';\nimport { Button } from '../../components/button';\nimport { Dialog } from '../../components/dialog';\nimport { CheckboxGroup } from '../../components/checkbox-group';\nimport { FormField } from '../../components/form-field';\nimport { SectionCard } from '../../components/section-card';\nimport { Link } from '../../components/link';\nimport { Select } from '../../components/select';\nimport { Sheet } from '../../components/sheet';\nimport { Switch } from '../../components/switch';\nimport {\n EVENT_FLAGS,\n STATUS_ICON,\n STATUS_LABEL_KEYS,\n} from '../../components/calendar-event-card/calendar-event-card';\nimport { safeAcademyHref } from './calendar-prompts';\nimport {\n DEFAULT_DURATION_RANGE,\n WEEK_DAYS_MONDAY_FIRST,\n type WorkspaceDisplaySettings,\n} from './calendar-workspace.model';\nimport {\n CalendarSettingsPractice,\n hasPracticeMember,\n} from './calendar-settings-practice';\nimport type { CalendarPracticeSettingsSeam } from './calendar.types';\n\n/** The agent instance id of the settings panel. Each control carries\n * `${id}-${setting}`, so an agent sets a row by its setting name. */\nexport const CALENDAR_SETTINGS_OVERLAY_ID = 'calendar-display-settings';\n\n/** A personal setting key as raised to `onChange`: a display field name,\n * `hiddenDays`, or `reset`. */\nexport type CalendarPersonalSetting =\n | keyof WorkspaceDisplaySettings\n | 'hiddenDays'\n | 'reset';\n\nexport interface CalendarSettingsOverlayProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** The user's current display settings. */\n display: WorkspaceDisplaySettings;\n /** One personal display setting changed. The host merges the patch. */\n onChange: (\n setting: keyof WorkspaceDisplaySettings,\n patch: Partial<WorkspaceDisplaySettings>,\n ) => void;\n /** The weekdays this user hides, 0 (Sunday) to 6 (Saturday). The overlay\n * never lets the last shown day be hidden. */\n hiddenDays: readonly number[];\n onHiddenDaysChange: (hiddenDays: number[]) => void;\n /** Return every display setting to the workspace defaults. */\n onReset: () => void;\n /** The practice's opening and closing hour, two digits each. */\n practiceHours: { from: string; to: string };\n /** The practice has operator groups. Without them the operator list\n * setting is withheld, as there is nothing to group. */\n hasOperatorGroups?: boolean;\n /** The grid shows Month: day-and-week settings carry a note. */\n isMonth?: boolean;\n /** The Academy calendar tutorial: the host's https link. Absent = no\n * link. Opens in a new tab. */\n academyHref?: string;\n /** Where focus goes when the overlay closes: the control that opened it. */\n returnFocusRef?: React.RefObject<HTMLElement | null>;\n /** The host's Practice section seam. Absent, or with no member, the\n * section does not render. */\n practiceSettings?: CalendarPracticeSettingsSeam;\n /** One practice key was saved (PRD event calendar_setting_changed). */\n onPracticeSettingChanged?: (setting: string) => void;\n /** The hours link of the Practice section was followed (PRD event\n * calendar_scheduler_opened). */\n onHoursOpened?: () => void;\n /** Filled with a close request that applies the same guard as Escape and\n * Close (a save in flight waits, an unsaved Practice draft is asked\n * about). For a host control outside the overlay that closes it. */\n closeRequestRef?: React.MutableRefObject<(() => void) | null>;\n}\n\n/** What the sections need: the overlay's props that describe the settings\n * themselves, without the Sheet's open state and focus plumbing. */\nexport interface CalendarSettingsSectionsProps extends Omit<\n CalendarSettingsOverlayProps,\n 'open' | 'onOpenChange' | 'onReset' | 'returnFocusRef' | 'closeRequestRef'\n> {\n /** A Practice save started or ended (the host panel holds while true). */\n onPracticeBusyChange?: (busy: boolean) => void;\n /** The Practice draft has, or no longer has, unsaved changes. */\n onPracticeDirtyChange?: (dirty: boolean) => void;\n /** The id of the Month note, when a parent names it as its description. */\n monthNoteId?: string;\n}\n\nconst DURATION_PRESETS = [10, 15, 20, 30, 45, 60];\n\n/**\n * The settings themselves: My calendar, then Practice when the host passes a\n * member, then the Academy link. It is the body of the Settings panel in the\n * tool rail (`CalendarSettingsPanel`) and of the deprecated\n * `CalendarSettingsOverlay` Sheet. Props-driven: no state of its own, no API.\n */\nexport function CalendarSettingsSections({\n display,\n onChange,\n hiddenDays,\n onHiddenDaysChange,\n practiceHours,\n isMonth = false,\n hasOperatorGroups = false,\n academyHref,\n practiceSettings,\n onPracticeSettingChanged,\n onHoursOpened,\n onPracticeBusyChange,\n onPracticeDirtyChange,\n monthNoteId: monthNoteIdProp,\n}: CalendarSettingsSectionsProps) {\n const { t, i18n } = useTranslation('ui');\n const key = (suffix: string): string => `calendarWorkspace.${suffix}`;\n const inc1 = (suffix: string): string => `calendarWorkspace.inc1.${suffix}`;\n const generatedMonthNoteId = useId();\n const monthNoteId = monthNoteIdProp ?? generatedMonthNoteId;\n const myCalendarId = useId();\n const academyUrl = safeAcademyHref(academyHref);\n const rowId = (setting: string): string =>\n `${CALENDAR_SETTINGS_OVERLAY_ID}-${setting}`;\n\n /* A practice already on another duration (say 40 minutes) keeps it: the\n current value joins the presets, so opening the overlay never silently\n changes a saved setting. */\n const durationOptions = [\n ...new Set([...DURATION_PRESETS, display.defaultDurationMin]),\n ]\n .filter(\n (minutes) =>\n minutes >= DEFAULT_DURATION_RANGE.min &&\n minutes <= DEFAULT_DURATION_RANGE.max,\n )\n .sort((a, b) => a - b)\n .map((minutes) => ({\n value: String(minutes),\n label: t(inc1('settings.durationOption'), { minutes }),\n }));\n\n const choice = <K extends keyof WorkspaceDisplaySettings>(\n setting: K,\n label: string,\n options: Array<{ value: string; label: string }>,\n value: string,\n parse: (raw: string) => WorkspaceDisplaySettings[K] = (raw) =>\n raw as WorkspaceDisplaySettings[K],\n description?: string,\n ): ReactNode => (\n <FormField label={label} description={description}>\n <Select\n id={rowId(setting)}\n options={options}\n value={value}\n onValueChange={(next) => {\n if (next !== '' && next !== value) {\n onChange(setting, {\n [setting]: parse(next),\n } as Partial<WorkspaceDisplaySettings>);\n }\n }}\n />\n </FormField>\n );\n\n const toggle = (\n setting:\n | 'zebraRows'\n | 'showTime'\n | 'showCardContext'\n | 'showCancelled'\n | 'mapsLink',\n label: string,\n checked: boolean,\n ): ReactNode => (\n <div className=\"ds:flex ds:min-h-[var(--min-target-size)] ds:items-center\">\n <Switch\n id={rowId(setting)}\n label={label}\n labelSide=\"start\"\n className=\"ds:ms-auto\"\n checked={checked}\n onCheckedChange={(next) =>\n onChange(setting, {\n [setting]: next,\n } as Partial<WorkspaceDisplaySettings>)\n }\n />\n </div>\n );\n\n return (\n <>\n <section\n aria-labelledby={myCalendarId}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n <h3 id={myCalendarId} className=\"ds:m-0 type-title-card\">\n {t(key('settings.myCalendar'))}\n </h3>\n {isMonth ? (\n <p id={monthNoteId} className=\"ds:m-0 type-body-sm\">\n {t(key('settings.monthNote'))}\n </p>\n ) : null}\n <SectionCard\n variant=\"outlined\"\n headingLevel={4}\n title={t(key('settings.sectionView'))}\n >\n {choice(\n 'orientation',\n t(key('settings.orientation')),\n [\n {\n value: 'vertical',\n label: t(key('settings.orientationColumns')),\n },\n {\n value: 'horizontal',\n label: t(key('settings.orientationTimeline')),\n },\n ],\n display.orientation,\n )}\n {choice(\n 'slotDensity',\n t('calendar.card.slotDensity'),\n [\n { value: 'compact', label: t('calendar.card.compact') },\n {\n value: 'comfortable',\n label: t('calendar.card.comfortable'),\n },\n ],\n display.slotDensity ?? 'compact',\n )}\n {choice(\n 'window',\n t(key('settings.window')),\n [\n {\n value: 'working',\n label: t(inc1('settings.windowPractice'), {\n from: practiceHours.from,\n to: practiceHours.to,\n }),\n },\n {\n value: 'extended',\n label: t(key('settings.windowExtended')),\n },\n { value: 'full', label: t(key('settings.windowFull')) },\n ],\n display.window,\n )}\n {choice(\n 'slotDuration',\n t(key('settings.slotDuration')),\n [\n { value: '00:10', label: t(key('settings.slot10')) },\n { value: '00:15', label: t(key('settings.slot15')) },\n { value: '00:20', label: t(key('settings.slot20')) },\n { value: '00:30', label: t(key('settings.slot30')) },\n { value: '01:00', label: t(key('settings.slot60')) },\n ],\n display.slotDuration,\n )}\n {toggle('zebraRows', t(key('settings.zebra')), display.zebraRows)}\n <CheckboxGroup\n id={rowId('daysShown')}\n label={t(key('settings.daysShown'))}\n orientation=\"horizontal\"\n min={1}\n value={WEEK_DAYS_MONDAY_FIRST.filter(\n (day) => !hiddenDays.includes(day),\n ).map(String)}\n options={WEEK_DAYS_MONDAY_FIRST.map((day) => ({\n value: String(day),\n /* 4 January 2026 is a Sunday: offset by the day number. */\n label: new Intl.DateTimeFormat(i18n.language, {\n weekday: 'long',\n }).format(new Date(2026, 0, 4 + day)),\n }))}\n onChange={(shown) => {\n /* The group blocks the last untick; an agent's empty\n selection is not a choice either. */\n if (shown.length === 0) return;\n onHiddenDaysChange(\n WEEK_DAYS_MONDAY_FIRST.filter(\n (day) => !shown.includes(String(day)),\n ).sort((a, b) => a - b),\n );\n }}\n />\n </SectionCard>\n <SectionCard\n variant=\"outlined\"\n headingLevel={4}\n title={t(key('settings.sectionCards'))}\n >\n {choice(\n 'eventColorStyle',\n t('calendar.card.eventColorStyle'),\n [\n { value: 'tinted', label: t('calendar.card.tinted') },\n { value: 'solid', label: t('calendar.card.solid') },\n ],\n display.eventColorStyle ?? 'tinted',\n )}\n {choice(\n 'colorAssociation',\n t(key('settings.colorBy')),\n [\n {\n value: 'appointment',\n label: t(key('settings.colorByAppointment')),\n },\n { value: 'care', label: t(key('settings.colorByCare')) },\n {\n value: 'operator',\n label: t(key('settings.colorByOperator')),\n },\n { value: 'chair', label: t(key('settings.colorByChair')) },\n {\n value: 'status',\n label: t(key('settings.colorByStatus')),\n },\n ],\n display.colorAssociation,\n undefined,\n display.colorAssociation === 'status'\n ? `${t(key('settings.colorByNote'))} ${t(key('settings.colorByStatusNote'))}`\n : t(key('settings.colorByNote')),\n )}\n {toggle(\n 'showCancelled',\n t(key('settings.showCancelled')),\n display.showCancelled,\n )}\n {choice(\n 'careDescription',\n t(key('settings.careDescription')),\n [\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 display.careDescription,\n )}\n {toggle('showTime', t(key('settings.showTime')), display.showTime)}\n {toggle(\n 'showCardContext',\n t('calendar.card.showContext'),\n display.showCardContext ?? false,\n )}\n </SectionCard>\n <SectionCard\n variant=\"outlined\"\n headingLevel={4}\n title={t('calendar.card.legend')}\n >\n <ul className=\"ds:m-0 ds:list-none ds:p-0 ds:space-y-[var(--spacing-xs)]\">\n {Object.entries(STATUS_ICON).map(([status, Icon]) => (\n <li\n key={status}\n className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)] type-body-sm\"\n >\n <Icon aria-hidden=\"true\" className=\"ds:size-4 ds:shrink-0\" />\n {t(STATUS_LABEL_KEYS[status as keyof typeof STATUS_ICON])}\n </li>\n ))}\n {EVENT_FLAGS.map(({ field, Icon, labelKey }) => (\n <li\n key={field}\n className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)] type-body-sm\"\n >\n <Icon aria-hidden=\"true\" className=\"ds:size-4 ds:shrink-0\" />\n {t(labelKey)}\n </li>\n ))}\n <li className=\"type-body-sm\">{t('calendar.card.moreLegend')}</li>\n </ul>\n </SectionCard>\n <SectionCard\n variant=\"outlined\"\n headingLevel={4}\n title={t(key('settings.sectionNames'))}\n >\n {choice(\n 'operatorNameDisplay',\n t(inc1('settings.operatorNames')),\n [\n { value: 'full', label: t(inc1('settings.operatorFull')) },\n {\n value: 'initials',\n label: t(inc1('settings.operatorInitials')),\n },\n ],\n display.operatorNameDisplay,\n )}\n {hasOperatorGroups\n ? choice(\n 'operatorListMode',\n t(inc1('settings.operatorList')),\n [\n {\n value: 'grouped',\n label: t(inc1('settings.operatorListGrouped')),\n },\n {\n value: 'flat',\n label: t(inc1('settings.operatorListFlat')),\n },\n ],\n display.operatorListMode ?? 'grouped',\n )\n : null}\n {choice(\n 'chairNameDisplay',\n t(inc1('settings.chairNames')),\n [\n { value: 'full', label: t(inc1('settings.chairFull')) },\n { value: 'short', label: t(inc1('settings.chairShort')) },\n ],\n display.chairNameDisplay,\n )}\n {choice(\n 'defaultDurationMin',\n t(inc1('settings.defaultDuration')),\n durationOptions,\n String(display.defaultDurationMin),\n Number,\n )}\n {toggle('mapsLink', t(inc1('settings.mapsLink')), display.mapsLink)}\n </SectionCard>\n </section>\n {hasPracticeMember(practiceSettings) ? (\n <CalendarSettingsPractice\n seam={practiceSettings}\n idPrefix={CALENDAR_SETTINGS_OVERLAY_ID}\n onBusyChange={onPracticeBusyChange}\n onDirtyChange={onPracticeDirtyChange}\n onHoursOpened={onHoursOpened}\n onSettingChanged={onPracticeSettingChanged}\n />\n ) : null}\n {academyUrl ? (\n <p className=\"ds:m-0 ds:mt-[var(--spacing-md)] type-body-sm\">\n <Link href={academyUrl} external>\n {t(key('settings.academyTutorial'))}\n </Link>\n </p>\n ) : null}\n </>\n );\n}\n\n/**\n * @deprecated The calendar workspace opens Settings as a rail panel\n * (`CalendarSettingsPanel`, tool id `settings`). This Sheet stays for a host\n * or demo that mounts the settings outside the workspace rail.\n */\nexport function CalendarSettingsOverlay({\n open,\n onOpenChange,\n display,\n onChange,\n hiddenDays,\n onHiddenDaysChange,\n onReset,\n practiceHours,\n isMonth = false,\n hasOperatorGroups = false,\n academyHref,\n returnFocusRef,\n practiceSettings,\n onPracticeSettingChanged,\n onHoursOpened,\n closeRequestRef,\n}: CalendarSettingsOverlayProps) {\n const { t } = useTranslation('ui');\n const key = (suffix: string): string => `calendarWorkspace.${suffix}`;\n /* A practice save in flight keeps the overlay open: Escape and Close wait,\n so the draft and its error are not lost under the call. An unsaved\n draft asks first. Both flags count only while the section shows: a\n section that unmounts mid-save must not hold the overlay shut. */\n const [practiceSaving, setPracticeSaving] = useState(false);\n const [practiceDirty, setPracticeDirty] = useState(false);\n const [confirmDiscard, setConfirmDiscard] = useState(false);\n const practiceShown = hasPracticeMember(practiceSettings);\n const saveBlocksClose = practiceSaving && practiceShown;\n const draftAsksFirst = practiceDirty && practiceShown;\n const requestOpenChange = (next: boolean): void => {\n if (!next && saveBlocksClose) return;\n if (!next && draftAsksFirst) {\n setConfirmDiscard(true);\n return;\n }\n onOpenChange(next);\n };\n const requestCloseRef = useRef(() => {});\n requestCloseRef.current = () => requestOpenChange(false);\n useEffect(() => {\n if (!closeRequestRef) return undefined;\n closeRequestRef.current = () => requestCloseRef.current();\n return () => {\n closeRequestRef.current = null;\n };\n }, [closeRequestRef]);\n const monthNoteId = useId();\n return (\n <>\n <Sheet\n id={CALENDAR_SETTINGS_OVERLAY_ID}\n open={open}\n onOpenChange={requestOpenChange}\n modal={false}\n >\n <Sheet.Content\n side=\"end\"\n size=\"md\"\n aria-describedby={isMonth ? monthNoteId : undefined}\n // The calendar stays usable behind the overlay: a click on the grid\n // does not close it. Close and Escape do.\n onInteractOutside={(event) => event.preventDefault()}\n onCloseAutoFocus={(event) => {\n event.preventDefault();\n returnFocusRef?.current?.focus();\n }}\n >\n <Sheet.Header>\n <Sheet.Title>{t(key('settings.title'))}</Sheet.Title>\n </Sheet.Header>\n <Sheet.Body>\n <CalendarSettingsSections\n display={display}\n onChange={onChange}\n hiddenDays={hiddenDays}\n onHiddenDaysChange={onHiddenDaysChange}\n practiceHours={practiceHours}\n isMonth={isMonth}\n hasOperatorGroups={hasOperatorGroups}\n academyHref={academyHref}\n practiceSettings={practiceSettings}\n onPracticeSettingChanged={onPracticeSettingChanged}\n onHoursOpened={onHoursOpened}\n onPracticeBusyChange={setPracticeSaving}\n onPracticeDirtyChange={setPracticeDirty}\n monthNoteId={monthNoteId}\n />\n </Sheet.Body>\n <Sheet.Footer>\n <Button\n type=\"button\"\n intent=\"outline\"\n startIcon={<RotateCcw aria-hidden />}\n onClick={onReset}\n >\n {t('common.resetToDefaults')}\n </Button>\n </Sheet.Footer>\n </Sheet.Content>\n </Sheet>\n <Dialog\n open={open && confirmDiscard}\n onOpenChange={(next) => {\n if (!next) setConfirmDiscard(false);\n }}\n >\n <Dialog.Content size=\"sm\" variant=\"alert\">\n <Dialog.Header>\n <Dialog.Title>\n {t(key('settings.practiceDiscardTitle'))}\n </Dialog.Title>\n <Dialog.Description>\n {t(key('settings.practiceDiscardBody'))}\n </Dialog.Description>\n </Dialog.Header>\n <Dialog.Footer>\n <Button\n type=\"button\"\n intent=\"secondary\"\n onClick={() => setConfirmDiscard(false)}\n >\n {t(key('settings.practiceKeepEditing'))}\n </Button>\n <Button\n type=\"button\"\n intent=\"destructive\"\n onClick={() => {\n setConfirmDiscard(false);\n onOpenChange(false);\n }}\n >\n {t(key('settings.practiceDiscard'))}\n </Button>\n </Dialog.Footer>\n </Dialog.Content>\n </Dialog>\n </>\n );\n}\n","/**\n * The Settings panel: the calendar's settings as a tool in the workspace\n * rail (decision P36, rule F1). The toolbar's Settings button opens it in\n * place of whichever rail tool is open, the way the appointment editor takes\n * the rail, so the grid stays visible beside it and a change applies at once.\n *\n * The surface owns the settings state and the toolbar button; the rail owns\n * the panel. A small bridge joins them without lifting the state: the\n * surface publishes the panel's props, the rail's panel slot reads the latest\n * ones, and the panel reports back whether it holds unsaved Practice changes\n * so the workspace can ask before the rail leaves it.\n */\nimport { useEffect, useRef, useSyncExternalStore, type RefObject } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { RotateCcw, SlidersHorizontal } from 'lucide-react';\nimport { Button } from '../../components/button';\nimport { Dialog } from '../../components/dialog';\nimport { PanelHeader } from '../../components/panel-header';\nimport {\n CalendarSettingsSections,\n type CalendarSettingsSectionsProps,\n} from './calendar-settings-overlay';\nimport { hasPracticeMember } from './calendar-settings-practice';\n\n/** What the panel needs from the surface. */\nexport interface CalendarSettingsPanelProps extends Omit<\n CalendarSettingsSectionsProps,\n 'monthNoteId' | 'onPracticeBusyChange' | 'onPracticeDirtyChange'\n> {\n /** Return every display setting to the workspace defaults. */\n onReset: () => void;\n}\n\n/** What the panel tells the workspace before the rail may leave it. */\nexport interface CalendarSettingsGuard {\n /** The Practice section holds changes that are not saved. */\n dirty: boolean;\n /** A Practice save is in flight: the panel holds the rail. */\n busy: boolean;\n /** Written by the open panel: moves focus to whatever is busy, so a\n * refused leave is heard instead of ignored. */\n holdFocus: (() => void) | null;\n}\n\n/** The link between the surface (button, state) and the rail (panel). */\nexport interface CalendarSettingsBridge {\n /** The surface publishes the panel's latest props; `null` withdraws them. */\n publish: (props: CalendarSettingsPanelProps | null) => void;\n subscribe: (listener: () => void) => () => void;\n getSnapshot: () => CalendarSettingsPanelProps | null;\n /** Written by the open panel, read by the workspace. */\n guard: CalendarSettingsGuard;\n /** The toolbar's Settings button: focus returns here when the panel closes. */\n buttonRef: RefObject<HTMLButtonElement | null>;\n}\n\nexport function createSettingsBridge(): CalendarSettingsBridge {\n let current: CalendarSettingsPanelProps | null = null;\n const listeners = new Set<() => void>();\n return {\n publish: (props) => {\n current = props;\n listeners.forEach((listener) => listener());\n },\n subscribe: (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n getSnapshot: () => current,\n guard: { dirty: false, busy: false, holdFocus: null },\n buttonRef: { current: null },\n };\n}\n\n/** The rail's panel body for the settings tool: a stable element that reads\n * the surface's latest props, so the rail never re-registers per change. */\nexport function CalendarSettingsPanelSlot({\n bridge,\n}: {\n bridge: CalendarSettingsBridge;\n}) {\n const props = useSyncExternalStore(\n bridge.subscribe,\n bridge.getSnapshot,\n bridge.getSnapshot,\n );\n return props ? <CalendarSettingsPanel {...props} bridge={bridge} /> : null;\n}\n\nexport function CalendarSettingsPanel({\n bridge,\n onReset,\n ...sections\n}: CalendarSettingsPanelProps & { bridge: CalendarSettingsBridge }) {\n const { t } = useTranslation('ui');\n const rootRef = useRef<HTMLDivElement>(null);\n const practiceShown = hasPracticeMember(sections.practiceSettings);\n const { guard } = bridge;\n\n /* Opening moves focus into the panel, unless it is already there. */\n useEffect(() => {\n const frame = requestAnimationFrame(() => {\n const root = rootRef.current;\n if (root && !root.contains(document.activeElement)) {\n root.focus({ preventScroll: true });\n }\n });\n return () => cancelAnimationFrame(frame);\n }, []);\n\n /* A leave refused during a save lands focus on the busy control, whose\n aria-busy a screen reader announces. */\n useEffect(() => {\n guard.holdFocus = () => {\n /* After the rail has put focus on its own strip icon. */\n requestAnimationFrame(() =>\n requestAnimationFrame(() => {\n const root = rootRef.current;\n const busy = root?.querySelector<HTMLElement>('[aria-busy=\"true\"]');\n (busy ?? root)?.focus({ preventScroll: true });\n }),\n );\n };\n return () => {\n guard.holdFocus = null;\n };\n }, [guard]);\n\n /* The flags count only while the Practice section shows, and never\n outlive the panel: a section that unmounts mid-save must not hold the\n rail shut. */\n useEffect(() => {\n if (!practiceShown) {\n guard.dirty = false;\n guard.busy = false;\n }\n }, [practiceShown, guard]);\n useEffect(\n () => () => {\n guard.dirty = false;\n guard.busy = false;\n },\n [guard],\n );\n\n return (\n <div\n ref={rootRef}\n tabIndex={-1}\n data-component=\"calendar-settings-panel\"\n className=\"ds:flex ds:flex-col ds:focus-visible:outline-none\"\n >\n <PanelHeader\n title={t('calendarWorkspace.settings.title')}\n icon={<SlidersHorizontal aria-hidden=\"true\" />}\n sticky\n divider\n />\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-lg)] ds:p-[var(--spacing-md)]\">\n <CalendarSettingsSections\n {...sections}\n onPracticeBusyChange={(busy) => {\n guard.busy = busy;\n }}\n onPracticeDirtyChange={(dirty) => {\n guard.dirty = dirty;\n }}\n />\n <div>\n <Button\n type=\"button\"\n intent=\"outline\"\n startIcon={<RotateCcw aria-hidden />}\n onClick={onReset}\n >\n {t('common.resetToDefaults')}\n </Button>\n </div>\n </div>\n </div>\n );\n}\n\n/**\n * The question before the rail leaves Settings with unsaved Practice changes:\n * by Close, Escape or another rail tool (a strip click, the editor or the\n * details docking from the grid). Keep editing stays; Discard leaves. The\n * appointment editor asks the same question about its typed data (B18), with\n * its own body.\n */\nexport function CalendarSettingsDiscardDialog({\n onKeep,\n onDiscard,\n scope = 'settings',\n}: {\n onKeep: () => void;\n onDiscard: () => void;\n scope?: 'settings' | 'editor';\n}) {\n const { t } = useTranslation('ui');\n return (\n <Dialog\n open\n onOpenChange={(next) => {\n if (!next) onKeep();\n }}\n >\n <Dialog.Content size=\"sm\" variant=\"alert\">\n <Dialog.Header>\n <Dialog.Title>\n {t('calendarWorkspace.settings.practiceDiscardTitle')}\n </Dialog.Title>\n <Dialog.Description>\n {scope === 'editor'\n ? t('calendarWorkspace.editor.discardBody')\n : t('calendarWorkspace.settings.practiceDiscardBody')}\n </Dialog.Description>\n </Dialog.Header>\n <Dialog.Footer>\n <Button type=\"button\" intent=\"secondary\" onClick={onKeep}>\n {t('calendarWorkspace.settings.practiceKeepEditing')}\n </Button>\n <Button type=\"button\" intent=\"destructive\" onClick={onDiscard}>\n {t('calendarWorkspace.settings.practiceDiscard')}\n </Button>\n </Dialog.Footer>\n </Dialog.Content>\n </Dialog>\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 CalendarCreatePatient,\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:sm:[min-block-size:var(--accessible-target-floor,0px)]';\nconst ACCESSIBLE_TARGET_SQUARE = `${ACCESSIBLE_TARGET} ds:[min-inline-size:var(--accessible-target-floor,auto)]`;\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 onOpen,\n ...member\n}: MemberProps & { number: string; label: string; onOpen?: () => void }) {\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 onClick={onOpen}\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 /** The user clicked the WhatsApp link. Raised for a link only (an entry\n * with a number), once per click, with the entry. */\n onWhatsAppClick?: (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 onWhatsAppClick,\n onOpenPatient,\n onOpenAppointment,\n },\n ref,\n ) => {\n const { t } = useTranslation('ui');\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\n number={whatsappNumber}\n label={whatsappLabel}\n onOpen={onWhatsAppClick && (() => onWhatsAppClick(entry))}\n />\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=\"outline\"\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=\"outline\"\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 /** \"Create patient\" under the entry form's patient search (not the\n * filter's). See `CalendarCreatePatient`. Omit it and it is withheld. */\n onCreatePatient?: CalendarCreatePatient;\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 /** The user picked a quick view that was not already chosen, or ran the\n * detailed search (`advanced_search`). Ids and enums only. */\n onFilterUsed?: (filter: WaitingQuickView | 'advanced_search') => void;\n /** The user showed or hid the detailed filters. */\n onAdvancedFilterToggled?: (action: 'show' | 'hide') => void;\n /** The user clicked an entry's WhatsApp link. Raised once per click and\n * never for an entry without a number or under privacy. Carries the\n * entry only: the host reads the id, never a name or a number. */\n onWhatsAppClick?: (entry: CalendarWaitingEntry) => 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 onCreatePatient,\n onCancelEntry,\n onOpenPatient,\n onOpenAppointment,\n readOnly = false,\n privacy = false,\n onFilterUsed,\n onAdvancedFilterToggled,\n onWhatsAppClick,\n },\n ref,\n ) => {\n const { t } = useTranslation('ui');\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 if (next !== quickView) onFilterUsed?.(next);\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 onFilterUsed?.('advanced_search');\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=\"ghost\"\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=\"ghost\"\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={() => {\n onAdvancedFilterToggled?.(\n showAdvanced ? 'hide' : 'show',\n );\n setShowAdvanced((prev) => !prev);\n }}\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\n size=\"sm\"\n intent=\"outline\"\n onClick={() => onRetry()}\n >\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 onWhatsAppClick={onWhatsAppClick}\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 onCreatePatient={onCreatePatient}\n /* The card's ⋮ menu seam, reused — not a second one. Removing\n the entry being edited leaves nothing to save, so the form\n closes the same way Cancel does. */\n onRemove={(removedEntry) => {\n onRemoveWaiting(removedEntry);\n onCancelEntry?.();\n }}\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('ui');\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\n * finder. The kit adds nothing else: no Inbox, no Alia, no patient tabs,\n * no care plan, no tasks. A host may append its own tools after these\n * (`extraTools`), which is how a host mounts TasksPanel. The panels are\n * the 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 {\n CalendarEventStatus,\n CalendarView,\n} from '../../components/calendar';\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type MouseEvent as ReactMouseEvent,\n type MutableRefObject,\n type ReactNode,\n type RefObject,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport type { TFunction } from 'i18next';\nimport { useIsomorphicLayoutEffect } from '../../hooks/use-isomorphic-layout-effect';\nimport {\n CalendarClock,\n CalendarDays,\n CalendarPlus,\n CalendarSearch,\n Hourglass,\n ListTodo,\n NotebookPen,\n SlidersHorizontal,\n SquareCheckBig,\n} from 'lucide-react';\nimport { UpcomingAppointmentsPanel } from './calendar-upcoming-panel';\nimport { CalendarTaskEditor } from './calendar-task-editor';\nimport {\n ControlRoomProvider,\n ControlRoomRail,\n useControlRoomActions,\n useControlRoomTools,\n type ControlRoomFavoriteChange,\n type ControlRoomTool,\n} from '../../components/control-room-rail';\nimport { ScrollArea } from '../../components/scroll-area';\nimport {\n AppFrameEndSlotContext,\n useAppFrameEndSlot,\n type AppFrameEndSlotContextValue,\n} from '../../components/app-frame/app-frame-context';\nimport { useMediaQuery } from '../../hooks/use-media-query';\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 CalendarAppointmentDetailsPanel,\n CalendarDetailsHydration,\n type CalendarAppointmentDetails,\n type CalendarDetailsAction,\n type CalendarDocumentKind,\n type CalendarDetailsSeries,\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 {\n CalendarAppointmentCopy,\n CalendarAppointmentMove,\n CalendarAppointmentResize,\n CalendarJourney,\n CalendarOccurrenceMove,\n} from './calendar.journey';\nimport { CalendarArchiveCreateDialog } from './calendar-archive';\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 CalendarHistoryEntry,\n type CalendarPatient,\n type CalendarArchive,\n type CalendarCreatePatient,\n type CalendarPrompts,\n type CalendarSignChannel,\n type CalendarPracticeSettingsSeam,\n type CalendarTask,\n type CalendarWaitingEntry,\n type PatientRef,\n type TaskDraft,\n patientRefName,\n} from './calendar.types';\nimport {\n type CalendarRow,\n type EditorDraft,\n type DraftSlot,\n type EditorPrefill,\n type FindSlotsSeed,\n type AvailabilityContext,\n type CalendarFreeSlot,\n type RailFocus,\n type WaitingEntryDraft,\n type WaitingQuickView,\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 isWorkspaceToolId,\n resolveAvailableTools,\n resolveExtraTools,\n WORKSPACE_TOOL,\n type WorkspaceDisplaySettings,\n readWorkspaceDisplaySettings,\n onlineBookingsToCheck,\n type BacklogGap,\n DEFAULT_BACKLOG_FILTERS,\n filterBacklogViews,\n bookingRowView,\n type CalendarViewChange,\n type WorkspaceViewId,\n type CreateModeRequest,\n type PlacementRequest,\n type SaveNotice,\n type EditorDraftExtras,\n type DeleteOptions,\n type RecurringScopeChosen,\n RECURRING_SCOPES,\n rowAsksScope,\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 {\n createEditorGuard,\n EditorGuardProvider,\n type CalendarEditorGuard,\n} from './calendar-editor-guard';\nimport {\n CalendarSettingsDiscardDialog,\n CalendarSettingsPanelSlot,\n createSettingsBridge,\n type CalendarSettingsBridge,\n} from './calendar-settings-panel';\nimport { WaitingListPanel } from './calendar-waiting-list-panel';\nimport { PrivacyNoticePanel } from './calendar-privacy';\nimport { isCustomRule } from './calendar-custom-recurrence';\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 kit adds no global tools: the agenda's own tools, then any the\n host appends (`extraTools`), all contextual. One stable array, so the\n provider never re-registers. */\nconst NO_GLOBAL_TOOLS: ControlRoomTool[] = [];\n\n/* Stable, so a host that passes no `extraTools` never re-registers. */\nconst NO_EXTRA_TOOLS: readonly CalendarWorkspaceExtraTool[] = [];\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 built-in tool docks. The editor line\n is the create form's: details docks from a grid selection, which names\n the patient instead. */\nfunction dockMessage(toolId: CalendarWorkspaceToolId, 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 if (toolId === WORKSPACE_TOOL.settings)\n return t('calendarWorkspace.rail.settingsDocked');\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 editorGuard,\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) => CalendarWorkspaceToolId | 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 /** The editor's unsaved-data guard (B18): the form writes it, the\n * surface asks it before a card click replaces the form. */\n editorGuard?: CalendarEditorGuard;\n children: ReactNode;\n}) {\n const { t } = useTranslation('ui');\n const { openTool } = useControlRoomActions();\n const restTool = useRestingTool(onAnnounce);\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 restTool();\n },\n }),\n [onOpenSheet, onAnnounce, onClose, openNotes, openTool, restTool, t],\n );\n return (\n <SheetHostProvider value={host}>\n <EditorGuardProvider value={editorGuard ?? null}>\n {children}\n </EditorGuardProvider>\n </SheetHostProvider>\n );\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/** Frames to wait for a closing full-screen panel (about 1.5s). */\nconst FOCUS_RETURN_FRAMES = 90;\n\n/** Below `md` the rail leaves the row, as `AppFrame`'s end slot does. */\nconst PHONE_QUERY = '(max-width: 767.98px)';\n\n/**\n * Where the rail goes when its tool has finished and nothing else was asked\n * for: the Appointments panel beside the grid, or, on a phone, nothing, so\n * the grid is back instead of a second full-screen panel.\n */\nfunction useRestingTool(\n onAnnounce: (message: string) => void,\n): (announce?: boolean) => void {\n const { t } = useTranslation('ui');\n const { openTool, closeTool } = useControlRoomActions();\n const frame = useAppFrameEndSlot();\n const phone = frame?.phone ?? false;\n const focusMain = frame?.focusMain;\n return useCallback(\n (announce = true) => {\n if (phone) {\n closeTool();\n /* The full-screen panel closes under the user, and the card or\n button that opened it may be gone (a delete): once the panel\n has left, focus that went nowhere lands on the toolbar. */\n let frames = 0;\n const settle = (): void => {\n frames += 1;\n if (\n frames < FOCUS_RETURN_FRAMES &&\n document.querySelector('[role=\"dialog\"][data-active-tool]')\n ) {\n requestAnimationFrame(settle);\n return;\n }\n const active = document.activeElement;\n if (!active || active === document.body || !active.isConnected)\n focusMain?.();\n };\n requestAnimationFrame(settle);\n return;\n }\n openTool(WORKSPACE_TOOL.appointments);\n if (announce) onAnnounce(dockMessage(WORKSPACE_TOOL.appointments, t));\n },\n [phone, focusMain, openTool, closeTool, onAnnounce, t],\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Rail registrar — the five tools, and the routing that docks them */\n/* ------------------------------------------------------------------ */\n\nfunction CalendarRailTools({\n onDraftChange,\n workspaceRef,\n activeToolId,\n availableTools,\n focus,\n rows,\n locale,\n privacy,\n onPrivacyOff: turnPrivacyOff,\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 mapsLink,\n noteUnrecordedEdits,\n recurrence,\n consentsForCares,\n medicalDevicesForCares,\n sameDayReminders,\n signatureCredits,\n createPatientFromBooking,\n createPatient,\n defaultReminders,\n proposeFirstVisit,\n readOnly,\n notesSeamFor,\n businessHours,\n onSave,\n onDelete,\n onRecurringScopeChosen,\n onDetailsActionUsed,\n onMove,\n onCopy,\n onEditOpened,\n onDeleteInitiated,\n onDocumentCreateClicked,\n onWhatsAppClicked,\n onStatusChange,\n onDescriptionChange,\n onBookSlotFromFinder,\n onRevealAppointment,\n toolSourceRef,\n onDetailsDocked,\n onRequestSignature,\n onRequestSignatureOnDevice,\n onOpenPatient,\n onOpenScheduler,\n onSaveAndReturn,\n onWaitingListFilterUsed,\n onWaitingListAdvancedFilterToggled,\n onRemoveWaiting,\n onOpenEntryForm,\n entryForm,\n onSaveEntry,\n onCancelEntry,\n onShowAvailability,\n onFinderSearchRange,\n gridAxis,\n bookings,\n bookingQueue,\n backlogFilters,\n onBacklogFiltersChange,\n waitingListState,\n stateSinceByEventId,\n reviewOnlyEventIds,\n bookingsSeedTick,\n bookingRequest,\n onCompleteBooking,\n onPlaceWaiting,\n onCreateTask,\n onUpdateTask,\n onDeleteTask,\n onSetTaskDone,\n loadTask,\n taskComposeTick,\n extraTools,\n extraToolIds,\n registeredToolIdsRef,\n settingsBridge,\n editorGuard,\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 /** The open create form's slot, for the grid's draft card. */\n onDraftChange: (draft: DraftSlot | null) => void;\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) => CalendarWorkspaceToolId | 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 /** The cog's map-link switch, read by the details extras. */\n mapsLink: boolean;\n /** History notes an edit recorded without detail. */\n noteUnrecordedEdits: boolean;\n /** What the host can persist for a new series; see the workspace prop. */\n recurrence?: CalendarWorkspaceRecurrence;\n /** The host's consents seam; see the workspace prop. */\n consentsForCares?: EditorPlatformOptions['consentsForCares'];\n /** The host's medical-devices seam; see the workspace prop. */\n medicalDevicesForCares?: EditorPlatformOptions['medicalDevicesForCares'];\n /** The host's same-day reminder seam; see the workspace prop. */\n sameDayReminders?: EditorPlatformOptions['sameDayReminders'];\n /** The host's signature-credits seam; see the workspace prop. */\n signatureCredits?: EditorPlatformOptions['signatureCredits'];\n /** The host's create-patient seam; see the workspace prop. */\n createPatientFromBooking?: EditorPlatformOptions['createPatientFromBooking'];\n /** The host's create-patient seam; see the workspace prop. */\n createPatient?: CalendarCreatePatient;\n /** The practice's saved reminder defaults, for the editor's boxes. */\n defaultReminders?: EditorPlatformOptions['defaultReminders'];\n /** The host's first-visit proposal; see the workspace prop. */\n proposeFirstVisit?: EditorPlatformOptions['proposeFirstVisit'];\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 | Promise<void>;\n onRecurringScopeChosen: (answer: RecurringScopeChosen) => void;\n onDetailsActionUsed: (event: { action: CalendarDetailsAction }) => void;\n onMove: (surface: CalendarMoveCopySurface) => void;\n onCopy: (\n withTreatments: boolean | undefined,\n surface: CalendarMoveCopySurface,\n ) => void;\n /** Click-time analytics: Edit on the panel, Delete on the panel or the\n * editor, the waiting list's WhatsApp link. Ids only. */\n onEditOpened: (eventId: string) => void;\n onDeleteInitiated: (eventId: string, surface: 'panel' | 'editor') => void;\n onDocumentCreateClicked: (\n eventId: string,\n kind: CalendarDocumentKind,\n ) => void;\n onWhatsAppClicked: (entryId: string) => 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: (\n eventId: string,\n source: Extract<\n CalendarDetailsOpenSource,\n 'appointments_panel' | 'bookings_panel' | 'waiting_list'\n >,\n ) => void;\n /** Tags the next tool open with where it came from. */\n toolSourceRef: MutableRefObject<CalendarToolOpenSource | null>;\n /** Details docked for a new selection. */\n onDetailsDocked: (eventId: string) => void;\n onRequestSignature: (eventId: string, channel: CalendarSignChannel) => void;\n /* Host seams the workspace passes through; each control is withheld when\n its seam is absent. */\n onRequestSignatureOnDevice?: (eventId: string) => void;\n onOpenPatient?: (patient: CalendarPatient) => void;\n onOpenScheduler?: () => void;\n onSaveAndReturn?: () => void;\n onWaitingListFilterUsed?: (\n filter: WaitingQuickView | 'advanced_search',\n ) => void;\n onWaitingListAdvancedFilterToggled?: (action: 'show' | 'hide') => 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 /** The backlog queue, already filtered by the header switches. */\n bookings: readonly CalendarRow[];\n bookingQueue?: CalendarOnlineBookings;\n backlogFilters: Readonly<Record<BacklogGap, boolean>>;\n onBacklogFiltersChange: (\n filters: Readonly<Record<BacklogGap, boolean>>,\n ) => void;\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 /* Task seams — see `CalendarJourney`. Every one optional: absent, the\n task editor withholds the control it would back. */\n onCreateTask?: (draft: TaskDraft) => Promise<CalendarTask>;\n onUpdateTask?: (id: string, draft: TaskDraft) => Promise<void>;\n onDeleteTask?: (id: string) => Promise<void>;\n onSetTaskDone?: (id: string, done: boolean) => Promise<void>;\n loadTask?: (id: string) => Promise<CalendarTask>;\n /** A fresh tick per \"New task\" toolbar click — docks the create form\n * and marks it as the task route. Separate from `editorSeed`, which\n * #172 kept appointment-only when it narrowed `handleComposeNew` to\n * zero arguments. */\n taskComposeTick: number;\n /** The host's own tools, already checked (`resolveExtraTools`): they\n * go after the built-in tools, in this order. */\n extraTools: readonly CalendarWorkspaceExtraTool[];\n /** Their ids, for the routing that must tell a host tool from an id no\n * tool carries. */\n extraToolIds: ReadonlySet<string>;\n /** Written with the ids this rail registers, so the workspace reports\n * only a tool that really docked. */\n registeredToolIdsRef: MutableRefObject<ReadonlySet<string>>;\n /** Where the Settings panel reads the surface's settings from. */\n settingsBridge: CalendarSettingsBridge;\n /** What the open editor form holds, for the question before a leave. */\n editorGuard: CalendarEditorGuard;\n}): ReactNode {\n const { t } = useTranslation('ui');\n const data = useCalendarData();\n const { openTool } = useControlRoomActions();\n const restTool = useRestingTool(onAnnounce);\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 /* \"Turn off privacy mode\" on a notice unmounts the focused button, which\n drops focus to the page: hand it to the open panel, as the rail does on\n a keyboard open, unless something else took it. */\n const noticeFocusFrame = useRef(0);\n useEffect(() => () => cancelAnimationFrame(noticeFocusFrame.current), []);\n const onPrivacyOff = useCallback(() => {\n turnPrivacyOff();\n cancelAnimationFrame(noticeFocusFrame.current);\n noticeFocusFrame.current = requestAnimationFrame(() => {\n const focused = document.activeElement;\n if (focused && focused !== document.body && focused.isConnected) return;\n workspaceRef.current\n ?.querySelector<HTMLElement>('section[data-active-tool]')\n ?.focus();\n });\n }, [turnPrivacyOff, workspaceRef]);\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 /* Reached only from the appointment panel: details or the form. */\n toolSourceRef.current = 'appointment_panel';\n openTool(WORKSPACE_TOOL.notes);\n toolSourceRef.current = null;\n onAnnounce(t('calendarWorkspace.rail.notes'));\n },\n [hasNotes, notesPatientId, openTool, onAnnounce, t, toolSourceRef],\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 consentsForCares,\n medicalDevicesForCares,\n sameDayReminders,\n signatureCredits,\n createPatientFromBooking,\n createPatient,\n rows,\n submitOnEnter: true,\n reminderChannels: WORKSPACE_REMINDER_CHANNELS,\n recurrenceExtras: recurrence?.endDate !== false,\n recurrenceSkipClosedDays: recurrence?.skipClosedDays !== false,\n recurrenceSkipClosedDaysDefault: recurrence?.skipClosedDaysDefault,\n /* The Custom rule (HTP-4261, PRD 03 rule D1): every N days, weeks,\n months or years, chosen weekdays, the Nth or last weekday. On unless\n the host cannot save `interval` and `byDay`. */\n recurrenceCustom: recurrence?.custom !== 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 defaultReminders,\n proposeFirstVisit,\n firstVisitRequiresPatient: true,\n priceListPhases: true,\n descriptionMaxLength: WORKSPACE_DESCRIPTION_MAX,\n /* The deep link's origin (a care plan, a patient folder) is the\n host's page: without `onSaveAndReturn` the split Save is withheld\n — see the `createParameters` arrival, which then drops\n `simpleSave: false`. */\n onSaveAndReturn,\n }),\n [\n data.branches,\n devicesByCare,\n unsignedRequiredDocs,\n consentsForCares,\n medicalDevicesForCares,\n sameDayReminders,\n signatureCredits,\n createPatientFromBooking,\n createPatient,\n rows,\n onSaveAndReturn,\n defaultReminders,\n proposeFirstVisit,\n ],\n );\n /* Details adds the series scope and, for ANY occurrence of a\n price-list series (decision P15), 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: rowAsksScope(selectedRow),\n recurringDeleteScope: Boolean(selectedRow?.series),\n carePlanCleanup:\n data.practiceFeatures.recurringPriceListCarePlanEntries &&\n selectedRow?.series != null &&\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 /* The advisory's link goes to the host's hours editor. The finder\n guards on the prop, so without it the advisory still states which\n hours are missing and just does not offer to open the page. */\n onOpenScheduler,\n }),\n [\n onOpenScheduler,\n devicesByCare,\n data.operatorGroups,\n businessHours?.practice,\n businessHours?.operators,\n recurrence?.endDate,\n recurrence?.custom,\n recurrence?.skipClosedDays,\n recurrence?.skipClosedDaysDefault,\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={(eventId) =>\n onRevealAppointment(eventId, 'appointments_panel')\n }\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 /* Set by the `taskComposeTick` effect below (the \"New task\" toolbar\n click) and cleared by the ordinary `editorSeed.tick` effect (any\n appointment-shaped compose) — a dedicated flag because #172 narrowed\n `handleComposeNew` to zero arguments, so a brand-new task can no\n longer announce itself through `editorSeed.prefill.isTask` the way\n an EXISTING task re-opened via a seeded `editEventId` still does. */\n const [composingTask, setComposingTask] = useState(false);\n /* Tasks have no separate details read view — the editor tool routes\n straight to the task editor, in EDIT mode, whenever the selected row\n or the create prefill carries `isTask`. Computed here (ahead of\n `formWithheld`, below) so the appointment privacy withholding never\n applies to a task route: the task editor masks its OWN linked\n patient, and a task about a company or about nobody has no identity\n to hide, so it must open under privacy rather than be blanket-blocked\n with the appointment \"turn privacy off\" notice. */\n const isTaskRoute = detailsMode\n ? Boolean(selectedRow?.event.isTask)\n : Boolean(editorSeed.prefill?.isTask) || composingTask;\n /* The id of the task being EDITED, on either host shape: `detailsMode`\n names it via `selectedRow`; without `loadAppointmentDetails` a\n patient-less task instead arrives as a create-seeded prefill carrying\n its own `editEventId` (`calendar.surface.tsx`'s `onBookSlot` branch) —\n that is still an edit of an existing task, never a blank create, so\n the task editor must be told which id to load rather than defaulting\n to create mode just because `detailsMode` is false. Gated on\n `editorSeed.prefill?.isTask` specifically (not `isTaskRoute`, which\n is also true from `composingTask`): a plain \"New task\" click must\n never inherit a STALE `editEventId` left over in `editorSeed.prefill`\n from an unrelated, already-cancelled appointment edit — that seed\n was never for this task route, and `composeTask` deliberately never\n touches `editorSeed`. */\n const taskEditingId = detailsMode\n ? selectedRow?.event.id\n : editorSeed.prefill?.isTask\n ? editorSeed.prefill?.editEventId\n : undefined;\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 !isTaskRoute &&\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 the action that\n opened the editor: Edit, or Assign patient. */\n const refocusEdit = useRef<{\n id: string;\n action: 'assign-patient' | 'edit-appointment';\n } | null>(null);\n /* The row whose Assign patient opened the editor on the patient field.\n It ends with the edit and with a change of selection, so a later edit\n of the same row by another route lands where it always did. */\n const [assignFocusId, setAssignFocusId] = useState<string | null>(null);\n const selectedEventId = selectedRow?.event.id;\n useEffect(() => {\n setAssignFocusId(null);\n }, [selectedEventId]);\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 /* The form has already closed: a host refusal can only be a toast. */\n Promise.resolve(onDelete(eventId, options)).catch(() =>\n toastWarning(t('emptyState.error.title')),\n );\n },\n [onDelete, t],\n );\n const closeEdit = useCallback((): void => {\n const outcome = editOutcome.current;\n editOutcome.current = null;\n setAssignFocusId(null);\n onEditorModeChange('details');\n if (outcome === 'deleted') {\n restTool();\n return;\n }\n if (outcome === 'saved') setDetailsTick((tick) => tick + 1);\n onAnnounce(\n t('calendarWorkspace.details.docked', { name: focusedPatientName }),\n );\n }, [onEditorModeChange, restTool, onAnnounce, focusedPatientName, t]);\n /* A save, a delete or Cancel on the task route all return to\n Appointments; there is nothing to re-dock in between. */\n const closeTaskPanel = useCallback((): void => {\n restTool();\n }, [restTool]);\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 setAssignFocusId(null);\n editOutcome.current = null;\n refocusEdit.current = { id: event.id, action: 'edit-appointment' };\n onEditorModeChange('edit');\n }, [selectedRow, onCompleteBooking, onEditorModeChange]);\n /* E14: Assign patient. An online booking takes the To complete flow, as\n the Backlog's segment does; any other row opens its editor on the\n patient field, which needs no operator to save. */\n const canCompleteBooking =\n !readOnly &&\n (!bookingQueue ||\n (bookingQueue.canComplete === true && Boolean(loadAppointmentEditor)));\n const assignFromDetails = useCallback((): void => {\n if (!selectedRow) return;\n const { event } = selectedRow;\n if (event.isBookedOnline) return onCompleteBooking(selectedRow, 'patient');\n setAssignFocusId(event.id);\n editOutcome.current = null;\n refocusEdit.current = { id: event.id, action: 'assign-patient' };\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 /* The host's read names its series; else the calendar's own rows do,\n as the editor's confirm does. */\n const deleteConfirm: Partial<CalendarDetailsSeries> | undefined =\n read.series ??\n (detailsPlatform.recurringDeleteScope\n ? {\n scopes: RECURRING_SCOPES,\n offersCarePlanCleanup: detailsPlatform.carePlanCleanup,\n }\n : detailsPlatform.carePlanCleanup\n ? { offersCarePlanCleanup: true }\n : undefined);\n return (\n <div\n className=\"ds:contents\"\n ref={(node) => {\n const target = refocusEdit.current;\n if (!node || !target || target.id !== 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. It re-lays out once measured\n and can replace the button: focus again if it was lost. */\n const liveAction = (action: string): HTMLElement | undefined =>\n [\n ...node.querySelectorAll<HTMLElement>(\n `[data-action=\"${action}\"]`,\n ),\n ].find((button) => !button.closest('[inert]'));\n /* A patient assigned removes Assign patient: Edit takes it. */\n const focusEdit = (): void =>\n (\n liveAction(target.action) ?? liveAction('edit-appointment')\n )?.focus();\n focusEdit();\n requestAnimationFrame(() => {\n if (node.isConnected && !node.contains(document.activeElement))\n focusEdit();\n });\n }}\n >\n <CalendarPatientContext\n patientId={notesPatient}\n onChange={reportPatient}\n />\n <CalendarAppointmentDetailsPanel\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 onAssignPatient={\n selectedRow?.event.isBookedOnline && !canCompleteBooking\n ? undefined\n : assignFromDetails\n }\n onOpenPatient={onOpenPatient}\n onSignOnDevice={\n onRequestSignatureOnDevice &&\n (() => onRequestSignatureOnDevice(read.eventId))\n }\n onEdit={() => {\n onEditOpened(read.eventId);\n editFromDetails();\n }}\n onDeleteInitiated={() => onDeleteInitiated(read.eventId, 'panel')}\n onDocumentCreateClicked={(kind) =>\n onDocumentCreateClicked(read.eventId, kind)\n }\n onMove={() => onMove('panel')}\n onCopy={(withTreatments) => onCopy(withTreatments, 'panel')}\n onDelete={async (options) => {\n /* A rejection leaves the panel, the analytics and the rail\n as they were: the confirm shows the host's message. */\n await onDelete(read.eventId, options);\n if (deleteConfirm?.scopes)\n onRecurringScopeChosen({\n action: 'delete',\n scope: options.scope,\n });\n restTool();\n /* The panel and its Delete button are gone, and a docked\n tool takes no focus of its own: hand it to the tool. */\n whenRailSettled(\n () =>\n workspaceRef.current?.querySelector<HTMLElement>(\n `section[data-active-tool=\"${WORKSPACE_TOOL.appointments}\"]`,\n ),\n (tool) => {\n const active = document.activeElement;\n if (\n !active ||\n active === document.body ||\n !active.isConnected\n )\n tool.focus();\n },\n );\n }}\n deleteConfirm={deleteConfirm}\n onDetailsActionUsed={onDetailsActionUsed}\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 noteUnrecordedEdits={noteUnrecordedEdits}\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 assignFromDetails,\n canCompleteBooking,\n editFromDetails,\n onOpenPatient,\n onRequestSignatureOnDevice,\n onMove,\n onCopy,\n onEditOpened,\n onDeleteInitiated,\n onDocumentCreateClicked,\n onDelete,\n onRecurringScopeChosen,\n onDetailsActionUsed,\n detailsPlatform,\n openTool,\n onAnnounce,\n workspaceRef,\n t,\n onStatusChange,\n onDescriptionChange,\n mapsLink,\n noteUnrecordedEdits,\n locale,\n ],\n );\n const editorTool = useMemo<ControlRoomTool>(\n () => ({\n id: WORKSPACE_TOOL.editor,\n label: isTaskRoute\n ? t(\n taskEditingId\n ? 'calendarWorkspace.taskEditor.editTitle'\n : 'calendarWorkspace.taskEditor.title',\n )\n : detailsMode\n ? t('calendarWorkspace.details.region')\n : t(\n editorSeed.prefill?.editEventId\n ? 'calendarWorkspace.editor.editTitle'\n : 'calendarWorkspace.editor.title',\n ),\n icon: isTaskRoute ? (\n <SquareCheckBig aria-hidden=\"true\" />\n ) : 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 editorGuard={editorGuard}\n onOpenSheet={onOpenSheet}\n onAnnounce={onAnnounce}\n onClose={\n isTaskRoute ? closeTaskPanel : editing ? closeEdit : undefined\n }\n details={\n !isTaskRoute &&\n readsDetails &&\n selectedRow &&\n loadAppointmentDetails\n ? {\n eventId: selectedRow.event.id,\n tick: detailsTick,\n load: loadAppointmentDetails,\n editing,\n render: renderDetails,\n }\n : undefined\n }\n >\n {isTaskRoute ? (\n /* A task's own form, never the appointment editor's fieldset\n reshaped: the published TaskEditor, through the calendar\n adapter in calendar-task-editor.tsx. */\n <CalendarTaskEditor\n key={\n taskEditingId\n ? `task-edit-${taskEditingId}`\n : `task-create-${editorSeed.tick}-${taskComposeTick}`\n }\n mode={taskEditingId ? 'edit' : 'create'}\n taskId={taskEditingId}\n initialDate={\n !taskEditingId && editorSeed.prefill?.isTask\n ? editorSeed.prefill?.date\n : undefined\n }\n onCancel={closeTaskPanel}\n onSaved={closeTaskPanel}\n onDeleted={closeTaskPanel}\n onCreateTask={onCreateTask}\n onUpdateTask={onUpdateTask}\n onDeleteTask={onDeleteTask}\n onSetTaskDone={onSetTaskDone}\n loadTask={loadTask}\n /* No readOnly: task rights are independent of appointment rights\n on the platform (taskEdit vs doctorAppointmentEdit). Absent task\n seams already withhold Save and Delete. */\n privacy={privacy}\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 assignFocusId === editorRow.event.id\n ? {\n ...(snapshot?.prefill ??\n editPrefillFromRow(editorRow)),\n initialFocus: 'patient',\n }\n : (snapshot?.prefill ??\n editPrefillFromRow(editorRow))\n }\n capabilities={snapshot?.capabilities}\n series={snapshot?.series}\n onRecurringScopeChosen={onRecurringScopeChosen}\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 /* Without `onOpenPatient` the strip takes its\n plain-text branch: the NAME stays, the link goes. */\n onOpenPatient={onOpenPatient}\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]\n ?.signRequestedVia\n }\n onRequestSignature={onRequestSignature}\n /* Without the host seam \"On this device…\" is\n withheld and the menu keeps SMS and e-mail. */\n onRequestSignatureOnDevice={\n onRequestSignatureOnDevice &&\n (() =>\n onRequestSignatureOnDevice(editorRow.event.id))\n }\n readOnly={detailsReadOnly}\n platform={\n snapshot\n ? {\n ...extrasPlatform,\n toCollectAmount:\n editorPatient?.unpaidAmount,\n }\n : extrasPlatform\n }\n />\n }\n history={sortHistoryNewestFirst(\n history[editorRow.event.id] ?? [],\n )}\n noteUnrecordedEdits={noteUnrecordedEdits}\n onSave={editing ? saveEdit : onSave}\n onDelete={editing ? deleteEdit : onDelete}\n onDeleteInitiated={(eventId) =>\n onDeleteInitiated(eventId, 'editor')\n }\n onMove={() => onMove('editor')}\n onCopy={(withTreatments) =>\n onCopy(withTreatments, 'editor')\n }\n readOnly={detailsReadOnly}\n platform={detailsPlatform}\n locale={locale}\n scheduleByEntry={schedule}\n />\n ) : (\n <AppointmentEditorPanel\n onPatientContextChange={reportPatient}\n key={`create-${editorSeed.tick}`}\n onDraftChange={onDraftChange}\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 onRecurringScopeChosen={onRecurringScopeChosen}\n onSave={onSave}\n onDelete={onDelete}\n onDeleteInitiated={(eventId) =>\n onDeleteInitiated(eventId, 'editor')\n }\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 locale={locale}\n scheduleByEntry={schedule}\n platform={editorPlatform}\n />\n )}\n </>\n );\n }}\n </CalendarEditorHydration>\n )}\n </EditorToolHost>\n ),\n }),\n [\n onDraftChange,\n formWithheld,\n seededPrefill,\n onPrivacyOff,\n detailsMode,\n noteUnrecordedEdits,\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 assignFocusId,\n patientRef,\n editorSeed,\n onOpenSheet,\n onAnnounce,\n onSave,\n onDelete,\n onRecurringScopeChosen,\n onMove,\n onCopy,\n onRequestSignature,\n onRequestSignatureOnDevice,\n onOpenPatient,\n signRequests,\n history,\n readOnly,\n extrasPlatform,\n detailsPlatform,\n editorPlatform,\n locale,\n schedule,\n t,\n isTaskRoute,\n taskEditingId,\n taskComposeTick,\n closeTaskPanel,\n onCreateTask,\n onUpdateTask,\n onDeleteTask,\n onSetTaskDone,\n loadTask,\n privacy,\n editorGuard,\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 /* Formerly the platform's \"Prenotazioni online\" PAGE alone; decision\n 2026-09-22 widened the queue to every appointment in view missing a\n patient, an operator or a chair, whatever its origin (desk-created\n slots qualify too). The platform page still exists for online\n bookings specifically — the booking e-mail and the top bar link to\n it — this rail panel is the one unified place to clear every gap. */\n const bookingsTool = useMemo<ControlRoomTool>(\n () => ({\n id: WORKSPACE_TOOL.bookings,\n label: t('calendarWorkspace.inc1.bookings.title'),\n icon: <ListTodo 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={(eventId) =>\n onRevealAppointment(eventId, 'bookings_panel')\n }\n resourceKind={gridAxis}\n filters={backlogFilters}\n onFiltersChange={onBacklogFiltersChange}\n onComplete={canCompleteBooking ? onCompleteBooking : undefined}\n />\n </CalendarSheetHost>\n ),\n }),\n [\n bookings,\n bookingQueue,\n bookingAddress,\n gridAxis,\n backlogFilters,\n onBacklogFiltersChange,\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 /* fill: the panel owns its scroll (its own internal ScrollArea) so\n the entry form's PanelSubview footer stays pinned — the rail's\n own ScrollArea would otherwise size this panel to its CONTENT\n height instead of the rail body's bounded height, so the subview\n never scrolls internally and its footer is reachable only by\n scrolling the whole rail. Same reason `editorTool` below is\n `fill: true`. */\n fill: true,\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 onCreatePatient={createPatient}\n onCancelEntry={onCancelEntry}\n /* Without `onOpenPatient` the row keeps the patient's NAME\n and loses the folder hop. */\n onOpenPatient={onOpenPatient}\n onFilterUsed={onWaitingListFilterUsed}\n onWhatsAppClick={(entry) => onWhatsAppClicked(entry.id)}\n onAdvancedFilterToggled={onWaitingListAdvancedFilterToggled}\n onOpenAppointment={(eventId) =>\n onRevealAppointment(eventId, 'waiting_list')\n }\n />\n )}\n </CalendarSheetHost>\n ),\n }),\n [\n privacy,\n onPrivacyOff,\n entryForm,\n onSaveEntry,\n onCancelEntry,\n createPatient,\n waitingList,\n waitingListState,\n rows,\n locale,\n onOpenSheet,\n onAnnounce,\n onPlaceWaiting,\n onRemoveWaiting,\n onOpenEntryForm,\n onRevealAppointment,\n onOpenPatient,\n onWaitingListFilterUsed,\n onWhatsAppClicked,\n onWaitingListAdvancedFilterToggled,\n readOnly,\n t,\n ],\n );\n\n /* The toolbar's Settings button opens this in place of the open tool\n (P36). The panel reads the surface's settings through the bridge, so\n the element is stable and the rail never re-registers per change. */\n const settingsTool = useMemo<ControlRoomTool>(\n () => ({\n id: WORKSPACE_TOOL.settings,\n label: t('calendarWorkspace.settings.title'),\n icon: <SlidersHorizontal aria-hidden=\"true\" />,\n panel: <CalendarSettingsPanelSlot bridge={settingsBridge} />,\n }),\n [settingsBridge, t],\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 /* The kit cannot see what a host panel shows, so under privacy it\n withholds the panel and header unless the host masks it ('host'). The\n strip button, label and badge stay: a count is not identity. */\n const hostTools = useMemo<ControlRoomTool[]>(\n () =>\n extraTools.map(({ privacy: mode, hold: _hold, ...tool }) =>\n privacy && mode !== 'host'\n ? {\n ...tool,\n header: undefined,\n panel: (\n <PrivacyNoticePanel\n title={tool.label}\n icon={tool.icon}\n onTurnOff={onPrivacyOff}\n />\n ),\n }\n : tool,\n ),\n [extraTools, privacy, onPrivacyOff],\n );\n\n /* Strip order, minus tools the host cannot back with real data (a finder\n with no hours reports shut days as free). Host tools follow in ONE\n registration: a second call would swap the groups on re-register. */\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 [WORKSPACE_TOOL.settings]: settingsTool,\n };\n return [\n ...ALL_WORKSPACE_TOOLS.filter(\n (id) =>\n availableTools.has(id) && (id !== WORKSPACE_TOOL.notes || hasNotes),\n ).map((id) => registry[id]),\n ...hostTools,\n ];\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 settingsTool,\n hostTools,\n ]);\n useControlRoomTools(tools);\n const registeredToolIds = useMemo(\n () => new Set(tools.map((tool) => tool.id)),\n [tools],\n );\n useIsomorphicLayoutEffect(() => {\n registeredToolIdsRef.current = registeredToolIds;\n }, [registeredToolIds, registeredToolIdsRef]);\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 /* A phone has no resting panel beside the grid: it opens none. */\n restTool(false);\n }, [restTool]);\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 /* A host tool with unsaved input keeps the dock (`hold`). */\n const heldRef = useRef(false);\n heldRef.current = extraTools.some(\n (tool) => tool.hold === true && tool.id === activeToolId,\n );\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 (heldRef.current) return;\n if (!focus) {\n if (prev) restTool();\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 toolSourceRef.current = 'selection';\n openTool(WORKSPACE_TOOL.editor);\n toolSourceRef.current = null;\n onDetailsDocked(focus.eventId);\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 toolSourceRef,\n onDetailsDocked,\n ]);\n\n /* A NEW editor seed (New appointment, an empty slot, Schedule,\n Book, Process booking) docks the create form. Always appointment-\n shaped (or an existing task's seeded `editEventId`, which carries its\n own `isTask` and needs no flag here) — never the \"New task\" toolbar\n click, so clear `composingTask` rather than leave a stale one active\n for whatever this seed actually is. */\n const prevSeedTickRef = useRef(editorSeed.tick);\n useEffect(() => {\n if (prevSeedTickRef.current === editorSeed.tick) return;\n prevSeedTickRef.current = editorSeed.tick;\n setComposingTask(false);\n onEditorModeChange('create');\n dockTool(WORKSPACE_TOOL.editor);\n }, [editorSeed.tick, onEditorModeChange, dockTool]);\n\n /* The \"New task\" toolbar click — see `composingTask` above. */\n const prevTaskComposeTickRef = useRef(taskComposeTick);\n useEffect(() => {\n if (prevTaskComposeTickRef.current === taskComposeTick) return;\n prevTaskComposeTickRef.current = taskComposeTick;\n setComposingTask(true);\n onEditorModeChange('create');\n dockTool(WORKSPACE_TOOL.editor);\n }, [taskComposeTick, 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 previous = previousTool.current;\n const target =\n (isWorkspaceToolId(previous) && availableTools.has(previous)) ||\n extraToolIds.has(previous)\n ? previous\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 }, [\n activeToolId,\n hasNotes,\n availableTools,\n extraToolIds,\n openTool,\n workspaceRef,\n ]);\n\n /* An active id no tool carries (a tool withdrawn while open, or an id an\n agent sets on the rail) docks the resting panel instead of collapsing\n it; Notes has its own fallback above. Silent if Appointments showed. */\n const lastDockedToolRef = useRef<string | null>(null);\n useEffect(() => {\n if (!activeToolId) {\n lastDockedToolRef.current = null;\n return;\n }\n if (registeredToolIds.has(activeToolId)) {\n lastDockedToolRef.current = activeToolId;\n return;\n }\n if (activeToolId === WORKSPACE_TOOL.notes) return;\n const unchanged = lastDockedToolRef.current === WORKSPACE_TOOL.appointments;\n restTool(!unchanged);\n }, [activeToolId, registeredToolIds, restTool]);\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\n/** Where a tool panel was opened from. `system` is a dock the workspace\n * made on its own (the resting panel, a return after a save, a\n * toolbar or journey hand-off), not a pick on the rail. */\nexport type CalendarToolOpenSource =\n | 'rail'\n | 'appointment_panel'\n | 'selection'\n | 'system';\n\n/** Where the appointment behind a details panel was selected. `host` is\n * a selection the journey made itself. */\nexport type CalendarDetailsOpenSource =\n | 'calendar'\n | 'appointments_panel'\n | 'bookings_panel'\n | 'waiting_list'\n | 'deep_link'\n | 'host';\n\n/** Where a Move or Copy was started: the read-only details panel, or the\n * editor opened on the appointment. */\nexport type CalendarMoveCopySurface = 'panel' | 'editor';\n\n/** Where a click-time analytics hook came from (the PRD's `surface`\n * property). The kit raises `panel` and `editor` for Edit and Delete and\n * `rail` for the waiting list's WhatsApp link; `grid` and `toolbar` are\n * for the host's own surfaces and for a grid action when one ships. */\nexport type CalendarAnalyticsSurface =\n | 'panel'\n | 'editor'\n | 'grid'\n | 'toolbar'\n | 'rail';\n\n/**\n * A host tool on the workspace rail (`CalendarWorkspaceProps.extraTools`):\n * a Control Room tool, plus what privacy mode does to it. `scope` and\n * `reorderable` are ignored: the workspace rail orders by favourites.\n */\nexport interface CalendarWorkspaceExtraTool extends ControlRoomTool {\n /**\n * What privacy mode does to this tool's panel. The kit cannot see what\n * the panel shows, so the default is the safe one.\n *\n * - `'withhold'` (default): while privacy mode is on, the panel and its\n * `header` are replaced by the privacy notice, titled with `label` and\n * offering \"Turn off privacy mode\". The host's panel is unmounted until\n * privacy is turned off. The strip button and `badgeCount` stay.\n * - `'host'`: the panel stays mounted and the host masks it, reading the\n * mode from `onPrivacyChange` (a task list sets `linkedLabelMasked`;\n * mind free-text titles, which the grid hides under privacy).\n * Also the right value for a panel that shows no patient data at all.\n * The kit cannot check either claim.\n */\n privacy?: 'withhold' | 'host';\n /**\n * Keeps this tool docked while it is open and `hold` is true: a click on\n * the grid (a card, a card with no patient, an empty slot) then changes\n * the selection but docks nothing over the panel, neither the details nor\n * the editor. Set it while the panel holds unsaved input, such as an open\n * task editor. Explicit requests still open another tool: the strip, the\n * toolbar, a free band's Book, a slot picked in an armed placement, and\n * the host. Once released, a click on the card docks its details.\n */\n hold?: boolean;\n}\n\n/**\n * Usage callbacks for the host's analytics. The kit raises no event of\n * its own and passes identifiers only, never patient data: the host owns\n * the calls, the property allow-list and any once-per guard.\n */\nexport interface CalendarWorkspaceRecurrence {\n /** The \"Ends: after N times / on a date\" choice. `false` when the host\n * stores only a repetition count. Defaults to on. */\n endDate?: boolean;\n /** The \"Skip closed days\" switch. `false` when the host cannot skip\n * closed days. Defaults to on. */\n skipClosedDays?: boolean;\n /** Start value of \"Skip closed days\" (on when absent); the user can\n * still flip it. */\n skipClosedDaysDefault?: boolean;\n /** The Custom repeat rule: every N days, weeks, months or years, chosen\n * weekdays, the Nth or last weekday. The host receives it as `interval`\n * and `byDay` on the draft's `recurrence`. `false` when the host cannot\n * save those two fields, so the user is never offered \"every 2 weeks\" and\n * given every week. Defaults to on. */\n custom?: boolean;\n}\n\nexport interface CalendarWorkspaceAnalytics {\n /** A built-in tool panel opened. Not raised again while it stays open,\n * and never for an id no tool carries. Host tools report through\n * `onExtraToolOpen` instead. */\n onToolOpen?: (event: {\n toolId: CalendarWorkspaceToolId;\n source: CalendarToolOpenSource;\n view: CalendarView;\n }) => void;\n /** An appointment's preview opened. Raised on EVERY opening: the\n * once-per-appointment guard is the host's. */\n onAppointmentPreviewOpen?: (event: {\n eventId: string;\n view: CalendarView;\n privacy: boolean;\n }) => void;\n /** An appointment's details docked for a new selection. Not raised when\n * details come back after an edit. */\n onAppointmentDetailsOpen?: (event: {\n eventId: string;\n source: CalendarDetailsOpenSource;\n view: CalendarView;\n }) => void;\n /** A new series was saved. Raised once per accepted save, never for a\n * failed one or an edit. `rule` is `custom` when the repeat uses\n * every-N or chosen weekdays; `end` is `date` for \"on a date\". */\n onRecurringCreated?: (event: {\n rule: 'preset' | 'custom';\n end: 'count' | 'date';\n skipClosedDays: boolean;\n }) => void;\n /** The user answered the repeat scope question: an accepted save (with\n * the scope it saved under), a confirmed move or a confirmed delete.\n * Never raised when the user cancels or a save is refused. An occurrence\n * changed on its own asks only on delete. */\n onRecurringScopeChosen?: (event: RecurringScopeChosen) => void;\n /** The user completed an action in the details panel: a status saved, a\n * handler run, a delete confirmed, a link followed. Raised once per\n * action, whatever the surface; the host adds `surface: \"panel\"`. */\n onDetailsActionUsed?: (event: { action: CalendarDetailsAction }) => void;\n /** The user clicked Edit on the details panel. Raised on the CLICK, even\n * when the host then routes elsewhere (an online booking completes on\n * its own flow), once per click. The old calendar's\n * `calendar_appointment_edit_opened`; its once-a-day guard is the\n * host's. `onDetailsActionUsed` keeps hearing the completed action. */\n onAppointmentEditOpened?: (event: {\n eventId: string;\n surface: CalendarAnalyticsSurface;\n view: CalendarView;\n }) => void;\n /** The user clicked Delete, on the details panel or in the editor,\n * BEFORE the confirm and whatever the answer. Raised once per click.\n * The old calendar's `calendar_appointment_delete_initiated`.\n * `onDetailsActionUsed` with `delete` still reports a confirmed delete. */\n onAppointmentDeleteInitiated?: (event: {\n eventId: string;\n surface: CalendarAnalyticsSurface;\n view: CalendarView;\n }) => void;\n /** The user picked an entry of the details panel's Create document menu.\n * Raised on the PICK, before the bill's \"this visit or all visits\"\n * question and whatever the answer, once per pick. The old calendar's\n * `calendar_popover_create_document_clicked`; the host maps `kind` to\n * its `action` value. `onDetailsActionUsed` with `document` still\n * reports the completed action. Carries the appointment id and the kind,\n * never patient data. */\n onDocumentCreateClicked?: (event: {\n eventId: string;\n kind: CalendarDocumentKind;\n surface: CalendarAnalyticsSurface;\n view: CalendarView;\n }) => void;\n /** The user clicked the WhatsApp link on a waiting-list entry. Raised\n * once per click, only for an entry that has a number and never under\n * privacy. The old calendar's `waiting_list_whatsapp_clicked`. Carries\n * the entry id: never a name, a number or a note. */\n onWaitingListWhatsAppClicked?: (event: {\n entryId: string;\n surface: CalendarAnalyticsSurface;\n view: CalendarView;\n }) => void;\n /** The user started a Move: Move on the details panel or the editor, or\n * a card dropped on the grid (`grid`). Raised when the move is armed or\n * dropped, not when it lands. The old calendar's\n * `calendar_appointment_move_initiated`; its once-a-day guard is the\n * host's. */\n onAppointmentMoveInitiated?: (event: {\n eventId: string;\n surface: CalendarMoveCopySurface | 'grid';\n view: CalendarView;\n }) => void;\n /** The user picked a Copy choice on the details panel or the editor.\n * `withTreatments` is false for \"appointment only\". Raised when the copy\n * is armed, not when it lands. The old calendar's\n * `calendar_appointment_copy_initiated`. */\n onAppointmentCopyInitiated?: (event: {\n eventId: string;\n withTreatments: boolean;\n surface: CalendarMoveCopySurface;\n view: CalendarView;\n }) => void;\n /** The user confirmed the print dialog for a day. The old calendar's\n * `calendar_print_used`. Raised once per confirmed print. */\n onPrintUsed?: (event: { view: CalendarView }) => void;\n /** The user picked a date in the jump-to-date picker. Raised on every\n * pick; the once-a-day guard is the host's. The old calendar's\n * `calendar_jump_to_date_used`. */\n onJumpToDateUsed?: (event: { view: CalendarView }) => void;\n /** The user picked a quick view of the waiting list that was not already\n * chosen, or ran the detailed search (`advanced_search`). The old\n * calendar's `waiting_list_filter_used`. */\n onWaitingListFilterUsed?: (event: {\n filter: WaitingQuickView | 'advanced_search';\n }) => void;\n /** The user showed or hid the waiting list's detailed filters. The old\n * calendar's `waiting_list_advanced_filter_toggled`. */\n onWaitingListAdvancedFilterToggled?: (event: {\n action: 'show' | 'hide';\n }) => void;\n /** A rail preference was saved on this device. `toolId` may be a host\n * tool's id. `resize` is raised only with `persistPanelWidthKey`, since\n * without it nothing is saved. */\n onToolPreferencesChange?: (event: {\n action: ControlRoomFavoriteChange['action'] | 'resize';\n toolId: string;\n }) => void;\n /**\n * A host tool's panel opened (`extraTools`). Not raised again while it\n * stays open. `rail` is a pick on the strip; `system` is any other open\n * (the host's own `useControlRoomActions().openTool`, an agent).\n */\n onExtraToolOpen?: (event: {\n toolId: string;\n source: Extract<CalendarToolOpenSource, 'rail' | 'system'>;\n view: CalendarView;\n }) => void;\n /** The Settings panel opened in the rail (PRD event\n * calendar_settings_opened). */\n onSettingsOpened?: () => void;\n /** A setting changed in the Settings panel (PRD event calendar_setting_changed).\n * Raised once per change. `setting` is the display field name,\n * `hiddenDays` or `reset`. */\n onSettingChanged?: (event: {\n setting: string;\n section: 'personal' | 'practice';\n }) => void;\n /** The Practice section's link to the host's opening hours editor was\n * followed, whether it is a button (`onOpen`) or a link (`href`) (PRD\n * event calendar_scheduler_opened). */\n onHoursOpened?: () => 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. Keep\n * it stable: passing a new function re-reads the open details panel,\n * which is how a host shows a change made outside the panel. */\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 /** Loads the visible range again. The workspace offers Retry above the\n * grid only while a visible day is `'error'` in `data.dayLoadState`, and\n * withholds the button when this is omitted. */\n onRetryLoad?: () => void;\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 /**\n * The Settings panel's Practice section (PRD 02). Each member is passed only when\n * the host grants this user that setting's existing right; with no member\n * the section is absent. Edits are a draft until Save, which calls\n * `onSave`. After a successful save the host re-feeds `data` (the\n * holiday wash and bookability read the host's `practiceClosedOn` and\n * `closureOn`, the care restriction reads the cares' allowed lists) so\n * the grid follows.\n */\n practiceSettings?: CalendarPracticeSettingsSeam;\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 /** In an appointment's History, say \"What changed was not recorded.\"\n * under an edit that carries no detail. Off by default. Turn it on\n * once the host records what each save changed, so the older entries\n * read as incomplete rather than empty. */\n noteUnrecordedEdits?: boolean;\n /** What the host can persist for a new series. Each control is offered\n * unless the host sets its flag to `false`. */\n recurrence?: CalendarWorkspaceRecurrence;\n /**\n * Treatment consents the chosen cares need for this visit (HTP-3395),\n * read by the editor on create and on edit. Omit it and the editor offers\n * no consents: the kit never lists what the host cannot back. Return the\n * consents of THIS appointment (a new one every visit, never the\n * patient's older ones). The editor shows each missing one as a tick\n * (ticked on create, unticked on edit) and reports the ticked ids in\n * `EditorDraftExtras.consentIds` on save: the host creates and sends\n * them, and chooses in-person or remote signing itself. The details panel\n * only lists them, under `signing.consents`.\n */\n consentsForCares?: EditorPlatformOptions['consentsForCares'];\n /**\n * Medical devices the chosen cares need at the visit's slot (PRD 01,\n * B9). The editor shows one choice per care that needs a device, set to\n * the host's `assignedId`, and reports the chosen devices in\n * `EditorDraftExtras.medicalDevices` on save. A pick resets when the date,\n * time or length changes, so the host assigns again for the new slot.\n * Pass it only when the practice has the feature (platform switch\n * `find_free_slots_by_care`); omit it and the editor offers no choice:\n * the kit never shows a control the host cannot back. When every device\n * is busy the editor says so and the save goes ahead. Synchronous and\n * pure: see `EditorPlatformOptions.medicalDevicesForCares`.\n */\n medicalDevicesForCares?: EditorPlatformOptions['medicalDevicesForCares'];\n /**\n * Same-day reminder seam (rule B8): see\n * `EditorPlatformOptions.sameDayReminders`. Omit it and neither message\n * appears.\n */\n sameDayReminders?: EditorPlatformOptions['sameDayReminders'];\n /**\n * The practice's signature credits (rule B10): see\n * `EditorPlatformOptions.signatureCredits`. Omit it and the editor shows\n * neither the no-credits message nor any limit on the sign mode.\n */\n signatureCredits?: EditorPlatformOptions['signatureCredits'];\n /**\n * Create a patient from an online booking that has none (PRD 01). The\n * editor shows \"Create patient\" in the booking card while no patient is\n * chosen; the host opens its own new-patient form filled with the booking\n * name, phone and email, and resolves with the new patient (or\n * `undefined` when the user cancels). Make the record available through\n * `CalendarData.patientById` before resolving. Omit it and the editor\n * offers no such button: the kit never shows a control the host cannot\n * back.\n */\n createPatientFromBooking?: EditorPlatformOptions['createPatientFromBooking'];\n /**\n * Create a patient from the patient search (PRD 01, B20). The editor and\n * the waiting-list entry form (not its filter) show \"Create patient\"\n * under the search while no patient is chosen. The host opens its own\n * new-patient form (`typedText` is the last text typed, to prefill it) and\n * resolves with the new patient, or `null` on cancel (nothing changes).\n * The kit then selects it as if it had been picked. Make the record\n * available through `CalendarData.patientById` before resolving. Reject\n * with a safe `Error` to show its message. Omit it and the action is\n * withheld; so it is for a read-only viewer. An online booking that has\n * `createPatientFromBooking` keeps its own button and prefill.\n */\n createPatient?: CalendarCreatePatient;\n /**\n * Propose the first-visit answer on a NEW appointment (PRD 01, B12). The\n * editor asks once a patient is chosen, and again when the date changes,\n * and sets the answer unless the user has already picked one. Resolve\n * `'unknown'` when the host cannot tell; a rejection is ignored. The\n * answer starts on unknown without this seam. An edit shows the saved\n * `EditorPrefill.firstVisit` and never asks.\n */\n proposeFirstVisit?: EditorPlatformOptions['proposeFirstVisit'];\n /** Where the cog's settings, the view, the days shown 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 /** The backlog panel's three switches (\"Senza paziente\" / \"Senza\n * operatore\" / \"Senza poltrona\"), all on by default and reached\n * through the panel header's settings cog. Controlled together with\n * `onBacklogFiltersChange`; omit both and the panel keeps its own\n * uncontrolled state — the kit does not persist this itself. The chair\n * switch is hidden when the practice has no chairs, and a chair value\n * it cannot show never marks the cog. */\n backlogFilters?: Readonly<Record<BacklogGap, boolean>>;\n onBacklogFiltersChange?: (\n filters: Readonly<Record<BacklogGap, boolean>>,\n ) => void;\n /** Device key the rail saves pinned tools and their order under. Omit\n * it and the rail keeps its generic default, `ui.controlRoom.favorites`. */\n persistFavoritesKey?: string;\n /** Device key the rail saves the panel width under. Omit it and width\n * is not saved, as before. On-device only; nothing reaches a server. */\n persistPanelWidthKey?: string;\n /** Usage callbacks for the host's analytics. Omit it and nothing is\n * reported. */\n analytics?: CalendarWorkspaceAnalytics;\n /** Opens a patient's record in the host (the patient file). Offered on\n * the editor's identity line and the waiting list; the name is plain\n * text without it. */\n onOpenPatient?: (patient: CalendarPatient) => void;\n /** Opens the host's hours editor (opening hours, closures, absences).\n * Offered beside the free-slot finder's missing-hours advisory; the\n * advisory still names what is missing without it. */\n onOpenScheduler?: () => void;\n /** Takes the user back to where a deep link came from (a care plan, the\n * patient file), called after a save. With it a `createParameters`\n * arrival with `simpleSave: false` keeps its two saves, \"Save and go\n * back\" and \"Save and continue\"; without it the arrival gets the single\n * Save. */\n onSaveAndReturn?: () => void;\n /** Starts the host's on-device e-signature for an appointment (signee,\n * operator, one-time code). Offered as \"On this device\" in the\n * signature request menu; withheld without it. */\n onRequestSignatureOnDevice?: (eventId: string) => void;\n /**\n * Host tools, appended to the rail after the built-in ones, in this\n * order. A tool is offered by passing it and withheld by leaving it out:\n * `availableTools` narrows the built-in tools only.\n *\n * Ids: every `WORKSPACE_TOOL` id is reserved, even for a tool\n * `availableTools` withholds, and a tool using one is left off the rail.\n * A repeated id keeps its first tool. Nothing throws. The kit's own\n * Storybook and tests warn; the published build drops the tool silently.\n *\n * The panel renders inside the workspace, so the host's own providers\n * reach it. It unmounts when another tool opens, so keep state that must\n * survive in the host. Render a kit `PanelHeader` first and the rail puts\n * its favourite and close controls in it. Opening one reports through\n * `analytics.onExtraToolOpen`. The workspace passes no permission to host\n * tools. Only the strip, an agent and code inside an open panel\n * (`useControlRoomActions`) open a tool: code outside the workspace\n * cannot, since the workspace owns its rail provider. If the host stops\n * passing the open tool, the rail docks the Appointments panel. Memoise\n * the array: a new one re-registers the rail.\n */\n extraTools?: readonly CalendarWorkspaceExtraTool[];\n /**\n * Raised when privacy mode turns on or off, from the toolbar toggle or a\n * withheld panel's \"Turn off privacy mode\". Observe-only: the workspace\n * owns the flag, it starts off on every mount (not reported) and is\n * never persisted. Unmounting with privacy on reports `false`, so the\n * host's copy never outlives the workspace. Raised in the same handler,\n * so a host that sets state here renders its masked tool in the same\n * commit as the masked grid.\n */\n onPrivacyChange?: (privacy: boolean) => void;\n /**\n * The calendar archive session (the practice's global archive plus one\n * second archive). Passing it turns on the seven old rules: a new\n * appointment first asks Global or Archive, the chair and operator\n * columns and filters are gone, drag and resize are off, the details\n * show no status change, a banner offers Exit, the view starts on Week,\n * and every action callback carries the appointment's own `archiveId`.\n */\n calendarArchive?: CalendarArchive;\n /**\n * The old calendar's kept prompts, each a host seam and withheld when\n * left out: a `banner` above the grid, the `firstAppointment` alert\n * with an optional host button, and the `academyHref` tutorial link in\n * the Settings panel.\n */\n prompts?: CalendarPrompts;\n /**\n * The view the page address names (`day`, `threeDays`, `week` or\n * `month`). It beats the user's remembered view until they pick another,\n * and the remembered view is not overwritten. The day it opens on is\n * `data.initialDateIso`; the column axis is `initialDisplay.resourceKind`.\n * The kit never reads `window.location`: the host reads its own address\n * and passes these in.\n */\n initialView?: WorkspaceViewId;\n /**\n * After every navigation (a view switch, previous, next, Today, the mini\n * month, jump to date, a Month day, the column axis), once, with the new\n * view, the day as `YYYY-MM-DD` and the axis. Not raised for the first\n * render. The host writes the page address; the kit writes nothing.\n */\n onViewChange?: (change: CalendarViewChange) => 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 * starts from the same values 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 onRetryLoad,\n stateSinceByEventId,\n locale,\n initialDisplay,\n permissions,\n practiceSettings,\n focusAppointmentId,\n focusBookingId,\n focusBookingKey,\n createParameters,\n freeSlot,\n businessHours,\n availableTools,\n schedulerLicenseKey,\n noteUnrecordedEdits = false,\n recurrence,\n consentsForCares,\n medicalDevicesForCares,\n sameDayReminders,\n signatureCredits,\n createPatientFromBooking,\n createPatient,\n proposeFirstVisit,\n preferences,\n onFinderSearchRange,\n loadAppointmentEditor,\n loadAppointmentDetails,\n id,\n backlogFilters: controlledBacklogFilters,\n onBacklogFiltersChange,\n persistFavoritesKey,\n persistPanelWidthKey,\n analytics,\n onOpenPatient,\n onOpenScheduler,\n onSaveAndReturn,\n onRequestSignatureOnDevice,\n extraTools,\n onPrivacyChange,\n calendarArchive,\n prompts,\n initialView,\n onViewChange,\n}: CalendarWorkspaceProps) {\n const { t, i18n } = useTranslation('ui');\n /* The saved practice default for the editor's reminder boxes. */\n const patientNotices = practiceSettings?.value.patientNotices;\n const reminderSms = patientNotices?.reminderSms;\n const reminderEmail = patientNotices?.reminderEmail;\n const reminderDefaults = useMemo(\n () =>\n reminderSms === undefined && reminderEmail === undefined\n ? undefined\n : { sms: reminderSms, email: reminderEmail },\n [reminderSms, reminderEmail],\n );\n /* Controlled with an uncontrolled default, as the cog: a host that\n does not pass both props gets its own session-local state, since\n the kit persists none of this itself. */\n const [uncontrolledBacklogFilters, setUncontrolledBacklogFilters] = useState(\n DEFAULT_BACKLOG_FILTERS,\n );\n const backlogFilters = controlledBacklogFilters ?? uncontrolledBacklogFilters;\n const setBacklogFilters =\n onBacklogFiltersChange ?? setUncontrolledBacklogFilters;\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 /* The open create form's slot: the grid holds it as a dashed draft card\n until Save or Cancel (the form clears it when it closes). */\n const [draftSlot, setDraftSlot] = useState<DraftSlot | 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 host's tools, checked once per array: the host memoises it, as\n the prop's doc asks, so this does not run per render. */\n const resolvedExtraTools = useMemo(\n () => resolveExtraTools(extraTools ?? NO_EXTRA_TOOLS),\n [extraTools],\n );\n /* The open host tool holds the dock while it has unsaved input. */\n const toolHeld = resolvedExtraTools.tools.some(\n (tool) => tool.hold === true && tool.id === activeToolId,\n );\n const extraToolIds = useMemo(\n () => new Set(resolvedExtraTools.tools.map((tool) => tool.id)),\n [resolvedExtraTools],\n );\n /* The ids the rail registered at its last commit (it writes them). */\n const registeredToolIdsRef = useRef<ReadonlySet<string>>(new Set());\n /* The text is the effect's key, so a host re-rendering the same mistake\n warns once, not on every render. */\n const rejectedTools = resolvedExtraTools.rejected\n .map(({ id, reason }) => `\"${id}\" (${reason})`)\n .join(', ');\n useEffect(() => {\n if (!import.meta.env.DEV || !rejectedTools) return;\n console.warn(\n `[CalendarWorkspace] extraTools left off the rail: ${rejectedTools}. ` +\n 'Built-in tool ids are reserved, a repeated id keeps its first tool ' +\n 'and an empty id is dropped.',\n );\n }, [rejectedTools]);\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 /* Reset in the cog returns here: the kit defaults, the caller's\n initialDisplay on top. */\n const defaultDisplay = useMemo(\n () => ({ ...DEFAULT_WORKSPACE_DISPLAY, ...initialDisplay }),\n [initialDisplay],\n );\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 /* Rule 2: an archive session offers only plain columns. The stored\n choice is untouched, so leaving the archive brings it back. */\n const gridDisplay = useMemo(\n () =>\n calendarArchive && display.resourceKind !== 'none'\n ? { ...display, resourceKind: 'none' as const }\n : display,\n [calendarArchive, display],\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: hostRequestSignature,\n handleComposeNew: hostComposeNew,\n handleRemoveWaiting,\n handleUpsertWaiting,\n handleOpenBacklog,\n handleVisibleRangeChange,\n handleDeleteAppointment: hostDeleteAppointment,\n handleMoveOccurrence: hostMoveOccurrence,\n handleMoveAppointment: hostMoveAppointment,\n handleResizeAppointment: hostResizeAppointment,\n handleCopyAppointment: hostCopyAppointment,\n handleStatusChange,\n handleDescriptionChange: hostDescriptionChange,\n handleBookSlot: hostBookSlot,\n handleRevealAppointment,\n handleCreateAppointment,\n handleFindSlotsForWaiting,\n clearFindSlotsSeed,\n handleBookSlotFromFinder: hostBookSlotFromFinder,\n availability,\n availabilityContext,\n handleShowAvailability,\n notesByPatient,\n notesLoadByPatient,\n handleLoadNotes,\n handleAddNote,\n handleEditNote,\n handleDeleteNote,\n handleToggleNotePin,\n handleToggleNoteFlag,\n handleNoteWriteError,\n requestNoteAiDraft,\n dictateNote,\n noteAiConsentFor,\n noteComposerExtrasFor,\n handleCreateTask,\n handleUpdateTask,\n handleDeleteTask,\n handleSetTaskDone,\n loadTask,\n } = journey;\n /* ---- calendar archive ---------------------------------------------\n Rule 7: every action callback carries the appointment's OWN archive\n id (absent = the global archive). Rule 1: a new appointment first\n asks Global or Archive; the answer rides the draft on save. */\n const archiveIdOf = useCallback(\n (eventId: string): string | undefined =>\n journeyRows.find((row) => row.event.id === eventId)?.archiveId,\n [journeyRows],\n );\n const archiveTail = useCallback(\n (eventId: string): [] | [string] => {\n const archiveId = archiveIdOf(eventId);\n return archiveId ? [archiveId] : [];\n },\n [archiveIdOf],\n );\n const handleRequestSignature = useCallback(\n (eventId: string, channel: CalendarSignChannel): void =>\n hostRequestSignature(eventId, channel, ...archiveTail(eventId)),\n [hostRequestSignature, archiveTail],\n );\n const handleDescriptionChange = useMemo(\n () =>\n hostDescriptionChange\n ? (eventId: string, description: string): Promise<void> =>\n hostDescriptionChange(eventId, description, ...archiveTail(eventId))\n : undefined,\n [hostDescriptionChange, archiveTail],\n );\n const handleMoveOccurrence = useMemo(\n () =>\n hostMoveOccurrence\n ? (move: CalendarOccurrenceMove): Promise<void> => {\n const archiveId = archiveIdOf(move.eventId);\n return hostMoveOccurrence(\n archiveId ? { ...move, archiveId } : move,\n );\n }\n : undefined,\n [hostMoveOccurrence, archiveIdOf],\n );\n const handleDeleteAppointment = useCallback(\n (eventId: string, options?: DeleteOptions): void | Promise<void> => {\n const archiveId = archiveIdOf(eventId);\n if (archiveId)\n return hostDeleteAppointment(eventId, {\n scope: 'this',\n ...options,\n archiveId,\n });\n return options\n ? hostDeleteAppointment(eventId, options)\n : hostDeleteAppointment(eventId);\n },\n [hostDeleteAppointment, archiveIdOf],\n );\n const handleMoveAppointment = useMemo(\n () =>\n hostMoveAppointment\n ? (move: CalendarAppointmentMove): Promise<void> => {\n const archiveId = archiveIdOf(move.eventId);\n return hostMoveAppointment(\n archiveId ? { ...move, archiveId } : move,\n );\n }\n : undefined,\n [hostMoveAppointment, archiveIdOf],\n );\n const handleResizeAppointment = useMemo(\n () =>\n hostResizeAppointment\n ? (resize: CalendarAppointmentResize): Promise<void> => {\n const archiveId = archiveIdOf(resize.eventId);\n return hostResizeAppointment(\n archiveId ? { ...resize, archiveId } : resize,\n );\n }\n : undefined,\n [hostResizeAppointment, archiveIdOf],\n );\n const handleCopyAppointment = useMemo(\n () =>\n hostCopyAppointment\n ? (copy: CalendarAppointmentCopy): Promise<{ id: string } | void> => {\n const archiveId = archiveIdOf(copy.sourceId);\n return hostCopyAppointment(\n archiveId ? { ...copy, archiveId } : copy,\n );\n }\n : undefined,\n [hostCopyAppointment, archiveIdOf],\n );\n /* The editor's own question (B18, P38): typed data in the open form. It\n is created here because every create route below asks through it. */\n const [editorGuard] = useState(createEditorGuard);\n /* The pending create question, and the archive the answered one saves to. */\n const [pendingCreate, setPendingCreate] = useState<(() => void) | null>(null);\n /* The answer is bound to the editor the answered create opens: it is\n armed on the answer and taken over by the next editor seed, and any\n seed that was not answered (a deep link, a host-driven compose) clears\n it. So a cancelled editor never leaks its archive into a later create,\n and a rejected save keeps it for the retry. */\n const armedArchiveIdRef = useRef<{ id?: string } | null>(null);\n const createArchiveIdRef = useRef<string | undefined>(undefined);\n useEffect(() => {\n createArchiveIdRef.current = armedArchiveIdRef.current?.id;\n armedArchiveIdRef.current = null;\n }, [editorSeed.tick]);\n /* Every route that seeds a NEW form (an empty slot, the toolbar's New,\n the finder's Book) remounts the open one, so each asks about typed data\n first (B18), then about the archive. */\n const askCreate = useCallback(\n (run: () => void): void => {\n editorGuard.ask(() => {\n if (calendarArchive) setPendingCreate(() => run);\n else run();\n });\n },\n [calendarArchive, editorGuard],\n );\n const handleComposeNew = useCallback(\n (): void => askCreate(hostComposeNew),\n [askCreate, hostComposeNew],\n );\n const handleBookSlot = useCallback(\n (prefill: EditorPrefill): void =>\n prefill.editEventId\n ? hostBookSlot(prefill)\n : askCreate(() => hostBookSlot(prefill)),\n [askCreate, hostBookSlot],\n );\n const handleBookSlotFromFinder = useCallback(\n (prefill: EditorPrefill): void =>\n askCreate(() => hostBookSlotFromFinder(prefill)),\n [askCreate, hostBookSlotFromFinder],\n );\n /* Dispatches the compose-task intent. #172 narrowed `handleComposeNew`\n to zero arguments (the toolbar's \"New task\" no longer seeds\n `EditorPrefill.isTask` through it), so a fresh tick here is the\n signal `CalendarRailTools` docks the create form on and marks\n `isTaskRoute` from — a dedicated counter rather than reusing\n `editorSeed`, which stays the appointment-only seed `handleComposeNew`\n / `handleBookSlot` / the deep-link props write to. */\n const [taskComposeTick, setTaskComposeTick] = useState(0);\n const composeTask = useCallback((): void => {\n editorGuard.ask(() => setTaskComposeTick((tick) => tick + 1));\n }, [editorGuard]);\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, ...archiveTail(eventId));\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, archiveTail],\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, next) =>\n handleToggleNotePin(patientId, noteId, next),\n onToggleFlag: handleToggleNoteFlag\n ? (noteId, next) => handleToggleNoteFlag(patientId, noteId, next)\n : undefined,\n /* The panel reports each refusal it can show; the host hears them\n all, and toasts only the ones it could not. */\n onWriteError: handleNoteWriteError\n ? (failure) => handleNoteWriteError(patientId, failure)\n : undefined,\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 handleToggleNoteFlag,\n handleNoteWriteError,\n requestNoteAiDraft,\n dictateNote,\n noteAiConsentFor,\n noteComposerExtrasFor,\n ],\n );\n /* Tasks used to be dropped here, at the feed boundary, before there was\n a task editor to route a click INTO — the grid, the peek, the call\n sheet, the editor's busy check and the Appointments panel never saw\n one. Now that `CalendarTaskEditor` exists, a task row reaches the\n grid like any other row: `isTaskRoute` / `taskEditingId` (above)\n route a click on it to the task editor rather than the appointment\n editor. The other four consumers already exclude `isTask` rows on\n their own — `slotConflicts` and `upcomingAppointmentRows`\n (`calendar-workspace.model.ts`) and `buildPrintSheet`'s patient\n section (`calendar.model.ts`) — so nothing downstream needed to\n change to keep tasks out of them. */\n const rows = journeyRows;\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 privacyRef = useRef(privacy);\n privacyRef.current = privacy;\n const onPrivacyChangeRef = useRef(onPrivacyChange);\n onPrivacyChangeRef.current = onPrivacyChange;\n /* Tells the host in the same handler, so its masked tool renders in the\n same commit as the masked grid. Only a real change is reported. */\n const changePrivacy = useCallback((next: boolean): void => {\n if (privacyRef.current === next) return;\n privacyRef.current = next;\n setPrivacy(next);\n onPrivacyChangeRef.current?.(next);\n }, []);\n const turnPrivacyOff = useCallback(\n () => changePrivacy(false),\n [changePrivacy],\n );\n /* Privacy ends with the workspace, so an unmount while it is on reports\n `false`; a remount that keeps the state (Fast Refresh) reports it again.\n A first mount starts off and reports nothing. */\n useEffect(() => {\n if (privacyRef.current) onPrivacyChangeRef.current?.(true);\n return () => {\n if (privacyRef.current) onPrivacyChangeRef.current?.(false);\n };\n }, []);\n\n /* ---- usage reporting (CTR-21) -------------------------------------\n Refs, so reporting never re-renders the workspace or re-registers\n the rail's tools. Each open is tagged with its source by the code\n that makes it, and the tag is cleared straight after. */\n const analyticsRef = useRef(analytics);\n analyticsRef.current = analytics;\n /* Read once, on the deep-link arrival: not a dependency of that effect. */\n const onSaveAndReturnRef = useRef(onSaveAndReturn);\n onSaveAndReturnRef.current = onSaveAndReturn;\n /* The surface reports the real view in a layout effect, before any\n dock; this seed is never read in practice. */\n const viewRef = useRef<CalendarView>('timeGridWeek');\n const handleViewChange = useCallback((view: CalendarView) => {\n viewRef.current = view;\n }, []);\n const toolSourceRef = useRef<CalendarToolOpenSource | null>(null);\n const activeToolRef = useRef<string | null>(null);\n /* The rail tool open when Settings replaced it, put back on close. */\n const toolBeforeSettingsRef = useRef<string | null>(null);\n /* The tool last reported open. An id no tool carries docks Appointments\n straight after, so an open is checked against this rather than the id\n before it: a panel that never left the screen is not reported twice. */\n const reportedToolRef = useRef<string | null>(null);\n /* An open of an id the rail had not registered yet: a host that adds a\n tool and opens it in one handler. Settled once the rail commits. */\n const unplacedOpenRef = useRef<{\n id: string;\n source: CalendarToolOpenSource;\n } | null>(null);\n const reportToolOpen = useCallback(\n (id: string, source: CalendarToolOpenSource) => {\n reportedToolRef.current = id;\n if (id === WORKSPACE_TOOL.settings) {\n /* Settings is not a usage tool: its own event fires when it opens. */\n analyticsRef.current?.onSettingsOpened?.();\n } else if (isWorkspaceToolId(id)) {\n analyticsRef.current?.onToolOpen?.({\n toolId: id,\n source,\n view: viewRef.current,\n });\n } else {\n analyticsRef.current?.onExtraToolOpen?.({\n toolId: id,\n /* Only the strip and the host's own code open a host tool. */\n source: source === 'rail' ? 'rail' : 'system',\n view: viewRef.current,\n });\n }\n },\n [],\n );\n /* The Settings panel (P36): the surface publishes into this bridge, the\n rail's panel reads it, and the panel reports unsaved Practice changes. */\n const [settingsBridge] = useState(createSettingsBridge);\n const { openTool, closeTool } = useControlRoomActions();\n /* Below md the rail's strip leaves the row; the rail then shows an open\n tool full screen, as it does in an AppFrame end slot (it reads that\n slot's context, which this workspace supplies for its own rail). */\n const phone = useMediaQuery(PHONE_QUERY);\n /* Read at call time: the rail reports its own phone close from a layout\n effect, before this callback is renewed with the new `phone`. */\n const phoneRef = useRef(phone);\n phoneRef.current = phone;\n const railFrame = useMemo<AppFrameEndSlotContextValue>(\n () => ({\n sharedWidth: null,\n phone,\n /* A tool that closes under focus (the rail went, or the screen is\n now a phone's): the toolbar is the nearest place to be. */\n focusMain: () => settingsBridge.buttonRef.current?.focus(),\n }),\n [phone, settingsBridge],\n );\n /* A leave from Settings that is waiting on the discard question. */\n const [pendingLeave, setPendingLeave] = useState<{\n id: string | null;\n source: CalendarToolOpenSource;\n /** What had focus when the leave was asked for. */\n returnTo: HTMLElement | null;\n } | null>(null);\n const [editorLeave, setEditorLeave] = useState<{\n proceed: () => void;\n returnTo: HTMLElement | null;\n } | null>(null);\n useEffect(() => {\n editorGuard.ask = (proceed) => {\n if (!editorGuard.dirty) {\n proceed();\n return;\n }\n setEditorLeave({\n proceed,\n returnTo:\n document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null,\n });\n };\n }, [editorGuard]);\n const handleActiveToolChange = useCallback(\n (id: string | null) => {\n const source = toolSourceRef.current ?? 'system';\n if (\n activeToolRef.current === WORKSPACE_TOOL.editor &&\n id !== WORKSPACE_TOOL.editor &&\n editorGuard.dirty\n ) {\n /* Close, Escape, a strip click or Settings: the form's typed data\n would go with it. Cancel leaves the tool as it was. */\n toolSourceRef.current = null;\n editorGuard.ask(() => {\n toolSourceRef.current = source;\n if (id) openTool(id);\n else closeTool();\n });\n return;\n }\n if (\n activeToolRef.current === WORKSPACE_TOOL.settings &&\n id !== WORKSPACE_TOOL.settings\n ) {\n /* Every way out of Settings comes through here: Close, Escape, a\n strip click, the editor or details docking from the grid. A save\n in flight holds the panel; unsaved Practice changes ask first. */\n const { busy, dirty, holdFocus } = settingsBridge.guard;\n if (busy) {\n holdFocus?.();\n return;\n }\n if (dirty) {\n toolSourceRef.current = null;\n setPendingLeave({\n id,\n source,\n returnTo:\n document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null,\n });\n return;\n }\n const back = toolBeforeSettingsRef.current;\n toolBeforeSettingsRef.current = null;\n if (id === null) {\n /* A close lands back on the toolbar button that opened it, after\n the rail has put focus on its own strip icon. */\n requestAnimationFrame(() =>\n requestAnimationFrame(() =>\n settingsBridge.buttonRef.current?.focus(),\n ),\n );\n /* A phone has no resting panel: Appointments is not put back\n there (it would open as a full-screen dialog over the grid). */\n const restPhone =\n phoneRef.current && back === WORKSPACE_TOOL.appointments;\n if (back && !restPhone && registeredToolIdsRef.current.has(back)) {\n /* Closing Settings puts back the tool it replaced: no usage\n event, it is not opened afresh. */\n toolSourceRef.current = null;\n activeToolRef.current = back;\n reportedToolRef.current = back;\n setActiveToolId(back);\n if (isWorkspaceToolId(back)) setAnnouncement(dockMessage(back, t));\n return;\n }\n }\n } else if (\n id === WORKSPACE_TOOL.settings &&\n activeToolRef.current !== WORKSPACE_TOOL.settings\n ) {\n toolBeforeSettingsRef.current = activeToolRef.current;\n }\n toolSourceRef.current = null;\n activeToolRef.current = id;\n setActiveToolId(id);\n unplacedOpenRef.current = null;\n if (!id) {\n reportedToolRef.current = null;\n return;\n }\n if (id === reportedToolRef.current) return;\n /* An id no tool carries is reported to neither callback: the rail\n docks Appointments straight after, and that is reported if it\n was not already showing. */\n if (registeredToolIdsRef.current.has(id)) reportToolOpen(id, source);\n else unplacedOpenRef.current = { id, source };\n },\n [reportToolOpen, settingsBridge, editorGuard, openTool, closeTool, t],\n );\n const toggleSettings = useCallback(() => {\n if (activeToolRef.current === WORKSPACE_TOOL.settings) closeTool();\n else openTool(WORKSPACE_TOOL.settings);\n }, [openTool, closeTool]);\n /* After the rail's commit (a child's effects run first), an open it has\n now registered is reported; one it docked away from is dropped. */\n useEffect(() => {\n const unplaced = unplacedOpenRef.current;\n if (!unplaced || unplaced.id !== activeToolId) return;\n unplacedOpenRef.current = null;\n if (registeredToolIdsRef.current.has(unplaced.id))\n reportToolOpen(unplaced.id, unplaced.source);\n }, [activeToolId, reportToolOpen]);\n /* A click on a strip button: the rail opens the tool in the same\n handler, which reads and clears this tag. */\n const markRailPick = useCallback((event: ReactMouseEvent) => {\n if (!(event.target instanceof Element)) return;\n if (!event.target.closest('[data-tool-id]')) return;\n toolSourceRef.current = 'rail';\n queueMicrotask(() => {\n if (toolSourceRef.current === 'rail') toolSourceRef.current = null;\n });\n }, []);\n /* Keyed by appointment, so a tag whose selection never docked cannot\n be credited to a later one. */\n const selectionRef = useRef<{\n eventId: string;\n source: CalendarDetailsOpenSource;\n } | null>(null);\n /* The rail's docking effect (a child's, so it runs first) has read the\n tag by now; one whose selection docked nothing goes with it. */\n useEffect(() => {\n selectionRef.current = null;\n }, [focus]);\n const focusFromCalendar = useCallback(\n (next: RailFocus) => {\n if (next)\n selectionRef.current = { eventId: next.eventId, source: 'calendar' };\n setFocus(next);\n },\n [setFocus],\n );\n const revealFrom = useCallback(\n (\n eventId: string,\n source: Extract<\n CalendarDetailsOpenSource,\n 'appointments_panel' | 'bookings_panel' | 'waiting_list'\n >,\n ) => {\n selectionRef.current = { eventId, source };\n handleRevealAppointment(eventId);\n },\n [handleRevealAppointment],\n );\n const handleDetailsDocked = useCallback((eventId: string) => {\n const tag = selectionRef.current;\n selectionRef.current = null;\n analyticsRef.current?.onAppointmentDetailsOpen?.({\n eventId,\n source: tag?.eventId === eventId ? tag.source : 'host',\n view: viewRef.current,\n });\n }, []);\n const handleRecurringScopeChosen = useCallback(\n (answer: RecurringScopeChosen) =>\n analyticsRef.current?.onRecurringScopeChosen?.(answer),\n [],\n );\n const handleDetailsActionUsed = useCallback(\n (event: { action: CalendarDetailsAction }) =>\n analyticsRef.current?.onDetailsActionUsed?.(event),\n [],\n );\n const handlePeekOpen = useCallback((eventId: string) => {\n analyticsRef.current?.onAppointmentPreviewOpen?.({\n eventId,\n view: viewRef.current,\n privacy: privacyRef.current,\n });\n }, []);\n const handleSettingChanged = useCallback(\n (event: { setting: string; section: 'personal' | 'practice' }) => {\n analyticsRef.current?.onSettingChanged?.(event);\n },\n [],\n );\n const handleHoursOpened = useCallback(() => {\n analyticsRef.current?.onHoursOpened?.();\n }, []);\n const handleFavoritesChange = useCallback(\n (_next: string[], change?: ControlRoomFavoriteChange) => {\n if (change) analyticsRef.current?.onToolPreferencesChange?.(change);\n },\n [],\n );\n const handlePanelWidthChange = useCallback(() => {\n const toolId = activeToolRef.current;\n if (!persistPanelWidthKey || !toolId) return;\n analyticsRef.current?.onToolPreferencesChange?.({\n action: 'resize',\n toolId,\n });\n }, [persistPanelWidthKey]);\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): CalendarWorkspaceToolId | 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. The backlog is\n counted separately, on its own toolbar button. */\n const waitingBadge = waitingList.length;\n const backlogRows = useMemo(\n () => bookingQueue?.rows ?? onlineBookingsToCheck(rows, data),\n [bookingQueue, rows, data],\n );\n /* The three header switches apply on top of the queue: a host-supplied\n `bookingQueue.rows` is still filtered, since the switches are a rail\n concern the host's own query does not need to know about. */\n const backlogViews = useMemo(\n () =>\n backlogRows.map((row) =>\n bookingRowView(\n row,\n data,\n bookingQueue?.lastSeenIso\n ? new Date(bookingQueue.lastSeenIso).getTime()\n : null,\n bookingQueue?.createdAtById?.[row.event.id],\n ),\n ),\n [backlogRows, data, bookingQueue],\n );\n /* Every downstream reader (the toolbar badge, the rail tool's own\n badge, and the panel it docks) shares this ONE filtered list, so the\n count on the button always matches the cards the panel shows. */\n const onlineBookings = useMemo(\n () => filterBacklogViews(backlogViews, backlogFilters).map((v) => v.row),\n [backlogViews, backlogFilters],\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 = rowAsksScope(prevRow);\n /* Rule 7 on an edit (the row's own archive); rule 1 on a create. */\n const archiveId = prevRow\n ? prevRow.archiveId\n : createArchiveIdRef.current;\n const archived = archiveId ? { ...draft, archiveId } : draft;\n await (expandsSeries\n ? handleCreateAppointment(archived)\n : handleCreateAppointment(archived, extras));\n createArchiveIdRef.current = undefined;\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 if (!draft.editEventId && draft.recurrence) {\n analyticsRef.current?.onRecurringCreated?.({\n rule: isCustomRule(draft.recurrence) ? 'custom' : 'preset',\n end: draft.recurrence.ends === 'until' ? 'date' : 'count',\n skipClosedDays: draft.recurrence.skipClosedDays === true,\n });\n }\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 ?? undefined,\n operatorId: draft.operatorId ?? undefined,\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 | Promise<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 const ids = rows.find((row) => row.event.id === eventId)?.series\n ? seriesScopeEventIds(rows, eventId, options?.scope ?? 'this')\n : null;\n const results = ids\n ? ids.map((id) => handleDeleteAppointment(id))\n : [handleDeleteAppointment(eventId, options)];\n /* Say it was done only once the host has done it. */\n const done = (): void => {\n if (ids && ids.length > 1) {\n toastInfo(\n t('calendarWorkspace.inc1.save.seriesDeleted', {\n count: ids.length,\n }),\n );\n }\n if (options?.removeFromCarePlan) {\n toastInfo(t('calendarWorkspace.inc1.save.carePlanRemoved'));\n }\n };\n if (results.every((result) => !result)) return done();\n return Promise.all(results).then(done);\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 (\n kind: 'move' | 'copy',\n surface: CalendarMoveCopySurface,\n withTreatments?: boolean,\n ) => {\n if (!selectedRow || reviewOnlyEventIds.has(selectedRow.event.id)) return;\n setPlacement({ kind, eventId: selectedRow.event.id, withTreatments });\n const eventId = selectedRow.event.id;\n const view = viewRef.current;\n if (kind === 'move') {\n analyticsRef.current?.onAppointmentMoveInitiated?.({\n eventId,\n surface,\n view,\n });\n } else {\n analyticsRef.current?.onAppointmentCopyInitiated?.({\n eventId,\n withTreatments: withTreatments === true,\n surface,\n view,\n });\n }\n },\n [selectedRow, reviewOnlyEventIds],\n );\n const handleMove = useCallback(\n (surface: CalendarMoveCopySurface) => armPlacement('move', surface),\n [armPlacement],\n );\n const handleCopy = useCallback(\n (withTreatments: boolean | undefined, surface: CalendarMoveCopySurface) =>\n armPlacement('copy', surface, withTreatments),\n [armPlacement],\n );\n /* Click-time hooks: Edit and Delete fire on the click, ahead of the\n confirm or the editor, for the selected appointment's id only. */\n const handleEditOpened = useCallback((eventId: string) => {\n analyticsRef.current?.onAppointmentEditOpened?.({\n eventId,\n surface: 'panel',\n view: viewRef.current,\n });\n }, []);\n const handleDeleteInitiated = useCallback(\n (eventId: string, surface: 'panel' | 'editor') => {\n analyticsRef.current?.onAppointmentDeleteInitiated?.({\n eventId,\n surface,\n view: viewRef.current,\n });\n },\n [],\n );\n const handleDocumentCreateClicked = useCallback(\n (eventId: string, kind: CalendarDocumentKind) => {\n analyticsRef.current?.onDocumentCreateClicked?.({\n eventId,\n kind,\n surface: 'panel',\n view: viewRef.current,\n });\n },\n [],\n );\n const handleWhatsAppClicked = useCallback((entryId: string) => {\n analyticsRef.current?.onWaitingListWhatsAppClicked?.({\n entryId,\n surface: 'rail',\n view: viewRef.current,\n });\n }, []);\n /* The surface reports a dragged card dropped, the grid's Move. */\n const handleMoveDropped = useCallback((eventId: string) => {\n analyticsRef.current?.onAppointmentMoveInitiated?.({\n eventId,\n surface: 'grid',\n view: viewRef.current,\n });\n }, []);\n const handlePrintUsed = useCallback(() => {\n analyticsRef.current?.onPrintUsed?.({ view: viewRef.current });\n }, []);\n const handleJumpToDateUsed = useCallback(() => {\n analyticsRef.current?.onJumpToDateUsed?.({ view: viewRef.current });\n }, []);\n /* Stable wrappers for the waiting list's memoised panel. */\n const handleWaitingFilterUsed = useCallback(\n (filter: WaitingQuickView | 'advanced_search') =>\n analyticsRef.current?.onWaitingListFilterUsed?.({ filter }),\n [],\n );\n const handleWaitingAdvancedToggled = useCallback(\n (action: 'show' | 'hide') =>\n analyticsRef.current?.onWaitingListAdvancedFilterToggled?.({ action }),\n [],\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 selectionRef.current = {\n eventId: focusAppointmentId,\n source: 'deep_link',\n };\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\". Going back is the host's page, so\n without `onSaveAndReturn` the arrival is forced to the SIMPLE save\n and the single-Save footer is what the editor shows. */\n setCreateMode({\n tick: 1,\n ...createParameters,\n prefill: onSaveAndReturnRef.current\n ? createParameters.prefill\n : { ...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 /* 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 return (\n <AppFrameEndSlotContext.Provider value={railFrame}>\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 onDraftChange={setDraftSlot}\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 mapsLink={display.mapsLink}\n noteUnrecordedEdits={noteUnrecordedEdits}\n recurrence={recurrence}\n consentsForCares={consentsForCares}\n medicalDevicesForCares={medicalDevicesForCares}\n sameDayReminders={sameDayReminders}\n signatureCredits={signatureCredits}\n createPatientFromBooking={createPatientFromBooking}\n createPatient={createPatient}\n defaultReminders={reminderDefaults}\n proposeFirstVisit={proposeFirstVisit}\n readOnly={readOnly}\n notesSeamFor={notesSeamFor}\n businessHours={businessHours}\n onSave={handleSave}\n onDelete={handleDelete}\n onRecurringScopeChosen={handleRecurringScopeChosen}\n onDetailsActionUsed={handleDetailsActionUsed}\n onMove={handleMove}\n onCopy={handleCopy}\n onEditOpened={handleEditOpened}\n onDeleteInitiated={handleDeleteInitiated}\n onDocumentCreateClicked={handleDocumentCreateClicked}\n onWhatsAppClicked={handleWhatsAppClicked}\n /* Rule 5: the archive offers no status change in the details. */\n onStatusChange={calendarArchive ? undefined : detailsStatusChange}\n onDescriptionChange={handleDescriptionChange}\n onRevealAppointment={revealFrom}\n toolSourceRef={toolSourceRef}\n onDetailsDocked={handleDetailsDocked}\n onRequestSignature={handleRequestSignature}\n onRequestSignatureOnDevice={onRequestSignatureOnDevice}\n onOpenPatient={onOpenPatient}\n onOpenScheduler={onOpenScheduler}\n onSaveAndReturn={onSaveAndReturn}\n onWaitingListFilterUsed={handleWaitingFilterUsed}\n onWaitingListAdvancedFilterToggled={handleWaitingAdvancedToggled}\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={gridDisplay.resourceKind}\n bookings={onlineBookings}\n bookingQueue={bookingQueue}\n backlogFilters={backlogFilters}\n onBacklogFiltersChange={setBacklogFilters}\n waitingListState={waitingListState}\n stateSinceByEventId={stateSinceByEventId}\n reviewOnlyEventIds={reviewOnlyEventIds}\n bookingsSeedTick={bookingsSeed}\n bookingRequest={bookingRequest}\n onCompleteBooking={handleCompleteBooking}\n onPlaceWaiting={handlePlaceWaiting}\n onCreateTask={handleCreateTask}\n onUpdateTask={handleUpdateTask}\n onDeleteTask={handleDeleteTask}\n onSetTaskDone={handleSetTaskDone}\n loadTask={loadTask}\n taskComposeTick={taskComposeTick}\n extraTools={resolvedExtraTools.tools}\n extraToolIds={extraToolIds}\n registeredToolIdsRef={registeredToolIdsRef}\n settingsBridge={settingsBridge}\n editorGuard={editorGuard}\n />\n {pendingLeave ? (\n <CalendarSettingsDiscardDialog\n onKeep={() => {\n const { returnTo } = pendingLeave;\n setPendingLeave(null);\n /* Keep editing puts the user back where they were. */\n requestAnimationFrame(() => {\n if (returnTo?.isConnected) returnTo.focus();\n });\n }}\n onDiscard={() => {\n const leave = pendingLeave;\n setPendingLeave(null);\n settingsBridge.guard.dirty = false;\n toolSourceRef.current = leave.source;\n if (leave.id) openTool(leave.id);\n else closeTool();\n }}\n />\n ) : null}\n {editorLeave ? (\n <CalendarSettingsDiscardDialog\n scope=\"editor\"\n onKeep={() => {\n const { returnTo } = editorLeave;\n setEditorLeave(null);\n /* Cancel puts the user back where they were, form untouched. */\n requestAnimationFrame(() => {\n if (returnTo?.isConnected) returnTo.focus();\n });\n }}\n onDiscard={() => {\n const { proceed } = editorLeave;\n setEditorLeave(null);\n editorGuard.dirty = false;\n proceed();\n }}\n />\n ) : null}\n {calendarArchive && pendingCreate ? (\n <CalendarArchiveCreateDialog\n archive={calendarArchive}\n onCancel={() => setPendingCreate(null)}\n onChoose={(target) => {\n armedArchiveIdRef.current = {\n id: target === 'archive' ? calendarArchive.id : undefined,\n };\n setPendingCreate(null);\n pendingCreate();\n }}\n />\n ) : null}\n <ScrollArea orientation=\"vertical\" className=\"ds:min-w-0 ds:flex-1\">\n <CalendarSheetHost\n onOpenSheet={handleOpenSheet}\n onAnnounce={setAnnouncement}\n editorGuard={editorGuard}\n >\n <CalendarSurface\n draftSlot={draftSlot}\n id={id}\n availableTools={available}\n schedulerLicenseKey={schedulerLicenseKey}\n preferences={preferences}\n rows={rows}\n setRows={setRows}\n display={gridDisplay}\n setDisplay={setDisplay}\n calendarArchive={calendarArchive}\n prompts={prompts}\n defaultDisplay={defaultDisplay}\n onFocus={focusFromCalendar}\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={changePrivacy}\n availability={availability}\n availabilityContext={availabilityContext}\n onComposeNew={\n readOnly\n ? () =>\n toastWarning(\n t('calendarWorkspace.inc1.readOnly.createBlocked'),\n )\n : handleComposeNew\n }\n /* Toolbar's second create button, withheld unless the journey\n supplies `handleCreateTask`. Not gated on `readOnly`: that is\n the appointment right, and task rights are independent. */\n onComposeTask={\n handleCreateTask === undefined ? undefined : composeTask\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 onRetryLoad={onRetryLoad}\n selectedEventId={focus?.eventId ?? null}\n gotoRequest={gotoRequest}\n onBookSlot={handleBookSlot}\n gridHeld={toolHeld}\n onBookSlotFromFinder={handleBookSlotFromFinder}\n reviewOnlyEventIds={reviewOnlyEventIds}\n onHistory={logHistory}\n onMoveOccurrence={handleMoveOccurrence}\n onMoveAppointment={handleMoveAppointment}\n onResizeAppointment={handleResizeAppointment}\n onCopyAppointment={handleCopyAppointment}\n onDeleteAppointment={\n /* A JS host may pass none: the copy Undo is then withheld. */\n typeof hostDeleteAppointment === 'function'\n ? handleDeleteAppointment\n : undefined\n }\n onRecurringScopeChosen={handleRecurringScopeChosen}\n onViewChange={handleViewChange}\n initialView={initialView}\n onNavigate={onViewChange}\n onPeekOpen={handlePeekOpen}\n settingsBridge={settingsBridge}\n settingsOpen={activeToolId === WORKSPACE_TOOL.settings}\n onToggleSettings={toggleSettings}\n onSettingChanged={handleSettingChanged}\n onHoursOpened={handleHoursOpened}\n practiceSettings={practiceSettings}\n onMoveDropped={handleMoveDropped}\n onPrintUsed={handlePrintUsed}\n onJumpToDateUsed={handleJumpToDateUsed}\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. Below md the\n strip is hidden but the rail still mounts, and shows an open tool\n full screen (the phone mode `railFrame` switches on). */}\n <div\n className=\"ds:hidden ds:h-full ds:shrink-0 ds:md:flex ds:print:hidden\"\n onClickCapture={markRailPick}\n >\n <ControlRoomRail\n activeToolId={activeToolId}\n onActiveToolChange={handleActiveToolChange}\n onFavoriteIdsChange={handleFavoritesChange}\n onPanelWidthChange={handlePanelWidthChange}\n side=\"end\"\n resizablePanel\n persistFavoritesKey={persistFavoritesKey}\n persistPanelWidthKey={persistPanelWidthKey}\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 </AppFrameEndSlotContext.Provider>\n );\n}\n","/* ------------------------------------------------------------------ */\n/* AppointmentEditorDialog: the calendar's appointment editor in a */\n/* centred modal, for a host that cannot dock it in the tool rail yet. */\n/* HTP-4261 stopgap: the platform's legacy calendar opens \"Nuovo */\n/* appuntamento\" in a modal, so until `CalendarWorkspace` ships there */\n/* the SAME editor (field order, platform rules, the Custom repeat */\n/* rule) mounts here instead of a second Bootstrap form. Nothing is */\n/* forked: this file is a host for `AppointmentEditorPanel`, exactly as */\n/* the rail is: the providers the panel reads, and a close button. */\n/* ------------------------------------------------------------------ */\nimport {\n useCallback,\n useMemo,\n useRef,\n useState,\n type ComponentProps,\n type ReactNode,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { X } from 'lucide-react';\nimport { Dialog } from '../../components/dialog';\nimport { IconButton } from '../../components/button';\nimport { PanelHeaderActionsProvider } from '../../components/panel-header';\nimport { TooltipProvider } from '../../components/tooltip';\nimport {\n EditorGuardProvider,\n createEditorGuard,\n} from './calendar-editor-guard';\nimport { CalendarSettingsDiscardDialog } from './calendar-settings-panel';\nimport { CalendarDataProvider, type CalendarData } from './calendar.data';\nimport { SheetHostProvider, type SheetHostContext } from './calendar.host';\nimport {\n AppointmentEditorPanel,\n type EditorPlatformOptions,\n type ReminderChannel,\n} from './calendar.sheets';\n\ntype EditorPanelProps = ComponentProps<typeof AppointmentEditorPanel>;\n\nexport interface AppointmentEditorDialogProps extends Omit<\n EditorPanelProps,\n | 'className'\n | 'closeOnSave'\n | 'returnsOnCancel'\n | 'onDraftChange'\n | 'slotPatch'\n /* Duplicate re-seeds the editor through the sheet host, and a dialog\n has no second editor to open. */\n | 'onDuplicate'\n> {\n open: boolean;\n /** Called with `false` on Cancel, the close button, a click outside,\n * and after a save the host accepted. */\n onOpenChange: (open: boolean) => void;\n /** The practice read model the editor resolves patients, operators,\n * chairs, treatments and care plans from: the same `CalendarData` a\n * `CalendarWorkspace` host hands in. */\n data: CalendarData;\n /** Opaque instance id, forwarded to the dialog's agent registration. */\n id?: string;\n}\n\n/** The legacy calendar has no \"send reminder now\" action. */\nconst NO_REMINDER_CHANNELS: readonly ReminderChannel[] = [];\n\n/** The platform modal's description limit (255 characters). */\nconst DESCRIPTION_MAX = 255;\n\n/**\n * The platform modal's own rules, as `CalendarWorkspace` applies them to\n * the docked editor, with the repeat rule the platform's appointment row\n * can store: count OR end date, the Custom rule (`recurrenceInterval`,\n * `recurrenceByDay`), and no closed-day skip, which the platform has no\n * field for. A host's `platform` prop overrides any of these.\n */\nfunction dialogPlatform(data: CalendarData): EditorPlatformOptions {\n return {\n branches: data.branches,\n devicesByCare: data.practiceFeatures.findFreeSlotsByCare\n ? data.careDevices\n : undefined,\n unsignedRequiredDocs: (patientId) =>\n data.unsignedRequiredDocs[patientId] ?? 0,\n submitOnEnter: true,\n reminderChannels: NO_REMINDER_CHANNELS,\n recurrenceExtras: true,\n recurrenceCustom: true,\n recurrenceSkipClosedDays: false,\n operatorAbsenceWarning: true,\n reminderCapability: true,\n firstVisitRequiresPatient: true,\n priceListPhases: true,\n descriptionMaxLength: DESCRIPTION_MAX,\n };\n}\n\nexport function AppointmentEditorDialog({\n open,\n onOpenChange,\n data,\n id,\n platform,\n panelTitle,\n ...panel\n}: AppointmentEditorDialogProps) {\n const { t } = useTranslation('ui');\n const close = useCallback(() => onOpenChange(false), [onOpenChange]);\n /* P38, rule B18: Escape, a click outside and the header's close ask\n before they discard typed data, exactly as the rail does. The form's\n own Cancel asks through the same guard. */\n const [editorGuard] = useState(createEditorGuard);\n const [leaving, setLeaving] = useState<{ proceed: () => void } | null>(null);\n const returnToRef = useRef<HTMLElement | null>(null);\n editorGuard.ask = (proceed) => {\n if (!editorGuard.dirty) {\n proceed();\n return;\n }\n returnToRef.current =\n document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null;\n setLeaving({ proceed });\n };\n const requestClose = useCallback(\n () => editorGuard.ask(close),\n [editorGuard, close],\n );\n /* The panel opens no other sheet from a dialog: Duplicate re-seeds the\n host's own editor through `onDuplicate`, so `open` has nothing to do. */\n const sheetHost = useMemo<SheetHostContext>(\n () => ({ open: () => {}, close }),\n [close],\n );\n const mergedPlatform = useMemo(\n () => ({ ...dialogPlatform(data), ...platform }),\n [data, platform],\n );\n const title =\n panelTitle ??\n t(\n panel.prefill?.editEventId\n ? 'calendarWorkspace.editor.editTitle'\n : 'calendarWorkspace.editor.title',\n );\n /* The panel's own header carries the title and this close button, the\n way the rail injects its own; the dialog's corner X would sit on top\n of the header's action cluster. */\n const closeAction: ReactNode = (\n <IconButton\n icon={<X aria-hidden=\"true\" />}\n intent=\"ghost\"\n size=\"sm\"\n aria-label={t('common.close', 'Close')}\n onClick={requestClose}\n />\n );\n\n return (\n <>\n <Dialog\n open={open}\n onOpenChange={(next) => (next ? onOpenChange(true) : requestClose())}\n id={id}\n >\n <Dialog.Content flush hideCloseButton aria-describedby={undefined}>\n {/* The visible heading is the panel's. The dialog still needs its\n own Title for its accessible name: a plain span, so a screen\n reader does not meet the same heading twice. */}\n <Dialog.Title asChild>\n <span className=\"ds:sr-only\">{title}</span>\n </Dialog.Title>\n <div\n data-component=\"appointment-editor-dialog\"\n className=\"ds:flex ds:min-h-0 ds:flex-1 ds:flex-col\"\n >\n <TooltipProvider>\n <CalendarDataProvider value={data}>\n <SheetHostProvider value={sheetHost}>\n <EditorGuardProvider value={editorGuard}>\n <PanelHeaderActionsProvider actions={closeAction}>\n <AppointmentEditorPanel\n {...panel}\n panelTitle={panelTitle}\n platform={mergedPlatform}\n closeOnSave\n returnsOnCancel\n className=\"ds:min-h-0 ds:flex-1\"\n />\n </PanelHeaderActionsProvider>\n </EditorGuardProvider>\n </SheetHostProvider>\n </CalendarDataProvider>\n </TooltipProvider>\n </div>\n </Dialog.Content>\n </Dialog>\n {leaving ? (\n <CalendarSettingsDiscardDialog\n scope=\"editor\"\n onKeep={() => {\n setLeaving(null);\n requestAnimationFrame(() => {\n if (returnToRef.current?.isConnected) returnToRef.current.focus();\n });\n }}\n onDiscard={() => {\n const { proceed } = leaving;\n setLeaving(null);\n editorGuard.dirty = false;\n proceed();\n }}\n />\n ) : null}\n </>\n );\n}\n"],"names":["__iconNode","CalendarSearch","createLucideIcon","ListPlus","ListTodo","StickyNote","CalendarDataContext","createContext","CalendarDataProvider","value","children","createElement","useCalendarData","data","useContext","OPERATOR_GROUP_NONE_ID","buildOperatorFilterGroups","args","byId","o","inactive","rank","sortMembers","members","a","b","activeDelta","grouped","sections","group","id","ungrouped","flattenOperatorFilterGroups","groups","inactiveIds","g","careSuffix","input","mode","phases","e","describe","careBlock","parts","_a","p","careLabel","cares","associationColor","association","ctx","sources","_b","c","first","_c","_d","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","APPOINTMENT_STATUS_LABEL_KEY","movesSilently","event","patientRefById","eventPatientRef","VIEW_OPTIONS","DEFAULT_DISPLAY","DISPLAY_READERS","readDisplayField","target","field","readChairIds","readOperatorIds","selectionState","selected","count","DAY_WINDOWS","patientAgeYears","dobIso","ageInYears","RECURRENCE_MAX_COUNT","RECURRENCE_FREQUENCIES","RECURRENCE_WEEKDAYS","weekdayOfMonth","date","day","daysInMonth","addMonthsClamped","base","months","d","lastDay","editPrefillFromRow","row","start","end","DRAFT_SNAP","snapForSlot","slotDuration","NONE","DURATION_PRESETS_MIN","durationDigitsFilter","search","digits","initialEditorColor","prefill","BANNER_INKS","APPOINTMENT_PALETTE","swatch","ink","bannerTextColor","backgroundHex","bg","hexToHsl","best","bestRatio","ratio","contrastRatio","drawnRowColors","statusColours","stored","status","colour","GOOGLE_CALENDAR_PALETTE","scheduleByEntryId","rows","out","startIso","entryId","list","careLengthForPhases","care","picked","shares","percent","sum","phase","deriveCareLinkDefaults","link","lines","plan","entry","l","signingSummary","docs","toSign","signatureStatusOf","historyEntriesFromEdit","draft","fields","prevStart","nextStart","prevMin","prevPatient","nextCares","EMPTY_SCHEDULE","priceListState","priceListIdFor","patientId","lists","name","statusChip","APPOINTMENT_STATUS_BADGE_VARIANT","APPOINTMENT_STATE_WORKFLOW","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","FREE_SLOT_DEFAULT_DURATION_MIN","rangeDays","from","to","localIsoDate","pad","n","parseIsoDate","fallbackNowIso","match","year","month","now","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","patient","phones","patientPhones","parseEventDate","byStart","buildPrintSheet","days","axisKind","visibleChairIds","visibleOperatorIds","visible","r","chairs","operators","onDay","appointments","unallocated","tasks","notes","closure","absence","PRINT_LINE_PX","PRINT_ROW_PAD_PX","PRINT_WRAP_CHARS","PRINT_PATIENT_WRAP_CHARS","PRINT_CELL_CLASS","printRowHeight","minLines","nameLength","patientLines","careLines","closureReason","t","locale","formatDay","mergeAvailabilityRanges","slots","slot","groupKey","ranges","sorted","current","startMs","endMs","buildFreeBands","valid","midnight","segmentEnd","range","options","buildFreeSlotCells","combo","answer","existing","searchFreeSlots","duration","notBefore","busy","dayHours","dayOperators","chair","operator","operatorWeek","minute","w","WORKSPACE_TOOL","ALL_WORKSPACE_TOOLS","resolveAvailableTools","requested","available","WORKSPACE_TOOL_IDS","isWorkspaceToolId","resolveExtraTools","tools","rejected","seen","tool","WORKSPACE_VIEWS","WORKSPACE_VIEW_STEM","VIEW_SHORTCUT_KEYS","readWorkspaceViewId","viewForShortcutKey","upper","SHORTCUT_BLOCKED_SELECTOR","shortcutAllowedOn","shortcutViewForKeydown","DEFAULT_HIDDEN_DAYS","weekendHiddenDays","showWeekends","WEEK_DAYS_MONDAY_FIRST","readHiddenDays","DEFAULT_DURATION_RANGE","DEFAULT_WORKSPACE_DISPLAY","readOperatorNameDisplay","readChairNameDisplay","readOperatorListMode","readDurationMin","rounded","readWorkspaceDisplaySettings","source","operatorName","chairName","mapsLink","showCancelled","listMode","minutesToClock","min","practiceDayWindow","workspaceDayWindow","window","effectiveIds","all","toggleSelectedIds","checked","activeFilterCount","selectedChairIds","selectedOperatorIds","bookedDisabledOperatorIds","booked","columnableOperatorIds","keep","listedOperators","showDisabled","chairResourceTitle","operatorResourceTitle","isDisabled","disabledLabel","minutesBetween","rowsWithEnd","eventId","RECURRING_SCOPES","RECURRING_SCOPE_LABEL_KEY","effectiveDeviceId","choice","free","rowAsksScope","seriesScopeEventIds","scope","series","slotConflicts","chairBusy","operatorBusy","rowStart","rowEnd","devicesForCares","devicesByCare","device","signChannelStates","defaultSignMode","copyRowAt","withTreatments","sourceStart","sourceEnd","durationMs","pad2","startValue","endValue","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","appointmentNeedsCompletion","onlineBookingsToCheck","bookingRowView","lastSeenMs","createdAtIso","bookedAtIso","bookedAt","DEFAULT_BACKLOG_FILTERS","filterBacklogViews","views","filters","EMPTY_WAITING_FILTERS","waitingFiltersActiveCount","waitingListRowView","patientRef","appointmentPatientRef","operatorTitle","patientAssigned","withinDayBounds","ms","startOfDayMs","endOfDayMs","copy","waitingEntryMatchesFilters","assigned","scheduled","needle","filterWaitingEntries","entries","quickView","WAITING_ENTRY_KINDS","waitingEntryKind","groupWaitingRows","waitingQuickViewCounts","waitingWhatsAppNumber","dayKey","m","useTickingNow","anchor","useRef","setTick","useEffect","stop","onVisibility","elapsedMs","relativeMinutes","fromMs","toMs","diffMin","elapsedDuration","total","unit","minutes","LIVE_BAND_OPEN_UP_TO","UpcomingAppointmentsPanel","onOpenAppointment","stateSinceByEventId","loading","useTranslation","setRange","todayKey","allItems","useMemo","todaysItems","live","liveIds","nextItem","listItems","summary","jsxs","jsx","Badge","liveBand","Collapsible","CollapsibleTrigger","Stethoscope","ChevronDown","CollapsibleContent","sinceIso","workflow","appointmentStateWorkflow","StateIcon","stateLabel","elapsed","Avatar","WorkflowStatusDisplay","loadingSkeleton","index","Skeleton","AppointmentTimeline","Fragment","CalendarTaskEditor","props","companies","resolvePatientLabel","TaskEditor","seriesIsValid","EDITOR_SKELETON_LABELS","CalendarEditorHydration","load","onCancel","failureMessage","result","setResult","retry","setRetry","controller","error","Alert","width","Button","previous","rowWithCanonicalEditor","snapshot","suffix","DeleteConfirmContent","scopes","offersCarePlanCleanup","onConfirm","setScope","removeFromCarePlan","setRemoveFromCarePlan","pending","setPending","failure","setFailure","confirm","Dialog","RadioGroup","v","option","Radio","Trash2","CalendarDeleteConfirm","open","onOpenChange","onCloseAutoFocus","ScopeContent","CalendarDocumentScopeConfirm","CalendarDetailsHydration","loader","setLoader","useAppointmentDetailsRead","CONTENT_ENTER_CLASS","AppointmentDetailsPanel","LINK_ACTIONS","DETAILS_SHORTCUT_ACTIONS","notesPreviewOf","seam","CalendarAppointmentDetailsPanel","details","notesSeam","onOpenNotes","readOnly","onAssignPatient","onOpenPatient","onSignOnDevice","onEdit","onMove","onCopy","onDelete","deleteConfirm","onDeleteInitiated","onDocumentCreateClicked","onDetailsActionUsed","onStatusChange","onDescriptionChange","noteUnrecordedEdits","privacyTitle","confirmingDelete","setConfirmingDelete","askingScopeFor","setAskingScopeFor","rootRef","returnFocusTo","selector","node","used","usedLink","followed","notesFor","notesShown","seamRef","hasLoader","noteId","description","CalendarNotesDock","editor","active","request","visited","setVisited","panel","CalendarPatientContext","onChange","CalendarArchiveBanner","archive","CalendarArchiveCreateDialog","onChoose","SheetHostReactContext","SheetHostProvider","useSheetHost","host","CalendarPatientPicker","onCreatePatient","created","setCreated","creating","setCreating","setError","mountedRef","focusNextRef","createPatient","typedText","selectedLabel","PatientPicker","CalendarPatientLocked","fallbackLabel","useFormField","MAX_FRAMES","isSettled","layer","whenRailSettled","getNode","run","frame","frames","calm","tick","CONTROLS","firstEnabledControl","useEditorInitialFocus","wrapper","control","CalendarSeriesScopeChooser","titleId","useId","warningId","setPicked","warns","createEditorGuard","proceed","EditorGuardContext","EditorGuardProvider","useEditorGuard","MAX_INTERVAL","UNIT_FREQUENCY","UNITS","UNIT_KEY","EVERY_KEY","ORDINAL_KEY","PRESET_STEP","WEEK_ORDER","weekdayCode","defaultCustomRecurrence","isCustomRule","rule","customRecurrenceFromRule","preset","ordinal","code","monthlyChoices","nth","resolveMonthlyBy","monthlyBy","weeklyDays","customRecurrenceRule","interval","weekdayName","style","useRecurrenceSummary","frequency","custom","ends","untilDate","monthlyLabel","weekday","every","RECURRENCE_LABEL_KEY","names","format","getShortDateFormat","CustomRecurrenceFields","fieldClassName","wideClassName","weekdaysLabelId","weekdaysHintId","anchorDay","pressed","weekdayLong","FormField","NumberInput","Select","isAnchor","on","RecurrenceSummaryLine","className","Repeat","restrictionFor","resources","pick","allowedOperatorsFor","allowedChairsFor","isResourceAllowed","restriction","bookingKey","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","avatar","EyeOff","UserX","Timestamp","Globe","TransactionChip","Armchair","treatment","Tag","ButtonGroup","UserPlus","IconButton","Eye","Pencil","WhatsAppGlyph","BookingCardsSkeleton","activeOperators","whatsAppUnavailableKey","PatientNotesPanel","PatientNotesPanelContent","editable","currentNoteId","currentNoteKey","note","writable","requestedPatient","NotesPanel","submission","DurationCombobox","Combobox","parsed","REMINDER_CHANNELS","EDITOR_TIER_CONTAINER","EDITOR_FORM_GRID","EDITOR_COMPACT_FIELDS_CLASS","EDITOR_FIELD_WIDE","EDITOR_FIELD_SHORT_STACKED","EDITOR_FIELD_SHORT","AppointmentEditorPanel","onSave","onDuplicate","panelTitle","headerIcon","identity","after","closeOnSave","returnsOnCancel","onDraftChange","onPatientContextChange","slotPatch","scheduleByEntry","history","onWhatsApp","hostCapabilities","onRecurringScopeChosen","platform","tUi","runtimeI18n","detailKey","closeSheet","openSheet","editorGuard","isEdit","hostScopes","seriesScopes","seriesScope","setSeriesScope","changingScope","setChangingScope","choosingScope","capabilityScope","capabilities","canEditCare","patientLocked","operatorOptions","saving","setSaving","accepted","setAccepted","saveError","setSaveError","reminderRefused","setReminderRefused","reminderAlertId","savingRef","acceptedRef","setPatientId","createdPatient","setCreatedPatient","creatingPatient","setCreatingPatient","focusPickerNextRef","createPatientFromBooking","createBookingPatient","setEmailReminder","setSmsReminder","type","setType","setDate","time","setTime","durationMin","setDurationMin","setOperatorId","setChairId","colorHex","setColorHex","setCare","takesReminderDefaults","emailReminder","smsReminder","firstVisit","setFirstVisit","openingTicks","savedFieldKnown","linkPrefill","careLink","setCareLink","carePlanId","setCarePlanId","entryIds","setEntryIds","phaseSelection","setPhaseSelection","priceListId","setPriceListId","priceRowKeyRef","priceRows","setPriceRows","isBilled","activeLocale","openPlans","lastPatientRef","nextId","priceLists","priceListCatalogue","priceListOffered","priceListRelationShown","linkCareShown","planChoices","planEntries","entryState","toggleEntry","togglePhase","ordered","patchPriceRow","patch","addPriceRow","removePriceRow","togglePriceRowPhase","catalogue","togglePriceRowAllPhases","currentLink","phasesByEntry","linkKey","appliedLinkRef","defaults","linkedCareIds","selectedCareIds","selectedCares","operatorRestriction","chairRestriction","allDay","setAllDay","appliedPatchRef","seededRule","seededCustom","repeats","setRepeats","recurrence","setRecurrence","customRecurrence","setCustomRecurrence","recurrenceEnds","setRecurrenceEnds","recurrenceCount","setRecurrenceCount","recurrenceUntil","setRecurrenceUntil","skipClosedDays","setSkipClosedDays","skipHintId","recurrenceExtras","recurrenceCustomOn","skipClosedDaysOn","untilRequired","untilInvalid","recurrenceStart","recurrenceSummary","addToWaitingList","setAddToWaitingList","offersWaitingTick","setStatus","consentsForCares","consentEventId","consentItems","consentsFlipped","setConsentsFlipped","consentTicked","consentIds","medicalDevicesForCares","deviceSlotKey","devicePicks","setDevicePicks","pickedDevices","deviceChoices","deviceAssignments","deviceId","serializeDraft","typed","autoPlan","initialDraftRef","dirty","typedBaselineRef","holdsTypedData","rawClosure","operatorAbsent","ctaSatisfied","descriptionMax","descriptionTooLong","twoStepSave","canSave","canCancel","formRef","editedEventTitle","formPatientLabel","confirmDeleteOpen","setConfirmDeleteOpen","recurringSaveMode","setRecurringSaveMode","signMode","setSignMode","signPatientRef","branches","branchId","setBranchId","unsignedDocs","noSignatureCredits","signModeOffered","creditsMessageShown","signChannels","smsOffered","emailOffered","smsReasonKey","emailReasonKey","gateOnPatient","showReminders","showFirstVisit","proposeFirstVisitRef","firstVisitPickedRef","firstVisitPatientRef","proposeDateMs","propose","requiredDevices","slotStart","sameDay","setSameDay","sameDayAskRef","sameDayDayMs","editedId","ask","sameDayOf","smsSameDay","emailSameDay","telehealthNoReminder","reminderRefusedShown","scopeApplies","cleanupApplies","deleteScopeApplies","deleteScopes","seriesStartChanged","discardsOverrides","patientFieldRef","operatorFieldRef","chairFieldRef","chooserRef","scopeChangeRef","choosingRef","saveExtras","subView","setSubView","historyBtnRef","historyHeaderRef","prevSubViewRef","panelLocale","handleSave","toastWarning","submitButtonRef","handleFormSubmit","handleDeleteConfirmed","handleDuplicate","PanelHeader","HistoryIcon","ArrowLeft","AppointmentHistoryTimeline","CalendarPlus","Lock","s","DETAIL_STAMP_FORMAT","Link","entryCare","Checkbox","el","CalendarClock","rowCare","rowPhases","locked","removeKey","allPhases","Plus","StateBackedTextInput","KeyValuePair","DatePicker","TimePicker","ColorPicker","_e","flipped","careName","chosen","allBusy","label","_f","SendReminderGroup","DropdownMenu","IconButtonGroup","Move","ClipboardPaste","Copy","ClipboardList","Save","X","AppointmentIdentity","showAge","anamnesisAnswers","AppointmentIdentityStrip","sentVia","setSentVia","channels","MessageSquare","Mail","VisuallyHidden","AppointmentExtras","signRequestedVia","onRequestSignature","onRequestSignatureOnDevice","meta","signing","signReadout","setSignReadout","requestSignature","requestedLine","linkedPlan","linkedEntries","priceListName","money","line","mapQuery","patientAddressLine","mapLabel","patientAddressLabel","showMapRow","hasPatientFacts","itemCare","PenLine","Check","doc","SignatureStatusChip","Send","Smartphone","patientMapsUrl","groupBookingViewsByDate","dateKey","BACKLOG_SETTINGS_MARK_CLASS","BACKLOG_SETTINGS_HINT_CLASS","backlogIsNarrowed","chairsExist","BacklogSettingsMenu","narrowed","onFiltersChange","hintId","setFilter","gap","Settings","RotateCcw","BookingsPanel","bookings","lastSeenIso","createdAtById","currentBookingId","currentBookingKey","onRetry","resourceKind","hasHiddenChairRows","currentCardRef","renderCard","EmptyState","useWaitingEntryForm","setDescription","showError","setShowError","reset","WaitingEntryFields","form","TextArea","WaitingListEntrySubview","onRemove","showRemove","PanelSubview","Hourglass","PrintPatientCell","PrintCaresCell","PrintAllocationCell","practice","PrintSheet","rangeTitle","columnDefs","cols","formatTimeRange","gridOptions","chairNames","operatorNames","noteLabel","createPortal","section","hasRows","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","nextOperators","nextChairs","eligibleOperators","eligibleChairs","scopedOperators","scopedChairs","projectionContext","chosenOperatorIds","operatorGroups","operatorSections","chairSections","buildQuery","computeSlots","computeFreeSlotsLocally","publish","searchStamp","askedStampRef","abortRef","askServer","query","searchedRef","runSearch","computeRef","publishRef","allFoundRef","searched","askServerRef","timer","handleSearch","pagerStepDays","handleShowMore","autoSearchedRef","handleShowOnGridChange","noResultsDescription","handleBook","careDevices","maxRangeDays","rangeTooLong","missingPracticeHours","missingOperatorHours","byDay","Funnel","UserCog","Switch","allocation","facts","rowIsButton","CalendarLoadError","STATUS_COLOUR_TOKEN","STATUSES","toHex","resolveToken","token","probe","painted","resolveStatusColours","hex","THEME_MEDIA","sameColours","useStatusColours","anchorRef","colours","setColours","refresh","observer","STICKY_HEADER_CELL","MODE_BANNER","stickyScrollport","overflowX","overflowY","stickyHeaderOffset","navigation","header","stickyOffsets","banner","navPort","bannerPort","nav","bannerTop","bannerClears","headerOffset","pinned","trackStickyHeaderOffset","surface","resizes","measure","follow","nextHeader","nextBanner","offsets","mutations","PromptAction","CalendarPromptAlerts","prompts","restoreFocus","safeAcademyHref","href","DEFAULT_CALENDAR_ID","NO_NOTIFY","NAV_BLOCK_SIZE_CLASS","FC_STICKY_OFFSET_CLASS","MODE_BANNER_OFFSET_CLASS","FOCUS_CLEARANCE_CLASS","ACTION_BADGE_CLASS","ACCESSIBLE_TARGET_CLASS","ACCESSIBLE_TARGET_SQUARE_CLASS","NO_IDS","RailToolButton","badgeCount","badgeVariant","iconProps","CalendarSurface","setRows","draftSlot","onFocus","onComposeNew","onComposeTask","onOpenWaitingList","onAddWaitingEntry","onOpenOnlineBookings","onlineBookingsCount","waitingBadgeCount","onVisibleRangeChange","onRetryLoad","selectedEventId","gotoRequest","onBookSlotFromFinder","display","setDisplay","defaultDisplay","onHistory","reviewOnlyEventIds","detailsOnEveryClick","gridHeld","placement","onPlacementEnd","createMode","onCreateModeEnd","focusScroll","saveNotice","onPrivacyChange","availability","availabilityContext","availableTools","schedulerLicenseKey","preferences","onMoveOccurrence","onMoveAppointment","onResizeAppointment","onCopyAppointment","onDeleteAppointment","onViewChange","initialView","onNavigate","onPeekOpen","settingsBridge","settingsOpen","onToggleSettings","onSettingChanged","onHoursOpened","practiceSettings","onMoveDropped","onPrintUsed","onJumpToDateUsed","calendarArchive","inc1","calRef","freeBand","setFreeBand","root","freeOptions","band","bookFreeSlot","onlyFreeOption","bookFreeSlotRef","surfaceRef","navigationRef","useLayoutEffect","chairFilterButtonRef","storedViewId","setStoredViewId","hiddenDays","setHiddenDays","legacy","storedChairIds","setSelectedChairIds","storedOperatorIds","setSelectedOperatorIds","archived","archiveViewId","setArchiveViewId","addressViewId","setAddressViewId","viewOptionId","setViewOptionId","gridLocked","setPrivacy","currentDate","setCurrentDate","currentDateRef","mountDate","setMountDate","onlyAvailable","setOnlyAvailable","showDisabledOperators","setShowDisabledOperators","chairFilterOpen","setChairFilterOpen","operatorFilterOpen","setOperatorFilterOpen","printOpen","setPrintOpen","printDay","setPrintDay","printPending","setPrintPending","setRangeTitle","peek","setPeek","pendingMove","setPendingMove","closedPrompt","setClosedPrompt","notifySms","setNotifySms","notifyEmail","setNotifyEmail","moveReadout","setMoveReadout","moveScope","setMoveScope","copyCountRef","hostSeriesMove","notifyOffered","asksScope","visibleRangeRef","visibleRange","setVisibleRange","isDateVisible","stem","isMonth","calendarView","placeRef","onViewChangeRef","projecting","allChairIds","keptDisabledIds","allOperatorIds","loadingDates","errorDates","dayWindow","printDays","printSections","cardContext","none","getInitials","fcEvents","mapped","shadeFrom","shadeTo","columnsHiddenWhenAbsent","closureBanners","availabilityEvents","cell","unavailabilityEvents","draftEvents","draftColumn","asAllDay","placementRow","activeMode","modeColorHex","modeInkHex","modeBannerLabel","endMode","lastFocusScrollRef","lastNoticeTickRef","reasons","message","toastSuccess","proceedEventClick","handleEventClick","handlePeekOpen","handlePeekClose","lastRangeRef","lastNavigationRef","onNavigateRef","handleDatesSet","info","axis","rangeKey","recordMoved","change","applyDrop","owned","targets","isPrimary","updated","settleWrite","written","rollback","fallback","onSaved","refusedReadout","commitMove","notify","setEnd","applyResize","newEnd","before","fromMin","toMin","patientNotices","movedNoticeOn","smsDefaultOn","emailDefaultOn","seedNotifyDefaults","handleDrop","operatorForDay","commit","handleResize","oldEnd","announce","oldMinutes","toastInfo","putBack","log","confirmMove","oldStart","newStart","hostScope","alsoIds","cancelMove","openDay","proceedDateClick","selectedDurationMin","copyId","undone","recordCreated","saved","canUndo","restore","resolve","handleDateClick","handleDateSelect","switchView","onKeyDown","setAxis","practiceHasOperatorGroups","flatOperators","revealDisabledOperators","flatOperatorList","filterCount","resetFilters","viewLabel","practiceWindow","changeSetting","setting","changeHiddenDays","resetSettings","operatorRow","headerBlock","SquareCheckBig","Printer","SlidersHorizontal","navigationRow","Tooltip","ResourceChip","Kbd","ChevronLeft","ChevronRight","peekMeta","peekRow","peekPlan","peekPatient","peekChair","peekOperator","pendingRow","pendingRef","pendingHostScope","pendingAsksScope","pendingNotify","pendingPatientName","pendingChannels","moveFromValue","moveToValue","oldResourceId","newResourceId","resourceChanged","resourceTitle","res","part","ScrollArea","Card","Calendar","HoverCard","openEvent","AppointmentPeek","IndicatorChips","CalendarSettingsIcal","icalLinks","idPrefix","onBusyChange","asking","setAsking","revoking","setRevoking","replaced","setReplaced","errors","setErrors","announcement","setAnnouncement","buttons","returnTo","busyRef","canRevoke","feed","anyRevoke","urlOf","mine","revoke","onRevoke","_dropped","rest","getErrorMessage","SectionCard","rowId","CopyField","PRACTICE_SWITCHES","PATIENT_NOTICE_SWITCHES","OPERATOR_NOTICE_SWITCHES","listedChannels","presentKeys","signature","_key","layerChanges","baseline","was","layered","text","hasIcalFeeds","hasPracticeMember","CalendarSettingsPractice","onDirtyChange","hoursSummary","shownKeys","shown","noticeId","setBaseline","setDraft","setSaved","changedKeys","whatsapp","tooLong","textRef","valueSignature","seenSignature","setSeenSignature","onBusyRef","onDirtyRef","busyKinds","reportBusy","save","setNotice","setWhatsapp","insertPlaceholder","discard","hoursLink","notices","renderNoticeGroup","titleKey","hintKey","labelKey","TokenInsertMenu","CALENDAR_SETTINGS_OVERLAY_ID","DURATION_PRESETS","CalendarSettingsSections","onHiddenDaysChange","hasOperatorGroups","academyHref","onPracticeSettingChanged","onPracticeBusyChange","onPracticeDirtyChange","monthNoteIdProp","i18n","generatedMonthNoteId","monthNoteId","myCalendarId","academyUrl","durationOptions","parse","toggle","CheckboxGroup","STATUS_ICON","Icon","STATUS_LABEL_KEYS","EVENT_FLAGS","CalendarSettingsOverlay","onReset","returnFocusRef","closeRequestRef","practiceSaving","setPracticeSaving","practiceDirty","setPracticeDirty","confirmDiscard","setConfirmDiscard","practiceShown","saveBlocksClose","draftAsksFirst","requestOpenChange","requestCloseRef","Sheet","createSettingsBridge","listeners","listener","CalendarSettingsPanelSlot","bridge","useSyncExternalStore","CalendarSettingsPanel","guard","CalendarSettingsDiscardDialog","onKeep","onDiscard","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","number","onOpen","member","EntryMenuMember","editLabel","editBlockedReason","removeLabel","triggerRef","Ellipsis","WaitingEntryCard","onPlace","onFindSlots","onWhatsAppClick","reasonId","linked","memo","notLoaded","hidden","appointmentTitle","masked","privacyMask","plainTitle","contactRef","who","honestGap","whatsappNumber","whatsappLabel","canWrite","assignBlocked","placeLabelKey","placeBlocked","dotStyle","blockedProps","blocked","withReason","reason","CalendarDays","Phone","WaitingListSkeleton","WaitingListPanel","onPlaceWaiting","onFindSlotsForWaiting","onRemoveWaiting","onOpenEntryForm","entryForm","onSaveEntry","onCancelEntry","onFilterUsed","onAdvancedFilterToggled","headerRef","advancedId","setQuickView","showAdvanced","setShowAdvanced","applied","setApplied","changeQuickView","counts","appliedCount","firstRead","followedLoading","enterClass","subview","lastEntryRef","yesNoOptions","advancedForm","advancedLabel","full","WaitingGroup","removedEntry","headingId","WORKSPACE_REMINDER_CHANNELS","WORKSPACE_DESCRIPTION_MAX","NO_GLOBAL_TOOLS","NO_EXTRA_TOOLS","dockMessage","toolId","CalendarSheetHost","onOpenSheet","onAnnounce","onClose","openNotes","openTool","useControlRoomActions","restTool","useRestingTool","EditorToolHost","withheld","UpcomingPanel","FOCUS_RETURN_FRAMES","PHONE_QUERY","closeTool","useAppFrameEndSlot","focusMain","settle","CalendarRailTools","workspaceRef","activeToolId","focus","turnPrivacyOff","selectedRow","editorMode","onEditorModeChange","editorSeed","loadAppointmentEditor","loadAppointmentDetails","waitingList","waitingSeedTick","findSlotsSeed","signRequests","sameDayReminders","signatureCredits","defaultReminders","proposeFirstVisit","notesSeamFor","businessHours","onEditOpened","onWhatsAppClicked","onRevealAppointment","toolSourceRef","onDetailsDocked","onOpenScheduler","onSaveAndReturn","onWaitingListFilterUsed","onWaitingListAdvancedFilterToggled","onShowAvailability","onFinderSearchRange","gridAxis","bookingQueue","backlogFilters","onBacklogFiltersChange","waitingListState","bookingsSeedTick","bookingRequest","onCompleteBooking","onCreateTask","onUpdateTask","onDeleteTask","onSetTaskDone","loadTask","taskComposeTick","extraTools","extraToolIds","registeredToolIdsRef","contextKey","patientContext","setPatientContext","reportPatient","notesPatientId","hasNotes","notesRequest","setNotesRequest","previousActiveTool","leftNotes","focusFrame","noticeFocusFrame","onPrivacyOff","focused","previousTool","schedule","focusedPatientId","focusedPatientName","unsignedRequiredDocs","editorPlatform","detailsPlatform","extrasPlatform","findSlotsPlatform","appointmentsTool","detailsMode","readsDetails","editing","detailsReadOnly","composingTask","setComposingTask","isTaskRoute","taskEditingId","seededPrefill","formWithheld","editOutcome","refocusEdit","assignFocusId","setAssignFocusId","detailsTick","setDetailsTick","saveEdit","extras","deleteEdit","closeEdit","outcome","closeTaskPanel","editFromDetails","canCompleteBooking","assignFromDetails","renderDetails","notesPatient","liveAction","button","focusEdit","editorTool","PrivacyNoticePanel","editorPatientRef","editorPatient","editorRow","sortHistoryNewestFirst","_g","bookingAddress","setBookingAddress","bookingQueued","bookingsTool","waitingListTool","settingsTool","findSlotsTool","hostTools","_hold","sharedPanel","NotebookPen","registry","useControlRoomTools","registeredToolIds","useIsomorphicLayoutEffect","dockTool","openedRef","prevFocusRef","heldRef","prevSeedTickRef","prevTaskComposeTickRef","prevFindSlotsTickRef","prevBookingsTickRef","prevWaitingTickRef","lastDockedToolRef","unchanged","initialWorkspaceDisplay","initialDisplay","CalendarWorkspace","TooltipProvider","ControlRoomProvider","CalendarWorkspaceBody","journey","permissions","focusAppointmentId","focusBookingId","focusBookingKey","createParameters","freeSlot","controlledBacklogFilters","persistFavoritesKey","persistPanelWidthKey","analytics","reminderSms","reminderEmail","reminderDefaults","uncontrolledBacklogFilters","setUncontrolledBacklogFilters","setBacklogFilters","resolvedLocale","setActiveToolId","setDraftSlot","availableToolsKey","resolvedExtraTools","toolHeld","rejectedTools","gridDisplay","journeyRows","setFocus","setWaitingList","backlogSeed","logHistory","hostRequestSignature","hostComposeNew","handleRemoveWaiting","handleUpsertWaiting","handleOpenBacklog","handleVisibleRangeChange","hostDeleteAppointment","hostMoveOccurrence","hostMoveAppointment","hostResizeAppointment","hostCopyAppointment","handleStatusChange","hostDescriptionChange","hostBookSlot","handleRevealAppointment","handleCreateAppointment","handleFindSlotsForWaiting","clearFindSlotsSeed","hostBookSlotFromFinder","handleShowAvailability","notesByPatient","notesLoadByPatient","handleLoadNotes","handleAddNote","handleEditNote","handleDeleteNote","handleToggleNotePin","handleToggleNoteFlag","handleNoteWriteError","requestNoteAiDraft","dictateNote","noteAiConsentFor","noteComposerExtrasFor","handleCreateTask","handleUpdateTask","handleDeleteTask","handleSetTaskDone","archiveIdOf","archiveTail","archiveId","handleRequestSignature","handleDescriptionChange","handleMoveOccurrence","move","handleDeleteAppointment","handleMoveAppointment","handleResizeAppointment","resize","handleCopyAppointment","pendingCreate","setPendingCreate","armedArchiveIdRef","createArchiveIdRef","askCreate","handleComposeNew","handleBookSlot","handleBookSlotFromFinder","setTaskComposeTick","composeTask","detailsStatusChange","content","setAnnouncementRaw","privacyRef","onPrivacyChangeRef","changePrivacy","analyticsRef","onSaveAndReturnRef","viewRef","handleViewChange","activeToolRef","toolBeforeSettingsRef","reportedToolRef","unplacedOpenRef","reportToolOpen","useMediaQuery","phoneRef","railFrame","pendingLeave","setPendingLeave","editorLeave","setEditorLeave","handleActiveToolChange","holdFocus","back","restPhone","toggleSettings","unplaced","markRailPick","selectionRef","focusFromCalendar","revealFrom","handleDetailsDocked","tag","handleRecurringScopeChosen","handleDetailsActionUsed","handleSettingChanged","handleHoursOpened","handleFavoritesChange","_next","handlePanelWidthChange","setEditorMode","handleOpenSheet","waitingBadge","backlogRows","backlogViews","onlineBookings","setSaveNotice","prevRow","expandsSeries","siblings","edited","handleDelete","done","setPlacement","placementRef","armPlacement","handleMove","handleCopy","handleEditOpened","handleDeleteInitiated","handleDocumentCreateClicked","handleWhatsAppClicked","handleMoveDropped","handlePrintUsed","handleJumpToDateUsed","handleWaitingFilterUsed","filter","handleWaitingAdvancedToggled","endPlacement","landed","settled","setCreateMode","endCreateMode","setFocusScroll","handleCompleteBooking","bookingsSeed","setBookingsSeed","handleOpenOnlineBookings","setBookingRequest","setEntryForm","entryOpenerRef","openEntryForm","closeEntryForm","prevEntryFormRef","had","opener","handleSaveEntry","handleRemoveWaitingEntry","handlePlaceWaiting","deepLinkRef","AppFrameEndSlotContext","leave","ControlRoomRail","NO_REMINDER_CHANNELS","DESCRIPTION_MAX","dialogPlatform","AppointmentEditorDialog","close","leaving","setLeaving","returnToRef","requestClose","sheetHost","mergedPlatform","closeAction","PanelHeaderActionsProvider"],"mappings":"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","x_google_ignoreList":[0,1,2,3]}